Added single file mode
Implemented feature request https://github.com/fangfufu/httpdirfs/issues/86
This commit is contained in:
parent
af45bcfa19
commit
f42264d3c3
|
@ -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,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
typedef enum {
|
||||
NORMAL = 1,
|
||||
SONIC = 2,
|
||||
SINGLE_FILE = 3,
|
||||
SINGLE = 3,
|
||||
} OperationMode;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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) {
|
||||
|
|
288
src/link.c
288
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];
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue