From 0f3cc618756c1db3e3181fbdbcd894fcea1fbf00 Mon Sep 17 00:00:00 2001 From: Fufu Fang Date: Mon, 30 Aug 2021 11:24:32 +0100 Subject: [PATCH] relabelled all log outputs --- Makefile | 2 +- src/cache.c | 1447 +++++++++++++++++++++++++--------------------- src/config.c | 42 +- src/config.h | 2 +- src/fuse_local.c | 218 +++---- src/link.c | 1287 ++++++++++++++++++++++------------------- src/log.c | 80 +-- src/log.h | 3 +- src/main.c | 526 +++++++++-------- src/network.c | 542 +++++++++-------- src/sonic.c | 701 +++++++++++----------- src/util.c | 159 ++--- 12 files changed, 2677 insertions(+), 2332 deletions(-) diff --git a/Makefile b/Makefile index 4505590..ae87a06 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION = 1.2.2 +VERSION = 1.2.3 CFLAGS += -O2 -Wall -Wextra -Wshadow -rdynamic -D_GNU_SOURCE\ -D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\ diff --git a/src/cache.c b/src/cache.c index 31e1991..4a55bb0 100644 --- a/src/cache.c +++ b/src/cache.c @@ -11,11 +11,15 @@ #include #include -/* ---------------- External variables -----------------------*/ +/* + * ---------------- External variables ----------------------- + */ int CACHE_SYSTEM_INIT = 0; char *META_DIR; -/* ----------------- Static variables ----------------------- */ +/* + * ----------------- Static variables ----------------------- + */ /** * \brief Cache file locking @@ -33,189 +37,214 @@ static char *DATA_DIR; */ static char *CacheSystem_calc_dir(const char *url) { - char *xdg_cache_home = getenv("XDG_CACHE_HOME"); - if (!xdg_cache_home) { - char *home = getenv("HOME"); - char *xdg_cache_home_default = "/.cache"; - xdg_cache_home = path_append(home, xdg_cache_home_default); - } - if (mkdir(xdg_cache_home, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", - strerror(errno)); - } - char *cache_dir_root = path_append(xdg_cache_home, "/httpdirfs/"); - if (mkdir(cache_dir_root, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", - strerror(errno)); - } + char *xdg_cache_home = getenv("XDG_CACHE_HOME"); + if (!xdg_cache_home) { + char *home = getenv("HOME"); + char *xdg_cache_home_default = "/.cache"; + xdg_cache_home = path_append(home, xdg_cache_home_default); + } + if (mkdir + (xdg_cache_home, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", + strerror(errno)); + } + char *cache_dir_root = path_append(xdg_cache_home, "/httpdirfs/"); + if (mkdir + (cache_dir_root, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", + strerror(errno)); + } - char *fn = path_append(cache_dir_root, "/CACHEDIR.TAG"); - FILE *fp = fopen(fn, "w"); - if (fp) { - fprintf(fp, -"Signature: 8a477f597d28d172789f06886806bc55\n\ + char *fn = path_append(cache_dir_root, "/CACHEDIR.TAG"); + FILE *fp = fopen(fn, "w"); + if (fp) { + fprintf(fp, "Signature: 8a477f597d28d172789f06886806bc55\n\ # This file is a cache directory tag created by httpdirfs.\n\ # For information about cache directory tags, see:\n\ # http://www.brynosaurus.com/cachedir/\n"); - } else { - lprintf(fatal, "CacheSystem_calc_dir(): fopen(%s): %s", fn, - strerror(errno)); - } - if (ferror(fp)) { - lprintf(fatal, - "CacheSystem_calc_dir(): fwrite(): encountered error!\n"); - } - if (fclose(fp)) { - lprintf(fatal, "CacheSystem_calc_dir(): fclose(%s): %s\n", fn, - strerror(errno)); - } - CURL* c = curl_easy_init(); - char *escaped_url = curl_easy_escape(c, url, 0); - char *full_path = path_append(cache_dir_root, escaped_url); - if (mkdir(full_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", - strerror(errno)); - } - FREE(fn); - FREE(cache_dir_root); - curl_free(escaped_url); - curl_easy_cleanup(c); - return full_path; + } else { + lprintf(fatal, "CacheSystem_calc_dir(): fopen(%s): %s", fn, + strerror(errno)); + } + if (ferror(fp)) { + lprintf(fatal, + "CacheSystem_calc_dir(): fwrite(): encountered error!\n"); + } + if (fclose(fp)) { + lprintf(fatal, "CacheSystem_calc_dir(): fclose(%s): %s\n", fn, + strerror(errno)); + } + CURL *c = curl_easy_init(); + char *escaped_url = curl_easy_escape(c, url, 0); + char *full_path = path_append(cache_dir_root, escaped_url); + if (mkdir(full_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_calc_dir(): mkdir(): %s\n", + strerror(errno)); + } + FREE(fn); + FREE(cache_dir_root); + curl_free(escaped_url); + curl_easy_cleanup(c); + return full_path; } void CacheSystem_init(const char *path, int url_supplied) { - if (pthread_mutex_init(&cf_lock, NULL) != 0) { - lprintf(fatal, - "CacheSystem_init(): cf_lock initialisation failed!\n"); - } + if (pthread_mutex_init(&cf_lock, NULL)) { + lprintf(fatal, + "CacheSystem_init(): cf_lock initialisation failed!\n"); + } - if (url_supplied) { - path = CacheSystem_calc_dir(path); - } + if (url_supplied) { + path = CacheSystem_calc_dir(path); + } - lprintf(debug, "CacheSystem_init(): directory: %s\n", path); + lprintf(debug, "CacheSystem_init(): directory: %s\n", path); - META_DIR = path_append(path, "meta/"); - DATA_DIR = path_append(path, "data/"); - /* Check if directories exist, if not, create them */ - if (mkdir(META_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", - strerror(errno)); - } + META_DIR = path_append(path, "meta/"); + DATA_DIR = path_append(path, "data/"); + /* + * Check if directories exist, if not, create them + */ + if (mkdir(META_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + } - if (mkdir(DATA_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", - strerror(errno)); - } + if (mkdir(DATA_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + } - if (CONFIG.mode == SONIC) { - char *sonic_path; - /* Create "rest" sub-directory for META_DIR */ - sonic_path = path_append(META_DIR, "rest/"); - if (mkdir(sonic_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", - strerror(errno)); - } - FREE(sonic_path); + if (CONFIG.mode == SONIC) { + char *sonic_path; + /* + * Create "rest" sub-directory for META_DIR + */ + sonic_path = path_append(META_DIR, "rest/"); + if (mkdir + (sonic_path, + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + } + FREE(sonic_path); - /* Create "rest" sub-directory for DATA_DIR */ - sonic_path = path_append(DATA_DIR, "rest/"); - if (mkdir(sonic_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - && (errno != EEXIST)) { - lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", - strerror(errno)); - } - FREE(sonic_path); - } + /* + * Create "rest" sub-directory for DATA_DIR + */ + sonic_path = path_append(DATA_DIR, "rest/"); + if (mkdir + (sonic_path, + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + lprintf(fatal, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + } + FREE(sonic_path); + } - CACHE_SYSTEM_INIT = 1; + CACHE_SYSTEM_INIT = 1; } /** * \brief read a metadata file * \return 0 on success, errno on error. */ -static int Meta_read(Cache *cf) +static int Meta_read(Cache * cf) { - FILE *fp = cf->mfp; - rewind(fp); + FILE *fp = cf->mfp; + rewind(fp); - int nmemb = 0; + int nmemb = 0; - if (!fp) { - /* The metadata file does not exist */ - lprintf(error, "Meta_read(): fopen(): %s\n", strerror(errno)); - return EIO; - } + if (!fp) { + /* + * The metadata file does not exist + */ + lprintf(error, "Meta_read(): fopen(): %s\n", strerror(errno)); + return EIO; + } - fread(&cf->time, sizeof(long), 1, fp); - fread(&cf->content_length, sizeof(off_t), 1, fp); - fread(&cf->blksz, sizeof(int), 1, fp); - fread(&cf->segbc, sizeof(long), 1, fp); + fread(&cf->time, sizeof(long), 1, fp); + fread(&cf->content_length, sizeof(off_t), 1, fp); + fread(&cf->blksz, sizeof(int), 1, fp); + fread(&cf->segbc, sizeof(long), 1, fp); - /* Error checking for fread */ - if (ferror(fp)) { - lprintf(error, - "Meta_read(): error reading core metadata!\n"); - return EIO; - } + /* + * Error checking for fread + */ + if (ferror(fp)) { + lprintf(error, "Meta_read(): error reading core metadata!\n"); + return EIO; + } - if (!cf->blksz) { - lprintf(error, - "Meta_read(): corrupt metadata: %s, blksz: %d", cf->path, - cf->blksz); - return EBADMSG; - } + if (!cf->blksz) { + lprintf(error, + "Meta_read(): corrupt metadata: %s, blksz: %d", + cf->path, cf->blksz); + return EBADMSG; + } - if (cf->blksz != CONFIG.data_blksz) { - lprintf(warning, - "Meta_read(): Warning: cf->blksz != CONFIG.data_blksz\n"); - } + if (cf->blksz != CONFIG.data_blksz) { + lprintf(warning, + "Meta_read(): Warning: cf->blksz != CONFIG.data_blksz\n"); + } - if (cf->segbc > CONFIG.max_segbc) { - lprintf(error, "Meta_read(): Error: segbc: %ld\n", cf->segbc); - return EFBIG; - } + if (cf->segbc > CONFIG.max_segbc) { + lprintf(error, "Meta_read(): Error: segbc: %ld\n", cf->segbc); + return EFBIG; + } - if (cf->segbc > 0) { - /* Allocate memory for all segments, and read them in */ - cf->seg = CALLOC(cf->segbc, sizeof(Seg)); - nmemb = fread(cf->seg, sizeof(Seg), cf->segbc, fp); + if (cf->segbc > 0) { + /* + * Allocate memory for all segments, and read them in + */ + cf->seg = CALLOC(cf->segbc, sizeof(Seg)); + nmemb = fread(cf->seg, sizeof(Seg), cf->segbc, fp); - /* We shouldn't have gone past the end of the file */ - if (feof(fp)) { - /* reached EOF */ - lprintf(error, - "Meta_read(): attempted to read past the end of the file!\n"); - return EBADMSG; - } + /* + * We shouldn't have gone past the end of the file + */ + if (feof(fp)) { + /* + * reached EOF + */ + lprintf(error, + "Meta_read(): attempted to read past the end of the \ +file!\n"); + return EBADMSG; + } - /* Error checking for fread */ - if (ferror(fp)) { - lprintf(error, - "Meta_read(): error reading bitmap!\n"); - return EIO; - } + /* + * Error checking for fread + */ + if (ferror(fp)) { + lprintf(error, "Meta_read(): error reading bitmap!\n"); + return EIO; + } - /* Check for inconsistent metadata file */ - if (nmemb != cf-> segbc) { - lprintf(error, - "Meta_read(): corrupted metadata!\n"); - return EBADMSG; - } - } else { - /* Allocate one single segment for empty file to prevent segfault */ - cf->seg = CALLOC(1, sizeof(Seg)); - } + /* + * Check for inconsistent metadata file + */ + if (nmemb != cf->segbc) { + lprintf(error, "Meta_read(): corrupted metadata!\n"); + return EBADMSG; + } + } else { + /* + * Allocate one single segment for empty file to prevent segfault + */ + cf->seg = CALLOC(1, sizeof(Seg)); + } - return 0; + return 0; } /** @@ -224,40 +253,46 @@ static int Meta_read(Cache *cf) * - -1 on error, * - 0 on success */ -static int Meta_write(Cache *cf) +static int Meta_write(Cache * cf) { - FILE *fp = cf->mfp; - rewind(fp); + FILE *fp = cf->mfp; + rewind(fp); - if (!fp) { - /* Cannot create the metadata file */ - lprintf(error, "Meta_write(): fopen(): %s\n", strerror(errno)); - return -1; - } + if (!fp) { + /* + * Cannot create the metadata file + */ + lprintf(error, "Meta_write(): fopen(): %s\n", strerror(errno)); + return -1; + } - /* These things really should not be zero!!! */ - if (!cf->content_length || !cf->blksz || !cf->segbc) { - lprintf(error, - "Meta_write(): Warning: content_length: %ld, blksz: %d, segbc: \ -%ld\n", cf->content_length, cf->blksz, cf->segbc); - } + /* + * These things really should not be zero!!! + */ + if (!cf->content_length || !cf->blksz || !cf->segbc) { + lprintf(error, + "Meta_write(): Warning: content_length: %ld, blksz: %d, segbc: \ +%ld\n", cf->content_length, cf->blksz, + cf->segbc); + } - fwrite(&cf->time, sizeof(long), 1, fp); - fwrite(&cf->content_length, sizeof(off_t), 1, fp); - fwrite(&cf->blksz, sizeof(int), 1, fp); - fwrite(&cf->segbc, sizeof(long), 1, fp); - if (cf->segbc > 0){ - fwrite(cf->seg, sizeof(Seg), cf->segbc, fp); - } + fwrite(&cf->time, sizeof(long), 1, fp); + fwrite(&cf->content_length, sizeof(off_t), 1, fp); + fwrite(&cf->blksz, sizeof(int), 1, fp); + fwrite(&cf->segbc, sizeof(long), 1, fp); + if (cf->segbc > 0) { + fwrite(cf->seg, sizeof(Seg), cf->segbc, fp); + } - /* Error checking for fwrite */ - if (ferror(fp)) { - lprintf(error, - "Meta_write(): fwrite(): encountered error!\n"); - return -1; - } + /* + * Error checking for fwrite + */ + if (ferror(fp)) { + lprintf(error, "Meta_write(): fwrite(): encountered error!\n"); + return -1; + } - return 0; + return 0; } /** @@ -265,24 +300,26 @@ static int Meta_write(Cache *cf) * \details We use sparse creation here * \return exit on failure */ -static void Data_create(Cache *cf) +static void Data_create(Cache * cf) { - int fd; - int mode; + int fd; + int mode; - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - char *datafn = path_append(DATA_DIR, cf->path); - fd = open(datafn, O_WRONLY | O_CREAT, mode); - FREE(datafn); - if (fd == -1) { - lprintf(fatal, "Data_create(): open(): %s\n", strerror(errno)); - } - if (ftruncate(fd, cf->content_length)) { - lprintf(warning, "Data_create(): ftruncate(): %s\n", strerror(errno)); - } - if (close(fd)) { - lprintf(fatal, "Data_create(): close:(): %s\n", strerror(errno)); - } + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + char *datafn = path_append(DATA_DIR, cf->path); + fd = open(datafn, O_WRONLY | O_CREAT, mode); + FREE(datafn); + if (fd == -1) { + lprintf(fatal, "Data_create(): open(): %s\n", strerror(errno)); + } + if (ftruncate(fd, cf->content_length)) { + lprintf(warning, "Data_create(): ftruncate(): %s\n", + strerror(errno)); + } + if (close(fd)) { + lprintf(fatal, "Data_create(): close:(): %s\n", + strerror(errno)); + } } /** @@ -291,15 +328,15 @@ static void Data_create(Cache *cf) */ static long Data_size(const char *fn) { - char *datafn = path_append(DATA_DIR, fn); - struct stat st; - int s = stat(datafn, &st); - FREE(datafn); - if (!s) { - return st.st_size; - } - lprintf(error, "Data_size(): stat(): %s\n", strerror(errno)); - return -1; + char *datafn = path_append(DATA_DIR, fn); + struct stat st; + int s = stat(datafn, &st); + FREE(datafn); + if (!s) { + return st.st_size; + } + lprintf(error, "Data_size(): stat(): %s\n", strerror(errno)); + return -1; } /** @@ -312,58 +349,69 @@ static long Data_size(const char *fn) * - negative values on error, * - otherwise, the number of bytes read. */ -static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset) +static long Data_read(Cache * cf, uint8_t * buf, off_t len, off_t offset) { - if (len == 0) { - lprintf(error, "Data_read(): requested to read 0 byte!\n"); - return -EINVAL; - } + if (len == 0) { + lprintf(error, "Data_read(): requested to read 0 byte!\n"); + return -EINVAL; + } - lprintf(cache_lock_debug, "Data_read(): thread %x: locking seek_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf->seek_lock); + lprintf(cache_lock_debug, + "Data_read(): thread %x: locking seek_lock;\n", pthread_self()); + PTHREAD_MUTEX_LOCK(&cf->seek_lock); - long byte_read = 0; + long byte_read = 0; - /* Seek to the right location */ - if (fseeko(cf->dfp, offset, SEEK_SET)) { - /* fseeko failed */ - lprintf(error, "Data_read(): fseeko(): %s\n", strerror(errno)); - byte_read = -EIO; - goto end; - } + /* + * Seek to the right location + */ + if (fseeko(cf->dfp, offset, SEEK_SET)) { + /* + * fseeko failed + */ + lprintf(error, "Data_read(): fseeko(): %s\n", strerror(errno)); + byte_read = -EIO; + goto end; + } - /* Calculate how much to read */ - if (offset + len > cf->content_length) { - len -= offset + len - cf->content_length; - if (len < 0) { - goto end; - } - } + /* + * Calculate how much to read + */ + if (offset + len > cf->content_length) { + len -= offset + len - cf->content_length; + if (len < 0) { + goto end; + } + } - byte_read = fread(buf, sizeof(uint8_t), len, cf->dfp); - if (byte_read != len) { - lprintf(debug, - "Data_read(): fread(): requested %ld, returned %ld!\n", - len, byte_read); - if (feof(cf->dfp)) { - /* reached EOF */ - lprintf(error, - "Data_read(): fread(): reached the end of the file!\n"); - } - if (ferror(cf->dfp)) { - /* filesystem error */ - lprintf(error, - "Data_read(): fread(): encountered error!\n"); - } - } + byte_read = fread(buf, sizeof(uint8_t), len, cf->dfp); + if (byte_read != len) { + lprintf(debug, + "Data_read(): fread(): requested %ld, returned %ld!\n", + len, byte_read); + if (feof(cf->dfp)) { + /* + * reached EOF + */ + lprintf(error, + "Data_read(): fread(): reached the end of the file!\n"); + } + if (ferror(cf->dfp)) { + /* + * filesystem error + */ + lprintf(error, + "Data_read(): fread(): encountered error!\n"); + } + } - end: - lprintf(cache_lock_debug, "Data_read(): thread %x: unlocking seek_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->seek_lock); + end: + lprintf(cache_lock_debug, + "Data_read(): thread %x: unlocking seek_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->seek_lock); - return byte_read; + return byte_read; } /** @@ -376,65 +424,76 @@ static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset) * - -1 when the data file does not exist * - otherwise, the number of bytes written. */ -static long Data_write(Cache *cf, const uint8_t *buf, off_t len, - off_t offset) +static long Data_write(Cache * cf, const uint8_t * buf, off_t len, off_t offset) { - if (len == 0) { - /* We should permit empty files */ - return 0; - } + if (len == 0) { + /* + * We should permit empty files + */ + return 0; + } - lprintf(cache_lock_debug, "Data_write(): thread %x: locking seek_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf->seek_lock); + lprintf(cache_lock_debug, + "Data_write(): thread %x: locking seek_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&cf->seek_lock); - long byte_written = 0; + long byte_written = 0; - if (fseeko(cf->dfp, offset, SEEK_SET)) { - /* fseeko failed */ - lprintf(error, "Data_write(): fseeko(): %s\n", strerror(errno)); - byte_written = -EIO; - goto end; - } + if (fseeko(cf->dfp, offset, SEEK_SET)) { + /* + * fseeko failed + */ + lprintf(error, "Data_write(): fseeko(): %s\n", strerror(errno)); + byte_written = -EIO; + goto end; + } - byte_written = fwrite(buf, sizeof(uint8_t), len, cf->dfp); + byte_written = fwrite(buf, sizeof(uint8_t), len, cf->dfp); - if (byte_written != len) { - lprintf(error, "Data_write(): fwrite(): requested %ld, returned %ld!\n", - len, byte_written); - } + if (byte_written != len) { + lprintf(error, + "Data_write(): fwrite(): requested %ld, returned %ld!\n", + len, byte_written); + } - if (ferror(cf->dfp)) { - /* filesystem error */ - lprintf(error, "Data_write(): fwrite(): encountered error!\n"); - } + if (ferror(cf->dfp)) { + /* + * filesystem error + */ + lprintf(error, "Data_write(): fwrite(): encountered error!\n"); + } - end: - lprintf(cache_lock_debug, - "Data_write(): thread %x: unlocking seek_lock;\n", pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->seek_lock); + end: + lprintf(cache_lock_debug, + "Data_write(): thread %x: unlocking seek_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->seek_lock); - return byte_written; + return byte_written; } int CacheDir_create(const char *dirn) { - char *metadirn = path_append(META_DIR, dirn); - char *datadirn = path_append(DATA_DIR, dirn); - int i; + char *metadirn = path_append(META_DIR, dirn); + char *datadirn = path_append(DATA_DIR, dirn); + int i; - i = -mkdir(metadirn, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - if (i && (errno != EEXIST)) { - lprintf(fatal, "CacheDir_create(): mkdir(): %s\n", strerror(errno)); - } + i = -mkdir(metadirn, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (i && (errno != EEXIST)) { + lprintf(fatal, "CacheDir_create(): mkdir(): %s\n", + strerror(errno)); + } - i |= -mkdir(datadirn, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) << 1; - if (i && (errno != EEXIST)) { - lprintf(fatal, "CacheDir_create(): mkdir(): %s\n", strerror(errno)); - } - FREE(datadirn); - FREE(metadirn); - return -i; + i |= -mkdir(datadirn, + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) << 1; + if (i && (errno != EEXIST)) { + lprintf(fatal, "CacheDir_create(): mkdir(): %s\n", + strerror(errno)); + } + FREE(datadirn); + FREE(metadirn); + return -i; } /** @@ -442,67 +501,71 @@ int CacheDir_create(const char *dirn) */ static Cache *Cache_alloc() { - Cache *cf = CALLOC(1, sizeof(Cache)); + Cache *cf = CALLOC(1, sizeof(Cache)); - if (pthread_mutex_init(&cf->seek_lock, NULL)) { - lprintf(fatal, "Cache_alloc(): seek_lock initialisation failed!\n"); - } + if (pthread_mutex_init(&cf->seek_lock, NULL)) { + lprintf(fatal, + "Cache_alloc(): seek_lock initialisation failed!\n"); + } - if (pthread_mutex_init(&cf->w_lock, NULL)) { - lprintf(fatal, "Cache_alloc(): w_lock initialisation failed!\n"); - } + if (pthread_mutex_init(&cf->w_lock, NULL)) { + lprintf(fatal, + "Cache_alloc(): w_lock initialisation failed!\n"); + } - if (pthread_mutexattr_init(&cf->bgt_lock_attr)) { - lprintf(fatal, - "Cache_alloc(): bgt_lock_attr initialisation failed!\n"); - } + if (pthread_mutexattr_init(&cf->bgt_lock_attr)) { + lprintf(fatal, + "Cache_alloc(): bgt_lock_attr initialisation failed!\n"); + } - if (pthread_mutexattr_setpshared(&cf->bgt_lock_attr, - PTHREAD_PROCESS_SHARED)) { - lprintf(fatal, "Cache_alloc(): could not set bgt_lock_attr!\n"); - } + if (pthread_mutexattr_setpshared(&cf->bgt_lock_attr, + PTHREAD_PROCESS_SHARED)) { + lprintf(fatal, "Cache_alloc(): could not set bgt_lock_attr!\n"); + } - if (pthread_mutex_init(&cf->bgt_lock, &cf->bgt_lock_attr)) { - lprintf(fatal, "Cache_alloc(): bgt_lock initialisation failed!\n"); - } + if (pthread_mutex_init(&cf->bgt_lock, &cf->bgt_lock_attr)) { + lprintf(fatal, + "Cache_alloc(): bgt_lock initialisation failed!\n"); + } - return cf; + return cf; } /** * \brief free a cache data structure */ -static void Cache_free(Cache *cf) +static void Cache_free(Cache * cf) { - if (pthread_mutex_destroy(&cf->seek_lock)) { - lprintf(fatal, "Cache_free(): could not destroy seek_lock!\n"); - } + if (pthread_mutex_destroy(&cf->seek_lock)) { + lprintf(fatal, "Cache_free(): could not destroy seek_lock!\n"); + } - if (pthread_mutex_destroy(&cf->w_lock)) { - lprintf(fatal, "Cache_free(): could not destroy w_lock!\n"); - } + if (pthread_mutex_destroy(&cf->w_lock)) { + lprintf(fatal, "Cache_free(): could not destroy w_lock!\n"); + } - if (pthread_mutex_destroy(&cf->bgt_lock)) { - lprintf(fatal, "Cache_free(): could not destroy bgt_lock!\n"); - } + if (pthread_mutex_destroy(&cf->bgt_lock)) { + lprintf(fatal, "Cache_free(): could not destroy bgt_lock!\n"); + } - if (pthread_mutexattr_destroy(&cf->bgt_lock_attr)) { - lprintf(fatal, "Cache_alloc(): could not destroy bgt_lock_attr!\n"); - } + if (pthread_mutexattr_destroy(&cf->bgt_lock_attr)) { + lprintf(fatal, + "Cache_alloc(): could not destroy bgt_lock_attr!\n"); + } - if (cf->path) { - FREE(cf->path); - } + if (cf->path) { + FREE(cf->path); + } - if (cf->seg) { - FREE(cf->seg); - } + if (cf->seg) { + FREE(cf->seg); + } - if (cf->fs_path) { - FREE(cf->fs_path); - } + if (cf->fs_path) { + FREE(cf->fs_path); + } - FREE(cf); + FREE(cf); } /** @@ -517,32 +580,35 @@ static void Cache_free(Cache *cf) */ static int Cache_exist(const char *fn) { - char *metafn = path_append(META_DIR, fn); - char *datafn = path_append(DATA_DIR, fn); - /* access() returns 0 on success */ - int no_meta = access(metafn, F_OK); - int no_data = access(datafn, F_OK); + char *metafn = path_append(META_DIR, fn); + char *datafn = path_append(DATA_DIR, fn); + /* + * access() returns 0 on success + */ + int no_meta = access(metafn, F_OK); + int no_data = access(datafn, F_OK); - if (no_meta ^ no_data) { - if (no_meta) { - lprintf(warning, "Cache_exist(): Cache file partially missing.\n"); - if(unlink(datafn)) { - lprintf(error, "Cache_exist(): unlink(): %s\n", - strerror(errno)); - } - } - if (no_data) { - if(unlink(metafn)) { - lprintf(error, "Cache_exist(): unlink(): %s\n", - strerror(errno)); - } - } - } + if (no_meta ^ no_data) { + if (no_meta) { + lprintf(warning, + "Cache_exist(): Cache file partially missing.\n"); + if (unlink(datafn)) { + lprintf(error, "Cache_exist(): unlink(): %s\n", + strerror(errno)); + } + } + if (no_data) { + if (unlink(metafn)) { + lprintf(error, "Cache_exist(): unlink(): %s\n", + strerror(errno)); + } + } + } - FREE(metafn); - FREE(datafn); + FREE(metafn); + FREE(datafn); - return no_meta | no_data; + return no_meta | no_data; } /** @@ -550,28 +616,28 @@ static int Cache_exist(const char *fn) */ void Cache_delete(const char *fn) { - if (CONFIG.mode == SONIC) { - Link *link = path_to_Link(fn); - fn = link->sonic_id; - } + if (CONFIG.mode == SONIC) { + Link *link = path_to_Link(fn); + fn = link->sonic_id; + } - char *metafn = path_append(META_DIR, fn); - char *datafn = path_append(DATA_DIR, fn); - if (!access(metafn, F_OK)) { - if(unlink(metafn)) { - lprintf(error, "Cache_delete(): unlink(): %s\n", - strerror(errno)); - } - } + char *metafn = path_append(META_DIR, fn); + char *datafn = path_append(DATA_DIR, fn); + if (!access(metafn, F_OK)) { + if (unlink(metafn)) { + lprintf(error, "Cache_delete(): unlink(): %s\n", + strerror(errno)); + } + } - if (!access(datafn, F_OK)) { - if(unlink(datafn)) { - lprintf(error, "Cache_delete(): unlink(): %s\n", - strerror(errno)); - } - } - FREE(metafn); - FREE(datafn); + if (!access(datafn, F_OK)) { + if (unlink(datafn)) { + lprintf(error, "Cache_delete(): unlink(): %s\n", + strerror(errno)); + } + } + FREE(metafn); + FREE(datafn); } /** @@ -580,18 +646,20 @@ void Cache_delete(const char *fn) * - 0 on success * - -1 on failure, with appropriate errno set. */ -static int Data_open(Cache *cf) +static int Data_open(Cache * cf) { - char *datafn = path_append(DATA_DIR, cf->path); - cf->dfp = fopen(datafn, "r+"); - FREE(datafn); - if (!cf->dfp) { - /* Failed to open the data file */ - lprintf(error, "Data_open(): fopen(%s): %s\n", datafn, - strerror(errno)); - return -1; - } - return 0; + char *datafn = path_append(DATA_DIR, cf->path); + cf->dfp = fopen(datafn, "r+"); + FREE(datafn); + if (!cf->dfp) { + /* + * Failed to open the data file + */ + lprintf(error, "Data_open(): fopen(%s): %s\n", datafn, + strerror(errno)); + return -1; + } + return 0; } /** @@ -600,237 +668,268 @@ static int Data_open(Cache *cf) * - 0 on success * - -1 on failure, with appropriate errno set. */ -static int Meta_open(Cache *cf) +static int Meta_open(Cache * cf) { - char *metafn = path_append(META_DIR, cf->path); - cf->mfp = fopen(metafn, "r+"); - if (!cf->mfp) { - /* Failed to open the data file */ - lprintf(error, "Meta_open(): fopen(%s): %s\n", metafn, - strerror(errno)); - FREE(metafn); - return -1; - } - FREE(metafn); - return 0; + char *metafn = path_append(META_DIR, cf->path); + cf->mfp = fopen(metafn, "r+"); + if (!cf->mfp) { + /* + * Failed to open the data file + */ + lprintf(error, "Meta_open(): fopen(%s): %s\n", metafn, + strerror(errno)); + FREE(metafn); + return -1; + } + FREE(metafn); + return 0; } /** * \brief Create a metafile * \return exit on error */ -static void Meta_create(Cache *cf) +static void Meta_create(Cache * cf) { - char *metafn = path_append(META_DIR, cf->path); - cf->mfp = fopen(metafn, "w"); - if (!cf->mfp) { - /* Failed to open the data file */ - lprintf(fatal, "Meta_create(): fopen(%s): %s\n", metafn, - strerror(errno)); - } - FREE(metafn); + char *metafn = path_append(META_DIR, cf->path); + cf->mfp = fopen(metafn, "w"); + if (!cf->mfp) { + /* + * Failed to open the data file + */ + lprintf(fatal, "Meta_create(): fopen(%s): %s\n", metafn, + strerror(errno)); + } + FREE(metafn); } int Cache_create(const char *path) { - Link *this_link = path_to_Link(path); + Link *this_link = path_to_Link(path); - char *fn = ""; - if (CONFIG.mode == NORMAL) { - fn = curl_easy_unescape(NULL, this_link->f_url + ROOT_LINK_OFFSET, 0, - NULL); - } else if (CONFIG.mode == SONIC) { - fn = this_link->sonic_id; - } - lprintf(debug, "Cache_create(): Creating cache files for %s.\n", fn); + char *fn = ""; + if (CONFIG.mode == NORMAL) { + fn = curl_easy_unescape(NULL, + this_link->f_url + ROOT_LINK_OFFSET, 0, + NULL); + } else if (CONFIG.mode == SONIC) { + fn = this_link->sonic_id; + } + lprintf(debug, "Cache_create(): Creating cache files for %s.\n", fn); - Cache *cf = Cache_alloc(); - cf->path = strndup(fn, MAX_PATH_LEN); - cf->time = this_link->time; - cf->content_length = this_link->content_length; - cf->blksz = CONFIG.data_blksz; - cf->segbc = (cf->content_length / cf->blksz) + 1; - cf->seg = CALLOC(cf->segbc, sizeof(Seg)); + Cache *cf = Cache_alloc(); + cf->path = strndup(fn, MAX_PATH_LEN); + cf->time = this_link->time; + cf->content_length = this_link->content_length; + cf->blksz = CONFIG.data_blksz; + cf->segbc = (cf->content_length / cf->blksz) + 1; + cf->seg = CALLOC(cf->segbc, sizeof(Seg)); - Meta_create(cf); + Meta_create(cf); - if (fclose(cf->mfp)) { - lprintf(error, - "Cache_create(): cannot close metadata after creation: %s.\n", - strerror(errno)); - } + if (fclose(cf->mfp)) { + lprintf(error, + "Cache_create(): cannot close metadata after creation: %s.\n", + strerror(errno)); + } - if (Meta_open(cf)) { - Cache_free(cf); - lprintf(error, "Cache_create(): cannot open metadata file, %s.\n", fn); - } + if (Meta_open(cf)) { + Cache_free(cf); + lprintf(error, + "Cache_create(): cannot open metadata file, %s.\n", fn); + } - if (Meta_write(cf)) { - lprintf(error, "Cache_create(): Meta_write() failed!\n"); - } + if (Meta_write(cf)) { + lprintf(error, "Cache_create(): Meta_write() failed!\n"); + } - if (fclose(cf->mfp)) { - lprintf(error, - "Cache_create(): cannot close metadata after write, %s.\n", - strerror(errno)); - } + if (fclose(cf->mfp)) { + lprintf(error, + "Cache_create(): cannot close metadata after write, %s.\n", + strerror(errno)); + } - Data_create(cf); + Data_create(cf); - Cache_free(cf); + Cache_free(cf); - int res = Cache_exist(fn); + int res = Cache_exist(fn); - if (CONFIG.mode == NORMAL) { - curl_free(fn); - } + if (CONFIG.mode == NORMAL) { + curl_free(fn); + } - return res; + return res; } Cache *Cache_open(const char *fn) { - /* Obtain the link structure memory pointer */ - Link *link = path_to_Link(fn); - if (!link) { - /* There is no associated link to the path */ - return NULL; - } + /* + * Obtain the link structure memory pointer + */ + Link *link = path_to_Link(fn); + if (!link) { + /* + * There is no associated link to the path + */ + return NULL; + } - lprintf(cache_lock_debug, "Cache_open(): thread %x: locking cf_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf_lock); + lprintf(cache_lock_debug, + "Cache_open(): thread %x: locking cf_lock;\n", pthread_self()); + PTHREAD_MUTEX_LOCK(&cf_lock); - if (link->cache_opened) { - link->cache_opened++; - lprintf(cache_lock_debug, - "Cache_open(): thread %x: unlocking cf_lock;\n", pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf_lock); - return link->cache_ptr; - } + if (link->cache_opened) { + link->cache_opened++; + lprintf(cache_lock_debug, + "Cache_open(): thread %x: unlocking cf_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf_lock); + return link->cache_ptr; + } - /* Check if both metadata and data file exist */ - if (CONFIG.mode == NORMAL) { - if (Cache_exist(fn)) { - return NULL; - } - } else if (CONFIG.mode == SONIC) { - if (Cache_exist(link->sonic_id)) { - return NULL; - } - } + /* + * Check if both metadata and data file exist + */ + if (CONFIG.mode == NORMAL) { + if (Cache_exist(fn)) { + return NULL; + } + } else if (CONFIG.mode == SONIC) { + if (Cache_exist(link->sonic_id)) { + return NULL; + } + } - /* Create the cache in-memory data structure */ - Cache *cf = Cache_alloc(); + /* + * Create the cache in-memory data structure + */ + Cache *cf = Cache_alloc(); - /* Fill in the fs_path */ - cf->fs_path = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - strncpy(cf->fs_path, fn, MAX_PATH_LEN); + /* + * Fill in the fs_path + */ + cf->fs_path = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + strncpy(cf->fs_path, fn, MAX_PATH_LEN); - /* Set the path for the local cache file, if we are in sonic mode */ - if (CONFIG.mode == SONIC) { - fn = link->sonic_id; - } + /* + * Set the path for the local cache file, if we are in sonic mode + */ + if (CONFIG.mode == SONIC) { + fn = link->sonic_id; + } - cf->path = strndup(fn, MAX_PATH_LEN); + cf->path = strndup(fn, MAX_PATH_LEN); - /* Associate the cache structure with a link */ - cf->link = link; + /* + * Associate the cache structure with a link + */ + cf->link = link; - if (Meta_open(cf)) { - Cache_free(cf); - lprintf(error, "Cache_open(): cannot open metadata file %s.\n", fn); - return NULL; - } + if (Meta_open(cf)) { + Cache_free(cf); + lprintf(error, "Cache_open(): cannot open metadata file %s.\n", + fn); + return NULL; + } - /* Corrupt metadata */ - if (Meta_read(cf)) { - Cache_free(cf); - lprintf(error, "Cache_open(): metadata error: %s.\n", fn); - return NULL; - } + /* + * Corrupt metadata + */ + if (Meta_read(cf)) { + Cache_free(cf); + lprintf(error, "Cache_open(): metadata error: %s.\n", fn); + return NULL; + } - /* - * Inconsistency between metadata and data file, note that on disk file - * size might be bigger than content_length, due to on-disk filesystem - * allocation policy. - */ - if (cf->content_length > Data_size(fn)) { - lprintf(error, "Cache_open(): metadata inconsistency %s, \ -cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length, - Data_size(fn)); - Cache_free(cf); - return NULL; - } + /* + * Inconsistency between metadata and data file, note that on disk file + * size might be bigger than content_length, due to on-disk filesystem + * allocation policy. + */ + if (cf->content_length > Data_size(fn)) { + lprintf(error, "Cache_open(): metadata inconsistency %s, \ +cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length, Data_size(fn)); + Cache_free(cf); + return NULL; + } - /* Check if the cache files are not outdated */ - if (cf->time != cf->link->time) { - lprintf(warning, "Cache_open(): outdated cache file: %s.\n", fn); - Cache_free(cf); - return NULL; - } + /* + * Check if the cache files are not outdated + */ + if (cf->time != cf->link->time) { + lprintf(warning, "Cache_open(): outdated cache file: %s.\n", + fn); + Cache_free(cf); + return NULL; + } - if (Data_open(cf)) { - Cache_free(cf); - lprintf(error, "Cache_open(): cannot open data file %s.\n", fn); - return NULL; - } + if (Data_open(cf)) { + Cache_free(cf); + lprintf(error, "Cache_open(): cannot open data file %s.\n", fn); + return NULL; + } - cf->link->cache_opened = 1; - /* Yup, we just created a circular loop. ;) */ - cf->link->cache_ptr = cf; + cf->link->cache_opened = 1; + /* + * Yup, we just created a circular loop. ;) + */ + cf->link->cache_ptr = cf; - lprintf(cache_lock_debug, "Cache_open(): thread %x: unlocking cf_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf_lock); + lprintf(cache_lock_debug, + "Cache_open(): thread %x: unlocking cf_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf_lock); - return cf; + return cf; } -void Cache_close(Cache *cf) +void Cache_close(Cache * cf) { - lprintf(cache_lock_debug, "Cache_close(): thread %x: locking cf_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf_lock); + lprintf(cache_lock_debug, + "Cache_close(): thread %x: locking cf_lock;\n", pthread_self()); + PTHREAD_MUTEX_LOCK(&cf_lock); - cf->link->cache_opened--; + cf->link->cache_opened--; - if (cf->link->cache_opened > 0) { - lprintf(cache_lock_debug, - "Cache_close(): thread %x: unlocking cf_lock;\n", pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf_lock); - return; - } + if (cf->link->cache_opened > 0) { + lprintf(cache_lock_debug, + "Cache_close(): thread %x: unlocking cf_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf_lock); + return; + } - if (Meta_write(cf)) { - lprintf(error, "Cache_close(): Meta_write() error."); - } + if (Meta_write(cf)) { + lprintf(error, "Cache_close(): Meta_write() error."); + } - if (fclose(cf->mfp)) { - lprintf(error, "Cache_close(): cannot close metadata: %s.\n", - strerror(errno)); - } + if (fclose(cf->mfp)) { + lprintf(error, "Cache_close(): cannot close metadata: %s.\n", + strerror(errno)); + } - if (fclose(cf->dfp)) { - lprintf(error, "Cache_close(): cannot close data file %s.\n", - strerror(errno)); - } + if (fclose(cf->dfp)) { + lprintf(error, "Cache_close(): cannot close data file %s.\n", + strerror(errno)); + } - lprintf(cache_lock_debug, "Cache_close(): thread %x: unlocking cf_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf_lock); + lprintf(cache_lock_debug, + "Cache_close(): thread %x: unlocking cf_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf_lock); - return Cache_free(cf); + return Cache_free(cf); } /** * \brief Check if a segment exists. * \return 1 if the segment exists */ -static int Seg_exist(Cache *cf, off_t offset) +static int Seg_exist(Cache * cf, off_t offset) { - off_t byte = offset / cf->blksz; - return cf->seg[byte]; + off_t byte = offset / cf->blksz; + return cf->seg[byte]; } /** @@ -840,10 +939,10 @@ static int Seg_exist(Cache *cf, off_t offset) * \param[in] i 1 for exist, 0 for doesn't exist * \note Call this after downloading a segment. */ -static void Seg_set(Cache *cf, off_t offset, int i) +static void Seg_set(Cache * cf, off_t offset, int i) { - off_t byte = offset / cf->blksz; - cf->seg[byte] = i; + off_t byte = offset / cf->blksz; + cf->seg[byte] = i; } /** @@ -854,132 +953,152 @@ static void Seg_set(Cache *cf, off_t offset, int i) */ static void *Cache_bgdl(void *arg) { - Cache *cf = (Cache *) arg; + Cache *cf = (Cache *) arg; - lprintf(cache_lock_debug, "Cache_bgdl(): thread %x: locking w_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf->w_lock); + lprintf(cache_lock_debug, "Cache_bgdl(): thread %x: locking w_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&cf->w_lock); - uint8_t *recv_buf = CALLOC(cf->blksz, sizeof(uint8_t)); - lprintf(debug, "Cache_bgdl(): thread %x spawned.\n ", pthread_self()); - long recv = path_download(cf->fs_path, (char *) recv_buf, cf->blksz, - cf->next_dl_offset); - if (recv < 0) { - lprintf(error, "Cache_bgdl(): thread %x received %ld bytes, \ + uint8_t *recv_buf = CALLOC(cf->blksz, sizeof(uint8_t)); + lprintf(debug, "Cache_bgdl(): thread %x spawned.\n ", pthread_self()); + long recv = path_download(cf->fs_path, (char *)recv_buf, cf->blksz, + cf->next_dl_offset); + if (recv < 0) { + lprintf(error, "Cache_bgdl(): thread %x received %ld bytes, \ which does't make sense\n", pthread_self(), recv); - } + } - if ( (recv == cf->blksz) || - (cf->next_dl_offset == (cf->content_length / cf->blksz * cf->blksz)) ) - { - Data_write(cf, recv_buf, recv, cf->next_dl_offset); - Seg_set(cf, cf->next_dl_offset, 1); - } else { - lprintf(error, - "Cache_bgdl(): received %ld rather than %ld, possible network \ + if ((recv == cf->blksz) || + (cf->next_dl_offset == + (cf->content_length / cf->blksz * cf->blksz))) { + Data_write(cf, recv_buf, recv, cf->next_dl_offset); + Seg_set(cf, cf->next_dl_offset, 1); + } else { + lprintf(error, + "Cache_bgdl(): received %ld rather than %ld, possible network \ error.\n", recv, cf->blksz); - } + } - FREE(recv_buf); + FREE(recv_buf); - lprintf(cache_lock_debug, "Cache_bgdl(): thread %x: unlocking bgt_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->bgt_lock); + lprintf(cache_lock_debug, + "Cache_bgdl(): thread %x: unlocking bgt_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->bgt_lock); - lprintf(cache_lock_debug, "Cache_bgdl(): thread %x: unlocking w_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->w_lock); + lprintf(cache_lock_debug, + "Cache_bgdl(): thread %x: unlocking w_lock;\n", pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->w_lock); - pthread_detach(pthread_self()); - pthread_exit(NULL); + pthread_detach(pthread_self()); + pthread_exit(NULL); } -long Cache_read(Cache *cf, char * const output_buf, const off_t len, - const off_t offset_start) +long +Cache_read(Cache * cf, char *const output_buf, const off_t len, + const off_t offset_start) { - long send; + long send; - /* The offset of the segment to be downloaded */ - off_t dl_offset = (offset_start + len) / cf->blksz * cf->blksz; + /* + * The offset of the segment to be downloaded + */ + off_t dl_offset = (offset_start + len) / cf->blksz * cf->blksz; - /* ------------------ Check if the segment already exists ---------------*/ - if (Seg_exist(cf, dl_offset)) { - send = Data_read(cf, (uint8_t *) output_buf, len, offset_start); - goto bgdl; - } else { - /* Wait for any other download thread to finish*/ + /* + * ------------------ Check if the segment already exists + * --------------- + */ + if (Seg_exist(cf, dl_offset)) { + send = Data_read(cf, (uint8_t *) output_buf, len, offset_start); + goto bgdl; + } else { + /* + * Wait for any other download thread to finish + */ - lprintf(cache_lock_debug, "Cache_read(): thread %ld: locking w_lock;\n", - pthread_self()); - PTHREAD_MUTEX_LOCK(&cf->w_lock); + lprintf(cache_lock_debug, + "Cache_read(): thread %ld: locking w_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&cf->w_lock); - if (Seg_exist(cf, dl_offset)) { - /* The segment now exists - it was downloaded by another - * download thread. Send it off and unlock the I/O */ - send = Data_read(cf, (uint8_t *) output_buf, len, offset_start); + if (Seg_exist(cf, dl_offset)) { + /* + * The segment now exists - it was downloaded by another + * download thread. Send it off and unlock the I/O + */ + send = + Data_read(cf, (uint8_t *) output_buf, len, + offset_start); - lprintf(cache_lock_debug, - "Cache_read(): thread %x: unlocking w_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->w_lock); + lprintf(cache_lock_debug, + "Cache_read(): thread %x: unlocking w_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->w_lock); - goto bgdl; - } - } + goto bgdl; + } + } - /* ------------------------Download the segment -------------------------*/ + /* + * ------------------------Download the segment + * ------------------------- + */ - uint8_t *recv_buf = CALLOC(cf->blksz, sizeof(uint8_t)); - lprintf(debug, "Cache_read(): thread %x: spawned.\n ", pthread_self()); - long recv = path_download(cf->fs_path, (char *) recv_buf, cf->blksz, - dl_offset); - if (recv < 0) { - lprintf(error, "Cache_read(): thread %x received %ld bytes, \ + uint8_t *recv_buf = CALLOC(cf->blksz, sizeof(uint8_t)); + lprintf(debug, "Cache_read(): thread %x: spawned.\n ", pthread_self()); + long recv = path_download(cf->fs_path, (char *)recv_buf, cf->blksz, + dl_offset); + if (recv < 0) { + lprintf(error, "Cache_read(): thread %x received %ld bytes, \ which does't make sense\n", pthread_self(), recv); - } - /* - * check if we have received enough data, write it to the disk - * - * Condition 1: received the exact amount as the segment size. - * Condition 2: offset is the last segment - */ - if ( (recv == cf->blksz) || - (dl_offset == (cf->content_length / cf->blksz * cf->blksz)) ) - { - Data_write(cf, recv_buf, recv, dl_offset); - Seg_set(cf, dl_offset, 1); - } else { - lprintf(error, - "Cache_read(): received %ld rather than %ld, possible network \ + } + /* + * check if we have received enough data, write it to the disk + * + * Condition 1: received the exact amount as the segment size. + * Condition 2: offset is the last segment + */ + if ((recv == cf->blksz) || + (dl_offset == (cf->content_length / cf->blksz * cf->blksz))) { + Data_write(cf, recv_buf, recv, dl_offset); + Seg_set(cf, dl_offset, 1); + } else { + lprintf(error, + "Cache_read(): received %ld rather than %ld, possible network \ error.\n", recv, cf->blksz); - } - FREE(recv_buf); - send = Data_read(cf, (uint8_t *) output_buf, len, offset_start); + } + FREE(recv_buf); + send = Data_read(cf, (uint8_t *) output_buf, len, offset_start); - lprintf(cache_lock_debug, "Cache_read(): thread %x: unlocking w_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&cf->w_lock); + lprintf(cache_lock_debug, + "Cache_read(): thread %x: unlocking w_lock;\n", pthread_self()); + PTHREAD_MUTEX_UNLOCK(&cf->w_lock); - /* -----------Download the next segment in background -------------------*/ - bgdl: - {} - off_t next_dl_offset = round_div(offset_start, cf->blksz) * cf->blksz; - if ( (next_dl_offset > dl_offset) && - !Seg_exist(cf, next_dl_offset) && - next_dl_offset < cf->content_length ){ - /* Stop the spawning of multiple background pthreads */ - if(!pthread_mutex_trylock(&cf->bgt_lock)) { - lprintf(cache_lock_debug, - "Cache_read(): thread %x: trylocked bgt_lock;\n", - pthread_self()); - cf->next_dl_offset = next_dl_offset; - if (pthread_create(&cf->bgt, NULL, Cache_bgdl, cf)) { - lprintf(error, - "Cache_read(): Error creating background download thread\n" - ); - } - } - } + /* + * -----------Download the next segment in background + * ------------------- + */ + bgdl: + { + } + off_t next_dl_offset = round_div(offset_start, cf->blksz) * cf->blksz; + if ((next_dl_offset > dl_offset) && !Seg_exist(cf, next_dl_offset) + && next_dl_offset < cf->content_length) { + /* + * Stop the spawning of multiple background pthreads + */ + if (!pthread_mutex_trylock(&cf->bgt_lock)) { + lprintf(cache_lock_debug, + "Cache_read(): thread %x: trylocked bgt_lock;\n", + pthread_self()); + cf->next_dl_offset = next_dl_offset; + if (pthread_create(&cf->bgt, NULL, Cache_bgdl, cf)) { + lprintf(error, + "Cache_read(): Error creating background download thread\n"); + } + } + } - return send; + return send; } diff --git a/src/config.c b/src/config.c index 7d97883..99ceb74 100644 --- a/src/config.c +++ b/src/config.c @@ -28,46 +28,46 @@ ConfigStruct CONFIG; */ void Config_init(void) { - CONFIG.mode = NORMAL; + CONFIG.mode = NORMAL; - CONFIG.log_level = log_level_init(); + CONFIG.log_type = log_level_init(); /*---------------- Network related --------------*/ - CONFIG.http_username = NULL; + CONFIG.http_username = NULL; - CONFIG.http_password = NULL; + CONFIG.http_password = NULL; - CONFIG.proxy = NULL; + CONFIG.proxy = NULL; - CONFIG.proxy_username = NULL; + CONFIG.proxy_username = NULL; - CONFIG.proxy_password = NULL; + CONFIG.proxy_password = NULL; - CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS; + CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS; - CONFIG.user_agent = DEFAULT_USER_AGENT; + CONFIG.user_agent = DEFAULT_USER_AGENT; - CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC; + CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC; - CONFIG.no_range_check = 0; + CONFIG.no_range_check = 0; - CONFIG.insecure_tls = 0; + CONFIG.insecure_tls = 0; /*--------------- Cache related ---------------*/ - CONFIG.cache_enabled = 0; + CONFIG.cache_enabled = 0; - CONFIG.cache_dir = NULL; + CONFIG.cache_dir = NULL; - CONFIG.data_blksz = DEFAULT_DATA_BLKSZ; + CONFIG.data_blksz = DEFAULT_DATA_BLKSZ; - CONFIG.max_segbc = DEFAULT_MAX_SEGBC; + CONFIG.max_segbc = DEFAULT_MAX_SEGBC; /*-------------- Sonic related -------------*/ - CONFIG.sonic_username = NULL; + CONFIG.sonic_username = NULL; - CONFIG.sonic_password = NULL; + CONFIG.sonic_password = NULL; - CONFIG.sonic_id3 = 0; + CONFIG.sonic_id3 = 0; - CONFIG.sonic_insecure = 0; -} \ No newline at end of file + CONFIG.sonic_insecure = 0; +} diff --git a/src/config.h b/src/config.h index b71951b..833d410 100644 --- a/src/config.h +++ b/src/config.h @@ -41,7 +41,7 @@ typedef struct { /** \brief Operation Mode */ OperationMode mode; /** \brief Current log level */ - int log_level; + int log_type; /*---------------- Network related --------------*/ /** \brief HTTP username */ char *http_username; diff --git a/src/fuse_local.c b/src/fuse_local.c index 0948897..6cf453e 100644 --- a/src/fuse_local.c +++ b/src/fuse_local.c @@ -2,7 +2,9 @@ #include "cache.h" -/* must be included before including */ +/* + * must be included before including + */ #define FUSE_USE_VERSION 26 #include @@ -12,105 +14,106 @@ static void *fs_init(struct fuse_conn_info *conn) { - (void) conn; - return NULL; + (void)conn; + return NULL; } /** \brief release an opened file */ static int fs_release(const char *path, struct fuse_file_info *fi) { - (void) path; - if (CACHE_SYSTEM_INIT) { - Cache_close((Cache *)fi->fh); - } - return 0; + (void)path; + if (CACHE_SYSTEM_INIT) { + Cache_close((Cache *) fi->fh); + } + return 0; } /** \brief return the attributes for a single file indicated by path */ static int fs_getattr(const char *path, struct stat *stbuf) { - int res = 0; - memset(stbuf, 0, sizeof(struct stat)); + int res = 0; + memset(stbuf, 0, sizeof(struct stat)); - if (!strcmp(path, "/")) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 1; - } else { - Link *link = path_to_Link(path); - if (!link) { - return -ENOENT; - } - struct timespec spec; - spec.tv_sec = link->time; + if (!strcmp(path, "/")) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 1; + } else { + Link *link = path_to_Link(path); + if (!link) { + return -ENOENT; + } + struct timespec spec; + spec.tv_sec = link->time; #if defined(__APPLE__) && defined(__MACH__) - stbuf->st_mtimespec = spec; + stbuf->st_mtimespec = spec; #else - stbuf->st_mtim = spec; + stbuf->st_mtim = spec; #endif - switch (link->type) { - case LINK_DIR: - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 1; - break; - case LINK_FILE: - stbuf->st_mode = S_IFREG | 0444; - stbuf->st_nlink = 1; - stbuf->st_size = link->content_length; - stbuf->st_blksize = 128*1024; - stbuf->st_blocks = (link->content_length)/512; - break; - default: - return -ENOENT; - } - } - stbuf->st_uid = getuid(); - stbuf->st_gid = getgid(); + switch (link->type) { + case LINK_DIR: + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 1; + break; + case LINK_FILE: + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = link->content_length; + stbuf->st_blksize = 128 * 1024; + stbuf->st_blocks = (link->content_length) / 512; + break; + default: + return -ENOENT; + } + } + stbuf->st_uid = getuid(); + stbuf->st_gid = getgid(); - return res; + return res; } /** \brief read a file */ -static int fs_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) +static int +fs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) { - long received; - if (CACHE_SYSTEM_INIT) { - received = Cache_read((Cache *)fi->fh, buf, size, offset); - } else { - received = path_download(path, buf, size, offset); - } - return received; + long received; + if (CACHE_SYSTEM_INIT) { + received = Cache_read((Cache *) fi->fh, buf, size, offset); + } else { + received = path_download(path, buf, size, offset); + } + return received; } /** \brief open a file indicated by the path */ static int fs_open(const char *path, struct fuse_file_info *fi) { - Link *link = path_to_Link(path); - if (!link) { - return -ENOENT; - } - if ((fi->flags & 3) != O_RDONLY) { - return -EACCES; - } - if (CACHE_SYSTEM_INIT) { - fi->fh = (uint64_t) Cache_open(path); - if (!fi->fh) { - /* - * The link clearly exists, the cache cannot be opened, attempt - * cache creation - */ - Cache_delete(path); - Cache_create(path); - fi->fh = (uint64_t) Cache_open(path); - /* - * The cache definitely cannot be opened for some reason. - */ - if (!fi->fh) { - return -ENOENT; - } - } - } - return 0; + Link *link = path_to_Link(path); + if (!link) { + return -ENOENT; + } + if ((fi->flags & 3) != O_RDONLY) { + return -EACCES; + } + if (CACHE_SYSTEM_INIT) { + fi->fh = (uint64_t) Cache_open(path); + if (!fi->fh) { + /* + * The link clearly exists, the cache cannot be opened, attempt + * cache creation + */ + Cache_delete(path); + Cache_create(path); + fi->fh = (uint64_t) Cache_open(path); + /* + * The cache definitely cannot be opened for some reason. + */ + if (!fi->fh) { + return -ENOENT; + } + } + } + return 0; } /** @@ -124,46 +127,49 @@ static int fs_open(const char *path, struct fuse_file_info *fi) * generate the LinkTables for previous level directories. We might * as well maintain our own tree structure. */ -static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add, - off_t offset, struct fuse_file_info *fi) +static int +fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add, + off_t offset, struct fuse_file_info *fi) { - (void) offset; - (void) fi; + (void)offset; + (void)fi; - LinkTable *linktbl; + LinkTable *linktbl; - if (!strcmp(path, "/")) { - linktbl = ROOT_LINK_TBL; - } else { - linktbl = path_to_Link_LinkTable_new(path); - if(!linktbl) { - return -ENOENT; - } - } + if (!strcmp(path, "/")) { + linktbl = ROOT_LINK_TBL; + } else { + linktbl = path_to_Link_LinkTable_new(path); + if (!linktbl) { + return -ENOENT; + } + } - /* start adding the links */ - dir_add(buf, ".", NULL, 0); - dir_add(buf, "..", NULL, 0); - for (int i = 1; i < linktbl->num; i++) { - Link *link = linktbl->links[i]; - if (link->type != LINK_INVALID) { - dir_add(buf, link->linkname, NULL, 0); - } - } + /* + * start adding the links + */ + dir_add(buf, ".", NULL, 0); + dir_add(buf, "..", NULL, 0); + for (int i = 1; i < linktbl->num; i++) { + Link *link = linktbl->links[i]; + if (link->type != LINK_INVALID) { + dir_add(buf, link->linkname, NULL, 0); + } + } - return 0; + return 0; } static struct fuse_operations fs_oper = { - .getattr = fs_getattr, - .readdir = fs_readdir, - .open = fs_open, - .read = fs_read, - .init = fs_init, - .release = fs_release + .getattr = fs_getattr, + .readdir = fs_readdir, + .open = fs_open, + .read = fs_read, + .init = fs_init, + .release = fs_release }; int fuse_local_init(int argc, char **argv) { - return fuse_main(argc, argv, &fs_oper, NULL); + return fuse_main(argc, argv, &fs_oper, NULL); } diff --git a/src/link.c b/src/link.c index b2d7c90..fd93f0e 100644 --- a/src/link.c +++ b/src/link.c @@ -16,11 +16,15 @@ #define STATUS_LEN 64 -/* ---------------- External variables -----------------------*/ +/* + * ---------------- External variables ----------------------- + */ LinkTable *ROOT_LINK_TBL = NULL; int ROOT_LINK_OFFSET = 0; -/* ----------------- Static variables ----------------------- */ +/* + * ----------------- Static variables ----------------------- + */ /** * \brief LinkTable generation priority lock @@ -31,54 +35,65 @@ static pthread_mutex_t link_lock; LinkTable *LinkSystem_init(const char *raw_url) { - /* Remove excess '/' if it is there */ - char *url = strdup(raw_url); - int url_len = strnlen(url, MAX_PATH_LEN) - 1; - if (url[url_len] == '/') { - url[url_len] = '\0'; - } + /* + * Remove excess '/' if it is there + */ + char *url = strdup(raw_url); + int url_len = strnlen(url, MAX_PATH_LEN) - 1; + if (url[url_len] == '/') { + url[url_len] = '\0'; + } - if (pthread_mutex_init(&link_lock, NULL) != 0) { - lprintf(error, - "link_system_init(): link_lock initialisation failed!\n"); - } + if (pthread_mutex_init(&link_lock, NULL)) { + lprintf(error, + "link_system_init(): link_lock initialisation failed!\n"); + } - /* --------- Set the length of the root link ----------- */ - /* This is where the '/' should be */ - ROOT_LINK_OFFSET = strnlen(url, MAX_PATH_LEN) + 1; + /* + * --------- Set the length of the root link ----------- + */ + /* + * This is where the '/' should be + */ + ROOT_LINK_OFFSET = strnlen(url, MAX_PATH_LEN) + 1; - /* --------------------- Enable cache system -------------------- */ - if (CONFIG.cache_enabled) { - if (CONFIG.cache_dir) { - CacheSystem_init(CONFIG.cache_dir, 0); - } else { - CacheSystem_init(url, 1); - } - } + /* + * --------------------- Enable cache system -------------------- + */ + if (CONFIG.cache_enabled) { + if (CONFIG.cache_dir) { + CacheSystem_init(CONFIG.cache_dir, 0); + } else { + CacheSystem_init(url, 1); + } + } - /* ----------- Create the root link table --------------*/ - if (CONFIG.mode == NORMAL) { - ROOT_LINK_TBL = LinkTable_new(url); - } else if (CONFIG.mode == SONIC) { - sonic_config_init(url, CONFIG.sonic_username, CONFIG.sonic_password); - if (!CONFIG.sonic_id3) { - ROOT_LINK_TBL = sonic_LinkTable_new_index("0"); - } else { - ROOT_LINK_TBL = sonic_LinkTable_new_id3(0, "0"); - } - } - FREE(url); - return ROOT_LINK_TBL; + /* + * ----------- Create the root link table -------------- + */ + if (CONFIG.mode == NORMAL) { + ROOT_LINK_TBL = LinkTable_new(url); + } else if (CONFIG.mode == SONIC) { + sonic_config_init(url, CONFIG.sonic_username, + CONFIG.sonic_password); + if (!CONFIG.sonic_id3) { + ROOT_LINK_TBL = sonic_LinkTable_new_index("0"); + } else { + ROOT_LINK_TBL = sonic_LinkTable_new_id3(0, "0"); + } + } + FREE(url); + return ROOT_LINK_TBL; } -void LinkTable_add(LinkTable *linktbl, Link *link) +void LinkTable_add(LinkTable * linktbl, Link * link) { - linktbl->num++; - linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *)); - if (!linktbl->links) { - lprintf(fatal, "LinkTable_add(): realloc() failure!\n"); - } - linktbl->links[linktbl->num - 1] = link; + linktbl->num++; + linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *)); + if (!linktbl->links) { + lprintf(fatal, "LinkTable_add(): realloc() failure!\n"); + } + linktbl->links[linktbl->num - 1] = link; } /** @@ -86,41 +101,48 @@ void LinkTable_add(LinkTable *linktbl, Link *link) */ static Link *Link_new(const char *linkname, LinkType type) { - Link *link = CALLOC(1, sizeof(Link)); + Link *link = CALLOC(1, sizeof(Link)); - strncpy(link->linkname, linkname, MAX_FILENAME_LEN); - link->type = type; + strncpy(link->linkname, linkname, MAX_FILENAME_LEN); + link->type = type; - /* remove the '/' from linkname if it exists */ - char *c = &(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]); - if ( *c == '/') { - *c = '\0'; - } + /* + * remove the '/' from linkname if it exists + */ + char *c = + &(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]); + if (*c == '/') { + *c = '\0'; + } - return link; + return link; } static LinkType linkname_to_LinkType(const char *linkname) { - /* The link name has to start with alphanumerical character */ - if (!isalnum(linkname[0]) && (linkname[0] != '%')) { - return LINK_INVALID; - } + /* + * The link name has to start with alphanumerical character + */ + if (!isalnum(linkname[0]) && (linkname[0] != '%')) { + return LINK_INVALID; + } - /* Check for stray '/' */ - char *slash = strchr(linkname, '/'); - if (slash) { - int linkname_len = strnlen(linkname, MAX_FILENAME_LEN) - 1; - if (slash - linkname != linkname_len) { - return LINK_INVALID; - } - } + /* + * Check for stray '/' + */ + char *slash = strchr(linkname, '/'); + if (slash) { + int linkname_len = strnlen(linkname, MAX_FILENAME_LEN) - 1; + if (slash - linkname != linkname_len) { + return LINK_INVALID; + } + } - if ( linkname[strnlen(linkname, MAX_FILENAME_LEN) - 1] == '/' ) { - return LINK_DIR; - } + if (linkname[strnlen(linkname, MAX_FILENAME_LEN) - 1] == '/') { + return LINK_DIR; + } - return LINK_UNINITIALISED_FILE; + return LINK_UNINITIALISED_FILE; } /** @@ -128,149 +150,161 @@ static LinkType linkname_to_LinkType(const char *linkname) */ static int linknames_equal(char *linkname, const char *linkname_new) { - if (!strncmp(linkname, linkname_new, MAX_FILENAME_LEN)) { - return 1; - } + if (!strncmp(linkname, linkname_new, MAX_FILENAME_LEN)) { + return 1; + } - /* check if the link names differ by a single '/' */ - if (!strncmp(linkname, linkname_new, strnlen(linkname, MAX_FILENAME_LEN))) { - size_t linkname_new_len = strnlen(linkname_new, MAX_FILENAME_LEN); - if ( (linkname_new_len - strnlen(linkname, MAX_FILENAME_LEN) == 1) && - (linkname_new[linkname_new_len - 1] == '/')) { - return 1; - } - } - return 0; + /* + * check if the link names differ by a single '/' + */ + if (!strncmp + (linkname, linkname_new, strnlen(linkname, MAX_FILENAME_LEN))) { + size_t linkname_new_len = + strnlen(linkname_new, MAX_FILENAME_LEN); + if ((linkname_new_len - strnlen(linkname, MAX_FILENAME_LEN) == + 1) + && (linkname_new[linkname_new_len - 1] == '/')) { + return 1; + } + } + return 0; } /** * Shamelessly copied and pasted from: * https://github.com/google/gumbo-parser/blob/master/examples/find_links.cc */ -static void HTML_to_LinkTable(GumboNode *node, LinkTable *linktbl) +static void HTML_to_LinkTable(GumboNode * node, LinkTable * linktbl) { - if (node->type != GUMBO_NODE_ELEMENT) { - return; - } - GumboAttribute* href; - if (node->v.element.tag == GUMBO_TAG_A && - (href = gumbo_get_attribute(&node->v.element.attributes, "href"))) { - /* if it is valid, copy the link onto the heap */ - LinkType type = linkname_to_LinkType(href->value); - /* - * We also check if the link being added is the same as the last link. - * This is to prevent duplicated link, if an Apache server has the - * IconsAreLinks option. - */ - size_t comp_len = strnlen(href->value, MAX_FILENAME_LEN); - if (type == LINK_DIR) { - comp_len--; - } - if (((type == LINK_DIR) || (type == LINK_UNINITIALISED_FILE)) && - !linknames_equal(linktbl->links[linktbl->num - 1]->linkname, - href->value)) { - LinkTable_add(linktbl, Link_new(href->value, type)); - } - } - /* Note the recursive call, lol. */ - GumboVector *children = &node->v.element.children; - for (size_t i = 0; i < children->length; ++i) { - HTML_to_LinkTable((GumboNode *)children->data[i], linktbl); - } - return; + if (node->type != GUMBO_NODE_ELEMENT) { + return; + } + GumboAttribute *href; + if (node->v.element.tag == GUMBO_TAG_A && + (href = gumbo_get_attribute(&node->v.element.attributes, "href"))) { + /* + * if it is valid, copy the link onto the heap + */ + LinkType type = linkname_to_LinkType(href->value); + /* + * We also check if the link being added is the same as the last link. + * This is to prevent duplicated link, if an Apache server has the + * IconsAreLinks option. + */ + size_t comp_len = strnlen(href->value, MAX_FILENAME_LEN); + if (type == LINK_DIR) { + comp_len--; + } + if (((type == LINK_DIR) || (type == LINK_UNINITIALISED_FILE)) && + !linknames_equal(linktbl->links[linktbl->num - 1]->linkname, + href->value)) { + LinkTable_add(linktbl, Link_new(href->value, type)); + } + } + /* + * Note the recursive call, lol. + */ + GumboVector *children = &node->v.element.children; + for (size_t i = 0; i < children->length; ++i) { + HTML_to_LinkTable((GumboNode *) children->data[i], linktbl); + } + return; } -static CURL *Link_to_curl(Link *link) +static CURL *Link_to_curl(Link * link) { - CURL *curl = curl_easy_init(); - if (!curl) { - lprintf(fatal, "Link_to_curl(): curl_easy_init() failed!\n"); - } - /* set up some basic curl stuff */ - curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - /* for following directories without the '/' */ - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2); - curl_easy_setopt(curl, CURLOPT_URL, link->f_url); - curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); - curl_easy_setopt(curl, CURLOPT_SHARE, CURL_SHARE); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); - if (CONFIG.insecure_tls) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - } + CURL *curl = curl_easy_init(); + if (!curl) { + lprintf(fatal, "Link_to_curl(): curl_easy_init() failed!\n"); + } + /* + * set up some basic curl stuff + */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + /* + * for following directories without the '/' + */ + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2); + curl_easy_setopt(curl, CURLOPT_URL, link->f_url); + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); + curl_easy_setopt(curl, CURLOPT_SHARE, CURL_SHARE); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); + if (CONFIG.insecure_tls) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + } + // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); -// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + if (CONFIG.http_username) { + curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username); + } - if (CONFIG.http_username) { - curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username); - } + if (CONFIG.http_password) { + curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password); + } - if (CONFIG.http_password) { - curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password); - } + if (CONFIG.proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy); + } - if (CONFIG.proxy) { - curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy); - } + if (CONFIG.proxy_username) { + curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, + CONFIG.proxy_username); + } - if (CONFIG.proxy_username) { - curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, - CONFIG.proxy_username); - } + if (CONFIG.proxy_password) { + curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, + CONFIG.proxy_password); + } - if (CONFIG.proxy_password) { - curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, - CONFIG.proxy_password); - } - - return curl; + return curl; } -static void Link_req_file_stat(Link *this_link) +static void Link_req_file_stat(Link * this_link) { - CURL *curl = Link_to_curl(this_link); - curl_easy_setopt(curl, CURLOPT_NOBODY, 1); - curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + CURL *curl = Link_to_curl(this_link); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); - /* - * We need to put the variable on the heap, because otherwise the - * variable gets popped from the stack as the function returns. - * - * It gets freed in curl_multi_perform_once(); - */ - TransferStruct *transfer = CALLOC(1, sizeof(TransferStruct)); + /* + * We need to put the variable on the heap, because otherwise the + * variable gets popped from the stack as the function returns. + * + * It gets freed in curl_multi_perform_once(); + */ + TransferStruct *transfer = CALLOC(1, sizeof(TransferStruct)); - transfer->link = this_link; - transfer->type = FILESTAT; - curl_easy_setopt(curl, CURLOPT_PRIVATE, transfer); + transfer->link = this_link; + transfer->type = FILESTAT; + curl_easy_setopt(curl, CURLOPT_PRIVATE, transfer); - transfer_nonblocking(curl); + transfer_nonblocking(curl); } -void Link_set_file_stat(Link* this_link, CURL *curl) +void Link_set_file_stat(Link * this_link, CURL * curl) { - long http_resp; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); - if (http_resp == HTTP_OK) { - double cl = 0; - curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); - curl_easy_getinfo(curl, CURLINFO_FILETIME, &(this_link->time)); - if (cl == -1) { - this_link->type = LINK_INVALID; - } else { - this_link->type = LINK_FILE; - this_link->content_length = cl; - } - } else { - lprintf(warning, "Link_set_file_stat(): HTTP %ld", http_resp); - if (HTTP_temp_failure(http_resp)) { - lprintf(warning, ", retrying later.\n"); - } else { - this_link->type = LINK_INVALID; - lprintf(warning, ".\n"); - } - } + long http_resp; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); + if (http_resp == HTTP_OK) { + double cl = 0; + curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); + curl_easy_getinfo(curl, CURLINFO_FILETIME, &(this_link->time)); + if (cl == -1) { + this_link->type = LINK_INVALID; + } else { + this_link->type = LINK_FILE; + this_link->content_length = cl; + } + } else { + lprintf(warning, "Link_set_file_stat(): HTTP %ld", http_resp); + if (HTTP_temp_failure(http_resp)) { + lprintf(warning, ", retrying later.\n"); + } else { + this_link->type = LINK_INVALID; + lprintf(warning, ".\n"); + } + } } /** @@ -278,510 +312,565 @@ void Link_set_file_stat(Link* this_link, CURL *curl) * \details Try and get the stats for each link in the link table. This will get * repeated until the uninitialised entry count drop to zero. */ -static void LinkTable_uninitialised_fill(LinkTable *linktbl) +static void LinkTable_uninitialised_fill(LinkTable * linktbl) { - int u; - char s[STATUS_LEN]; - lprintf(debug, "LinkTable_uninitialised_fill(): ... "); - do { - u = 0; - for (int i = 0; i < linktbl->num; i++) { - Link *this_link = linktbl->links[i]; - if (this_link->type == LINK_UNINITIALISED_FILE) { - Link_req_file_stat(linktbl->links[i]); - u++; - } - } - /* Block until the gaps are filled */ - int n = curl_multi_perform_once(); - int i = 0; - int j = 0; - while ( (i = curl_multi_perform_once()) ) { - if (CONFIG.log_level & debug) { - if (j) { - erase_string(stderr, STATUS_LEN, s); - } - snprintf(s, STATUS_LEN, "%d / %d", n-i, n); - fprintf(stderr, "%s", s); - j++; - } - } - } while (u); - if (CONFIG.log_level & debug) { - erase_string(stderr, STATUS_LEN, s); - fprintf(stderr, "Done!\n"); - } + int u; + char s[STATUS_LEN]; + lprintf(debug, "LinkTable_uninitialised_fill(): ... "); + do { + u = 0; + for (int i = 0; i < linktbl->num; i++) { + Link *this_link = linktbl->links[i]; + if (this_link->type == LINK_UNINITIALISED_FILE) { + Link_req_file_stat(linktbl->links[i]); + u++; + } + } + /* + * Block until the gaps are filled + */ + int n = curl_multi_perform_once(); + int i = 0; + int j = 0; + while ((i = curl_multi_perform_once())) { + if (CONFIG.log_type & debug) { + if (j) { + erase_string(stderr, STATUS_LEN, s); + } + snprintf(s, STATUS_LEN, "%d / %d", n - i, n); + fprintf(stderr, "%s", s); + j++; + } + } + } + while (u); + if (CONFIG.log_type & debug) { + erase_string(stderr, STATUS_LEN, s); + fprintf(stderr, "Done!\n"); + } } -static void LinkTable_fill(LinkTable *linktbl) +static void LinkTable_fill(LinkTable * linktbl) { - Link *head_link = linktbl->links[0]; - for (int i = 1; i < linktbl->num; i++) { - Link *this_link = linktbl->links[i]; - char *url; - url = path_append(head_link->f_url, this_link->linkname); - strncpy(this_link->f_url, url, MAX_PATH_LEN); - FREE(url); - char *unescaped_linkname; - CURL* c = curl_easy_init(); - unescaped_linkname = curl_easy_unescape(c, this_link->linkname, - 0, NULL); - strncpy(this_link->linkname, unescaped_linkname, MAX_FILENAME_LEN); - curl_free(unescaped_linkname); - curl_easy_cleanup(c); - } - LinkTable_uninitialised_fill(linktbl); + Link *head_link = linktbl->links[0]; + for (int i = 1; i < linktbl->num; i++) { + Link *this_link = linktbl->links[i]; + char *url; + url = path_append(head_link->f_url, this_link->linkname); + strncpy(this_link->f_url, url, MAX_PATH_LEN); + FREE(url); + char *unescaped_linkname; + CURL *c = curl_easy_init(); + unescaped_linkname = curl_easy_unescape(c, this_link->linkname, + 0, NULL); + strncpy(this_link->linkname, unescaped_linkname, + MAX_FILENAME_LEN); + curl_free(unescaped_linkname); + curl_easy_cleanup(c); + } + LinkTable_uninitialised_fill(linktbl); } /** * \brief Reset invalid links in the link table */ -static void LinkTable_invalid_reset(LinkTable *linktbl) +static void LinkTable_invalid_reset(LinkTable * linktbl) { - int j = 0; - for (int i = 0; i < linktbl->num; i++) { - Link *this_link = linktbl->links[i]; - if (this_link->type == LINK_INVALID) { - this_link->type = LINK_UNINITIALISED_FILE; - j++; - } - } - lprintf(debug, "LinkTable_invalid_reset(): %d invalid links\n", j); + int j = 0; + for (int i = 0; i < linktbl->num; i++) { + Link *this_link = linktbl->links[i]; + if (this_link->type == LINK_INVALID) { + this_link->type = LINK_UNINITIALISED_FILE; + j++; + } + } + lprintf(debug, "LinkTable_invalid_reset(): %d invalid links\n", j); } -void LinkTable_free(LinkTable *linktbl) +void LinkTable_free(LinkTable * linktbl) { - for (int i = 0; i < linktbl->num; i++) { - FREE(linktbl->links[i]); - } - FREE(linktbl->links); - FREE(linktbl); + for (int i = 0; i < linktbl->num; i++) { + FREE(linktbl->links[i]); + } + FREE(linktbl->links); + FREE(linktbl); } -void LinkTable_print(LinkTable *linktbl) +void LinkTable_print(LinkTable * linktbl) { - int j = 0; - lprintf(debug, "--------------------------------------------\n"); - lprintf(debug, " LinkTable %p for %s\n", linktbl, - linktbl->links[0]->f_url); - lprintf(debug, "--------------------------------------------\n"); - for (int i = 0; i < linktbl->num; i++) { - Link *this_link = linktbl->links[i]; - lprintf(debug, "%d %c %lu %s %s\n", - i, - this_link->type, - this_link->content_length, - this_link->linkname, - this_link->f_url - ); - if ((this_link->type != LINK_FILE) && - (this_link->type != LINK_DIR) && - (this_link->type != LINK_HEAD)) { - j++; - } - } - lprintf(debug, "--------------------------------------------\n"); - lprintf(debug, "LinkTable_print(): Invalid link count: %d\n", j); - lprintf(debug, "--------------------------------------------\n"); + if (CONFIG.log_type & debug) { + int j = 0; + lprintf(debug, "--------------------------------------------\n"); + lprintf(debug, " LinkTable %p for %s\n", linktbl, + linktbl->links[0]->f_url); + lprintf(debug, "--------------------------------------------\n"); + for (int i = 0; i < linktbl->num; i++) { + Link *this_link = linktbl->links[i]; + lprintf(debug, "%d %c %lu %s %s\n", + i, + this_link->type, + this_link->content_length, + this_link->linkname, this_link->f_url); + if ((this_link->type != LINK_FILE) + && (this_link->type != LINK_DIR) + && (this_link->type != LINK_HEAD)) { + j++; + } + } + lprintf(debug, "--------------------------------------------\n"); + lprintf(debug, "LinkTable_print(): Invalid link count: %d\n", j); + lprintf(debug, "--------------------------------------------\n"); + } } -DataStruct Link_to_DataStruct(Link *head_link) +DataStruct Link_to_DataStruct(Link * head_link) { - char *url = head_link->f_url; - CURL *curl = Link_to_curl(head_link); + char *url = head_link->f_url; + CURL *curl = Link_to_curl(head_link); - DataStruct buf; - buf.size = 0; - buf.data = NULL; + DataStruct buf; + buf.size = 0; + buf.data = NULL; - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); - /* If we get temporary HTTP failure, wait for 5 seconds before retry */ - long http_resp = 0; - do { - transfer_blocking(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); - if (HTTP_temp_failure(http_resp)) { - lprintf(warning, - "Link_to_DataStruct(): URL: %s, HTTP %ld, retrying later.\n" - , url, http_resp); - sleep(CONFIG.http_wait_sec); - } else if (http_resp != HTTP_OK) { - lprintf(warning, - "Link_to_DataStruct(): cannot retrieve URL: %s, HTTP %ld\n", - url, http_resp); - buf.size = 0; - curl_easy_cleanup(curl); - return buf; - } - } while (HTTP_temp_failure(http_resp)); + /* + * If we get temporary HTTP failure, wait for 5 seconds before retry + */ + long http_resp = 0; + do { + transfer_blocking(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); + if (HTTP_temp_failure(http_resp)) { + lprintf(warning, + "Link_to_DataStruct(): URL: %s, HTTP %ld, retrying later.\n", + url, http_resp); + sleep(CONFIG.http_wait_sec); + } else if (http_resp != HTTP_OK) { + lprintf(warning, + "Link_to_DataStruct(): cannot retrieve URL: %s, HTTP %ld\n", + url, http_resp); + buf.size = 0; + curl_easy_cleanup(curl); + return buf; + } + } + while (HTTP_temp_failure(http_resp)); - curl_easy_getinfo(curl, CURLINFO_FILETIME, &(head_link->time)); - curl_easy_cleanup(curl); - return buf; + curl_easy_getinfo(curl, CURLINFO_FILETIME, &(head_link->time)); + curl_easy_cleanup(curl); + return buf; } LinkTable *LinkTable_alloc(const char *url) { - LinkTable *linktbl = CALLOC(1, sizeof(LinkTable)); + LinkTable *linktbl = CALLOC(1, sizeof(LinkTable)); - /* populate the base URL */ - Link *head_link = Link_new("/", LINK_HEAD); - LinkTable_add(linktbl, head_link); - strncpy(head_link->f_url, url, MAX_PATH_LEN); - assert(linktbl->num == 1); - return linktbl; + /* + * populate the base URL + */ + Link *head_link = Link_new("/", LINK_HEAD); + LinkTable_add(linktbl, head_link); + strncpy(head_link->f_url, url, MAX_PATH_LEN); + assert(linktbl->num == 1); + return linktbl; } LinkTable *LinkTable_new(const char *url) { - LinkTable *linktbl = LinkTable_alloc(url); + LinkTable *linktbl = LinkTable_alloc(url); - /* start downloading the base URL */ - DataStruct buf = Link_to_DataStruct(linktbl->links[0]); - if (buf.size == 0) { - LinkTable_free(linktbl); - return NULL; - } + /* + * start downloading the base URL + */ + DataStruct buf = Link_to_DataStruct(linktbl->links[0]); + if (buf.size == 0) { + LinkTable_free(linktbl); + return NULL; + } - /* Otherwise parsed the received data */ - GumboOutput* output = gumbo_parse(buf.data); - HTML_to_LinkTable(output->root, linktbl); - gumbo_destroy_output(&kGumboDefaultOptions, output); - FREE(buf.data); + /* + * Otherwise parsed the received data + */ + GumboOutput *output = gumbo_parse(buf.data); + HTML_to_LinkTable(output->root, linktbl); + gumbo_destroy_output(&kGumboDefaultOptions, output); + FREE(buf.data); - int skip_fill = 0; - char *unescaped_path; - CURL* c = curl_easy_init(); - unescaped_path = curl_easy_unescape(c, url + ROOT_LINK_OFFSET, 0, NULL); - if (CACHE_SYSTEM_INIT) { - CacheDir_create(unescaped_path); - LinkTable *disk_linktbl; - disk_linktbl = LinkTable_disk_open(unescaped_path); - if (disk_linktbl) { - /* Check if we need to update the link table */ - lprintf(debug, - "LinkTable_new(): disk_linktbl->num: %d, linktbl->num: %d\n", - disk_linktbl->num, linktbl->num); - if (disk_linktbl->num == linktbl->num) { - LinkTable_free(linktbl); - linktbl = disk_linktbl; - skip_fill = 1; - } else { - LinkTable_free(disk_linktbl); - } - } - } + int skip_fill = 0; + char *unescaped_path; + CURL *c = curl_easy_init(); + unescaped_path = curl_easy_unescape(c, url + ROOT_LINK_OFFSET, 0, NULL); + if (CACHE_SYSTEM_INIT) { + CacheDir_create(unescaped_path); + LinkTable *disk_linktbl; + disk_linktbl = LinkTable_disk_open(unescaped_path); + if (disk_linktbl) { + /* + * Check if we need to update the link table + */ + lprintf(debug, + "LinkTable_new(): disk_linktbl->num: %d, linktbl->num: %d\n", + disk_linktbl->num, linktbl->num); + if (disk_linktbl->num == linktbl->num) { + LinkTable_free(linktbl); + linktbl = disk_linktbl; + skip_fill = 1; + } else { + LinkTable_free(disk_linktbl); + } + } + } - if (!skip_fill) { - /* Fill in the link table */ - LinkTable_fill(linktbl); - } else { - /* Fill in the holes in the link table */ - LinkTable_invalid_reset(linktbl); - LinkTable_uninitialised_fill(linktbl); - } + if (!skip_fill) { + /* + * Fill in the link table + */ + LinkTable_fill(linktbl); + } else { + /* + * Fill in the holes in the link table + */ + LinkTable_invalid_reset(linktbl); + LinkTable_uninitialised_fill(linktbl); + } - /* Save the link table */ - if (CACHE_SYSTEM_INIT) { - if (LinkTable_disk_save(linktbl, unescaped_path)) { - exit_failure(); - } - } + /* + * Save the link table + */ + if (CACHE_SYSTEM_INIT) { + if (LinkTable_disk_save(linktbl, unescaped_path)) { + exit_failure(); + } + } - curl_free(unescaped_path); - curl_easy_cleanup(c); + curl_free(unescaped_path); + curl_easy_cleanup(c); - LinkTable_print(linktbl); + LinkTable_print(linktbl); - return linktbl; + return linktbl; } static void LinkTable_disk_delete(const char *dirn) { - char *metadirn = path_append(META_DIR, dirn); - char *path; - if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { - path = path_append(metadirn, ".LinkTable"); - } else { - path = path_append(metadirn, "/.LinkTable"); - } - if(unlink(path)) { - lprintf(error, "LinkTable_disk_delete(): unlink(%s): %s\n", path, - strerror(errno)); - } - FREE(path); - FREE(metadirn); + char *metadirn = path_append(META_DIR, dirn); + char *path; + if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { + path = path_append(metadirn, ".LinkTable"); + } else { + path = path_append(metadirn, "/.LinkTable"); + } + if (unlink(path)) { + lprintf(error, "LinkTable_disk_delete(): unlink(%s): %s\n", + path, strerror(errno)); + } + FREE(path); + FREE(metadirn); } -int LinkTable_disk_save(LinkTable *linktbl, const char *dirn) +int LinkTable_disk_save(LinkTable * linktbl, const char *dirn) { - char *metadirn = path_append(META_DIR, dirn); - char *path; - if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { - path = path_append(metadirn, ".LinkTable"); - } else { - path = path_append(metadirn, "/.LinkTable"); - } - FILE *fp = fopen(path, "w"); - FREE(metadirn); + char *metadirn = path_append(META_DIR, dirn); + char *path; + if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { + path = path_append(metadirn, ".LinkTable"); + } else { + path = path_append(metadirn, "/.LinkTable"); + } + FILE *fp = fopen(path, "w"); + FREE(metadirn); - if (!fp) { - lprintf(error, "LinkTable_disk_save(): fopen(%s): %s\n", path, - strerror(errno)); - FREE(path); - return -1; - } - FREE(path); + if (!fp) { + lprintf(error, "LinkTable_disk_save(): fopen(%s): %s\n", path, + strerror(errno)); + FREE(path); + return -1; + } + FREE(path); - fwrite(&linktbl->num, sizeof(int), 1, fp); - for (int i = 0; i < linktbl->num; i++) { - fwrite(linktbl->links[i]->linkname, sizeof(char), MAX_FILENAME_LEN, fp); - fwrite(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, fp); - fwrite(&linktbl->links[i]->type, sizeof(LinkType), 1, fp); - fwrite(&linktbl->links[i]->content_length, sizeof(size_t), 1, fp); - fwrite(&linktbl->links[i]->time, sizeof(long), 1, fp); - } + fwrite(&linktbl->num, sizeof(int), 1, fp); + for (int i = 0; i < linktbl->num; i++) { + fwrite(linktbl->links[i]->linkname, sizeof(char), + MAX_FILENAME_LEN, fp); + fwrite(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, + fp); + fwrite(&linktbl->links[i]->type, sizeof(LinkType), 1, fp); + fwrite(&linktbl->links[i]->content_length, sizeof(size_t), 1, + fp); + fwrite(&linktbl->links[i]->time, sizeof(long), 1, fp); + } - int res = 0; + int res = 0; - if (ferror(fp)) { - lprintf(error, "LinkTable_disk_save(): encountered ferror!\n"); - res = -1; - } + if (ferror(fp)) { + lprintf(error, "LinkTable_disk_save(): encountered ferror!\n"); + res = -1; + } - if (fclose(fp)) { - lprintf(error, - "LinkTable_disk_save(): cannot close the file pointer, %s\n", - strerror(errno)); - res = -1; - } + if (fclose(fp)) { + lprintf(error, + "LinkTable_disk_save(): cannot close the file pointer, %s\n", + strerror(errno)); + res = -1; + } - return res; + return res; } LinkTable *LinkTable_disk_open(const char *dirn) { - char *metadirn = path_append(META_DIR, dirn); - char *path; - if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { - path = path_append(metadirn, ".LinkTable"); - } else { - path = path_append(metadirn, "/.LinkTable"); - } - FILE *fp = fopen(path, "r"); - FREE(metadirn); + char *metadirn = path_append(META_DIR, dirn); + char *path; + if (metadirn[strnlen(metadirn, MAX_PATH_LEN)] == '/') { + path = path_append(metadirn, ".LinkTable"); + } else { + path = path_append(metadirn, "/.LinkTable"); + } + FILE *fp = fopen(path, "r"); + FREE(metadirn); - if (!fp) { - FREE(path); - return NULL; - } + if (!fp) { + FREE(path); + return NULL; + } - LinkTable *linktbl = CALLOC(1, sizeof(LinkTable)); + LinkTable *linktbl = CALLOC(1, sizeof(LinkTable)); - fread(&linktbl->num, sizeof(int), 1, fp); - linktbl->links = CALLOC(linktbl->num, sizeof(Link *)); - for (int i = 0; i < linktbl->num; i++) { - linktbl->links[i] = CALLOC(1, sizeof(Link)); - fread(linktbl->links[i]->linkname, sizeof(char), MAX_FILENAME_LEN, fp); - fread(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, fp); - fread(&linktbl->links[i]->type, sizeof(LinkType), 1, fp); - fread(&linktbl->links[i]->content_length, sizeof(size_t), 1, fp); - fread(&linktbl->links[i]->time, sizeof(long), 1, fp); - if (feof(fp)) { - /* reached EOF */ - lprintf(error, - "LinkTable_disk_open(): reached EOF!\n"); - LinkTable_free(linktbl); - LinkTable_disk_delete(dirn); - return NULL; - } - if (ferror(fp)) { - lprintf(error, "LinkTable_disk_open(): encountered ferror!\n"); - LinkTable_free(linktbl); - LinkTable_disk_delete(dirn); - return NULL; - } - } - if (fclose(fp)) { - lprintf(error, - "LinkTable_disk_open(): cannot close the file pointer, %s\n", - strerror(errno)); - } - return linktbl; + fread(&linktbl->num, sizeof(int), 1, fp); + linktbl->links = CALLOC(linktbl->num, sizeof(Link *)); + for (int i = 0; i < linktbl->num; i++) { + linktbl->links[i] = CALLOC(1, sizeof(Link)); + fread(linktbl->links[i]->linkname, sizeof(char), + MAX_FILENAME_LEN, fp); + fread(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, fp); + fread(&linktbl->links[i]->type, sizeof(LinkType), 1, fp); + fread(&linktbl->links[i]->content_length, sizeof(size_t), 1, + fp); + fread(&linktbl->links[i]->time, sizeof(long), 1, fp); + if (feof(fp)) { + /* + * reached EOF + */ + lprintf(error, "LinkTable_disk_open(): reached EOF!\n"); + LinkTable_free(linktbl); + LinkTable_disk_delete(dirn); + return NULL; + } + if (ferror(fp)) { + lprintf(error, + "LinkTable_disk_open(): encountered ferror!\n"); + LinkTable_free(linktbl); + LinkTable_disk_delete(dirn); + return NULL; + } + } + if (fclose(fp)) { + lprintf(error, + "LinkTable_disk_open(): cannot close the file pointer, %s\n", + strerror(errno)); + } + return linktbl; } - LinkTable *path_to_Link_LinkTable_new(const char *path) { - Link *link = path_to_Link(path); - LinkTable *next_table = link->next_table; - if (!next_table) { - if (CONFIG.mode == NORMAL) { - next_table = LinkTable_new(link->f_url); - } else if (CONFIG.mode == SONIC) { - if (!CONFIG.sonic_id3) { - next_table = sonic_LinkTable_new_index(link->sonic_id); - } else { - next_table = sonic_LinkTable_new_id3(link->sonic_depth, - link->sonic_id); - } - } - } - link->next_table = next_table; - return next_table; + Link *link = path_to_Link(path); + LinkTable *next_table = link->next_table; + if (!next_table) { + if (CONFIG.mode == NORMAL) { + next_table = LinkTable_new(link->f_url); + } else if (CONFIG.mode == SONIC) { + if (!CONFIG.sonic_id3) { + next_table = + sonic_LinkTable_new_index(link->sonic_id); + } else { + next_table = + sonic_LinkTable_new_id3(link->sonic_depth, + link->sonic_id); + } + } + } + link->next_table = next_table; + return next_table; } -static Link *path_to_Link_recursive(char *path, LinkTable *linktbl) +static Link *path_to_Link_recursive(char *path, LinkTable * linktbl) { - /* skip the leading '/' if it exists */ - if (*path == '/') { - path++; - } + /* + * skip the leading '/' if it exists + */ + if (*path == '/') { + path++; + } - /* remove the last '/' if it exists */ - char *slash = &(path[strnlen(path, MAX_PATH_LEN) - 1]); - if (*slash == '/') { - *slash = '\0'; - } + /* + * remove the last '/' if it exists + */ + char *slash = &(path[strnlen(path, MAX_PATH_LEN) - 1]); + if (*slash == '/') { + *slash = '\0'; + } - slash = strchr(path, '/'); - if ( slash == NULL ) { - /* We cannot find another '/', we have reached the last level */ - for (int i = 1; i < linktbl->num; i++) { - if (!strncmp(path, linktbl->links[i]->linkname, MAX_FILENAME_LEN)) { - /* We found our link */ - return linktbl->links[i]; - } - } - } else { - /* - * We can still find '/', time to consume the path and traverse - * the tree structure - */ + slash = strchr(path, '/'); + if (slash == NULL) { + /* + * We cannot find another '/', we have reached the last level + */ + for (int i = 1; i < linktbl->num; i++) { + if (!strncmp + (path, linktbl->links[i]->linkname, + MAX_FILENAME_LEN)) { + /* + * We found our link + */ + return linktbl->links[i]; + } + } + } else { + /* + * We can still find '/', time to consume the path and traverse + * the tree structure + */ - /* - * add termination mark to the current string, - * effective create two substrings - */ - *slash = '\0'; - /* move the pointer past the '/' */ - char *next_path = slash + 1; - for (int i = 1; i < linktbl->num; i++) { - if (!strncmp(path, linktbl->links[i]->linkname, MAX_FILENAME_LEN)) { - /* The next sub-directory exists */ - LinkTable *next_table = linktbl->links[i]->next_table; - if (!next_table) { - if (CONFIG.mode == NORMAL) { - next_table = LinkTable_new( - linktbl->links[i]->f_url); - } else if (CONFIG.mode == SONIC) { - if (!CONFIG.sonic_id3) { - next_table = sonic_LinkTable_new_index( - linktbl->links[i]->sonic_id); - } else { - next_table = sonic_LinkTable_new_id3( - linktbl->links[i]->sonic_depth, - linktbl->links[i]->sonic_id); - } - } - } - linktbl->links[i]->next_table = next_table; - return path_to_Link_recursive(next_path, next_table); - } - } - } - return NULL; + /* + * add termination mark to the current string, + * effective create two substrings + */ + *slash = '\0'; + /* + * move the pointer past the '/' + */ + char *next_path = slash + 1; + for (int i = 1; i < linktbl->num; i++) { + if (!strncmp + (path, linktbl->links[i]->linkname, + MAX_FILENAME_LEN)) { + /* + * The next sub-directory exists + */ + LinkTable *next_table = + linktbl->links[i]->next_table; + if (!next_table) { + if (CONFIG.mode == NORMAL) { + next_table = + LinkTable_new(linktbl-> + links[i]-> + f_url); + } else if (CONFIG.mode == SONIC) { + if (!CONFIG.sonic_id3) { + next_table = + sonic_LinkTable_new_index + (linktbl->links[i]-> + sonic_id); + } else { + next_table = + sonic_LinkTable_new_id3 + (linktbl->links + [i]->sonic_depth, + linktbl->links[i]-> + sonic_id); + } + } + } + linktbl->links[i]->next_table = next_table; + return path_to_Link_recursive(next_path, + next_table); + } + } + } + return NULL; } Link *path_to_Link(const char *path) { - lprintf(link_lock_debug, - "path_to_Link(): thread %x: locking link_lock;\n", - pthread_self()); + lprintf(link_lock_debug, + "path_to_Link(): thread %x: locking link_lock;\n", + pthread_self()); - PTHREAD_MUTEX_LOCK(&link_lock); - char *new_path = strndup(path, MAX_PATH_LEN); - if (!new_path) { - lprintf(fatal, "path_to_Link(): cannot allocate memory\n"); - } - Link *link = path_to_Link_recursive(new_path, ROOT_LINK_TBL); - FREE(new_path); + PTHREAD_MUTEX_LOCK(&link_lock); + char *new_path = strndup(path, MAX_PATH_LEN); + if (!new_path) { + lprintf(fatal, "path_to_Link(): cannot allocate memory\n"); + } + Link *link = path_to_Link_recursive(new_path, ROOT_LINK_TBL); + FREE(new_path); - lprintf(link_lock_debug, - "path_to_Link(): thread %x: unlocking link_lock;\n", - pthread_self()); - PTHREAD_MUTEX_UNLOCK(&link_lock); - return link; + lprintf(link_lock_debug, + "path_to_Link(): thread %x: unlocking link_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&link_lock); + return link; } -long path_download(const char *path, char *output_buf, size_t size, - off_t offset) +long +path_download(const char *path, char *output_buf, size_t size, off_t offset) { - if (!path) { - lprintf(fatal, "\npath_download(): NULL path supplied\n"); - } - Link *link; - link = path_to_Link(path); - if (!link) { - return -ENOENT; - } + if (!path) { + lprintf(fatal, "\npath_download(): NULL path supplied\n"); + } + Link *link; + link = path_to_Link(path); + if (!link) { + return -ENOENT; + } - size_t start = offset; - size_t end = start + size; - char range_str[64]; - snprintf(range_str, sizeof(range_str), "%lu-%lu", start, end); - lprintf(debug, "path_download(%s, %s);\n", path, range_str); + size_t start = offset; + size_t end = start + size; + char range_str[64]; + snprintf(range_str, sizeof(range_str), "%lu-%lu", start, end); + lprintf(debug, "path_download(%s, %s);\n", path, range_str); - DataStruct buf; - buf.size = 0; - buf.data = NULL; + DataStruct buf; + buf.size = 0; + buf.data = NULL; - CURL *curl = Link_to_curl(link); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); - curl_easy_setopt(curl, CURLOPT_RANGE, range_str); + CURL *curl = Link_to_curl(link); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); + curl_easy_setopt(curl, CURLOPT_RANGE, range_str); - DataStruct header; - header.size = 0; - header.data = NULL; - curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&header); + DataStruct header; + header.size = 0; + header.data = NULL; + curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&header); - transfer_blocking(curl); + transfer_blocking(curl); - /* Check for range seek support */ - if (!CONFIG.no_range_check) { - if (!strcasestr((header.data), "Accept-Ranges: bytes")) { - fprintf(stderr, "This web server does not support HTTP \ + /* + * Check for range seek support + */ + if (!CONFIG.no_range_check) { + if (!strcasestr((header.data), "Accept-Ranges: bytes")) { + fprintf(stderr, "This web server does not support HTTP \ range requests\n"); - exit(EXIT_FAILURE); - } - } + exit(EXIT_FAILURE); + } + } - FREE(header.data); + FREE(header.data); - long http_resp; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); - if ( !( - (http_resp != HTTP_OK) || - (http_resp != HTTP_PARTIAL_CONTENT) || - (http_resp != HTTP_RANGE_NOT_SATISFIABLE) - )) { - lprintf(warning, "path_download(): Could not download %s, HTTP %ld\n", - link->f_url, http_resp); - return -ENOENT; - } + long http_resp; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); + if (!((http_resp != HTTP_OK) || + (http_resp != HTTP_PARTIAL_CONTENT) || + (http_resp != HTTP_RANGE_NOT_SATISFIABLE))) { + lprintf(warning, + "path_download(): Could not download %s, HTTP %ld\n", + link->f_url, http_resp); + return -ENOENT; + } - double dl; - curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dl); + double dl; + curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dl); - size_t recv = dl; - if (recv > size) { - recv = size; - } + size_t recv = dl; + if (recv > size) { + recv = size; + } - memmove(output_buf, buf.data, recv); - curl_easy_cleanup(curl); - FREE(buf.data); + memmove(output_buf, buf.data, recv); + curl_easy_cleanup(curl); + FREE(buf.data); - return recv; + return recv; } diff --git a/src/log.c b/src/log.c index c1d4133..031e82b 100644 --- a/src/log.c +++ b/src/log.c @@ -9,48 +9,50 @@ int log_level_init() { - char *env = getenv("HTTPDIRFS_LOG_LEVEL"); - if (env) { - return atoi(env); - } - return DEFAULT_LOG_LEVEL; + char *env = getenv("HTTPDIRFS_LOG_LEVEL"); + if (env) { + return atoi(env); + } + return DEFAULT_LOG_LEVEL; } -void log_printf(LogType type, const char *file, const char *func, int line, - const char *format, ...) +void +log_printf(LogType type, const char *file, const char *func, int line, + const char *format, ...) { - FILE *out = stderr; - if (type & CONFIG.log_level) { - switch (type) { - case fatal: - fprintf(out, "Fatal: "); - break; - case error: - fprintf(out, "Error: "); - break; - case warning: - fprintf(out, "Warning: "); - break; - case info: - out = stdout; - goto print_actual_message; - break; - default: - fprintf(out, "Debug (%x):", type); - break; - } + FILE *out = stderr; + if (type & CONFIG.log_type) { + switch (type) { + case fatal: + fprintf(out, "Fatal: "); + break; + case error: + fprintf(out, "Error: "); + break; + case warning: + fprintf(out, "Warning: "); + break; + case info: + out = stdout; + goto print_actual_message; + break; + default: + fprintf(out, "Debug (%x):", type); + break; + } - fprintf(out, "(%s:%s:%d): ", file, func, line); + fprintf(out, "(%s:%s:%d): ", file, func, line); - print_actual_message: - {} - va_list args; - va_start(args, format); - vfprintf(out, format, args); - va_end(args); + print_actual_message: + { + } + va_list args; + va_start(args, format); + vfprintf(out, format, args); + va_end(args); - if (type == fatal) { - exit_failure(); - } - } -} \ No newline at end of file + if (type == fatal) { + exit_failure(); + } + } +} diff --git a/src/log.h b/src/log.h index 0492ff5..559e6da 100644 --- a/src/log.h +++ b/src/log.h @@ -11,7 +11,8 @@ typedef enum { info = 1 << 3, debug = 1 << 4, link_lock_debug = 1 << 5, - cache_lock_debug = 1 << 6, + network_lock_debug = 1 << 6, + cache_lock_debug = 1 << 7, } LogType; /** diff --git a/src/main.c b/src/main.c index c1a5d36..c8c2854 100644 --- a/src/main.c +++ b/src/main.c @@ -20,258 +20,301 @@ static char *config_path = NULL; int main(int argc, char **argv) { - /* Automatically print help if not enough arguments are supplied */ - if (argc < 2) { - print_help(argv[0], 0); - fprintf(stderr, "For more information, run \"%s --help.\"\n", argv[0]); - exit(EXIT_FAILURE); - } + /* + * Automatically print help if not enough arguments are supplied + */ + if (argc < 2) { + print_help(argv[0], 0); + fprintf(stderr, "For more information, run \"%s --help.\"\n", + argv[0]); + exit(EXIT_FAILURE); + } - /* These are passed into fuse initialiser */ - char **fuse_argv = NULL; - int fuse_argc = 0; - /* These are the combined argument with the config file */ - char **all_argv = NULL; - int all_argc = 0; + /* + * These are passed into fuse initialiser + */ + char **fuse_argv = NULL; + int fuse_argc = 0; + /* + * These are the combined argument with the config file + */ + char **all_argv = NULL; + int all_argc = 0; /*--- Add the program's name to the combined argument list ---*/ - add_arg(&all_argv, &all_argc, argv[0]); + add_arg(&all_argv, &all_argc, argv[0]); /*--- FUSE expects the first initialisation to be the program's name ---*/ - add_arg(&fuse_argv, &fuse_argc, argv[0]); + add_arg(&fuse_argv, &fuse_argc, argv[0]); - /* initialise network configuration struct */ - Config_init(); + /* + * initialise network configuration struct + */ + Config_init(); - /* initialise network subsystem */ - NetworkSystem_init(); + /* + * initialise network subsystem + */ + NetworkSystem_init(); - /* Copy the command line argument list to the combined argument list */ - for (int i = 1; i < argc; i++) { - add_arg(&all_argv, &all_argc, argv[i]); - if (!strcmp(argv[i], "--config")) { - config_path = strdup(argv[i+1]); - } - } + /* + * Copy the command line argument list to the combined argument list + */ + for (int i = 1; i < argc; i++) { + add_arg(&all_argv, &all_argc, argv[i]); + if (!strcmp(argv[i], "--config")) { + config_path = strdup(argv[i + 1]); + } + } - /* parse the config file, if it exists, store it in all_argv and all_argc */ - parse_config_file(&all_argv, &all_argc); + /* + * parse the config file, if it exists, store it in all_argv and + * all_argc + */ + parse_config_file(&all_argv, &all_argc); - /* parse the combined argument list */ - if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) { - /* - * The user basically didn't supply enough arguments, if we reach here - * The point is to print some error messages - */ - goto fuse_start; - } + /* + * parse the combined argument list + */ + if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) { + /* + * The user basically didn't supply enough arguments, if we reach here + * The point is to print some error messages + */ + goto fuse_start; + } /*--- Add the last remaining argument, which is the mountpoint ---*/ - add_arg(&fuse_argv, &fuse_argc, argv[argc-1]); + add_arg(&fuse_argv, &fuse_argc, argv[argc - 1]); - /* The second last remaining argument is the URL */ - char *base_url = argv[argc-2]; - if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) { - fprintf(stderr, "Error: Please supply a valid URL.\n"); - print_help(argv[0], 0); - exit(EXIT_FAILURE); - } else { - if (CONFIG.sonic_username && CONFIG.sonic_password) { - CONFIG.mode = SONIC; - } else if (CONFIG.sonic_username || CONFIG.sonic_password) { - fprintf(stderr, - "Error: You have to supply both username and password to \ + /* + * The second last remaining argument is the URL + */ + char *base_url = argv[argc - 2]; + if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) { + fprintf(stderr, "Error: Please supply a valid URL.\n"); + print_help(argv[0], 0); + exit(EXIT_FAILURE); + } else { + if (CONFIG.sonic_username && CONFIG.sonic_password) { + CONFIG.mode = SONIC; + } else if (CONFIG.sonic_username || CONFIG.sonic_password) { + fprintf(stderr, + "Error: You have to supply both username and password to \ activate Sonic mode.\n"); - exit(EXIT_FAILURE); - } - if(!LinkSystem_init(base_url)) { - fprintf(stderr, "Network initialisation failed.\n"); - exit(EXIT_FAILURE); - } - } + exit(EXIT_FAILURE); + } + if (!LinkSystem_init(base_url)) { + fprintf(stderr, "Network initialisation failed.\n"); + exit(EXIT_FAILURE); + } + } - fuse_start: - fuse_local_init(fuse_argc, fuse_argv); + fuse_start: + fuse_local_init(fuse_argc, fuse_argv); - return 0; + return 0; } void parse_config_file(char ***argv, int *argc) { - char *full_path; - if (!config_path) { - char *xdg_config_home = getenv("XDG_CONFIG_HOME"); - if (!xdg_config_home) { - char *home = getenv("HOME"); - char *xdg_config_home_default = "/.config"; - xdg_config_home = path_append(home, xdg_config_home_default); - } - full_path = path_append(xdg_config_home, "/httpdirfs/config"); - } else { - full_path = config_path; - } + char *full_path; + if (!config_path) { + char *xdg_config_home = getenv("XDG_CONFIG_HOME"); + if (!xdg_config_home) { + char *home = getenv("HOME"); + char *xdg_config_home_default = "/.config"; + xdg_config_home = + path_append(home, xdg_config_home_default); + } + full_path = path_append(xdg_config_home, "/httpdirfs/config"); + } else { + full_path = config_path; + } - /* The buffer has to be able to fit a URL */ - int buf_len = MAX_PATH_LEN; - char buf[buf_len]; - FILE *config = fopen(full_path, "r"); - if (config) { - while (fgets(buf, buf_len, config)) { - if (buf[0] == '-') { - (*argc)++; - buf[strnlen(buf, buf_len) - 1] = '\0'; - char *space; - space = strchr(buf, ' '); - if (!space) { - *argv = realloc(*argv, *argc * sizeof(char **)); - (*argv)[*argc - 1] = strndup(buf, buf_len); - } else { - (*argc)++; - *argv = realloc(*argv, *argc * sizeof(char **)); - /* Only copy up to the space character*/ - (*argv)[*argc - 2] = strndup(buf, space - buf); - /* Starts copying after the space */ - (*argv)[*argc - 1] = strndup(space + 1, - buf_len - (space + 1 - buf)); - } - } - } - } - FREE(full_path); + /* + * The buffer has to be able to fit a URL + */ + int buf_len = MAX_PATH_LEN; + char buf[buf_len]; + FILE *config = fopen(full_path, "r"); + if (config) { + while (fgets(buf, buf_len, config)) { + if (buf[0] == '-') { + (*argc)++; + buf[strnlen(buf, buf_len) - 1] = '\0'; + char *space; + space = strchr(buf, ' '); + if (!space) { + *argv = + realloc(*argv, + *argc * sizeof(char **)); + (*argv)[*argc - 1] = + strndup(buf, buf_len); + } else { + (*argc)++; + *argv = + realloc(*argv, + *argc * sizeof(char **)); + /* + * Only copy up to the space character + */ + (*argv)[*argc - 2] = + strndup(buf, space - buf); + /* + * Starts copying after the space + */ + (*argv)[*argc - 1] = strndup(space + 1, + buf_len - + (space + + 1 - buf)); + } + } + } + } + FREE(full_path); } static int parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) { - char c; - int long_index = 0; - const char *short_opts = "o:hVdfsp:u:P:"; - const struct option long_opts[] = { - /* Note that 'L' is returned for long options */ - {"help", no_argument, NULL, 'h'}, /* 0 */ - {"version", no_argument, NULL, 'V'}, /* 1 */ - {"debug", no_argument, NULL, 'd'}, /* 2 */ - {"username", required_argument, NULL, 'u'}, /* 3 */ - {"password", required_argument, NULL, 'p'}, /* 4 */ - {"proxy", required_argument, NULL, 'P'}, /* 5 */ - {"proxy-username", required_argument, NULL, 'L'}, /* 6 */ - {"proxy-password", required_argument, NULL, 'L'}, /* 7 */ - {"cache", no_argument, NULL, 'L'}, /* 8 */ - {"dl-seg-size", required_argument, NULL, 'L'}, /* 9 */ - {"max-seg-count", required_argument, NULL, 'L'}, /* 10 */ - {"max-conns", required_argument, NULL, 'L'}, /* 11 */ - {"user-agent", required_argument, NULL, 'L'}, /* 12 */ - {"retry-wait", required_argument, NULL, 'L'}, /* 13 */ - {"cache-location", required_argument, NULL, 'L'}, /* 14 */ - {"sonic-username", required_argument, NULL, 'L'}, /* 15 */ - {"sonic-password", required_argument, NULL, 'L'}, /* 16 */ - {"sonic-id3", no_argument, NULL, 'L'}, /* 17 */ - {"no-range-check", no_argument, NULL, 'L'}, /* 18 */ - {"sonic-insecure", no_argument, NULL, 'L'}, /* 19 */ - {"insecure-tls", no_argument, NULL, 'L'}, /* 20 */ - {"config", required_argument, NULL, 'L'}, /* 21 */ - {"single-file-mode", required_argument, NULL, 'L'}, /* 22 */ - {0, 0, 0, 0} - }; - while ((c = - getopt_long(argc, argv, short_opts, long_opts, - &long_index)) != -1) { - switch (c) { - case 'o': - add_arg(fuse_argv, fuse_argc, "-o"); - add_arg(fuse_argv, fuse_argc, optarg); - break; - case 'h': - print_help(argv[0], 1); - add_arg(fuse_argv, fuse_argc, "-ho"); - /* skip everything else to print the help */ - return 1; - case 'V': - print_version(argv[0], 1); - add_arg(fuse_argv, fuse_argc, "-V"); - return 1; - case 'd': - add_arg(fuse_argv, fuse_argc, "-d"); - break; - case 'f': - add_arg(fuse_argv, fuse_argc, "-f"); - break; - case 's': - add_arg(fuse_argv, fuse_argc, "-s"); - break; - case 'u': - CONFIG.http_username = strdup(optarg); - break; - case 'p': - CONFIG.http_password = strdup(optarg); - break; - case 'P': - CONFIG.proxy = strdup(optarg); - break; - case 'L': - /* Long options */ - switch (long_index) { - case 6: - CONFIG.proxy_username = strdup(optarg); - break; - case 7: - CONFIG.proxy_password = strdup(optarg); - break; - case 8: - CONFIG.cache_enabled = 1; - break; - case 9: - CONFIG.data_blksz = atoi(optarg) * 1024 * 1024; - break; - case 10: - CONFIG.max_segbc = atoi(optarg); - break; - case 11: - CONFIG.max_conns = atoi(optarg); - break; - case 12: - CONFIG.user_agent = strdup(optarg); - break; - case 13: - CONFIG.http_wait_sec = atoi(optarg); - break; - case 14: - CONFIG.cache_dir = strdup(optarg); - break; - case 15: - CONFIG.sonic_username = strdup(optarg); - break; - case 16: - CONFIG.sonic_password = strdup(optarg); - break; - case 17: - CONFIG.sonic_id3 = 1; - break; - case 18: - CONFIG.no_range_check = 1; - break; - case 19: - CONFIG.sonic_insecure = 1; - break; - case 20: - CONFIG.insecure_tls = 1; - break; - case 21: - /* This is for --config, we don't need to do anything */ - break; - case 22: - CONFIG.mode = SINGLE_FILE; - break; - default: - fprintf(stderr, "see httpdirfs -h for usage\n"); - return 1; - } - break; - default: - fprintf(stderr, "see httpdirfs -h for usage\n"); - return 1; - } - }; - return 0; + char c; + int long_index = 0; + const char *short_opts = "o:hVdfsp:u:P:"; + const struct option long_opts[] = { + /* + * Note that 'L' is returned for long options + */ + {"help", no_argument, NULL, 'h'}, /* 0 */ + {"version", no_argument, NULL, 'V'}, /* 1 */ + {"debug", no_argument, NULL, 'd'}, /* 2 */ + {"username", required_argument, NULL, 'u'}, /* 3 */ + {"password", required_argument, NULL, 'p'}, /* 4 */ + {"proxy", required_argument, NULL, 'P'}, /* 5 */ + {"proxy-username", required_argument, NULL, 'L'}, /* 6 */ + {"proxy-password", required_argument, NULL, 'L'}, /* 7 */ + {"cache", no_argument, NULL, 'L'}, /* 8 */ + {"dl-seg-size", required_argument, NULL, 'L'}, /* 9 */ + {"max-seg-count", required_argument, NULL, 'L'}, /* 10 */ + {"max-conns", required_argument, NULL, 'L'}, /* 11 */ + {"user-agent", required_argument, NULL, 'L'}, /* 12 */ + {"retry-wait", required_argument, NULL, 'L'}, /* 13 */ + {"cache-location", required_argument, NULL, 'L'}, /* 14 */ + {"sonic-username", required_argument, NULL, 'L'}, /* 15 */ + {"sonic-password", required_argument, NULL, 'L'}, /* 16 */ + {"sonic-id3", no_argument, NULL, 'L'}, /* 17 */ + {"no-range-check", no_argument, NULL, 'L'}, /* 18 */ + {"sonic-insecure", no_argument, NULL, 'L'}, /* 19 */ + {"insecure-tls", no_argument, NULL, 'L'}, /* 20 */ + {"config", required_argument, NULL, 'L'}, /* 21 */ + {"single-file-mode", required_argument, NULL, 'L'}, /* 22 */ + {0, 0, 0, 0} + }; + while ((c = + getopt_long(argc, argv, short_opts, long_opts, + &long_index)) != -1) { + switch (c) { + case 'o': + add_arg(fuse_argv, fuse_argc, "-o"); + add_arg(fuse_argv, fuse_argc, optarg); + break; + case 'h': + print_help(argv[0], 1); + add_arg(fuse_argv, fuse_argc, "-ho"); + /* + * skip everything else to print the help + */ + return 1; + case 'V': + print_version(argv[0], 1); + add_arg(fuse_argv, fuse_argc, "-V"); + return 1; + case 'd': + add_arg(fuse_argv, fuse_argc, "-d"); + break; + case 'f': + add_arg(fuse_argv, fuse_argc, "-f"); + break; + case 's': + add_arg(fuse_argv, fuse_argc, "-s"); + break; + case 'u': + CONFIG.http_username = strdup(optarg); + break; + case 'p': + CONFIG.http_password = strdup(optarg); + break; + case 'P': + CONFIG.proxy = strdup(optarg); + break; + case 'L': + /* + * Long options + */ + switch (long_index) { + case 6: + CONFIG.proxy_username = strdup(optarg); + break; + case 7: + CONFIG.proxy_password = strdup(optarg); + break; + case 8: + CONFIG.cache_enabled = 1; + break; + case 9: + CONFIG.data_blksz = atoi(optarg) * 1024 * 1024; + break; + case 10: + CONFIG.max_segbc = atoi(optarg); + break; + case 11: + CONFIG.max_conns = atoi(optarg); + break; + case 12: + CONFIG.user_agent = strdup(optarg); + break; + case 13: + CONFIG.http_wait_sec = atoi(optarg); + break; + case 14: + CONFIG.cache_dir = strdup(optarg); + break; + case 15: + CONFIG.sonic_username = strdup(optarg); + break; + case 16: + CONFIG.sonic_password = strdup(optarg); + break; + case 17: + CONFIG.sonic_id3 = 1; + break; + case 18: + CONFIG.no_range_check = 1; + break; + case 19: + CONFIG.sonic_insecure = 1; + break; + case 20: + CONFIG.insecure_tls = 1; + break; + case 21: + /* + * This is for --config, we don't need to do anything + */ + break; + case 22: + CONFIG.mode = SINGLE_FILE; + break; + default: + fprintf(stderr, "see httpdirfs -h for usage\n"); + return 1; + } + break; + default: + fprintf(stderr, "see httpdirfs -h for usage\n"); + return 1; + } + }; + return 0; } /** @@ -280,32 +323,33 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) */ void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string) { - (*fuse_argc)++; - *fuse_argv_ptr = realloc(*fuse_argv_ptr, *fuse_argc * sizeof(char *)); - char **fuse_argv = *fuse_argv_ptr; - fuse_argv[*fuse_argc - 1] = strdup(opt_string); + (*fuse_argc)++; + *fuse_argv_ptr = realloc(*fuse_argv_ptr, *fuse_argc * sizeof(char *)); + char **fuse_argv = *fuse_argv_ptr; + fuse_argv[*fuse_argc - 1] = strdup(opt_string); } static void print_help(char *program_name, int long_help) { - printf("usage: %s [options] URL mountpoint\n", program_name); - if (long_help) { - print_long_help(); - } + printf("usage: %s [options] URL mountpoint\n", program_name); + if (long_help) { + print_long_help(); + } } static void print_version() { - printf("HTTPDirFS version " VERSION "\n"); - /* --------- Print off SSL engine version --------- */ - curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); - printf("libcurl SSL engine: %s\n", data->ssl_version); + printf("HTTPDirFS version " VERSION "\n"); + /* + * --------- Print off SSL engine version --------- + */ + curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); + printf("libcurl SSL engine: %s\n", data->ssl_version); } static void print_long_help() { - printf( -"\n\ + printf("\n\ general options:\n\ --config Specify a configuration file \n\ -o opt,[opt...] Mount options\n\ diff --git a/src/network.c b/src/network.c index b89b798..42303d4 100644 --- a/src/network.c +++ b/src/network.c @@ -11,11 +11,14 @@ #include #include - -/* ----------------- External variables ---------------------- */ +/* + * ----------------- External variables ---------------------- + */ CURLSH *CURL_SHARE; -/* ----------------- Static variable ----------------------- */ +/* + * ----------------- Static variable ----------------------- + */ /** \brief curl multi interface handle */ static CURLM *curl_multi; /** \brief mutex for transfer functions */ @@ -25,7 +28,9 @@ static pthread_mutex_t *crypto_lockarray; /** \brief mutex for curl share interface itself */ static pthread_mutex_t curl_lock; -/* -------------------- Functions -------------------------- */ +/* + * -------------------- Functions -------------------------- + */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" /** @@ -34,13 +39,13 @@ static pthread_mutex_t curl_lock; */ static void crypto_lock_callback(int mode, int type, char *file, int line) { - (void) file; - (void) line; - if (mode & CRYPTO_LOCK) { - PTHREAD_MUTEX_LOCK(&(crypto_lockarray[type])); - } else { - PTHREAD_MUTEX_UNLOCK(&(crypto_lockarray[type])); - } + (void)file; + (void)line; + if (mode & CRYPTO_LOCK) { + PTHREAD_MUTEX_LOCK(&(crypto_lockarray[type])); + } else { + PTHREAD_MUTEX_UNLOCK(&(crypto_lockarray[type])); + } } /** @@ -49,25 +54,31 @@ static void crypto_lock_callback(int mode, int type, char *file, int line) */ static unsigned long thread_id(void) { - unsigned long ret; + unsigned long ret; - ret = (unsigned long)pthread_self(); - return ret; + ret = (unsigned long)pthread_self(); + return ret; } + #pragma GCC diagnostic pop static void crypto_lock_init(void) { - int i; + int i; - crypto_lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * - sizeof(pthread_mutex_t)); - for(i = 0; imsg == CURLMSG_DONE) { - TransferStruct *transfer; - CURL *curl = curl_msg->easy_handle; - curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, - &transfer); - transfer->transferring = 0; - char *url = NULL; - curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); + (void)n_running_curl; + (void)n_mesgs; + static volatile int slept = 0; + if (curl_msg->msg == CURLMSG_DONE) { + TransferStruct *transfer; + CURL *curl = curl_msg->easy_handle; + curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, + &transfer); + transfer->transferring = 0; + char *url = NULL; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); - /* Wait for 5 seconds if we get HTTP 429 */ - long http_resp = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); - if (HTTP_temp_failure(http_resp)) { - if (!slept) { - lprintf(debug, - "curl_process_msgs(): HTTP %ld, sleeping for %d sec\n", - http_resp, CONFIG.http_wait_sec); - sleep(CONFIG.http_wait_sec); - slept = 1; - } - } else { - slept = 0; - } + /* + * Wait for 5 seconds if we get HTTP 429 + */ + long http_resp = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); + if (HTTP_temp_failure(http_resp)) { + if (!slept) { + lprintf(warning, + "curl_process_msgs(): HTTP %ld, sleeping for %d sec\n", + http_resp, CONFIG.http_wait_sec); + sleep(CONFIG.http_wait_sec); + slept = 1; + } + } else { + slept = 0; + } - if (!curl_msg->data.result) { - /* Transfer successful, set the file size */ - if (transfer->type == FILESTAT) { - Link_set_file_stat(transfer->link, curl); - } - } else { - lprintf(debug, "curl_process_msgs(): %d - %s <%s>\n", - curl_msg->data.result, - curl_easy_strerror(curl_msg->data.result), - url); - } - curl_multi_remove_handle(curl_multi, curl); - /* clean up the handle, if we are querying the file size */ - if (transfer->type == FILESTAT) { - curl_easy_cleanup(curl); - FREE(transfer); - } - } else { - lprintf(debug, "curl_process_msgs(): curl_msg->msg: %d\n", - curl_msg->msg); - } + if (!curl_msg->data.result) { + /* + * Transfer successful, set the file size + */ + if (transfer->type == FILESTAT) { + Link_set_file_stat(transfer->link, curl); + } + } else { + lprintf(error, "curl_process_msgs(): %d - %s <%s>\n", + curl_msg->data.result, + curl_easy_strerror(curl_msg->data.result), url); + } + curl_multi_remove_handle(curl_multi, curl); + /* + * clean up the handle, if we are querying the file size + */ + if (transfer->type == FILESTAT) { + curl_easy_cleanup(curl); + FREE(transfer); + } + } else { + lprintf(warning, "curl_process_msgs(): curl_msg->msg: %d\n", + curl_msg->msg); + } } /** @@ -158,214 +175,229 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl, */ int curl_multi_perform_once(void) { - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "curl_multi_perform_once(): thread %x: locking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_LOCK(&transfer_lock); - /* Get curl multi interface to perform pending tasks */ - int n_running_curl; - CURLMcode mc = curl_multi_perform(curl_multi, &n_running_curl); - if(mc > 0) { - lprintf(debug, "curl_multi_perform(): %s\n", curl_multi_strerror(mc)); - } + lprintf(network_lock_debug, + "curl_multi_perform_once(): thread %x: locking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&transfer_lock); - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd = -1; + /* + * Get curl multi interface to perform pending tasks + */ + int n_running_curl; + CURLMcode mc = curl_multi_perform(curl_multi, &n_running_curl); + if (mc > 0) { + lprintf(error, "curl_multi_perform(): %s\n", + curl_multi_strerror(mc)); + } - long curl_timeo = -1; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd = -1; - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); + long curl_timeo = -1; - /* set a default timeout for select() */ - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); - curl_multi_timeout(curl_multi, &curl_timeo); - /* We effectively cap timeout to 1 sec */ - if (curl_timeo >= 0) { - timeout.tv_sec = curl_timeo / 1000; - if (timeout.tv_sec > 1) { - timeout.tv_sec = 1; - } else { - timeout.tv_usec = (curl_timeo % 1000) * 1000; - } - } + /* + * set a default timeout for select() + */ + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; - /* get file descriptors from the transfers */ - mc = curl_multi_fdset(curl_multi, &fdread, &fdwrite, &fdexcep, &maxfd); + curl_multi_timeout(curl_multi, &curl_timeo); + /* + * We effectively cap timeout to 1 sec + */ + if (curl_timeo >= 0) { + timeout.tv_sec = curl_timeo / 1000; + if (timeout.tv_sec > 1) { + timeout.tv_sec = 1; + } else { + timeout.tv_usec = (curl_timeo % 1000) * 1000; + } + } - if (mc > 0) { - lprintf(debug, "curl_multi_fdset(): %s.\n", curl_multi_strerror(mc)); - } + /* + * get file descriptors from the transfers + */ + mc = curl_multi_fdset(curl_multi, &fdread, &fdwrite, &fdexcep, &maxfd); - if (maxfd == -1) { - usleep(100*1000); - } else { - if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) < 0) { - lprintf(debug, "curl_multi_perform_once(): select(): %s.\n", - strerror(errno)); - } - } + if (mc > 0) { + lprintf(error, "curl_multi_fdset(): %s.\n", + curl_multi_strerror(mc)); + } - /* Process the message queue */ - int n_mesgs; - CURLMsg *curl_msg; - while((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) { - curl_process_msgs(curl_msg, n_running_curl, n_mesgs); - } - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "curl_multi_perform_once(): thread %x: unlocking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_UNLOCK(&transfer_lock); - return n_running_curl; + if (maxfd == -1) { + usleep(100 * 1000); + } else { + if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) < + 0) { + lprintf(error, + "curl_multi_perform_once(): select(): %s.\n", + strerror(errno)); + } + } + + /* + * Process the message queue + */ + int n_mesgs; + CURLMsg *curl_msg; + while ((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) { + curl_process_msgs(curl_msg, n_running_curl, n_mesgs); + } + + lprintf(network_lock_debug, + "curl_multi_perform_once(): thread %x: unlocking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&transfer_lock); + + return n_running_curl; } void NetworkSystem_init(void) { - /* ------- Global related ----------*/ - if (curl_global_init(CURL_GLOBAL_ALL)) { - lprintf(debug, "network_init(): curl_global_init() failed!\n"); - exit_failure(); - } + /* + * ------- Global related ---------- + */ + if (curl_global_init(CURL_GLOBAL_ALL)) { + lprintf(fatal, "network_init(): curl_global_init() failed!\n"); + } - /* -------- Share related ----------*/ - CURL_SHARE = curl_share_init(); - if (!(CURL_SHARE)) { - lprintf(debug, "network_init(): curl_share_init() failed!\n"); - exit_failure(); - } + /* + * -------- Share related ---------- + */ + CURL_SHARE = curl_share_init(); + if (!(CURL_SHARE)) { + lprintf(fatal, "network_init(): curl_share_init() failed!\n"); + } - curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); - curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); - curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); + curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, + CURL_LOCK_DATA_SSL_SESSION); - if (pthread_mutex_init(&curl_lock, NULL) != 0) { - lprintf(debug, "network_init(): curl_lock initialisation failed!\n"); - exit_failure(); - } - curl_share_setopt(CURL_SHARE, CURLSHOPT_LOCKFUNC, curl_callback_lock); - curl_share_setopt(CURL_SHARE, CURLSHOPT_UNLOCKFUNC, curl_callback_unlock); + if (pthread_mutex_init(&curl_lock, NULL)) { + lprintf(fatal, + "network_init(): curl_lock initialisation failed!\n"); + } + curl_share_setopt(CURL_SHARE, CURLSHOPT_LOCKFUNC, curl_callback_lock); + curl_share_setopt(CURL_SHARE, CURLSHOPT_UNLOCKFUNC, + curl_callback_unlock); - /* ------------- Multi related -----------*/ - curl_multi = curl_multi_init(); - if (!curl_multi) { - lprintf(debug, "network_init(): curl_multi_init() failed!\n"); - exit_failure(); - } - curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, - CONFIG.max_conns); - curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS, - CONFIG.max_conns); + /* + * ------------- Multi related ----------- + */ + curl_multi = curl_multi_init(); + if (!curl_multi) { + lprintf(fatal, "network_init(): curl_multi_init() failed!\n"); + } + curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, + CONFIG.max_conns); + curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS, + CONFIG.max_conns); - /* ------------ Initialise locks ---------*/ - if (pthread_mutex_init(&transfer_lock, NULL)) { - lprintf(debug, - "network_init(): transfer_lock initialisation failed!\n"); - exit_failure(); - } + /* + * ------------ Initialise locks --------- + */ + if (pthread_mutex_init(&transfer_lock, NULL)) { + lprintf(fatal, + "network_init(): transfer_lock initialisation failed!\n"); + } - /* - * cryptographic lock functions were shamelessly copied from - * https://curl.haxx.se/libcurl/c/threaded-ssl.html - */ - crypto_lock_init(); + /* + * cryptographic lock functions were shamelessly copied from + * https://curl.haxx.se/libcurl/c/threaded-ssl.html + */ + crypto_lock_init(); } -void transfer_blocking(CURL *curl) +void transfer_blocking(CURL * curl) { - /* - * We don't need to malloc here, as the transfer is finished before - * the variable gets popped from the stack - */ - volatile TransferStruct transfer; - transfer.type = DATA; - transfer.transferring = 1; - curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer); - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "transfer_blocking(): thread %x: locking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_LOCK(&transfer_lock); - CURLMcode res = curl_multi_add_handle(curl_multi, curl); - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "transfer_blocking(): thread %x: unlocking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_UNLOCK(&transfer_lock); + /* + * We don't need to malloc here, as the transfer is finished before + * the variable gets popped from the stack + */ + volatile TransferStruct transfer; + transfer.type = DATA; + transfer.transferring = 1; + curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer); - if(res > 0) { - lprintf(debug, "transfer_blocking(): %d, %s\n", - res, curl_multi_strerror(res)); - exit_failure(); - } + lprintf(network_lock_debug, + "transfer_blocking(): thread %x: locking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&transfer_lock); - while (transfer.transferring) { - curl_multi_perform_once(); - } + CURLMcode res = curl_multi_add_handle(curl_multi, curl); + + lprintf(network_lock_debug, + "transfer_blocking(): thread %x: unlocking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&transfer_lock); + + if (res > 0) { + lprintf(error, "transfer_blocking(): %d, %s\n", + res, curl_multi_strerror(res)); + } + + while (transfer.transferring) { + curl_multi_perform_once(); + } } -void transfer_nonblocking(CURL *curl) +void transfer_nonblocking(CURL * curl) { - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "transfer_nonblocking(): thread %x: locking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_LOCK(&transfer_lock); - CURLMcode res = curl_multi_add_handle(curl_multi, curl); - #ifdef NETWORK_LOCK_DEBUG - lprintf(debug, - "transfer_nonblocking(): thread %x: unlocking transfer_lock;\n", - pthread_self()); - #endif - PTHREAD_MUTEX_UNLOCK(&transfer_lock); + lprintf(network_lock_debug, + "transfer_nonblocking(): thread %x: locking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_LOCK(&transfer_lock); - if(res > 0) { - lprintf(debug, "transfer_nonblocking(): %s\n", - curl_multi_strerror(res)); - } + CURLMcode res = curl_multi_add_handle(curl_multi, curl); + + lprintf(network_lock_debug, + "transfer_nonblocking(): thread %x: unlocking transfer_lock;\n", + pthread_self()); + PTHREAD_MUTEX_UNLOCK(&transfer_lock); + + if (res > 0) { + lprintf(error, "transfer_nonblocking(): %s\n", + curl_multi_strerror(res)); + } } -size_t write_memory_callback(void *contents, size_t size, size_t nmemb, - void *userp) +size_t +write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp) { - size_t realsize = size * nmemb; - DataStruct *mem = (DataStruct *)userp; + size_t realsize = size * nmemb; + DataStruct *mem = (DataStruct *) userp; - mem->data = realloc(mem->data, mem->size + realsize + 1); - if(!mem->data) { - /* out of memory! */ - lprintf(debug, "write_memory_callback(): realloc failure!\n"); - exit_failure(); - return 0; - } + mem->data = realloc(mem->data, mem->size + realsize + 1); + if (!mem->data) { + /* + * out of memory! + */ + lprintf(fatal, "write_memory_callback(): realloc failure!\n"); + } - memmove(&mem->data[mem->size], contents, realsize); - mem->size += realsize; - mem->data[mem->size] = 0; + memmove(&mem->data[mem->size], contents, realsize); + mem->size += realsize; + mem->data[mem->size] = 0; - return realsize; + return realsize; } int HTTP_temp_failure(HTTPResponseCode http_resp) { - switch (http_resp) { - case HTTP_TOO_MANY_REQUESTS: - case HTTP_CLOUDFLARE_UNKNOWN_ERROR: - case HTTP_CLOUDFLARE_TIMEOUT: - return 1; - default: - return 0; - } + switch (http_resp) { + case HTTP_TOO_MANY_REQUESTS: + case HTTP_CLOUDFLARE_UNKNOWN_ERROR: + case HTTP_CLOUDFLARE_TIMEOUT: + return 1; + default: + return 0; + } } diff --git a/src/sonic.c b/src/sonic.c index b22d6cc..059441d 100644 --- a/src/sonic.c +++ b/src/sonic.c @@ -14,11 +14,11 @@ #include typedef struct { - char *server; - char *username; - char *password; - char *client; - char *api_version; + char *server; + char *username; + char *password; + char *client; + char *api_version; } SonicConfigStruct; static SonicConfigStruct SONIC_CONFIG; @@ -26,31 +26,34 @@ static SonicConfigStruct SONIC_CONFIG; /** * \brief initalise Sonic configuration struct */ -void sonic_config_init(const char *server, const char *username, - const char *password) +void +sonic_config_init(const char *server, const char *username, + const char *password) { - SONIC_CONFIG.server = strndup(server, MAX_PATH_LEN); - /* Correct for the extra '/' */ - size_t server_url_len = strnlen(SONIC_CONFIG.server, MAX_PATH_LEN) - 1; - if (SONIC_CONFIG.server[server_url_len] == '/') { - SONIC_CONFIG.server[server_url_len] = '\0'; - } - SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN); - SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN); - SONIC_CONFIG.client = DEFAULT_USER_AGENT; + SONIC_CONFIG.server = strndup(server, MAX_PATH_LEN); + /* + * Correct for the extra '/' + */ + size_t server_url_len = strnlen(SONIC_CONFIG.server, MAX_PATH_LEN) - 1; + if (SONIC_CONFIG.server[server_url_len] == '/') { + SONIC_CONFIG.server[server_url_len] = '\0'; + } + SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN); + SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN); + SONIC_CONFIG.client = DEFAULT_USER_AGENT; - if (!CONFIG.sonic_insecure) { - /* - * API 1.13.0 is the minimum version that supports - * salt authentication scheme - */ - SONIC_CONFIG.api_version = "1.13.0"; - } else { - /* - * API 1.8.0 is the minimum version that supports ID3 mode - */ - SONIC_CONFIG.api_version = "1.8.0"; - } + if (!CONFIG.sonic_insecure) { + /* + * API 1.13.0 is the minimum version that supports + * salt authentication scheme + */ + SONIC_CONFIG.api_version = "1.13.0"; + } else { + /* + * API 1.8.0 is the minimum version that supports ID3 mode + */ + SONIC_CONFIG.api_version = "1.8.0"; + } } /** @@ -58,32 +61,33 @@ void sonic_config_init(const char *server, const char *username, */ static char *sonic_gen_auth_str(void) { - if (!CONFIG.sonic_insecure) { - char *salt = generate_salt(); - size_t pwd_len = strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN); - size_t pwd_salt_len = pwd_len + strnlen(salt, MAX_FILENAME_LEN); - char *pwd_salt = CALLOC(pwd_salt_len + 1, sizeof(char)); - strncat(pwd_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN); - strncat(pwd_salt + pwd_len, salt, MAX_FILENAME_LEN); - char *token = generate_md5sum(pwd_salt); - char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(auth_str, MAX_PATH_LEN, - ".view?u=%s&t=%s&s=%s&v=%s&c=%s", - SONIC_CONFIG.username, token, salt, - SONIC_CONFIG.api_version, SONIC_CONFIG.client); - FREE(salt); - FREE(token); - return auth_str; - } else { - char *pwd_hex = str_to_hex(SONIC_CONFIG.password); - char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(auth_str, MAX_PATH_LEN, - ".view?u=%s&p=enc:%s&v=%s&c=%s", - SONIC_CONFIG.username, pwd_hex, SONIC_CONFIG.api_version, - SONIC_CONFIG.client); - FREE(pwd_hex); - return auth_str; - } + if (!CONFIG.sonic_insecure) { + char *salt = generate_salt(); + size_t pwd_len = + strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN); + size_t pwd_salt_len = pwd_len + strnlen(salt, MAX_FILENAME_LEN); + char *pwd_salt = CALLOC(pwd_salt_len + 1, sizeof(char)); + strncat(pwd_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN); + strncat(pwd_salt + pwd_len, salt, MAX_FILENAME_LEN); + char *token = generate_md5sum(pwd_salt); + char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(auth_str, MAX_PATH_LEN, + ".view?u=%s&t=%s&s=%s&v=%s&c=%s", + SONIC_CONFIG.username, token, salt, + SONIC_CONFIG.api_version, SONIC_CONFIG.client); + FREE(salt); + FREE(token); + return auth_str; + } else { + char *pwd_hex = str_to_hex(SONIC_CONFIG.password); + char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(auth_str, MAX_PATH_LEN, + ".view?u=%s&p=enc:%s&v=%s&c=%s", + SONIC_CONFIG.username, pwd_hex, + SONIC_CONFIG.api_version, SONIC_CONFIG.client); + FREE(pwd_hex); + return auth_str; + } } /** @@ -91,12 +95,12 @@ static char *sonic_gen_auth_str(void) */ static char *sonic_gen_url_first_part(char *method) { - char *auth_str = sonic_gen_auth_str(); - char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(url, MAX_PATH_LEN, "%s/rest/%s%s", SONIC_CONFIG.server, method, - auth_str); - FREE(auth_str); - return url; + char *auth_str = sonic_gen_auth_str(); + char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(url, MAX_PATH_LEN, "%s/rest/%s%s", SONIC_CONFIG.server, + method, auth_str); + FREE(auth_str); + return url; } /** @@ -104,11 +108,11 @@ static char *sonic_gen_url_first_part(char *method) */ static char *sonic_getMusicDirectory_link(const char *id) { - char *first_part = sonic_gen_url_first_part("getMusicDirectory"); - char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); - FREE(first_part); - return url; + char *first_part = sonic_gen_url_first_part("getMusicDirectory"); + char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); + FREE(first_part); + return url; } /** @@ -116,11 +120,11 @@ static char *sonic_getMusicDirectory_link(const char *id) */ static char *sonic_getArtist_link(const char *id) { - char *first_part = sonic_gen_url_first_part("getArtist"); - char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); - FREE(first_part); - return url; + char *first_part = sonic_gen_url_first_part("getArtist"); + char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); + FREE(first_part); + return url; } /** @@ -128,11 +132,11 @@ static char *sonic_getArtist_link(const char *id) */ static char *sonic_getAlbum_link(const char *id) { - char *first_part = sonic_gen_url_first_part("getAlbum"); - char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); - FREE(first_part); - return url; + char *first_part = sonic_gen_url_first_part("getAlbum"); + char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id); + FREE(first_part); + return url; } /** @@ -140,12 +144,11 @@ static char *sonic_getAlbum_link(const char *id) */ static char *sonic_stream_link(const char *id) { - char *first_part = sonic_gen_url_first_part("stream"); - char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); - snprintf(url, MAX_PATH_LEN, - "%s&format=raw&id=%s", first_part, id); - FREE(first_part); - return url; + char *first_part = sonic_gen_url_first_part("stream"); + char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); + snprintf(url, MAX_PATH_LEN, "%s&format=raw&id=%s", first_part, id); + FREE(first_part); + return url; } /** @@ -162,299 +165,345 @@ static char *sonic_stream_link(const char *id) * parser terminates the strings properly, which is a fair assumption, * considering how mature expat is. */ -static void XMLCALL XML_parser_general(void *data, const char *elem, - const char **attr) +static void XMLCALL +XML_parser_general(void *data, const char *elem, const char **attr) { - /* Error checking */ - if (!strcmp(elem, "error")) { - lprintf(error, "XML_parser_general() error:\n"); - for (int i = 0; attr[i]; i += 2) { - lprintf(error, "%s: %s\n", attr[i], attr[i+1]); - } - } + /* + * Error checking + */ + if (!strcmp(elem, "error")) { + lprintf(error, "XML_parser_general() error:\n"); + for (int i = 0; attr[i]; i += 2) { + lprintf(error, "%s: %s\n", attr[i], attr[i + 1]); + } + } - LinkTable *linktbl = (LinkTable *) data; - Link *link; + LinkTable *linktbl = (LinkTable *) data; + Link *link; - /* - * Please refer to the documentation at the function prototype of - * sonic_LinkTable_new_id3() - */ - if (!strcmp(elem, "child")) { - link = CALLOC(1, sizeof(Link)); - /* Initialise to LINK_DIR, as the LINK_FILE is set later. */ - link->type = LINK_DIR; - } else if (!strcmp(elem, "artist") && linktbl->links[0]->sonic_depth != 3) { - /* We want to skip the first "artist" element in the album table */ - link = CALLOC(1, sizeof(Link)); - link->type = LINK_DIR; - } else if (!strcmp(elem, "album") && linktbl->links[0]->sonic_depth == 3) { - link = CALLOC(1, sizeof(Link)); - link->type = LINK_DIR; - /* The new table should be a level 4 song table */ - link->sonic_depth = 4; - } else if (!strcmp(elem, "song") && linktbl->links[0]->sonic_depth == 4) { - link = CALLOC(1, sizeof(Link)); - link->type = LINK_FILE; - } else { - /* The element does not contain directory structural information */ - return; - } + /* + * Please refer to the documentation at the function prototype of + * sonic_LinkTable_new_id3() + */ + if (!strcmp(elem, "child")) { + link = CALLOC(1, sizeof(Link)); + /* + * Initialise to LINK_DIR, as the LINK_FILE is set later. + */ + link->type = LINK_DIR; + } else if (!strcmp(elem, "artist") + && linktbl->links[0]->sonic_depth != 3) { + /* + * We want to skip the first "artist" element in the album table + */ + link = CALLOC(1, sizeof(Link)); + link->type = LINK_DIR; + } else if (!strcmp(elem, "album") + && linktbl->links[0]->sonic_depth == 3) { + link = CALLOC(1, sizeof(Link)); + link->type = LINK_DIR; + /* + * The new table should be a level 4 song table + */ + link->sonic_depth = 4; + } else if (!strcmp(elem, "song") && linktbl->links[0]->sonic_depth == 4) { + link = CALLOC(1, sizeof(Link)); + link->type = LINK_FILE; + } else { + /* + * The element does not contain directory structural information + */ + return; + } - int id_set = 0; - int linkname_set = 0; + int id_set = 0; + int linkname_set = 0; - int track = 0; - char *title = ""; - char *suffix = ""; - for (int i = 0; attr[i]; i += 2) { - if (!strcmp("id", attr[i])) { - link->sonic_id = CALLOC(MAX_FILENAME_LEN + 1, sizeof(char)); - strncpy(link->sonic_id, attr[i+1], MAX_FILENAME_LEN); - id_set = 1; - continue; - } + int track = 0; + char *title = ""; + char *suffix = ""; + for (int i = 0; attr[i]; i += 2) { + if (!strcmp("id", attr[i])) { + link->sonic_id = + CALLOC(MAX_FILENAME_LEN + 1, sizeof(char)); + strncpy(link->sonic_id, attr[i + 1], MAX_FILENAME_LEN); + id_set = 1; + continue; + } - if (!strcmp("path", attr[i])) { - memset(link->linkname, 0, MAX_FILENAME_LEN); - /* Skip to the last '/' if it exists */ - char *s = strrchr(attr[i+1], '/'); - if (s) { - strncpy(link->linkname, s + 1, MAX_FILENAME_LEN); - } else { - strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN); - } - linkname_set = 1; - continue; - } + if (!strcmp("path", attr[i])) { + memset(link->linkname, 0, MAX_FILENAME_LEN); + /* + * Skip to the last '/' if it exists + */ + char *s = strrchr(attr[i + 1], '/'); + if (s) { + strncpy(link->linkname, s + 1, + MAX_FILENAME_LEN); + } else { + strncpy(link->linkname, attr[i + 1], + MAX_FILENAME_LEN); + } + linkname_set = 1; + continue; + } - /* - * "title" is used for directory name, - * "name" is for top level directories - * N.B. "path" attribute is given the preference - */ - if (!linkname_set) { - if (!strcmp("title", attr[i]) || !strcmp("name", attr[i])) { - strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN); - linkname_set = 1; - continue; - } - } + /* + * "title" is used for directory name, + * "name" is for top level directories + * N.B. "path" attribute is given the preference + */ + if (!linkname_set) { + if (!strcmp("title", attr[i]) + || !strcmp("name", attr[i])) { + strncpy(link->linkname, attr[i + 1], + MAX_FILENAME_LEN); + linkname_set = 1; + continue; + } + } - if (!strcmp("isDir", attr[i])) { - if (!strcmp("false", attr[i+1])) { - link->type = LINK_FILE; - } - continue; - } + if (!strcmp("isDir", attr[i])) { + if (!strcmp("false", attr[i + 1])) { + link->type = LINK_FILE; + } + continue; + } - if (!strcmp("created", attr[i])) { - struct tm *tm = CALLOC(1, sizeof(struct tm)); - strptime(attr[i+1], "%Y-%m-%dT%H:%M:%S.000Z", tm); - link->time = mktime(tm); - FREE(tm); - continue; - } + if (!strcmp("created", attr[i])) { + struct tm *tm = CALLOC(1, sizeof(struct tm)); + strptime(attr[i + 1], "%Y-%m-%dT%H:%M:%S.000Z", tm); + link->time = mktime(tm); + FREE(tm); + continue; + } - if (!strcmp("size", attr[i])) { - link->content_length = atoll(attr[i+1]); - continue; - } + if (!strcmp("size", attr[i])) { + link->content_length = atoll(attr[i + 1]); + continue; + } - if (!strcmp("track", attr[i])) { - track = atoi(attr[i+1]); - continue; - } + if (!strcmp("track", attr[i])) { + track = atoi(attr[i + 1]); + continue; + } - if (!strcmp("title", attr[i])) { - title = (char *) attr[i+1]; - continue; - } + if (!strcmp("title", attr[i])) { + title = (char *)attr[i + 1]; + continue; + } - if (!strcmp("suffix", attr[i])) { - suffix = (char *) attr[i+1]; - continue; - } - } + if (!strcmp("suffix", attr[i])) { + suffix = (char *)attr[i + 1]; + continue; + } + } - if (!linkname_set && strlen(title) > 0 && strlen(suffix) > 0) { - snprintf(link->linkname, MAX_FILENAME_LEN, "%02d - %s.%s", - track, title, suffix); - linkname_set = 1; - } + if (!linkname_set && strlen(title) > 0 && strlen(suffix) > 0) { + snprintf(link->linkname, MAX_FILENAME_LEN, "%02d - %s.%s", + track, title, suffix); + linkname_set = 1; + } - /* Clean up if linkname or id is not set */ - if (!linkname_set || !id_set) { - FREE(link); - return; - } + /* + * Clean up if linkname or id is not set + */ + if (!linkname_set || !id_set) { + FREE(link); + return; + } - if (link->type == LINK_FILE) { - char *url = sonic_stream_link(link->sonic_id); - strncpy(link->f_url, url, MAX_PATH_LEN); - FREE(url); - } + if (link->type == LINK_FILE) { + char *url = sonic_stream_link(link->sonic_id); + strncpy(link->f_url, url, MAX_PATH_LEN); + FREE(url); + } - LinkTable_add(linktbl, link); + LinkTable_add(linktbl, link); } /** * \brief parse a XML string in order to fill in the LinkTable */ static LinkTable *sonic_url_to_LinkTable(const char *url, - XML_StartElementHandler handler, - int depth) + XML_StartElementHandler handler, + int depth) { - LinkTable *linktbl = LinkTable_alloc(url); - linktbl->links[0]->sonic_depth = depth; + LinkTable *linktbl = LinkTable_alloc(url); + linktbl->links[0]->sonic_depth = depth; - /* start downloading the base URL */ - DataStruct xml = Link_to_DataStruct(linktbl->links[0]); - if (xml.size == 0) { - LinkTable_free(linktbl); - return NULL; - } + /* + * start downloading the base URL + */ + DataStruct xml = Link_to_DataStruct(linktbl->links[0]); + if (xml.size == 0) { + LinkTable_free(linktbl); + return NULL; + } - XML_Parser parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, linktbl); + XML_Parser parser = XML_ParserCreate(NULL); + XML_SetUserData(parser, linktbl); - XML_SetStartElementHandler(parser, handler); + XML_SetStartElementHandler(parser, handler); - if (XML_Parse(parser, xml.data, xml.size, 1) == XML_STATUS_ERROR) { - lprintf(error, - "sonic_XML_to_LinkTable(): Parse error at line %lu: %s\n", - XML_GetCurrentLineNumber(parser), - XML_ErrorString(XML_GetErrorCode(parser))); - } + if (XML_Parse(parser, xml.data, xml.size, 1) == XML_STATUS_ERROR) { + lprintf(error, + "sonic_XML_to_LinkTable(): Parse error at line %lu: %s\n", + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); + } - XML_ParserFree(parser); + XML_ParserFree(parser); - FREE(xml.data); + FREE(xml.data); - LinkTable_print(linktbl); + LinkTable_print(linktbl); - return linktbl; + return linktbl; } LinkTable *sonic_LinkTable_new_index(const char *id) { - char *url; - if (strcmp(id, "0")) { - url = sonic_getMusicDirectory_link(id); - } else { - url = sonic_gen_url_first_part("getIndexes"); - } - LinkTable *linktbl = sonic_url_to_LinkTable(url, XML_parser_general, 0); - FREE(url); - return linktbl; + char *url; + if (strcmp(id, "0")) { + url = sonic_getMusicDirectory_link(id); + } else { + url = sonic_gen_url_first_part("getIndexes"); + } + LinkTable *linktbl = sonic_url_to_LinkTable(url, XML_parser_general, 0); + FREE(url); + return linktbl; } - -static void XMLCALL XML_parser_id3_root(void *data, const char *elem, - const char **attr) +static void XMLCALL +XML_parser_id3_root(void *data, const char *elem, const char **attr) { - if (!strcmp(elem, "error")) { - lprintf(error, "XML_parser_id3_root():\n"); - for (int i = 0; attr[i]; i += 2) { - lprintf(error, "%s: %s\n", attr[i], attr[i+1]); - } - } + if (!strcmp(elem, "error")) { + lprintf(error, "XML_parser_id3_root():\n"); + for (int i = 0; attr[i]; i += 2) { + lprintf(error, "%s: %s\n", attr[i], attr[i + 1]); + } + } - LinkTable *root_linktbl = (LinkTable *) data; - LinkTable *this_linktbl = NULL; + LinkTable *root_linktbl = (LinkTable *) data; + LinkTable *this_linktbl = NULL; - /* Set the current linktbl, if we have more than head link. */ - if (root_linktbl->num > 1) { - this_linktbl = root_linktbl->links[root_linktbl->num - 1]->next_table; - } + /* + * Set the current linktbl, if we have more than head link. + */ + if (root_linktbl->num > 1) { + this_linktbl = + root_linktbl->links[root_linktbl->num - 1]->next_table; + } - int id_set = 0; - int linkname_set = 0; - Link *link; - if (!strcmp(elem, "index")) { - /* Add a subdirectory */ - link = CALLOC(1, sizeof(Link)); - link->type = LINK_DIR; - for (int i = 0; attr[i]; i += 2) { - if (!strcmp("name", attr[i])) { - strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN); - linkname_set = 1; - /* Allocate a new LinkTable */ - link->next_table = LinkTable_alloc("/"); - } - } - /* Make sure we don't add an empty directory */ - if (linkname_set) { - LinkTable_add(root_linktbl, link); - } else { - FREE(link); - } - return; - } else if (!strcmp(elem, "artist")) { - link = CALLOC(1, sizeof(Link)); - link->type = LINK_DIR; - /* The new table should be a level 3 album table */ - link->sonic_depth = 3; - for (int i = 0; attr[i]; i += 2) { - if (!strcmp("name", attr[i])) { - strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN); - linkname_set = 1; - continue; - } + int id_set = 0; + int linkname_set = 0; + Link *link; + if (!strcmp(elem, "index")) { + /* + * Add a subdirectory + */ + link = CALLOC(1, sizeof(Link)); + link->type = LINK_DIR; + for (int i = 0; attr[i]; i += 2) { + if (!strcmp("name", attr[i])) { + strncpy(link->linkname, attr[i + 1], + MAX_FILENAME_LEN); + linkname_set = 1; + /* + * Allocate a new LinkTable + */ + link->next_table = LinkTable_alloc("/"); + } + } + /* + * Make sure we don't add an empty directory + */ + if (linkname_set) { + LinkTable_add(root_linktbl, link); + } else { + FREE(link); + } + return; + } else if (!strcmp(elem, "artist")) { + link = CALLOC(1, sizeof(Link)); + link->type = LINK_DIR; + /* + * The new table should be a level 3 album table + */ + link->sonic_depth = 3; + for (int i = 0; attr[i]; i += 2) { + if (!strcmp("name", attr[i])) { + strncpy(link->linkname, attr[i + 1], + MAX_FILENAME_LEN); + linkname_set = 1; + continue; + } - if (!strcmp("id", attr[i])) { - link->sonic_id = CALLOC(MAX_FILENAME_LEN + 1, sizeof(char)); - strncpy(link->sonic_id, attr[i+1], MAX_FILENAME_LEN); - id_set = 1; - continue; - } - } + if (!strcmp("id", attr[i])) { + link->sonic_id = + CALLOC(MAX_FILENAME_LEN + 1, sizeof(char)); + strncpy(link->sonic_id, attr[i + 1], + MAX_FILENAME_LEN); + id_set = 1; + continue; + } + } - /* Clean up if linkname is not set */ - if (!linkname_set || !id_set) { - FREE(link); - return; - } + /* + * Clean up if linkname is not set + */ + if (!linkname_set || !id_set) { + FREE(link); + return; + } - LinkTable_add(this_linktbl, link); - } - /* - * If we reach here, then this element does not contain directory structural - * information - */ + LinkTable_add(this_linktbl, link); + } + /* + * If we reach here, then this element does not contain directory structural + * information + */ } LinkTable *sonic_LinkTable_new_id3(int depth, const char *id) { - char *url; - LinkTable *linktbl = ROOT_LINK_TBL; - switch (depth) { - /* Root table */ - case 0: - url = sonic_gen_url_first_part("getArtists"); - linktbl = sonic_url_to_LinkTable(url, XML_parser_id3_root, 0); - FREE(url); - break; - /* Album table - get all the albums of an artist */ - case 3: - url = sonic_getArtist_link(id); - linktbl = sonic_url_to_LinkTable(url, XML_parser_general, depth); - FREE(url); - break; - /* Song table - get all the songs of an album */ - case 4: - url = sonic_getAlbum_link(id); - linktbl = sonic_url_to_LinkTable(url, XML_parser_general, depth); - FREE(url); - break; - default: - /* - * We shouldn't reach here. - */ - lprintf(fatal, "sonic_LinkTable_new_id3(): case %d.\n", depth); - break; - } - return linktbl; + char *url; + LinkTable *linktbl = ROOT_LINK_TBL; + switch (depth) { + /* + * Root table + */ + case 0: + url = sonic_gen_url_first_part("getArtists"); + linktbl = sonic_url_to_LinkTable(url, XML_parser_id3_root, 0); + FREE(url); + break; + /* + * Album table - get all the albums of an artist + */ + case 3: + url = sonic_getArtist_link(id); + linktbl = + sonic_url_to_LinkTable(url, XML_parser_general, depth); + FREE(url); + break; + /* + * Song table - get all the songs of an album + */ + case 4: + url = sonic_getAlbum_link(id); + linktbl = + sonic_url_to_LinkTable(url, XML_parser_general, depth); + FREE(url); + break; + default: + /* + * We shouldn't reach here. + */ + lprintf(fatal, "sonic_LinkTable_new_id3(): case %d.\n", depth); + break; + } + return linktbl; } - diff --git a/src/util.c b/src/util.c index b30774c..bf58cf4 100644 --- a/src/util.c +++ b/src/util.c @@ -29,123 +29,126 @@ char *path_append(const char *path, const char *filename) { - int needs_separator = 0; - if ((path[strnlen(path, MAX_PATH_LEN)-1] != '/') && (filename[0] != '/')) { - needs_separator = 1; - } + int needs_separator = 0; + if ((path[strnlen(path, MAX_PATH_LEN) - 1] != '/') + && (filename[0] != '/')) { + needs_separator = 1; + } - char *str; - size_t ul = strnlen(path, MAX_PATH_LEN); - size_t sl = strnlen(filename, MAX_FILENAME_LEN); - str = CALLOC(ul + sl + needs_separator + 1, sizeof(char)); - strncpy(str, path, ul); - if (needs_separator) { - str[ul] = '/'; - } - strncat(str, filename, sl); - return str; + char *str; + size_t ul = strnlen(path, MAX_PATH_LEN); + size_t sl = strnlen(filename, MAX_FILENAME_LEN); + str = CALLOC(ul + sl + needs_separator + 1, sizeof(char)); + strncpy(str, path, ul); + if (needs_separator) { + str[ul] = '/'; + } + strncat(str, filename, sl); + return str; } int64_t round_div(int64_t a, int64_t b) { - return (a + (b / 2)) / b; + return (a + (b / 2)) / b; } -void PTHREAD_MUTEX_UNLOCK(pthread_mutex_t *x) +void PTHREAD_MUTEX_UNLOCK(pthread_mutex_t * x) { - int i; - i = pthread_mutex_unlock(x); - if (i) { - lprintf(fatal, "thread %x: pthread_mutex_unlock() failed, %d, %s\n", - pthread_self(), i, strerror(i)); - } + int i; + i = pthread_mutex_unlock(x); + if (i) { + lprintf(fatal, + "thread %x: pthread_mutex_unlock() failed, %d, %s\n", + pthread_self(), i, strerror(i)); + } } -void PTHREAD_MUTEX_LOCK(pthread_mutex_t *x) +void PTHREAD_MUTEX_LOCK(pthread_mutex_t * x) { - int i; - i = pthread_mutex_lock(x); - if (i) { - lprintf(fatal, "thread %x: pthread_mutex_lock() failed, %d, %s\n", - pthread_self(), i, strerror(i)); - } + int i; + i = pthread_mutex_lock(x); + if (i) { + lprintf(fatal, + "thread %x: pthread_mutex_lock() failed, %d, %s\n", + pthread_self(), i, strerror(i)); + } } void exit_failure(void) { - int nptrs; - void *buffer[BT_BUF_SIZE]; + int nptrs; + void *buffer[BT_BUF_SIZE]; - nptrs = backtrace(buffer, BT_BUF_SIZE); - fprintf(stderr, "\nOops! HTTPDirFS crashed! :(\n"); - fprintf(stderr, "backtrace() returned the following %d addresses:\n", - nptrs); - backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); + nptrs = backtrace(buffer, BT_BUF_SIZE); + fprintf(stderr, "\nOops! HTTPDirFS crashed! :(\n"); + fprintf(stderr, "backtrace() returned the following %d addresses:\n", + nptrs); + backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } -void erase_string(FILE *file, size_t max_len, char *s) +void erase_string(FILE * file, size_t max_len, char *s) { - size_t l = strnlen(s, max_len); - for (size_t k = 0; k < l; k++) { - fprintf(file, "\b"); - } - for (size_t k = 0; k < l; k++) { - fprintf(file, " "); - } - for (size_t k = 0; k < l; k++) { - fprintf(file, "\b"); - } + size_t l = strnlen(s, max_len); + for (size_t k = 0; k < l; k++) { + fprintf(file, "\b"); + } + for (size_t k = 0; k < l; k++) { + fprintf(file, " "); + } + for (size_t k = 0; k < l; k++) { + fprintf(file, "\b"); + } } char *generate_salt(void) { - char *out; - out = CALLOC(SALT_LEN + 1, sizeof(char)); - uuid_t uu; - uuid_generate(uu); - uuid_unparse(uu, out); - return out; + char *out; + out = CALLOC(SALT_LEN + 1, sizeof(char)); + uuid_t uu; + uuid_generate(uu); + uuid_unparse(uu, out); + return out; } char *generate_md5sum(const char *str) { - MD5_CTX c; - unsigned char md5[MD5_DIGEST_LENGTH]; - size_t len = strnlen(str, MAX_PATH_LEN); - char *out = CALLOC(MD5_HASH_LEN + 1, sizeof(char)); + MD5_CTX c; + unsigned char md5[MD5_DIGEST_LENGTH]; + size_t len = strnlen(str, MAX_PATH_LEN); + char *out = CALLOC(MD5_HASH_LEN + 1, sizeof(char)); - MD5_Init(&c); - MD5_Update(&c, str, len); - MD5_Final(md5, &c); + MD5_Init(&c); + MD5_Update(&c, str, len); + MD5_Final(md5, &c); - for(int i = 0; i < MD5_DIGEST_LENGTH; i++) { - sprintf(out + 2 * i, "%02x", md5[i]); - } - return out; + for (int i = 0; i < MD5_DIGEST_LENGTH; i++) { + sprintf(out + 2 * i, "%02x", md5[i]); + } + return out; } void *CALLOC(size_t nmemb, size_t size) { - void *ptr = calloc(nmemb, size); - if (!ptr) { - lprintf(fatal, "calloc() failed, %s!\n", strerror(errno)); - } - return ptr; + void *ptr = calloc(nmemb, size); + if (!ptr) { + lprintf(fatal, "calloc() failed, %s!\n", strerror(errno)); + } + return ptr; } void FREE(void *ptr) { - free(ptr); - ptr = NULL; + free(ptr); + ptr = NULL; } char *str_to_hex(char *s) { - char *hex = CALLOC(strlen(s) * 2 + 1, sizeof(char)); - for (char *c = s, *h = hex; *c; c++, h+=2) { - sprintf(h, "%x", *c); - } - return hex; -} \ No newline at end of file + char *hex = CALLOC(strlen(s) * 2 + 1, sizeof(char)); + for (char *c = s, *h = hex; *c; c++, h += 2) { + sprintf(h, "%x", *c); + } + return hex; +}