mirror of
https://github.com/xorgy/mediafire-fuse
synced 2026-01-13 21:24:28 -08:00
rely on some properties of fuse to avoid checks and sanitizing
This commit is contained in:
@@ -567,6 +567,19 @@ bool folder_tree_path_is_root(folder_tree * tree, const char *path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool folder_tree_path_is_file(folder_tree * tree, const char *path)
|
||||||
|
{
|
||||||
|
struct h_entry *result;
|
||||||
|
|
||||||
|
result = folder_tree_lookup_path(tree, path);
|
||||||
|
|
||||||
|
if (result != NULL) {
|
||||||
|
return result->atime != 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool folder_tree_path_is_directory(folder_tree * tree, const char *path)
|
bool folder_tree_path_is_directory(folder_tree * tree, const char *path)
|
||||||
{
|
{
|
||||||
struct h_entry *result;
|
struct h_entry *result;
|
||||||
|
|||||||
@@ -61,4 +61,6 @@ const char *folder_tree_path_get_key(folder_tree * tree, const char *path);
|
|||||||
|
|
||||||
bool folder_tree_path_is_root(folder_tree * tree, const char *path);
|
bool folder_tree_path_is_root(folder_tree * tree, const char *path);
|
||||||
|
|
||||||
|
bool folder_tree_path_is_file(folder_tree * tree, const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
141
fuse/main.c
141
fuse/main.c
@@ -32,6 +32,55 @@
|
|||||||
#include "../mfapi/apicalls.h"
|
#include "../mfapi/apicalls.h"
|
||||||
#include "hashtbl.h"
|
#include "hashtbl.h"
|
||||||
|
|
||||||
|
/* what you can safely assume about requests to your filesystem
|
||||||
|
*
|
||||||
|
* from: http://sourceforge.net/p/fuse/wiki/FuseInvariants/
|
||||||
|
*
|
||||||
|
* There are a number of assumptions that one can safely make when
|
||||||
|
* implementing a filesystem using fuse. This page should be completed with a
|
||||||
|
* set of such assumptions.
|
||||||
|
*
|
||||||
|
* - All requests are absolute, i.e. all paths begin with "/" and include the
|
||||||
|
* complete path to a file or a directory. Symlinks, "." and ".." are
|
||||||
|
* already resolved.
|
||||||
|
*
|
||||||
|
* - For every request you can get except for "Getattr()", "Read()" and
|
||||||
|
* "Write()", usually for every path argument (both source and destination
|
||||||
|
* for link and rename, but only the source for symlink), you will get a
|
||||||
|
* "Getattr()" request just before the callback.
|
||||||
|
*
|
||||||
|
* For example, suppose I store file names of files in a filesystem also into a
|
||||||
|
* database. To keep data in sync, I would like, for each filesystem operation
|
||||||
|
* that succeeds, to check if the file exists on the database. I just do this in
|
||||||
|
* the "Getattr()" call, since all other calls will be preceded by a getattr.
|
||||||
|
*
|
||||||
|
* - The value of the "st_dev" attribute in the "Getattr()" call are ignored
|
||||||
|
* by fuse and an appropriate anomynous device number is inserted instead.
|
||||||
|
*
|
||||||
|
* - The arguments for every request are already verified as much as
|
||||||
|
* possible. This means that, for example "readdir()" is only called with
|
||||||
|
* an existing directory name, "Readlink()" is only called with an existing
|
||||||
|
* symlink, "Symlink()" is only called if there isn't already another
|
||||||
|
* object with the requested linkname, "read()" and "Write()" are only
|
||||||
|
* called if the file has been opened with the correct flags.
|
||||||
|
*
|
||||||
|
* - The VFS also takes care of avoiding race conditions:
|
||||||
|
*
|
||||||
|
* - while "Unlink()" is running on a specific file, it cannot be interrupted
|
||||||
|
* by a "Chmod()", "Link()" or "Open()" call from a different thread on the
|
||||||
|
* same file.
|
||||||
|
*
|
||||||
|
* - while "Rmdir()" is running, no files can be created in the directory
|
||||||
|
* that "Rmdir()" is acting on.
|
||||||
|
*
|
||||||
|
* - If a request returns invalid values (e.g. in the structure returned by
|
||||||
|
* "Getattr()" or in the link target returned by "Symlink()") or if a
|
||||||
|
* request appears to have failed (e.g. if a "Create()" request succeds but
|
||||||
|
* a subsequent "Getattr()" (that fuse calls automatically) ndicates that
|
||||||
|
* no regular file has been created), the syscall returns EIO to the
|
||||||
|
* caller.
|
||||||
|
*/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_HELP,
|
KEY_HELP,
|
||||||
KEY_VERSION,
|
KEY_VERSION,
|
||||||
@@ -92,6 +141,11 @@ static void usage(const char *progname)
|
|||||||
|
|
||||||
static int mediafirefs_getattr(const char *path, struct stat *stbuf)
|
static int mediafirefs_getattr(const char *path, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* since getattr is called before every other call (except for getattr,
|
||||||
|
* read and write) wee only call folder_tree_update in the getattr call
|
||||||
|
* and not the others
|
||||||
|
*/
|
||||||
folder_tree_update(tree, conn);
|
folder_tree_update(tree, conn);
|
||||||
return folder_tree_getattr(tree, path, stbuf);
|
return folder_tree_getattr(tree, path, stbuf);
|
||||||
}
|
}
|
||||||
@@ -103,7 +157,6 @@ static int mediafirefs_readdir(const char *path, void *buf,
|
|||||||
(void)offset;
|
(void)offset;
|
||||||
(void)info;
|
(void)info;
|
||||||
|
|
||||||
folder_tree_update(tree, conn);
|
|
||||||
return folder_tree_readdir(tree, path, buf, filldir);
|
return folder_tree_readdir(tree, path, buf, filldir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,28 +184,19 @@ static int mediafirefs_mkdir(const char *path, mode_t mode)
|
|||||||
char *basename;
|
char *basename;
|
||||||
const char *key;
|
const char *key;
|
||||||
|
|
||||||
folder_tree_update(tree, conn);
|
/* we don't need to check whether the path already existed because the
|
||||||
|
* getattr call made before this one takes care of that
|
||||||
|
*/
|
||||||
|
|
||||||
/* before calling the remote function we check locally */
|
/* before calling the remote function we check locally */
|
||||||
|
|
||||||
dirname = strdup(path);
|
dirname = strdup(path);
|
||||||
|
|
||||||
if (strcmp(dirname, "/") == 0) {
|
|
||||||
fprintf(stderr, "the root already exists\n");
|
|
||||||
return -EEXIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove possible trailing slash */
|
/* remove possible trailing slash */
|
||||||
if (dirname[strlen(dirname) - 1] == '/') {
|
if (dirname[strlen(dirname) - 1] == '/') {
|
||||||
dirname[strlen(dirname) - 1] = '\0';
|
dirname[strlen(dirname) - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the path already exists */
|
|
||||||
if (folder_tree_path_exists(tree, dirname)) {
|
|
||||||
fprintf(stderr, "the path %s already exists\n", dirname);
|
|
||||||
return -EEXIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split into dirname and basename */
|
/* split into dirname and basename */
|
||||||
|
|
||||||
basename = rindex(dirname, '/');
|
basename = rindex(dirname, '/');
|
||||||
@@ -190,34 +234,24 @@ static int mediafirefs_mkdir(const char *path, mode_t mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mediafirefs_rmdir(const char *path)
|
static int mediafirefs_rmdir(const char *path)
|
||||||
{
|
{
|
||||||
const char *key;
|
const char *key;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
folder_tree_update(tree, conn);
|
/* no need to check
|
||||||
|
* - if path is directory
|
||||||
/* check if path is directory */
|
* - if directory is empty
|
||||||
if (!folder_tree_path_is_directory(tree, path)) {
|
* - if directory is root
|
||||||
fprintf(stderr, "path is not a directory\n");
|
*
|
||||||
// FIXME: find a better errno in this case
|
* because getattr was called before and already made sure
|
||||||
return -ENOENT;
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
/* check if directory is empty */
|
|
||||||
if (folder_tree_path_get_num_children(tree, path) != 0) {
|
|
||||||
fprintf(stderr, "path is not empty\n");
|
|
||||||
return -ENOTEMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if directory is root */
|
|
||||||
if (folder_tree_path_is_root(tree, path)) {
|
|
||||||
fprintf(stderr, "cannot remove root\n");
|
|
||||||
// FIXME: find better errno in this case
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = folder_tree_path_get_key(tree, path);
|
key = folder_tree_path_get_key(tree, path);
|
||||||
|
if (key == NULL) {
|
||||||
|
fprintf(stderr, "key is NULL\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
retval = mfconn_api_folder_delete(conn, key);
|
retval = mfconn_api_folder_delete(conn, key);
|
||||||
mfconn_update_secret_key(conn);
|
mfconn_update_secret_key(conn);
|
||||||
@@ -227,26 +261,57 @@ int mediafirefs_rmdir(const char *path)
|
|||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* retrieve remote changes to not get out of sync */
|
||||||
folder_tree_update(tree, conn);
|
folder_tree_update(tree, conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mediafirefs_open(const char * path, struct fuse_file_info * file_info)
|
||||||
|
{
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
if((file_info->flags & O_ACCMODE) != O_RDONLY) {
|
||||||
|
fprintf(stderr, "can only open read-only");
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if file has already been downloaded */
|
||||||
|
|
||||||
|
/* check if downloaded version is the current one */
|
||||||
|
|
||||||
|
/* download file from remote */
|
||||||
|
|
||||||
|
/* update local file with patch */
|
||||||
|
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mediafirefs_read(const char * path, char * buf, size_t size, off_t offset, struct fuse_file_info * file_info)
|
||||||
|
{
|
||||||
|
(void)path;
|
||||||
|
(void)buf;
|
||||||
|
(void)size;
|
||||||
|
(void)offset;
|
||||||
|
(void)file_info;
|
||||||
|
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fuse_operations mediafirefs_oper = {
|
static struct fuse_operations mediafirefs_oper = {
|
||||||
.getattr = mediafirefs_getattr,
|
.getattr = mediafirefs_getattr,
|
||||||
.readdir = mediafirefs_readdir,
|
.readdir = mediafirefs_readdir,
|
||||||
.destroy = mediafirefs_destroy,
|
.destroy = mediafirefs_destroy,
|
||||||
.mkdir = mediafirefs_mkdir,
|
.mkdir = mediafirefs_mkdir,
|
||||||
.rmdir = mediafirefs_rmdir,
|
.rmdir = mediafirefs_rmdir,
|
||||||
|
.open = mediafirefs_open,
|
||||||
|
.read = mediafirefs_read,
|
||||||
/* .create = mediafirefs_create,
|
/* .create = mediafirefs_create,
|
||||||
.fsync = mediafirefs_fsync,
|
.fsync = mediafirefs_fsync,
|
||||||
.getattr = mediafirefs_getattr,
|
|
||||||
.getxattr = mediafirefs_getxattr,
|
.getxattr = mediafirefs_getxattr,
|
||||||
.init = mediafirefs_init,
|
.init = mediafirefs_init,
|
||||||
.listxattr = mediafirefs_listxattr,
|
.listxattr = mediafirefs_listxattr,
|
||||||
.open = mediafirefs_open,
|
|
||||||
.opendir = mediafirefs_opendir,
|
.opendir = mediafirefs_opendir,
|
||||||
.read = mediafirefs_read,
|
|
||||||
.releasedir = mediafirefs_releasedir,
|
.releasedir = mediafirefs_releasedir,
|
||||||
.setxattr = mediafirefs_setxattr,
|
.setxattr = mediafirefs_setxattr,
|
||||||
.statfs = mediafirefs_statfs,
|
.statfs = mediafirefs_statfs,
|
||||||
|
|||||||
Reference in New Issue
Block a user