mirror of
https://github.com/fangfufu/httpdirfs.git
synced 2024-09-27 20:51:55 +02:00
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);
|
Link *this_link = path_to_Link(path);
|
||||||
|
|
||||||
char *fn = "";
|
char *fn = "__UNINITIALISED__";
|
||||||
if (CONFIG.mode == NORMAL) {
|
if (CONFIG.mode == NORMAL) {
|
||||||
fn = curl_easy_unescape(NULL,
|
fn = curl_easy_unescape(NULL,
|
||||||
this_link->f_url + ROOT_LINK_OFFSET, 0,
|
this_link->f_url + ROOT_LINK_OFFSET, 0,
|
||||||
NULL);
|
NULL);
|
||||||
|
} else if (CONFIG.mode == SINGLE) {
|
||||||
|
fn = curl_easy_unescape(NULL,
|
||||||
|
this_link->linkname, 0,
|
||||||
|
NULL);
|
||||||
} else if (CONFIG.mode == SONIC) {
|
} else if (CONFIG.mode == SONIC) {
|
||||||
fn = this_link->sonic_id;
|
fn = this_link->sonic_id;
|
||||||
} else {
|
} else {
|
||||||
@ -751,7 +755,7 @@ Cache *Cache_open(const char *fn)
|
|||||||
/*
|
/*
|
||||||
* Check if both metadata and data file exist
|
* Check if both metadata and data file exist
|
||||||
*/
|
*/
|
||||||
if (CONFIG.mode == NORMAL) {
|
if (CONFIG.mode == NORMAL || CONFIG.mode == SINGLE) {
|
||||||
if (Cache_exist(fn)) {
|
if (Cache_exist(fn)) {
|
||||||
|
|
||||||
lprintf(cache_lock_debug,
|
lprintf(cache_lock_debug,
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
NORMAL = 1,
|
NORMAL = 1,
|
||||||
SONIC = 2,
|
SONIC = 2,
|
||||||
SINGLE_FILE = 3,
|
SINGLE = 3,
|
||||||
} OperationMode;
|
} 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);
|
||||||
dir_add(buf, "..", NULL, 0);
|
dir_add(buf, "..", NULL, 0);
|
||||||
|
/* We skip the head link */
|
||||||
for (int i = 1; i < linktbl->num; i++) {
|
for (int i = 1; i < linktbl->num; i++) {
|
||||||
Link *link = linktbl->links[i];
|
Link *link = linktbl->links[i];
|
||||||
if (link->type != LINK_INVALID) {
|
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;
|
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
|
* \brief Create the root linktable for single file mode
|
||||||
*/
|
*/
|
||||||
static LinkTable *single_LinkTable_new(const char *url)
|
static LinkTable *single_LinkTable_new(const char *url)
|
||||||
{
|
{
|
||||||
char *ptr = strrchr(url, '/');
|
char *ptr = strrchr(url, '/') + 1;
|
||||||
int dir_len = ptr - url;
|
LinkTable *linktbl = LinkTable_alloc(url);
|
||||||
char *dir_name = CALLOC(dir_len + 1, sizeof(char));
|
Link *link = Link_new(ptr, LINK_UNINITIALISED_FILE);
|
||||||
|
strncpy(link->f_url, url, MAX_FILENAME_LEN);
|
||||||
free(dir_name);
|
LinkTable_add(linktbl, link);
|
||||||
return NULL;
|
LinkTable_uninitialised_fill(linktbl);
|
||||||
|
LinkTable_print(linktbl);
|
||||||
|
return linktbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkTable *LinkSystem_init(const char *raw_url)
|
LinkTable *LinkSystem_init(const char *raw_url)
|
||||||
@ -79,6 +217,8 @@ LinkTable *LinkSystem_init(const char *raw_url)
|
|||||||
*/
|
*/
|
||||||
if (CONFIG.mode == NORMAL) {
|
if (CONFIG.mode == NORMAL) {
|
||||||
ROOT_LINK_TBL = LinkTable_new(url);
|
ROOT_LINK_TBL = LinkTable_new(url);
|
||||||
|
} else if (CONFIG.mode == SINGLE) {
|
||||||
|
ROOT_LINK_TBL = single_LinkTable_new(url);
|
||||||
} else if (CONFIG.mode == SONIC) {
|
} else if (CONFIG.mode == SONIC) {
|
||||||
sonic_config_init(url, CONFIG.sonic_username,
|
sonic_config_init(url, CONFIG.sonic_username,
|
||||||
CONFIG.sonic_password);
|
CONFIG.sonic_password);
|
||||||
@ -105,28 +245,6 @@ void LinkTable_add(LinkTable * linktbl, Link * link)
|
|||||||
linktbl->links[linktbl->num - 1] = 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)
|
static LinkType linkname_to_LinkType(const char *linkname)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -219,77 +337,6 @@ static void HTML_to_LinkTable(GumboNode * node, LinkTable * linktbl)
|
|||||||
return;
|
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)
|
void Link_set_file_stat(Link * this_link, CURL * curl)
|
||||||
{
|
{
|
||||||
long http_resp;
|
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)
|
static void LinkTable_fill(LinkTable * linktbl)
|
||||||
{
|
{
|
||||||
Link *head_link = linktbl->links[0];
|
Link *head_link = linktbl->links[0];
|
||||||
|
@ -295,7 +295,7 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
|||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case 22:
|
case 22:
|
||||||
CONFIG.mode = SINGLE_FILE;
|
CONFIG.mode = SINGLE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user