diff --git a/src/cache.c b/src/cache.c index a2c6255..5bc8deb 100644 --- a/src/cache.c +++ b/src/cache.c @@ -666,11 +666,15 @@ int Cache_create(const char *path) { Link *this_link = path_to_Link(path); - char *fn = ""; + char *fn = "__UNINITIALISED__"; if (CONFIG.mode == NORMAL) { fn = curl_easy_unescape(NULL, this_link->f_url + ROOT_LINK_OFFSET, 0, NULL); + } else if (CONFIG.mode == SINGLE) { + fn = curl_easy_unescape(NULL, + this_link->linkname, 0, + NULL); } else if (CONFIG.mode == SONIC) { fn = this_link->sonic_id; } else { @@ -751,7 +755,7 @@ Cache *Cache_open(const char *fn) /* * Check if both metadata and data file exist */ - if (CONFIG.mode == NORMAL) { + if (CONFIG.mode == NORMAL || CONFIG.mode == SINGLE) { if (Cache_exist(fn)) { lprintf(cache_lock_debug, diff --git a/src/config.h b/src/config.h index e4731ad..cc50c08 100644 --- a/src/config.h +++ b/src/config.h @@ -29,7 +29,7 @@ typedef enum { NORMAL = 1, SONIC = 2, - SINGLE_FILE = 3, + SINGLE = 3, } OperationMode; /** diff --git a/src/fuse_local.c b/src/fuse_local.c index eb68b3c..0257834 100644 --- a/src/fuse_local.c +++ b/src/fuse_local.c @@ -152,6 +152,7 @@ fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add, */ dir_add(buf, ".", NULL, 0); dir_add(buf, "..", NULL, 0); + /* We skip the head link */ for (int i = 1; i < linktbl->num; i++) { Link *link = linktbl->links[i]; if (link->type != LINK_INVALID) { diff --git a/src/link.c b/src/link.c index 9d0dfe0..4b297ad 100644 --- a/src/link.c +++ b/src/link.c @@ -29,17 +29,155 @@ int ROOT_LINK_OFFSET = 0; */ static pthread_mutex_t link_lock; +/** + * \brief create a new Link + */ +static Link *Link_new(const char *linkname, LinkType type) +{ + Link *link = CALLOC(1, sizeof(Link)); + + strncpy(link->linkname, linkname, MAX_FILENAME_LEN); + link->type = type; + + /* + * remove the '/' from linkname if it exists + */ + char *c = + &(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]); + if (*c == '/') { + *c = '\0'; + } + + return link; +} + +static CURL *Link_to_curl(Link * link) +{ + CURL *curl = curl_easy_init(); + if (!curl) { + lprintf(fatal, "curl_easy_init() failed!\n"); + } + /* + * set up some basic curl stuff + */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + /* + * for following directories without the '/' + */ + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2); + curl_easy_setopt(curl, CURLOPT_URL, link->f_url); + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); + curl_easy_setopt(curl, CURLOPT_SHARE, CURL_SHARE); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); + if (CONFIG.insecure_tls) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + } + // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + if (CONFIG.http_username) { + curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username); + } + + if (CONFIG.http_password) { + curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password); + } + + if (CONFIG.proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy); + } + + if (CONFIG.proxy_username) { + curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, + CONFIG.proxy_username); + } + + if (CONFIG.proxy_password) { + curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, + CONFIG.proxy_password); + } + + return curl; +} + +static void Link_req_file_stat(Link * this_link) +{ + CURL *curl = Link_to_curl(this_link); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + + /* + * We need to put the variable on the heap, because otherwise the + * variable gets popped from the stack as the function returns. + * + * It gets freed in curl_multi_perform_once(); + */ + TransferStruct *transfer = CALLOC(1, sizeof(TransferStruct)); + + transfer->link = this_link; + transfer->type = FILESTAT; + curl_easy_setopt(curl, CURLOPT_PRIVATE, transfer); + + transfer_nonblocking(curl); +} + +/** + * \brief Fill in the uninitialised entries in a link table + * \details Try and get the stats for each link in the link table. This will get + * repeated until the uninitialised entry count drop to zero. + */ +static void LinkTable_uninitialised_fill(LinkTable * linktbl) +{ + int u; + char s[STATUS_LEN]; + lprintf(debug, "LinkTable_uninitialised_fill(): ... "); + do { + u = 0; + for (int i = 0; i < linktbl->num; i++) { + Link *this_link = linktbl->links[i]; + if (this_link->type == LINK_UNINITIALISED_FILE) { + Link_req_file_stat(linktbl->links[i]); + u++; + } + } + /* + * Block until the gaps are filled + */ + int n = curl_multi_perform_once(); + int i = 0; + int j = 0; + while ((i = curl_multi_perform_once())) { + if (CONFIG.log_type & debug) { + if (j) { + erase_string(stderr, STATUS_LEN, s); + } + snprintf(s, STATUS_LEN, "%d / %d", n - i, n); + fprintf(stderr, "%s", s); + j++; + } + } + } + while (u); + if (CONFIG.log_type & debug) { + erase_string(stderr, STATUS_LEN, s); + fprintf(stderr, "... Done!\n"); + } +} + /** * \brief Create the root linktable for single file mode */ static LinkTable *single_LinkTable_new(const char *url) { - char *ptr = strrchr(url, '/'); - int dir_len = ptr - url; - char *dir_name = CALLOC(dir_len + 1, sizeof(char)); - - free(dir_name); - return NULL; + char *ptr = strrchr(url, '/') + 1; + LinkTable *linktbl = LinkTable_alloc(url); + Link *link = Link_new(ptr, LINK_UNINITIALISED_FILE); + strncpy(link->f_url, url, MAX_FILENAME_LEN); + LinkTable_add(linktbl, link); + LinkTable_uninitialised_fill(linktbl); + LinkTable_print(linktbl); + return linktbl; } LinkTable *LinkSystem_init(const char *raw_url) @@ -79,6 +217,8 @@ LinkTable *LinkSystem_init(const char *raw_url) */ if (CONFIG.mode == NORMAL) { ROOT_LINK_TBL = LinkTable_new(url); + } else if (CONFIG.mode == SINGLE) { + ROOT_LINK_TBL = single_LinkTable_new(url); } else if (CONFIG.mode == SONIC) { sonic_config_init(url, CONFIG.sonic_username, CONFIG.sonic_password); @@ -105,28 +245,6 @@ void LinkTable_add(LinkTable * linktbl, Link * link) linktbl->links[linktbl->num - 1] = link; } -/** - * \brief create a new Link - */ -static Link *Link_new(const char *linkname, LinkType type) -{ - Link *link = CALLOC(1, sizeof(Link)); - - strncpy(link->linkname, linkname, MAX_FILENAME_LEN); - link->type = type; - - /* - * remove the '/' from linkname if it exists - */ - char *c = - &(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]); - if (*c == '/') { - *c = '\0'; - } - - return link; -} - static LinkType linkname_to_LinkType(const char *linkname) { /* @@ -219,77 +337,6 @@ static void HTML_to_LinkTable(GumboNode * node, LinkTable * linktbl) return; } -static CURL *Link_to_curl(Link * link) -{ - CURL *curl = curl_easy_init(); - if (!curl) { - lprintf(fatal, "curl_easy_init() failed!\n"); - } - /* - * set up some basic curl stuff - */ - curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - /* - * for following directories without the '/' - */ - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2); - curl_easy_setopt(curl, CURLOPT_URL, link->f_url); - curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); - curl_easy_setopt(curl, CURLOPT_SHARE, CURL_SHARE); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); - if (CONFIG.insecure_tls) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - } - // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - - if (CONFIG.http_username) { - curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username); - } - - if (CONFIG.http_password) { - curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password); - } - - if (CONFIG.proxy) { - curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy); - } - - if (CONFIG.proxy_username) { - curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, - CONFIG.proxy_username); - } - - if (CONFIG.proxy_password) { - curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, - CONFIG.proxy_password); - } - - return curl; -} - -static void Link_req_file_stat(Link * this_link) -{ - CURL *curl = Link_to_curl(this_link); - curl_easy_setopt(curl, CURLOPT_NOBODY, 1); - curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); - - /* - * We need to put the variable on the heap, because otherwise the - * variable gets popped from the stack as the function returns. - * - * It gets freed in curl_multi_perform_once(); - */ - TransferStruct *transfer = CALLOC(1, sizeof(TransferStruct)); - - transfer->link = this_link; - transfer->type = FILESTAT; - curl_easy_setopt(curl, CURLOPT_PRIVATE, transfer); - - transfer_nonblocking(curl); -} - void Link_set_file_stat(Link * this_link, CURL * curl) { long http_resp; @@ -315,49 +362,6 @@ void Link_set_file_stat(Link * this_link, CURL * curl) } } -/** - * \brief Fill in the uninitialised entries in a link table - * \details Try and get the stats for each link in the link table. This will get - * repeated until the uninitialised entry count drop to zero. - */ -static void LinkTable_uninitialised_fill(LinkTable * linktbl) -{ - int u; - char s[STATUS_LEN]; - lprintf(debug, "LinkTable_uninitialised_fill(): ... "); - do { - u = 0; - for (int i = 0; i < linktbl->num; i++) { - Link *this_link = linktbl->links[i]; - if (this_link->type == LINK_UNINITIALISED_FILE) { - Link_req_file_stat(linktbl->links[i]); - u++; - } - } - /* - * Block until the gaps are filled - */ - int n = curl_multi_perform_once(); - int i = 0; - int j = 0; - while ((i = curl_multi_perform_once())) { - if (CONFIG.log_type & debug) { - if (j) { - erase_string(stderr, STATUS_LEN, s); - } - snprintf(s, STATUS_LEN, "%d / %d", n - i, n); - fprintf(stderr, "%s", s); - j++; - } - } - } - while (u); - if (CONFIG.log_type & debug) { - erase_string(stderr, STATUS_LEN, s); - fprintf(stderr, "... Done!\n"); - } -} - static void LinkTable_fill(LinkTable * linktbl) { Link *head_link = linktbl->links[0]; diff --git a/src/main.c b/src/main.c index 523843b..de31d53 100644 --- a/src/main.c +++ b/src/main.c @@ -295,7 +295,7 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) */ break; case 22: - CONFIG.mode = SINGLE_FILE; + CONFIG.mode = SINGLE; break; default: fprintf(stderr, "see httpdirfs -h for usage\n");