relabelled all log outputs
This commit is contained in:
parent
0219d7460a
commit
0f3cc61875
2
Makefile
2
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)\"\
|
||||
|
|
349
src/cache.c
349
src/cache.c
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++) {
|
||||
|
|
257
src/link.c
257
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,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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
96
src/main.c
96
src/main.c
|
@ -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\
|
||||
|
|
176
src/network.c
176
src/network.c
|
@ -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);
|
||||
|
|
141
src/sonic.c
141
src/sonic.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue