X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fvclone.c;h=458a0ba0dbfc7e7622fd621bd77844047781c416;hb=4415d2a7377be61789eb5a6e35222962cbe7a146;hp=f4a994bcb72fd52f08cd2ff929d5e494b6ab1b46;hpb=b0a62d195efca12c5cb9e7c0b3bea3be2cd57fc9;p=util-vserver.git diff --git a/src/vclone.c b/src/vclone.c index f4a994b..458a0ba 100644 --- a/src/vclone.c +++ b/src/vclone.c @@ -1,4 +1,4 @@ -// $Id: vclone.c 2494 2007-02-11 00:45:04Z dhozac $ --*- c -*-- +// $Id: vclone.c 2569 2007-07-22 17:24:29Z dhozac $ --*- c -*-- // Copyright (C) 2007 Daniel Hokka Zakrisson // @@ -25,6 +25,7 @@ #include "lib_internal/pathinfo.h" #include "lib_internal/unify.h" +#include "lib_internal/matchlist.h" #include #include @@ -40,20 +41,25 @@ #define ENSC_WRAPPERS_UNISTD 1 #define ENSC_WRAPPERS_FCNTL 1 #define ENSC_WRAPPERS_DIRENT 1 +#define ENSC_WRAPPERS_VSERVER 1 #include #define CMD_HELP 0x8000 #define CMD_VERSION 0x8001 +#define CMD_XID 0x8002 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; @@ -63,8 +69,10 @@ int wrapper_exit_code = 1; struct option const CMDLINE_OPTIONS[] = { - { "help", no_argument, 0, CMD_HELP }, - { "version", no_argument, 0, CMD_VERSION }, + { "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 } }; @@ -77,7 +85,8 @@ showHelp(int fd, char const *cmd, int res) WRITE_MSG(fd, "Usage:\n "); WRITE_STR(fd, cmd); WRITE_MSG(fd, - " \n\n" + " [--xid ] [--exclude-from ]\n" + " \n\n" "Please report bugs to " PACKAGE_BUGREPORT "\n"); exit(res); } @@ -103,6 +112,87 @@ bool Global_doRenew() { #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) { @@ -117,34 +207,19 @@ 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()"); - exit(wrapper_exit_code); - } - 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; @@ -154,19 +229,24 @@ int main(int argc, char *argv[]) { 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, "+", + int c = getopt_long(argc, argv, "+vX:", CMDLINE_OPTIONS, 0); if (c==-1) break; switch (c) { 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 '"); WRITE_STR(2, argv[0]); @@ -204,11 +284,19 @@ int main(int argc, char *argv[]) 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; }