This attempts to accomplish some per-file memory-savings by moving the uid+gid items out of the file-list (since their values are common to multiple file-list entries) and replacing them with an index to an array of structures. This only saves 4 bytes per file (not counting the overhead of the array). This probably needs a hashing algorithm to be added if the uid+gid list gets to be really large. --- old/flist.c +++ new/flist.c @@ -54,6 +54,7 @@ extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; extern struct stats stats; +extern struct id_pair *id_pairs; extern struct file_list *the_file_list; extern char curr_dir[MAXPATHLEN]; @@ -355,14 +356,14 @@ static void send_file_entry(struct file_ } } else if (protocol_version < 28) rdev = makedev(0, 0); - if (file->uid == uid) + if (id_pairs[file->id_ndx].uid == uid) flags |= XMIT_SAME_UID; else - uid = file->uid; - if (file->gid == gid) + uid = id_pairs[file->id_ndx].uid; + if (id_pairs[file->id_ndx].gid == gid) flags |= XMIT_SAME_GID; else - gid = file->gid; + gid = id_pairs[file->id_ndx].gid; if (file->modtime == modtime) flags |= XMIT_SAME_TIME; else @@ -613,8 +614,7 @@ static struct file_struct *receive_file_ file->modtime = modtime; file->length = file_length; file->mode = mode; - file->uid = uid; - file->gid = gid; + file->id_ndx = id_pair(uid, gid); if (dirname_len) { file->dirname = lastdir = bp; @@ -865,8 +865,7 @@ struct file_struct *make_file(char *fnam file->modtime = st.st_mtime; file->length = st.st_size; file->mode = st.st_mode; - file->uid = st.st_uid; - file->gid = st.st_gid; + file->id_ndx = id_pair(st.st_uid, st.st_gid); #ifdef SUPPORT_HARD_LINKS if (flist && flist->hlink_pool) { @@ -934,8 +933,7 @@ struct file_struct *make_file(char *fnam file->modtime = st2.st_mtime; file->length = st2.st_size; file->mode = st2.st_mode; - file->uid = st2.st_uid; - file->gid = st2.st_gid; + file->id_ndx = id_pair(st2.st_uid, st2.st_gid); file->u.link = NULL; } else file->mode = save_mode; @@ -1379,7 +1377,7 @@ struct file_list *recv_file_list(int f) clean_flist(flist, relative_paths, 1); if (f >= 0) { - recv_uid_list(f, flist); + recv_uid_list(f); /* Recv the io_error flag */ if (lp_ignore_errors(module_id) || ignore_errors) @@ -1695,13 +1693,15 @@ static void output_flist(struct file_lis for (i = 0; i < flist->count; i++) { file = flist->files[i]; - if ((am_root || am_sender) && preserve_uid) - sprintf(uidbuf, " uid=%ld", (long)file->uid); - else + if ((am_root || am_sender) && preserve_uid) { + sprintf(uidbuf, " uid=%ld", + (long)id_pairs[file->id_ndx].uid); + } else *uidbuf = '\0'; - if (preserve_gid && file->gid != GID_NONE) - sprintf(gidbuf, " gid=%ld", (long)file->gid); - else + if (preserve_gid && id_pairs[file->id_ndx].gid != GID_NONE) { + sprintf(gidbuf, " gid=%ld", + (long)id_pairs[file->id_ndx].gid); + } else *gidbuf = '\0'; if (!am_sender) sprintf(depthbuf, "%d", file->dir.depth); --- old/generator.c +++ new/generator.c @@ -90,6 +90,7 @@ extern dev_t filesystem_dev; extern char *backup_dir; extern char *backup_suffix; extern int backup_suffix_len; +extern struct id_pair *id_pairs; extern struct file_list *the_file_list; extern struct filter_list_struct server_filter_list; @@ -323,10 +324,12 @@ int unchanged_attrs(struct file_struct * && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) return 0; - if (am_root && preserve_uid && st->st_uid != file->uid) + if (am_root && preserve_uid + && st->st_uid != id_pairs[file->id_ndx].uid) return 0; - if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid) + if (preserve_gid && id_pairs[file->id_ndx].gid != GID_NONE + && st->st_gid != id_pairs[file->id_ndx].gid) return 0; return 1; @@ -339,6 +342,8 @@ void itemize(struct file_struct *file, i int keep_time = !preserve_times ? 0 : S_ISDIR(file->mode) ? !omit_dir_times : !S_ISLNK(file->mode); + uid_t uid = id_pairs[file->id_ndx].uid; + gid_t gid = id_pairs[file->id_ndx].gid; if (S_ISREG(file->mode) && file->length != st->st_size) iflags |= ITEM_REPORT_SIZE; @@ -348,10 +353,10 @@ void itemize(struct file_struct *file, i iflags |= ITEM_REPORT_TIME; if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS)) iflags |= ITEM_REPORT_PERMS; - if (preserve_uid && am_root && file->uid != st->st_uid) + if (preserve_uid && am_root && uid != st->st_uid) iflags |= ITEM_REPORT_OWNER; - if (preserve_gid && file->gid != GID_NONE - && st->st_gid != file->gid) + if (preserve_gid && gid != GID_NONE + && st->st_gid != gid) iflags |= ITEM_REPORT_GROUP; } else iflags |= ITEM_IS_NEW; --- old/log.c +++ new/log.c @@ -43,6 +43,7 @@ extern int daemon_log_format_has_o_or_i; extern mode_t orig_umask; extern char *auth_user; extern char *log_format; +extern struct id_pair *id_pairs; #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H extern iconv_t ic_chck; #endif @@ -475,16 +476,16 @@ static void log_formatted(enum logcode c case 'U': strlcat(fmt, "ld", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, - (long)file->uid); + (long)id_pairs[file->id_ndx].uid); n = buf2; break; case 'G': - if (file->gid == GID_NONE) + if (id_pairs[file->id_ndx].gid == GID_NONE) n = "DEFAULT"; else { strlcat(fmt, "ld", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, - (long)file->gid); + (long)id_pairs[file->id_ndx].gid); n = buf2; } break; --- old/rsync.c +++ new/rsync.c @@ -50,6 +50,7 @@ extern int keep_dirlinks; extern int make_backups; extern mode_t orig_umask; extern struct stats stats; +extern struct id_pair *id_pairs; extern struct chmod_mode_struct *daemon_chmod_modes; #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H @@ -128,6 +129,8 @@ int set_file_attrs(char *fname, struct f int updated = 0; STRUCT_STAT st2; int change_uid, change_gid; + uid_t uid; + gid_t gid; if (!st) { if (dry_run) @@ -160,9 +163,11 @@ int set_file_attrs(char *fname, struct f updated = 1; } - change_uid = am_root && preserve_uid && st->st_uid != file->uid; - change_gid = preserve_gid && file->gid != GID_NONE - && st->st_gid != file->gid; + uid = id_pairs[file->id_ndx].uid; + gid = id_pairs[file->id_ndx].gid; + change_uid = am_root && preserve_uid && st->st_uid != uid; + change_gid = preserve_gid && gid != GID_NONE + && st->st_gid != gid; #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK if (S_ISLNK(st->st_mode)) ; @@ -174,18 +179,18 @@ int set_file_attrs(char *fname, struct f rprintf(FINFO, "set uid of %s from %ld to %ld\n", fname, - (long)st->st_uid, (long)file->uid); + (long)st->st_uid, (long)uid); } if (change_gid) { rprintf(FINFO, "set gid of %s from %ld to %ld\n", fname, - (long)st->st_gid, (long)file->gid); + (long)st->st_gid, (long)gid); } } if (do_lchown(fname, - change_uid ? file->uid : st->st_uid, - change_gid ? file->gid : st->st_gid) != 0) { + change_uid ? uid : st->st_uid, + change_gid ? gid : st->st_gid) != 0) { /* shouldn't have attempted to change uid or gid * unless have the privilege */ rsyserr(FERROR, errno, "%s %s failed", --- old/rsync.h +++ new/rsync.h @@ -495,6 +495,11 @@ struct hlink { int hlindex; }; +struct id_pair { + uid_t uid; + gid_t gid; +}; + #define F_DEV link_u.idev->dev #define F_INODE link_u.idev->inode @@ -519,8 +524,7 @@ struct file_struct { struct hlink *links; } link_u; time_t modtime; - uid_t uid; - gid_t gid; + int id_ndx; mode_t mode; uchar flags; /* this item MUST remain last */ }; --- old/uidlist.c +++ new/uidlist.c @@ -38,6 +38,8 @@ extern int preserve_gid; extern int numeric_ids; extern int am_root; +struct id_pair *id_pairs; + struct idlist { struct idlist *next; int id, id2; @@ -47,6 +49,8 @@ struct idlist { static struct idlist *uidlist; static struct idlist *gidlist; +static int pair_cnt = 0, pair_alloc = 0; + static struct idlist *add_to_list(struct idlist **root, int id, char *name, int id2) { @@ -308,7 +312,7 @@ void send_uid_list(int f) /* recv a complete uid/gid mapping from the peer and map the uid/gid * in the file list to local names */ -void recv_uid_list(int f, struct file_list *flist) +void recv_uid_list(int f) { int id, i; char *name; @@ -339,11 +343,40 @@ void recv_uid_list(int f, struct file_li /* Now convert all the uids/gids from sender values to our values. */ if (am_root && preserve_uid && !numeric_ids) { - for (i = 0; i < flist->count; i++) - flist->files[i]->uid = match_uid(flist->files[i]->uid); + for (i = 0; i < pair_cnt; i++) + id_pairs[i].uid = match_uid(id_pairs[i].uid); } if (preserve_gid && (!am_root || !numeric_ids)) { - for (i = 0; i < flist->count; i++) - flist->files[i]->gid = match_gid(flist->files[i]->gid); + for (i = 0; i < pair_cnt; i++) + id_pairs[i].gid = match_gid(id_pairs[i].gid); } } + +int id_pair(uid_t uid, gid_t gid) +{ + static int j = 0; + + if (pair_cnt) { + int start = j; + /* We start our search where we left off because + * the IDs usually come in clumps. */ + do { + if (uid == id_pairs[j].uid && gid == id_pairs[j].gid) + return j; + if (++j == pair_cnt) + j = 0; + } while (j != start); + } + + if (pair_cnt == pair_alloc) { + pair_alloc += 128; + id_pairs = realloc_array(id_pairs, struct id_pair, + pair_alloc); + } + + j = pair_cnt++; + id_pairs[j].uid = uid; + id_pairs[j].gid = gid; + + return j; +}