Annotation of embedaddon/rsync/lib/sysxattrs.c, revision 1.1.1.4
1.1 misho 1: /*
2: * Extended attribute support for rsync.
3: *
4: * Copyright (C) 2004 Red Hat, Inc.
1.1.1.4 ! misho 5: * Copyright (C) 2003-2019 Wayne Davison
1.1 misho 6: * Written by Jay Fenlason.
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
23: #include "sysxattrs.h"
24:
1.1.1.4 ! misho 25: extern int preserve_hfs_compression;
! 26:
1.1 misho 27: #ifdef SUPPORT_XATTRS
28:
1.1.1.3 misho 29: #ifdef HAVE_OSX_XATTRS
1.1.1.4 ! misho 30: #ifndef XATTR_SHOWCOMPRESSION
! 31: #define XATTR_SHOWCOMPRESSION 0x0020
! 32: #endif
1.1.1.3 misho 33: #define GETXATTR_FETCH_LIMIT (64*1024*1024)
1.1.1.4 ! misho 34:
! 35: int xattr_options = XATTR_NOFOLLOW;
1.1.1.3 misho 36: #endif
37:
1.1 misho 38: #if defined HAVE_LINUX_XATTRS
39:
40: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
41: {
42: return lgetxattr(path, name, value, size);
43: }
44:
45: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
46: {
47: return fgetxattr(filedes, name, value, size);
48: }
49:
50: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
51: {
52: return lsetxattr(path, name, value, size, 0);
53: }
54:
55: int sys_lremovexattr(const char *path, const char *name)
56: {
57: return lremovexattr(path, name);
58: }
59:
60: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
61: {
62: return llistxattr(path, list, size);
63: }
64:
65: #elif HAVE_OSX_XATTRS
66:
67: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
68: {
1.1.1.4 ! misho 69: ssize_t len;
! 70:
! 71: if (preserve_hfs_compression)
! 72: xattr_options |= XATTR_SHOWCOMPRESSION;
! 73:
! 74: len = getxattr(path, name, value, size, 0, xattr_options);
1.1.1.3 misho 75:
76: /* If we're retrieving data, handle resource forks > 64MB specially */
77: if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) {
78: /* getxattr will only return 64MB of data at a time, need to call again with a new offset */
79: u_int32_t offset = len;
80: size_t data_retrieved = len;
81: while (data_retrieved < size) {
1.1.1.4 ! misho 82: len = getxattr(path, name, value + offset, size - data_retrieved, offset, xattr_options);
1.1.1.3 misho 83: if (len <= 0)
84: break;
85: data_retrieved += len;
86: offset += (u_int32_t)len;
87: }
88: len = data_retrieved;
89: }
90:
91: return len;
1.1 misho 92: }
93:
94: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
95: {
96: return fgetxattr(filedes, name, value, size, 0, 0);
97: }
98:
99: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
100: {
101: return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
102: }
103:
104: int sys_lremovexattr(const char *path, const char *name)
105: {
1.1.1.4 ! misho 106: if (preserve_hfs_compression)
! 107: xattr_options |= XATTR_SHOWCOMPRESSION;
! 108: return removexattr(path, name, xattr_options);
1.1 misho 109: }
110:
111: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
112: {
1.1.1.4 ! misho 113: if (preserve_hfs_compression)
! 114: xattr_options |= XATTR_SHOWCOMPRESSION;
! 115: return listxattr(path, list, size, xattr_options);
1.1 misho 116: }
117:
118: #elif HAVE_FREEBSD_XATTRS
119:
120: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
121: {
122: return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
123: }
124:
125: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
126: {
127: return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size);
128: }
129:
130: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
131: {
132: return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
133: }
134:
135: int sys_lremovexattr(const char *path, const char *name)
136: {
137: return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
138: }
139:
140: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
141: {
142: unsigned char keylen;
143: ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
144:
145: if (len <= 0 || (size_t)len > size)
146: return len;
147:
148: /* FreeBSD puts a single-byte length before each string, with no '\0'
149: * terminator. We need to change this into a series of null-terminted
150: * strings. Since the size is the same, we can simply transform the
151: * output in place. */
152: for (off = 0; off < len; off += keylen + 1) {
153: keylen = ((unsigned char*)list)[off];
154: if (off + keylen >= len) {
155: /* Should be impossible, but kernel bugs happen! */
156: errno = EINVAL;
157: return -1;
158: }
159: memmove(list+off, list+off+1, keylen);
160: list[off+keylen] = '\0';
161: }
162:
163: return len;
164: }
165:
1.1.1.2 misho 166: #elif HAVE_SOLARIS_XATTRS
167:
168: static ssize_t read_xattr(int attrfd, void *buf, size_t buflen)
169: {
170: STRUCT_STAT sb;
171: ssize_t ret;
172:
173: if (fstat(attrfd, &sb) < 0)
174: ret = -1;
175: else if (sb.st_size > SSIZE_MAX) {
176: errno = ERANGE;
177: ret = -1;
178: } else if (buflen == 0)
179: ret = sb.st_size;
180: else if (sb.st_size > buflen) {
181: errno = ERANGE;
182: ret = -1;
183: } else {
184: size_t bufpos;
185: for (bufpos = 0; bufpos < sb.st_size; ) {
186: ssize_t cnt = read(attrfd, buf + bufpos, sb.st_size - bufpos);
187: if (cnt <= 0) {
188: if (cnt < 0 && errno == EINTR)
189: continue;
190: bufpos = -1;
191: break;
192: }
193: bufpos += cnt;
194: }
195: ret = bufpos;
196: }
197:
198: close(attrfd);
199:
200: return ret;
201: }
202:
203: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
204: {
205: int attrfd;
206:
207: if ((attrfd = attropen(path, name, O_RDONLY)) < 0) {
208: errno = ENOATTR;
209: return -1;
210: }
211:
212: return read_xattr(attrfd, value, size);
213: }
214:
215: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
216: {
217: int attrfd;
218:
219: if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) {
220: errno = ENOATTR;
221: return -1;
222: }
223:
224: return read_xattr(attrfd, value, size);
225: }
226:
227: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
228: {
229: int attrfd;
230: size_t bufpos;
231: mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
232:
233: if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0)
234: return -1;
235:
236: for (bufpos = 0; bufpos < size; ) {
237: ssize_t cnt = write(attrfd, value+bufpos, size);
238: if (cnt <= 0) {
239: if (cnt < 0 && errno == EINTR)
240: continue;
241: bufpos = -1;
242: break;
243: }
244: bufpos += cnt;
245: }
246:
247: close(attrfd);
248:
249: return bufpos > 0 ? 0 : -1;
250: }
251:
252: int sys_lremovexattr(const char *path, const char *name)
253: {
254: int attrdirfd;
255: int ret;
256:
257: if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0)
258: return -1;
259:
260: ret = unlinkat(attrdirfd, name, 0);
261:
262: close(attrdirfd);
263:
264: return ret;
265: }
266:
267: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
268: {
269: int attrdirfd;
270: DIR *dirp;
271: struct dirent *dp;
272: ssize_t ret = 0;
273:
274: if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) {
275: errno = ENOTSUP;
276: return -1;
277: }
278:
279: if ((dirp = fdopendir(attrdirfd)) == NULL) {
280: close(attrdirfd);
281: return -1;
282: }
283:
284: while ((dp = readdir(dirp))) {
285: int len = strlen(dp->d_name);
286:
287: if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.')))
288: continue;
289: if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0
290: && (dp->d_name[10] == 'o' || dp->d_name[10] == 'w'))
291: continue;
292:
293: if ((ret += len+1) > size) {
294: if (size == 0)
295: continue;
296: ret = -1;
297: errno = ERANGE;
298: break;
299: }
300: memcpy(list, dp->d_name, len+1);
301: list += len+1;
302: }
303:
304: closedir(dirp);
305: close(attrdirfd);
306:
307: return ret;
308: }
309:
1.1 misho 310: #else
311:
312: #error You need to create xattr compatibility functions.
313:
314: #endif
315:
316: #endif /* SUPPORT_XATTRS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>