| 1 | This attempts to accomplish some per-file memory-savings by moving the |
| 2 | uid+gid items out of the file-list (since their values are common to |
| 3 | multiple file-list entries) and replacing them with an index to an |
| 4 | array of structures. |
| 5 | |
| 6 | This only saves 4 bytes per file (not counting the overhead of the array). |
| 7 | |
| 8 | This probably needs a hashing algorithm to be added if the uid+gid list |
| 9 | gets to be really large. |
| 10 | |
| 11 | To use this patch, run these commands for a successful build: |
| 12 | |
| 13 | patch -p1 <patches/id-pair.diff |
| 14 | ./configure (optional if already run) |
| 15 | make |
| 16 | |
| 17 | --- old/flist.c |
| 18 | +++ new/flist.c |
| 19 | @@ -54,6 +54,7 @@ extern int copy_unsafe_links; |
| 20 | extern int protocol_version; |
| 21 | extern int sanitize_paths; |
| 22 | extern struct stats stats; |
| 23 | +extern struct id_pair *id_pairs; |
| 24 | extern struct file_list *the_file_list; |
| 25 | |
| 26 | extern char curr_dir[MAXPATHLEN]; |
| 27 | @@ -351,14 +352,14 @@ static void send_file_entry(struct file_ |
| 28 | } |
| 29 | } else if (protocol_version < 28) |
| 30 | rdev = MAKEDEV(0, 0); |
| 31 | - if (file->uid == uid) |
| 32 | + if (id_pairs[file->id_ndx].uid == uid) |
| 33 | flags |= XMIT_SAME_UID; |
| 34 | else |
| 35 | - uid = file->uid; |
| 36 | - if (file->gid == gid) |
| 37 | + uid = id_pairs[file->id_ndx].uid; |
| 38 | + if (id_pairs[file->id_ndx].gid == gid) |
| 39 | flags |= XMIT_SAME_GID; |
| 40 | else |
| 41 | - gid = file->gid; |
| 42 | + gid = id_pairs[file->id_ndx].gid; |
| 43 | if (file->modtime == modtime) |
| 44 | flags |= XMIT_SAME_TIME; |
| 45 | else |
| 46 | @@ -609,8 +610,7 @@ static struct file_struct *receive_file_ |
| 47 | file->modtime = modtime; |
| 48 | file->length = file_length; |
| 49 | file->mode = mode; |
| 50 | - file->uid = uid; |
| 51 | - file->gid = gid; |
| 52 | + file->id_ndx = id_pair(uid, gid); |
| 53 | |
| 54 | if (dirname_len) { |
| 55 | file->dirname = lastdir = bp; |
| 56 | @@ -862,8 +862,7 @@ struct file_struct *make_file(char *fnam |
| 57 | file->modtime = st.st_mtime; |
| 58 | file->length = st.st_size; |
| 59 | file->mode = st.st_mode; |
| 60 | - file->uid = st.st_uid; |
| 61 | - file->gid = st.st_gid; |
| 62 | + file->id_ndx = id_pair(st.st_uid, st.st_gid); |
| 63 | |
| 64 | #ifdef SUPPORT_HARD_LINKS |
| 65 | if (flist && flist->hlink_pool) { |
| 66 | @@ -931,8 +930,7 @@ struct file_struct *make_file(char *fnam |
| 67 | file->modtime = st2.st_mtime; |
| 68 | file->length = st2.st_size; |
| 69 | file->mode = st2.st_mode; |
| 70 | - file->uid = st2.st_uid; |
| 71 | - file->gid = st2.st_gid; |
| 72 | + file->id_ndx = id_pair(st2.st_uid, st2.st_gid); |
| 73 | file->u.link = NULL; |
| 74 | } else |
| 75 | file->mode = save_mode; |
| 76 | @@ -1380,7 +1378,7 @@ struct file_list *recv_file_list(int f) |
| 77 | clean_flist(flist, relative_paths, 1); |
| 78 | |
| 79 | if (f >= 0) { |
| 80 | - recv_uid_list(f, flist); |
| 81 | + recv_uid_list(f); |
| 82 | |
| 83 | /* Recv the io_error flag */ |
| 84 | if (lp_ignore_errors(module_id) || ignore_errors) |
| 85 | @@ -1696,13 +1694,15 @@ static void output_flist(struct file_lis |
| 86 | |
| 87 | for (i = 0; i < flist->count; i++) { |
| 88 | file = flist->files[i]; |
| 89 | - if ((am_root || am_sender) && preserve_uid) |
| 90 | - snprintf(uidbuf, sizeof uidbuf, " uid=%ld", (long)file->uid); |
| 91 | - else |
| 92 | + if ((am_root || am_sender) && preserve_uid) { |
| 93 | + snprintf(uidbuf, sizeof uidbuf, " uid=%ld", |
| 94 | + (long)id_pairs[file->id_ndx].uid); |
| 95 | + } else |
| 96 | *uidbuf = '\0'; |
| 97 | - if (preserve_gid && file->gid != GID_NONE) |
| 98 | - snprintf(gidbuf, sizeof gidbuf, " gid=%ld", (long)file->gid); |
| 99 | - else |
| 100 | + if (preserve_gid && id_pairs[file->id_ndx].gid != GID_NONE) { |
| 101 | + snprintf(gidbuf, sizeof gidbuf, " gid=%ld", |
| 102 | + (long)id_pairs[file->id_ndx].gid); |
| 103 | + } else |
| 104 | *gidbuf = '\0'; |
| 105 | if (!am_sender) |
| 106 | snprintf(depthbuf, sizeof depthbuf, "%d", file->dir.depth); |
| 107 | --- old/generator.c |
| 108 | +++ new/generator.c |
| 109 | @@ -90,6 +90,7 @@ extern dev_t filesystem_dev; |
| 110 | extern char *backup_dir; |
| 111 | extern char *backup_suffix; |
| 112 | extern int backup_suffix_len; |
| 113 | +extern struct id_pair *id_pairs; |
| 114 | extern struct file_list *the_file_list; |
| 115 | extern struct filter_list_struct server_filter_list; |
| 116 | |
| 117 | @@ -323,10 +324,12 @@ int unchanged_attrs(struct file_struct * |
| 118 | && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) |
| 119 | return 0; |
| 120 | |
| 121 | - if (am_root && preserve_uid && st->st_uid != file->uid) |
| 122 | + if (am_root && preserve_uid |
| 123 | + && st->st_uid != id_pairs[file->id_ndx].uid) |
| 124 | return 0; |
| 125 | |
| 126 | - if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid) |
| 127 | + if (preserve_gid && id_pairs[file->id_ndx].gid != GID_NONE |
| 128 | + && st->st_gid != id_pairs[file->id_ndx].gid) |
| 129 | return 0; |
| 130 | |
| 131 | return 1; |
| 132 | @@ -339,6 +342,8 @@ void itemize(struct file_struct *file, i |
| 133 | int keep_time = !preserve_times ? 0 |
| 134 | : S_ISDIR(file->mode) ? !omit_dir_times |
| 135 | : !S_ISLNK(file->mode); |
| 136 | + uid_t uid = id_pairs[file->id_ndx].uid; |
| 137 | + gid_t gid = id_pairs[file->id_ndx].gid; |
| 138 | |
| 139 | if (S_ISREG(file->mode) && file->length != st->st_size) |
| 140 | iflags |= ITEM_REPORT_SIZE; |
| 141 | @@ -348,10 +353,10 @@ void itemize(struct file_struct *file, i |
| 142 | iflags |= ITEM_REPORT_TIME; |
| 143 | if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS)) |
| 144 | iflags |= ITEM_REPORT_PERMS; |
| 145 | - if (preserve_uid && am_root && file->uid != st->st_uid) |
| 146 | + if (preserve_uid && am_root && uid != st->st_uid) |
| 147 | iflags |= ITEM_REPORT_OWNER; |
| 148 | - if (preserve_gid && file->gid != GID_NONE |
| 149 | - && st->st_gid != file->gid) |
| 150 | + if (preserve_gid && gid != GID_NONE |
| 151 | + && st->st_gid != gid) |
| 152 | iflags |= ITEM_REPORT_GROUP; |
| 153 | } else |
| 154 | iflags |= ITEM_IS_NEW; |
| 155 | --- old/log.c |
| 156 | +++ new/log.c |
| 157 | @@ -46,6 +46,7 @@ extern char *auth_user; |
| 158 | extern char *stdout_format; |
| 159 | extern char *logfile_format; |
| 160 | extern char *logfile_name; |
| 161 | +extern struct id_pair *id_pairs; |
| 162 | #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H |
| 163 | extern iconv_t ic_chck; |
| 164 | #endif |
| 165 | @@ -470,16 +471,16 @@ static void log_formatted(enum logcode c |
| 166 | case 'U': |
| 167 | strlcat(fmt, "ld", sizeof fmt); |
| 168 | snprintf(buf2, sizeof buf2, fmt, |
| 169 | - (long)file->uid); |
| 170 | + (long)id_pairs[file->id_ndx].uid); |
| 171 | n = buf2; |
| 172 | break; |
| 173 | case 'G': |
| 174 | - if (file->gid == GID_NONE) |
| 175 | + if (id_pairs[file->id_ndx].gid == GID_NONE) |
| 176 | n = "DEFAULT"; |
| 177 | else { |
| 178 | strlcat(fmt, "ld", sizeof fmt); |
| 179 | snprintf(buf2, sizeof buf2, fmt, |
| 180 | - (long)file->gid); |
| 181 | + (long)id_pairs[file->id_ndx].gid); |
| 182 | n = buf2; |
| 183 | } |
| 184 | break; |
| 185 | --- old/rsync.c |
| 186 | +++ new/rsync.c |
| 187 | @@ -49,6 +49,7 @@ extern int keep_dirlinks; |
| 188 | extern int make_backups; |
| 189 | extern mode_t orig_umask; |
| 190 | extern struct stats stats; |
| 191 | +extern struct id_pair *id_pairs; |
| 192 | extern struct chmod_mode_struct *daemon_chmod_modes; |
| 193 | |
| 194 | #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H |
| 195 | @@ -130,6 +131,8 @@ int set_file_attrs(char *fname, struct f |
| 196 | STRUCT_STAT st2; |
| 197 | int change_uid, change_gid; |
| 198 | mode_t new_mode = file->mode; |
| 199 | + uid_t uid; |
| 200 | + gid_t gid; |
| 201 | |
| 202 | if (!st) { |
| 203 | if (dry_run) |
| 204 | @@ -162,9 +165,11 @@ int set_file_attrs(char *fname, struct f |
| 205 | updated = 1; |
| 206 | } |
| 207 | |
| 208 | - change_uid = am_root && preserve_uid && st->st_uid != file->uid; |
| 209 | - change_gid = preserve_gid && file->gid != GID_NONE |
| 210 | - && st->st_gid != file->gid; |
| 211 | + uid = id_pairs[file->id_ndx].uid; |
| 212 | + gid = id_pairs[file->id_ndx].gid; |
| 213 | + change_uid = am_root && preserve_uid && st->st_uid != uid; |
| 214 | + change_gid = preserve_gid && gid != GID_NONE |
| 215 | + && st->st_gid != gid; |
| 216 | #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK |
| 217 | if (S_ISLNK(st->st_mode)) |
| 218 | ; |
| 219 | @@ -176,18 +181,18 @@ int set_file_attrs(char *fname, struct f |
| 220 | rprintf(FINFO, |
| 221 | "set uid of %s from %ld to %ld\n", |
| 222 | fname, |
| 223 | - (long)st->st_uid, (long)file->uid); |
| 224 | + (long)st->st_uid, (long)uid); |
| 225 | } |
| 226 | if (change_gid) { |
| 227 | rprintf(FINFO, |
| 228 | "set gid of %s from %ld to %ld\n", |
| 229 | fname, |
| 230 | - (long)st->st_gid, (long)file->gid); |
| 231 | + (long)st->st_gid, (long)gid); |
| 232 | } |
| 233 | } |
| 234 | if (do_lchown(fname, |
| 235 | - change_uid ? file->uid : st->st_uid, |
| 236 | - change_gid ? file->gid : st->st_gid) != 0) { |
| 237 | + change_uid ? uid : st->st_uid, |
| 238 | + change_gid ? gid : st->st_gid) != 0) { |
| 239 | /* shouldn't have attempted to change uid or gid |
| 240 | * unless have the privilege */ |
| 241 | rsyserr(FERROR, errno, "%s %s failed", |
| 242 | --- old/rsync.h |
| 243 | +++ new/rsync.h |
| 244 | @@ -503,6 +503,11 @@ struct hlink { |
| 245 | unsigned short link_dest_used; |
| 246 | }; |
| 247 | |
| 248 | +struct id_pair { |
| 249 | + uid_t uid; |
| 250 | + gid_t gid; |
| 251 | +}; |
| 252 | + |
| 253 | #define F_DEV link_u.idev->dev |
| 254 | #define F_INODE link_u.idev->inode |
| 255 | |
| 256 | @@ -527,8 +532,7 @@ struct file_struct { |
| 257 | struct hlink *links; |
| 258 | } link_u; |
| 259 | time_t modtime; |
| 260 | - uid_t uid; |
| 261 | - gid_t gid; |
| 262 | + int id_ndx; |
| 263 | mode_t mode; |
| 264 | uchar flags; /* this item MUST remain last */ |
| 265 | }; |
| 266 | --- old/uidlist.c |
| 267 | +++ new/uidlist.c |
| 268 | @@ -38,6 +38,8 @@ extern int preserve_gid; |
| 269 | extern int numeric_ids; |
| 270 | extern int am_root; |
| 271 | |
| 272 | +struct id_pair *id_pairs; |
| 273 | + |
| 274 | struct idlist { |
| 275 | struct idlist *next; |
| 276 | int id, id2; |
| 277 | @@ -47,6 +49,8 @@ struct idlist { |
| 278 | static struct idlist *uidlist; |
| 279 | static struct idlist *gidlist; |
| 280 | |
| 281 | +static int pair_cnt = 0, pair_alloc = 0; |
| 282 | + |
| 283 | static struct idlist *add_to_list(struct idlist **root, int id, char *name, |
| 284 | int id2) |
| 285 | { |
| 286 | @@ -306,7 +310,7 @@ void send_uid_list(int f) |
| 287 | |
| 288 | /* recv a complete uid/gid mapping from the peer and map the uid/gid |
| 289 | * in the file list to local names */ |
| 290 | -void recv_uid_list(int f, struct file_list *flist) |
| 291 | +void recv_uid_list(int f) |
| 292 | { |
| 293 | int id, i; |
| 294 | char *name; |
| 295 | @@ -337,11 +341,40 @@ void recv_uid_list(int f, struct file_li |
| 296 | |
| 297 | /* Now convert all the uids/gids from sender values to our values. */ |
| 298 | if (am_root && preserve_uid && !numeric_ids) { |
| 299 | - for (i = 0; i < flist->count; i++) |
| 300 | - flist->files[i]->uid = match_uid(flist->files[i]->uid); |
| 301 | + for (i = 0; i < pair_cnt; i++) |
| 302 | + id_pairs[i].uid = match_uid(id_pairs[i].uid); |
| 303 | } |
| 304 | if (preserve_gid && (!am_root || !numeric_ids)) { |
| 305 | - for (i = 0; i < flist->count; i++) |
| 306 | - flist->files[i]->gid = match_gid(flist->files[i]->gid); |
| 307 | + for (i = 0; i < pair_cnt; i++) |
| 308 | + id_pairs[i].gid = match_gid(id_pairs[i].gid); |
| 309 | } |
| 310 | } |
| 311 | + |
| 312 | +int id_pair(uid_t uid, gid_t gid) |
| 313 | +{ |
| 314 | + static int j = 0; |
| 315 | + |
| 316 | + if (pair_cnt) { |
| 317 | + int start = j; |
| 318 | + /* We start our search where we left off because |
| 319 | + * the IDs usually come in clumps. */ |
| 320 | + do { |
| 321 | + if (uid == id_pairs[j].uid && gid == id_pairs[j].gid) |
| 322 | + return j; |
| 323 | + if (++j == pair_cnt) |
| 324 | + j = 0; |
| 325 | + } while (j != start); |
| 326 | + } |
| 327 | + |
| 328 | + if (pair_cnt == pair_alloc) { |
| 329 | + pair_alloc += 128; |
| 330 | + id_pairs = realloc_array(id_pairs, struct id_pair, |
| 331 | + pair_alloc); |
| 332 | + } |
| 333 | + |
| 334 | + j = pair_cnt++; |
| 335 | + id_pairs[j].uid = uid; |
| 336 | + id_pairs[j].gid = gid; |
| 337 | + |
| 338 | + return j; |
| 339 | +} |