#define ENSC_WRAPPERS_UNISTD 1
#define ENSC_WRAPPERS_FCNTL 1
#define ENSC_WRAPPERS_DIRENT 1
+#define ENSC_WRAPPERS_IO 1
#include <wrappers.h>
#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'
{ 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;
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() {
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
for (size_t in=0;
out+1<sizeof(HashPath)-(sizeof(unsigned int)*2 + 2) && in<d_size;
++in) {
- if (in%2 == 0 && in>0) 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)
{
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 ||
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(<hash>)");
+ 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;
}
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;
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) {
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);
{
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) {
(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");
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",
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");
freeHashList(&global_info.hash_dirs);
hashFunctionContextFree(&global_info.hash_context);
#endif
+
+ return EXIT_SUCCESS;
}