Added mtime and fixed bugs
authorRobert Pengelly <robertapengelly@hotmail.com>
Fri, 27 Feb 2026 20:52:08 +0000 (20:52 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Fri, 27 Feb 2026 20:52:08 +0000 (20:52 +0000)
stdint.h [new file with mode: 0644]
tar.c

diff --git a/stdint.h b/stdint.h
new file mode 100644 (file)
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    <limits.h>
+
+/* 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 5a642811eac9a9e4c3d876a0e149b33078568cb7..b5393fabbd68bbd4d558facc6c88453e50a17368 100755 (executable)
--- 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       <sys/stat.h>
 # include       <dirent.h>
 # include       <fcntl.h>
+# include       <time.h>
 # include       <unistd.h>
 
 #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));