Finished writing the code to generate Subsonic LinkTable

- Also refactored various bits and pieces
This commit is contained in:
Fufu Fang 2019-10-23 21:04:25 +01:00
parent b7c63f4418
commit 5062f511bd
No known key found for this signature in database
GPG Key ID: 0F6BB5EF6F8BB729
11 changed files with 307 additions and 133 deletions

View File

@ -1,7 +1,8 @@
VERSION=1.1.10 VERSION=1.1.10
CFLAGS+= -O2 -Wall -Wextra -Wshadow -rdynamic\ CFLAGS+= -O2 -Wall -Wextra -Wshadow\
-D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\" \ -rdynamic -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE\
-D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\
`pkg-config --cflags-only-I gumbo libcurl fuse uuid expat` `pkg-config --cflags-only-I gumbo libcurl fuse uuid expat`
LIBS = -pthread -lgumbo -lcurl -lfuse -lcrypto -luuid -lexpat LIBS = -pthread -lgumbo -lcurl -lfuse -lcrypto -luuid -lexpat
COBJS = network.o fuse_local.o link.o cache.o util.o main.o COBJS = network.o fuse_local.o link.o cache.o util.o main.o

View File

@ -9,21 +9,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/**
* \brief Data file block size
* \details We set it to 1024*1024*8 = 8MiB
*/
#define DEFAULT_DATA_BLK_SZ 8*1024*1024
/**
* \brief Maximum segment block count
* \details This is set to 128*1024 blocks, which uses 128KB. By default,
* this allows the user to store (128*1024)*(8*1024*1024) = 1TB of data
*/
#define DEFAULT_MAX_SEGBC 128*1024
/** /**
* \brief error associated with metadata * \brief error associated with metadata
*/ */
@ -36,10 +21,7 @@ typedef enum {
} MetaError; } MetaError;
/* ---------------- External variables -----------------------*/ /* ---------------- External variables -----------------------*/
int CACHE_SYSTEM_INIT = 0; int CACHE_SYSTEM_INIT = 0;
int DATA_BLK_SZ = 0;
int MAX_SEGBC = DEFAULT_MAX_SEGBC;
char *META_DIR; char *META_DIR;
/* ----------------- Static variables ----------------------- */ /* ----------------- Static variables ----------------------- */
@ -156,10 +138,6 @@ void CacheSystem_init(const char *path, int url_supplied)
strerror(errno)); strerror(errno));
} }
if (!DATA_BLK_SZ) {
DATA_BLK_SZ = DEFAULT_DATA_BLK_SZ;
}
CACHE_SYSTEM_INIT = 1; CACHE_SYSTEM_INIT = 1;
} }
@ -202,12 +180,12 @@ blksz: %d, segbc: %ld\n", cf->path, cf->content_length, cf->blksz, cf->segbc);
return EZERO; return EZERO;
} }
if (cf->blksz != DATA_BLK_SZ) { if (cf->blksz != CONFIG.data_blksz) {
fprintf(stderr, "Meta_read(): Warning: cf->blksz != DATA_BLK_SZ\n"); fprintf(stderr, "Meta_read(): Warning: cf->blksz != CONFIG.data_blksz\n");
} }
/* Allocate some memory for the segment */ /* Allocate some memory for the segment */
if (cf->segbc > MAX_SEGBC) { if (cf->segbc > CONFIG.max_segbc) {
fprintf(stderr, "Meta_read(): Error: segbc: %ld\n", cf->segbc); fprintf(stderr, "Meta_read(): Error: segbc: %ld\n", cf->segbc);
return EMEM; return EMEM;
} }
@ -671,7 +649,7 @@ int Cache_create(Link *this_link)
cf->path = strndup(fn, MAX_PATH_LEN); cf->path = strndup(fn, MAX_PATH_LEN);
cf->time = this_link->time; cf->time = this_link->time;
cf->content_length = this_link->content_length; cf->content_length = this_link->content_length;
cf->blksz = DATA_BLK_SZ; cf->blksz = CONFIG.data_blksz;
cf->segbc = (cf->content_length / cf->blksz) + 1; cf->segbc = (cf->content_length / cf->blksz) + 1;
cf->seg = CALLOC(cf->segbc, sizeof(Seg)); cf->seg = CALLOC(cf->segbc, sizeof(Seg));

View File

@ -70,16 +70,6 @@ struct Cache {
*/ */
extern int CACHE_SYSTEM_INIT; extern int CACHE_SYSTEM_INIT;
/**
* \brief The size of each download segment
*/
extern int DATA_BLK_SZ;
/**
* \brief The maximum segment count for a single cache file
*/
extern int MAX_SEGBC;
/** /**
* \brief The metadata directory * \brief The metadata directory
*/ */

View File

@ -49,9 +49,9 @@ LinkTable *LinkSystem_init(const char *url)
} }
/* ----------- Enable cache system --------------------*/ /* ----------- Enable cache system --------------------*/
if (NETWORK_CONFIG.cache_enabled) { if (CONFIG.cache_enabled) {
if (NETWORK_CONFIG.cache_dir) { if (CONFIG.cache_dir) {
CacheSystem_init(NETWORK_CONFIG.cache_dir, 0); CacheSystem_init(CONFIG.cache_dir, 0);
} else { } else {
CacheSystem_init(url, 1); CacheSystem_init(url, 1);
} }
@ -62,7 +62,7 @@ LinkTable *LinkSystem_init(const char *url)
return ROOT_LINK_TBL; return ROOT_LINK_TBL;
} }
static void LinkTable_add(LinkTable *linktbl, Link *link) void LinkTable_add(LinkTable *linktbl, Link *link)
{ {
linktbl->num++; linktbl->num++;
linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *)); linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *));
@ -139,7 +139,7 @@ static CURL *Link_to_curl(Link *link)
fprintf(stderr, "Link_to_curl(): curl_easy_init() failed!\n"); fprintf(stderr, "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, NETWORK_CONFIG.user_agent); curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); 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_MAXREDIRS, 2);
@ -151,26 +151,26 @@ static CURL *Link_to_curl(Link *link)
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
if (NETWORK_CONFIG.username) { if (CONFIG.http_username) {
curl_easy_setopt(curl, CURLOPT_USERNAME, NETWORK_CONFIG.username); curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username);
} }
if (NETWORK_CONFIG.password) { if (CONFIG.http_password) {
curl_easy_setopt(curl, CURLOPT_PASSWORD, NETWORK_CONFIG.password); curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password);
} }
if (NETWORK_CONFIG.proxy) { if (CONFIG.proxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, NETWORK_CONFIG.proxy); curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy);
} }
if (NETWORK_CONFIG.proxy_user) { if (CONFIG.proxy_username) {
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME,
NETWORK_CONFIG.proxy_user); CONFIG.proxy_username);
} }
if (NETWORK_CONFIG.proxy_pass) { if (CONFIG.proxy_password) {
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD,
NETWORK_CONFIG.proxy_pass); CONFIG.proxy_password);
} }
return curl; return curl;
@ -355,7 +355,7 @@ DataStruct Link_to_DataStruct(Link *head_link)
fprintf(stderr, fprintf(stderr,
"LinkTable_new(): URL: %s, HTTP %ld, retrying later.\n", "LinkTable_new(): URL: %s, HTTP %ld, retrying later.\n",
url, http_resp); url, http_resp);
sleep(HTTP_WAIT_SEC); sleep(CONFIG.http_wait_sec);
} else if (http_resp != HTTP_OK) { } else if (http_resp != HTTP_OK) {
fprintf(stderr, fprintf(stderr,
"LinkTable_new(): cannot retrieve URL: %s, HTTP %ld\n", "LinkTable_new(): cannot retrieve URL: %s, HTTP %ld\n",

View File

@ -159,4 +159,8 @@ void LinkTable_free(LinkTable *linktbl);
*/ */
void LinkTable_print(LinkTable *linktbl); void LinkTable_print(LinkTable *linktbl);
/**
* \brief add a Link to a LinkTable
*/
void LinkTable_add(LinkTable *linktbl, Link *link);
#endif #endif

View File

@ -36,7 +36,7 @@ int main(int argc, char **argv)
add_arg(&fuse_argv, &fuse_argc, argv[0]); add_arg(&fuse_argv, &fuse_argc, argv[0]);
/* initialise network configuration struct */ /* initialise network configuration struct */
NetworkConfig_init(); Config_init();
/* initialise network subsystem */ /* initialise network subsystem */
NetworkSystem_init(); NetworkSystem_init();
@ -140,7 +140,10 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
{"max-conns", required_argument, NULL, 'L'}, /* 11 */ {"max-conns", required_argument, NULL, 'L'}, /* 11 */
{"user-agent", required_argument, NULL, 'L'}, /* 12 */ {"user-agent", required_argument, NULL, 'L'}, /* 12 */
{"retry-wait", required_argument, NULL, 'L'}, /* 13 */ {"retry-wait", required_argument, NULL, 'L'}, /* 13 */
{"cache-location", required_argument, NULL, 'L'}, /* 14 */ {"cache-location", required_argument, NULL, 'L'}, /* 14 */
{"sonic-username", required_argument, NULL, 'L'}, /* 15 */
{"sonic-password", required_argument, NULL, 'L'}, /* 16 */
{"sonic", no_argument, NULL, 'L'}, /* 17 */
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
while ((c = while ((c =
@ -170,43 +173,52 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
add_arg(fuse_argv, fuse_argc, "-s"); add_arg(fuse_argv, fuse_argc, "-s");
break; break;
case 'u': case 'u':
NETWORK_CONFIG.username = strdup(optarg); CONFIG.http_username = strdup(optarg);
break; break;
case 'p': case 'p':
NETWORK_CONFIG.password = strdup(optarg); CONFIG.http_password = strdup(optarg);
break; break;
case 'P': case 'P':
NETWORK_CONFIG.proxy = strdup(optarg); CONFIG.proxy = strdup(optarg);
break; break;
case 'L': case 'L':
/* Long options */ /* Long options */
switch (long_index) { switch (long_index) {
case 6: case 6:
NETWORK_CONFIG.proxy_user = strdup(optarg); CONFIG.proxy_username = strdup(optarg);
break; break;
case 7: case 7:
NETWORK_CONFIG.proxy_pass = strdup(optarg); CONFIG.proxy_password = strdup(optarg);
break; break;
case 8: case 8:
NETWORK_CONFIG.cache_enabled = 1; CONFIG.cache_enabled = 1;
break; break;
case 9: case 9:
DATA_BLK_SZ = atoi(optarg) * 1024 * 1024; CONFIG.data_blksz = atoi(optarg) * 1024 * 1024;
break; break;
case 10: case 10:
MAX_SEGBC = atoi(optarg); CONFIG.max_segbc = atoi(optarg);
break; break;
case 11: case 11:
NETWORK_CONFIG.max_conns = atoi(optarg); CONFIG.max_conns = atoi(optarg);
break; break;
case 12: case 12:
NETWORK_CONFIG.user_agent = strdup(optarg); CONFIG.user_agent = strdup(optarg);
break; break;
case 13: case 13:
HTTP_WAIT_SEC = atoi(optarg); CONFIG.http_wait_sec = atoi(optarg);
break; break;
case 14: case 14:
NETWORK_CONFIG.cache_dir = strdup(optarg); CONFIG.cache_dir = strdup(optarg);
break;
case 15:
CONFIG.sonic_username = strdup(optarg);
break;
case 16:
CONFIG.sonic_password = strdup(optarg);
break;
case 17:
CONFIG.sonic_mode = 1;
break; break;
default: default:
fprintf(stderr, "see httpdirfs -h for usage\n"); fprintf(stderr, "see httpdirfs -h for usage\n");

View File

@ -9,13 +9,9 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#define DEFAULT_NETWORK_MAX_CONNS 10
#define DEFAULT_HTTP_WAIT_SEC 5
/* ----------------- External variables ---------------------- */ /* ----------------- External variables ---------------------- */
CURLSH *CURL_SHARE; CURLSH *CURL_SHARE;
NetworkConfigStruct NETWORK_CONFIG;
int HTTP_WAIT_SEC = DEFAULT_HTTP_WAIT_SEC;
/* ----------------- Static variable ----------------------- */ /* ----------------- Static variable ----------------------- */
/** \brief curl multi interface handle */ /** \brief curl multi interface handle */
@ -123,8 +119,8 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
if (!slept) { if (!slept) {
fprintf(stderr, fprintf(stderr,
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n", "curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
http_resp, HTTP_WAIT_SEC); http_resp, CONFIG.http_wait_sec);
sleep(HTTP_WAIT_SEC); sleep(CONFIG.http_wait_sec);
slept = 1; slept = 1;
} }
} else { } else {
@ -231,19 +227,6 @@ int curl_multi_perform_once(void)
return n_running_curl; return n_running_curl;
} }
void NetworkConfig_init(void)
{
NETWORK_CONFIG.username = NULL;
NETWORK_CONFIG.password = NULL;
NETWORK_CONFIG.proxy = NULL;
NETWORK_CONFIG.proxy_user = NULL;
NETWORK_CONFIG.proxy_pass = NULL;
NETWORK_CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
NETWORK_CONFIG.user_agent = DEFAULT_USER_AGENT;
NETWORK_CONFIG.cache_enabled = 0;
NETWORK_CONFIG.cache_dir = NULL;
}
void NetworkSystem_init(void) void NetworkSystem_init(void)
{ {
/* ------- Global related ----------*/ /* ------- Global related ----------*/
@ -277,9 +260,9 @@ void NetworkSystem_init(void)
exit_failure(); exit_failure();
} }
curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS,
NETWORK_CONFIG.max_conns); CONFIG.max_conns);
curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS, curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS,
NETWORK_CONFIG.max_conns); CONFIG.max_conns);
/* ------------ Initialise locks ---------*/ /* ------------ Initialise locks ---------*/
if (pthread_mutex_init(&transfer_lock, NULL)) { if (pthread_mutex_init(&transfer_lock, NULL)) {

View File

@ -8,24 +8,6 @@
#include "link.h" #include "link.h"
/**
* \brief the default user agent string
*/
#define DEFAULT_USER_AGENT "HTTPDirFS-" VERSION
typedef struct {
char *username;
char *password;
char *proxy;
char *proxy_user;
char *proxy_pass;
long max_conns;
char *user_agent;
int http_429_wait;
char *cache_dir;
int cache_enabled;
} NetworkConfigStruct;
/** \brief HTTP response codes */ /** \brief HTTP response codes */
typedef enum { typedef enum {
HTTP_OK = 200, HTTP_OK = 200,
@ -36,21 +18,12 @@ typedef enum {
HTTP_CLOUDFLARE_TIMEOUT = 524 HTTP_CLOUDFLARE_TIMEOUT = 524
} HTTPResponseCode; } HTTPResponseCode;
/** \brief The waiting time after getting HTTP 429 */
extern int HTTP_WAIT_SEC;
/** \brief CURL configuration */
extern NetworkConfigStruct NETWORK_CONFIG;
/** \brief curl shared interface */ /** \brief curl shared interface */
extern CURLSH *CURL_SHARE; extern CURLSH *CURL_SHARE;
/** \brief perform one transfer cycle */ /** \brief perform one transfer cycle */
int curl_multi_perform_once(void); int curl_multi_perform_once(void);
/** \brief initialise network config struct */
void NetworkConfig_init(void);
/** \brief initialise the network module */ /** \brief initialise the network module */
void NetworkSystem_init(void); void NetworkSystem_init(void);

View File

@ -8,6 +8,8 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
typedef struct { typedef struct {
char *server; char *server;
@ -31,8 +33,8 @@ void sonic_config_init(const char *server, const char *username,
if (SONIC_CONFIG.server[server_url_len] == '/') { if (SONIC_CONFIG.server[server_url_len] == '/') {
SONIC_CONFIG.server[server_url_len] = '\0'; SONIC_CONFIG.server[server_url_len] = '\0';
} }
SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN); SONIC_CONFIG.http_username = strndup(username, MAX_FILENAME_LEN);
SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN); SONIC_CONFIG.http_password = strndup(password, MAX_FILENAME_LEN);
SONIC_CONFIG.client = DEFAULT_USER_AGENT; SONIC_CONFIG.client = DEFAULT_USER_AGENT;
/* /*
* API 1.13.0 is the minimum version that supports * API 1.13.0 is the minimum version that supports
@ -47,16 +49,16 @@ void sonic_config_init(const char *server, const char *username,
static char *sonic_gen_auth_str() static char *sonic_gen_auth_str()
{ {
char *salt = generate_salt(); char *salt = generate_salt();
size_t password_len = strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN); size_t password_len = strnlen(SONIC_CONFIG.http_password, MAX_FILENAME_LEN);
size_t password_salt_len = password_len + strnlen(salt, MAX_FILENAME_LEN); size_t password_salt_len = password_len + strnlen(salt, MAX_FILENAME_LEN);
char *password_salt = CALLOC(password_salt_len + 1, sizeof(char)); char *password_salt = CALLOC(password_salt_len + 1, sizeof(char));
strncat(password_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN); strncat(password_salt, SONIC_CONFIG.http_password, MAX_FILENAME_LEN);
strncat(password_salt + password_len, salt, MAX_FILENAME_LEN); strncat(password_salt + password_len, salt, MAX_FILENAME_LEN);
char *token = generate_md5sum(password_salt); char *token = generate_md5sum(password_salt);
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char)); char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
snprintf(auth_str, MAX_PATH_LEN, snprintf(auth_str, MAX_PATH_LEN,
".view?u=%s&t=%s&s=%s&v=%s&c=%s", ".view?u=%s&t=%s&s=%s&v=%s&c=%s",
SONIC_CONFIG.username, token, salt, SONIC_CONFIG.http_username, token, salt,
SONIC_CONFIG.api_version, SONIC_CONFIG.client); SONIC_CONFIG.api_version, SONIC_CONFIG.client);
free(salt); free(salt);
free(token); free(token);
@ -76,27 +78,54 @@ static char *sonic_gen_url_first_part(char *method)
return url; return url;
} }
/**
* \brief generate a getMusicDirectory request URL
*/
static char *sonic_getMusicDirectory_link(const int id)
{
char *first_part = sonic_gen_url_first_part("getMusicDirectory");
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
snprintf(url, MAX_PATH_LEN, "%s&id=%d", first_part, id);
free(first_part);
return url;
}
/**
* \brief generate a download request URL
*/
static char *sonic_download_link(const int id)
{
char *first_part = sonic_gen_url_first_part("download");
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
snprintf(url, MAX_PATH_LEN, "%s&id=%d", first_part, id);
free(first_part);
return url;
}
/** /**
* \brief Process a single element output by the parser * \brief Process a single element output by the parser
* \details This is the callback function called by the the XML parser. * \details This is the callback function called by the the XML parser.
* \param[in] data user supplied data, in this case it is the pointer to the * \param[in] data user supplied data, in this case it is the pointer to the
* LinkTable. * LinkTable.
* \param[in] element the name of this element, it should be either "child" or * \param[in] elem the name of this element, it should be either "child" or
* "artist" * "artist"
* \param[in] attributes Each attribute seen in a start (or empty) tag occupies * \param[in] attr Each attribute seen in a start (or empty) tag occupies
* 2 consecutive places in this vector: the attribute name followed by the * 2 consecutive places in this vector: the attribute name followed by the
* attribute value. These pairs are terminated by a null pointer. * attribute value. These pairs are terminated by a null pointer.
* \note we are using strcmp rather than strncmp, because we are assuming the
* parser terminates the strings properly, which is a fair assumption,
* considering how mature expat is.
*/ */
static void XMLCALL XML_process_single_element(void *data, const char *element, static void XMLCALL XML_process_single_element(void *data, const char *elem,
const char **attributes) const char **attr)
{ {
LinkTable *linktbl = (LinkTable *) data; LinkTable *linktbl = (LinkTable *) data;
Link *link; Link *link;
if (!strncmp(element, "child", 5)) { if (!strcmp(elem, "child")) {
/* Return from getMusicDirectory */ /* Return from getMusicDirectory */
link = CALLOC(1, sizeof(Link)); link = CALLOC(1, sizeof(Link));
link->type = LINK_INVALID; link->type = LINK_INVALID;
} else if (!strncmp(element, "artist", 6)){ } else if (!strcmp(elem, "artist")){
/* Return from getIndexes */ /* Return from getIndexes */
link = CALLOC(1, sizeof(Link)); link = CALLOC(1, sizeof(Link));
link->type = LINK_DIR; link->type = LINK_DIR;
@ -105,9 +134,78 @@ static void XMLCALL XML_process_single_element(void *data, const char *element,
return; return;
} }
for (int i = 0; attributes[i]; i += 2) { int id_set = 0;
int linkname_set = 0;
for (int i = 0; attr[i]; i += 2) {
if (!strcmp("id", attr[i])) {
link->sonic_id = atoi(attr[i+1]);
id_set = 1;
continue;
}
if (!strcmp("name", attr[i]) || !strcmp("title", attr[i])) {
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
linkname_set = 1;
continue;
}
if (!strcmp("isDir", attr[i])) {
if (!strcmp("true", attr[i+1])) {
link->type = LINK_DIR;
} else if (!strcmp("false", attr[i+1])) {
link->type = LINK_FILE;
} else {
link->type = LINK_DIR;
}
continue;
}
if (!strcmp("created", attr[i])) {
struct tm *tm = calloc(1, sizeof(struct tm));
strptime(attr[i+1], "%Y-%m-%dT%H:%M:%S.000Z", tm);
link->time = mktime(tm);
free(tm);
continue;
}
if (!strcmp("size", attr[i])) {
link->content_length = atoll(attr[i+1]);
continue;
}
} }
/* Clean up if linkname is not set */
if (!linkname_set) {
free(link);
return;
}
/* Clean up if id is not set */
if (!id_set) {
if (linkname_set) {
free(link->linkname);
}
free(link);
return;
}
if (link->type == LINK_DIR) {
char *url = sonic_getMusicDirectory_link(link->sonic_id);
strncpy(link->f_url, url, MAX_PATH_LEN);
free(url);
} else if (link->type == LINK_FILE) {
char *url = sonic_download_link(link->sonic_id);
strncpy(link->f_url, url, MAX_PATH_LEN);
free(url);
} else {
/* Invalid link */
free(link->linkname);
free(link);
return;
}
LinkTable_add(linktbl, link);
} }
/** /**
@ -127,14 +225,12 @@ static void sonic_XML_to_LinkTable(DataStruct ds, LinkTable *linktbl)
XML_ParserFree(parser); XML_ParserFree(parser);
} }
LinkTable *sonic_LinkTable_new(const int id) LinkTable *sonic_LinkTable_new(const int id)
{ {
char *url; char *url;
if (id > 0) { if (id > 0) {
char *first_part = sonic_gen_url_first_part("getMusicDirectory"); url = sonic_getMusicDirectory_link(id);
url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
snprintf(url, MAX_PATH_LEN, "%s&id=%d", first_part, id);
free(first_part);
} else { } else {
url = sonic_gen_url_first_part("getIndexes"); url = sonic_gen_url_first_part("getIndexes");
} }
@ -166,7 +262,7 @@ int main(int argc, char **argv)
sonic_config_init(argv[1], argv[2], argv[3]); sonic_config_init(argv[1], argv[2], argv[3]);
NetworkConfig_init(); Config_init();
NetworkSystem_init(); NetworkSystem_init();
sonic_LinkTable_new(0); sonic_LinkTable_new(0);

View File

@ -9,10 +9,86 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
/**
* \brief Backtrace buffer size
*/
#define BT_BUF_SIZE 100 #define BT_BUF_SIZE 100
/**
* \brief The length of a MD5SUM string
*/
#define MD5_HASH_LEN 32 #define MD5_HASH_LEN 32
/**
* \brief The length of the salt
* \details This is basically the length of a UUID
*/
#define SALT_LEN 36 #define SALT_LEN 36
/**
* \brief The default maximum number of network connections
*/
#define DEFAULT_NETWORK_MAX_CONNS 10
/**
* \brief The default HTTP 429 (too many requests) wait time
*/
#define DEFAULT_HTTP_WAIT_SEC 5
/**
* \brief Data file block size
* \details We set it to 1024*1024*8 = 8MiB
*/
#define DEFAULT_DATA_BLKSZ 8*1024*1024
/**
* \brief Maximum segment block count
* \details This is set to 128*1024 blocks, which uses 128KB. By default,
* this allows the user to store (128*1024)*(8*1024*1024) = 1TB of data
*/
#define DEFAULT_MAX_SEGBC 128*1024
ConfigStruct CONFIG;
/**
* \note The opening curly bracket should be at line 39, so the code lines up
* with the definition code in util.h.
*/
void Config_init(void)
{
/*---------------- Network related --------------*/
CONFIG.http_username = NULL;
CONFIG.http_password = NULL;
CONFIG.proxy = NULL;
CONFIG.proxy_username = NULL;
CONFIG.proxy_password = NULL;
CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
CONFIG.user_agent = DEFAULT_USER_AGENT;
CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC;
/*--------------- Cache related ---------------*/
CONFIG.cache_enabled = 0;
CONFIG.cache_dir = NULL;
CONFIG.data_blksz = DEFAULT_DATA_BLKSZ;
CONFIG.max_segbc = DEFAULT_MAX_SEGBC;
/*-------------- Subsonic related -------------*/
CONFIG.sonic_mode = 0;
CONFIG.sonic_username = NULL;
CONFIG.sonic_password = NULL;
}
char *path_append(const char *path, const char *filename) char *path_append(const char *path, const char *filename)
{ {
int needs_separator = 0; int needs_separator = 0;
@ -123,3 +199,4 @@ void *CALLOC(size_t nmemb, size_t size)
} }
return ptr; return ptr;
} }

View File

@ -21,6 +21,61 @@
*/ */
#define MAX_FILENAME_LEN 255 #define MAX_FILENAME_LEN 255
/**
* \brief the default user agent string
*/
#define DEFAULT_USER_AGENT "HTTPDirFS-" VERSION
/**
* \brief configuration data structure
* \note The opening curly bracket should be at line 39, so the code belong
* lines up with the initialisation code in util.c
*/
typedef struct {
/** \brief HTTP username */
char *http_username;
/** \brief HTTP password */
char *http_password;
/** \brief HTTP proxy URL */
char *proxy;
/** \brief HTTP proxy username */
char *proxy_username;
/** \brief HTTP proxy password */
char *proxy_password;
/** \brief HTTP maximum connection count */
long max_conns;
/** \brief HTTP user agent*/
char *user_agent;
/** \brief The waiting time after getting HTTP 429 (too many requests) */
int http_wait_sec;
/** \brief Whether cache mode is enabled */
int cache_enabled;
/** \brief The cache location*/
char *cache_dir;
/** \brief The size of each download segment for cache mode */
int data_blksz;
/** \brief The maximum segment count for a single cache file */
int max_segbc;
/** \brief Whether we are using the Subsonic mode */
int sonic_mode;
/** \brief The Subsonic server username */
char *sonic_username;
/** \brief The Subsonic server password */
char *sonic_password;
} ConfigStruct;
/**
* \brief The Configuration data structure
*/
extern ConfigStruct CONFIG;
/** /**
* \brief append a path * \brief append a path
* \details This function appends a path with the next level, while taking the * \details This function appends a path with the next level, while taking the
@ -74,4 +129,9 @@ char *generate_md5sum(const char *str);
*/ */
void *CALLOC(size_t nmemb, size_t size); void *CALLOC(size_t nmemb, size_t size);
/**
* \brief initialise the configuration data structure
*/
void Config_init(void);
#endif #endif