Commit | Line | Data |
---|---|---|
55175a2c WD |
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. | |
4 | ||
5 | To use this patch, run these commands for a successful build: | |
6 | ||
7 | patch -p1 <patches/osx-create-time.diff | |
8 | ./configure (optional if already run) | |
9 | make | |
10 | ||
cc3e685d WD |
11 | diff --git a/lib/sysxattrs.c b/lib/sysxattrs.c |
12 | --- a/lib/sysxattrs.c | |
13 | +++ b/lib/sysxattrs.c | |
14 | @@ -52,29 +52,118 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size) | |
55175a2c WD |
15 | |
16 | #elif HAVE_OSX_XATTRS | |
17 | ||
18 | +#include <sys/attr.h> | |
19 | + | |
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) | |
23 | + | |
24 | +struct CreationTime { | |
25 | + unsigned long length; | |
42d12f3d | 26 | + struct timespec crtime; |
55175a2c WD |
27 | +}; |
28 | + | |
42d12f3d | 29 | +static struct timespec *getCreationTime(const char *path) |
55175a2c | 30 | +{ |
42d12f3d | 31 | + static struct CreationTime attrBuf; |
55175a2c | 32 | + struct attrlist attrList; |
42d12f3d WD |
33 | + |
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) | |
38 | + return NULL; | |
39 | + return &attrBuf.crtime; | |
40 | +} | |
41 | + | |
42 | +static ssize_t get_crtime_xattr(const char *path, char *buf, size_t size) | |
43 | +{ | |
44 | + struct timespec *crtime_p; | |
55175a2c WD |
45 | + |
46 | + if (buf == NULL) | |
47 | + return CRTIME_XATTR_LEN; | |
48 | + if (size < CRTIME_XATTR_LEN) | |
49 | + return -1; /* Doesn't happen with rsync code... */ | |
50 | + | |
42d12f3d | 51 | + if ((crtime_p = getCreationTime(path)) == NULL) |
55175a2c WD |
52 | + return -1; |
53 | + | |
42d12f3d | 54 | + SIVAL(buf, 0, crtime_p->tv_sec); |
55175a2c | 55 | +#if SIZEOF_TIME_T > 4 |
42d12f3d | 56 | + SIVAL(buf, 4, crtime_p->tv_sec >> 32); |
55175a2c WD |
57 | +#else |
58 | + SIVAL(buf, 4, 0); | |
59 | +#endif | |
42d12f3d | 60 | + SIVAL(buf, 8, crtime_p->tv_nsec); |
55175a2c WD |
61 | + |
62 | + return CRTIME_XATTR_LEN; | |
63 | +} | |
64 | + | |
42d12f3d | 65 | +static int set_crtime_xattr(const char *path, const char *buf, size_t size) |
55175a2c WD |
66 | +{ |
67 | + struct attrlist attrList; | |
42d12f3d | 68 | + struct timespec crtime; |
55175a2c WD |
69 | + |
70 | + if (size != CRTIME_XATTR_LEN) | |
71 | + return -1; | |
72 | + | |
42d12f3d | 73 | + crtime.tv_sec = IVAL(buf, 0); |
55175a2c | 74 | +#if SIZEOF_TIME_T > 4 |
42d12f3d | 75 | + crtime.tv_sec += (time_t)IVAL(buf, 4) << 32; |
55175a2c | 76 | +#endif |
42d12f3d | 77 | + crtime.tv_nsec = IVAL(buf, 8); |
55175a2c WD |
78 | + |
79 | + memset(&attrList, 0, sizeof attrList); | |
80 | + attrList.bitmapcount = ATTR_BIT_MAP_COUNT; | |
81 | + attrList.commonattr = ATTR_CMN_CRTIME; | |
42d12f3d | 82 | + return setattrlist(path, &attrList, &crtime, sizeof crtime, FSOPT_NOFOLLOW); |
55175a2c WD |
83 | +} |
84 | + | |
85 | ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) | |
86 | { | |
87 | + if (IS_CRTIME(name)) | |
42d12f3d | 88 | + return get_crtime_xattr(path, value, size); |
55175a2c WD |
89 | return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); |
90 | } | |
91 | ||
92 | ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) | |
93 | { | |
42d12f3d | 94 | + /* XXX Figure out how to get creation time from an open filedes? */ |
55175a2c WD |
95 | return fgetxattr(filedes, name, value, size, 0, 0); |
96 | } | |
97 | ||
98 | int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) | |
99 | { | |
100 | + if (IS_CRTIME(name)) | |
42d12f3d | 101 | + return set_crtime_xattr(path, value, size); |
55175a2c WD |
102 | return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW); |
103 | } | |
104 | ||
105 | int sys_lremovexattr(const char *path, const char *name) | |
106 | { | |
107 | + /* Every file on hfs+ has this; you can't remove it... */ | |
108 | + if (IS_CRTIME(name)) | |
109 | + return 0; | |
110 | return removexattr(path, name, XATTR_NOFOLLOW); | |
111 | } | |
112 | ||
113 | ssize_t sys_llistxattr(const char *path, char *list, size_t size) | |
114 | { | |
115 | - return listxattr(path, list, size, XATTR_NOFOLLOW); | |
116 | + ssize_t ret = listxattr(path, list, size, XATTR_NOFOLLOW); | |
117 | + if (ret < 0) | |
118 | + return ret; | |
42d12f3d WD |
119 | + if (getCreationTime(path) != NULL) { |
120 | + ret += sizeof CRTIME_XATTR; | |
121 | + if (list) { | |
122 | + if ((size_t)ret > size) { | |
123 | + errno = ERANGE; | |
124 | + return -1; | |
125 | + } | |
126 | + memcpy(list + ret - sizeof CRTIME_XATTR, | |
127 | + CRTIME_XATTR, sizeof CRTIME_XATTR); | |
55175a2c | 128 | + } |
55175a2c WD |
129 | + } |
130 | + return ret; | |
131 | } | |
132 | ||
133 | #elif HAVE_FREEBSD_XATTRS |