1This attempts to accomplish some per-file memory-savings by moving the 2uid+gid items out of the file-list (since their values are common to 3multiple file-list entries) and replacing them with an index to an 4array of structures. 5 6This only saves 4 bytes per file (not counting the overhead of the array). 7 8This probably needs a hashing algorithm to be added if the uid+gid list 9gets to be really large. 10 11To 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+} 340--- old/proto.h 341+++ new/proto.h 342@@ -271,7 +271,8 @@ void see_token(char *data, int32 toklen) 343 void add_uid(uid_t uid); 344 void add_gid(gid_t gid); 345 void send_uid_list(int f); 346-void recv_uid_list(int f, struct file_list *flist); 347+void recv_uid_list(int f); 348+int id_pair(uid_t uid, gid_t gid); 349 void set_nonblocking(int fd); 350 void set_blocking(int fd); 351 int fd_pair(int fd[2]); 352