更好的 `chowning` 未知 uid/gid 文件 `rsync`(包括 --exclude-from 文件)将被视为源文件
Better way of `chowning` unknown uid/gid of files `rsync` (including an --exclude-from file) would consider as source files
我正在尝试更改我的 rsync
命令在执行 rsync
命令之前将其视为源文件的文件的未知 uid 和 gid。
我的 rsync
命令包含一个排除文件。
我需要这样做的原因在我的问题 中有解释。
我试过这个find
命令:
find /cygdrive/f -uid 4294967295 -exec chown 544. '{}' + -o -gid 4294967295 -exec chown .197121 '{}' +
但是,它不处理排除文件。我的意思是,上面的 find
在整个 f 驱动器中搜索匹配未知 uid/gid 的文件,然后 chowns
它们。我的 rsync
查看驱动器 f 并复制除了排除文件中的文件之外的所有文件。我不想 chown
任何 rsync
不复制的 Win7 副文件。
例如,Win7 保护其某些 hidden/sys 文件的方法之一是将它们的 uid 和 gid 设置为 4294967295(例如 c:\pagefil.sys 和 c:\hiberfil.sys).我已经在 rsync
排除文件中排除了这两个文件,我想单独保留它们的 Win7 端 uid/gid。 find
命令会 chown
他们。
我还尝试解析一个 ls
列表,这可能有效,但速度非常慢。因为我只处理 Win7 文件,所以我认为 ls
适合解析。
在 chowning
脚本之前使用 ls
列表(或解析 find
输出)之前,是否有更好的方法来解决我的问题?
另一种更精确的方法,但对我来说速度慢且需要更困难的脚本,是解析 rsync --dry-run ...
列表以确定哪些项目需要 chowning
。
编辑 2015-12-13:不幸的是,rsync --dry-run ...
不会生成关于在干 运行 期间无法设置 UID/GID 的警告,因此该方法已失效。
但是,我找到了 rsync
的源代码,在我看来,修改它非常容易,这样 UID/GID 就可以设置为 UID,并且如果在会话期间发现错误的 UID/GID,则执行 rsync
命令的进程 运行 的 GID。
谁能给我总结一下在Win7电脑上编译rsync
源代码需要什么工具?
这里是来自源代码的rsync.c(搜索'impossible to set'):
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
const char *fnamecmp, int flags)
{
int updated = 0;
stat_x sx2;
int change_uid, change_gid;
mode_t new_mode = file->mode;
int inherit;
if (!sxp) {
if (dry_run)
return 1;
if (link_stat(fname, &sx2.st, 0) < 0) {
rsyserr(FERROR_XFER, errno, "stat %s failed",
full_fname(fname));
return 0;
}
init_stat_x(&sx2);
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;
}
if (daemon_chmod_modes && !S_ISLNK(new_mode))
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
get_acl(fname, sxp);
#endif
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
&& sxp->st.st_gid != (gid_t)F_GROUP(file);
#ifndef CAN_CHOWN_SYMLINK
if (S_ISLNK(sxp->st.st_mode)) {
;
} else
#endif
if (change_uid || change_gid) {
if (DEBUG_GTE(OWN, 1)) {
if (change_uid) {
rprintf(FINFO,
"set uid of %s from %u to %u\n",
fname, (unsigned)sxp->st.st_uid, F_OWNER(file));
}
if (change_gid) {
rprintf(FINFO,
"set gid of %s from %u to %u\n",
fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
}
}
if (am_root >= 0) {
uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid;
gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid;
if (do_lchown(fname, uid, gid) != 0) {
/* We shouldn't have attempted to change uid
* or gid unless have the privilege. */
rsyserr(FERROR_XFER, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname));
goto cleanup;
}
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1)
rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
/* A lchown had been done, so we need to re-stat if
* the destination had the setuid or setgid bits set
* (due to the side effect of the chown call). */
if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, &sxp->st,
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
}
}
updated = 1;
}
#ifdef SUPPORT_XATTRS
if (am_root < 0)
set_stat_xattr(fname, file, new_mode);
if (preserve_xattrs && fnamecmp)
set_xattr(fname, file, fnamecmp, sxp);
#endif
if (!preserve_times
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
if (ret < 0) {
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
else
file->flags |= FLAG_TIME_FAILED;
}
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
* will enable owner-writability using chmod, if necessary.
*
* If set_acl() changes permission bits in the process of setting
* an access ACL, it changes sxp->st.st_mode so we know whether we
* need to chmod(). */
if (preserve_acls && !S_ISLNK(new_mode)) {
if (set_acl(fname, file, sxp, new_mode) > 0)
updated = 1;
}
#endif
#ifdef HAVE_CHMOD
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
if (ret < 0) {
rsyserr(FERROR_XFER, errno,
"failed to set permissions on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
}
#endif
if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
if (updated)
rprintf(FCLIENT, "%s\n", fname);
else
rprintf(FCLIENT, "%s is uptodate\n", fname);
}
cleanup:
if (sxp == &sx2)
free_stat_x(&sx2);
return updated;
}
如果您的 Win7 计算机上有备用 space,请尝试以下操作:
rsync 将您想要的文件同步到同一台计算机上的临时位置。因为是同一台电脑所以UID/GID应该设置成功。
在副本中执行您的find/chown脚本来为all[=30=设置UID/GID ] 文件。
rsync 将副本返回到原始位置(小心!)文件的内容应该没有改变了,所以 rsync 应该做的唯一改变是设置 UID/GID.
确保使用 -aHAX
进行复制,并在覆盖任何内容之前进行干燥 运行!
我找到了两个解决基本问题的实用解决方案:
如果源环境和目标环境都使用 rsync 3.1.0 或更新版本,则有可用的新选项。在那种情况下,我可以将这些选项添加到我的 rsync 命令中:
--usermap=4294967295:544 --groupmap=4294967295:197121
感谢 Wayne Davison 指导我选择这些新选项!
如果您在目的地使用较旧的 rsync(就像我的 WD MyCloud 一样),您可以使用 cygwin 修改 rsync 源代码,如下所示。
确保你的 cygwin 安装了 gcc
gcc-core
perl
make
和 quilt
下载最新的 rsync
源 tar 文件
我将其解压缩到我的 ~ 目录中的一个文件夹中。
我下载了 Eclipse
作为 IDE 使用,但您可以使用 NotePad++
修改文件,如下所示:
在 main.c 文件中,我添加了一个信息行,您每次 运行 rsync 时都会看到该信息行,因此您知道您正在使用个人 rsync 版本。我确信还有一种适当的方法可以将版本号设置为我自己的版本号,但我会让别人评论如何做到这一点。 (我所有的行都以 /* dalek */ 结尾):
starttime = time(NULL);
our_uid = MY_UID();
our_gid = MY_GID();
rprintf(FINFO,"rsync 3.1.1 with edits started by uid: %u gid: %u\n", our_uid, our_gid ); /* dalek */
然后,在flist.c中添加我的 /* dalek */ 行如下:
if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
xflags |= XMIT_SAME_UID;
else {
uid = F_OWNER(file);
if (uid==4294967295){ /* dalek */
if (do_lchown(fname, our_uid, F_GROUP(file)) != 0) { /* dalek */
rprintf(FINFO, "COULD NOT CHANGE 4294967295 UID to %u on %s\n",our_uid,fname); /* dalek */
}else{ /* dalek */
uid=our_uid; /* dalek */
} /* dalek */
} /* dalek */
if (!numeric_ids) {
user_name = add_uid(uid);
if (inc_recurse && user_name)
xflags |= XMIT_USER_NAME_FOLLOWS;
}
}
if (!preserve_gid || ((gid_t)F_GROUP(file) == gid && *lastname))
xflags |= XMIT_SAME_GID;
else {
gid = F_GROUP(file);
if (gid==4294967295){ /* dalek */
if (do_lchown(fname, F_OWNER(file), our_gid) != 0) { /* dalek */
rprintf(FINFO, "COULD NOT CHANGE 4294967295 GID to %u on %s\n",our_gid,fname); /* dalek */
}else{ /* dalek */
gid=our_gid; /* dalek */
} /* dalek */
} /* dalek */
if (!numeric_ids) {
group_name = add_gid(gid);
if (inc_recurse && group_name)
xflags |= XMIT_GROUP_NAME_FOLLOWS;
}
}
然后在你最近添加的rsync源目录运行./configure.sh
然后运行make
然后运行make install
。这就对了!您应该在 .../usr/local/bin 中有一个新的 rsync.exe 文件,从现在开始只要您使用 rsync 就会 运行 因为 cygwin 将 .../usr/local/bin 放在 .. ./bin 在它使用的 PATH 中。原来的rsync还在.../bin。要使用原始文件,只需将修改后的 rsync.exe 移出 .../usr/local/bin.
我正在尝试更改我的 rsync
命令在执行 rsync
命令之前将其视为源文件的文件的未知 uid 和 gid。
我的 rsync
命令包含一个排除文件。
我需要这样做的原因在我的问题
我试过这个find
命令:
find /cygdrive/f -uid 4294967295 -exec chown 544. '{}' + -o -gid 4294967295 -exec chown .197121 '{}' +
但是,它不处理排除文件。我的意思是,上面的 find
在整个 f 驱动器中搜索匹配未知 uid/gid 的文件,然后 chowns
它们。我的 rsync
查看驱动器 f 并复制除了排除文件中的文件之外的所有文件。我不想 chown
任何 rsync
不复制的 Win7 副文件。
例如,Win7 保护其某些 hidden/sys 文件的方法之一是将它们的 uid 和 gid 设置为 4294967295(例如 c:\pagefil.sys 和 c:\hiberfil.sys).我已经在 rsync
排除文件中排除了这两个文件,我想单独保留它们的 Win7 端 uid/gid。 find
命令会 chown
他们。
我还尝试解析一个 ls
列表,这可能有效,但速度非常慢。因为我只处理 Win7 文件,所以我认为 ls
适合解析。
在 chowning
脚本之前使用 ls
列表(或解析 find
输出)之前,是否有更好的方法来解决我的问题?
另一种更精确的方法,但对我来说速度慢且需要更困难的脚本,是解析 rsync --dry-run ...
列表以确定哪些项目需要 chowning
。
编辑 2015-12-13:不幸的是,rsync --dry-run ...
不会生成关于在干 运行 期间无法设置 UID/GID 的警告,因此该方法已失效。
但是,我找到了 rsync
的源代码,在我看来,修改它非常容易,这样 UID/GID 就可以设置为 UID,并且如果在会话期间发现错误的 UID/GID,则执行 rsync
命令的进程 运行 的 GID。
谁能给我总结一下在Win7电脑上编译rsync
源代码需要什么工具?
这里是来自源代码的rsync.c(搜索'impossible to set'):
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
const char *fnamecmp, int flags)
{
int updated = 0;
stat_x sx2;
int change_uid, change_gid;
mode_t new_mode = file->mode;
int inherit;
if (!sxp) {
if (dry_run)
return 1;
if (link_stat(fname, &sx2.st, 0) < 0) {
rsyserr(FERROR_XFER, errno, "stat %s failed",
full_fname(fname));
return 0;
}
init_stat_x(&sx2);
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;
}
if (daemon_chmod_modes && !S_ISLNK(new_mode))
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
get_acl(fname, sxp);
#endif
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
&& sxp->st.st_gid != (gid_t)F_GROUP(file);
#ifndef CAN_CHOWN_SYMLINK
if (S_ISLNK(sxp->st.st_mode)) {
;
} else
#endif
if (change_uid || change_gid) {
if (DEBUG_GTE(OWN, 1)) {
if (change_uid) {
rprintf(FINFO,
"set uid of %s from %u to %u\n",
fname, (unsigned)sxp->st.st_uid, F_OWNER(file));
}
if (change_gid) {
rprintf(FINFO,
"set gid of %s from %u to %u\n",
fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
}
}
if (am_root >= 0) {
uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid;
gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid;
if (do_lchown(fname, uid, gid) != 0) {
/* We shouldn't have attempted to change uid
* or gid unless have the privilege. */
rsyserr(FERROR_XFER, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname));
goto cleanup;
}
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1)
rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
/* A lchown had been done, so we need to re-stat if
* the destination had the setuid or setgid bits set
* (due to the side effect of the chown call). */
if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, &sxp->st,
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
}
}
updated = 1;
}
#ifdef SUPPORT_XATTRS
if (am_root < 0)
set_stat_xattr(fname, file, new_mode);
if (preserve_xattrs && fnamecmp)
set_xattr(fname, file, fnamecmp, sxp);
#endif
if (!preserve_times
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
if (ret < 0) {
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
else
file->flags |= FLAG_TIME_FAILED;
}
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
* will enable owner-writability using chmod, if necessary.
*
* If set_acl() changes permission bits in the process of setting
* an access ACL, it changes sxp->st.st_mode so we know whether we
* need to chmod(). */
if (preserve_acls && !S_ISLNK(new_mode)) {
if (set_acl(fname, file, sxp, new_mode) > 0)
updated = 1;
}
#endif
#ifdef HAVE_CHMOD
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
if (ret < 0) {
rsyserr(FERROR_XFER, errno,
"failed to set permissions on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
}
#endif
if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
if (updated)
rprintf(FCLIENT, "%s\n", fname);
else
rprintf(FCLIENT, "%s is uptodate\n", fname);
}
cleanup:
if (sxp == &sx2)
free_stat_x(&sx2);
return updated;
}
如果您的 Win7 计算机上有备用 space,请尝试以下操作:
rsync 将您想要的文件同步到同一台计算机上的临时位置。因为是同一台电脑所以UID/GID应该设置成功。
在副本中执行您的find/chown脚本来为all[=30=设置UID/GID ] 文件。
rsync 将副本返回到原始位置(小心!)文件的内容应该没有改变了,所以 rsync 应该做的唯一改变是设置 UID/GID.
确保使用 -aHAX
进行复制,并在覆盖任何内容之前进行干燥 运行!
我找到了两个解决基本问题的实用解决方案:
如果源环境和目标环境都使用 rsync 3.1.0 或更新版本,则有可用的新选项。在那种情况下,我可以将这些选项添加到我的 rsync 命令中:
--usermap=4294967295:544 --groupmap=4294967295:197121
感谢 Wayne Davison 指导我选择这些新选项!
如果您在目的地使用较旧的 rsync(就像我的 WD MyCloud 一样),您可以使用 cygwin 修改 rsync 源代码,如下所示。
确保你的 cygwin 安装了
下载最新的gcc
gcc-core
perl
make
和quilt
rsync
源 tar 文件我将其解压缩到我的 ~ 目录中的一个文件夹中。
我下载了
Eclipse
作为 IDE 使用,但您可以使用NotePad++
修改文件,如下所示:在 main.c 文件中,我添加了一个信息行,您每次 运行 rsync 时都会看到该信息行,因此您知道您正在使用个人 rsync 版本。我确信还有一种适当的方法可以将版本号设置为我自己的版本号,但我会让别人评论如何做到这一点。 (我所有的行都以 /* dalek */ 结尾):
starttime = time(NULL); our_uid = MY_UID(); our_gid = MY_GID(); rprintf(FINFO,"rsync 3.1.1 with edits started by uid: %u gid: %u\n", our_uid, our_gid ); /* dalek */
然后,在flist.c中添加我的 /* dalek */ 行如下:
if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname)) xflags |= XMIT_SAME_UID; else { uid = F_OWNER(file); if (uid==4294967295){ /* dalek */ if (do_lchown(fname, our_uid, F_GROUP(file)) != 0) { /* dalek */ rprintf(FINFO, "COULD NOT CHANGE 4294967295 UID to %u on %s\n",our_uid,fname); /* dalek */ }else{ /* dalek */ uid=our_uid; /* dalek */ } /* dalek */ } /* dalek */ if (!numeric_ids) { user_name = add_uid(uid); if (inc_recurse && user_name) xflags |= XMIT_USER_NAME_FOLLOWS; } } if (!preserve_gid || ((gid_t)F_GROUP(file) == gid && *lastname)) xflags |= XMIT_SAME_GID; else { gid = F_GROUP(file); if (gid==4294967295){ /* dalek */ if (do_lchown(fname, F_OWNER(file), our_gid) != 0) { /* dalek */ rprintf(FINFO, "COULD NOT CHANGE 4294967295 GID to %u on %s\n",our_gid,fname); /* dalek */ }else{ /* dalek */ gid=our_gid; /* dalek */ } /* dalek */ } /* dalek */ if (!numeric_ids) { group_name = add_gid(gid); if (inc_recurse && group_name) xflags |= XMIT_GROUP_NAME_FOLLOWS; } }
然后在你最近添加的rsync源目录运行
./configure.sh
然后运行make
然后运行make install
。这就对了!您应该在 .../usr/local/bin 中有一个新的 rsync.exe 文件,从现在开始只要您使用 rsync 就会 运行 因为 cygwin 将 .../usr/local/bin 放在 .. ./bin 在它使用的 PATH 中。原来的rsync还在.../bin。要使用原始文件,只需将修改后的 rsync.exe 移出 .../usr/local/bin.