00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "rsync.h"
00021 #include "lib/sysxattr.h"
00022
00023 #ifdef SUPPORT_XATTRS
00024
00025 extern int dry_run;
00026
00027 #define RSYNC_XAL_INITIAL 5
00028 #define RSYNC_XAL_LIST_INITIAL 100
00029
00030 typedef struct {
00031 size_t name_len;
00032 char *name;
00033 size_t datum_len;
00034 char *datum;
00035 } rsync_xa;
00036
00037 typedef struct {
00038 size_t count;
00039 size_t alloc;
00040 rsync_xa *rxas;
00041 } rsync_xal;
00042
00043 typedef struct {
00044 size_t count;
00045 size_t alloc;
00046 rsync_xal *rxals;
00047 } rsync_xal_list;
00048
00049 static size_t namebuf_len = 0;
00050 static char *namebuf = NULL;
00051
00052 static size_t datumbuf_len = 0;
00053 static char *datumbuf = NULL;
00054
00055 static rsync_xal curr_rsync_xal = { 0, 0, NULL };
00056 static rsync_xal_list rsync_xal_l = { 0, 0, NULL };
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 typedef struct {
00067 const struct file_struct *file;
00068 int xalidx;
00069 } file_xal_index;
00070
00071 typedef struct {
00072 size_t count;
00073 size_t alloc;
00074 file_xal_index *filexalidxs;
00075 } file_xal_index_list;
00076
00077 static file_xal_index_list fxil = {0, 0, NULL };
00078
00079
00080
00081 static const struct file_struct *backup_orig_file = NULL;
00082 static const char null_string[] = "";
00083 static const char *backup_orig_fname = null_string;
00084 static const char *backup_dest_fname = null_string;
00085 static rsync_xal backup_xal;
00086
00087
00088
00089 static void rsync_xal_free(rsync_xal *x)
00090 {
00091 size_t i;
00092
00093 for (i = 0; i < x->count; i++) {
00094 free(x->rxas[i].name);
00095
00096 }
00097 x->count = 0;
00098 }
00099
00100 static int rsync_xal_compare_names(const void *x1, const void *x2)
00101 {
00102 const rsync_xa *xa1;
00103 const rsync_xa *xa2;
00104
00105 xa1 = x1;
00106 xa2 = x2;
00107 return strcmp(xa1->name, xa2->name);
00108 }
00109
00110 static int rsync_xal_get(const char *fname, rsync_xal *x)
00111 {
00112 ssize_t name_size;
00113 ssize_t datum_size;
00114 ssize_t left;
00115 char *name;
00116 size_t len;
00117 char *ptr;
00118
00119 if (!namebuf) {
00120 namebuf_len = 100;
00121 namebuf = new_array(char, namebuf_len);
00122 datumbuf_len = 100;
00123 datumbuf = new_array(char, datumbuf_len);
00124 if (!namebuf || !datumbuf)
00125 out_of_memory("rsync_xal_get");
00126 }
00127
00128 name_size = sys_llistxattr(fname, namebuf, namebuf_len);
00129 if (name_size > (ssize_t)namebuf_len) {
00130 name_size = -1;
00131 errno = ERANGE;
00132 }
00133 if (name_size < 0) {
00134 if (errno == ENOTSUP)
00135 return -1;
00136 if (errno == ERANGE) {
00137 name_size = sys_llistxattr(fname, NULL, 0);
00138 if (name_size < 0) {
00139 rprintf(FERROR, "%s: rsync_xal_get: llistxattr: %s\n",
00140 fname, strerror(errno));
00141 return -1;
00142 }
00143 namebuf = realloc_array(namebuf, char, name_size + 1);
00144 if (!namebuf)
00145 out_of_memory("rsync_xal_get");
00146 namebuf_len = name_size;
00147 name_size = sys_llistxattr(fname, namebuf, namebuf_len);
00148 if (name_size < 0) {
00149 rprintf(FERROR,
00150 "%s: rsync_xal_get: re-llistxattr failed: %s\n",
00151 fname, strerror(errno));
00152 return -1;
00153 }
00154 } else {
00155 rprintf(FERROR,
00156 "%s: rsync_xal_get: llistxattr failed: %s\n",
00157 fname, strerror(errno));
00158 return -1;
00159 }
00160 }
00161 rsync_xal_free(x);
00162 if (name_size == 0)
00163 return 0;
00164 for (left = name_size, name = namebuf; left > 0 ; left -= len, name += len) {
00165 len = strlen(name) + 1;
00166
00167 if (x->count >= x->alloc) {
00168 size_t new_alloc;
00169 rsync_xa *new_rxas;
00170
00171 new_alloc = x->alloc < RSYNC_XAL_INITIAL ? RSYNC_XAL_INITIAL : x->alloc * 2;
00172 new_rxas = realloc_array(x->rxas, rsync_xa, new_alloc);
00173 if (!new_rxas)
00174 out_of_memory("rsync_xal_get");
00175 x->alloc = new_alloc;
00176 x->rxas = new_rxas;
00177 }
00178 datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
00179 if (datum_size > (ssize_t)datumbuf_len) {
00180 datum_size = -1;
00181 errno = ERANGE;
00182 }
00183 if (datum_size < 0) {
00184 if (errno == ENOTSUP)
00185 return -1;
00186 if (errno == ERANGE) {
00187 datum_size = sys_lgetxattr(fname, name, NULL, 0);
00188 if (datum_size < 0) {
00189 rprintf(FERROR,
00190 "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
00191 fname, name, strerror(errno));
00192 return -1;
00193 }
00194 datumbuf = realloc_array(datumbuf, char, datum_size + 1);
00195 if (!datumbuf)
00196 out_of_memory("rsync_xal_get");
00197 datumbuf_len = datum_size;
00198 datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
00199 if (datum_size < 0) {
00200 rprintf(FERROR,
00201 "%s: rsync_xal_get: re-lgetxattr of %s failed: %s\n",
00202 name, fname, strerror(errno));
00203 return -1;
00204 }
00205 } else {
00206 rprintf(FERROR,
00207 "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
00208 fname, name, strerror(errno));
00209 return -1;
00210 }
00211 }
00212 ptr = new_array(char, len + datum_size);
00213 if (!ptr)
00214 out_of_memory("rsync_xal_get");
00215 strcpy(ptr, name);
00216 if (datum_size)
00217 memcpy(ptr + len, datumbuf, datum_size);
00218 x->rxas[x->count].name_len = len;
00219 x->rxas[x->count].name = ptr;
00220 x->rxas[x->count].datum_len = datum_size;
00221 x->rxas[x->count].datum = ptr + len;
00222 x->count++;
00223 }
00224 if (x->count > 1) {
00225 qsort(x->rxas, x->count, sizeof (rsync_xa), rsync_xal_compare_names);
00226 }
00227 return 0;
00228 }
00229
00230
00231
00232
00233
00234 int make_xattr(UNUSED(const struct file_struct *file), const char *fname)
00235 {
00236 rsync_xal_get(fname, &curr_rsync_xal);
00237 return 0;
00238 }
00239
00240 static ssize_t rsync_xal_find_matching(void)
00241 {
00242 size_t i;
00243 size_t j;
00244
00245 for (i = 0; i < rsync_xal_l.count; i++) {
00246
00247 if (rsync_xal_l.rxals[i].count != curr_rsync_xal.count)
00248 continue;
00249
00250 for (j = 0; j < curr_rsync_xal.count; j++) {
00251 if (rsync_xal_l.rxals[i].rxas[j].name_len != curr_rsync_xal.rxas[j].name_len
00252 || rsync_xal_l.rxals[i].rxas[j].datum_len != curr_rsync_xal.rxas[j].datum_len
00253 || strcmp(rsync_xal_l.rxals[i].rxas[j].name, curr_rsync_xal.rxas[j].name)
00254 || memcmp(rsync_xal_l.rxals[i].rxas[j].datum, curr_rsync_xal.rxas[j].datum, curr_rsync_xal.rxas[j].datum_len))
00255 break;
00256 }
00257
00258 if (j == curr_rsync_xal.count)
00259 break;
00260 }
00261 if (i < rsync_xal_l.count)
00262 return i;
00263 return (ssize_t)-1;
00264 }
00265
00266
00267 static void rsync_xal_store(void)
00268 {
00269 if (rsync_xal_l.count <= rsync_xal_l.alloc) {
00270 size_t new_alloc;
00271 void *new_xal;
00272
00273 new_alloc = rsync_xal_l.count < RSYNC_XAL_LIST_INITIAL ? RSYNC_XAL_LIST_INITIAL : rsync_xal_l.count * 2;
00274 new_xal = realloc_array(rsync_xal_l.rxals, rsync_xal, new_alloc);
00275 if (!new_xal)
00276 out_of_memory("rsync_xal_store");
00277 rsync_xal_l.alloc = new_alloc;
00278 rsync_xal_l.rxals = new_xal;
00279 }
00280 rsync_xal_l.rxals[rsync_xal_l.count] = curr_rsync_xal;
00281 rsync_xal_l.count++;
00282 curr_rsync_xal.count = 0;
00283 curr_rsync_xal.alloc = 0;
00284 curr_rsync_xal.rxas = NULL;
00285 }
00286
00287
00288
00289
00290 void send_xattr(UNUSED(const struct file_struct *file), int f)
00291 {
00292 ssize_t index;
00293
00294 if (f == -1) {
00295 rsync_xal_free(&curr_rsync_xal);
00296 return;
00297 }
00298 index = rsync_xal_find_matching();
00299 if (index != -1) {
00300 write_byte(f, 'x');
00301 write_int(f, index);
00302 rsync_xal_free(&curr_rsync_xal);
00303 } else {
00304 rsync_xa *rxa;
00305 size_t count;
00306
00307 count = curr_rsync_xal.count;
00308 write_byte(f, 'X');
00309 write_int(f, count);
00310 for (rxa = curr_rsync_xal.rxas; count--; rxa++) {
00311 write_int(f, rxa->name_len);
00312 write_int(f, rxa->datum_len);
00313 write_buf(f, rxa->name, rxa->name_len);
00314 write_buf(f, rxa->datum, rxa->datum_len);
00315 }
00316 rsync_xal_store();
00317 }
00318 }
00319
00320
00321
00322
00323
00324 void receive_xattr(struct file_struct *file, int f)
00325 {
00326 char *fname;
00327 int tag;
00328
00329 fname = f_name(file, NULL);
00330 tag = read_byte(f);
00331 if (tag != 'X' && tag != 'x') {
00332 rprintf(FERROR,
00333 "%s: receive_xattr: unknown extended attribute type tag: %c\n",
00334 fname, tag);
00335 exit_cleanup(RERR_STREAMIO);
00336 }
00337
00338 if (fxil.alloc <= fxil.count) {
00339 void *new_ptr;
00340 size_t new_alloc;
00341
00342 if (fxil.count < RSYNC_XAL_LIST_INITIAL)
00343 new_alloc = fxil.alloc + RSYNC_XAL_LIST_INITIAL;
00344 else
00345 new_alloc = fxil.alloc * 2;
00346 new_ptr = realloc_array(fxil.filexalidxs, file_xal_index, new_alloc);
00347 if (!new_ptr)
00348 out_of_memory("receive_xattr");
00349 if (verbose >= 3) {
00350 rprintf(FINFO, "receive_xattr to %lu bytes, %s move\n",
00351 (unsigned long)(new_alloc * sizeof (file_xal_index)),
00352 fxil.filexalidxs == new_ptr ? "did not" : "did");
00353 }
00354
00355 fxil.filexalidxs = new_ptr;
00356 fxil.alloc = new_alloc;
00357 }
00358
00359 fxil.filexalidxs[fxil.count].file = file;
00360 if (tag == 'X') {
00361 size_t count;
00362 size_t i;
00363
00364 fxil.filexalidxs[fxil.count].xalidx = rsync_xal_l.count;
00365
00366 count = read_int(f);
00367 curr_rsync_xal.count = count;
00368 curr_rsync_xal.alloc = count;
00369 curr_rsync_xal.rxas = new_array(rsync_xa, count);
00370 if (!curr_rsync_xal.rxas)
00371 out_of_memory("receive_xattr");
00372 for (i = 0; i < count; i++) {
00373 size_t name_len;
00374 size_t datum_len;
00375 char *ptr;
00376
00377 name_len = read_int(f);
00378 datum_len = read_int(f);
00379 if (name_len + datum_len < name_len)
00380 out_of_memory("receive_xattr");
00381 ptr = new_array(char, name_len + datum_len);
00382 if (!ptr)
00383 out_of_memory("receive_xattr");
00384 read_buf(f, ptr, name_len);
00385 read_buf(f, ptr + name_len, datum_len);
00386 curr_rsync_xal.rxas[i].name_len = name_len;
00387 curr_rsync_xal.rxas[i].datum_len = datum_len;
00388 curr_rsync_xal.rxas[i].name = ptr;
00389 curr_rsync_xal.rxas[i].datum = ptr + name_len;
00390 }
00391 rsync_xal_store();
00392 } else {
00393 size_t index;
00394
00395 index = read_int(f);
00396 if (index >= rsync_xal_l.count) {
00397 rprintf(FERROR, "%s: receive_xattr: xa index %lu out of range\n",
00398 fname, (unsigned long)index);
00399 exit_cleanup(RERR_STREAMIO);
00400 }
00401 fxil.filexalidxs[fxil.count].xalidx = index;
00402 }
00403 fxil.count++;
00404 }
00405
00406 static int rsync_xal_set(const char *fname, rsync_xal *x)
00407 {
00408 size_t i;
00409 int ret = 0;
00410
00411 for (i = 0; i < x->count; i++) {
00412 int status = sys_lsetxattr(fname, x->rxas[i].name, x->rxas[i].datum, x->rxas[i].datum_len, 0);
00413 if (status < 0) {
00414 rprintf(FERROR, "%s: rsync_xal_set: lsetxattr %s failed: %s\n",
00415 fname, x->rxas[i].name, strerror(errno));
00416 ret = -1;
00417 }
00418 }
00419 return ret;
00420 }
00421
00422
00423
00424 int dup_xattr(const char *orig, const char *bak)
00425 {
00426 int ret;
00427
00428 if (rsync_xal_get(orig, &backup_xal) < 0)
00429 ret = rsync_xal_set(bak, &backup_xal);
00430 else
00431 ret = 0;
00432 rsync_xal_free(&backup_xal);
00433
00434 return ret;
00435 }
00436
00437 void push_keep_backup_xattr(const struct file_struct *file, const char *orig, const char *dest)
00438 {
00439 backup_orig_file = file;
00440 backup_orig_fname = orig;
00441 backup_dest_fname = dest;
00442 rsync_xal_get(orig, &backup_xal);
00443 }
00444
00445 static int set_keep_backup_xal(void)
00446 {
00447 return rsync_xal_set(backup_dest_fname, &backup_xal);
00448 }
00449
00450 void cleanup_keep_backup_xattr(void)
00451 {
00452 backup_orig_file = NULL;
00453 backup_orig_fname = null_string;
00454 backup_dest_fname = null_string;
00455 rsync_xal_free(&backup_xal);
00456 }
00457
00458 static int file_xal_index_compare(const void *x1, const void *x2)
00459 {
00460 const file_xal_index *xa1;
00461 const file_xal_index *xa2;
00462
00463 xa1 = x1;
00464 xa2 = x2;
00465 return xa1->file == xa2->file ? 0 : xa1->file < xa2->file ? -1 : 1;
00466 }
00467
00468 void sort_file_xattr_index_lists(void)
00469 {
00470 qsort(fxil.filexalidxs, fxil.count, sizeof (file_xal_index), file_xal_index_compare);
00471 }
00472
00473 static int find_file_xal_index(const struct file_struct *file)
00474 {
00475 int low = 0, high = fxil.count;
00476 const struct file_struct *file_mid;
00477
00478 if (!high--) {
00479 rprintf(FERROR, "find_file_xal_index: no entries\n");
00480 exit_cleanup(RERR_STREAMIO);
00481 return -1;
00482 }
00483 do {
00484 int mid = (high + low) / 2;
00485 file_mid = fxil.filexalidxs[mid].file;
00486 if (file_mid == file)
00487 return fxil.filexalidxs[mid].xalidx;
00488 if (file_mid > file)
00489 high = mid - 1;
00490 else
00491 low = mid + 1;
00492 } while (low < high);
00493 if (low == high) {
00494 file_mid = fxil.filexalidxs[low].file;
00495 if (file_mid == file)
00496 return fxil.filexalidxs[low].xalidx;
00497 }
00498 rprintf(FERROR,
00499 "find_file_xal_index: can't find entry for file in list\n");
00500 exit_cleanup(RERR_STREAMIO);
00501 return -1;
00502 }
00503
00504
00505
00506 int set_xattr(const char *fname, const struct file_struct *file)
00507 {
00508 int xalidx;
00509 rsync_xal *x;
00510
00511 if (dry_run)
00512 return 1;
00513
00514 if (file == backup_orig_file) {
00515 if (!strcmp(fname, backup_dest_fname))
00516 return set_keep_backup_xal();
00517 }
00518 xalidx = find_file_xal_index(file);
00519 x = &(rsync_xal_l.rxals[xalidx]);
00520
00521 return rsync_xal_set(fname, x);
00522 }
00523
00524 #endif