#include "lib.h"
#include "report.h"
+#include "stdint.h"
#include "tar.h"
struct tar_state *state = 0;
}
+#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
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) {
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);
}
FILE *fp;
unsigned char *data;
- unsigned long bytes, read;
+ uint64_t bytes, read;
if (!(fp = fopen (p2, "r+b"))) {
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));
}
-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] == ':') {
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);
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) {
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)) {
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);
}
FILE *fp;
unsigned char *data;
- unsigned long bytes, read;
+ uint64_t bytes, read;
if (!(fp = fopen (p2, "r+b"))) {
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));