Commit 29f496d2 authored by Aleksey Kravchenko's avatar Aleksey Kravchenko

Imported Upstream version 1.3.0

parent d653946c
Tue Jun 11 2013 Aleksey
* === Version 1.3.0 ===
Tue May 21 2013 Aleksey
* Fixed output of percents when two or more files are hashed
Mon Apr 29 2013 Aleksey
* Supported SHA3 (Keccak) hash function
Sat Apr 27 2013 Aleksey
* Fixed memory leaks
Tue Apr 23 2013 Aleksey
* Bugfix: %{mtime} formating option was broken
Mon Dec 31 2012 Aleksey
* imported translations from Launchpad: de, es, gl, it
Tue Dec 25 2012 Aleksey
* === Version 1.2.10 ===
......
......@@ -2,7 +2,7 @@
# compile with debug info: make CFLAGS=-g
# compile for pentiumpro: make CFLAGS="-O2 -DNDEBUG -march=i586 -mcpu=pentiumpro -fomit-frame-pointer"
# create rpm with statically linked program: make rpm ADDLDFLAGS="-static -s -Wl,--gc-sections"
VERSION = 1.2.10
VERSION = 1.3.0
PREFIX = /usr/local
CC = gcc
# using OPTFLAGS/OPTLDFLAGS for compatibilty with old scripts using this makefile
......@@ -40,13 +40,14 @@ LIBRHASH_FILES = librhash/algorithms.c librhash/algorithms.h \
librhash/aich.c librhash/aich.h librhash/crc32.c librhash/crc32.h \
librhash/ed2k.c librhash/ed2k.h librhash/edonr.c librhash/edonr.h \
librhash/gost.c librhash/gost.h librhash/has160.c librhash/has160.h \
librhash/hex.c librhash/hex.h librhash/md4.c librhash/md4.h librhash/md5.c librhash/md5.h \
librhash/ripemd-160.c librhash/ripemd-160.h librhash/sha1.c librhash/sha1.h \
librhash/hex.c librhash/hex.h librhash/md4.c librhash/md4.h \
librhash/md5.c librhash/md5.h librhash/ripemd-160.c librhash/ripemd-160.h \
librhash/sha1.c librhash/sha1.h librhash/sha3.c librhash/sha3.h \
librhash/sha256.c librhash/sha256.h librhash/sha512.c librhash/sha512.h \
librhash/snefru.c librhash/snefru.h librhash/tiger.c librhash/tiger.h \
librhash/tiger_sbox.c librhash/tth.c librhash/tth.h librhash/whirlpool.c \
librhash/whirlpool.h librhash/whirlpool_sbox.c librhash/test_hashes.c \
librhash/test_hashes.h librhash/torrent.h librhash/torrent.c \
librhash/test_hashes.h librhash/torrent.h librhash/torrent.c librhash/ustd.h \
librhash/util.c librhash/util.h librhash/config.h librhash/Makefile
I18N_FILES = po/de.po po/en_AU.po po/es.po po/gl.po po/it.po po/ru.po
DIST_FILES = $(LIN_DIST_FILES) $(LIBRHASH_FILES) $(WIN_DIST_FILES) $(WIN_SRC_FILES) $(I18N_FILES)
......@@ -127,13 +128,16 @@ $(SHAREDLIB):
$(LIBRHASH): $(LIBRHASH_FILES)
+make -C librhash lib-static
test-lib: $(LIBRHASH)
test-static-lib: $(LIBRHASH)
+make -C librhash test-static
test-shared-lib: $(SHAREDLIB)
+make -C librhash test-shared
test: test-static test-lib
test-libs: $(LIBRHASH) $(SHAREDLIB)
+make -C librhash test-static test-shared
test: test-static
test-static: $(TARGET)
chmod +x tests/test_$(PROGNAME).sh
tests/test_$(PROGNAME).sh
......@@ -145,13 +149,12 @@ test-shared: $(SHARED_TRG) test-shared-lib
version.h: Makefile
echo "#define VERSION \"$(VERSION)\"" > version.h
bindings/version.properties: Makefile
echo "version=$(VERSION)" > bindings/version.properties
# check version
check: version.h bindings/version.properties
check: version.h
grep -q '\* === Version $(VERSION) ===' ChangeLog
grep -q '^#define VERSION "$(VERSION)"' version.h
[ ! -d bindings -o bindings/version.properties -nt Makefile ] || \
echo "version=$(VERSION)" > bindings/version.properties
[ -s dist/rhash.1.html ]
$(TARGET): $(OBJECTS) $(LIBRHASH)
......@@ -323,6 +326,6 @@ install-gmo: compile-gmo
done
.PHONY: all install uninstall lib-shared lib-static dist dist-full zip \
test test-static test-shared test-lib test-shared-lib \
test test-static test-shared test-libs test-static-lib test-shared-lib \
check copy-dist gzip gzip-bindings gzip-full bzip 7z zip clean clean-bindings \
update-po compile-gmo install-gmo
......@@ -2,15 +2,15 @@
RHash is a console utility for calculation and verification of magnet links
and a wide range of hash sums like CRC32, MD4, MD5, SHA1, SHA256, SHA512,
AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
HAS-160, EDON-R, Whirlpool and Snefru.
SHA3, AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94,
RIPEMD-160, HAS-160, EDON-R, Whirlpool and Snefru.
Hash sums are used to ensure and verify integrity of large volumes of data
for a long-term storing or transferring.
Features:
* Output in a predefined (SFV, BSD-like) or a user-defined format.
* Can calculate Magnet links and EDonkey 2000 links.
* Can calculate Magnet links.
* Updating hash files (adding hash sums of files missing in the hash file).
* Calculates several hash sums in one pass
* Ability to process directories recursively.
......@@ -21,8 +21,8 @@ Features:
LibRHash is a professional, portable, thread-safe C library for computing
a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94, RIPEMD-160,
HAS-160, EDON-R, Whirlpool and Snefru.
SHA3, AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94,
RIPEMD-160, HAS-160, EDON-R, Whirlpool and Snefru.
Hash sums are used to ensure and verify integrity of large volumes of data
for a long-term storing or transferring.
......
......@@ -96,9 +96,9 @@ static int calc_sums(struct file_info *info)
{
FILE* fd = stdin; /* stdin */
int res;
uint64_t initial_size;
if(IS_DASH_STR(info->full_path)) {
assert(info->file);
if(info->file->mode & FILE_IFSTDIN) {
info->print_path = "(stdin)";
#ifdef _WIN32
......@@ -108,23 +108,17 @@ static int calc_sums(struct file_info *info)
}
#endif
} else {
struct rsh_stat_struct stat_buf;
/* skip non-existing files */
if(rsh_stat(info->full_path, &stat_buf) < 0) {
return -1;
}
if((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && S_ISDIR(stat_buf.st_mode)) {
if((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && FILE_ISDIR(info->file)) {
errno = EISDIR;
return -1;
}
info->size = stat_buf.st_size; /* total size, in bytes */
IF_WINDOWS(win32_set_filesize64(info->full_path, &info->size)); /* set correct filesize for large files under win32 */
info->size = info->file->size; /* total size, in bytes */
if(!info->sums_flags) return 0;
/* skip files opened with exclusive rights without reporting an error */
/* skip without reporting an error the files
* opened exclusively by another process */
fd = rsh_fopen_bin(info->full_path, "rb");
if(!fd) {
return -1;
......@@ -132,7 +126,8 @@ static int calc_sums(struct file_info *info)
}
re_init_rhash_context(info);
initial_size = info->rctx->msg_size;
/* save initial msg_size, for correct calculation of percents */
info->msg_offset = info->rctx->msg_size;
if(percents_output->update != 0) {
rhash_set_callback(info->rctx, (rhash_callback_t)percents_output->update, info);
......@@ -144,8 +139,10 @@ static int calc_sums(struct file_info *info)
rhash_final(info->rctx, 0); /* finalize hashing */
}
}
info->size = info->rctx->msg_size - initial_size;
/* calculate real file size */
info->size = info->rctx->msg_size - info->msg_offset;
rhash_data.total_size += info->size;
assert(rhash_data.total_size == info->rctx->msg_size);
if(fd != stdin) fclose(fd);
return res;
......@@ -238,13 +235,13 @@ static int find_embedded_crc32(const char* filepath, unsigned* crc32_be)
}
/**
* Rename given file inserting its crc32 sum enclosed in braces just before
* the file extension.
* Rename given file inserting its crc32 sum enclosed into square braces
* and placing it right before the file extension.
*
* @param info pointer to the data of the file to rename.
* @return 0 on success, -1 on fail with error code in errno
*/
int rename_file_to_embed_crc32(struct file_info *info)
int rename_file_by_embeding_crc32(struct file_info *info)
{
size_t len = strlen(info->full_path);
const char* p = info->full_path + len;
......@@ -373,15 +370,15 @@ int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path)
int res = 0;
memset(&info, 0, sizeof(info));
info.file = file;
info.full_path = rsh_strdup(file->path);
file_info_set_print_path(&info, print_path);
info.size = 0;
info.sums_flags = opt.sum_flags;
if(IS_DASH_STR(info.full_path)) {
if(file->mode & FILE_IFSTDIN) {
print_path = "(stdin)";
memset(&info.stat_buf, 0, sizeof(info.stat_buf));
} else {
if(file->mode & FILE_IFDIR) return 0; /* don't handle directories */
info.size = file->size; /* total size, in bytes */
......@@ -408,27 +405,23 @@ int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path)
info.time = rhash_timer_stop(&timer);
finish_percents(&info, res);
if((opt.mode & MODE_TORRENT) && !opt.bt_batch_file) {
save_torrent(&info);
}
if(opt.flags & OPT_EMBED_CRC) {
/* rename the file */
rename_file_to_embed_crc32(&info);
rename_file_by_embeding_crc32(&info);
}
if((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) {
file_t file;
file.path = info.full_path;
file.wpath = 0;
rsh_file_stat2(&file, 0);
if((opt.mode & MODE_TORRENT) && !opt.bt_batch_file) {
save_torrent(&info);
}
print_sfv_header_line(rhash_data.upd_fd, &file, info.full_path);
if((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) {
/* updating SFV file: print SFV header line */
print_sfv_header_line(rhash_data.upd_fd, file, 0);
if(opt.flags & OPT_VERBOSE) {
print_sfv_header_line(rhash_data.log, &file, info.full_path);
print_sfv_header_line(rhash_data.log, file, 0);
fflush(rhash_data.log);
}
rsh_file_cleanup(&file);
rsh_file_cleanup(file);
}
if(rhash_data.print_list && res >= 0) {
......@@ -524,6 +517,7 @@ int check_hash_file(file_t* file, int chdir)
/* initialize file_info structure */
memset(&info, 0, sizeof(info));
info.full_path = rsh_strdup(hash_file_path);
info.file = file;
file_info_set_print_path(&info, info.full_path);
info.sums_flags = info.hc.hash_mask = RHASH_CRC32;
info.hc.flags = HC_HAS_EMBCRC32;
......@@ -550,7 +544,7 @@ int check_hash_file(file_t* file, int chdir)
rhash_data.processed = rhash_data.ok = rhash_data.miss = 0;
rhash_data.total_size = 0;
if( IS_DASH_STR(hash_file_path) ) {
if(file->mode & FILE_IFSTDIN) {
fd = stdin;
hash_file_path = "<stdin>";
} else if( !(fd = rsh_fopen_bin(hash_file_path, "rb") )) {
......@@ -612,6 +606,7 @@ int check_hash_file(file_t* file, int chdir)
}
if(info.print_path != NULL) {
file_t file_to_check;
int is_absolute = IS_PATH_SEPARATOR(info.print_path[0]);
IF_WINDOWS(is_absolute = is_absolute || (info.print_path[0] && info.print_path[1] == ':'));
......@@ -624,6 +619,10 @@ int check_hash_file(file_t* file, int chdir)
} else {
info.full_path = rsh_strdup(info.print_path);
}
memset(&file_to_check, 0, sizeof(file_t));
file_to_check.path = info.full_path;
rsh_file_stat(&file_to_check);
info.file = &file_to_check;
/* verify hash sums of the file */
res = verify_sums(&info);
......
......@@ -17,19 +17,19 @@ extern "C" {
* Information about a file to calculate/verify hashes for.
*/
struct file_info {
char* full_path; /* file path (in system encoding) */
const char* print_path; /* the path part to print */
char* utf8_print_path; /* file path in UTF8 */
uint64_t size; /* the size of the file */
double time; /* file processing time in seconds */
struct infohash_ctx *infohash;
struct rhash_context* rctx; /* state of hash algorithms */
/* the file path (in system encoding). It can be changed
* if a crc sum is embedded into the filename. */
char* full_path;
const char* print_path; /* the part of the path for printing */
char* utf8_print_path; /* file path in UTF8 */
uint64_t size; /* the size of the hashed file */
uint64_t msg_offset; /* rctx->msg_size before hashing this file */
double time; /* file processing time in seconds */
struct file_t* file; /* the file being processed */
struct rhash_context* rctx; /* state of hash algorithms */
int error; /* -1 for i/o error, -2 for wrong sum, 0 on success */
char* allocated_ptr;
/* note: rsh_stat_struct size depends on _FILE_OFFSET_BITS */
struct rsh_stat_struct stat_buf; /* file attributes */
unsigned sums_flags; /* mask of ids of calculated hash functions */
struct hash_check hc; /* hash values parsed from a hash file */
};
......@@ -40,7 +40,7 @@ const char* file_info_get_utf8_print_path(struct file_info*);
void save_torrent_to(const char* path, struct rhash_context* rctx);
int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path);
int check_hash_file(file_t* file, int chdir);
int rename_file_to_embed_crc32(struct file_info *info);
int rename_file_by_embeding_crc32(struct file_info *info);
void print_sfv_banner(FILE* out);
int print_sfv_header_line(FILE* out, file_t* file, const char* printpath);
......
......@@ -87,7 +87,7 @@ static char* print_hex_byte(char *dst, const unsigned char byte, int upper_case)
/**
* URL-encode a string.
*
* @param dst buffer to receive result or NULL to calculate
* @param dst buffer to receive result or NULL to calculate
* the lengths of encoded string
* @param filename the file name
* @return the length of the result string
......@@ -283,8 +283,9 @@ char* make_path(const char* dir_path, const char* filename)
strcpy(buf, dir_path);
/* separate directory from filename */
if(len > 0 && !IS_PATH_SEPARATOR(buf[len-1]))
if(len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) {
buf[len++] = SYS_PATH_SEPARATOR;
}
/* append filename */
strcpy(buf+len, filename);
......@@ -342,44 +343,51 @@ unsigned rhash_get_ticks(void)
* @return 0 on success, -1 on error
*/
int rsh_file_stat2(file_t* file, int use_lstat)
{
struct rsh_stat_struct st;
int res = -1;
{
#ifdef _WIN32
int i;
(void)use_lstat; /* ignore on windows */
file->mtime = 0;
if(file->wpath) {
free(file->wpath);
file->wpath = NULL;
}
for(i = 0; i < 2; i++) {
WIN32_FILE_ATTRIBUTE_DATA data;
wchar_t* wpath = c2w(file->path, i);
if(wpath == NULL) continue;
res = clib_wstat(wpath, &st);
if(res == 0) {
file->wpath = wpath;
file->size = st.st_size;
/* set correct file size for large files under win32 */
win32_set_filesize64(file->path, &file->size);
break;
/* read file attributes */
if(GetFileAttributesExW(wpath, GetFileExInfoStandard, &data)) {
uint64_t u;
file->wpath = wpath;
file->size = (((uint64_t)data.nFileSizeHigh) << 32) + data.nFileSizeLow;
file->mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? FILE_IFDIR : 0);
/* the number of 100-nanosecond intervals since January 1, 1601 */
u = (((uint64_t)data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime;
/* convert to second and substract epoch difference */
file->mtime = u / 10000000 - 11644473600LL;
return 0;
}
free(wpath);
}
errno = ENOENT; /* no such file or directory */
return -1;
#else
res = (use_lstat ? lstat(file->path, &st) :
rsh_stat(file->path, &st));
struct rsh_stat_struct st;
int res = -1;
res = (use_lstat ? lstat(file->path, &st) : rsh_stat(file->path, &st));
file->size = st.st_size;
#endif /* _WIN32 */
file->mtime = st.st_mtime;
file->mode = 0;
if(S_ISDIR(st.st_mode)) file->mode |= FILE_IFDIR;
return res;
#endif /* _WIN32 */
}
/**
......@@ -402,6 +410,8 @@ void rsh_file_cleanup(file_t* file)
file->wpath = NULL;
}
#endif /* _WIN32 */
file->mtime = file->size = 0;
file->mode = 0;
}
/* program exit and error reporting functions */
......@@ -493,30 +503,6 @@ char* rhash_strdup(const char* str, const char* srcfile, int srcline)
return res;
}
/**
* Duplicate wide string with reporting memory error to stderr.
*
* @param str the zero-terminated string to duplicate
* @param srcfile source file to report error on fail
* @param srcline source code line to be reported on fail
* @return allocated memory buffer with copied string
*/
wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline)
{
#ifndef __STRICT_ANSI__
wchar_t* res = wcsdup(str);
#else
wchar_t* res = (wchar_t*)malloc((wcslen(str) + 1) * sizeof(wchar_t));
if(res) wcscpy(res, str);
#endif
if(!res) {
rsh_report_error(srcfile, srcline, "wcsdup(\"%u\") failed\n", (wcslen(str) + 1));
rsh_exit(2);
}
return res;
}
/**
* Reallocates a buffer via realloc with reporting memory error to stderr.
*
......
......@@ -49,12 +49,14 @@ char* str_set(char* buf, int ch, int size);
char* str_append(const char* orig, const char* append);
size_t strlen_utf8_c(const char *str);
#define IS_DASH_STR(s) ((s)[0] == '-' && (s)[1] == '\0')
#define IS_COMMENT(c) ((c) == ';' || (c) == '#')
/* modes for file_t.mode */
#define FILE_IFDIR 0x01
#define FILE_IFLNK 0x02
#define FILE_IFROOT 0x10
#define FILE_IFSTDIN 0x20
#define FILE_ISDIR(file) ((file)->mode & FILE_IFDIR)
/* portable file information */
typedef struct file_t {
......@@ -100,17 +102,14 @@ typedef char rsh_tchar;
/* rhash stat function */
#if (__MSVCRT_VERSION__ >= 0x0601) || (_MSC_VER >= 1400)
# define rsh_stat_struct __stat64
# define rsh_time_struct __time64_t
# define rsh_stat(path, st) win_stat(path, st)
# define clib_wstat(path, st) _wstat64(path, st)
#elif defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER))
# define rsh_stat_struct _stati64
# define rsh_time_struct __time64_t
# define rsh_stat(path, st) win_stat(path, st)
# define clib_wstat(path, st) _wstati64(path, st)
#else
# define rsh_stat_struct stat
# define rsh_time_struct time_t
# define rsh_stat(path, st) stat(path, st)
/* # define clib_wstat(path, st) _wstat32(path, st) */
#endif
......@@ -125,12 +124,10 @@ void rhash_exit(int code);
#define rsh_malloc(size) rhash_malloc(size, __FILE__, __LINE__)
#define rsh_calloc(num, size) rhash_calloc(num, size, __FILE__, __LINE__)
#define rsh_strdup(str) rhash_strdup(str, __FILE__, __LINE__)
#define rsh_wcsdup(str) rhash_wcsdup(str, __FILE__, __LINE__)
#define rsh_realloc(mem, size) rhash_realloc(mem, size, __FILE__, __LINE__)
void* rhash_malloc(size_t size, const char* srcfile, int srcline);
void* rhash_calloc(size_t num, size_t size, const char* srcfile, int srcline);
char* rhash_strdup(const char* str, const char* srcfile, int srcline);
wchar_t* rhash_wcsdup(const wchar_t* str, const char* srcfile, int srcline);
void* rhash_realloc(void* mem, size_t size, const char* srcfile, int srcline);
extern void (*rsh_exit)(int code);
......@@ -145,12 +142,12 @@ typedef struct vector_t
void (*destructor)(void*);
} vector_t;
struct vector_t* rsh_vector_new(void (*destructor)(void*));
struct vector_t* rsh_vector_new_simple(void);
void rsh_vector_free(struct vector_t* vect);
void rsh_vector_destroy(struct vector_t* vect);
void rsh_vector_add_ptr(struct vector_t* vect, void *item);
void rsh_vector_add_empty(struct vector_t* vect, size_t item_size);
vector_t* rsh_vector_new(void (*destructor)(void*));
vector_t* rsh_vector_new_simple(void);
void rsh_vector_free(vector_t* vect);
void rsh_vector_destroy(vector_t* vect);
void rsh_vector_add_ptr(vector_t* vect, void *item);
void rsh_vector_add_empty(vector_t* vect, size_t item_size);
#define rsh_vector_add_uint32(vect, item) { \
rsh_vector_add_empty(vect, item_size); \
((unsigned*)(vect)->array)[(vect)->size - 1] = item; \
......@@ -167,8 +164,8 @@ typedef struct blocks_vector_t
vector_t blocks;
} blocks_vector_t;
void rsh_blocks_vector_init(struct blocks_vector_t*);
void rsh_blocks_vector_destroy(struct blocks_vector_t* vect);
void rsh_blocks_vector_init(blocks_vector_t*);
void rsh_blocks_vector_destroy(blocks_vector_t* vect);
#define rsh_blocks_vector_get_item(bvector, index, blocksize, item_type) \
(&((item_type*)((bvector)->blocks.array[(index) / (blocksize)]))[(index) % (blocksize)])
#define rsh_blocks_vector_get_ptr(bvector, index, blocksize, item_size) \
......
%define version 1.2.10
%define version 1.3.0
# major is the part of the shared library name after the .so
%define major 0
%define libname %mklibname rhash %{major}
......@@ -102,6 +102,7 @@ ldconfig
ldconfig
%changelog
* Tue Jun 11 2013 Aleksey <rhash.admin@gmail.com> 1.3.0-1mdk
* Tue Dec 25 2012 Aleksey <rhash.admin@gmail.com> 1.2.10-1mdk
* Sat Apr 14 2012 Aleksey <rhash.admin@gmail.com> 1.2.9-1mdk
* Wed Sep 14 2011 Aleksey <rhash.admin@gmail.com> 1.2.8-1mdk
......
......@@ -102,6 +102,7 @@ ldconfig
ldconfig
%changelog
* Tue Jun 11 2013 Aleksey <rhash.admin@gmail.com> 1.3.0-1mdk
* Tue Dec 25 2012 Aleksey <rhash.admin@gmail.com> 1.2.10-1mdk
* Sat Apr 14 2012 Aleksey <rhash.admin@gmail.com> 1.2.9-1mdk
* Wed Sep 14 2011 Aleksey <rhash.admin@gmail.com> 1.2.8-1mdk
......
......@@ -169,7 +169,7 @@ int file_set_exist(file_set *set, const char* filepath)
hash = file_set_make_hash(search_filepath);
/* fast binary search */
for(a = -1, b = set->size; (a + 1) < b;) {
for(a = -1, b = (int)set->size; (a + 1) < b;) {
file_set_item *item;
c = (a + b) / 2;
......
......@@ -20,35 +20,52 @@
#include "find_file.h"
#if !defined(_WIN32) && (defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500)
# define USE_LSTAT_FOR_SYMLINKS
# define USE_LSTAT 1
#else
# define USE_LSTAT 0
#endif
void process_files(const char* paths[], size_t count,
find_file_options* opt)
#define IS_DASH_STR(s) ((s)[0] == '-' && (s)[1] == '\0')
#define IS_CURRENT_OR_PARENT_DIR(s) ((s)[0]=='.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
void process_files(const char* paths[], size_t count, find_file_options* opt)
{
struct file_t file;
size_t i;
memset(&file, 0, sizeof(file));
for(i = 0; i < count && !(opt->options & FIND_CANCEL); i++) {
for(i = 0; i < count && !(opt->options & FIND_CANCEL); i++)
{
rsh_file_cleanup(&file);
file.path = (char*)paths[i];
if(!IS_DASH_STR(file.path) && rsh_file_stat2(&file, USE_LSTAT) < 0) {
if((opt->options & FIND_LOG_ERRORS) != 0) {
log_file_error(file.path);
opt->errors_count++;
}
continue;
}
if(!IS_DASH_STR(file.path) && (file.mode & FILE_IFDIR) != 0) {
find_file(&file, opt);
if (IS_DASH_STR(file.path)) {
file.mode = FILE_IFSTDIN;
} else {
file.mode |= FILE_ISROOT;
opt->call_back(&file, opt->call_back_data);
/* read attributes of the file */
if(rsh_file_stat2(&file, USE_LSTAT) < 0) {
if((opt->options & FIND_LOG_ERRORS) != 0) {
log_file_error(file.path);
opt->errors_count++;
}
continue;
}
/* check if file is a directory */
if(FILE_ISDIR(&file)) {
if(opt->max_depth) {
find_file(&file, opt);
} else {
errno = EISDIR;
log_file_error(file.path);
}
continue;
}
}
assert(!FILE_ISDIR(&file));
/* process a regular file or a dash '-' path */
file.mode |= FILE_IFROOT;
opt->call_back(&file, opt->call_back_data);
}
rsh_file_cleanup(&file);
......@@ -103,12 +120,14 @@ static dir_entry* dir_entry_insert(dir_entry **at, char* filename, unsigned type
}
/**
* Free memory allocated by a dir_entry object.
* Free the first entry of the list of dir_entry elements.
*
* @param e pointer to object to deallocate
* @param p pointer to the list.
*/
static void dir_entry_free(dir_entry* e)
static void dir_entry_drop_head(dir_entry** p)
{
dir_entry* e = *p;
*p = e->next;
free(e->filename);
free(e);
}
......@@ -119,7 +138,7 @@ static void dir_entry_free(dir_entry* e)
typedef struct dir_iterator
{
int left;
char* prev_dir;
char* dir_path;
} dir_iterator;
#define MAX_DIRS_DEPTH 64
......@@ -128,29 +147,25 @@ typedef struct dir_iterator
*
* @param start_dir path to the directory to walk recursively
* @param options the options specifying how to walk the directory tree
* @return 0 on success, -1 on error
*/
int find_file(file_t* start_dir, find_file_options* options)
{
dir_entry *dirs_stack = NULL; /* root of the dir_list */
dir_iterator* it;
int level = 1;
int level = 0;
int max_depth = options->max_depth;
int flags = options->options;
dir_entry* entry;
file_t file;
if(max_depth < 0 || max_depth >= MAX_DIRS_DEPTH) {
max_depth = MAX_DIRS_DEPTH;
max_depth = MAX_DIRS_DEPTH - 1;
}
/* skip the directory if max_depth == 0 */
if(max_depth == 0) {
return 0;
}
if(!max_depth) return 0;
memset(&file, 0, sizeof(file));
if((start_dir->mode & FILE_IFDIR) == 0) {
if(!FILE_ISDIR(start_dir)) {
errno = ENOTDIR;
return -1;
}
......@@ -161,107 +176,116 @@ int find_file(file_t* start_dir, find_file_options* options)
return 0;
}
it = (dir_iterator*)malloc(MAX_DIRS_DEPTH * sizeof(dir_iterator));
if(!it) return 0;
/* push root directory into dirs_stack */
it[0].left = 1;
it[0].prev_dir = rsh_strdup(start_dir->path);
it[1].prev_dir = NULL;
if(!it[0].prev_dir) {
errno = ENOMEM;
return -1;
}
entry = dir_entry_insert(&dirs_stack, NULL, 0);
if(!entry) {
free(it[0].prev_dir);
free(it);
errno = ENOMEM;
/* allocate array of counters of directory elements */
it = (dir_iterator*)malloc((MAX_DIRS_DEPTH + 1) * sizeof(dir_iterator));
if(!it) {
return -1;
}
while(!(options->options & FIND_CANCEL)) {
dir_entry *dir, **insert_at;
/* push dummy counter for the root element */
it[0].left = 1;
it[0].dir_path = 0;
memset(&file, 0, sizeof(file));
while(!(options->options & FIND_CANCEL))
{
dir_entry **insert_at;
char* dir_path;
DIR *dp;
struct dirent *de;
/* walk back */
while((--level) >= 0 && it[level].left <= 0) free(it[level+1].prev_dir);
if(level < 0) break;
assert(dirs_stack != NULL);
/* on the first cycle: level == 0, stack[0] == 0; */
/* climb down from the tree */
while(--it[level].left < 0) {