relabelled all log outputs

This commit is contained in:
Fufu Fang 2021-08-30 11:24:32 +01:00
parent 0219d7460a
commit 0f3cc61875
No known key found for this signature in database
GPG Key ID: 0F6BB5EF6F8BB729
12 changed files with 2677 additions and 2332 deletions

View File

@ -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)\"\

View File

@ -11,11 +11,15 @@
#include <string.h>
#include <unistd.h>
/* ---------------- External variables -----------------------*/
/*
* ---------------- External variables -----------------------
*/
int CACHE_SYSTEM_INIT = 0;
char *META_DIR;
/* ----------------- Static variables ----------------------- */
/*
* ----------------- Static variables -----------------------
*/
/**
* \brief Cache file locking
@ -39,13 +43,15 @@ static char *CacheSystem_calc_dir(const char *url)
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)
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)
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));
@ -54,8 +60,7 @@ static char *CacheSystem_calc_dir(const char *url)
char *fn = path_append(cache_dir_root, "/CACHEDIR.TAG");
FILE *fp = fopen(fn, "w");
if (fp) {
fprintf(fp,
"Signature: 8a477f597d28d172789f06886806bc55\n\
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");
@ -88,7 +93,7 @@ static char *CacheSystem_calc_dir(const char *url)
void CacheSystem_init(const char *path, int url_supplied)
{
if (pthread_mutex_init(&cf_lock, NULL) != 0) {
if (pthread_mutex_init(&cf_lock, NULL)) {
lprintf(fatal,
"CacheSystem_init(): cf_lock initialisation failed!\n");
}
@ -101,7 +106,9 @@ void CacheSystem_init(const char *path, int url_supplied)
META_DIR = path_append(path, "meta/");
DATA_DIR = path_append(path, "data/");
/* Check if directories exist, if not, create them */
/*
* 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",
@ -116,18 +123,26 @@ void CacheSystem_init(const char *path, int url_supplied)
if (CONFIG.mode == SONIC) {
char *sonic_path;
/* Create "rest" sub-directory for META_DIR */
/*
* 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)
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 */
/*
* 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)
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));
@ -150,7 +165,9 @@ static int Meta_read(Cache *cf)
int nmemb = 0;
if (!fp) {
/* The metadata file does not exist */
/*
* The metadata file does not exist
*/
lprintf(error, "Meta_read(): fopen(): %s\n", strerror(errno));
return EIO;
}
@ -160,17 +177,18 @@ static int Meta_read(Cache *cf)
fread(&cf->blksz, sizeof(int), 1, fp);
fread(&cf->segbc, sizeof(long), 1, fp);
/* Error checking for fread */
/*
* Error checking for fread
*/
if (ferror(fp)) {
lprintf(error,
"Meta_read(): error reading core metadata!\n");
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);
"Meta_read(): corrupt metadata: %s, blksz: %d",
cf->path, cf->blksz);
return EBADMSG;
}
@ -185,33 +203,44 @@ static int Meta_read(Cache *cf)
}
if (cf->segbc > 0) {
/* Allocate memory for all segments, and read them in */
/*
* 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 */
/*
* We shouldn't have gone past the end of the file
*/
if (feof(fp)) {
/* reached EOF */
/*
* reached EOF
*/
lprintf(error,
"Meta_read(): attempted to read past the end of the file!\n");
"Meta_read(): attempted to read past the end of the \
file!\n");
return EBADMSG;
}
/* Error checking for fread */
/*
* Error checking for fread
*/
if (ferror(fp)) {
lprintf(error,
"Meta_read(): error reading bitmap!\n");
lprintf(error, "Meta_read(): error reading bitmap!\n");
return EIO;
}
/* Check for inconsistent metadata file */
/*
* Check for inconsistent metadata file
*/
if (nmemb != cf->segbc) {
lprintf(error,
"Meta_read(): corrupted metadata!\n");
lprintf(error, "Meta_read(): corrupted metadata!\n");
return EBADMSG;
}
} else {
/* Allocate one single segment for empty file to prevent segfault */
/*
* Allocate one single segment for empty file to prevent segfault
*/
cf->seg = CALLOC(1, sizeof(Seg));
}
@ -230,16 +259,21 @@ static int Meta_write(Cache *cf)
rewind(fp);
if (!fp) {
/* Cannot create the metadata file */
/*
* Cannot create the metadata file
*/
lprintf(error, "Meta_write(): fopen(): %s\n", strerror(errno));
return -1;
}
/* These things really should not be zero!!! */
/*
* 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);
%ld\n", cf->content_length, cf->blksz,
cf->segbc);
}
fwrite(&cf->time, sizeof(long), 1, fp);
@ -250,10 +284,11 @@ static int Meta_write(Cache *cf)
fwrite(cf->seg, sizeof(Seg), cf->segbc, fp);
}
/* Error checking for fwrite */
/*
* Error checking for fwrite
*/
if (ferror(fp)) {
lprintf(error,
"Meta_write(): fwrite(): encountered error!\n");
lprintf(error, "Meta_write(): fwrite(): encountered error!\n");
return -1;
}
@ -278,10 +313,12 @@ static void Data_create(Cache *cf)
lprintf(fatal, "Data_create(): open(): %s\n", strerror(errno));
}
if (ftruncate(fd, cf->content_length)) {
lprintf(warning, "Data_create(): ftruncate(): %s\n", strerror(errno));
lprintf(warning, "Data_create(): ftruncate(): %s\n",
strerror(errno));
}
if (close(fd)) {
lprintf(fatal, "Data_create(): close:(): %s\n", strerror(errno));
lprintf(fatal, "Data_create(): close:(): %s\n",
strerror(errno));
}
}
@ -319,21 +356,27 @@ static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset)
return -EINVAL;
}
lprintf(cache_lock_debug, "Data_read(): thread %x: locking seek_lock;\n",
pthread_self());
lprintf(cache_lock_debug,
"Data_read(): thread %x: locking seek_lock;\n", pthread_self());
PTHREAD_MUTEX_LOCK(&cf->seek_lock);
long byte_read = 0;
/* Seek to the right location */
/*
* Seek to the right location
*/
if (fseeko(cf->dfp, offset, SEEK_SET)) {
/* fseeko failed */
/*
* fseeko failed
*/
lprintf(error, "Data_read(): fseeko(): %s\n", strerror(errno));
byte_read = -EIO;
goto end;
}
/* Calculate how much to read */
/*
* Calculate how much to read
*/
if (offset + len > cf->content_length) {
len -= offset + len - cf->content_length;
if (len < 0) {
@ -347,19 +390,24 @@ static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset)
"Data_read(): fread(): requested %ld, returned %ld!\n",
len, byte_read);
if (feof(cf->dfp)) {
/* reached EOF */
/*
* reached EOF
*/
lprintf(error,
"Data_read(): fread(): reached the end of the file!\n");
}
if (ferror(cf->dfp)) {
/* filesystem error */
/*
* filesystem error
*/
lprintf(error,
"Data_read(): fread(): encountered error!\n");
}
}
end:
lprintf(cache_lock_debug, "Data_read(): thread %x: unlocking seek_lock;\n",
lprintf(cache_lock_debug,
"Data_read(): thread %x: unlocking seek_lock;\n",
pthread_self());
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
@ -376,22 +424,26 @@ 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 */
/*
* We should permit empty files
*/
return 0;
}
lprintf(cache_lock_debug, "Data_write(): thread %x: locking seek_lock;\n",
lprintf(cache_lock_debug,
"Data_write(): thread %x: locking seek_lock;\n",
pthread_self());
PTHREAD_MUTEX_LOCK(&cf->seek_lock);
long byte_written = 0;
if (fseeko(cf->dfp, offset, SEEK_SET)) {
/* fseeko failed */
/*
* fseeko failed
*/
lprintf(error, "Data_write(): fseeko(): %s\n", strerror(errno));
byte_written = -EIO;
goto end;
@ -400,18 +452,22 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len,
byte_written = fwrite(buf, sizeof(uint8_t), len, cf->dfp);
if (byte_written != len) {
lprintf(error, "Data_write(): fwrite(): requested %ld, returned %ld!\n",
lprintf(error,
"Data_write(): fwrite(): requested %ld, returned %ld!\n",
len, byte_written);
}
if (ferror(cf->dfp)) {
/* filesystem error */
/*
* 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());
"Data_write(): thread %x: unlocking seek_lock;\n",
pthread_self());
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
return byte_written;
@ -425,12 +481,15 @@ int CacheDir_create(const char *dirn)
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));
lprintf(fatal, "CacheDir_create(): mkdir(): %s\n",
strerror(errno));
}
i |= -mkdir(datadirn, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) << 1;
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));
lprintf(fatal, "CacheDir_create(): mkdir(): %s\n",
strerror(errno));
}
FREE(datadirn);
FREE(metadirn);
@ -445,11 +504,13 @@ static Cache *Cache_alloc()
Cache *cf = CALLOC(1, sizeof(Cache));
if (pthread_mutex_init(&cf->seek_lock, NULL)) {
lprintf(fatal, "Cache_alloc(): seek_lock initialisation failed!\n");
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");
lprintf(fatal,
"Cache_alloc(): w_lock initialisation failed!\n");
}
if (pthread_mutexattr_init(&cf->bgt_lock_attr)) {
@ -463,7 +524,8 @@ static Cache *Cache_alloc()
}
if (pthread_mutex_init(&cf->bgt_lock, &cf->bgt_lock_attr)) {
lprintf(fatal, "Cache_alloc(): bgt_lock initialisation failed!\n");
lprintf(fatal,
"Cache_alloc(): bgt_lock initialisation failed!\n");
}
return cf;
@ -487,7 +549,8 @@ static void Cache_free(Cache *cf)
}
if (pthread_mutexattr_destroy(&cf->bgt_lock_attr)) {
lprintf(fatal, "Cache_alloc(): could not destroy bgt_lock_attr!\n");
lprintf(fatal,
"Cache_alloc(): could not destroy bgt_lock_attr!\n");
}
if (cf->path) {
@ -519,13 +582,16 @@ 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 */
/*
* 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");
lprintf(warning,
"Cache_exist(): Cache file partially missing.\n");
if (unlink(datafn)) {
lprintf(error, "Cache_exist(): unlink(): %s\n",
strerror(errno));
@ -586,7 +652,9 @@ static int Data_open(Cache *cf)
cf->dfp = fopen(datafn, "r+");
FREE(datafn);
if (!cf->dfp) {
/* Failed to open the data file */
/*
* Failed to open the data file
*/
lprintf(error, "Data_open(): fopen(%s): %s\n", datafn,
strerror(errno));
return -1;
@ -605,7 +673,9 @@ 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 */
/*
* Failed to open the data file
*/
lprintf(error, "Meta_open(): fopen(%s): %s\n", metafn,
strerror(errno));
FREE(metafn);
@ -624,7 +694,9 @@ 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 */
/*
* Failed to open the data file
*/
lprintf(fatal, "Meta_create(): fopen(%s): %s\n", metafn,
strerror(errno));
}
@ -637,7 +709,8 @@ int Cache_create(const char *path)
char *fn = "";
if (CONFIG.mode == NORMAL) {
fn = curl_easy_unescape(NULL, this_link->f_url + ROOT_LINK_OFFSET, 0,
fn = curl_easy_unescape(NULL,
this_link->f_url + ROOT_LINK_OFFSET, 0,
NULL);
} else if (CONFIG.mode == SONIC) {
fn = this_link->sonic_id;
@ -662,7 +735,8 @@ int Cache_create(const char *path)
if (Meta_open(cf)) {
Cache_free(cf);
lprintf(error, "Cache_create(): cannot open metadata file, %s.\n", fn);
lprintf(error,
"Cache_create(): cannot open metadata file, %s.\n", fn);
}
if (Meta_write(cf)) {
@ -690,26 +764,33 @@ int Cache_create(const char *path)
Cache *Cache_open(const char *fn)
{
/* Obtain the link structure memory pointer */
/*
* Obtain the link structure memory pointer
*/
Link *link = path_to_Link(fn);
if (!link) {
/* There is no associated link to the path */
/*
* There is no associated link to the path
*/
return NULL;
}
lprintf(cache_lock_debug, "Cache_open(): thread %x: locking cf_lock;\n",
pthread_self());
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());
"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 */
/*
* Check if both metadata and data file exist
*/
if (CONFIG.mode == NORMAL) {
if (Cache_exist(fn)) {
return NULL;
@ -720,30 +801,41 @@ Cache *Cache_open(const char *fn)
}
}
/* Create the cache in-memory data structure */
/*
* Create the cache in-memory data structure
*/
Cache *cf = Cache_alloc();
/* Fill in the fs_path */
/*
* 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 */
/*
* 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);
/* Associate the cache structure with a 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);
lprintf(error, "Cache_open(): cannot open metadata file %s.\n",
fn);
return NULL;
}
/* Corrupt metadata */
/*
* Corrupt metadata
*/
if (Meta_read(cf)) {
Cache_free(cf);
lprintf(error, "Cache_open(): metadata error: %s.\n", fn);
@ -757,15 +849,17 @@ Cache *Cache_open(const char *fn)
*/
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));
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 */
/*
* Check if the cache files are not outdated
*/
if (cf->time != cf->link->time) {
lprintf(warning, "Cache_open(): outdated cache file: %s.\n", fn);
lprintf(warning, "Cache_open(): outdated cache file: %s.\n",
fn);
Cache_free(cf);
return NULL;
}
@ -777,10 +871,13 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length,
}
cf->link->cache_opened = 1;
/* Yup, we just created a circular loop. ;) */
/*
* Yup, we just created a circular loop. ;)
*/
cf->link->cache_ptr = cf;
lprintf(cache_lock_debug, "Cache_open(): thread %x: unlocking cf_lock;\n",
lprintf(cache_lock_debug,
"Cache_open(): thread %x: unlocking cf_lock;\n",
pthread_self());
PTHREAD_MUTEX_UNLOCK(&cf_lock);
@ -789,15 +886,16 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length,
void Cache_close(Cache * cf)
{
lprintf(cache_lock_debug, "Cache_close(): thread %x: locking cf_lock;\n",
pthread_self());
lprintf(cache_lock_debug,
"Cache_close(): thread %x: locking cf_lock;\n", pthread_self());
PTHREAD_MUTEX_LOCK(&cf_lock);
cf->link->cache_opened--;
if (cf->link->cache_opened > 0) {
lprintf(cache_lock_debug,
"Cache_close(): thread %x: unlocking cf_lock;\n", pthread_self());
"Cache_close(): thread %x: unlocking cf_lock;\n",
pthread_self());
PTHREAD_MUTEX_UNLOCK(&cf_lock);
return;
}
@ -816,7 +914,8 @@ void Cache_close(Cache *cf)
strerror(errno));
}
lprintf(cache_lock_debug, "Cache_close(): thread %x: unlocking cf_lock;\n",
lprintf(cache_lock_debug,
"Cache_close(): thread %x: unlocking cf_lock;\n",
pthread_self());
PTHREAD_MUTEX_UNLOCK(&cf_lock);
@ -870,8 +969,8 @@ which does't make sense\n", pthread_self(), recv);
}
if ((recv == cf->blksz) ||
(cf->next_dl_offset == (cf->content_length / cf->blksz * 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 {
@ -882,41 +981,55 @@ error.\n", recv, cf->blksz);
FREE(recv_buf);
lprintf(cache_lock_debug, "Cache_bgdl(): thread %x: unlocking bgt_lock;\n",
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());
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);
}
long Cache_read(Cache *cf, char * const output_buf, const off_t len,
long
Cache_read(Cache * cf, char *const output_buf, const off_t len,
const off_t offset_start)
{
long send;
/* The offset of the segment to be downloaded */
/*
* 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 ---------------*/
/*
* ------------------ 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*/
/*
* Wait for any other download thread to finish
*/
lprintf(cache_lock_debug, "Cache_read(): thread %ld: locking w_lock;\n",
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);
/*
* 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",
@ -927,7 +1040,10 @@ long Cache_read(Cache *cf, char * const output_buf, const off_t len,
}
}
/* ------------------------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());
@ -944,8 +1060,7 @@ which does't make sense\n", pthread_self(), recv);
* Condition 2: offset is the last segment
*/
if ((recv == cf->blksz) ||
(dl_offset == (cf->content_length / cf->blksz * 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 {
@ -956,18 +1071,23 @@ error.\n", recv, cf->blksz);
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());
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 -------------------*/
/*
* -----------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 ((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",
@ -975,8 +1095,7 @@ error.\n", recv, cf->blksz);
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"
);
"Cache_read(): Error creating background download thread\n");
}
}
}

View File

@ -30,7 +30,7 @@ void Config_init(void)
{
CONFIG.mode = NORMAL;
CONFIG.log_level = log_level_init();
CONFIG.log_type = log_level_init();
/*---------------- Network related --------------*/
CONFIG.http_username = NULL;

View File

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

View File

@ -2,7 +2,9 @@
#include "cache.h"
/* must be included before including <fuse.h> */
/*
* must be included before including <fuse.h>
*/
#define FUSE_USE_VERSION 26
#include <fuse.h>
@ -70,7 +72,8 @@ static int fs_getattr(const char *path, struct stat *stbuf)
}
/** \brief read a file */
static int fs_read(const char *path, char *buf, size_t size, off_t offset,
static int
fs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
long received;
@ -124,7 +127,8 @@ 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,
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;
@ -141,7 +145,9 @@ static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add,
}
}
/* start adding the links */
/*
* start adding the links
*/
dir_add(buf, ".", NULL, 0);
dir_add(buf, "..", NULL, 0);
for (int i = 1; i < linktbl->num; i++) {

View File

@ -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,23 +35,31 @@ static pthread_mutex_t link_lock;
LinkTable *LinkSystem_init(const char *raw_url)
{
/* Remove excess '/' if it is there */
/*
* 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) {
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 */
/*
* --------- 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 -------------------- */
/*
* --------------------- Enable cache system --------------------
*/
if (CONFIG.cache_enabled) {
if (CONFIG.cache_dir) {
CacheSystem_init(CONFIG.cache_dir, 0);
@ -56,11 +68,14 @@ LinkTable *LinkSystem_init(const char *raw_url)
}
}
/* ----------- Create the root link table --------------*/
/*
* ----------- 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);
sonic_config_init(url, CONFIG.sonic_username,
CONFIG.sonic_password);
if (!CONFIG.sonic_id3) {
ROOT_LINK_TBL = sonic_LinkTable_new_index("0");
} else {
@ -91,8 +106,11 @@ static Link *Link_new(const char *linkname, LinkType 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]);
/*
* remove the '/' from linkname if it exists
*/
char *c =
&(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]);
if (*c == '/') {
*c = '\0';
}
@ -102,12 +120,16 @@ static Link *Link_new(const char *linkname, LinkType type)
static LinkType linkname_to_LinkType(const char *linkname)
{
/* The link name has to start with alphanumerical character */
/*
* The link name has to start with alphanumerical character
*/
if (!isalnum(linkname[0]) && (linkname[0] != '%')) {
return LINK_INVALID;
}
/* Check for stray '/' */
/*
* Check for stray '/'
*/
char *slash = strchr(linkname, '/');
if (slash) {
int linkname_len = strnlen(linkname, MAX_FILENAME_LEN) - 1;
@ -132,11 +154,16 @@ static int linknames_equal(char *linkname, const char *linkname_new)
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] == '/')) {
/*
* 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;
}
}
@ -155,7 +182,9 @@ static void HTML_to_LinkTable(GumboNode *node, LinkTable *linktbl)
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 */
/*
* 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.
@ -172,7 +201,9 @@ static void HTML_to_LinkTable(GumboNode *node, LinkTable *linktbl)
LinkTable_add(linktbl, Link_new(href->value, type));
}
}
/* Note the recursive call, lol. */
/*
* 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);
@ -186,10 +217,14 @@ static CURL *Link_to_curl(Link *link)
if (!curl) {
lprintf(fatal, "Link_to_curl(): curl_easy_init() failed!\n");
}
/* set up some basic curl stuff */
/*
* 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 '/' */
/*
* 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);
@ -199,7 +234,6 @@ static CURL *Link_to_curl(Link *link)
if (CONFIG.insecure_tls) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
}
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
if (CONFIG.http_username) {
@ -292,12 +326,14 @@ static void LinkTable_uninitialised_fill(LinkTable *linktbl)
u++;
}
}
/* Block until the gaps are filled */
/*
* 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 (CONFIG.log_type & debug) {
if (j) {
erase_string(stderr, STATUS_LEN, s);
}
@ -306,8 +342,9 @@ static void LinkTable_uninitialised_fill(LinkTable *linktbl)
j++;
}
}
} while (u);
if (CONFIG.log_level & debug) {
}
while (u);
if (CONFIG.log_type & debug) {
erase_string(stderr, STATUS_LEN, s);
fprintf(stderr, "Done!\n");
}
@ -326,7 +363,8 @@ static void LinkTable_fill(LinkTable *linktbl)
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);
strncpy(this_link->linkname, unescaped_linkname,
MAX_FILENAME_LEN);
curl_free(unescaped_linkname);
curl_easy_cleanup(c);
}
@ -360,6 +398,7 @@ void LinkTable_free(LinkTable *linktbl)
void LinkTable_print(LinkTable * linktbl)
{
if (CONFIG.log_type & debug) {
int j = 0;
lprintf(debug, "--------------------------------------------\n");
lprintf(debug, " LinkTable %p for %s\n", linktbl,
@ -371,12 +410,10 @@ void LinkTable_print(LinkTable *linktbl)
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)) {
this_link->linkname, this_link->f_url);
if ((this_link->type != LINK_FILE)
&& (this_link->type != LINK_DIR)
&& (this_link->type != LINK_HEAD)) {
j++;
}
}
@ -384,6 +421,7 @@ void LinkTable_print(LinkTable *linktbl)
lprintf(debug, "LinkTable_print(): Invalid link count: %d\n", j);
lprintf(debug, "--------------------------------------------\n");
}
}
DataStruct Link_to_DataStruct(Link * head_link)
{
@ -396,15 +434,17 @@ DataStruct Link_to_DataStruct(Link *head_link)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf);
/* If we get temporary HTTP failure, wait for 5 seconds before retry */
/*
* 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);
"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,
@ -414,7 +454,8 @@ DataStruct Link_to_DataStruct(Link *head_link)
curl_easy_cleanup(curl);
return buf;
}
} while (HTTP_temp_failure(http_resp));
}
while (HTTP_temp_failure(http_resp));
curl_easy_getinfo(curl, CURLINFO_FILETIME, &(head_link->time));
curl_easy_cleanup(curl);
@ -425,7 +466,9 @@ LinkTable *LinkTable_alloc(const char *url)
{
LinkTable *linktbl = CALLOC(1, sizeof(LinkTable));
/* populate the base URL */
/*
* 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);
@ -437,14 +480,18 @@ LinkTable *LinkTable_new(const char *url)
{
LinkTable *linktbl = LinkTable_alloc(url);
/* start downloading the base URL */
/*
* 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 */
/*
* Otherwise parsed the received data
*/
GumboOutput *output = gumbo_parse(buf.data);
HTML_to_LinkTable(output->root, linktbl);
gumbo_destroy_output(&kGumboDefaultOptions, output);
@ -459,7 +506,9 @@ LinkTable *LinkTable_new(const char *url)
LinkTable *disk_linktbl;
disk_linktbl = LinkTable_disk_open(unescaped_path);
if (disk_linktbl) {
/* Check if we need to update the link table */
/*
* 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);
@ -474,15 +523,21 @@ LinkTable *LinkTable_new(const char *url)
}
if (!skip_fill) {
/* Fill in the link table */
/*
* Fill in the link table
*/
LinkTable_fill(linktbl);
} else {
/* Fill in the holes in the link table */
/*
* Fill in the holes in the link table
*/
LinkTable_invalid_reset(linktbl);
LinkTable_uninitialised_fill(linktbl);
}
/* Save the link table */
/*
* Save the link table
*/
if (CACHE_SYSTEM_INIT) {
if (LinkTable_disk_save(linktbl, unescaped_path)) {
exit_failure();
@ -507,8 +562,8 @@ static void LinkTable_disk_delete(const char *dirn)
path = path_append(metadirn, "/.LinkTable");
}
if (unlink(path)) {
lprintf(error, "LinkTable_disk_delete(): unlink(%s): %s\n", path,
strerror(errno));
lprintf(error, "LinkTable_disk_delete(): unlink(%s): %s\n",
path, strerror(errno));
}
FREE(path);
FREE(metadirn);
@ -536,10 +591,13 @@ int LinkTable_disk_save(LinkTable *linktbl, const char *dirn)
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]->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]->content_length, sizeof(size_t), 1,
fp);
fwrite(&linktbl->links[i]->time, sizeof(long), 1, fp);
}
@ -583,21 +641,25 @@ LinkTable *LinkTable_disk_open(const char *dirn)
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]->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]->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");
/*
* 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");
lprintf(error,
"LinkTable_disk_open(): encountered ferror!\n");
LinkTable_free(linktbl);
LinkTable_disk_delete(dirn);
return NULL;
@ -611,7 +673,6 @@ LinkTable *LinkTable_disk_open(const char *dirn)
return linktbl;
}
LinkTable *path_to_Link_LinkTable_new(const char *path)
{
Link *link = path_to_Link(path);
@ -621,9 +682,11 @@ LinkTable *path_to_Link_LinkTable_new(const char *path)
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);
next_table =
sonic_LinkTable_new_index(link->sonic_id);
} else {
next_table = sonic_LinkTable_new_id3(link->sonic_depth,
next_table =
sonic_LinkTable_new_id3(link->sonic_depth,
link->sonic_id);
}
}
@ -634,12 +697,16 @@ LinkTable *path_to_Link_LinkTable_new(const char *path)
static Link *path_to_Link_recursive(char *path, LinkTable * linktbl)
{
/* skip the leading '/' if it exists */
/*
* skip the leading '/' if it exists
*/
if (*path == '/') {
path++;
}
/* remove the last '/' if it exists */
/*
* remove the last '/' if it exists
*/
char *slash = &(path[strnlen(path, MAX_PATH_LEN) - 1]);
if (*slash == '/') {
*slash = '\0';
@ -647,10 +714,16 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
slash = strchr(path, '/');
if (slash == NULL) {
/* We cannot find another '/', we have reached the last level */
/*
* 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 */
if (!strncmp
(path, linktbl->links[i]->linkname,
MAX_FILENAME_LEN)) {
/*
* We found our link
*/
return linktbl->links[i];
}
}
@ -665,29 +738,44 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
* effective create two substrings
*/
*slash = '\0';
/* move the pointer past the '/' */
/*
* 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 (!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);
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);
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);
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 path_to_Link_recursive(next_path,
next_table);
}
}
}
@ -715,8 +803,8 @@ Link *path_to_Link(const char *path)
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");
@ -748,7 +836,9 @@ long path_download(const char *path, char *output_buf, size_t size,
transfer_blocking(curl);
/* Check for range seek support */
/*
* 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 \
@ -761,12 +851,11 @@ range requests\n");
long http_resp;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
if ( !(
(http_resp != HTTP_OK) ||
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",
(http_resp != HTTP_RANGE_NOT_SATISFIABLE))) {
lprintf(warning,
"path_download(): Could not download %s, HTTP %ld\n",
link->f_url, http_resp);
return -ENOENT;
}

View File

@ -16,11 +16,12 @@ int log_level_init()
return DEFAULT_LOG_LEVEL;
}
void log_printf(LogType type, const char *file, const char *func, int line,
void
log_printf(LogType type, const char *file, const char *func, int line,
const char *format, ...)
{
FILE *out = stderr;
if (type & CONFIG.log_level) {
if (type & CONFIG.log_type) {
switch (type) {
case fatal:
fprintf(out, "Fatal: ");
@ -43,7 +44,8 @@ void log_printf(LogType type, const char *file, const char *func, int line,
fprintf(out, "(%s:%s:%d): ", file, func, line);
print_actual_message:
{}
{
}
va_list args;
va_start(args, format);
vfprintf(out, format, args);

View File

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

View File

@ -20,17 +20,24 @@ static char *config_path = NULL;
int main(int argc, char **argv)
{
/* Automatically print help if not enough arguments are supplied */
/*
* 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]);
fprintf(stderr, "For more information, run \"%s --help.\"\n",
argv[0]);
exit(EXIT_FAILURE);
}
/* These are passed into fuse initialiser */
/*
* These are passed into fuse initialiser
*/
char **fuse_argv = NULL;
int fuse_argc = 0;
/* These are the combined argument with the config file */
/*
* These are the combined argument with the config file
*/
char **all_argv = NULL;
int all_argc = 0;
@ -39,13 +46,19 @@ int main(int argc, char **argv)
/*--- FUSE expects the first initialisation to be the program's name ---*/
add_arg(&fuse_argv, &fuse_argc, argv[0]);
/* initialise network configuration struct */
/*
* initialise network configuration struct
*/
Config_init();
/* initialise network subsystem */
/*
* initialise network subsystem
*/
NetworkSystem_init();
/* Copy the command line argument list to the combined argument list */
/*
* 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")) {
@ -53,10 +66,15 @@ int main(int argc, char **argv)
}
}
/* parse the config file, if it exists, store it in all_argv and 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 */
/*
* 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
@ -68,7 +86,9 @@ int main(int argc, char **argv)
/*--- Add the last remaining argument, which is the mountpoint ---*/
add_arg(&fuse_argv, &fuse_argc, argv[argc - 1]);
/* The second last remaining argument is the URL */
/*
* 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");
@ -103,14 +123,17 @@ void parse_config_file(char ***argv, int *argc)
if (!xdg_config_home) {
char *home = getenv("HOME");
char *xdg_config_home_default = "/.config";
xdg_config_home = path_append(home, xdg_config_home_default);
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 */
/*
* 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");
@ -122,16 +145,28 @@ void parse_config_file(char ***argv, int *argc)
char *space;
space = strchr(buf, ' ');
if (!space) {
*argv = realloc(*argv, *argc * sizeof(char **));
(*argv)[*argc - 1] = strndup(buf, buf_len);
*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 =
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));
buf_len -
(space +
1 - buf));
}
}
}
@ -146,7 +181,9 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
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 */
/*
* 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 */
@ -183,7 +220,9 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
case 'h':
print_help(argv[0], 1);
add_arg(fuse_argv, fuse_argc, "-ho");
/* skip everything else to print the help */
/*
* skip everything else to print the help
*/
return 1;
case 'V':
print_version(argv[0], 1);
@ -208,7 +247,9 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
CONFIG.proxy = strdup(optarg);
break;
case 'L':
/* Long options */
/*
* Long options
*/
switch (long_index) {
case 6:
CONFIG.proxy_username = strdup(optarg);
@ -256,7 +297,9 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
CONFIG.insecure_tls = 1;
break;
case 21:
/* This is for --config, we don't need to do anything */
/*
* This is for --config, we don't need to do anything
*/
break;
case 22:
CONFIG.mode = SINGLE_FILE;
@ -297,15 +340,16 @@ static void print_help(char *program_name, int long_help)
static void print_version()
{
printf("HTTPDirFS version " VERSION "\n");
/* --------- Print off SSL engine version --------- */
/*
* --------- 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\

View File

@ -11,11 +11,14 @@
#include <stdio.h>
#include <unistd.h>
/* ----------------- 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"
/**
@ -54,16 +59,22 @@ static unsigned long thread_id(void)
ret = (unsigned long)pthread_self();
return ret;
}
#pragma GCC diagnostic pop
static void crypto_lock_init(void)
{
int i;
crypto_lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
crypto_lockarray =
(pthread_mutex_t *) OPENSSL_malloc(CRYPTO_num_locks() *
sizeof(pthread_mutex_t));
for (i = 0; i < CRYPTO_num_locks(); i++) {
pthread_mutex_init(&(crypto_lockarray[i]), NULL);
if (pthread_mutex_init(&(crypto_lockarray[i]), NULL)) {
lprintf(fatal,
"crypto_lock_init(): crypto_lockarray[%d] initialisation \
failed!\n", i);
};
}
CRYPTO_set_id_callback((unsigned long (*)())thread_id);
@ -75,7 +86,8 @@ static void crypto_lock_init(void)
* \details Adapted from:
* https://curl.haxx.se/libcurl/c/threaded-shared-conn.html
*/
static void curl_callback_lock(CURL *handle, curl_lock_data data,
static void
curl_callback_lock(CURL * handle, curl_lock_data data,
curl_lock_access access, void *userptr)
{
(void)access; /* unused */
@ -85,8 +97,8 @@ static void curl_callback_lock(CURL *handle, curl_lock_data data,
PTHREAD_MUTEX_LOCK(&curl_lock);
}
static void curl_callback_unlock(CURL *handle, curl_lock_data data,
void *userptr)
static void
curl_callback_unlock(CURL * handle, curl_lock_data data, void *userptr)
{
(void)userptr; /* unused */
(void)handle; /* unused */
@ -99,8 +111,8 @@ static void curl_callback_unlock(CURL *handle, curl_lock_data data,
* \details Adapted from:
* https://curl.haxx.se/libcurl/c/10-at-a-time.html
*/
static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
int n_mesgs)
static void
curl_process_msgs(CURLMsg * curl_msg, int n_running_curl, int n_mesgs)
{
(void)n_running_curl;
(void)n_mesgs;
@ -114,12 +126,14 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
char *url = NULL;
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
/* Wait for 5 seconds if we get HTTP 429 */
/*
* 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,
lprintf(warning,
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
http_resp, CONFIG.http_wait_sec);
sleep(CONFIG.http_wait_sec);
@ -130,24 +144,27 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
}
if (!curl_msg->data.result) {
/* Transfer successful, set the file size */
/*
* 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",
lprintf(error, "curl_process_msgs(): %d - %s <%s>\n",
curl_msg->data.result,
curl_easy_strerror(curl_msg->data.result),
url);
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 */
/*
* 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",
lprintf(warning, "curl_process_msgs(): curl_msg->msg: %d\n",
curl_msg->msg);
}
}
@ -158,17 +175,19 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
*/
int curl_multi_perform_once(void)
{
#ifdef NETWORK_LOCK_DEBUG
lprintf(debug,
lprintf(network_lock_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 */
/*
* 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(error, "curl_multi_perform(): %s\n",
curl_multi_strerror(mc));
}
fd_set fdread;
@ -182,13 +201,17 @@ int curl_multi_perform_once(void)
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a default timeout for select() */
/*
* set a default timeout for select()
*/
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
curl_multi_timeout(curl_multi, &curl_timeo);
/* We effectively cap timeout to 1 sec */
/*
* We effectively cap timeout to 1 sec
*/
if (curl_timeo >= 0) {
timeout.tv_sec = curl_timeo / 1000;
if (timeout.tv_sec > 1) {
@ -198,79 +221,92 @@ int curl_multi_perform_once(void)
}
}
/* get file descriptors from the transfers */
/*
* get file descriptors from the transfers
*/
mc = curl_multi_fdset(curl_multi, &fdread, &fdwrite, &fdexcep, &maxfd);
if (mc > 0) {
lprintf(debug, "curl_multi_fdset(): %s.\n", curl_multi_strerror(mc));
lprintf(error, "curl_multi_fdset(): %s.\n",
curl_multi_strerror(mc));
}
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",
if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) <
0) {
lprintf(error,
"curl_multi_perform_once(): select(): %s.\n",
strerror(errno));
}
}
/* Process the message queue */
/*
* 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,
lprintf(network_lock_debug,
"curl_multi_perform_once(): thread %x: unlocking transfer_lock;\n",
pthread_self());
#endif
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
return n_running_curl;
}
void NetworkSystem_init(void)
{
/* ------- Global related ----------*/
/*
* ------- Global related ----------
*/
if (curl_global_init(CURL_GLOBAL_ALL)) {
lprintf(debug, "network_init(): curl_global_init() failed!\n");
exit_failure();
lprintf(fatal, "network_init(): curl_global_init() failed!\n");
}
/* -------- Share related ----------*/
/*
* -------- Share related ----------
*/
CURL_SHARE = curl_share_init();
if (!(CURL_SHARE)) {
lprintf(debug, "network_init(): curl_share_init() failed!\n");
exit_failure();
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_SSL_SESSION);
if (pthread_mutex_init(&curl_lock, NULL) != 0) {
lprintf(debug, "network_init(): curl_lock initialisation failed!\n");
exit_failure();
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);
curl_share_setopt(CURL_SHARE, CURLSHOPT_UNLOCKFUNC,
curl_callback_unlock);
/* ------------- Multi related -----------*/
/*
* ------------- Multi related -----------
*/
curl_multi = curl_multi_init();
if (!curl_multi) {
lprintf(debug, "network_init(): curl_multi_init() failed!\n");
exit_failure();
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 ---------*/
/*
* ------------ Initialise locks ---------
*/
if (pthread_mutex_init(&transfer_lock, NULL)) {
lprintf(debug,
lprintf(fatal,
"network_init(): transfer_lock initialisation failed!\n");
exit_failure();
}
/*
@ -290,24 +326,22 @@ void transfer_blocking(CURL *curl)
transfer.type = DATA;
transfer.transferring = 1;
curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer);
#ifdef NETWORK_LOCK_DEBUG
lprintf(debug,
lprintf(network_lock_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,
lprintf(network_lock_debug,
"transfer_blocking(): thread %x: unlocking transfer_lock;\n",
pthread_self());
#endif
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
if (res > 0) {
lprintf(debug, "transfer_blocking(): %d, %s\n",
lprintf(error, "transfer_blocking(): %d, %s\n",
res, curl_multi_strerror(res));
exit_failure();
}
while (transfer.transferring) {
@ -317,38 +351,36 @@ void transfer_blocking(CURL *curl)
void transfer_nonblocking(CURL * curl)
{
#ifdef NETWORK_LOCK_DEBUG
lprintf(debug,
lprintf(network_lock_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,
lprintf(network_lock_debug,
"transfer_nonblocking(): thread %x: unlocking transfer_lock;\n",
pthread_self());
#endif
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
if (res > 0) {
lprintf(debug, "transfer_nonblocking(): %s\n",
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;
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;
/*
* out of memory!
*/
lprintf(fatal, "write_memory_callback(): realloc failure!\n");
}
memmove(&mem->data[mem->size], contents, realsize);

View File

@ -26,11 +26,14 @@ static SonicConfigStruct SONIC_CONFIG;
/**
* \brief initalise Sonic configuration struct
*/
void sonic_config_init(const char *server, const char *username,
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 '/' */
/*
* 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';
@ -60,7 +63,8 @@ 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_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);
@ -79,8 +83,8 @@ static char *sonic_gen_auth_str(void)
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);
SONIC_CONFIG.username, pwd_hex,
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
FREE(pwd_hex);
return auth_str;
}
@ -93,8 +97,8 @@ 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);
snprintf(url, MAX_PATH_LEN, "%s/rest/%s%s", SONIC_CONFIG.server,
method, auth_str);
FREE(auth_str);
return url;
}
@ -142,8 +146,7 @@ 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);
snprintf(url, MAX_PATH_LEN, "%s&format=raw&id=%s", first_part, id);
FREE(first_part);
return url;
}
@ -162,10 +165,12 @@ 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 */
/*
* Error checking
*/
if (!strcmp(elem, "error")) {
lprintf(error, "XML_parser_general() error:\n");
for (int i = 0; attr[i]; i += 2) {
@ -182,22 +187,32 @@ static void XMLCALL XML_parser_general(void *data, const char *elem,
*/
if (!strcmp(elem, "child")) {
link = CALLOC(1, sizeof(Link));
/* Initialise to LINK_DIR, as the LINK_FILE is set later. */
/*
* 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 */
} 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) {
} 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 */
/*
* 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 */
/*
* The element does not contain directory structural information
*/
return;
}
@ -209,7 +224,8 @@ static void XMLCALL XML_parser_general(void *data, const char *elem,
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));
link->sonic_id =
CALLOC(MAX_FILENAME_LEN + 1, sizeof(char));
strncpy(link->sonic_id, attr[i + 1], MAX_FILENAME_LEN);
id_set = 1;
continue;
@ -217,12 +233,16 @@ static void XMLCALL XML_parser_general(void *data, const char *elem,
if (!strcmp("path", attr[i])) {
memset(link->linkname, 0, MAX_FILENAME_LEN);
/* Skip to the last '/' if it exists */
/*
* Skip to the last '/' if it exists
*/
char *s = strrchr(attr[i + 1], '/');
if (s) {
strncpy(link->linkname, s + 1, MAX_FILENAME_LEN);
strncpy(link->linkname, s + 1,
MAX_FILENAME_LEN);
} else {
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
strncpy(link->linkname, attr[i + 1],
MAX_FILENAME_LEN);
}
linkname_set = 1;
continue;
@ -234,8 +254,10 @@ static void XMLCALL XML_parser_general(void *data, const char *elem,
* 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);
if (!strcmp("title", attr[i])
|| !strcmp("name", attr[i])) {
strncpy(link->linkname, attr[i + 1],
MAX_FILENAME_LEN);
linkname_set = 1;
continue;
}
@ -283,7 +305,9 @@ static void XMLCALL XML_parser_general(void *data, const char *elem,
linkname_set = 1;
}
/* Clean up if linkname or id is not set */
/*
* Clean up if linkname or id is not set
*/
if (!linkname_set || !id_set) {
FREE(link);
return;
@ -308,7 +332,9 @@ static LinkTable *sonic_url_to_LinkTable(const char *url,
LinkTable *linktbl = LinkTable_alloc(url);
linktbl->links[0]->sonic_depth = depth;
/* start downloading the base URL */
/*
* start downloading the base URL
*/
DataStruct xml = Link_to_DataStruct(linktbl->links[0]);
if (xml.size == 0) {
LinkTable_free(linktbl);
@ -350,9 +376,8 @@ LinkTable *sonic_LinkTable_new_index(const char *id)
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");
@ -364,27 +389,37 @@ static void XMLCALL XML_parser_id3_root(void *data, const char *elem,
LinkTable *root_linktbl = (LinkTable *) data;
LinkTable *this_linktbl = NULL;
/* Set the current linktbl, if we have more than head link. */
/*
* 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;
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 */
/*
* 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);
strncpy(link->linkname, attr[i + 1],
MAX_FILENAME_LEN);
linkname_set = 1;
/* Allocate a new LinkTable */
/*
* Allocate a new LinkTable
*/
link->next_table = LinkTable_alloc("/");
}
}
/* Make sure we don't add an empty directory */
/*
* Make sure we don't add an empty directory
*/
if (linkname_set) {
LinkTable_add(root_linktbl, link);
} else {
@ -394,24 +429,31 @@ static void XMLCALL XML_parser_id3_root(void *data, const char *elem,
} else if (!strcmp(elem, "artist")) {
link = CALLOC(1, sizeof(Link));
link->type = LINK_DIR;
/* The new table should be a level 3 album table */
/*
* 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);
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);
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 */
/*
* Clean up if linkname is not set
*/
if (!linkname_set || !id_set) {
FREE(link);
return;
@ -430,22 +472,30 @@ LinkTable *sonic_LinkTable_new_id3(int depth, const char *id)
char *url;
LinkTable *linktbl = ROOT_LINK_TBL;
switch (depth) {
/* Root table */
/*
* 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 */
/*
* 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);
linktbl =
sonic_url_to_LinkTable(url, XML_parser_general, depth);
FREE(url);
break;
/* Song table - get all the songs of an album */
/*
* 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);
linktbl =
sonic_url_to_LinkTable(url, XML_parser_general, depth);
FREE(url);
break;
default:
@ -457,4 +507,3 @@ LinkTable *sonic_LinkTable_new_id3(int depth, const char *id)
}
return linktbl;
}

View File

@ -30,7 +30,8 @@
char *path_append(const char *path, const char *filename)
{
int needs_separator = 0;
if ((path[strnlen(path, MAX_PATH_LEN)-1] != '/') && (filename[0] != '/')) {
if ((path[strnlen(path, MAX_PATH_LEN) - 1] != '/')
&& (filename[0] != '/')) {
needs_separator = 1;
}
@ -56,7 +57,8 @@ 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",
lprintf(fatal,
"thread %x: pthread_mutex_unlock() failed, %d, %s\n",
pthread_self(), i, strerror(i));
}
}
@ -66,7 +68,8 @@ 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",
lprintf(fatal,
"thread %x: pthread_mutex_lock() failed, %d, %s\n",
pthread_self(), i, strerror(i));
}
}