X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=util-vserver%2Fsrc%2Fvhashify.c;h=5e37887753fee0cfc73382c0e88eaa80bd47d54a;hb=5b39edfee423f5f3cbe8fa223dcfdc9e8d66e286;hp=2774631618e69281f204019097b875d4a40209b1;hpb=a2a43f198d74492b597315f83ba77b14b769eb45;p=util-vserver.git diff --git a/util-vserver/src/vhashify.c b/util-vserver/src/vhashify.c index 2774631..5e37887 100644 --- a/util-vserver/src/vhashify.c +++ b/util-vserver/src/vhashify.c @@ -48,11 +48,14 @@ #define ENSC_WRAPPERS_UNISTD 1 #define ENSC_WRAPPERS_FCNTL 1 #define ENSC_WRAPPERS_DIRENT 1 +#define ENSC_WRAPPERS_IO 1 #include #define HASH_BLOCKSIZE 0x10000000u #define HASH_MINSIZE 0x10 +#define HASH_MAXBITS 256 // we have to take care about + // max filename-length... #if HASH_MINSIZE<=0 # error HASH_MINSIZE must be not '0' @@ -82,13 +85,23 @@ CMDLINE_OPTIONS[] = { { 0,0,0,0 } }; - // SHA1, grouped by 4 digits + hash-collision counter + 2* '/' + NULL -typedef char HashPath[160/4 + (160/4/4) + sizeof(unsigned int)*2 + 3]; + // hash digest grouped by 2 digits + hash-collision counter + 2* '/' + NULL +typedef char HashPath[HASH_MAXBITS/4 + (HASH_MAXBITS/4/2) + + sizeof(unsigned int)*2 + 3]; + +struct HashDirConfiguration +{ + hashFunction const *method; + enum { hshALL=0, hshSTART = 1, hshMIDDLE=2, + hshEND = 4, hshINVALID = -1 } blocks; + size_t blocksize; +}; struct WalkdownInfo { PathInfo state; struct MatchList dst_list; + struct HashDirConfiguration hash_conf; HashDirCollection hash_dirs; size_t hash_dirs_max_size; @@ -97,9 +110,14 @@ struct WalkdownInfo int wrapper_exit_code = 1; struct Arguments const *global_args; -struct WalkdownInfo global_info; static struct SkipReason skip_reason; +struct WalkdownInfo global_info = { + .hash_conf = { .method = 0, + .blocks = hshALL, + .blocksize = 0x10000 } +}; + #include "vhashify-init.hc" int Global_getVerbosity() { @@ -215,14 +233,14 @@ checkFstat(PathInfo const * const basename, return true; } -static jmp_buf bus_error_restore; +static sigjmp_buf bus_error_restore; static volatile sig_atomic_t bus_error; static void handlerSIGBUS(int UNUSED num) { bus_error = 1; - longjmp(bus_error_restore, 1); + siglongjmp(bus_error_restore, 1); } static bool @@ -241,15 +259,17 @@ convertDigest(HashPath d_path) for (size_t in=0; out+10) d_path[out++]='/'; - d_path[out++] = HEX_DIGIT[digest[in] >> 4]; - d_path[out++] = HEX_DIGIT[digest[in] & 0x0f]; + if ((in+254)%(in<=2 ? 1 : 256) == 0 && in>0) + d_path[out++]='/'; + d_path[out++] = HEX_DIGIT[digest[in] >> 4]; + d_path[out++] = HEX_DIGIT[digest[in] & 0x0f]; } d_path[out++] = '\0'; return true; } +#ifndef ENSC_TESTSUITE static bool addStatHash(hashFunctionContext *h_ctx, struct stat const * const st) { @@ -272,18 +292,27 @@ addStatHash(hashFunctionContext *h_ctx, struct stat const * const st) SET_ATTR(mtime) }; +#undef SET_ATTR +#undef DECL_ATTR + + return hashFunctionContextUpdate(h_ctx, (void *)&tmp, sizeof tmp)!=-1; } - +#else +static bool +addStatHash(hashFunctionContext UNUSED *h_ctx, struct stat const UNUSED * const st) +{ + return true; +} +#endif + static bool calculateHashFromFD(int fd, HashPath d_path, struct stat const * const st) { hashFunctionContext * const h_ctx = &global_info.hash_context; - bool res = false; - loff_t offset = 0; - void *buf = 0; - off_t size = st->st_size; - loff_t cur_size = 0; + void const * volatile buf = 0; + loff_t volatile buf_size = 0; + bool volatile res = false; if (hashFunctionContextReset(h_ctx)==-1 || @@ -291,30 +320,33 @@ calculateHashFromFD(int fd, HashPath d_path, struct stat const * const st) return false; bus_error = 0; - if (setjmp(bus_error_restore)!=0) goto out; + if (sigsetjmp(bus_error_restore,1)==0) { + loff_t offset = 0; + off_t size = st->st_size; - while (offset < size) { - cur_size = size-offset; - if (cur_size>HASH_BLOCKSIZE) cur_size = HASH_BLOCKSIZE; + while (offset < size) { + buf_size = size-offset; + if (buf_size>HASH_BLOCKSIZE) buf_size = HASH_BLOCKSIZE; - buf = mmap(0, cur_size, PROT_READ, MAP_SHARED, fd, offset); - if (buf==0) goto out; - - offset += cur_size; - madvise(buf, cur_size, MADV_SEQUENTIAL); // ignore error... + if ((buf=mmap(0, buf_size, PROT_READ, MAP_SHARED, fd, offset))==0) { + perror("mmap()"); + goto out; + } - if (hashFunctionContextUpdate(h_ctx, buf, cur_size)==-1) goto out; + offset += buf_size; + madvise(const_cast(void *)(buf), buf_size, MADV_SEQUENTIAL); // ignore error... - munmap(buf, cur_size); - buf = 0; - } + if (hashFunctionContextUpdate(h_ctx, buf, buf_size)==-1) goto out; - if (!convertDigest(d_path)) goto out; - - res = true; + munmap(const_cast(void *)(buf), buf_size); + buf = 0; + } + + res = convertDigest(d_path); + } out: - if (buf!=0) munmap(buf, cur_size); + if (buf!=0) munmap(const_cast(void *)(buf), buf_size); return res; } @@ -357,31 +389,64 @@ calculateHash(PathInfo const *filename, HashPath d_path, struct stat const * con 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) { - struct stat st; - - if (path[0]!='/') return false; // only absolute paths - if (lstat(path,&st)!=-1) return true; + if (path[0]!='/') return false; // only absolute paths char buf[strlen(path)+1]; - char * ptr = buf+1; - + char * ptr = buf + sizeof(buf) - 2; + strcpy(buf, path); - while ((ptr = strchr(ptr, '/'))!=0) { - *ptr = '\0'; - if (mkdir(buf, 0700)==-1 && errno!=EEXIST) { - int old_errno = errno; - WRITE_MSG(2, "mkdir('"); - WRITE_STR(2, buf); - errno = old_errno; - perror("')"); - return false; + 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; } - *ptr = '/'; - ++ptr; } return true; @@ -399,18 +464,13 @@ resolveCollisions(char *result, PathInfo const *root, HashPath d_path, char buf[sizeof(int)*2 + 1]; size_t len; - *ptr++ = '/'; - *ptr = '\0'; - ptr[sizeof(int)*2] = '\0'; - - if (!global_args->dry_run && - !mkdirRecursive(result)) - return false; + *ptr = '-'; + ptr[sizeof(int)*2+1] = '\0'; for (;; ++idx) { len = utilvserver_fmt_xuint(buf, idx); - memset(ptr, '0', sizeof(int)*2 - len); - memcpy(ptr + sizeof(int)*2 - len, buf, len); + memset(ptr+1, '0', sizeof(int)*2 - len); + memcpy(ptr+1 + sizeof(int)*2 - len, buf, len); if (lstat(result, hash_st)==-1) { if (global_args->dry_run && errno!=ENOENT) { @@ -432,9 +492,14 @@ resolveCollisions(char *result, PathInfo const *root, HashPath d_path, break; // ok, we finish here if (!global_args->dry_run) { + *ptr = '\0'; + if (!mkdirRecursive(result)) + return false; + *ptr = '-'; + int fd = open(result, O_NOFOLLOW|O_EXCL|O_CREAT|O_WRONLY, 0200); - if (global_args->dry_run && fd==-1) { + if (fd==-1) { int old_errno = errno; WRITE_MSG(2, "open('"); WRITE_STR(2, buf); @@ -516,7 +581,7 @@ doit(char const *src, char const *dst, { if (global_args->dry_run || Global_getVerbosity()>=2) { WRITE_MSG(1, "unifying '"); - (void)write(1, path->d, path->l); + Vwrite(1, path->d, path->l); WRITE_MSG(1, "'"); if (Global_getVerbosity()>=4) { @@ -591,7 +656,7 @@ visitDirEntry(struct dirent const *ent) (Global_getVerbosity()>=6 && is_dotfile) || (Global_getVerbosity()>=6 && is_link)) ) { WRITE_MSG(1, " skipping '"); - write(1, path.d, path.l); + Vwrite(1, path.d, path.l); WRITE_MSG(1, "'"); if (Global_getVerbosity()>=2) printSkipReason(); WRITE_MSG(1, "\n"); @@ -627,11 +692,6 @@ int main(int argc, char *argv[]) Vector_init(&global_info.hash_dirs, sizeof(struct HashDirInfo)); - if (hashFunctionContextInit(&global_info.hash_context, - hashFunctionDefault())==-1) - return EXIT_FAILURE; - - global_args = &args; while (1) { int c = getopt_long(argc, argv, "+nv", @@ -673,6 +733,12 @@ int main(int argc, char *argv[]) default : assert(false); return EXIT_FAILURE; }; + if (hashFunctionContextInit(&global_info.hash_context, + global_info.hash_conf.method)==-1) { + WRITE_MSG(2, "Failed to initialize hash-context\n"); + return EXIT_FAILURE; + } + if (Global_getVerbosity()>=1) WRITE_MSG(1, "Starting to traverse directories...\n"); @@ -686,4 +752,6 @@ int main(int argc, char *argv[]) freeHashList(&global_info.hash_dirs); hashFunctionContextFree(&global_info.hash_context); #endif + + return EXIT_SUCCESS; }