From: Robert Pengelly Date: Fri, 27 Feb 2026 20:52:08 +0000 (+0000) Subject: Added mtime and fixed bugs X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=2eb78a8380b46da47f5445b5b9a5b5d50d8ab542;p=tar.git Added mtime and fixed bugs --- diff --git a/stdint.h b/stdint.h new file mode 100644 index 0000000..1b97ab8 --- /dev/null +++ b/stdint.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * @file stdint.h + *****************************************************************************/ +#ifndef _STDINT_H_INCLUDED +#ifndef _STDINT_H +#ifndef _STDINT_H_ + +#define _STDINT_H_INCLUDED +#define _STDINT_H +#define _STDINT_H_ + +#include + +/* Add all data types (even though we don't use them) as the project seems to fail to build on some systems. */ +typedef signed char int8_t; +typedef unsigned char uint8_t; + +typedef signed short int16_t; +typedef unsigned short uint16_t; + +#if INT_MAX > 32767 +typedef signed int int32_t; +typedef unsigned int uint32_t; +#else +typedef signed long int32_t; +typedef unsigned long uint32_t; +#endif + +#ifndef _INT64_T +#define _INT64_T +#if defined (NO_LONG_LONG) || ((ULONG_MAX >> 16) >> 16) == 0xffffffff +typedef signed long int64_t; +#else +typedef signed long long int64_t; +#endif +#endif /* _INT64_T */ + +#ifndef _UINT64_T +#define _UINT64_T +#if defined (NO_LONG_LONG) || ((ULONG_MAX >> 16) >> 16) == 0xffffffff +typedef unsigned long uint64_t; +#else +typedef unsigned long long uint64_t; +#endif +#endif /* _UINT64_T */ + +#endif /* _STDINT_H_ */ +#endif /* _STDINT_H */ +#endif /* _STDINT_H_INCLUDED */ diff --git a/tar.c b/tar.c index 5a64281..b5393fa 100755 --- a/tar.c +++ b/tar.c @@ -9,6 +9,7 @@ #include "lib.h" #include "report.h" +#include "stdint.h" #include "tar.h" struct tar_state *state = 0; @@ -63,10 +64,23 @@ static int write_null_bytes (FILE *fp, int n) { } +#if defined (NO_LONG_LONG) +# define I64_FMT "l" +#elif defined (_MSVC_) +# define I64_FMT "I64" +#elif defined (__PRI_64_LENGTH_MODIFIER__) /* Mac */ +# define I64_FMT __PRI_64_LENGTH_MODIFIER__ +#elif (defined (SIZEOF_LONG) && SIZEOF_LONG >= 8) || ((ULONG_MAX >> 16) >> 16) == 0xffffffff +# define I64_FMT "l" +#else +# define I64_FMT "ll" +#endif + #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) # include # include # include +# include # include #ifndef S_IFDIR @@ -140,9 +154,9 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { memset (&header, 0, sizeof (header)); strcpy (header.name, p); - sprintf (header.mode, "%o", mode); - sprintf (header.owner, "%o", 0); - sprintf (header.mtime, "%o", 0); + sprintf (header.mode, "%07o", mode); + sprintf (header.owner, "%07o", 0); + sprintf (header.mtime, "%011"I64_FMT"o", stbuf.st_mtime); if (stbuf.st_mode & S_IFDIR) { @@ -151,14 +165,16 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { struct dirent *de; char *subpath; - sprintf (header.size, "%o", 0); + memset (header.size, '0', 11); header.type = '5'; /* MTAR_TDIR */ + if (header.name[strlen(p) - 1] != '/') { + header.name[strlen(p)] = '/'; + } + sprintf (header.checksum, "%06o", checksum (&header)); header.checksum[7] = ' '; - header.name[strlen(p)] = '/'; - if (fwrite (&header, 1, sizeof (header), tarfp) != sizeof (header)) { report_at (program_name, 0, REPORT_ERROR, "failed to write header to '%s'", state->target); } @@ -218,7 +234,7 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { FILE *fp; unsigned char *data; - unsigned long bytes, read; + uint64_t bytes, read; if (!(fp = fopen (p2, "r+b"))) { @@ -232,7 +248,7 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { fseek (fp, 0, SEEK_SET); - sprintf (header.size, "%lo", bytes); + sprintf (header.size, "%011"I64_FMT"o", bytes); header.type = '0'; /* MTAR_TREG */ sprintf (header.checksum, "%06o", checksum (&header)); @@ -440,14 +456,47 @@ static BOOL IsDirectory (LPCTSTR szPath) { } -static void add_entry (FILE *tarfp, const char *root, const char *path) { +static uint64_t FileTimeToUnixTime (FILETIME ft) { + + // 1. Copy FILETIME into a 64-bit integer + ULARGE_INTEGER ull; + + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + + // 2. The offset between 1601 and 1970 in 100-nanosecond intervals + // This magic number is (11644473600 * 10,000,000) + const unsigned __int64 UNIX_EPOCH_OFFSET_TICKS = 116444736000000000ULL; + + // 3. Subtract the offset and divide by 10 million to get seconds + if (ull.QuadPart < UNIX_EPOCH_OFFSET_TICKS) { + return 0; /* File is older than 1970 */ + } + + return (uint64_t) ((ull.QuadPart - UNIX_EPOCH_OFFSET_TICKS) / 10000000ULL); + +} + +static uint64_t CreationTime (LPCTSTR szPath) { + + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + + if (GetFileAttributesEx (szPath, GetFileExInfoStandard, &fileInfo)) { + return FileTimeToUnixTime (fileInfo.ftCreationTime); + } + + return 0; + +} + +static void add_entry (FILE *tarfp, char *root, const char *path) { struct tar_raw_header header; const char *p = path; char *p2; - unsigned long len; + unsigned long len, i; int mode; if (isalpha ((int) p[0]) && p[1] == ':') { @@ -462,21 +511,23 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { len = strlen (root); - if (root[len - 1] == '/' || root[len - 1] == '\\') { + while (root[len - 1] == '/' || root[len - 1] == '\\') { - len += (strlen (p) + 1); - - p2 = xmalloc (len); - sprintf (p2, "%s%s", root, p); + root[len - 1] = '\0'; + len--; - } else { + } - len += (1 + strlen (p) + 1); - - p2 = xmalloc (len); - sprintf (p2, "%s/%s", root, p); + for (i = 0; i < len; i++) { + + if (root[i] == '\\') { + root[i] = '/'; + } } + + p2 = xmalloc (len + 1); + sprintf (p2, "%s/", root); } else { p2 = xstrdup (path); @@ -485,8 +536,8 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { memset (&header, 0, sizeof (header)); strcpy (header.name, p); - sprintf (header.owner, "%o", 0); - sprintf (header.mtime, "%o", 0); + sprintf (header.owner, "%07o", 0); + sprintf (header.mtime, "%011"I64_FMT"o", CreationTime (p2)); if (state->mode) { @@ -499,10 +550,10 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { mode = (o1 << 6) | (o2 << 3) | o3; } else { - mode = (IsDirectory (p2) ? 775 : 644); + mode = (IsDirectory (p2) ? 0775 : 0644); } - sprintf (header.mode, "%o", mode); + sprintf (header.mode, "%07o", mode); if (IsDirectory (p2)) { @@ -511,14 +562,16 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { HANDLE hFind; WIN32_FIND_DATA FindFileData; - sprintf (header.size, "%o", 0); + memset (header.size, '0', 11); header.type = '5'; /* MTAR_TDIR */ + if (header.name[strlen(p) - 1] != '/') { + header.name[strlen(p)] = '/'; + } + sprintf (header.checksum, "%06o", checksum (&header)); header.checksum[7] = ' '; - header.name[strlen(p)] = '/'; - if (fwrite (&header, 1, sizeof (header), tarfp) != sizeof (header)) { report_at (program_name, 0, REPORT_ERROR, "failed to write header to '%s'", state->target); } @@ -596,7 +649,7 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { FILE *fp; unsigned char *data; - unsigned long bytes, read; + uint64_t bytes, read; if (!(fp = fopen (p2, "r+b"))) { @@ -610,7 +663,7 @@ static void add_entry (FILE *tarfp, const char *root, const char *path) { fseek (fp, 0, SEEK_SET); - sprintf (header.size, "%lo", bytes); + sprintf (header.size, "%011"I64_FMT"o", bytes); header.type = '0'; /* MTAR_TREG */ sprintf (header.checksum, "%06o", checksum (&header));