@@ -53,9 +53,8 @@ enum error cmd_ed2k(void *data) | |||||
opts.link = *link; | opts.link = *link; | ||||
for (int i = 0; i < fcount; i++) { | 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; | return err; | ||||
} | } | ||||
@@ -2,28 +2,27 @@ | |||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <ftw.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include "util.h" | |||||
#include "ed2k.h" | #include "ed2k.h" | ||||
#include "ed2k_util.h" | #include "ed2k_util.h" | ||||
#include "uio.h" | #include "uio.h" | ||||
#include "globals.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]; | unsigned char buf[blksize], hash[ED2K_HASH_SIZE]; | ||||
struct ed2k_util_opts *opts = data; | |||||
struct ed2k_ctx ed2k; | struct ed2k_ctx ed2k; | ||||
enum error err; | enum error err; | ||||
FILE *f; | FILE *f; | ||||
size_t read_len; | size_t read_len; | ||||
int en; | 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) | if (err == ED2KUTIL_DONTHASH) | ||||
return NOERR; | return NOERR; | ||||
else if (err != 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) | if (en == EINTR && should_exit) | ||||
return ERR_SHOULD_EXIT; | return ERR_SHOULD_EXIT; | ||||
else | else | ||||
return ERR_ED2KUTIL_FS; | |||||
return ERR_ITERPATH; | |||||
} | } | ||||
ed2k_init(&ed2k); | 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 */ | if (ferror(f)) { /* Loop stopped bcuz of error, not EOF */ | ||||
uio_error("Failure while reading file"); | uio_error("Failure while reading file"); | ||||
err = ERR_ED2KUTIL_FS; | |||||
err = ERR_ITERPATH; | |||||
goto fail; | goto fail; | ||||
} | } | ||||
assert(feof(f)); | 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) | if (en == EINTR && should_exit) | ||||
return ERR_SHOULD_EXIT; | return ERR_SHOULD_EXIT; | ||||
else | 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; | return NOERR; | ||||
fail: | fail: | ||||
@@ -80,46 +79,7 @@ fail: | |||||
return err; | 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) | 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_NONE) /* No command was run */ \ | ||||
E(ERR_CMD_ARG) /* Some problem with the command arguments */ \ | 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(ED2KUTIL_DONTHASH) /* Skip the hashing part. pre_hash_fn can return this */ \ | ||||
\ | \ | ||||
E(ERR_API_ENCRYPTFAIL) /* Cannot start encryption with the api */ \ | 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 <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <assert.h> | |||||
#include <errno.h> | |||||
#include <sys/stat.h> | |||||
#include <ftw.h> | |||||
#include "util.h" | #include "util.h" | ||||
#include "error.h" | |||||
#include "uio.h" | |||||
void util_byte2hex(const uint8_t* bytes, size_t bytes_len, | void util_byte2hex(const uint8_t* bytes, size_t bytes_len, | ||||
bool uppercase, char* out) | bool uppercase, char* out) | ||||
@@ -86,3 +92,62 @@ uint64_t util_iso2unix(const char *isotime) | |||||
return mktime(&tm); | 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 | #ifndef _UTIL_H | ||||
#define _UTIL_H | #define _UTIL_H | ||||
#include <sys/stat.h> | |||||
#include <time.h> | |||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stddef.h> | #include <stddef.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include "error.h" | |||||
#define MS_TO_TIMESPEC(ts, ms) { \ | #define MS_TO_TIMESPEC(ts, ms) { \ | ||||
ts->tv_sec = ms / 1000; \ | ts->tv_sec = ms / 1000; \ | ||||
ts->tv_nsec = (ms % 1000) * 1000000; \ | 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); | 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 */ | #endif /* _UTIL_H */ |