X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/6755a7d7426dcc9b887f80f066021dbacffc7b10..13710874ce907cd9405f83814cbebbe73f884e2e:/rsync.c diff --git a/rsync.c b/rsync.c index 1ae33684..731528fe 100644 --- a/rsync.c +++ b/rsync.c @@ -6,8 +6,9 @@ * Copyright (C) 2003-2007 Wayne Davison * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 @@ -19,6 +20,7 @@ */ #include "rsync.h" +#include "ifuncs.h" #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET #include #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO @@ -32,7 +34,6 @@ extern int preserve_xattrs; extern int preserve_perms; extern int preserve_executability; extern int preserve_times; -extern int omit_dir_times; extern int am_root; extern int am_server; extern int am_sender; @@ -55,29 +56,28 @@ extern char *iconv_opt; #ifdef ICONV_CONST iconv_t ic_chck = (iconv_t)-1; -#ifdef ICONV_OPTION +# ifdef ICONV_OPTION iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1; -int ic_ndx; -#endif +# endif static const char *default_charset(void) { -#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET +# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET return locale_charset(); -#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO +# elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO return nl_langinfo(CODESET); -#else +# else return ""; /* Works with (at the very least) gnu iconv... */ -#endif +# endif } -void setup_iconv() +void setup_iconv(void) { const char *defset = default_charset(); # ifdef ICONV_OPTION const char *charset; char *cp; -#endif +# endif if (!am_server && !allow_8bit_chars) { @@ -126,9 +126,6 @@ void setup_iconv() exit_cleanup(RERR_UNSUPPORTED); } - if (!am_sender || inc_recurse) - ic_ndx = ++file_extra_cnt; - if (verbose > 1) { rprintf(FINFO, "%s charset: %s\n", am_server ? "server" : "client", @@ -136,6 +133,79 @@ void setup_iconv() } # endif } + +# ifdef ICONV_OPTION + +/* This function converts the characters in the "in" xbuf into characters + * in the "out" xbuf. The "len" of the "in" xbuf is used starting from its + * "pos". The "size" of the "out" xbuf restricts how many characters can be + * stored, starting at its "pos+len" position. Note that the last byte of + * the buffer is never used, which reserves space for a terminating '\0'. + * We return a 0 on success or a -1 on error. An error also sets errno to + * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0. + * The "in" xbuf is altered to update "pos" and "len". The "out" xbuf has + * data appended, and its "len" incremented. If ICB_EXPAND_OUT is set in + * "flags", the "out" xbuf will also be allocated if empty, and expanded if + * too small (so E2BIG will not be returned). If ICB_INCLUDE_BAD is set in + * "flags", any badly-encoded chars are included verbatim in the "out" xbuf, + * so EILSEQ will not be returned. Likewise for ICB_INCLUDE_INCOMPLETE with + * respect to an incomplete multi-byte char at the end, which ensures that + * EINVAL is not returned. Anytime "in.pos" is 0 we will reset the iconv() + * state prior to processing the characters. */ +int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) +{ + ICONV_CONST char *ibuf; + size_t icnt, ocnt; + char *obuf; + + if (!out->size && flags & ICB_EXPAND_OUT) + alloc_xbuf(out, 1024); + + if (!in->pos) + iconv(ic, NULL, 0, NULL, 0); + + ibuf = in->buf + in->pos; + icnt = in->len; + + obuf = out->buf + (out->pos + out->len); + ocnt = out->size - (out->pos + out->len) - 1; + + while (icnt) { + while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) { + if (errno == EINTR) + continue; + if (errno == EINVAL) { + if (!(flags & ICB_INCLUDE_INCOMPLETE)) + goto finish; + } else if (errno == EILSEQ) { + if (!(flags & ICB_INCLUDE_BAD)) + goto finish; + } else { + size_t opos = obuf - out->buf; + if (!(flags & ICB_EXPAND_OUT)) { + errno = E2BIG; + goto finish; + } + realloc_xbuf(out, out->size + 1024); + obuf = out->buf + opos; + ocnt += 1024; + continue; + } + *obuf++ = *ibuf++; + ocnt--, icnt--; + } + } + + errno = 0; + + finish: + in->len = icnt; + in->pos = ibuf - in->buf; + out->len = obuf - out->buf - out->pos; + + return errno ? -1 : 0; +} +# endif #endif int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, @@ -267,13 +337,14 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, return new_mode; } -int set_file_attrs(const char *fname, struct file_struct *file, statx *sxp, +int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags) { int updated = 0; - statx sx2; + stat_x sx2; int change_uid, change_gid; mode_t new_mode = file->mode; + int inherit; if (!sxp) { if (dry_run) @@ -289,13 +360,15 @@ int set_file_attrs(const char *fname, struct file_struct *file, statx *sxp, #ifdef SUPPORT_XATTRS sx2.xattr = NULL; #endif - if (!preserve_perms && S_ISDIR(new_mode) - && sx2.st.st_mode & S_ISGID) { - /* We just created this directory and its setgid - * bit is on, so make sure it stays on. */ - new_mode |= S_ISGID; - } sxp = &sx2; + inherit = !preserve_perms; + } else + inherit = !preserve_perms && file->flags & FLAG_DIR_CREATED; + + if (inherit && S_ISDIR(new_mode) && sxp->st.st_mode & S_ISGID) { + /* We just created this directory and its setgid + * bit is on, so make sure it stays on. */ + new_mode |= S_ISGID; } #ifdef SUPPORT_ACLS @@ -310,7 +383,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, statx *sxp, set_stat_xattr(fname, file); #endif - if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times)) + if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && preserve_times == 1)) flags |= ATTRS_SKIP_MTIME; if (!(flags & ATTRS_SKIP_MTIME) && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {