mirror of
https://github.com/xorgy/mediafire-fuse
synced 2026-01-13 13:14:29 -08:00
allow to change local files
- fuse/filecache:
* add filecache_upload_patch
* allow opening files in modes other than RDONLY
- fuse/hashtbl:
* add folder_tree_upload_patch
- fuse/operations:
* allow opening files in modes other than RDONLY
* add members to private context which allow tracking of
not-yet-uploaded files and files opened for writing and
files opened in read-only mode
- mfapi/apicalls/upload_patch:
* supply x-filename and x-filesize headers
- mfapi/apicalls/upload_simple:
* do not supply the x-filehash header as it is not used by the
server
- utils/hash:
* hex characters must be lower case for the server
- utils/strings:
* clean up unused functions strdup_join, strdup_substr,
string_chomp
- utils/stringv:
* complete rewrite with different string vector implementation
This commit is contained in:
219
fuse/filecache.c
219
fuse/filecache.c
@@ -26,6 +26,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "../utils/hash.h"
|
#include "../utils/hash.h"
|
||||||
#include "../utils/xdelta3.h"
|
#include "../utils/xdelta3.h"
|
||||||
@@ -54,25 +57,200 @@ static int filecache_patch_file(const char *filecache_path,
|
|||||||
uint64_t source_revision,
|
uint64_t source_revision,
|
||||||
uint64_t target_revision);
|
uint64_t target_revision);
|
||||||
|
|
||||||
|
int filecache_upload_patch(const char *quickkey, uint64_t local_revision,
|
||||||
|
const char *filecache_path, mfconn * conn)
|
||||||
|
{
|
||||||
|
FILE *source_fh;
|
||||||
|
FILE *target_fh;
|
||||||
|
FILE *patchfile_fh;
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
char *source_hash;
|
||||||
|
char *target_hash;
|
||||||
|
uint64_t target_size;
|
||||||
|
char *cachefile;
|
||||||
|
char *newfile;
|
||||||
|
char *patch_file;
|
||||||
|
int retval;
|
||||||
|
char *upload_key;
|
||||||
|
int status;
|
||||||
|
int fileerror;
|
||||||
|
|
||||||
|
cachefile = strdup_printf("%s/%s_%d", filecache_path, quickkey,
|
||||||
|
local_revision);
|
||||||
|
|
||||||
|
source_fh = fopen(cachefile, "r");
|
||||||
|
if (source_fh == NULL) {
|
||||||
|
fprintf(stderr, "cannot open %s\n", cachefile);
|
||||||
|
free(cachefile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(cachefile);
|
||||||
|
|
||||||
|
newfile = strdup_printf("%s/%s_%d_new", filecache_path, quickkey,
|
||||||
|
local_revision);
|
||||||
|
|
||||||
|
target_fh = fopen(newfile, "r");
|
||||||
|
if (target_fh == NULL) {
|
||||||
|
fprintf(stderr, "cannot open %s\n", newfile);
|
||||||
|
free(newfile);
|
||||||
|
fclose(source_fh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(newfile);
|
||||||
|
|
||||||
|
retval = calc_sha256(source_fh, hash, NULL);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "failed to calculate hash\n");
|
||||||
|
fclose(source_fh);
|
||||||
|
fclose(target_fh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_hash = binary2hex(hash, SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
|
retval = calc_sha256(target_fh, hash, &target_size);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "failed to calculate hash\n");
|
||||||
|
fclose(source_fh);
|
||||||
|
fclose(target_fh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_hash = binary2hex(hash, SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
|
if (strcmp(source_hash, target_hash) == 0) {
|
||||||
|
// no changes were done
|
||||||
|
free(source_hash);
|
||||||
|
free(target_hash);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_file = strdup_printf("%s/%s_patch_%d_new", filecache_path, quickkey,
|
||||||
|
local_revision);
|
||||||
|
|
||||||
|
patchfile_fh = fopen(patch_file, "w");
|
||||||
|
if (patchfile_fh == NULL) {
|
||||||
|
fprintf(stderr, "cannot open %s\n", patch_file);
|
||||||
|
fclose(source_fh);
|
||||||
|
fclose(target_fh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind(source_fh);
|
||||||
|
rewind(target_fh);
|
||||||
|
retval = xdelta3_diff(source_fh, target_fh, patchfile_fh);
|
||||||
|
fclose(source_fh);
|
||||||
|
fclose(target_fh);
|
||||||
|
fclose(patchfile_fh);
|
||||||
|
|
||||||
|
upload_key = NULL;
|
||||||
|
retval = mfconn_api_upload_patch(conn, quickkey, source_hash, target_hash,
|
||||||
|
target_size, patch_file, &upload_key);
|
||||||
|
|
||||||
|
if (retval != 0 || upload_key == NULL) {
|
||||||
|
fprintf(stderr, "mfconn_api_upload_patch failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// poll for completion
|
||||||
|
for (;;) {
|
||||||
|
// no need to update the secret key after this
|
||||||
|
retval = mfconn_api_upload_poll_upload(conn, upload_key,
|
||||||
|
&status, &fileerror);
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "mfconn_api_upload_poll_upload failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "status: %d, filerror: %d\n", status, fileerror);
|
||||||
|
if (status == 99) {
|
||||||
|
fprintf(stderr, "done\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(upload_key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int filecache_open_file(const char *quickkey, uint64_t local_revision,
|
int filecache_open_file(const char *quickkey, uint64_t local_revision,
|
||||||
uint64_t remote_revision, uint64_t fsize,
|
uint64_t remote_revision, uint64_t fsize,
|
||||||
const unsigned char *fhash,
|
const unsigned char *fhash,
|
||||||
const char *filecache_path, mfconn * conn)
|
const char *filecache_path, mfconn * conn, mode_t mode,
|
||||||
|
bool update)
|
||||||
{
|
{
|
||||||
char *cachefile;
|
char *cachefile;
|
||||||
|
char *newfile;
|
||||||
int fd;
|
int fd;
|
||||||
int retval;
|
int retval;
|
||||||
|
const int BUFSIZE = 4096;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
size_t size;
|
||||||
|
int source;
|
||||||
|
int dest;
|
||||||
|
|
||||||
/* check if the requested file is already in the cache */
|
if (update) {
|
||||||
cachefile =
|
cachefile = strdup_printf("%s/%s_%d", filecache_path, quickkey,
|
||||||
strdup_printf("%s/%s_%d", filecache_path, quickkey, remote_revision);
|
remote_revision);
|
||||||
fd = open(cachefile, O_RDWR);
|
} else {
|
||||||
if (fd > 0) {
|
cachefile = strdup_printf("%s/%s_%d", filecache_path, quickkey,
|
||||||
/* file existed - return handle */
|
local_revision);
|
||||||
free(cachefile);
|
}
|
||||||
return fd;
|
/* check if the requested file is already in the cache */
|
||||||
|
if ((mode & O_ACCMODE) == O_RDONLY) {
|
||||||
|
// if file is opened in readonly mode, we try to open it directly
|
||||||
|
fd = open(cachefile, mode);
|
||||||
|
free(cachefile);
|
||||||
|
if (fd > 0) {
|
||||||
|
/* file existed - return handle */
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
// if the file cannot be opened, then it has to be retrieved
|
||||||
|
} else {
|
||||||
|
// if file is opened writable then a temporary file has to be opened
|
||||||
|
// instead to upload a patch if necessary
|
||||||
|
if (update) {
|
||||||
|
newfile = strdup_printf("%s/%s_%d_new", filecache_path, quickkey,
|
||||||
|
remote_revision);
|
||||||
|
} else {
|
||||||
|
newfile = strdup_printf("%s/%s_%d_new", filecache_path, quickkey,
|
||||||
|
local_revision);
|
||||||
|
}
|
||||||
|
fd = open(newfile, mode);
|
||||||
|
if (fd > 0) {
|
||||||
|
/* file existed - return handle */
|
||||||
|
free(newfile);
|
||||||
|
free(cachefile);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
// the temporary file wasn't available, so we copy it from the
|
||||||
|
// original
|
||||||
|
source = open(cachefile, O_RDONLY);
|
||||||
|
free(cachefile);
|
||||||
|
if (fd > 0) {
|
||||||
|
dest = open(newfile, O_WRONLY | O_CREAT, 0644);
|
||||||
|
while ((size = read(source, buf, BUFSIZE)) > 0) {
|
||||||
|
write(dest, buf, size);
|
||||||
|
}
|
||||||
|
close(source);
|
||||||
|
close(dest);
|
||||||
|
fd = open(newfile, mode);
|
||||||
|
free(newfile);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
free(newfile);
|
||||||
|
// if the source file cannot be opened for copying, then it has to be
|
||||||
|
// retrieved
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no updating is requested and we end up here, then something failed
|
||||||
|
// but since we must not update, this is a failure
|
||||||
|
if (!update) {
|
||||||
|
fprintf(stderr, "no updating but cannot open\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
free(cachefile);
|
|
||||||
|
|
||||||
/* if the file with remote revision didn't exist, then check whether an
|
/* if the file with remote revision didn't exist, then check whether an
|
||||||
* old revision exists and in that case update that.
|
* old revision exists and in that case update that.
|
||||||
@@ -81,7 +259,7 @@ int filecache_open_file(const char *quickkey, uint64_t local_revision,
|
|||||||
|
|
||||||
cachefile =
|
cachefile =
|
||||||
strdup_printf("%s/%s_%d", filecache_path, quickkey, local_revision);
|
strdup_printf("%s/%s_%d", filecache_path, quickkey, local_revision);
|
||||||
fd = open(cachefile, O_RDWR);
|
fd = open(cachefile, O_RDONLY);
|
||||||
free(cachefile);
|
free(cachefile);
|
||||||
if (fd > 0) {
|
if (fd > 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -115,7 +293,24 @@ int filecache_open_file(const char *quickkey, uint64_t local_revision,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(cachefile, O_RDWR);
|
if ((mode & O_ACCMODE) == O_RDONLY) {
|
||||||
|
// if file is opened in readonly mode, we open it directly
|
||||||
|
fd = open(cachefile, mode);
|
||||||
|
} else {
|
||||||
|
// if file is opened writable then a temporary file has to be opened
|
||||||
|
// instead to upload a patch if necessary
|
||||||
|
newfile = strdup_printf("%s/%s_%d_new", filecache_path, quickkey,
|
||||||
|
remote_revision);
|
||||||
|
source = open(cachefile, O_RDONLY);
|
||||||
|
dest = open(newfile, O_WRONLY | O_CREAT, 0644);
|
||||||
|
while ((size = read(source, buf, BUFSIZE)) > 0) {
|
||||||
|
write(dest, buf, size);
|
||||||
|
}
|
||||||
|
close(source);
|
||||||
|
close(dest);
|
||||||
|
fd = open(newfile, mode);
|
||||||
|
free(newfile);
|
||||||
|
}
|
||||||
|
|
||||||
free(cachefile);
|
free(cachefile);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ int filecache_open_file(const char *quickkey,
|
|||||||
uint64_t local_revision,
|
uint64_t local_revision,
|
||||||
uint64_t remote_revision, uint64_t fsize,
|
uint64_t remote_revision, uint64_t fsize,
|
||||||
const unsigned char *fhash,
|
const unsigned char *fhash,
|
||||||
const char *filecache, mfconn * conn);
|
const char *filecache, mfconn * conn,
|
||||||
|
mode_t mode, bool update);
|
||||||
|
|
||||||
|
int filecache_upload_patch(const char *quickkey,
|
||||||
|
uint64_t local_revision,
|
||||||
|
const char *filecache, mfconn * conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -34,24 +34,17 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#ifdef __linux
|
|
||||||
#include <bits/fcntl-linux.h>
|
|
||||||
#endif
|
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
#include "hashtbl.h"
|
#include "hashtbl.h"
|
||||||
#include "filecache.h"
|
#include "filecache.h"
|
||||||
#include "../mfapi/mfconn.h"
|
#include "../mfapi/mfconn.h"
|
||||||
#include "../mfapi/file.h"
|
#include "../mfapi/file.h"
|
||||||
#include "../mfapi/patch.h"
|
|
||||||
#include "../mfapi/folder.h"
|
#include "../mfapi/folder.h"
|
||||||
#include "../mfapi/apicalls.h"
|
#include "../mfapi/apicalls.h"
|
||||||
#include "../utils/strings.h"
|
#include "../utils/strings.h"
|
||||||
#include "../utils/http.h"
|
|
||||||
#include "../utils/hash.h"
|
#include "../utils/hash.h"
|
||||||
#include "../utils/xdelta3.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we build a hashtable using the first three characters of the file or folder
|
* we build a hashtable using the first three characters of the file or folder
|
||||||
@@ -746,7 +739,31 @@ int folder_tree_tmp_open(folder_tree * tree)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int folder_tree_open_file(folder_tree * tree, mfconn * conn, const char *path)
|
int folder_tree_upload_patch(folder_tree * tree, mfconn * conn,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
struct h_entry *entry;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
entry = folder_tree_lookup_path(tree, conn, path);
|
||||||
|
/* either file not found or found entry is not a file */
|
||||||
|
if (entry == NULL || entry->atime == 0) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = filecache_upload_patch(entry->key, entry->local_revision,
|
||||||
|
tree->filecache, conn);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "filecache_upload_patch failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int folder_tree_open_file(folder_tree * tree, mfconn * conn, const char *path,
|
||||||
|
mode_t mode, bool update)
|
||||||
{
|
{
|
||||||
struct h_entry *entry;
|
struct h_entry *entry;
|
||||||
int retval;
|
int retval;
|
||||||
@@ -762,16 +779,19 @@ int folder_tree_open_file(folder_tree * tree, mfconn * conn, const char *path)
|
|||||||
|
|
||||||
retval = filecache_open_file(entry->key, entry->local_revision,
|
retval = filecache_open_file(entry->key, entry->local_revision,
|
||||||
entry->remote_revision, entry->fsize,
|
entry->remote_revision, entry->fsize,
|
||||||
entry->hash, tree->filecache, conn);
|
entry->hash, tree->filecache, conn, mode,
|
||||||
|
update);
|
||||||
if (retval == -1) {
|
if (retval == -1) {
|
||||||
fprintf(stderr, "filecache_open_file failed\n");
|
fprintf(stderr, "filecache_open_file failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure that the local_revision is equal to the remote revision
|
if (update) {
|
||||||
* because filecache_open_file took care of doing any updating if it was
|
/* make sure that the local_revision is equal to the remote revision
|
||||||
* necessary */
|
* because filecache_open_file took care of doing any updating if it
|
||||||
entry->local_revision = entry->remote_revision;
|
* was necessary */
|
||||||
|
entry->local_revision = entry->remote_revision;
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "../mfapi/mfconn.h"
|
#include "../mfapi/mfconn.h"
|
||||||
|
|
||||||
@@ -72,8 +73,12 @@ bool folder_tree_path_is_file(folder_tree * tree, mfconn * conn,
|
|||||||
const char *path);
|
const char *path);
|
||||||
|
|
||||||
int folder_tree_open_file(folder_tree * tree, mfconn * conn,
|
int folder_tree_open_file(folder_tree * tree, mfconn * conn,
|
||||||
const char *path);
|
const char *path, mode_t mode,
|
||||||
|
bool update);
|
||||||
|
|
||||||
int folder_tree_tmp_open(folder_tree * tree);
|
int folder_tree_tmp_open(folder_tree * tree);
|
||||||
|
|
||||||
|
int folder_tree_upload_patch(folder_tree * tree, mfconn * conn,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include "hashtbl.h"
|
#include "hashtbl.h"
|
||||||
#include "operations.h"
|
#include "operations.h"
|
||||||
#include "../utils/strings.h"
|
#include "../utils/strings.h"
|
||||||
|
#include "../utils/stringv.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_HELP,
|
KEY_HELP,
|
||||||
@@ -410,8 +411,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
connect_mf(&options, ctx);
|
connect_mf(&options, ctx);
|
||||||
|
|
||||||
ctx->tmpfiles = NULL;
|
ctx->sv_writefiles = stringv_alloc();
|
||||||
ctx->num_tmpfiles = 0;
|
ctx->sv_readonlyfiles = stringv_alloc();
|
||||||
|
|
||||||
ret = fuse_main(argc, argv, &mediafirefs_oper, ctx);
|
ret = fuse_main(argc, argv, &mediafirefs_oper, ctx);
|
||||||
|
|
||||||
@@ -423,6 +424,8 @@ int main(int argc, char *argv[])
|
|||||||
free(ctx->configfile);
|
free(ctx->configfile);
|
||||||
free(ctx->dircache);
|
free(ctx->dircache);
|
||||||
free(ctx->filecache);
|
free(ctx->filecache);
|
||||||
|
stringv_free(ctx->sv_writefiles);
|
||||||
|
stringv_free(ctx->sv_readonlyfiles);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -95,12 +95,11 @@
|
|||||||
struct mediafirefs_openfile {
|
struct mediafirefs_openfile {
|
||||||
// to fread and fwrite from/to the file
|
// to fread and fwrite from/to the file
|
||||||
int fd;
|
int fd;
|
||||||
|
char *path;
|
||||||
// whether or not a patch has to be uploaded when closing
|
// whether or not a patch has to be uploaded when closing
|
||||||
bool is_readonly;
|
bool is_readonly;
|
||||||
// whether or not to do a new file upload when closing
|
// whether or not to do a new file upload when closing
|
||||||
// if this is NULL then the file already existed remotely
|
bool is_local;
|
||||||
// otherwise a new upload has to be done to the given remote path
|
|
||||||
char *remote_path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int mediafirefs_getattr(const char *path, struct stat *stbuf)
|
int mediafirefs_getattr(const char *path, struct stat *stbuf)
|
||||||
@@ -115,27 +114,21 @@ int mediafirefs_getattr(const char *path, struct stat *stbuf)
|
|||||||
*/
|
*/
|
||||||
struct mediafirefs_context_private *ctx;
|
struct mediafirefs_context_private *ctx;
|
||||||
int retval;
|
int retval;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
ctx = fuse_get_context()->private_data;
|
ctx = fuse_get_context()->private_data;
|
||||||
folder_tree_update(ctx->tree, ctx->conn, false);
|
folder_tree_update(ctx->tree, ctx->conn, false);
|
||||||
retval = folder_tree_getattr(ctx->tree, ctx->conn, path, stbuf);
|
retval = folder_tree_getattr(ctx->tree, ctx->conn, path, stbuf);
|
||||||
|
|
||||||
if (retval != 0) {
|
if (retval != 0 && stringv_mem(ctx->sv_writefiles, path)) {
|
||||||
for (i = 0; i < ctx->num_tmpfiles; i++) {
|
stbuf->st_uid = geteuid();
|
||||||
if (strcmp(ctx->tmpfiles[i], path) == 0) {
|
stbuf->st_gid = getegid();
|
||||||
stbuf->st_uid = geteuid();
|
stbuf->st_ctime = 0;
|
||||||
stbuf->st_gid = getegid();
|
stbuf->st_mtime = 0;
|
||||||
stbuf->st_ctime = 0;
|
stbuf->st_mode = S_IFREG | 0666;
|
||||||
stbuf->st_mtime = 0;
|
stbuf->st_nlink = 1;
|
||||||
stbuf->st_mode = S_IFREG | 0666;
|
stbuf->st_atime = 0;
|
||||||
stbuf->st_nlink = 1;
|
stbuf->st_size = 0;
|
||||||
stbuf->st_atime = 0;
|
retval = 0;
|
||||||
stbuf->st_size = 0;
|
|
||||||
retval = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -308,20 +301,60 @@ int mediafirefs_unlink(const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the following restrictions apply:
|
||||||
|
* 1. a file can be opened in read-only mode more than once at a time
|
||||||
|
* 2. a file can only be be opened in write-only or read-write mode if it is
|
||||||
|
* not open for writing at the same time
|
||||||
|
* 3. a file that is only local and has not been uploaded yet cannot be read
|
||||||
|
* from
|
||||||
|
* 4. a file that has opened in any way will not be updated to its latest
|
||||||
|
* remote revision until all its opened handles are closed
|
||||||
|
*
|
||||||
|
* Point 2 is enforced by a lookup in the writefiles string vector. If the
|
||||||
|
* path is in there then it was either just created locally or opened with
|
||||||
|
* write-only or read-write. In both cases it must not be opened for
|
||||||
|
* writing again.
|
||||||
|
*
|
||||||
|
* Point 3 is enforced by the lookup in the hashtable failing.
|
||||||
|
*
|
||||||
|
* Point 4 is enforced by checking if the current path is in the writefiles or
|
||||||
|
* readonlyfiles string vector and if yes, no updating will be done.
|
||||||
|
*/
|
||||||
int mediafirefs_open(const char *path, struct fuse_file_info *file_info)
|
int mediafirefs_open(const char *path, struct fuse_file_info *file_info)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
bool is_open;
|
||||||
struct mediafirefs_openfile *openfile;
|
struct mediafirefs_openfile *openfile;
|
||||||
struct mediafirefs_context_private *ctx;
|
struct mediafirefs_context_private *ctx;
|
||||||
|
|
||||||
ctx = fuse_get_context()->private_data;
|
ctx = fuse_get_context()->private_data;
|
||||||
|
|
||||||
if ((file_info->flags & O_ACCMODE) != O_RDONLY) {
|
/* if file is not opened read-only, check if it was already opened in a
|
||||||
fprintf(stderr, "can only open read-only\n");
|
* not read-only mode and abort if yes */
|
||||||
|
if ((file_info->flags & O_ACCMODE) != O_RDONLY
|
||||||
|
&& stringv_mem(ctx->sv_writefiles, path)) {
|
||||||
|
fprintf(stderr, "file %s was already opened for writing\n", path);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = folder_tree_open_file(ctx->tree, ctx->conn, path);
|
is_open = false;
|
||||||
|
// check if the file was already opened
|
||||||
|
// check read-only files first
|
||||||
|
if (stringv_mem(ctx->sv_readonlyfiles, path)) {
|
||||||
|
is_open = true;
|
||||||
|
}
|
||||||
|
// check writable files only if the file was
|
||||||
|
// - not yet found in the read-only files
|
||||||
|
// - the file is opened in read-only mode (because otherwise the
|
||||||
|
// writable files were already searched above without failing)
|
||||||
|
if (!is_open && (file_info->flags & O_ACCMODE) == O_RDONLY
|
||||||
|
&& stringv_mem(ctx->sv_writefiles, path)) {
|
||||||
|
is_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = folder_tree_open_file(ctx->tree, ctx->conn, path, file_info->flags,
|
||||||
|
!is_open);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "folder_tree_file_open unsuccessful\n");
|
fprintf(stderr, "folder_tree_file_open unsuccessful\n");
|
||||||
return fd;
|
return fd;
|
||||||
@@ -329,8 +362,19 @@ int mediafirefs_open(const char *path, struct fuse_file_info *file_info)
|
|||||||
|
|
||||||
openfile = malloc(sizeof(struct mediafirefs_openfile));
|
openfile = malloc(sizeof(struct mediafirefs_openfile));
|
||||||
openfile->fd = fd;
|
openfile->fd = fd;
|
||||||
openfile->is_readonly = true;
|
openfile->is_local = false;
|
||||||
openfile->remote_path = NULL;
|
openfile->path = strdup(path);
|
||||||
|
|
||||||
|
if ((file_info->flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
openfile->is_readonly = true;
|
||||||
|
// add to readonlyfiles
|
||||||
|
stringv_add(ctx->sv_readonlyfiles, path);
|
||||||
|
} else {
|
||||||
|
openfile->is_readonly = false;
|
||||||
|
// add to writefiles
|
||||||
|
stringv_add(ctx->sv_writefiles, path);
|
||||||
|
}
|
||||||
|
|
||||||
file_info->fh = (uint64_t) openfile;
|
file_info->fh = (uint64_t) openfile;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -359,14 +403,13 @@ int mediafirefs_create(const char *path, mode_t mode,
|
|||||||
|
|
||||||
openfile = malloc(sizeof(struct mediafirefs_openfile));
|
openfile = malloc(sizeof(struct mediafirefs_openfile));
|
||||||
openfile->fd = fd;
|
openfile->fd = fd;
|
||||||
|
openfile->is_local = true;
|
||||||
openfile->is_readonly = false;
|
openfile->is_readonly = false;
|
||||||
openfile->remote_path = strdup(path);
|
openfile->path = strdup(path);
|
||||||
file_info->fh = (uint64_t) openfile;
|
file_info->fh = (uint64_t) openfile;
|
||||||
|
|
||||||
// add to tmpfiles
|
// add to writefiles
|
||||||
ctx->num_tmpfiles++;
|
stringv_add(ctx->sv_writefiles, path);
|
||||||
ctx->tmpfiles = realloc(ctx->tmpfiles, sizeof(char *) * ctx->num_tmpfiles);
|
|
||||||
ctx->tmpfiles[ctx->num_tmpfiles - 1] = openfile->remote_path;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -411,19 +454,38 @@ int mediafirefs_release(const char *path, struct fuse_file_info *file_info)
|
|||||||
|
|
||||||
openfile = (struct mediafirefs_openfile *)file_info->fh;
|
openfile = (struct mediafirefs_openfile *)file_info->fh;
|
||||||
|
|
||||||
// if the file was opened readonly, then no new updates have to be
|
// if file was opened as readonly then it just has to be closed
|
||||||
// uploaded
|
|
||||||
if (openfile->is_readonly) {
|
if (openfile->is_readonly) {
|
||||||
|
// remove this entry from readonlyfiles
|
||||||
|
if (stringv_del(ctx->sv_readonlyfiles, openfile->path) != 0) {
|
||||||
|
fprintf(stderr, "FATAL: readonly entry %s not found\n",
|
||||||
|
openfile->path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
close(openfile->fd);
|
close(openfile->fd);
|
||||||
|
free(openfile->path);
|
||||||
free(openfile);
|
free(openfile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
// if the file is not readonly, its entry in writefiles has to be removed
|
||||||
|
if (stringv_del(ctx->sv_writefiles, openfile->path) != 0) {
|
||||||
|
fprintf(stderr, "FATAL: writefiles entry %s not found\n",
|
||||||
|
openfile->path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (stringv_mem(ctx->sv_writefiles, openfile->path) != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"FATAL: writefiles entry %s was found more than once\n",
|
||||||
|
openfile->path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
// if the file only exists locally, an initial upload has to be done
|
// if the file only exists locally, an initial upload has to be done
|
||||||
if (openfile->remote_path != NULL) {
|
if (openfile->is_local) {
|
||||||
// pass a copy because dirname and basename may modify their argument
|
// pass a copy because dirname and basename may modify their argument
|
||||||
temp1 = strdup(openfile->remote_path);
|
temp1 = strdup(openfile->path);
|
||||||
file_name = basename(temp1);
|
file_name = basename(temp1);
|
||||||
temp2 = strdup(openfile->remote_path);
|
temp2 = strdup(openfile->path);
|
||||||
dir_name = dirname(temp2);
|
dir_name = dirname(temp2);
|
||||||
|
|
||||||
fh = fdopen(openfile->fd, "r");
|
fh = fdopen(openfile->fd, "r");
|
||||||
@@ -438,7 +500,7 @@ int mediafirefs_release(const char *path, struct fuse_file_info *file_info)
|
|||||||
fclose(fh);
|
fclose(fh);
|
||||||
free(temp1);
|
free(temp1);
|
||||||
free(temp2);
|
free(temp2);
|
||||||
free(openfile->remote_path);
|
free(openfile->path);
|
||||||
free(openfile);
|
free(openfile);
|
||||||
|
|
||||||
if (retval != 0 || upload_key == NULL) {
|
if (retval != 0 || upload_key == NULL) {
|
||||||
@@ -462,11 +524,6 @@ int mediafirefs_release(const char *path, struct fuse_file_info *file_info)
|
|||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove from tmpfiles
|
|
||||||
ctx->num_tmpfiles--;
|
|
||||||
ctx->tmpfiles = realloc(ctx->tmpfiles,
|
|
||||||
sizeof(char *) * ctx->num_tmpfiles);
|
|
||||||
|
|
||||||
free(upload_key);
|
free(upload_key);
|
||||||
|
|
||||||
folder_tree_update(ctx->tree, ctx->conn, true);
|
folder_tree_update(ctx->tree, ctx->conn, true);
|
||||||
@@ -475,9 +532,18 @@ int mediafirefs_release(const char *path, struct fuse_file_info *file_info)
|
|||||||
// the file was not opened readonly and also existed on the remote
|
// the file was not opened readonly and also existed on the remote
|
||||||
// thus, we have to check whether any changes were made and if yes, upload
|
// thus, we have to check whether any changes were made and if yes, upload
|
||||||
// a patch
|
// a patch
|
||||||
// FIXME: not implemented yet
|
|
||||||
close(openfile->fd);
|
close(openfile->fd);
|
||||||
|
|
||||||
|
retval = folder_tree_upload_patch(ctx->tree, ctx->conn, openfile->path);
|
||||||
|
free(openfile->path);
|
||||||
free(openfile);
|
free(openfile);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "folder_tree_upload_patch failed\n");
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
folder_tree_update(ctx->tree, ctx->conn, true);
|
folder_tree_update(ctx->tree, ctx->conn, true);
|
||||||
return -ENOSYS;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "../mfapi/mfconn.h"
|
#include "../mfapi/mfconn.h"
|
||||||
#include "hashtbl.h"
|
#include "hashtbl.h"
|
||||||
|
#include "../utils/stringv.h"
|
||||||
|
|
||||||
struct mediafirefs_context_private {
|
struct mediafirefs_context_private {
|
||||||
mfconn *conn;
|
mfconn *conn;
|
||||||
@@ -31,12 +32,14 @@ struct mediafirefs_context_private {
|
|||||||
char *configfile;
|
char *configfile;
|
||||||
char *dircache;
|
char *dircache;
|
||||||
char *filecache;
|
char *filecache;
|
||||||
/* stores all currently open temporary files which are to be uploaded when
|
/* stores:
|
||||||
* they are closed.
|
* - all currently open temporary files which are to be uploaded when
|
||||||
* we use a normal array because the number of open temporary files will
|
* they are closed.
|
||||||
* never be very high but is limited by the number of threads */
|
* - all files that are opened for writing
|
||||||
char **tmpfiles;
|
*/
|
||||||
size_t num_tmpfiles;
|
stringv *sv_writefiles;
|
||||||
|
/* stores all files that have been opened for reading only */
|
||||||
|
stringv *sv_readonlyfiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
int mediafirefs_getattr(const char *path, struct stat *stbuf);
|
int mediafirefs_getattr(const char *path, struct stat *stbuf);
|
||||||
|
|||||||
@@ -107,8 +107,11 @@ int mfconn_api_upload_simple(mfconn * conn, const char *folderkey,
|
|||||||
char **upload_key);
|
char **upload_key);
|
||||||
|
|
||||||
int mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
int mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
||||||
FILE * source_fh, FILE * target_fh,
|
const char *source_hash,
|
||||||
FILE * patch_fh, char **upload_key);
|
const char *target_hash,
|
||||||
|
uint64_t target_size,
|
||||||
|
const char *patch_path,
|
||||||
|
char **upload_key);
|
||||||
|
|
||||||
int mfconn_api_upload_poll_upload(mfconn * conn,
|
int mfconn_api_upload_poll_upload(mfconn * conn,
|
||||||
const char *upload_key,
|
const char *upload_key,
|
||||||
|
|||||||
@@ -26,10 +26,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <openssl/sha.h>
|
#include <curl/curl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "../../utils/http.h"
|
#include "../../utils/http.h"
|
||||||
#include "../../utils/hash.h"
|
#include "../../utils/strings.h"
|
||||||
#include "../mfconn.h"
|
#include "../mfconn.h"
|
||||||
#include "../apicalls.h" // IWYU pragma: keep
|
#include "../apicalls.h" // IWYU pragma: keep
|
||||||
|
|
||||||
@@ -37,52 +38,47 @@ static int _decode_upload_patch(mfhttp * conn, void *data);
|
|||||||
|
|
||||||
int
|
int
|
||||||
mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
||||||
FILE * source_fh, FILE * target_fh,
|
const char *source_hash, const char *target_hash,
|
||||||
FILE * patch_fh, char **upload_key)
|
uint64_t target_size,
|
||||||
|
const char *patch_path, char **upload_key)
|
||||||
{
|
{
|
||||||
const char *api_call;
|
const char *api_call;
|
||||||
int retval;
|
int retval;
|
||||||
mfhttp *http;
|
mfhttp *http;
|
||||||
uint64_t target_size;
|
|
||||||
int i;
|
int i;
|
||||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
FILE *patch_fh;
|
||||||
char *source_hash;
|
struct curl_slist *custom_headers = NULL;
|
||||||
char *target_hash;
|
char *tmpheader;
|
||||||
|
uint64_t patch_size;
|
||||||
|
struct stat file_info;
|
||||||
|
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (source_fh == NULL)
|
memset(&file_info, 0, sizeof(file_info));
|
||||||
return -1;
|
retval = stat(patch_path, &file_info);
|
||||||
|
|
||||||
if (target_fh == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
rewind(source_fh);
|
|
||||||
retval = calc_sha256(source_fh, hash, NULL);
|
|
||||||
|
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
fprintf(stderr, "failed to calculate hash\n");
|
fprintf(stderr, "stat failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
source_hash = binary2hex(hash, SHA256_DIGEST_LENGTH);
|
patch_size = file_info.st_size;
|
||||||
|
|
||||||
rewind(target_fh);
|
|
||||||
retval = calc_sha256(target_fh, hash, &target_size);
|
|
||||||
|
|
||||||
if (retval != 0) {
|
|
||||||
fprintf(stderr, "failed to calculate hash\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_hash = binary2hex(hash, SHA256_DIGEST_LENGTH);
|
|
||||||
|
|
||||||
for (i = 0; i < mfconn_get_max_num_retries(conn); i++) {
|
for (i = 0; i < mfconn_get_max_num_retries(conn); i++) {
|
||||||
if (*upload_key != NULL) {
|
if (*upload_key != NULL) {
|
||||||
free(*upload_key);
|
free(*upload_key);
|
||||||
*upload_key = NULL;
|
*upload_key = NULL;
|
||||||
}
|
}
|
||||||
|
if (custom_headers != NULL) {
|
||||||
|
curl_slist_free_all(custom_headers);
|
||||||
|
custom_headers = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_fh = fopen(patch_path, "r");
|
||||||
|
if (patch_fh == NULL) {
|
||||||
|
fprintf(stderr, "cannot open %s\n", patch_path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
api_call = mfconn_create_signed_get(conn, 0,
|
api_call = mfconn_create_signed_get(conn, 0,
|
||||||
"upload/patch.php",
|
"upload/patch.php",
|
||||||
@@ -90,19 +86,23 @@ mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
|||||||
"&source_hash=%s"
|
"&source_hash=%s"
|
||||||
"&target_hash=%s"
|
"&target_hash=%s"
|
||||||
"&target_size=%" PRIu64
|
"&target_size=%" PRIu64
|
||||||
"&quick_key=%s", source_hash,
|
"&quickkey=%s", source_hash,
|
||||||
target_hash, target_size,
|
target_hash, target_size,
|
||||||
quickkey);
|
quickkey);
|
||||||
|
|
||||||
// make sure that we are at the beginning of the file
|
custom_headers = curl_slist_append(custom_headers,
|
||||||
rewind(patch_fh);
|
"x-filename: dummy.patch");
|
||||||
|
tmpheader = strdup_printf("x-filesize: %" PRIu64, patch_size);
|
||||||
|
custom_headers = curl_slist_append(custom_headers, tmpheader);
|
||||||
|
free(tmpheader);
|
||||||
|
|
||||||
http = http_create();
|
http = http_create();
|
||||||
retval = http_post_file(http, api_call, patch_fh, NULL, target_size,
|
retval = http_post_file(http, api_call, patch_fh, &custom_headers,
|
||||||
_decode_upload_patch, upload_key);
|
patch_size, _decode_upload_patch, upload_key);
|
||||||
http_destroy(http);
|
http_destroy(http);
|
||||||
mfconn_update_secret_key(conn);
|
mfconn_update_secret_key(conn);
|
||||||
|
|
||||||
|
fclose(patch_fh);
|
||||||
free((void *)api_call);
|
free((void *)api_call);
|
||||||
|
|
||||||
if (retval != 127 && retval != 28)
|
if (retval != 127 && retval != 28)
|
||||||
@@ -122,9 +122,6 @@ mfconn_api_upload_patch(mfconn * conn, const char *quickkey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(source_hash);
|
|
||||||
free(target_hash);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <openssl/sha.h>
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include "../../utils/http.h"
|
#include "../../utils/http.h"
|
||||||
#include "../../utils/hash.h"
|
|
||||||
#include "../../utils/strings.h"
|
#include "../../utils/strings.h"
|
||||||
#include "../mfconn.h"
|
#include "../mfconn.h"
|
||||||
#include "../apicalls.h" // IWYU pragma: keep
|
#include "../apicalls.h" // IWYU pragma: keep
|
||||||
@@ -44,8 +42,7 @@ mfconn_api_upload_simple(mfconn * conn, const char *folderkey,
|
|||||||
const char *api_call;
|
const char *api_call;
|
||||||
int retval;
|
int retval;
|
||||||
mfhttp *http;
|
mfhttp *http;
|
||||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
long l_file_size;
|
||||||
char *file_hash;
|
|
||||||
uint64_t file_size;
|
uint64_t file_size;
|
||||||
int i;
|
int i;
|
||||||
struct curl_slist *custom_headers = NULL;
|
struct curl_slist *custom_headers = NULL;
|
||||||
@@ -57,18 +54,21 @@ mfconn_api_upload_simple(mfconn * conn, const char *folderkey,
|
|||||||
if (fh == NULL)
|
if (fh == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// make sure that we are at the beginning of the file
|
retval = fseek(fh, 0, SEEK_END);
|
||||||
rewind(fh);
|
|
||||||
|
|
||||||
// calculate hash
|
|
||||||
retval = calc_sha256(fh, hash, &file_size);
|
|
||||||
|
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
fprintf(stderr, "failed to calculate hash\n");
|
fprintf(stderr, "fseek failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_hash = binary2hex(hash, SHA256_DIGEST_LENGTH);
|
l_file_size = ftell(fh);
|
||||||
|
if (l_file_size == -1) {
|
||||||
|
fprintf(stderr, "ftell failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file_size = l_file_size;
|
||||||
|
|
||||||
|
// make sure that we are at the beginning of the file
|
||||||
|
rewind(fh);
|
||||||
|
|
||||||
for (i = 0; i < mfconn_get_max_num_retries(conn); i++) {
|
for (i = 0; i < mfconn_get_max_num_retries(conn); i++) {
|
||||||
if (*upload_key != NULL) {
|
if (*upload_key != NULL) {
|
||||||
@@ -102,9 +102,6 @@ mfconn_api_upload_simple(mfconn * conn, const char *folderkey,
|
|||||||
tmpheader = strdup_printf("x-filesize: %" PRIu64, file_size);
|
tmpheader = strdup_printf("x-filesize: %" PRIu64, file_size);
|
||||||
custom_headers = curl_slist_append(custom_headers, tmpheader);
|
custom_headers = curl_slist_append(custom_headers, tmpheader);
|
||||||
free(tmpheader);
|
free(tmpheader);
|
||||||
tmpheader = strdup_printf("x-filehash: %s", file_hash);
|
|
||||||
custom_headers = curl_slist_append(custom_headers, tmpheader);
|
|
||||||
free(tmpheader);
|
|
||||||
|
|
||||||
http = http_create();
|
http = http_create();
|
||||||
retval = http_post_file(http, api_call, fh, &custom_headers, file_size,
|
retval = http_post_file(http, api_call, fh, &custom_headers, file_size,
|
||||||
@@ -135,8 +132,6 @@ mfconn_api_upload_simple(mfconn * conn, const char *folderkey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(file_hash);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
47
utils/hash.c
47
utils/hash.c
@@ -51,30 +51,33 @@ static unsigned char base36_decoding_table[] = {
|
|||||||
/*
|
/*
|
||||||
* table to convert from a byte into the two hexadecimal digits representing
|
* table to convert from a byte into the two hexadecimal digits representing
|
||||||
* it
|
* it
|
||||||
|
*
|
||||||
|
* the hex chars have to be lower case until server-side is fixed to accept
|
||||||
|
* both cases
|
||||||
*/
|
*/
|
||||||
static char base16_encoding_table[][2] = {
|
static char base16_encoding_table[][2] = {
|
||||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
|
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b",
|
||||||
"0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
|
"0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", "16", "17",
|
||||||
"18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
|
"18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23",
|
||||||
"24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
|
"24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
|
||||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
|
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b",
|
||||||
"3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
|
"3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", "46", "47",
|
||||||
"48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
|
"48", "49", "4a", "4b", "4c", "4d", "4e", "4f", "50", "51", "52", "53",
|
||||||
"54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
|
"54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
|
||||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
|
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b",
|
||||||
"6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
|
"6c", "6d", "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77",
|
||||||
"78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
|
"78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83",
|
||||||
"84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
|
"84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
|
||||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
|
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b",
|
||||||
"9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
"9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
|
||||||
"A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
|
"a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3",
|
||||||
"B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
|
"b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
|
||||||
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
|
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb",
|
||||||
"CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
"cc", "cd", "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
|
||||||
"D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
|
"d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1", "e2", "e3",
|
||||||
"E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
|
"e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
|
||||||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
|
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb",
|
||||||
"FC", "FD", "FE", "FF"
|
"fc", "fd", "fe", "ff"
|
||||||
};
|
};
|
||||||
|
|
||||||
int calc_md5(FILE * file, unsigned char *hash)
|
int calc_md5(FILE * file, unsigned char *hash)
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ http_post_file(mfhttp * conn, const char *url, FILE * fh,
|
|||||||
|
|
||||||
if (custom_headers == NULL) {
|
if (custom_headers == NULL) {
|
||||||
custom_headers = &fallback_headers;
|
custom_headers = &fallback_headers;
|
||||||
|
*custom_headers = NULL;
|
||||||
}
|
}
|
||||||
// when using POST, curl implicitly sets
|
// when using POST, curl implicitly sets
|
||||||
// Content-Type: application/x-www-form-urlencoded
|
// Content-Type: application/x-www-form-urlencoded
|
||||||
|
|||||||
126
utils/strings.c
126
utils/strings.c
@@ -59,132 +59,6 @@ char *strdup_printf(char *fmt, ...)
|
|||||||
return ret_str;
|
return ret_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strdup_join(char *string1, char *string2)
|
|
||||||
{
|
|
||||||
char *new_string;
|
|
||||||
size_t string1_len;
|
|
||||||
size_t string2_len;
|
|
||||||
|
|
||||||
if (string1 == NULL || string2 == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
string1_len = strlen(string1);
|
|
||||||
string2_len = strlen(string2);
|
|
||||||
|
|
||||||
new_string = (char *)malloc(string1_len + string2_len + 1);
|
|
||||||
|
|
||||||
strncpy(new_string, string1, string1_len);
|
|
||||||
strncat(new_string, string2, string2_len);
|
|
||||||
|
|
||||||
new_string[string1_len + string2_len] = '\0';
|
|
||||||
|
|
||||||
return new_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *strdup_subst(char *string, char *token, char *subst,
|
|
||||||
unsigned int max)
|
|
||||||
{
|
|
||||||
size_t string_len = 0;
|
|
||||||
size_t subst_len = 0;
|
|
||||||
size_t token_len = 0;
|
|
||||||
size_t total_len = 0;
|
|
||||||
size_t copy_len = 0;
|
|
||||||
size_t token_count;
|
|
||||||
char *str_new = NULL;
|
|
||||||
char **vectors;
|
|
||||||
char **rewind;
|
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (token == NULL || subst == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
string_len = strlen(string);
|
|
||||||
token_len = strlen(token);
|
|
||||||
|
|
||||||
// return on conditions that we could never handle.
|
|
||||||
if (token_len > string_len)
|
|
||||||
return NULL;
|
|
||||||
if (token[0] == '\0')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
vectors = stringv_find(string, token, max);
|
|
||||||
if (vectors == NULL)
|
|
||||||
return NULL;
|
|
||||||
rewind = vectors;
|
|
||||||
|
|
||||||
// count the number of tokens found in the string
|
|
||||||
token_count = stringv_len(vectors);
|
|
||||||
|
|
||||||
if (token_count > max)
|
|
||||||
token_count = max;
|
|
||||||
|
|
||||||
// start with the original string size;
|
|
||||||
total_len = string_len;
|
|
||||||
|
|
||||||
// subtract the total number of token chars to be removed
|
|
||||||
total_len -= (token_len * token_count);
|
|
||||||
|
|
||||||
// add back the total number of subst chars to be inserted
|
|
||||||
total_len += (subst_len * token_count);
|
|
||||||
|
|
||||||
str_new = (char *)malloc((total_len + 1) * sizeof(char));
|
|
||||||
str_new[0] = '\0';
|
|
||||||
|
|
||||||
while (*vectors != NULL) {
|
|
||||||
// calculate distance to the next token from current position
|
|
||||||
copy_len = *vectors - string;
|
|
||||||
|
|
||||||
if (copy_len > 0) {
|
|
||||||
strncat(str_new, string, copy_len);
|
|
||||||
string += copy_len;
|
|
||||||
|
|
||||||
// when total_len == 0 the process is complete
|
|
||||||
total_len -= copy_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncat(str_new, token, token_len);
|
|
||||||
|
|
||||||
// when total_len == 0 the process is complete
|
|
||||||
total_len -= token_len;
|
|
||||||
|
|
||||||
vectors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// might have one more copy operation to complete
|
|
||||||
if (total_len > 0) {
|
|
||||||
strcat(str_new, string);
|
|
||||||
}
|
|
||||||
// todo: can't free vectors directly cuz it was incremented
|
|
||||||
free(rewind);
|
|
||||||
|
|
||||||
return str_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void string_chomp(char *string)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char *pos;
|
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
len = strlen(string);
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pos = &string[len - 1];
|
|
||||||
|
|
||||||
while (isspace((int)*pos) != 0) {
|
|
||||||
*pos = '\0';
|
|
||||||
pos--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *string_line_from_stdin(bool hide)
|
char *string_line_from_stdin(bool hide)
|
||||||
{
|
{
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
|||||||
@@ -24,13 +24,6 @@
|
|||||||
|
|
||||||
char *strdup_printf(char *fmt, ...);
|
char *strdup_printf(char *fmt, ...);
|
||||||
|
|
||||||
char *strdup_join(char *string1, char *string2);
|
|
||||||
|
|
||||||
char *strdup_subst(char *string, char *str_old, char *str_new,
|
|
||||||
unsigned int max);
|
|
||||||
|
|
||||||
void string_chomp(char *string);
|
|
||||||
|
|
||||||
char *string_line_from_stdin(bool hide);
|
char *string_line_from_stdin(bool hide);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
200
utils/stringv.c
200
utils/stringv.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
* Copyright (C) 2014 Johannes Schauer <j.schauer@email.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License version 2, as published by
|
* under the terms of the GNU General Public License version 2, as published by
|
||||||
@@ -18,166 +18,90 @@
|
|||||||
|
|
||||||
#define _POSIX_C_SOURCE 200809L // for strdup
|
#define _POSIX_C_SOURCE 200809L // for strdup
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "stringv.h"
|
#include "stringv.h"
|
||||||
|
|
||||||
size_t stringv_len(char **array)
|
struct stringv {
|
||||||
|
size_t len;
|
||||||
|
char **array;
|
||||||
|
};
|
||||||
|
|
||||||
|
stringv *stringv_alloc(void)
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
stringv *sv;
|
||||||
char **pos;
|
|
||||||
|
|
||||||
if (array == NULL)
|
sv = (stringv *) calloc(1, sizeof(stringv));
|
||||||
return 0;
|
sv->len = 0;
|
||||||
|
sv->array = NULL;
|
||||||
pos = array;
|
return sv;
|
||||||
while (pos[0] != NULL) {
|
|
||||||
pos++;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stringv_free(char **array, int b_free)
|
void stringv_free(stringv * sv)
|
||||||
{
|
{
|
||||||
char **pos;
|
size_t i;
|
||||||
|
|
||||||
if (array == NULL)
|
for (i = 0; i < sv->len; i++) {
|
||||||
return;
|
free(sv->array[i]);
|
||||||
|
|
||||||
pos = array;
|
|
||||||
|
|
||||||
while ((*pos) != NULL) {
|
|
||||||
free(*pos);
|
|
||||||
++pos;
|
|
||||||
}
|
}
|
||||||
|
free(sv->array);
|
||||||
if (b_free == STRINGV_FREE_ALL)
|
free(sv);
|
||||||
free(array);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char **stringv_copy(char **array)
|
bool stringv_mem(stringv * sv, const char *e)
|
||||||
{
|
{
|
||||||
uint32_t array_len;
|
size_t i;
|
||||||
char **array_pos;
|
|
||||||
|
|
||||||
char **dup_array;
|
for (i = 0; i < sv->len; i++) {
|
||||||
char **dup_pos;
|
if (strcmp(sv->array[i], e) == 0)
|
||||||
|
return true;
|
||||||
if (array == NULL)
|
|
||||||
return (char **)NULL;
|
|
||||||
|
|
||||||
array_pos = array;
|
|
||||||
|
|
||||||
array_len = stringv_len(array);
|
|
||||||
|
|
||||||
if (array_len > UINT32_MAX - 1)
|
|
||||||
array_len = UINT32_MAX - 1;
|
|
||||||
|
|
||||||
dup_array = (char **)calloc(array_len, sizeof(char *));
|
|
||||||
dup_pos = dup_array;
|
|
||||||
|
|
||||||
while ((*array_pos) != NULL) {
|
|
||||||
*dup_pos = strdup((const char *)*array_pos);
|
|
||||||
|
|
||||||
array_pos++;
|
|
||||||
dup_pos++;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return dup_array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char **stringv_find(char *string, char *token, int limit)
|
int stringv_add(stringv * sv, const char *e)
|
||||||
{
|
{
|
||||||
char **results = NULL;
|
sv->len++;
|
||||||
char *pos = NULL;
|
sv->array = realloc(sv->array, sizeof(char *) * sv->len);
|
||||||
int count = 0;
|
if (sv->array == NULL) {
|
||||||
|
fprintf(stderr, "failed to realloc\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sv->array[sv->len - 1] = strdup(e);
|
||||||
|
if (sv->array[sv->len - 1] == NULL) {
|
||||||
|
fprintf(stderr, "failed to strdup\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (string == NULL)
|
int stringv_del(stringv * sv, const char *e)
|
||||||
return (char **)NULL;
|
{
|
||||||
if (token == NULL)
|
size_t i;
|
||||||
return (char **)NULL;
|
|
||||||
if (limit == 0)
|
|
||||||
return (char **)NULL;
|
|
||||||
|
|
||||||
pos = string;
|
for (i = 0; i < sv->len; i++) {
|
||||||
|
if (strcmp(sv->array[i], e) == 0) {
|
||||||
if (strlen(token) > strlen(string))
|
free(sv->array[i]);
|
||||||
return (char **)NULL;
|
|
||||||
|
|
||||||
while (count != limit) {
|
|
||||||
pos = strstr(pos, token);
|
|
||||||
if (pos == NULL)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
count++;
|
|
||||||
results =
|
|
||||||
(char **)realloc((void *)results, sizeof(char *) * count + 1);
|
|
||||||
|
|
||||||
results[count - 1] = pos;
|
|
||||||
}
|
}
|
||||||
|
if (i == sv->len) {
|
||||||
if (count == 0)
|
fprintf(stderr, "not found\n");
|
||||||
return (char **)NULL;
|
return -1;
|
||||||
|
|
||||||
results[count] = (char *)NULL;
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
char **stringv_split(char *string, char *token, int limit)
|
|
||||||
{
|
|
||||||
char **results = NULL;
|
|
||||||
char *curr = NULL;
|
|
||||||
char *next = NULL;
|
|
||||||
int count = 0;
|
|
||||||
unsigned int len;
|
|
||||||
size_t copy_len = 0;
|
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
return (char **)NULL;
|
|
||||||
if (token == NULL)
|
|
||||||
return (char **)NULL;
|
|
||||||
if (limit == 0)
|
|
||||||
return (char **)NULL;
|
|
||||||
|
|
||||||
len = strlen(string);
|
|
||||||
if (strlen(token) > len)
|
|
||||||
return (char **)NULL;
|
|
||||||
|
|
||||||
curr = string;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// alloc space for current item plus NULL vector terminator
|
|
||||||
results = (char **)realloc(results, sizeof(char *) * (count + 2));
|
|
||||||
|
|
||||||
// find the next occurrence
|
|
||||||
next = strstr(curr, token);
|
|
||||||
|
|
||||||
if (next != NULL)
|
|
||||||
copy_len = next - curr;
|
|
||||||
else
|
|
||||||
copy_len = strlen(curr);
|
|
||||||
|
|
||||||
results[count] = (char *)calloc(copy_len + 1, sizeof(char));
|
|
||||||
memcpy(results[count], curr, copy_len);
|
|
||||||
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (next == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
curr = next;
|
|
||||||
curr++;
|
|
||||||
}
|
}
|
||||||
while (count < limit);
|
// shift the remaining entries one place to the left
|
||||||
|
memmove(sv->array + i, sv->array + i + 1,
|
||||||
results[count] = NULL;
|
sizeof(char *) * (sv->len - i - 1));
|
||||||
|
sv->len--;
|
||||||
return results;
|
if (sv->len == 0) {
|
||||||
|
free(sv->array);
|
||||||
|
sv->array = NULL;
|
||||||
|
} else {
|
||||||
|
sv->array = realloc(sv->array, sizeof(char *) * sv->len);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
* Copyright (C) 2014 Johannes Schauer <j.schauer@email.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License version 2, as published by
|
* under the terms of the GNU General Public License version 2, as published by
|
||||||
@@ -19,23 +19,18 @@
|
|||||||
#ifndef _STRING_V_H_
|
#ifndef _STRING_V_H_
|
||||||
#define _STRING_V_H_
|
#define _STRING_V_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define STRINGV_FREE_ALL 1
|
typedef struct stringv stringv;
|
||||||
|
|
||||||
// count number of strings in a NULL in a string vector
|
stringv *stringv_alloc(void);
|
||||||
size_t stringv_len(char **array);
|
|
||||||
|
|
||||||
// free all of the strings in a vector and optionally the vector pointer
|
void stringv_free(stringv * sv);
|
||||||
void stringv_free(char **array, int b_free);
|
|
||||||
|
|
||||||
// deep copy of string vector. returns a new vector pointer
|
bool stringv_mem(stringv * sv, const char *e);
|
||||||
char **stringv_copy(char **array);
|
|
||||||
|
|
||||||
// returns a NULL terminated vector array to every location 'token' is found
|
int stringv_add(stringv * sv, const char *e);
|
||||||
char **stringv_find(char *string, char *token, int limit);
|
|
||||||
|
|
||||||
// returns a NULL terminated vector array of items delimited by 'token'
|
int stringv_del(stringv * sv, const char *e);
|
||||||
char **stringv_split(char *string, char *token, int limit);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user