Move iterpath into util from ed2k_util

This commit is contained in:
x3 2023-08-08 21:32:37 +02:00
parent b7619f4404
commit f1ed4b0944
Signed by: x3
GPG Key ID: 7E9961E8AD0E240E
5 changed files with 94 additions and 58 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 */ \

View File

@ -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;
}

View File

@ -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 */