1 This patch handles the creation time on OS X by putting it into an
2 extended attribute. This is a modified version of a patch that was
3 provided by Wesley W. Terpstra.
5 To use this patch, run these commands for a successful build:
7 patch -p1 <patches/osx-create-time.diff
8 ./configure (optional if already run)
11 diff --git a/lib/sysxattrs.c b/lib/sysxattrs.c
14 @@ -52,29 +52,118 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
18 +#include <sys/attr.h>
20 +#define CRTIME_XATTR "com.apple.crtime96"
21 +#define IS_CRTIME(name) (*(name) == *CRTIME_XATTR && strcmp(name, CRTIME_XATTR) == 0)
22 +#define CRTIME_XATTR_LEN (8+4)
24 +struct CreationTime {
25 + unsigned long length;
26 + struct timespec crtime;
29 +static struct timespec *getCreationTime(const char *path)
31 + static struct CreationTime attrBuf;
32 + struct attrlist attrList;
34 + memset(&attrList, 0, sizeof attrList);
35 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
36 + attrList.commonattr = ATTR_CMN_CRTIME;
37 + if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
39 + return &attrBuf.crtime;
42 +static ssize_t get_crtime_xattr(const char *path, char *buf, size_t size)
44 + struct timespec *crtime_p;
47 + return CRTIME_XATTR_LEN;
48 + if (size < CRTIME_XATTR_LEN)
49 + return -1; /* Doesn't happen with rsync code... */
51 + if ((crtime_p = getCreationTime(path)) == NULL)
54 + SIVAL(buf, 0, crtime_p->tv_sec);
55 +#if SIZEOF_TIME_T > 4
56 + SIVAL(buf, 4, crtime_p->tv_sec >> 32);
60 + SIVAL(buf, 8, crtime_p->tv_nsec);
62 + return CRTIME_XATTR_LEN;
65 +static int set_crtime_xattr(const char *path, const char *buf, size_t size)
67 + struct attrlist attrList;
68 + struct timespec crtime;
70 + if (size != CRTIME_XATTR_LEN)
73 + crtime.tv_sec = IVAL(buf, 0);
74 +#if SIZEOF_TIME_T > 4
75 + crtime.tv_sec += (time_t)IVAL(buf, 4) << 32;
77 + crtime.tv_nsec = IVAL(buf, 8);
79 + memset(&attrList, 0, sizeof attrList);
80 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
81 + attrList.commonattr = ATTR_CMN_CRTIME;
82 + return setattrlist(path, &attrList, &crtime, sizeof crtime, FSOPT_NOFOLLOW);
85 ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
87 + if (IS_CRTIME(name))
88 + return get_crtime_xattr(path, value, size);
89 return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
92 ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
94 + /* XXX Figure out how to get creation time from an open filedes? */
95 return fgetxattr(filedes, name, value, size, 0, 0);
98 int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
100 + if (IS_CRTIME(name))
101 + return set_crtime_xattr(path, value, size);
102 return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
105 int sys_lremovexattr(const char *path, const char *name)
107 + /* Every file on hfs+ has this; you can't remove it... */
108 + if (IS_CRTIME(name))
110 return removexattr(path, name, XATTR_NOFOLLOW);
113 ssize_t sys_llistxattr(const char *path, char *list, size_t size)
115 - return listxattr(path, list, size, XATTR_NOFOLLOW);
116 + ssize_t ret = listxattr(path, list, size, XATTR_NOFOLLOW);
119 + if (getCreationTime(path) != NULL) {
120 + ret += sizeof CRTIME_XATTR;
122 + if ((size_t)ret > size) {
126 + memcpy(list + ret - sizeof CRTIME_XATTR,
127 + CRTIME_XATTR, sizeof CRTIME_XATTR);
133 #elif HAVE_FREEBSD_XATTRS