1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-04-27 19:15:07 +00:00
seafile-server/fuse/seaf-fuse.c
feiniks 6af96fe1d2
Log format (#704)
* Format c log

* Format go log

* Add SEAFILE_LOG_TO_STDOUT env

* Modify parameters name

* Set stdout to output

* Add app name and print error log

* Disable daemon mode when SEAFILE_LOG_TO_STDOUT is true

---------

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-10-24 10:46:41 +08:00

344 lines
9.1 KiB
C

#include "common.h"
#include <unistd.h>
#include <getopt.h>
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <fuse_opt.h>
#include <glib.h>
#include <glib-object.h>
#include <seaf-db.h>
#include "log.h"
#include "utils.h"
#include "seaf-fuse.h"
SeafileSession *seaf = NULL;
static char *parse_repo_id (const char *repo_id_name)
{
if (strlen(repo_id_name) < 36)
return NULL;
return g_strndup(repo_id_name, 36);
}
/*
* Path format can be:
* 1. / --> list all users
* 2. /user --> list libraries owned by user
* 3. /user/repo-id_name --> list root of the library
* 4. /user/repo-id_name/repo_path --> list library content
*/
int parse_fuse_path (const char *path,
int *n_parts, char **user, char **repo_id, char **repo_path)
{
char **tokens;
int n;
int ret = 0;
*user = NULL;
*repo_id = NULL;
*repo_path = NULL;
if (*path == '/')
++path;
tokens = g_strsplit (path, "/", 3);
n = g_strv_length (tokens);
*n_parts = n;
switch (n) {
case 0:
break;
case 1:
*user = g_strdup(tokens[0]);
break;
case 2:
*repo_id = parse_repo_id(tokens[1]);
if (*repo_id == NULL) {
ret = -1;
break;
}
*user = g_strdup(tokens[0]);
*repo_path = g_strdup("/");
break;
case 3:
*repo_id = parse_repo_id(tokens[1]);
if (*repo_id == NULL) {
ret = -1;
break;
}
*user = g_strdup(tokens[0]);
*repo_path = g_strdup(tokens[2]);
break;
}
g_strfreev (tokens);
return ret;
}
static int seaf_fuse_getattr(const char *path, struct stat *stbuf)
{
memset(stbuf, 0, sizeof(struct stat));
return do_getattr(seaf, path, stbuf);
}
static int seaf_fuse_readdir(const char *path, void *buf,
fuse_fill_dir_t filler, off_t offset,
struct fuse_file_info *info)
{
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
return do_readdir(seaf, path, buf, filler, offset, info);
}
static int seaf_fuse_open(const char *path, struct fuse_file_info *info)
{
int n_parts;
char *user, *repo_id, *repo_path;
SeafRepo *repo = NULL;
SeafBranch *branch = NULL;
SeafCommit *commit = NULL;
guint32 mode = 0;
int ret = 0;
/* Now we only support read-only mode */
if ((info->flags & 3) != O_RDONLY)
return -EACCES;
if (parse_fuse_path (path, &n_parts, &user, &repo_id, &repo_path) < 0) {
seaf_warning ("Invalid input path %s.\n", path);
return -ENOENT;
}
if (n_parts != 2 && n_parts != 3) {
seaf_warning ("Invalid input path for open: %s.\n", path);
ret = -EACCES;
goto out;
}
repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id);
if (!repo) {
seaf_warning ("Failed to get repo %s.\n", repo_id);
ret = -ENOENT;
goto out;
}
branch = repo->head;
commit = seaf_commit_manager_get_commit(seaf->commit_mgr,
repo->id,
repo->version,
branch->commit_id);
if (!commit) {
seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, branch->commit_id);
ret = -ENOENT;
goto out;
}
char *id = seaf_fs_manager_path_to_obj_id(seaf->fs_mgr,
repo->store_id, repo->version,
commit->root_id,
repo_path, &mode, NULL);
if (!id) {
seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id);
ret = -ENOENT;
goto out;
}
g_free (id);
if (!S_ISREG(mode))
return -EACCES;
out:
g_free (user);
g_free (repo_id);
g_free (repo_path);
seaf_repo_unref (repo);
seaf_commit_unref (commit);
return ret;
}
static int seaf_fuse_read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *info)
{
int n_parts;
char *user, *repo_id, *repo_path;
SeafRepo *repo = NULL;
SeafBranch *branch = NULL;
SeafCommit *commit = NULL;
Seafile *file = NULL;
char *file_id = NULL;
int ret = 0;
/* Now we only support read-only mode */
if ((info->flags & 3) != O_RDONLY)
return -EACCES;
if (parse_fuse_path (path, &n_parts, &user, &repo_id, &repo_path) < 0) {
seaf_warning ("Invalid input path %s.\n", path);
return -ENOENT;
}
if (n_parts != 2 && n_parts != 3) {
seaf_warning ("Invalid input path for open: %s.\n", path);
ret = -EACCES;
goto out;
}
repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id);
if (!repo) {
seaf_warning ("Failed to get repo %s.\n", repo_id);
ret = -ENOENT;
goto out;
}
branch = repo->head;
commit = seaf_commit_manager_get_commit(seaf->commit_mgr,
repo->id,
repo->version,
branch->commit_id);
if (!commit) {
seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, branch->commit_id);
ret = -ENOENT;
goto out;
}
file_id = seaf_fs_manager_get_seafile_id_by_path(seaf->fs_mgr,
repo->store_id, repo->version,
commit->root_id,
repo_path, NULL);
if (!file_id) {
seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id);
ret = -ENOENT;
goto out;
}
file = seaf_fs_manager_get_seafile(seaf->fs_mgr,
repo->store_id, repo->version, file_id);
if (!file) {
ret = -ENOENT;
goto out;
}
ret = read_file(seaf, repo->store_id, repo->version,
file, buf, size, offset, info);
seafile_unref (file);
out:
g_free (user);
g_free (repo_id);
g_free (repo_path);
g_free (file_id);
seaf_repo_unref (repo);
seaf_commit_unref (commit);
return ret;
}
struct options {
char *central_config_dir;
char *config_dir;
char *seafile_dir;
char *log_file;
} options;
#define SEAF_FUSE_OPT_KEY(t, p, v) { t, offsetof(struct options, p), v }
enum {
KEY_VERSION,
KEY_HELP,
};
static struct fuse_opt seaf_fuse_opts[] = {
SEAF_FUSE_OPT_KEY("-c %s", config_dir, 0),
SEAF_FUSE_OPT_KEY("--config %s", config_dir, 0),
SEAF_FUSE_OPT_KEY("-F %s", central_config_dir, 0),
SEAF_FUSE_OPT_KEY("--central-config-dir %s", central_config_dir, 0),
SEAF_FUSE_OPT_KEY("-d %s", seafile_dir, 0),
SEAF_FUSE_OPT_KEY("--seafdir %s", seafile_dir, 0),
SEAF_FUSE_OPT_KEY("-l %s", log_file, 0),
SEAF_FUSE_OPT_KEY("--logfile %s", log_file, 0),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_END
};
static struct fuse_operations seaf_fuse_ops = {
.getattr = seaf_fuse_getattr,
.readdir = seaf_fuse_readdir,
.open = seaf_fuse_open,
.read = seaf_fuse_read,
};
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
const char *debug_str = NULL;
char *config_dir = DEFAULT_CONFIG_DIR;
char *central_config_dir = NULL;
char *seafile_dir = NULL;
char *logfile = NULL;
char *ccnet_debug_level_str = "info";
char *seafile_debug_level_str = "debug";
int ret;
memset(&options, 0, sizeof(struct options));
if (fuse_opt_parse(&args, &options, seaf_fuse_opts, NULL) == -1) {
seaf_warning("Parse argument Failed\n");
exit(1);
}
#if !GLIB_CHECK_VERSION(2,36,0)
g_type_init();
#endif
config_dir = options.config_dir ? : DEFAULT_CONFIG_DIR;
config_dir = ccnet_expand_path (config_dir);
central_config_dir = options.central_config_dir;
if (!debug_str)
debug_str = g_getenv("SEAFILE_DEBUG");
seafile_debug_set_flags_string(debug_str);
if (!options.seafile_dir)
seafile_dir = g_build_filename(config_dir, "seafile", NULL);
else
seafile_dir = options.seafile_dir;
if (!options.log_file)
logfile = g_build_filename(seafile_dir, "seaf-fuse.log", NULL);
else
logfile = options.log_file;
if (seafile_log_init(logfile, ccnet_debug_level_str,
seafile_debug_level_str, "seaf-fuse") < 0) {
fprintf (stderr, "Failed to init log.\n");
exit(1);
}
seaf = seafile_session_new(central_config_dir, seafile_dir, config_dir);
if (!seaf) {
seaf_warning("Failed to create seafile session.\n");
exit(1);
}
if (seafile_session_init(seaf) < 0) {
seaf_warning("Failed to init seafile session.\n");
exit(1);
}
set_syslog_config (seaf->config);
ret = fuse_main(args.argc, args.argv, &seaf_fuse_ops, NULL);
fuse_opt_free_args(&args);
return ret;
}