diff options
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | flist.c | 23 | ||||
-rw-r--r-- | main.c | 12 | ||||
-rw-r--r-- | rsync.h | 6 | ||||
-rw-r--r-- | uidlist.c | 310 | ||||
-rw-r--r-- | version.h | 2 |
6 files changed, 347 insertions, 8 deletions
diff --git a/Makefile.in b/Makefile.in index 6b93fea7..585fee43 100644 --- a/Makefile.in +++ b/Makefile.in @@ -21,7 +21,7 @@ SHELL=/bin/sh LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o -OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o $(LIBOBJ) +OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o uidlist.o $(LIBOBJ) .c.o: $(CC) $(CFLAGS) -c $*.c -o $*.o @@ -43,6 +43,7 @@ extern int preserve_gid; extern int preserve_times; extern int relative_paths; extern int copy_links; +extern int remote_version; static char **local_exclude_list = NULL; @@ -142,10 +143,14 @@ void send_file_entry_v11(struct file_struct *file,int f) write_int(f,(int)file->modtime); if (!(flags & SAME_MODE)) write_int(f,(int)file->mode); - if (preserve_uid && !(flags & SAME_UID)) - write_int(f,(int)file->uid); - if (preserve_gid && !(flags & SAME_GID)) - write_int(f,(int)file->gid); + if (preserve_uid && !(flags & SAME_UID)) { + add_uid(file->uid); + write_int(f,(int)file->uid); + } + if (preserve_gid && !(flags & SAME_GID)) { + add_gid(file->gid); + write_int(f,(int)file->gid); + } if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV)) write_int(f,(int)file->rdev); @@ -502,6 +507,11 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) clean_flist(flist); + /* now send the uid/gid list. This was introduced in protocol version 15 */ + if (f != -1 && remote_version >= 15) { + send_uid_list(f); + } + return flist; } @@ -564,6 +574,11 @@ struct file_list *recv_file_list(int f) fprintf(FINFO,"done\n"); } + /* now recv the uid/gid list. This was introduced in protocol version 15 */ + if (f != -1 && remote_version >= 15) { + recv_uid_list(f, flist); + } + return flist; oom: @@ -52,6 +52,7 @@ int do_compression=0; int am_root=0; int orig_umask=0; int relative_paths=0; +int numeric_ids = 0; extern int csum_length; @@ -166,6 +167,9 @@ static void server_options(char **args,int *argc) if (delete_mode) args[ac++] = "--delete"; + if (numeric_ids) + args[ac++] = "--numeric-ids"; + *argc = ac; } @@ -434,6 +438,7 @@ static void usage(FILE *f) fprintf(f," --rsync-path PATH specify path to rsync on the remote machine\n"); fprintf(f,"-C, --cvs-exclude auto ignore files in the same way CVS does\n"); fprintf(f," --delete delete files that don't exist on the sending side\n"); + fprintf(f," --numeric-ids don't map uid/gid values by user/group name\n"); fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n"); fprintf(f,"-z, --compress compress file data\n"); fprintf(f," --exclude FILE exclude file FILE\n"); @@ -447,7 +452,7 @@ static void usage(FILE *f) } enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE, - OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH}; + OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH}; static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:z"; @@ -456,6 +461,7 @@ static struct option long_options[] = { {"server", 0, 0, OPT_SERVER}, {"sender", 0, 0, OPT_SENDER}, {"delete", 0, 0, OPT_DELETE}, + {"numeric-ids", 0, 0, OPT_NUMERIC_IDS}, {"exclude", 1, 0, OPT_EXCLUDE}, {"exclude-from",1, 0, OPT_EXCLUDE_FROM}, {"rsync-path", 1, 0, OPT_RSYNC_PATH}, @@ -549,6 +555,10 @@ int main(int argc,char *argv[]) delete_mode = 1; break; + case OPT_NUMERIC_IDS: + numeric_ids = 1; + break; + case OPT_EXCLUDE: add_exclude(optarg); break; @@ -39,7 +39,7 @@ #define SAME_TIME (1<<7) /* update this if you make incompatible changes */ -#define PROTOCOL_VERSION 14 +#define PROTOCOL_VERSION 15 #define MIN_PROTOCOL_VERSION 10 #define MAX_PROTOCOL_VERSION 20 @@ -163,6 +163,10 @@ #include "lib/getopt.h" #endif +/* these are needed for the uid/gid mapping code */ +#include <pwd.h> +#include <grp.h> + #ifndef S_IFLNK #define S_IFLNK 0120000 #endif diff --git a/uidlist.c b/uidlist.c new file mode 100644 index 00000000..b7d84ce9 --- /dev/null +++ b/uidlist.c @@ -0,0 +1,310 @@ +/* + Copyright (C) Andrew Tridgell 1996 + Copyright (C) Paul Mackerras 1996 + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* handle the mapping of uid/gid and user/group names between systems. + If the source username/group does not exist on the target then use + the numeric ids. Never do any mapping for uid=0 or gid=0 as these + are special. +*/ + +#include "rsync.h" + +extern int preserve_uid; +extern int preserve_gid; +extern int numeric_ids; + +struct idlist { + struct idlist *next; + int id, id2; + char *name; +}; + +static struct idlist *uidlist; +static struct idlist *gidlist; + +static struct idlist *add_list(int id, char *name) +{ + struct idlist *list = (struct idlist *)malloc(sizeof(list[0])); + if (!list) out_of_memory("add_list"); + list->next = NULL; + list->name = strdup(name); + if (!list->name) out_of_memory("add_list"); + list->id = (int)id; + return list; +} + + + +/* turn a uid into a user name */ +static char *uid_to_name(uid_t uid) +{ + struct passwd *pass = getpwuid(uid); + if (pass) return(pass->pw_name); + return NULL; +} + +/* turn a gid into a group name */ +static char *gid_to_name(gid_t gid) +{ + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + return NULL; +} + + +/* turn a user name into a uid */ +static uid_t name_to_uid(char *name) +{ + struct passwd *pass; + if (!name || !*name) return 0; + pass = getpwnam(name); + if (pass) return(pass->pw_uid); + return 0; +} + +/* turn a group name into a gid */ +static gid_t name_to_gid(char *name) +{ + struct group *grp; + if (!name || !*name) return 0; + grp = getgrnam(name); + if (grp) return(grp->gr_gid); + return 0; +} + +static int map_uid(int id, char *name) +{ + uid_t uid = name_to_uid(name); + if (uid != 0) return uid; + return id; +} + +static int map_gid(int id, char *name) +{ + gid_t gid = name_to_gid(name); + if (gid != 0) return gid; + return id; +} + +/* this function is a definate candidate for a faster algorithm */ +static uid_t match_uid(uid_t uid) +{ + static uid_t last_in, last_out; + struct idlist *list = uidlist; + + if (uid == last_in) return last_out; + + last_in = uid; + + while (list) { + if (list->id == (int)uid) { + last_out = (uid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = uid; + return last_out; +} + +static gid_t match_gid(gid_t gid) +{ + static gid_t last_in, last_out; + struct idlist *list = gidlist; + + if (gid == last_in) return last_out; + + last_in = gid; + + while (list) { + if (list->id == (int)gid) { + last_out = (gid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = gid; + return last_out; +} + +/* add a uid to the list of uids */ +void add_uid(uid_t uid) +{ + struct idlist *list = uidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (uid==0) return; + + if (!list) { + if (!(name = uid_to_name(uid))) return; + uidlist = add_list((int)uid, name); + return; + } + + while (list->next) { + if (list->id == (int)uid) return; + list = list->next; + } + + if (list->id == (int)uid) return; + + if (!(name = uid_to_name(uid))) return; + + list->next = add_list((int)uid, name); +} + +/* add a gid to the list of gids */ +void add_gid(gid_t gid) +{ + struct idlist *list = gidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (gid==0) return; + + if (!list) { + if (!(name = gid_to_name(gid))) return; + gidlist = add_list((int)gid, name); + return; + } + + while (list->next) { + if (list->id == (int)gid) return; + list = list->next; + } + + if (list->id == (int)gid) return; + + if (!(name = gid_to_name(gid))) return; + + list->next = add_list((int)gid, name); +} + + +/* send a complete uid/gid mapping to the peer */ +void send_uid_list(int f) +{ + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* we send sequences of uid/byte-length/name */ + list = uidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + + /* terminate the uid list with a 0 uid. We explicitly exclude + 0 from the list */ + write_int(f, 0); + } + + if (preserve_gid) { + list = gidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + write_int(f, 0); + } +} + +/* 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) +{ + int id, i; + char *name; + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* read the uid list */ + list = uidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + uidlist = add_list(id, name); + list = uidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_uid(id, name); + free(name); + id = read_int(f); + } + } + + + if (preserve_gid) { + /* and the gid list */ + list = gidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + gidlist = add_list(id, name); + list = gidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_gid(id, name); + free(name); + id = read_int(f); + } + } + + if (!uidlist && !gidlist) return; + + /* now convert the uid/gid of all files in the list to the mapped + uid/gid */ + for (i=0;i<flist->count;i++) { + if (preserve_uid && flist->files[i].uid != 0) { + flist->files[i].uid = match_uid(flist->files[i].uid); + } + if (preserve_gid && flist->files[i].gid != 0) { + flist->files[i].gid = match_gid(flist->files[i].gid); + } + } +} @@ -1 +1 @@ -#define VERSION "1.6.8" +#define VERSION "1.6.9" |