Added single file mode

Implemented feature request
https://github.com/fangfufu/httpdirfs/issues/86
This commit is contained in:
Fufu Fang 2021-08-31 13:52:25 +01:00
parent af45bcfa19
commit f42264d3c3
No known key found for this signature in database
GPG Key ID: 0F6BB5EF6F8BB729
5 changed files with 155 additions and 146 deletions

View File

@ -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,

View File

@ -29,7 +29,7 @@
typedef enum {
NORMAL = 1,
SONIC = 2,
SINGLE_FILE = 3,
SINGLE = 3,
} OperationMode;
/**

View File

@ -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) {

View File

@ -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];

View File

@ -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");