#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
if (S_ISLNK(file->mode)) {
;
-@@ -923,6 +927,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
+@@ -921,6 +925,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
if (link_dest) {
if (!hard_link_one(file, fname, cmpbuf, 1))
goto try_a_copy;
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
-@@ -1113,6 +1119,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
+@@ -1111,6 +1117,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
static void list_file_entry(struct file_struct *f)
{
char permbuf[PERMSTRING_SIZE];
double len;
if (!F_IS_ACTIVE(f)) {
-@@ -1127,14 +1134,16 @@ static void list_file_entry(struct file_struct *f)
+@@ -1125,14 +1132,16 @@ static void list_file_entry(struct file_struct *f)
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) {
f_name(f, NULL));
}
}
-@@ -1884,7 +1893,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
+@@ -1882,7 +1891,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
if (!(file->mode & S_IWUSR))
do_chmod(fname, file->mode);
if (need_retouch_dir_times)
t[0].tv_usec = 0;
t[1].tv_sec = modtime;
t[1].tv_usec = 0;
-@@ -154,12 +158,12 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode)
+@@ -155,12 +159,12 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode)
return utimes(fname, t);
#elif defined HAVE_STRUCT_UTIMBUF
struct utimbuf tbuf;
extern int io_timeout;
extern int no_detach;
extern int write_batch;
-@@ -704,6 +705,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
+@@ -708,6 +709,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
else if (am_root < 0) /* Treat --fake-super from client as --super. */
am_root = 2;
diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
--- a/rsyncd.conf.yo
+++ b/rsyncd.conf.yo
-@@ -237,6 +237,20 @@ locking on this file to ensure that the max connections limit is not
+@@ -241,6 +241,20 @@ locking on this file to ensure that the max connections limit is not
exceeded for the modules sharing the lock file.
The default is tt(/var/run/rsyncd.lock).
typedef struct {
char *datum, *name;
-@@ -841,6 +845,39 @@ int del_def_xattr_acl(const char *fname)
+@@ -853,6 +857,39 @@ int del_def_xattr_acl(const char *fname)
}
#endif
extern int preserve_specials;
extern int preserve_hard_links;
extern int preserve_perms;
-@@ -1566,7 +1567,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1564,7 +1565,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
diff = u_strcmp(fmid->basename, f->basename);
if (diff == 0) {
good_match = mid;
-@@ -1864,6 +1866,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1862,6 +1864,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp = partialptr;
fnamecmp_type = FNAMECMP_PARTIAL_DIR;
statret = 0;
if (do_progress && !am_server)
rprintf(FINFO, " \r");
-@@ -1139,6 +1290,7 @@ static void list_file_entry(struct file_struct *f)
+@@ -1137,6 +1288,7 @@ static void list_file_entry(struct file_struct *f)
}
}
static int phase = 0;
static int dflt_perms;
-@@ -1383,8 +1535,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1381,8 +1533,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
}
else if (delete_during && f_out != -1 && !phase && dry_run < 2
goto cleanup;
}
-@@ -1662,8 +1818,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1660,8 +1816,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
#endif
rsyserr(FERROR_XFER, stat_errno, "recv_generator: failed to stat %s",
full_fname(fname));
goto cleanup;
-@@ -2000,6 +2162,12 @@ void generate_files(int f_out, const char *local_name)
+@@ -2004,6 +2166,12 @@ void generate_files(int f_out, const char *local_name)
if (verbose > 2)
rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
if (delete_before && !solo_file && cur_flist->used > 0)
do_delete_pass();
if (delete_during == 2) {
-@@ -2010,7 +2178,7 @@ void generate_files(int f_out, const char *local_name)
+@@ -2014,7 +2182,7 @@ void generate_files(int f_out, const char *local_name)
}
do_progress = 0;
whole_file = 0;
if (verbose >= 2) {
rprintf(FINFO, "delta-transmission %s\n",
-@@ -2048,7 +2216,7 @@ void generate_files(int f_out, const char *local_name)
+@@ -2052,7 +2220,7 @@ void generate_files(int f_out, const char *local_name)
dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
} else
dirdev = MAKEDEV(0, 0);
}
}
}
-@@ -2091,7 +2259,21 @@ void generate_files(int f_out, const char *local_name)
+@@ -2095,7 +2263,21 @@ void generate_files(int f_out, const char *local_name)
} while ((cur_flist = cur_flist->next) != NULL);
if (delete_during)
diff --git a/util.c b/util.c
--- a/util.c
+++ b/util.c
-@@ -1022,6 +1022,32 @@ int handle_partial_dir(const char *fname, int create)
+@@ -1019,6 +1019,32 @@ int handle_partial_dir(const char *fname, int create)
return 1;
}
extern int ignore_existing;
extern int ignore_non_existing;
extern int inplace;
-@@ -1603,6 +1604,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1601,6 +1602,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
fnamecmp_type = FNAMECMP_FNAME;
@@ -1917,6 +1925,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
- ignore_existing = -ignore_existing;
- ignore_non_existing = -ignore_non_existing;
- update_only = -update_only;
-+ downdate_only = -downdate_only;
- always_checksum = -always_checksum;
- size_only = -size_only;
- append_mode = -append_mode;
+ ignore_existing = -ignore_existing;
+ ignore_non_existing = -ignore_non_existing;
+ update_only = -update_only;
++ downdate_only = -downdate_only;
+ always_checksum = -always_checksum;
+ size_only = -size_only;
+ append_mode = -append_mode;
@@ -1942,6 +1951,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
- ignore_existing = -ignore_existing;
- ignore_non_existing = -ignore_non_existing;
- update_only = -update_only;
-+ downdate_only = -downdate_only;
- always_checksum = -always_checksum;
- size_only = -size_only;
- append_mode = -append_mode;
+ ignore_existing = -ignore_existing;
+ ignore_non_existing = -ignore_non_existing;
+ update_only = -update_only;
++ downdate_only = -downdate_only;
+ always_checksum = -always_checksum;
+ size_only = -size_only;
+ append_mode = -append_mode;
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
- extattr_get_link sigaction sigprocmask setattrlist)
+ extattr_get_link sigaction sigprocmask setattrlist posix_fadvise64)
- AC_CHECK_FUNCS(getpgrp tcgetpgrp)
- if test $ac_cv_func_getpgrp = yes; then
+ dnl cygwin iconv.h defines iconv_open as libiconv_open
+ if test x"$ac_cv_func_iconv_open" != x"yes"; then
diff --git a/fileio.c b/fileio.c
--- a/fileio.c
+++ b/fileio.c
+ chflags strerror putenv iconv_open locale_charset nl_langinfo getxattr \
extattr_get_link sigaction sigprocmask setattrlist)
- AC_CHECK_FUNCS(getpgrp tcgetpgrp)
+ dnl cygwin iconv.h defines iconv_open as libiconv_open
diff --git a/flist.c b/flist.c
--- a/flist.c
+++ b/flist.c
}
}
-@@ -1296,7 +1307,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1294,7 +1305,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
* full later (right before we handle its contents). */
if (statret == 0
&& (S_ISDIR(sx.st.st_mode)
goto cleanup; /* Any errors get reported later. */
if (do_mkdir(fname, file->mode & 0700) == 0)
file->flags |= FLAG_DIR_CREATED;
-@@ -1308,7 +1319,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1306,7 +1317,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
* we need to delete it. If it doesn't exist, then
* (perhaps recursively) create it. */
if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
goto skipping_dir_contents;
statret = -1;
}
-@@ -1437,7 +1448,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1435,7 +1446,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* Not the right symlink (or not a symlink), so
* delete it. */
goto cleanup;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
-@@ -1516,7 +1527,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1514,7 +1525,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto return_with_success;
goto cleanup;
}
goto cleanup;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
-@@ -1607,7 +1618,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1605,7 +1616,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp_type = FNAMECMP_FNAME;
if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
if (verbose > 1 && flags & ATTRS_REPORT) {
if (updated)
rprintf(FCLIENT, "%s\n", fname);
-@@ -528,6 +583,9 @@ void finish_transfer(const char *fname, const char *fnametmp,
+@@ -530,6 +585,9 @@ int finish_transfer(const char *fname, const char *fnametmp,
set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
/* move tmp file over real file */
if (verbose > 2)
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
-@@ -542,6 +600,9 @@ void finish_transfer(const char *fname, const char *fnametmp,
+@@ -547,6 +605,9 @@ int finish_transfer(const char *fname, const char *fnametmp,
}
if (ret == 0) {
/* The file was moved into place (not copied), so it's done. */
+#ifdef SUPPORT_FLAGS
+ undo_make_mutable(fname, file->mode, F_FFLAGS(file));
+#endif
- return;
+ return 1;
}
/* The file was copied, so tweak the perms of the copied file. If it
diff --git a/rsync.h b/rsync.h
extern int modify_window;
extern int relative_paths;
extern int human_readable;
-@@ -314,6 +315,13 @@ int copy_file(const char *source, const char *dest, int ofd,
+@@ -315,6 +316,13 @@ int copy_file(const char *source, const char *dest, int ofd,
full_fname(source));
}
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern struct chmod_mode_struct *daemon_chmod_modes;
#ifdef ICONV_OPTION
-@@ -531,8 +532,15 @@ void finish_transfer(const char *fname, const char *fnametmp,
+@@ -533,8 +534,15 @@ int finish_transfer(const char *fname, const char *fnametmp,
/* move tmp file over real file */
if (verbose > 2)
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
-- ret = robust_rename(fnametmp, fname, partialptr,
+- ret = robust_rename(fnametmp, fname, temp_copy_name,
- file->mode & INITACCESSPERMS);
+#ifdef HAVE_LINK
+ if (link_by_hash_dir)
+ else
+#endif
+ {
-+ ret = robust_rename(fnametmp, fname, partialptr,
++ ret = robust_rename(fnametmp, fname, temp_copy_name,
+ file->mode & INITACCESSPERMS);
+ }
if (ret < 0) {
diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
--- a/rsyncd.conf.yo
+++ b/rsyncd.conf.yo
-@@ -460,7 +460,8 @@ quote(itemization(
+@@ -464,7 +464,8 @@ quote(itemization(
it() %a the remote IP address
it() %b the number of bytes actually transferred
it() %B the permission bits of the file (e.g. rwxrwxrwt)
--- /dev/null
+This patch adds a "name converter" daemon option that allows you
+to specify a user-/group- name converter program that converts
+between ID numbers and names. This only works in daemon mode,
+and is useful for both chroot use (since the converter runs
+outside the chroot) or to specify a converter that doesn't use
+the normal passwd/group setup.
+
+The converter must use a null char ('\0') as the line terminator
+for input/output on stdin/stdout. A sample converter written in
+perl is supplied in the support dir: nameconvert. To use it,
+specify this daemon option:
+
+ name converter = /path/nameconvert
+
+If /path/ is omitted, the script will be found on the $PATH.
+
+To use this patch, run these commands for a successful build:
+
+ patch -p1 <patches/nameconverter.diff
+ ./configure (optional if already run)
+ make
+
+diff --git a/clientserver.c b/clientserver.c
+--- a/clientserver.c
++++ b/clientserver.c
+@@ -59,6 +59,7 @@ char *auth_user;
+ int read_only = 0;
+ int module_id = -1;
+ int munge_symlinks = 0;
++pid_t namecvt_pid = 0;
+ struct chmod_mode_struct *daemon_chmod_modes;
+
+ /* module_dirlen is the length of the module_dir string when in daemon
+@@ -67,6 +68,7 @@ char *module_dir = NULL;
+ unsigned int module_dirlen = 0;
+
+ static int rl_nulls = 0;
++static int namecvt_fd_req = -1, namecvt_fd_ans = -1;
+
+ #ifdef HAVE_SIGACTION
+ static struct sigaction sigact;
+@@ -508,7 +510,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
+ log_init(1);
+
+ #ifdef HAVE_PUTENV
+- if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
++ if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i) || *lp_name_converter(i)) {
+ char *modname, *modpath, *hostaddr, *hostname, *username;
+ int status;
+ if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
+@@ -595,6 +597,44 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
+ set_blocking(fds[1]);
+ pre_exec_fd = fds[1];
+ }
++ if (*lp_name_converter(i)) {
++ int fds_to[2], fds_from[2];
++ if (pipe(fds_to) < 0 || pipe(fds_from) < 0
++ || (namecvt_pid = fork()) < 0) {
++ rsyserr(FLOG, errno, "name-converter exec preparation failed");
++ io_printf(f_out, "@ERROR: name-converter exec preparation failed\n");
++ return -1;
++ }
++ if (namecvt_pid == 0) {
++ char *args[100], *run = lp_name_converter(i);
++ int cnt = 0;
++ close(fds_to[1]);
++ close(fds_from[0]);
++ set_blocking(fds_to[0]);
++ set_blocking(fds_from[1]);
++ close(STDIN_FILENO);
++ close(STDOUT_FILENO);
++ dup2(fds_to[0], STDIN_FILENO);
++ dup2(fds_from[1], STDOUT_FILENO);
++ while (cnt+1 < (int)(sizeof args / sizeof (char *))) {
++ char *space = strchr(run, ' ');
++ args[cnt++] = run;
++ if (!space)
++ break;
++ *space = '\0';
++ run = space + 1;
++ }
++ args[cnt] = NULL;
++ execvp(args[0], args);
++ _exit(1);
++ }
++ close(fds_to[0]);
++ close(fds_from[1]);
++ set_blocking(fds_to[1]);
++ set_blocking(fds_from[0]);
++ namecvt_fd_req = fds_to[1];
++ namecvt_fd_ans = fds_from[0];
++ }
+ umask(0);
+ }
+ #endif
+@@ -789,6 +829,44 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
+ return 0;
+ }
+
++int namecvt_name(const char *cmd, const char *name)
++{
++ char buf[1024];
++ int got, len = snprintf(buf, sizeof buf, "%s %s", cmd, name);
++ if (len >= (int)sizeof buf) {
++ rprintf(FERROR, "namecvt_name() request was too large.\n");
++ exit_cleanup(RERR_UNSUPPORTED);
++ }
++ while ((got = write(namecvt_fd_req, buf, len + 1)) != len + 1) {
++ if (got < 0 && errno == EINTR)
++ continue;
++ rprintf(FERROR, "Connection to name-converter failed.\n");
++ exit_cleanup(RERR_SOCKETIO);
++ }
++ if (!(len = read_arg_from_pipe(namecvt_fd_ans, buf, sizeof buf)))
++ return 0;
++ return atoi(buf);
++}
++
++const char *namecvt_id(const char *cmd, int id)
++{
++ char buf[1024];
++ int got, len = snprintf(buf, sizeof buf, "%s %d", cmd, id);
++ if (len >= (int)sizeof buf) {
++ rprintf(FERROR, "namecvt_id() request was too large.\n");
++ exit_cleanup(RERR_UNSUPPORTED);
++ }
++ while ((got = write(namecvt_fd_req, buf, len + 1)) != len + 1) {
++ if (got < 0 && errno == EINTR)
++ continue;
++ rprintf(FERROR, "Connection to name-converter failed.\n");
++ exit_cleanup(RERR_SOCKETIO);
++ }
++ if (!(len = read_arg_from_pipe(namecvt_fd_ans, buf, sizeof buf)))
++ return NULL;
++ return strdup(buf);
++}
++
+ /* send a list of available modules to the client. Don't list those
+ with "list = False". */
+ static void send_listing(int fd)
+diff --git a/loadparm.c b/loadparm.c
+--- a/loadparm.c
++++ b/loadparm.c
+@@ -139,6 +139,7 @@ typedef struct
+ char *log_file;
+ char *log_format;
+ char *name;
++ char *name_converter;
+ char *outgoing_chmod;
+ char *path;
+ char *postxfer_exec;
+@@ -188,6 +189,7 @@ static service sDefault =
+ /* log_file; */ NULL,
+ /* log_format; */ "%o %h [%a] %m (%u) %f %l",
+ /* name; */ NULL,
++ /* name_converter; */ NULL,
+ /* outgoing_chmod; */ NULL,
+ /* path; */ NULL,
+ /* postxfer_exec; */ NULL,
+@@ -323,6 +325,7 @@ static struct parm_struct parm_table[] =
+ {"max verbosity", P_INTEGER,P_LOCAL, &sDefault.max_verbosity, NULL,0},
+ {"munge symlinks", P_BOOL, P_LOCAL, &sDefault.munge_symlinks, NULL,0},
+ {"name", P_STRING, P_LOCAL, &sDefault.name, NULL,0},
++ {"name converter", P_STRING, P_LOCAL, &sDefault.name_converter, NULL,0},
+ {"outgoing chmod", P_STRING, P_LOCAL, &sDefault.outgoing_chmod, NULL,0},
+ {"path", P_PATH, P_LOCAL, &sDefault.path, NULL,0},
+ #ifdef HAVE_PUTENV
+@@ -411,6 +414,7 @@ FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod)
+ FN_LOCAL_STRING(lp_path, path)
+ FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
+ FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
++FN_LOCAL_STRING(lp_name_converter, name_converter)
+ FN_LOCAL_STRING(lp_refuse_options, refuse_options)
+ FN_LOCAL_STRING(lp_secrets_file, secrets_file)
+ FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
+diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
+--- a/rsyncd.conf.yo
++++ b/rsyncd.conf.yo
+@@ -144,7 +144,10 @@ args if rsync believes they would escape the chroot.
+ The default for "use chroot" is true, and is the safer choice (especially
+ if the module is not read-only).
+
+-In order to preserve usernames and groupnames, rsync needs to be able to
++In order to preserve usernames and groupnames, you can use the
++bf(name converter) option to specify a name-converting program that the
++rsync daemon will start prior to enabling chroot (see the option for more
++details). If that option is not specified, the daemon needs to be able to
+ use the standard library functions for looking up names and IDs (i.e.
+ code(getpwuid()), code(getgrgid()), code(getpwname()), and code(getgrnam())). This means a
+ process in the chroot namespace will need to have access to the resources
+@@ -200,6 +203,27 @@ path elements that rsync believes will allow a symlink to escape the module's
+ hierarchy. There are tricky ways to work around this, though, so you had
+ better trust your users if you choose this combination of options.
+
++dit(bf(name converter)) The "name converter" option lets you specify a
++program that will be run by the rsync daemon (prior to bf(use chroot), if
++that option is enabled) to convert user/group names into numbers or visa
++versa. There is a sample perl script in the support directory named
++"nameconvert" that you can use to enable the use of the normal passwd/group
++lookup calls in a chroot daemon (which does not require any extra files
++be placed in the chroot area). This use is configured as follows:
++
++verb( name converter = /path/nameconvert)
++
++You could alternately specify a program that responds to each request using
++a lookup table to find the names and numbers, this allows you to configure
++per-module name conversion. See the support/nameconvert script for the
++details of what requests can be sent to the program.
++
++The program will have access to some of the environment variables that are
++described in the section on bf(pre-xfer exec): bf(RSYNC_MODULE_NAME),
++bf(RSYNC_MODULE_PATH), bf(RSYNC_HOST_ADDR), bf(RSYNC_HOST_NAME), and
++bf(RSYNC_USER_NAME). This is useful if you want to customize the
++conversion using a single program invocation.
++
+ dit(bf(max connections)) The "max connections" option allows you to
+ specify the maximum number of simultaneous connections you will allow.
+ Any clients connecting when the maximum has been reached will receive a
+diff --git a/support/nameconvert b/support/nameconvert
+new file mode 100755
+--- /dev/null
++++ b/support/nameconvert
+@@ -0,0 +1,42 @@
++#!/usr/bin/perl -w
++# This implements a simple protocol to do {user,group}-{name,id}
++# conversions. All input and output consists of simple strings
++# with a terminating null char (or newline for debugging). If
++# the conversion fails, an empty string is returned.
++#
++# The requests can be:
++#
++# uid ID_NUM\0 -> NAME\0
++# gid ID_NUM\0 -> NAME\0
++# usr NAME\0 -> ID_NUM\0
++# grp NAME\0 -> ID_NUM\0
++#
++# An unknown ID_NUM or NAME results in an empty return value.
++#
++# This is used by an rsync daemon when configured with the
++# "name converter" setting.
++
++use strict;
++
++my $eol = grep(/^--debug$/, @ARGV) ? "\n" : "\0";
++$/ = $eol;
++
++$| = 1;
++
++while (<STDIN>) {
++ chomp;
++ my $ans;
++ if (/^uid (\d+)$/) {
++ $ans = getpwuid($1);
++ } elsif (/^gid (\d+)$/) {
++ $ans = getgrgid($1);
++ } elsif (/^usr (\S+)$/) {
++ $ans = getpwnam($1);
++ } elsif (/^grp (\S+)$/) {
++ $ans = getgrnam($1);
++ } else {
++ die "Invalid request: $_";
++ }
++ $ans = '' unless defined $ans;
++ print $ans, $eol;
++}
+diff --git a/t_stub.c b/t_stub.c
+--- a/t_stub.c
++++ b/t_stub.c
+@@ -29,6 +29,7 @@ int module_dirlen = 0;
+ mode_t orig_umask = 002;
+ char *partial_dir;
+ char *module_dir;
++pid_t namecvt_pid;
+ struct filter_list_struct server_filter_list;
+
+ void rprintf(UNUSED(enum logcode code), const char *format, ...)
+@@ -69,6 +70,11 @@ struct filter_list_struct server_filter_list;
+ return -1;
+ }
+
++ int namecvt_name(UNUSED(const char *cmd), UNUSED(const char *name))
++{
++ return 0;
++}
++
+ char *lp_name(UNUSED(int mod))
+ {
+ return NULL;
+diff --git a/uidlist.c b/uidlist.c
+--- a/uidlist.c
++++ b/uidlist.c
+@@ -32,6 +32,7 @@ extern int preserve_uid;
+ extern int preserve_gid;
+ extern int preserve_acls;
+ extern int numeric_ids;
++extern pid_t namecvt_pid;
+
+ #ifdef HAVE_GETGROUPS
+ # ifndef GETGROUPS_T
+@@ -69,8 +70,12 @@ static struct idlist *add_to_list(struct idlist **root, id_t id, const char *nam
+ /* turn a uid into a user name */
+ static const char *uid_to_name(uid_t uid)
+ {
+- struct passwd *pass = getpwuid(uid);
+- if (pass)
++ struct passwd *pass;
++
++ if (namecvt_pid)
++ return namecvt_id("uid", (int)uid);
++
++ if ((pass = getpwuid(uid)) != NULL)
+ return strdup(pass->pw_name);
+ return NULL;
+ }
+@@ -78,8 +83,12 @@ static const char *uid_to_name(uid_t uid)
+ /* turn a gid into a group name */
+ static const char *gid_to_name(gid_t gid)
+ {
+- struct group *grp = getgrgid(gid);
+- if (grp)
++ struct group *grp;
++
++ if (namecvt_pid)
++ return namecvt_id("gid", (int)gid);
++
++ if ((grp = getgrgid(gid)) != NULL)
+ return strdup(grp->gr_name);
+ return NULL;
+ }
+diff --git a/util.c b/util.c
+--- a/util.c
++++ b/util.c
+@@ -30,9 +30,10 @@ extern int modify_window;
+ extern int relative_paths;
+ extern int human_readable;
+ extern char *module_dir;
+-extern unsigned int module_dirlen;
+ extern mode_t orig_umask;
+ extern char *partial_dir;
++extern pid_t namecvt_pid;
++extern unsigned int module_dirlen;
+ extern struct filter_list_struct server_filter_list;
+
+ int sanitize_paths = 0;
+@@ -468,24 +469,44 @@ void kill_all(int sig)
+ /** Turn a user name into a uid */
+ int name_to_uid(const char *name, uid_t *uid_p)
+ {
+- struct passwd *pass;
++ uid_t uid;
++
+ if (!name || !*name)
+ return 0;
+- if (!(pass = getpwnam(name)))
+- return 0;
+- *uid_p = pass->pw_uid;
++
++ if (namecvt_pid) {
++ if (!(uid = namecvt_name("usr", name)))
++ return 0;
++ } else {
++ struct passwd *pass;
++ if (!(pass = getpwnam(name)))
++ return 0;
++ uid = pass->pw_uid;
++ }
++
++ *uid_p = uid;
+ return 1;
+ }
+
+ /** Turn a group name into a gid */
+ int name_to_gid(const char *name, gid_t *gid_p)
+ {
+- struct group *grp;
++ gid_t gid;
++
+ if (!name || !*name)
+ return 0;
+- if (!(grp = getgrnam(name)))
+- return 0;
+- *gid_p = grp->gr_gid;
++
++ if (namecvt_pid) {
++ if (!(gid = namecvt_name("grp", name)))
++ return 0;
++ } else {
++ struct group *grp;
++ if (!(grp = getgrnam(name)))
++ return 0;
++ gid = grp->gr_gid;
++ }
++
++ *gid_p = gid;
+ return 1;
+ }
+
iflags |= ITEM_REPORT_GROUP;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
-@@ -1321,7 +1324,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1319,7 +1322,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
real_sx = sx;
if (file->flags & FLAG_DIR_CREATED)
statret = -1;
return -1;
}
-@@ -835,6 +882,9 @@ int start_daemon(int f_in, int f_out)
+@@ -839,6 +886,9 @@ int start_daemon(int f_in, int f_out)
if (exchange_protocols(f_in, f_out, line, sizeof line, 0) < 0)
return -1;
line[0] = 0;
if (!read_line_old(f_in, line, sizeof line))
return -1;
-@@ -846,6 +896,20 @@ int start_daemon(int f_in, int f_out)
+@@ -850,6 +900,20 @@ int start_daemon(int f_in, int f_out)
return -1;
}
- extattr_get_link sigaction sigprocmask setattrlist)
+ extattr_get_link sigaction sigprocmask setattrlist posix_fallocate)
- AC_CHECK_FUNCS(getpgrp tcgetpgrp)
- if test $ac_cv_func_getpgrp = yes; then
+ dnl cygwin iconv.h defines iconv_open as libiconv_open
+ if test x"$ac_cv_func_iconv_open" != x"yes"; then
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
extern int module_id;
extern int modify_window;
extern int relative_paths;
-@@ -272,6 +273,10 @@ int copy_file(const char *source, const char *dest, int ofd,
+@@ -273,6 +274,10 @@ int copy_file(const char *source, const char *dest, int ofd,
int ifd;
char buf[1024 * 8];
int len; /* Number of bytes read into `buf'. */
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
-@@ -293,7 +298,27 @@ int copy_file(const char *source, const char *dest, int ofd,
+@@ -294,7 +299,27 @@ int copy_file(const char *source, const char *dest, int ofd,
}
}
if (full_write(ofd, buf, len) < 0) {
rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
close(ifd);
-@@ -314,6 +339,16 @@ int copy_file(const char *source, const char *dest, int ofd,
+@@ -315,6 +340,16 @@ int copy_file(const char *source, const char *dest, int ofd,
full_fname(source));
}
diff --git a/clientserver.c b/clientserver.c
--- a/clientserver.c
+++ b/clientserver.c
-@@ -969,6 +969,13 @@ int daemon_main(void)
+@@ -973,6 +973,13 @@ int daemon_main(void)
* address too. In fact, why not just do inet_ntop on the
* local address??? */
diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
-@@ -632,6 +632,29 @@ if test $rsync_cv_can_hardlink_special = yes; then
+@@ -637,6 +637,29 @@ if test $rsync_cv_can_hardlink_special = yes; then
AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
fi
enddit()
-@@ -603,6 +612,7 @@ use chroot = no
+@@ -607,6 +616,7 @@ use chroot = no
max connections = 4
syslog facility = local5
pid file = /var/run/rsyncd.pid
+ }
+
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
- char *temp_copy_name;
if (partialptr == fname)
+ partialptr = NULL;
diff --git a/rsync.h b/rsync.h
--- a/rsync.h
+++ b/rsync.h
+
struct idlist {
struct idlist *next;
- char *name;
+ const char *name;
@@ -48,8 +54,8 @@ struct idlist {
uint16 flags;
};
+static struct idlist *uidlist, *uidmap;
+static struct idlist *gidlist, *gidmap;
- static struct idlist *add_to_list(struct idlist **root, id_t id, char *name,
+ static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
id_t id2, uint16 flags)
-@@ -84,22 +90,6 @@ static char *gid_to_name(gid_t gid)
+@@ -84,22 +90,6 @@ static const char *gid_to_name(gid_t gid)
return NULL;
}
#define RSYNC_XAL_INITIAL 5
#define RSYNC_XAL_LIST_INITIAL 100
-@@ -241,7 +243,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
+@@ -242,7 +244,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
return -1;
/* For large datums, we store a flag and a checksum. */
name_offset = 1 + MAX_DIGEST_LEN;
sum_init(checksum_seed);
-@@ -305,7 +307,7 @@ static int find_matching_xattr(item_list *xalp)
+@@ -310,7 +312,7 @@ static int find_matching_xattr(item_list *xalp)
|| rxas1[j].datum_len != rxas2[j].datum_len
|| strcmp(rxas1[j].name, rxas2[j].name))
break;
if (memcmp(rxas1[j].datum + 1,
rxas2[j].datum + 1,
MAX_DIGEST_LEN) != 0)
-@@ -342,34 +344,43 @@ int send_xattr(stat_x *sxp, int f)
+@@ -347,34 +349,43 @@ int send_xattr(stat_x *sxp, int f)
{
int ndx = find_matching_xattr(sxp->xattr);
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
else
write_buf(f, rxa->datum, rxa->datum_len);
-@@ -419,7 +430,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
+@@ -424,7 +435,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
if (cmp > 0)
same = 0;
same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
&& memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
MAX_DIGEST_LEN) == 0;
-@@ -462,6 +473,9 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
- int j, cnt, prior_req = -1;
+@@ -467,6 +478,9 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
+ int cnt, prior_req = 0;
rsync_xa *rxa;
+ if (protocol_version < 30)
+ return;
+
lst += F_XATTR(file);
- cnt = lst->count;
- for (rxa = lst->items, j = 0; j < cnt; rxa++, j++) {
-@@ -536,6 +550,9 @@ int recv_xattr_request(struct file_struct *file, int f_in)
+ for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
+ if (rxa->datum_len <= MAX_FULL_DATUM)
+@@ -540,6 +554,9 @@ int recv_xattr_request(struct file_struct *file, int f_in)
rsync_xa *rxa;
- int rel_pos, cnt, got_xattr_data = 0;
+ int rel_pos, cnt, num, got_xattr_data = 0;
+ if (protocol_version < 30)
+ return 0;
if (F_XATTR(file) < 0) {
rprintf(FERROR, "recv_xattr_request: internal data error!\n");
exit_cleanup(RERR_STREAMIO);
-@@ -585,7 +602,22 @@ void receive_xattr(struct file_struct *file, int f)
+@@ -596,7 +613,22 @@ void receive_xattr(struct file_struct *file, int f)
{
static item_list temp_xattr = EMPTY_ITEM_LIST;
- int count;
+ int count, num;
- int ndx = read_varint(f);
+ int ndx;
+
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
rprintf(FERROR, "receive_xattr: xa index %d out of"
-@@ -598,7 +630,7 @@ void receive_xattr(struct file_struct *file, int f)
+@@ -609,7 +641,7 @@ void receive_xattr(struct file_struct *file, int f)
return;
}
(void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
temp_xattr.count = 0;
}
-@@ -606,9 +638,10 @@ void receive_xattr(struct file_struct *file, int f)
- while (count--) {
+@@ -617,9 +649,10 @@ void receive_xattr(struct file_struct *file, int f)
+ for (num = 1; num <= count; num++) {
char *ptr, *name;
rsync_xa *rxa;
- size_t name_len = read_varint(f);