xattr.c

説明を見る。
00001 /* Extended Attribute support for rsync */
00002 /* Copyright (C) 2004 Red Hat, Inc */
00003 /* Written by Jay Fenlason, vaguely based on the ACLs patch */
00004 
00005 /* This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 /* the below stuff is only used by the receiver */
00062 
00063 /* structure to hold index to rsync_xal_l member corresponding to
00064  * flist->files[i] */
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 /* stuff for redirecting calls to set_acl() from set_perms()
00080  * for keep_backup() */
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                 /* free(x->rxas[i].value); */
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 /* generate the xattr(s) for this flist entry;
00232  * xattr(s) are either sent or cleaned-up by send_xattr() below */
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; /* TODO:  This needs to return 1 if no xattrs changed! */
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                 /* Wrong number of elements? */
00247                 if (rsync_xal_l.rxals[i].count != curr_rsync_xal.count)
00248                         continue;
00249                 /* any elements different? */
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                 /* no differences found.  This is The One! */
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 /* Store curr_rsync_xal on the end of rsync_xal_l */
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 /* send the make_xattr()-generated xattr list for this flist entry,
00288  * or clean up after an flist entry that's not being sent (f == -1) */
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 /* receive and build the rsync_xattr_lists */
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"); /* overflow */
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 /* for duplicating xattrs on backups when using backup_dir */
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 /* set extended attributes on rsync-ed or keep_backup-ed file */
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; /* FIXME: --dry-run needs to compute this value */
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 /* SUPPORT_XATTRS */

rsyncに対してSat Dec 5 19:45:42 2009に生成されました。  doxygen 1.4.7