diff --git a/Makefile b/Makefile index 8264ca1..35e2809 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION=1.1.10 CFLAGS+= -O2 -Wall -Wextra -Wshadow\ - -rdynamic -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE\ + -rdynamic -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE -D_GNU_SOURCE\ -D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\ `pkg-config --cflags-only-I gumbo libcurl fuse uuid expat` LIBS = -pthread -lgumbo -lcurl -lfuse -lcrypto -luuid -lexpat diff --git a/src/cache.c b/src/cache.c index aaefd6a..0d2c1fc 100644 --- a/src/cache.c +++ b/src/cache.c @@ -116,26 +116,45 @@ void CacheSystem_init(const char *path, int url_supplied) exit_failure(); } - /* Handle the case of missing '/' */ - if (path[strnlen(path, MAX_PATH_LEN) - 1] == '/') { - META_DIR = path_append(path, "meta/"); - DATA_DIR = path_append(path, "data/"); - } else { - META_DIR = path_append(path, "/meta/"); - DATA_DIR = path_append(path, "/data/"); - } + META_DIR = path_append(path, "meta/"); + DATA_DIR = path_append(path, "data/"); /* Check if directories exist, if not, create them */ if (mkdir(META_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) && (errno != EEXIST)) { fprintf(stderr, "CacheSystem_init(): mkdir(): %s\n", strerror(errno)); + exit_failure(); } if (mkdir(DATA_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) && (errno != EEXIST)) { fprintf(stderr, "CacheSystem_init(): mkdir(): %s\n", strerror(errno)); + exit_failure(); + } + + if (CONFIG.sonic_mode) { + char *sonic_path; + /* Create "rest" sub-directory for META_DIR */ + sonic_path = path_append(META_DIR, "rest/"); + if (mkdir(sonic_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + fprintf(stderr, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + exit_failure(); + } + free(sonic_path); + + /* Create "rest" sub-directory for DATA_DIR */ + sonic_path = path_append(DATA_DIR, "rest/"); + if (mkdir(sonic_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) + && (errno != EEXIST)) { + fprintf(stderr, "CacheSystem_init(): mkdir(): %s\n", + strerror(errno)); + exit_failure(); + } + free(sonic_path); } CACHE_SYSTEM_INIT = 1; @@ -410,6 +429,7 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len, fprintf(stderr, "Data_write(): fwrite(): requested %ld, returned %ld!\n", len, byte_written); + exit_failure(); if (ferror(cf->dfp)) { /* filesystem error */ fprintf(stderr, @@ -558,6 +578,11 @@ static int Cache_exist(const char *fn) */ void Cache_delete(const char *fn) { + if (CONFIG.sonic_mode) { + Link *link = path_to_Link(fn); + fn = link->sonic_id_str; + } + char *metafn = path_append(META_DIR, fn); char *datafn = path_append(DATA_DIR, fn); if (!access(metafn, F_OK)) { @@ -642,7 +667,12 @@ static int Meta_create(Cache *cf) int Cache_create(Link *this_link) { char *fn; - fn = curl_easy_unescape(NULL, this_link->f_url + ROOT_LINK_OFFSET, 0, NULL); + if (!CONFIG.sonic_mode) { + fn = curl_easy_unescape(NULL, this_link->f_url + ROOT_LINK_OFFSET, 0, + NULL); + } else { + fn = this_link->sonic_id_str; + } fprintf(stderr, "Cache_create(): Creating cache files for %s.\n", fn); Cache *cf = Cache_alloc(); @@ -655,6 +685,7 @@ int Cache_create(Link *this_link) if (Meta_create(cf)) { fprintf(stderr, "Cache_create(): cannot create metadata.\n"); + exit_failure(); } if (fclose(cf->mfp)) { @@ -689,23 +720,33 @@ int Cache_create(Link *this_link) * function returns 0 on success. */ int res = -(!Cache_exist(fn)); - curl_free(fn); + if (!CONFIG.sonic_mode) { + curl_free(fn); + } + return res; } Cache *Cache_open(const char *fn) { - /* Check if both metadata and data file exist */ - if (!Cache_exist(fn)) { - return NULL; - } - /* Obtain the link structure memory pointer */ Link *link = path_to_Link(fn); if (!link) { return NULL; } + /* Check if both metadata and data file exist */ + if (!CONFIG.sonic_mode) { + if (!Cache_exist(fn)) { + return NULL; + } + } else { + if (!Cache_exist(link->sonic_id_str)) { + return NULL; + } + fn = link->sonic_id_str; + } + /*---------------- Cache_open() critical section -----------------*/ #ifdef CACHE_LOCK_DEBUG diff --git a/src/link.c b/src/link.c index a92b922..8495ee7 100644 --- a/src/link.c +++ b/src/link.c @@ -49,24 +49,24 @@ LinkTable *LinkSystem_init(const char *url) ROOT_LINK_OFFSET += 1; } - /* ----------- Enable cache system --------------------*/ - /* For now, disable cache mode if sonic mode is enabled */ - if (!CONFIG.sonic_mode) { - if (CONFIG.cache_enabled) { - if (CONFIG.cache_dir) { - CacheSystem_init(CONFIG.cache_dir, 0); - } else { - CacheSystem_init(url, 1); - } + /* --------------------- Enable cache system -------------------- / + * + * Note that cache system is enabled automatically if sonic mode is + * enabled + */ + if (CONFIG.cache_enabled || CONFIG.sonic_mode) { + if (CONFIG.cache_dir) { + CacheSystem_init(CONFIG.cache_dir, 0); + } else { + CacheSystem_init(url, 1); } - } else { - sonic_config_init(url, CONFIG.sonic_username, CONFIG.sonic_password); } /* ----------- Create the root link table --------------*/ if (!CONFIG.sonic_mode) { ROOT_LINK_TBL = LinkTable_new(url); } else { + sonic_config_init(url, CONFIG.sonic_username, CONFIG.sonic_password); ROOT_LINK_TBL = sonic_LinkTable_new(0); } return ROOT_LINK_TBL; @@ -360,9 +360,11 @@ DataStruct Link_to_DataStruct(Link *head_link) { char *url = head_link->f_url; CURL *curl = Link_to_curl(head_link); + DataStruct buf; buf.size = 0; buf.data = NULL; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); /* If we get temporary HTTP failure, wait for 5 seconds before retry */ @@ -385,7 +387,6 @@ DataStruct Link_to_DataStruct(Link *head_link) } } while (HTTP_temp_failure(http_resp)); - curl_easy_getinfo(curl, CURLINFO_FILETIME, &(head_link->time)); curl_easy_cleanup(curl); return buf; @@ -705,8 +706,23 @@ long path_download(const char *path, char *output_buf, size_t size, PTHREAD_MUTEX_LOCK(&link_lock); PTHREAD_MUTEX_UNLOCK(&link_lock); + DataStruct header; + header.size = 0; + header.data = NULL; + curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&header); + transfer_blocking(curl); + /* Check for range seek support */ + if (!CONFIG.sonic_mode) { + if (!strcasestr((header.data), "Accept-Ranges: bytes")) { + fprintf(stderr, "Error: This web server does not support HTTP \ +range requests\n"); + exit(EXIT_FAILURE); + } + } + free(header.data); + long http_resp; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp); if ( !( diff --git a/src/link.h b/src/link.h index ac881be..2971b04 100644 --- a/src/link.h +++ b/src/link.h @@ -73,6 +73,10 @@ struct Link { * \details We use linkname to store filename */ int sonic_id; + /** + * \brief Sonic Music Directory ID in string format + */ + char sonic_id_str[MAX_FILENAME_LEN+1]; }; struct LinkTable { diff --git a/src/sonic.c b/src/sonic.c index 38b4ef1..6080aa3 100644 --- a/src/sonic.c +++ b/src/sonic.c @@ -140,6 +140,8 @@ static void XMLCALL XML_process_single_element(void *data, const char *elem, for (int i = 0; attr[i]; i += 2) { if (!strcmp("id", attr[i])) { link->sonic_id = atoi(attr[i+1]); + snprintf(link->sonic_id_str, MAX_FILENAME_LEN, "%d", + link->sonic_id); id_set = 1; continue; } diff --git a/src/util.h b/src/util.h index b99fd68..48892ec 100644 --- a/src/util.h +++ b/src/util.h @@ -80,8 +80,7 @@ extern ConfigStruct CONFIG; * \brief append a path * \details This function appends a path with the next level, while taking the * trailing slash of the upper level into account. - * - * Please free the char * after use. + * \note You need to free the char * after use. */ char *path_append(const char *path, const char *filename);