@@ -53,9 +53,8 @@ enum error cmd_ed2k(void *data) | |||
opts.link = *link; | |||
for (int i = 0; i < fcount; i++) { | |||
err = ed2k_util_iterpath(config_get_nonopt(i), &ed2k_opts); | |||
if (err != NOERR) | |||
break; | |||
ed2k_util_iterpath(config_get_nonopt(i), &ed2k_opts); | |||
/* Above may fail if the path doesn't exists or smth, but still continue */ | |||
} | |||
return err; | |||
} | |||
@@ -2,28 +2,27 @@ | |||
#include <sys/stat.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <ftw.h> | |||
#include <assert.h> | |||
#include "util.h" | |||
#include "ed2k.h" | |||
#include "ed2k_util.h" | |||
#include "uio.h" | |||
#include "globals.h" | |||
static struct ed2k_util_opts l_opts; | |||
static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
const struct stat *st) | |||
static enum error ed2k_util_hash(const char *file_path, const struct stat *st, void *data) | |||
{ | |||
off_t blksize = st->st_blksize; | |||
unsigned char buf[blksize], hash[ED2K_HASH_SIZE]; | |||
struct ed2k_util_opts *opts = data; | |||
struct ed2k_ctx ed2k; | |||
enum error err; | |||
FILE *f; | |||
size_t read_len; | |||
int en; | |||
if (l_opts.pre_hash_fn) { | |||
err = l_opts.pre_hash_fn(file_path, st, l_opts.data); | |||
if (opts->pre_hash_fn) { | |||
err = opts->pre_hash_fn(file_path, st, opts->data); | |||
if (err == ED2KUTIL_DONTHASH) | |||
return NOERR; | |||
else if (err != NOERR) | |||
@@ -38,7 +37,7 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
if (en == EINTR && should_exit) | |||
return ERR_SHOULD_EXIT; | |||
else | |||
return ERR_ED2KUTIL_FS; | |||
return ERR_ITERPATH; | |||
} | |||
ed2k_init(&ed2k); | |||
@@ -54,7 +53,7 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
} | |||
if (ferror(f)) { /* Loop stopped bcuz of error, not EOF */ | |||
uio_error("Failure while reading file"); | |||
err = ERR_ED2KUTIL_FS; | |||
err = ERR_ITERPATH; | |||
goto fail; | |||
} | |||
assert(feof(f)); | |||
@@ -67,11 +66,11 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
if (en == EINTR && should_exit) | |||
return ERR_SHOULD_EXIT; | |||
else | |||
return ERR_ED2KUTIL_FS; | |||
return ERR_ITERPATH; | |||
} | |||
if (l_opts.post_hash_fn) | |||
return l_opts.post_hash_fn(file_path, hash, st, l_opts.data); | |||
if (opts->post_hash_fn) | |||
return opts->post_hash_fn(file_path, hash, st, opts->data); | |||
return NOERR; | |||
fail: | |||
@@ -80,46 +79,7 @@ fail: | |||
return err; | |||
} | |||
static int ed2k_util_walk(const char *fpath, const struct stat *sb, | |||
int typeflag, struct FTW *ftwbuf) | |||
{ | |||
if (typeflag == FTW_DNR) { | |||
uio_error("Cannot read directory '%s'. Skipping", fpath); | |||
return NOERR; | |||
} | |||
if (typeflag == FTW_D) | |||
return NOERR; | |||
if (typeflag != FTW_F) { | |||
uio_error("Unhandled error '%d'", typeflag); | |||
return ERR_ED2KUTIL_UNSUP; | |||
} | |||
return ed2k_util_hash(fpath, sb->st_blksize, sb); | |||
} | |||
enum error ed2k_util_iterpath(const char *path, const struct ed2k_util_opts *opts) | |||
{ | |||
struct stat ts; | |||
if (stat(path, &ts) != 0) { | |||
uio_error("Stat failed for path: '%s' (%s)", | |||
path, strerror(errno)); | |||
return ERR_ED2KUTIL_FS; | |||
} | |||
l_opts = *opts; | |||
if (S_ISREG(ts.st_mode)) { | |||
return ed2k_util_hash(path, ts.st_blksize, &ts); | |||
} else if (S_ISDIR(ts.st_mode)) { | |||
int ftwret = nftw(path, ed2k_util_walk, 20, 0); | |||
if (ftwret == -1) { | |||
uio_error("nftw failure"); | |||
return ERR_ED2KUTIL_FS; | |||
} | |||
return ftwret; | |||
} | |||
uio_error("Unsupported file type: %d", ts.st_mode & S_IFMT); | |||
return ERR_ED2KUTIL_UNSUP; | |||
return util_iterpath(path, ed2k_util_hash, (void*)opts); | |||
} |
@@ -25,8 +25,7 @@ | |||
E(ERR_CMD_NONE) /* No command was run */ \ | |||
E(ERR_CMD_ARG) /* Some problem with the command arguments */ \ | |||
\ | |||
E(ERR_ED2KUTIL_FS) /* Some filesystem problem */ \ | |||
E(ERR_ED2KUTIL_UNSUP) /* Operation or file type is unsupported */ \ | |||
E(ERR_ITERPATH) /* Couldn't start iterating over the given path */ \ | |||
E(ED2KUTIL_DONTHASH) /* Skip the hashing part. pre_hash_fn can return this */ \ | |||
\ | |||
E(ERR_API_ENCRYPTFAIL) /* Cannot start encryption with the api */ \ | |||
@@ -1,9 +1,15 @@ | |||
#define _XOPEN_SOURCE | |||
#define _XOPEN_SOURCE 500 | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <time.h> | |||
#include <assert.h> | |||
#include <errno.h> | |||
#include <sys/stat.h> | |||
#include <ftw.h> | |||
#include "util.h" | |||
#include "error.h" | |||
#include "uio.h" | |||
void util_byte2hex(const uint8_t* bytes, size_t bytes_len, | |||
bool uppercase, char* out) | |||
@@ -86,3 +92,62 @@ uint64_t util_iso2unix(const char *isotime) | |||
return mktime(&tm); | |||
} | |||
/* nftw doesn't support passing in user data to the callback function :/ */ | |||
static util_itercb global_iterpath_cb = NULL; | |||
static void *global_iterpath_data = NULL; | |||
static int util_iterpath_walk(const char *fpath, const struct stat *sb, | |||
int typeflag, struct FTW *ftwbuf) | |||
{ | |||
if (typeflag == FTW_DNR) { | |||
uio_error("Cannot read directory '%s'. Skipping", fpath); | |||
return NOERR; | |||
} | |||
if (typeflag == FTW_D) | |||
return NOERR; | |||
if (typeflag != FTW_F) { | |||
uio_error("Unhandled error '%d'", typeflag); | |||
return ERR_ITERPATH; | |||
} | |||
return global_iterpath_cb(fpath, sb, global_iterpath_data); | |||
} | |||
enum error util_iterpath(const char *path, util_itercb cb, void *data) | |||
{ | |||
assert(global_iterpath_cb == NULL); | |||
enum error ret = ERR_ITERPATH; | |||
struct stat ts; | |||
if (stat(path, &ts) != 0) { | |||
uio_error("Stat failed for path: '%s' (%s)", | |||
path, strerror(errno)); | |||
goto error; | |||
} | |||
if (S_ISREG(ts.st_mode)) { | |||
/* If the path is a regular file, call the cb once */ | |||
ret = cb(path, &ts, data); | |||
goto end; | |||
} else if (S_ISDIR(ts.st_mode)) { | |||
global_iterpath_cb = cb; | |||
global_iterpath_data = data; | |||
/* If a directory, walk over it */ | |||
ret = nftw(path, util_iterpath_walk, 20, 0); | |||
if (ret == -1) { | |||
uio_error("nftw failure"); | |||
goto error; | |||
} | |||
goto end; | |||
} | |||
uio_error("Unsupported file type: %d", ts.st_mode & S_IFMT); | |||
end: | |||
global_iterpath_cb = global_iterpath_data = NULL; | |||
return ret; | |||
error: | |||
ret = ERR_ITERPATH; | |||
goto end; | |||
} |
@@ -1,9 +1,13 @@ | |||
#ifndef _UTIL_H | |||
#define _UTIL_H | |||
#include <sys/stat.h> | |||
#include <time.h> | |||
#include <stdint.h> | |||
#include <stddef.h> | |||
#include <stdbool.h> | |||
#include "error.h" | |||
#define MS_TO_TIMESPEC(ts, ms) { \ | |||
ts->tv_sec = ms / 1000; \ | |||
ts->tv_nsec = (ms % 1000) * 1000000; \ | |||
@@ -50,4 +54,13 @@ uint64_t util_timespec_diff(const struct timespec *past, | |||
*/ | |||
uint64_t util_iso2unix(const char *isotime); | |||
/* | |||
* Iterate over a given path and call the 'cb' function for each file | |||
* If 'cb' returns anything other than NOERR, the iteration will stop and | |||
* that error will be returned. | |||
* !! THIS FUNCTION IS NOT THREAD SAFE !! | |||
*/ | |||
typedef enum error (*util_itercb)(const char *path, const struct stat *fstat, void *data); | |||
enum error util_iterpath(const char *path, util_itercb cb, void *data); | |||
#endif /* _UTIL_H */ |