]> git.ipfire.org Git - thirdparty/rsync.git/blobdiff - xattrs.c
More tweaks for Actions.
[thirdparty/rsync.git] / xattrs.c
index b10c256766859628f9341919ca28a94bf45536a7..26e50a6f9ccb48e0496da3126363ac5f61d6494b 100644 (file)
--- a/xattrs.c
+++ b/xattrs.c
@@ -3,7 +3,7 @@
  * Written by Jay Fenlason, vaguely based on the ACLs patch.
  *
  * Copyright (C) 2004 Red Hat, Inc.
- * Copyright (C) 2006-2020 Wayne Davison
+ * Copyright (C) 2006-2022 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,9 +39,13 @@ extern int preserve_specials;
 extern int checksum_seed;
 extern int saw_xattr_filter;
 
+extern struct name_num_item *xattr_sum_nni;
+extern int xattr_sum_len;
+
 #define RSYNC_XAL_INITIAL 5
 #define RSYNC_XAL_LIST_INITIAL 100
 
+#define MAX_XATTR_DIGEST_LEN MD5_DIGEST_LEN
 #define MAX_FULL_DATUM 32
 
 #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0)
@@ -199,7 +203,7 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr
 
        if (!datum_len && !extra_len)
                extra_len = 1; /* request non-zero amount of memory */
-       if (datum_len + extra_len < datum_len)
+       if (SIZE_MAX - datum_len < extra_len)
                overflow_exit("get_xattr_data");
        ptr = new_array(char, datum_len + extra_len);
 
@@ -269,8 +273,8 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
 
                if (datum_len > MAX_FULL_DATUM) {
                        /* For large datums, we store a flag and a checksum. */
-                       name_offset = 1 + MAX_DIGEST_LEN;
-                       sum_init(-1, checksum_seed);
+                       name_offset = 1 + MAX_XATTR_DIGEST_LEN;
+                       sum_init(xattr_sum_nni, checksum_seed);
                        sum_update(ptr, datum_len);
                        free(ptr);
 
@@ -377,20 +381,14 @@ static int64 xattr_lookup_hash(const item_list *xalp)
 {
        const rsync_xa *rxas = xalp->items;
        size_t i;
-       int64 key = hashlittle(&xalp->count, sizeof xalp->count);
+       int64 key = hashlittle2(&xalp->count, sizeof xalp->count);
 
        for (i = 0; i < xalp->count; i++) {
-               key += hashlittle(rxas[i].name, rxas[i].name_len);
+               key += hashlittle2(rxas[i].name, rxas[i].name_len);
                if (rxas[i].datum_len > MAX_FULL_DATUM)
-                       key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
+                       key += hashlittle2(rxas[i].datum, xattr_sum_len);
                else
-                       key += hashlittle(rxas[i].datum, rxas[i].datum_len);
-       }
-
-       if (key == 0) {
-               /* This is very unlikely, but we should never
-                * return 0 as hashtable_find() doesn't like it. */
-               return 1;
+                       key += hashlittle2(rxas[i].datum, rxas[i].datum_len);
        }
 
        return key;
@@ -435,7 +433,7 @@ static int find_matching_xattr(const item_list *xalp)
                        if (rxas1[j].datum_len > MAX_FULL_DATUM) {
                                if (memcmp(rxas1[j].datum + 1,
                                           rxas2[j].datum + 1,
-                                          MAX_DIGEST_LEN) != 0)
+                                          xattr_sum_len) != 0)
                                        break;
                        } else {
                                if (memcmp(rxas1[j].datum, rxas2[j].datum,
@@ -471,8 +469,6 @@ static int rsync_xal_store(item_list *xalp)
 
        if (rsync_xal_h == NULL)
                rsync_xal_h = hashtable_create(512, HT_KEY64);
-       if (rsync_xal_h == NULL)
-               out_of_memory("rsync_xal_h hashtable_create()");
 
        new_ref = new0(rsync_xa_list_ref);
        new_ref->ndx = ndx;
@@ -535,7 +531,7 @@ int send_xattr(int f, stat_x *sxp)
 #endif
                        write_buf(f, name, name_len);
                        if (rxa->datum_len > MAX_FULL_DATUM)
-                               write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
+                               write_buf(f, rxa->datum + 1, xattr_sum_len);
                        else
                                write_bigbuf(f, rxa->datum, rxa->datum_len);
                }
@@ -588,7 +584,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
                else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
                        same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
                            && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
-                                     MAX_DIGEST_LEN) == 0;
+                                     xattr_sum_len) == 0;
                        /* Flag unrequested items that we need. */
                        if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
                                snd_rxa->datum[0] = XSTATE_TODO;
@@ -748,7 +744,7 @@ int recv_xattr_request(struct file_struct *file, int f_in)
                old_datum = rxa->datum;
                rxa->datum_len = read_varint(f_in);
 
-               if (rxa->name_len + rxa->datum_len < rxa->name_len)
+               if (SIZE_MAX - rxa->name_len < rxa->datum_len)
                        overflow_exit("recv_xattr_request");
                rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
                name = rxa->datum + rxa->datum_len;
@@ -797,10 +793,9 @@ void receive_xattr(int f, struct file_struct *file)
                rsync_xa *rxa;
                size_t name_len = read_varint(f);
                size_t datum_len = read_varint(f);
-               size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
+               size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + (size_t)xattr_sum_len : datum_len;
                size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
-               if ((dget_len + extra_len < dget_len)
-                || (dget_len + extra_len + name_len < dget_len + extra_len))
+               if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
                        overflow_exit("receive_xattr");
                ptr = new_array(char, dget_len + extra_len + name_len);
                name = ptr + dget_len + extra_len;
@@ -813,7 +808,7 @@ void receive_xattr(int f, struct file_struct *file)
                        read_buf(f, ptr, dget_len);
                else {
                        *ptr = XSTATE_ABBREV;
-                       read_buf(f, ptr + 1, MAX_DIGEST_LEN);
+                       read_buf(f, ptr + 1, xattr_sum_len);
                }
 
                if (saw_xattr_filter) {
@@ -944,7 +939,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
        rsync_xa *rxas = xalp->items;
        ssize_t list_len;
        size_t i, len;
-       char *name, *ptr, sum[MAX_DIGEST_LEN];
+       char *name, *ptr, sum[MAX_XATTR_DIGEST_LEN];
 #ifdef HAVE_LINUX_XATTRS
        int user_only = am_root <= 0;
 #endif
@@ -959,7 +954,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
                name = rxas[i].name;
 
                if (XATTR_ABBREV(rxas[i])) {
-                       int sum_len;
                        /* See if the fnamecmp version is identical. */
                        len = name_len = rxas[i].name_len;
                        if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
@@ -976,10 +970,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
                                goto still_abbrev;
                        }
 
-                       sum_init(-1, checksum_seed);
+                       sum_init(xattr_sum_nni, checksum_seed);
                        sum_update(ptr, len);
-                       sum_len = sum_end(sum);
-                       if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) {
+                       sum_end(sum);
+                       if (memcmp(sum, rxas[i].datum + 1, xattr_sum_len) != 0) {
                                free(ptr);
                                goto still_abbrev;
                        }
@@ -1056,7 +1050,7 @@ int set_xattr(const char *fname, const struct file_struct *file, const char *fna
 {
        rsync_xa_list *glst = rsync_xal_l.items;
        item_list *lst;
-       int ndx;
+       int ndx, added_write_perm = 0;
 
        if (dry_run)
                return 1; /* FIXME: --dry-run needs to compute this value */
@@ -1085,10 +1079,23 @@ int set_xattr(const char *fname, const struct file_struct *file, const char *fna
        }
 #endif
 
+       /* If the target file lacks write permission, we try to add it
+        * temporarily so we can change the extended attributes. */
+       if (!am_root
+#ifdef SUPPORT_LINKS
+        && !S_ISLNK(sxp->st.st_mode)
+#endif
+        && access(fname, W_OK) < 0
+        && do_chmod(fname, (sxp->st.st_mode & CHMOD_BITS) | S_IWUSR) == 0)
+               added_write_perm = 1;
+
        ndx = F_XATTR(file);
        glst += ndx;
        lst = &glst->xa_items;
-       return rsync_xal_set(fname, lst, fnamecmp, sxp);
+       int return_value = rsync_xal_set(fname, lst, fnamecmp, sxp);
+       if (added_write_perm) /* remove the temporary write permission */
+               do_chmod(fname, sxp->st.st_mode);
+       return return_value;
 }
 
 #ifdef SUPPORT_ACLS
@@ -1119,7 +1126,8 @@ int del_def_xattr_acl(const char *fname)
 
 int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
 {
-       int mode, rdev_major, rdev_minor, uid, gid, len;
+       unsigned int mode;
+       int rdev_major, rdev_minor, uid, gid, len;
        char buf[256];
 
        if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))