mirror of
https://github.com/TurboGit/hubicfuse.git
synced 2026-08-04 11:51:53 +02:00
Reformat code using astyle.
This commit is contained in:
+232
-151
@@ -48,7 +48,8 @@ extern bool option_extensive_debug;
|
|||||||
extern bool option_enable_chown;
|
extern bool option_enable_chown;
|
||||||
extern bool option_enable_chmod;
|
extern bool option_enable_chmod;
|
||||||
static int rhel5_mode = 0;
|
static int rhel5_mode = 0;
|
||||||
static struct statvfs statcache = {
|
static struct statvfs statcache =
|
||||||
|
{
|
||||||
.f_bsize = 4096,
|
.f_bsize = 4096,
|
||||||
.f_frsize = 4096,
|
.f_frsize = 4096,
|
||||||
.f_blocks = INT_MAX,
|
.f_blocks = INT_MAX,
|
||||||
@@ -62,7 +63,8 @@ static struct statvfs statcache = {
|
|||||||
//used to compute statfs cache interval
|
//used to compute statfs cache interval
|
||||||
static time_t last_stat_read_time = 0;
|
static time_t last_stat_read_time = 0;
|
||||||
extern FuseOptions options;
|
extern FuseOptions options;
|
||||||
struct MemoryStruct {
|
struct MemoryStruct
|
||||||
|
{
|
||||||
char* memory;
|
char* memory;
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
@@ -118,12 +120,16 @@ static void add_header(curl_slist **headers, const char *name,
|
|||||||
const char* value_ptr;
|
const char* value_ptr;
|
||||||
|
|
||||||
debugf(DBG_LEVEL_EXT, "add_header(%s:%s)", name, value);
|
debugf(DBG_LEVEL_EXT, "add_header(%s:%s)", name, value);
|
||||||
if (strlen(value) > 256) {
|
if (strlen(value) > 256)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"add_header: warning, value size > 256 (%s:%s) ", name, value);
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, KRED"add_header: warning, value size > 256 (%s:%s) ",
|
||||||
|
name, value);
|
||||||
//hubic will throw an HTTP 400 error on X-Copy-To operation if X-Object-Meta-FilePath header value is larger than 256 chars
|
//hubic will throw an HTTP 400 error on X-Copy-To operation if X-Object-Meta-FilePath header value is larger than 256 chars
|
||||||
//fix for issue #95 https://github.com/TurboGit/hubicfuse/issues/95
|
//fix for issue #95 https://github.com/TurboGit/hubicfuse/issues/95
|
||||||
if (!strcasecmp(name, "X-Object-Meta-FilePath")) {
|
if (!strcasecmp(name, "X-Object-Meta-FilePath"))
|
||||||
debugf(DBG_LEVEL_NORM, KRED"add_header: trimming header (%s) value to max allowed", name);
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"add_header: trimming header (%s) value to max allowed", name);
|
||||||
//trim header size to max allowed
|
//trim header size to max allowed
|
||||||
strncpy(safe_value, value, 256 - 1);
|
strncpy(safe_value, value, 256 - 1);
|
||||||
safe_value[255] = '\0';
|
safe_value[255] = '\0';
|
||||||
@@ -139,7 +145,8 @@ static void add_header(curl_slist **headers, const char *name,
|
|||||||
*headers = curl_slist_append(*headers, x_header);
|
*headers = curl_slist_append(*headers, x_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t header_dispatch(void *ptr, size_t size, size_t nmemb, void *dir_entry)
|
static size_t header_dispatch(void* ptr, size_t size, size_t nmemb,
|
||||||
|
void* dir_entry)
|
||||||
{
|
{
|
||||||
char* header = (char*)alloca(size * nmemb + 1);
|
char* header = (char*)alloca(size * nmemb + 1);
|
||||||
char* head = (char*)alloca(size * nmemb + 1);
|
char* head = (char*)alloca(size * nmemb + 1);
|
||||||
@@ -153,9 +160,11 @@ static size_t header_dispatch(void *ptr, size_t size, size_t nmemb, void *dir_en
|
|||||||
if (!strncasecmp(head, "x-storage-url", size * nmemb))
|
if (!strncasecmp(head, "x-storage-url", size * nmemb))
|
||||||
strncpy(storage_url, value, sizeof(storage_url));
|
strncpy(storage_url, value, sizeof(storage_url));
|
||||||
if (!strncasecmp(head, "x-account-meta-quota", size * nmemb))
|
if (!strncasecmp(head, "x-account-meta-quota", size * nmemb))
|
||||||
statcache.f_blocks = (unsigned long) (strtoull(value, NULL, 10)/statcache.f_frsize);
|
statcache.f_blocks = (unsigned long) (strtoull(value, NULL,
|
||||||
|
10) / statcache.f_frsize);
|
||||||
if (!strncasecmp(head, "x-account-bytes-used", size * nmemb))
|
if (!strncasecmp(head, "x-account-bytes-used", size * nmemb))
|
||||||
statcache.f_bfree = statcache.f_bavail = statcache.f_blocks - (unsigned long) (strtoull(value, NULL, 10)/statcache.f_frsize);
|
statcache.f_bfree = statcache.f_bavail = statcache.f_blocks - (unsigned long) (
|
||||||
|
strtoull(value, NULL, 10) / statcache.f_frsize);
|
||||||
if (!strncasecmp(head, "x-account-object-count", size * nmemb))
|
if (!strncasecmp(head, "x-account-object-count", size * nmemb))
|
||||||
{
|
{
|
||||||
unsigned long object_count = strtoul(value, NULL, 10);
|
unsigned long object_count = strtoul(value, NULL, 10);
|
||||||
@@ -166,7 +175,9 @@ static size_t header_dispatch(void *ptr, size_t size, size_t nmemb, void *dir_en
|
|||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void header_set_time_from_str(char *time_str, struct timespec *time_entry) {
|
static void header_set_time_from_str(char* time_str,
|
||||||
|
struct timespec* time_entry)
|
||||||
|
{
|
||||||
char sec_value[TIME_CHARS] = { 0 };
|
char sec_value[TIME_CHARS] = { 0 };
|
||||||
char nsec_value[TIME_CHARS] = { 0 };
|
char nsec_value[TIME_CHARS] = { 0 };
|
||||||
time_t sec;
|
time_t sec;
|
||||||
@@ -178,21 +189,25 @@ static void header_set_time_from_str(char *time_str, struct timespec *time_entry
|
|||||||
sec_value, nsec_value, sec, nsec, time_entry->tv_sec, time_entry->tv_nsec);
|
sec_value, nsec_value, sec, nsec, time_entry->tv_sec, time_entry->tv_nsec);
|
||||||
if (sec != time_entry->tv_sec || nsec != time_entry->tv_nsec)
|
if (sec != time_entry->tv_sec || nsec != time_entry->tv_nsec)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXTALL, "Time changed, setting new time=%li.%li, existing was=%li.%li",
|
debugf(DBG_LEVEL_EXTALL,
|
||||||
|
"Time changed, setting new time=%li.%li, existing was=%li.%li",
|
||||||
sec, nsec, time_entry->tv_sec, time_entry->tv_nsec);
|
sec, nsec, time_entry->tv_sec, time_entry->tv_nsec);
|
||||||
time_entry->tv_sec = sec;
|
time_entry->tv_sec = sec;
|
||||||
time_entry->tv_nsec = nsec;
|
time_entry->tv_nsec = nsec;
|
||||||
|
|
||||||
char time_str_local[TIME_CHARS] = "";
|
char time_str_local[TIME_CHARS] = "";
|
||||||
get_time_as_string((time_t)sec, nsec, time_str_local, sizeof(time_str_local));
|
get_time_as_string((time_t)sec, nsec, time_str_local, sizeof(time_str_local));
|
||||||
debugf(DBG_LEVEL_EXTALL, "header_set_time_from_str received time=[%s]", time_str_local);
|
debugf(DBG_LEVEL_EXTALL, "header_set_time_from_str received time=[%s]",
|
||||||
|
time_str_local);
|
||||||
|
|
||||||
get_timespec_as_str(time_entry, time_str_local, sizeof(time_str_local));
|
get_timespec_as_str(time_entry, time_str_local, sizeof(time_str_local));
|
||||||
debugf(DBG_LEVEL_EXTALL, "header_set_time_from_str set time=[%s]", time_str_local);
|
debugf(DBG_LEVEL_EXTALL, "header_set_time_from_str set time=[%s]",
|
||||||
|
time_str_local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t header_get_meta_dispatch(void *ptr, size_t size, size_t nmemb, void *userdata)
|
static size_t header_get_meta_dispatch(void* ptr, size_t size, size_t nmemb,
|
||||||
|
void* userdata)
|
||||||
{
|
{
|
||||||
char* header = (char*)alloca(size * nmemb + 1);
|
char* header = (char*)alloca(size * nmemb + 1);
|
||||||
char* head = (char*)alloca(size * nmemb + 1);
|
char* head = (char*)alloca(size * nmemb + 1);
|
||||||
@@ -207,41 +222,32 @@ static size_t header_get_meta_dispatch(void *ptr, size_t size, size_t nmemb, voi
|
|||||||
if (de != NULL)
|
if (de != NULL)
|
||||||
{
|
{
|
||||||
if (!strncasecmp(head, HEADER_TEXT_ATIME, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_ATIME, size * nmemb))
|
||||||
{
|
|
||||||
header_set_time_from_str(value, &de->atime);
|
header_set_time_from_str(value, &de->atime);
|
||||||
}
|
|
||||||
if (!strncasecmp(head, HEADER_TEXT_CTIME, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_CTIME, size * nmemb))
|
||||||
{
|
|
||||||
header_set_time_from_str(value, &de->ctime);
|
header_set_time_from_str(value, &de->ctime);
|
||||||
}
|
|
||||||
if (!strncasecmp(head, HEADER_TEXT_MTIME, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_MTIME, size * nmemb))
|
||||||
{
|
|
||||||
header_set_time_from_str(value, &de->mtime);
|
header_set_time_from_str(value, &de->mtime);
|
||||||
}
|
|
||||||
if (!strncasecmp(head, HEADER_TEXT_CHMOD, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_CHMOD, size * nmemb))
|
||||||
{
|
|
||||||
de->chmod = atoi(value);
|
de->chmod = atoi(value);
|
||||||
}
|
|
||||||
if (!strncasecmp(head, HEADER_TEXT_GID, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_GID, size * nmemb))
|
||||||
{
|
|
||||||
de->gid = atoi(value);
|
de->gid = atoi(value);
|
||||||
}
|
|
||||||
if (!strncasecmp(head, HEADER_TEXT_UID, size * nmemb))
|
if (!strncasecmp(head, HEADER_TEXT_UID, size * nmemb))
|
||||||
{
|
|
||||||
de->uid = atoi(value);
|
de->uid = atoi(value);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"Unexpected NULL dir_entry on header(%s), file should be in cache already",
|
||||||
|
storage);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "Unexpected NULL dir_entry on header(%s), file should be in cache already", storage);
|
{
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//debugf(DBG_LEVEL_NORM, "Received unexpected header line");
|
//debugf(DBG_LEVEL_NORM, "Received unexpected header line");
|
||||||
}
|
}
|
||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t rw_callback(size_t (*rw)(void*, size_t, size_t, FILE*), void *ptr,
|
static size_t rw_callback(size_t (*rw)(void*, size_t, size_t, FILE*),
|
||||||
|
void* ptr,
|
||||||
size_t size, size_t nmemb, void* userp)
|
size_t size, size_t nmemb, void* userp)
|
||||||
{
|
{
|
||||||
struct segment_info* info = (struct segment_info*)userp;
|
struct segment_info* info = (struct segment_info*)userp;
|
||||||
@@ -270,7 +276,8 @@ static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//http://curl.haxx.se/libcurl/c/CURLOPT_XFERINFOFUNCTION.html
|
//http://curl.haxx.se/libcurl/c/CURLOPT_XFERINFOFUNCTION.html
|
||||||
int progress_callback_xfer(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
int progress_callback_xfer(void* clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||||
|
curl_off_t ultotal, curl_off_t ulnow)
|
||||||
{
|
{
|
||||||
struct curl_progress* myp = (struct curl_progress*)clientp;
|
struct curl_progress* myp = (struct curl_progress*)clientp;
|
||||||
CURL* curl = myp->curl;
|
CURL* curl = myp->curl;
|
||||||
@@ -295,23 +302,28 @@ int progress_callback_xfer(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
|||||||
point = dlnow + ulnow;
|
point = dlnow + ulnow;
|
||||||
frac = (double)point / (double)total;
|
frac = (double)point / (double)total;
|
||||||
percent = frac * 100.0f;
|
percent = frac * 100.0f;
|
||||||
debugf(DBG_LEVEL_EXT, "TOTAL TIME: %.0f sec Down=%.0f Kbps UP=%.0f Kbps", curtime, dspeed/1024, uspeed/1024);
|
debugf(DBG_LEVEL_EXT, "TOTAL TIME: %.0f sec Down=%.0f Kbps UP=%.0f Kbps",
|
||||||
debugf(DBG_LEVEL_EXT, "UP: %lld of %lld DOWN: %lld/%lld Completion %.1f %%", ulnow, ultotal, dlnow, dltotal, percent);
|
curtime, dspeed / 1024, uspeed / 1024);
|
||||||
|
debugf(DBG_LEVEL_EXT, "UP: %lld of %lld DOWN: %lld/%lld Completion %.1f %%",
|
||||||
|
ulnow, ultotal, dlnow, dltotal, percent);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//http://curl.haxx.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
|
//http://curl.haxx.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
|
||||||
int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
|
int progress_callback(void* clientp, double dltotal, double dlnow,
|
||||||
|
double ultotal, double ulnow)
|
||||||
{
|
{
|
||||||
return progress_callback_xfer(clientp, (curl_off_t)dltotal, (curl_off_t)dlnow, (curl_off_t)ultotal, (curl_off_t)ulnow);
|
return progress_callback_xfer(clientp, (curl_off_t)dltotal, (curl_off_t)dlnow,
|
||||||
|
(curl_off_t)ultotal, (curl_off_t)ulnow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//get the response from HTTP requests, mostly for debug purposes
|
//get the response from HTTP requests, mostly for debug purposes
|
||||||
// http://stackoverflow.com/questions/2329571/c-libcurl-get-output-into-a-string
|
// http://stackoverflow.com/questions/2329571/c-libcurl-get-output-into-a-string
|
||||||
// http://curl.haxx.se/libcurl/c/getinmemory.html
|
// http://curl.haxx.se/libcurl/c/getinmemory.html
|
||||||
size_t writefunc_callback(void *contents, size_t size, size_t nmemb, void *userp)
|
size_t writefunc_callback(void* contents, size_t size, size_t nmemb,
|
||||||
|
void* userp)
|
||||||
{
|
{
|
||||||
size_t realsize = size * nmemb;
|
size_t realsize = size * nmemb;
|
||||||
struct MemoryStruct* mem = (struct MemoryStruct*)userp;
|
struct MemoryStruct* mem = (struct MemoryStruct*)userp;
|
||||||
@@ -348,13 +360,15 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
//needed to keep the response data, for debug purposes
|
//needed to keep the response data, for debug purposes
|
||||||
struct MemoryStruct chunk;
|
struct MemoryStruct chunk;
|
||||||
|
|
||||||
if (!storage_url[0]) {
|
if (!storage_url[0])
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"send_request with no storage_url?");
|
debugf(DBG_LEVEL_NORM, KRED"send_request with no storage_url?");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
//char *encoded_path = curl_escape(path, 0);
|
//char *encoded_path = curl_escape(path, 0);
|
||||||
|
|
||||||
while ((slash = strstr(path, "%2F")) || (slash = strstr(path, "%2f"))) {
|
while ((slash = strstr(path, "%2F")) || (slash = strstr(path, "%2f")))
|
||||||
|
{
|
||||||
*slash = '/';
|
*slash = '/';
|
||||||
memmove(slash + 1, slash + 3, strlen(slash + 3) + 1);
|
memmove(slash + 1, slash + 3, strlen(slash + 3) + 1);
|
||||||
}
|
}
|
||||||
@@ -385,27 +399,33 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
add_header(&headers, "X-Auth-Token", storage_token);
|
add_header(&headers, "X-Auth-Token", storage_token);
|
||||||
dir_entry* de;
|
dir_entry* de;
|
||||||
if (de_cached_entry == NULL)
|
if (de_cached_entry == NULL)
|
||||||
{
|
|
||||||
de = check_path_info(unencoded_path);
|
de = check_path_info(unencoded_path);
|
||||||
}
|
else
|
||||||
else {
|
{
|
||||||
// updating metadata on a file about to be added to cache (for x-copy, dest meta = src meta)
|
// updating metadata on a file about to be added to cache (for x-copy, dest meta = src meta)
|
||||||
de = de_cached_entry;
|
de = de_cached_entry;
|
||||||
debugf(DBG_LEVEL_EXTALL, "send_request_size: using param dir_entry(%s)", orig_path);
|
debugf(DBG_LEVEL_EXTALL, "send_request_size: using param dir_entry(%s)",
|
||||||
|
orig_path);
|
||||||
}
|
}
|
||||||
if (!de)
|
if (!de)
|
||||||
|
debugf(DBG_LEVEL_EXTALL,
|
||||||
|
"send_request_size: "KYEL"file not in cache (%s)(%s)(%s)", orig_path, path,
|
||||||
|
unencoded_path);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXTALL, "send_request_size: "KYEL"file not in cache (%s)(%s)(%s)", orig_path, path, unencoded_path);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// add headers to save utimens attribs only on upload
|
// add headers to save utimens attribs only on upload
|
||||||
if (!strcasecmp(method, "PUT") || !strcasecmp(method, "MKDIR"))
|
if (!strcasecmp(method, "PUT") || !strcasecmp(method, "MKDIR"))
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXTALL, "send_request_size: Saving utimens for file %s", orig_path);
|
debugf(DBG_LEVEL_EXTALL, "send_request_size: Saving utimens for file %s",
|
||||||
debugf(DBG_LEVEL_EXTALL, "send_request_size: Cached utime for path=%s ctime=%li.%li mtime=%li.%li atime=%li.%li", orig_path,
|
orig_path);
|
||||||
de->ctime.tv_sec, de->ctime.tv_nsec, de->mtime.tv_sec, de->mtime.tv_nsec, de->atime.tv_sec, de->atime.tv_nsec);
|
debugf(DBG_LEVEL_EXTALL,
|
||||||
|
"send_request_size: Cached utime for path=%s ctime=%li.%li mtime=%li.%li atime=%li.%li",
|
||||||
|
orig_path,
|
||||||
|
de->ctime.tv_sec, de->ctime.tv_nsec, de->mtime.tv_sec, de->mtime.tv_nsec,
|
||||||
|
de->atime.tv_sec, de->atime.tv_nsec);
|
||||||
|
|
||||||
char atime_str_nice[TIME_CHARS] = "", mtime_str_nice[TIME_CHARS] = "", ctime_str_nice[TIME_CHARS] = "";
|
char atime_str_nice[TIME_CHARS] = "", mtime_str_nice[TIME_CHARS] = "",
|
||||||
|
ctime_str_nice[TIME_CHARS] = "";
|
||||||
get_timespec_as_str(&(de->atime), atime_str_nice, sizeof(atime_str_nice));
|
get_timespec_as_str(&(de->atime), atime_str_nice, sizeof(atime_str_nice));
|
||||||
debugf(DBG_LEVEL_EXTALL, KCYN"send_request_size: atime=[%s]", atime_str_nice);
|
debugf(DBG_LEVEL_EXTALL, KCYN"send_request_size: atime=[%s]", atime_str_nice);
|
||||||
get_timespec_as_str(&(de->mtime), mtime_str_nice, sizeof(mtime_str_nice));
|
get_timespec_as_str(&(de->mtime), mtime_str_nice, sizeof(mtime_str_nice));
|
||||||
@@ -415,9 +435,12 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
|
|
||||||
char mtime_str[TIME_CHARS], atime_str[TIME_CHARS], ctime_str[TIME_CHARS];
|
char mtime_str[TIME_CHARS], atime_str[TIME_CHARS], ctime_str[TIME_CHARS];
|
||||||
char string_float[TIME_CHARS];
|
char string_float[TIME_CHARS];
|
||||||
snprintf(mtime_str, TIME_CHARS, "%lu.%lu", de->mtime.tv_sec, de->mtime.tv_nsec);
|
snprintf(mtime_str, TIME_CHARS, "%lu.%lu", de->mtime.tv_sec,
|
||||||
snprintf(atime_str, TIME_CHARS, "%lu.%lu", de->atime.tv_sec, de->atime.tv_nsec);
|
de->mtime.tv_nsec);
|
||||||
snprintf(ctime_str, TIME_CHARS, "%lu.%lu", de->ctime.tv_sec, de->ctime.tv_nsec);
|
snprintf(atime_str, TIME_CHARS, "%lu.%lu", de->atime.tv_sec,
|
||||||
|
de->atime.tv_nsec);
|
||||||
|
snprintf(ctime_str, TIME_CHARS, "%lu.%lu", de->ctime.tv_sec,
|
||||||
|
de->ctime.tv_nsec);
|
||||||
add_header(&headers, HEADER_TEXT_FILEPATH, orig_path);
|
add_header(&headers, HEADER_TEXT_FILEPATH, orig_path);
|
||||||
add_header(&headers, HEADER_TEXT_MTIME, mtime_str);
|
add_header(&headers, HEADER_TEXT_MTIME, mtime_str);
|
||||||
add_header(&headers, HEADER_TEXT_ATIME, atime_str);
|
add_header(&headers, HEADER_TEXT_ATIME, atime_str);
|
||||||
@@ -434,9 +457,9 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
add_header(&headers, HEADER_TEXT_UID, uid_str);
|
add_header(&headers, HEADER_TEXT_UID, uid_str);
|
||||||
add_header(&headers, HEADER_TEXT_CHMOD, chmod_str);
|
add_header(&headers, HEADER_TEXT_CHMOD, chmod_str);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXTALL, "send_request_size: not setting utimes (%s)", orig_path);
|
debugf(DBG_LEVEL_EXTALL, "send_request_size: not setting utimes (%s)",
|
||||||
}
|
orig_path);
|
||||||
}
|
}
|
||||||
if (!strcasecmp(method, "MKDIR"))
|
if (!strcasecmp(method, "MKDIR"))
|
||||||
{
|
{
|
||||||
@@ -462,9 +485,8 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
|
||||||
curl_easy_setopt(curl, CURLOPT_READDATA, fp);
|
curl_easy_setopt(curl, CURLOPT_READDATA, fp);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
||||||
}
|
|
||||||
if (is_segment)
|
if (is_segment)
|
||||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
||||||
//enable progress reporting
|
//enable progress reporting
|
||||||
@@ -496,7 +518,8 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
if (ftruncate(fileno(fp), 0) < 0)
|
if (ftruncate(fileno(fp), 0) < 0)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"ftruncate failed. I don't know what to do about that.");
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"ftruncate failed. I don't know what to do about that.");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
@@ -517,7 +540,8 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, xmlctx);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, xmlctx);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &xml_dispatch);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &xml_dispatch);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
//asumming retrieval of headers only
|
//asumming retrieval of headers only
|
||||||
debugf(DBG_LEVEL_EXT, "send_request_size: GET HEADERS only(%s)");
|
debugf(DBG_LEVEL_EXT, "send_request_size: GET HEADERS only(%s)");
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &header_get_meta_dispatch);
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &header_get_meta_dispatch);
|
||||||
@@ -525,7 +549,8 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "send_request_size: catch_all (%s)");
|
debugf(DBG_LEVEL_EXT, "send_request_size: catch_all (%s)");
|
||||||
// this posts an HEAD request (e.g. for statfs)
|
// this posts an HEAD request (e.g. for statfs)
|
||||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method);
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method);
|
||||||
@@ -539,14 +564,16 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
headers = curl_slist_append(headers, extra->data);
|
headers = curl_slist_append(headers, extra->data);
|
||||||
}
|
}
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
debugf(DBG_LEVEL_EXT, "status: send_request_size(%s) started HTTP REQ:%s", orig_path, url);
|
debugf(DBG_LEVEL_EXT, "status: send_request_size(%s) started HTTP REQ:%s",
|
||||||
|
orig_path, url);
|
||||||
curl_easy_perform(curl);
|
curl_easy_perform(curl);
|
||||||
double total_time;
|
double total_time;
|
||||||
char* effective_url;
|
char* effective_url;
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||||
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
|
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
|
||||||
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
|
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
|
||||||
debugf(DBG_LEVEL_EXT, "status: send_request_size(%s) completed HTTP REQ:%s total_time=%.1f seconds",
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"status: send_request_size(%s) completed HTTP REQ:%s total_time=%.1f seconds",
|
||||||
orig_path, effective_url, total_time);
|
orig_path, effective_url, total_time);
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
curl_easy_reset(curl);
|
curl_easy_reset(curl);
|
||||||
@@ -555,46 +582,59 @@ static int send_request_size(const char *method, const char *path, void *fp,
|
|||||||
if (response != 404 && (response >= 400 || response < 200))
|
if (response != 404 && (response >= 400 || response < 200))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Now, our chunk.memory points to a memory block that is chunk.size
|
Now, our chunk.memory points to a memory block that is chunk.size
|
||||||
* bytes big and contains the remote file.
|
bytes big and contains the remote file.
|
||||||
*/
|
*/
|
||||||
debugf(DBG_LEVEL_NORM, KRED"send_request_size: error message, size=%lu, [HTTP %d] (%s)(%s)",
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"send_request_size: error message, size=%lu, [HTTP %d] (%s)(%s)",
|
||||||
(long)chunk.size, response, method, path);
|
(long)chunk.size, response, method, path);
|
||||||
debugf(DBG_LEVEL_NORM, KRED"send_request_size: error message=[%s]", chunk.memory);
|
debugf(DBG_LEVEL_NORM, KRED"send_request_size: error message=[%s]",
|
||||||
|
chunk.memory);
|
||||||
}
|
}
|
||||||
free(chunk.memory);
|
free(chunk.memory);
|
||||||
|
|
||||||
if ((response >= 200 && response < 400) || (!strcasecmp(method, "DELETE") && response == 409))
|
if ((response >= 200 && response < 400) || (!strcasecmp(method, "DELETE")
|
||||||
|
&& response == 409))
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, "exit 0: send_request_size(%s) speed=%.1f sec "KCYN"(%s) "KGRN"[HTTP OK]",
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
"exit 0: send_request_size(%s) speed=%.1f sec "KCYN"(%s) "KGRN"[HTTP OK]",
|
||||||
orig_path, total_time, method);
|
orig_path, total_time, method);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
//handle cases when file is not found, no point in retrying, will exit
|
//handle cases when file is not found, no point in retrying, will exit
|
||||||
if (response == 404)
|
if (response == 404)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, "send_request_size: not found error for (%s)(%s), ignored "KYEL"[HTTP 404].", method, path);
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
"send_request_size: not found error for (%s)(%s), ignored "KYEL"[HTTP 404].",
|
||||||
|
method, path);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_NORM, "send_request_size: httpcode=%d (%s)(%s), retrying "KRED"[HTTP ERR]", response, method, path);
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
"send_request_size: httpcode=%d (%s)(%s), retrying "KRED"[HTTP ERR]", response,
|
||||||
|
method, path);
|
||||||
//todo: try to list response content for debug purposes
|
//todo: try to list response content for debug purposes
|
||||||
sleep(8 << tries); // backoff
|
sleep(8 << tries); // backoff
|
||||||
}
|
}
|
||||||
if (response == 401 && !cloudfs_connect())
|
if (response == 401 && !cloudfs_connect())
|
||||||
{ // re-authenticate on 401s
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KYEL"exit 1: send_request_size(%s) (%s) [HTTP REAUTH]", path, method);
|
// re-authenticate on 401s
|
||||||
|
debugf(DBG_LEVEL_NORM, KYEL"exit 1: send_request_size(%s) (%s) [HTTP REAUTH]",
|
||||||
|
path, method);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
if (xmlctx)
|
if (xmlctx)
|
||||||
xmlCtxtResetPush(xmlctx, NULL, 0, NULL, NULL);
|
xmlCtxtResetPush(xmlctx, NULL, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
debugf(DBG_LEVEL_NORM, "exit 2: send_request_size(%s)"KCYN"(%s) response=%d", path, method, response);
|
debugf(DBG_LEVEL_NORM, "exit 2: send_request_size(%s)"KCYN"(%s) response=%d",
|
||||||
|
path, method, response);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_request(char* method, const char* path, FILE* fp,
|
int send_request(char* method, const char* path, FILE* fp,
|
||||||
xmlParserCtxtPtr xmlctx, curl_slist *extra_headers, dir_entry *de_cached_entry, const char *unencoded_path)
|
xmlParserCtxtPtr xmlctx, curl_slist* extra_headers, dir_entry* de_cached_entry,
|
||||||
|
const char* unencoded_path)
|
||||||
{
|
{
|
||||||
long flen = 0;
|
long flen = 0;
|
||||||
if (fp)
|
if (fp)
|
||||||
@@ -603,7 +643,8 @@ int send_request(char *method, const char *path, FILE *fp,
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
flen = cloudfs_file_size(fileno(fp));
|
flen = cloudfs_file_size(fileno(fp));
|
||||||
}
|
}
|
||||||
return send_request_size(method, path, fp, xmlctx, extra_headers, flen, 0, de_cached_entry, unencoded_path);
|
return send_request_size(method, path, fp, xmlctx, extra_headers, flen, 0,
|
||||||
|
de_cached_entry, unencoded_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
//thread that downloads or uploads large file segments
|
//thread that downloads or uploads large file segments
|
||||||
@@ -626,7 +667,8 @@ void *upload_segment(void *seginfo)
|
|||||||
info->size, 1, NULL, seg_path);
|
info->size, 1, NULL, seg_path);
|
||||||
|
|
||||||
if (!(response >= 200 && response < 300))
|
if (!(response >= 200 && response < 300))
|
||||||
fprintf(stderr, "Segment upload %s failed with response %d", seg_path, response);
|
fprintf(stderr, "Segment upload %s failed with response %d", seg_path,
|
||||||
|
response);
|
||||||
|
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
fclose(info->fp);
|
fclose(info->fp);
|
||||||
@@ -635,7 +677,8 @@ void *upload_segment(void *seginfo)
|
|||||||
|
|
||||||
// segment_size is the globabl config variable and size_of_segment is local
|
// segment_size is the globabl config variable and size_of_segment is local
|
||||||
//TODO: return whether the upload/download failed or not
|
//TODO: return whether the upload/download failed or not
|
||||||
void run_segment_threads(const char *method, int segments, int full_segments, int remaining,
|
void run_segment_threads(const char* method, int segments, int full_segments,
|
||||||
|
int remaining,
|
||||||
FILE* fp, char* seg_base, int size_of_segments)
|
FILE* fp, char* seg_base, int size_of_segments)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "run_segment_threads(%s)", method);
|
debugf(DBG_LEVEL_EXT, "run_segment_threads(%s)", method);
|
||||||
@@ -665,7 +708,8 @@ void run_segment_threads(const char *method, int segments, int full_segments, in
|
|||||||
pthread_create(&threads[i], NULL, upload_segment, (void*) & (info[i]));
|
pthread_create(&threads[i], NULL, upload_segment, (void*) & (info[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < segments; i++) {
|
for (i = 0; i < segments; i++)
|
||||||
|
{
|
||||||
if ((ret = pthread_join(threads[i], NULL)) != 0)
|
if ((ret = pthread_join(threads[i], NULL)) != 0)
|
||||||
fprintf(stderr, "error waiting for thread %d, status = %d\n", i, ret);
|
fprintf(stderr, "error waiting for thread %d, status = %d\n", i, ret);
|
||||||
}
|
}
|
||||||
@@ -684,7 +728,8 @@ void split_path(const char *path, char *seg_base, char *container,
|
|||||||
char* _object = strsep(&string, "/");
|
char* _object = strsep(&string, "/");
|
||||||
char* remstr;
|
char* remstr;
|
||||||
|
|
||||||
while (remstr = strsep(&string, "/")) {
|
while (remstr = strsep(&string, "/"))
|
||||||
|
{
|
||||||
strncat(container, "/",
|
strncat(container, "/",
|
||||||
MAX_URL_SIZE - strnlen(container, MAX_URL_SIZE));
|
MAX_URL_SIZE - strnlen(container, MAX_URL_SIZE));
|
||||||
strncat(container, _object,
|
strncat(container, _object,
|
||||||
@@ -701,7 +746,8 @@ void split_path(const char *path, char *seg_base, char *container,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//checks on the cloud if this file (seg_path) have an associated segment folder
|
//checks on the cloud if this file (seg_path) have an associated segment folder
|
||||||
int internal_is_segmented(const char *seg_path, const char *object, const char *parent_path)
|
int internal_is_segmented(const char* seg_path, const char* object,
|
||||||
|
const char* parent_path)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "internal_is_segmented(%s)", seg_path);
|
debugf(DBG_LEVEL_EXT, "internal_is_segmented(%s)", seg_path);
|
||||||
//try to avoid an additional http request for small files
|
//try to avoid an additional http request for small files
|
||||||
@@ -713,27 +759,33 @@ int internal_is_segmented(const char *seg_path, const char *object, const char *
|
|||||||
//to force segment meta download for segmented files
|
//to force segment meta download for segmented files
|
||||||
potentially_segmented = true;
|
potentially_segmented = true;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
//potentially segmented, assumption is that 0 size files are potentially segmented
|
//potentially segmented, assumption is that 0 size files are potentially segmented
|
||||||
//while size>0 is for sure not segmented, so no point in making an expensive HTTP GET call
|
//while size>0 is for sure not segmented, so no point in making an expensive HTTP GET call
|
||||||
potentially_segmented = (de->size == 0 && !de->isdir) ? true : false;
|
potentially_segmented = (de->size == 0 && !de->isdir) ? true : false;
|
||||||
}
|
}
|
||||||
debugf(DBG_LEVEL_EXT, "internal_is_segmented: potentially segmented=%d", potentially_segmented);
|
debugf(DBG_LEVEL_EXT, "internal_is_segmented: potentially segmented=%d",
|
||||||
|
potentially_segmented);
|
||||||
dir_entry* seg_dir;
|
dir_entry* seg_dir;
|
||||||
if (potentially_segmented && cloudfs_list_directory(seg_path, &seg_dir))
|
if (potentially_segmented && cloudfs_list_directory(seg_path, &seg_dir))
|
||||||
{
|
{
|
||||||
if (seg_dir && seg_dir->isdir)
|
if (seg_dir && seg_dir->isdir)
|
||||||
{
|
{
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if (!strncmp(seg_dir->name, object, MAX_URL_SIZE))
|
if (!strncmp(seg_dir->name, object, MAX_URL_SIZE))
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "exit 0: internal_is_segmented(%s) "KGRN"TRUE", seg_path);
|
debugf(DBG_LEVEL_EXT, "exit 0: internal_is_segmented(%s) "KGRN"TRUE",
|
||||||
|
seg_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} while ((seg_dir = seg_dir->next));
|
}
|
||||||
|
while ((seg_dir = seg_dir->next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugf(DBG_LEVEL_EXT, "exit 1: internal_is_segmented(%s) "KYEL"FALSE", seg_path);
|
debugf(DBG_LEVEL_EXT, "exit 1: internal_is_segmented(%s) "KYEL"FALSE",
|
||||||
|
seg_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,7 +842,8 @@ int format_segments(const char *path, char * seg_base, long *segments,
|
|||||||
|
|
||||||
char* str_size = seg_dir->name;
|
char* str_size = seg_dir->name;
|
||||||
snprintf(manifest, MAX_URL_SIZE, "%s/%s", seg_path, str_size);
|
snprintf(manifest, MAX_URL_SIZE, "%s/%s", seg_path, str_size);
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"format_segments manifest2(%s) size=%s", manifest, str_size);
|
debugf(DBG_LEVEL_EXT, KMAG"format_segments manifest2(%s) size=%s", manifest,
|
||||||
|
str_size);
|
||||||
if (!cloudfs_list_directory(manifest, &seg_dir))
|
if (!cloudfs_list_directory(manifest, &seg_dir))
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "exit 2: format_segments(%s)", path);
|
debugf(DBG_LEVEL_EXT, "exit 2: format_segments(%s)", path);
|
||||||
@@ -821,18 +874,20 @@ int format_segments(const char *path, char * seg_base, long *segments,
|
|||||||
strncpy(tmp, seg_base, MAX_URL_SIZE);
|
strncpy(tmp, seg_base, MAX_URL_SIZE);
|
||||||
snprintf(seg_base, MAX_URL_SIZE, "%s/%s", tmp, manifest);
|
snprintf(seg_base, MAX_URL_SIZE, "%s/%s", tmp, manifest);
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"format_segments seg_base(%s)", seg_base);
|
debugf(DBG_LEVEL_EXT, KMAG"format_segments seg_base(%s)", seg_base);
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"exit 4: format_segments(%s) total=%d size_of_segments=%d remaining=%d, full_segments=%d segments=%d",
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
KMAG"exit 4: format_segments(%s) total=%d size_of_segments=%d remaining=%d, full_segments=%d segments=%d",
|
||||||
path, &total_size, &size_of_segments, &remaining, &full_segments, &segments);
|
path, &total_size, &size_of_segments, &remaining, &full_segments, &segments);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"exit 5: format_segments(%s) not segmented?", path);
|
debugf(DBG_LEVEL_EXT, KMAG"exit 5: format_segments(%s) not segmented?", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public interface
|
Public interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cloudfs_init()
|
void cloudfs_init()
|
||||||
@@ -874,7 +929,8 @@ void cloudfs_free()
|
|||||||
debugf(DBG_LEVEL_EXT, "Destroy mutex");
|
debugf(DBG_LEVEL_EXT, "Destroy mutex");
|
||||||
pthread_mutex_destroy(&pool_mut);
|
pthread_mutex_destroy(&pool_mut);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < curl_pool_count; ++n) {
|
for (n = 0; n < curl_pool_count; ++n)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "Cleaning curl conn %d", n);
|
debugf(DBG_LEVEL_EXT, "Cleaning curl conn %d", n);
|
||||||
curl_easy_cleanup(curl_pool[n]);
|
curl_easy_cleanup(curl_pool[n]);
|
||||||
}
|
}
|
||||||
@@ -926,14 +982,11 @@ int cloudfs_object_read_fp(const char *path, FILE *fp)
|
|||||||
if (is_segmented(path))
|
if (is_segmented(path))
|
||||||
{
|
{
|
||||||
if (!cloudfs_delete_object(path))
|
if (!cloudfs_delete_object(path))
|
||||||
{
|
debugf(DBG_LEVEL_NORM,
|
||||||
debugf(DBG_LEVEL_NORM, KRED"cloudfs_object_read_fp: couldn't delete existing file");
|
KRED"cloudfs_object_read_fp: couldn't delete existing file");
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
debugf(DBG_LEVEL_EXT, KYEL"cloudfs_object_read_fp: deleted existing file");
|
debugf(DBG_LEVEL_EXT, KYEL"cloudfs_object_read_fp: deleted existing file");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
if (flen >= segment_above)
|
if (flen >= segment_above)
|
||||||
@@ -974,13 +1027,16 @@ int cloudfs_object_read_fp(const char *path, FILE *fp)
|
|||||||
add_header(&headers, "x-object-manifest", manifest);
|
add_header(&headers, "x-object-manifest", manifest);
|
||||||
add_header(&headers, "Content-Length", "0");
|
add_header(&headers, "Content-Length", "0");
|
||||||
add_header(&headers, "Content-Type", filemimetype);
|
add_header(&headers, "Content-Type", filemimetype);
|
||||||
int response = send_request_size("PUT", encoded, NULL, NULL, headers, 0, 0, NULL, path);
|
int response = send_request_size("PUT", encoded, NULL, NULL, headers, 0, 0,
|
||||||
|
NULL, path);
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
debugf(DBG_LEVEL_EXT, "exit 0: cloudfs_object_read_fp(%s) uploaded ok, response=%d", path, response);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit 0: cloudfs_object_read_fp(%s) uploaded ok, response=%d", path, response);
|
||||||
return (response >= 200 && response < 300);
|
return (response >= 200 && response < 300);
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
// assume enters here when file is composed of only one segment (small files)
|
// assume enters here when file is composed of only one segment (small files)
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) "KYEL"unknown state", path);
|
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) "KYEL"unknown state", path);
|
||||||
}
|
}
|
||||||
@@ -989,9 +1045,8 @@ int cloudfs_object_read_fp(const char *path, FILE *fp)
|
|||||||
dir_entry* de = path_info(path);
|
dir_entry* de = path_info(path);
|
||||||
if (!de)
|
if (!de)
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) not in cache", path);
|
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) not in cache", path);
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) found in cache", path);
|
debugf(DBG_LEVEL_EXT, "cloudfs_object_read_fp(%s) found in cache", path);
|
||||||
}
|
|
||||||
int response = send_request("PUT", encoded, fp, NULL, NULL, NULL, path);
|
int response = send_request("PUT", encoded, fp, NULL, NULL, NULL, path);
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
debugf(DBG_LEVEL_EXT, "exit 1: cloudfs_object_read_fp(%s)", path);
|
debugf(DBG_LEVEL_EXT, "exit 1: cloudfs_object_read_fp(%s)", path);
|
||||||
@@ -1019,7 +1074,8 @@ int cloudfs_object_write_fp(const char *path, FILE *fp)
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
if (ftruncate(fileno(fp), 0) < 0)
|
if (ftruncate(fileno(fp), 0) < 0)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"ftruncate failed. I don't know what to do about that.");
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"ftruncate failed. I don't know what to do about that.");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
run_segment_threads("GET", segments, full_segments, remaining, fp,
|
run_segment_threads("GET", segments, full_segments, remaining, fp,
|
||||||
@@ -1052,7 +1108,8 @@ int cloudfs_object_truncate(const char *path, off_t size)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{//TODO: this is busted
|
{
|
||||||
|
//TODO: this is busted
|
||||||
response = send_request("GET", encoded, NULL, NULL, NULL, NULL, path);
|
response = send_request("GET", encoded, NULL, NULL, NULL, NULL, path);
|
||||||
}
|
}
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
@@ -1072,19 +1129,19 @@ void get_file_metadata(dir_entry *de)
|
|||||||
long remaining;
|
long remaining;
|
||||||
long size_of_segments;
|
long size_of_segments;
|
||||||
long total_size;
|
long total_size;
|
||||||
if (format_segments(de->full_name, seg_base, &segments, &full_segments, &remaining,
|
if (format_segments(de->full_name, seg_base, &segments, &full_segments,
|
||||||
|
&remaining,
|
||||||
&size_of_segments, &total_size))
|
&size_of_segments, &total_size))
|
||||||
{
|
|
||||||
de->size = total_size;
|
de->size = total_size;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (option_get_extended_metadata)
|
if (option_get_extended_metadata)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KCYN "get_file_metadata(%s)", de->full_name);
|
debugf(DBG_LEVEL_EXT, KCYN "get_file_metadata(%s)", de->full_name);
|
||||||
//retrieve additional file metadata with a quick HEAD query
|
//retrieve additional file metadata with a quick HEAD query
|
||||||
char* encoded = curl_escape(de->full_name, 0);
|
char* encoded = curl_escape(de->full_name, 0);
|
||||||
de->metadata_downloaded = true;
|
de->metadata_downloaded = true;
|
||||||
int response = send_request("GET", encoded, NULL, NULL, NULL, de, de->full_name);
|
int response = send_request("GET", encoded, NULL, NULL, NULL, de,
|
||||||
|
de->full_name);
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
debugf(DBG_LEVEL_EXT, KCYN "exit: get_file_metadata(%s)", de->full_name);
|
debugf(DBG_LEVEL_EXT, KCYN "exit: get_file_metadata(%s)", de->full_name);
|
||||||
}
|
}
|
||||||
@@ -1136,7 +1193,8 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
|
|
||||||
if ((!strcmp(path, "") || !strcmp(path, "/")) && *override_storage_url)
|
if ((!strcmp(path, "") || !strcmp(path, "/")) && *override_storage_url)
|
||||||
response = 404;
|
response = 404;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// this was generating 404 err on non segmented files (small files)
|
// this was generating 404 err on non segmented files (small files)
|
||||||
response = send_request("GET", container, NULL, xmlctx, NULL, NULL, path);
|
response = send_request("GET", container, NULL, xmlctx, NULL, NULL, path);
|
||||||
}
|
}
|
||||||
@@ -1165,11 +1223,13 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
char* content = "<?!?>";
|
char* content = "<?!?>";
|
||||||
for (text_node = anode->children; text_node; text_node = text_node->next)
|
for (text_node = anode->children; text_node; text_node = text_node->next)
|
||||||
{
|
{
|
||||||
if (text_node->type == XML_TEXT_NODE){
|
if (text_node->type == XML_TEXT_NODE)
|
||||||
|
{
|
||||||
content = (char*)text_node->content;
|
content = (char*)text_node->content;
|
||||||
//debugf(DBG_LEVEL_NORM, "List dir anode=%s content=%s", (const char *)anode->name, content);
|
//debugf(DBG_LEVEL_NORM, "List dir anode=%s content=%s", (const char *)anode->name, content);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
//debugf(DBG_LEVEL_NORM, "List dir anode=%s", (const char *)anode->name);
|
//debugf(DBG_LEVEL_NORM, "List dir anode=%s", (const char *)anode->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1181,14 +1241,10 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
if (slash && (0 == *(slash + 1)))
|
if (slash && (0 == *(slash + 1)))
|
||||||
*slash = 0;
|
*slash = 0;
|
||||||
if (asprintf(&(de->full_name), "%s/%s", path, de->name) < 0)
|
if (asprintf(&(de->full_name), "%s/%s", path, de->name) < 0)
|
||||||
{
|
|
||||||
de->full_name = NULL;
|
de->full_name = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!strcasecmp((const char*)anode->name, "bytes"))
|
if (!strcasecmp((const char*)anode->name, "bytes"))
|
||||||
{
|
|
||||||
de->size = strtoll(content, NULL, 10);
|
de->size = strtoll(content, NULL, 10);
|
||||||
}
|
|
||||||
if (!strcasecmp((const char*)anode->name, "content_type"))
|
if (!strcasecmp((const char*)anode->name, "content_type"))
|
||||||
{
|
{
|
||||||
de->content_type = strdup(content);
|
de->content_type = strdup(content);
|
||||||
@@ -1197,14 +1253,13 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
*semicolon = '\0';
|
*semicolon = '\0';
|
||||||
}
|
}
|
||||||
if (!strcasecmp((const char*)anode->name, "hash"))
|
if (!strcasecmp((const char*)anode->name, "hash"))
|
||||||
{
|
|
||||||
de->md5sum = strdup(content);
|
de->md5sum = strdup(content);
|
||||||
}
|
|
||||||
if (!strcasecmp((const char*)anode->name, "last_modified"))
|
if (!strcasecmp((const char*)anode->name, "last_modified"))
|
||||||
{
|
{
|
||||||
time_t last_modified_t = get_time_from_str_as_gmt(content);
|
time_t last_modified_t = get_time_from_str_as_gmt(content);
|
||||||
char local_time_str[64];
|
char local_time_str[64];
|
||||||
time_t local_time_t = get_time_as_local(last_modified_t, local_time_str, sizeof(local_time_str));
|
time_t local_time_t = get_time_as_local(last_modified_t, local_time_str,
|
||||||
|
sizeof(local_time_str));
|
||||||
de->last_modified = local_time_t;
|
de->last_modified = local_time_t;
|
||||||
de->ctime.tv_sec = local_time_t;
|
de->ctime.tv_sec = local_time_t;
|
||||||
de->ctime.tv_nsec = 0;
|
de->ctime.tv_nsec = 0;
|
||||||
@@ -1228,7 +1283,9 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
{
|
{
|
||||||
//todo: check why is needed and if memory is freed properly, seems to generate many missed delete operations
|
//todo: check why is needed and if memory is freed properly, seems to generate many missed delete operations
|
||||||
//cloudfs_free_dir_list(de);
|
//cloudfs_free_dir_list(de);
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_list_directory: "KYEL"ignore "KNRM"cloudfs_free_dir_list(%s) command", de->name);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"cloudfs_list_directory: "KYEL"ignore "KNRM"cloudfs_free_dir_list(%s) command",
|
||||||
|
de->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
strncpy(last_subdir, de->name, sizeof(last_subdir));
|
strncpy(last_subdir, de->name, sizeof(last_subdir));
|
||||||
@@ -1240,10 +1297,9 @@ int cloudfs_list_directory(const char *path, dir_entry **dir_list)
|
|||||||
debugf(DBG_LEVEL_EXT, KCYN"new dir_entry %s size=%d %s dir=%d lnk=%d mod=[%s]",
|
debugf(DBG_LEVEL_EXT, KCYN"new dir_entry %s size=%d %s dir=%d lnk=%d mod=[%s]",
|
||||||
de->full_name, de->size, de->content_type, de->isdir, de->islink, time_str);
|
de->full_name, de->size, de->content_type, de->isdir, de->islink, time_str);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "unknown element: %s", onode->name);
|
debugf(DBG_LEVEL_EXT, "unknown element: %s", onode->name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
else if ((!strcmp(path, "") || !strcmp(path, "/")) && *override_storage_url)
|
else if ((!strcmp(path, "") || !strcmp(path, "/")) && *override_storage_url)
|
||||||
@@ -1296,7 +1352,8 @@ int cloudfs_delete_object(const char *path)
|
|||||||
response = send_request("DELETE", encoded, NULL, NULL, NULL, NULL, seg_path);
|
response = send_request("DELETE", encoded, NULL, NULL, NULL, NULL, seg_path);
|
||||||
if (response < 200 || response >= 300)
|
if (response < 200 || response >= 300)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "exit 1: cloudfs_delete_object(%s) response=%d", path, response);
|
debugf(DBG_LEVEL_EXT, "exit 1: cloudfs_delete_object(%s) response=%d", path,
|
||||||
|
response);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1306,7 +1363,8 @@ int cloudfs_delete_object(const char *path)
|
|||||||
int response = send_request("DELETE", encoded, NULL, NULL, NULL, NULL, path);
|
int response = send_request("DELETE", encoded, NULL, NULL, NULL, NULL, path);
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
int ret = (response >= 200 && response < 300);
|
int ret = (response >= 200 && response < 300);
|
||||||
debugf(DBG_LEVEL_EXT, "status: cloudfs_delete_object(%s) response=%d", path, response);
|
debugf(DBG_LEVEL_EXT, "status: cloudfs_delete_object(%s) response=%d", path,
|
||||||
|
response);
|
||||||
if (response == 409)
|
if (response == 409)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "status: cloudfs_delete_object(%s) NOT EMPTY", path);
|
debugf(DBG_LEVEL_EXT, "status: cloudfs_delete_object(%s) NOT EMPTY", path);
|
||||||
@@ -1320,14 +1378,17 @@ int cloudfs_delete_object(const char *path)
|
|||||||
// this operation also causes an HTTP 400 error if X-Object-Meta-FilePath value is larger than 256 chars
|
// this operation also causes an HTTP 400 error if X-Object-Meta-FilePath value is larger than 256 chars
|
||||||
int cloudfs_copy_object(const char* src, const char* dst)
|
int cloudfs_copy_object(const char* src, const char* dst)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_copy_object(%s, %s) lensrc=%d, lendst=%d", src, dst, strlen(src), strlen(dst));
|
debugf(DBG_LEVEL_EXT, "cloudfs_copy_object(%s, %s) lensrc=%d, lendst=%d", src,
|
||||||
|
dst, strlen(src), strlen(dst));
|
||||||
|
|
||||||
char* dst_encoded = curl_escape(dst, 0);
|
char* dst_encoded = curl_escape(dst, 0);
|
||||||
char* src_encoded = curl_escape(src, 0);
|
char* src_encoded = curl_escape(src, 0);
|
||||||
|
|
||||||
//convert encoded string (slashes are encoded as well) to encoded string with slashes
|
//convert encoded string (slashes are encoded as well) to encoded string with slashes
|
||||||
char* slash;
|
char* slash;
|
||||||
while ((slash = strstr(src_encoded, "%2F")) || (slash = strstr(src_encoded, "%2f"))) {
|
while ((slash = strstr(src_encoded, "%2F"))
|
||||||
|
|| (slash = strstr(src_encoded, "%2f")))
|
||||||
|
{
|
||||||
*slash = '/';
|
*slash = '/';
|
||||||
memmove(slash + 1, slash + 3, strlen(slash + 3) + 1);
|
memmove(slash + 1, slash + 3, strlen(slash + 3) + 1);
|
||||||
}
|
}
|
||||||
@@ -1337,18 +1398,20 @@ int cloudfs_copy_object(const char *src, const char *dst)
|
|||||||
add_header(&headers, "Content-Length", "0");
|
add_header(&headers, "Content-Length", "0");
|
||||||
//get source file entry
|
//get source file entry
|
||||||
dir_entry* de_src = check_path_info(src);
|
dir_entry* de_src = check_path_info(src);
|
||||||
if (de_src) {
|
if (de_src)
|
||||||
debugf(DBG_LEVEL_EXT, "status cloudfs_copy_object(%s, %s): src file found", src, dst);
|
debugf(DBG_LEVEL_EXT, "status cloudfs_copy_object(%s, %s): src file found",
|
||||||
}
|
src, dst);
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_NORM, KRED"status cloudfs_copy_object(%s, %s): src file NOT found", src, dst);
|
debugf(DBG_LEVEL_NORM,
|
||||||
}
|
KRED"status cloudfs_copy_object(%s, %s): src file NOT found", src, dst);
|
||||||
//pass src metadata so that PUT will set time attributes of the src file
|
//pass src metadata so that PUT will set time attributes of the src file
|
||||||
int response = send_request("PUT", dst_encoded, NULL, NULL, headers, de_src, dst);
|
int response = send_request("PUT", dst_encoded, NULL, NULL, headers, de_src,
|
||||||
|
dst);
|
||||||
curl_free(dst_encoded);
|
curl_free(dst_encoded);
|
||||||
curl_free(src_encoded);
|
curl_free(src_encoded);
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
debugf(DBG_LEVEL_EXT, "exit: cloudfs_copy_object(%s,%s) response=%d", src, dst, response);
|
debugf(DBG_LEVEL_EXT, "exit: cloudfs_copy_object(%s,%s) response=%d", src, dst,
|
||||||
|
response);
|
||||||
return (response >= 200 && response < 300);
|
return (response >= 200 && response < 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1369,12 +1432,16 @@ int cloudfs_statfs(const char *path, struct statvfs *stat)
|
|||||||
//todo: check why stat head request is always set to /, why not path?
|
//todo: check why stat head request is always set to /, why not path?
|
||||||
int response = send_request("HEAD", "/", NULL, NULL, NULL, NULL, "/");
|
int response = send_request("HEAD", "/", NULL, NULL, NULL, NULL, "/");
|
||||||
*stat = statcache;
|
*stat = statcache;
|
||||||
debugf(DBG_LEVEL_EXT, "exit: cloudfs_statfs (new recent values, was cached since %d seconds)", lapsed);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit: cloudfs_statfs (new recent values, was cached since %d seconds)",
|
||||||
|
lapsed);
|
||||||
last_stat_read_time = now;
|
last_stat_read_time = now;
|
||||||
return (response >= 200 && response < 300);
|
return (response >= 200 && response < 300);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "exit: cloudfs_statfs (old values, cached since %d seconds)", lapsed);
|
{
|
||||||
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit: cloudfs_statfs (old values, cached since %d seconds)", lapsed);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1397,7 +1464,8 @@ int cloudfs_create_directory(const char *path)
|
|||||||
char* encoded = curl_escape(path, 0);
|
char* encoded = curl_escape(path, 0);
|
||||||
int response = send_request("MKDIR", encoded, NULL, NULL, NULL, NULL, path);
|
int response = send_request("MKDIR", encoded, NULL, NULL, NULL, NULL, path);
|
||||||
curl_free(encoded);
|
curl_free(encoded);
|
||||||
debugf(DBG_LEVEL_EXT, "cloudfs_create_directory(%s) response=%d", path, response);
|
debugf(DBG_LEVEL_EXT, "cloudfs_create_directory(%s) response=%d", path,
|
||||||
|
response);
|
||||||
return (response >= 200 && response < 300);
|
return (response >= 200 && response < 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1423,30 +1491,38 @@ void cloudfs_option_curl_verbose(int option)
|
|||||||
option_curl_verbose = option ? true : false;
|
option_curl_verbose = option ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct
|
||||||
|
{
|
||||||
char client_id [MAX_HEADER_SIZE];
|
char client_id [MAX_HEADER_SIZE];
|
||||||
char client_secret[MAX_HEADER_SIZE];
|
char client_secret[MAX_HEADER_SIZE];
|
||||||
char refresh_token[MAX_HEADER_SIZE];
|
char refresh_token[MAX_HEADER_SIZE];
|
||||||
} reconnect_args;
|
} reconnect_args;
|
||||||
|
|
||||||
void cloudfs_set_credentials(char *client_id, char *client_secret, char *refresh_token)
|
void cloudfs_set_credentials(char* client_id, char* client_secret,
|
||||||
|
char* refresh_token)
|
||||||
{
|
{
|
||||||
strncpy(reconnect_args.client_id , client_id , sizeof(reconnect_args.client_id ));
|
strncpy(reconnect_args.client_id , client_id ,
|
||||||
strncpy(reconnect_args.client_secret, client_secret, sizeof(reconnect_args.client_secret));
|
sizeof(reconnect_args.client_id ));
|
||||||
strncpy(reconnect_args.refresh_token, refresh_token, sizeof(reconnect_args.refresh_token));
|
strncpy(reconnect_args.client_secret, client_secret,
|
||||||
|
sizeof(reconnect_args.client_secret));
|
||||||
|
strncpy(reconnect_args.refresh_token, refresh_token,
|
||||||
|
sizeof(reconnect_args.refresh_token));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct htmlString {
|
struct htmlString
|
||||||
|
{
|
||||||
char* text;
|
char* text;
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t writefunc_string(void *contents, size_t size, size_t nmemb, void *data)
|
static size_t writefunc_string(void* contents, size_t size, size_t nmemb,
|
||||||
|
void* data)
|
||||||
{
|
{
|
||||||
struct htmlString* mem = (struct htmlString*) data;
|
struct htmlString* mem = (struct htmlString*) data;
|
||||||
size_t realsize = size * nmemb;
|
size_t realsize = size * nmemb;
|
||||||
mem->text = realloc(mem->text, mem->size + realsize + 1);
|
mem->text = realloc(mem->text, mem->size + realsize + 1);
|
||||||
if (mem->text == NULL) { /* out of memory! */
|
if (mem->text == NULL) /* out of memory! */
|
||||||
|
{
|
||||||
perror(__FILE__);
|
perror(__FILE__);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -1464,9 +1540,11 @@ char* htmlStringGet(CURL *curl)
|
|||||||
chunk.text[0] = '\0';//added to avoid valgrind unitialised warning
|
chunk.text[0] = '\0';//added to avoid valgrind unitialised warning
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
curl_easy_perform(curl);
|
curl_easy_perform(curl);
|
||||||
} while (chunk.size == 0);
|
}
|
||||||
|
while (chunk.size == 0);
|
||||||
|
|
||||||
chunk.text[chunk.size] = '\0';
|
chunk.text[chunk.size] = '\0';
|
||||||
return chunk.text;
|
return chunk.text;
|
||||||
@@ -1529,7 +1607,8 @@ int cloudfs_connect()
|
|||||||
struct json_object* json_obj;
|
struct json_object* json_obj;
|
||||||
|
|
||||||
pthread_mutex_lock(&pool_mut);
|
pthread_mutex_lock(&pool_mut);
|
||||||
debugf(DBG_LEVEL_NORM, "Authenticating... (client_id = '%s')", HUBIC_CLIENT_ID);
|
debugf(DBG_LEVEL_NORM, "Authenticating... (client_id = '%s')",
|
||||||
|
HUBIC_CLIENT_ID);
|
||||||
storage_token[0] = storage_url[0] = '\0';
|
storage_token[0] = storage_url[0] = '\0';
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
|
|
||||||
@@ -1551,7 +1630,8 @@ int cloudfs_connect()
|
|||||||
/* Step 2 : get request code - Not needed anymore with refresh_token */
|
/* Step 2 : get request code - Not needed anymore with refresh_token */
|
||||||
/* Step 3 : get access token */
|
/* Step 3 : get access token */
|
||||||
|
|
||||||
sprintf(payload, "refresh_token=%s&grant_type=refresh_token", HUBIC_REFRESH_TOKEN);
|
sprintf(payload, "refresh_token=%s&grant_type=refresh_token",
|
||||||
|
HUBIC_REFRESH_TOKEN);
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, HUBIC_TOKEN_URL);
|
curl_easy_setopt(curl, CURLOPT_URL, HUBIC_TOKEN_URL);
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
|
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
|
||||||
@@ -1616,5 +1696,6 @@ int cloudfs_connect()
|
|||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
pthread_mutex_unlock(&pool_mut);
|
pthread_mutex_unlock(&pool_mut);
|
||||||
return (response >= 200 && response < 300 && storage_token[0] && storage_url[0]);
|
return (response >= 200 && response < 300 && storage_token[0]
|
||||||
|
&& storage_url[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -16,12 +16,14 @@
|
|||||||
typedef struct curl_slist curl_slist;
|
typedef struct curl_slist curl_slist;
|
||||||
|
|
||||||
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 5
|
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 5
|
||||||
struct curl_progress {
|
struct curl_progress
|
||||||
|
{
|
||||||
double lastruntime;
|
double lastruntime;
|
||||||
CURL* curl;
|
CURL* curl;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct options {
|
typedef struct options
|
||||||
|
{
|
||||||
char cache_timeout[OPTION_SIZE];
|
char cache_timeout[OPTION_SIZE];
|
||||||
char verify_ssl[OPTION_SIZE];
|
char verify_ssl[OPTION_SIZE];
|
||||||
char segment_size[OPTION_SIZE];
|
char segment_size[OPTION_SIZE];
|
||||||
@@ -34,7 +36,8 @@ typedef struct options {
|
|||||||
char refresh_token[OPTION_SIZE];
|
char refresh_token[OPTION_SIZE];
|
||||||
} FuseOptions;
|
} FuseOptions;
|
||||||
|
|
||||||
typedef struct extra_options {
|
typedef struct extra_options
|
||||||
|
{
|
||||||
char get_extended_metadata[OPTION_SIZE];
|
char get_extended_metadata[OPTION_SIZE];
|
||||||
char curl_verbose[OPTION_SIZE];
|
char curl_verbose[OPTION_SIZE];
|
||||||
char cache_statfs_timeout[OPTION_SIZE];
|
char cache_statfs_timeout[OPTION_SIZE];
|
||||||
@@ -46,7 +49,8 @@ typedef struct extra_options {
|
|||||||
|
|
||||||
void cloudfs_init(void);
|
void cloudfs_init(void);
|
||||||
void cloudfs_free(void);
|
void cloudfs_free(void);
|
||||||
void cloudfs_set_credentials(char *client_id, char *client_secret, char *refresh_token);
|
void cloudfs_set_credentials(char* client_id, char* client_secret,
|
||||||
|
char* refresh_token);
|
||||||
int cloudfs_connect(void);
|
int cloudfs_connect(void);
|
||||||
|
|
||||||
struct segment_info
|
struct segment_info
|
||||||
|
|||||||
+223
-132
@@ -56,21 +56,24 @@ static int cfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
//get file. if not in cache will be downloaded.
|
//get file. if not in cache will be downloaded.
|
||||||
dir_entry* de = path_info(path);
|
dir_entry* de = path_info(path);
|
||||||
if (!de) {
|
if (!de)
|
||||||
|
{
|
||||||
debug_list_cache_content();
|
debug_list_cache_content();
|
||||||
debugf(DBG_LEVEL_NORM, KBLU"exit 1: cfs_getattr(%s) "KYEL"not-in-cache/cloud", path);
|
debugf(DBG_LEVEL_NORM, KBLU"exit 1: cfs_getattr(%s) "KYEL"not-in-cache/cloud",
|
||||||
|
path);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
//lazzy download of file metadata, only when really needed
|
//lazzy download of file metadata, only when really needed
|
||||||
if (option_get_extended_metadata && !de->metadata_downloaded) {
|
if (option_get_extended_metadata && !de->metadata_downloaded)
|
||||||
get_file_metadata(de);
|
get_file_metadata(de);
|
||||||
}
|
if (option_enable_chown)
|
||||||
if (option_enable_chown) {
|
{
|
||||||
stbuf->st_uid = de->uid;
|
stbuf->st_uid = de->uid;
|
||||||
stbuf->st_gid = de->gid;
|
stbuf->st_gid = de->gid;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
stbuf->st_uid = geteuid();
|
stbuf->st_uid = geteuid();
|
||||||
stbuf->st_gid = getegid();
|
stbuf->st_gid = getegid();
|
||||||
}
|
}
|
||||||
@@ -91,21 +94,25 @@ static int cfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
|
|
||||||
int default_mode_dir, default_mode_file;
|
int default_mode_dir, default_mode_file;
|
||||||
|
|
||||||
if (option_enable_chmod) {
|
if (option_enable_chmod)
|
||||||
|
{
|
||||||
default_mode_dir = de->chmod;
|
default_mode_dir = de->chmod;
|
||||||
default_mode_file = de->chmod;
|
default_mode_file = de->chmod;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
default_mode_dir = 0755;
|
default_mode_dir = 0755;
|
||||||
default_mode_file = 0666;
|
default_mode_file = 0666;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (de->isdir) {
|
if (de->isdir)
|
||||||
|
{
|
||||||
stbuf->st_size = 0;
|
stbuf->st_size = 0;
|
||||||
stbuf->st_mode = S_IFDIR | default_mode_dir;
|
stbuf->st_mode = S_IFDIR | default_mode_dir;
|
||||||
stbuf->st_nlink = 2;
|
stbuf->st_nlink = 2;
|
||||||
}
|
}
|
||||||
else if (de->islink) {
|
else if (de->islink)
|
||||||
|
{
|
||||||
stbuf->st_size = 1;
|
stbuf->st_size = 1;
|
||||||
stbuf->st_mode = S_IFLNK | default_mode_dir;
|
stbuf->st_mode = S_IFLNK | default_mode_dir;
|
||||||
stbuf->st_nlink = 1;
|
stbuf->st_nlink = 1;
|
||||||
@@ -113,7 +120,8 @@ static int cfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
/* calc. blocks as if 4K blocksize filesystem; stat uses units of 512B */
|
/* calc. blocks as if 4K blocksize filesystem; stat uses units of 512B */
|
||||||
stbuf->st_blocks = ((4095 + de->size) / 4096) * 8;
|
stbuf->st_blocks = ((4095 + de->size) / 4096) * 8;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
stbuf->st_size = de->size;
|
stbuf->st_size = de->size;
|
||||||
/* calc. blocks as if 4K blocksize filesystem; stat uses units of 512B */
|
/* calc. blocks as if 4K blocksize filesystem; stat uses units of 512B */
|
||||||
stbuf->st_blocks = ((4095 + de->size) / 4096) * 8;
|
stbuf->st_blocks = ((4095 + de->size) / 4096) * 8;
|
||||||
@@ -124,7 +132,8 @@ static int cfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *info)
|
static int cfs_fgetattr(const char* path, struct stat* stbuf,
|
||||||
|
struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_fgetattr(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_fgetattr(%s)", path);
|
||||||
openfile* of = (openfile*)(uintptr_t)info->fh;
|
openfile* of = (openfile*)(uintptr_t)info->fh;
|
||||||
@@ -132,18 +141,18 @@ static int cfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_i
|
|||||||
{
|
{
|
||||||
//get file. if not in cache will be downloaded.
|
//get file. if not in cache will be downloaded.
|
||||||
dir_entry* de = path_info(path);
|
dir_entry* de = path_info(path);
|
||||||
if (!de) {
|
if (!de)
|
||||||
|
{
|
||||||
debug_list_cache_content();
|
debug_list_cache_content();
|
||||||
debugf(DBG_LEVEL_NORM, KBLU"exit 1: cfs_fgetattr(%s) "KYEL"not-in-cache/cloud", path);
|
debugf(DBG_LEVEL_NORM, KBLU"exit 1: cfs_fgetattr(%s) "KYEL"not-in-cache/cloud",
|
||||||
|
path);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
int default_mode_file;
|
int default_mode_file;
|
||||||
if (option_enable_chmod) {
|
if (option_enable_chmod)
|
||||||
default_mode_file = de->chmod;
|
default_mode_file = de->chmod;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
default_mode_file = 0666;
|
default_mode_file = 0666;
|
||||||
}
|
|
||||||
|
|
||||||
stbuf->st_size = cloudfs_file_size(of->fd);
|
stbuf->st_size = cloudfs_file_size(of->fd);
|
||||||
stbuf->st_mode = S_IFREG | default_mode_file;
|
stbuf->st_mode = S_IFREG | default_mode_file;
|
||||||
@@ -155,11 +164,13 @@ static int cfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_i
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_readdir(const char *path, void *buf, fuse_fill_dir_t filldir, off_t offset, struct fuse_file_info *info)
|
static int cfs_readdir(const char* path, void* buf, fuse_fill_dir_t filldir,
|
||||||
|
off_t offset, struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_readdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_readdir(%s)", path);
|
||||||
dir_entry* de;
|
dir_entry* de;
|
||||||
if (!caching_list_directory(path, &de)) {
|
if (!caching_list_directory(path, &de))
|
||||||
|
{
|
||||||
debug_list_cache_content();
|
debug_list_cache_content();
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_readdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_readdir(%s)", path);
|
||||||
return -ENOLINK;
|
return -ENOLINK;
|
||||||
@@ -177,37 +188,48 @@ static int cfs_mkdir(const char *path, mode_t mode)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_mkdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_mkdir(%s)", path);
|
||||||
int response = cloudfs_create_directory(path);
|
int response = cloudfs_create_directory(path);
|
||||||
if (response){
|
if (response)
|
||||||
|
{
|
||||||
update_dir_cache(path, 0, 1, 0);
|
update_dir_cache(path, 0, 1, 0);
|
||||||
debug_list_cache_content();
|
debug_list_cache_content();
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_mkdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_mkdir(%s)", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 1: cfs_mkdir(%s) response=%d", path, response);
|
debugf(DBG_LEVEL_NORM, KRED "exit 1: cfs_mkdir(%s) response=%d", path,
|
||||||
|
response);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_create(const char *path, mode_t mode, struct fuse_file_info *info)
|
static int cfs_create(const char* path, mode_t mode,
|
||||||
|
struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_create(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_create(%s)", path);
|
||||||
FILE* temp_file;
|
FILE* temp_file;
|
||||||
int errsv;
|
int errsv;
|
||||||
char file_path_safe[NAME_MAX] = "";
|
char file_path_safe[NAME_MAX] = "";
|
||||||
|
|
||||||
if (*temp_dir) {
|
if (*temp_dir)
|
||||||
|
{
|
||||||
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
||||||
temp_file = fopen(file_path_safe, "w+b");
|
temp_file = fopen(file_path_safe, "w+b");
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (temp_file == NULL){
|
if (temp_file == NULL)
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_create cannot open temp file %s.error %s\n", file_path_safe, strerror(errsv));
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, KRED
|
||||||
|
"exit 0: cfs_create cannot open temp file %s.error %s\n", file_path_safe,
|
||||||
|
strerror(errsv));
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
temp_file = tmpfile();
|
temp_file = tmpfile();
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (temp_file == NULL){
|
if (temp_file == NULL)
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 1: cfs_create cannot open tmp file for path %s.error %s\n", path, strerror(errsv));
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, KRED
|
||||||
|
"exit 1: cfs_create cannot open tmp file for path %s.error %s\n", path,
|
||||||
|
strerror(errsv));
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +241,8 @@ static int cfs_create(const char *path, mode_t mode, struct fuse_file_info *info
|
|||||||
update_dir_cache(path, 0, 0, 0);
|
update_dir_cache(path, 0, 0, 0);
|
||||||
info->direct_io = 1;
|
info->direct_io = 1;
|
||||||
dir_entry* de = check_path_info(path);
|
dir_entry* de = check_path_info(path);
|
||||||
if (de) {
|
if (de)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KCYN"cfs_create(%s): found in cache", path);
|
debugf(DBG_LEVEL_EXT, KCYN"cfs_create(%s): found in cache", path);
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_REALTIME, &now);
|
clock_gettime(CLOCK_REALTIME, &now);
|
||||||
@@ -244,10 +267,10 @@ static int cfs_create(const char *path, mode_t mode, struct fuse_file_info *info
|
|||||||
de->uid = geteuid();
|
de->uid = geteuid();
|
||||||
de->gid = getegid();
|
de->gid = getegid();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, KBLU "cfs_create(%s) "KYEL"dir-entry not found", path);
|
debugf(DBG_LEVEL_EXT, KBLU "cfs_create(%s) "KYEL"dir-entry not found", path);
|
||||||
}
|
debugf(DBG_LEVEL_NORM, KBLU "exit 2: cfs_create(%s)=(%s) result=%d:%s", path,
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 2: cfs_create(%s)=(%s) result=%d:%s", path, file_path_safe, errsv, strerror(errsv));
|
file_path_safe, errsv, strerror(errsv));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,23 +283,29 @@ static int cfs_open(const char *path, struct fuse_file_info *info)
|
|||||||
int errsv;
|
int errsv;
|
||||||
dir_entry* de = path_info(path);
|
dir_entry* de = path_info(path);
|
||||||
|
|
||||||
if (*temp_dir) {
|
if (*temp_dir)
|
||||||
|
{
|
||||||
char file_path_safe[NAME_MAX];
|
char file_path_safe[NAME_MAX];
|
||||||
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
||||||
|
|
||||||
debugf(DBG_LEVEL_EXT, "cfs_open: try open (%s)", file_path_safe);
|
debugf(DBG_LEVEL_EXT, "cfs_open: try open (%s)", file_path_safe);
|
||||||
if (access(file_path_safe, F_OK) != -1){
|
if (access(file_path_safe, F_OK) != -1)
|
||||||
|
{
|
||||||
// file exists
|
// file exists
|
||||||
temp_file = fopen(file_path_safe, "r");
|
temp_file = fopen(file_path_safe, "r");
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (temp_file == NULL) {
|
if (temp_file == NULL)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_open can't open temp_file=[%s] err=%d:%s", file_path_safe, errsv, strerror(errsv));
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"exit 0: cfs_open can't open temp_file=[%s] err=%d:%s", file_path_safe,
|
||||||
|
errsv, strerror(errsv));
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "cfs_open: file exists");
|
debugf(DBG_LEVEL_EXT, "cfs_open: file exists");
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
debugf(DBG_LEVEL_EXT, "cfs_open: file not in cache, err=%s", strerror(errsv));
|
debugf(DBG_LEVEL_EXT, "cfs_open: file not in cache, err=%s", strerror(errsv));
|
||||||
//FIXME: commented out as this condition will not be meet in some odd cases and program will crash
|
//FIXME: commented out as this condition will not be meet in some odd cases and program will crash
|
||||||
@@ -303,14 +332,19 @@ static int cfs_open(const char *path, struct fuse_file_info *info)
|
|||||||
// TODO: just to prevent this craziness for now
|
// TODO: just to prevent this craziness for now
|
||||||
temp_file = fopen(file_path_safe, "w+b");
|
temp_file = fopen(file_path_safe, "w+b");
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (temp_file == NULL) {
|
if (temp_file == NULL)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_open cannot open temp_file=[%s] err=%d:%s", file_path_safe, errsv, strerror(errsv));
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"exit 1: cfs_open cannot open temp_file=[%s] err=%d:%s", file_path_safe,
|
||||||
|
errsv, strerror(errsv));
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cloudfs_object_write_fp(path, temp_file)) {
|
if (!cloudfs_object_write_fp(path, temp_file))
|
||||||
|
{
|
||||||
fclose(temp_file);
|
fclose(temp_file);
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 2: cfs_open(%s) cannot download/write", path);
|
debugf(DBG_LEVEL_NORM, KRED "exit 2: cfs_open(%s) cannot download/write",
|
||||||
|
path);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,13 +352,17 @@ static int cfs_open(const char *path, struct fuse_file_info *info)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
temp_file = tmpfile();
|
temp_file = tmpfile();
|
||||||
if (temp_file == NULL) {
|
if (temp_file == NULL)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 3: cfs_open cannot create temp_file err=%s", strerror(errno));
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, KRED"exit 3: cfs_open cannot create temp_file err=%s",
|
||||||
|
strerror(errno));
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(info->flags & O_TRUNC)) {
|
if (!(info->flags & O_TRUNC))
|
||||||
if (!cloudfs_object_write_fp(path, temp_file) && !(info->flags & O_CREAT)) {
|
{
|
||||||
|
if (!cloudfs_object_write_fp(path, temp_file) && !(info->flags & O_CREAT))
|
||||||
|
{
|
||||||
fclose(temp_file);
|
fclose(temp_file);
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 4: cfs_open(%s) cannot download/write", path);
|
debugf(DBG_LEVEL_NORM, KRED"exit 4: cfs_open(%s) cannot download/write", path);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@@ -353,13 +391,16 @@ static int cfs_open(const char *path, struct fuse_file_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *info)
|
static int cfs_read(const char* path, char* buf, size_t size, off_t offset,
|
||||||
|
struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXTALL, KBLU "cfs_read(%s) buffsize=%lu offset=%lu", path, size, offset);
|
debugf(DBG_LEVEL_EXTALL, KBLU "cfs_read(%s) buffsize=%lu offset=%lu", path,
|
||||||
|
size, offset);
|
||||||
file_buffer_size = size;
|
file_buffer_size = size;
|
||||||
debug_print_descriptor(info);
|
debug_print_descriptor(info);
|
||||||
int result = pread(((openfile*)(uintptr_t)info->fh)->fd, buf, size, offset);
|
int result = pread(((openfile*)(uintptr_t)info->fh)->fd, buf, size, offset);
|
||||||
debugf(DBG_LEVEL_EXTALL, KBLU "exit: cfs_read(%s) result=%s", path, strerror(errno));
|
debugf(DBG_LEVEL_EXTALL, KBLU "exit: cfs_read(%s) result=%s", path,
|
||||||
|
strerror(errno));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,9 +413,11 @@ static int cfs_flush(const char *path, struct fuse_file_info *info)
|
|||||||
openfile* of = (openfile*)(uintptr_t)info->fh;
|
openfile* of = (openfile*)(uintptr_t)info->fh;
|
||||||
int errsv = 0;
|
int errsv = 0;
|
||||||
|
|
||||||
if (of) {
|
if (of)
|
||||||
|
{
|
||||||
update_dir_cache(path, cloudfs_file_size(of->fd), 0, 0);
|
update_dir_cache(path, cloudfs_file_size(of->fd), 0, 0);
|
||||||
if (of->flags & O_RDWR || of->flags & O_WRONLY) {
|
if (of->flags & O_RDWR || of->flags & O_WRONLY)
|
||||||
|
{
|
||||||
FILE* fp = fdopen(dup(of->fd), "r");
|
FILE* fp = fdopen(dup(of->fd), "r");
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (fp != NULL)
|
if (fp != NULL)
|
||||||
@@ -384,34 +427,43 @@ static int cfs_flush(const char *path, struct fuse_file_info *info)
|
|||||||
char md5_file_hash_str[MD5_DIGEST_LENGTH + 1] = "\0";
|
char md5_file_hash_str[MD5_DIGEST_LENGTH + 1] = "\0";
|
||||||
file_md5(fp, md5_file_hash_str);
|
file_md5(fp, md5_file_hash_str);
|
||||||
dir_entry* de = check_path_info(path);
|
dir_entry* de = check_path_info(path);
|
||||||
if (de && de->md5sum != NULL && (!strcasecmp(md5_file_hash_str, de->md5sum))) {
|
if (de && de->md5sum != NULL && (!strcasecmp(md5_file_hash_str, de->md5sum)))
|
||||||
|
{
|
||||||
//file content is identical, no need to upload entire file, just update metadata
|
//file content is identical, no need to upload entire file, just update metadata
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_flush(%s): skip full upload as content did not change", path);
|
debugf(DBG_LEVEL_NORM, KBLU
|
||||||
|
"cfs_flush(%s): skip full upload as content did not change", path);
|
||||||
cloudfs_update_meta(de);
|
cloudfs_update_meta(de);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_flush(%s): perform full upload as content changed (or no file found in cache)", path);
|
debugf(DBG_LEVEL_NORM, KBLU
|
||||||
if (!cloudfs_object_read_fp(path, fp)) {
|
"cfs_flush(%s): perform full upload as content changed (or no file found in cache)",
|
||||||
|
path);
|
||||||
|
if (!cloudfs_object_read_fp(path, fp))
|
||||||
|
{
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_flush(%s) result=%d:%s", path, errsv, strerror(errno));
|
debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_flush(%s) result=%d:%s", path, errsv,
|
||||||
|
strerror(errno));
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, KRED "status: cfs_flush, err=%d:%s", errsv, strerror(errno));
|
debugf(DBG_LEVEL_EXT, KRED "status: cfs_flush, err=%d:%s", errsv,
|
||||||
|
strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_flush(%s) result=%d:%s", path, errsv,
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_flush(%s) result=%d:%s", path, errsv, strerror(errno));
|
strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_release(const char *path, struct fuse_file_info *info) {
|
static int cfs_release(const char* path, struct fuse_file_info* info)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_release(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_release(%s)", path);
|
||||||
close(((openfile*)(uintptr_t)info->fh)->fd);
|
close(((openfile*)(uintptr_t)info->fh)->fd);
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit: cfs_release(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit: cfs_release(%s)", path);
|
||||||
@@ -422,11 +474,13 @@ static int cfs_rmdir(const char *path)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_rmdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_rmdir(%s)", path);
|
||||||
int success = cloudfs_delete_object(path);
|
int success = cloudfs_delete_object(path);
|
||||||
if (success == -1) {
|
if (success == -1)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_rmdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_rmdir(%s)", path);
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
}
|
}
|
||||||
if (success){
|
if (success)
|
||||||
|
{
|
||||||
dir_decache(path);
|
dir_decache(path);
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_rmdir(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_rmdir(%s)", path);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -435,7 +489,8 @@ static int cfs_rmdir(const char *path)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_ftruncate(const char *path, off_t size, struct fuse_file_info *info)
|
static int cfs_ftruncate(const char* path, off_t size,
|
||||||
|
struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_ftruncate(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_ftruncate(%s)", path);
|
||||||
file_buffer_size = size;
|
file_buffer_size = size;
|
||||||
@@ -448,20 +503,22 @@ static int cfs_ftruncate(const char *path, off_t size, struct fuse_file_info *in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfs_write(const char *path, const char *buf, size_t length, off_t offset, struct fuse_file_info *info)
|
static int cfs_write(const char* path, const char* buf, size_t length,
|
||||||
|
off_t offset, struct fuse_file_info* info)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXTALL, KBLU "cfs_write(%s) bufflength=%lu offset=%lu", path, length, offset);
|
debugf(DBG_LEVEL_EXTALL, KBLU "cfs_write(%s) bufflength=%lu offset=%lu", path,
|
||||||
|
length, offset);
|
||||||
// FIXME: Potential inconsistent cache update if pwrite fails?
|
// FIXME: Potential inconsistent cache update if pwrite fails?
|
||||||
update_dir_cache(path, offset + length, 0, 0);
|
update_dir_cache(path, offset + length, 0, 0);
|
||||||
//int result = pwrite(info->fh, buf, length, offset);
|
//int result = pwrite(info->fh, buf, length, offset);
|
||||||
int result = pwrite(((openfile*)(uintptr_t)info->fh)->fd, buf, length, offset);
|
int result = pwrite(((openfile*)(uintptr_t)info->fh)->fd, buf, length, offset);
|
||||||
int errsv = errno;
|
int errsv = errno;
|
||||||
if (errsv == 0) {
|
if (errsv == 0)
|
||||||
debugf(DBG_LEVEL_EXTALL, KBLU "exit 0: cfs_write(%s) result=%d:%s", path, errsv, strerror(errsv));
|
debugf(DBG_LEVEL_EXTALL, KBLU "exit 0: cfs_write(%s) result=%d:%s", path,
|
||||||
}
|
errsv, strerror(errsv));
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXTALL, KBLU "exit 1: cfs_write(%s) "KRED"result=%d:%s", path, errsv, strerror(errsv));
|
debugf(DBG_LEVEL_EXTALL, KBLU "exit 1: cfs_write(%s) "KRED"result=%d:%s", path,
|
||||||
}
|
errsv, strerror(errsv));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +526,8 @@ static int cfs_unlink(const char *path)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_unlink(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_unlink(%s)", path);
|
||||||
int success = cloudfs_delete_object(path);
|
int success = cloudfs_delete_object(path);
|
||||||
if (success == -1) {
|
if (success == -1)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_unlink(%s)", path);
|
debugf(DBG_LEVEL_NORM, KRED "exit 0: cfs_unlink(%s)", path);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
@@ -501,11 +559,13 @@ static int cfs_truncate(const char *path, off_t size)
|
|||||||
static int cfs_statfs(const char* path, struct statvfs* stat)
|
static int cfs_statfs(const char* path, struct statvfs* stat)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_statfs(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_statfs(%s)", path);
|
||||||
if (cloudfs_statfs(path, stat)){
|
if (cloudfs_statfs(path, stat))
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_statfs(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit 0: cfs_statfs(%s)", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_statfs(%s) not-found", path);
|
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_statfs(%s) not-found", path);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@@ -515,9 +575,12 @@ static int cfs_chown(const char *path, uid_t uid, gid_t gid)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "cfs_chown(%s,%d,%d)", path, uid, gid);
|
debugf(DBG_LEVEL_NORM, KBLU "cfs_chown(%s,%d,%d)", path, uid, gid);
|
||||||
dir_entry* de = check_path_info(path);
|
dir_entry* de = check_path_info(path);
|
||||||
if (de) {
|
if (de)
|
||||||
if (de->uid != uid || de->gid != gid) {
|
{
|
||||||
debugf(DBG_LEVEL_NORM, "cfs_chown(%s): change from uid:gid %d:%d to %d:%d", path, de->uid, de->gid, uid, gid);
|
if (de->uid != uid || de->gid != gid)
|
||||||
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, "cfs_chown(%s): change from uid:gid %d:%d to %d:%d",
|
||||||
|
path, de->uid, de->gid, uid, gid);
|
||||||
de->uid = uid;
|
de->uid = uid;
|
||||||
de->gid = gid;
|
de->gid = gid;
|
||||||
//issue a PUT request to update metadata (quick request just to update headers)
|
//issue a PUT request to update metadata (quick request just to update headers)
|
||||||
@@ -531,9 +594,12 @@ static int cfs_chmod(const char *path, mode_t mode)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU"cfs_chmod(%s,%d)", path, mode);
|
debugf(DBG_LEVEL_NORM, KBLU"cfs_chmod(%s,%d)", path, mode);
|
||||||
dir_entry* de = check_path_info(path);
|
dir_entry* de = check_path_info(path);
|
||||||
if (de) {
|
if (de)
|
||||||
if (de->chmod != mode) {
|
{
|
||||||
debugf(DBG_LEVEL_NORM, "cfs_chmod(%s): change mode from %d to %d", path, de->chmod, mode);
|
if (de->chmod != mode)
|
||||||
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, "cfs_chmod(%s): change mode from %d to %d", path,
|
||||||
|
de->chmod, mode);
|
||||||
de->chmod = mode;
|
de->chmod = mode;
|
||||||
//todo: issue a PUT request to update metadata (empty request just to update headers?)
|
//todo: issue a PUT request to update metadata (empty request just to update headers?)
|
||||||
int response = cloudfs_update_meta(de);
|
int response = cloudfs_update_meta(de);
|
||||||
@@ -546,25 +612,30 @@ static int cfs_rename(const char *src, const char *dst)
|
|||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU"cfs_rename(%s, %s)", src, dst);
|
debugf(DBG_LEVEL_NORM, KBLU"cfs_rename(%s, %s)", src, dst);
|
||||||
dir_entry* src_de = path_info(src);
|
dir_entry* src_de = path_info(src);
|
||||||
if (!src_de) {
|
if (!src_de)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_rename(%s,%s) not-found", src, dst);
|
debugf(DBG_LEVEL_NORM, KRED"exit 0: cfs_rename(%s,%s) not-found", src, dst);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
if (src_de->isdir) {
|
if (src_de->isdir)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_rename(%s,%s) cannot rename dirs!", src, dst);
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_rename(%s,%s) cannot rename dirs!",
|
||||||
|
src, dst);
|
||||||
return -EISDIR;
|
return -EISDIR;
|
||||||
}
|
}
|
||||||
if (cloudfs_copy_object(src, dst)) {
|
if (cloudfs_copy_object(src, dst))
|
||||||
|
{
|
||||||
/* FIXME this isn't quite right as doesn't preserve last modified */
|
/* FIXME this isn't quite right as doesn't preserve last modified */
|
||||||
//fix done in cloudfs_copy_object()
|
//fix done in cloudfs_copy_object()
|
||||||
update_dir_cache(dst, src_de->size, 0, 0);
|
update_dir_cache(dst, src_de->size, 0, 0);
|
||||||
int result = cfs_unlink(src);
|
int result = cfs_unlink(src);
|
||||||
|
|
||||||
dir_entry* dst_de = path_info(dst);
|
dir_entry* dst_de = path_info(dst);
|
||||||
if (!dst_de) {
|
if (!dst_de)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"cfs_rename(%s,%s) dest-not-found-in-cache", src, dst);
|
debugf(DBG_LEVEL_NORM, KRED"cfs_rename(%s,%s) dest-not-found-in-cache", src,
|
||||||
}
|
dst);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KBLU"cfs_rename(%s,%s) upload ok", src, dst);
|
debugf(DBG_LEVEL_NORM, KBLU"cfs_rename(%s,%s) upload ok", src, dst);
|
||||||
//copy attributes, shortcut, rather than forcing a download from cloud
|
//copy attributes, shortcut, rather than forcing a download from cloud
|
||||||
copy_dir_entry(src_de, dst_de);
|
copy_dir_entry(src_de, dst_de);
|
||||||
@@ -597,12 +668,14 @@ static int cfs_readlink(const char* path, char* buf, size_t size)
|
|||||||
FILE* temp_file = tmpfile();
|
FILE* temp_file = tmpfile();
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!cloudfs_object_write_fp(path, temp_file)) {
|
if (!cloudfs_object_write_fp(path, temp_file))
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_readlink(%s) not found", path);
|
debugf(DBG_LEVEL_NORM, KRED"exit 1: cfs_readlink(%s) not found", path);
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pread(fileno(temp_file), buf, size, 0)) {
|
if (!pread(fileno(temp_file), buf, size, 0))
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"exit 2: cfs_readlink(%s) not found", path);
|
debugf(DBG_LEVEL_NORM, KRED"exit 2: cfs_readlink(%s) not found", path);
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
}
|
}
|
||||||
@@ -631,11 +704,16 @@ static int cfs_utimens(const char *path, const struct timespec times[2])
|
|||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_REALTIME, &now);
|
clock_gettime(CLOCK_REALTIME, &now);
|
||||||
|
|
||||||
if (path_de->atime.tv_sec != times[0].tv_sec || path_de->atime.tv_nsec != times[0].tv_nsec ||
|
if (path_de->atime.tv_sec != times[0].tv_sec
|
||||||
path_de->mtime.tv_sec != times[1].tv_sec || path_de->mtime.tv_nsec != times[1].tv_nsec)
|
|| path_de->atime.tv_nsec != times[0].tv_nsec ||
|
||||||
|
path_de->mtime.tv_sec != times[1].tv_sec
|
||||||
|
|| path_de->mtime.tv_nsec != times[1].tv_nsec)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KCYN "cfs_utimens: change for %s, prev: atime=%li.%li mtime=%li.%li, new: atime=%li.%li mtime=%li.%li", path,
|
debugf(DBG_LEVEL_EXT, KCYN
|
||||||
path_de->atime.tv_sec, path_de->atime.tv_nsec, path_de->mtime.tv_sec, path_de->mtime.tv_nsec,
|
"cfs_utimens: change for %s, prev: atime=%li.%li mtime=%li.%li, new: atime=%li.%li mtime=%li.%li",
|
||||||
|
path,
|
||||||
|
path_de->atime.tv_sec, path_de->atime.tv_nsec, path_de->mtime.tv_sec,
|
||||||
|
path_de->mtime.tv_nsec,
|
||||||
times[0].tv_sec, times[0].tv_nsec, times[1].tv_sec, times[1].tv_nsec);
|
times[0].tv_sec, times[0].tv_nsec, times[1].tv_sec, times[1].tv_nsec);
|
||||||
char time_str[TIME_CHARS] = "";
|
char time_str[TIME_CHARS] = "";
|
||||||
get_timespec_as_str(×[1], time_str, sizeof(time_str));
|
get_timespec_as_str(×[1], time_str, sizeof(time_str));
|
||||||
@@ -651,15 +729,15 @@ static int cfs_utimens(const char *path, const struct timespec times[2])
|
|||||||
//worth implementing a meta cache functionality to avoid multiple uploads on meta changes
|
//worth implementing a meta cache functionality to avoid multiple uploads on meta changes
|
||||||
//when changing timestamps on very large files, touch command will trigger 2 x long and useless file uploads on cfs_flush()
|
//when changing timestamps on very large files, touch command will trigger 2 x long and useless file uploads on cfs_flush()
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, KCYN"cfs_utimens: a/m/time not changed");
|
debugf(DBG_LEVEL_EXT, KCYN"cfs_utimens: a/m/time not changed");
|
||||||
}
|
|
||||||
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_utimens(%s)", path);
|
debugf(DBG_LEVEL_NORM, KBLU "exit 1: cfs_utimens(%s)", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int cfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags)
|
int cfs_setxattr(const char* path, const char* name, const char* value,
|
||||||
|
size_t size, int flags)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -679,7 +757,8 @@ int cfs_listxattr(const char *path, char *list, size_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuseOptions options = {
|
FuseOptions options =
|
||||||
|
{
|
||||||
.cache_timeout = "600",
|
.cache_timeout = "600",
|
||||||
.verify_ssl = "true",
|
.verify_ssl = "true",
|
||||||
.segment_size = "1073741824",
|
.segment_size = "1073741824",
|
||||||
@@ -693,7 +772,8 @@ FuseOptions options = {
|
|||||||
.refresh_token = ""
|
.refresh_token = ""
|
||||||
};
|
};
|
||||||
|
|
||||||
ExtraFuseOptions extra_options = {
|
ExtraFuseOptions extra_options =
|
||||||
|
{
|
||||||
.get_extended_metadata = "false",
|
.get_extended_metadata = "false",
|
||||||
.curl_verbose = "false",
|
.curl_verbose = "false",
|
||||||
.cache_statfs_timeout = 0,
|
.cache_statfs_timeout = 0,
|
||||||
@@ -703,7 +783,8 @@ ExtraFuseOptions extra_options = {
|
|||||||
.enable_chmod = "false"
|
.enable_chmod = "false"
|
||||||
};
|
};
|
||||||
|
|
||||||
int parse_option(void *data, const char *arg, int key, struct fuse_args *outargs)
|
int parse_option(void* data, const char* arg, int key,
|
||||||
|
struct fuse_args* outargs)
|
||||||
{
|
{
|
||||||
if (sscanf(arg, " cache_timeout = %[^\r\n ]", options.cache_timeout) ||
|
if (sscanf(arg, " cache_timeout = %[^\r\n ]", options.cache_timeout) ||
|
||||||
sscanf(arg, " verify_ssl = %[^\r\n ]", options.verify_ssl) ||
|
sscanf(arg, " verify_ssl = %[^\r\n ]", options.verify_ssl) ||
|
||||||
@@ -716,11 +797,14 @@ int parse_option(void *data, const char *arg, int key, struct fuse_args *outargs
|
|||||||
sscanf(arg, " client_secret = %[^\r\n ]", options.client_secret) ||
|
sscanf(arg, " client_secret = %[^\r\n ]", options.client_secret) ||
|
||||||
sscanf(arg, " refresh_token = %[^\r\n ]", options.refresh_token) ||
|
sscanf(arg, " refresh_token = %[^\r\n ]", options.refresh_token) ||
|
||||||
|
|
||||||
sscanf(arg, " get_extended_metadata = %[^\r\n ]", extra_options.get_extended_metadata) ||
|
sscanf(arg, " get_extended_metadata = %[^\r\n ]",
|
||||||
|
extra_options.get_extended_metadata) ||
|
||||||
sscanf(arg, " curl_verbose = %[^\r\n ]", extra_options.curl_verbose) ||
|
sscanf(arg, " curl_verbose = %[^\r\n ]", extra_options.curl_verbose) ||
|
||||||
sscanf(arg, " cache_statfs_timeout = %[^\r\n ]", extra_options.cache_statfs_timeout) ||
|
sscanf(arg, " cache_statfs_timeout = %[^\r\n ]",
|
||||||
|
extra_options.cache_statfs_timeout) ||
|
||||||
sscanf(arg, " debug_level = %[^\r\n ]", extra_options.debug_level) ||
|
sscanf(arg, " debug_level = %[^\r\n ]", extra_options.debug_level) ||
|
||||||
sscanf(arg, " curl_progress_state = %[^\r\n ]", extra_options.curl_progress_state) ||
|
sscanf(arg, " curl_progress_state = %[^\r\n ]",
|
||||||
|
extra_options.curl_progress_state) ||
|
||||||
sscanf(arg, " enable_chmod = %[^\r\n ]", extra_options.enable_chmod) ||
|
sscanf(arg, " enable_chmod = %[^\r\n ]", extra_options.enable_chmod) ||
|
||||||
sscanf(arg, " enable_chown = %[^\r\n ]", extra_options.enable_chown)
|
sscanf(arg, " enable_chown = %[^\r\n ]", extra_options.enable_chown)
|
||||||
)
|
)
|
||||||
@@ -731,7 +815,8 @@ int parse_option(void *data, const char *arg, int key, struct fuse_args *outargs
|
|||||||
}
|
}
|
||||||
|
|
||||||
//allows memory leaks inspections
|
//allows memory leaks inspections
|
||||||
void interrupt_handler(int sig) {
|
void interrupt_handler(int sig)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, "Got interrupt signal %d, cleaning memory", sig);
|
debugf(DBG_LEVEL_NORM, "Got interrupt signal %d, cleaning memory", sig);
|
||||||
//TODO: clean memory allocations
|
//TODO: clean memory allocations
|
||||||
//http://www.cprogramming.com/debugging/valgrind.html
|
//http://www.cprogramming.com/debugging/valgrind.html
|
||||||
@@ -745,30 +830,22 @@ void initialise_options()
|
|||||||
{
|
{
|
||||||
//todo: handle param init consistently, quite heavy implementation
|
//todo: handle param init consistently, quite heavy implementation
|
||||||
cloudfs_verify_ssl(!strcasecmp(options.verify_ssl, "true"));
|
cloudfs_verify_ssl(!strcasecmp(options.verify_ssl, "true"));
|
||||||
cloudfs_option_get_extended_metadata(!strcasecmp(extra_options.get_extended_metadata, "true"));
|
cloudfs_option_get_extended_metadata(!strcasecmp(
|
||||||
|
extra_options.get_extended_metadata, "true"));
|
||||||
cloudfs_option_curl_verbose(!strcasecmp(extra_options.curl_verbose, "true"));
|
cloudfs_option_curl_verbose(!strcasecmp(extra_options.curl_verbose, "true"));
|
||||||
//lean way to init params, to be used as reference
|
//lean way to init params, to be used as reference
|
||||||
if (*extra_options.debug_level)
|
if (*extra_options.debug_level)
|
||||||
{
|
|
||||||
option_debug_level = atoi(extra_options.debug_level);
|
option_debug_level = atoi(extra_options.debug_level);
|
||||||
}
|
|
||||||
if (*extra_options.cache_statfs_timeout)
|
if (*extra_options.cache_statfs_timeout)
|
||||||
{
|
|
||||||
option_cache_statfs_timeout = atoi(extra_options.cache_statfs_timeout);
|
option_cache_statfs_timeout = atoi(extra_options.cache_statfs_timeout);
|
||||||
}
|
|
||||||
if (*extra_options.curl_progress_state)
|
if (*extra_options.curl_progress_state)
|
||||||
{
|
option_curl_progress_state = !strcasecmp(extra_options.curl_progress_state,
|
||||||
option_curl_progress_state = !strcasecmp(extra_options.curl_progress_state, "true");
|
"true");
|
||||||
}
|
|
||||||
if (*extra_options.enable_chmod)
|
if (*extra_options.enable_chmod)
|
||||||
{
|
|
||||||
option_enable_chmod = !strcasecmp(extra_options.enable_chmod, "true");
|
option_enable_chmod = !strcasecmp(extra_options.enable_chmod, "true");
|
||||||
}
|
|
||||||
if (*extra_options.enable_chown)
|
if (*extra_options.enable_chown)
|
||||||
{
|
|
||||||
option_enable_chown = !strcasecmp(extra_options.enable_chown, "true");
|
option_enable_chown = !strcasecmp(extra_options.enable_chown, "true");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@@ -781,7 +858,8 @@ int main(int argc, char **argv)
|
|||||||
FILE* settings;
|
FILE* settings;
|
||||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||||
|
|
||||||
snprintf(settings_filename, sizeof(settings_filename), "%s/.hubicfuse", get_home_dir());
|
snprintf(settings_filename, sizeof(settings_filename), "%s/.hubicfuse",
|
||||||
|
get_home_dir());
|
||||||
if ((settings = fopen(settings_filename, "r")))
|
if ((settings = fopen(settings_filename, "r")))
|
||||||
{
|
{
|
||||||
char line[OPTION_SIZE];
|
char line[OPTION_SIZE];
|
||||||
@@ -801,25 +879,36 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (!*options.client_id || !*options.client_secret || !*options.refresh_token)
|
if (!*options.client_id || !*options.client_secret || !*options.refresh_token)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unable to determine client_id, client_secret or refresh_token.\n\n");
|
fprintf(stderr,
|
||||||
|
"Unable to determine client_id, client_secret or refresh_token.\n\n");
|
||||||
fprintf(stderr, "These can be set either as mount options or in "
|
fprintf(stderr, "These can be set either as mount options or in "
|
||||||
"a file named %s\n\n", settings_filename);
|
"a file named %s\n\n", settings_filename);
|
||||||
fprintf(stderr, " client_id=[App's id]\n");
|
fprintf(stderr, " client_id=[App's id]\n");
|
||||||
fprintf(stderr, " client_secret=[App's secret]\n");
|
fprintf(stderr, " client_secret=[App's secret]\n");
|
||||||
fprintf(stderr, " refresh_token=[Get it running hubic_token]\n");
|
fprintf(stderr, " refresh_token=[Get it running hubic_token]\n");
|
||||||
fprintf(stderr, "The following settings are optional:\n\n");
|
fprintf(stderr, "The following settings are optional:\n\n");
|
||||||
fprintf(stderr, " cache_timeout=[Seconds for directory caching, default 600]\n");
|
fprintf(stderr,
|
||||||
|
" cache_timeout=[Seconds for directory caching, default 600]\n");
|
||||||
fprintf(stderr, " verify_ssl=[false to disable SSL cert verification]\n");
|
fprintf(stderr, " verify_ssl=[false to disable SSL cert verification]\n");
|
||||||
fprintf(stderr, " segment_size=[Size to use when creating DLOs, default 1073741824]\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, " segment_above=[File size at which to use segments, defult 2147483648]\n");
|
" segment_size=[Size to use when creating DLOs, default 1073741824]\n");
|
||||||
fprintf(stderr, " storage_url=[Storage URL for other tenant to view container]\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, " container=[Public container to view of tenant specified by storage_url]\n");
|
" segment_above=[File size at which to use segments, defult 2147483648]\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" storage_url=[Storage URL for other tenant to view container]\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" container=[Public container to view of tenant specified by storage_url]\n");
|
||||||
fprintf(stderr, " temp_dir=[Directory to store temp files]\n");
|
fprintf(stderr, " temp_dir=[Directory to store temp files]\n");
|
||||||
fprintf(stderr, " get_extended_metadata=[true to enable download of utime, chmod, chown file attributes (but slower)]\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, " curl_verbose=[true to debug info on curl requests (lots of output)]\n");
|
" get_extended_metadata=[true to enable download of utime, chmod, chown file attributes (but slower)]\n");
|
||||||
fprintf(stderr, " curl_progress_state=[true to enable progress callback enabled. Mostly used for debugging]\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, " cache_statfs_timeout=[number of seconds to cache requests to statfs (cloud statistics), 0 for no cache]\n");
|
" curl_verbose=[true to debug info on curl requests (lots of output)]\n");
|
||||||
fprintf(stderr, " debug_level=[0 to 2, 0 for minimal verbose debugging. No debug if -d or -f option is not provided.]\n");
|
fprintf(stderr,
|
||||||
|
" curl_progress_state=[true to enable progress callback enabled. Mostly used for debugging]\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" cache_statfs_timeout=[number of seconds to cache requests to statfs (cloud statistics), 0 for no cache]\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" debug_level=[0 to 2, 0 for minimal verbose debugging. No debug if -d or -f option is not provided.]\n");
|
||||||
fprintf(stderr, " enable_chmod=[true to enable chmod support on fuse]\n");
|
fprintf(stderr, " enable_chmod=[true to enable chmod support on fuse]\n");
|
||||||
fprintf(stderr, " enable_chown=[true to enable chown support on fuse]\n");
|
fprintf(stderr, " enable_chown=[true to enable chown support on fuse]\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -834,7 +923,8 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr, "enable_chmod = %d\n", option_enable_chmod);
|
fprintf(stderr, "enable_chmod = %d\n", option_enable_chmod);
|
||||||
fprintf(stderr, "enable_chown = %d\n", option_enable_chown);
|
fprintf(stderr, "enable_chown = %d\n", option_enable_chown);
|
||||||
}
|
}
|
||||||
cloudfs_set_credentials(options.client_id, options.client_secret, options.refresh_token);
|
cloudfs_set_credentials(options.client_id, options.client_secret,
|
||||||
|
options.refresh_token);
|
||||||
|
|
||||||
if (!cloudfs_connect())
|
if (!cloudfs_connect())
|
||||||
{
|
{
|
||||||
@@ -847,7 +937,8 @@ int main(int argc, char **argv)
|
|||||||
fuse_opt_add_arg(&args, "-s");
|
fuse_opt_add_arg(&args, "-s");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct fuse_operations cfs_oper = {
|
struct fuse_operations cfs_oper =
|
||||||
|
{
|
||||||
.readdir = cfs_readdir,
|
.readdir = cfs_readdir,
|
||||||
.mkdir = cfs_mkdir,
|
.mkdir = cfs_mkdir,
|
||||||
.read = cfs_read,
|
.read = cfs_read,
|
||||||
|
|||||||
+73
-57
@@ -68,7 +68,8 @@ time_t get_time_as_local(time_t time_t_val, char time_str[], int char_buf_size)
|
|||||||
{
|
{
|
||||||
struct tm loc_time_tm;
|
struct tm loc_time_tm;
|
||||||
loc_time_tm = *localtime(&time_t_val);
|
loc_time_tm = *localtime(&time_t_val);
|
||||||
if (time_str != NULL) {
|
if (time_str != NULL)
|
||||||
|
{
|
||||||
//debugf(DBG_LEVEL_NORM, 0,"Local len=%d size=%d pass=%d", strlen(time_str), sizeof(time_str), char_buf_size);
|
//debugf(DBG_LEVEL_NORM, 0,"Local len=%d size=%d pass=%d", strlen(time_str), sizeof(time_str), char_buf_size);
|
||||||
strftime(time_str, char_buf_size, "%c", &loc_time_tm);
|
strftime(time_str, char_buf_size, "%c", &loc_time_tm);
|
||||||
//debugf(DBG_LEVEL_NORM, 0,"Local timestr=[%s] size=%d", time_str, strlen(time_str));
|
//debugf(DBG_LEVEL_NORM, 0,"Local timestr=[%s] size=%d", time_str, strlen(time_str));
|
||||||
@@ -77,19 +78,24 @@ time_t get_time_as_local(time_t time_t_val, char time_str[], int char_buf_size)
|
|||||||
return mktime(&loc_time_tm);
|
return mktime(&loc_time_tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_time_as_string(time_t time_t_val, long nsec, char *time_str, int time_str_len)
|
int get_time_as_string(time_t time_t_val, long nsec, char* time_str,
|
||||||
|
int time_str_len)
|
||||||
{
|
{
|
||||||
struct tm time_val_tm;
|
struct tm time_val_tm;
|
||||||
time_t safe_input_time;
|
time_t safe_input_time;
|
||||||
//if time is incorrect (too long) you get segfault, need to check length and trim
|
//if time is incorrect (too long) you get segfault, need to check length and trim
|
||||||
if (time_t_val > INT_MAX) {
|
if (time_t_val > INT_MAX)
|
||||||
debugf(DBG_LEVEL_NORM, KRED"get_time_as_string: input time length too long, %lu > max=%lu, trimming!", time_t_val, INT_MAX);
|
{
|
||||||
|
debugf(DBG_LEVEL_NORM,
|
||||||
|
KRED"get_time_as_string: input time length too long, %lu > max=%lu, trimming!",
|
||||||
|
time_t_val, INT_MAX);
|
||||||
safe_input_time = 0;//(int)time_t_val;
|
safe_input_time = 0;//(int)time_t_val;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
safe_input_time = time_t_val;
|
safe_input_time = time_t_val;
|
||||||
time_val_tm = *gmtime(&safe_input_time);
|
time_val_tm = *gmtime(&safe_input_time);
|
||||||
int str_len = strftime(time_str, time_str_len, HUBIC_DATE_FORMAT, &time_val_tm);
|
int str_len = strftime(time_str, time_str_len, HUBIC_DATE_FORMAT,
|
||||||
|
&time_val_tm);
|
||||||
char nsec_str[TIME_CHARS];
|
char nsec_str[TIME_CHARS];
|
||||||
sprintf(nsec_str, "%d", nsec);
|
sprintf(nsec_str, "%d", nsec);
|
||||||
strcat(time_str, nsec_str);
|
strcat(time_str, nsec_str);
|
||||||
@@ -114,9 +120,11 @@ size_t get_time_now_as_str(char *time_str, int time_str_len)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_timespec_as_str(const struct timespec *times, char *time_str, int time_str_len)
|
int get_timespec_as_str(const struct timespec* times, char* time_str,
|
||||||
|
int time_str_len)
|
||||||
{
|
{
|
||||||
return get_time_as_string(times->tv_sec, times->tv_nsec, time_str, time_str_len);
|
return get_time_as_string(times->tv_sec, times->tv_nsec, time_str,
|
||||||
|
time_str_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* str2md5(const char* str, int length)
|
char* str2md5(const char* str, int length)
|
||||||
@@ -127,31 +135,31 @@ char *str2md5(const char *str, int length)
|
|||||||
char* out = (char*)malloc(33);
|
char* out = (char*)malloc(33);
|
||||||
|
|
||||||
MD5_Init(&c);
|
MD5_Init(&c);
|
||||||
while (length > 0) {
|
while (length > 0)
|
||||||
if (length > 512) {
|
{
|
||||||
|
if (length > 512)
|
||||||
MD5_Update(&c, str, 512);
|
MD5_Update(&c, str, 512);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
MD5_Update(&c, str, length);
|
MD5_Update(&c, str, length);
|
||||||
}
|
|
||||||
length -= 512;
|
length -= 512;
|
||||||
str += 512;
|
str += 512;
|
||||||
}
|
}
|
||||||
MD5_Final(digest, &c);
|
MD5_Final(digest, &c);
|
||||||
for (n = 0; n < 16; ++n) {
|
for (n = 0; n < 16; ++n)
|
||||||
snprintf(&(out[n * 2]), 16 * 2, "%02x", (unsigned int)digest[n]);
|
snprintf(&(out[n * 2]), 16 * 2, "%02x", (unsigned int)digest[n]);
|
||||||
}
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/10324611/how-to-calculate-the-md5-hash-of-a-large-file-in-c
|
// http://stackoverflow.com/questions/10324611/how-to-calculate-the-md5-hash-of-a-large-file-in-c
|
||||||
int file_md5(FILE* file_handle, char* md5_file_str)
|
int file_md5(FILE* file_handle, char* md5_file_str)
|
||||||
{
|
{
|
||||||
if (file_handle == NULL) {
|
if (file_handle == NULL)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KRED"file_md5: NULL file handle");
|
debugf(DBG_LEVEL_NORM, KRED"file_md5: NULL file handle");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (file_buffer_size == 0) {
|
if (file_buffer_size == 0)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_NORM, KYEL"file_md5: 0 file buffer size, using default");
|
debugf(DBG_LEVEL_NORM, KYEL"file_md5: 0 file buffer size, using default");
|
||||||
file_buffer_size = 1024;
|
file_buffer_size = 1024;
|
||||||
}
|
}
|
||||||
@@ -165,7 +173,8 @@ int file_md5(FILE *file_handle, char *md5_file_str)
|
|||||||
while ((bytes = fread(data_buf, 1, file_buffer_size, file_handle)) != 0)
|
while ((bytes = fread(data_buf, 1, file_buffer_size, file_handle)) != 0)
|
||||||
MD5_Update(&mdContext, data_buf, bytes);
|
MD5_Update(&mdContext, data_buf, bytes);
|
||||||
MD5_Final(c, &mdContext);
|
MD5_Final(c, &mdContext);
|
||||||
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
for (i = 0; i < MD5_DIGEST_LENGTH; i++)
|
||||||
|
{
|
||||||
snprintf(mdchar, 3, "%02x", c[i]);
|
snprintf(mdchar, 3, "%02x", c[i]);
|
||||||
strcat(md5_file_str, mdchar);
|
strcat(md5_file_str, mdchar);
|
||||||
}
|
}
|
||||||
@@ -173,14 +182,14 @@ int file_md5(FILE *file_handle, char *md5_file_str)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_safe_cache_file_path(const char *path, char *file_path_safe, char *temp_dir)
|
int get_safe_cache_file_path(const char* path, char* file_path_safe,
|
||||||
|
char* temp_dir)
|
||||||
{
|
{
|
||||||
char tmp_path[PATH_MAX];
|
char tmp_path[PATH_MAX];
|
||||||
strncpy(tmp_path, path, PATH_MAX);
|
strncpy(tmp_path, path, PATH_MAX);
|
||||||
char* pch;
|
char* pch;
|
||||||
while ((pch = strchr(tmp_path, '/'))) {
|
while ((pch = strchr(tmp_path, '/')))
|
||||||
* pch = '.';
|
* pch = '.';
|
||||||
}
|
|
||||||
char file_path[PATH_MAX] = "";
|
char file_path[PATH_MAX] = "";
|
||||||
//temp file name had process pid in it, removed as on restart files are left in cache (pid changes)
|
//temp file name had process pid in it, removed as on restart files are left in cache (pid changes)
|
||||||
snprintf(file_path, PATH_MAX, TEMP_FILE_NAME_FORMAT, temp_dir, tmp_path);
|
snprintf(file_path, PATH_MAX, TEMP_FILE_NAME_FORMAT, temp_dir, tmp_path);
|
||||||
@@ -221,7 +230,8 @@ void debug_print_flags(int flags)
|
|||||||
if (val & O_APPEND) debugf(DBG_LEVEL_EXTALL, KYEL", append");
|
if (val & O_APPEND) debugf(DBG_LEVEL_EXTALL, KYEL", append");
|
||||||
if (val & O_NONBLOCK) debugf(DBG_LEVEL_EXTALL, KYEL", nonblocking");
|
if (val & O_NONBLOCK) debugf(DBG_LEVEL_EXTALL, KYEL", nonblocking");
|
||||||
#if !defined(_POSIX_SOURCE) && defined(O_SYNC)
|
#if !defined(_POSIX_SOURCE) && defined(O_SYNC)
|
||||||
if (val & O_SYNC) debugf(DBG_LEVEL_EXT, 0,KRED ", synchronous writes");
|
if (val & O_SYNC) debugf(DBG_LEVEL_EXT, 0,
|
||||||
|
KRED ", synchronous writes");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -231,7 +241,8 @@ void debug_print_descriptor(struct fuse_file_info *info)
|
|||||||
{
|
{
|
||||||
char file_path[MAX_PATH_SIZE];
|
char file_path[MAX_PATH_SIZE];
|
||||||
get_file_path_from_fd(info->fh, file_path, sizeof(file_path));
|
get_file_path_from_fd(info->fh, file_path, sizeof(file_path));
|
||||||
debugf(DBG_LEVEL_EXT, KCYN "descriptor localfile=[%s] fd=%d", file_path, info->fh);
|
debugf(DBG_LEVEL_EXT, KCYN "descriptor localfile=[%s] fd=%d", file_path,
|
||||||
|
info->fh);
|
||||||
debug_print_flags(info->flags);
|
debug_print_flags(info->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,18 +255,18 @@ void dir_for(const char *path, char *dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//prints cache content for debug purposes
|
//prints cache content for debug purposes
|
||||||
void debug_list_cache_content() {
|
void debug_list_cache_content()
|
||||||
|
{
|
||||||
return;//disabled
|
return;//disabled
|
||||||
dir_cache* cw;
|
dir_cache* cw;
|
||||||
dir_entry* de;
|
dir_entry* de;
|
||||||
for (cw = dcache; cw; cw = cw->next)
|
for (cw = dcache; cw; cw = cw->next)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "LIST-CACHE: DIR[%s]", cw->path);
|
debugf(DBG_LEVEL_EXT, "LIST-CACHE: DIR[%s]", cw->path);
|
||||||
for (de = cw->entries; de; de = de->next) {
|
for (de = cw->entries; de; de = de->next)
|
||||||
debugf(DBG_LEVEL_EXT, "LIST-CACHE: FOLDER[%s]", de->full_name);
|
debugf(DBG_LEVEL_EXT, "LIST-CACHE: FOLDER[%s]", de->full_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int delete_file(char* path)
|
int delete_file(char* path)
|
||||||
{
|
{
|
||||||
@@ -263,7 +274,8 @@ int delete_file(char *path)
|
|||||||
char file_path_safe[NAME_MAX] = "";
|
char file_path_safe[NAME_MAX] = "";
|
||||||
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
get_safe_cache_file_path(path, file_path_safe, temp_dir);
|
||||||
int result = unlink(file_path_safe);
|
int result = unlink(file_path_safe);
|
||||||
debugf(DBG_LEVEL_EXT, KYEL"delete_file(%s) (%s) result=%s", path, file_path_safe, strerror(result));
|
debugf(DBG_LEVEL_EXT, KYEL"delete_file(%s) (%s) result=%s", path,
|
||||||
|
file_path_safe, strerror(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +306,8 @@ void cloudfs_free_dir_list(dir_entry *dir_list)
|
|||||||
{
|
{
|
||||||
//check for NULL as dir might be already removed from cache by other thread
|
//check for NULL as dir might be already removed from cache by other thread
|
||||||
debugf(DBG_LEVEL_NORM, "cloudfs_free_dir_list(%s)", dir_list->full_name);
|
debugf(DBG_LEVEL_NORM, "cloudfs_free_dir_list(%s)", dir_list->full_name);
|
||||||
while (dir_list) {
|
while (dir_list)
|
||||||
|
{
|
||||||
dir_entry* de = dir_list;
|
dir_entry* de = dir_list;
|
||||||
dir_list = dir_list->next;
|
dir_list = dir_list->next;
|
||||||
//remove file from disk cache, fix for issue #89, https://github.com/TurboGit/hubicfuse/issues/89
|
//remove file from disk cache, fix for issue #89, https://github.com/TurboGit/hubicfuse/issues/89
|
||||||
@@ -316,7 +329,8 @@ void dir_decache(const char *path)
|
|||||||
dir_entry* de, *tmpde;
|
dir_entry* de, *tmpde;
|
||||||
char dir[MAX_PATH_SIZE];
|
char dir[MAX_PATH_SIZE];
|
||||||
dir_for(path, dir);
|
dir_for(path, dir);
|
||||||
for (cw = dcache; cw; cw = cw->next) {
|
for (cw = dcache; cw; cw = cw->next)
|
||||||
|
{
|
||||||
debugf(DBG_LEVEL_EXT, "dir_decache: parse(%s)", cw->path);
|
debugf(DBG_LEVEL_EXT, "dir_decache: parse(%s)", cw->path);
|
||||||
if (!strcmp(cw->path, path))
|
if (!strcmp(cw->path, path))
|
||||||
{
|
{
|
||||||
@@ -425,16 +439,11 @@ void update_dir_cache(const char *path, off_t size, int isdir, int islink)
|
|||||||
de->full_name = strdup(path);
|
de->full_name = strdup(path);
|
||||||
//fixed: the conditions below were mixed up dir -> link?
|
//fixed: the conditions below were mixed up dir -> link?
|
||||||
if (islink)
|
if (islink)
|
||||||
{
|
|
||||||
de->content_type = strdup("application/link");
|
de->content_type = strdup("application/link");
|
||||||
}
|
|
||||||
if (isdir)
|
if (isdir)
|
||||||
{
|
|
||||||
de->content_type = strdup("application/directory");
|
de->content_type = strdup("application/directory");
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
de->content_type = strdup("application/octet-stream");
|
de->content_type = strdup("application/octet-stream");
|
||||||
}
|
|
||||||
de->next = cw->entries;
|
de->next = cw->entries;
|
||||||
cw->entries = de;
|
cw->entries = de;
|
||||||
if (isdir)
|
if (isdir)
|
||||||
@@ -459,13 +468,16 @@ int caching_list_directory(const char *path, dir_entry **list)
|
|||||||
{
|
{
|
||||||
if (cw->was_deleted == true)
|
if (cw->was_deleted == true)
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"caching_list_directory status: dir(%s) is empty as cached expired, reload from cloud", cw->path);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
KMAG"caching_list_directory status: dir(%s) is empty as cached expired, reload from cloud",
|
||||||
|
cw->path);
|
||||||
if (!cloudfs_list_directory(cw->path, list))
|
if (!cloudfs_list_directory(cw->path, list))
|
||||||
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
KMAG"caching_list_directory status: cannot reload dir(%s)", cw->path);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"caching_list_directory status: cannot reload dir(%s)", cw->path);
|
debugf(DBG_LEVEL_EXT, KMAG"caching_list_directory status: reloaded dir(%s)",
|
||||||
}
|
cw->path);
|
||||||
else {
|
|
||||||
debugf(DBG_LEVEL_EXT, KMAG"caching_list_directory status: reloaded dir(%s)", cw->path);
|
|
||||||
//cw->entries = *list;
|
//cw->entries = *list;
|
||||||
cw->was_deleted = false;
|
cw->was_deleted = false;
|
||||||
cw->cached = time(NULL);
|
cw->cached = time(NULL);
|
||||||
@@ -474,11 +486,9 @@ int caching_list_directory(const char *path, dir_entry **list)
|
|||||||
if (cw->was_deleted == false)
|
if (cw->was_deleted == false)
|
||||||
{
|
{
|
||||||
if (!strcmp(cw->path, path))
|
if (!strcmp(cw->path, path))
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!cw)
|
if (!cw)
|
||||||
{
|
{
|
||||||
//trying to download this entry from cloud, list will point to cached or downloaded entries
|
//trying to download this entry from cloud, list will point to cached or downloaded entries
|
||||||
@@ -486,10 +496,12 @@ int caching_list_directory(const char *path, dir_entry **list)
|
|||||||
{
|
{
|
||||||
//download was not ok
|
//download was not ok
|
||||||
pthread_mutex_unlock(&dcachemut);
|
pthread_mutex_unlock(&dcachemut);
|
||||||
debugf(DBG_LEVEL_EXT, "exit 0: caching_list_directory(%s) "KYEL"[CACHE-DIR-MISS]", path);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit 0: caching_list_directory(%s) "KYEL"[CACHE-DIR-MISS]", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
debugf(DBG_LEVEL_EXT, "caching_list_directory: new_cache(%s) "KYEL"[CACHE-CREATE]", path);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"caching_list_directory: new_cache(%s) "KYEL"[CACHE-CREATE]", path);
|
||||||
cw = new_cache(path);
|
cw = new_cache(path);
|
||||||
new_entry = true;
|
new_entry = true;
|
||||||
}
|
}
|
||||||
@@ -509,16 +521,21 @@ int caching_list_directory(const char *path, dir_entry **list)
|
|||||||
cloudfs_free_dir_list(cw->entries);
|
cloudfs_free_dir_list(cw->entries);
|
||||||
cw->was_deleted = true;
|
cw->was_deleted = true;
|
||||||
cw->cached = time(NULL);
|
cw->cached = time(NULL);
|
||||||
debugf(DBG_LEVEL_EXT, "caching_list_directory(%s) "KYEL"[CACHE-EXPIRED]", path);
|
debugf(DBG_LEVEL_EXT, "caching_list_directory(%s) "KYEL"[CACHE-EXPIRED]",
|
||||||
|
path);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "got NULL on caching_list_directory(%s) "KYEL"[CACHE-EXPIRED w NULL]", path);
|
{
|
||||||
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"got NULL on caching_list_directory(%s) "KYEL"[CACHE-EXPIRED w NULL]", path);
|
||||||
pthread_mutex_unlock(&dcachemut);
|
pthread_mutex_unlock(&dcachemut);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "caching_list_directory(%s) "KGRN"[CACHE-DIR-HIT]", path);
|
{
|
||||||
|
debugf(DBG_LEVEL_EXT, "caching_list_directory(%s) "KGRN"[CACHE-DIR-HIT]",
|
||||||
|
path);
|
||||||
*list = cw->entries;
|
*list = cw->entries;
|
||||||
}
|
}
|
||||||
//adding new dir file list to global cache, now this dir becomes visible in cache
|
//adding new dir file list to global cache, now this dir becomes visible in cache
|
||||||
@@ -539,9 +556,8 @@ dir_entry *path_info(const char *path)
|
|||||||
debugf(DBG_LEVEL_EXT, "exit 0: path_info(%s) "KYEL"[CACHE-DIR-MISS]", dir);
|
debugf(DBG_LEVEL_EXT, "exit 0: path_info(%s) "KYEL"[CACHE-DIR-MISS]", dir);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
debugf(DBG_LEVEL_EXT, "path_info(%s) "KGRN"[CACHE-DIR-HIT]", dir);
|
debugf(DBG_LEVEL_EXT, "path_info(%s) "KGRN"[CACHE-DIR-HIT]", dir);
|
||||||
}
|
|
||||||
//iterate in file list obtained from cache or downloaded
|
//iterate in file list obtained from cache or downloaded
|
||||||
for (; tmp; tmp = tmp->next)
|
for (; tmp; tmp = tmp->next)
|
||||||
{
|
{
|
||||||
@@ -570,11 +586,13 @@ int check_caching_list_directory(const char *path, dir_entry **list)
|
|||||||
{
|
{
|
||||||
*list = cw->entries;
|
*list = cw->entries;
|
||||||
pthread_mutex_unlock(&dcachemut);
|
pthread_mutex_unlock(&dcachemut);
|
||||||
debugf(DBG_LEVEL_EXT, "exit 0: check_caching_list_directory(%s) "KGRN"[CACHE-DIR-HIT]", path);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit 0: check_caching_list_directory(%s) "KGRN"[CACHE-DIR-HIT]", path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&dcachemut);
|
pthread_mutex_unlock(&dcachemut);
|
||||||
debugf(DBG_LEVEL_EXT, "exit 1: check_caching_list_directory(%s) "KYEL"[CACHE-DIR-MISS]", path);
|
debugf(DBG_LEVEL_EXT,
|
||||||
|
"exit 1: check_caching_list_directory(%s) "KYEL"[CACHE-DIR-MISS]", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,12 +630,10 @@ dir_entry *check_path_info(const char *path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!strcmp(path, "/"))
|
if (!strcmp(path, "/"))
|
||||||
{
|
debugf(DBG_LEVEL_EXT,
|
||||||
debugf(DBG_LEVEL_EXT, "exit 2: check_path_info(%s) "KYEL"ignoring root [CACHE-MISS]", path);
|
"exit 2: check_path_info(%s) "KYEL"ignoring root [CACHE-MISS]", path);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
debugf(DBG_LEVEL_EXT, "exit 3: check_path_info(%s) "KYEL"[CACHE-MISS]", path);
|
debugf(DBG_LEVEL_EXT, "exit 3: check_path_info(%s) "KYEL"[CACHE-MISS]", path);
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -81,14 +81,18 @@ typedef struct dir_cache
|
|||||||
|
|
||||||
time_t my_timegm(struct tm* tm);
|
time_t my_timegm(struct tm* tm);
|
||||||
time_t get_time_from_str_as_gmt(char* time_str);
|
time_t get_time_from_str_as_gmt(char* time_str);
|
||||||
time_t get_time_as_local(time_t time_t_val, char time_str[], int char_buf_size);
|
time_t get_time_as_local(time_t time_t_val, char time_str[],
|
||||||
int get_time_as_string(time_t time_t_val, long nsec, char *time_str, int time_str_len);
|
int char_buf_size);
|
||||||
|
int get_time_as_string(time_t time_t_val, long nsec, char* time_str,
|
||||||
|
int time_str_len);
|
||||||
time_t get_time_now();
|
time_t get_time_now();
|
||||||
int get_timespec_as_str(const struct timespec *times, char *time_str, int time_str_len);
|
int get_timespec_as_str(const struct timespec* times, char* time_str,
|
||||||
|
int time_str_len);
|
||||||
char* str2md5(const char* str, int length);
|
char* str2md5(const char* str, int length);
|
||||||
int file_md5(FILE* file_handle, char* md5_file_str);
|
int file_md5(FILE* file_handle, char* md5_file_str);
|
||||||
void debug_print_descriptor(struct fuse_file_info* info);
|
void debug_print_descriptor(struct fuse_file_info* info);
|
||||||
int get_safe_cache_file_path(const char *file_path, char *file_path_safe, char *temp_dir);
|
int get_safe_cache_file_path(const char* file_path, char* file_path_safe,
|
||||||
|
char* temp_dir);
|
||||||
dir_entry* init_dir_entry();
|
dir_entry* init_dir_entry();
|
||||||
void copy_dir_entry(dir_entry* src, dir_entry* dst);
|
void copy_dir_entry(dir_entry* src, dir_entry* dst);
|
||||||
dir_cache* new_cache(const char* path);
|
dir_cache* new_cache(const char* path);
|
||||||
|
|||||||
Reference in New Issue
Block a user