summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--flist.c23
-rw-r--r--main.c12
-rw-r--r--rsync.h6
-rw-r--r--uidlist.c310
-rw-r--r--version.h2
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
diff --git a/flist.c b/flist.c
index 40158fae..d438400a 100644
--- a/flist.c
+++ b/flist.c
@@ -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:
diff --git a/main.c b/main.c
index 837d3097..16f280d2 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/rsync.h b/rsync.h
index 0b881039..836c67d6 100644
--- a/rsync.h
+++ b/rsync.h
@@ -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);
+ }
+ }
+}
diff --git a/version.h b/version.h
index 9f46e2dc..24228d72 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define VERSION "1.6.8"
+#define VERSION "1.6.9"