--- /dev/null
+// $Id$ --*- c -*--
+
+// Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//
+// 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; version 2 of the License.
+//
+// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+static enum { mkdirFAIL, mkdirSUCCESS, mkdirSKIP }
+mkdirSingle(char const *path, char *end_ptr, int good_err)
+{
+ *end_ptr = '\0';
+ if (mkdir(path, 0700)!=-1 || errno==EEXIST) {
+ *end_ptr = '/';
+ return mkdirSUCCESS;
+ }
+ else if (errno==good_err) {
+ *end_ptr = '/';
+ return mkdirSKIP;
+ }
+ else
+ return mkdirFAIL;
+}
+
+static char *
+rstrchr(char *str, char c)
+{
+ while (*str!=c) --str;
+ return str;
+}
+
+bool
+mkdirRecursive(char const *path)
+{
+ char buf[strlen(path)+1];
+ char * ptr = buf + sizeof(buf) - 2;
+
+ if (path[0]!='/') return false; // only absolute paths
+
+ strcpy(buf, path);
+
+ while (ptr>buf && (ptr = rstrchr(ptr, '/'))!=0) {
+ switch (mkdirSingle(buf, ptr, ENOENT)) {
+ case mkdirSUCCESS : break;
+ case mkdirSKIP : --ptr; continue;
+ case mkdirFAIL : return false;
+ }
+
+ break; // implied by mkdirSUCCESS
+ }
+
+ assert(ptr!=0);
+ ++ptr;
+
+ while ((ptr=strchr(ptr, '/'))!=0) {
+ switch (mkdirSingle(buf, ptr, 0)) {
+ case mkdirSKIP :
+ case mkdirFAIL : return false;
+ case mkdirSUCCESS : ++ptr; continue;
+ }
+ }
+
+ return true;
+}
lib_internal/testsuite/isnumber \
lib_internal/testsuite/isnumber-gnu \
lib_internal/testsuite/sigbus \
- lib_internal/testsuite/sigbus-gnu
+ lib_internal/testsuite/sigbus-gnu \
+ lib_internal/testsuite/matchlist \
+ lib_internal/testsuite/matchlist-gnu
TESTS += lib_internal/testsuite/filecfg-ml \
lib_internal/testsuite/copy-check \
lib_internal/testsuite/isnumber \
lib_internal/testsuite/isnumber-gnu \
lib_internal/testsuite/sigbus \
- lib_internal/testsuite/sigbus-gnu
+ lib_internal/testsuite/sigbus-gnu \
+ lib_internal/testsuite/matchlist \
+ lib_internal/testsuite/matchlist-gnu
endif
DIETPROGS += lib_internal/testsuite/isnumber \
- lib_internal/testsuite/sigbus
+ lib_internal/testsuite/sigbus \
+ lib_internal/testsuite/matchlist
EXTRA_DIST += lib_internal/testsuite/copy-check
lib_internal_testsuite_sigbus_gnu_SOURCES = lib_internal/testsuite/sigbus.c
lib_internal_testsuite_sigbus_gnu_CPPFLAGS = $(AM_CPPFLAGS) # see note above
+
+lib_internal_testsuite_matchlist_SOURCES = lib_internal/testsuite/matchlist.c
+lib_internal_testsuite_matchlist_LDADD = $(LIBINTERNAL)
+lib_internal_testsuite_matchlist_CPPFLAGS = $(AM_CPPFLAGS) # see note above
+
+lib_internal_testsuite_matchlist_gnu_SOURCES = lib_internal/testsuite/matchlist.c
+lib_internal_testsuite_matchlist_gnu_LDADD = $(LIBINTERNAL_GLIBC)
+lib_internal_testsuite_matchlist_gnu_CPPFLAGS = $(AM_CPPFLAGS) # see note above
--- /dev/null
+// $Id$ --*- c -*--
+
+// Copyright (C) 2007 Daniel Hokka Zakrisson
+//
+// 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; version 2 of the License.
+//
+// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lib_internal/util.h>
+#include <lib_internal/matchlist.h>
+
+int wrapper_exit_code = 255;
+
+int main(int argc, char *argv[])
+{
+ struct MatchList list;
+ static const char *files[] = {
+ "/bin",
+ "+/bin/a",
+ };
+ int test = 0;
+ uint32_t result = 0;
+
+ MatchList_init(&list, "/", sizeof(files) / sizeof(*files));
+ MatchList_appendFiles(&list, 0, files, sizeof(files) / sizeof(*files), true);
+
+#define DO_TEST(x) switch (MatchList_compare(&list, x)) { \
+ case stINCLUDE: result |= 1 << test; break; \
+ case stEXCLUDE: result |= 2 << test; break; \
+ case stSKIP: result |= 4 << test; break; \
+ } \
+ test += 3;
+ DO_TEST("/bin");
+ list.skip_depth++;
+ DO_TEST("/bin/a");
+ DO_TEST("/bin/b");
+ list.skip_depth--;
+ DO_TEST("/sbin");
+ DO_TEST("/usr/lib/a");
+
+ MatchList_destroy(&list);
+
+ if (result == 011212)
+ return 0;
+ else {
+ char buf[(sizeof(result) * 8) / 3 + 2], *ptr;
+ ssize_t i;
+ WRITE_MSG(1, "result = ");
+ buf[sizeof(buf) - 1] = '\0';
+ for (i = 0, ptr = buf + sizeof(buf) - 2; i < (sizeof(result) * 8); i += 3, ptr--)
+ *ptr = '0' + ((result & (7 << i)) >> i);
+ WRITE_STR(1, buf);
+ WRITE_MSG(1, "\n");
+ return 1;
+ }
+}
#include "lib_internal/pathinfo.h"
#include "lib_internal/unify.h"
+#include "lib_internal/matchlist.h"
#include <unistd.h>
#include <getopt.h>
struct WalkdownInfo
{
- PathInfo state;
- PathInfo src;
- PathInfo dst;
+ PathInfo state;
+ PathInfo src;
+ PathInfo dst;
+ struct MatchList excludes;
};
struct Arguments {
unsigned int verbosity;
xid_t xid;
+ const char * exclude_list;
};
static struct WalkdownInfo global_info;
struct option const
CMDLINE_OPTIONS[] = {
- { "help", no_argument, 0, CMD_HELP },
- { "version", no_argument, 0, CMD_VERSION },
- { "xid", required_argument, 0, CMD_XID },
+ { "help", no_argument, 0, CMD_HELP },
+ { "version", no_argument, 0, CMD_VERSION },
+ { "xid", required_argument, 0, CMD_XID },
+ { "exclude-from", required_argument, 0, 'X' },
{ 0,0,0,0 }
};
WRITE_MSG(fd, "Usage:\n ");
WRITE_STR(fd, cmd);
WRITE_MSG(fd,
- " [--xid <xid>] <source> <absolute path to destination>\n\n"
+ " [--xid <xid>] [--exclude-from <exclude-list>]\n"
+ " <source> <absolute path to destination>\n\n"
"Please report bugs to " PACKAGE_BUGREPORT "\n");
exit(res);
}
#include "vserver-visitdir.hc"
+static bool
+handleDirEntry(const PathInfo *src_path, const PathInfo *basename,
+ bool *is_dir, struct stat *st)
+{
+ bool res = false;
+
+ *is_dir = false;
+
+ if (lstat(basename->d, st)==-1)
+ PERROR_Q(ENSC_WRAPPERS_PREFIX "lstat", src_path->d);
+ else {
+ PathInfo dst_path = global_info.dst;
+ char dst_path_buf[ENSC_PI_APPSZ(dst_path, *src_path)];
+
+ if (S_ISDIR(st->st_mode))
+ *is_dir = true;
+
+ if (MatchList_compare(&global_info.excludes, src_path->d) != stINCLUDE) {
+ if (Global_getVerbosity() > 1) {
+ WRITE_MSG(1, " skipping '");
+ Vwrite(1, src_path->d, src_path->l);
+ WRITE_MSG(1, "' (excluded)\n");
+ }
+ return false;
+ }
+
+ PathInfo_append(&dst_path, src_path, dst_path_buf);
+
+ /* skip files that already exist */
+ if (access(dst_path.d, F_OK)!=-1) {
+ if (Global_getVerbosity() > 1) {
+ WRITE_MSG(1, " skipping '");
+ Vwrite(1, src_path->d, src_path->l);
+ WRITE_MSG(1, "' (exists in destination)\n");
+ }
+ res = true;
+ }
+ else {
+ /* create directory that might have been skipped */
+ if (global_info.excludes.skip_depth > 0) {
+ if (Global_getVerbosity() > 4) {
+ WRITE_MSG(1, " creating directories for '");
+ Vwrite(1, dst_path.d, dst_path.l);
+ WRITE_MSG(1, "'\n");
+ }
+ if (mkdirRecursive(dst_path.d) == -1)
+ PERROR_Q(ENSC_WRAPPERS_PREFIX "mkdirRecursive", dst_path.d);
+ }
+
+ /* already unified file */
+ if (S_ISREG(st->st_mode) && Unify_isIUnlinkable(basename->d) == unifyBUSY) {
+ if (Global_getVerbosity() > 2) {
+ WRITE_MSG(1, " linking unified file '");
+ Vwrite(1, src_path->d, src_path->l);
+ WRITE_MSG(1, "'\n");
+ }
+ Elink(basename->d, dst_path.d);
+ res = true;
+ }
+ /* something we have to copy */
+ else {
+ if (Global_getVerbosity() > 2) {
+ WRITE_MSG(1, " copying non-unified file '");
+ Vwrite(1, src_path->d, src_path->l);
+ WRITE_MSG(1, "'\n");
+ }
+ if (!Unify_copy(basename->d, st, dst_path.d))
+ PERROR_Q(ENSC_WRAPPERS_PREFIX "Unify_copy", dst_path.d);
+ else if (global_args->xid != VC_NOCTX &&
+ vc_set_iattr(dst_path.d, global_args->xid, 0, VC_IATTR_XID) == -1)
+ PERROR_Q(ENSC_WRAPPERS_PREFIX "vc_set_iattr", dst_path.d);
+ else
+ res = true;
+ }
+ }
+ }
+
+ return res;
+}
+
+/* returns 1 on error, 0 on success */
static uint64_t
visitDirEntry(struct dirent const *ent)
{
};
char path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
struct stat f_stat = { .st_dev = 0 };
+ bool is_dir;
PathInfo_append(&src_path, &src_d_path, path_buf);
-
- if (lstat(dirname, &f_stat)==-1)
- perror(ENSC_WRAPPERS_PREFIX "lstat()");
- else {
- PathInfo dst_path = global_info.dst;
- char dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
-
- PathInfo_append(&dst_path, &src_path, dst_path_buf);
+ if (handleDirEntry(&src_path, &src_d_path, &is_dir, &f_stat))
+ res = 0;
- /* skip files that already exist */
- if (access(dst_path.d, F_OK)!=-1)
- res = 0;
- else if (S_ISREG(f_stat.st_mode) && Unify_isIUnlinkable(src_d_path.d) == unifyBUSY) {
- Elink(src_d_path.d, dst_path.d);
- res = 0;
- }
- else {
- if (!Unify_copy(src_d_path.d, &f_stat, dst_path.d))
- perror(ENSC_WRAPPERS_PREFIX "Unify_copy()");
- else if (vc_set_iattr(dst_path.d, global_args->xid, 0, VC_IATTR_XID) == -1)
- perror(ENSC_WRAPPERS_PREFIX "vc_set_iattr()");
- else
- res = 0;
- }
- if (S_ISDIR(f_stat.st_mode))
- res = visitDir(dirname, &f_stat);
+ if (is_dir) {
+ if (res || global_info.excludes.skip_depth > 0)
+ global_info.excludes.skip_depth++;
+ res = res + visitDir(dirname, &f_stat);
+ if (global_info.excludes.skip_depth > 0)
+ global_info.excludes.skip_depth--;
}
return res;
struct Arguments args = {
.verbosity = 0,
.xid = VC_NOCTX,
+ .exclude_list = NULL,
};
uint64_t res;
int num_args;
global_args = &args;
while (1) {
- int c = getopt_long(argc, argv, "+v",
+ int c = getopt_long(argc, argv, "+vX:",
CMDLINE_OPTIONS, 0);
if (c==-1) break;
case CMD_HELP : showHelp(1, argv[0], 0);
case CMD_VERSION : showVersion();
case 'v' : args.verbosity++; break;
+ case 'X' : args.exclude_list = optarg; break;
case CMD_XID : args.xid = Evc_xidopt2xid(optarg,true); break;
default :
WRITE_MSG(2, "Try '");
ENSC_PI_SETSTR(global_info.src, argv[optind]);
ENSC_PI_SETSTR(global_info.dst, argv[optind+1]);
+ if (global_args->exclude_list)
+ MatchList_initManually(&global_info.excludes, 0, strdup(argv[optind]),
+ global_args->exclude_list);
+ else
+ MatchList_init(&global_info.excludes, argv[optind], 0);
+
if (global_args->verbosity>3)
WRITE_MSG(1, "Starting to traverse directories...\n");
Echdir(global_info.src.d);
res = visitDir("/", 0);
+
+ MatchList_destroy(&global_info.excludes);
return res>0 ? 1 : 0;
}
return res;
}
-static enum { mkdirFAIL, mkdirSUCCESS, mkdirSKIP }
-mkdirSingle(char const *path, char *end_ptr, int good_err)
-{
- *end_ptr = '\0';
- if (mkdir(path, 0700)!=-1 || errno==EEXIST) {
- *end_ptr = '/';
- return mkdirSUCCESS;
- }
- else if (errno==good_err) {
- *end_ptr = '/';
- return mkdirSKIP;
- }
- else {
- int old_errno = errno;
- WRITE_MSG(2, "mkdir('");
- WRITE_STR(2, path);
- errno = old_errno;
- perror("')");
- return mkdirFAIL;
- }
-}
-
-static char *
-rstrchr(char *str, char c)
-{
- while (*str!=c) --str;
- return str;
-}
-
-static bool
-mkdirRecursive(char const *path)
-{
- if (path[0]!='/') return false; // only absolute paths
-
- char buf[strlen(path)+1];
- char * ptr = buf + sizeof(buf) - 2;
-
- strcpy(buf, path);
-
- while (ptr>buf && (ptr = rstrchr(ptr, '/'))!=0) {
- switch (mkdirSingle(buf, ptr, ENOENT)) {
- case mkdirSUCCESS : break;
- case mkdirSKIP : --ptr; continue;
- case mkdirFAIL : return false;
- }
-
- break; // implied by mkdirSUCCESS
- }
-
- assert(ptr!=0);
- ++ptr;
-
- while ((ptr=strchr(ptr, '/'))!=0) {
- switch (mkdirSingle(buf, ptr, 0)) {
- case mkdirSKIP :
- case mkdirFAIL : return false;
- case mkdirSUCCESS : ++ptr; continue;
- }
- }
-
- return true;
-}
-
static bool
resolveCollisions(char *result, PathInfo const *root, HashPath d_path,
struct stat *st, struct stat *hash_st)
if (!global_args->dry_run) {
*ptr = '\0';
- if (!mkdirRecursive(result))
+ if (!mkdirRecursive(result)) {
+ PERROR_Q("mkdir", result);
return false;
+ }
*ptr = '-';
int fd = open(result, O_NOFOLLOW|O_EXCL|O_CREAT|O_WRONLY, 0200);
if (fd==-1) {
- int old_errno = errno;
- WRITE_MSG(2, "open('");
- WRITE_STR(2, buf);
- errno = old_errno;
- perror("')");
+ PERROR_Q("open", buf);
return false;
}