summaryrefslogtreecommitdiff
path: root/uidlist.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1998-01-13 15:57:26 +0000
committerAndrew Tridgell <tridge@samba.org>1998-01-13 15:57:26 +0000
commitf6c347425ac550dd1b7d1ff739bedd1489099d91 (patch)
treee809fc3af665129184bf114c0f300d3d5d2cb3c6 /uidlist.c
parent3b3a2fbcf058b90d9116f48ba26ad9528d450134 (diff)
downloadrsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.tar.gz
rsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.tar.bz2
rsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.zip
*** empty log message ***
Diffstat (limited to 'uidlist.c')
-rw-r--r--uidlist.c310
1 files changed, 310 insertions, 0 deletions
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);
+ }
+ }
+}