diff --git a/Makefile.am b/Makefile.am index 572bf19a..1e29bf28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,41 +1,9 @@ -MAKE_CLIENT = +SUBDIRS = include lib common daemon app doc -if COMPILE_CLIENT - MAKE_CLIENT += daemon -endif - -if WIN32 - MAKE_CONTROLLER = -else - MAKE_CONTROLLER = controller -endif - -if COMPILE_FUSE - MAKE_FUSE = fuse -else - MAKE_FUSE = -endif - -if COMPILE_SERVER - MAKE_SERVER = server tools $(MAKE_CONTROLLER) $(MAKE_FUSE) -endif - -SUBDIRS = include lib common app python tests doc \ - $(MAKE_CLIENT) $(MAKE_SERVER) - -DIST_SUBDIRS = include lib common app python tests \ - daemon server tools controller \ - doc fuse - -INTLTOOL = \ - intltool-extract.in \ - intltool-merge.in \ - intltool-update.in +DIST_SUBDIRS = include lib common app daemon doc EXTRA_DIST = install-sh $(INTLTOOL) README.markdown scripts debian msi LICENSE.txt -DISTCHECK_CONFIGURE_FLAGS = --enable-server - ACLOCAL_AMFLAGS = -I m4 dist-hook: diff --git a/app/Makefile.am b/app/Makefile.am index 72ac41e0..89a596b6 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -1,20 +1,3 @@ -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/common \ - -I$(top_srcdir)/lib \ - @CCNET_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @MSVC_CFLAGS@ \ - -Wall - -if COMPILE_CLIENT bin_SCRIPTS = seaf-cli -endif - -# monitor_tool_SOURCES = monitor-tool.c -# monitor_tool_LDADD = @CCNET_CFLAGS@ \ -# -lsearpc \ -# @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ -lrt -luuid -lsqlite3 EXTRA_DIST = seaf-cli diff --git a/app/monitor-tool.c b/app/monitor-tool.c deleted file mode 100644 index 13c426c3..00000000 --- a/app/monitor-tool.c +++ /dev/null @@ -1,227 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -struct cmd { - char *name; - int (*handler) (int argc, char **argv); -}; - -static int add_server (int, char **); -static int del_server (int, char **); -static int list_servers (int, char **); - -static struct cmd cmdtab[] = { - { "add-server", add_server }, - { "del-server", del_server }, - { "list-servers", list_servers }, - { 0 }, -}; - -CcnetClient *client; -SearpcClient *rpc_client; -SearpcUserPriv priv; - -struct cmd * -getcmd (char *name) -{ - char *p, *q; - struct cmd *c, *found; - int nmatches, longest; - - longest = 0; - nmatches = 0; - found = 0; - for (c = cmdtab; (p = c->name); c++) { - for (q = name; *q == *p++; q++) - if (*q == 0) /* exact match? */ - return c; - if (!*q) { /* the name was a prefix */ - if (q - name > longest) { - longest = q - name; - nmatches = 1; - found = c; - } else if (q - name == longest) - nmatches++; - } - } - - if (nmatches > 1) - return (struct cmd *)-1; - return found; -} - - -void usage() -{ - fputs ( -"Usage: seaf-server [--version ] [-c CONF_DIR] COMMAND [ARGS]\n" -"\n" -"Available commands are:\n" -" add-server Add a chunk server\n" -" del-server Delete a chunk server\n" -" list-servers List current chunk servers\n" - ,stderr); -} - -void show_version() -{ - fputs ("seafile version: 0.1\n", stderr); -} - -SEARPC_CLIENT_DEFUN_INT__STRING(monitor_add_chunk_server) -SEARPC_CLIENT_DEFUN_INT__STRING(monitor_del_chunk_server) -SEARPC_CLIENT_DEFUN_STRING__VOID(monitor_list_chunk_servers) - -static gboolean print_version = FALSE; -static char *config_dir = NULL; -static char *central_config_dir = NULL; - -static GOptionEntry entries[] = -{ - { "version", 0, 0, G_OPTION_ARG_NONE, &print_version, "show version", NULL }, - { "config-file", 'c', 0, G_OPTION_ARG_STRING, &config_dir, - "ccnet configuration directory", NULL }, - { "server-conf-dir", 'F', 0, G_OPTION_ARG_STRING, ¢ral_config_dir, - "server configuration directory", NULL }, - { NULL }, -}; - -int main (int argc, char *argv[]) -{ - struct cmd *c; - - g_type_init (); - config_dir = DEFAULT_CONFIG_DIR; - - if (argc == 1) { - usage(); - exit(1); - } - - GError *error = NULL; - GOptionContext *context; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, "seafile"); - if (!g_option_context_parse (context, &argc, &argv, &error)) - { - g_print ("option parsing failed: %s\n", error->message); - exit (1); - } - - if (print_version) { - show_version(); - exit(1); - } - - if (argc <= 1) { - usage(); - exit(1); - } - - c = getcmd (argv[1]); - if (c == NULL) { - usage(); - exit(1); - } - - client = ccnet_client_new (); - if ( (ccnet_client_load_confdir(client, central_config_dir, config_dir)) < 0 ) { - fprintf (stderr, "Read config dir error\n"); - exit(1); - } - - if (ccnet_client_connect_daemon(client, CCNET_CLIENT_SYNC) < 0) - { - fprintf(stderr, "Connect to server fail: %s\n", strerror(errno)); - exit(1); - } - - priv.session = client; - priv.peer_id = NULL; - priv.service = "monitor"; - - rpc_client = searpc_client_new (); - rpc_client->transport = searpc_transport_send; - rpc_client->arg = &priv; - - argc -= 2; - argv += 2; - c->handler (argc, argv); - - ccnet_client_disconnect_daemon (client); - - return 0; -} - -static int add_server (int argc, char **argv) -{ - char *server_id; - GError *error = NULL; - - if (argc != 1) { - fprintf (stderr, "monitor-tool add-server \n"); - return -1; - } - - server_id = argv[0]; - - if (monitor_add_chunk_server (rpc_client, server_id, &error) < 0) { - fprintf (stderr, "Failed to add chunk server %s.\n", server_id); - return -1; - } - - printf ("Added chunk server %s.\n", server_id); - - return 0; -} - -static int del_server (int argc, char **argv) -{ - char *server_id; - GError *error = NULL; - - if (argc != 1) { - fprintf (stderr, "monitor-tool del-server \n"); - return -1; - } - - server_id = argv[0]; - - if (monitor_del_chunk_server (rpc_client, server_id, &error) < 0) { - fprintf (stderr, "Failed to delete chunk server %s.\n", server_id); - return -1; - } - - printf ("Deleted chunk server %s.\n", server_id); - - return 0; -} - -static int list_servers (int argc, char **argv) -{ - GError *error = NULL; - char *list = NULL; - - list = monitor_list_chunk_servers (rpc_client, &error); - if (!list) { - fprintf (stderr, "%s\n", error->message); - return -1; - } - - printf ("%s", list); - - return 0; -} diff --git a/configure.ac b/configure.ac index 3122a579..62ef79cb 100644 --- a/configure.ac +++ b/configure.ac @@ -59,94 +59,6 @@ else AC_MSG_RESULT(no) fi -# test which sub-component to compile - -if test "$bwin32" = true; then - compile_client=yes - compile_cli=no - compile_tools=no - compile_server=no -fi - -if test "$bmac" = true; then - compile_client=yes - compile_cli=no - compile_tools=no - compile_server=no -fi - -if test "$blinux" = true; then - compile_cli=yes - compile_tools=yes - - compile_server=no - -# AC_ARG_ENABLE(seablock, AC_HELP_STRING([--enable-seablock], -# [enable seablock]), [compile_seablock=$enableval], -# [compile_seablock="no"]) - - AC_ARG_ENABLE(riak, AC_HELP_STRING([--enable-riak], [enable riak backend]), - [compile_riak=$enableval],[compile_riak="no"]) -fi - -if test "$bwin32" != true; then - AC_ARG_ENABLE(fuse, AC_HELP_STRING([--enable-fuse], [enable fuse virtual file system]), - [compile_fuse=$enableval],[compile_fuse="yes"]) -fi - -AC_ARG_ENABLE(client, AC_HELP_STRING([--enable-client], [enable client]), - [compile_client=$enableval],[compile_client="yes"]) - -AC_ARG_ENABLE(server, AC_HELP_STRING([--enable-server], [enable server]), - [compile_server=$enableval],[compile_server="no"]) - -AC_ARG_ENABLE(python, - AC_HELP_STRING([--enable-python],[build ccnet python binding]), - [compile_python=$enableval], - [compile_python=yes]) - - -AC_ARG_ENABLE(server-pkg, AC_HELP_STRING([--enable-server-pkg], [enable static compile]), - [server_pkg=$enableval],[server_pkg="no"]) - -AM_CONDITIONAL([SERVER_ONLY], [test "${server_pkg}" = "yes"]) - - -AC_ARG_ENABLE(static-build, AC_HELP_STRING([--enable-static-build], [enable static compile]), - [static_comp=$enableval],[static_comp="no"]) - -if test x${static_comp} = xyes; then - STATIC_COMPILE=-static -fi -AC_SUBST(STATIC_COMPILE) - - -# If we're building server release package, set the run-time path -# for the executables. So that the loader will lookup shared libs -# in 'lib' dir of the release package. -# Read "man ld.so" for description of $ORIGIN. -# Refer to http://blog.linuxgamepublishing.com/2009/02/08/our-new-way-to-meet-the-lgpl/ -if test x${server_pkg} = xyes; then - compile_client=no - compile_cli=yes - compile_tools=yes - compile_server=yes - SERVER_PKG_RPATH=-Wl,-R,\'\$\$ORIGIN/../lib\' - SERVER_PKG_PY_RPATH=-Wl,-R,\'\$\$ORIGIN/../../..\' -fi -AC_SUBST(SERVER_PKG_RPATH) -AC_SUBST(SERVER_PKG_PY_RPATH) - - -AM_CONDITIONAL([COMPILE_CLI], [test "${compile_cli}" = "yes"]) -AM_CONDITIONAL([COMPILE_TOOLS], [test "${compile_tools}" = "yes"]) -AM_CONDITIONAL([COMPILE_PYTHON], [test "${compile_python}" = "yes"]) -AM_CONDITIONAL([COMPILE_CLIENT], [test "${compile_client}" = "yes"]) -AM_CONDITIONAL([COMPILE_SERVER], [test "${compile_server}" = "yes"]) -#AM_CONDITIONAL([COMPILE_SEABLOCK], [test "${compile_seablock}" = "yes"]) -AM_CONDITIONAL([COMPILE_RIAK], [test "${compile_riak}" = "yes"]) -AM_CONDITIONAL([COMPILE_FUSE], [test "${compile_fuse}" = "yes"]) - AM_CONDITIONAL([WIN32], [test "$bwin32" = "true"]) AM_CONDITIONAL([MACOS], [test "$bmac" = "true"]) AM_CONDITIONAL([LINUX], [test "$blinux" = "true"]) @@ -243,10 +155,7 @@ GLIB_REQUIRED=2.16.0 CCNET_REQUIRED=0.9.3 SEARPC_REQUIRED=1.0 JANSSON_REQUIRED=2.2.1 -ZDB_REQUIRED=2.10 -#LIBNAUTILUS_EXTENSION_REQUIRED=2.30.1 CURL_REQUIRED=7.17 -FUSE_REQUIRED=2.7.3 ZLIB_REQUIRED=1.2.0 PKG_CHECK_MODULES(SSL, [openssl]) @@ -281,56 +190,22 @@ PKG_CHECK_MODULES(ZLIB, [zlib >= $ZLIB_REQUIRED]) AC_SUBST(ZLIB_CFLAGS) AC_SUBST(ZLIB_LIBS) -if test x${compile_python} = xyes; then - AM_PATH_PYTHON([2.6]) +PKG_CHECK_MODULES(CURL, [libcurl >= $CURL_REQUIRED]) +AC_SUBST(CURL_CFLAGS) +AC_SUBST(CURL_LIBS) - if test "$bwin32" = true; then - # set pyexecdir to somewhere like /c/Python26/Lib/site-packages - pyexecdir=${PYTHON_DIR}/Lib/site-packages - pythondir=${pyexecdir} - pkgpyexecdir=${pyexecdir}/${PACKAGE} - pkgpythondir=${pythondir}/${PACKAGE} +AM_PATH_PYTHON([2.6]) - fi # end for bwin32 +if test "$bwin32" = true; then + # set pyexecdir to somewhere like /c/Python26/Lib/site-packages + pyexecdir=${PYTHON_DIR}/Lib/site-packages + pythondir=${pyexecdir} + pkgpyexecdir=${pyexecdir}/${PACKAGE} + pkgpythondir=${pythondir}/${PACKAGE} -fi +fi # end for bwin32 -# Check libzdb if compile seafile server -if test "${compile_server}" = "yes"; then - PKG_CHECK_MODULES(ZDB, [zdb >= $ZDB_REQUIRED]) - AC_SUBST(ZDB_CFLAGS) - AC_SUBST(ZDB_LIBS) -fi - -if test "${compile_fuse}" = "yes"; then - PKG_CHECK_MODULES(FUSE, [fuse >= $FUSE_REQUIRED]) - AC_SUBST(FUSE_CFLAGS) - AC_SUBST(FUSE_LIBS) -fi - -if test x${compile_server} = xyes; then - dnl check libarchive - LIBARCHIVE_REQUIRED=2.8.5 - PKG_CHECK_MODULES(LIBARCHIVE, [libarchive >= $LIBARCHIVE_REQUIRED]) - AC_SUBST(LIBARCHIVE_CFLAGS) - AC_SUBST(LIBARCHIVE_LIBS) -fi - -if test "${compile_client}" = "yes"; then - PKG_CHECK_MODULES(CURL, [libcurl >= $CURL_REQUIRED]) - AC_SUBST(CURL_CFLAGS) - AC_SUBST(CURL_LIBS) -fi - -AM_CONDITIONAL([HAVE_KEYSTORAGE_GK], [test "${compile_gnome_keyring}" = "yes"]) -if test "${compile_gnome_keyring}" = "yes"; then - PKG_CHECK_MODULES(GNOME_KEYRING, [gnome-keyring-1]) - AC_SUBST(GNOME_KEYRING_CFLAGS) - AC_SUBST(GNOME_KEYRING_LIBS) - AC_DEFINE(HAVE_KEYSTORAGE_GK, 1, [Have Gnome-Keyring support]) -fi - BPWRAPPER_REQUIRED=0.1 AC_ARG_ENABLE(breakpad, AC_HELP_STRING([--enable-breakpad], [build google breadpad support]), [compile_breakpad=$enableval],[compile_breakpad="no"]) @@ -349,37 +224,14 @@ ac_configure_args="$ac_configure_args -q" AC_CONFIG_FILES( Makefile include/Makefile - fuse/Makefile lib/Makefile lib/libseafile.pc common/Makefile common/cdc/Makefile common/index/Makefile daemon/Makefile - server/Makefile - server/gc/Makefile app/Makefile - python/Makefile - python/seafile/Makefile - python/seaserv/Makefile - controller/Makefile - tools/Makefile - tests/Makefile - tests/common-conf.sh doc/Makefile ) AC_OUTPUT - - -echo -echo "The following modules will be built:" -echo -if test x${compile_client} = xyes; then - echo "seaf-daemon" -fi -if test x${compile_server} = xyes; then - echo "seaf-server" -fi - -echo diff --git a/controller/Makefile.am b/controller/Makefile.am deleted file mode 100644 index 2000a8e1..00000000 --- a/controller/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -bin_PROGRAMS = seafile-controller - -AM_CFLAGS = \ - -DSEAFILE_SERVER \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/common \ - @CCNET_CFLAGS@ \ - @SEARPC_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @ZDB_CFLAGS@ \ - -Wall - -noinst_HEADERS = seafile-controller.h ../common/log.h - -seafile_controller_SOURCES = seafile-controller.c ../common/log.c - -seafile_controller_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/lib/libseafile_common.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ @LIBEVENT_LIBS@ \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZLIB_LIBS@ - -seafile_controller_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ diff --git a/controller/seafile-controller.c b/controller/seafile-controller.c deleted file mode 100644 index fdc18366..00000000 --- a/controller/seafile-controller.c +++ /dev/null @@ -1,1046 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "utils.h" -#include "log.h" -#include "seafile-controller.h" - -#define CHECK_PROCESS_INTERVAL 10 /* every 10 seconds */ - -SeafileController *ctl; - -static char *controller_pidfile = NULL; - -char *bin_dir = NULL; -char *installpath = NULL; -char *topdir = NULL; - -char *seafile_ld_library_path = NULL; - -static const char *short_opts = "hvftc:d:L:g:G:P:F:"; -static const struct option long_opts[] = { - { "help", no_argument, NULL, 'h', }, - { "version", no_argument, NULL, 'v', }, - { "foreground", no_argument, NULL, 'f', }, - { "test", no_argument, NULL, 't', }, - { "config-dir", required_argument, NULL, 'c', }, - { "seafile-dir", required_argument, NULL, 'd', }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "logdir", required_argument, NULL, 'L', }, - { "ccnet-debug-level", required_argument, NULL, 'g' }, - { "seafile-debug-level", required_argument, NULL, 'G' }, - { "pidfile", required_argument, NULL, 'P' }, -}; - -static void controller_exit (int code) __attribute__((noreturn)); - -static int read_seafdav_config(); - -static void -controller_exit (int code) -{ - if (code != 0) { - seaf_warning ("seaf-controller exited with code %d\n", code); - } - exit(code); -} - -// -// Utility functions Start -// - -/* returns the pid of the newly created process */ -static int -spawn_process (char *argv[]) -{ - char **ptr = argv; - GString *buf = g_string_new(argv[0]); - while (*(++ptr)) { - g_string_append_printf (buf, " %s", *ptr); - } - seaf_message ("spawn_process: %s\n", buf->str); - g_string_free (buf, TRUE); - - pid_t pid = fork(); - - if (pid == 0) { - /* child process */ - execvp (argv[0], argv); - seaf_warning ("failed to execvp %s\n", argv[0]); - exit(-1); - } else { - /* controller */ - if (pid == -1) - seaf_warning ("error when fork %s: %s\n", argv[0], strerror(errno)); - else - seaf_message ("spawned %s, pid %d\n", argv[0], pid); - - return (int)pid; - } -} - -#define PID_ERROR_ENOENT 0 -#define PID_ERROR_OTHER -1 - -/** - * @return - * - pid if successfully opened and read the file - * - PID_ERROR_ENOENT if file not exists, - * - PID_ERROR_OTHER if other errors - */ -static int -read_pid_from_pidfile (const char *pidfile) -{ - FILE *pf = g_fopen (pidfile, "r"); - if (!pf) { - if (errno == ENOENT) { - return PID_ERROR_ENOENT; - } else { - return PID_ERROR_OTHER; - } - } - - int pid = PID_ERROR_OTHER; - if (fscanf (pf, "%d", &pid) < 0) { - seaf_warning ("bad pidfile format: %s\n", pidfile); - fclose(pf); - return PID_ERROR_OTHER; - } - - fclose(pf); - - return pid; -} - -static void -try_kill_process(int which) -{ - if (which < 0 || which >= N_PID) - return; - - char *pidfile = ctl->pidfile[which]; - int pid = read_pid_from_pidfile(pidfile); - if (pid > 0) { - // if SIGTERM send success, then remove related pid file - if (kill ((pid_t)pid, SIGTERM) == 0) { - g_unlink (pidfile); - } - } -} - - -// -// Utility functions End -// - -static int -start_ccnet_server () -{ - if (!ctl->config_dir) - return -1; - - seaf_message ("starting ccnet-server ...\n"); - - - static char *logfile = NULL; - if (logfile == NULL) { - logfile = g_build_filename (ctl->logdir, "ccnet.log", NULL); - } - - char *argv[] = { - "ccnet-server", - "-F", ctl->central_config_dir, - "-c", ctl->config_dir, - "-f", logfile, - "-d", - "-P", ctl->pidfile[PID_CCNET], - NULL}; - - int pid = spawn_process (argv); - if (pid <= 0) { - seaf_warning ("Failed to spawn ccnet-server\n"); - return -1; - } - - return 0; -} - -static int -start_seaf_server () -{ - if (!ctl->config_dir || !ctl->seafile_dir) - return -1; - - seaf_message ("starting seaf-server ...\n"); - static char *logfile = NULL; - if (logfile == NULL) { - logfile = g_build_filename (ctl->logdir, "seafile.log", NULL); - } - - char *argv[] = { - "seaf-server", - "-F", ctl->central_config_dir, - "-c", ctl->config_dir, - "-d", ctl->seafile_dir, - "-l", logfile, - "-P", ctl->pidfile[PID_SERVER], - NULL}; - - int pid = spawn_process (argv); - if (pid <= 0) { - seaf_warning ("Failed to spawn seaf-server\n"); - return -1; - } - - return 0; -} - -static const char * -get_python_executable() { - static const char *python = NULL; - if (python != NULL) { - return python; - } - - static const char *try_list[] = { - "python2.7", - "python27", - "python2.6", - "python26", - }; - - int i; - for (i = 0; i < G_N_ELEMENTS(try_list); i++) { - char *executable = g_find_program_in_path (try_list[i]); - if (executable != NULL) { - python = executable; - break; - } - } - - if (python == NULL) { - python = g_getenv ("PYTHON"); - if (python == NULL) { - python = "python"; - } - } - - return python; -} - -static void -init_seafile_path () -{ - GError *error = NULL; - char *executable = g_file_read_link ("/proc/self/exe", &error); - char *tmp = NULL; - if (error != NULL) { - seaf_warning ("failed to readlink: %s\n", error->message); - return; - } - - bin_dir = g_path_get_dirname (executable); - - tmp = g_path_get_dirname (bin_dir); - installpath = g_path_get_dirname (tmp); - - topdir = g_path_get_dirname (installpath); - - g_free (executable); - g_free (tmp); -} - -static void -setup_python_path() -{ - static GList *path_list = NULL; - if (path_list != NULL) { - /* Only setup once */ - return; - } - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seahub", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seahub/thirdpart", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seahub/seahub-extra", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seahub/seahub-extra/thirdparts", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seafile/lib/python2.6/site-packages", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seafile/lib64/python2.6/site-packages", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seafile/lib/python2.7/site-packages", NULL)); - - path_list = g_list_prepend (path_list, - g_build_filename (installpath, "seafile/lib64/python2.7/site-packages", NULL)); - - path_list = g_list_reverse (path_list); - - GList *ptr; - GString *new_pypath = g_string_new (g_getenv("PYTHONPATH")); - - for (ptr = path_list; ptr != NULL; ptr = ptr->next) { - const char *path = (char *)ptr->data; - - g_string_append_c (new_pypath, ':'); - g_string_append (new_pypath, path); - } - - g_setenv ("PYTHONPATH", g_string_free (new_pypath, FALSE), TRUE); - - /* seaf_message ("PYTHONPATH is:\n\n%s\n", g_getenv ("PYTHONPATH")); */ -} - -static void -setup_env () -{ - g_setenv ("CCNET_CONF_DIR", ctl->config_dir, TRUE); - g_setenv ("SEAFILE_CONF_DIR", ctl->seafile_dir, TRUE); - g_setenv ("SEAFILE_CENTRAL_CONF_DIR", ctl->central_config_dir, TRUE); - - char *seahub_dir = g_build_filename (installpath, "seahub", NULL); - char *seafdav_conf = g_build_filename (ctl->central_config_dir, "seafdav.conf", NULL); - g_setenv ("SEAHUB_DIR", seahub_dir, TRUE); - g_setenv ("SEAFDAV_CONF", seafdav_conf, TRUE); - - setup_python_path(); -} - -static int -start_seafdav() { - static char *seafdav_log_file = NULL; - if (seafdav_log_file == NULL) - seafdav_log_file = g_build_filename (ctl->logdir, - "seafdav.log", - NULL); - - SeafDavConfig conf = ctl->seafdav_config; - char port[16]; - snprintf (port, sizeof(port), "%d", conf.port); - - char *argv[] = { - (char *)get_python_executable(), - "-m", "wsgidav.server.run_server", - "--log-file", seafdav_log_file, - "--pid", ctl->pidfile[PID_SEAFDAV], - "--port", port, - "--host", conf.host, - NULL - }; - - char *argv_fastcgi[] = { - (char *)get_python_executable(), - "-m", "wsgidav.server.run_server", - "runfcgi", - "--log-file", seafdav_log_file, - "--pid", ctl->pidfile[PID_SEAFDAV], - "--port", port, - "--host", conf.host, - NULL - }; - - char **args; - if (ctl->seafdav_config.fastcgi) { - args = argv_fastcgi; - } else { - args = argv; - } - - int pid = spawn_process (args); - - if (pid <= 0) { - seaf_warning ("Failed to spawn seafdav\n"); - return -1; - } - - return 0; -} - -static void -run_controller_loop () -{ - GMainLoop *mainloop = g_main_loop_new (NULL, FALSE); - - g_main_loop_run (mainloop); -} - -static gboolean -need_restart (int which) -{ - if (which < 0 || which >= N_PID) - return FALSE; - - int pid = read_pid_from_pidfile (ctl->pidfile[which]); - if (pid == PID_ERROR_ENOENT) { - seaf_warning ("pid file %s does not exist\n", ctl->pidfile[which]); - return TRUE; - } else if (pid == PID_ERROR_OTHER) { - seaf_warning ("failed to read pidfile %s: %s\n", ctl->pidfile[which], strerror(errno)); - return FALSE; - } else { - char buf[256]; - snprintf (buf, sizeof(buf), "/proc/%d", pid); - if (g_file_test (buf, G_FILE_TEST_IS_DIR)) { - return FALSE; - } else { - return TRUE; - } - } -} - -static gboolean -check_process (void *data) -{ - if (need_restart(PID_SERVER)) { - seaf_message ("seaf-server need restart...\n"); - start_seaf_server (); - } - - if (ctl->seafdav_config.enabled) { - if (need_restart(PID_SEAFDAV)) { - seaf_message ("seafdav need restart...\n"); - start_seafdav (); - } - } - - return TRUE; -} - -static void -start_process_monitor () -{ - ctl->check_process_timer = g_timeout_add ( - CHECK_PROCESS_INTERVAL * 1000, check_process, NULL); -} - -static void -stop_process_monitor () -{ - if (ctl->check_process_timer != 0) { - g_source_remove (ctl->check_process_timer); - ctl->check_process_timer = 0; - } -} - -static void -disconnect_clients () -{ - CcnetClient *client, *sync_client; - client = ctl->client; - sync_client = ctl->sync_client; - - if (client->connected) { - ccnet_client_disconnect_daemon (client); - } - - if (sync_client->connected) { - ccnet_client_disconnect_daemon (sync_client); - } -} - -static void rm_client_fd_from_mainloop (); -static int seaf_controller_start (); - -static void -on_ccnet_daemon_down () -{ - stop_process_monitor (); - disconnect_clients (); - rm_client_fd_from_mainloop (); - - seaf_message ("restarting ccnet server ...\n"); - - /* restart ccnet */ - if (seaf_controller_start () < 0) { - seaf_warning ("Failed to restart ccnet server.\n"); - controller_exit (1); - } -} - -static gboolean -client_io_cb (GIOChannel *source, GIOCondition condition, gpointer data) -{ - if (condition & G_IO_IN) { - if (ccnet_client_read_input (ctl->client) <= 0) { - on_ccnet_daemon_down (); - return FALSE; - } - return TRUE; - } else { - on_ccnet_daemon_down (); - return FALSE; - } -} - -static void -add_client_fd_to_mainloop () -{ - GIOChannel *channel; - - channel = g_io_channel_unix_new (ctl->client->connfd); - ctl->client_io_id = g_io_add_watch (channel, - G_IO_IN | G_IO_HUP | G_IO_ERR, - client_io_cb, NULL); -} - -static void -rm_client_fd_from_mainloop () -{ - if (ctl->client_io_id != 0) { - g_source_remove (ctl->client_io_id); - ctl->client_io_id = 0; - } -} - -static void -on_ccnet_connected () -{ - if (start_seaf_server () < 0) - controller_exit(1); - - if (ctl->seafdav_config.enabled) { - if (need_restart(PID_SEAFDAV)) { - if (start_seafdav() < 0) - controller_exit(1); - } - } else { - seaf_message ("seafdav not enabled.\n"); - } - - add_client_fd_to_mainloop (); - - start_process_monitor (); -} - -static gboolean -do_connect_ccnet () -{ - CcnetClient *client, *sync_client; - client = ctl->client; - sync_client = ctl->sync_client; - - if (!client->connected) { - if (ccnet_client_connect_daemon (client, CCNET_CLIENT_ASYNC) < 0) { - return TRUE; - } - } - - if (!sync_client->connected) { - if (ccnet_client_connect_daemon (sync_client, CCNET_CLIENT_SYNC) < 0) { - return TRUE; - } - } - - seaf_message ("ccnet daemon connected.\n"); - - on_ccnet_connected (); - - return FALSE; -} - -/* This would also stop seaf-server & other components */ -static void -stop_ccnet_server () -{ - seaf_message ("shutting down ccnet-server ...\n"); - GError *error = NULL; - ccnet_client_send_cmd (ctl->sync_client, "shutdown", &error); - - try_kill_process(PID_CCNET); - try_kill_process(PID_SERVER); - try_kill_process(PID_SEAFDAV); -} - -static void -init_pidfile_path (SeafileController *ctl) -{ - char *pid_dir = g_build_filename (topdir, "pids", NULL); - if (!g_file_test(pid_dir, G_FILE_TEST_EXISTS)) { - if (g_mkdir(pid_dir, 0777) < 0) { - seaf_warning("failed to create pid dir %s: %s", pid_dir, strerror(errno)); - controller_exit(1); - } - } - - ctl->pidfile[PID_CCNET] = g_build_filename (pid_dir, "ccnet.pid", NULL); - ctl->pidfile[PID_SERVER] = g_build_filename (pid_dir, "seaf-server.pid", NULL); - ctl->pidfile[PID_SEAFDAV] = g_build_filename (pid_dir, "seafdav.pid", NULL); -} - -static int -seaf_controller_init (SeafileController *ctl, - char *central_config_dir, - char *config_dir, - char *seafile_dir, - char *logdir) -{ - init_seafile_path (); - if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR)) { - seaf_warning ("invalid config_dir: %s\n", config_dir); - return -1; - } - - if (!g_file_test (seafile_dir, G_FILE_TEST_IS_DIR)) { - seaf_warning ("invalid seafile_dir: %s\n", seafile_dir); - return -1; - } - - ctl->client = ccnet_client_new (); - ctl->sync_client = ccnet_client_new (); - - if (ccnet_client_load_confdir (ctl->client, central_config_dir, config_dir) < 0) { - seaf_warning ("Failed to load ccnet confdir\n"); - return -1; - } - - if (ccnet_client_load_confdir (ctl->sync_client, central_config_dir, config_dir) < 0) { - seaf_warning ("Failed to load ccnet confdir\n"); - return -1; - } - - if (logdir == NULL) { - char *topdir = g_path_get_dirname(config_dir); - logdir = g_build_filename (topdir, "logs", NULL); - if (checkdir_with_mkdir(logdir) < 0) { - fprintf (stderr, "failed to create log folder \"%s\": %s\n", - logdir, strerror(errno)); - return -1; - } - g_free (topdir); - } - - ctl->central_config_dir = central_config_dir; - ctl->config_dir = config_dir; - ctl->seafile_dir = seafile_dir; - ctl->logdir = logdir; - - if (read_seafdav_config() < 0) { - return -1; - } - - init_pidfile_path (ctl); - setup_env (); - - return 0; -} - -static int -seaf_controller_start () -{ - if (start_ccnet_server () < 0) { - seaf_warning ("Failed to start ccnet server\n"); - return -1; - } - - g_timeout_add (1000 * 1, do_connect_ccnet, NULL); - - return 0; -} - -static int -write_controller_pidfile () -{ - if (!controller_pidfile) - return -1; - - pid_t pid = getpid(); - - FILE *pidfile = g_fopen(controller_pidfile, "w"); - if (!pidfile) { - seaf_warning ("Failed to fopen() pidfile %s: %s\n", - controller_pidfile, strerror(errno)); - return -1; - } - - char buf[32]; - snprintf (buf, sizeof(buf), "%d\n", pid); - if (fputs(buf, pidfile) < 0) { - seaf_warning ("Failed to write pidfile %s: %s\n", - controller_pidfile, strerror(errno)); - fclose (pidfile); - return -1; - } - - fflush (pidfile); - fclose (pidfile); - return 0; -} - -static void -remove_controller_pidfile () -{ - if (controller_pidfile) { - g_unlink (controller_pidfile); - } -} - -static void -sigint_handler (int signo) -{ - stop_ccnet_server (); - - remove_controller_pidfile(); - - signal (signo, SIG_DFL); - raise (signo); -} - -static void -sigchld_handler (int signo) -{ - waitpid (-1, NULL, WNOHANG); -} - -static void -set_signal_handlers () -{ - signal (SIGINT, sigint_handler); - signal (SIGTERM, sigint_handler); - signal (SIGCHLD, sigchld_handler); - signal (SIGPIPE, SIG_IGN); -} - -static void -usage () -{ - fprintf (stderr, "Usage: seafile-controller OPTIONS\n" - "OPTIONS:\n" - " -b, --bin-dir insert a directory in front of the PATH env\n" - " -c, --config-dir ccnet config dir\n" - " -d, --seafile-dir seafile dir\n" - ); -} - -/* seafile-controller -t is used to test whether config file is valid */ -static void -test_config (const char *central_config_dir, - const char *ccnet_dir, - const char *seafile_dir) -{ - char buf[1024]; - GError *error = NULL; - int retcode = 0; - char *child_stdout = NULL; - char *child_stderr = NULL; - - snprintf(buf, - sizeof(buf), - "ccnet-server -F \"%s\" -c \"%s\" -t", - central_config_dir, - ccnet_dir); - - g_spawn_command_line_sync (buf, - &child_stdout, /* stdout */ - &child_stderr, /* stderror */ - &retcode, - &error); - - if (error != NULL) { - fprintf (stderr, - "failed to run \"ccnet-server -t\": %s\n", - error->message); - exit (1); - } - - if (child_stdout) { - fputs (child_stdout, stdout); - } - - if (child_stderr) { - fputs (child_stderr, stdout); - } - - if (retcode != 0) { - fprintf (stderr, - "failed to run \"ccnet-server -t\"\n"); - exit (1); - } - - exit(0); -} - -static int -read_seafdav_config() -{ - int ret = 0; - char *seafdav_conf = NULL; - GKeyFile *key_file = NULL; - GError *error = NULL; - - seafdav_conf = g_build_filename(ctl->central_config_dir, "seafdav.conf", NULL); - if (!g_file_test(seafdav_conf, G_FILE_TEST_EXISTS)) { - goto out; - } - - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, seafdav_conf, - G_KEY_FILE_KEEP_COMMENTS, NULL)) { - seaf_warning("Failed to load seafdav.conf\n"); - ret = -1; - goto out; - } - - /* enabled */ - ctl->seafdav_config.enabled = g_key_file_get_boolean(key_file, "WEBDAV", "enabled", &error); - if (error != NULL) { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - seaf_message ("Error when reading WEBDAV.enabled, use default value 'false'\n"); - } - ctl->seafdav_config.enabled = FALSE; - g_clear_error (&error); - goto out; - } - - if (!ctl->seafdav_config.enabled) { - goto out; - } - - /* fastcgi */ - ctl->seafdav_config.fastcgi = g_key_file_get_boolean(key_file, "WEBDAV", "fastcgi", &error); - if (error != NULL) { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - seaf_message ("Error when reading WEBDAV.fastcgi, use default value 'false'\n"); - } - ctl->seafdav_config.fastcgi = FALSE; - g_clear_error (&error); - } - - /* host */ - char *host = g_key_file_get_string(key_file, "WEBDAV", "host", &error); - // set default host depending on fastcgi setting in order to preserve default behaviour - const char *host_default = ctl->seafdav_config.fastcgi ? "localhost" : "0.0.0.0"; - gboolean host_valid = TRUE; - if (error != NULL) { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - seaf_message ("Error when reading WEBDAV.host, use default value '%s'\n", host_default); - } - host_valid = FALSE; - g_clear_error(&error); - } else { - // no error occured while reading host, validate it - size_t len = strlen(host); - if (len == 0 || len > SEAFDAV_MAX_HOST) { - seaf_message ("Error when validating WEBDAV.host, use default value '%s'\n", host_default); - host_valid = FALSE; - } - } - - ctl->seafdav_config.host = g_strdup(host_valid ? host : host_default); - g_free(host); - - /* port */ - ctl->seafdav_config.port = g_key_file_get_integer(key_file, "WEBDAV", "port", &error); - if (error != NULL) { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { - seaf_message ("Error when reading WEBDAV.port, use deafult value 8080\n"); - } - ctl->seafdav_config.port = 8080; - g_clear_error (&error); - } - - if (ctl->seafdav_config.port <= 0 || ctl->seafdav_config.port > 65535) { - seaf_warning("Failed to load seafdav config: invalid port %d\n", ctl->seafdav_config.port); - ret = -1; - goto out; - } - -out: - if (key_file) { - g_key_file_free (key_file); - } - g_free (seafdav_conf); - - return ret; -} - -static int -init_syslog_config () -{ - char *seafile_conf = g_build_filename (ctl->central_config_dir, "seafile.conf", NULL); - GKeyFile *key_file = g_key_file_new (); - int ret = 0; - - if (!g_key_file_load_from_file (key_file, seafile_conf, - G_KEY_FILE_KEEP_COMMENTS, NULL)) { - seaf_warning("Failed to load seafile.conf.\n"); - ret = -1; - goto out; - } - - set_syslog_config (key_file); - -out: - g_key_file_free (key_file); - g_free (seafile_conf); - - return ret; -} - -int main (int argc, char **argv) -{ - if (argc <= 1) { - usage (); - exit (1); - } - - char *config_dir = DEFAULT_CONFIG_DIR; - char *central_config_dir = NULL; - char *seafile_dir = NULL; - char *logdir = NULL; - char *ccnet_debug_level_str = "info"; - char *seafile_debug_level_str = "debug"; - int daemon_mode = 1; - gboolean test_conf = FALSE; - - int c; - while ((c = getopt_long (argc, argv, short_opts, - long_opts, NULL)) != EOF) - { - switch (c) { - case 'h': - usage (); - exit(1); - break; - case 'v': - fprintf (stderr, "seafile-controller version 1.0\n"); - break; - case 't': - test_conf = TRUE; - break; - case 'c': - config_dir = optarg; - break; - case 'F': - central_config_dir = g_strdup(optarg); - break; - case 'd': - seafile_dir = g_strdup(optarg); - break; - case 'f': - daemon_mode = 0; - break; - case 'L': - logdir = g_strdup(optarg); - break; - case 'g': - ccnet_debug_level_str = optarg; - break; - case 'G': - seafile_debug_level_str = optarg; - break; - case 'P': - controller_pidfile = optarg; - break; - default: - usage (); - exit (1); - } - } - -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif -#if !GLIB_CHECK_VERSION(2,32,0) - g_thread_init (NULL); -#endif - - if (!seafile_dir) { - fprintf (stderr, " must be specified with --seafile-dir\n"); - exit(1); - } - - if (!central_config_dir) { - fprintf (stderr, " must be specified with --central-config-dir\n"); - exit(1); - } - - central_config_dir = ccnet_expand_path (central_config_dir); - config_dir = ccnet_expand_path (config_dir); - seafile_dir = ccnet_expand_path (seafile_dir); - - if (test_conf) { - test_config (central_config_dir, config_dir, seafile_dir); - } - - ctl = g_new0 (SeafileController, 1); - if (seaf_controller_init (ctl, central_config_dir, config_dir, seafile_dir, logdir) < 0) { - controller_exit(1); - } - - char *logfile = g_build_filename (ctl->logdir, "controller.log", NULL); - if (seafile_log_init (logfile, ccnet_debug_level_str, - seafile_debug_level_str) < 0) { - seaf_warning ("Failed to init log.\n"); - controller_exit (1); - } - - if (init_syslog_config () < 0) { - controller_exit (1); - } - - set_signal_handlers (); - - if (seaf_controller_start () < 0) - controller_exit (1); - -#ifndef WIN32 - if (daemon_mode) { -#ifndef __APPLE__ - daemon (1, 0); -#else /* __APPLE */ - /* daemon is deprecated under APPLE - * use fork() instead - * */ - switch (fork ()) { - case -1: - seaf_warning ("Failed to daemonize"); - exit (-1); - break; - case 0: - /* all good*/ - break; - default: - /* kill origin process */ - exit (0); - } -#endif /* __APPLE */ - } -#endif /* !WIN32 */ - - if (controller_pidfile == NULL) { - controller_pidfile = g_strdup(g_getenv ("SEAFILE_PIDFILE")); - } - - if (controller_pidfile != NULL) { - if (write_controller_pidfile () < 0) { - seaf_warning ("Failed to write pidfile %s\n", controller_pidfile); - return -1; - } - } - - run_controller_loop (); - - return 0; -} - diff --git a/controller/seafile-controller.h b/controller/seafile-controller.h deleted file mode 100644 index ed158511..00000000 --- a/controller/seafile-controller.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* - * Seafile-controller is responsible for: - * - * 1. Start: start server processes: - * - * - ccnet-server - * - seaf-server - * - seaf-mon - * - * 2. Repair: - * - * - ensure ccnet process availability by watching client->connfd - * - ensure server processes availablity by checking process is running periodically - * If some process has stopped working, try to restart it. - * - */ - -#ifndef SEAFILE_CONTROLLER_H -#define SEAFILE_CONTROLLER_H - -typedef struct _SeafileController SeafileController; - -enum { - PID_CCNET = 0, - PID_SERVER, - PID_SEAFDAV, - N_PID -}; - -// host size limit (39 charaters: max ipv6 size) -#define SEAFDAV_MAX_HOST 39 - -typedef struct SeafDavConfig { - gboolean enabled; - gboolean fastcgi; - int port; - // host to bind server to - char *host; - -} SeafDavConfig; - -struct _SeafileController { - char *central_config_dir; - char *config_dir; - char *seafile_dir; - char *logdir; - - CcnetClient *client; - CcnetClient *sync_client; - CcnetMqclientProc *mqclient_proc; - - guint check_process_timer; - guint client_io_id; - /* Decide whether to start seaf-server in cloud mode */ - gboolean cloud_mode; - - int pid[N_PID]; - char *pidfile[N_PID]; - - SeafDavConfig seafdav_config; -}; -#endif diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 25133ec2..2c9c6e3e 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -14,10 +14,7 @@ AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ @BPWRAPPER_CFLAGS@ \ -Wall -bin_PROGRAMS = -if !SERVER_ONLY -bin_PROGRAMS += seaf-daemon -endif +bin_PROGRAMS = seaf-daemon proc_headers = $(addprefix processors/, \ check-tx-v3-proc.h \ @@ -122,10 +119,9 @@ common_src = \ seaf_daemon_SOURCES = seaf-daemon.c $(common_src) seaf_daemon_LDADD = $(top_builddir)/lib/libseafile_common.la \ - @LIB_INTL@ \ @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ $(top_builddir)/common/cdc/libcdc.la \ $(top_builddir)/common/index/libindex.la @LIB_WS32@ @LIB_CRYPT32@ \ - @SEARPC_LIBS@ @CCNET_LIBS@ @GNOME_KEYRING_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@ @CURL_LIBS@ @BPWRAPPER_LIBS@ + @SEARPC_LIBS@ @CCNET_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@ @CURL_LIBS@ @BPWRAPPER_LIBS@ -seaf_daemon_LDFLAGS = @STATIC_COMPILE@ @CONSOLE@ +seaf_daemon_LDFLAGS = @CONSOLE@ diff --git a/doc/Makefile.am b/doc/Makefile.am index d2c0cfb3..79844832 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,7 +1,5 @@ -if COMPILE_CLIENT CLIENT_MANUALS = seaf-daemon.1 seaf-cli.1 -endif dist_man1_MANS = $(CLIENT_MANUALS) -EXTRA_DIST = cli-readme.txt seafile-tutorial.doc Seafile-tutorial-cn.doc +EXTRA_DIST = cli-readme.txt diff --git a/doc/Seafile-tutorial-cn.doc b/doc/Seafile-tutorial-cn.doc deleted file mode 100644 index 6bbc82a9..00000000 Binary files a/doc/Seafile-tutorial-cn.doc and /dev/null differ diff --git a/doc/ccnet.1 b/doc/ccnet.1 deleted file mode 100644 index a310a62f..00000000 --- a/doc/ccnet.1 +++ /dev/null @@ -1,20 +0,0 @@ -.\" Manpage for seafile-client -.\" Contact freeplant@gmail.com to correct errors or typos. -.TH seafile 1 "31 Jan 2013" "Linux" "seafile client man page" -.SH NAME -ccnet \- the networking daemon of seafile client -.SH SYNOPSIS -ccnet [OPTIONS] -.SH DESCRIPTION -.BR ccnet -is the networking daemon of seafile client. It handles the identification and -communication with seafile server. -It's started by seafile-applet(1). -.SH SEE ALSO -seafile-applet(1), seaf-daemon(1), seafile-web(1), seaf-cli(1) -.SH AUTHOR -Lingtao Pan (freeplant@gmail.com) -.SH WEBSTIE -http://www.seafile.com -.LP -https://github.com/haiwen/seafile/ diff --git a/doc/seafile-applet.1 b/doc/seafile-applet.1 deleted file mode 100644 index c054e51e..00000000 --- a/doc/seafile-applet.1 +++ /dev/null @@ -1,24 +0,0 @@ -.\" Manpage for seafile-client -.\" Contact freeplant@gmail.com to correct errors or typos. -.TH seafile 1 "31 Jan 2013" "Linux" "seafile-client man page" -.SH NAME -seafile-applet \- start the seafile client -.SH SYNOPSIS -seafile-applet [OPTIONS] -.SH DESCRIPTION -.BR seafile-applet -is the client program of seafile. It will start -.BR ccnet(1) -, -.BR seaf-daemon(1) -, -.BR seafile-web(1) -for you -.SH SEE ALSO -ccnet(1), seaf-daemon(1), seafile-web(1), seaf-cli(1) -.SH AUTHOR -Lingtao Pan (freeplant@gmail.com) -.SH WEBSTIE -http://www.seafile.com -.LP -https://github.com/haiwen/seafile/ diff --git a/doc/seafile-tutorial.doc b/doc/seafile-tutorial.doc deleted file mode 100644 index 63fdf059..00000000 Binary files a/doc/seafile-tutorial.doc and /dev/null differ diff --git a/fuse/Makefile.am b/fuse/Makefile.am deleted file mode 100644 index 63192f80..00000000 --- a/fuse/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - -DSEAFILE_SERVER \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/common \ - @CCNET_CFLAGS@ \ - @SEARPC_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @ZDB_CFLAGS@ \ - @FUSE_CFLAGS@ \ - -Wall - -bin_PROGRAMS = seaf-fuse - -noinst_HEADERS = seaf-fuse.h seafile-session.h repo-mgr.h - -seaf_fuse_SOURCES = seaf-fuse.c \ - seafile-session.c \ - file.c \ - getattr.c \ - readdir.c \ - repo-mgr.c \ - ../common/block-mgr.c \ - ../common/block-backend.c \ - ../common/block-backend-fs.c \ - ../common/branch-mgr.c \ - ../common/commit-mgr.c \ - ../common/fs-mgr.c \ - ../common/log.c \ - ../common/seaf-db.c \ - ../common/seaf-utils.c \ - ../common/obj-store.c \ - ../common/obj-backend-fs.c \ - ../common/obj-backend-riak.c \ - ../common/seafile-crypt.c - -seaf_fuse_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/lib/libseafile.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ \ - -lsqlite3 @LIBEVENT_LIBS@ \ - $(top_builddir)/common/cdc/libcdc.la \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @FUSE_LIBS@ @ZLIB_LIBS@ - -seaf_fuse_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ diff --git a/fuse/file.c b/fuse/file.c deleted file mode 100644 index ce7696ae..00000000 --- a/fuse/file.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "common.h" - -#define FUSE_USE_VERSION 26 -#include - -#include -#include - -#include -#include - -#include "log.h" -#include "utils.h" - -#include "seaf-fuse.h" - -int read_file(SeafileSession *seaf, - const char *store_id, int version, - Seafile *file, - char *buf, size_t size, - off_t offset, struct fuse_file_info *info) -{ - BlockHandle *handle = NULL;; - BlockMetadata *bmd; - char *blkid; - char *ptr; - off_t off = 0, nleft; - int i, n, ret = -EIO; - - for (i = 0; i < file->n_blocks; i++) { - blkid = file->blk_sha1s[i]; - - bmd = seaf_block_manager_stat_block(seaf->block_mgr, store_id, version, blkid); - if (!bmd) - return -EIO; - - if (offset < off + bmd->size) { - g_free (bmd); - break; - } - - off += bmd->size; - g_free (bmd); - } - - /* beyond the file size */ - if (i == file->n_blocks) - return 0; - - nleft = size; - ptr = buf; - while (nleft > 0 && i < file->n_blocks) { - blkid = file->blk_sha1s[i]; - - handle = seaf_block_manager_open_block(seaf->block_mgr, - store_id, version, - blkid, BLOCK_READ); - if (!handle) { - seaf_warning ("Failed to open block %s:%s.\n", store_id, blkid); - return -EIO; - } - - /* trim the offset in a block */ - if (offset > off) { - char *tmp = (char *)malloc(sizeof(char) * (offset - off)); - if (!tmp) - return -ENOMEM; - - n = seaf_block_manager_read_block(seaf->block_mgr, handle, - tmp, offset-off); - if (n != offset - off) { - seaf_warning ("Failed to read block %s:%s.\n", store_id, blkid); - free (tmp); - goto out; - } - - off += n; - free(tmp); - } - - if ((n = seaf_block_manager_read_block(seaf->block_mgr, - handle, ptr, nleft)) < 0) { - seaf_warning ("Failed to read block %s:%s.\n", store_id, blkid); - goto out; - } - - nleft -= n; - ptr += n; - off += n; - ++i; - - /* At this point we should have read all the content of the block or - * have read up to @size bytes. So it's safe to close the block. - */ - seaf_block_manager_close_block(seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - } - - return size - nleft; - -out: - if (handle) { - seaf_block_manager_close_block(seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - } - return ret; -} diff --git a/fuse/getattr.c b/fuse/getattr.c deleted file mode 100644 index 071ff1a9..00000000 --- a/fuse/getattr.c +++ /dev/null @@ -1,190 +0,0 @@ -#include "common.h" - -#define FUSE_USE_VERSION 26 -#include - -#include -#include - -#include -#include -#include - -#include "log.h" -#include "utils.h" - -#include "seaf-fuse.h" -#include "seafile-session.h" - -static CcnetEmailUser *get_user_from_ccnet (SearpcClient *client, const char *user) -{ - return (CcnetEmailUser *)searpc_client_call__object (client, - "get_emailuser", CCNET_TYPE_EMAIL_USER, NULL, - 1, "string", user); -} - -static int getattr_root(SeafileSession *seaf, struct stat *stbuf) -{ - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - stbuf->st_size = 4096; - - return 0; -} - -static int getattr_user(SeafileSession *seaf, const char *user, struct stat *stbuf) -{ - SearpcClient *client; - CcnetEmailUser *emailuser; - - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-threaded-rpcserver"); - if (!client) { - seaf_warning ("Failed to alloc rpc client.\n"); - return -ENOMEM; - } - - emailuser = get_user_from_ccnet (client, user); - if (!emailuser) { - ccnet_rpc_client_free (client); - return -ENOENT; - } - g_object_unref (emailuser); - ccnet_rpc_client_free (client); - - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - stbuf->st_size = 4096; - - return 0; -} - -static int getattr_repo(SeafileSession *seaf, - const char *user, const char *repo_id, const char *repo_path, - struct stat *stbuf) -{ - SeafRepo *repo = NULL; - SeafBranch *branch; - SeafCommit *commit = NULL; - guint32 mode = 0; - char *id = NULL; - int ret = 0; - - 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; - } - - 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; - } - - if (S_ISDIR(mode)) { - SeafDir *dir; - GList *l; - int cnt = 2; /* '.' and '..' */ - - dir = seaf_fs_manager_get_seafdir(seaf->fs_mgr, - repo->store_id, repo->version, id); - if (dir) { - for (l = dir->entries; l; l = l->next) - cnt++; - } - - if (strcmp (repo_path, "/") != 0) { - // get dirent of the dir - SeafDirent *dirent = seaf_fs_manager_get_dirent_by_path (seaf->fs_mgr, - repo->store_id, - repo->version, - commit->root_id, - repo_path, NULL); - if (dirent && repo->version != 0) - stbuf->st_mtime = dirent->mtime; - - seaf_dirent_free (dirent); - } - - stbuf->st_size += cnt * sizeof(SeafDirent); - stbuf->st_mode = mode | 0755; - stbuf->st_nlink = 2; - - seaf_dir_free (dir); - } else if (S_ISREG(mode)) { - Seafile *file; - - file = seaf_fs_manager_get_seafile(seaf->fs_mgr, - repo->store_id, repo->version, id); - if (file) - stbuf->st_size = file->file_size; - - SeafDirent *dirent = seaf_fs_manager_get_dirent_by_path (seaf->fs_mgr, - repo->store_id, - repo->version, - commit->root_id, - repo_path, NULL); - if (dirent && repo->version != 0) - stbuf->st_mtime = dirent->mtime; - - stbuf->st_mode = mode | 0644; - stbuf->st_nlink = 1; - - seaf_dirent_free (dirent); - seafile_unref (file); - } else { - return -ENOENT; - } - -out: - g_free (id); - seaf_repo_unref (repo); - seaf_commit_unref (commit); - return ret; -} - -int do_getattr(SeafileSession *seaf, const char *path, struct stat *stbuf) -{ - int n_parts; - char *user, *repo_id, *repo_path; - int ret = 0; - - if (parse_fuse_path (path, &n_parts, &user, &repo_id, &repo_path) < 0) { - return -ENOENT; - } - - switch (n_parts) { - case 0: - ret = getattr_root(seaf, stbuf); - break; - case 1: - ret = getattr_user(seaf, user, stbuf); - break; - case 2: - case 3: - ret = getattr_repo(seaf, user, repo_id, repo_path, stbuf); - break; - } - - g_free (user); - g_free (repo_id); - g_free (repo_path); - return ret; -} diff --git a/fuse/readdir.c b/fuse/readdir.c deleted file mode 100644 index 0e7a44ec..00000000 --- a/fuse/readdir.c +++ /dev/null @@ -1,237 +0,0 @@ -#include "common.h" - -#define FUSE_USE_VERSION 26 -#include - -#include -#include - -#include -#include -#include - -#include "log.h" -#include "utils.h" - -#include "seaf-fuse.h" -#include "seafile-session.h" - -static char *replace_slash (const char *repo_name) -{ - char *ret = g_strdup(repo_name); - char *p; - - for (p = ret; *p != 0; ++p) - if (*p == '/') - *p = '_'; - - return ret; -} - -static GList *get_users_from_ccnet (SearpcClient *client, const char *source) -{ - return searpc_client_call__objlist (client, - "get_emailusers", CCNET_TYPE_EMAIL_USER, NULL, - 3, "string", source, "int", -1, "int", -1); -} - -static CcnetEmailUser *get_user_from_ccnet (SearpcClient *client, const char *user) -{ - return (CcnetEmailUser *)searpc_client_call__object (client, - "get_emailuser", CCNET_TYPE_EMAIL_USER, NULL, - 1, "string", user); -} - -static int readdir_root(SeafileSession *seaf, - void *buf, fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *info) -{ - SearpcClient *client = NULL; - GList *users, *p; - CcnetEmailUser *user; - const char *email; - GHashTable *user_hash; - int dummy; - - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-threaded-rpcserver"); - if (!client) { - seaf_warning ("Failed to alloc rpc client.\n"); - return -ENOMEM; - } - - user_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - users = get_users_from_ccnet (client, "DB"); - for (p = users; p; p = p->next) { - user = p->data; - email = ccnet_email_user_get_email (user); - g_hash_table_insert (user_hash, g_strdup(email), &dummy); - g_object_unref (user); - } - g_list_free (users); - - users = get_users_from_ccnet (client, "LDAP"); - for (p = users; p; p = p->next) { - user = p->data; - email = ccnet_email_user_get_email (user); - g_hash_table_insert (user_hash, g_strdup(email), &dummy); - g_object_unref (user); - } - g_list_free (users); - - users = g_hash_table_get_keys (user_hash); - for (p = users; p; p = p->next) { - email = p->data; - filler (buf, email, NULL, 0); - } - g_list_free (users); - - g_hash_table_destroy (user_hash); - ccnet_rpc_client_free (client); - - return 0; -} - -static int readdir_user(SeafileSession *seaf, const char *user, - void *buf, fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *info) -{ - SearpcClient *client; - CcnetEmailUser *emailuser; - GList *list = NULL, *p; - GString *name; - - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-threaded-rpcserver"); - if (!client) { - seaf_warning ("Failed to alloc rpc client.\n"); - return -ENOMEM; - } - - emailuser = get_user_from_ccnet (client, user); - if (!emailuser) { - ccnet_rpc_client_free (client); - return -ENOENT; - } - g_object_unref (emailuser); - ccnet_rpc_client_free (client); - - list = seaf_repo_manager_get_repos_by_owner (seaf->repo_mgr, user); - if (!list) - return 0; - - for (p = list; p; p = p->next) { - SeafRepo *repo = (SeafRepo *)p->data; - - /* Don't list virtual repos. */ - if (seaf_repo_manager_is_virtual_repo(seaf->repo_mgr, repo->id)) { - seaf_repo_unref (repo); - continue; - } - - // Don't list encrypted repo - if (repo->encrypted) { - continue; - } - - char *clean_repo_name = replace_slash (repo->name); - - name = g_string_new (""); - g_string_printf (name, "%s_%s", repo->id, clean_repo_name); - filler(buf, name->str, NULL, 0); - g_string_free (name, TRUE); - g_free (clean_repo_name); - - seaf_repo_unref (repo); - } - - g_list_free (list); - - return 0; -} - -static int readdir_repo(SeafileSession *seaf, - const char *user, const char *repo_id, const char *repo_path, - void *buf, fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *info) -{ - SeafRepo *repo = NULL; - SeafBranch *branch; - SeafCommit *commit = NULL; - SeafDir *dir = NULL; - GList *l; - int ret = 0; - - 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; - } - - dir = seaf_fs_manager_get_seafdir_by_path(seaf->fs_mgr, - repo->store_id, repo->version, - commit->root_id, - repo_path, NULL); - if (!dir) { - seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id); - ret = -ENOENT; - goto out; - } - - for (l = dir->entries; l; l = l->next) { - SeafDirent *seaf_dent = (SeafDirent *) l->data; - /* FIXME: maybe we need to return stbuf */ - filler(buf, seaf_dent->name, NULL, 0); - } - -out: - seaf_repo_unref (repo); - seaf_commit_unref (commit); - seaf_dir_free (dir); - return ret; -} - -int do_readdir(SeafileSession *seaf, const char *path, void *buf, - fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *info) -{ - int n_parts; - char *user, *repo_id, *repo_path; - int ret = 0; - - if (parse_fuse_path (path, &n_parts, &user, &repo_id, &repo_path) < 0) { - return -ENOENT; - } - - switch (n_parts) { - case 0: - ret = readdir_root(seaf, buf, filler, offset, info); - break; - case 1: - ret = readdir_user(seaf, user, buf, filler, offset, info); - break; - case 2: - case 3: - ret = readdir_repo(seaf, user, repo_id, repo_path, buf, filler, offset, info); - break; - } - - g_free (user); - g_free (repo_id); - g_free (repo_path); - return ret; -} diff --git a/fuse/repo-mgr.c b/fuse/repo-mgr.c deleted file mode 100644 index 0165a543..00000000 --- a/fuse/repo-mgr.c +++ /dev/null @@ -1,428 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" -#include - -#include -#include "utils.h" -#include "log.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "fs-mgr.h" -#include "seafile-error.h" - -#include "seaf-db.h" - -#define INDEX_DIR "index" - -struct _SeafRepoManagerPriv { - -}; - -static SeafRepo * -load_repo (SeafRepoManager *manager, const char *repo_id); - -gboolean -is_repo_id_valid (const char *id) -{ - if (!id) - return FALSE; - - return is_uuid_valid (id); -} - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc) -{ - SeafRepo* repo; - - /* valid check */ - - - repo = g_new0 (SeafRepo, 1); - memcpy (repo->id, id, 36); - repo->id[36] = '\0'; - - repo->name = g_strdup(name); - repo->desc = g_strdup(desc); - - repo->ref_cnt = 1; - - return repo; -} - -void -seaf_repo_free (SeafRepo *repo) -{ - if (repo->name) g_free (repo->name); - if (repo->desc) g_free (repo->desc); - if (repo->category) g_free (repo->category); - if (repo->head) seaf_branch_unref (repo->head); - g_free (repo); -} - -void -seaf_repo_ref (SeafRepo *repo) -{ - g_atomic_int_inc (&repo->ref_cnt); -} - -void -seaf_repo_unref (SeafRepo *repo) -{ - if (!repo) - return; - - if (g_atomic_int_dec_and_test (&repo->ref_cnt)) - seaf_repo_free (repo); -} - -static void -set_head_common (SeafRepo *repo, SeafBranch *branch) -{ - if (repo->head) - seaf_branch_unref (repo->head); - repo->head = branch; - seaf_branch_ref(branch); -} - -void -seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit) -{ - repo->name = g_strdup (commit->repo_name); - repo->desc = g_strdup (commit->repo_desc); - repo->encrypted = commit->encrypted; - if (repo->encrypted) { - repo->enc_version = commit->enc_version; - if (repo->enc_version >= 1) - memcpy (repo->magic, commit->magic, 33); - } - repo->no_local_history = commit->no_local_history; - repo->version = commit->version; -} - -void -seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit) -{ - commit->repo_name = g_strdup (repo->name); - commit->repo_desc = g_strdup (repo->desc); - commit->encrypted = repo->encrypted; - if (commit->encrypted) { - commit->enc_version = repo->enc_version; - if (commit->enc_version >= 1) - commit->magic = g_strdup (repo->magic); - } - commit->no_local_history = repo->no_local_history; - commit->version = repo->version; -} - -static gboolean -collect_commit (SeafCommit *commit, void *vlist, gboolean *stop) -{ - GList **commits = vlist; - - /* The traverse function will unref the commit, so we need to ref it. - */ - seaf_commit_ref (commit); - *commits = g_list_prepend (*commits, commit); - return TRUE; -} - -GList * -seaf_repo_get_commits (SeafRepo *repo) -{ - GList *branches; - GList *ptr; - SeafBranch *branch; - GList *commits = NULL; - - branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); - if (branches == NULL) { - seaf_warning ("Failed to get branch list of repo %s.\n", repo->id); - return NULL; - } - - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - branch = ptr->data; - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - branch->commit_id, - collect_commit, - &commits, - FALSE); - if (!res) { - for (ptr = commits; ptr != NULL; ptr = ptr->next) - seaf_commit_unref ((SeafCommit *)(ptr->data)); - g_list_free (commits); - goto out; - } - } - - commits = g_list_reverse (commits); - -out: - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - seaf_branch_unref ((SeafBranch *)ptr->data); - } - return commits; -} - -static int -compare_repo (const SeafRepo *srepo, const SeafRepo *trepo) -{ - return g_strcmp0 (srepo->id, trepo->id); -} - -SeafRepoManager* -seaf_repo_manager_new (SeafileSession *seaf) -{ - SeafRepoManager *mgr = g_new0 (SeafRepoManager, 1); - - mgr->priv = g_new0 (SeafRepoManagerPriv, 1); - mgr->seaf = seaf; - - return mgr; -} - -int -seaf_repo_manager_init (SeafRepoManager *mgr) -{ - return 0; -} - -int -seaf_repo_manager_start (SeafRepoManager *mgr) -{ - return 0; -} - -static gboolean -repo_exists_in_db (SeafDB *db, const char *id) -{ - char sql[256]; - gboolean db_err = FALSE; - - snprintf (sql, sizeof(sql), "SELECT repo_id FROM Repo WHERE repo_id = '%s'", - id); - return seaf_db_check_for_existence (db, sql, &db_err); -} - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id) -{ - SeafRepo repo; - int len = strlen(id); - - if (len >= 37) - return NULL; - - memcpy (repo.id, id, len + 1); - - if (repo_exists_in_db (manager->seaf->db, id)) { - SeafRepo *ret = load_repo (manager, id); - if (!ret) - return NULL; - /* seaf_repo_ref (ret); */ - return ret; - } - - return NULL; -} - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id) -{ - SeafRepo repo; - memcpy (repo.id, id, 37); - - return repo_exists_in_db (manager->seaf->db, id); -} - -static void -load_repo_commit (SeafRepoManager *manager, - SeafRepo *repo, - SeafBranch *branch) -{ - SeafCommit *commit; - - commit = seaf_commit_manager_get_commit_compatible (manager->seaf->commit_mgr, - repo->id, - branch->commit_id); - if (!commit) { - seaf_warning ("Commit %s is missing\n", branch->commit_id); - repo->is_corrupted = TRUE; - return; - } - - set_head_common (repo, branch); - seaf_repo_from_commit (repo, commit); - - seaf_commit_unref (commit); -} - -static gboolean -load_virtual_info (SeafDBRow *row, void *vrepo_id) -{ - char *ret_repo_id = vrepo_id; - const char *origin_repo_id; - - origin_repo_id = seaf_db_row_get_column_text (row, 0); - memcpy (ret_repo_id, origin_repo_id, 37); - - return FALSE; -} - -char * -get_origin_repo_id (SeafRepoManager *mgr, const char *repo_id) -{ - char sql[256]; - char origin_repo_id[37]; - - memset (origin_repo_id, 0, 37); - - snprintf (sql, 256, - "SELECT origin_repo FROM VirtualRepo " - "WHERE repo_id = '%s'", repo_id); - seaf_db_foreach_selected_row (seaf->db, sql, load_virtual_info, origin_repo_id); - - if (origin_repo_id[0] != 0) - return g_strdup(origin_repo_id); - else - return NULL; -} - -static SeafRepo * -load_repo (SeafRepoManager *manager, const char *repo_id) -{ - SeafRepo *repo; - SeafBranch *branch; - - repo = seaf_repo_new(repo_id, NULL, NULL); - if (!repo) { - seaf_warning ("[repo mgr] failed to alloc repo.\n"); - return NULL; - } - - repo->manager = manager; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); - if (!branch) { - seaf_warning ("Failed to get master branch of repo %.8s.\n", repo_id); - repo->is_corrupted = TRUE; - } else { - load_repo_commit (manager, repo, branch); - seaf_branch_unref (branch); - } - - if (repo->is_corrupted) { - seaf_warning ("Repo %.8s is corrupted.\n", repo->id); - seaf_repo_free (repo); - return NULL; - } - - char *origin_repo_id = get_origin_repo_id (manager, repo->id); - if (origin_repo_id) - memcpy (repo->store_id, origin_repo_id, 36); - else - memcpy (repo->store_id, repo->id, 36); - g_free (origin_repo_id); - - return repo; -} - -static gboolean -collect_repo_id (SeafDBRow *row, void *data) -{ - GList **p_ids = data; - const char *repo_id; - - repo_id = seaf_db_row_get_column_text (row, 0); - *p_ids = g_list_prepend (*p_ids, g_strdup(repo_id)); - - return TRUE; -} - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr) -{ - GList *ret = NULL; - char sql[256]; - - snprintf (sql, 256, "SELECT repo_id FROM Repo"); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &ret) < 0) - return NULL; - - return ret; -} - -GList * -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit) -{ - GList *id_list = NULL, *ptr; - GList *ret = NULL; - SeafRepo *repo; - char sql[256]; - - if (start == -1 && limit == -1) - snprintf (sql, 256, "SELECT repo_id FROM Repo"); - else - snprintf (sql, 256, "SELECT repo_id FROM Repo LIMIT %d, %d", start, limit); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &id_list) < 0) - return NULL; - - for (ptr = id_list; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (repo != NULL) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - return g_list_reverse (ret); -} - -GList * -seaf_repo_manager_get_repos_by_owner (SeafRepoManager *mgr, - const char *email) -{ - GList *id_list = NULL, *ptr; - GList *ret = NULL; - char sql[256]; - - snprintf (sql, 256, "SELECT repo_id FROM RepoOwner WHERE owner_id='%s'", - email); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &id_list) < 0) - return NULL; - - for (ptr = id_list; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - SeafRepo *repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (repo != NULL) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - - return ret; -} - -gboolean -seaf_repo_manager_is_virtual_repo (SeafRepoManager *mgr, const char *repo_id) -{ - char sql[256]; - gboolean db_err; - - snprintf (sql, 256, - "SELECT 1 FROM VirtualRepo WHERE repo_id = '%s'", repo_id); - return seaf_db_check_for_existence (seaf->db, sql, &db_err); -} diff --git a/fuse/repo-mgr.h b/fuse/repo-mgr.h deleted file mode 100644 index 7e6cbebe..00000000 --- a/fuse/repo-mgr.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAF_REPO_MGR_H -#define SEAF_REPO_MGR_H - -#include - -#include "seafile-object.h" -#include "commit-mgr.h" -#include "branch-mgr.h" - -struct _SeafRepoManager; -typedef struct _SeafRepo SeafRepo; - -struct _SeafRepo { - struct _SeafRepoManager *manager; - - gchar id[37]; - gchar *name; - gchar *desc; - gchar *category; /* not used yet */ - gboolean encrypted; - int enc_version; - gchar magic[33]; /* hash(repo_id + passwd), key stretched. */ - gboolean no_local_history; - - SeafBranch *head; - - gboolean is_corrupted; - gboolean delete_pending; - int ref_cnt; - - int version; - /* Used to access fs and block sotre. - * This id is different from repo_id when this repo is virtual. - * Virtual repos share fs and block store with its origin repo. - * However, commit store for each repo is always independent. - * So always use repo_id to access commit store. - */ - gchar store_id[37]; -}; - -gboolean is_repo_id_valid (const char *id); - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc); - -void -seaf_repo_free (SeafRepo *repo); - -void -seaf_repo_ref (SeafRepo *repo); - -void -seaf_repo_unref (SeafRepo *repo); - -typedef struct _SeafRepoManager SeafRepoManager; -typedef struct _SeafRepoManagerPriv SeafRepoManagerPriv; - -struct _SeafRepoManager { - struct _SeafileSession *seaf; - - SeafRepoManagerPriv *priv; -}; - -SeafRepoManager* -seaf_repo_manager_new (struct _SeafileSession *seaf); - -int -seaf_repo_manager_init (SeafRepoManager *mgr); - -int -seaf_repo_manager_start (SeafRepoManager *mgr); - -int -seaf_repo_manager_add_repo (SeafRepoManager *mgr, SeafRepo *repo); - -int -seaf_repo_manager_del_repo (SeafRepoManager *mgr, SeafRepo *repo); - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id); - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id); - -GList* -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit); - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr); - -GList * -seaf_repo_manager_get_repos_by_owner (SeafRepoManager *mgr, - const char *email); - -gboolean -seaf_repo_manager_is_virtual_repo (SeafRepoManager *mgr, const char *repo_id); - -#endif diff --git a/fuse/seaf-fuse.c b/fuse/seaf-fuse.c deleted file mode 100644 index 4908402b..00000000 --- a/fuse/seaf-fuse.c +++ /dev/null @@ -1,355 +0,0 @@ -#include "common.h" - -#include -#include - -#define FUSE_USE_VERSION 26 -#include -#include - -#include -#include - -#include -#include - -#include "log.h" -#include "utils.h" - -#include "seaf-fuse.h" - -CcnetClient *ccnet_client = NULL; -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); - } - - g_type_init(); - - 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) < 0) { - fprintf(stderr, "Failed to init log.\n"); - exit(1); - } - - ccnet_client = ccnet_client_new(); - if ((ccnet_client_load_confdir(ccnet_client, central_config_dir, config_dir)) < 0) { - seaf_warning("Read config dir error\n"); - exit(1); - } - - seaf = seafile_session_new(central_config_dir, seafile_dir, ccnet_client); - 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); - } - - seaf->client_pool = ccnet_client_pool_new(central_config_dir, config_dir); - if (!seaf->client_pool) { - seaf_warning("Failed to creat client pool\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; -} diff --git a/fuse/seaf-fuse.h b/fuse/seaf-fuse.h deleted file mode 100644 index eae1061c..00000000 --- a/fuse/seaf-fuse.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SEAF_FUSE_H -#define SEAF_FUSE_H - -#include "seafile-session.h" - -int parse_fuse_path (const char *path, - int *n_parts, char **user, char **repo_id, char **repo_path); - -SeafDirent * -fuse_get_dirent_by_path (SeafFSManager *mgr, - const char *repo_id, - int version, - const char *root_id, - const char *path); - -/* file.c */ -int read_file(SeafileSession *seaf, const char *store_id, int version, - Seafile *file, char *buf, size_t size, - off_t offset, struct fuse_file_info *info); - -/* getattr.c */ -int do_getattr(SeafileSession *seaf, const char *path, struct stat *stbuf); - -/* readdir.c */ -int do_readdir(SeafileSession *seaf, const char *path, void *buf, - fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *info); - -#endif /* SEAF_FUSE_H */ diff --git a/fuse/seafile-session.c b/fuse/seafile-session.c deleted file mode 100644 index 330777bd..00000000 --- a/fuse/seafile-session.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "common.h" - -#include -#include -#include - -#include -#include -#include - -#include "seafile-session.h" -#include "seaf-utils.h" - -#include "log.h" - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - CcnetClient *ccnet_session) -{ - char *abs_central_config_dir = NULL; - char *abs_seafile_dir; - char *tmp_file_dir; - char *config_file_path; - struct stat st; - GKeyFile *config; - SeafileSession *session = NULL; - - if (!ccnet_session) - return NULL; - - abs_seafile_dir = ccnet_expand_path (seafile_dir); - tmp_file_dir = g_build_filename(abs_seafile_dir, "tmpfiles", NULL); - if (central_config_dir) { - abs_central_config_dir = ccnet_expand_path (central_config_dir); - } - config_file_path = g_build_filename( - abs_central_config_dir ? abs_central_config_dir : abs_seafile_dir, - "seafile.conf", NULL); - - if (g_stat(abs_seafile_dir, &st) < 0 || !S_ISDIR(st.st_mode)) { - seaf_warning ("Seafile data dir %s does not exist and is unable to create\n", - abs_seafile_dir); - goto onerror; - } - - if (g_stat(tmp_file_dir, &st) < 0 || !S_ISDIR(st.st_mode)) { - seaf_warning("Seafile tmp dir %s does not exist and is unable to create\n", - tmp_file_dir); - goto onerror; - } - - GError *error = NULL; - config = g_key_file_new (); - if (!g_key_file_load_from_file (config, config_file_path, - G_KEY_FILE_NONE, &error)) { - seaf_warning ("Failed to load config file.\n"); - g_key_file_free (config); - goto onerror; - } - - session = g_new0(SeafileSession, 1); - session->seaf_dir = abs_seafile_dir; - session->tmp_file_dir = tmp_file_dir; - session->session = ccnet_session; - session->config = config; - - if (load_database_config (session) < 0) { - seaf_warning ("Failed to load database config.\n"); - goto onerror; - } - - session->fs_mgr = seaf_fs_manager_new (session, abs_seafile_dir); - if (!session->fs_mgr) - goto onerror; - session->block_mgr = seaf_block_manager_new (session, abs_seafile_dir); - if (!session->block_mgr) - goto onerror; - session->commit_mgr = seaf_commit_manager_new (session); - if (!session->commit_mgr) - goto onerror; - session->repo_mgr = seaf_repo_manager_new (session); - if (!session->repo_mgr) - goto onerror; - session->branch_mgr = seaf_branch_manager_new (session); - if (!session->branch_mgr) - goto onerror; - - return session; - -onerror: - free (abs_seafile_dir); - g_free (config_file_path); - g_free (session); - return NULL; -} - -int -seafile_session_init (SeafileSession *session) -{ - if (seaf_commit_manager_init (session->commit_mgr) < 0) - return -1; - - if (seaf_fs_manager_init (session->fs_mgr) < 0) - return -1; - - if (seaf_branch_manager_init (session->branch_mgr) < 0) - return -1; - - if (seaf_repo_manager_init (session->repo_mgr) < 0) - return -1; - - return 0; -} - -int -seafile_session_start (SeafileSession *session) -{ - return 0; -} diff --git a/fuse/seafile-session.h b/fuse/seafile-session.h deleted file mode 100644 index 3cfb6e99..00000000 --- a/fuse/seafile-session.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef SEAFILE_SESSION_H -#define SEAFILE_SESSION_H - -#include -#include - -#include - -#include "block-mgr.h" -#include "fs-mgr.h" -#include "branch-mgr.h" -#include "commit-mgr.h" -#include "repo-mgr.h" - -struct _CcnetClient; - -typedef struct _SeafileSession SeafileSession; - -struct CcnetClientPool; - -struct _SeafileSession { - struct _CcnetClient *session; - - char *seaf_dir; - char *tmp_file_dir; - /* Config that's only loaded on start */ - GKeyFile *config; - SeafDB *db; - - struct CcnetClientPool *client_pool; - - SeafBlockManager *block_mgr; - SeafFSManager *fs_mgr; - SeafBranchManager *branch_mgr; - SeafCommitManager *commit_mgr; - SeafRepoManager *repo_mgr; -}; - -extern SeafileSession *seaf; - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - struct _CcnetClient *ccnet_session); - -int -seafile_session_init (SeafileSession *session); - -int -seafile_session_start (SeafileSession *session); - -#endif diff --git a/include/Makefile.am b/include/Makefile.am index aabd4610..30c3ffb9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,4 +3,4 @@ seafiledir = $(includedir)/seafile noinst_HEADERS = seafile-error.h -seafile_HEADERS = seafile-rpc.h monitor-rpc.h seafile.h +seafile_HEADERS = seafile-rpc.h seafile.h diff --git a/include/monitor-rpc.h b/include/monitor-rpc.h deleted file mode 100644 index 81814ccb..00000000 --- a/include/monitor-rpc.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MONITOR_RPC_H -#define MONITOR_RPC_H - -/** - * monitor_compute_repo_size: - * @repo_id: repo id - * - * Returns 0 if successfully scheduled computation. - */ -int -monitor_compute_repo_size (const char *repo_id, GError **error); - -#endif diff --git a/integration-tests/README.md b/integration-tests/README.md deleted file mode 100644 index 00790ae1..00000000 --- a/integration-tests/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Seafile Integration Tests - -The purpose of integration tests is to build a seafile release package and run tests against it. diff --git a/integration-tests/autosetup.py b/integration-tests/autosetup.py deleted file mode 100755 index af25de42..00000000 --- a/integration-tests/autosetup.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python -#coding: UTF-8 - -import os -from os.path import abspath, basename, exists, dirname, join -import sys -import argparse -import re -from collections import namedtuple - -import requests -from pexpect import spawn - -from utils import green, red, debug, info, warning, cd, shell, chdir, setup_logging - -USERNAME = 'test@seafiletest.com' -PASSWORD = 'testtest' -ADMIN_USERNAME = 'admin@seafiletest.com' -ADMIN_PASSWORD = 'adminadmin' -MYSQL_ROOT_PASSWD = 's123' - -ServerConfig = namedtuple('ServerConfig', [ - 'installdir', - 'tarball', - 'version', - 'initmode', -]) - - -def setup_server(cfg, db): - '''Setup seafile server with the setup-seafile.sh script. We use pexpect to - interactive with the setup process of the script. - ''' - info('uncompressing server tarball') - shell('tar xf seafile-server_{}_x86-64.tar.gz -C {}' - .format(cfg.version, cfg.installdir)) - if db == 'mysql': - autosetup_mysql(cfg) - else: - autosetup_sqlite3(cfg) - - with open(join(cfg.installdir, 'conf/seahub_settings.py'), 'a') as fp: - fp.write('\n') - fp.write('DEBUG = True') - fp.write('\n') - fp.write('''\ -REST_FRAMEWORK = { - 'DEFAULT_THROTTLE_RATES': { - 'ping': '600/minute', - 'anon': '1000/minute', - 'user': '1000/minute', - }, -}''') - fp.write('\n') - - -def autosetup_sqlite3(cfg): - setup_script = get_script(cfg, 'setup-seafile.sh') - shell('''sed -i -e '/^check_root;.*/d' "{}"'''.format(setup_script)) - - if cfg.initmode == 'prompt': - setup_sqlite3_prompt(setup_script) - else: - setup_sqlite3_auto(setup_script) - -def setup_sqlite3_prompt(setup_script): - info('setting up seafile server with pexepct, script %s', setup_script) - answers = [ - ('ENTER', ''), - # server name - ('server name', 'my-seafile'), - # ip or domain - ('ip or domain', '127.0.0.1'), - # seafile data dir - ('seafile-data', ''), - # fileserver port - ('seafile fileserver', ''), - ('ENTER', ''), - ('ENTER', ''), - ] - _answer_questions(setup_script, answers) - -def setup_sqlite3_auto(setup_script): - info('setting up seafile server in auto mode, script %s', setup_script) - env = os.environ.copy() - env['SERVER_IP'] = '127.0.0.1' - shell('%s auto -n my-seafile' % setup_script, env=env) - -def createdbs(): - sql = '''\ -create database `ccnet-existing` character set = 'utf8'; -create database `seafile-existing` character set = 'utf8'; -create database `seahub-existing` character set = 'utf8'; - -create user 'seafile'@'localhost' identified by 'seafile'; - -GRANT ALL PRIVILEGES ON `ccnet-existing`.* to `seafile`@localhost; -GRANT ALL PRIVILEGES ON `seafile-existing`.* to `seafile`@localhost; -GRANT ALL PRIVILEGES ON `seahub-existing`.* to `seafile`@localhost; - ''' - - shell('mysql -u root -p%s' % MYSQL_ROOT_PASSWD, inputdata=sql) - - -def autosetup_mysql(cfg): - setup_script = get_script(cfg, 'setup-seafile-mysql.sh') - if not exists(setup_script): - print 'please specify seafile script path' - - if cfg.initmode == 'prompt': - createdbs() - setup_mysql_prompt(setup_script) - else : - # in auto mode, test create new db - setup_mysql_auto(setup_script) - -def setup_mysql_prompt(setup_script): - info('setting up seafile server with pexepct, script %s', setup_script) - answers = [ - ('ENTER', ''), - # server name - ('server name', 'my-seafile'), - # ip or domain - ('ip or domain', '127.0.0.1'), - # seafile data dir - ('seafile-data', ''), - # fileserver port - ('seafile fileserver', ''), - # use existing - ('choose a way to initialize seafile databases', '2'), - ('host of mysql server', ''), - ('port of mysql server', ''), - ('Which mysql user', 'seafile'), - ('password for mysql user', 'seafile'), - ('ccnet database', 'ccnet-existing'), - ('seafile database', 'seafile-existing'), - ('seahub database', 'seahub-existing'), - ('ENTER', ''), - ] - _answer_questions(abspath(setup_script), answers) - -def setup_mysql_auto(setup_script): - info('setting up seafile server in auto mode, script %s', setup_script) - env = os.environ.copy() - env['MYSQL_USER'] = 'seafile-new' - env['MYSQL_USER_PASSWD'] = 'seafile' - env['MYSQL_ROOT_PASSWD']= MYSQL_ROOT_PASSWD - env['CCNET_DB'] = 'ccnet-new' - env['SEAFILE_DB'] = 'seafile-new' - env['SEAHUB_DB'] = 'seahub-new' - shell('%s auto -n my-seafile -e 0' % setup_script, env=env) - -def start_server(cfg): - with cd(cfg.installdir): - shell('find . -maxdepth 2 | sort | xargs ls -lhd') - seafile_sh = get_script(cfg, 'seafile.sh') - shell('{} start'.format(seafile_sh)) - - info('starting seahub') - seahub_sh = get_script(cfg, 'seahub.sh') - answers = [ - # admin email/pass - ('admin email', ADMIN_USERNAME), - ('admin password', ADMIN_PASSWORD), - ('admin password again', ADMIN_PASSWORD), - ] - _answer_questions('{} start'.format(abspath(seahub_sh)), answers) - with cd(cfg.installdir): - shell('find . -maxdepth 2 | sort | xargs ls -lhd') - # shell('sqlite3 ccnet/PeerMgr/usermgr.db "select * from EmailUser"', cwd=INSTALLDIR) - shell('http -v localhost:8000/api2/server-info/ || true') - # shell('http -v -f POST localhost:8000/api2/auth-token/ username=admin@seafiletest.com password=adminadmin || true') - shell('netstat -nltp') - - -def _answer_questions(cmd, answers): - info('expect: spawing %s', cmd) - child = spawn(cmd) - child.logfile = sys.stdout - - def autofill(pattern, line): - child.expect(pattern) - child.sendline(line) - - for k, v in answers: - autofill(k, v) - child.sendline('') - child.logfile = None - child.interact() - - -def get_script(cfg, path): - """ - :type cfg: ServerConfig - """ - return join(server_dir(cfg), path) - - -def server_dir(cfg): - """ - :type cfg: ServerConfig - """ - return join(cfg.installdir, 'seafile-server-{}'.format(cfg.version)) - - -def apiurl(path): - path = path.lstrip('/') - root = os.environ.get('SEAFILE_SERVER', 'http://127.0.0.1:8000') - return '{}/api2/{}'.format(root, path) - - -def create_test_user(cfg): - data = {'username': ADMIN_USERNAME, 'password': ADMIN_PASSWORD, } - res = requests.post(apiurl('/auth-token/'), data=data) - debug('%s %s', res.status_code, res.text) - token = res.json()['token'] - data = {'password': PASSWORD, } - headers = {'Authorization': 'Token ' + token} - res = requests.put( - apiurl('/accounts/{}/'.format(USERNAME)), - data=data, - headers=headers) - assert res.status_code == 201 - - -def main(): - ap = argparse.ArgumentParser() - ap.add_argument('-v', '--verbose', action='store_true') - ap.add_argument('--db', choices=('sqlite3', 'mysql'), default='sqlite3') - ap.add_argument('installdir') - ap.add_argument('tarball') - args = ap.parse_args() - - if not exists(args.installdir): - print 'directory {} does not exist'.format(args.installdir) - sys.exit(1) - - if os.listdir(args.installdir): - print 'directory {} is not empty'.format(args.installdir) - sys.exit(1) - - if not exists(args.tarball): - print 'file {} does not exist'.format(args.tarball) - sys.exit(1) - - m = re.match(r'^.*?_([\d\.]+).*?\.tar\.gz$', basename(args.tarball)) - version = m.group(1) - - cfg = ServerConfig(installdir=args.installdir, - tarball=args.tarball, - version=version) - setup_server(cfg, args.db) - start_server(cfg) - create_test_user(cfg) - - -if __name__ == '__main__': - setup_logging() - main() diff --git a/integration-tests/install-deps.sh b/integration-tests/install-deps.sh deleted file mode 100755 index 929be274..00000000 --- a/integration-tests/install-deps.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -set -e -x - -pip install http://effbot.org/media/downloads/PIL-1.1.7.tar.gz -pip install -r ./integration-tests/requirements.txt - -pushd $HOME - -# download precompiled libevhtp -libevhtp_bin=libevhtp-bin_1.2.0.tar.gz -wget https://dl.bintray.com/lins05/generic/libevhtp-bin/$libevhtp_bin -tar xf $libevhtp_bin -find $HOME/opt - -# download precompiled libzdb -# zdb_bin=libzdb-bin_2.11.1.tar.gz -# wget https://dl.bintray.com/lins05/generic/libzdb-bin/$zdb_bin -# tar xf $zdb_bin -# sed -i -e "s|prefix=/opt/local|prefix=$HOME/opt/local|g" $HOME/opt/local/lib/pkgconfig/zdb.pc -# find $HOME/opt -pushd /tmp/ -git clone --depth=1 https://github.com/haiwen/libzdb.git -cd libzdb -./bootstrap -./configure --prefix=$HOME/opt/local -make -j2 -make install -popd - -# download seahub thirdpart python libs -WGET="wget --no-check-certificate" -downloads=$HOME/downloads -thirdpart=$HOME/thirdpart - -mkdir -p $downloads $thirdpart -cd $thirdpart -save_pythonpath=$PYTHONPATH -export PYTHONPATH=. -urls=( - https://pypi.python.org/packages/source/p/pytz/pytz-2016.1.tar.gz - https://www.djangoproject.com/m/releases/1.8/Django-1.8.10.tar.gz - https://pypi.python.org/packages/source/d/django-statici18n/django-statici18n-1.1.3.tar.gz - https://pypi.python.org/packages/source/d/djangorestframework/djangorestframework-3.3.2.tar.gz - https://pypi.python.org/packages/source/d/django_compressor/django_compressor-1.4.tar.gz - - https://pypi.python.org/packages/source/j/jsonfield/jsonfield-1.0.3.tar.gz - https://pypi.python.org/packages/source/d/django-post_office/django-post_office-2.0.6.tar.gz - - http://pypi.python.org/packages/source/g/gunicorn/gunicorn-19.4.5.tar.gz - http://pypi.python.org/packages/source/f/flup/flup-1.0.2.tar.gz - https://pypi.python.org/packages/source/c/chardet/chardet-2.3.0.tar.gz - https://labix.org/download/python-dateutil/python-dateutil-1.5.tar.gz - https://pypi.python.org/packages/source/s/six/six-1.9.0.tar.gz - - https://pypi.python.org/packages/source/d/django-picklefield/django-picklefield-0.3.2.tar.gz - https://pypi.python.org/packages/source/d/django-constance/django-constance-1.0.1.tar.gz - - https://pypi.python.org/packages/source/j/jdcal/jdcal-1.2.tar.gz - https://pypi.python.org/packages/source/e/et_xmlfile/et_xmlfile-1.0.1.tar.gz - https://pypi.python.org/packages/source/o/openpyxl/openpyxl-2.3.0.tar.gz -) -for url in ${urls[*]}; do - path="${downloads}/$(basename $url)" - if [[ ! -e $path ]]; then - $WGET -O $path $url - fi - easy_install -d . $path -done -export PYTHONPATH=$save_pythonpath - -popd diff --git a/integration-tests/requirements.txt b/integration-tests/requirements.txt deleted file mode 100644 index 7edd8f12..00000000 --- a/integration-tests/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -termcolor==1.1.0 -prettytable==0.7.2 -pexpect==4.0 -requests==2.8.0 -httpie -django-constance[database] -MySQL-python==1.2.5 diff --git a/integration-tests/run.py b/integration-tests/run.py deleted file mode 100755 index a40dacd2..00000000 --- a/integration-tests/run.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/usr/bin/env python - -import os -from os.path import abspath, basename, exists, expanduser, join -import sys -import re -import glob -import json -import logging -import requests - -import termcolor -from pexpect import spawn -from utils import green, red, debug, info, warning, cd, shell, chdir, setup_logging -from autosetup import (setup_server, ServerConfig, get_script, server_dir, - start_server, create_test_user, MYSQL_ROOT_PASSWD) - -TOPDIR = abspath(join(os.getcwd(), '..')) -PREFIX = expanduser('~/opt/local') -SRCDIR = '/tmp/src' -INSTALLDIR = '/tmp/haiwen' -THIRDPARTDIR = expanduser('~/thirdpart') - -logger = logging.getLogger(__file__) -seafile_version = '' - -TRAVIS_BRANCH = os.environ.get('TRAVIS_BRANCH', 'master') - - -def make_build_env(): - env = dict(os.environ) - libsearpc_dir = abspath(join(TOPDIR, 'libsearpc')) - ccnet_dir = abspath(join(TOPDIR, 'ccnet')) - - def _env_add(*a, **kw): - kw['env'] = env - return prepend_env_value(*a, **kw) - - _env_add('CPPFLAGS', '-I%s' % join(PREFIX, 'include'), seperator=' ') - - _env_add('LDFLAGS', '-L%s' % os.path.join(PREFIX, 'lib'), seperator=' ') - - _env_add('LDFLAGS', '-L%s' % os.path.join(PREFIX, 'lib64'), seperator=' ') - - _env_add('PATH', os.path.join(PREFIX, 'bin')) - _env_add('PATH', THIRDPARTDIR) - _env_add('PKG_CONFIG_PATH', os.path.join(PREFIX, 'lib', 'pkgconfig')) - _env_add('PKG_CONFIG_PATH', os.path.join(PREFIX, 'lib64', 'pkgconfig')) - _env_add('PKG_CONFIG_PATH', libsearpc_dir) - _env_add('PKG_CONFIG_PATH', ccnet_dir) - - for key in ('PATH', 'PKG_CONFIG_PATH', 'CPPFLAGS', 'LDFLAGS', - 'PYTHONPATH'): - info('%s: %s', key, env.get(key, '')) - return env - - -def prepend_env_value(name, value, seperator=':', env=None): - '''append a new value to a list''' - env = env or os.environ - current_value = env.get(name, '') - new_value = value - if current_value: - new_value += seperator + current_value - - env[name] = new_value - return env - - -def get_project_branch(project, default_branch='master'): - if project.name == 'seafile': - return TRAVIS_BRANCH - conf = json.loads(requests.get( - 'https://raw.githubusercontent.com/haiwen/seafile-test-deploy/master/branches.json').text) - return conf.get(TRAVIS_BRANCH, {}).get(project.name, - default_branch) - - -class Project(object): - configure_cmd = './configure' - - def __init__(self, name): - self.name = name - self.version = '' - - @property - def url(self): - return 'https://www.github.com/haiwen/{}.git'.format(self.name) - - @property - def projectdir(self): - return join(TOPDIR, self.name) - - @property - def branch(self): - return get_project_branch(self) - - def clone(self): - if exists(self.name): - with cd(self.name): - shell('git fetch origin --tags') - else: - shell('git clone --depth=1 --branch {} {}'.format(self.branch, - self.url)) - - @chdir - def make_dist(self): - info('making tarball for %s', self.name) - if exists('./autogen.sh'): - shell('./autogen.sh') - shell(self.configure_cmd, env=make_build_env()) - shell('make dist') - - @chdir - def copy_dist(self): - self.make_dist() - tarball = glob.glob('*.tar.gz')[0] - info('copying %s to %s', tarball, SRCDIR) - shell('cp {} {}'.format(tarball, SRCDIR)) - m = re.match('{}-(.*).tar.gz'.format(self.name), basename(tarball)) - if m: - self.version = m.group(1) - - @chdir - def use_branch(self, branch): - shell('git checkout {}'.format(branch)) - - -class Ccnet(Project): - def __init__(self): - super(Ccnet, self).__init__('ccnet') - - -class Seafile(Project): - configure_cmd = './configure --enable-client --enable-server' - - def __init__(self): - super(Seafile, self).__init__('seafile') - - @chdir - def copy_dist(self): - super(Seafile, self).copy_dist() - global seafile_version - seafile_version = self.version - - -class Seahub(Project): - def __init__(self): - super(Seahub, self).__init__('seahub') - - @chdir - def make_dist(self): - cmds = [ - # 'git add -f media/css/*.css', - # 'git commit -a -m "%s"' % msg, - './tools/gen-tarball.py --version={} --branch=HEAD >/dev/null' - .format(seafile_version), - ] - for cmd in cmds: - shell(cmd, env=make_build_env()) - - -class SeafDAV(Project): - def __init__(self): - super(SeafDAV, self).__init__('seafdav') - - @chdir - def make_dist(self): - shell('make') - - -class SeafObj(Project): - def __init__(self): - super(SeafObj, self).__init__('seafobj') - - @chdir - def make_dist(self): - shell('make dist') - - -def build_server(libsearpc, ccnet, seafile): - cmd = [ - 'python', - join(TOPDIR, 'seafile/scripts/build/build-server.py'), - '--yes', - '--version=%s' % seafile.version, - '--libsearpc_version=%s' % libsearpc.version, - '--ccnet_version=%s' % ccnet.version, - '--seafile_version=%s' % seafile.version, - '--thirdpartdir=%s' % THIRDPARTDIR, - '--srcdir=%s' % SRCDIR, - '--jobs=4', - ] - shell(cmd, shell=False, env=make_build_env()) - - -def fetch_and_build(): - libsearpc = Project('libsearpc') - ccnet = Ccnet() - seafile = Seafile() - seahub = Seahub() - seafobj = SeafObj() - seafdav = SeafDAV() - - for project in (libsearpc, ccnet, seafile, seahub, seafdav, seafobj): - if project.name != 'seafile': - project.clone() - project.copy_dist() - - build_server(libsearpc, ccnet, seafile) - - -def run_tests(cfg): - # run_python_seafile_tests() - # run_seafdav_tests(cfg) - # must stop seafile server before running seaf-gc - shell('{} stop'.format(get_script(cfg, 'seafile.sh'))) - shell('{} stop'.format(get_script(cfg, 'seahub.sh'))) - shell('{} --verbose --rm-deleted'.format(get_script(cfg, 'seaf-gc.sh'))) - - -def run_python_seafile_tests(): - python_seafile = Project('python-seafile') - if not exists(python_seafile.projectdir): - python_seafile.clone() - shell('pip install -r {}/requirements.txt'.format( - python_seafile.projectdir)) - - with cd(python_seafile.projectdir): - # install python-seafile because seafdav tests needs it - shell('python setup.py install') - shell('py.test') - - -def _seafdav_env(cfg): - env = dict(os.environ) - env['CCNET_CONF_DIR'] = join(INSTALLDIR, 'ccnet') - env['SEAFILE_CONF_DIR'] = join(INSTALLDIR, 'seafile-data') - env['SEAFILE_CENTRAL_CONF_DIR'] = join(INSTALLDIR, 'conf') - for path in glob.glob(join( - server_dir(cfg), 'seafile/lib*/python*/*-packages')): - prepend_env_value('PYTHONPATH', path, env=env) - return env - - -def run_seafdav_tests(cfg): - seafdav = SeafDAV() - shell('pip install -r {}/test-requirements.txt'.format(seafdav.projectdir)) - with cd(seafdav.projectdir): - shell('nosetests -v -s', env=_seafdav_env(cfg)) - - -def _mkdirs(*paths): - for path in paths: - if not exists(path): - os.mkdir(path) - - -def main(): - _mkdirs(SRCDIR, INSTALLDIR) - setup_logging() - fetch_and_build() - for db in ('sqlite3', 'mysql'): - if db == 'mysql': - shell('mysqladmin -u root password %s' % MYSQL_ROOT_PASSWD) - for i in ('prompt', 'auto'): - shell('rm -rf {}/*'.format(INSTALLDIR)) - setup_and_test(db, i) - - -def setup_and_test(db, initmode): - cfg = ServerConfig( - installdir=INSTALLDIR, - tarball=join(TOPDIR, 'seafile-server_{}_x86-64.tar.gz'.format( - seafile_version)), - version=seafile_version, - initmode=initmode) - info('Setting up seafile server with %s database', db) - setup_server(cfg, db) - # enable webdav, we're going to seafdav tests later - shell('''sed -i -e "s/enabled = false/enabled = true/g" {}''' - .format(join(INSTALLDIR, 'conf/seafdav.conf'))) - try: - start_server(cfg) - info('Testing seafile server with %s database', db) - create_test_user(cfg) - run_tests(cfg) - except: - for logfile in glob.glob('{}/logs/*.log'.format(INSTALLDIR)): - shell('echo {0}; cat {0}'.format(logfile)) - for logfile in glob.glob('{}/seafile-server-{}/runtime/*.log'.format( - INSTALLDIR, seafile_version)): - shell('echo {0}; cat {0}'.format(logfile)) - raise - - -if __name__ == '__main__': - os.chdir(TOPDIR) - main() diff --git a/integration-tests/utils.py b/integration-tests/utils.py deleted file mode 100644 index fdb468b0..00000000 --- a/integration-tests/utils.py +++ /dev/null @@ -1,81 +0,0 @@ -#coding: UTF-8 - -import os -from os.path import abspath, basename, exists, expanduser, join -import sys -import re -import logging -from contextlib import contextmanager -from subprocess import Popen, PIPE, CalledProcessError - -import termcolor -import requests -from pexpect import spawn - -logger = logging.getLogger(__file__) - -def _color(s, color): - return s if not os.isatty(sys.stdout.fileno()) \ - else termcolor.colored(str(s), color) - - -def green(s): - return _color(s, 'green') - - -def red(s): - return _color(s, 'red') - - -def debug(fmt, *a): - logger.debug(green(fmt), *a) - - -def info(fmt, *a): - logger.info(green(fmt), *a) - - -def warning(fmt, *a): - logger.warn(red(fmt), *a) - - -def shell(cmd, inputdata=None, **kw): - info('calling "%s" in %s', cmd, kw.get('cwd', os.getcwd())) - kw['shell'] = not isinstance(cmd, list) - kw['stdin'] = PIPE if inputdata else None - p = Popen(cmd, **kw) - if inputdata: - p.communicate(inputdata) - p.wait() - if p.returncode: - raise CalledProcessError(p.returncode, cmd) - - -@contextmanager -def cd(path): - olddir = os.getcwd() - os.chdir(path) - try: - yield - finally: - os.chdir(olddir) - - -def chdir(func): - def wrapped(self, *w, **kw): - with cd(self.projectdir): - return func(self, *w, **kw) - - return wrapped - -def setup_logging(): - kw = { - 'format': '[%(asctime)s][%(module)s]: %(message)s', - 'datefmt': '%m/%d/%Y %H:%M:%S', - 'level': logging.DEBUG, - 'stream': sys.stdout, - } - - logging.basicConfig(**kw) - logging.getLogger('requests.packages.urllib3.connectionpool').setLevel( - logging.WARNING) diff --git a/python/Makefile.am b/python/Makefile.am deleted file mode 100644 index 4034e77e..00000000 --- a/python/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = seafile seaserv diff --git a/python/seafile/Makefile.am b/python/seafile/Makefile.am deleted file mode 100644 index 2d08da6f..00000000 --- a/python/seafile/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -seafiledir=${pyexecdir}/seafile - -seafile_PYTHON = __init__.py rpcclient.py diff --git a/python/seafile/__init__.py b/python/seafile/__init__.py deleted file mode 100644 index df48bda0..00000000 --- a/python/seafile/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -from rpcclient import SeafileRpcClient as RpcClient -from rpcclient import SeafileThreadedRpcClient as ThreadedRpcClient -from rpcclient import MonitorRpcClient as MonitorRpcClient -from rpcclient import SeafServerRpcClient as ServerRpcClient -from rpcclient import SeafServerThreadedRpcClient as ServerThreadedRpcClient - -class TaskType(object): - DOWNLOAD = 0 - UPLOAD = 1 diff --git a/python/seafile/rpcclient.py b/python/seafile/rpcclient.py deleted file mode 100644 index d9ae314f..00000000 --- a/python/seafile/rpcclient.py +++ /dev/null @@ -1,954 +0,0 @@ - -import ccnet -from pysearpc import searpc_func, SearpcError - -class SeafileRpcClient(ccnet.RpcClientBase): - """RPC used in client""" - - def __init__(self, ccnet_client_pool, *args, **kwargs): - ccnet.RpcClientBase.__init__(self, ccnet_client_pool, "seafile-rpcserver", - *args, **kwargs) - - @searpc_func("object", []) - def seafile_get_session_info(): - pass - get_session_info = seafile_get_session_info - - @searpc_func("int", ["string"]) - def seafile_calc_dir_size(path): - pass - calc_dir_size = seafile_calc_dir_size - - @searpc_func("int64", []) - def seafile_get_total_block_size(): - pass - get_total_block_size = seafile_get_total_block_size; - - @searpc_func("string", ["string"]) - def seafile_get_config(key): - pass - get_config = seafile_get_config - - @searpc_func("int", ["string", "string"]) - def seafile_set_config(key, value): - pass - set_config = seafile_set_config - - @searpc_func("int", ["string"]) - def seafile_get_config_int(key): - pass - get_config_int = seafile_get_config_int - - @searpc_func("int", ["string", "int"]) - def seafile_set_config_int(key, value): - pass - set_config_int = seafile_set_config_int - - @searpc_func("int", ["int"]) - def seafile_set_upload_rate_limit(limit): - pass - set_upload_rate_limit = seafile_set_upload_rate_limit - - @searpc_func("int", ["int"]) - def seafile_set_download_rate_limit(limit): - pass - set_download_rate_limit = seafile_set_download_rate_limit - - ### repo - @searpc_func("objlist", ["int", "int"]) - def seafile_get_repo_list(): - pass - get_repo_list = seafile_get_repo_list - - @searpc_func("object", ["string"]) - def seafile_get_repo(): - pass - get_repo = seafile_get_repo - - @searpc_func("string", ["string", "string", "string", "string", "string", "int"]) - def seafile_create_repo(name, desc, passwd, base, relay_id, keep_history): - pass - create_repo = seafile_create_repo - - @searpc_func("int", ["string"]) - def seafile_destroy_repo(repo_id): - pass - remove_repo = seafile_destroy_repo - - @searpc_func("objlist", ["string", "string", "string", "int"]) - def seafile_diff(): - pass - get_diff = seafile_diff - - @searpc_func("object", ["string", "int", "string"]) - def seafile_get_commit(repo_id, version, commit_id): - pass - get_commit = seafile_get_commit - - @searpc_func("objlist", ["string", "int", "int"]) - def seafile_get_commit_list(): - pass - get_commit_list = seafile_get_commit_list - - @searpc_func("objlist", ["string"]) - def seafile_branch_gets(repo_id): - pass - branch_gets = seafile_branch_gets - - @searpc_func("int", ["string", "string"]) - def seafile_branch_add(repo_id, branch): - pass - branch_add = seafile_branch_add - - ##### clone related - @searpc_func("string", ["string", "string"]) - def gen_default_worktree(worktree_parent, repo_name): - pass - - @searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"]) - def seafile_clone(repo_id, repo_version, peer_id, repo_name, worktree, token, password, magic, peer_addr, peer_port, email, random_key, enc_version, more_info): - pass - clone = seafile_clone - - @searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"]) - def seafile_download(repo_id, repo_version, peer_id, repo_name, wt_parent, token, password, magic, peer_addr, peer_port, email, random_key, enc_version, more_info): - pass - download = seafile_download - - @searpc_func("int", ["string"]) - def seafile_cancel_clone_task(repo_id): - pass - cancel_clone_task = seafile_cancel_clone_task - - @searpc_func("int", ["string"]) - def seafile_remove_clone_task(repo_id): - pass - remove_clone_task = seafile_remove_clone_task - - @searpc_func("objlist", []) - def seafile_get_clone_tasks(): - pass - get_clone_tasks = seafile_get_clone_tasks - - @searpc_func("object", ["string"]) - def seafile_find_transfer_task(repo_id): - pass - find_transfer_task = seafile_find_transfer_task - - @searpc_func("object", ["string"]) - def seafile_get_checkout_task(repo_id): - pass - get_checkout_task = seafile_get_checkout_task - - ### sync - @searpc_func("int", ["string", "string"]) - def seafile_sync(repo_id, peer_id): - pass - sync = seafile_sync - - @searpc_func("object", ["string"]) - def seafile_get_repo_sync_task(): - pass - get_repo_sync_task = seafile_get_repo_sync_task - - @searpc_func("object", ["string"]) - def seafile_get_repo_sync_info(): - pass - get_repo_sync_info = seafile_get_repo_sync_info - - @searpc_func("int", []) - def seafile_is_auto_sync_enabled(): - pass - is_auto_sync_enabled = seafile_is_auto_sync_enabled - - ###### Property Management ######### - - @searpc_func("int", ["string", "string"]) - def seafile_set_repo_passwd(repo_id, passwd): - pass - set_repo_passwd = seafile_set_repo_passwd - - @searpc_func("int", ["string", "string", "string"]) - def seafile_set_repo_property(repo_id, key, value): - pass - set_repo_property = seafile_set_repo_property - - @searpc_func("string", ["string", "string"]) - def seafile_get_repo_property(repo_id, key): - pass - get_repo_property = seafile_get_repo_property - - @searpc_func("string", ["string"]) - def seafile_get_repo_relay_address(repo_id): - pass - get_repo_relay_address = seafile_get_repo_relay_address - - @searpc_func("string", ["string"]) - def seafile_get_repo_relay_port(repo_id): - pass - get_repo_relay_port = seafile_get_repo_relay_port - - @searpc_func("int", ["string", "string", "string"]) - def seafile_update_repo_relay_info(repo_id, addr, port): - pass - update_repo_relay_info = seafile_update_repo_relay_info - - @searpc_func("int", ["string", "string"]) - def seafile_set_repo_token(repo_id, token): - pass - set_repo_token = seafile_set_repo_token - - @searpc_func("string", ["string"]) - def seafile_get_repo_token(repo_id): - pass - get_repo_token = seafile_get_repo_token - - @searpc_func("object", ["int", "string", "string"]) - def seafile_generate_magic_and_random_key(enc_version, repo_id, password): - pass - generate_magic_and_random_key = seafile_generate_magic_and_random_key - -class SeafileThreadedRpcClient(ccnet.RpcClientBase): - """RPC used in client that run in a thread""" - - def __init__(self, ccnet_client_pool, *args, **kwargs): - ccnet.RpcClientBase.__init__(self, ccnet_client_pool, - "seafile-threaded-rpcserver", - *args, **kwargs) - - @searpc_func("int", ["string", "string", "string"]) - def seafile_edit_repo(): - pass - edit_repo = seafile_edit_repo - - @searpc_func("int", ["string", "string"]) - def seafile_reset(repo_id, commit_id): - pass - reset = seafile_reset - - @searpc_func("int", ["string", "string"]) - def seafile_revert(repo_id, commit_id): - pass - revert = seafile_revert - - @searpc_func("int", ["string", "string"]) - def seafile_add(repo_id, path): - pass - add = seafile_add - - @searpc_func("int", ["string", "string"]) - def seafile_rm(): - pass - rm = seafile_rm - - @searpc_func("string", ["string", "string"]) - def seafile_commit(repo_id, description): - pass - commit = seafile_commit - - -class MonitorRpcClient(ccnet.RpcClientBase): - - def __init__(self, ccnet_client_pool): - ccnet.RpcClientBase.__init__(self, ccnet_client_pool, "monitor-rpcserver") - - @searpc_func("int", ["string"]) - def monitor_get_repos_size(repo_ids): - pass - get_repos_size = monitor_get_repos_size - - -class SeafServerRpcClient(ccnet.RpcClientBase): - - def __init__(self, ccnet_client_pool, *args, **kwargs): - ccnet.RpcClientBase.__init__(self, ccnet_client_pool, "seafserv-rpcserver", - *args, **kwargs) - - # token for web access to repo - @searpc_func("string", ["string", "string", "string", "string", "int"]) - def seafile_web_get_access_token(repo_id, obj_id, op, username, use_onetime=1): - pass - web_get_access_token = seafile_web_get_access_token - - @searpc_func("object", ["string"]) - def seafile_web_query_access_token(token): - pass - web_query_access_token = seafile_web_query_access_token - - @searpc_func("string", ["string"]) - def seafile_query_zip_progress(token): - pass - query_zip_progress = seafile_query_zip_progress - - ###### GC #################### - @searpc_func("int", []) - def seafile_gc(): - pass - gc = seafile_gc - - @searpc_func("int", []) - def seafile_gc_get_progress(): - pass - gc_get_progress = seafile_gc_get_progress - - # password management - @searpc_func("int", ["string", "string"]) - def seafile_is_passwd_set(repo_id, user): - pass - is_passwd_set = seafile_is_passwd_set - - @searpc_func("object", ["string", "string"]) - def seafile_get_decrypt_key(repo_id, user): - pass - get_decrypt_key = seafile_get_decrypt_key - - # Copy tasks - - @searpc_func("object", ["string"]) - def get_copy_task(task_id): - pass - - @searpc_func("int", ["string"]) - def cancel_copy_task(task_id): - pass - -class SeafServerThreadedRpcClient(ccnet.RpcClientBase): - - def __init__(self, ccnet_client_pool, *args, **kwargs): - ccnet.RpcClientBase.__init__(self, ccnet_client_pool, - "seafserv-threaded-rpcserver", - *args, **kwargs) - - # repo manipulation - @searpc_func("string", ["string", "string", "string", "string"]) - def seafile_create_repo(name, desc, owner_email, passwd): - pass - create_repo = seafile_create_repo - - @searpc_func("string", ["string", "string", "string", "string", "string", "string", "int"]) - def seafile_create_enc_repo(repo_id, name, desc, owner_email, magic, random_key, enc_version): - pass - create_enc_repo = seafile_create_enc_repo - - @searpc_func("object", ["string"]) - def seafile_get_repo(repo_id): - pass - get_repo = seafile_get_repo - - @searpc_func("int", ["string"]) - def seafile_destroy_repo(repo_id): - pass - remove_repo = seafile_destroy_repo - - @searpc_func("objlist", ["int", "int"]) - def seafile_get_repo_list(start, limit): - pass - get_repo_list = seafile_get_repo_list - - @searpc_func("int64", []) - def seafile_count_repos(): - pass - count_repos = seafile_count_repos - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_edit_repo(repo_id, name, description, user): - pass - edit_repo = seafile_edit_repo - - @searpc_func("int", ["string", "string"]) - def seafile_is_repo_owner(user_id, repo_id): - pass - is_repo_owner = seafile_is_repo_owner - - @searpc_func("int", ["string", "string"]) - def seafile_set_repo_owner(email, repo_id): - pass - set_repo_owner = seafile_set_repo_owner - - @searpc_func("string", ["string"]) - def seafile_get_repo_owner(repo_id): - pass - get_repo_owner = seafile_get_repo_owner - - @searpc_func("objlist", []) - def seafile_get_orphan_repo_list(): - pass - get_orphan_repo_list = seafile_get_orphan_repo_list - - @searpc_func("objlist", ["string", "int"]) - def seafile_list_owned_repos(user_id, ret_corrupted): - pass - list_owned_repos = seafile_list_owned_repos - - @searpc_func("int64", ["string"]) - def seafile_server_repo_size(repo_id): - pass - server_repo_size = seafile_server_repo_size - - @searpc_func("int", ["string", "string"]) - def seafile_repo_set_access_property(repo_id, role): - pass - repo_set_access_property = seafile_repo_set_access_property - - @searpc_func("string", ["string"]) - def seafile_repo_query_access_property(repo_id): - pass - repo_query_access_property = seafile_repo_query_access_property - - @searpc_func("int", ["string", "string", "string"]) - def seafile_revert_on_server(repo_id, commit_id, user_name): - pass - revert_on_server = seafile_revert_on_server - - @searpc_func("objlist", ["string", "string", "string"]) - def seafile_diff(): - pass - get_diff = seafile_diff - - @searpc_func("int", ["string", "string", "string", "string", "string"]) - def seafile_post_file(repo_id, tmp_file_path, parent_dir, filename, user): - pass - post_file = seafile_post_file - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_post_dir(repo_id, parent_dir, new_dir_name, user): - pass - post_dir = seafile_post_dir - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_post_empty_file(repo_id, parent_dir, filename, user): - pass - post_empty_file = seafile_post_empty_file - - @searpc_func("int", ["string", "string", "string", "string", "string", "string"]) - def seafile_put_file(repo_id, tmp_file_path, parent_dir, filename, user, head_id): - pass - put_file = seafile_put_file - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_del_file(repo_id, parent_dir, filename, user): - pass - del_file = seafile_del_file - - @searpc_func("object", ["string", "string", "string", "string", "string", "string", "string", "int", "int"]) - def seafile_copy_file(src_repo, src_dir, src_filename, dst_repo, dst_dir, dst_filename, user, need_progress, synchronous): - pass - copy_file = seafile_copy_file - - @searpc_func("object", ["string", "string", "string", "string", "string", "string", "int", "string", "int", "int"]) - def seafile_move_file(src_repo, src_dir, src_filename, dst_repo, dst_dir, dst_filename, replace, user, need_progress, synchronous): - pass - move_file = seafile_move_file - - @searpc_func("int", ["string", "string", "string", "string", "string"]) - def seafile_rename_file(repo_id, parent_dir, oldname, newname, user): - pass - rename_file = seafile_rename_file - - @searpc_func("int", ["string", "string"]) - def seafile_is_valid_filename(repo_id, filename): - pass - is_valid_filename = seafile_is_valid_filename - - @searpc_func("object", ["string", "int", "string"]) - def seafile_get_commit(repo_id, version, commit_id): - pass - get_commit = seafile_get_commit - - @searpc_func("string", ["string", "string", "int", "int"]) - def seafile_list_file_blocks(repo_id, file_id, offset, limit): - pass - list_file_blocks = seafile_list_file_blocks - - @searpc_func("objlist", ["string", "string", "int", "int"]) - def seafile_list_dir(repo_id, dir_id, offset, limit): - pass - list_dir = seafile_list_dir - - @searpc_func("objlist", ["string", "string", "sting", "string", "int", "int"]) - def list_dir_with_perm(repo_id, dir_path, dir_id, user, offset, limit): - pass - - @searpc_func("int64", ["string", "int", "string"]) - def seafile_get_file_size(store_id, version, file_id): - pass - get_file_size = seafile_get_file_size - - @searpc_func("int64", ["string", "int", "string"]) - def seafile_get_dir_size(store_id, version, dir_id): - pass - get_dir_size = seafile_get_dir_size - - @searpc_func("objlist", ["string", "string", "string"]) - def seafile_list_dir_by_path(repo_id, commit_id, path): - pass - list_dir_by_path = seafile_list_dir_by_path - - @searpc_func("string", ["string", "string", "string"]) - def seafile_get_dir_id_by_commit_and_path(repo_id, commit_id, path): - pass - get_dir_id_by_commit_and_path = seafile_get_dir_id_by_commit_and_path - - @searpc_func("string", ["string", "string"]) - def seafile_get_file_id_by_path(repo_id, path): - pass - get_file_id_by_path = seafile_get_file_id_by_path - - @searpc_func("string", ["string", "string"]) - def seafile_get_dir_id_by_path(repo_id, path): - pass - get_dir_id_by_path = seafile_get_dir_id_by_path - - @searpc_func("string", ["string", "string", "string"]) - def seafile_get_file_id_by_commit_and_path(repo_id, commit_id, path): - pass - get_file_id_by_commit_and_path = seafile_get_file_id_by_commit_and_path - - @searpc_func("object", ["string", "string"]) - def seafile_get_dirent_by_path(repo_id, commit_id, path): - pass - get_dirent_by_path = seafile_get_dirent_by_path - - @searpc_func("objlist", ["string", "string", "int", "int", "int"]) - def seafile_list_file_revisions(repo_id, path, max_revision, limit, show_days): - pass - list_file_revisions = seafile_list_file_revisions - - @searpc_func("objlist", ["string", "string"]) - def seafile_calc_files_last_modified(repo_id, parent_dir, limit): - pass - calc_files_last_modified = seafile_calc_files_last_modified - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_revert_file(repo_id, commit_id, path, user): - pass - revert_file = seafile_revert_file - - @searpc_func("string", ["string", "string"]) - def seafile_check_repo_blocks_missing(repo_id, blklist): - pass - check_repo_blocks_missing = seafile_check_repo_blocks_missing - - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_revert_dir(repo_id, commit_id, path, user): - pass - revert_dir = seafile_revert_dir - - @searpc_func("objlist", ["string", "int", "string", "string", "int"]) - def get_deleted(repo_id, show_days, path, scan_stat, limit): - pass - - # share repo to user - @searpc_func("string", ["string", "string", "string", "string"]) - def seafile_add_share(repo_id, from_email, to_email, permission): - pass - add_share = seafile_add_share - - @searpc_func("objlist", ["string", "string", "int", "int"]) - def seafile_list_share_repos(email, query_col, start, limit): - pass - list_share_repos = seafile_list_share_repos - - @searpc_func("objlist", ["string", "string"]) - def seafile_list_repo_shared_to(from_user, repo_id): - pass - list_repo_shared_to = seafile_list_repo_shared_to - - @searpc_func("int", ["string", "string", "string", "string", "string", "string"]) - def share_subdir_to_user(repo_id, path, owner, share_user, permission, passwd): - pass - - @searpc_func("int", ["string", "string", "string", "string"]) - def unshare_subdir_for_user(repo_id, path, owner, share_user): - pass - - @searpc_func("int", ["string", "string", "string", "string", "string"]) - def update_share_subdir_perm_for_user(repo_id, path, owner, share_user, permission): - pass - - @searpc_func("objlist", ["int", "string", "string", "int", "int"]) - def seafile_list_org_share_repos(org_id, email, query_col, start, limit): - pass - list_org_share_repos = seafile_list_org_share_repos - - @searpc_func("int", ["string", "string", "string"]) - def seafile_remove_share(repo_id, from_email, to_email): - pass - remove_share = seafile_remove_share - - @searpc_func("int", ["string", "string", "string", "string"]) - def set_share_permission(repo_id, from_email, to_email, permission): - pass - - # share repo to group - @searpc_func("int", ["string", "int", "string", "string"]) - def seafile_group_share_repo(repo_id, group_id, user_name, permisson): - pass - group_share_repo = seafile_group_share_repo - - @searpc_func("int", ["string", "int", "string"]) - def seafile_group_unshare_repo(repo_id, group_id, user_name): - pass - group_unshare_repo = seafile_group_unshare_repo - - @searpc_func("string", ["string"]) - def seafile_get_shared_groups_by_repo(repo_id): - pass - get_shared_groups_by_repo=seafile_get_shared_groups_by_repo - - @searpc_func("objlist", ["string", "string"]) - def seafile_list_repo_shared_group(from_user, repo_id): - pass - list_repo_shared_group = seafile_list_repo_shared_group - - @searpc_func("objlist", ["string", "string", "string"]) - def seafile_get_shared_users_for_subdir(repo_id, path, from_user): - pass - get_shared_users_for_subdir = seafile_get_shared_users_for_subdir - - @searpc_func("objlist", ["string", "string", "string"]) - def seafile_get_shared_groups_for_subdir(repo_id, path, from_user): - pass - get_shared_groups_for_subdir = seafile_get_shared_groups_for_subdir - - @searpc_func("int", ["string", "string", "string", "int", "string", "string"]) - def share_subdir_to_group(repo_id, path, owner, share_group, permission, passwd): - pass - - @searpc_func("int", ["string", "string", "string", "int"]) - def unshare_subdir_for_group(repo_id, path, owner, share_group): - pass - - @searpc_func("int", ["string", "string", "string", "int", "string"]) - def update_share_subdir_perm_for_group(repo_id, path, owner, share_group, permission): - pass - - @searpc_func("string", ["int"]) - def seafile_get_group_repoids(group_id): - pass - get_group_repoids = seafile_get_group_repoids - - @searpc_func("objlist", ["int"]) - def seafile_get_repos_by_group(group_id): - pass - get_repos_by_group = seafile_get_repos_by_group - - @searpc_func("objlist", ["string"]) - def get_group_repos_by_owner(user_name): - pass - - @searpc_func("string", ["string"]) - def get_group_repo_owner(repo_id): - pass - - @searpc_func("int", ["int", "string"]) - def seafile_remove_repo_group(group_id, user_name): - pass - remove_repo_group = seafile_remove_repo_group - - @searpc_func("int", ["int", "string", "string"]) - def set_group_repo_permission(group_id, repo_id, permission): - pass - - # branch and commit - @searpc_func("objlist", ["string"]) - def seafile_branch_gets(repo_id): - pass - branch_gets = seafile_branch_gets - - @searpc_func("objlist", ["string", "int", "int"]) - def seafile_get_commit_list(repo_id, offset, limit): - pass - get_commit_list = seafile_get_commit_list - - - ###### Token #################### - - @searpc_func("int", ["string", "string", "string"]) - def seafile_set_repo_token(repo_id, email, token): - pass - set_repo_token = seafile_set_repo_token - - @searpc_func("string", ["string", "string"]) - def seafile_get_repo_token_nonnull(repo_id, email): - """Get the token of the repo for the email user. If the token does not - exist, a new one is generated and returned. - - """ - pass - get_repo_token_nonnull = seafile_get_repo_token_nonnull - - - @searpc_func("string", ["string", "string"]) - def seafile_generate_repo_token(repo_id, email): - pass - generate_repo_token = seafile_generate_repo_token - - @searpc_func("int", ["string", "string"]) - def seafile_delete_repo_token(repo_id, token, user): - pass - delete_repo_token = seafile_delete_repo_token - - @searpc_func("objlist", ["string"]) - def seafile_list_repo_tokens(repo_id): - pass - list_repo_tokens = seafile_list_repo_tokens - - @searpc_func("objlist", ["string"]) - def seafile_list_repo_tokens_by_email(email): - pass - list_repo_tokens_by_email = seafile_list_repo_tokens_by_email - - @searpc_func("int", ["string", "string"]) - def seafile_delete_repo_tokens_by_peer_id(email, user_id): - pass - delete_repo_tokens_by_peer_id = seafile_delete_repo_tokens_by_peer_id - - @searpc_func("int", ["string"]) - def delete_repo_tokens_by_email(email): - pass - - ###### quota ########## - @searpc_func("int64", ["string"]) - def seafile_get_user_quota_usage(user_id): - pass - get_user_quota_usage = seafile_get_user_quota_usage - - @searpc_func("int64", ["string"]) - def seafile_get_user_share_usage(user_id): - pass - get_user_share_usage = seafile_get_user_share_usage - - @searpc_func("int64", ["int"]) - def seafile_get_org_quota_usage(org_id): - pass - get_org_quota_usage = seafile_get_org_quota_usage - - @searpc_func("int64", ["int", "string"]) - def seafile_get_org_user_quota_usage(org_id, user): - pass - get_org_user_quota_usage = seafile_get_org_user_quota_usage - - @searpc_func("int", ["string", "int64"]) - def set_user_quota(user, quota): - pass - - @searpc_func("int64", ["string"]) - def get_user_quota(user): - pass - - @searpc_func("int", ["int", "int64"]) - def set_org_quota(org_id, quota): - pass - - @searpc_func("int64", ["int"]) - def get_org_quota(org_id): - pass - - @searpc_func("int", ["int", "string", "int64"]) - def set_org_user_quota(org_id, user, quota): - pass - - @searpc_func("int64", ["int", "string"]) - def get_org_user_quota(org_id, user): - pass - - @searpc_func("int", ["string"]) - def check_quota(repo_id): - pass - - # password management - @searpc_func("int", ["string", "string"]) - def seafile_check_passwd(repo_id, magic): - pass - check_passwd = seafile_check_passwd - - @searpc_func("int", ["string", "string", "string"]) - def seafile_set_passwd(repo_id, user, passwd): - pass - set_passwd = seafile_set_passwd - - @searpc_func("int", ["string", "string"]) - def seafile_unset_passwd(repo_id, user, passwd): - pass - unset_passwd = seafile_unset_passwd - - # repo permission checking - @searpc_func("string", ["string", "string"]) - def check_permission(repo_id, user): - pass - - # folder permission check - @searpc_func("string", ["string", "string", "string"]) - def check_permission_by_path(repo_id, path, user): - pass - - # org repo - @searpc_func("string", ["string", "string", "string", "string", "string", "int", "int"]) - def seafile_create_org_repo(name, desc, user, passwd, magic, random_key, enc_version, org_id): - pass - create_org_repo = seafile_create_org_repo - - @searpc_func("int", ["string"]) - def seafile_get_org_id_by_repo_id(repo_id): - pass - get_org_id_by_repo_id = seafile_get_org_id_by_repo_id - - @searpc_func("objlist", ["int", "int", "int"]) - def seafile_get_org_repo_list(org_id, start, limit): - pass - get_org_repo_list = seafile_get_org_repo_list - - @searpc_func("int", ["int"]) - def seafile_remove_org_repo_by_org_id(org_id): - pass - remove_org_repo_by_org_id = seafile_remove_org_repo_by_org_id - - @searpc_func("objlist", ["int", "string"]) - def list_org_repos_by_owner(org_id, user): - pass - - @searpc_func("string", ["string"]) - def get_org_repo_owner(repo_id): - pass - - # org group repo - @searpc_func("int", ["string", "int", "int", "string", "string"]) - def add_org_group_repo(repo_id, org_id, group_id, owner, permission): - pass - - @searpc_func("int", ["string", "int", "int"]) - def del_org_group_repo(repo_id, org_id, group_id): - pass - - @searpc_func("string", ["int", "int"]) - def get_org_group_repoids(org_id, group_id): - pass - - @searpc_func("string", ["int", "int", "string"]) - def get_org_group_repo_owner(org_id, group_id, repo_id): - pass - - @searpc_func("objlist", ["int", "string"]) - def get_org_group_repos_by_owner(org_id, user): - pass - - @searpc_func("string", ["int", "string"]) - def get_org_groups_by_repo(org_id, repo_id): - pass - - @searpc_func("int", ["int", "int", "string", "string"]) - def set_org_group_repo_permission(org_id, group_id, repo_id, permission): - pass - - # inner pub repo - @searpc_func("int", ["string", "string"]) - def set_inner_pub_repo(repo_id, permission): - pass - - @searpc_func("int", ["string"]) - def unset_inner_pub_repo(repo_id): - pass - - @searpc_func("objlist", []) - def list_inner_pub_repos(): - pass - - @searpc_func("objlist", ["string"]) - def list_inner_pub_repos_by_owner(user): - pass - - @searpc_func("int64", []) - def count_inner_pub_repos(): - pass - - @searpc_func("int", ["string"]) - def is_inner_pub_repo(repo_id): - pass - - # org inner pub repo - @searpc_func("int", ["int", "string", "string"]) - def set_org_inner_pub_repo(org_id, repo_id, permission): - pass - - @searpc_func("int", ["int", "string"]) - def unset_org_inner_pub_repo(org_id, repo_id): - pass - - @searpc_func("objlist", ["int"]) - def list_org_inner_pub_repos(org_id): - pass - - @searpc_func("objlist", ["int", "string"]) - def list_org_inner_pub_repos_by_owner(org_id, user): - pass - - @searpc_func("int", ["string", "int"]) - def set_repo_history_limit(repo_id, days): - pass - - @searpc_func("int", ["string"]) - def get_repo_history_limit(repo_id): - pass - - # virtual repo - @searpc_func("string", ["string", "string", "string", "string", "string", "string"]) - def create_virtual_repo(origin_repo_id, path, repo_name, repo_desc, owner, passwd=''): - pass - - @searpc_func("objlist", ["string"]) - def get_virtual_repos_by_owner(owner): - pass - - @searpc_func("object", ["string", "string", "string"]) - def get_virtual_repo(origin_repo, path, owner): - pass - - # system default library - @searpc_func("string", []) - def get_system_default_repo_id(): - pass - - # Change password - @searpc_func("int", ["string", "string", "string", "string"]) - def seafile_change_repo_passwd(repo_id, old_passwd, new_passwd, user): - pass - change_repo_passwd = seafile_change_repo_passwd - - # Clean trash - @searpc_func("int", ["string", "int"]) - def clean_up_repo_history(repo_id, keep_days): - pass - - # Trashed repos - @searpc_func("objlist", ["int", "int"]) - def get_trash_repo_list(start, limit): - pass - - @searpc_func("int", ["string"]) - def del_repo_from_trash(repo_id): - pass - - @searpc_func("int", ["string"]) - def restore_repo_from_trash(repo_id): - pass - - @searpc_func("objlist", ["string"]) - def get_trash_repos_by_owner(owner): - pass - - @searpc_func("int", []) - def empty_repo_trash(): - pass - - @searpc_func("int", ["string"]) - def empty_repo_trash_by_owner(owner): - pass - - @searpc_func("object", ["string"]) - def empty_repo_trash_by_owner(owner): - pass - - @searpc_func("object", ["int", "string", "string"]) - def generate_magic_and_random_key(enc_version, repo_id, password): - pass diff --git a/python/seaserv/Makefile.am b/python/seaserv/Makefile.am deleted file mode 100644 index 9edf1deb..00000000 --- a/python/seaserv/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -seaservdir=${pyexecdir}/seaserv - -seaserv_PYTHON = __init__.py service.py api.py diff --git a/python/seaserv/__init__.py b/python/seaserv/__init__.py deleted file mode 100644 index 6b6ab7d2..00000000 --- a/python/seaserv/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ - -import service -from service import ccnet_rpc, seafserv_rpc, seafserv_threaded_rpc, ccnet_threaded_rpc -from service import send_command, check_quota, web_get_access_token, \ - unset_repo_passwd, get_user_quota_usage, get_user_share_usage, \ - get_user_quota -from service import get_emailusers, count_emailusers, get_session_info, \ - get_emailuser_with_import -from service import get_org_groups, get_personal_groups_by_user, \ - get_group_repoids, get_personal_groups, list_share_repos, remove_share, \ - check_group_staff, remove_group_user, get_group, get_org_id_by_group, \ - get_group_members, get_shared_groups_by_repo, is_group_user, \ - get_org_group_repos, get_group_repos, get_org_groups_by_user, is_org_group,\ - del_org_group_repo, get_org_groups_by_repo, get_org_group_repoids, \ - get_group_repos_by_owner, unshare_group_repo -from service import get_repos, get_repo, get_commits, get_branches, remove_repo, \ - get_org_repos, is_repo_owner, create_org_repo, is_inner_pub_repo, \ - list_org_inner_pub_repos, get_org_id_by_repo_id, list_org_shared_repos, \ - list_personal_shared_repos, is_personal_repo, list_inner_pub_repos, \ - is_org_repo_owner, get_org_repo_owner, is_org_repo, get_file_size,\ - list_personal_repos_by_owner, get_repo_token_nonnull, get_repo_owner, \ - server_repo_size, get_file_id_by_path, get_commit, set_repo_history_limit,\ - get_repo_history_limit, list_inner_pub_repos_by_owner, unset_inner_pub_repo,\ - count_inner_pub_repos, edit_repo, list_dir_by_path, create_repo, remove_repo - -from service import get_binding_peerids, is_valid_filename, check_permission,\ - is_passwd_set -from service import create_org, get_orgs_by_user, get_org_by_url_prefix, \ - get_user_current_org, add_org_user, remove_org_user, get_org_by_id, \ - get_org_id_by_repo_id, is_org_staff, get_org_users_by_url_prefix, \ - org_user_exists, list_org_repos_by_owner - -from service import get_related_users_by_repo, get_related_users_by_org_repo -from service import post_empty_file, del_file - -from service import CCNET_CONF_PATH, CCNET_SERVER_ADDR, CCNET_SERVER_PORT, \ - MAX_UPLOAD_FILE_SIZE, MAX_DOWNLOAD_DIR_SIZE, FILE_SERVER_ROOT, \ - CALC_SHARE_USAGE, SERVICE_URL, FILE_SERVER_PORT, SERVER_ID, \ - SEAFILE_CENTRAL_CONF_DIR - -from service import send_message - -from api import seafile_api, ccnet_api diff --git a/python/seaserv/api.py b/python/seaserv/api.py deleted file mode 100644 index 7b2192bb..00000000 --- a/python/seaserv/api.py +++ /dev/null @@ -1,920 +0,0 @@ - -from service import seafserv_rpc, seafserv_threaded_rpc, ccnet_threaded_rpc -from pysearpc import SearpcError - -""" -General rules for return values and exception handling of Seafile python API: -- Read operations return corresponding values. Raises exceptions on parameter errors - or I/O errors in seaf-server. -- Write or set operations return 0 on success, -1 on error. On error, an exceptioin - will be raised. - -All paths in parameters can be in absolute path format (like '/test') or -relative path format (like 'test'). The API can handle both formats. -""" - -class SeafileAPI(object): - - def __init__(self): - pass - - # fileserver token - - def get_fileserver_access_token(self, repo_id, obj_id, op, username, use_onetime=True): - """Generate token for access file/dir in fileserver - - op: the operation, can be 'view', 'download', 'download-dir', 'downloadblks', - 'upload', 'update', 'upload-blks-api', 'upload-blks-aj', - 'update-blks-api', 'update-blks-aj' - - Return: the access token in string - """ - onetime = 1 if bool(use_onetime) else 0 - return seafserv_rpc.web_get_access_token(repo_id, obj_id, op, username, - onetime) - - def query_fileserver_access_token(self, token): - """Get the WebAccess object - - token: the access token in string - - Return: the WebAccess object (lib/webaccess.vala) - """ - return seafserv_rpc.web_query_access_token(token) - - def query_zip_progress(self, token): - """Query zip progress for download-dir, download-multi - token: obtained by get_fileserver_access_token - Return: json formated string `{"zipped":, "total":}`, otherwise None. - """ - return seafserv_rpc.query_zip_progress(token) - - # password - - def is_password_set(self, repo_id, username): - """ - Return non-zero if True, otherwise 0. - """ - return seafserv_rpc.is_passwd_set(repo_id, username) - - def get_decrypt_key(self, repo_id, username): - """ - Return: a CryptKey object (lib/crypt.vala) - """ - return seafserv_rpc.get_decrypt_key(repo_id, username) - - # repo manipulation - - def create_repo(self, name, desc, username, passwd): - return seafserv_threaded_rpc.create_repo(name, desc, username, passwd) - - def create_enc_repo(self, repo_id, name, desc, username, magic, random_key, enc_version): - return seafserv_threaded_rpc.create_enc_repo(repo_id, name, desc, username, magic, random_key, enc_version) - - def get_repo(self, repo_id): - """ - Return: a Repo object (lib/repo.vala) - """ - return seafserv_threaded_rpc.get_repo(repo_id) - - def remove_repo(self, repo_id): - return seafserv_threaded_rpc.remove_repo(repo_id) - - def get_repo_list(self, start, limit): - """ - Return: a list of Repo objects (lib/repo.vala) - """ - return seafserv_threaded_rpc.get_repo_list(start, limit) - - def count_repos(self): - return seafserv_threaded_rpc.count_repos() - - def edit_repo(self, repo_id, name, description, username): - return seafserv_threaded_rpc.edit_repo(repo_id, name, description, username) - - def is_repo_owner(self, username, repo_id): - """ - Return 1 if True, otherwise 0. - """ - return seafserv_threaded_rpc.is_repo_owner(username, repo_id) - - def set_repo_owner(self, email, repo_id): - return seafserv_threaded_rpc.set_repo_owner(email, repo_id) - - def get_repo_owner(self, repo_id): - """ - Return: repo owner in string - """ - return seafserv_threaded_rpc.get_repo_owner(repo_id) - - def get_owned_repo_list(self, username, ret_corrupted=False): - """ - Return: a list of Repo objects - """ - return seafserv_threaded_rpc.list_owned_repos(username, - 1 if ret_corrupted else 0) - - def get_orphan_repo_list(self): - return seafserv_threaded_rpc.get_orphan_repo_list() - - def get_repo_size(self, repo_id): - return seafserv_threaded_rpc.server_repo_size(repo_id) - - def revert_repo(self, repo_id, commit_id, username): - return seafserv_threaded_rpc.revert_on_server(repo_id, commit_id, username) - - def diff_commits(self, repo_id, old_commit, new_commit, fold_dir_diff = 1): - """ - Return: a list of DiffEntry objects (lib/repo.vala) - """ - return seafserv_threaded_rpc.get_diff(repo_id, old_commit, new_commit, fold_dir_diff) - - def get_commit_list(self, repo_id, offset, limit): - """ - Return: a list of Commit objects (lib/commit.vala) - """ - return seafserv_threaded_rpc.get_commit_list(repo_id, offset, limit) - - def change_repo_passwd(self, repo_id, old_passwd, new_passwd, user): - return seafserv_threaded_rpc.change_repo_passwd(repo_id, old_passwd, - new_passwd, user) - - # File property and dir listing - - def is_valid_filename(self, repo_id, filename): - """ - Return: 0 on invalid; 1 on valid. - """ - return seafserv_threaded_rpc.is_valid_filename(repo_id, filename) - - def get_file_size(self, store_id, version, file_id): - return seafserv_threaded_rpc.get_file_size(store_id, version, file_id) - - def get_dir_size(self, store_id, version, dir_id): - """ - Return the size of a dir. It needs to recursively calculate the size - of the dir. It can cause great delay before returning. Use with caution! - """ - return seafserv_threaded_rpc.get_dir_size(store_id, version, dir_id) - - def get_file_id_by_path(self, repo_id, path): - """ - Returns None if path not found. Only raise exception on parameter or IO error. - """ - return seafserv_threaded_rpc.get_file_id_by_path(repo_id, path) - - def get_file_id_by_commit_and_path(self, repo_id, commit_id, path): - return seafserv_threaded_rpc.get_file_id_by_commit_and_path(repo_id, - commit_id, - path) - - def get_dirent_by_path(self, repo_id, path): - """ - Return: a Dirent object (lib/dirent.vala) - """ - return seafserv_threaded_rpc.get_dirent_by_path(repo_id, path) - - def list_file_by_file_id(self, repo_id, file_id, offset=-1, limit=-1): - # deprecated, use list_blocks_by_file_id instead. - return seafserv_threaded_rpc.list_file_blocks(repo_id, file_id, offset, limit) - - def list_blocks_by_file_id(self, repo_id, file_id, offset=-1, limit=-1): - """ - list block ids of a file. - Return: a string containing block list. Each id is seperated by '\n' - """ - return seafserv_threaded_rpc.list_file_blocks(repo_id, file_id, offset, limit) - - def get_dir_id_by_path(self, repo_id, path): - return seafserv_threaded_rpc.get_dir_id_by_path(repo_id, path) - - def list_dir_by_dir_id(self, repo_id, dir_id, offset=-1, limit=-1): - """ - Return: a list of Dirent objects. The objects are sorted as follows: - - Directories are always before files - - Entries are sorted by names in ascending order - """ - return seafserv_threaded_rpc.list_dir(repo_id, dir_id, offset, limit) - - def list_dir_by_path(self, repo_id, path, offset=-1, limit=-1): - dir_id = seafserv_threaded_rpc.get_dir_id_by_path(repo_id, path) - if dir_id is None: - return None - return seafserv_threaded_rpc.list_dir(repo_id, dir_id, offset, limit) - - def list_dir_by_commit_and_path(self, repo_id, - commit_id, path, offset=-1, limit=-1): - dir_id = seafserv_threaded_rpc.get_dir_id_by_commit_and_path(repo_id, commit_id, path) - if dir_id is None: - return None - return seafserv_threaded_rpc.list_dir(repo_id, dir_id, offset, limit) - - def get_dir_id_by_commit_and_path(self, repo_id, commit_id, path): - return seafserv_threaded_rpc.get_dir_id_by_commit_and_path(repo_id, commit_id, path) - - # file/dir operations - - def post_file(self, repo_id, tmp_file_path, parent_dir, filename, username): - """Add a file to a directory""" - return seafserv_threaded_rpc.post_file(repo_id, tmp_file_path, parent_dir, - filename, username) - - def post_empty_file(self, repo_id, parent_dir, filename, username): - return seafserv_threaded_rpc.post_empty_file(repo_id, parent_dir, - filename, username) - - def put_file(self, repo_id, tmp_file_path, parent_dir, filename, - username, head_id): - """Update an existing file - - head_id: the original commit id of the old file - """ - return seafserv_threaded_rpc.put_file(repo_id, tmp_file_path, parent_dir, - filename, username, head_id) - - def del_file(self, repo_id, parent_dir, filename, username): - return seafserv_threaded_rpc.del_file(repo_id, parent_dir, filename, username) - - def copy_file(self, src_repo, src_dir, src_filename, dst_repo, - dst_dir, dst_filename, username, need_progress, synchronous=0): - return seafserv_threaded_rpc.copy_file(src_repo, src_dir, src_filename, - dst_repo, dst_dir, dst_filename, - username, need_progress, synchronous) - - def move_file(self, src_repo, src_dir, src_filename, dst_repo, dst_dir, - dst_filename, replace, username, need_progress, synchronous=0): - return seafserv_threaded_rpc.move_file(src_repo, src_dir, src_filename, - dst_repo, dst_dir, dst_filename, - replace, username, need_progress, synchronous) - - def get_copy_task(self, task_id): - return seafserv_rpc.get_copy_task(task_id) - - def cancel_copy_task(self, task_id): - return seafserv_rpc.cancel_copy_task(task_id) - - def rename_file(self, repo_id, parent_dir, oldname, newname, username): - return seafserv_threaded_rpc.rename_file(repo_id, parent_dir, - oldname, newname, username) - - def post_dir(self, repo_id, parent_dir, dirname, username): - """Add a directory""" - return seafserv_threaded_rpc.post_dir(repo_id, parent_dir, dirname, username) - - def revert_file(self, repo_id, commit_id, path, username): - return seafserv_threaded_rpc.revert_file(repo_id, commit_id, path, username) - - def revert_dir(self, repo_id, commit_id, path, username): - return seafserv_threaded_rpc.revert_dir(repo_id, commit_id, path, username) - - def get_deleted(self, repo_id, show_days, path='/', scan_stat=None, limit=100): - """ - Get list of deleted paths. - - @show_days: return deleted path in the last @show_days - @path: return deleted files under this path. The path will be recursively traversed. - @scan_stat: An opaque status returned by the last call. In the first call, None - must be passed. The last entry of the result list contains a 'scan_stat' - attribute. In the next call, pass in the returned 'scan_stat'. - @limit: Advisory maximum number of result entries returned. Sometimes more than @limit - entries will be returned. - - Return a list of DeletedEntry objects (lib/repo.vala). - If no more deleted entries can be returned within the given time frame (specified by - @show_days) or all deleted entries in the history have been returned, 'None' will be - returned. - """ - return seafserv_threaded_rpc.get_deleted(repo_id, show_days, path, scan_stat, limit) - - def get_file_revisions(self, repo_id, path, max_revision, limit, show_days=-1): - return seafserv_threaded_rpc.list_file_revisions(repo_id, path, - max_revision, limit, - show_days) - - # This api is slow and should only be used for version 0 repos. - def get_files_last_modified(self, repo_id, parent_dir, limit): - """Get last modification time for files in a dir - - limit: the max number of commits to analyze - """ - return seafserv_threaded_rpc.calc_files_last_modified(repo_id, - parent_dir, limit) - - def get_repo_history_limit(self, repo_id): - """ - Return repo history limit in days. Returns -1 if it's unlimited. - """ - return seafserv_threaded_rpc.get_repo_history_limit(repo_id) - - def set_repo_history_limit(self, repo_id, days): - """ - Set repo history limit in days. Pass -1 if set to unlimited. - """ - return seafserv_threaded_rpc.set_repo_history_limit(repo_id, days) - - def check_repo_blocks_missing(self, repo_id, blklist): - return seafserv_threaded_rpc.check_repo_blocks_missing(repo_id, blklist) - - # file lock - def check_file_lock(self, repo_id, path, user): - """ - Always return 0 since CE doesn't support file locking. - """ - return 0 - - # share repo to user - def share_repo(self, repo_id, from_username, to_username, permission): - return seafserv_threaded_rpc.add_share(repo_id, from_username, - to_username, permission) - - def remove_share(self, repo_id, from_username, to_username): - return seafserv_threaded_rpc.remove_share(repo_id, from_username, - to_username) - - def set_share_permission(self, repo_id, from_username, to_username, permission): - return seafserv_threaded_rpc.set_share_permission(repo_id, from_username, - to_username, permission) - - def share_subdir_to_user(self, repo_id, path, owner, share_user, permission, passwd=''): - return seafserv_threaded_rpc.share_subdir_to_user(repo_id, path, owner, - share_user, permission, passwd) - - def unshare_subdir_for_user(self, repo_id, path, owner, share_user): - return seafserv_threaded_rpc.unshare_subdir_for_user(repo_id, path, owner, - share_user) - - def update_share_subdir_perm_for_user(self, repo_id, path, owner, - share_user, permission): - return seafserv_threaded_rpc.update_share_subdir_perm_for_user(repo_id, path, owner, - share_user, permission) - - def get_share_out_repo_list(self, username, start, limit): - """ - Get repo list shared by this user. - Return: a list of Repo objects - """ - return seafserv_threaded_rpc.list_share_repos(username, "from_email", - start, limit) - - def get_share_in_repo_list(self, username, start, limit): - """ - Get repo list shared to this user. - """ - return seafserv_threaded_rpc.list_share_repos(username, "to_email", - start, limit) - - def list_repo_shared_to(self, from_user, repo_id): - """ - Get user list this repo is shared to. - Return: a list of SharedUser objects (lib/repo.vala) - """ - return seafserv_threaded_rpc.list_repo_shared_to(from_user, repo_id) - - # share repo to group - def group_share_repo(self, repo_id, group_id, username, permission): - # deprecated, use ``set_group_repo`` - return seafserv_threaded_rpc.group_share_repo(repo_id, group_id, - username, permission) - - def set_group_repo(self, repo_id, group_id, username, permission): - return seafserv_threaded_rpc.group_share_repo(repo_id, group_id, - username, permission) - - def group_unshare_repo(self, repo_id, group_id, username): - # deprecated, use ``unset_group_repo`` - return seafserv_threaded_rpc.group_unshare_repo(repo_id, group_id, username) - - def unset_group_repo(self, repo_id, group_id, username): - return seafserv_threaded_rpc.group_unshare_repo(repo_id, group_id, username) - - def get_shared_group_ids_by_repo(self, repo_id): - """ - Return: a string containing list of group ids. Each id is seperated by '\n' - """ - return seafserv_threaded_rpc.get_shared_groups_by_repo(repo_id) - - def list_repo_shared_group(self, from_user, repo_id): - # deprecated, use list_repo_shared_group_by_user instead. - return seafserv_threaded_rpc.list_repo_shared_group(from_user, repo_id) - - def list_repo_shared_group_by_user(self, from_user, repo_id): - """ - Return: a list of SharedGroup objects (lib/repo.vala) - """ - return seafserv_threaded_rpc.list_repo_shared_group(from_user, repo_id) - - def share_subdir_to_group(self, repo_id, path, owner, share_group, permission, passwd=''): - return seafserv_threaded_rpc.share_subdir_to_group(repo_id, path, owner, - share_group, permission, passwd) - - def unshare_subdir_for_group(self, repo_id, path, owner, share_group): - return seafserv_threaded_rpc.unshare_subdir_for_group(repo_id, path, owner, - share_group) - - def update_share_subdir_perm_for_group(self, repo_id, path, owner, - share_group, permission): - return seafserv_threaded_rpc.update_share_subdir_perm_for_group(repo_id, path, owner, - share_group, permission) - - def get_group_repoids(self, group_id): - """ - Return the list of group repo ids - """ - repo_ids = seafserv_threaded_rpc.get_group_repoids(group_id) - if not repo_ids: - return [] - l = [] - for repo_id in repo_ids.split("\n"): - if repo_id == '': - continue - l.append(repo_id) - return l - - def get_group_repo_list(self, group_id): - # deprecated, use get_repos_by_group instead. - ret = [] - for repo_id in self.get_group_repoids(group_id): - r = self.get_repo(repo_id) - if r is None: - continue - ret.append(r) - return ret - - def get_repos_by_group(self, group_id): - """ - Return: a list of Repo objects - """ - return seafserv_threaded_rpc.get_repos_by_group(group_id) - - def get_group_repos_by_owner(self, username): - """ - Get all repos a user share to any group - Return: a list of Repo objects - """ - return seafserv_threaded_rpc.get_group_repos_by_owner(username) - - def remove_group_repos_by_owner(self, group_id, username): - """ - Unshare all repos a user shared to a group. - """ - return seafserv_threaded_rpc.remove_repo_group(group_id, username) - - def remove_group_repos(self, group_id): - """ - Remove all repos under group. - Return: 0 success; -1 failed - """ - return seafserv_threaded_rpc.remove_repo_group(group_id, None) - - def set_group_repo_permission(self, group_id, repo_id, permission): - return seafserv_threaded_rpc.set_group_repo_permission(group_id, repo_id, - permission) - - def get_shared_users_for_subdir(self, repo_id, path, from_user): - """ - Get all users a path is shared to. - Return: a list of SharedUser objects. - """ - return seafserv_threaded_rpc.get_shared_users_for_subdir(repo_id, path, from_user) - - def get_shared_groups_for_subdir(self, repo_id, path, from_user): - """ - Get all groups a path is shared to. - Return: a list of SharedGroup objects. - """ - return seafserv_threaded_rpc.get_shared_groups_for_subdir(repo_id, path, from_user) - - # organization wide repo - def add_inner_pub_repo(self, repo_id, permission): - return seafserv_threaded_rpc.set_inner_pub_repo(repo_id, permission) - - def remove_inner_pub_repo(self, repo_id): - return seafserv_threaded_rpc.unset_inner_pub_repo(repo_id) - - def get_inner_pub_repo_list(self): - """ - Return: a list of Repo objects. - """ - return seafserv_threaded_rpc.list_inner_pub_repos() - - def list_inner_pub_repos_by_owner(self, repo_owner): - """ - Return: a list of Repo objects. - """ - return seafserv_threaded_rpc.list_inner_pub_repos_by_owner(repo_owner) - - def count_inner_pub_repos(self): - return seafserv_threaded_rpc.count_inner_pub_repos() - - def is_inner_pub_repo(self, repo_id): - return seafserv_threaded_rpc.is_inner_pub_repo(repo_id) - - # permission checks - def check_permission(self, repo_id, user): - """ - Check repo share permissions. Only check user share, group share and inner-pub - shares. - Return: 'r', 'rw', or None - """ - return seafserv_threaded_rpc.check_permission(repo_id, user) - - def check_permission_by_path(self, repo_id, path, user): - """ - Check both repo share permission and sub-folder access permissions. - This function should be used when updating file/folder in a repo. - In CE, this function is equivalent to check_permission. - Return: 'r', 'rw', or None - """ - return seafserv_threaded_rpc.check_permission_by_path(repo_id, path, user) - - # token - def generate_repo_token(self, repo_id, username): - """Generate a token for sync a repo - """ - return seafserv_threaded_rpc.generate_repo_token(repo_id, username) - - def delete_repo_token(self, repo_id, token, user): - return seafserv_threaded_rpc.delete_repo_token(repo_id, token, user) - - def list_repo_tokens(self, repo_id): - """ - Return: a list of RepoTokenInfo objects. - """ - return seafserv_threaded_rpc.list_repo_tokens(repo_id) - - def list_repo_tokens_by_email(self, username): - return seafserv_threaded_rpc.list_repo_tokens_by_email(username) - - def delete_repo_tokens_by_peer_id(self, email, peer_id): - return seafserv_threaded_rpc.delete_repo_tokens_by_peer_id(email, peer_id) - - def delete_repo_tokens_by_email(self, email): - return seafserv_threaded_rpc.delete_repo_tokens_by_email(email) - - # quota - def get_user_self_usage(self, username): - """Get the sum of repos' size of the user""" - return seafserv_threaded_rpc.get_user_quota_usage(username) - - def get_user_share_usage(self, username): - # sum (repo_size * number_of_shares) - return seafserv_threaded_rpc.get_user_share_usage(username) - - def get_user_quota(self, username): - """ - Return: -2 if quota is unlimited; otherwise it must be number > 0. - """ - return seafserv_threaded_rpc.get_user_quota(username) - - def set_user_quota(self, username, quota): - return seafserv_threaded_rpc.set_user_quota(username, quota) - - def get_user_share_quota(self, username): - return -2 # unlimited - - def set_user_share_quota(self, username, quota): - pass - - def check_quota(self, repo_id): - pass - - # encrypted repo password management - def check_passwd(self, repo_id, magic): - return seafserv_threaded_rpc.check_passwd(repo_id, magic) - - def set_passwd(self, repo_id, user, passwd): - return seafserv_threaded_rpc.set_passwd(repo_id, user, passwd) - - def unset_passwd(self, repo_id, user, passwd): - return seafserv_threaded_rpc.unset_passwd(repo_id, user, passwd) - - def generate_magic_and_random_key(self, enc_version, repo_id, password): - return seafserv_threaded_rpc.generate_magic_and_random_key(enc_version, repo_id, password) - - # virtual repo - def create_virtual_repo(self, origin_repo_id, path, repo_name, repo_desc, owner, passwd=''): - return seafserv_threaded_rpc.create_virtual_repo(origin_repo_id, - path, - repo_name, - repo_desc, - owner, - passwd) - - def get_virtual_repos_by_owner(self, owner): - return seafserv_threaded_rpc.get_virtual_repos_by_owner(owner) - - def get_virtual_repo(self, origin_repo, path, owner): - return seafserv_threaded_rpc.get_virtual_repo(origin_repo, path, owner) - - # Clean trash - - def clean_up_repo_history(self, repo_id, keep_days): - return seafserv_threaded_rpc.clean_up_repo_history(repo_id, keep_days) - - # Trashed repos - def get_trash_repo_list(self, start, limit): - return seafserv_threaded_rpc.get_trash_repo_list(start, limit) - - def del_repo_from_trash(self, repo_id): - return seafserv_threaded_rpc.del_repo_from_trash(repo_id) - - def restore_repo_from_trash(self, repo_id): - return seafserv_threaded_rpc.restore_repo_from_trash(repo_id) - - def get_trash_repos_by_owner(self, owner): - return seafserv_threaded_rpc.get_trash_repos_by_owner(owner) - - def empty_repo_trash(self): - return seafserv_threaded_rpc.empty_repo_trash() - - def empty_repo_trash_by_owner(self, owner): - return seafserv_threaded_rpc.empty_repo_trash_by_owner(owner) - -seafile_api = SeafileAPI() - -class CcnetAPI(object): - - def __init__(self): - pass - - # user management - def add_emailuser(self, email, passwd, is_staff, is_active): - return ccnet_threaded_rpc.add_emailuser(email, passwd, is_staff, is_active) - - def remove_emailuser(self, source, email): - """ - source can be 'DB' or 'LDAP'. - - 'DB': remove a user created in local database - - 'LDAP': remove a user imported from LDAP - """ - return ccnet_threaded_rpc.remove_emailuser(source, email) - - def validate_emailuser(self, email, passwd): - """ - Verify user's password on login. Can be used to verify DB and LDAP users. - The function first verify password with LDAP, then local database. - """ - return ccnet_threaded_rpc.validate_emailuser(email, passwd) - - def get_emailuser(self, email): - """ - Only return local database user or imported LDAP user. - It first lookup user from local database, if not found, lookup imported - LDAP user. - Return: a list of EmailUser objects (ccnet/lib/ccnetobj.vala) - The 'source' attribute of EmailUser object is set to 'LDAPImport' for LDAP - imported user, and 'DB' for local database user. - """ - return ccnet_threaded_rpc.get_emailuser(email) - - def get_emailuser_with_import(self, email): - """ - The same as get_emailuser() but import the user from LDAP if it was not - imported yet. - """ - return ccnet_threaded_rpc.get_emailuser_with_import(email) - - def get_emailuser_by_id(self, user_id): - """ - Get a user from local database with the db index id. - """ - return ccnet_threaded_rpc.get_emailuser_by_id(user_id) - - def get_emailusers(self, source, start, limit, is_active=None): - """ - source: - - 'DB': return local db users - - 'LDAPImport': return imported LDAP users - - 'LDAP': retrieve users directly from LDAP server - start: offset to start retrieving, -1 to start from the beginning - limit: number of users to get, -1 to get all user from start - is_active: True to return only active users; False to return inactive users; - None to return all users. - Return: a list of EmailUser objects. - """ - if is_active is True: - status = "active" # list active users - elif is_active is False: - status = "inactive" # list inactive users - else: - status = "" # list all users - - return ccnet_threaded_rpc.get_emailusers(source, start, limit, status) - - def search_emailusers(self, source, email_patt, start, limit): - """ - Search for users whose name contains @email_patt. - source: 'DB' for local db users; 'LDAP' for imported LDAP users. - This function cannot search LDAP users directly in LDAP server. - """ - return ccnet_threaded_rpc.search_emailusers(source, email_patt, start, limit) - - def search_ldapusers(self, keyword, start, limit): - """ - Search for users whose name contains @keyword directly from LDAP server. - """ - return ccnet_threaded_rpc.search_ladpusers(keyword, start, limit) - - def count_emailusers(self, source): - """ - Return the number of active users by source. - source: 'DB' for local db users; 'LDAP' for imported LDAP users. - """ - return ccnet_threaded_rpc.count_emailusers(source) - - def count_inactive_emailusers(self, source): - """ - Return the number of inactive users by source. - source: 'DB' for local db users; 'LDAP' for imported LDAP users. - """ - return ccnet_threaded_rpc.count_inactive_emailusers(source) - - def update_emailuser(self, source, user_id, password, is_staff, is_active): - """ - source: 'DB' for local db user; 'LDAP' for imported LDAP user. - user_id: usually not changed. - password: new password in plain text. Only effective for DB users. - If '!' is passed, the password won't be updated. - is_staff: change superuser status - is_active: activate or deactivate user - """ - return ccnet_threaded_rpc.update_emailuser(source, user_id, password, is_staff, is_active) - - def update_role_emailuser(self, email, role): - return ccnet_threaded_rpc.update_role_emailuser(email, role) - - def get_superusers(self): - """ - Return: a list of EmailUser objects. - """ - return ccnet_threaded_rpc.get_superusers() - - # group management - def create_group(self, group_name, user_name, gtype=None): - """ - For CE, gtype is not used and should always be None. - """ - return ccnet_threaded_rpc.create_group(group_name, user_name, gtype) - - def create_org_group(self, org_id, group_name, user_name): - return ccnet_threaded_rpc.create_org_group(org_id, group_name, user_name) - - def remove_group(self, group_id): - """ - permission check should be done before calling this function. - """ - return ccnet_threaded_rpc.remove_group(group_id) - - def group_add_member(self, group_id, user_name, member_name): - """ - user_name: unused. - """ - return ccnet_threaded_rpc.group_add_member(group_id, user_name, member_name) - - def group_remove_member(self, group_id, user_name, member_name): - """ - user_name: unused. - """ - return ccnet_threaded_rpc.group_remove_member(group_id, user_name, member_name) - - def group_set_admin(self, group_id, member_name): - """ - No effect if member_name is not in the group. - """ - return ccnet_threaded_rpc.group_set_admin(group_id, member_name) - - def group_unset_admin(self, group_id, member_name): - """ - No effect if member_name is not in the group. - """ - return ccnet_threaded_rpc.group_unset_admin(group_id, member_name) - - def set_group_name(self, group_id, group_name): - return ccnet_threaded_rpc.set_group_name(group_id, group_name) - - def quit_group(self, group_id, user_name): - return ccnet_threaded_rpc.quit_group(group_id, user_name) - - def get_groups(self, user_name): - """ - Get all groups the user belongs to. - Return: a list of Group objects (ccnet/lib/ccnetobj.vala) - """ - return ccnet_threaded_rpc.get_groups(user_name) - - def get_all_groups(self, start, limit, source=None): - """ - For CE, source is not used and should alwasys be None. - """ - return ccnet_threaded_rpc.get_all_groups(start, limit, source) - - def get_group(self, group_id): - return ccnet_threaded_rpc.get_group(group_id) - - def get_group_members(self, group_id): - """ - Return a list of GroupUser objects (ccnet/lib/ccnetobj.vala) - """ - return ccnet_threaded_rpc.get_group_members(group_id) - - def check_group_staff(self, group_id, username): - """ - Return non-zero value if true, 0 if not true - """ - return ccnet_threaded_rpc.check_group_staff(group_id, username) - - def remove_group_user(self, username): - return ccnet_threaded_rpc.remove_group_user(username) - - def is_group_user(self, group_id, user): - """ - Return non-zero value if true, 0 if not true - """ - return ccnet_threaded_rpc.is_group_user(group_id, user) - - def set_group_creator(self, group_id, user_name): - return ccnet_threaded_rpc.set_group_creator(group_id, user_name) - - # organization management - def create_org(self, org_name, url_prefix, creator): - return ccnet_threaded_rpc.create_org(org_name, url_prefix, creator) - - def remove_org(self, org_id): - return ccnet_threaded_rpc.remove_org(org_id) - - def get_all_orgs(self, start, limit): - """ - Return a list of Organization objects (ccnet/lib/ccnetobj.vala) - """ - return ccnet_threaded_rpc.get_all_orgs(start, limit) - - def count_orgs(self): - return ccnet_threaded_rpc.count_orgs() - - def get_org_by_url_prefix(self, url_prefix): - """ - Return an Organizaion object. - """ - return ccnet_threaded_rpc.get_org_by_url_prefix(url_prefix) - - def get_org_by_id(self, org_id): - return ccnet_threaded_rpc.get_org_by_id(org_id) - - def add_org_user(self, org_id, email, is_staff): - return ccnet_threaded_rpc.add_org_user(org_id, email, is_staff) - - def remove_org_user(self, org_id, email): - return ccnet_threaded_rpc.remove_org_user(org_id, email) - - def get_orgs_by_user(self, email): - return ccnet_threaded_rpc.get_orgs_by_user(email) - - def get_org_emailusers(self, url_prefix, start, limit): - """ - Return a list of EmailUser objects. - """ - return ccnet_threaded_rpc.get_org_emailusers(url_prefix, start, limit) - - def add_org_group(self, org_id, group_id): - return ccnet_threaded_rpc.add_org_group(org_id, group_id) - - def remove_org_group(self, org_id, group_id): - return ccnet_threaded_rpc.remove_org_group(org_id, group_id) - - def is_org_group(self, group_id): - """ - Return non-zero if True, otherwise 0. - """ - return ccnet_threaded_rpc.is_org_group(group_id) - - def get_org_id_by_group(self, group_id): - return ccnet_threaded_rpc.get_org_id_by_group(group_id) - - def get_org_groups(self, org_id, start, limit): - """ - Return a list of int, each int is group id. - """ - return ccnet_threaded_rpc.get_org_groups(org_id, start, limit) - - def org_user_exists(self, org_id, email): - """ - Return non-zero if True, otherwise 0. - """ - return ccnet_threaded_rpc.org_user_exists(org_id, email) - - def is_org_staff(self, org_id, user): - """ - Return non-zero if True, otherwise 0. - """ - return ccnet_threaded_rpc.is_org_staff(org_id, user) - - def set_org_staff(self, org_id, user): - return ccnet_threaded_rpc.set_org_staff(org_id, user) - - def unset_org_staff(self, org_id, user): - return ccnet_threaded_rpc.unset_org_staff(org_id, user) - - def set_org_name(self, org_id, org_name): - return ccnet_threaded_rpc.set_org_name(org_id, org_name) - -ccnet_api = CcnetAPI() diff --git a/python/seaserv/service.py b/python/seaserv/service.py deleted file mode 100644 index 71d63814..00000000 --- a/python/seaserv/service.py +++ /dev/null @@ -1,958 +0,0 @@ -from datetime import datetime -import json -import logging -import os -import sys -import ConfigParser -from urlparse import urlparse - -import ccnet -import seafile -import re -from pysearpc import SearpcError - -_DEBUG = 'SEAFILE_DEBUG' in os.environ - -ENVIRONMENT_VARIABLES = ('CCNET_CONF_DIR', 'SEAFILE_CONF_DIR') - -# Used to fix bug in some rpc calls, will be removed in near future. -MAX_INT = 2147483647 - -def _load_path_from_env(key, check=True): - v = os.environ.get(key, '') - if not v: - if check: - raise ImportError("Seaserv cannot be imported, because environment variable %s is undefined." % key) - return None - if _DEBUG: - print "Loading %s from %s" % (key, v) - return os.path.normpath(os.path.expanduser(v)) - -CCNET_CONF_PATH = _load_path_from_env('CCNET_CONF_DIR') -SEAFILE_CONF_DIR = _load_path_from_env('SEAFILE_CONF_DIR') -SEAFILE_CENTRAL_CONF_DIR = _load_path_from_env('SEAFILE_CENTRAL_CONF_DIR', check=False) - -pool = ccnet.ClientPool(CCNET_CONF_PATH, central_config_dir=SEAFILE_CENTRAL_CONF_DIR) -ccnet_rpc = ccnet.CcnetRpcClient(pool, req_pool=True) -ccnet_threaded_rpc = ccnet.CcnetThreadedRpcClient(pool, req_pool=True) -seafserv_rpc = seafile.ServerRpcClient(pool, req_pool=True) -seafserv_threaded_rpc = seafile.ServerThreadedRpcClient(pool, req_pool=True) - -# load ccnet server addr and port from ccnet.conf. -# 'addr:port' is used when downloading a repo -config = ConfigParser.ConfigParser() -config.read(os.path.join(SEAFILE_CENTRAL_CONF_DIR if SEAFILE_CENTRAL_CONF_DIR else CCNET_CONF_PATH, - 'ccnet.conf')) - -if config.has_option('General', 'SERVICE_URL'): - service_url = config.get('General', 'SERVICE_URL') - hostname = urlparse(service_url).hostname - - SERVICE_URL = service_url - CCNET_SERVER_ADDR = hostname - if config.has_option('Network', 'PORT'): - CCNET_SERVER_PORT = config.get('Network', 'PORT') - else: - CCNET_SERVER_PORT = 10001 -else: - print "Warning: SERVICE_URL not set in ccnet.conf" - CCNET_SERVER_ADDR = None - CCNET_SERVER_PORT = None - SERVICE_URL = None - -SERVER_ID = config.get('General', 'ID') -config.read(os.path.join(SEAFILE_CENTRAL_CONF_DIR if SEAFILE_CENTRAL_CONF_DIR else SEAFILE_CONF_DIR, - 'seafile.conf')) - -def get_fileserver_option(key, default): - ''' - "fileserver" used to be "httpserver" - ''' - for section in ('fileserver', 'httpserver'): - if config.has_option(section, key): - return config.get(section, key) - - return default - -MAX_UPLOAD_FILE_SIZE = None # Defaults to no limit -try: - max_upload_size_mb = int(get_fileserver_option('max_upload_size', 0)) - if max_upload_size_mb > 0: - MAX_UPLOAD_FILE_SIZE = max_upload_size_mb * (2 ** 20) -except ValueError: - pass - -MAX_DOWNLOAD_DIR_SIZE = 100 * (2 ** 20) # Default max size of a downloadable dir -try: - max_download_dir_size_mb = int(get_fileserver_option('max_download_dir_size', 0)) - if max_download_dir_size_mb > 0: - MAX_DOWNLOAD_DIR_SIZE = max_download_dir_size_mb * (2 ** 20) -except ValueError: - pass - -FILE_SERVER_PORT = get_fileserver_option('port', '8082') - -if CCNET_SERVER_ADDR: - FILE_SERVER_ROOT = 'http://' + CCNET_SERVER_ADDR + ':' + FILE_SERVER_PORT -else: - FILE_SERVER_ROOT = None - -CALC_SHARE_USAGE = False -if config.has_option('quota', 'calc_share_usage'): - CALC_SHARE_USAGE = config.getboolean('quota', 'calc_share_usage') - -# Get an instance of a logger -logger = logging.getLogger(__name__) - -#### Basic ccnet API #### - -def get_emailusers(source, start, limit, is_active=None): - if is_active is True: - status = "active" # list active users - elif is_active is False: - status = "inactive" # list inactive users - else: - status = "" # list all users - - return ccnet_threaded_rpc.get_emailusers(source, start, limit, status) - -def count_emailusers(): - try: - ret = ccnet_threaded_rpc.count_emailusers() - except SearpcError: - ret = -1 - return 0 if ret < 0 else ret - -def get_emailuser_with_import(email): - return ccnet_threaded_rpc.get_emailuser_with_import(email) - -def get_session_info(): - return ccnet_rpc.get_session_info() - -# group -def get_group(group_id): - group_id_int = int(group_id) - try: - group = ccnet_threaded_rpc.get_group(group_id_int) - except SearpcError: - group = None - return group - -def get_personal_groups(start, limit): - try: - groups_all = ccnet_threaded_rpc.get_all_groups(start, limit) - except SearpcError: - return [] - return [ x for x in groups_all if not is_org_group(x.id) ] - -def get_personal_groups_by_user(email): - try: - groups_all = ccnet_threaded_rpc.get_groups(email) - except SearpcError: - return [] - - return [ x for x in groups_all if not is_org_group(x.id) ] - -# group user -def is_group_user(group_id, user): - try: - ret = ccnet_threaded_rpc.is_group_user(group_id, user) - except SearpcError: - ret = 0 - return ret - -def check_group_staff(group_id, username): - """Check where user is group staff""" - group_id = int(group_id) - try: - ret = ccnet_threaded_rpc.check_group_staff(group_id, username) - except SearpcError, e: - logger.error(e) - ret = 0 - - return True if ret == 1 else False - -def remove_group_user(user): - """ - Remove group user relationship. - """ - return ccnet_threaded_rpc.remove_group_user(user) - -def get_group_members(group_id, start=-1, limit=-1): - group_id_int = int(group_id) - try: - members = ccnet_threaded_rpc.get_group_members(group_id_int) - except SearpcError: - members = [] - return members - -# org group -def is_org_group(group_id): - try: - ret = ccnet_threaded_rpc.is_org_group(group_id) - except SearpcError: - ret = -1 - return True if ret == 1 else False - -def get_org_id_by_group(group_id): - try: - org_id = ccnet_threaded_rpc.get_org_id_by_group(group_id) - except SearpcError: - org_id = -1 - return org_id - -def get_org_groups(org_id, start, limit): - try: - groups = ccnet_threaded_rpc.get_org_groups(org_id, start, limit) - except SearpcError: - groups = [] - return groups - -def get_org_groups_by_user(org_id, user): - """ - Get user's groups in org. - """ - try: - groups_all = ccnet_threaded_rpc.get_groups(user) - except SearpcError: - return [] - - return [ x for x in groups_all if org_id == get_org_id_by_group(x.id) ] - -# org -def create_org(org_name, url_prefix, username): - ccnet_threaded_rpc.create_org(org_name, url_prefix, username) - -def get_org_by_url_prefix(url_prefix): - try: - org = ccnet_threaded_rpc.get_org_by_url_prefix(url_prefix) - except SearpcError: - org = None - - return org - -def get_org_by_id(org_id): - try: - org = ccnet_threaded_rpc.get_org_by_id(org_id) - except SearpcError: - org = None - - return org - -# org user -def add_org_user(org_id, email, is_staff): - try: - ccnet_threaded_rpc.add_org_user(org_id, email, is_staff) - except SearpcError: - pass - -def remove_org_user(org_id, email): - try: - ccnet_threaded_rpc.remove_org_user(org_id, email) - except SearpcError: - pass - -def org_user_exists(org_id, user): - try: - ret = ccnet_threaded_rpc.org_user_exists(org_id, user) - except SearpcError: - ret = -1 - return True if ret == 1 else False - -def get_org_users_by_url_prefix(url_prefix, start, limit): - """ - List org users. - """ - try: - users = ccnet_threaded_rpc.get_org_emailusers(url_prefix, start, limit) - except: - users = [] - return users - -def get_orgs_by_user(user): - try: - orgs = ccnet_threaded_rpc.get_orgs_by_user(user) - except SearpcError: - orgs = [] - - return orgs - -def is_org_staff(org_id, user): - """ - Check whether user is staff of a org. - """ - try: - ret = ccnet_threaded_rpc.is_org_staff(org_id, user) - except SearpcError: - ret = -1 - return True if ret == 1 else False - -def get_user_current_org(user, url_prefix): - orgs = get_orgs_by_user(user) - for org in orgs: - if org.url_prefix == url_prefix: - return org - return None - -def send_command(command): - client = pool.get_client() - client.send_cmd(command) - ret = client.response[2] - pool.return_client(client) - return ret - -def send_message(msg_type, content): - client = pool.get_client() - client.send_message(msg_type, content) - pool.return_client(client) - -def get_binding_peerids(email): - """Get peer ids of a given email""" - try: - peer_ids = ccnet_threaded_rpc.get_binding_peerids(email) - except SearpcError: - return [] - - if not peer_ids: - return [] - - peerid_list = [] - for peer_id in peer_ids.split("\n"): - if peer_id == '': - continue - peerid_list.append(peer_id) - return peerid_list - -######## seafserv API #### - -# repo -def get_repos(): - """ - Return repository list. - - """ - return seafserv_threaded_rpc.get_repo_list("", 100) - -def get_repo(repo_id): - return seafserv_threaded_rpc.get_repo(repo_id) - -def edit_repo(repo_id, name, desc, user): - try: - ret = seafserv_threaded_rpc.edit_repo(repo_id, name, desc, user) - except SearpcError, e: - ret = -1 - return True if ret == 0 else False - -def create_repo(name, desc, user, passwd): - """ - Return repo id if successfully created a repo, otherwise None. - """ - try: - ret = seafserv_threaded_rpc.create_repo(name, desc, user, passwd) - except SearpcError, e: - logger.error(e) - ret = None - return ret - -def remove_repo(repo_id): - """ - Return true if successfully removed a repo, otherwise false. - """ - try: - ret = seafserv_threaded_rpc.remove_repo(repo_id) - except SearpcError, e: - logger.error(e) - ret = -1 - return True if ret == 0 else False - -def list_personal_repos_by_owner(owner): - """ - List users owned repos in personal context. - """ - try: - repos = seafserv_threaded_rpc.list_owned_repos(owner) - except SearpcError: - repos = [] - return repos - -def get_repo_token_nonnull(repo_id, username): - return seafserv_threaded_rpc.get_repo_token_nonnull (repo_id, username) - -def get_repo_owner(repo_id): - """ - Get owner of a repo. - """ - try: - ret = seafserv_threaded_rpc.get_repo_owner(repo_id) - except SearpcError: - ret = '' - return ret - -def is_repo_owner(user, repo_id): - """ - Check whether user is repo owner. - """ - try: - ret = seafserv_threaded_rpc.is_repo_owner(user, repo_id) - except SearpcError: - ret = 0 - return ret - -def server_repo_size(repo_id): - try: - size = seafserv_threaded_rpc.server_repo_size(repo_id) - except SearpcError: - size = 0 - return size - -# org repo -def create_org_repo(repo_name, repo_desc, user, passwd, org_id): - """ - Create org repo, return valid repo id if success. - """ - try: - repo_id = seafserv_threaded_rpc.create_org_repo(repo_name, repo_desc, - user, passwd, org_id) - except SearpcError: - repo_id = None - - return repo_id - -def is_org_repo(repo_id): - org_id = get_org_id_by_repo_id(repo_id) - return True if org_id > 0 else False - -def list_org_repos_by_owner(org_id, user): - try: - repos = seafserv_threaded_rpc.list_org_repos_by_owner(org_id, user) - except SearpcError: - repos = [] - return repos - -def get_org_repos(org_id, start, limit): - """ - List repos created in org. - """ - try: - repos = seafserv_threaded_rpc.get_org_repo_list(org_id, start, limit) - except SearpcError: - repos = [] - - if repos: - for r in repos: - r.owner = get_org_repo_owner(r.id) - - return repos - -def get_org_id_by_repo_id(repo_id): - """ - Get org id according repo id. - """ - try: - org_id = seafserv_threaded_rpc.get_org_id_by_repo_id(repo_id) - except SearpcError: - org_id = -1 - return org_id - -def is_org_repo_owner(org_id, repo_id, user): - """ - Check whether user is org repo owner. - NOTE: - `org_id` may used in future. - """ - owner = get_org_repo_owner(repo_id) - if not owner: - return False - return True if owner == user else False - -def get_org_repo_owner(repo_id): - """ - Get owner of org repo. - """ - try: - owner = seafserv_threaded_rpc.get_org_repo_owner(repo_id) - except SearpcError: - owner = None - return owner - -# commit -def get_commit(repo_id, repo_version, cmt_id): - """ Get a commit. """ - try: - ret = seafserv_threaded_rpc.get_commit(repo_id, repo_version, cmt_id) - except SearpcError: - ret = None - return ret - -def get_commits(repo_id, offset, limit): - """Get commit lists.""" - try: - ret = seafserv_threaded_rpc.get_commit_list(repo_id, offset, limit) - except SearpcError: - ret = None - return ret - -# branch -def get_branches(repo_id): - """Get branches of a given repo""" - return seafserv_threaded_rpc.branch_gets(repo_id) - -# group repo -def get_group_repos_by_owner(user): - """ - List user's repos that are sharing to groups - """ - try: - ret = seafserv_threaded_rpc.get_group_repos_by_owner(user) - except SearpcError: - ret = [] - return ret - -def get_shared_groups_by_repo(repo_id): - try: - group_ids = seafserv_threaded_rpc.get_shared_groups_by_repo(repo_id) - except SearpcError: - group_ids = '' - if not group_ids: - return [] - - groups = [] - for group_id in group_ids.split('\n'): - if not group_id: - continue - group = get_group(group_id) - if group: - groups.append(group) - return groups - -def conv_repoids_to_list(repo_ids): - """ - Convert repo ids seperated by "\n" to list. - """ - if not repo_ids: - return [] - - repoid_list = [] - for repo_id in repo_ids.split("\n"): - if repo_id == '': - continue - repoid_list.append(repo_id) - return repoid_list - -def get_group_repoids(group_id): - """Get repo ids of a given group id.""" - try: - repo_ids = seafserv_threaded_rpc.get_group_repoids(group_id) - except SearpcError: - return [] - - return conv_repoids_to_list(repo_ids) - -def get_group_repos(group_id, user): - """Get repos of a given group id.""" - repoid_list = get_group_repoids(group_id) - - repos = [] - for repo_id in repoid_list: - if not repo_id: - continue - repo = get_repo(repo_id) - if not repo: - continue - - repo.owner = seafserv_threaded_rpc.get_group_repo_owner(repo_id) - repo.share_from_me = True if user == repo.owner else False - - last_commit = get_commits(repo.id, 0, 1)[0] - repo.latest_modify = last_commit.ctime if last_commit else None - - repos.append(repo) - repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify)) - - return repos - -# org group repo -def del_org_group_repo(repo_id, org_id, group_id): - seafserv_threaded_rpc.del_org_group_repo(repo_id, org_id, group_id) - -def get_org_group_repoids(org_id, group_id): - try: - repo_ids = seafserv_threaded_rpc.get_org_group_repoids(org_id, group_id) - except SearpcError: - repo_ids = '' - - return conv_repoids_to_list(repo_ids) - -def get_org_group_repos(org_id, group_id, user): - """Get org repos of a given group id.""" - repoid_list = get_org_group_repoids(org_id, group_id) - if not repoid_list: - return [] - - repos = [] - for repo_id in repoid_list: - if not repo_id: - continue - repo = get_repo(repo_id) - if not repo: - continue - - repo.owner = seafserv_threaded_rpc.get_org_group_repo_owner(org_id, - group_id, - repo_id) - repo.sharecd_from_me = True if user == repo.owner else False - - last_commit = get_commits(repo.id, 0, 1)[0] - repo.latest_modify = last_commit.ctime if last_commit else None - - repos.append(repo) - repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify)) - - return repos - -def get_org_groups_by_repo(org_id, repo_id): - try: - group_ids = seafserv_threaded_rpc.get_org_groups_by_repo(org_id, - repo_id) - except SearpcError: - group_ids = '' - if not group_ids: - return [] - - groups = [] - for group_id in group_ids.split('\n'): - if not group_id: - continue - group = get_group(group_id) - if group: - groups.append(group) - return groups - -# inner pub repo -def list_inner_pub_repos_by_owner(user): - """ - List a user's inner pub repos. - """ - try: - ret = seafserv_threaded_rpc.list_inner_pub_repos_by_owner(user) - except SearpcError: - ret = [] - return ret - -def list_inner_pub_repos(username): - """ - List inner pub repos, which can be access by everyone. - """ - try: - shared_repos = seafserv_threaded_rpc.list_inner_pub_repos() - except: - shared_repos = [] - - for repo in shared_repos: - repo.user_perm = check_permission(repo.props.repo_id, username) - - shared_repos.sort(lambda x, y: cmp(y.props.last_modified, x.props.last_modified)) - return shared_repos - -def count_inner_pub_repos(): - try: - ret = seafserv_threaded_rpc.count_inner_pub_repos() - except SearpcError: - ret = -1 - return 0 if ret < 0 else ret - -def is_inner_pub_repo(repo_id): - """ - Check whether a repo is public. - Return 0 if repo is not inner public, otherwise non-zero. - """ - try: - ret = seafserv_threaded_rpc.is_inner_pub_repo(repo_id) - except SearpcError: - ret = 0 - - return ret - -def unset_inner_pub_repo(repo_id): - seafserv_threaded_rpc.unset_inner_pub_repo(repo_id) - -# org inner pub repo -def list_org_inner_pub_repos(org_id, username, start=None, limit=None): - """ - List org inner pub repos, which can be access by all org members. - """ - try: - shared_repos = seafserv_threaded_rpc.list_org_inner_pub_repos(org_id) - except SearpcError: - shared_repos = [] - - for repo in shared_repos: - repo.user_perm = check_permission(repo.props.repo_id, username) - - # sort repos by last modify time - shared_repos.sort(lambda x, y: cmp(y.props.last_modified, x.props.last_modified)) - return shared_repos - -# repo permissoin -def check_permission(repo_id, user): - """ - Check whether user has permission to access repo. - Return values can be 'rw' or 'r' or None. - """ - try: - ret = seafserv_threaded_rpc.check_permission(repo_id, user) - except SearpcError: - ret = None - return ret - -def is_personal_repo(repo_id): - """ - Check whether repo is personal repo. - """ - try: - owner = seafserv_threaded_rpc.get_repo_owner(repo_id) - except SearpcError: - owner = '' - return True if owner else False - -# shared repo -def list_share_repos(user, share_type, start, limit): - try: - ret = seafserv_threaded_rpc.list_share_repos(user, share_type, - start, limit) - except SearpcError: - ret = [] - return ret - -def remove_share(repo_id, from_user, to_user): - seafserv_threaded_rpc.remove_share(repo_id, from_user, to_user) - -def unshare_group_repo(repo_id, group_id, from_user): - return seafserv_threaded_rpc.group_unshare_repo(repo_id, int(group_id), - from_user) - -def list_personal_shared_repos(user, user_type, start, limit): - """ - List personal repos that user share with others. - If `user_type` is 'from_email', list repos user shares to others; - If `user_type` is 'to_email', list repos others share to user. - """ - share_repos = list_share_repos(user, user_type, start, limit) - for repo in share_repos: - repo.user_perm = check_permission(repo.props.repo_id, user) - - share_repos.sort(lambda x, y: cmp(y.last_modified, x.last_modified)) - return share_repos - -def list_org_shared_repos(org_id, user, user_type, start, limit): - """ - List org repos that user share with others. - If `user_type` is 'from_email', list repos user shares to others; - If `user_type` is 'to_email', list repos others sahre to user. - """ - try: - share_repos = seafserv_threaded_rpc.list_org_share_repos(org_id, - user, user_type, - start, limit) - except SearpcError: - share_repos = [] - - for repo in share_repos: - repo.user_perm = check_permission(repo.props.repo_id, user) - - share_repos.sort(lambda x, y: cmp(y.last_modified, x.last_modified)) - return share_repos - -# dir -def list_dir_by_path(repo_id, commit_id, path): - try: - ret = seafserv_threaded_rpc.list_dir_by_path(repo_id, commit_id, path) - except SearpcError: - ret = None - return ret - -# file -def post_empty_file(repo_id, parent_dir, file_name, user): - """ - Return true if successfully make a new file, otherwise false. - """ - try: - ret = seafserv_threaded_rpc.post_empty_file(repo_id, parent_dir, - file_name, user) - except SearpcError, e: - logger.error(e) - ret = -1 - return True if ret == 0 else False - -def del_file(repo_id, parent_dir, file_name, user): - """ - Return true if successfully delete a file, otherwise false. - """ - try: - ret = seafserv_threaded_rpc.del_file(repo_id, parent_dir, - file_name, user) - except SearpcError, e: - logger.error(e) - ret = -1 - return True if ret == 0 else False - -# misc functions -def is_valid_filename(file_or_dir): - """ - Check whether file name or directory name is valid. - """ - try: - ret = seafserv_threaded_rpc.is_valid_filename('', file_or_dir) - except SearpcError: - ret = 0 - - return ret - -def get_file_size(store_id, version, file_id): - try: - fs = seafserv_threaded_rpc.get_file_size(store_id, version, file_id) - except SearpcError, e: - fs = 0 - return fs - -def get_file_id_by_path(repo_id, path): - try: - ret = seafserv_threaded_rpc.get_file_id_by_path(repo_id, path) - except SearpcError, e: - ret = '' - return ret - -def get_related_users_by_repo(repo_id): - """Give a repo id, returns a list of users of: - - the repo owner - - members of groups to which the repo is shared - - users to which the repo is shared - """ - owner = seafserv_threaded_rpc.get_repo_owner(repo_id) - if not owner: - # Can't happen - return [] - - users = [owner] - - groups = get_shared_groups_by_repo(repo_id) - - for group in groups: - members = get_group_members(group.id) - for member in members: - if member.user_name not in users: - users.append(member.user_name) - - share_repos = list_share_repos(owner, 'from_email', -1, -1) - for repo in share_repos: - if repo.repo_id == repo_id: - if repo.user not in users: - users.append(repo.user) - - return users - -def get_related_users_by_org_repo(org_id, repo_id): - """Org version of get_related_users_by_repo - """ - owner = get_org_repo_owner(repo_id) - - if not owner: - # Can't happen - return [] - - users = [owner] - - groups = get_org_groups_by_repo(org_id, repo_id) - - for group in groups: - members = get_group_members(group.id) - for member in members: - if member.user_name not in users: - users.append(member.user_name) - - share_repos = seafserv_threaded_rpc.list_org_share_repos(org_id, \ - owner, 'from_email', -1, -1) - - for repo in share_repos: - if repo.repo_id == repo_id: - if repo.user not in users: - users.append(repo.user) - - return users - -# quota -def check_quota(repo_id): - try: - ret = seafserv_threaded_rpc.check_quota(repo_id) - except SearpcError, e: - logger.error(e) - ret = -1 - return ret - -def get_user_quota(user): - try: - ret = seafserv_threaded_rpc.get_user_quota(user) - except SearpcError, e: - logger.error(e) - ret = 0 - return ret - -def get_user_quota_usage(user): - try: - ret = seafserv_threaded_rpc.get_user_quota_usage(user) - except SearpcError, e: - logger.error(e) - ret = 0 - return ret - -def get_user_share_usage(user): - try: - ret = seafserv_threaded_rpc.get_user_share_usage(user) - except SearpcError, e: - logger.error(e) - ret = 0 - return ret - -# access token -def web_get_access_token(repo_id, obj_id, op, username, use_onetime=1): - try: - ret = seafserv_rpc.web_get_access_token(repo_id, obj_id, op, username, use_onetime) - except SearpcError, e: - ret = '' - return ret - -# password management -def unset_repo_passwd(repo_id, user): - """ - Remove user password of a encrypt repo. - Arguments: - - `repo_id`: encrypt repo id - - `user`: username - """ - try: - ret = seafserv_threaded_rpc.unset_passwd(repo_id, user) - except SearpcError, e: - ret = -1 - return ret - -def is_passwd_set(repo_id, user): - try: - ret = seafserv_rpc.is_passwd_set(repo_id, user) - except SearpcError, e: - ret = -1 - return True if ret == 1 else False - -# repo history limit -def get_repo_history_limit(repo_id): - try: - ret = seafserv_threaded_rpc.get_repo_history_limit(repo_id) - except SearpcError, e: - ret = -1 - return ret - -def set_repo_history_limit(repo_id, days): - try: - ret = seafserv_threaded_rpc.set_repo_history_limit(repo_id, days) - except SearpcError, e: - ret = -1 - return ret diff --git a/scripts/build/build-server-src.py b/scripts/build/build-server-src.py deleted file mode 100755 index acefa80f..00000000 --- a/scripts/build/build-server-src.py +++ /dev/null @@ -1,396 +0,0 @@ -#!/usr/bin/env python -# coding: UTF-8 - -'''This scirpt builds the seafile debian source tarball. In this tarball, -libsearpc and ccnet is also included. - -''' -import sys - -#################### -### Requires Python 2.6+ -#################### -if sys.version_info[0] == 3: - print 'Python 3 not supported yet. Quit now.' - sys.exit(1) -if sys.version_info[1] < 6: - print 'Python 2.6 or above is required. Quit now.' - sys.exit(1) - -import os -import tempfile -import glob -import shutil -import re -import subprocess -import optparse -import atexit - -#################### -### Global variables -#################### - -# command line configuartion -conf = {} - -# key names in the conf dictionary. -CONF_VERSION = 'version' -CONF_LIBSEARPC_VERSION = 'libsearpc_version' -CONF_CCNET_VERSION = 'ccnet_version' -CONF_SEAFILE_VERSION = 'seafile_version' -CONF_SRCDIR = 'srcdir' -CONF_KEEP = 'keep' -CONF_BUILDDIR = 'builddir' -CONF_OUTPUTDIR = 'outputdir' - -#################### -### Common helper functions -#################### -def highlight(content, is_error=False): - '''Add ANSI color to content to get it highlighted on terminal''' - if is_error: - return '\x1b[1;31m%s\x1b[m' % content - else: - return '\x1b[1;32m%s\x1b[m' % content - -def info(msg): - print highlight('[INFO] ') + msg - -def exist_in_path(prog): - '''Test whether prog exists in system path''' - dirs = os.environ['PATH'].split(':') - for d in dirs: - if d == '': - continue - path = os.path.join(d, prog) - if os.path.exists(path): - return True - - return False - -def error(msg=None, usage=None): - if msg: - print highlight('[ERROR] ') + msg - if usage: - print usage - sys.exit(1) - -def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Run a program and wait it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - - info('running %s, cwd=%s' % (' '.join(argv), cwd if cwd else os.getcwd())) - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - -def run(cmdline, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Like run_argv but specify a command line string instead of argv''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(cmdline, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env, - shell=True) - return proc.wait() - -def must_mkdir(path): - '''Create a directory, exit on failure''' - try: - os.mkdir(path) - except OSError, e: - error('failed to create directory %s:%s' % (path, e)) - -def must_copy(src, dst): - '''Copy src to dst, exit on failure''' - try: - shutil.copy(src, dst) - except Exception, e: - error('failed to copy %s to %s: %s' % (src, dst, e)) - -def check_targz_src(proj, version, srcdir): - src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version)) - if not os.path.exists(src_tarball): - error('%s not exists' % src_tarball) - -def remove_unused_files(): - srcdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION]) - web_sh_files = glob.glob(os.path.join(srcdir, 'web', '*.sh')) - files = [ - os.path.join(srcdir, 'web', 'pygettext.py'), - ] - files.extend(web_sh_files) - - for f in files: - run('rm -f %s' % f) - -def gen_tarball(): - output = os.path.join(conf[CONF_OUTPUTDIR], 'seafile-server-latest.tar.gz') - dirname = 'seafile-%s' % conf[CONF_VERSION] - - ignored_patterns = [ - # windows msvc dlls - os.path.join(dirname, 'msi', 'bin*'), - ] - - excludes_list = [ '--exclude=%s' % pattern for pattern in ignored_patterns ] - argv = [ - 'tar', - 'czvf', - output, - dirname, - ] - - argv.append(*excludes_list) - - if run_argv(argv) != 0: - error('failed to gen %s' % output) - - print '---------------------------------------------' - print 'The build is successfully. Output is:\t%s' % output - print '---------------------------------------------' - -def uncompress_seafile(): - src = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_SEAFILE_VERSION]) - dst = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION]) - - if os.path.exists(src): - error('dir %s already exists' % src) - if os.path.exists(dst): - error('dir %s already exists' % dst) - - tarball = os.path.join(conf[CONF_SRCDIR], 'seafile-%s.tar.gz' % conf[CONF_SEAFILE_VERSION]) - argv = [ 'tar', 'xf', - tarball, - '-C', conf[CONF_BUILDDIR], - ] - - if run_argv(argv) != 0: - error('failed to uncompress seafile') - - if conf[CONF_VERSION] != conf[CONF_SEAFILE_VERSION]: - shutil.move(src, dst) - -def uncompress_libsearpc(): - tarball = os.path.join(conf[CONF_SRCDIR], 'libsearpc-%s.tar.gz' % conf[CONF_LIBSEARPC_VERSION]) - dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'libsearpc') - must_mkdir(dst_dir) - argv = [ 'tar', 'xf', - tarball, - '--strip-components=1', - '-C', dst_dir, - ] - - if run_argv(argv) != 0: - error('failed to uncompress libsearpc') - -def uncompress_ccnet(): - tarball = os.path.join(conf[CONF_SRCDIR], 'ccnet-%s.tar.gz' % conf[CONF_CCNET_VERSION]) - dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'ccnet') - must_mkdir(dst_dir) - argv = [ 'tar', 'xf', - tarball, - '--strip-components=1', - '-C', dst_dir, - ] - - if run_argv(argv) != 0: - error('failed to uncompress ccnet') - - -def remove_debian_subdir(): - debian_subdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'debian') - argv = [ 'rm', '-rf', debian_subdir ] - if run_argv(argv) != 0: - error('failed to uncompress ccnet') - - -def parse_args(): - parser = optparse.OptionParser() - def long_opt(opt): - return '--' + opt - - parser.add_option(long_opt(CONF_VERSION), - dest=CONF_VERSION, - nargs=1, - help='the version of seafile source. Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_SEAFILE_VERSION), - dest=CONF_SEAFILE_VERSION, - nargs=1, - help='the version of seafile. Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_LIBSEARPC_VERSION), - dest=CONF_LIBSEARPC_VERSION, - nargs=1, - help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_CCNET_VERSION), - dest=CONF_CCNET_VERSION, - nargs=1, - help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0') - - - parser.add_option(long_opt(CONF_BUILDDIR), - dest=CONF_BUILDDIR, - nargs=1, - help='the directory to build the source. Defaults to /tmp', - default=tempfile.gettempdir()) - - parser.add_option(long_opt(CONF_OUTPUTDIR), - dest=CONF_OUTPUTDIR, - nargs=1, - help='the output directory to put the generated server tarball. Defaults to the current directory.', - default=os.getcwd()) - - parser.add_option(long_opt(CONF_SRCDIR), - dest=CONF_SRCDIR, - nargs=1, - help='''Source tarballs must be placed in this directory.''') - - parser.add_option(long_opt(CONF_KEEP), - dest=CONF_KEEP, - action='store_true', - help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''') - - usage = parser.format_help() - options, remain = parser.parse_args() - if remain: - error(usage=usage) - - validate_args(usage, options) - -def validate_args(usage, options): - required_args = [ - CONF_VERSION, - CONF_SEAFILE_VERSION, - CONF_LIBSEARPC_VERSION, - CONF_CCNET_VERSION, - CONF_SRCDIR, - ] - - # fist check required args - for optname in required_args: - if getattr(options, optname, None) == None: - error('%s must be specified' % optname, usage=usage) - - def get_option(optname): - return getattr(options, optname) - - # [ version ] - def check_project_version(version): - '''A valid version must be like 1.2.2, 1.3''' - if not re.match('^[0-9](\.[0-9])+$', version): - error('%s is not a valid version' % version, usage=usage) - - version = get_option(CONF_VERSION) - libsearpc_version = get_option(CONF_LIBSEARPC_VERSION) - ccnet_version = get_option(CONF_CCNET_VERSION) - seafile_version = get_option(CONF_SEAFILE_VERSION) - - check_project_version(version) - check_project_version(libsearpc_version) - check_project_version(ccnet_version) - check_project_version(seafile_version) - - # [ srcdir ] - srcdir = get_option(CONF_SRCDIR) - check_targz_src('libsearpc', libsearpc_version, srcdir) - check_targz_src('ccnet', ccnet_version, srcdir) - check_targz_src('seafile', seafile_version, srcdir) - - # [ builddir ] - builddir = get_option(CONF_BUILDDIR) - if not os.path.exists(builddir): - error('%s does not exist' % builddir, usage=usage) - - builddir = os.path.join(builddir, 'seafile-deb-src') - - # [ outputdir ] - outputdir = get_option(CONF_OUTPUTDIR) - if not os.path.exists(outputdir): - error('outputdir %s does not exist' % outputdir, usage=usage) - - # [ keep ] - keep = get_option(CONF_KEEP) - - conf[CONF_VERSION] = version - conf[CONF_LIBSEARPC_VERSION] = libsearpc_version - conf[CONF_CCNET_VERSION] = ccnet_version - conf[CONF_SEAFILE_VERSION] = seafile_version - - conf[CONF_BUILDDIR] = builddir - conf[CONF_SRCDIR] = srcdir - conf[CONF_OUTPUTDIR] = outputdir - conf[CONF_KEEP] = keep - - prepare_builddir(builddir) - show_build_info() - -def prepare_builddir(builddir): - must_mkdir(builddir) - - if not conf[CONF_KEEP]: - def remove_builddir(): - '''Remove the builddir when exit''' - info('remove builddir before exit') - shutil.rmtree(builddir, ignore_errors=True) - atexit.register(remove_builddir) - - os.chdir(builddir) - -def show_build_info(): - '''Print all conf information. Confirm before continue.''' - info('------------------------------------------') - info('Seafile debian source tarball %s:' % conf[CONF_VERSION]) - info('------------------------------------------') - info('seafile: %s' % conf[CONF_SEAFILE_VERSION]) - info('ccnet: %s' % conf[CONF_CCNET_VERSION]) - info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION]) - info('builddir: %s' % conf[CONF_BUILDDIR]) - info('outputdir: %s' % conf[CONF_OUTPUTDIR]) - info('source dir: %s' % conf[CONF_SRCDIR]) - info('clean on exit: %s' % (not conf[CONF_KEEP])) - info('------------------------------------------') - info('press any key to continue ') - info('------------------------------------------') - dummy = raw_input() - -def main(): - parse_args() - uncompress_seafile() - uncompress_libsearpc() - uncompress_ccnet() - remove_debian_subdir() - remove_unused_files() - gen_tarball() - -if __name__ == '__main__': - main() diff --git a/scripts/build/build-server.py b/scripts/build/build-server.py deleted file mode 100755 index daba8bad..00000000 --- a/scripts/build/build-server.py +++ /dev/null @@ -1,889 +0,0 @@ -#!/usr/bin/env python -# coding: UTF-8 - -'''This script builds the seafile server tarball. - -Some notes: - -1. The working directory is always the 'builddir'. 'os.chdir' is only called -to change to the 'builddir'. We make use of the 'cwd' argument in -'subprocess.Popen' to run a command in a specific directory. - -2. django/djangorestframework/djblets/gunicorn/flup must be easy_install-ed to -a directory before running this script. That directory is passed in as the -'--thirdpartdir' arguments. - -''' - -import sys - -#################### -### Requires Python 2.6+ -#################### -if sys.version_info[0] == 3: - print 'Python 3 not supported yet. Quit now.' - sys.exit(1) -if sys.version_info[1] < 6: - print 'Python 2.6 or above is required. Quit now.' - sys.exit(1) - -import os -import glob -import commands -import tempfile -import shutil -import re -import subprocess -import optparse -import atexit -import platform - -#################### -### Global variables -#################### - -# command line configuartion -conf = {} - -# key names in the conf dictionary. -CONF_VERSION = 'version' -CONF_SEAFILE_VERSION = 'seafile_version' -CONF_LIBSEARPC_VERSION = 'libsearpc_version' -CONF_CCNET_VERSION = 'ccnet_version' -CONF_SRCDIR = 'srcdir' -CONF_KEEP = 'keep' -CONF_BUILDDIR = 'builddir' -CONF_OUTPUTDIR = 'outputdir' -CONF_THIRDPARTDIR = 'thirdpartdir' -CONF_NO_STRIP = 'nostrip' -CONF_ENABLE_S3 = 's3' -CONF_YES = 'yes' -CONF_JOBS = 'jobs' - -#################### -### Common helper functions -#################### -def highlight(content, is_error=False): - '''Add ANSI color to content to get it highlighted on terminal''' - if is_error: - return '\x1b[1;31m%s\x1b[m' % content - else: - return '\x1b[1;32m%s\x1b[m' % content - -def info(msg): - print highlight('[INFO] ') + msg - -def find_in_path(prog): - '''Find a file in system path''' - dirs = os.environ['PATH'].split(':') - for d in dirs: - if d == '': - continue - path = os.path.join(d, prog) - if os.path.exists(path): - return path - - return None - -def error(msg=None, usage=None): - if msg: - print highlight('[ERROR] ') + msg - if usage: - print usage - sys.exit(1) - -def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Run a program and wait for it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - -def run(cmdline, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Like run_argv but specify a command line string instead of argv''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(cmdline, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env, - shell=True) - return proc.wait() - -def must_mkdir(path): - '''Create a directory, exit on failure''' - try: - os.mkdir(path) - except OSError, e: - error('failed to create directory %s:%s' % (path, e)) - -def must_copy(src, dst): - '''Copy src to dst, exit on failure''' - try: - shutil.copy(src, dst) - except Exception, e: - error('failed to copy %s to %s: %s' % (src, dst, e)) - -class Project(object): - '''Base class for a project''' - # Probject name, i.e. libseaprc/ccnet/seafile/seahub - name = '' - - # A list of shell commands to configure/build the project - build_commands = [] - - def __init__(self): - # the path to pass to --prefix=/ - self.prefix = os.path.join(conf[CONF_BUILDDIR], 'seafile-server', 'seafile') - self.version = self.get_version() - self.src_tarball = os.path.join(conf[CONF_SRCDIR], - '%s-%s.tar.gz' % (self.name, self.version)) - # project dir, like /seafile-1.2.2/ - self.projdir = os.path.join(conf[CONF_BUILDDIR], '%s-%s' % (self.name, self.version)) - - def get_version(self): - # libsearpc and ccnet can have different versions from seafile. - raise NotImplementedError - - def uncompress(self): - '''Uncompress the source from the tarball''' - info('Uncompressing %s' % self.name) - - if run('tar xf %s' % self.src_tarball) < 0: - error('failed to uncompress source of %s' % self.name) - - def build(self): - '''Build the source''' - info('Building %s' % self.name) - for cmd in self.build_commands: - if run(cmd, cwd=self.projdir) != 0: - error('error when running command:\n\t%s\n' % cmd) - -class Libsearpc(Project): - name = 'libsearpc' - - def __init__(self): - Project.__init__(self) - self.build_commands = [ - './configure --prefix=%s' % self.prefix, - 'make -j%s' % conf[CONF_JOBS], - 'make install' - ] - - def get_version(self): - return conf[CONF_LIBSEARPC_VERSION] - -class Ccnet(Project): - name = 'ccnet' - def __init__(self): - Project.__init__(self) - self.build_commands = [ - './configure --prefix=%s --disable-client --enable-server --enable-pgsql --enable-ldap' % self.prefix, - 'make -j%s' % conf[CONF_JOBS], - 'make install' - ] - - def get_version(self): - return conf[CONF_CCNET_VERSION] - -class Seafile(Project): - name = 'seafile' - def __init__(self): - Project.__init__(self) - s3_support = '' - if conf[CONF_ENABLE_S3]: - s3_support = '--enable-s3' - - self.build_commands = [ - './configure --prefix=%s --disable-client --enable-server --enable-pgsql %s' \ - % (self.prefix, s3_support), - 'make -j%s' % conf[CONF_JOBS], - 'make install' - ] - - def get_version(self): - return conf[CONF_SEAFILE_VERSION] - -class Seahub(Project): - name = 'seahub' - def __init__(self): - Project.__init__(self) - # nothing to do for seahub - self.build_commands = [ - ] - - def get_version(self): - return conf[CONF_SEAFILE_VERSION] - - def build(self): - self.write_version_to_settings_py() - - Project.build(self) - - def write_version_to_settings_py(self): - '''Write the version of current seafile server to seahub''' - settings_py = os.path.join(self.projdir, 'seahub', 'settings.py') - - line = '\nSEAFILE_VERSION = "%s"\n' % conf[CONF_VERSION] - with open(settings_py, 'a+') as fp: - fp.write(line) - - -def check_seahub_thirdpart(thirdpartdir): - '''The ${thirdpartdir} must have django/djblets/gunicorn pre-installed. So - we can copy it to seahub/thirdpart - - ''' - thirdpart_libs = [ - 'Django', - # 'Djblets', - 'gunicorn', - 'flup', - 'chardet', - 'python_dateutil', - 'django_picklefield', - 'django_constance', - # 'SQLAlchemy', - # 'python_daemon', - # 'lockfile', - # 'six', - ] - def check_thirdpart_lib(name): - name += '*' - if not glob.glob(os.path.join(thirdpartdir, name)): - error('%s not found in %s' % (name, thirdpartdir)) - - for lib in thirdpart_libs: - check_thirdpart_lib(lib) - -def check_targz_src(proj, version, srcdir): - src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version)) - if not os.path.exists(src_tarball): - error('%s not exists' % src_tarball) - -def check_targz_src_no_version(proj, srcdir): - src_tarball = os.path.join(srcdir, '%s.tar.gz' % proj) - if not os.path.exists(src_tarball): - error('%s not exists' % src_tarball) - -def check_pdf2htmlEX(): - pdf2htmlEX_executable = find_in_path('pdf2htmlEX') - if pdf2htmlEX_executable is None: - error('pdf2htmlEX not found') - -def validate_args(usage, options): - required_args = [ - CONF_VERSION, - CONF_LIBSEARPC_VERSION, - CONF_CCNET_VERSION, - CONF_SEAFILE_VERSION, - CONF_SRCDIR, - CONF_THIRDPARTDIR, - ] - - # fist check required args - for optname in required_args: - if getattr(options, optname, None) == None: - error('%s must be specified' % optname, usage=usage) - - def get_option(optname): - return getattr(options, optname) - - # [ version ] - def check_project_version(version): - '''A valid version must be like 1.2.2, 1.3''' - if not re.match('^[0-9]+(\.([0-9])+)+$', version): - error('%s is not a valid version' % version, usage=usage) - - version = get_option(CONF_VERSION) - seafile_version = get_option(CONF_SEAFILE_VERSION) - libsearpc_version = get_option(CONF_LIBSEARPC_VERSION) - ccnet_version = get_option(CONF_CCNET_VERSION) - - check_project_version(version) - check_project_version(libsearpc_version) - check_project_version(ccnet_version) - check_project_version(seafile_version) - - # [ srcdir ] - srcdir = get_option(CONF_SRCDIR) - check_targz_src('libsearpc', libsearpc_version, srcdir) - check_targz_src('ccnet', ccnet_version, srcdir) - check_targz_src('seafile', seafile_version, srcdir) - check_targz_src('seahub', seafile_version, srcdir) - check_targz_src_no_version('seafdav', srcdir) - check_targz_src_no_version('seafobj', srcdir) - - # check_pdf2htmlEX() - - # [ builddir ] - builddir = get_option(CONF_BUILDDIR) - if not os.path.exists(builddir): - error('%s does not exist' % builddir, usage=usage) - - builddir = os.path.join(builddir, 'seafile-server-build') - - # [ thirdpartdir ] - thirdpartdir = get_option(CONF_THIRDPARTDIR) - check_seahub_thirdpart(thirdpartdir) - - # [ outputdir ] - outputdir = get_option(CONF_OUTPUTDIR) - if outputdir: - if not os.path.exists(outputdir): - error('outputdir %s does not exist' % outputdir, usage=usage) - else: - outputdir = os.getcwd() - - # [ yes ] - yes = get_option(CONF_YES) - - # [ jobs ] - jobs = get_option(CONF_JOBS) - - # [ keep ] - keep = get_option(CONF_KEEP) - - # [ no strip] - nostrip = get_option(CONF_NO_STRIP) - - # [ s3 ] - s3 = get_option(CONF_ENABLE_S3) - - conf[CONF_VERSION] = version - conf[CONF_LIBSEARPC_VERSION] = libsearpc_version - conf[CONF_SEAFILE_VERSION] = seafile_version - conf[CONF_CCNET_VERSION] = ccnet_version - - conf[CONF_BUILDDIR] = builddir - conf[CONF_SRCDIR] = srcdir - conf[CONF_OUTPUTDIR] = outputdir - conf[CONF_KEEP] = keep - conf[CONF_THIRDPARTDIR] = thirdpartdir - conf[CONF_NO_STRIP] = nostrip - conf[CONF_ENABLE_S3] = s3 - conf[CONF_YES] = yes - conf[CONF_JOBS] = jobs - - prepare_builddir(builddir) - show_build_info() - -def show_build_info(): - '''Print all conf information. Confirm before continue.''' - info('------------------------------------------') - info('Seafile server %s: BUILD INFO' % conf[CONF_VERSION]) - info('------------------------------------------') - info('seafile: %s' % conf[CONF_SEAFILE_VERSION]) - info('ccnet: %s' % conf[CONF_CCNET_VERSION]) - info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION]) - info('builddir: %s' % conf[CONF_BUILDDIR]) - info('outputdir: %s' % conf[CONF_OUTPUTDIR]) - info('source dir: %s' % conf[CONF_SRCDIR]) - info('strip symbols: %s' % (not conf[CONF_NO_STRIP])) - info('s3 support: %s' % (conf[CONF_ENABLE_S3])) - info('clean on exit: %s' % (not conf[CONF_KEEP])) - if conf[CONF_YES]: - return - info('------------------------------------------') - info('press any key to continue ') - info('------------------------------------------') - raw_input() - -def prepare_builddir(builddir): - must_mkdir(builddir) - - if not conf[CONF_KEEP]: - def remove_builddir(): - '''Remove the builddir when exit''' - info('remove builddir before exit') - shutil.rmtree(builddir, ignore_errors=True) - atexit.register(remove_builddir) - - os.chdir(builddir) - - must_mkdir(os.path.join(builddir, 'seafile-server')) - must_mkdir(os.path.join(builddir, 'seafile-server', 'seafile')) - -def parse_args(): - parser = optparse.OptionParser() - def long_opt(opt): - return '--' + opt - - parser.add_option(long_opt(CONF_YES), - dest=CONF_YES, - action='store_true') - - parser.add_option(long_opt(CONF_JOBS), - dest=CONF_JOBS, - default=2, - type=int) - - parser.add_option(long_opt(CONF_THIRDPARTDIR), - dest=CONF_THIRDPARTDIR, - nargs=1, - help='where to find the thirdpart libs for seahub') - - parser.add_option(long_opt(CONF_VERSION), - dest=CONF_VERSION, - nargs=1, - help='the version to build. Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_SEAFILE_VERSION), - dest=CONF_SEAFILE_VERSION, - nargs=1, - help='the version of seafile as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_LIBSEARPC_VERSION), - dest=CONF_LIBSEARPC_VERSION, - nargs=1, - help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_CCNET_VERSION), - dest=CONF_CCNET_VERSION, - nargs=1, - help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0') - - parser.add_option(long_opt(CONF_BUILDDIR), - dest=CONF_BUILDDIR, - nargs=1, - help='the directory to build the source. Defaults to /tmp', - default=tempfile.gettempdir()) - - parser.add_option(long_opt(CONF_OUTPUTDIR), - dest=CONF_OUTPUTDIR, - nargs=1, - help='the output directory to put the generated server tarball. Defaults to the current directory.', - default=os.getcwd()) - - parser.add_option(long_opt(CONF_SRCDIR), - dest=CONF_SRCDIR, - nargs=1, - help='''Source tarballs must be placed in this directory.''') - - parser.add_option(long_opt(CONF_KEEP), - dest=CONF_KEEP, - action='store_true', - help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''') - - parser.add_option(long_opt(CONF_NO_STRIP), - dest=CONF_NO_STRIP, - action='store_true', - help='''do not strip debug symbols''') - - parser.add_option(long_opt(CONF_ENABLE_S3), - dest=CONF_ENABLE_S3, - action='store_true', - help='''enable amazon s3 support''') - usage = parser.format_help() - options, remain = parser.parse_args() - if remain: - error(usage=usage) - - validate_args(usage, options) - -def setup_build_env(): - '''Setup environment variables, such as export PATH=$BUILDDDIR/bin:$PATH''' - prefix = os.path.join(conf[CONF_BUILDDIR], 'seafile-server', 'seafile') - def prepend_env_value(name, value, seperator=':'): - '''append a new value to a list''' - try: - current_value = os.environ[name] - except KeyError: - current_value = '' - - new_value = value - if current_value: - new_value += seperator + current_value - - os.environ[name] = new_value - - prepend_env_value('CPPFLAGS', - '-I%s' % os.path.join(prefix, 'include'), - seperator=' ') - - prepend_env_value('CPPFLAGS', - '-DLIBICONV_PLUG', - seperator=' ') - - if conf[CONF_NO_STRIP]: - prepend_env_value('CPPFLAGS', - '-g -O0', - seperator=' ') - - prepend_env_value('CFLAGS', - '-g -O0', - seperator=' ') - - prepend_env_value('LDFLAGS', - '-L%s' % os.path.join(prefix, 'lib'), - seperator=' ') - - prepend_env_value('LDFLAGS', - '-L%s' % os.path.join(prefix, 'lib64'), - seperator=' ') - - prepend_env_value('PATH', os.path.join(prefix, 'bin')) - prepend_env_value('PKG_CONFIG_PATH', os.path.join(prefix, 'lib', 'pkgconfig')) - prepend_env_value('PKG_CONFIG_PATH', os.path.join(prefix, 'lib64', 'pkgconfig')) - -def copy_user_manuals(): - builddir = conf[CONF_BUILDDIR] - # src_pattern = os.path.join(builddir, Seafile().projdir, 'doc', '*.doc') - src_pattern = os.path.join(builddir, Seafile().projdir, 'doc', 'seafile-tutorial.doc') - dst_dir = os.path.join(builddir, 'seafile-server', 'seafile', 'docs') - - must_mkdir(dst_dir) - - for path in glob.glob(src_pattern): - must_copy(path, dst_dir) - -def copy_seafdav(): - dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-server', 'seahub', 'thirdpart') - tarball = os.path.join(conf[CONF_SRCDIR], 'seafdav.tar.gz') - if run('tar xf %s -C %s' % (tarball, dst_dir)) != 0: - error('failed to uncompress %s' % tarball) - - dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-server', 'seahub', 'thirdpart') - tarball = os.path.join(conf[CONF_SRCDIR], 'seafobj.tar.gz') - if run('tar xf %s -C %s' % (tarball, dst_dir)) != 0: - error('failed to uncompress %s' % tarball) - -def copy_scripts_and_libs(): - '''Copy server release scripts and shared libs, as well as seahub - thirdpart libs - - ''' - builddir = conf[CONF_BUILDDIR] - scripts_srcdir = os.path.join(builddir, Seafile().projdir, 'scripts') - serverdir = os.path.join(builddir, 'seafile-server') - - must_copy(os.path.join(scripts_srcdir, 'setup-seafile.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'setup-seafile-mysql.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'setup-seafile-mysql.py'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'seafile.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'seahub.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'reset-admin.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'seaf-fuse.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'check_init_admin.py'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'seaf-gc.sh'), - serverdir) - must_copy(os.path.join(scripts_srcdir, 'seaf-fsck.sh'), - serverdir) - - # copy update scripts - update_scriptsdir = os.path.join(scripts_srcdir, 'upgrade') - dst_update_scriptsdir = os.path.join(serverdir, 'upgrade') - try: - shutil.copytree(update_scriptsdir, dst_update_scriptsdir) - except Exception, e: - error('failed to copy upgrade scripts: %s' % e) - - # copy runtime/seahub.conf - runtimedir = os.path.join(serverdir, 'runtime') - must_mkdir(runtimedir) - must_copy(os.path.join(scripts_srcdir, 'seahub.conf'), - runtimedir) - - # move seahub to seafile-server/seahub - src_seahubdir = Seahub().projdir - dst_seahubdir = os.path.join(serverdir, 'seahub') - try: - shutil.move(src_seahubdir, dst_seahubdir) - except Exception, e: - error('failed to move seahub to seafile-server/seahub: %s' % e) - - # copy seahub thirdpart libs - seahub_thirdpart = os.path.join(dst_seahubdir, 'thirdpart') - copy_seahub_thirdpart_libs(seahub_thirdpart) - copy_seafdav() - - - # copy_pdf2htmlex() - - # copy shared c libs - copy_shared_libs() - copy_user_manuals() - -def copy_pdf2htmlex(): - '''Copy pdf2htmlEX exectuable and its dependent libs''' - pdf2htmlEX_executable = find_in_path('pdf2htmlEX') - libs = get_dependent_libs(pdf2htmlEX_executable) - - builddir = conf[CONF_BUILDDIR] - dst_lib_dir = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'lib') - - dst_bin_dir = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'bin') - - for lib in libs: - dst_file = os.path.join(dst_lib_dir, os.path.basename(lib)) - if os.path.exists(dst_file): - continue - info('Copying %s' % lib) - must_copy(lib, dst_lib_dir) - - must_copy(pdf2htmlEX_executable, dst_bin_dir) - -def get_dependent_libs(executable): - syslibs = ['libsearpc', 'libccnet', 'libseafile', 'libpthread.so', 'libc.so', 'libm.so', 'librt.so', 'libdl.so', 'libselinux.so', 'libresolv.so' ] - def is_syslib(lib): - for syslib in syslibs: - if syslib in lib: - return True - return False - - ldd_output = commands.getoutput('ldd %s' % executable) - ret = set() - for line in ldd_output.splitlines(): - tokens = line.split() - if len(tokens) != 4: - continue - if is_syslib(tokens[0]): - continue - - ret.add(tokens[2]) - - return ret - -def copy_shared_libs(): - '''copy shared c libs, such as libevent, glib, libmysqlclient''' - builddir = conf[CONF_BUILDDIR] - - dst_dir = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'lib') - - seafile_path = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'bin', - 'seaf-server') - - ccnet_server_path = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'bin', - 'ccnet-server') - - seaf_fuse_path = os.path.join(builddir, - 'seafile-server', - 'seafile', - 'bin', - 'seaf-fuse') - - libs = set() - libs.update(get_dependent_libs(ccnet_server_path)) - libs.update(get_dependent_libs(seafile_path)) - libs.update(get_dependent_libs(seaf_fuse_path)) - - for lib in libs: - dst_file = os.path.join(dst_dir, os.path.basename(lib)) - if os.path.exists(dst_file): - continue - info('Copying %s' % lib) - shutil.copy(lib, dst_dir) - -def copy_seahub_thirdpart_libs(seahub_thirdpart): - '''copy django/djblets/gunicorn from ${thirdpartdir} to - seahub/thirdpart - - ''' - src = conf[CONF_THIRDPARTDIR] - dst = seahub_thirdpart - - pattern = os.path.join(src, '*') - try: - for path in glob.glob(pattern): - target_path = os.path.join(dst, os.path.basename(path)) - if os.path.isdir(path): - shutil.copytree(path, target_path) - else: - shutil.copy(path, target_path) - except Exception, e: - error('failed to copy seahub thirdpart libs: %s' % e) - -def strip_symbols(): - def do_strip(fn): - run('chmod u+w %s' % fn) - info('stripping: %s' % fn) - run('strip "%s"' % fn) - - def remove_static_lib(fn): - info('removing: %s' % fn) - os.remove(fn) - - for parent, dnames, fnames in os.walk('seafile-server/seafile'): - dummy = dnames # avoid pylint 'unused' warning - for fname in fnames: - fn = os.path.join(parent, fname) - if os.path.isdir(fn): - continue - - if fn.endswith(".a") or fn.endswith(".la"): - remove_static_lib(fn) - continue - - if os.path.islink(fn): - continue - - finfo = commands.getoutput('file "%s"' % fn) - - if 'not stripped' in finfo: - do_strip(fn) - -def create_tarball(tarball_name): - '''call tar command to generate a tarball''' - version = conf[CONF_VERSION] - - serverdir = 'seafile-server' - versioned_serverdir = 'seafile-server-' + version - - # move seafile-server to seafile-server-${version} - try: - shutil.move(serverdir, versioned_serverdir) - except Exception, e: - error('failed to move %s to %s: %s' % (serverdir, versioned_serverdir, e)) - - ignored_patterns = [ - # common ignored files - '*.pyc', - '*~', - '*#', - - # seahub - os.path.join(versioned_serverdir, 'seahub', '.git*'), - os.path.join(versioned_serverdir, 'seahub', 'media', 'flexpaper*'), - os.path.join(versioned_serverdir, 'seahub', 'avatar', 'testdata*'), - - # seafile - os.path.join(versioned_serverdir, 'seafile', 'share*'), - os.path.join(versioned_serverdir, 'seafile', 'include*'), - os.path.join(versioned_serverdir, 'seafile', 'lib', 'pkgconfig*'), - os.path.join(versioned_serverdir, 'seafile', 'lib64', 'pkgconfig*'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'ccnet-demo*'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'ccnet-tool'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'ccnet-servtool'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'searpc-codegen.py'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'seafile-admin'), - os.path.join(versioned_serverdir, 'seafile', 'bin', 'seafile'), - ] - - excludes_list = [ '--exclude=%s' % pattern for pattern in ignored_patterns ] - excludes = ' '.join(excludes_list) - - tar_cmd = 'tar czf %(tarball_name)s %(versioned_serverdir)s %(excludes)s' \ - % dict(tarball_name=tarball_name, - versioned_serverdir=versioned_serverdir, - excludes=excludes) - - if run(tar_cmd) < 0: - error('failed to generate the tarball') - -def gen_tarball(): - # strip symbols of libraries to reduce size - if not conf[CONF_NO_STRIP]: - try: - strip_symbols() - except Exception, e: - error('failed to strip symbols: %s' % e) - - # determine the output name - # 64-bit: seafile-server_1.2.2_x86-64.tar.gz - # 32-bit: seafile-server_1.2.2_i386.tar.gz - version = conf[CONF_VERSION] - arch = os.uname()[-1].replace('_', '-') - if 'arm' in platform.machine(): - arch = 'pi' - elif arch != 'x86-64': - arch = 'i386' - - dbg = '' - if conf[CONF_NO_STRIP]: - dbg = '.dbg' - - tarball_name = 'seafile-server_%(version)s_%(arch)s%(dbg)s.tar.gz' \ - % dict(version=version, arch=arch, dbg=dbg) - dst_tarball = os.path.join(conf[CONF_OUTPUTDIR], tarball_name) - - # generate the tarball - try: - create_tarball(tarball_name) - except Exception, e: - error('failed to generate tarball: %s' % e) - - # move tarball to outputdir - try: - shutil.copy(tarball_name, dst_tarball) - except Exception, e: - error('failed to copy %s to %s: %s' % (tarball_name, dst_tarball, e)) - - print '---------------------------------------------' - print 'The build is successful. Output is:\t%s' % dst_tarball - print '---------------------------------------------' - -def main(): - parse_args() - setup_build_env() - - libsearpc = Libsearpc() - ccnet = Ccnet() - seafile = Seafile() - seahub = Seahub() - - libsearpc.uncompress() - libsearpc.build() - - ccnet.uncompress() - ccnet.build() - - seafile.uncompress() - seafile.build() - - seahub.uncompress() - seahub.build() - - copy_scripts_and_libs() - gen_tarball() - -if __name__ == '__main__': - main() diff --git a/scripts/check_init_admin.py b/scripts/check_init_admin.py deleted file mode 100644 index 281944ed..00000000 --- a/scripts/check_init_admin.py +++ /dev/null @@ -1,373 +0,0 @@ -#coding: UTF-8 - -'''This script would check if there is admin, and prompt the user to create a new one if non exist''' - -import sys -import os -import time -import re -import shutil -import glob -import subprocess -import hashlib -import getpass -import uuid -import warnings - -from ConfigParser import ConfigParser - -try: - import readline # pylint: disable=W0611 -except ImportError: - pass - - -SERVER_MANUAL_HTTP = 'https://github.com/haiwen/seafile/wiki' - -class Utils(object): - '''Groups all helper functions here''' - @staticmethod - def welcome(): - '''Show welcome message''' - welcome_msg = '''\ ------------------------------------------------------------------ -This script will guide you to setup your seafile server using MySQL. -Make sure you have read seafile server manual at - - %s - -Press ENTER to continue ------------------------------------------------------------------''' % SERVER_MANUAL_HTTP - print welcome_msg - raw_input() - - @staticmethod - def highlight(content): - '''Add ANSI color to content to get it highlighted on terminal''' - return '\x1b[33m%s\x1b[m' % content - - @staticmethod - def info(msg): - print msg - - @staticmethod - def error(msg): - '''Print error and exit''' - print - print 'Error: ' + msg - sys.exit(1) - - @staticmethod - def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Run a program and wait it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - - @staticmethod - def run(cmdline, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Like run_argv but specify a command line string instead of argv''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(cmdline, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env, - shell=True) - return proc.wait() - - @staticmethod - def prepend_env_value(name, value, env=None, seperator=':'): - '''prepend a new value to a list''' - if env is None: - env = os.environ - - try: - current_value = env[name] - except KeyError: - current_value = '' - - new_value = value - if current_value: - new_value += seperator + current_value - - env[name] = new_value - - @staticmethod - def must_mkdir(path): - '''Create a directory, exit on failure''' - try: - os.mkdir(path) - except OSError, e: - Utils.error('failed to create directory %s:%s' % (path, e)) - - @staticmethod - def must_copy(src, dst): - '''Copy src to dst, exit on failure''' - try: - shutil.copy(src, dst) - except Exception, e: - Utils.error('failed to copy %s to %s: %s' % (src, dst, e)) - - @staticmethod - def find_in_path(prog): - if 'win32' in sys.platform: - sep = ';' - else: - sep = ':' - - dirs = os.environ['PATH'].split(sep) - for d in dirs: - d = d.strip() - if d == '': - continue - path = os.path.join(d, prog) - if os.path.exists(path): - return path - - return None - - @staticmethod - def get_python_executable(): - '''Return the python executable. This should be the PYTHON environment - variable which is set in setup-seafile-mysql.sh - - ''' - return os.environ['PYTHON'] - - @staticmethod - def read_config(fn): - '''Return a case sensitive ConfigParser by reading the file "fn"''' - cp = ConfigParser() - cp.optionxform = str - cp.read(fn) - - return cp - - @staticmethod - def write_config(cp, fn): - '''Return a case sensitive ConfigParser by reading the file "fn"''' - with open(fn, 'w') as fp: - cp.write(fp) - - @staticmethod - def ask_question(desc, - key=None, - note=None, - default=None, - validate=None, - yes_or_no=False, - password=False): - '''Ask a question, return the answer. - @desc description, e.g. "What is the port of ccnet?" - - @key a name to represent the target of the question, e.g. "port for - ccnet server" - - @note additional information for the question, e.g. "Must be a valid - port number" - - @default the default value of the question. If the default value is - not None, when the user enter nothing and press [ENTER], the default - value would be returned - - @validate a function that takes the user input as the only parameter - and validate it. It should return a validated value, or throws an - "InvalidAnswer" exception if the input is not valid. - - @yes_or_no If true, the user must answer "yes" or "no", and a boolean - value would be returned - - @password If true, the user input would not be echoed to the - console - - ''' - assert key or yes_or_no - # Format description - print - if note: - desc += '\n' + note - - desc += '\n' - if yes_or_no: - desc += '[ yes or no ]' - else: - if default: - desc += '[ default "%s" ]' % default - else: - desc += '[ %s ]' % key - - desc += ' ' - while True: - # prompt for user input - if password: - answer = getpass.getpass(desc).strip() - else: - answer = raw_input(desc).strip() - - # No user input: use default - if not answer: - if default: - answer = default - else: - continue - - # Have user input: validate answer - if yes_or_no: - if answer not in ['yes', 'no']: - print Utils.highlight('\nPlease answer yes or no\n') - continue - else: - return answer == 'yes' - else: - if validate: - try: - return validate(answer) - except InvalidAnswer, e: - print Utils.highlight('\n%s\n' % e) - continue - else: - return answer - - @staticmethod - def validate_port(port): - try: - port = int(port) - except ValueError: - raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port)) - - if port <= 0 or port > 65535: - raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port)) - - return port - - -class InvalidAnswer(Exception): - def __init__(self, msg): - Exception.__init__(self) - self.msg = msg - def __str__(self): - return self.msg - -### END of Utils -#################### - -class RPC(object): - def __init__(self): - import ccnet - ccnet_dir = os.environ['CCNET_CONF_DIR'] - central_config_dir = os.environ['SEAFILE_CENTRAL_CONF_DIR'] - self.rpc_client = ccnet.CcnetThreadedRpcClient( - ccnet.ClientPool(ccnet_dir, central_config_dir=central_config_dir)) - - def get_db_email_users(self): - return self.rpc_client.get_emailusers('DB', 0, 1) - - def create_admin(self, email, user): - return self.rpc_client.add_emailuser(email, user, 1, 1) - -def need_create_admin(): - users = rpc.get_db_email_users() - return len(users) == 0 - -def create_admin(email, passwd): - if rpc.create_admin(email, passwd) < 0: - raise Exception('failed to create admin') - else: - print '\n\n' - print '----------------------------------------' - print 'Successfully created seafile admin' - print '----------------------------------------' - print '\n\n' - -def ask_admin_email(): - print - print '----------------------------------------' - print 'It\'s the first time you start the seafile server. Now let\'s create the admin account' - print '----------------------------------------' - def validate(email): - # whitespace is not allowed - if re.match(r'[\s]', email): - raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email)) - # must be a valid email address - if not re.match(r'^.+@.*\..+$', email): - raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email)) - - return email - - key = 'admin email' - question = 'What is the ' + Utils.highlight('email') + ' for the admin account?' - return Utils.ask_question(question, - key=key, - validate=validate) - -def ask_admin_password(): - def validate(password): - key = 'admin password again' - question = 'Enter the ' + Utils.highlight('password again:') - password_again = Utils.ask_question(question, - key=key, - password=True) - - if password_again != password: - raise InvalidAnswer('password mismatch') - - return password - - key = 'admin password' - question = 'What is the ' + Utils.highlight('password') + ' for the admin account?' - return Utils.ask_question(question, - key=key, - password=True, - validate=validate) - -rpc = RPC() - -def main(): - if not need_create_admin(): - return - - email = ask_admin_email() - passwd = ask_admin_password() - - create_admin(email, passwd) - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - print '\n\n\n' - print Utils.highlight('Aborted.') - print - sys.exit(1) - except Exception, e: - print - print Utils.highlight('Error happened during creating seafile admin.') - print diff --git a/scripts/gc.bat b/scripts/gc.bat deleted file mode 100644 index 84770301..00000000 --- a/scripts/gc.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\seahub\thirdpart -start python upgrade/py/gc.py diff --git a/scripts/reset-admin.sh b/scripts/reset-admin.sh deleted file mode 100755 index 5c10cdfd..00000000 --- a/scripts/reset-admin.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -central_config_dir=${TOPDIR}/conf - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable; -read_seafile_data_dir; - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export SEAFILE_CONF_DIR=${seafile_data_dir} -export SEAFILE_CENTRAL_CONF_DIR=${central_config_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -manage_py=${INSTALLPATH}/seahub/manage.py -exec "$PYTHON" "$manage_py" createsuperuser diff --git a/scripts/seaf-fsck.sh b/scripts/seaf-fsck.sh deleted file mode 100755 index 18b654ba..00000000 --- a/scripts/seaf-fsck.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -echo "" - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_conf_dir=${TOPDIR}/conf -seaf_fsck=${INSTALLPATH}/seafile/bin/seaf-fsck - -export PATH=${INSTALLPATH}/seafile/bin:$PATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -script_name=$0 -function usage () { - echo "usage : " - echo "$(basename ${script_name}) [-h/--help] [-r/--repair] [-E/--export path_to_export] [repo_id_1 [repo_id_2 ...]]" - echo "" -} - -function validate_ccnet_conf_dir () { - if [[ ! -d ${default_ccnet_conf_dir} ]]; then - echo "Error: there is no ccnet config directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -function run_seaf_fsck () { - validate_ccnet_conf_dir; - read_seafile_data_dir; - - echo "Starting seaf-fsck, please wait ..." - echo - - LD_LIBRARY_PATH=$SEAFILE_LD_LIBRARY_PATH ${seaf_fsck} \ - -c "${default_ccnet_conf_dir}" -d "${seafile_data_dir}" \ - -F "${default_conf_dir}" \ - ${seaf_fsck_opts} - - echo "seaf-fsck run done" - echo -} - -if [ $# -gt 0 ]; -then - for param in $@; - do - if [ ${param} = "-h" -o ${param} = "--help" ]; - then - usage; - exit 1; - fi - done -fi - -seaf_fsck_opts=$@ -run_seaf_fsck; - -echo "Done." diff --git a/scripts/seaf-fuse.sh b/scripts/seaf-fuse.sh deleted file mode 100755 index d67a45a9..00000000 --- a/scripts/seaf-fuse.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/bash - -echo "" - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_conf_dir=${TOPDIR}/conf -seaf_fuse=${INSTALLPATH}/seafile/bin/seaf-fuse - -export PATH=${INSTALLPATH}/seafile/bin:$PATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -script_name=$0 -function usage () { - echo "usage : " - echo "$(basename ${script_name}) { start | stop | restart } " - echo "" -} - -# check args -if [[ "$1" != "start" && "$1" != "stop" && "$1" != "restart" ]]; then - usage; - exit 1; -fi - -if [[ ($1 == "start" || $1 == "restart" ) && $# -lt 2 ]]; then - usage; - exit 1 -fi - -if [[ $1 == "stop" && $# != 1 ]]; then - usage; - exit 1 -fi - -function validate_ccnet_conf_dir () { - if [[ ! -d ${default_ccnet_conf_dir} ]]; then - echo "Error: there is no ccnet config directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -function validate_already_running () { - if pid=$(pgrep -f "seaf-fuse -c ${default_ccnet_conf_dir}" 2>/dev/null); then - echo "seaf-fuse is already running, pid $pid" - echo - exit 1; - fi -} - -function warning_if_seafile_not_running () { - if ! pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo - echo "Warning: seafile-controller not running. Have you run \"./seafile.sh start\" ?" - echo - fi -} - -function start_seaf_fuse () { - validate_already_running; - warning_if_seafile_not_running; - validate_ccnet_conf_dir; - read_seafile_data_dir; - - echo "Starting seaf-fuse, please wait ..." - - logfile=${TOPDIR}/logs/seaf-fuse.log - - LD_LIBRARY_PATH=$SEAFILE_LD_LIBRARY_PATH ${seaf_fuse} \ - -c "${default_ccnet_conf_dir}" \ - -d "${seafile_data_dir}" \ - -F "${default_conf_dir}" \ - -l "${logfile}" \ - "$@" - - sleep 2 - - # check if seaf-fuse started successfully - if ! pgrep -f "seaf-fuse -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo "Failed to start seaf-fuse" - exit 1; - fi - - echo "seaf-fuse started" - echo -} - -function stop_seaf_fuse() { - if ! pgrep -f "seaf-fuse -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo "seaf-fuse not running yet" - return 1; - fi - - echo "Stopping seaf-fuse ..." - pkill -SIGTERM -f "seaf-fuse -c ${default_ccnet_conf_dir}" - return 0 -} - -function restart_seaf_fuse () { - stop_seaf_fuse - sleep 2 - start_seaf_fuse $@ -} - -case $1 in - "start" ) - shift - start_seaf_fuse $@; - ;; - "stop" ) - stop_seaf_fuse; - ;; - "restart" ) - shift - restart_seaf_fuse $@; -esac - -echo "Done." diff --git a/scripts/seaf-gc.sh b/scripts/seaf-gc.sh deleted file mode 100755 index f33ad20c..00000000 --- a/scripts/seaf-gc.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/bash - -echo "" - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_conf_dir=${TOPDIR}/conf -seaf_gc=${INSTALLPATH}/seafile/bin/seafserv-gc -seaf_gc_opts="" - -export PATH=${INSTALLPATH}/seafile/bin:$PATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -script_name=$0 -function usage () { - echo "usage : " - echo "$(basename ${script_name}) [--dry-run | -D] [--rm-deleted | -r] [repo-id1] [repo-id2]" - echo "" -} - - -function validate_ccnet_conf_dir () { - if [[ ! -d ${default_ccnet_conf_dir} ]]; then - echo "Error: there is no ccnet config directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -function check_component_running() { - name=$1 - cmd=$2 - if pid=$(pgrep -f "$cmd" 2>/dev/null); then - echo "[$name] is running, pid $pid. You can stop it by: " - echo - echo " kill $pid" - echo - echo "Stop it and try again." - echo - exit - fi -} - -function validate_already_running () { - if pid=$(pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null); then - echo "seafile server is still running, stop it by \"seafile.sh stop\"" - echo - exit 1; - fi - - check_component_running "ccnet-server" "ccnet-server -c ${default_ccnet_conf_dir}" - check_component_running "seaf-server" "seaf-server -c ${default_ccnet_conf_dir}" - check_component_running "fileserver" "fileserver -c ${default_ccnet_conf_dir}" - check_component_running "seafdav" "wsgidav.server.run_server" -} - -function run_seaf_gc () { - validate_already_running; - validate_ccnet_conf_dir; - read_seafile_data_dir; - - echo "Starting seafserv-gc, please wait ..." - - LD_LIBRARY_PATH=$SEAFILE_LD_LIBRARY_PATH ${seaf_gc} \ - -c "${default_ccnet_conf_dir}" \ - -d "${seafile_data_dir}" \ - -F "${default_conf_dir}" \ - ${seaf_gc_opts} - - echo "seafserv-gc run done" - echo -} - -if [ $# -gt 0 ]; -then - for param in $@; - do - if [ ${param} = "-h" -o ${param} = "--help" ]; - then - usage; - exit 1; - fi - done -fi - -seaf_gc_opts=$@ -run_seaf_gc; - -echo "Done." diff --git a/scripts/seafile.sh b/scripts/seafile.sh deleted file mode 100755 index 4be558f8..00000000 --- a/scripts/seafile.sh +++ /dev/null @@ -1,181 +0,0 @@ -#!/bin/bash - -### BEGIN INIT INFO -# Provides: seafile -# Required-Start: $local_fs $remote_fs $network -# Required-Stop: $local_fs -# Default-Start: 1 2 3 4 5 -# Default-Stop: -# Short-Description: Starts Seafile Server -# Description: starts Seafile Server -### END INIT INFO - -echo "" - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -central_config_dir=${TOPDIR}/conf -seaf_controller="${INSTALLPATH}/seafile/bin/seafile-controller" - - -export PATH=${INSTALLPATH}/seafile/bin:$PATH -export ORIG_LD_LIBRARY_PATH=${LD_LIBRARY_PATH} -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -script_name=$0 -function usage () { - echo "usage : " - echo "$(basename ${script_name}) { start | stop | restart } " - echo "" -} - -# check args -if [[ $# != 1 || ( "$1" != "start" && "$1" != "stop" && "$1" != "restart" ) ]]; then - usage; - exit 1; -fi - -function validate_running_user () { - real_data_dir=`readlink -f ${seafile_data_dir}` - running_user=`id -un` - data_dir_owner=`stat -c %U ${real_data_dir}` - - if [[ "${running_user}" != "${data_dir_owner}" ]]; then - echo "Error: the user running the script (\"${running_user}\") is not the owner of \"${real_data_dir}\" folder, you should use the user \"${data_dir_owner}\" to run the script." - exit -1; - fi -} - -function validate_ccnet_conf_dir () { - if [[ ! -d ${default_ccnet_conf_dir} ]]; then - echo "Error: there is no ccnet config directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function validate_central_conf_dir () { - if [[ ! -d ${central_config_dir} ]]; then - echo "Error: there is no conf/ directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -function test_config() { - if ! LD_LIBRARY_PATH=$SEAFILE_LD_LIBRARY_PATH ${seaf_controller} --test \ - -c "${default_ccnet_conf_dir}" \ - -d "${seafile_data_dir}" \ - -F "${central_config_dir}" ; then - exit 1; - fi -} - -function check_component_running() { - name=$1 - cmd=$2 - if pid=$(pgrep -f "$cmd" 2>/dev/null); then - echo "[$name] is running, pid $pid. You can stop it by: " - echo - echo " kill $pid" - echo - echo "Stop it and try again." - echo - exit - fi -} - -function validate_already_running () { - if pid=$(pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null); then - echo "Seafile controller is already running, pid $pid" - echo - exit 1; - fi - - check_component_running "ccnet-server" "ccnet-server -c ${default_ccnet_conf_dir}" - check_component_running "seaf-server" "seaf-server -c ${default_ccnet_conf_dir}" - check_component_running "fileserver" "fileserver -c ${default_ccnet_conf_dir}" - check_component_running "seafdav" "wsgidav.server.run_server" -} - -function start_seafile_server () { - validate_already_running; - validate_central_conf_dir; - validate_ccnet_conf_dir; - read_seafile_data_dir; - validate_running_user; - test_config; - - echo "Starting seafile server, please wait ..." - - mkdir -p $TOPDIR/logs - LD_LIBRARY_PATH=$SEAFILE_LD_LIBRARY_PATH ${seaf_controller} \ - -c "${default_ccnet_conf_dir}" \ - -d "${seafile_data_dir}" \ - -F "${central_config_dir}" - - sleep 3 - - # check if seafile server started successfully - if ! pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo "Failed to start seafile server" - exit 1; - fi - - echo "Seafile server started" - echo -} - -function stop_seafile_server () { - if ! pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo "seafile server not running yet" - return 1; - fi - - echo "Stopping seafile server ..." - pkill -SIGTERM -f "seafile-controller -c ${default_ccnet_conf_dir}" - pkill -f "ccnet-server -c ${default_ccnet_conf_dir}" - pkill -f "seaf-server -c ${default_ccnet_conf_dir}" - pkill -f "fileserver -c ${default_ccnet_conf_dir}" - pkill -f "soffice.*--invisible --nocrashreport" - pkill -f "wsgidav.server.run_server" - return 0 -} - -function restart_seafile_server () { - stop_seafile_server; - sleep 2 - start_seafile_server; -} - -case $1 in - "start" ) - start_seafile_server; - ;; - "stop" ) - stop_seafile_server; - ;; - "restart" ) - restart_seafile_server; -esac - -echo "Done." diff --git a/scripts/seahub.conf b/scripts/seahub.conf deleted file mode 100644 index 60e2b9b0..00000000 --- a/scripts/seahub.conf +++ /dev/null @@ -1,12 +0,0 @@ -import os - -daemon = True -workers = 3 - -# Logging -runtime_dir = os.path.dirname(__file__) -pidfile = os.path.join(runtime_dir, 'seahub.pid') -errorlog = os.path.join(runtime_dir, 'error.log') -accesslog = os.path.join(runtime_dir, 'access.log') -# for file upload, we need a longer timeout value (default is only 30s, too short) -timeout = 1200 diff --git a/scripts/seahub.sh b/scripts/seahub.sh deleted file mode 100755 index 8a3fa7ce..00000000 --- a/scripts/seahub.sh +++ /dev/null @@ -1,274 +0,0 @@ -#!/bin/bash - -### BEGIN INIT INFO -# Provides: seahub -# Required-Start: $local_fs $remote_fs $network -# Required-Stop: $local_fs -# Default-Start: 1 2 3 4 5 -# Default-Stop: -# Short-Description: Starts Seahub -# Description: starts Seahub -### END INIT INFO - -echo "" - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -central_config_dir=${TOPDIR}/conf - -manage_py=${INSTALLPATH}/seahub/manage.py -gunicorn_conf=${INSTALLPATH}/runtime/seahub.conf -pidfile=${INSTALLPATH}/runtime/seahub.pid -errorlog=${INSTALLPATH}/runtime/error.log -accesslog=${INSTALLPATH}/runtime/access.log -gunicorn_exe=${INSTALLPATH}/seahub/thirdpart/gunicorn - - -script_name=$0 -function usage () { - echo "Usage: " - echo - echo " $(basename ${script_name}) { start | stop | restart }" - echo - echo "To run seahub in fastcgi:" - echo - echo " $(basename ${script_name}) { start-fastcgi | stop | restart-fastcgi }" - echo - echo " is optional, and defaults to 8000" - echo "" -} - -# Check args -if [[ $1 != "start" && $1 != "stop" && $1 != "restart" \ - && $1 != "start-fastcgi" && $1 != "restart-fastcgi" && $1 != "clearsessions" ]]; then - usage; - exit 1; -fi - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function validate_ccnet_conf_dir () { - if [[ ! -d ${default_ccnet_conf_dir} ]]; then - echo "Error: there is no ccnet config directory." - echo "Have you run setup-seafile.sh before this?" - echo "" - exit -1; - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -function validate_seahub_running () { - if pgrep -f "${manage_py}" 2>/dev/null 1>&2; then - echo "Seahub is already running." - exit 1; - elif pgrep -f "seahub.wsgi:application" 2>/dev/null 1>&2; then - echo "Seahub is already running." - exit 1; - fi -} - -function validate_port () { - if ! [[ ${port} =~ ^[1-9][0-9]{1,4}$ ]] ; then - printf "\033[033m${port}\033[m is not a valid port number\n\n" - usage; - exit 1 - fi -} - -if [[ ($1 == "start" || $1 == "restart" || $1 == "start-fastcgi" || $1 == "restart-fastcgi") \ - && ($# == 2 || $# == 1) ]]; then - if [[ $# == 2 ]]; then - port=$2 - validate_port - else - port=8000 - fi -elif [[ $1 == "stop" && $# == 1 ]]; then - dummy=dummy -elif [[ $1 == "clearsessions" && $# == 1 ]]; then - dummy=dummy -else - usage; - exit 1 -fi - -function warning_if_seafile_not_running () { - if ! pgrep -f "seafile-controller -c ${default_ccnet_conf_dir}" 2>/dev/null 1>&2; then - echo - echo "Warning: seafile-controller not running. Have you run \"./seafile.sh start\" ?" - echo - exit 1 - fi -} - -function prepare_seahub_log_dir() { - logdir=${TOPDIR}/logs - if ! [[ -d ${logsdir} ]]; then - if ! mkdir -p "${logdir}"; then - echo "ERROR: failed to create logs dir \"${logdir}\"" - exit 1 - fi - fi - export SEAHUB_LOG_DIR=${logdir} -} - -function before_start() { - prepare_env; - warning_if_seafile_not_running; - validate_seahub_running; - prepare_seahub_log_dir; -} - -function start_seahub () { - before_start; - echo "Starting seahub at port ${port} ..." - check_init_admin; - $PYTHON $gunicorn_exe seahub.wsgi:application -c "${gunicorn_conf}" -b "0.0.0.0:${port}" --preload - - # Ensure seahub is started successfully - sleep 5 - if ! pgrep -f "seahub.wsgi:application" 2>/dev/null 1>&2; then - printf "\033[33mError:Seahub failed to start.\033[m\n" - echo "Please try to run \"./seahub.sh start\" again" - exit 1; - fi - echo - echo "Seahub is started" - echo -} - -function start_seahub_fastcgi () { - before_start; - - # Returns 127.0.0.1 if SEAFILE_FASTCGI_HOST is unset or hasn't got any value, - # otherwise returns value of SEAFILE_FASTCGI_HOST environment variable - address=`(test -z "$SEAFILE_FASTCGI_HOST" && echo "127.0.0.1") || echo $SEAFILE_FASTCGI_HOST` - - echo "Starting seahub (fastcgi) at ${address}:${port} ..." - check_init_admin; - $PYTHON "${manage_py}" runfcgi host=$address port=$port pidfile=$pidfile \ - outlog=${accesslog} errlog=${errorlog} - - # Ensure seahub is started successfully - sleep 5 - if ! pgrep -f "${manage_py}" 1>/dev/null; then - printf "\033[33mError:Seahub failed to start.\033[m\n" - exit 1; - fi - echo - echo "Seahub is started" - echo -} - -function prepare_env() { - check_python_executable; - validate_ccnet_conf_dir; - read_seafile_data_dir; - - if [[ -z "$LANG" ]]; then - echo "LANG is not set in ENV, set to en_US.UTF-8" - export LANG='en_US.UTF-8' - fi - if [[ -z "$LC_ALL" ]]; then - echo "LC_ALL is not set in ENV, set to en_US.UTF-8" - export LC_ALL='en_US.UTF-8' - fi - - export CCNET_CONF_DIR=${default_ccnet_conf_dir} - export SEAFILE_CONF_DIR=${seafile_data_dir} - export SEAFILE_CENTRAL_CONF_DIR=${central_config_dir} - export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seahub:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH - export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -} - -function clear_sessions () { - prepare_env; - - echo "Start clear expired session records ..." - $PYTHON "${manage_py}" clearsessions - - echo - echo "Done" - echo -} - -function stop_seahub () { - if [[ -f ${pidfile} ]]; then - pid=$(cat "${pidfile}") - echo "Stopping seahub ..." - kill ${pid} - rm -f ${pidfile} - return 0 - else - echo "Seahub is not running" - fi -} - -function check_init_admin() { - check_init_admin_script=${INSTALLPATH}/check_init_admin.py - if ! $PYTHON $check_init_admin_script; then - exit 1 - fi -} - -case $1 in - "start" ) - start_seahub; - ;; - "start-fastcgi" ) - start_seahub_fastcgi; - ;; - "stop" ) - stop_seahub; - ;; - "restart" ) - stop_seahub - sleep 2 - start_seahub - ;; - "restart-fastcgi" ) - stop_seahub - sleep 2 - start_seahub_fastcgi - ;; - "clearsessions" ) - clear_sessions - ;; -esac - -echo "Done." -echo "" diff --git a/scripts/server-release.md b/scripts/server-release.md deleted file mode 100644 index c02226a6..00000000 --- a/scripts/server-release.md +++ /dev/null @@ -1,31 +0,0 @@ -# Server Release Package - -1. Libsearpc - cd libsearpc; - CFLAGS="-O2" configure --prefix=$dest - make install -2. Ccnet - cd ccnet; - CFLAGS="-O2" ./configure --enable-server-pkg --prefix=$dest - make install -3. Seafile - cd seafile; - CFLAGS="-O2" configure --enable-server-pkg --prefix=$dest - make install -4. copy shared libraries - scripts/cp-shared-lib.py $dest/lib -5. strip libs/executables - python do-strip.py -6. Update seahub - cd seahub - git fetch origin - git checkout release - git rebase origin/master - -7. Pack - ./pack-server.sh 1.0.0 - -DONE! - - - diff --git a/scripts/setup-seafile-mysql.py b/scripts/setup-seafile-mysql.py deleted file mode 100644 index 2d95f19a..00000000 --- a/scripts/setup-seafile-mysql.py +++ /dev/null @@ -1,1445 +0,0 @@ -#coding: UTF-8 - -'''This script would guide the seafile admin to setup seafile with MySQL''' - -import sys -import os -import time -import re -import shutil -import glob -import subprocess -import hashlib -import getpass -import uuid -import warnings -import MySQLdb -import argparse -import socket - -from ConfigParser import ConfigParser - -try: - import readline # pylint: disable=W0611 -except ImportError: - pass - - -SERVER_MANUAL_HTTP = 'https://github.com/haiwen/seafile/wiki' - -class Utils(object): - '''Groups all helper functions here''' - @staticmethod - def welcome(): - '''Show welcome message''' - welcome_msg = '''\ ------------------------------------------------------------------ -This script will guide you to setup your seafile server using MySQL. -Make sure you have read seafile server manual at - - %s - -Press ENTER to continue ------------------------------------------------------------------''' % SERVER_MANUAL_HTTP - print welcome_msg - raw_input() - - @staticmethod - def highlight(content): - '''Add ANSI color to content to get it highlighted on terminal''' - return '\x1b[33m%s\x1b[m' % content - - @staticmethod - def info(msg): - print msg - - @staticmethod - def error(msg): - '''Print error and exit''' - print - print 'Error: ' + msg - sys.exit(1) - - @staticmethod - def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Run a program and wait it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - - @staticmethod - def run(cmdline, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Like run_argv but specify a command line string instead of argv''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(cmdline, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env, - shell=True) - return proc.wait() - - @staticmethod - def prepend_env_value(name, value, env=None, seperator=':'): - '''prepend a new value to a list''' - if env is None: - env = os.environ - - try: - current_value = env[name] - except KeyError: - current_value = '' - - new_value = value - if current_value: - new_value += seperator + current_value - - env[name] = new_value - - @staticmethod - def must_mkdir(path): - '''Create a directory, exit on failure''' - if os.path.exists(path): - return - try: - os.mkdir(path) - except OSError, e: - Utils.error('failed to create directory %s:%s' % (path, e)) - - @staticmethod - def must_copy(src, dst): - '''Copy src to dst, exit on failure''' - try: - shutil.copy(src, dst) - except Exception, e: - Utils.error('failed to copy %s to %s: %s' % (src, dst, e)) - - @staticmethod - def find_in_path(prog): - if 'win32' in sys.platform: - sep = ';' - else: - sep = ':' - - dirs = os.environ['PATH'].split(sep) - for d in dirs: - d = d.strip() - if d == '': - continue - path = os.path.join(d, prog) - if os.path.exists(path): - return path - - return None - - @staticmethod - def get_python_executable(): - '''Return the python executable. This should be the PYTHON environment - variable which is set in setup-seafile-mysql.sh - - ''' - return os.environ['PYTHON'] - - @staticmethod - def read_config(fn): - '''Return a case sensitive ConfigParser by reading the file "fn"''' - cp = ConfigParser() - cp.optionxform = str - cp.read(fn) - - return cp - - @staticmethod - def write_config(cp, fn): - '''Return a case sensitive ConfigParser by reading the file "fn"''' - with open(fn, 'w') as fp: - cp.write(fp) - - @staticmethod - def ask_question(desc, - key=None, - note=None, - default=None, - validate=None, - yes_or_no=False, - password=False): - '''Ask a question, return the answer. - @desc description, e.g. "What is the port of ccnet?" - - @key a name to represent the target of the question, e.g. "port for - ccnet server" - - @note additional information for the question, e.g. "Must be a valid - port number" - - @default the default value of the question. If the default value is - not None, when the user enter nothing and press [ENTER], the default - value would be returned - - @validate a function that takes the user input as the only parameter - and validate it. It should return a validated value, or throws an - "InvalidAnswer" exception if the input is not valid. - - @yes_or_no If true, the user must answer "yes" or "no", and a boolean - value would be returned - - @password If true, the user input would not be echoed to the - console - - ''' - assert key or yes_or_no - # Format description - print - if note: - desc += '\n' + note - - desc += '\n' - if yes_or_no: - desc += '[ yes or no ]' - else: - if default: - desc += '[ default "%s" ]' % default - else: - desc += '[ %s ]' % key - - desc += ' ' - while True: - # prompt for user input - if password: - answer = getpass.getpass(desc).strip() - else: - answer = raw_input(desc).strip() - - # No user input: use default - if not answer: - if default: - answer = default - else: - continue - - # Have user input: validate answer - if yes_or_no: - if answer not in ['yes', 'no']: - print Utils.highlight('\nPlease answer yes or no\n') - continue - else: - return answer == 'yes' - else: - if validate: - try: - return validate(answer) - except InvalidAnswer, e: - print Utils.highlight('\n%s\n' % e) - continue - else: - return answer - - @staticmethod - def validate_port(port): - try: - port = int(port) - except ValueError: - raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port)) - - if port <= 0 or port > 65535: - raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port)) - - return port - - -class InvalidAnswer(Exception): - def __init__(self, msg): - Exception.__init__(self) - self.msg = msg - def __str__(self): - return self.msg - -class InvalidParams(Exception): - def __init__(self, msg): - Exception.__init__(self) - self.msg = msg - def __str__(self): - return self.msg - -### END of Utils -#################### - -class EnvManager(object): - '''System environment and directory layout''' - def __init__(self): - self.install_path = os.path.dirname(os.path.abspath(__file__)) - self.top_dir = os.path.dirname(self.install_path) - self.bin_dir = os.path.join(self.install_path, 'seafile', 'bin') - self.central_config_dir = os.path.join(self.top_dir, 'conf') - Utils.must_mkdir(self.central_config_dir) - - def check_pre_condiction(self): - def error_if_not_exists(path): - if not os.path.exists(path): - Utils.error('"%s" not found' % path) - - paths = [ - os.path.join(self.install_path, 'seafile'), - os.path.join(self.install_path, 'seahub'), - os.path.join(self.install_path, 'runtime'), - ] - - for path in paths: - error_if_not_exists(path) - - if os.path.exists(ccnet_config.ccnet_dir): - Utils.error('Ccnet config dir \"%s\" already exists.' % ccnet_config.ccnet_dir) - - def get_seahub_env(self): - '''Prepare for seahub syncdb''' - env = dict(os.environ) - env['CCNET_CONF_DIR'] = ccnet_config.ccnet_dir - env['SEAFILE_CONF_DIR'] = seafile_config.seafile_dir - self.setup_python_path(env) - return env - - def setup_python_path(self, env): - '''And PYTHONPATH and CCNET_CONF_DIR/SEAFILE_CONF_DIR to env, which is - needed by seahub - - ''' - install_path = self.install_path - pro_pylibs_dir = os.path.join(install_path, 'pro', 'python') - extra_python_path = [ - pro_pylibs_dir, - - os.path.join(install_path, 'seahub', 'thirdpart'), - - os.path.join(install_path, 'seafile/lib/python2.6/site-packages'), - os.path.join(install_path, 'seafile/lib64/python2.6/site-packages'), - os.path.join(install_path, 'seafile/lib/python2.7/site-packages'), - os.path.join(install_path, 'seafile/lib64/python2.7/site-packages'), - ] - - for path in extra_python_path: - Utils.prepend_env_value('PYTHONPATH', path, env=env) - - def get_binary_env(self): - '''Set LD_LIBRARY_PATH for seafile server executables''' - env = dict(os.environ) - lib_dir = os.path.join(self.install_path, 'seafile', 'lib') - lib64_dir = os.path.join(self.install_path, 'seafile', 'lib64') - Utils.prepend_env_value('LD_LIBRARY_PATH', lib_dir, env=env) - Utils.prepend_env_value('LD_LIBRARY_PATH', lib64_dir, env=env) - return env - -class AbstractConfigurator(object): - '''Abstract Base class for ccnet/seafile/seahub/db configurator''' - def __init__(self): - pass - - def ask_questions(self): - raise NotImplementedError - - def generate(self): - raise NotImplementedError - - -class AbstractDBConfigurator(AbstractConfigurator): - '''Abstract class for database related configuration''' - def __init__(self): - AbstractConfigurator.__init__(self) - self.mysql_host = 'localhost' - self.mysql_port = 3306 - self.mysql_userhost = 'localhost' - - self.use_existing_db = False - - self.seafile_mysql_user = '' - self.seafile_mysql_password = '' - - self.ccnet_db_name = '' - self.seafile_db_name = '' - self.seahub_db_name = '' - - self.seahub_admin_email = '' - self.seahub_admin_password = '' - - @staticmethod - def ask_use_existing_db(): - def validate(choice): - if choice not in ['1', '2']: - raise InvalidAnswer('Please choose 1 or 2') - - return choice == '2' - - question = '''\ -------------------------------------------------------- -Please choose a way to initialize seafile databases: -------------------------------------------------------- -''' - - note = '''\ -[1] Create new ccnet/seafile/seahub databases -[2] Use existing ccnet/seafile/seahub databases -''' - return Utils.ask_question(question, - key='1 or 2', - note=note, - validate=validate) - - def validate_mysql_host(self, host): - if not re.match(r'^[a-zA-Z0-9_\-\.]+$', host): - raise InvalidAnswer('%s is not a valid host' % Utils.highlight(host)) - - if host == 'localhost': - host = '127.0.0.1' - return host - - def ask_mysql_host(self): - question = 'What is the host of mysql server?' - key = 'mysql server host' - default = 'localhost' - self.mysql_host = Utils.ask_question(question, - key=key, - default=default, - validate=self.validate_mysql_host) - - def validate_mysql_user_host(self, mysql_userhost): - if mysql_userhost != '%': - if not re.match(r'^[^.].+\..+[^.]$', mysql_userhost): - raise InvalidAnswer('%s is not a valid ip or domain' % mysql_userhost) - return mysql_userhost - - def ask_mysql_user_host(self): - question = 'Which hosts should be able to use your MySQL Account?' - key = 'mysql user host' - default = '%' - self.mysql_userhost = Utils.ask_question(question, - key=key, - default=default, - validate=self.validate_mysql_user_host) - - def ask_mysql_port(self): - question = 'What is the port of mysql server?' - key = 'mysql server port' - default = '3306' - port = Utils.ask_question(question, - key=key, - default=default, - validate=Utils.validate_port) - - # self.check_mysql_server(host, port) - self.mysql_port = port - - def ask_mysql_host_port(self): - self.ask_mysql_host() - if self.mysql_host != '127.0.0.1': - self.ask_mysql_user_host() - self.ask_mysql_port() - - def check_mysql_server(self, host, port): - print '\nverifying mysql server running ... ', - try: - dummy = MySQLdb.connect(host=host, port=port) - except Exception: - print - raise InvalidAnswer('Failed to connect to mysql server at "%s:%s"' \ - % (host, port)) - - print 'done' - - def check_mysql_user(self, user, password): - print '\nverifying password of user %s ... ' % user, - kwargs = dict(host=self.mysql_host, - port=self.mysql_port, - user=user, - passwd=password) - - try: - conn = MySQLdb.connect(**kwargs) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' \ - % (user, e.args[1])) - else: - raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' \ - % (user, e)) - - print 'done' - return conn - - def create_seahub_admin(self): - try: - conn = MySQLdb.connect(host=self.mysql_host, - port=self.mysql_port, - user=self.seafile_mysql_user, - passwd=self.seafile_mysql_password, - db=self.ccnet_db_name) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to connect to mysql database %s: %s' % (self.ccnet_db_name, e.args[1])) - else: - Utils.error('Failed to connect to mysql database %s: %s' % (self.ccnet_db_name, e)) - - cursor = conn.cursor() - sql = '''\ -CREATE TABLE IF NOT EXISTS EmailUser (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255), passwd CHAR(64), is_staff BOOL NOT NULL, is_active BOOL NOT NULL, ctime BIGINT, UNIQUE INDEX (email)) ENGINE=INNODB''' - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to create ccnet user table: %s' % e.args[1]) - else: - Utils.error('Failed to create ccnet user table: %s' % e) - - sql = '''REPLACE INTO EmailUser(email, passwd, is_staff, is_active, ctime) VALUES ('%s', '%s', 1, 1, 0)''' \ - % (seahub_config.admin_email, seahub_config.hashed_admin_password()) - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to create admin user: %s' % e.args[1]) - else: - Utils.error('Failed to create admin user: %s' % e) - - conn.commit() - - def ask_questions(self): - '''Ask questions and do database operations''' - raise NotImplementedError - - -class NewDBConfigurator(AbstractDBConfigurator): - '''Handles the case of creating new mysql databases for ccnet/seafile/seahub''' - def __init__(self): - AbstractDBConfigurator.__init__(self) - - self.root_password = '' - self.root_conn = '' - - def ask_questions(self): - self.ask_mysql_host_port() - - self.ask_root_password() - self.ask_seafile_mysql_user_password() - - self.ask_db_names() - - def generate(self): - if not self.mysql_user_exists(self.seafile_mysql_user): - self.create_user() - self.create_databases() - - def validate_root_passwd(self, password): - self.root_conn = self.check_mysql_user('root', password) - return password - - def ask_root_password(self): - question = 'What is the password of the mysql root user?' - key = 'root password' - self.root_password = Utils.ask_question(question, - key=key, - validate=self.validate_root_passwd, - password=True) - - def mysql_user_exists(self, user): - cursor = self.root_conn.cursor() - - sql = '''SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '%s' and host = '%s')''' % \ - (user, self.mysql_userhost) - - try: - cursor.execute(sql) - return cursor.fetchall()[0][0] - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to check mysql user %s@%s: %s' % \ - (user, self.mysql_userhost, e.args[1])) - else: - Utils.error('Failed to check mysql user %s@%s: %s' % \ - (user, self.mysql_userhost, e)) - finally: - cursor.close() - - - def ask_seafile_mysql_user_password(self): - def validate(user): - if user == 'root': - self.seafile_mysql_password = self.root_password - else: - question = 'Enter the password for mysql user "%s":' % Utils.highlight(user) - key = 'password for %s' % user - password = Utils.ask_question(question, key=key, password=True) - # If the user already exists, check the password here - if self.mysql_user_exists(user): - self.check_mysql_user(user, password) - self.seafile_mysql_password = password - - return user - - - question = 'Enter the name for mysql user of seafile. It would be created if not exists.' - key = 'mysql user for seafile' - default = 'root' - self.seafile_mysql_user = Utils.ask_question(question, - key=key, - default=default, - validate=validate) - - def ask_db_name(self, program, default): - question = 'Enter the database name for %s:' % program - key = '%s database' % program - return Utils.ask_question(question, - key=key, - default=default, - validate=self.validate_db_name) - - def ask_db_names(self): - self.ccnet_db_name = self.ask_db_name('ccnet-server', 'ccnet-db') - self.seafile_db_name = self.ask_db_name('seafile-server', 'seafile-db') - self.seahub_db_name = self.ask_db_name('seahub', 'seahub-db') - - def validate_db_name(self, db_name): - return db_name - - def create_user(self): - cursor = self.root_conn.cursor() - sql = '''CREATE USER '%s'@'%s' IDENTIFIED BY '%s' ''' \ - % (self.seafile_mysql_user, self.mysql_userhost, self.seafile_mysql_password) - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to create mysql user %s@%s: %s' % (self.seafile_mysql_user, self.mysql_userhost, e.args[1])) - else: - Utils.error('Failed to create mysql user %s@%s: %s' % (self.seafile_mysql_user, self.mysql_userhost, e)) - finally: - cursor.close() - - - def create_db(self, db_name): - cursor = self.root_conn.cursor() - sql = '''CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8''' \ - % db_name - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to create database %s: %s' % (db_name, e.args[1])) - else: - Utils.error('Failed to create database %s: %s' % (db_name, e)) - finally: - cursor.close() - - def grant_db_permission(self, db_name): - cursor = self.root_conn.cursor() - sql = '''GRANT ALL PRIVILEGES ON `%s`.* to `%s`@`%s` ''' \ - % (db_name, self.seafile_mysql_user, self.mysql_userhost) - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to grant permission of database %s: %s' % (db_name, e.args[1])) - else: - Utils.error('Failed to grant permission of database %s: %s' % (db_name, e)) - finally: - cursor.close() - - def create_databases(self): - self.create_db(self.ccnet_db_name) - self.create_db(self.seafile_db_name) - self.create_db(self.seahub_db_name) - - if self.seafile_mysql_user != 'root': - self.grant_db_permission(self.ccnet_db_name) - self.grant_db_permission(self.seafile_db_name) - self.grant_db_permission(self.seahub_db_name) - - -class ExistingDBConfigurator(AbstractDBConfigurator): - '''Handles the case of use existing mysql databases for ccnet/seafile/seahub''' - def __init__(self): - AbstractDBConfigurator.__init__(self) - self.use_existing_db = True - - def ask_questions(self): - self.ask_mysql_host_port() - - self.ask_existing_mysql_user_password() - - self.ccnet_db_name = self.ask_db_name('ccnet') - self.seafile_db_name = self.ask_db_name('seafile') - self.seahub_db_name = self.ask_db_name('seahub') - - def generate(self): - pass - - def ask_existing_mysql_user_password(self): - def validate(user): - question = 'What is the password for mysql user "%s"?' % Utils.highlight(user) - key = 'password for %s' % user - password = Utils.ask_question(question, key=key, password=True) - self.check_mysql_user(user, password) - self.seafile_mysql_password = password - return user - - question = 'Which mysql user to use for seafile?' - key = 'mysql user for seafile' - self.seafile_mysql_user = Utils.ask_question(question, - key=key, - validate=validate) - - def validate_db_name(self, db_name): - self.check_user_db_access(db_name) - return db_name - - def ask_db_name(self, program): - question = 'Enter the existing database name for %s:' % program - key = '%s database' % program - return Utils.ask_question(question, - key=key, - validate=self.validate_db_name) - - def check_user_db_access(self, db_name): - user = self.seafile_mysql_user - password = self.seafile_mysql_password - - print '\nverifying user "%s" access to database %s ... ' % (user, db_name), - try: - conn = MySQLdb.connect(host=self.mysql_host, - port=self.mysql_port, - user=user, - passwd=password, - db=db_name) - - cursor = conn.cursor() - cursor.execute('show tables') - cursor.close() - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - raise InvalidAnswer('Failed to access database %s using user "%s" and password "***": %s' \ - % (db_name, user, e.args[1])) - else: - raise InvalidAnswer('Failed to access database %s using user "%s" and password "***": %s' \ - % (db_name, user, e)) - - print 'done' - - return conn - - -class CcnetConfigurator(AbstractConfigurator): - SERVER_NAME_REGEX = r'^[a-zA-Z0-9_\-]{3,15}$' - SERVER_IP_OR_DOMAIN_REGEX = r'^[^.].+\..+[^.]$' - - def __init__(self): - '''Initialize default values of ccnet configuration''' - AbstractConfigurator.__init__(self) - self.ccnet_dir = os.path.join(env_mgr.top_dir, 'ccnet') - self.port = 10001 - self.server_name = None - self.ip_or_domain = None - self.ccnet_conf = os.path.join(env_mgr.central_config_dir, 'ccnet.conf') - - def ask_questions(self): - if not self.server_name: - self.ask_server_name() - if not self.ip_or_domain: - self.ask_server_ip_or_domain() - # self.ask_port() - - def generate(self): - print 'Generating ccnet configuration ...\n' - ccnet_init = os.path.join(env_mgr.bin_dir, 'ccnet-init') - argv = [ - ccnet_init, - '-F', env_mgr.central_config_dir, - '--config-dir', self.ccnet_dir, - '--name', self.server_name, - '--host', self.ip_or_domain, - ] - - if Utils.run_argv(argv, env=env_mgr.get_binary_env()) != 0: - Utils.error('Failed to generate ccnet configuration') - - time.sleep(1) - self.generate_db_conf() - - def generate_db_conf(self): - config = Utils.read_config(self.ccnet_conf) - # [Database] - # ENGINE= - # HOST= - # USER= - # PASSWD= - # DB= - db_section = 'Database' - if not config.has_section(db_section): - config.add_section(db_section) - config.set(db_section, 'ENGINE', 'mysql') - config.set(db_section, 'HOST', db_config.mysql_host) - config.set(db_section, 'PORT', db_config.mysql_port) - config.set(db_section, 'USER', db_config.seafile_mysql_user) - config.set(db_section, 'PASSWD', db_config.seafile_mysql_password) - config.set(db_section, 'DB', db_config.ccnet_db_name) - config.set(db_section, 'CONNECTION_CHARSET', 'utf8') - - Utils.write_config(config, self.ccnet_conf) - - def validate_server_name(self, name): - if not re.match(self.SERVER_NAME_REGEX, name): - raise InvalidAnswer('%s is not a valid name' % Utils.highlight(name)) - return name - - def ask_server_name(self): - question = 'What is the name of the server? It will be displayed on the client.' - key = 'server name' - note = '3 - 15 letters or digits' - self.server_name = Utils.ask_question(question, - key=key, - note=note, - validate=self.validate_server_name) - - def validate_server_ip(self, ip_or_domain): - if not re.match(self.SERVER_IP_OR_DOMAIN_REGEX, ip_or_domain): - raise InvalidAnswer('%s is not a valid ip or domain' % ip_or_domain) - return ip_or_domain - - def ask_server_ip_or_domain(self): - question = 'What is the ip or domain of the server?' - key = 'This server\'s ip or domain' - note = 'For example: www.mycompany.com, 192.168.1.101' - self.ip_or_domain = Utils.ask_question(question, - key=key, - note=note, - validate=self.validate_server_ip) - - def ask_port(self): - def validate(port): - return Utils.validate_port(port) - - question = 'Which port do you want to use for the ccnet server?' - key = 'ccnet server port' - default = 10001 - self.port = Utils.ask_question(question, - key=key, - default=default, - validate=validate) - - -class SeafileConfigurator(AbstractConfigurator): - def __init__(self): - AbstractConfigurator.__init__(self) - self.seafile_dir = None - self.port = 12001 - self.fileserver_port = None - self.seafile_conf = os.path.join(env_mgr.central_config_dir, 'seafile.conf') - - def ask_questions(self): - if not self.seafile_dir: - self.ask_seafile_dir() - # self.ask_port() - if not self.fileserver_port: - self.ask_fileserver_port() - - def generate(self): - print 'Generating seafile configuration ...\n' - seafserv_init = os.path.join(env_mgr.bin_dir, 'seaf-server-init') - argv = [ - seafserv_init, - '-F', env_mgr.central_config_dir, - '--seafile-dir', self.seafile_dir, - '--fileserver-port', str(self.fileserver_port), - ] - - if Utils.run_argv(argv, env=env_mgr.get_binary_env()) != 0: - Utils.error('Failed to generate ccnet configuration') - - time.sleep(1) - self.generate_db_conf() - self.write_seafile_ini() - print 'done' - - def generate_db_conf(self): - config = Utils.read_config(self.seafile_conf) - # [database] - # type= - # host= - # user= - # password= - # db_name= - # unix_socket= - db_section = 'database' - if not config.has_section(db_section): - config.add_section(db_section) - config.set(db_section, 'type', 'mysql') - config.set(db_section, 'host', db_config.mysql_host) - config.set(db_section, 'port', db_config.mysql_port) - config.set(db_section, 'user', db_config.seafile_mysql_user) - config.set(db_section, 'password', db_config.seafile_mysql_password) - config.set(db_section, 'db_name', db_config.seafile_db_name) - config.set(db_section, 'connection_charset', 'utf8') - - Utils.write_config(config, self.seafile_conf) - - def validate_seafile_dir(self, path): - if os.path.exists(path): - raise InvalidAnswer('%s already exists' % Utils.highlight(path)) - return path - - def ask_seafile_dir(self): - question = 'Where do you want to put your seafile data?' - key = 'seafile-data' - note = 'Please use a volume with enough free space' - default = os.path.join(env_mgr.top_dir, 'seafile-data') - self.seafile_dir = Utils.ask_question(question, - key=key, - note=note, - default=default, - validate=self.validate_seafile_dir) - - def ask_port(self): - def validate(port): - port = Utils.validate_port(port) - if port == ccnet_config.port: - raise InvalidAnswer('%s is used by ccnet server, choose another one' \ - % Utils.highlight(port)) - return port - - question = 'Which port do you want to use for the seafile server?' - key = 'seafile server port' - default = 12001 - self.port = Utils.ask_question(question, - key=key, - default=default, - validate=validate) - - def ask_fileserver_port(self): - question = 'Which port do you want to use for the seafile fileserver?' - key = 'seafile fileserver port' - default = 8082 - self.fileserver_port = Utils.ask_question(question, - key=key, - default=default, - validate=Utils.validate_port) - - def write_seafile_ini(self): - seafile_ini = os.path.join(ccnet_config.ccnet_dir, 'seafile.ini') - with open(seafile_ini, 'w') as fp: - fp.write(self.seafile_dir) - -class SeahubConfigurator(AbstractConfigurator): - def __init__(self): - AbstractConfigurator.__init__(self) - self.admin_email = '' - self.admin_password = '' - self.seahub_settings_py = os.path.join(env_mgr.central_config_dir, 'seahub_settings.py') - - def hashed_admin_password(self): - return hashlib.sha1(self.admin_password).hexdigest() # pylint: disable=E1101 - - def ask_questions(self): - pass - # self.ask_admin_email() - # self.ask_admin_password() - - def generate(self): - '''Generating seahub_settings.py''' - print 'Generating seahub configuration ...\n' - time.sleep(1) - self.write_secret_key() - with open(self.seahub_settings_py, 'a') as fp: - self.write_database_config(fp) - - def write_secret_key(self): - Utils.run_argv([Utils.get_python_executable(), - os.path.join(env_mgr.install_path, 'seahub', - 'tools', 'secret_key_generator.py'), - self.seahub_settings_py]) - - def write_database_config(self, fp): - template = '''\ -\nDATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': '%(name)s', - 'USER': '%(username)s', - 'PASSWORD': '%(password)s', - 'HOST': '%(host)s', - 'PORT': '%(port)s' - } -} - -''' - text = template % dict(name=db_config.seahub_db_name, - username=db_config.seafile_mysql_user, - password=db_config.seafile_mysql_password, - host=db_config.mysql_host, - port=db_config.mysql_port) - - fp.write(text) - - def ask_admin_email(self): - print - print '----------------------------------------' - print 'Now let\'s create the admin account' - print '----------------------------------------' - def validate(email): - # whitespace is not allowed - if re.match(r'[\s]', email): - raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email)) - # must be a valid email address - if not re.match(r'^.+@.*\..+$', email): - raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email)) - - return email - - key = 'admin email' - question = 'What is the ' + Utils.highlight('email') + ' for the admin account?' - self.admin_email = Utils.ask_question(question, - key=key, - validate=validate) - - def ask_admin_password(self): - def validate(password): - key = 'admin password again' - question = 'Enter the ' + Utils.highlight('password again:') - password_again = Utils.ask_question(question, - key=key, - password=True) - - if password_again != password: - raise InvalidAnswer('password mismatch') - - return password - - key = 'admin password' - question = 'What is the ' + Utils.highlight('password') + ' for the admin account?' - self.admin_password = Utils.ask_question(question, - key=key, - password=True, - validate=validate) - - def do_syncdb(self): - print '----------------------------------------' - print 'Now creating seahub database tables ...\n' - print '----------------------------------------' - - try: - conn = MySQLdb.connect(host=db_config.mysql_host, - port=db_config.mysql_port, - user=db_config.seafile_mysql_user, - passwd=db_config.seafile_mysql_password, - db=db_config.seahub_db_name) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to connect to mysql database %s: %s' % (db_config.seahub_db_name, e.args[1])) - else: - Utils.error('Failed to connect to mysql database %s: %s' % (db_config.seahub_db_name, e)) - - cursor = conn.cursor() - - sql_file = os.path.join(env_mgr.install_path, 'seahub', 'sql', 'mysql.sql') - with open(sql_file, 'r') as fp: - content = fp.read() - - sqls = [line.strip() for line in content.split(';') if line.strip()] - for sql in sqls: - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to init seahub database: %s' % e.args[1]) - else: - Utils.error('Failed to init seahub database: %s' % e) - - conn.commit() - - def prepare_avatar_dir(self): - # media_dir=${INSTALLPATH}/seahub/media - # orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - # dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # if [[ ! -d ${dest_avatar_dir} ]]; then - # mkdir -p "${TOPDIR}/seahub-data" - # mv "${orig_avatar_dir}" "${dest_avatar_dir}" - # ln -s ../../../seahub-data/avatars ${media_dir} - # fi - - try: - media_dir = os.path.join(env_mgr.install_path, 'seahub', 'media') - orig_avatar_dir = os.path.join(media_dir, 'avatars') - - seahub_data_dir = os.path.join(env_mgr.top_dir, 'seahub-data') - dest_avatar_dir = os.path.join(seahub_data_dir, 'avatars') - - if os.path.exists(dest_avatar_dir): - return - - if not os.path.exists(seahub_data_dir): - os.mkdir(seahub_data_dir) - - shutil.move(orig_avatar_dir, dest_avatar_dir) - os.symlink('../../../seahub-data/avatars', orig_avatar_dir) - except Exception, e: - Utils.error('Failed to prepare seahub avatars dir: %s' % e) - -class SeafDavConfigurator(AbstractConfigurator): - def __init__(self): - AbstractConfigurator.__init__(self) - self.seafdav_conf = None - - def ask_questions(self): - pass - - def generate(self): - self.seafdav_conf = os.path.join(env_mgr.central_config_dir, 'seafdav.conf') - text = ''' -[WEBDAV] -enabled = false -port = 8080 -fastcgi = false -share_name = / -''' - - with open(self.seafdav_conf, 'w') as fp: - fp.write(text) - -class UserManualHandler(object): - def __init__(self): - self.src_docs_dir = os.path.join(env_mgr.install_path, 'seafile', 'docs') - self.library_template_dir = None - - def copy_user_manuals(self): - self.library_template_dir = os.path.join(seafile_config.seafile_dir, 'library-template') - Utils.must_mkdir(self.library_template_dir) - - pattern = os.path.join(self.src_docs_dir, '*.doc') - - for doc in glob.glob(pattern): - Utils.must_copy(doc, self.library_template_dir) - -def report_config(): - print - print '---------------------------------' - print 'This is your configuration' - print '---------------------------------' - print - - template = '''\ - server name: %(server_name)s - server ip/domain: %(ip_or_domain)s - - seafile data dir: %(seafile_dir)s - fileserver port: %(fileserver_port)s - - database: %(use_existing_db)s - ccnet database: %(ccnet_db_name)s - seafile database: %(seafile_db_name)s - seahub database: %(seahub_db_name)s - database user: %(db_user)s - -''' - config = { - 'server_name' : ccnet_config.server_name, - 'ip_or_domain' : ccnet_config.ip_or_domain, - - 'seafile_dir' : seafile_config.seafile_dir, - 'fileserver_port' : seafile_config.fileserver_port, - - 'admin_email' : seahub_config.admin_email, - - - 'use_existing_db': 'use existing' if db_config.use_existing_db else 'create new', - 'ccnet_db_name': db_config.ccnet_db_name, - 'seafile_db_name': db_config.seafile_db_name, - 'seahub_db_name': db_config.seahub_db_name, - 'db_user': db_config.seafile_mysql_user - } - - print template % config - - if need_pause: - print - print '---------------------------------' - print 'Press ENTER to continue, or Ctrl-C to abort' - print '---------------------------------' - - raw_input() - - -def create_seafile_server_symlink(): - print '\ncreating seafile-server-latest symbolic link ... ', - seafile_server_symlink = os.path.join(env_mgr.top_dir, 'seafile-server-latest') - try: - os.symlink(os.path.basename(env_mgr.install_path), seafile_server_symlink) - except Exception, e: - print '\n' - Utils.error('Failed to create symbolic link %s: %s' % (seafile_server_symlink, e)) - else: - print 'done\n\n' - -def set_file_perm(): - filemode = 0600 - dirmode = 0700 - files = [ - seahub_config.seahub_settings_py, - ] - dirs = [ - env_mgr.central_config_dir, - ccnet_config.ccnet_dir, - seafile_config.seafile_dir, - seahub_config.seahub_settings_py, - ] - for fpath in files: - os.chmod(fpath, filemode) - for dpath in dirs: - os.chmod(dpath, dirmode) - -env_mgr = EnvManager() -ccnet_config = CcnetConfigurator() -seafile_config = SeafileConfigurator() -seafdav_config = SeafDavConfigurator() -seahub_config = SeahubConfigurator() -user_manuals_handler = UserManualHandler() -# Would be created after AbstractDBConfigurator.ask_use_existing_db() -db_config = None -need_pause = True - -def get_param_val(arg, env, default=None): - return arg or os.environ.get(env, default) - -def check_params(args): - host_name = socket.gethostname() - if len(host_name) > 15: - host_name = host_name[0:15] - server_name = get_param_val(args.server_name, 'SERVER_NAME', host_name) - ccnet_config.server_name = ccnet_config.validate_server_name(server_name) - - server_ip = get_param_val(args.server_ip, 'SERVER_IP', - socket.gethostbyname(socket.gethostname())) - ccnet_config.ip_or_domain = ccnet_config.validate_server_ip(server_ip) - - fileserver_port = get_param_val(args.fileserver_port, 'FILESERVER_PORT', '8082') - seafile_config.fileserver_port = Utils.validate_port(fileserver_port) - - seafile_dir = get_param_val(args.seafile_dir, 'SEAFILE_DIR', - os.path.join(env_mgr.top_dir, 'seafile-data')) - seafile_config.seafile_dir = seafile_config.validate_seafile_dir(seafile_dir) - - global db_config - - use_existing_db = get_param_val(args.use_existing_db, 'USE_EXISTING_DB', '0') - if use_existing_db == '0': - db_config = NewDBConfigurator() - elif use_existing_db == '1': - db_config = ExistingDBConfigurator() - else: - raise InvalidParams('Invalid use existing db parameter, the value can only be 0 or 1') - - mysql_host = get_param_val(args.mysql_host, 'MYSQL_HOST', '127.0.0.1') - if not mysql_host: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing mysql host parameter') - db_config.mysql_host = db_config.validate_mysql_host(mysql_host) - - mysql_port = get_param_val(args.mysql_port, 'MYSQL_PORT', '3306') - db_config.mysql_port = Utils.validate_port(mysql_port) - - mysql_user = get_param_val(args.mysql_user, 'MYSQL_USER') - if not mysql_user: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing mysql user name parameter') - - mysql_user_passwd = get_param_val(args.mysql_user_passwd, 'MYSQL_USER_PASSWD') - if not mysql_user_passwd: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing mysql user password parameter') - - ccnet_db = get_param_val(args.ccnet_db, 'CCNET_DB', 'ccnet_db') - if not ccnet_db: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing ccnet db name parameter') - - seafile_db = get_param_val(args.seafile_db, 'SEAFILE_DB', 'seafile_db') - if not seafile_db: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing seafile db name parameter') - - seahub_db = get_param_val(args.seahub_db, 'SEAHUB_DB', 'seahub_db') - if not seahub_db: - raise InvalidParams('Incomplete mysql configuration parameters, ' \ - 'missing seahub db name parameter') - - mysql_user_host = get_param_val(args.mysql_user_host, 'MYSQL_USER_HOST') - mysql_root_passwd = get_param_val(args.mysql_root_passwd, 'MYSQL_ROOT_PASSWD') - - if db_config.use_existing_db: - db_config.check_mysql_user(mysql_user, mysql_user_passwd) - db_config.seafile_mysql_user = mysql_user - db_config.seafile_mysql_password = mysql_user_passwd - db_config.ccnet_db_name = db_config.validate_db_name(ccnet_db) - db_config.seafile_db_name = db_config.validate_db_name(seafile_db) - db_config.seahub_db_name = db_config.validate_db_name(seahub_db) - else: - if db_config.mysql_host != '127.0.0.1' and not mysql_user_host: - raise InvalidParams('mysql user host parameter is missing in creating new db mode') - if not mysql_user_host: - db_config.mysql_userhost = 'localhost' - else: - db_config.mysql_userhost = db_config.validate_mysql_user_host(mysql_user_host) - - if not mysql_root_passwd: - raise InvalidParams('mysql root password parameter is missing in creating new db mode') - db_config.root_password = db_config.validate_root_passwd(mysql_root_passwd) - - if mysql_user == 'root': - db_config.seafile_mysql_user = 'root' - db_config.seafile_mysql_password = db_config.root_password - else: - if db_config.mysql_user_exists(mysql_user): - db_config.check_mysql_user(mysql_user, mysql_user_passwd) - db_config.seafile_mysql_user = mysql_user - db_config.seafile_mysql_password = mysql_user_passwd - db_config.ccnet_db_name = ccnet_db - db_config.seafile_db_name = seafile_db - db_config.seahub_db_name = seahub_db - - global need_pause - need_pause = False - - -def main(): - if len(sys.argv) > 2 and sys.argv[1] == 'auto': - sys.argv.remove('auto') - parser = argparse.ArgumentParser() - parser.add_argument('-n', '--server-name', help='server name') - parser.add_argument('-i', '--server-ip', help='server ip or domain') - parser.add_argument('-p', '--fileserver-port', help='fileserver port') - parser.add_argument('-d', '--seafile-dir', help='seafile dir to store seafile data') - parser.add_argument('-e', '--use-existing-db', - help='use mysql existing dbs or create new dbs, ' - '0: create new dbs 1: use existing dbs') - parser.add_argument('-o', '--mysql-host', help='mysql host') - parser.add_argument('-t', '--mysql-port', help='mysql port') - parser.add_argument('-u', '--mysql-user', help='mysql user name') - parser.add_argument('-w', '--mysql-user-passwd', help='mysql user password') - parser.add_argument('-q', '--mysql-user-host', help='mysql user host') - parser.add_argument('-r', '--mysql-root-passwd', help='mysql root password') - parser.add_argument('-c', '--ccnet-db', help='ccnet db name') - parser.add_argument('-s', '--seafile-db', help='seafile db name') - parser.add_argument('-b', '--seahub-db', help='seahub db name') - - args = parser.parse_args() - - try: - check_params(args) - except (InvalidAnswer, InvalidParams) as e: - print Utils.highlight('\n%s\n' % e) - sys.exit(-1) - - global db_config - - if need_pause: - Utils.welcome() - warnings.filterwarnings('ignore', category=MySQLdb.Warning) - - env_mgr.check_pre_condiction() - - # Part 1: collect configuration - ccnet_config.ask_questions() - seafile_config.ask_questions() - seahub_config.ask_questions() - - if not db_config: - if AbstractDBConfigurator.ask_use_existing_db(): - db_config = ExistingDBConfigurator() - else: - db_config = NewDBConfigurator() - - db_config.ask_questions() - - report_config() - - # Part 2: generate configuration - db_config.generate() - ccnet_config.generate() - seafile_config.generate() - seafdav_config.generate() - seahub_config.generate() - - seahub_config.do_syncdb() - seahub_config.prepare_avatar_dir() - # db_config.create_seahub_admin() - user_manuals_handler.copy_user_manuals() - create_seafile_server_symlink() - - set_file_perm() - - report_success() - -def report_success(): - message = '''\ - - ------------------------------------------------------------------ -Your seafile server configuration has been finished successfully. ------------------------------------------------------------------ - -run seafile server: ./seafile.sh { start | stop | restart } -run seahub server: ./seahub.sh { start | stop | restart } - ------------------------------------------------------------------ -If you are behind a firewall, remember to allow input/output of these tcp ports: ------------------------------------------------------------------ - -port of seafile fileserver: %(fileserver_port)s -port of seahub: 8000 - -When problems occur, Refer to - - %(server_manual_http)s - -for information. - -''' - - print message % dict(fileserver_port=seafile_config.fileserver_port, - server_manual_http=SERVER_MANUAL_HTTP) - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - print - print Utils.highlight('The setup process is aborted') - print diff --git a/scripts/setup-seafile-mysql.sh b/scripts/setup-seafile-mysql.sh deleted file mode 100755 index cb8b8c5b..00000000 --- a/scripts/setup-seafile-mysql.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -######## -### This script is a wrapper for setup-seafile-mysql.py -######## - -set -e - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") - -cd "$INSTALLPATH" - -python_script=setup-seafile-mysql.py - -function err_and_quit () { - printf "\n\n\033[33mError occured during setup. \nPlease fix possible problems and run the script again.\033[m\n\n" - exit 1; -} - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function check_python_module () { - module=$1 - name=$2 - hint=$3 - printf " Checking python module: ${name} ... " - if ! $PYTHON -c "import ${module}" 2>/dev/null 1>&2; then - echo - printf "\033[33m ${name} \033[m is not installed, Please install it first.\n" - if [[ "${hint}" != "" ]]; then - printf "${hint}" - echo - fi - err_and_quit; - fi - echo -e "Done." -} - -function check_python () { - echo "Checking python on this machine ..." - check_python_executable - if ! which $PYTHON 2>/dev/null 1>&2; then - echo "No $PYTHON found on this machine. Please install it first." - err_and_quit; - else - if ($Python --version 2>&1 | grep "3\\.[0-9].\\.[0-9]") 2>/dev/null 1>&2 ; then - printf "\033[33m Python version 3.x \033[m detected\n" - echo "Python 3.x is not supported. Please use python 2.x. Now quit." - err_and_quit; - fi - - if [[ $PYTHON == "python2.6" ]]; then - py26="2.6" - fi - hint="\nOn Debian/Ubntu: apt-get install python-setuptools\nOn CentOS/RHEL: yum install python${py26}-distribute" - check_python_module pkg_resources setuptools "${hint}" - - hint="\nOn Debian/Ubntu: apt-get install python-imaging\nOn CentOS/RHEL: yum install python${py26}-imaging" - check_python_module PIL python-imaging "${hint}" - - hint='\nOn Debian/Ubuntu:\n\nsudo apt-get install python-mysqldb\n\nOn CentOS/RHEL:\n\nsudo yum install MySQL-python' - check_python_module MySQLdb python-mysqldb "${hint}" - fi - echo -} - -check_python; - -export PYTHON=$PYTHON - -exec $PYTHON "$python_script" "$@" diff --git a/scripts/setup-seafile.sh b/scripts/setup-seafile.sh deleted file mode 100755 index 80654d56..00000000 --- a/scripts/setup-seafile.sh +++ /dev/null @@ -1,704 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") -INSTALLPATH=$(dirname "${SCRIPT}") -TOPDIR=$(dirname "${INSTALLPATH}") -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf - -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -use_existing_ccnet="false" -use_existing_seafile="false" - -server_manual_http="https://github.com/haiwen/seafile/wiki" - -function welcome () { - echo "-----------------------------------------------------------------" - echo "This script will guide you to config and setup your seafile server." - echo -e "\nMake sure you have read seafile server manual at \n\n\t${server_manual_http}\n" - echo -e "Note: This script will guide your to setup seafile server using sqlite3," - echo "which may have problems if your disk is on a NFS/CIFS/USB." - echo "In these cases, we sugguest you setup seafile server using MySQL." - echo - echo "Press [ENTER] to continue" - echo "-----------------------------------------------------------------" - read dummy - echo -} - -function err_and_quit () { - printf "\n\n\033[33mError occured during setup. \nPlease fix possible issues and run the script again.\033[m\n\n" - exit 1; -} - -function on_ctrl_c_pressed () { - printf "\n\n\033[33mYou have pressed Ctrl-C. Setup is interrupted.\033[m\n\n" - exit 1; -} - -# clean newly created ccnet/seafile configs when exit on SIGINT -trap on_ctrl_c_pressed 2 - -function check_sanity () { - if ! [[ -d ${INSTALLPATH}/seahub && -d ${INSTALLPATH}/seafile \ - && -d ${INSTALLPATH}/runtime ]]; then - echo - echo "The seafile-server diretory doesn't contain all needed files." - echo "Please make sure you have extracted all files and folders from tarball." - err_and_quit; - fi -} - -function read_yes_no () { - printf "[yes|no] " - read yesno; - while [[ "${yesno}" != "yes" && "${yesno}" != "no" ]] - do - printf "please answer [yes|no] " - read yesno; - done - - if [[ "${yesno}" == "no" ]]; then - return 1; - else - return 0; - fi -} - -function check_existing_ccnet () { - if [[ -d ${default_ccnet_conf_dir} ]]; then - echo "It seems that you have created a ccnet configuration before. " - echo "Would you like to use the existing configuration?" - - if ! read_yes_no; then - echo - echo "Please remove the existing configuration before continuing." - echo "You can do it by running \"rm -rf ${default_ccnet_conf_dir}\"" - echo - exit 1; - else - echo - echo "Existing ccnet configuration is being used." - use_existing_ccnet=true - fi - fi - echo -} - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi - - echo "Find python: $PYTHON" - echo -} - -function check_python_module () { - module=$1 - name=$2 - hint=$3 - printf " Checking python module: ${name} ... " - if ! $PYTHON -c "import ${module}" 2>/dev/null 1>&2; then - echo - printf "\033[33m ${name} \033[m is not installed, Please install it first.\n" - if [[ "${hint}" != "" ]]; then - printf "${hint}" - echo - fi - err_and_quit; - fi - echo -e "Done." -} - -function check_python () { - echo "Checking python on this machine ..." - check_python_executable - if ! which $PYTHON 2>/dev/null 1>&2; then - echo "No $PYTHON found on this machine. Please install it first." - err_and_quit; - else - if ($Python --version 2>&1 | grep "3\\.[0-9].\\.[0-9]") 2>/dev/null 1>&2 ; then - printf "\033[33m Python version 3.x \033[m detected\n" - echo "Python 3.x is not supported. Please use python 2.x." - err_and_quit; - fi - - if [[ $PYTHON == "python2.6" ]]; then - py26="2.6" - fi - hint="\nOn Debian/Ubntu: apt-get install python-setuptools\nOn CentOS/RHEL: yum install python${py26}-distribute" - check_python_module pkg_resources setuptools "${hint}" - hint="\nOn Debian/Ubntu: apt-get install python-imaging\nOn CentOS/RHEL: yum install python${py26}-imaging" - check_python_module PIL python-imaging "${hint}" - check_python_module sqlite3 python-sqlite3 - fi - echo -} - -function check_sqlite3 () { - echo -n "Checking for sqlite3 ..." - if ! which sqlite3 2>/dev/null 1>&2; then - echo -e "\nSqlite3 is not found. install it first.\n" - echo "On Debian/Ubuntu: apt-get install sqlite3" - echo "On CentOS/RHEL: yum install sqlite" - err_and_quit; - fi - printf "Done.\n\n" -} - -function check_system_dependency () { - printf "Checking packages needed by seafile ...\n\n" - check_python; - check_sqlite3; - printf "Checking Done.\n\n" -} - -function ask_question () { - question=$1 - default=$2 - key=$3 - printf "${question}" - printf "\n" - if [[ "${default}" != "" && "${default}" != "nodefault" ]] ; then - printf "[default: ${default} ] " - elif [[ "${key}" != "" ]]; then - printf "[${key}]: " - fi -} - -function get_server_name () { - question="What would you like to use as the name of this seafile server?\nYour seafile users will be able to see the name in their seafile client." - hint="You can use a-z, A-Z, 0-9, _ and -, and the length should be 3 ~ 15" - ask_question "${question}\n${hint}" "nodefault" "server name" - read server_name - if [[ "${server_name}" == "" ]]; then - echo - echo "server name cannot be empty" - get_server_name - elif [[ ! ${server_name} =~ ^[a-zA-Z0-9_-]{3,14}$ ]]; then - printf "\n\033[33m${server_name}\033[m is not a valid name.\n" - get_server_name; - fi - echo -} - -function get_server_ip_or_domain () { - question="What is the ip or domain of this server?\nFor example, www.mycompany.com, or, 192.168.1.101" - ask_question "${question}\n" "nodefault" "This server's ip or domain" - read ip_or_domain - if [[ "${ip_or_domain}" == "" ]]; then - echo - echo "ip or domain cannot be empty" - get_server_ip_or_domain - fi - echo -} - -function get_ccnet_server_port () { - question="What tcp port do you want to use for ccnet server?" - hint="10001 is the recommended port." - default="10001" - ask_question "${question}\n${hint}" "${default}" - read server_port - if [[ "${server_port}" == "" ]]; then - server_port="${default}" - fi - if [[ ! ${server_port} =~ ^[0-9]+$ ]]; then - echo "\"${server_port}\" is not a valid port number. " - get_ccnet_server_port - fi - echo -} - -function get_seafile_server_port () { - question="What tcp port would you like to use for seafile server?" - hint="12001 is the recommended port." - default="12001" - ask_question "${question}\n${hint}" "${default}" - read seafile_server_port - if [[ "${seafile_server_port}" == "" ]]; then - seafile_server_port="${default}" - fi - if [[ ! ${seafile_server_port} =~ ^[0-9]+$ ]]; then - echo "\"${seafile_server_port}\" is not a valid port number. " - get_seafile_server_port - fi - echo -} - -function get_fileserver_port () { - question="What tcp port do you want to use for seafile fileserver?" - hint="8082 is the recommended port." - default="8082" - ask_question "${question}\n${hint}" "${default}" - read fileserver_port - if [[ "${fileserver_port}" == "" ]]; then - fileserver_port="${default}" - fi - if [[ ! ${fileserver_port} =~ ^[0-9]+$ ]]; then - echo "\"${fileserver_port}\" is not a valid port number. " - get_fileserver_port - fi - echo -} - - -function get_seafile_data_dir () { - question="Where would you like to store your seafile data?" - note="Please use a volume with enough free space." - default=${default_seafile_data_dir} - ask_question "${question} \n\033[33mNote: \033[m${note}" "${default}" - read seafile_data_dir - if [[ "${seafile_data_dir}" == "" ]]; then - seafile_data_dir=${default} - fi - - if [[ -d ${seafile_data_dir} && -f ${seafile_data_dir}/seafile.conf ]]; then - echo - echo "It seems that you have already existing seafile data in ${seafile_data_dir}." - echo "Would you like to use the existing seafile data?" - if ! read_yes_no; then - echo "You have chosen not to use existing seafile data in ${seafile_data_dir}" - echo "You need to specify a different seafile data directory or remove ${seafile_data_dir} before continuing." - get_seafile_data_dir - else - use_existing_seafile="true" - fi - elif [[ -d ${seafile_data_dir} && $(ls -A ${seafile_data_dir}) != "" ]]; then - echo - echo "${seafile_data_dir} is an existing non-empty directory. Please specify a different directory" - echo - get_seafile_data_dir - elif [[ ! ${seafile_data_dir} =~ ^/ ]]; then - echo - echo "\"${seafile_data_dir}\" is not an absolute path. Please specify an absolute path." - echo - get_seafile_data_dir - elif [[ ! -d $(dirname ${seafile_data_dir}) ]]; then - echo - echo "The path $(dirname ${seafile_data_dir}) does not exist." - echo - get_seafile_data_dir - fi - echo -} - -function gen_seafdav_conf () { - mkdir -p ${default_conf_dir} - seafdav_conf=${default_conf_dir}/seafdav.conf - if ! $(cat > ${seafdav_conf} < "${default_ccnet_conf_dir}/seafile.ini" - -# ------------------------------------------- -# Generate seafevents.conf -# ------------------------------------------- - -gen_seafdav_conf; - -# ------------------------------------------- -# generate seahub/settings.py -# ------------------------------------------- -dest_settings_py=${TOPDIR}/conf/seahub_settings.py -seahub_secret_keygen=${INSTALLPATH}/seahub/tools/secret_key_generator.py - -if [[ ! -f ${dest_settings_py} ]]; then - echo -n "SECRET_KEY = " >> "${dest_settings_py}" - key=$($PYTHON "${seahub_secret_keygen}") - echo "\"${key}\"" >> "${dest_settings_py}" -fi - -# ------------------------------------------- -# Seahub related config -# ------------------------------------------- -if [[ "${need_pause}" == "1" ]]; then - echo "-----------------------------------------------------------------" - echo "Seahub is the web interface for seafile server." - echo "Now let's setup seahub configuration. Press [ENTER] to continue" - echo "-----------------------------------------------------------------" - echo - read dummy -fi - -# echo "Please specify the email address and password for the seahub administrator." -# echo "You can use them to login as admin on your seahub website." -# echo - -function get_seahub_admin_email () { - question="Please specify the email address for the seahub administrator:" - ask_question "${question}" "nodefault" "seahub admin email" - read seahub_admin_email - if [[ "${seahub_admin_email}" == "" ]]; then - echo "Seahub admin user name cannot be empty." - get_seahub_admin_email; - elif [[ ! ${seahub_admin_email} =~ ^.+@.*\..+$ ]]; then - echo "${seahub_admin_email} is not a valid email address" - get_seahub_admin_email; - fi -} - -function get_seahub_admin_passwd () { - echo - question="Please specify the password you would like to use for seahub administrator:" - ask_question "${question}" "nodefault" "seahub admin password" - read -s seahub_admin_passwd - echo - question="Please enter the password again:" - ask_question "${question}" "nodefault" "seahub admin password again" - read -s seahub_admin_passwd_again - echo - if [[ "${seahub_admin_passwd}" != "${seahub_admin_passwd_again}" ]]; then - printf "\033[33mThe passwords didn't match.\033[m" - get_seahub_admin_passwd; - elif [[ "${seahub_admin_passwd}" == "" ]]; then - echo "Password cannot be empty." - get_seahub_admin_passwd; - fi -} - -# get_seahub_admin_email; -# sleep .5; -# get_seahub_admin_passwd; -# seahub_admin_passwd_enc=$(echo -n ${seahub_admin_passwd} | sha1sum | grep -o "[0-9a-f]*") -# sleep .5; - -# printf "\n\n" -# echo "This is your seahub admin username/password" -# echo -# printf "admin username: \033[33m${seahub_admin_email}\033[m\n" -# printf "admin password: \033[33m**************\033[m\n\n" - -# echo -# echo "If you are OK with the configuration, press [ENTER] to continue." -# read dummy - -# usermgr_db_dir=${default_ccnet_conf_dir}/PeerMgr/ -# usermgr_db=${usermgr_db_dir}/usermgr.db - -# if [[ "${use_existing_ccnet}" != "true" ]]; then -# # create admin user/passwd entry in ccnet db -# if ! mkdir -p "${usermgr_db_dir}"; then -# echo "Failed to create seahub admin." -# err_and_quit; -# fi - -# sql="CREATE TABLE IF NOT EXISTS EmailUser (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, email TEXT, passwd TEXT, is_staff bool NOT NULL, is_active bool NOT NULL, ctime INTEGER)"; - -# if ! sqlite3 "${usermgr_db}" "${sql}" ; then -# rm -f "${usermgr_db}" -# echo "Failed to create seahub admin." -# err_and_quit; -# fi - -# sql="INSERT INTO EmailUser(email, passwd, is_staff, is_active, ctime) VALUES (\"${seahub_admin_email}\", \"${seahub_admin_passwd_enc}\", 1, 1, 0);" - -# if ! sqlite3 "${usermgr_db}" "${sql}" ; then -# rm -f "${usermgr_db}" -# echo "Failed to create seahub admin." -# err_and_quit; -# fi -# fi - -echo "Creating seahub database now, it may take one minute, please wait... " -echo - -seahub_db=${TOPDIR}/seahub.db -seahub_sqls=${INSTALLPATH}/seahub/sql/sqlite3.sql - -if ! sqlite3 ${seahub_db} ".read ${seahub_sqls}" 2>/dev/null 1>&2; then - echo "Failed to sync seahub database." - err_and_quit; -fi -echo -echo "Done." - -# prepare avatar folder - -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -# Make a seafile-server symlink, like this: -# /data/haiwen/ -# -- seafile-server-2.0.4 -# -- seafile-server-latest # symlink to 2.0.4 -seafile_server_symlink=${TOPDIR}/seafile-server-latest -echo -echo -n "creating seafile-server-latest symbolic link ... " -if ! ln -s $(basename ${INSTALLPATH}) ${seafile_server_symlink}; then - echo - echo - echo "Failed to create symbolic link ${seafile_server_symlink}" - err_and_quit; -fi -echo "done" -echo - -chmod 0600 "$dest_settings_py" -chmod 0700 "$default_ccnet_conf_dir" -chmod 0700 "$seafile_data_dir" -chmod 0700 "$default_conf_dir" - -# ------------------------------------------- -# copy user manuals to library template -# ------------------------------------------- -copy_user_manuals; - -# ------------------------------------------- -# final message -# ------------------------------------------- - -sleep 1 - -echo -echo "-----------------------------------------------------------------" -echo "Your seafile server configuration has been completed successfully." -echo "-----------------------------------------------------------------" -echo -echo "run seafile server: ./seafile.sh { start | stop | restart }" -echo "run seahub server: ./seahub.sh { start | stop | restart }" -echo -echo "-----------------------------------------------------------------" -echo "If the server is behind a firewall, remember to open these tcp ports:" -echo "-----------------------------------------------------------------" -echo -echo "port of seafile fileserver: ${fileserver_port}" -echo "port of seahub: 8000" -echo -echo -e "When problems occur, refer to\n" -echo -e " ${server_manual_http}\n" -echo "for more information." -echo diff --git a/scripts/sqlite2mysql.py b/scripts/sqlite2mysql.py deleted file mode 100644 index 384cfa21..00000000 --- a/scripts/sqlite2mysql.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -"""Lifted from: -http://stackoverflow.com/questions/18671/quick-easy-way-to-migrate-sqlite3-to-mysql - -Run like so: - -sqlite3 .db .dump | python sqlite2mysql.py > .sql - -Then you can import the .sql file into MySql - -Note - you need to add foreign key constrains manually since sqlite doesn't actually support them -""" - -import re -import fileinput - -def this_line_is_useless(line): - useless_es = [ - 'BEGIN TRANSACTION', - 'COMMIT', - 'sqlite_sequence', - 'CREATE UNIQUE INDEX', - 'PRAGMA', - ] - for useless in useless_es: - if re.search(useless, line): - return True - -def has_primary_key(line): - return bool(re.search(r'PRIMARY KEY', line)) - -for line in fileinput.input(): - searching_for_end = False - if this_line_is_useless(line): continue - - # this line was necessary because ''); was getting - # converted (inappropriately) to \'); - if re.match(r".*, ''\);", line): - line = re.sub(r"''\);", r'``);', line) - - if re.match(r'^CREATE TABLE.*', line): - searching_for_end = True - - m = re.search('CREATE TABLE [`"]?(\w*)[`"]?(.*)', line) - if m: - name, sub = m.groups() - sub = sub.replace('"','`') - line = "DROP TABLE IF EXISTS `%(name)s`;\nCREATE TABLE IF NOT EXISTS `%(name)s`%(sub)s\n" - line = line % dict(name=name, sub=sub) - else: - m = re.search('INSERT INTO "(\w*)"(.*)', line) - if m: - name, sub = m.groups() - line = 'INSERT INTO `%s`%s\n' % m.groups() - line = line.replace('"', r'\"') - line = line.replace('"', "'") - # line = re.sub(r"([^'])'t'(.)", r"\1THIS_IS_TRUE\2", line) - # line = line.replace('THIS_IS_TRUE', '1') - # line = re.sub(r"([^'])'f'(.)", r"\1THIS_IS_FALSE\2", line) - # line = line.replace('THIS_IS_FALSE', '0') - - # Add auto_increment if it's not there since sqlite auto_increments ALL - # primary keys - if searching_for_end: - if re.search(r"integer(?:\s+\w+)*\s*PRIMARY KEY(?:\s+\w+)*\s*,", line, re.I): - line = line.replace("PRIMARY KEY", "PRIMARY KEY AUTO_INCREMENT") - # replace " and ' with ` because mysql doesn't like quotes in CREATE commands - line = line.replace('"', '`').replace("'", '`') - - # And now we convert it back (see above) - if re.match(r".*, ``\);", line): - line = re.sub(r'``\);', r"'');", line) - - if searching_for_end and re.match(r'.*\);', line): - searching_for_end = False - - if re.match(r"CREATE INDEX", line): - line = re.sub('"', '`', line) - - line = line.replace('"', '`') - line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT') - print line, diff --git a/scripts/sqlite2mysql.sh b/scripts/sqlite2mysql.sh deleted file mode 100755 index 960b4204..00000000 --- a/scripts/sqlite2mysql.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh -# -# This shell script and corresponding sqlite2mysql.py are used to -# migrate Seafile data from SQLite to MySQL. -# -# Setup: -# -# 1. Move this file and sqlite2mysql.py to the top directory of your Seafile -# installation path (e.g. /data/haiwen). -# 2. Run: ./sqlite2mysql.sh -# 3. Three files(ccnet-db.sql, seafile-db.sql, seahub-db.sql) are created. -# 4. Loads these files to MySQL -# (mysql> source ccnet-db.sql) -# - -CCNET_DB='ccnet-db.sql' -SEAFILE_DB='seafile-db.sql' -SEAHUB_DB='seahub-db.sql' - -########## ccnet -seafile_path=$(pwd) -if [ -f "${seafile_path}/ccnet/ccnet.conf" ]; then - USER_MGR_DB=${seafile_path}/ccnet/PeerMgr/usermgr.db - GRP_MGR_DB=${seafile_path}/ccnet/GroupMgr/groupmgr.db -else - echo "${seafile_path}/ccnet/ccnet.conf does not exists." - read -p "Please provide your ccnet.conf path(e.g. /data/haiwen/ccnet/ccnet.conf): " ccnet_conf_path - if [ -f ${ccnet_conf_path} ]; then - USER_MGR_DB=$(dirname "${ccnet_conf_path}")/PeerMgr/usermgr.db - GRP_MGR_DB=$(dirname "${ccnet_conf_path}")/GroupMgr/groupmgr.db - else - echo "${ccnet_conf_path} does not exists, quit." - exit 1 - fi -fi - -rm -rf ${CCNET_DB} - -echo "sqlite3 ${USER_MGR_DB} .dump | python sqlite2mysql.py > ${CCNET_DB}" -sqlite3 ${USER_MGR_DB} .dump | python sqlite2mysql.py > ${CCNET_DB} -echo "sqlite3 ${GRP_MGR_DB} .dump | python sqlite2mysql.py >> ${CCNET_DB}" -sqlite3 ${GRP_MGR_DB} .dump | python sqlite2mysql.py >> ${CCNET_DB} - -# change ctime from INTEGER to BIGINT in EmailUser table -sed 's/ctime INTEGER/ctime BIGINT/g' ${CCNET_DB} > ${CCNET_DB}.tmp && mv ${CCNET_DB}.tmp ${CCNET_DB} - -# change email in UserRole from TEXT to VARCHAR(255) -sed 's/email TEXT, role TEXT/email VARCHAR(255), role TEXT/g' ${CCNET_DB} > ${CCNET_DB}.tmp && mv ${CCNET_DB}.tmp ${CCNET_DB} - -########## seafile -rm -rf ${SEAFILE_DB} - -if [ -f "${seafile_path}/seafile-data/seafile.db" ]; then - echo "sqlite3 ${seafile_path}/seafile-data/seafile.db .dump | python sqlite2mysql.py > ${SEAFILE_DB}" - sqlite3 ${seafile_path}/seafile-data/seafile.db .dump | python sqlite2mysql.py > ${SEAFILE_DB} -else - echo "${seafile_path}/seafile-data/seafile.db does not exists." - read -p "Please provide your seafile.db path(e.g. /data/haiwen/seafile-data/seafile.db): " seafile_db_path - if [ -f ${seafile_db_path} ];then - echo "sqlite3 ${seafile_db_path} .dump | python sqlite2mysql.py > ${SEAFILE_DB}" - sqlite3 ${seafile_db_path} .dump | python sqlite2mysql.py > ${SEAFILE_DB} - else - echo "${seafile_db_path} does not exists, quit." - exit 1 - fi -fi - -# change owner_id in RepoOwner from TEXT to VARCHAR(255) -sed 's/owner_id TEXT/owner_id VARCHAR(255)/g' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} - -# change user_name in RepoGroup from TEXT to VARCHAR(255) -sed 's/user_name TEXT/user_name VARCHAR(255)/g' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} - -########## seahub -rm -rf ${SEAHUB_DB} - -if [ -f "${seafile_path}/seahub.db" ]; then - echo "sqlite3 ${seafile_path}/seahub.db .dump | tr -d '\n' | sed 's/;/;\n/g' | python sqlite2mysql.py > ${SEAHUB_DB}" - sqlite3 ${seafile_path}/seahub.db .dump | tr -d '\n' | sed 's/;/;\n/g' | python sqlite2mysql.py > ${SEAHUB_DB} -else - echo "${seafile_path}/seahub.db does not exists." - read -p "Please prove your seahub.db path(e.g. /data/haiwen/seahub.db): " seahub_db_path - if [ -f ${seahub_db_path} ]; then - echo "sqlite3 ${seahub_db_path} .dump | tr -d '\n' | sed 's/;/;\n/g' | python sqlite2mysql.py > ${SEAHUB_DB}" - sqlite3 ${seahub_db_path} .dump | tr -d '\n' | sed 's/;/;\n/g' | python sqlite2mysql.py > ${SEAHUB_DB} - else - echo "${seahub_db_path} does not exists, quit." - exit 1 - fi -fi - -# change username from VARCHAR(256) to VARCHAR(255) in wiki_personalwiki -sed 's/varchar(256) NOT NULL UNIQUE/varchar(255) NOT NULL UNIQUE/g' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} - -# remove unique from contacts_contact -sed 's/, UNIQUE (`user_email`, `contact_email`)//g' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} - -# remove base_dirfileslastmodifiedinfo records to avoid json string parsing issue between sqlite and mysql -sed '/INSERT INTO `base_dirfileslastmodifiedinfo`/d' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} - -# remove notifications_usernotification records to avoid json string parsing issue between sqlite and mysql -sed '/INSERT INTO `notifications_usernotification`/d' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} - - -########## common logic - -# add ENGIN=INNODB to create table statment -for sql_file in $CCNET_DB $SEAFILE_DB $SEAHUB_DB -do - sed -r 's/(CREATE TABLE.*);/\1 ENGINE=INNODB;/g' $sql_file > $sql_file.tmp && mv $sql_file.tmp $sql_file -done - -# remove COLLATE NOCASE if possible -for sql_file in $CCNET_DB $SEAFILE_DB $SEAHUB_DB -do - sed 's/COLLATE NOCASE//g' $sql_file > $sql_file.tmp && mv $sql_file.tmp $sql_file -done - diff --git a/scripts/upgrade/add_collate.sh b/scripts/upgrade/add_collate.sh deleted file mode 100755 index e85a74d7..00000000 --- a/scripts/upgrade/add_collate.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh -# -# This shell script is used to add COLLATE NOCASE to email field to avoid case -# issue in sqlite. -# -# 1. ./add-collate.sh -# - -USER_DB='/tmp/user-db.sql' -GROUP_DB='/tmp/group-db.sql' -SEAFILE_DB='/tmp/seafile-db.sql' -SEAHUB_DB='/tmp/seahub-db.sql' - -ccnet_dir=$1 - -########## ccnet -USER_MGR_DB=${ccnet_dir}/PeerMgr/usermgr.db -GRP_MGR_DB=${ccnet_dir}/GroupMgr/groupmgr.db - -rm -rf ${USER_DB} -rm -rf ${GROUP_DB} - -echo "sqlite3 ${USER_MGR_DB} .dump > ${USER_DB}" -sqlite3 ${USER_MGR_DB} .dump > ${USER_DB} -echo "sqlite3 ${GRP_MGR_DB} .dump > ${GROUP_DB}" -sqlite3 ${GRP_MGR_DB} .dump > ${GROUP_DB} - -sed -r 's/(CREATE TABLE EmailUser.*)email TEXT,(.*)/\1email TEXT COLLATE NOCASE,\2/I' ${USER_DB} > ${USER_DB}.tmp && mv ${USER_DB}.tmp ${USER_DB} -sed -r 's/(CREATE TABLE Binding.*)email TEXT,(.*)/\1email TEXT COLLATE NOCASE,\2/I' ${USER_DB} > ${USER_DB}.tmp && mv ${USER_DB}.tmp ${USER_DB} -sed -r 's/(CREATE TABLE `Group`.*)`creator_name` VARCHAR\(255\),(.*)/\1`creator_name` VARCHAR\(255\) COLLATE NOCASE,\2/I' ${GROUP_DB} > ${GROUP_DB}.tmp && mv ${GROUP_DB}.tmp ${GROUP_DB} -sed -r 's/(CREATE TABLE `GroupUser`.*)`user_name` VARCHAR\(255\),(.*)/\1`user_name` VARCHAR\(255\) COLLATE NOCASE,\2/I' ${GROUP_DB} > ${GROUP_DB}.tmp && mv ${GROUP_DB}.tmp ${GROUP_DB} - -# backup & restore -mv ${USER_MGR_DB} ${USER_MGR_DB}.`date +"%Y%m%d%H%M%S"` -mv ${GRP_MGR_DB} ${GRP_MGR_DB}.`date +"%Y%m%d%H%M%S"` -sqlite3 ${USER_MGR_DB} < ${USER_DB} -sqlite3 ${GRP_MGR_DB} < ${GROUP_DB} - -########## seafile -rm -rf ${SEAFILE_DB} - -SEAFILE_DB_FILE=$2/seafile.db -echo "sqlite3 ${SEAFILE_DB_FILE} .dump > ${SEAFILE_DB}" -sqlite3 ${SEAFILE_DB_FILE} .dump > ${SEAFILE_DB} - -sed -r 's/(CREATE TABLE RepoOwner.*)owner_id TEXT(.*)/\1owner_id TEXT COLLATE NOCASE\2/I' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} -sed -r 's/(CREATE TABLE RepoGroup.*)user_name TEXT,(.*)/\1user_name TEXT COLLATE NOCASE,\2/I' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} -sed -r 's/(CREATE TABLE RepoUserToken.*)email VARCHAR\(255\),(.*)/\1email VARCHAR\(255\) COLLATE NOCASE,\2/I' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} -sed -r 's/(CREATE TABLE UserQuota.*)user VARCHAR\(255\),(.*)/\1user VARCHAR\(255\) COLLATE NOCASE,\2/I' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} -sed -r 's/(CREATE TABLE SharedRepo.*)from_email VARCHAR\(512\), to_email VARCHAR\(512\),(.*)/\1from_email VARCHAR\(512\), to_email VARCHAR\(512\) COLLATE NOCASE,\2/I' ${SEAFILE_DB} > ${SEAFILE_DB}.tmp && mv ${SEAFILE_DB}.tmp ${SEAFILE_DB} - -# backup & restore -mv ${SEAFILE_DB_FILE} ${SEAFILE_DB_FILE}.`date +"%Y%m%d%H%M%S"` -sqlite3 ${SEAFILE_DB_FILE} < ${SEAFILE_DB} - -########## seahub -rm -rf ${SEAHUB_DB} - -SEAHUB_DB_FILE=$3 -echo "sqlite3 ${SEAHUB_DB_FILE} .Dump | tr -d '\n' | sed 's/;/;\n/g' > ${SEAHUB_DB}" -sqlite3 ${SEAHUB_DB_FILE} .dump | tr -d '\n' | sed 's/;/;\n/g' > ${SEAHUB_DB} - -sed -r 's/(CREATE TABLE "notifications_usernotification".*)"to_user" varchar\(255\) NOT NULL,(.*)/\1"to_user" varchar\(255\) NOT NULL COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "profile_profile".*)"user" varchar\(75\) NOT NULL UNIQUE,(.*)/\1"user" varchar\(75\) NOT NULL UNIQUE COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "share_fileshare".*)"username" varchar\(255\) NOT NULL,(.*)/\1"username" varchar\(255\) NOT NULL COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "api2_token".*)"user" varchar\(255\) NOT NULL UNIQUE,(.*)/\1"user" varchar\(255\) NOT NULL UNIQUE COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "wiki_personalwiki".*)"username" varchar\(256\) NOT NULL UNIQUE,(.*)/\1"username" varchar\(256\) NOT NULL UNIQUE COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "message_usermessage".*)"from_email" varchar\(75\) NOT NULL,\s*"to_email" varchar\(75\) NOT NULL,(.*)/\1"from_email" varchar\(75\) NOT NULL COLLATE NOCASE, "to_email" varchar\(75\) NOT NULL COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} -sed -r 's/(CREATE TABLE "avatar_avatar".*)"emailuser" varchar\(255\) NOT NULL,(.*)/\1"emailuser" varchar\(255\) NOT NULL COLLATE NOCASE,\2/I' ${SEAHUB_DB} > ${SEAHUB_DB}.tmp && mv ${SEAHUB_DB}.tmp ${SEAHUB_DB} - -# backup & restore -mv ${SEAHUB_DB_FILE} ${SEAHUB_DB_FILE}.`date +"%Y%m%d%H%M%S"` -sqlite3 ${SEAHUB_DB_FILE} < ${SEAHUB_DB} - -rm -rf ${USER_DB} ${GROUP_DB} ${SEAFILE_DB} ${SEAHUB_DB} diff --git a/scripts/upgrade/db_update_1.3_1.4.py b/scripts/upgrade/db_update_1.3_1.4.py deleted file mode 100644 index dcd1d6ba..00000000 --- a/scripts/upgrade/db_update_1.3_1.4.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -import sqlite3 -import os -import sys - -def usage(): - msg = 'usage: %s ' % os.path.basename(sys.argv[0]) - print msg - -def main(): - seahub_db = sys.argv[1] - - conn = sqlite3.connect(seahub_db) - c = conn.cursor() - - try: - c.execute('SELECT s_type from share_fileshare') - except sqlite3.OperationalError: - # only add this column if not exist yet, so this script is idempotent - c.execute('ALTER table share_fileshare add column "s_type" varchar(2) NOT NULL DEFAULT "f"') - - c.execute('CREATE INDEX IF NOT EXISTS "share_fileshare_f775835c" ON "share_fileshare" ("s_type")') - - sql = '''CREATE TABLE IF NOT EXISTS "base_dirfileslastmodifiedinfo" ( - "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, - "repo_id" varchar(36) NOT NULL, - "parent_dir" text NOT NULL, - "parent_dir_hash" varchar(12) NOT NULL, - "dir_id" varchar(40) NOT NULL, - "last_modified_info" text NOT NULL, - UNIQUE ("repo_id", "parent_dir_hash"))''' - - c.execute(sql) - - sql = '''CREATE TABLE IF NOT EXISTS "api2_token" ( - "key" varchar(40) NOT NULL PRIMARY KEY, - "user" varchar(255) NOT NULL UNIQUE, - "created" datetime NOT NULL)''' - - c.execute(sql) - - conn.commit() - -if __name__ == '__main__': - if len(sys.argv) != 2: - usage() - sys.exit(1) - - main() - - diff --git a/scripts/upgrade/db_update_helper.py b/scripts/upgrade/db_update_helper.py deleted file mode 100644 index 8c363e6e..00000000 --- a/scripts/upgrade/db_update_helper.py +++ /dev/null @@ -1,362 +0,0 @@ -#coding: UTF-8 - -import sys -import os -import ConfigParser -import glob - -HAS_MYSQLDB = True -try: - import MySQLdb -except ImportError: - HAS_MYSQLDB = False - -HAS_SQLITE3 = True -try: - import sqlite3 -except ImportError: - HAS_SQLITE3 = False - -class EnvManager(object): - def __init__(self): - self.upgrade_dir = os.path.dirname(__file__) - self.install_path = os.path.dirname(self.upgrade_dir) - self.top_dir = os.path.dirname(self.install_path) - self.ccnet_dir = os.environ['CCNET_CONF_DIR'] - self.seafile_dir = os.environ['SEAFILE_CONF_DIR'] - self.central_config_dir = os.environ.get('SEAFILE_CENTRAL_CONF_DIR') - -env_mgr = EnvManager() - -class Utils(object): - @staticmethod - def highlight(content, is_error=False): - '''Add ANSI color to content to get it highlighted on terminal''' - if is_error: - return '\x1b[1;31m%s\x1b[m' % content - else: - return '\x1b[1;32m%s\x1b[m' % content - - @staticmethod - def info(msg): - print Utils.highlight('[INFO] ') + msg - - @staticmethod - def error(msg): - print Utils.highlight('[ERROR] ') + msg - sys.exit(1) - - @staticmethod - def read_config(config_path, defaults): - if not os.path.exists(config_path): - Utils.error('Config path %s doesn\'t exist, stop db upgrade' % - config_path) - cp = ConfigParser.ConfigParser(defaults) - cp.read(config_path) - return cp - - -class MySQLDBInfo(object): - def __init__(self, host, port, username, password, db, unix_socket=None): - self.host = host - self.port = port - self.username = username - self.password = password - self.db = db - self.unix_socket = unix_socket - - -class DBUpdater(object): - def __init__(self, version, name): - self.sql_dir = os.path.join(env_mgr.upgrade_dir, 'sql', version, name) - - @staticmethod - def get_instance(version): - '''Detect whether we are using mysql or sqlite3''' - ccnet_db_info = DBUpdater.get_ccnet_mysql_info(version) - seafile_db_info = DBUpdater.get_seafile_mysql_info(version) - seahub_db_info = DBUpdater.get_seahub_mysql_info() - - if ccnet_db_info and seafile_db_info and seahub_db_info: - Utils.info('You are using MySQL') - if not HAS_MYSQLDB: - Utils.error('Python MySQLdb module is not found') - updater = MySQLDBUpdater(version, ccnet_db_info, seafile_db_info, seahub_db_info) - - elif (ccnet_db_info is None) and (seafile_db_info is None) and (seahub_db_info is None): - Utils.info('You are using SQLite3') - if not HAS_SQLITE3: - Utils.error('Python sqlite3 module is not found') - updater = SQLiteDBUpdater(version) - - else: - def to_db_string(info): - if info is None: - return 'SQLite3' - else: - return 'MySQL' - Utils.error('Error:\n ccnet is using %s\n seafile is using %s\n seahub is using %s\n' - % (to_db_string(ccnet_db_info), - to_db_string(seafile_db_info), - to_db_string(seahub_db_info))) - - return updater - - def update_db(self): - ccnet_sql = os.path.join(self.sql_dir, 'ccnet.sql') - seafile_sql = os.path.join(self.sql_dir, 'seafile.sql') - seahub_sql = os.path.join(self.sql_dir, 'seahub.sql') - - if os.path.exists(ccnet_sql): - Utils.info('updating ccnet database...') - self.update_ccnet_sql(ccnet_sql) - - if os.path.exists(seafile_sql): - Utils.info('updating seafile database...') - self.update_seafile_sql(seafile_sql) - - if os.path.exists(seahub_sql): - Utils.info('updating seahub database...') - self.update_seahub_sql(seahub_sql) - - @staticmethod - def get_ccnet_mysql_info(version): - if version > '5.0.0': - config_path = env_mgr.central_config_dir - else: - config_path = env_mgr.ccnet_dir - - ccnet_conf = os.path.join(config_path, 'ccnet.conf') - defaults = { - 'HOST': '127.0.0.1', - 'PORT': '3306', - 'UNIX_SOCKET': '', - } - - config = Utils.read_config(ccnet_conf, defaults) - db_section = 'Database' - - if not config.has_section(db_section): - return None - - type = config.get(db_section, 'ENGINE') - if type != 'mysql': - return None - - try: - host = config.get(db_section, 'HOST') - port = config.getint(db_section, 'PORT') - username = config.get(db_section, 'USER') - password = config.get(db_section, 'PASSWD') - db = config.get(db_section, 'DB') - unix_socket = config.get(db_section, 'UNIX_SOCKET') - except ConfigParser.NoOptionError, e: - Utils.error('Database config in ccnet.conf is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db, unix_socket) - return info - - @staticmethod - def get_seafile_mysql_info(version): - if version > '5.0.0': - config_path = env_mgr.central_config_dir - else: - config_path = env_mgr.seafile_dir - - seafile_conf = os.path.join(config_path, 'seafile.conf') - defaults = { - 'HOST': '127.0.0.1', - 'PORT': '3306', - 'UNIX_SOCKET': '', - } - config = Utils.read_config(seafile_conf, defaults) - db_section = 'database' - - if not config.has_section(db_section): - return None - - type = config.get(db_section, 'type') - if type != 'mysql': - return None - - try: - host = config.get(db_section, 'host') - port = config.getint(db_section, 'port') - username = config.get(db_section, 'user') - password = config.get(db_section, 'password') - db = config.get(db_section, 'db_name') - unix_socket = config.get(db_section, 'unix_socket') - except ConfigParser.NoOptionError, e: - Utils.error('Database config in seafile.conf is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db, unix_socket) - return info - - @staticmethod - def get_seahub_mysql_info(): - sys.path.insert(0, env_mgr.top_dir) - if env_mgr.central_config_dir: - sys.path.insert(0, env_mgr.central_config_dir) - try: - import seahub_settings # pylint: disable=F0401 - except ImportError, e: - Utils.error('Failed to import seahub_settings.py: %s' % e) - - if not hasattr(seahub_settings, 'DATABASES'): - return None - - try: - d = seahub_settings.DATABASES['default'] - if d['ENGINE'] != 'django.db.backends.mysql': - return None - - host = d.get('HOST', '127.0.0.1') - port = int(d.get('PORT', 3306)) - username = d['USER'] - password = d['PASSWORD'] - db = d['NAME'] - unix_socket = host if host.startswith('/') else None - except KeyError: - Utils.error('Database config in seahub_settings.py is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db, unix_socket) - return info - - def update_ccnet_sql(self, ccnet_sql): - raise NotImplementedError - - def update_seafile_sql(self, seafile_sql): - raise NotImplementedError - - def update_seahub_sql(self, seahub_sql): - raise NotImplementedError - -class CcnetSQLiteDB(object): - def __init__(self, ccnet_dir): - self.ccnet_dir = ccnet_dir - - def get_db(self, dbname): - dbs = ( - 'ccnet.db', - 'GroupMgr/groupmgr.db', - 'misc/config.db', - 'OrgMgr/orgmgr.db', - ) - for db in dbs: - if os.path.splitext(os.path.basename(db))[0] == dbname: - return os.path.join(self.ccnet_dir, db) - -class SQLiteDBUpdater(DBUpdater): - def __init__(self, version): - DBUpdater.__init__(self, version, 'sqlite3') - - self.ccnet_db = CcnetSQLiteDB(env_mgr.ccnet_dir) - self.seafile_db = os.path.join(env_mgr.seafile_dir, 'seafile.db') - self.seahub_db = os.path.join(env_mgr.top_dir, 'seahub.db') - - def update_db(self): - super(SQLiteDBUpdater, self).update_db() - for sql_path in glob.glob(os.path.join(self.sql_dir, 'ccnet', '*.sql')): - self.update_ccnet_sql(sql_path) - - def apply_sqls(self, db_path, sql_path): - with open(sql_path, 'r') as fp: - lines = fp.read().split(';') - - with sqlite3.connect(db_path) as conn: - for line in lines: - line = line.strip() - if not line: - continue - else: - conn.execute(line) - - def update_ccnet_sql(self, sql_path): - dbname = os.path.splitext(os.path.basename(sql_path))[0] - self.apply_sqls(self.ccnet_db.get_db(dbname), sql_path) - - def update_seafile_sql(self, sql_path): - self.apply_sqls(self.seafile_db, sql_path) - - def update_seahub_sql(self, sql_path): - self.apply_sqls(self.seahub_db, sql_path) - - -class MySQLDBUpdater(DBUpdater): - def __init__(self, version, ccnet_db_info, seafile_db_info, seahub_db_info): - DBUpdater.__init__(self, version, 'mysql') - self.ccnet_db_info = ccnet_db_info - self.seafile_db_info = seafile_db_info - self.seahub_db_info = seahub_db_info - - def update_ccnet_sql(self, ccnet_sql): - self.apply_sqls(self.ccnet_db_info, ccnet_sql) - - def update_seafile_sql(self, seafile_sql): - self.apply_sqls(self.seafile_db_info, seafile_sql) - - def update_seahub_sql(self, seahub_sql): - self.apply_sqls(self.seahub_db_info, seahub_sql) - - def get_conn(self, info): - kw = dict( - user=info.username, - passwd=info.password, - db=info.db, - ) - if info.unix_socket: - kw['unix_socket'] = info.unix_socket - else: - kw['host'] = info.host - kw['port'] = info.port - try: - conn = MySQLdb.connect(**kw) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - msg = str(e.args[1]) - else: - msg = str(e) - Utils.error('Failed to connect to mysql database %s: %s' % (info.db, msg)) - - return conn - - def execute_sql(self, conn, sql): - cursor = conn.cursor() - try: - cursor.execute(sql) - conn.commit() - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - msg = str(e.args[1]) - else: - msg = str(e) - - Utils.error('Failed to execute sql: %s' % msg) - - def apply_sqls(self, info, sql_path): - with open(sql_path, 'r') as fp: - lines = fp.read().split(';') - - conn = self.get_conn(info) - - for line in lines: - line = line.strip() - if not line: - continue - else: - self.execute_sql(conn, line) - - -def main(): - skipdb = os.environ.get('SEAFILE_SKIP_DB_UPGRADE', '').lower() - if skipdb in ('1', 'true', 'on'): - print 'Database upgrade skipped because SEAFILE_SKIP_DB_UPGRADE=%s' % skipdb - sys.exit() - version = sys.argv[1] - db_updater = DBUpdater.get_instance(version) - db_updater.update_db() - - return 0 - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/fix_mysql_user.py b/scripts/upgrade/fix_mysql_user.py deleted file mode 100644 index d68c8eae..00000000 --- a/scripts/upgrade/fix_mysql_user.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import re -import ConfigParser -import getpass -from collections import namedtuple - -try: - import MySQLdb - HAS_MYSQLDB = True -except ImportError: - HAS_MYSQLDB = False - -MySQLDBInfo = namedtuple('MySQLDBInfo', 'host port username password db') - -class EnvManager(object): - def __init__(self): - self.upgrade_dir = os.path.abspath(os.path.dirname(__file__)) - self.install_path = os.path.dirname(self.upgrade_dir) - self.top_dir = os.path.dirname(self.install_path) - self.ccnet_dir = os.environ['CCNET_CONF_DIR'] - self.seafile_dir = os.environ['SEAFILE_CONF_DIR'] - -env_mgr = EnvManager() - -class Utils(object): - @staticmethod - def highlight(content, is_error=False): - '''Add ANSI color to content to get it highlighted on terminal''' - if is_error: - return '\x1b[1;31m%s\x1b[m' % content - else: - return '\x1b[1;32m%s\x1b[m' % content - - @staticmethod - def info(msg): - print Utils.highlight('[INFO] ') + msg - - @staticmethod - def error(msg): - print Utils.highlight('[ERROR] ') + msg - sys.exit(1) - - @staticmethod - def read_config(config_path, defaults): - cp = ConfigParser.ConfigParser(defaults) - cp.read(config_path) - return cp - -def get_ccnet_mysql_info(): - ccnet_conf = os.path.join(env_mgr.ccnet_dir, 'ccnet.conf') - defaults = { - 'HOST': '127.0.0.1', - 'PORT': '3306', - } - - config = Utils.read_config(ccnet_conf, defaults) - db_section = 'Database' - - if not config.has_section(db_section): - return None - - type = config.get(db_section, 'ENGINE') - if type != 'mysql': - return None - - try: - host = config.get(db_section, 'HOST') - port = config.getint(db_section, 'PORT') - username = config.get(db_section, 'USER') - password = config.get(db_section, 'PASSWD') - db = config.get(db_section, 'DB') - except ConfigParser.NoOptionError, e: - Utils.error('Database config in ccnet.conf is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db) - return info - -def get_seafile_mysql_info(): - seafile_conf = os.path.join(env_mgr.seafile_dir, 'seafile.conf') - defaults = { - 'HOST': '127.0.0.1', - 'PORT': '3306', - } - config = Utils.read_config(seafile_conf, defaults) - db_section = 'database' - - if not config.has_section(db_section): - return None - - type = config.get(db_section, 'type') - if type != 'mysql': - return None - - try: - host = config.get(db_section, 'host') - port = config.getint(db_section, 'port') - username = config.get(db_section, 'user') - password = config.get(db_section, 'password') - db = config.get(db_section, 'db_name') - except ConfigParser.NoOptionError, e: - Utils.error('Database config in seafile.conf is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db) - return info - -def get_seahub_mysql_info(): - sys.path.insert(0, env_mgr.top_dir) - try: - import seahub_settings# pylint: disable=F0401 - except ImportError, e: - Utils.error('Failed to import seahub_settings.py: %s' % e) - - if not hasattr(seahub_settings, 'DATABASES'): - return None - - try: - d = seahub_settings.DATABASES['default'] - if d['ENGINE'] != 'django.db.backends.mysql': - return None - - host = d.get('HOST', '127.0.0.1') - port = int(d.get('PORT', 3306)) - username = d['USER'] - password = d['PASSWORD'] - db = d['NAME'] - except KeyError: - Utils.error('Database config in seahub_settings.py is invalid: %s' % e) - - info = MySQLDBInfo(host, port, username, password, db) - return info - -def get_seafile_db_infos(): - ccnet_db_info = get_ccnet_mysql_info() - seafile_db_info = get_seafile_mysql_info() - seahub_db_info = get_seahub_mysql_info() - - infos = [ccnet_db_info, seafile_db_info, seahub_db_info] - - for info in infos: - if info is None: - return None - if info.host not in ('localhost', '127.0.0.1'): - return None - return infos - -def ask_root_password(port): - while True: - desc = 'What is the root password for mysql? ' - password = getpass.getpass(desc).strip() - if password: - try: - return check_mysql_user('root', password, port) - except InvalidAnswer, e: - print '\n%s\n' % e - continue - -class InvalidAnswer(Exception): - def __init__(self, msg): - Exception.__init__(self) - self.msg = msg - - def __str__(self): - return self.msg - -def check_mysql_user(user, password, port): - print '\nverifying password of root user %s ... ' % user, - kwargs = dict(host='localhost', - port=port, - user=user, - passwd=password) - - try: - conn = MySQLdb.connect(**kwargs) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' - % (user, e.args[1])) - else: - raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' - % (user, e)) - - print 'done' - return conn - -def apply_fix(root_conn, user, dbs): - for db in dbs: - grant_db_permission(root_conn, user, db) - - cursor = root_conn.cursor() - sql = """ - SELECT * - FROM mysql.user - WHERE Host = '%%' - AND password = '' - AND User = '%s' - """ % user - cursor.execute(sql) - if cursor.rowcount > 0: - sql = 'DROP USER `%s`@`%%`' % user - cursor.execute(sql) - -def grant_db_permission(conn, user, db): - cursor = conn.cursor() - sql = '''GRANT ALL PRIVILEGES ON `%s`.* to `%s`@localhost ''' \ - % (db, user) - - try: - cursor.execute(sql) - except Exception, e: - if isinstance(e, MySQLdb.OperationalError): - Utils.error('Failed to grant permission of database %s: %s' % (db, e.args[1])) - else: - Utils.error('Failed to grant permission of database %s: %s' % (db, e)) - - finally: - cursor.close() - -def main(): - dbinfos = get_seafile_db_infos() - if not dbinfos: - return - if dbinfos[0].username == 'root': - return - - if not HAS_MYSQLDB: - Utils.error('Python MySQLdb module is not found') - root_conn = ask_root_password(dbinfos[0].port) - apply_fix(root_conn, dbinfos[0].username, [info.db for info in dbinfos]) - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/minor-upgrade.sh b/scripts/upgrade/minor-upgrade.sh deleted file mode 100755 index 792b09f3..00000000 --- a/scripts/upgrade/minor-upgrade.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ - -echo -echo "-------------------------------------------------------------" -echo "This script would do the minor upgrade for you." -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data - -function migrate_avatars() { - echo - echo "------------------------------" - echo "migrating avatars ..." - echo - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - echo - echo "Error: avatars directory \"${dest_avatar_dir}\" does not exist" 2>&1 - echo - exit 1 - - elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo - echo "DONE" - echo "------------------------------" - echo -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -function update_latest_symlink() { - # update the symlink seafile-server to the new server version - echo - echo "updating seafile-server-latest symbolic link to ${INSTALLPATH} ..." - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi -} - -migrate_avatars; - -move_old_customdir_outside; -make_media_custom_symlink; - -update_latest_symlink; - - -echo "DONE" -echo "------------------------------" -echo diff --git a/scripts/upgrade/regenerate_secret_key.sh b/scripts/upgrade/regenerate_secret_key.sh deleted file mode 100755 index b59f44d1..00000000 --- a/scripts/upgrade/regenerate_secret_key.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") -UPGRADEDIR=$(dirname "${SCRIPT}") -INSTALLPATH=$(dirname "${UPGRADEDIR}") -TOPDIR=$(dirname "${INSTALLPATH}") - -seahub_secret_keygen=${INSTALLPATH}/seahub/tools/secret_key_generator.py -seahub_settings_py=${TOPDIR}/seahub_settings.py - -line="SECRET_KEY = \"$(python $seahub_secret_keygen)\"" - -sed -i -e "/SECRET_KEY/c\\$line" $seahub_settings_py diff --git a/scripts/upgrade/sql/1.6.0/mysql/seahub.sql b/scripts/upgrade/sql/1.6.0/mysql/seahub.sql deleted file mode 100644 index c8706549..00000000 --- a/scripts/upgrade/sql/1.6.0/mysql/seahub.sql +++ /dev/null @@ -1,47 +0,0 @@ -CREATE TABLE IF NOT EXISTS `wiki_groupwiki` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `group_id` int(11) NOT NULL, - `repo_id` varchar(36) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `group_id` (`group_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `wiki_personalwiki` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `repo_id` varchar(36) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `username` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `group_publicgroup` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `group_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `group_publicgroup_425ae3c4` (`group_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `base_filediscuss` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `group_message_id` int(11) NOT NULL, - `repo_id` varchar(36) NOT NULL, - `path` longtext NOT NULL, - `path_hash` varchar(12) NOT NULL, - PRIMARY KEY (`id`), - KEY `base_filediscuss_3c1a2584` (`group_message_id`), - KEY `base_filediscuss_6844bd5a` (`path_hash`), - CONSTRAINT `group_message_id_refs_id_2ade200f` FOREIGN KEY (`group_message_id`) REFERENCES `group_groupmessage` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `base_filelastmodifiedinfo` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `repo_id` varchar(36) NOT NULL, - `file_id` varchar(40) NOT NULL, - `file_path` longtext NOT NULL, - `file_path_hash` varchar(12) NOT NULL, - `last_modified` bigint(20) NOT NULL, - `email` varchar(75) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `repo_id` (`repo_id`,`file_path_hash`), - KEY `base_filelastmodifiedinfo_359081cc` (`repo_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; \ No newline at end of file diff --git a/scripts/upgrade/sql/1.6.0/sqlite3/seahub.sql b/scripts/upgrade/sql/1.6.0/sqlite3/seahub.sql deleted file mode 100644 index b1a97440..00000000 --- a/scripts/upgrade/sql/1.6.0/sqlite3/seahub.sql +++ /dev/null @@ -1,39 +0,0 @@ -CREATE TABLE IF NOT EXISTS "wiki_groupwiki" ( - "id" integer NOT NULL PRIMARY KEY, - "group_id" integer NOT NULL UNIQUE, - "repo_id" varchar(36) NOT NULL -); - -CREATE TABLE IF NOT EXISTS "wiki_personalwiki" ( - "id" integer NOT NULL PRIMARY KEY, - "username" varchar(256) NOT NULL UNIQUE, - "repo_id" varchar(36) NOT NULL -); - -CREATE TABLE IF NOT EXISTS "group_publicgroup" ( - "id" integer NOT NULL PRIMARY KEY, - "group_id" integer NOT NULL -); -CREATE INDEX IF NOT EXISTS "group_publicgroup_bda51c3c" ON "group_publicgroup" ("group_id"); - -CREATE TABLE IF NOT EXISTS "base_filediscuss" ( - "id" integer NOT NULL PRIMARY KEY, - "group_message_id" integer NOT NULL REFERENCES "group_groupmessage" ("id"), - "repo_id" varchar(40) NOT NULL, - "path" text NOT NULL, - "path_hash" varchar(12) NOT NULL -); -CREATE INDEX IF NOT EXISTS "base_filediscuss_6844bd5a" ON "base_filediscuss" ("path_hash"); -CREATE INDEX IF NOT EXISTS "base_filediscuss_c3e5da7c" ON "base_filediscuss" ("group_message_id"); - -CREATE TABLE IF NOT EXISTS "base_filelastmodifiedinfo" ( - "id" integer NOT NULL PRIMARY KEY, - "repo_id" varchar(36) NOT NULL, - "file_id" varchar(40) NOT NULL, - "file_path" text NOT NULL, - "file_path_hash" varchar(12) NOT NULL, - "last_modified" bigint NOT NULL, - "email" varchar(75) NOT NULL, - UNIQUE ("repo_id", "file_path_hash") -); -CREATE INDEX IF NOT EXISTS "base_filelastmodifiedinfo_ca6f7e34" ON "base_filelastmodifiedinfo" ("repo_id"); \ No newline at end of file diff --git a/scripts/upgrade/sql/1.7.0/mysql/seafile.sql b/scripts/upgrade/sql/1.7.0/mysql/seafile.sql deleted file mode 100644 index 5dfc278c..00000000 --- a/scripts/upgrade/sql/1.7.0/mysql/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX repousertoken_email on RepoUserToken(email); diff --git a/scripts/upgrade/sql/1.7.0/mysql/seahub.sql b/scripts/upgrade/sql/1.7.0/mysql/seahub.sql deleted file mode 100644 index 6ad01f33..00000000 --- a/scripts/upgrade/sql/1.7.0/mysql/seahub.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE `message_usermessage` ( - `message_id` int(11) NOT NULL AUTO_INCREMENT, - `message` varchar(512) NOT NULL, - `from_email` varchar(75) NOT NULL, - `to_email` varchar(75) NOT NULL, - `timestamp` datetime NOT NULL, - `ifread` tinyint(1) NOT NULL, - PRIMARY KEY (`message_id`), - KEY `message_usermessage_8b1dd4eb` (`from_email`), - KEY `message_usermessage_590d1560` (`to_email`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `message_usermsglastcheck` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `check_time` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/scripts/upgrade/sql/1.7.0/sqlite3/seafile.sql b/scripts/upgrade/sql/1.7.0/sqlite3/seafile.sql deleted file mode 100644 index 9b5a1c32..00000000 --- a/scripts/upgrade/sql/1.7.0/sqlite3/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX IF NOT EXISTS repousertoken_email on RepoUserToken(email); \ No newline at end of file diff --git a/scripts/upgrade/sql/1.7.0/sqlite3/seahub.sql b/scripts/upgrade/sql/1.7.0/sqlite3/seahub.sql deleted file mode 100644 index c21efddc..00000000 --- a/scripts/upgrade/sql/1.7.0/sqlite3/seahub.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE IF NOT EXISTS "message_usermessage" ( - "message_id" integer NOT NULL PRIMARY KEY, - "message" varchar(512) NOT NULL, - "from_email" varchar(75) NOT NULL, - "to_email" varchar(75) NOT NULL, - "timestamp" datetime NOT NULL, - "ifread" bool NOT NULL -) -; -CREATE TABLE IF NOT EXISTS "message_usermsglastcheck" ( - "id" integer NOT NULL PRIMARY KEY, - "check_time" datetime NOT NULL -) -; -CREATE INDEX IF NOT EXISTS "message_usermessage_8b1dd4eb" ON "message_usermessage" ("from_email"); -CREATE INDEX IF NOT EXISTS "message_usermessage_590d1560" ON "message_usermessage" ("to_email"); diff --git a/scripts/upgrade/sql/1.8.0/mysql/ccnet.sql b/scripts/upgrade/sql/1.8.0/mysql/ccnet.sql deleted file mode 100644 index 5ee7e0cb..00000000 --- a/scripts/upgrade/sql/1.8.0/mysql/ccnet.sql +++ /dev/null @@ -1,2 +0,0 @@ --- ccnet -ALTER TABLE EmailUser MODIFY passwd varchar(64); diff --git a/scripts/upgrade/sql/1.8.0/mysql/seahub.sql b/scripts/upgrade/sql/1.8.0/mysql/seahub.sql deleted file mode 100644 index f1c79e79..00000000 --- a/scripts/upgrade/sql/1.8.0/mysql/seahub.sql +++ /dev/null @@ -1,30 +0,0 @@ --- seahub -ALTER TABLE group_groupmessage MODIFY message varchar(2048); -ALTER TABLE group_messagereply MODIFY message varchar(2048); - -CREATE TABLE IF NOT EXISTS `share_privatefiledirshare` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `from_user` varchar(255) NOT NULL, - `to_user` varchar(255) NOT NULL, - `repo_id` varchar(36) NOT NULL, - `path` longtext NOT NULL, - `token` varchar(10) NOT NULL, - `permission` varchar(5) NOT NULL, - `s_type` varchar(5) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `token` (`token`), - KEY `share_privatefiledirshare_0e7efed3` (`from_user`), - KEY `share_privatefiledirshare_bc172800` (`to_user`), - KEY `share_privatefiledirshare_2059abe4` (`repo_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `message_usermsgattachment` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_msg_id` int(11) NOT NULL, - `priv_file_dir_share_id` int(11) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `message_usermsgattachment_72f290f5` (`user_msg_id`), - KEY `message_usermsgattachment_cee41a9a` (`priv_file_dir_share_id`), - CONSTRAINT `priv_file_dir_share_id_refs_id_163f8f83` FOREIGN KEY (`priv_file_dir_share_id`) REFERENCES `share_privatefiledirshare` (`id`), - CONSTRAINT `user_msg_id_refs_message_id_debb82ad` FOREIGN KEY (`user_msg_id`) REFERENCES `message_usermessage` (`message_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/scripts/upgrade/sql/1.8.0/sqlite3/seahub.sql b/scripts/upgrade/sql/1.8.0/sqlite3/seahub.sql deleted file mode 100644 index 52658083..00000000 --- a/scripts/upgrade/sql/1.8.0/sqlite3/seahub.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE IF NOT EXISTS "share_privatefiledirshare" ( - "id" integer NOT NULL PRIMARY KEY, - "from_user" varchar(255) NOT NULL, - "to_user" varchar(255) NOT NULL, - "repo_id" varchar(36) NOT NULL, - "path" text NOT NULL, - "token" varchar(10) NOT NULL UNIQUE, - "permission" varchar(5) NOT NULL, - "s_type" varchar(5) NOT NULL -); - -CREATE TABLE IF NOT EXISTS "message_usermsgattachment" ( - "id" integer NOT NULL PRIMARY KEY, - "user_msg_id" integer NOT NULL REFERENCES "message_usermessage" ("message_id"), - "priv_file_dir_share_id" integer REFERENCES "share_privatefiledirshare" ("id") -); - -CREATE INDEX IF NOT EXISTS "share_privatefiledirshare_0e7efed3" ON "share_privatefiledirshare" ("from_user"); -CREATE INDEX IF NOT EXISTS "share_privatefiledirshare_2059abe4" ON "share_privatefiledirshare" ("repo_id"); -CREATE INDEX IF NOT EXISTS "share_privatefiledirshare_bc172800" ON "share_privatefiledirshare" ("to_user"); \ No newline at end of file diff --git a/scripts/upgrade/sql/2.0.0/mysql/seahub.sql b/scripts/upgrade/sql/2.0.0/mysql/seahub.sql deleted file mode 100644 index f7cb4ab7..00000000 --- a/scripts/upgrade/sql/2.0.0/mysql/seahub.sql +++ /dev/null @@ -1,24 +0,0 @@ --- seahub -CREATE TABLE IF NOT EXISTS `base_groupenabledmodule` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `group_id` varchar(10) NOT NULL, - `module_name` varchar(20) NOT NULL, - PRIMARY KEY (`id`), - KEY `base_groupenabledmodule_dc00373b` (`group_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `base_userenabledmodule` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `module_name` varchar(20) NOT NULL, - PRIMARY KEY (`id`), - KEY `base_userenabledmodule_ee0cafa2` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `base_userlastlogin` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `last_login` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `base_userlastlogin_ee0cafa2` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/scripts/upgrade/sql/2.0.0/sqlite3/seahub.sql b/scripts/upgrade/sql/2.0.0/sqlite3/seahub.sql deleted file mode 100644 index 9d0dae3e..00000000 --- a/scripts/upgrade/sql/2.0.0/sqlite3/seahub.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE IF NOT EXISTS "base_groupenabledmodule" ( - "id" integer NOT NULL PRIMARY KEY, - "group_id" varchar(10) NOT NULL, - "module_name" varchar(20) NOT NULL -); - -CREATE TABLE IF NOT EXISTS "base_userenabledmodule" ( - "id" integer NOT NULL PRIMARY KEY, - "username" varchar(255) NOT NULL, - "module_name" varchar(20) NOT NULL -); - -CREATE TABLE IF NOT EXISTS "base_userlastlogin" ( - "id" integer NOT NULL PRIMARY KEY, - "username" varchar(255) NOT NULL, - "last_login" datetime NOT NULL -); - -CREATE INDEX IF NOT EXISTS "base_groupenabledmodule_dc00373b" ON "base_groupenabledmodule" ("group_id"); -CREATE INDEX IF NOT EXISTS "base_userenabledmodule_ee0cafa2" ON "base_userenabledmodule" ("username"); diff --git a/scripts/upgrade/sql/2.1.0/mysql/seahub.sql b/scripts/upgrade/sql/2.1.0/mysql/seahub.sql deleted file mode 100644 index 391b688b..00000000 --- a/scripts/upgrade/sql/2.1.0/mysql/seahub.sql +++ /dev/null @@ -1,53 +0,0 @@ -CREATE TABLE IF NOT EXISTS `captcha_captchastore` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `challenge` varchar(32) NOT NULL, - `response` varchar(32) NOT NULL, - `hashkey` varchar(40) NOT NULL, - `expiration` datetime NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `hashkey` (`hashkey`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `notifications_usernotification`; -CREATE TABLE IF NOT EXISTS `notifications_usernotification` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `to_user` varchar(255) NOT NULL, - `msg_type` varchar(30) NOT NULL, - `detail` longtext NOT NULL, - `timestamp` datetime NOT NULL, - `seen` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - KEY `notifications_usernotification_bc172800` (`to_user`), - KEY `notifications_usernotification_265e5521` (`msg_type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `options_useroptions` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `email` varchar(255) NOT NULL, - `option_key` varchar(50) NOT NULL, - `option_val` varchar(50) NOT NULL, - PRIMARY KEY (`id`), - KEY `options_useroptions_830a6ccb` (`email`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `profile_detailedprofile` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user` varchar(255) NOT NULL, - `department` varchar(512) NOT NULL, - `telephone` varchar(100) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `share_uploadlinkshare` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `repo_id` varchar(36) NOT NULL, - `path` longtext NOT NULL, - `token` varchar(10) NOT NULL, - `ctime` datetime NOT NULL, - `view_cnt` int(11) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `token` (`token`), - KEY `share_uploadlinkshare_ee0cafa2` (`username`), - KEY `share_uploadlinkshare_2059abe4` (`repo_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/scripts/upgrade/sql/2.1.0/sqlite3/seahub.sql b/scripts/upgrade/sql/2.1.0/sqlite3/seahub.sql deleted file mode 100644 index f6b0c9c1..00000000 --- a/scripts/upgrade/sql/2.1.0/sqlite3/seahub.sql +++ /dev/null @@ -1,48 +0,0 @@ -CREATE TABLE IF NOT EXISTS "captcha_captchastore" ( - "id" integer NOT NULL PRIMARY KEY, - "challenge" varchar(32) NOT NULL, - "response" varchar(32) NOT NULL, - "hashkey" varchar(40) NOT NULL UNIQUE, - "expiration" datetime NOT NULL -); - -DROP TABLE IF EXISTS "notifications_usernotification"; -CREATE TABLE IF NOT EXISTS "notifications_usernotification" ( - "id" integer NOT NULL PRIMARY KEY, - "to_user" varchar(255) NOT NULL, - "msg_type" varchar(30) NOT NULL, - "detail" text NOT NULL, - "timestamp" datetime NOT NULL, - "seen" bool NOT NULL -); - -CREATE INDEX IF NOT EXISTS "notifications_usernotification_265e5521" ON "notifications_usernotification" ("msg_type"); -CREATE INDEX IF NOT EXISTS "notifications_usernotification_bc172800" ON "notifications_usernotification" ("to_user"); - -CREATE TABLE IF NOT EXISTS "options_useroptions" ( - "id" integer NOT NULL PRIMARY KEY, - "email" varchar(255) NOT NULL, - "option_key" varchar(50) NOT NULL, - "option_val" varchar(50) NOT NULL -); -CREATE INDEX IF NOT EXISTS "options_useroptions_830a6ccb" ON "options_useroptions" ("email"); - -CREATE TABLE IF NOT EXISTS "profile_detailedprofile" ( - "id" integer NOT NULL PRIMARY KEY, - "user" varchar(255) NOT NULL, - "department" varchar(512) NOT NULL, - "telephone" varchar(100) NOT NULL -); -CREATE INDEX IF NOT EXISTS "profile_detailedprofile_6340c63c" ON "profile_detailedprofile" ("user"); - -CREATE TABLE IF NOT EXISTS "share_uploadlinkshare" ( - "id" integer NOT NULL PRIMARY KEY, - "username" varchar(255) NOT NULL, - "repo_id" varchar(36) NOT NULL, - "path" text NOT NULL, - "token" varchar(10) NOT NULL UNIQUE, - "ctime" datetime NOT NULL, - "view_cnt" integer NOT NULL -); -CREATE INDEX IF NOT EXISTS "share_uploadlinkshare_2059abe4" ON "share_uploadlinkshare" ("repo_id"); -CREATE INDEX IF NOT EXISTS "share_uploadlinkshare_ee0cafa2" ON "share_uploadlinkshare" ("username"); diff --git a/scripts/upgrade/sql/2.2.0/mysql/ccnet.sql b/scripts/upgrade/sql/2.2.0/mysql/ccnet.sql deleted file mode 100644 index 88385eed..00000000 --- a/scripts/upgrade/sql/2.2.0/mysql/ccnet.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE EmailUser MODIFY passwd varchar(256); - diff --git a/scripts/upgrade/sql/3.0.0/mysql/seahub.sql b/scripts/upgrade/sql/3.0.0/mysql/seahub.sql deleted file mode 100644 index 7e656ba0..00000000 --- a/scripts/upgrade/sql/3.0.0/mysql/seahub.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE IF NOT EXISTS `api2_tokenv2` ( - `key` varchar(40) NOT NULL, - `user` varchar(255) NOT NULL, - `platform` varchar(32) NOT NULL, - `device_id` varchar(40) NOT NULL, - `device_name` varchar(40) NOT NULL, - `platform_version` varchar(16) NOT NULL, - `client_version` varchar(16) NOT NULL, - `last_accessed` datetime NOT NULL, - `last_login_ip` char(39) DEFAULT NULL, - PRIMARY KEY (`key`), - UNIQUE KEY `user` (`user`,`platform`,`device_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/scripts/upgrade/sql/3.0.0/sqlite3/seahub.sql b/scripts/upgrade/sql/3.0.0/sqlite3/seahub.sql deleted file mode 100644 index c05453ac..00000000 --- a/scripts/upgrade/sql/3.0.0/sqlite3/seahub.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE IF NOT EXISTS "api2_tokenv2" ( - "key" varchar(40) NOT NULL PRIMARY KEY, - "user" varchar(255) NOT NULL, - "platform" varchar(32) NOT NULL, - "device_id" varchar(40) NOT NULL, - "device_name" varchar(40) NOT NULL, - "platform_version" varchar(16) NOT NULL, - "client_version" varchar(16) NOT NULL, - "last_accessed" datetime NOT NULL, - "last_login_ip" char(39), - UNIQUE ("user", "platform", "device_id") -); diff --git a/scripts/upgrade/sql/3.1.0/mysql/seahub.sql b/scripts/upgrade/sql/3.1.0/mysql/seahub.sql deleted file mode 100644 index ad139cd1..00000000 --- a/scripts/upgrade/sql/3.1.0/mysql/seahub.sql +++ /dev/null @@ -1,20 +0,0 @@ -alter table message_usermessage add column sender_deleted_at datetime DEFAULT NULL; -alter table message_usermessage add column recipient_deleted_at datetime DEFAULT NULL; - -alter table share_fileshare add column password varchar(128); -alter table share_fileshare add column expire_date datetime; -alter table share_uploadlinkshare add column password varchar(128); -alter table share_uploadlinkshare add column expire_date datetime; -alter table profile_profile add column lang_code varchar(50) DEFAULT NULL; - -CREATE TABLE IF NOT EXISTS `share_orgfileshare` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `org_id` int(11) NOT NULL, - `file_share_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `file_share_id` (`file_share_id`), - KEY `share_orgfileshare_944dadb6` (`org_id`), - CONSTRAINT `file_share_id_refs_id_bd2fd9f8` FOREIGN KEY (`file_share_id`) REFERENCES `share_fileshare` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `base_userstarredfiles` ADD INDEX `base_userstarredfiles_email` (email); diff --git a/scripts/upgrade/sql/3.1.0/sqlite3/seahub.sql b/scripts/upgrade/sql/3.1.0/sqlite3/seahub.sql deleted file mode 100644 index 42846156..00000000 --- a/scripts/upgrade/sql/3.1.0/sqlite3/seahub.sql +++ /dev/null @@ -1,16 +0,0 @@ -alter table "message_usermessage" add column "sender_deleted_at" datetime; -alter table "message_usermessage" add column "recipient_deleted_at" datetime; -alter table "share_fileshare" add column "password" varchar(128); -alter table "share_fileshare" add column "expire_date" datetime; -alter table "share_uploadlinkshare" add column "password" varchar(128); -alter table "share_uploadlinkshare" add column "expire_date" datetime; -alter table "profile_profile" add column "lang_code" varchar(50); - -CREATE TABLE IF NOT EXISTS "share_orgfileshare" ( - "id" integer NOT NULL PRIMARY KEY, - "org_id" integer NOT NULL, - "file_share_id" integer NOT NULL UNIQUE REFERENCES "share_fileshare" ("id") -); -CREATE INDEX IF NOT EXISTS "share_orgfileshare_944dadb6" ON "share_orgfileshare" ("org_id"); - -CREATE INDEX IF NOT EXISTS "base_userstarredfiles_email" on "base_userstarredfiles" ("email"); diff --git a/scripts/upgrade/sql/4.1.0/mysql/ccnet.sql b/scripts/upgrade/sql/4.1.0/mysql/ccnet.sql deleted file mode 100644 index 42e78881..00000000 --- a/scripts/upgrade/sql/4.1.0/mysql/ccnet.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `Group` ADD type VARCHAR(32); diff --git a/scripts/upgrade/sql/4.1.0/mysql/seafile.sql b/scripts/upgrade/sql/4.1.0/mysql/seafile.sql deleted file mode 100644 index f82e4b75..00000000 --- a/scripts/upgrade/sql/4.1.0/mysql/seafile.sql +++ /dev/null @@ -1,30 +0,0 @@ -ALTER TABLE SharedRepo MODIFY from_email VARCHAR(255); -ALTER TABLE SharedRepo MODIFY to_email VARCHAR(255); -ALTER TABLE SharedRepo ADD INDEX (from_email); -ALTER TABLE SharedRepo ADD INDEX (to_email); - -CREATE TABLE IF NOT EXISTS OrgSharedRepo ( - id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, - org_id INT, - repo_id CHAR(37) , - from_email VARCHAR(255), - to_email VARCHAR(255), - permission CHAR(15), - INDEX (org_id, repo_id), - INDEX(from_email), - INDEX(to_email) -) ENGINE=INNODB; - -ALTER TABLE OrgSharedRepo MODIFY from_email VARCHAR(255); -ALTER TABLE OrgSharedRepo MODIFY to_email VARCHAR(255); - -CREATE TABLE IF NOT EXISTS RepoTrash ( - repo_id CHAR(36) PRIMARY KEY, - repo_name VARCHAR(255), - head_id CHAR(40), - owner_id VARCHAR(255), - size BIGINT(20), - org_id INTEGER, - INDEX(owner_id), - INDEX(org_id) -) ENGINE=INNODB; diff --git a/scripts/upgrade/sql/4.1.0/sqlite3/ccnet/groupmgr.sql b/scripts/upgrade/sql/4.1.0/sqlite3/ccnet/groupmgr.sql deleted file mode 100644 index 42e78881..00000000 --- a/scripts/upgrade/sql/4.1.0/sqlite3/ccnet/groupmgr.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `Group` ADD type VARCHAR(32); diff --git a/scripts/upgrade/sql/4.1.0/sqlite3/seafile.sql b/scripts/upgrade/sql/4.1.0/sqlite3/seafile.sql deleted file mode 100644 index 71147f24..00000000 --- a/scripts/upgrade/sql/4.1.0/sqlite3/seafile.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE INDEX IF NOT EXISTS FromEmailIndex on SharedRepo (from_email); -CREATE INDEX IF NOT EXISTS ToEmailIndex on SharedRepo (to_email); - -CREATE TABLE IF NOT EXISTS RepoTrash ( - repo_id CHAR(36) PRIMARY KEY, - repo_name VARCHAR(255), - head_id CHAR(40), - owner_id VARCHAR(255), - size BIGINT UNSIGNED, - org_id INTEGER -); - -CREATE INDEX IF NOT EXISTS repotrash_owner_id_idx ON RepoTrash(owner_id); -CREATE INDEX IF NOT EXISTS repotrash_org_id_idx ON RepoTrash(org_id); diff --git a/scripts/upgrade/sql/4.2.0/mysql/seafile.sql b/scripts/upgrade/sql/4.2.0/mysql/seafile.sql deleted file mode 100644 index 45a06dd9..00000000 --- a/scripts/upgrade/sql/4.2.0/mysql/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -alter table RepoTrash add del_time BIGINT; diff --git a/scripts/upgrade/sql/4.2.0/mysql/seahub.sql b/scripts/upgrade/sql/4.2.0/mysql/seahub.sql deleted file mode 100644 index b6268184..00000000 --- a/scripts/upgrade/sql/4.2.0/mysql/seahub.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE IF NOT EXISTS `base_clientlogintoken` ( - `token` varchar(32) NOT NULL, - `username` varchar(255) NOT NULL, - `timestamp` datetime NOT NULL, - PRIMARY KEY (`token`), - KEY `base_clientlogintoken_ee0cafa2` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `organizations_orgmemberquota` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `org_id` int(11) NOT NULL, - `quota` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `organizations_orgmemberquota_944dadb6` (`org_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -REPLACE INTO django_content_type VALUES(44,'client login token','base','clientlogintoken'); -REPLACE INTO django_content_type VALUES(45,'org member quota','organizations','orgmemberquota'); diff --git a/scripts/upgrade/sql/4.2.0/sqlite3/seafile.sql b/scripts/upgrade/sql/4.2.0/sqlite3/seafile.sql deleted file mode 100644 index 45a06dd9..00000000 --- a/scripts/upgrade/sql/4.2.0/sqlite3/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -alter table RepoTrash add del_time BIGINT; diff --git a/scripts/upgrade/sql/4.2.0/sqlite3/seahub.sql b/scripts/upgrade/sql/4.2.0/sqlite3/seahub.sql deleted file mode 100644 index 6bd3b520..00000000 --- a/scripts/upgrade/sql/4.2.0/sqlite3/seahub.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE IF NOT EXISTS "base_clientlogintoken" ( - "token" varchar(32) NOT NULL PRIMARY KEY, - "username" varchar(255) NOT NULL, - "timestamp" datetime NOT NULL -); - -CREATE INDEX IF NOT EXISTS "base_clientlogintoken_ee0cafa2" ON "base_clientlogintoken" ("username"); - -CREATE TABLE IF NOT EXISTS "organizations_orgmemberquota" ( - "id" integer NOT NULL PRIMARY KEY, - "org_id" integer NOT NULL, - "quota" integer NOT NULL -); - -CREATE INDEX IF NOT EXISTS "organizations_orgmemberquota_944dadb6" ON "organizations_orgmemberquota" ("org_id"); - -REPLACE INTO "django_content_type" VALUES(44,'client login token','base','clientlogintoken'); -REPLACE INTO "django_content_type" VALUES(45,'org member quota','organizations','orgmemberquota'); diff --git a/scripts/upgrade/sql/4.3.0/mysql/.gitkeep b/scripts/upgrade/sql/4.3.0/mysql/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/upgrade/sql/4.3.0/sqlite3/.gitkeep b/scripts/upgrade/sql/4.3.0/sqlite3/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/upgrade/sql/4.4.0/mysql/.gitkeep b/scripts/upgrade/sql/4.4.0/mysql/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/upgrade/sql/4.4.0/sqlite3/.gitkeep b/scripts/upgrade/sql/4.4.0/sqlite3/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/upgrade/sql/5.0.0/mysql/seahub.sql b/scripts/upgrade/sql/5.0.0/mysql/seahub.sql deleted file mode 100644 index c51a14d6..00000000 --- a/scripts/upgrade/sql/5.0.0/mysql/seahub.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE IF NOT EXISTS `constance_config` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `key` varchar(255) NOT NULL, - `value` longtext NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key` (`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `profile_profile` ADD `login_id` varchar(225) DEFAULT NULL; -ALTER TABLE `profile_profile` ADD `contact_email` varchar(225) DEFAULT NULL; -ALTER TABLE `profile_profile` ADD `institution` varchar(225) DEFAULT NULL; - -ALTER TABLE `profile_profile` ADD UNIQUE INDEX (`login_id`); -ALTER TABLE `profile_profile` ADD INDEX (`contact_email`); -ALTER TABLE `profile_profile` ADD INDEX (`institution`); - - diff --git a/scripts/upgrade/sql/5.0.0/sqlite3/seahub.sql b/scripts/upgrade/sql/5.0.0/sqlite3/seahub.sql deleted file mode 100644 index a6714968..00000000 --- a/scripts/upgrade/sql/5.0.0/sqlite3/seahub.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE IF NOT EXISTS "constance_config" ( - "id" integer NOT NULL PRIMARY KEY, - "key" varchar(255) NOT NULL UNIQUE, - "value" text NOT NULL -); - -ALTER TABLE "profile_profile" ADD COLUMN "login_id" varchar(225); -ALTER TABLE "profile_profile" ADD COLUMN "contact_email" varchar(225); -ALTER TABLE "profile_profile" ADD COLUMN "institution" varchar(225); - -CREATE UNIQUE INDEX "profile_profile_1b43c217" ON "profile_profile" ("login_id"); -CREATE INDEX "profile_profile_3b46cb17" ON "profile_profile" ("contact_email"); -CREATE INDEX "profile_profile_71bbc151" ON "profile_profile" ("institution"); diff --git a/scripts/upgrade/sql/5.1.0/mysql/seafile.sql b/scripts/upgrade/sql/5.1.0/mysql/seafile.sql deleted file mode 100644 index 2742df03..00000000 --- a/scripts/upgrade/sql/5.1.0/mysql/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -alter table RepoTokenPeerInfo add client_ver varchar(20); \ No newline at end of file diff --git a/scripts/upgrade/sql/5.1.0/mysql/seahub.sql b/scripts/upgrade/sql/5.1.0/mysql/seahub.sql deleted file mode 100644 index 056fd8a3..00000000 --- a/scripts/upgrade/sql/5.1.0/mysql/seahub.sql +++ /dev/null @@ -1,124 +0,0 @@ -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - - -CREATE TABLE IF NOT EXISTS `post_office_attachment` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `file` varchar(100) NOT NULL, - `name` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `post_office_attachment_emails` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `attachment_id` int(11) NOT NULL, - `email_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `attachment_id` (`attachment_id`,`email_id`), - KEY `post_office_attachment_emails_4be595e7` (`attachment_id`), - KEY `post_office_attachment_emails_830a6ccb` (`email_id`), - CONSTRAINT `attachment_id_refs_id_2d59d8fc` FOREIGN KEY (`attachment_id`) REFERENCES `post_office_attachment` (`id`), - CONSTRAINT `email_id_refs_id_061d81d8` FOREIGN KEY (`email_id`) REFERENCES `post_office_email` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `post_office_emailtemplate` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `description` longtext NOT NULL, - `created` datetime NOT NULL, - `last_updated` datetime NOT NULL, - `subject` varchar(255) NOT NULL, - `content` longtext NOT NULL, - `html_content` longtext NOT NULL, - `language` varchar(12) NOT NULL, - `default_template_id` int(11) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `language` (`language`,`default_template_id`), - KEY `post_office_emailtemplate_84c7951d` (`default_template_id`), - CONSTRAINT `default_template_id_refs_id_a2bc649e` FOREIGN KEY (`default_template_id`) REFERENCES `post_office_emailtemplate` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `post_office_email` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `from_email` varchar(254) NOT NULL, - `to` longtext NOT NULL, - `cc` longtext NOT NULL, - `bcc` longtext NOT NULL, - `subject` varchar(255) NOT NULL, - `message` longtext NOT NULL, - `html_message` longtext NOT NULL, - `status` smallint(5) unsigned DEFAULT NULL, - `priority` smallint(5) unsigned DEFAULT NULL, - `created` datetime NOT NULL, - `last_updated` datetime NOT NULL, - `scheduled_time` datetime DEFAULT NULL, - `headers` longtext, - `template_id` int(11) DEFAULT NULL, - `context` longtext, - `backend_alias` varchar(64) NOT NULL, - PRIMARY KEY (`id`), - KEY `post_office_email_48fb58bb` (`status`), - KEY `post_office_email_63b5ea41` (`created`), - KEY `post_office_email_470d4868` (`last_updated`), - KEY `post_office_email_c83ff05e` (`scheduled_time`), - KEY `post_office_email_43d23afc` (`template_id`), - CONSTRAINT `template_id_refs_id_a5d97662` FOREIGN KEY (`template_id`) REFERENCES `post_office_emailtemplate` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -CREATE TABLE IF NOT EXISTS `post_office_log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `email_id` int(11) NOT NULL, - `date` datetime NOT NULL, - `status` smallint(5) unsigned NOT NULL, - `exception_type` varchar(255) NOT NULL, - `message` longtext NOT NULL, - PRIMARY KEY (`id`), - KEY `post_office_log_830a6ccb` (`email_id`), - CONSTRAINT `email_id_refs_id_3d87f587` FOREIGN KEY (`email_id`) REFERENCES `post_office_email` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `institutions_institution` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(200) NOT NULL, - `create_time` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `institutions_institutionadmin` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user` varchar(254) NOT NULL, - `institution_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `i_institution_id_5f792d6fe9a87ac9_fk_institutions_institution_id` (`institution_id`), - CONSTRAINT `i_institution_id_5f792d6fe9a87ac9_fk_institutions_institution_id` FOREIGN KEY (`institution_id`) REFERENCES `institutions_institution` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `sysadmin_extra_userloginlog` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `login_date` datetime NOT NULL, - `login_ip` varchar(128) NOT NULL, - PRIMARY KEY (`id`), - KEY `sysadmin_extra_userloginlog_14c4b06b` (`username`), - KEY `sysadmin_extra_userloginlog_28ed1ef0` (`login_date`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `sysadmin_extra_userloginlog` MODIFY `login_ip` VARCHAR(128); - -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/scripts/upgrade/sql/5.1.0/sqlite3/seafile.sql b/scripts/upgrade/sql/5.1.0/sqlite3/seafile.sql deleted file mode 100644 index 2742df03..00000000 --- a/scripts/upgrade/sql/5.1.0/sqlite3/seafile.sql +++ /dev/null @@ -1 +0,0 @@ -alter table RepoTokenPeerInfo add client_ver varchar(20); \ No newline at end of file diff --git a/scripts/upgrade/sql/5.1.0/sqlite3/seahub.sql b/scripts/upgrade/sql/5.1.0/sqlite3/seahub.sql deleted file mode 100644 index 6e68aa06..00000000 --- a/scripts/upgrade/sql/5.1.0/sqlite3/seahub.sql +++ /dev/null @@ -1,72 +0,0 @@ -CREATE TABLE IF NOT EXISTS "post_office_attachment" ( - "id" integer NOT NULL PRIMARY KEY, - "file" varchar(100) NOT NULL, - "name" varchar(255) NOT NULL -); -CREATE TABLE IF NOT EXISTS "post_office_attachment_emails" ( - "id" integer NOT NULL PRIMARY KEY, - "attachment_id" integer NOT NULL, - "email_id" integer NOT NULL REFERENCES "post_office_email" ("id"), - UNIQUE ("attachment_id", "email_id") -); -CREATE TABLE IF NOT EXISTS "post_office_email" ( - "id" integer NOT NULL PRIMARY KEY, - "from_email" varchar(254) NOT NULL, - "to" text NOT NULL, - "cc" text NOT NULL, - "bcc" text NOT NULL, - "subject" varchar(255) NOT NULL, - "message" text NOT NULL, - "html_message" text NOT NULL, - "status" smallint unsigned, - "priority" smallint unsigned, - "created" datetime NOT NULL, - "last_updated" datetime NOT NULL, - "scheduled_time" datetime, - "headers" text, - "template_id" integer, - "context" text, - "backend_alias" varchar(64) NOT NULL -); -CREATE TABLE IF NOT EXISTS "post_office_emailtemplate" ( - "id" integer NOT NULL PRIMARY KEY, - "name" varchar(255) NOT NULL, - "description" text NOT NULL, - "created" datetime NOT NULL, - "last_updated" datetime NOT NULL, - "subject" varchar(255) NOT NULL, - "content" text NOT NULL, - "html_content" text NOT NULL, - "language" varchar(12) NOT NULL, - "default_template_id" integer, - UNIQUE ("language", "default_template_id") -); -CREATE TABLE IF NOT EXISTS "post_office_log" ( - "id" integer NOT NULL PRIMARY KEY, - "email_id" integer NOT NULL REFERENCES "post_office_email" ("id"), - "date" datetime NOT NULL, - "status" smallint unsigned NOT NULL, - "exception_type" varchar(255) NOT NULL, - "message" text NOT NULL -); -CREATE TABLE IF NOT EXISTS "institutions_institution" ( - "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, - "name" varchar(200) NOT NULL, - "create_time" datetime NOT NULL -); -CREATE TABLE IF NOT EXISTS "institutions_institutionadmin" ( - "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, - "user" varchar(254) NOT NULL, - "institution_id" integer NOT NULL REFERENCES "institutions_institution" ("id") -); - -CREATE INDEX IF NOT EXISTS "post_office_attachment_emails_4be595e7" ON "post_office_attachment_emails" ("attachment_id"); -CREATE INDEX IF NOT EXISTS "post_office_attachment_emails_830a6ccb" ON "post_office_attachment_emails" ("email_id"); -CREATE INDEX IF NOT EXISTS "post_office_email_43d23afc" ON "post_office_email" ("template_id"); -CREATE INDEX IF NOT EXISTS "post_office_email_470d4868" ON "post_office_email" ("last_updated"); -CREATE INDEX IF NOT EXISTS "post_office_email_48fb58bb" ON "post_office_email" ("status"); -CREATE INDEX IF NOT EXISTS "post_office_email_63b5ea41" ON "post_office_email" ("created"); -CREATE INDEX IF NOT EXISTS "post_office_email_c83ff05e" ON "post_office_email" ("scheduled_time"); -CREATE INDEX IF NOT EXISTS "post_office_emailtemplate_84c7951d" ON "post_office_emailtemplate" ("default_template_id"); -CREATE INDEX IF NOT EXISTS "post_office_log_830a6ccb" ON "post_office_log" ("email_id"); -CREATE INDEX "institutions_institutionadmin_a964baeb" ON "institutions_institutionadmin" ("institution_id"); diff --git a/scripts/upgrade/sql/6.0.0/mysql/seahub.sql b/scripts/upgrade/sql/6.0.0/mysql/seahub.sql deleted file mode 100644 index fe9516a1..00000000 --- a/scripts/upgrade/sql/6.0.0/mysql/seahub.sql +++ /dev/null @@ -1,104 +0,0 @@ -ALTER TABLE api2_tokenv2 ADD COLUMN wiped_at DATETIME DEFAULT NULL; -ALTER TABLE api2_tokenv2 ADD COLUMN created_at DATETIME NOT NULL DEFAULT "1970-01-01 00:00:00"; - -CREATE TABLE IF NOT EXISTS `base_filecomment` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `repo_id` varchar(36) NOT NULL, - `parent_path` longtext NOT NULL, - `repo_id_parent_path_md5` varchar(100) NOT NULL, - `item_name` longtext NOT NULL, - `author` varchar(255) NOT NULL, - `comment` longtext NOT NULL, - `created_at` datetime NOT NULL, - `updated_at` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `base_filecomment_9a8c79bf` (`repo_id`), - KEY `base_filecomment_c5bf47d4` (`repo_id_parent_path_md5`), - KEY `base_filecomment_02bd92fa` (`author`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `termsandconditions_termsandconditions` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `slug` varchar(50) NOT NULL, - `name` longtext NOT NULL, - `version_number` decimal(6,2) NOT NULL, - `text` longtext, - `info` longtext, - `date_active` datetime DEFAULT NULL, - `date_created` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `termsandconditions_termsandconditions_2dbcba41` (`slug`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `termsandconditions_usertermsandconditions` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `ip_address` char(39) DEFAULT NULL, - `date_accepted` datetime NOT NULL, - `terms_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `termsandconditions_usertermsandcon_username_f4ab54cafa29322_uniq` (`username`,`terms_id`), - KEY `e4da106203f3f13ff96409b55de6f515` (`terms_id`), - CONSTRAINT `e4da106203f3f13ff96409b55de6f515` FOREIGN KEY (`terms_id`) REFERENCES `termsandconditions_termsandconditions` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `two_factor_totpdevice` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user` varchar(255) NOT NULL, - `name` varchar(64) NOT NULL, - `confirmed` tinyint(1) NOT NULL, - `key` varchar(80) NOT NULL, - `step` smallint(5) unsigned NOT NULL, - `t0` bigint(20) NOT NULL, - `digits` smallint(5) unsigned NOT NULL, - `tolerance` smallint(5) unsigned NOT NULL, - `drift` smallint(6) NOT NULL, - `last_t` bigint(20) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `user` (`user`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `two_factor_phonedevice` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user` varchar(255) NOT NULL, - `name` varchar(64) NOT NULL, - `confirmed` tinyint(1) NOT NULL, - `number` varchar(40) NOT NULL, - `key` varchar(40) NOT NULL, - `method` varchar(4) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `user` (`user`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `two_factor_staticdevice` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user` varchar(255) NOT NULL, - `name` varchar(64) NOT NULL, - `confirmed` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `user` (`user`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `two_factor_statictoken` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `token` varchar(16) NOT NULL, - `device_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `two_fac_device_id_55a7b345293a7c6c_fk_two_factor_staticdevice_id` (`device_id`), - KEY `two_factor_statictoken_94a08da1` (`token`), - CONSTRAINT `two_fac_device_id_55a7b345293a7c6c_fk_two_factor_staticdevice_id` FOREIGN KEY (`device_id`) REFERENCES `two_factor_staticdevice` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `invitations_invitation` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `token` varchar(40) NOT NULL, - `inviter` varchar(255) NOT NULL, - `accepter` varchar(255) NOT NULL, - `invite_time` datetime NOT NULL, - `accept_time` datetime DEFAULT NULL, - `invite_type` varchar(20) NOT NULL, - `expire_time` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `invitations_invitation_d5dd16f8` (`inviter`), - KEY `invitations_invitation_token_1961fbb98c05e5fd_uniq` (`token`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/scripts/upgrade/sql/6.0.0/sqlite3/seahub.sql b/scripts/upgrade/sql/6.0.0/sqlite3/seahub.sql deleted file mode 100644 index 46bb396d..00000000 --- a/scripts/upgrade/sql/6.0.0/sqlite3/seahub.sql +++ /dev/null @@ -1,24 +0,0 @@ -CREATE TABLE IF NOT EXISTS "base_filecomment" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "repo_id" varchar(36) NOT NULL, "parent_path" text NOT NULL, "repo_id_parent_path_md5" varchar(100) NOT NULL, "item_name" text NOT NULL, "author" varchar(255) NOT NULL, "comment" text NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL); -CREATE INDEX IF NOT EXISTS "base_filecomment_02bd92fa" ON "base_filecomment" ("author"); -CREATE INDEX IF NOT EXISTS "base_filecomment_9a8c79bf" ON "base_filecomment" ("repo_id"); -CREATE INDEX IF NOT EXISTS "base_filecomment_c5bf47d4" ON "base_filecomment" ("repo_id_parent_path_md5"); - -CREATE TABLE IF NOT EXISTS "termsandconditions_termsandconditions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "slug" varchar(50) NOT NULL, "name" text NOT NULL, "version_number" decimal NOT NULL, "text" text NULL, "info" text NULL, "date_active" datetime NULL, "date_created" datetime NOT NULL); -CREATE INDEX IF NOT EXISTS "termsandconditions_termsandconditions_2dbcba41" ON "termsandconditions_termsandconditions" ("slug"); - -CREATE TABLE IF NOT EXISTS "termsandconditions_usertermsandconditions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255) NOT NULL, "ip_address" char(39) NULL, "date_accepted" datetime NOT NULL, "terms_id" integer NOT NULL REFERENCES "termsandconditions_termsandconditions" ("id"), UNIQUE ("username", "terms_id")); -CREATE INDEX IF NOT EXISTS "termsandconditions_usertermsandconditions_2ab34720" ON "termsandconditions_usertermsandconditions" ("terms_id"); - -CREATE TABLE IF NOT EXISTS "two_factor_phonedevice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user" varchar(255) NOT NULL UNIQUE, "name" varchar(64) NOT NULL, "confirmed" bool NOT NULL, "number" varchar(40) NOT NULL, "key" varchar(40) NOT NULL, "method" varchar(4) NOT NULL); -CREATE TABLE IF NOT EXISTS "two_factor_staticdevice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user" varchar(255) NOT NULL UNIQUE, "name" varchar(64) NOT NULL, "confirmed" bool NOT NULL); -CREATE TABLE IF NOT EXISTS "two_factor_statictoken" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "token" varchar(16) NOT NULL, "device_id" integer NOT NULL REFERENCES "two_factor_staticdevice" ("id")); -CREATE TABLE IF NOT EXISTS "two_factor_totpdevice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user" varchar(255) NOT NULL UNIQUE, "name" varchar(64) NOT NULL, "confirmed" bool NOT NULL, "key" varchar(80) NOT NULL, "step" smallint unsigned NOT NULL, "t0" bigint NOT NULL, "digits" smallint unsigned NOT NULL, "tolerance" smallint unsigned NOT NULL, "drift" smallint NOT NULL, "last_t" bigint NOT NULL); -CREATE INDEX IF NOT EXISTS "two_factor_statictoken_94a08da1" ON "two_factor_statictoken" ("token"); -CREATE INDEX IF NOT EXISTS "two_factor_statictoken_9379346c" ON "two_factor_statictoken" ("device_id"); - -CREATE TABLE IF NOT EXISTS "invitations_invitation" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "token" varchar(40) NOT NULL, "inviter" varchar(255) NOT NULL, "accepter" varchar(255) NOT NULL, "invite_time" datetime NOT NULL, "accept_time" datetime NULL, "invite_type" varchar(20) NOT NULL, "expire_time" datetime NOT NULL); -CREATE INDEX IF NOT EXISTS "invitations_invitation_94a08da1" ON "invitations_invitation" ("token"); -CREATE INDEX IF NOT EXISTS "invitations_invitation_d5dd16f8" ON "invitations_invitation" ("inviter"); - -ALTER TABLE api2_tokenv2 ADD COLUMN wiped_at datetime DEFAULT NULL; -ALTER TABLE api2_tokenv2 ADD COLUMN created_at datetime NOT NULL DEFAULT '1970-01-01 00:00:00'; diff --git a/scripts/upgrade/upgrade_1.2_1.3.sh b/scripts/upgrade/upgrade_1.2_1.3.sh deleted file mode 100755 index a689434d..00000000 --- a/scripts/upgrade/upgrade_1.2_1.3.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.2.0 -current_version=1.3.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "manage.py run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -# run django syncdb command -echo "------------------------------" -echo "updating seahub database ... " -echo -manage_py=${INSTALLPATH}/seahub/manage.py -pushd "${INSTALLPATH}/seahub" 2>/dev/null 1>&2 -if ! $PYTHON manage.py syncdb 2>/dev/null 1>&2; then - echo "failed" - exit -1 -fi -popd 2>/dev/null 1>&2 - -echo "DONE" -echo "------------------------------" -echo - -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo \ No newline at end of file diff --git a/scripts/upgrade/upgrade_1.3_1.4.sh b/scripts/upgrade/upgrade_1.3_1.4.sh deleted file mode 100755 index 36ff6d71..00000000 --- a/scripts/upgrade/upgrade_1.3_1.4.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.3 -current_version=1.4.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "manage.py run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo - -# update database -echo "------------------------------" -echo "updating seahub database ... " -echo - -db_update_py=$UPGRADE_DIR/db_update_1.3_1.4.py -if ! $PYTHON $db_update_py $default_seahub_db 1>/dev/null; then - echo "failed" -fi - -echo "DONE" -echo "------------------------------" -echo diff --git a/scripts/upgrade/upgrade_1.4_1.5.sh b/scripts/upgrade/upgrade_1.4_1.5.sh deleted file mode 100755 index d5e6b33e..00000000 --- a/scripts/upgrade/upgrade_1.4_1.5.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.4 -current_version=1.5 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "manage.py run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo \ No newline at end of file diff --git a/scripts/upgrade/upgrade_1.5_1.6.sh b/scripts/upgrade/upgrade_1.5_1.6.sh deleted file mode 100755 index ee265028..00000000 --- a/scripts/upgrade/upgrade_1.5_1.6.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.5 -current_version=1.6 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "manage.py run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo - -echo -echo "------------------------------" -echo "Updating seahub database ..." -echo - -seahub_db=${TOPDIR}/seahub.db -seahub_sql=${UPGRADE_DIR}/sql/1.6.0/sqlite3/seahub.sql -if ! sqlite3 "${seahub_db}" < "${seahub_sql}"; then - echo "Failed to update seahub database" - exit 1 -fi - -echo "DONE" -echo "------------------------------" -echo \ No newline at end of file diff --git a/scripts/upgrade/upgrade_1.6_1.7.sh b/scripts/upgrade/upgrade_1.6_1.7.sh deleted file mode 100755 index 72dd3ffa..00000000 --- a/scripts/upgrade/upgrade_1.6_1.7.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.6 -current_version=1.7 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo - -echo -echo "------------------------------" -echo "Updating seafile/seahub database ..." -echo - -seahub_db=${TOPDIR}/seahub.db -seahub_sql=${UPGRADE_DIR}/sql/1.7.0/sqlite3/seahub.sql -if ! sqlite3 "${seahub_db}" < "${seahub_sql}"; then - echo "Failed to update seahub database" - exit 1 -fi - -seafile_db=${seafile_data_dir}/seafile.db -seafile_sql=${UPGRADE_DIR}/sql/1.7.0/sqlite3/seafile.sql -if ! sqlite3 "${seafile_db}" < "${seafile_sql}"; then - echo "Failed to update seafile database" - exit 1 -fi - -echo "DONE" -echo "------------------------------" -echo diff --git a/scripts/upgrade/upgrade_1.7_1.8.sh b/scripts/upgrade/upgrade_1.7_1.8.sh deleted file mode 100755 index c68094d5..00000000 --- a/scripts/upgrade/upgrade_1.7_1.8.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.7 -current_version=1.8 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo - -echo -echo "------------------------------" -echo "Updating seafile/seahub database ..." -echo - -seahub_db=${TOPDIR}/seahub.db -seahub_sql=${UPGRADE_DIR}/sql/1.8.0/sqlite3/seahub.sql -if ! sqlite3 "${seahub_db}" < "${seahub_sql}"; then - echo "Failed to update seahub database" - exit 1 -fi - -echo "DONE" -echo "------------------------------" -echo diff --git a/scripts/upgrade/upgrade_1.8_2.0.sh b/scripts/upgrade/upgrade_1.8_2.0.sh deleted file mode 100755 index 71eb2ae2..00000000 --- a/scripts/upgrade/upgrade_1.8_2.0.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=1.8 -current_version=2.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi -} - -check_python_executable -read_seafile_data_dir - -export SEAFILE_CONF_DIR=$seafile_data_dir - -# test whether seafile server has been stopped. -if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 -fi - -echo -echo "------------------------------" -echo "migrating avatars ..." -echo -media_dir=${INSTALLPATH}/seahub/media -orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars -dest_avatar_dir=${TOPDIR}/seahub-data/avatars - -# move "media/avatars" directory outside -if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars ${media_dir} - -elif [[ ! -L ${orig_avatar_dir}} ]]; then - mv ${orig_avatar_dir}/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars ${media_dir} -fi - -echo "DONE" -echo "------------------------------" -echo - -echo -echo "------------------------------" -echo "Updating seafile/seahub database ..." -echo - -seahub_db=${TOPDIR}/seahub.db -seahub_sql=${UPGRADE_DIR}/sql/2.0.0/sqlite3/seahub.sql -if ! sqlite3 "${seahub_db}" < "${seahub_sql}"; then - echo "Failed to update seahub database" - exit 1 -fi - -add_collate_script=${UPGRADE_DIR}/add_collate.sh -echo "fix seafile database case issues..." -if ! ${add_collate_script} ${default_ccnet_conf_dir} ${seafile_data_dir} ${seahub_db}; then - echo "Failed." - exit 1 -fi - -echo "DONE" -echo "------------------------------" -echo diff --git a/scripts/upgrade/upgrade_2.0_2.1.sh b/scripts/upgrade/upgrade_2.0_2.1.sh deleted file mode 100755 index 5f5dbb4e..00000000 --- a/scripts/upgrade/upgrade_2.0_2.1.sh +++ /dev/null @@ -1,206 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH - -prev_version=2.0 -current_version=2.1 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 2.1.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - seafile_server_symlink=${TOPDIR}/seafile-server-latest - if [[ -L "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function gen_seafdav_conf() { - echo - echo "generating seafdav.conf ..." - echo - seafdav_conf=${default_conf_dir}/seafdav.conf - mkdir -p "${default_conf_dir}" - if ! $(cat > "${seafdav_conf}" </dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 2.2.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - seafile_server_symlink=${TOPDIR}/seafile-server-latest - if [[ -L "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -export SEAFILE_CONF_DIR=$seafile_data_dir - -migrate_avatars; - -update_database; - -upgrade_seafile_server_latest_symlink; - - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_2.2_3.0.sh b/scripts/upgrade/upgrade_2.2_3.0.sh deleted file mode 100755 index d0643d3a..00000000 --- a/scripts/upgrade/upgrade_2.2_3.0.sh +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=2.2 -current_version=3.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_fcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 3.0.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - seafile_server_symlink=${TOPDIR}/seafile-server-latest - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function migrate_seafile_data_format() { - seaf_migrate=${INSTALLPATH}/seafile/bin/seaf-migrate - echo - echo "now migrating seafile data to 3.0 format" - echo - if ! LD_LIBRARY_PATH=${SEAFILE_LD_LIBRARY_PATH} ${seaf_migrate} \ - -c "${default_ccnet_conf_dir}" -d "${seafile_data_dir}"; then - echo - echo "Failed to migrate seafile data to 3.0 format" - echo - exit 1; - fi - echo - echo "Successfully migrated seafile data to 3.0 format" - echo -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -export SEAFILE_CONF_DIR=$seafile_data_dir - -migrate_seafile_data_format; - -migrate_avatars; - -update_database; - -upgrade_seafile_server_latest_symlink; - - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_3.0_3.1.sh b/scripts/upgrade/upgrade_3.0_3.1.sh deleted file mode 100755 index d3b7f4f2..00000000 --- a/scripts/upgrade/upgrade_3.0_3.1.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=3.0 -current_version=3.1 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 3.1.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -migrate_avatars; - -update_database; - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_3.1_4.0.sh b/scripts/upgrade/upgrade_3.1_4.0.sh deleted file mode 100755 index 6a6bc9a9..00000000 --- a/scripts/upgrade/upgrade_3.1_4.0.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=3.1 -current_version=4.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 4.0.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -migrate_avatars; - -update_database; - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_4.0_4.1.sh b/scripts/upgrade/upgrade_4.0_4.1.sh deleted file mode 100755 index e3eb848d..00000000 --- a/scripts/upgrade/upgrade_4.0_4.1.sh +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data -seahub_settings_py=${TOPDIR}/seahub_settings.py - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=4.0 -current_version=4.1 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 4.1.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function fix_mysql_user() { - - fix_script=${UPGRADE_DIR}/fix_mysql_user.py - if ! $PYTHON "${fix_script}"; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -fix_mysql_user; -update_database; - -migrate_avatars; - - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - -chmod 0600 "$seahub_settings_py" -chmod 0700 "$seafile_data_dir" -chmod 0700 "$default_ccnet_conf_dir" -chmod 0700 "$default_conf_dir" - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_4.1_4.2.sh b/scripts/upgrade/upgrade_4.1_4.2.sh deleted file mode 100755 index f1754387..00000000 --- a/scripts/upgrade/upgrade_4.1_4.2.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data -seahub_settings_py=${TOPDIR}/seahub_settings.py - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=4.1 -current_version=4.2 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 4.2.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -update_database; - -migrate_avatars; - - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_4.2_4.3.sh b/scripts/upgrade/upgrade_4.2_4.3.sh deleted file mode 100755 index b79035d2..00000000 --- a/scripts/upgrade/upgrade_4.2_4.3.sh +++ /dev/null @@ -1,226 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data -seahub_settings_py=${TOPDIR}/seahub_settings.py - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=4.2 -current_version=4.3 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 4.3.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -function regenerate_secret_key() { - regenerate_secret_key_script=$UPGRADE_DIR/regenerate_secret_key.sh - if ! $regenerate_secret_key_script ; then - echo "Failed to regenerate the seahub secret key" - exit 1 - fi -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -regenerate_secret_key; - -update_database; - -migrate_avatars; - - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_4.3_4.4.sh b/scripts/upgrade/upgrade_4.3_4.4.sh deleted file mode 100755 index c92b5b37..00000000 --- a/scripts/upgrade/upgrade_4.3_4.4.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_seafile_data_dir=${TOPDIR}/seafile-data -default_seahub_db=${TOPDIR}/seahub.db -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data -seahub_settings_py=${TOPDIR}/seahub_settings.py - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=4.3 -current_version=4.4 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 4.4.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -update_database; - -migrate_avatars; - - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/upgrade_4.4_5.0.sh b/scripts/upgrade/upgrade_4.4_5.0.sh deleted file mode 100755 index dbec11d0..00000000 --- a/scripts/upgrade/upgrade_4.4_5.0.sh +++ /dev/null @@ -1,243 +0,0 @@ -#!/bin/bash - -SCRIPT=$(readlink -f "$0") # haiwen/seafile-server-1.3.0/upgrade/upgrade_xx_xx.sh -UPGRADE_DIR=$(dirname "$SCRIPT") # haiwen/seafile-server-1.3.0/upgrade/ -INSTALLPATH=$(dirname "$UPGRADE_DIR") # haiwen/seafile-server-1.3.0/ -TOPDIR=$(dirname "${INSTALLPATH}") # haiwen/ -default_ccnet_conf_dir=${TOPDIR}/ccnet -default_conf_dir=${TOPDIR}/conf -seafile_server_symlink=${TOPDIR}/seafile-server-latest -seahub_data_dir=${TOPDIR}/seahub-data -seahub_settings_py=${TOPDIR}/seahub_settings.py - -manage_py=${INSTALLPATH}/seahub/manage.py - -export CCNET_CONF_DIR=${default_ccnet_conf_dir} -export SEAFILE_CENTRAL_CONF_DIR=${default_conf_dir} -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.6/site-packages:${INSTALLPATH}/seafile/lib64/python2.6/site-packages:${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seahub/thirdpart:$PYTHONPATH -export PYTHONPATH=${INSTALLPATH}/seafile/lib/python2.7/site-packages:${INSTALLPATH}/seafile/lib64/python2.7/site-packages:$PYTHONPATH -export SEAFILE_LD_LIBRARY_PATH=${INSTALLPATH}/seafile/lib/:${INSTALLPATH}/seafile/lib64:${LD_LIBRARY_PATH} - -prev_version=4.4 -current_version=5.0 - -echo -echo "-------------------------------------------------------------" -echo "This script would upgrade your seafile server from ${prev_version} to ${current_version}" -echo "Press [ENTER] to contiune" -echo "-------------------------------------------------------------" -echo -read dummy - -function check_python_executable() { - if [[ "$PYTHON" != "" && -x $PYTHON ]]; then - return 0 - fi - - if which python2.7 2>/dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - elif which python2.6 2>/dev/null 1>&2; then - PYTHON=python2.6 - elif which python26 2>/dev/null 1>&2; then - PYTHON=python26 - else - echo - echo "Can't find a python executable of version 2.6 or above in PATH" - echo "Install python 2.6+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 5.0.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -function regenerate_secret_key() { - regenerate_secret_key_script=$UPGRADE_DIR/regenerate_secret_key.sh - if ! $regenerate_secret_key_script ; then - echo "Failed to regenerate the seahub secret key" - exit 1 - fi -} - -# copy ccnet.conf/seafile.conf etc. to conf/ dir, and make the original files read-only -function copy_confs_to_central_conf_dir() { - local confs=( - $default_ccnet_conf_dir/ccnet.conf - $seafile_data_dir/seafile.conf - $seahub_settings_py - ) - for conffile in ${confs[*]}; do - if grep -q "This file has been moved" $conffile; then - continue - fi - cp $conffile $conffile.seafile-5.0.0-bak - cp -av $conffile $default_conf_dir/ - cat >$conffile</dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 \ - || pgrep -f "seahub.wsgi:application" 2>/dev/null 1>&2; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 5.1.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -function regenerate_secret_key() { - regenerate_secret_key_script=$UPGRADE_DIR/regenerate_secret_key.sh - if ! $regenerate_secret_key_script ; then - echo "Failed to regenerate the seahub secret key" - exit 1 - fi -} - -# copy ccnet.conf/seafile.conf etc. to conf/ dir, and make the original files read-only -function copy_confs_to_central_conf_dir() { - local confs=( - $default_ccnet_conf_dir/ccnet.conf - $seafile_data_dir/seafile.conf - $seahub_settings_py - ) - for conffile in ${confs[*]}; do - if grep -q "This file has been moved" $conffile; then - continue - fi - cp $conffile $conffile.seafile-5.0.0-bak - cp -av $conffile $default_conf_dir/ - cat >$conffile</dev/null 1>&2; then - PYTHON=python2.7 - elif which python27 2>/dev/null 1>&2; then - PYTHON=python27 - else - echo - echo "Can't find a python executable of version 2.7 or above in PATH" - echo "Install python 2.7+ before continue." - echo "Or if you installed it in a non-standard PATH, set the PYTHON enviroment varirable to it" - echo - exit 1 - fi -} - -function read_seafile_data_dir () { - seafile_ini=${default_ccnet_conf_dir}/seafile.ini - if [[ ! -f ${seafile_ini} ]]; then - echo "${seafile_ini} not found. Now quit" - exit 1 - fi - seafile_data_dir=$(cat "${seafile_ini}") - if [[ ! -d ${seafile_data_dir} ]]; then - echo "Your seafile server data directory \"${seafile_data_dir}\" is invalid or doesn't exits." - echo "Please check it first, or create this directory yourself." - echo "" - exit 1; - fi - - export SEAFILE_CONF_DIR=$seafile_data_dir -} - -function ensure_server_not_running() { - # test whether seafile server has been stopped. - if pgrep seaf-server 2>/dev/null 1>&2 ; then - echo - echo "seafile server is still running !" - echo "stop it using scripts before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} run_gunicorn" 2>/dev/null 1>&2 \ - || pgrep -f "seahub.wsgi:application" 2>/dev/null 1>&2; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - elif pgrep -f "${manage_py} runfcgi" 2>/dev/null 1>&2 ; then - echo - echo "seahub server is still running !" - echo "stop it before upgrade." - echo - exit 1 - fi -} - -function migrate_avatars() { - echo - echo "migrating avatars ..." - echo - media_dir=${INSTALLPATH}/seahub/media - orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars - dest_avatar_dir=${TOPDIR}/seahub-data/avatars - - # move "media/avatars" directory outside - if [[ ! -d ${dest_avatar_dir} ]]; then - mkdir -p "${TOPDIR}/seahub-data" - mv "${orig_avatar_dir}" "${dest_avatar_dir}" 2>/dev/null 1>&2 - ln -s ../../../seahub-data/avatars "${media_dir}" - - elif [[ ! -L ${orig_avatar_dir} ]]; then - mv "${orig_avatar_dir}"/* "${dest_avatar_dir}" 2>/dev/null 1>&2 - rm -rf "${orig_avatar_dir}" - ln -s ../../../seahub-data/avatars "${media_dir}" - fi - echo "Done" -} - -function update_database() { - echo - echo "Updating seafile/seahub database ..." - echo - - db_update_helper=${UPGRADE_DIR}/db_update_helper.py - if ! $PYTHON "${db_update_helper}" 6.0.0; then - echo - echo "Failed to upgrade your database" - echo - exit 1 - fi - echo "Done" -} - -function upgrade_seafile_server_latest_symlink() { - # update the symlink seafile-server to the new server version - if [[ -L "${seafile_server_symlink}" || ! -e "${seafile_server_symlink}" ]]; then - echo - printf "updating \033[33m${seafile_server_symlink}\033[m symbolic link to \033[33m${INSTALLPATH}\033[m ...\n\n" - echo - if ! rm -f "${seafile_server_symlink}"; then - echo "Failed to remove ${seafile_server_symlink}" - echo - exit 1; - fi - - if ! ln -s "$(basename ${INSTALLPATH})" "${seafile_server_symlink}"; then - echo "Failed to update ${seafile_server_symlink} symbolic link." - echo - exit 1; - fi - fi -} - -function make_media_custom_symlink() { - media_symlink=${INSTALLPATH}/seahub/media/custom - if [[ -L "${media_symlink}" ]]; then - return - - elif [[ ! -e "${media_symlink}" ]]; then - ln -s ../../../seahub-data/custom "${media_symlink}" - return - - - elif [[ -d "${media_symlink}" ]]; then - cp -rf "${media_symlink}" "${seahub_data_dir}/" - rm -rf "${media_symlink}" - ln -s ../../../seahub-data/custom "${media_symlink}" - fi - -} - -function move_old_customdir_outside() { - # find the path of the latest seafile server folder - if [[ -L ${seafile_server_symlink} ]]; then - latest_server=$(readlink -f "${seafile_server_symlink}") - else - return - fi - - old_customdir=${latest_server}/seahub/media/custom - - # old customdir is already a symlink, do nothing - if [[ -L "${old_customdir}" ]]; then - return - fi - - # old customdir does not exist, do nothing - if [[ ! -e "${old_customdir}" ]]; then - return - fi - - # media/custom exist and is not a symlink - cp -rf "${old_customdir}" "${seahub_data_dir}/" -} - -################# -# The main execution flow of the script -################ - -check_python_executable; -read_seafile_data_dir; -ensure_server_not_running; - -update_database; -migrate_avatars; - -move_old_customdir_outside; -make_media_custom_symlink; -upgrade_seafile_server_latest_symlink; - -echo -echo "-----------------------------------------------------------------" -echo "Upgraded your seafile server successfully." -echo "-----------------------------------------------------------------" -echo diff --git a/scripts/upgrade/win32/py/add_collate.py b/scripts/upgrade/win32/py/add_collate.py deleted file mode 100644 index b861d2df..00000000 --- a/scripts/upgrade/win32/py/add_collate.py +++ /dev/null @@ -1,180 +0,0 @@ -# coding: UTF-8 - -''' -Database Upgrade scripts for seafile windows server 2.0.2 -''' - -import os -import sys -import re -import sqlite3 -import logging -import shutil - -from upgrade_common import seafserv_dir, ccnet_dir, seafile_dir - -# seafserv_dir = '/tmp/haiwen' -# ccnet_dir = os.path.join(seafserv_dir, 'ccnet') -# seafile_dir = os.path.join(seafserv_dir, 'seafile-data') - -def error_exit(msg): - print 'Error: %s' % msg - sys.exit(1) - -class Pattern(object): - def __init__(self, old, new): - self.old = old - self.new = new - -class AbstractDBUpdater(object): - '''Base class to update a database''' - - name = '' - patterns = [] - - def __init__(self, db_path): - self.db_path = db_path - self.lines = [] - self.tmp = self.db_path + '.tmp' - - try: - if os.path.exists(self.tmp): - os.remove(self.tmp) - except: - logging.exception('Error when delete temporary database %s' % self.tmp) - sys.exit(1) - - def do_update(self): - print 'updating %s' % self.name - self.dump_db() - self.update_schema() - self.write_db() - - def dump_db(self): - '''Dump all the schema and data''' - with sqlite3.connect(self.db_path) as conn: - for line in conn.iterdump(): - self.lines.append(line.replace('\n', ' ')) - - def update_schema(self): - '''Update schema of tables in this database to add "collate nocase"''' - new_lines = [] - for line in self.lines: - new_line = line - if line.lower().startswith("create table"): - for pattern in self.patterns: - new_line = re.sub(pattern.old, pattern.new, new_line) - new_lines.append(new_line) - - self.lines = new_lines - - def write_db(self): - with sqlite3.connect(self.tmp) as conn: - cursor = conn.cursor() - for line in self.lines: - if line.lower().strip().strip(';') in ('begin transaction', 'commit'): - continue - cursor.execute(line) - - shutil.copy(self.tmp, self.db_path) - - try: - if os.path.exists(self.tmp): - os.remove(self.tmp) - except: - pass - -class CcnetUserDBUpdater(AbstractDBUpdater): - name = 'user database' - patterns = [ - Pattern(r'(CREATE TABLE EmailUser.*)email TEXT,(.*)', - r'\1email TEXT COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE Binding.*)email TEXT,(.*)', - r'\1email TEXT COLLATE NOCASE,\2'), - ] - - def __init__(self, user_db): - AbstractDBUpdater.__init__(self, user_db) - -class CcnetGroupDBUpdater(AbstractDBUpdater): - name = 'group database' - patterns = [ - Pattern(r'(CREATE TABLE `Group`.*)`creator_name` VARCHAR\(255\),(.*)', - r'\1`creator_name` VARCHAR(255) COLLATE NOCASE,\2'), - Pattern(r'(CREATE TABLE `GroupUser`.*)`user_name` VARCHAR\(255\),(.*)', - r'\1`user_name` VARCHAR(255) COLLATE NOCASE,\2'), - ] - - def __init__(self, group_db): - AbstractDBUpdater.__init__(self, group_db) - -class SeafileDBUpdater(AbstractDBUpdater): - name = 'seafile database' - patterns = [ - Pattern(r'(CREATE TABLE RepoOwner.*)owner_id TEXT(.*)', - r'\1owner_id TEXT COLLATE NOCASE\2'), - - Pattern(r'(CREATE TABLE RepoGroup.*)user_name TEXT,(.*)', - r'\1user_name TEXT COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE RepoUserToken.*)email VARCHAR\(255\),(.*)', - r'\1email VARCHAR(255) COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE UserQuota.*)user VARCHAR\(255\),(.*)', - r'\1user VARCHAR(255) COLLATE NOCASE,\2' ), - - Pattern(r'(CREATE TABLE SharedRepo.*)from_email VARCHAR\(512\), to_email VARCHAR\(512\),(.*)', - r'\1from_email VARCHAR(512), to_email VARCHAR(512) COLLATE NOCASE,\2'), - ] - - def __init__(self, seafile_db): - AbstractDBUpdater.__init__(self, seafile_db) - -class SeahubDBUpdater(AbstractDBUpdater): - name = 'seahub database' - patterns = [ - Pattern(r'(CREATE TABLE "notifications_usernotification".*)"to_user" varchar\(255\) NOT NULL,(.*)', - r'\1"to_user" varchar(255) NOT NULL COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "profile_profile".*)"user" varchar\(75\) NOT NULL UNIQUE,(.*)', - r'\1"user" varchar(75) NOT NULL UNIQUE COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "share_fileshare".*)"username" varchar\(255\) NOT NULL,(.*)', - r'\1"username" varchar(255) NOT NULL COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "api2_token".*)"user" varchar\(255\) NOT NULL UNIQUE,(.*)', - r'\1"user" varchar(255) NOT NULL UNIQUE COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "wiki_personalwiki".*)"username" varchar\(255\) NOT NULL UNIQUE,(.*)', - r'\1"username" varchar(255) NOT NULL UNIQUE COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "message_usermessage".*)"from_email" varchar\(75\) NOT NULL,\s*"to_email" varchar\(75\) NOT NULL,(.*)', - r'\1"from_email" varchar(75) NOT NULL COLLATE NOCASE, "to_email" varchar(75) NOT NULL COLLATE NOCASE,\2'), - - Pattern(r'(CREATE TABLE "avatar_avatar".*)"emailuser" varchar\(255\) NOT NULL,(.*)', - r'\1"emailuser" varchar(255) NOT NULL COLLATE NOCASE,\2'), - ] - - def __init__(self, seahub_db): - AbstractDBUpdater.__init__(self, seahub_db) - -def upgrade_collate(): - '''Update database schema to add "COLLATE NOCASE" of email field''' - user_db = os.path.join(ccnet_dir, 'PeerMgr', 'usermgr.db') - group_db = os.path.join(ccnet_dir, 'GroupMgr', 'groupmgr.db') - seafile_db = os.path.join(seafile_dir, 'seafile.db') - seahub_db = os.path.join(seafserv_dir, 'seahub.db') - updaters = [ - CcnetUserDBUpdater(user_db), - CcnetGroupDBUpdater(group_db), - SeafileDBUpdater(seafile_db), - SeahubDBUpdater(seahub_db), - ] - - for updater in updaters: - updater.do_update() - - -if __name__ == '__main__': - upgrade_collate() diff --git a/scripts/upgrade/win32/py/gc.py b/scripts/upgrade/win32/py/gc.py deleted file mode 100644 index c609f4a1..00000000 --- a/scripts/upgrade/win32/py/gc.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: UTF-8 - -import os -import sys -import traceback -import ccnet - -from upgrade_common import install_path, seafile_dir, ccnet_dir, run_argv, ensure_server_not_running, central_config_dir - - -def call_seafserv_gc(): - args = [ - os.path.join(install_path, 'seafile', 'bin', 'seafserv-gc.exe'), - '-c', - ccnet_dir, - '-d', - seafile_dir, - '-F', - central_config_dir, - ] - - print 'Starting gc...\n' - run_argv(args) - - -def main(): - try: - ensure_server_not_running() - call_seafserv_gc() - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_1.7_1.8.py b/scripts/upgrade/win32/py/upgrade_1.7_1.8.py deleted file mode 100644 index 23bd1dc7..00000000 --- a/scripts/upgrade/win32/py/upgrade_1.7_1.8.py +++ /dev/null @@ -1,17 +0,0 @@ -# coding: UTF-8 - -from upgrade_common import upgrade_db - -def main(): - try: - upgrade_db('1.8.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_1.8_2.0.py b/scripts/upgrade/win32/py/upgrade_1.8_2.0.py deleted file mode 100644 index 99aac3dd..00000000 --- a/scripts/upgrade/win32/py/upgrade_1.8_2.0.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -from upgrade_common import upgrade_db -from add_collate import upgrade_collate - -def main(): - try: - upgrade_db('2.0.0') - upgrade_collate() - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_2.0_2.1.py b/scripts/upgrade/win32/py/upgrade_2.0_2.1.py deleted file mode 100644 index a7f76e18..00000000 --- a/scripts/upgrade/win32/py/upgrade_2.0_2.1.py +++ /dev/null @@ -1,31 +0,0 @@ -# coding: UTF-8 - -import os -import glob -import shutil - -from upgrade_common import install_path, seafile_dir, upgrade_db - -def copy_template_library(): - src_docs_dir = os.path.join(install_path, 'seafile', 'docs') - library_template_dir= os.path.join(seafile_dir, 'library-template') - if not os.path.exists(library_template_dir): - os.mkdir(library_template_dir) - - for fn in glob.glob(os.path.join(src_docs_dir, '*.doc')): - shutil.copy(fn, library_template_dir) - -def main(): - try: - upgrade_db('2.1.0') - copy_template_library() - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_2.1_3.0.py b/scripts/upgrade/win32/py/upgrade_2.1_3.0.py deleted file mode 100644 index dc11f0b4..00000000 --- a/scripts/upgrade/win32/py/upgrade_2.1_3.0.py +++ /dev/null @@ -1,32 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def do_migrate_storage(): - '''use seaf-migrate to migrate objects from the 2.1 layout to 3.0 layout''' - args = [ - os.path.join(install_path, 'seafile', 'bin', 'seaf-migrate.exe'), - '-c', ccnet_dir, - '-d', seafile_dir, - ] - - print 'Starting migrate your data...\n' - if run_argv(args) != 0: - raise Exception('failed to migrate seafile data to 3.0 format') - -def main(): - try: - upgrade_db('3.0.0') - do_migrate_storage() - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_3.0_3.1.py b/scripts/upgrade/win32/py/upgrade_3.0_3.1.py deleted file mode 100644 index 8bb2b89b..00000000 --- a/scripts/upgrade/win32/py/upgrade_3.0_3.1.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def main(): - try: - upgrade_db('3.1.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_3.1_4.0.py b/scripts/upgrade/win32/py/upgrade_3.1_4.0.py deleted file mode 100644 index acdda536..00000000 --- a/scripts/upgrade/win32/py/upgrade_3.1_4.0.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def main(): - try: - upgrade_db('4.0.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_4.0_4.1.py b/scripts/upgrade/win32/py/upgrade_4.0_4.1.py deleted file mode 100644 index 6eb3f9e2..00000000 --- a/scripts/upgrade/win32/py/upgrade_4.0_4.1.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def main(): - try: - upgrade_db('4.1.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_4.1_4.2.py b/scripts/upgrade/win32/py/upgrade_4.1_4.2.py deleted file mode 100644 index 43d9986b..00000000 --- a/scripts/upgrade/win32/py/upgrade_4.1_4.2.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def main(): - try: - upgrade_db('4.2.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_4.2_4.3.py b/scripts/upgrade/win32/py/upgrade_4.2_4.3.py deleted file mode 100644 index 17829180..00000000 --- a/scripts/upgrade/win32/py/upgrade_4.2_4.3.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: UTF-8 - -import os - -from upgrade_common import install_path, ccnet_dir, seafile_dir, upgrade_db, run_argv - -def main(): - try: - upgrade_db('4.3.0') - except Exception, e: - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_4.3_5.0.py b/scripts/upgrade/win32/py/upgrade_4.3_5.0.py deleted file mode 100644 index 0c807314..00000000 --- a/scripts/upgrade/win32/py/upgrade_4.3_5.0.py +++ /dev/null @@ -1,49 +0,0 @@ -# coding: UTF-8 - -import shutil -import os -import traceback -from os.path import abspath, basename, exists, dirname, join -from upgrade_common import (install_path, seafserv_dir, ccnet_dir, seafile_dir, - upgrade_db, run_argv) - - -def move_all_conf_to_central_config_dir(): - central_config_dir = join(seafserv_dir, 'conf') - if not exists(central_config_dir): - os.mkdir(central_config_dir) - files = [ - join(ccnet_dir, 'ccnet.conf'), - join(seafile_dir, 'seafile.conf'), - join(seafserv_dir, 'seahub_settings.py'), - ] - for fn in files: - if not exists(fn): - raise RuntimeError('file %s does not exist' % fn) - for fn in files: - with open(fn, 'r') as fp: - if 'This file has been moved' in fp.read(): - return - dstfile = join(central_config_dir, basename(fn)) - shutil.copyfile(fn, dstfile) - with open(fn, 'w') as fp: - content = '# This file has been moved to %s in seafile 5.0.0' % dstfile - fp.write(content) - - -def main(): - try: - upgrade_db('5.0.0') - move_all_conf_to_central_config_dir() - except Exception, e: - traceback.print_exc() - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_5.0_5.1.py b/scripts/upgrade/win32/py/upgrade_5.0_5.1.py deleted file mode 100644 index 298c07e9..00000000 --- a/scripts/upgrade/win32/py/upgrade_5.0_5.1.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: UTF-8 - -import shutil -import os -import traceback -from os.path import abspath, basename, exists, dirname, join -from upgrade_common import (install_path, seafserv_dir, ccnet_dir, seafile_dir, - upgrade_db, run_argv) - -def main(): - try: - upgrade_db('5.1.0') - except Exception, e: - traceback.print_exc() - print 'Error:\n', e - else: - print '\ndone\n' - finally: - print '\nprint ENTER to exit\n' - raw_input() - - -if __name__ == '__main__': - main() diff --git a/scripts/upgrade/win32/py/upgrade_common.py b/scripts/upgrade/win32/py/upgrade_common.py deleted file mode 100644 index 5698b6fd..00000000 --- a/scripts/upgrade/win32/py/upgrade_common.py +++ /dev/null @@ -1,155 +0,0 @@ -# coding: UTF-8 - -import os -import sys -import sqlite3 -import subprocess -import ccnet -import glob - - -# Directory layout: -# -# - SeafileProgram/ -# - seafserv.ini -# - seafile-server-1.7.0/ -# - seafile-server-1.8.0/ -# - seafile-server-1.9.0/ -# - upgrade/ -# - sql/ -# - 1.8.0/ -# - sqlite3 -# - ccnet.sql -# - seafile.sql -# - seahub.sql -# - upgrade_1.7_1.8.bat -# - upgrade_1.8_1.9.bat -# - py/ -# - upgrade_1.7_1.8.py -# - upgrade_1.8_1.9.py - -pyscript_dir = os.path.dirname(os.path.abspath(__file__)) -upgrade_dir = os.path.dirname(pyscript_dir) -sql_dir = os.path.join(upgrade_dir, 'sql') -install_path = os.path.dirname(upgrade_dir) -program_top_dir = os.path.dirname(install_path) - -seafserv_dir = '' -ccnet_dir = '' -seafile_dir = '' -central_config_dir = '' - -def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False): - '''Run a program and wait it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - -def error(message): - print message - sys.exit(1) - -def read_seafserv_dir(): - global seafserv_dir, ccnet_dir, seafile_dir, central_config_dir - seafserv_ini = os.path.join(program_top_dir, 'seafserv.ini') - if not os.path.exists(seafserv_ini): - error('%s not found' % seafserv_ini) - - with open(seafserv_ini, 'r') as fp: - seafserv_dir = fp.read().strip() - - ccnet_dir = os.path.join(seafserv_dir, 'ccnet') - seafile_dir = os.path.join(seafserv_dir, 'seafile-data') - central_config_dir = os.path.join(seafserv_dir, 'conf') - -def apply_sqls(db_path, sql_path): - with open(sql_path, 'r') as fp: - lines = fp.read().split(';') - - with sqlite3.connect(db_path) as conn: - for line in lines: - line = line.strip() - if not line: - continue - else: - conn.execute(line) - -def _get_ccnet_db(ccnet_dir, dbname): - dbs = ( - 'ccnet.db', - 'GroupMgr/groupmgr.db', - 'misc/config.db', - 'OrgMgr/orgmgr.db', - ) - for db in dbs: - if os.path.splitext(os.path.basename(db))[0] == dbname: - return os.path.join(ccnet_dir, db) - -def _handle_ccnet_sqls(version): - for sql_path in glob.glob(os.path.join(sql_dir, version, 'sqlite3', 'ccnet', '*.sql')): - dbname = os.path.splitext(os.path.basename(sql_path))[0] - apply_sqls(_get_ccnet_db(ccnet_dir, dbname), sql_path) - -def upgrade_db(version): - ensure_server_not_running() - print 'upgrading databases ...' - ccnet_db = os.path.join(ccnet_dir, 'ccnet.db') - seafile_db = os.path.join(seafile_dir, 'seafile.db') - seahub_db = os.path.join(seafserv_dir, 'seahub.db') - - def get_sql(prog): - ret = os.path.join(sql_dir, version, 'sqlite3', '%s.sql' % prog) - return ret - - ccnet_sql = get_sql('ccnet') - seafile_sql = get_sql('seafile') - seahub_sql = get_sql('seahub') - - if os.path.exists(ccnet_sql): - print ' upgrading ccnet databases ...' - apply_sqls(ccnet_db, ccnet_sql) - _handle_ccnet_sqls(version) - - if os.path.exists(seafile_sql): - print ' upgrading seafile databases ...' - apply_sqls(seafile_db, seafile_sql) - - if os.path.exists(seahub_sql): - print ' upgrading seahub databases ...' - apply_sqls(seahub_db, seahub_sql) - -def get_current_version(): - return os.path.basename(install_path).split('-')[-1] - -def ensure_server_not_running(): - if os.path.exists(os.path.join(central_config_dir, 'ccnet.conf')): - client = ccnet.SyncClient(ccnet_dir, - central_config_dir=central_config_dir) - else: - client = ccnet.SyncClient(ccnet_dir) - try: - client.connect_daemon() - except ccnet.NetworkError: - pass - else: - raise Exception('Seafile server is running! You must turn it off before running this script!') - - -read_seafserv_dir() diff --git a/scripts/upgrade/win32/upgrade_1.7_1.8.bat b/scripts/upgrade/win32/upgrade_1.7_1.8.bat deleted file mode 100644 index 058b6e08..00000000 --- a/scripts/upgrade/win32/upgrade_1.7_1.8.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_1.7_1.8.py diff --git a/scripts/upgrade/win32/upgrade_1.8_2.0.bat b/scripts/upgrade/win32/upgrade_1.8_2.0.bat deleted file mode 100644 index 1a9f09be..00000000 --- a/scripts/upgrade/win32/upgrade_1.8_2.0.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_1.8_2.0.py diff --git a/scripts/upgrade/win32/upgrade_2.0_2.1.bat b/scripts/upgrade/win32/upgrade_2.0_2.1.bat deleted file mode 100644 index 043be480..00000000 --- a/scripts/upgrade/win32/upgrade_2.0_2.1.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_2.0_2.1.py diff --git a/scripts/upgrade/win32/upgrade_2.1_3.0.bat b/scripts/upgrade/win32/upgrade_2.1_3.0.bat deleted file mode 100644 index cb07cabb..00000000 --- a/scripts/upgrade/win32/upgrade_2.1_3.0.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_2.1_3.0.py diff --git a/scripts/upgrade/win32/upgrade_3.0_3.1.bat b/scripts/upgrade/win32/upgrade_3.0_3.1.bat deleted file mode 100644 index a26c33c7..00000000 --- a/scripts/upgrade/win32/upgrade_3.0_3.1.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_3.0_3.1.py diff --git a/scripts/upgrade/win32/upgrade_3.1_4.0.bat b/scripts/upgrade/win32/upgrade_3.1_4.0.bat deleted file mode 100644 index 7b9afac7..00000000 --- a/scripts/upgrade/win32/upgrade_3.1_4.0.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_3.1_4.0.py diff --git a/scripts/upgrade/win32/upgrade_4.0_4.1.bat b/scripts/upgrade/win32/upgrade_4.0_4.1.bat deleted file mode 100644 index 023dd505..00000000 --- a/scripts/upgrade/win32/upgrade_4.0_4.1.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_4.0_4.1.py diff --git a/scripts/upgrade/win32/upgrade_4.1_4.2.bat b/scripts/upgrade/win32/upgrade_4.1_4.2.bat deleted file mode 100644 index 064a43a4..00000000 --- a/scripts/upgrade/win32/upgrade_4.1_4.2.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_4.1_4.2.py diff --git a/scripts/upgrade/win32/upgrade_4.2_4.3.bat b/scripts/upgrade/win32/upgrade_4.2_4.3.bat deleted file mode 100644 index 550bc61f..00000000 --- a/scripts/upgrade/win32/upgrade_4.2_4.3.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_4.2_4.3.py diff --git a/scripts/upgrade/win32/upgrade_4.3_5.0.bat b/scripts/upgrade/win32/upgrade_4.3_5.0.bat deleted file mode 100644 index cb4d01d9..00000000 --- a/scripts/upgrade/win32/upgrade_4.3_5.0.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_4.3_5.0.py diff --git a/scripts/upgrade/win32/upgrade_5.0_5.1.bat b/scripts/upgrade/win32/upgrade_5.0_5.1.bat deleted file mode 100644 index 2c9e64a6..00000000 --- a/scripts/upgrade/win32/upgrade_5.0_5.1.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -cd /d %~dp0 -set PYTHONPATH=%PYTHONPATH%;%~dp0\..\seahub\thirdpart -start python py/upgrade_5.0_5.1.py diff --git a/server/Makefile.am b/server/Makefile.am deleted file mode 100644 index 5613e287..00000000 --- a/server/Makefile.am +++ /dev/null @@ -1,123 +0,0 @@ -SUBDIRS = gc - -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - -DSEAFILE_SERVER \ - -DFULL_FEATURE \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/common \ - @CCNET_CFLAGS@ \ - @SEARPC_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @ZDB_CFLAGS@ \ - @MSVC_CFLAGS@ \ - @CURL_CFLAGS@ \ - @LIBARCHIVE_CFLAGS@ - -Wall - -bin_PROGRAMS = seaf-server - -proc_headers = $(addprefix processors/, \ - recvfs-proc.h \ - recvbranch-proc.h \ - putcs-proc.h \ - sync-repo-slave-proc.h \ - check-tx-slave-v3-proc.h \ - putfs-proc.h \ - putcommit-v2-proc.h \ - putcommit-v3-proc.h \ - recvcommit-v3-proc.h \ - putcs-v2-proc.h \ - checkbl-proc.h \ - checkff-proc.h \ - putca-proc.h \ - check-protocol-slave-proc.h \ - recvfs-v2-proc.h \ - recvbranch-v2-proc.h \ - putfs-v2-proc.h) - -noinst_HEADERS = web-accesstoken-mgr.h chunkserv-mgr.h seafile-session.h \ - repo-mgr.h \ - share-mgr.h \ - token-mgr.h \ - passwd-mgr.h \ - quota-mgr.h \ - listen-mgr.h \ - ../common/mq-mgr.h \ - size-sched.h \ - block-tx-server.h \ - copy-mgr.h \ - http-server.h \ - upload-file.h \ - access-file.h \ - pack-dir.h \ - fileserver-config.h \ - http-status-codes.h \ - zip-download-mgr.h \ - $(proc_headers) - -seaf_server_SOURCES = \ - seaf-server.c \ - web-accesstoken-mgr.c chunkserv-mgr.c seafile-session.c \ - zip-download-mgr.c \ - share-mgr.c \ - token-mgr.c \ - passwd-mgr.c \ - quota-mgr.c \ - listen-mgr.c \ - repo-op.c \ - repo-perm.c \ - size-sched.c \ - virtual-repo.c \ - copy-mgr.c \ - http-server.c \ - upload-file.c \ - access-file.c \ - pack-dir.c \ - fileserver-config.c \ - ../common/seaf-db.c \ - ../common/branch-mgr.c ../common/fs-mgr.c \ - repo-mgr.c ../common/commit-mgr.c \ - ../common/log.c ../common/object-list.c \ - ../common/rpc-service.c \ - ../common/vc-common.c \ - ../common/seaf-utils.c \ - ../common/obj-store.c \ - ../common/obj-backend-fs.c \ - ../common/seafile-crypt.c \ - ../common/diff-simple.c \ - ../common/mq-mgr.c \ - ../common/block-mgr.c \ - ../common/block-backend.c \ - ../common/block-backend-fs.c \ - ../common/merge-new.c \ - block-tx-server.c \ - ../common/block-tx-utils.c \ - processors/recvfs-proc.c \ - processors/recvbranch-proc.c \ - processors/putcs-proc.c \ - processors/sync-repo-slave-proc.c \ - processors/check-tx-slave-v3-proc.c \ - processors/putfs-proc.c \ - processors/putcommit-v2-proc.c \ - processors/putcommit-v3-proc.c \ - processors/recvcommit-v3-proc.c \ - processors/putcs-v2-proc.c \ - processors/checkbl-proc.c \ - processors/checkff-proc.c \ - processors/putca-proc.c \ - processors/check-protocol-slave-proc.c \ - processors/recvfs-v2-proc.c \ - processors/recvbranch-v2-proc.c \ - processors/putfs-v2-proc.c - -seaf_server_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/lib/libseafile_common.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ -levhtp \ - $(top_builddir)/common/cdc/libcdc.la \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \ - @LIBARCHIVE_LIBS@ @LIB_ICONV@ - -seaf_server_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ diff --git a/server/access-file.c b/server/access-file.c deleted file mode 100644 index 45a79f7b..00000000 --- a/server/access-file.c +++ /dev/null @@ -1,1480 +0,0 @@ -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_HTTP -#include "log.h" - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -#include -#else -#include -#endif - -#include - -#include -#include -#include - -#include - -#include "seafile-object.h" -#include "seafile-crypt.h" - -#include "utils.h" - -#include "seafile-session.h" -#include "access-file.h" -#include "zip-download-mgr.h" - -#define FILE_TYPE_MAP_DEFAULT_LEN 1 -#define BUFFER_SIZE 1024 * 64 -#define MULTI_DOWNLOAD_FILE_PREFIX "documents-export-" - -struct file_type_map { - char *suffix; - char *type; -}; - -typedef struct SendBlockData { - evhtp_request_t *req; - char *block_id; - BlockHandle *handle; - uint32_t bsize; - uint32_t remain; - - char store_id[37]; - int repo_version; - - bufferevent_data_cb saved_read_cb; - bufferevent_data_cb saved_write_cb; - bufferevent_event_cb saved_event_cb; - void *saved_cb_arg; -} SendBlockData; - -typedef struct SendfileData { - evhtp_request_t *req; - Seafile *file; - SeafileCrypt *crypt; - gboolean enc_init; - EVP_CIPHER_CTX ctx; - BlockHandle *handle; - size_t remain; - int idx; - - char store_id[37]; - int repo_version; - - bufferevent_data_cb saved_read_cb; - bufferevent_data_cb saved_write_cb; - bufferevent_event_cb saved_event_cb; - void *saved_cb_arg; -} SendfileData; - -typedef struct SendFileRangeData { - evhtp_request_t *req; - Seafile *file; - BlockHandle *handle; - int blk_idx; - guint64 start_off; - guint64 range_remain; - - char store_id[37]; - int repo_version; - - bufferevent_data_cb saved_read_cb; - bufferevent_data_cb saved_write_cb; - bufferevent_event_cb saved_event_cb; - void *saved_cb_arg; -} SendFileRangeData; - -typedef struct SendDirData { - evhtp_request_t *req; - size_t remain; - - int zipfd; - char *zipfile; - char *token; - - bufferevent_data_cb saved_read_cb; - bufferevent_data_cb saved_write_cb; - bufferevent_event_cb saved_event_cb; - void *saved_cb_arg; -} SendDirData; - - - -extern SeafileSession *seaf; - -static struct file_type_map ftmap[] = { - { "txt", "text/plain" }, - { "doc", "application/vnd.ms-word" }, - { "docx", "application/vnd.ms-word" }, - { "ppt", "application/vnd.ms-powerpoint" }, - { "pptx", "application/vnd.ms-powerpoint" }, - { "xls", "application/vnd.ms-excel" }, - { "xlsx", "application/vnd.ms-excel" }, - { "pdf", "application/pdf" }, - { "zip", "application/zip"}, - { "mp3", "audio/mp3" }, - { "mpeg", "video/mpeg" }, - { "mp4", "video/mp4" }, - { "jpg", "image/jpg" }, - { "JPG", "image/jpg" }, - { "png", "image/png" }, - { "PNG", "image/png" }, - { "gif", "image/gif" }, - { "GIF", "image/gif" }, - { NULL, NULL }, -}; - -static void -free_sendblock_data (SendBlockData *data) -{ - if (data->handle) { - seaf_block_manager_close_block(seaf->block_mgr, data->handle); - seaf_block_manager_block_handle_free(seaf->block_mgr, data->handle); - } - - g_free (data->block_id); - g_free (data); -} - -static void -free_sendfile_data (SendfileData *data) -{ - if (data->handle) { - seaf_block_manager_close_block(seaf->block_mgr, data->handle); - seaf_block_manager_block_handle_free(seaf->block_mgr, data->handle); - } - - if (data->enc_init) - EVP_CIPHER_CTX_cleanup (&data->ctx); - - seafile_unref (data->file); - g_free (data->crypt); - g_free (data); -} - -static void -free_send_file_range_data (SendFileRangeData *data) -{ - if (data->handle) { - seaf_block_manager_close_block(seaf->block_mgr, data->handle); - seaf_block_manager_block_handle_free(seaf->block_mgr, data->handle); - } - - seafile_unref (data->file); - g_free (data); -} - -static void -free_senddir_data (SendDirData *data) -{ - close (data->zipfd); - - zip_download_mgr_del_zip_progress (seaf->zip_download_mgr, data->token); - - g_free (data->token); - g_free (data); -} - -static void -write_block_data_cb (struct bufferevent *bev, void *ctx) -{ - SendBlockData *data = ctx; - char *blk_id; - BlockHandle *handle; - char buf[1024 * 64]; - int n; - - blk_id = data->block_id; - - if (!data->handle) { - data->handle = seaf_block_manager_open_block(seaf->block_mgr, - data->store_id, - data->repo_version, - blk_id, BLOCK_READ); - if (!data->handle) { - seaf_warning ("Failed to open block %s:%s\n", data->store_id, blk_id); - goto err; - } - - data->remain = data->bsize; - } - handle = data->handle; - - n = seaf_block_manager_read_block(seaf->block_mgr, handle, buf, sizeof(buf)); - data->remain -= n; - if (n < 0) { - seaf_warning ("Error when reading from block %s:%s.\n", - data->store_id, blk_id); - goto err; - } else if (n == 0) { - /* We've read up the data of this block, finish. */ - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - data->handle = NULL; - - /* Recover evhtp's callbacks */ - bev->readcb = data->saved_read_cb; - bev->writecb = data->saved_write_cb; - bev->errorcb = data->saved_event_cb; - bev->cbarg = data->saved_cb_arg; - - /* Resume reading incomming requests. */ - evhtp_request_resume (data->req); - - evhtp_send_reply_end (data->req); - - free_sendblock_data (data); - return; - } - - /* OK, we've got some data to send. */ - bufferevent_write (bev, buf, n); - - return; - -err: - evhtp_connection_free (evhtp_request_get_connection (data->req)); - free_sendblock_data (data); - return; -} - -static void -write_data_cb (struct bufferevent *bev, void *ctx) -{ - SendfileData *data = ctx; - char *blk_id; - BlockHandle *handle; - char buf[1024 * 64]; - int n; - -next: - blk_id = data->file->blk_sha1s[data->idx]; - - if (!data->handle) { - data->handle = seaf_block_manager_open_block(seaf->block_mgr, - data->store_id, - data->repo_version, - blk_id, BLOCK_READ); - if (!data->handle) { - seaf_warning ("Failed to open block %s:%s\n", data->store_id, blk_id); - goto err; - } - - BlockMetadata *bmd; - bmd = seaf_block_manager_stat_block_by_handle (seaf->block_mgr, - data->handle); - if (!bmd) - goto err; - data->remain = bmd->size; - g_free (bmd); - - if (data->crypt) { - if (seafile_decrypt_init (&data->ctx, - data->crypt->version, - (unsigned char *)data->crypt->key, - (unsigned char *)data->crypt->iv) < 0) { - seaf_warning ("Failed to init decrypt.\n"); - goto err; - } - data->enc_init = TRUE; - } - } - handle = data->handle; - - n = seaf_block_manager_read_block(seaf->block_mgr, handle, buf, sizeof(buf)); - data->remain -= n; - if (n < 0) { - seaf_warning ("Error when reading from block %s.\n", blk_id); - goto err; - } else if (n == 0) { - /* We've read up the data of this block, finish or try next block. */ - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - data->handle = NULL; - if (data->crypt != NULL) { - EVP_CIPHER_CTX_cleanup (&data->ctx); - data->enc_init = FALSE; - } - - if (data->idx == data->file->n_blocks - 1) { - /* Recover evhtp's callbacks */ - bev->readcb = data->saved_read_cb; - bev->writecb = data->saved_write_cb; - bev->errorcb = data->saved_event_cb; - bev->cbarg = data->saved_cb_arg; - - /* Resume reading incomming requests. */ - evhtp_request_resume (data->req); - - evhtp_send_reply_end (data->req); - - free_sendfile_data (data); - return; - } - - ++(data->idx); - goto next; - } - - /* OK, we've got some data to send. */ - if (data->crypt != NULL) { - char *dec_out; - int dec_out_len = -1; - struct evbuffer *tmp_buf; - - dec_out = g_new (char, n + 16); - if (!dec_out) { - seaf_warning ("Failed to alloc memory.\n"); - goto err; - } - - int ret = EVP_DecryptUpdate (&data->ctx, - (unsigned char *)dec_out, - &dec_out_len, - (unsigned char *)buf, - n); - if (ret == 0) { - seaf_warning ("Decrypt block %s:%s failed.\n", data->store_id, blk_id); - g_free (dec_out); - goto err; - } - - tmp_buf = evbuffer_new (); - - evbuffer_add (tmp_buf, dec_out, dec_out_len); - - /* If it's the last piece of a block, call decrypt_final() - * to decrypt the possible partial block. */ - if (data->remain == 0) { - ret = EVP_DecryptFinal_ex (&data->ctx, - (unsigned char *)dec_out, - &dec_out_len); - if (ret == 0) { - seaf_warning ("Decrypt block %s:%s failed.\n", data->store_id, blk_id); - evbuffer_free (tmp_buf); - g_free (dec_out); - goto err; - } - evbuffer_add (tmp_buf, dec_out, dec_out_len); - } - /* This may call write_data_cb() recursively (by libevent_openssl). - * SendfileData struct may be free'd in the recursive calls. - * So don't use "data" variable after here. - */ - bufferevent_write_buffer (bev, tmp_buf); - - evbuffer_free (tmp_buf); - g_free (dec_out); - } else { - bufferevent_write (bev, buf, n); - } - - return; - -err: - evhtp_connection_free (evhtp_request_get_connection (data->req)); - free_sendfile_data (data); - return; -} - -static void -write_dir_data_cb (struct bufferevent *bev, void *ctx) -{ - SendDirData *data = ctx; - char buf[64 * 1024]; - int n; - - n = readn (data->zipfd, buf, sizeof(buf)); - if (n < 0) { - seaf_warning ("Failed to read zipfile %s: %s.\n", data->zipfile, strerror (errno)); - evhtp_connection_free (evhtp_request_get_connection (data->req)); - free_senddir_data (data); - } else if (n > 0) { - bufferevent_write (bev, buf, n); - data->remain -= n; - - if (data->remain == 0) { - /* Recover evhtp's callbacks */ - bev->readcb = data->saved_read_cb; - bev->writecb = data->saved_write_cb; - bev->errorcb = data->saved_event_cb; - bev->cbarg = data->saved_cb_arg; - - /* Resume reading incomming requests. */ - evhtp_request_resume (data->req); - - evhtp_send_reply_end (data->req); - - free_senddir_data (data); - return; - } - } -} - -static void -my_block_event_cb (struct bufferevent *bev, short events, void *ctx) -{ - SendBlockData *data = ctx; - - data->saved_event_cb (bev, events, data->saved_cb_arg); - - /* Free aux data. */ - free_sendblock_data (data); -} - -static void -my_event_cb (struct bufferevent *bev, short events, void *ctx) -{ - SendfileData *data = ctx; - - data->saved_event_cb (bev, events, data->saved_cb_arg); - - /* Free aux data. */ - free_sendfile_data (data); -} - -static void -file_range_event_cb (struct bufferevent *bev, short events, void *ctx) -{ - SendFileRangeData *data = ctx; - - data->saved_event_cb (bev, events, data->saved_cb_arg); - - /* Free aux data. */ - free_send_file_range_data (data); -} - -static void -my_dir_event_cb (struct bufferevent *bev, short events, void *ctx) -{ - SendDirData *data = ctx; - - data->saved_event_cb (bev, events, data->saved_cb_arg); - - /* Free aux data. */ - free_senddir_data (data); -} - -static char * -parse_content_type(const char *filename) -{ - char *p; - int i; - - if ((p = strrchr(filename, '.')) == NULL) - return NULL; - p++; - - for (i = 0; ftmap[i].suffix != NULL; i++) { - if (strcmp(p, ftmap[i].suffix) == 0) - return ftmap[i].type; - } - - return NULL; -} - -static gboolean -test_windows (evhtp_request_t *req) -{ - const char *user_agent = evhtp_header_find (req->headers_in, "User-Agent"); - if (!user_agent) - return FALSE; - - GString *s = g_string_new (user_agent); - if (g_strrstr (g_string_ascii_down (s)->str, "windows")) { - g_string_free (s, TRUE); - return TRUE; - } - else { - g_string_free (s, TRUE); - return FALSE; - } -} - -static gboolean -test_firefox (evhtp_request_t *req) -{ - const char *user_agent = evhtp_header_find (req->headers_in, "User-Agent"); - if (!user_agent) - return FALSE; - - GString *s = g_string_new (user_agent); - if (g_strrstr (g_string_ascii_down (s)->str, "firefox")) { - g_string_free (s, TRUE); - return TRUE; - } - else { - g_string_free (s, TRUE); - return FALSE; - } -} - -static int -do_file(evhtp_request_t *req, SeafRepo *repo, const char *file_id, - const char *filename, const char *operation, - SeafileCryptKey *crypt_key) -{ - Seafile *file; - char *type = NULL; - char file_size[255]; - gchar *content_type = NULL; - char cont_filename[SEAF_PATH_MAX]; - char *key_hex, *iv_hex; - unsigned char enc_key[32], enc_iv[16]; - SeafileCrypt *crypt = NULL; - SendfileData *data; - - file = seaf_fs_manager_get_seafile(seaf->fs_mgr, - repo->store_id, repo->version, file_id); - if (file == NULL) - return -1; - - if (crypt_key != NULL) { - g_object_get (crypt_key, - "key", &key_hex, - "iv", &iv_hex, - NULL); - if (repo->enc_version == 1) - hex_to_rawdata (key_hex, enc_key, 16); - else - hex_to_rawdata (key_hex, enc_key, 32); - hex_to_rawdata (iv_hex, enc_iv, 16); - crypt = seafile_crypt_new (repo->enc_version, enc_key, enc_iv); - g_free (key_hex); - g_free (iv_hex); - } - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - - - type = parse_content_type(filename); - if (type != NULL) { - if (strstr(type, "text")) { - content_type = g_strjoin("; ", type, "charset=gbk", NULL); - } else { - content_type = g_strdup (type); - } - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Type", - content_type, 1, 1)); - g_free (content_type); - } else - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Type", - "application/octet-stream", 1, 1)); - - snprintf(file_size, sizeof(file_size), "%"G_GINT64_FORMAT"", file->file_size); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Length", file_size, 1, 1)); - - if (strcmp(operation, "download") == 0) { - if (test_firefox (req)) { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename*=\"utf8\' \'%s\"", filename); - } else { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename=\"%s\"", filename); - } - } else { - if (test_firefox (req)) { - snprintf(cont_filename, SEAF_PATH_MAX, - "inline;filename*=\"utf8\' \'%s\"", filename); - } else { - snprintf(cont_filename, SEAF_PATH_MAX, - "inline;filename=\"%s\"", filename); - } - } - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Disposition", cont_filename, - 1, 1)); - - if (g_strcmp0 (type, "image/jpg") != 0) { - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("X-Content-Type-Options", "nosniff", - 1, 1)); - } - - /* If it's an empty file, send an empty reply. */ - if (file->n_blocks == 0) { - evhtp_send_reply (req, EVHTP_RES_OK); - seafile_unref (file); - return 0; - } - - data = g_new0 (SendfileData, 1); - data->req = req; - data->file = file; - data->crypt = crypt; - - memcpy (data->store_id, repo->store_id, 36); - data->repo_version = repo->version; - - /* We need to overwrite evhtp's callback functions to - * write file data piece by piece. - */ - struct bufferevent *bev = evhtp_request_get_bev (req); - data->saved_read_cb = bev->readcb; - data->saved_write_cb = bev->writecb; - data->saved_event_cb = bev->errorcb; - data->saved_cb_arg = bev->cbarg; - bufferevent_setcb (bev, - NULL, - write_data_cb, - my_event_cb, - data); - /* Block any new request from this connection before finish - * handling this request. - */ - evhtp_request_pause (req); - - /* Kick start data transfer by sending out http headers. */ - evhtp_send_reply_start(req, EVHTP_RES_OK); - - return 0; -} - -// get block handle for range start -static BlockHandle * -get_start_block_handle (const char *store_id, int version, Seafile *file, - guint64 start, int *blk_idx) -{ - BlockHandle *handle = NULL; - BlockMetadata *bmd; - char *blkid; - guint64 tolsize = 0; - int i = 0; - - for (; i < file->n_blocks; i++) { - blkid = file->blk_sha1s[i]; - - bmd = seaf_block_manager_stat_block(seaf->block_mgr, store_id, - version, blkid); - if (!bmd) - return NULL; - - if (start < tolsize + bmd->size) { - g_free (bmd); - break; - } - tolsize += bmd->size; - g_free (bmd); - } - - /* beyond the file size */ - if (i == file->n_blocks) - return NULL; - - handle = seaf_block_manager_open_block(seaf->block_mgr, - store_id, version, - blkid, BLOCK_READ); - if (!handle) { - seaf_warning ("Failed to open block %s:%s.\n", store_id, blkid); - return NULL; - } - - /* trim the offset in a block */ - if (start > tolsize) { - char *tmp = (char *)malloc(sizeof(*tmp) * (start - tolsize)); - if (!tmp) - goto err; - - int n = seaf_block_manager_read_block(seaf->block_mgr, handle, - tmp, start-tolsize); - if (n != start-tolsize) { - seaf_warning ("Failed to read block %s:%s.\n", store_id, blkid); - free (tmp); - goto err; - } - free (tmp); - } - - *blk_idx = i; - return handle; - -err: - seaf_block_manager_close_block(seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - return NULL; -} - -static void -finish_file_range_request (struct bufferevent *bev, SendFileRangeData *data) -{ - /* Recover evhtp's callbacks */ - bev->readcb = data->saved_read_cb; - bev->writecb = data->saved_write_cb; - bev->errorcb = data->saved_event_cb; - bev->cbarg = data->saved_cb_arg; - - /* Resume reading incomming requests. */ - evhtp_request_resume (data->req); - - evhtp_send_reply_end (data->req); - - free_send_file_range_data (data); -} - -static void -write_file_range_cb (struct bufferevent *bev, void *ctx) -{ - SendFileRangeData *data = ctx; - char *blk_id; - char buf[BUFFER_SIZE]; - int bsize; - int n; - - if (data->blk_idx == -1) { - // start to send block - data->handle = get_start_block_handle (data->store_id, data->repo_version, - data->file, data->start_off, - &data->blk_idx); - if (!data->handle) - goto err; - } - -next: - blk_id = data->file->blk_sha1s[data->blk_idx]; - - if (!data->handle) { - data->handle = seaf_block_manager_open_block(seaf->block_mgr, - data->store_id, - data->repo_version, - blk_id, BLOCK_READ); - if (!data->handle) { - seaf_warning ("Failed to open block %s:%s\n", data->store_id, blk_id); - goto err; - } - } - - bsize = data->range_remain < BUFFER_SIZE ? data->range_remain : BUFFER_SIZE; - n = seaf_block_manager_read_block(seaf->block_mgr, data->handle, buf, bsize); - data->range_remain -= n; - if (n < 0) { - seaf_warning ("Error when reading from block %s:%s.\n", - data->store_id, blk_id); - goto err; - } else if (n == 0) { - seaf_block_manager_close_block (seaf->block_mgr, data->handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, data->handle); - data->handle = NULL; - ++data->blk_idx; - goto next; - } - - bufferevent_write (bev, buf, n); - if (data->range_remain == 0) { - finish_file_range_request (bev, data); - } - - return; - -err: - evhtp_connection_free (evhtp_request_get_connection (data->req)); - free_send_file_range_data (data); -} - -// parse range offset, only support single range (-num, num-num, num-) -static gboolean -parse_range_val (const char *byte_ranges, guint64 *pstart, guint64 *pend, - guint64 fsize) -{ - char *minus; - char *end_ptr; - gboolean error = FALSE; - char *ranges_dup = g_strdup (strchr(byte_ranges, '=') + 1); - char *tmp = ranges_dup; - guint64 start; - guint64 end; - - minus = strchr(tmp, '-'); - if (!minus) - return FALSE; - - if (minus == tmp) { - // -num mode - start = strtoll(tmp, &end_ptr, 10); - if (start == 0) { - // range format is invalid - error = TRUE; - } else if (*end_ptr == '\0') { - end = fsize - 1; - start += fsize; - } else { - error = TRUE; - } - } else if (*(minus + 1) == '\0') { - // num- mode - start = strtoll(tmp, &end_ptr, 10); - if (end_ptr == minus) { - end = fsize - 1; - } else { - error = TRUE; - } - } else { - // num-num mode - start = strtoll(tmp, &end_ptr, 10); - if (end_ptr == minus) { - end = strtoll(minus + 1, &end_ptr, 10); - if (*end_ptr != '\0') { - error = TRUE; - } - } else { - error = TRUE; - } - } - - g_free (ranges_dup); - - if (error) - return FALSE; - - if (end > fsize - 1) { - end = fsize - 1; - } - if (start > end) { - // Range format is valid, but range number is invalid - return FALSE; - } - - *pstart = start; - *pend = end; - - return TRUE; -} - -static void -set_resp_disposition (evhtp_request_t *req, const char *operation, - const char *filename) -{ - char *cont_filename = NULL; - - if (strcmp(operation, "download") == 0) { - if (test_firefox (req)) { - cont_filename = g_strdup_printf("attachment;filename*=\"utf8\' \'%s\"", - filename); - - } else { - cont_filename = g_strdup_printf("attachment;filename=\"%s\"", filename); - } - } else { - if (test_firefox (req)) { - cont_filename = g_strdup_printf("inline;filename*=\"utf8\' \'%s\"", - filename); - } else { - cont_filename = g_strdup_printf("inline;filename=\"%s\"", filename); - } - } - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Disposition", cont_filename, - 0, 1)); - g_free (cont_filename); -} - -static int -do_file_range (evhtp_request_t *req, SeafRepo *repo, const char *file_id, - const char *filename, const char *operation, const char *byte_ranges) -{ - Seafile *file; - SendFileRangeData *data = NULL; - guint64 start; - guint64 end; - - file = seaf_fs_manager_get_seafile(seaf->fs_mgr, - repo->store_id, repo->version, file_id); - if (file == NULL) - return -1; - - /* If it's an empty file, send an empty reply. */ - if (file->n_blocks == 0) { - evhtp_send_reply (req, EVHTP_RES_OK); - seafile_unref (file); - return 0; - } - - if (!parse_range_val (byte_ranges, &start, &end, file->file_size)) { - seafile_unref (file); - char *con_range = g_strdup_printf ("bytes */%"G_GUINT64_FORMAT, file->file_size); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Range", con_range, - 0, 1)); - g_free (con_range); - evhtp_send_reply (req, EVHTP_RES_RANGENOTSC); - return 0; - } - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new ("Accept-Ranges", "bytes", 0, 0)); - - char *content_type = NULL; - char *type = parse_content_type (filename); - if (type != NULL) { - if (strstr(type, "text")) { - content_type = g_strjoin("; ", type, "charset=gbk", NULL); - } else { - content_type = g_strdup (type); - } - } else { - content_type = g_strdup ("application/octet-stream"); - } - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new ("Content-Type", content_type, 0, 1)); - g_free (content_type); - - char *con_len = g_strdup_printf ("%"G_GUINT64_FORMAT, end-start+1); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Length", con_len, 0, 1)); - g_free (con_len); - - char *con_range = g_strdup_printf ("%s %"G_GUINT64_FORMAT"-%"G_GUINT64_FORMAT - "/%"G_GUINT64_FORMAT, "bytes", - start, end, file->file_size); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new ("Content-Range", con_range, 0, 1)); - g_free (con_range); - - set_resp_disposition (req, operation, filename); - - if (g_strcmp0 (type, "image/jpg") != 0) { - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("X-Content-Type-Options", "nosniff", - 1, 1)); - } - - data = g_new0 (SendFileRangeData, 1); - if (!data) { - seafile_unref (file); - return -1; - } - data->req = req; - data->file = file; - data->blk_idx = -1; - data->start_off = start; - data->range_remain = end-start+1; - - memcpy (data->store_id, repo->store_id, 36); - data->repo_version = repo->version; - - /* We need to overwrite evhtp's callback functions to - * write file data piece by piece. - */ - struct bufferevent *bev = evhtp_request_get_bev (req); - data->saved_read_cb = bev->readcb; - data->saved_write_cb = bev->writecb; - data->saved_event_cb = bev->errorcb; - data->saved_cb_arg = bev->cbarg; - bufferevent_setcb (bev, - NULL, - write_file_range_cb, - file_range_event_cb, - data); - - - /* Block any new request from this connection before finish - * handling this request. - */ - evhtp_request_pause (req); - - /* Kick start data transfer by sending out http headers. */ - evhtp_send_reply_start(req, EVHTP_RES_PARTIAL); - - return 0; -} - -static int -start_download_zip_file (evhtp_request_t *req, const char *token, - const char *zipname, char *zipfile) -{ - SeafStat st; - char file_size[255]; - char cont_filename[SEAF_PATH_MAX]; - int zipfd = 0; - - if (seaf_stat(zipfile, &st) < 0) { - seaf_warning ("Failed to stat %s: %s.\n", zipfile, strerror(errno)); - return -1; - } - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Type", "application/zip", 1, 1)); - - snprintf (file_size, sizeof(file_size), "%"G_GUINT64_FORMAT"", st.st_size); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Length", file_size, 1, 1)); - - if (test_firefox (req)) { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename*=\"utf8\' \'%s.zip\"", zipname); - } else { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename=\"%s.zip\"", zipname); - } - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Disposition", cont_filename, 1, 1)); - - zipfd = g_open (zipfile, O_RDONLY | O_BINARY, 0); - if (zipfd < 0) { - seaf_warning ("Failed to open zipfile %s: %s.\n", zipfile, strerror(errno)); - return -1; - } - - SendDirData *data; - data = g_new0 (SendDirData, 1); - data->req = req; - data->zipfd = zipfd; - data->zipfile = zipfile; - data->token = g_strdup (token); - data->remain = st.st_size; - - /* We need to overwrite evhtp's callback functions to - * write file data piece by piece. - */ - struct bufferevent *bev = evhtp_request_get_bev (req); - data->saved_read_cb = bev->readcb; - data->saved_write_cb = bev->writecb; - data->saved_event_cb = bev->errorcb; - data->saved_cb_arg = bev->cbarg; - bufferevent_setcb (bev, - NULL, - write_dir_data_cb, - my_dir_event_cb, - data); - /* Block any new request from this connection before finish - * handling this request. - */ - evhtp_request_pause (req); - - /* Kick start data transfer by sending out http headers. */ - evhtp_send_reply_start(req, EVHTP_RES_OK); - - return 0; -} - -static gboolean -can_use_cached_content (evhtp_request_t *req) -{ - if (evhtp_kv_find (req->headers_in, "If-Modified-Since") != NULL) { - evhtp_send_reply (req, EVHTP_RES_NOTMOD); - return TRUE; - } - - char http_date[256]; - evhtp_kv_t *kv; - time_t now = time(NULL); - - /* Set Last-Modified header if the client gets this file - * for the first time. So that the client will set - * If-Modified-Since header the next time it gets the same - * file. - */ -#ifndef WIN32 - strftime (http_date, sizeof(http_date), "%a, %d %b %Y %T GMT", - gmtime(&now)); -#else - strftime (http_date, sizeof(http_date), "%a, %d %b %Y %H:%M:%S GMT", - gmtime(&now)); -#endif - kv = evhtp_kv_new ("Last-Modified", http_date, 1, 1); - evhtp_kvs_add_kv (req->headers_out, kv); - - kv = evhtp_kv_new ("Cache-Control", "max-age=3600", 1, 1); - evhtp_kvs_add_kv (req->headers_out, kv); - - return FALSE; -} - -static void -access_zip_cb (evhtp_request_t *req, void *arg) -{ - char *token; - SeafileWebAccess *info = NULL; - char *info_str = NULL; - json_t *info_obj = NULL; - json_error_t jerror; - char *filename = NULL; - char *zip_file_path; - const char *error = NULL; - int error_code; - - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - if (g_strv_length (parts) != 2) { - error = "Invalid URL\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - token = parts[1]; - info = seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token); - // Here only check token exist, follow will get zip file path, if zip file path exist - // then the token is valid, because it pass some validations in zip stage - if (!info) { - seaf_warning ("Token doesn't exist.\n"); - error = "Invalid token\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - g_object_get (info, "obj_id", &info_str, NULL); - if (!info_str) { - seaf_warning ("Invalid token.\n"); - error = "Invalid token\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - info_obj = json_loadb (info_str, strlen(info_str), 0, &jerror); - if (!info_obj) { - seaf_warning ("Failed to parse obj_id field: %s.\n", jerror.text); - error = "Invalid token\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - if (json_object_has_member (info_obj, "dir_name")) { - // Download dir - filename = g_strdup (json_object_get_string_member (info_obj, "dir_name")); - } else if (json_object_has_member (info_obj, "file_list")) { - // Download multi - time_t now = time(NULL); - char date_str[11]; - strftime(date_str, sizeof(date_str), "%Y-%m-%d", localtime(&now)); - filename = g_strconcat (MULTI_DOWNLOAD_FILE_PREFIX, date_str, NULL); - } else { - seaf_warning ("Invalid token.\n"); - error = "Invalid token\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - zip_file_path = zip_download_mgr_get_zip_file_path (seaf->zip_download_mgr, token); - if (!zip_file_path) { - seaf_warning ("Failed to get zip file path.\n"); - error = "Invalid token\n"; - error_code = EVHTP_RES_BADREQ; - goto out; - } - - if (can_use_cached_content (req)) { - // Clean zip progress related resource - zip_download_mgr_del_zip_progress (seaf->zip_download_mgr, token); - goto out; - } - - int ret = start_download_zip_file (req, token, filename, zip_file_path); - if (ret < 0) { - error = "Internal server error\n"; - error_code = EVHTP_RES_SERVERR; - } - -out: - g_strfreev (parts); - if (info) - g_object_unref (info); - if (info_str) - g_free (info_str); - if (info_obj) - json_decref (info_obj); - if (filename) - g_free (filename); - - if (error) { - evbuffer_add_printf(req->buffer_out, "%s\n", error); - evhtp_send_reply(req, error_code); - } -} - -static void -access_cb(evhtp_request_t *req, void *arg) -{ - SeafRepo *repo = NULL; - char *error = NULL; - char *token = NULL; - char *filename = NULL; - const char *repo_id = NULL; - const char *data = NULL; - const char *operation = NULL; - const char *user = NULL; - const char *byte_ranges = NULL; - - GError *err = NULL; - SeafileCryptKey *key = NULL; - SeafileWebAccess *webaccess = NULL; - - /* Skip the first '/'. */ - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - if (!parts || g_strv_length (parts) < 3 || - strcmp (parts[0], "files") != 0) { - error = "Invalid URL"; - goto bad_req; - } - - token = parts[1]; - filename = parts[2]; - - webaccess = seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token); - if (!webaccess) { - error = "Bad access token"; - goto bad_req; - } - - repo_id = seafile_web_access_get_repo_id (webaccess); - data = seafile_web_access_get_obj_id (webaccess); - operation = seafile_web_access_get_op (webaccess); - user = seafile_web_access_get_username (webaccess); - - if (strcmp(operation, "view") != 0 && - strcmp(operation, "download") != 0) { - error = "Bad access token"; - goto bad_req; - } - - if (can_use_cached_content (req)) { - goto success; - } - - byte_ranges = evhtp_kv_find (req->headers_in, "Range"); - - repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id); - if (!repo) { - error = "Bad repo id\n"; - goto bad_req; - } - - if (repo->encrypted) { - err = NULL; - key = seaf_passwd_manager_get_decrypt_key (seaf->passwd_mgr, - repo_id, user); - if (!key) { - error = "Repo is encrypted. Please provide password to view it."; - goto bad_req; - } - } - - if (!seaf_fs_manager_object_exists (seaf->fs_mgr, - repo->store_id, repo->version, data)) { - error = "Invalid file id\n"; - goto bad_req; - } - - if (!repo->encrypted && byte_ranges) { - if (do_file_range (req, repo, data, filename, operation, byte_ranges) < 0) { - error = "Internal server error\n"; - goto bad_req; - } - } else if (do_file(req, repo, data, filename, operation, key) < 0) { - error = "Internal server error\n"; - goto bad_req; - } - -success: - g_strfreev (parts); - if (repo != NULL) - seaf_repo_unref (repo); - if (key != NULL) - g_object_unref (key); - if (webaccess) - g_object_unref (webaccess); - - return; - -bad_req: - g_strfreev (parts); - if (repo != NULL) - seaf_repo_unref (repo); - if (key != NULL) - g_object_unref (key); - if (webaccess != NULL) - g_object_unref (webaccess); - - evbuffer_add_printf(req->buffer_out, "%s\n", error); - evhtp_send_reply(req, EVHTP_RES_BADREQ); -} - -static int -do_block(evhtp_request_t *req, SeafRepo *repo, const char *file_id, - const char *blk_id) -{ - Seafile *file; - uint32_t bsize; - gboolean found = FALSE; - int i; - char blk_size[255]; - char cont_filename[SEAF_PATH_MAX]; - SendBlockData *data; - - file = seaf_fs_manager_get_seafile(seaf->fs_mgr, - repo->store_id, repo->version, file_id); - if (file == NULL) - return -1; - - for (i = 0; i < file->n_blocks; i++) { - if (memcmp(file->blk_sha1s[i], blk_id, 40) == 0) { - BlockMetadata *bm = seaf_block_manager_stat_block (seaf->block_mgr, - repo->store_id, - repo->version, - blk_id); - if (bm && bm->size >= 0) { - bsize = bm->size; - found = TRUE; - } - g_free (bm); - break; - } - } - - seafile_unref (file); - - /* block not found. */ - if (!found) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return 0; - } - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - - if (test_firefox (req)) { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename*=\"utf8\' \'%s\"", blk_id); - } else { - snprintf(cont_filename, SEAF_PATH_MAX, - "attachment;filename=\"%s\"", blk_id); - } - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Disposition", cont_filename, - 1, 1)); - - snprintf(blk_size, sizeof(blk_size), "%"G_GUINT32_FORMAT"", bsize); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Content-Length", blk_size, 1, 1)); - - data = g_new0 (SendBlockData, 1); - data->req = req; - data->block_id = g_strdup(blk_id); - - memcpy (data->store_id, repo->store_id, 36); - data->repo_version = repo->version; - - /* We need to overwrite evhtp's callback functions to - * write file data piece by piece. - */ - struct bufferevent *bev = evhtp_request_get_bev (req); - data->saved_read_cb = bev->readcb; - data->saved_write_cb = bev->writecb; - data->saved_event_cb = bev->errorcb; - data->saved_cb_arg = bev->cbarg; - data->bsize = bsize; - bufferevent_setcb (bev, - NULL, - write_block_data_cb, - my_block_event_cb, - data); - /* Block any new request from this connection before finish - * handling this request. - */ - evhtp_request_pause (req); - - /* Kick start data transfer by sending out http headers. */ - evhtp_send_reply_start(req, EVHTP_RES_OK); - - return 0; -} - -static void -access_blks_cb(evhtp_request_t *req, void *arg) -{ - SeafRepo *repo = NULL; - char *error = NULL; - char *token = NULL; - char *blkid = NULL; - const char *repo_id = NULL; - const char *id = NULL; - const char *operation = NULL; - - char *repo_role = NULL; - SeafileWebAccess *webaccess = NULL; - - /* Skip the first '/'. */ - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - if (!parts || g_strv_length (parts) < 3 || - strcmp (parts[0], "blks") != 0) { - error = "Invalid URL"; - goto bad_req; - } - - token = parts[1]; - blkid = parts[2]; - - webaccess = seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token); - if (!webaccess) { - error = "Bad access token"; - goto bad_req; - } - - if (can_use_cached_content (req)) { - goto success; - } - - repo_id = seafile_web_access_get_repo_id (webaccess); - id = seafile_web_access_get_obj_id (webaccess); - operation = seafile_web_access_get_op (webaccess); - - repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id); - if (!repo) { - error = "Bad repo id\n"; - goto bad_req; - } - - if (!seaf_fs_manager_object_exists (seaf->fs_mgr, - repo->store_id, repo->version, id)) { - error = "Invalid file id\n"; - goto bad_req; - } - - if (strcmp(operation, "downloadblks") == 0) { - if (do_block(req, repo, id, blkid) < 0) { - error = "Internal server error\n"; - goto bad_req; - } - } - -success: - g_strfreev (parts); - if (repo != NULL) - seaf_repo_unref (repo); - g_free (repo_role); - g_object_unref (webaccess); - - return; - -bad_req: - g_strfreev (parts); - if (repo != NULL) - seaf_repo_unref (repo); - g_free (repo_role); - if (webaccess != NULL) - g_object_unref (webaccess); - - evbuffer_add_printf(req->buffer_out, "%s\n", error); - evhtp_send_reply(req, EVHTP_RES_BADREQ); -} - -int -access_file_init (evhtp_t *htp) -{ - evhtp_set_regex_cb (htp, "^/files/.*", access_cb, NULL); - evhtp_set_regex_cb (htp, "^/blks/.*", access_blks_cb, NULL); - evhtp_set_regex_cb (htp, "^/zip/.*", access_zip_cb, NULL); - - return 0; -} diff --git a/server/access-file.h b/server/access-file.h deleted file mode 100644 index 012e52ac..00000000 --- a/server/access-file.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ACCESS_FILE_H -#define ACCESS_FILE_H - -int -access_file_init (evhtp_t *htp); - -#endif diff --git a/server/block-tx-server.c b/server/block-tx-server.c deleted file mode 100644 index b50f9f4d..00000000 --- a/server/block-tx-server.c +++ /dev/null @@ -1,702 +0,0 @@ -#include "common.h" -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include "net.h" - -#ifndef WIN32 -#include -#endif -#include -#include - -#include -#include - -#include "seafile-session.h" -#include "block-tx-server.h" -#include "block-tx-utils.h" -#include "utils.h" - -enum { - RECV_STATE_HANDSHAKE = 0, - RECV_STATE_AUTH, - RECV_STATE_HEADER, - RECV_STATE_CONTENT, -}; - -struct _BlockTxServer { - evutil_socket_t data_fd; - struct evbuffer *recv_buf; - - int recv_state; - int session_key_len; - int command; - char curr_block_id[41]; - - /* Used by put block */ - BlockHandle *block; - - unsigned char key[ENC_KEY_SIZE]; - unsigned char iv[ENC_BLOCK_SIZE]; - - unsigned char key_v2[ENC_KEY_SIZE]; - unsigned char iv_v2[ENC_BLOCK_SIZE]; - - FrameParser parser; - - gboolean break_loop; - - int version; - - char store_id[37]; - int repo_version; -}; - -typedef struct _BlockTxServer BlockTxServer; - -/* Handshake */ - -static int -send_handshake_response (BlockTxServer *server, int status) -{ - HandshakeResponse rsp; - - rsp.status = htonl (status); - rsp.version = htonl (BLOCK_PROTOCOL_VERSION); - - if (sendn (server->data_fd, &rsp, sizeof(rsp)) < 0) { - seaf_warning ("Failed to send handshake response: %s.\n", - evutil_socket_error_to_string(evutil_socket_geterror(server->data_fd))); - return -1; - } - - return 0; -} - -static void -init_frame_parser (BlockTxServer *server) -{ - FrameParser *parser = &server->parser; - - if (server->version == 1) { - memcpy (parser->key, server->key, ENC_BLOCK_SIZE); - memcpy (parser->iv, server->iv, ENC_BLOCK_SIZE); - } else if (server->version == 2) { - memcpy (parser->key_v2, server->key_v2, ENC_KEY_SIZE); - memcpy (parser->iv_v2, server->iv_v2, ENC_BLOCK_SIZE); - } - - parser->version = server->version; - parser->cbarg = server; -} - -static int -process_session_key (BlockTxServer *server, unsigned char *enc_session_key) -{ - char *enc_key_b64 = NULL, *key_b64 = NULL; - unsigned char *session_key = NULL; - gsize len; - SearpcClient *client = NULL; - int ret = 0; - - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-rpcserver"); - if (!client) { - seaf_warning ("Failed to create rpc client.\n"); - send_handshake_response (server, STATUS_INTERNAL_SERVER_ERROR); - ret = -1; - goto out; - } - - enc_key_b64 = g_base64_encode (enc_session_key, server->session_key_len); - - key_b64 = ccnet_privkey_decrypt (client, enc_key_b64); - if (!key_b64) { - seaf_warning ("Failed to decrypt session key.\n"); - send_handshake_response (server, STATUS_INTERNAL_SERVER_ERROR); - ret = -1; - goto out; - } - - session_key = g_base64_decode (key_b64, &len); - - if (server->version == 1) - blocktx_generate_encrypt_key (session_key, len, server->key, server->iv); - else if (server->version == 2) - blocktx_generate_encrypt_key (session_key, len, server->key_v2, server->iv_v2); - - init_frame_parser (server); - -out: - g_free (enc_key_b64); - g_free (key_b64); - g_free (session_key); - ccnet_rpc_client_free (client); - - return ret; -} - -static int -handle_auth_req_content_cb (char *content, int clen, void *cbarg); - -#define MAX_SESSION_KEY_SIZE 1024 - -static int -handle_handshake_request (BlockTxServer *server) -{ - HandshakeRequest req; - struct evbuffer *input = server->recv_buf; - unsigned char *enc_session_key; - - if (!server->session_key_len) { - if (evbuffer_get_length (input) < sizeof(req)) - return 0; - - evbuffer_remove (input, &req, sizeof(req)); - - req.version = ntohl (req.version); - server->version = MIN (req.version, BLOCK_PROTOCOL_VERSION); - if (server->version != 1 && server->version != 2) { - seaf_warning ("Bad block protocol version %d.\n", server->version); - send_handshake_response (server, STATUS_VERSION_MISMATCH); - return -1; - } - - seaf_debug ("Block protocol version %d.\n", server->version); - - server->session_key_len = ntohl (req.key_len); - if (server->session_key_len > MAX_SESSION_KEY_SIZE) { - seaf_warning ("Encrypted session key is too long: %d.\n", - server->session_key_len); - send_handshake_response (server, STATUS_BAD_REQUEST); - return -1; - } - } - - if (evbuffer_get_length (input) < server->session_key_len) - return 0; - - enc_session_key = g_malloc (server->session_key_len); - - evbuffer_remove (input, enc_session_key, server->session_key_len); - - if (process_session_key (server, enc_session_key) < 0) { - g_free (enc_session_key); - return -1; - } - g_free (enc_session_key); - - if (send_handshake_response (server, STATUS_OK) < 0) - return -1; - - seaf_debug ("recv_state set to AUTH.\n"); - - server->parser.content_cb = handle_auth_req_content_cb; - server->recv_state = RECV_STATE_AUTH; - - return 0; -} - -/* Authentication */ - -static int -send_auth_response (BlockTxServer *server, int status) -{ - AuthResponse rsp; - EVP_CIPHER_CTX ctx; - int ret = 0; - - rsp.status = htonl (status); - - if (server->version == 1) - blocktx_encrypt_init (&ctx, server->key, server->iv); - else if (server->version == 2) - blocktx_encrypt_init (&ctx, server->key_v2, server->iv_v2); - - if (send_encrypted_data_frame_begin (server->data_fd, sizeof(rsp)) < 0) { - seaf_warning ("Send auth response: failed to begin.\n"); - ret = -1; - goto out; - } - - if (send_encrypted_data (&ctx, server->data_fd, &rsp, sizeof(rsp)) < 0) - { - seaf_warning ("Send auth response: failed to send data.\n"); - ret = -1; - goto out; - } - - if (send_encrypted_data_frame_end (&ctx, server->data_fd) < 0) { - seaf_warning ("Send auth response: failed to end.\n"); - ret = -1; - goto out; - } - -out: - EVP_CIPHER_CTX_cleanup (&ctx); - return ret; -} - -static int -handle_block_header_content_cb (char *content, int clen, void *cbarg); - -static int -handle_auth_req_content_cb (char *content, int clen, void *cbarg) -{ - BlockTxServer *server = cbarg; - char *session_token = content; - SearpcClient *client = NULL; - char repo_id[37]; - SeafRepo *repo; - - if (session_token[clen - 1] != '\0') { - seaf_warning ("Invalid session token format.\n"); - send_auth_response (server, STATUS_BAD_REQUEST); - return -1; - } - - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-rpcserver"); - if (!client) { - seaf_warning ("Failed to create rpc client.\n"); - send_auth_response (server, STATUS_INTERNAL_SERVER_ERROR); - return -1; - } - - if (seaf_token_manager_verify_token (seaf->token_mgr, client, NULL, - session_token, repo_id) < 0) { - seaf_warning ("Session token check failed.\n"); - send_auth_response (server, STATUS_ACCESS_DENIED); - ccnet_rpc_client_free (client); - return -1; - } - - ccnet_rpc_client_free (client); - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %.8s.\n", repo_id); - return -1; - } - memcpy (server->store_id, repo->store_id, 36); - server->repo_version = repo->version; - seaf_repo_unref (repo); - - if (send_auth_response (server, STATUS_OK) < 0) - return -1; - - seaf_debug ("recv_state set to HEADER.\n"); - - server->parser.content_cb = handle_block_header_content_cb; - server->recv_state = RECV_STATE_HEADER; - - return 0; -} - -static int -handle_auth_request (BlockTxServer *server) -{ - return handle_one_frame (server->recv_buf, &server->parser); -} - -/* Block header */ - -static int -send_block_response_header (BlockTxServer *server, int status) -{ - ResponseHeader header; - EVP_CIPHER_CTX ctx; - int ret = 0; - - header.status = htonl (status); - - if (server->version == 1) - blocktx_encrypt_init (&ctx, server->key, server->iv); - else if (server->version == 2) - blocktx_encrypt_init (&ctx, server->key_v2, server->iv_v2); - - if (send_encrypted_data_frame_begin (server->data_fd, sizeof(header)) < 0) { - seaf_warning ("Send block response header %s: failed to begin.\n", - server->curr_block_id); - ret = -1; - goto out; - } - - if (send_encrypted_data (&ctx, server->data_fd, - &header, sizeof(header)) < 0) - { - seaf_warning ("Send block response header %s: failed to send data.\n", - server->curr_block_id); - ret = -1; - goto out; - } - - if (send_encrypted_data_frame_end (&ctx, server->data_fd) < 0) { - seaf_warning ("Send block response header %s: failed to end.\n", - server->curr_block_id); - ret = -1; - goto out; - } - -out: - EVP_CIPHER_CTX_cleanup (&ctx); - return ret; -} - -static int -send_block_content (BlockTxServer *server, int block_size); - -static int -save_block_content_cb (char *content, int clen, int end, void *cbarg); - -static int -handle_block_header_content_cb (char *content, int clen, void *cbarg) -{ - BlockTxServer *server = cbarg; - RequestHeader *hdr; - - if (clen != sizeof(RequestHeader)) { - seaf_warning ("Invalid block request header length %d.\n", clen); - send_block_response_header (server, STATUS_BAD_REQUEST); - return -1; - } - - hdr = (RequestHeader *)content; - hdr->command = ntohl (hdr->command); - - if (hdr->command != REQUEST_COMMAND_GET && - hdr->command != REQUEST_COMMAND_PUT) { - seaf_warning ("Unknow command %d.\n", hdr->command); - send_block_response_header (server, STATUS_BAD_REQUEST); - return -1; - } - - server->command = hdr->command; - memcpy (server->curr_block_id, hdr->block_id, 40); - - if (server->command == REQUEST_COMMAND_GET) { - BlockMetadata *md; - int block_size; - - seaf_debug ("Received GET request for block %s.\n", server->curr_block_id); - - md = seaf_block_manager_stat_block (seaf->block_mgr, - server->store_id, - server->repo_version, - server->curr_block_id); - if (!md) { - seaf_warning ("Failed to stat block %s:%s.\n", - server->store_id, server->curr_block_id); - send_block_response_header (server, STATUS_NOT_FOUND); - return -1; - } - block_size = md->size; - g_free (md); - - if (send_block_response_header (server, STATUS_OK) < 0) - return -1; - - if (send_block_content (server, block_size) < 0) - return -1; - - seaf_debug ("recv_state set to HEADER.\n"); - - server->recv_state = RECV_STATE_HEADER; - } else { - seaf_debug ("Received PUT request for block %s.\n", server->curr_block_id); - - server->block = seaf_block_manager_open_block (seaf->block_mgr, - server->store_id, - server->repo_version, - server->curr_block_id, - BLOCK_WRITE); - if (!server->block) { - seaf_warning ("Failed to open block %s:%s for write.\n", - server->store_id, server->curr_block_id); - send_block_response_header (server, STATUS_INTERNAL_SERVER_ERROR); - return -1; - } - - seaf_debug ("recv_state set to CONTENT.\n"); - - server->parser.fragment_cb = save_block_content_cb; - server->recv_state = RECV_STATE_CONTENT; - } - - return 0; -} - -static int -handle_block_header (BlockTxServer *server) -{ - return handle_one_frame (server->recv_buf, &server->parser); -} - -/* Block content */ - -#define SEND_BUFFER_SIZE 4096 - -static int -send_encrypted_block (BlockTxServer *server, - BlockHandle *handle, - const char *block_id, - int size) -{ - int n, remain; - int ret = 0; - EVP_CIPHER_CTX ctx; - char send_buf[SEND_BUFFER_SIZE]; - - if (server->version == 1) - blocktx_encrypt_init (&ctx, server->key, server->iv); - else if (server->version == 2) - blocktx_encrypt_init (&ctx, server->key_v2, server->iv_v2); - - if (send_encrypted_data_frame_begin (server->data_fd, size) < 0) { - seaf_warning ("Send block %s: failed to begin.\n", block_id); - ret = -1; - goto out; - } - - remain = size; - while (remain > 0) { - n = seaf_block_manager_read_block (seaf->block_mgr, - handle, - send_buf, SEND_BUFFER_SIZE); - if (n < 0) { - seaf_warning ("Failed to read block %s.\n", block_id); - ret = -1; - goto out; - } - - if (send_encrypted_data (&ctx, server->data_fd, send_buf, n) < 0) { - seaf_warning ("Send block %s: failed to send data.\n", block_id); - ret = -1; - goto out; - } - - remain -= n; - } - - if (send_encrypted_data_frame_end (&ctx, server->data_fd) < 0) { - seaf_warning ("Send block %s: failed to end.\n", block_id); - ret = -1; - goto out; - } - - seaf_debug ("Send block %s done.\n", server->curr_block_id); - -out: - EVP_CIPHER_CTX_cleanup (&ctx); - return ret; -} - -static int -send_block_content (BlockTxServer *server, int block_size) -{ - BlockHandle *handle = NULL; - int ret = 0; - - handle = seaf_block_manager_open_block (seaf->block_mgr, - server->store_id, - server->repo_version, - server->curr_block_id, - BLOCK_READ); - if (!handle) { - seaf_warning ("Failed to open block %s:%s.\n", - server->store_id, server->curr_block_id); - return -1; - } - - ret = send_encrypted_block (server, handle, server->curr_block_id, block_size); - - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - return ret; -} - -static int -save_block_content_cb (char *content, int clen, int end, void *cbarg) -{ - BlockTxServer *server = cbarg; - int n; - - n = seaf_block_manager_write_block (seaf->block_mgr, server->block, - content, clen); - if (n < 0) { - seaf_warning ("Failed to write block %s.\n", server->curr_block_id); - send_block_response_header (server, STATUS_INTERNAL_SERVER_ERROR); - return -1; - } - - if (end) { - if (seaf_block_manager_close_block (seaf->block_mgr, server->block) < 0) { - seaf_warning ("Failed to close block %s.\n", server->curr_block_id); - send_block_response_header (server, STATUS_INTERNAL_SERVER_ERROR); - return -1; - } - - if (seaf_block_manager_commit_block (seaf->block_mgr, server->block) < 0) { - seaf_warning ("Failed to commit block %s.\n", server->curr_block_id); - send_block_response_header (server, STATUS_INTERNAL_SERVER_ERROR); - return -1; - } - - seaf_block_manager_block_handle_free (seaf->block_mgr, server->block); - /* Set this handle to invalid. */ - server->block = NULL; - - send_block_response_header (server, STATUS_OK); - - seaf_debug ("Receive block %s done.\n", server->curr_block_id); - seaf_debug ("recv_state set to HEADER.\n"); - - server->recv_state = RECV_STATE_HEADER; - } - - return 0; -} - -static int -handle_block_content (BlockTxServer *server) -{ - return handle_frame_fragments (server->recv_buf, &server->parser); -} - -static void -recv_data_cb (BlockTxServer *server) -{ - int ret = 0; - - /* Let evbuffer determine how much data can be read. */ - int n = evbuffer_read (server->recv_buf, server->data_fd, -1); - if (n == 0) { - seaf_debug ("Data connection is closed by the client. Transfer done.\n"); - server->break_loop = TRUE; - return; - } else if (n < 0) { - seaf_warning ("Read data connection error: %s.\n", - evutil_socket_error_to_string(evutil_socket_geterror(server->data_fd))); - server->break_loop = TRUE; - return; - } - - switch (server->recv_state) { - case RECV_STATE_HANDSHAKE: - ret = handle_handshake_request (server); - break; - case RECV_STATE_AUTH: - ret = handle_auth_request (server); - break; - case RECV_STATE_HEADER: - ret = handle_block_header (server); - if (ret < 0) - break; - - if (server->recv_state == RECV_STATE_CONTENT && - server->command == REQUEST_COMMAND_PUT) - ret = handle_block_content (server); - - break; - case RECV_STATE_CONTENT: - ret = handle_block_content (server); - break; - } - - if (ret < 0) - server->break_loop = TRUE; -} - -#define BLOCKTX_TIMEOUT 30 - -static void -server_thread_loop (BlockTxServer *server) -{ - fd_set fds; - struct timeval tv = { BLOCKTX_TIMEOUT, 0 }; - int rc; - - while (1) { - FD_ZERO (&fds); - FD_SET (server->data_fd, &fds); - tv.tv_sec = BLOCKTX_TIMEOUT; - tv.tv_usec = 0; - - rc = select (server->data_fd + 1, &fds, NULL, NULL, &tv); - if (rc < 0 && errno == EINTR) { - continue; - } else if (rc < 0) { - seaf_warning ("select error: %s.\n", strerror(errno)); - break; - } - - if (rc == 0) { - seaf_warning ("Recv block timeout.\n"); - break; - } - - if (FD_ISSET (server->data_fd, &fds)) { - recv_data_cb (server); - if (server->break_loop) - break; - } - } -} - -static void * -block_tx_server_thread (void *vdata) -{ - BlockTxServer *server = vdata; - - server->recv_buf = evbuffer_new (); - - server_thread_loop (server); - - if (server->block) { - seaf_block_manager_close_block (seaf->block_mgr, server->block); - seaf_block_manager_block_handle_free (seaf->block_mgr, server->block); - } - - if (server->parser.enc_init) - EVP_CIPHER_CTX_cleanup (&server->parser.ctx); - - evbuffer_free (server->recv_buf); - evutil_closesocket (server->data_fd); - - return vdata; -} - -static void -block_tx_server_thread_done (void *vdata) -{ - BlockTxServer *server = vdata; - - g_free (server); -} - -int -block_tx_server_start (evutil_socket_t data_fd) -{ - BlockTxServer *server = g_new0 (BlockTxServer, 1); - int ret = 0; - - int val = 1; - ev_socklen_t optlen = sizeof(int); - setsockopt (data_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, optlen); - - server->data_fd = data_fd; - - ret = ccnet_job_manager_schedule_job (seaf->job_mgr, - block_tx_server_thread, - block_tx_server_thread_done, - server); - if (ret < 0) { - seaf_warning ("Failed to start block tx server thread.\n"); - return -1; - } - - return 0; -} diff --git a/server/block-tx-server.h b/server/block-tx-server.h deleted file mode 100644 index cc9bb4e4..00000000 --- a/server/block-tx-server.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef BLOCK_TX_SERVER_H -#define BLOCK_TX_SERVER_H - -#include - -int -block_tx_server_start (evutil_socket_t data_fd); - -#endif diff --git a/server/chunkserv-mgr.c b/server/chunkserv-mgr.c deleted file mode 100644 index 4bd959c7..00000000 --- a/server/chunkserv-mgr.c +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include - -#include -#include "seafile-session.h" -#include "chunkserv-mgr.h" -#include "processors/putcs-proc.h" - -#define CHUNKSERVER_DB "chunkserver.db" - -SeafCSManager * -seaf_cs_manager_new (SeafileSession *seaf) -{ - SeafCSManager *mgr = g_new0 (SeafCSManager, 1); - - /* char *db_path = g_build_filename (seaf->seaf_dir, CHUNKSERVER_DB, NULL); */ - /* if (sqlite_open_db (db_path, &mgr->db) < 0) { */ - /* g_critical ("Failed to open chunk server db\n"); */ - /* g_free (db_path); */ - /* g_free (mgr); */ - /* return NULL; */ - /* } */ - - mgr->seaf = seaf; - mgr->chunk_servers = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - return mgr; -} - -static int -load_chunk_servers (SeafCSManager *mgr) -{ - /* char sql[256]; */ - /* sqlite3_stmt *stmt; */ - /* int result; */ - /* char *cs_id; */ - - /* snprintf (sql, 256, "SELECT cs_id FROM chunkservers;"); */ - - /* stmt = sqlite_query_prepare (mgr->db, sql); */ - /* if (!stmt) */ - /* return -1; */ - - /* while ((result = sqlite3_step (stmt)) == SQLITE_ROW) { */ - /* cs_id = (char *) sqlite3_column_text (stmt, 0); */ - /* g_hash_table_insert (mgr->chunk_servers, g_strdup(cs_id), NULL); */ - /* } */ - - /* if (result == SQLITE_ERROR) { */ - /* const gchar *str = sqlite3_errmsg (mgr->db); */ - - /* g_warning ("Couldn't execute query, error: %d->'%s'\n", */ - /* result, str ? str : "no error given"); */ - /* sqlite3_finalize (stmt); */ - - /* return -1; */ - /* } */ - /* sqlite3_finalize (stmt); */ - - /* Add myself as chunk server by default. */ - g_hash_table_insert (mgr->chunk_servers, - g_strdup(mgr->seaf->session->base.id), - NULL); - - return 0; -} - -static void -register_processors (SeafCSManager *mgr) -{ - CcnetClient *client = mgr->seaf->session; - - ccnet_register_service (client, "seafile-putcs", "basic", - SEAFILE_TYPE_PUTCS_PROC, NULL); -} - -int -seaf_cs_manager_start (SeafCSManager *mgr) -{ - /* const char *sql; */ - - register_processors (mgr); - - /* sql = "CREATE TABLE IF NOT EXISTS chunkservers " */ - /* "(id INTEGER PRIMARY KEY, cs_id TEXT);"; */ - /* if (sqlite_query_exec (mgr->db, sql) < 0) */ - /* return -1; */ - - return (load_chunk_servers (mgr)); -} - -int -seaf_cs_manager_add_chunk_server (SeafCSManager *mgr, const char *cs_id) -{ - char sql[256]; - - snprintf (sql, 256, "INSERT INTO chunkservers VALUES (NULL, '%s');", cs_id); - if (sqlite_query_exec (mgr->db, sql) < 0) - return -1; - - g_hash_table_insert (mgr->chunk_servers, g_strdup(cs_id), NULL); - - return 0; -} - -int -seaf_cs_manager_del_chunk_server (SeafCSManager *mgr, const char *cs_id) -{ - char sql[256]; - - snprintf (sql, 256, "DELETE FROM chunkservers WHERE cs_id = '%s';", cs_id); - if (sqlite_query_exec (mgr->db, sql) < 0) - return -1; - - g_hash_table_remove (mgr->chunk_servers, cs_id); - - return 0; -} - -GList* -seaf_cs_manager_get_chunk_servers (SeafCSManager *mgr) -{ - return (g_hash_table_get_keys(mgr->chunk_servers)); -} diff --git a/server/chunkserv-mgr.h b/server/chunkserv-mgr.h deleted file mode 100644 index 67362804..00000000 --- a/server/chunkserv-mgr.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CHUNKSERV_MGR_H -#define CHUNKSERV_MGR_H - -#include -#include - -struct _SeafileSession; - -struct _SeafCSManager { - struct _SeafileSession *seaf; - GHashTable *chunk_servers; - sqlite3 *db; -}; -typedef struct _SeafCSManager SeafCSManager; - -SeafCSManager* seaf_cs_manager_new (struct _SeafileSession *seaf); -int seaf_cs_manager_start (SeafCSManager *mgr); - -int seaf_cs_manager_add_chunk_server (SeafCSManager *mgr, const char *cs_id); -int seaf_cs_manager_del_chunk_server (SeafCSManager *mgr, const char *cs_id); -GList* seaf_cs_manager_get_chunk_servers (SeafCSManager *mgr); - -#endif diff --git a/server/copy-mgr.c b/server/copy-mgr.c deleted file mode 100644 index 5e823901..00000000 --- a/server/copy-mgr.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "common.h" -#include "log.h" - -#include - -#include - -#include "seafile-session.h" -#include "seafile-object.h" -#include "seafile-error.h" - -#include "copy-mgr.h" - -#include "utils.h" - -#include "log.h" - -#define DEFAULT_MAX_THREADS 50 - -struct _SeafCopyManagerPriv { - GHashTable *copy_tasks; - pthread_mutex_t lock; - CcnetJobManager *job_mgr; -}; - -static void -copy_task_free (CopyTask *task) -{ - if (!task) return; - - g_free (task); -} - -SeafCopyManager * -seaf_copy_manager_new (struct _SeafileSession *session) -{ - SeafCopyManager *mgr = g_new0 (SeafCopyManager, 1); - - mgr->session = session; - mgr->priv = g_new0 (struct _SeafCopyManagerPriv, 1); - mgr->priv->copy_tasks = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, - (GDestroyNotify)copy_task_free); - pthread_mutex_init (&mgr->priv->lock, NULL); - - mgr->max_files = g_key_file_get_int64 (session->config, - "web_copy", "max_files", NULL); - mgr->max_size = g_key_file_get_int64 (session->config, - "web_copy", "max_size", NULL); - /* size is given in MB */ - mgr->max_size <<= 20; - - return mgr; -} - -int -seaf_copy_manager_start (SeafCopyManager *mgr) -{ - mgr->priv->job_mgr = ccnet_job_manager_new (DEFAULT_MAX_THREADS); - - return 1; -} - -SeafileCopyTask * -seaf_copy_manager_get_task (SeafCopyManager *mgr, - const char *task_id) -{ - SeafCopyManagerPriv *priv = mgr->priv; - CopyTask *task; - SeafileCopyTask *t = NULL; - - pthread_mutex_lock (&priv->lock); - - task = g_hash_table_lookup (priv->copy_tasks, task_id); - if (task) { - t = seafile_copy_task_new (); - g_object_set (t, "done", task->done, "total", task->total, - "canceled", task->canceled, "failed", task->failed, - "successful", task->successful, - NULL); - } - - pthread_mutex_unlock (&priv->lock); - - return t; -} - -struct CopyThreadData { - SeafCopyManager *mgr; - char src_repo_id[37]; - char *src_path; - char *src_filename; - char dst_repo_id[37]; - char *dst_path; - char *dst_filename; - int replace; - char *modifier; - CopyTask *task; - CopyTaskFunc func; -}; -typedef struct CopyThreadData CopyThreadData; - -static void * -copy_thread (void *vdata) -{ - CopyThreadData *data = vdata; - - data->func (data->src_repo_id, data->src_path, data->src_filename, - data->dst_repo_id, data->dst_path, data->dst_filename, - data->replace, data->modifier, data->task); - - return vdata; -} - -static void -copy_done (void *vdata) -{ - CopyThreadData *data = vdata; - - g_free (data->src_path); - g_free (data->src_filename); - g_free (data->dst_path); - g_free (data->dst_filename); - g_free (data->modifier); - g_free (data); -} - -char * -seaf_copy_manager_add_task (SeafCopyManager *mgr, - const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - int replace, - const char *modifier, - gint64 total_files, - CopyTaskFunc function, - gboolean need_progress) -{ - SeafCopyManagerPriv *priv = mgr->priv; - char *task_id = NULL; - CopyTask *task = NULL; - struct CopyThreadData *data; - - if (need_progress) { - task_id = gen_uuid(); - task = g_new0 (CopyTask, 1); - memcpy (task->task_id, task_id, 36); - task->total = total_files; - - pthread_mutex_lock (&priv->lock); - g_hash_table_insert (priv->copy_tasks, g_strdup(task_id), task); - pthread_mutex_unlock (&priv->lock); - } - - data = g_new0 (CopyThreadData, 1); - data->mgr = mgr; - memcpy (data->src_repo_id, src_repo_id, 36); - data->src_path = g_strdup(src_path); - data->src_filename = g_strdup(src_filename); - memcpy (data->dst_repo_id, dst_repo_id, 36); - data->dst_path = g_strdup(dst_path); - data->dst_filename = g_strdup(dst_filename); - data->replace = replace; - data->modifier = g_strdup(modifier); - data->task = task; - data->func = function; - - ccnet_job_manager_schedule_job (mgr->priv->job_mgr, - copy_thread, - copy_done, - data); - return task_id; -} - -int -seaf_copy_manager_cancel_task (SeafCopyManager *mgr, const char *task_id) -{ - SeafCopyManagerPriv *priv = mgr->priv; - CopyTask *task; - - pthread_mutex_lock (&priv->lock); - - task = g_hash_table_lookup (priv->copy_tasks, task_id); - - pthread_mutex_unlock (&priv->lock); - - if (task) { - if (task->canceled || task->failed || task->successful) - return -1; - g_atomic_int_set (&task->canceled, 1); - } - - return 0; -} diff --git a/server/copy-mgr.h b/server/copy-mgr.h deleted file mode 100644 index 4b26f374..00000000 --- a/server/copy-mgr.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef COPY_MGR_H -#define COPY_MGR_H - -#include - -struct _SeafileSession; -struct _SeafCopyManagerPriv; -struct _SeafileCopyTask; - -struct _SeafCopyManager { - struct _SeafileSession *session; - struct _SeafCopyManagerPriv *priv; - - gint64 max_files; - gint64 max_size; -}; -typedef struct _SeafCopyManager SeafCopyManager; -typedef struct _SeafCopyManagerPriv SeafCopyManagerPriv; - -struct CopyTask { - char task_id[37]; - gint64 done; - gint64 total; - gint canceled; - gboolean failed; - gboolean successful; -}; -typedef struct CopyTask CopyTask; - -SeafCopyManager * -seaf_copy_manager_new (struct _SeafileSession *session); - -int -seaf_copy_manager_start (SeafCopyManager *mgr); - -typedef int (*CopyTaskFunc) (const char *, const char *, const char *, - const char *, const char *, const char *, - int, const char *, CopyTask *); - -char * -seaf_copy_manager_add_task (SeafCopyManager *mgr, - const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - int replace, - const char *modifier, - gint64 total_files, - CopyTaskFunc function, - gboolean need_progress); - -struct _SeafileCopyTask * -seaf_copy_manager_get_task (SeafCopyManager *mgr, - const char * id); - -int -seaf_copy_manager_cancel_task (SeafCopyManager *mgr, const char *task_id); - -#endif diff --git a/server/fileserver-config.c b/server/fileserver-config.c deleted file mode 100644 index 984e77ce..00000000 --- a/server/fileserver-config.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "common.h" - -#include - -#include "fileserver-config.h" - -const char *OLD_GROUP_NAME = "httpserver"; -const char *GROUP_NAME = "fileserver"; - -static const char * -get_group_name(GKeyFile *config) -{ - return g_key_file_has_group (config, GROUP_NAME) ? GROUP_NAME : OLD_GROUP_NAME; -} - -int -fileserver_config_get_integer(GKeyFile *config, char *key, GError **error) -{ - const char *group = get_group_name(config); - return g_key_file_get_integer (config, group, key, error); -} - -char * -fileserver_config_get_string(GKeyFile *config, char *key, GError **error) -{ - const char *group = get_group_name(config); - return g_key_file_get_string (config, group, key, error); -} - -gboolean -fileserver_config_get_boolean(GKeyFile *config, char *key, GError **error) -{ - const char *group = get_group_name(config); - return g_key_file_get_boolean (config, group, key, error); -} diff --git a/server/fileserver-config.h b/server/fileserver-config.h deleted file mode 100644 index 9bc44073..00000000 --- a/server/fileserver-config.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SEAFILE_FILESERVER_CONFIG_H -#define SEAFILE_FILESERVER_CONFIG_H - -struct GKeyFile; - -int -fileserver_config_get_integer(GKeyFile *config, char *key, GError **error); - -char * -fileserver_config_get_string(GKeyFile *config, char *key, GError **error); - -gboolean -fileserver_config_get_boolean(GKeyFile *config, char *key, GError **error); - -#endif // SEAFILE_FILESERVER_CONFIG_H diff --git a/server/gc/Makefile.am b/server/gc/Makefile.am deleted file mode 100644 index 8df8f45c..00000000 --- a/server/gc/Makefile.am +++ /dev/null @@ -1,94 +0,0 @@ - -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - -DSEAFILE_SERVER \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/common \ - @CCNET_CFLAGS@ \ - @SEARPC_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @ZDB_CFLAGS@ \ - @MSVC_CFLAGS@ \ - @CURL_CFLAGS@ \ - -Wall - -bin_PROGRAMS = seafserv-gc seaf-fsck seaf-migrate - -noinst_HEADERS = \ - seafile-session.h \ - repo-mgr.h \ - verify.h \ - fsck.h \ - gc-core.h - -common_sources = \ - seafile-session.c \ - repo-mgr.c \ - ../../common/seaf-db.c \ - ../../common/branch-mgr.c \ - ../../common/fs-mgr.c \ - ../../common/block-mgr.c \ - ../../common/block-backend.c \ - ../../common/block-backend-fs.c \ - ../../common/commit-mgr.c \ - ../../common/log.c \ - ../../common/seaf-utils.c \ - ../../common/obj-store.c \ - ../../common/obj-backend-fs.c \ - ../../common/seafile-crypt.c - -seafserv_gc_SOURCES = \ - seafserv-gc.c \ - verify.c \ - gc-core.c \ - $(common_sources) - -seafserv_gc_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/common/cdc/libcdc.la \ - $(top_builddir)/lib/libseafile_common.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ - -seafserv_gc_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ - -seaf_fsck_SOURCES = \ - seaf-fsck.c \ - fsck.c \ - $(common_sources) - -seaf_fsck_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/common/cdc/libcdc.la \ - $(top_builddir)/lib/libseafile_common.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ - -seaf_fsck_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ - -seaf_migrate_SOURCES = \ - seaf-migrate.c \ - $(common_sources) - -seaf_migrate_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/common/cdc/libcdc.la \ - $(top_builddir)/lib/libseafile_common.la \ - @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ - @SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ - -seaf_migrate_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ - -seaf_migrate_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - -DSEAFILE_SERVER -DMIGRATION \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib \ - -I$(top_srcdir)/common \ - @CCNET_CFLAGS@ \ - @SEARPC_CFLAGS@ \ - @GLIB2_CFLAGS@ \ - @ZDB_CFLAGS@ \ - @MSVC_CFLAGS@ \ - @CURL_CFLAGS@ \ - -Wall diff --git a/server/gc/fsck.c b/server/gc/fsck.c deleted file mode 100644 index 98541b4a..00000000 --- a/server/gc/fsck.c +++ /dev/null @@ -1,1118 +0,0 @@ -#include "common.h" - -#include - -#include "seafile-session.h" -#include "log.h" -#include "utils.h" - -#include "fsck.h" - -typedef struct FsckData { - gboolean repair; - SeafRepo *repo; - GHashTable *existing_blocks; - GList *repaired_files; - GList *repaired_folders; -} FsckData; - -typedef enum VerifyType { - VERIFY_FILE, - VERIFY_DIR -} VerifyType; - -static gboolean -fsck_verify_seafobj (const char *store_id, - int version, - const char *obj_id, - gboolean *io_error, - VerifyType type, - gboolean repair) -{ - gboolean valid = TRUE; - - valid = seaf_fs_manager_object_exists (seaf->fs_mgr, store_id, - version, obj_id); - if (!valid) { - if (type == VERIFY_FILE) { - seaf_message ("File %s is missing.\n", obj_id); - } else if (type == VERIFY_DIR) { - seaf_message ("Dir %s is missing.\n", obj_id); - } - return valid; - } - - if (type == VERIFY_FILE) { - valid = seaf_fs_manager_verify_seafile (seaf->fs_mgr, store_id, version, - obj_id, TRUE, io_error); - if (!valid && !*io_error && repair) { - seaf_message ("File %s is corrupted, remove it.\n", obj_id); - seaf_fs_manager_delete_object (seaf->fs_mgr, store_id, version, obj_id); - } - } else if (type == VERIFY_DIR) { - valid = seaf_fs_manager_verify_seafdir (seaf->fs_mgr, store_id, version, - obj_id, TRUE, io_error); - if (!valid && !*io_error && repair) { - seaf_message ("Dir %s is corrupted, remove it.\n", obj_id); - seaf_fs_manager_delete_object (seaf->fs_mgr, store_id, version, obj_id); - } - } - - return valid; -} - -static int -check_blocks (const char *file_id, FsckData *fsck_data, gboolean *io_error) -{ - Seafile *seafile; - int i; - char *block_id; - int ret = 0; - int dummy; - - gboolean ok = TRUE; - SeafRepo *repo = fsck_data->repo; - const char *store_id = repo->store_id; - int version = repo->version; - - seafile = seaf_fs_manager_get_seafile (seaf->fs_mgr, store_id, - version, file_id); - - for (i = 0; i < seafile->n_blocks; ++i) { - block_id = seafile->blk_sha1s[i]; - - if (g_hash_table_lookup (fsck_data->existing_blocks, block_id)) - continue; - - if (!seaf_block_manager_block_exists (seaf->block_mgr, - store_id, version, - block_id)) { - seaf_warning ("Block %s:%s is missing.\n", store_id, block_id); - ret = -1; - break; - } - - // check block integrity, if not remove it - ok = seaf_block_manager_verify_block (seaf->block_mgr, - store_id, version, - block_id, io_error); - if (!ok) { - if (*io_error) { - ret = -1; - break; - } else { - if (fsck_data->repair) { - seaf_message ("Block %s is corrupted, remove it.\n", block_id); - seaf_block_manager_remove_block (seaf->block_mgr, - store_id, version, - block_id); - } else { - seaf_message ("Block %s is corrupted.\n", block_id); - } - ret = -1; - break; - } - } - - g_hash_table_insert (fsck_data->existing_blocks, g_strdup(block_id), &dummy); - } - - seafile_unref (seafile); - - return ret; -} - -static char* -fsck_check_dir_recursive (const char *id, const char *parent_dir, FsckData *fsck_data) -{ - SeafDir *dir; - SeafDir *new_dir; - GList *p; - SeafDirent *seaf_dent; - char *dir_id = NULL; - char *path = NULL; - gboolean io_error = FALSE; - - SeafFSManager *mgr = seaf->fs_mgr; - char *store_id = fsck_data->repo->store_id; - int version = fsck_data->repo->version; - gboolean is_corrupted = FALSE; - - dir = seaf_fs_manager_get_seafdir (mgr, store_id, version, id); - - for (p = dir->entries; p; p = p->next) { - seaf_dent = p->data; - io_error = FALSE; - - if (S_ISREG(seaf_dent->mode)) { - path = g_strdup_printf ("%s%s", parent_dir, seaf_dent->name); - if (!path) { - seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", - fsck_data->repo->id); - goto out; - } - if (!fsck_verify_seafobj (store_id, version, - seaf_dent->id, &io_error, - VERIFY_FILE, fsck_data->repair)) { - if (io_error) { - g_free (path); - goto out; - } - is_corrupted = TRUE; - if (fsck_data->repair) { - seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n", - path, seaf_dent->id); - } else { - seaf_message ("File %s(%.8s) is corrupted.\n", - path, seaf_dent->id); - } - // file corrupted, set it empty - memcpy (seaf_dent->id, EMPTY_SHA1, 40); - seaf_dent->mtime = (gint64)time(NULL); - seaf_dent->size = 0; - } else { - if (check_blocks (seaf_dent->id, fsck_data, &io_error) < 0) { - if (io_error) { - g_free (path); - goto out; - } - is_corrupted = TRUE; - if (fsck_data->repair) { - seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n", - path, seaf_dent->id); - } else { - seaf_message ("File %s(%.8s) is corrupted.\n", - path, seaf_dent->id); - } - // file corrupted, set it empty - memcpy (seaf_dent->id, EMPTY_SHA1, 40); - seaf_dent->mtime = (gint64)time(NULL); - seaf_dent->size = 0; - } - } - - if (is_corrupted) - fsck_data->repaired_files = g_list_prepend (fsck_data->repaired_files, - g_strdup(path)); - g_free (path); - } else if (S_ISDIR(seaf_dent->mode)) { - path = g_strdup_printf ("%s%s/", parent_dir, seaf_dent->name); - if (!path) { - seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", - fsck_data->repo->id); - goto out; - } - if (!fsck_verify_seafobj (store_id, version, - seaf_dent->id, &io_error, - VERIFY_DIR, fsck_data->repair)) { - if (io_error) { - g_free (path); - goto out; - } - if (fsck_data->repair) { - seaf_message ("Dir %s(%.8s) is corrupted, recreate an empty dir.\n", - path, seaf_dent->id); - } else { - seaf_message ("Dir %s(%.8s) is corrupted.\n", - path, seaf_dent->id); - } - is_corrupted = TRUE; - // dir corrupted, set it empty - memcpy (seaf_dent->id, EMPTY_SHA1, 40); - - fsck_data->repaired_folders = g_list_prepend (fsck_data->repaired_folders, - g_strdup(path)); - } else { - dir_id = fsck_check_dir_recursive (seaf_dent->id, path, fsck_data); - if (dir_id == NULL) { - // IO error - g_free (path); - goto out; - } - if (strcmp (dir_id, seaf_dent->id) != 0) { - is_corrupted = TRUE; - // dir corrupted, set it to new dir_id - memcpy (seaf_dent->id, dir_id, 41); - } - g_free (dir_id); - } - g_free (path); - } - } - - if (is_corrupted) { - new_dir = seaf_dir_new (NULL, dir->entries, version); - if (fsck_data->repair) { - if (seaf_dir_save (mgr, store_id, version, new_dir) < 0) { - seaf_warning ("Failed to save dir\n"); - seaf_dir_free (new_dir); - goto out; - } - } - dir_id = g_strdup (new_dir->dir_id); - seaf_dir_free (new_dir); - dir->entries = NULL; - } else { - dir_id = g_strdup (dir->dir_id); - } - -out: - seaf_dir_free (dir); - - return dir_id; -} - -static gboolean -collect_token_list (SeafDBRow *row, void *data) -{ - GList **p_tokens = data; - const char *token; - - token = seaf_db_row_get_column_text (row, 0); - *p_tokens = g_list_prepend (*p_tokens, g_strdup(token)); - - return TRUE; -} - -int -delete_repo_tokens (SeafRepo *repo) -{ - int ret = 0; - const char *template; - GList *token_list = NULL; - GList *ptr; - GString *token_list_str = g_string_new (""); - GString *sql = g_string_new (""); - int rc; - - template = "SELECT u.token FROM RepoUserToken as u WHERE u.repo_id=?"; - rc = seaf_db_statement_foreach_row (seaf->db, template, - collect_token_list, &token_list, - 1, "string", repo->id); - if (rc < 0) { - goto out; - } - - if (rc == 0) - goto out; - - for (ptr = token_list; ptr; ptr = ptr->next) { - const char *token = (char *)ptr->data; - if (token_list_str->len == 0) - g_string_append_printf (token_list_str, "'%s'", token); - else - g_string_append_printf (token_list_str, ",'%s'", token); - } - - /* Note that there is a size limit on sql query. In MySQL it's 1MB by default. - * Normally the token_list won't be that long. - */ - g_string_printf (sql, "DELETE FROM RepoUserToken WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (seaf->db, sql->str, 0); - if (rc < 0) { - goto out; - } - - g_string_printf (sql, "DELETE FROM RepoTokenPeerInfo WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (seaf->db, sql->str, 0); - if (rc < 0) { - goto out; - } - -out: - g_string_free (token_list_str, TRUE); - g_string_free (sql, TRUE); - g_list_free_full (token_list, (GDestroyNotify)g_free); - - if (rc < 0) { - ret = -1; - } - - return ret; -} - -static char * -gen_repair_commit_desc (GList *repaired_files, GList *repaired_folders) -{ - GString *desc = g_string_new("Repaired by system."); - GList *p; - char *path; - - if (!repaired_files && !repaired_folders) - return g_string_free (desc, FALSE); - - if (repaired_files) { - g_string_append (desc, "\nCorrupted files:\n"); - for (p = repaired_files; p; p = p->next) { - path = p->data; - g_string_append_printf (desc, "%s\n", path); - } - } - - if (repaired_folders) { - g_string_append (desc, "\nCorrupted folders:\n"); - for (p = repaired_folders; p; p = p->next) { - path = p->data; - g_string_append_printf (desc, "%s\n", path); - } - } - - return g_string_free (desc, FALSE); -} - -static void -reset_commit_to_repair (SeafRepo *repo, SeafCommit *parent, char *new_root_id, - GList *repaired_files, GList *repaired_folders) -{ - if (delete_repo_tokens (repo) < 0) { - seaf_warning ("Failed to delete repo sync tokens, abort repair.\n"); - return; - } - - char *desc = gen_repair_commit_desc (repaired_files, repaired_folders); - - SeafCommit *new_commit = NULL; - new_commit = seaf_commit_new (NULL, repo->id, new_root_id, - parent->creator_name, parent->creator_id, - desc, 0); - g_free (desc); - if (!new_commit) { - seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", - repo->id); - return; - } - - new_commit->parent_id = g_strdup (parent->commit_id); - seaf_repo_to_commit (repo, new_commit); - - seaf_message ("Update repo %.8s status to commit %.8s.\n", - repo->id, new_commit->commit_id); - seaf_branch_set_commit (repo->head, new_commit->commit_id); - if (seaf_branch_manager_add_branch (seaf->branch_mgr, repo->head) < 0) { - seaf_warning ("Update head of repo %.8s to commit %.8s failed, " - "recover failed.\n", repo->id, new_commit->commit_id); - } else { - seaf_commit_manager_add_commit (seaf->commit_mgr, new_commit); - } - seaf_commit_unref (new_commit); -} - -/* - * check and recover repo, for corrupted file or folder set it empty - */ -static void -check_and_recover_repo (SeafRepo *repo, gboolean reset, gboolean repair) -{ - FsckData fsck_data; - SeafCommit *rep_commit = NULL; - char *root_id = NULL; - - seaf_message ("Checking file system integrity of repo %s(%.8s)...\n", - repo->name, repo->id); - - rep_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, - repo->version, repo->head->commit_id); - if (!rep_commit) { - seaf_warning ("Failed to load commit %s of repo %s\n", - repo->head->commit_id, repo->id); - return; - } - - memset (&fsck_data, 0, sizeof(fsck_data)); - fsck_data.repair = repair; - fsck_data.repo = repo; - fsck_data.existing_blocks = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - root_id = fsck_check_dir_recursive (rep_commit->root_id, "/", &fsck_data); - g_hash_table_destroy (fsck_data.existing_blocks); - if (root_id == NULL) { - goto out; - } - - if (repair) { - if (strcmp (root_id, rep_commit->root_id) != 0) { - // some fs objects corrupted for the head commit, - // create new head commit using the new root_id - reset_commit_to_repair (repo, rep_commit, root_id, - fsck_data.repaired_files, - fsck_data.repaired_folders); - } else if (reset) { - // for reset commit but fs objects not corrupted, also create a repaired commit - reset_commit_to_repair (repo, rep_commit, rep_commit->root_id, - NULL, NULL); - } - } - -out: - g_list_free_full (fsck_data.repaired_files, g_free); - g_list_free_full (fsck_data.repaired_folders, g_free); - g_free (root_id); - seaf_commit_unref (rep_commit); -} - -static gint -compare_commit_by_ctime (gconstpointer a, gconstpointer b) -{ - const SeafCommit *commit_a = a; - const SeafCommit *commit_b = b; - - return (commit_b->ctime - commit_a->ctime); -} - -static gboolean -fsck_get_repo_commit (const char *repo_id, int version, - const char *obj_id, void *commit_list) -{ - void *data = NULL; - int data_len; - GList **cur_list = (GList **)commit_list; - - int ret = seaf_obj_store_read_obj (seaf->commit_mgr->obj_store, repo_id, - version, obj_id, &data, &data_len); - if (ret < 0 || data == NULL) - return TRUE; - - SeafCommit *cur_commit = seaf_commit_from_data (obj_id, data, data_len); - if (cur_commit != NULL) { - *cur_list = g_list_prepend (*cur_list, cur_commit); - } - - g_free(data); - return TRUE; -} - -static SeafRepo* -get_available_repo (char *repo_id, gboolean repair) -{ - GList *commit_list = NULL; - GList *temp_list = NULL; - SeafCommit *temp_commit = NULL; - SeafBranch *branch = NULL; - SeafRepo *repo = NULL; - SeafVirtRepo *vinfo = NULL; - gboolean io_error; - - seaf_message ("Scanning available commits...\n"); - - seaf_obj_store_foreach_obj (seaf->commit_mgr->obj_store, repo_id, - 1, fsck_get_repo_commit, &commit_list); - - if (commit_list == NULL) { - seaf_warning ("No available commits for repo %.8s, can't be repaired.\n", - repo_id); - return NULL; - } - - commit_list = g_list_sort (commit_list, compare_commit_by_ctime); - - repo = seaf_repo_new (repo_id, NULL, NULL); - if (repo == NULL) { - seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", - repo_id); - goto out; - } - - vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, repo_id); - if (vinfo) { - repo->is_virtual = TRUE; - memcpy (repo->store_id, vinfo->origin_repo_id, 36); - seaf_virtual_repo_info_free (vinfo); - } else { - repo->is_virtual = FALSE; - memcpy (repo->store_id, repo->id, 36); - } - - for (temp_list = commit_list; temp_list; temp_list = temp_list->next) { - temp_commit = temp_list->data; - io_error = FALSE; - - if (!fsck_verify_seafobj (repo->store_id, 1, temp_commit->root_id, - &io_error, VERIFY_DIR, repair)) { - if (io_error) { - seaf_repo_unref (repo); - repo = NULL; - goto out; - } - // fs object of this commit is corrupted, - // continue to verify next - continue; - } - - branch = seaf_branch_new ("master", repo_id, temp_commit->commit_id); - if (branch == NULL) { - seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", - repo_id); - seaf_repo_unref (repo); - repo = NULL; - goto out; - } - repo->head = branch; - seaf_repo_from_commit (repo, temp_commit); - - char time_buf[64]; - strftime (time_buf, 64, "%Y-%m-%d %H:%M:%S", localtime((time_t *)&temp_commit->ctime)); - seaf_message ("Find available commit %.8s(created at %s) for repo %.8s.\n", - temp_commit->commit_id, time_buf, repo_id); - break; - } - -out: - for (temp_list = commit_list; temp_list; temp_list = temp_list->next) { - temp_commit = temp_list->data; - seaf_commit_unref (temp_commit); - } - g_list_free (commit_list); - - return repo; -} - -static void -repair_repos (GList *repo_id_list, gboolean repair) -{ - GList *ptr; - char *repo_id; - SeafRepo *repo; - gboolean exists; - gboolean reset; - gboolean io_error; - - for (ptr = repo_id_list; ptr; ptr = ptr->next) { - reset = FALSE; - repo_id = ptr->data; - - seaf_message ("Running fsck for repo %s.\n", repo_id); - - if (!is_uuid_valid (repo_id)) { - seaf_warning ("Invalid repo id %s.\n", repo_id); - goto next; - } - - exists = seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id); - if (!exists) { - seaf_warning ("Repo %.8s doesn't exist.\n", repo_id); - goto next; - } - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - - if (!repo) { - seaf_message ("Repo %.8s HEAD commit is corrupted, " - "need to restore to an old version.\n", repo_id); - repo = get_available_repo (repo_id, repair); - if (!repo) { - goto next; - } - reset = TRUE; - } else { - SeafCommit *commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, - repo->version, - repo->head->commit_id); - if (!commit) { - seaf_warning ("Failed to get head commit %s of repo %s\n", - repo->head->commit_id, repo->id); - seaf_repo_unref (repo); - goto next; - } - - io_error = FALSE; - if (!fsck_verify_seafobj (repo->store_id, repo->version, - commit->root_id, &io_error, - VERIFY_DIR, repair)) { - if (io_error) { - seaf_commit_unref (commit); - seaf_repo_unref (repo); - goto next; - } else { - // root fs object is corrupted, get available commit - seaf_message ("Repo %.8s HEAD commit is corrupted, " - "need to restore to an old version.\n", repo_id); - seaf_commit_unref (commit); - seaf_repo_unref (repo); - repo = get_available_repo (repo_id, repair); - if (!repo) { - goto next; - } - reset = TRUE; - } - } else { - // head commit is available - seaf_commit_unref (commit); - } - } - - check_and_recover_repo (repo, reset, repair); - - seaf_repo_unref (repo); -next: - seaf_message ("Fsck finished for repo %.8s.\n\n", repo_id); - } -} - -int -seaf_fsck (GList *repo_id_list, gboolean repair) -{ - if (!repo_id_list) - repo_id_list = seaf_repo_manager_get_repo_id_list (seaf->repo_mgr); - - repair_repos (repo_id_list, repair); - - while (repo_id_list) { - g_free (repo_id_list->data); - repo_id_list = g_list_delete_link (repo_id_list, repo_id_list); - } - - return 0; -} - -/* Export files. */ - -/*static gboolean -write_enc_block_to_file (const char *repo_id, - int version, - const char *block_id, - SeafileCrypt *crypt, - int fd, - const char *path) -{ - BlockHandle *handle; - BlockMetadata *bmd; - char buf[64 * 1024]; - int n; - int remain; - EVP_CIPHER_CTX ctx; - char *dec_out; - int dec_out_len; - gboolean ret = TRUE; - - bmd = seaf_block_manager_stat_block (seaf->block_mgr, - repo_id, version, - block_id); - if (!bmd) { - seaf_warning ("Failed to stat block %s.\n", block_id); - return FALSE; - } - - handle = seaf_block_manager_open_block (seaf->block_mgr, - repo_id, version, - block_id, BLOCK_READ); - if (!handle) { - seaf_warning ("Failed to open block %s.\n", block_id); - g_free (bmd); - return FALSE; - } - - if (seafile_decrypt_init (&ctx, crypt->version, - crypt->key, crypt->iv) < 0) { - seaf_warning ("Failed to init decrypt.\n"); - ret = FALSE; - goto out; - } - - remain = bmd->size; - while (1) { - n = seaf_block_manager_read_block (seaf->block_mgr, handle, buf, sizeof(buf)); - if (n < 0) { - seaf_warning ("Failed to read block %s.\n", block_id); - ret = FALSE; - break; - } else if (n == 0) { - break; - } - remain -= n; - - dec_out = g_new0 (char, n + 16); - if (!dec_out) { - seaf_warning ("Failed to alloc memory.\n"); - ret = FALSE; - break; - } - - if (EVP_DecryptUpdate (&ctx, - (unsigned char *)dec_out, - &dec_out_len, - (unsigned char *)buf, - n) == 0) { - seaf_warning ("Failed to decrypt block %s .\n", block_id); - g_free (dec_out); - ret = FALSE; - break; - } - - if (writen (fd, dec_out, dec_out_len) != dec_out_len) { - seaf_warning ("Failed to write block %s to file %s.\n", - block_id, path); - g_free (dec_out); - ret = FALSE; - break; - } - - if (remain == 0) { - if (EVP_DecryptFinal_ex (&ctx, - (unsigned char *)dec_out, - &dec_out_len) == 0) { - seaf_warning ("Failed to decrypt block %s .\n", block_id); - g_free (dec_out); - ret = FALSE; - break; - } - if (dec_out_len > 0) { - if (writen (fd, dec_out, dec_out_len) != dec_out_len) { - seaf_warning ("Failed to write block %s to file %s.\n", - block_id, path); - g_free (dec_out); - ret = FALSE; - break; - } - } - } - - g_free (dec_out); - } - - EVP_CIPHER_CTX_cleanup (&ctx); - -out: - g_free (bmd); - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - - return ret; -}*/ - -static gboolean -write_nonenc_block_to_file (const char *repo_id, - int version, - const char *block_id, - int fd, - const char *path) -{ - BlockHandle *handle; - char buf[64 * 1024]; - gboolean ret = TRUE; - int n; - - handle = seaf_block_manager_open_block (seaf->block_mgr, - repo_id, version, - block_id, BLOCK_READ); - if (!handle) { - return FALSE; - } - - while (1) { - n = seaf_block_manager_read_block (seaf->block_mgr, handle, buf, sizeof(buf)); - if (n < 0) { - seaf_warning ("Failed to read block %s.\n", block_id); - ret = FALSE; - break; - } else if (n == 0) { - break; - } - - if (writen (fd, buf, n) != n) { - seaf_warning ("Failed to write block %s to file %s.\n", - block_id, path); - ret = FALSE; - break; - } - } - - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - - return ret; -} - -static void -create_file (const char *repo_id, - const char *file_id, - const char *path) -{ - int i; - char *block_id; - int fd; - Seafile *seafile; - gboolean ret = TRUE; - int version = 1; - - fd = g_open (path, O_CREAT | O_WRONLY | O_BINARY, 0666); - if (fd < 0) { - seaf_warning ("Open file %s failed: %s.\n", path, strerror (errno)); - return; - } - - seafile = seaf_fs_manager_get_seafile (seaf->fs_mgr, repo_id, - version, file_id); - if (!seafile) { - ret = FALSE; - goto out; - } - - for (i = 0; i < seafile->n_blocks; ++i) { - block_id = seafile->blk_sha1s[i]; - - ret = write_nonenc_block_to_file (repo_id, version, block_id, - fd, path); - if (!ret) { - break; - } - } - -out: - close (fd); - if (!ret) { - if (g_unlink (path) < 0) { - seaf_warning ("Failed to delete file %s: %s.\n", path, strerror (errno)); - } - seaf_message ("Failed to export file %s.\n", path); - } else { - seaf_message ("Export file %s.\n", path); - } - seafile_unref (seafile); -} - -static void -export_repo_files_recursive (const char *repo_id, - const char *id, - const char *parent_dir) -{ - SeafDir *dir; - GList *p; - SeafDirent *seaf_dent; - char *path; - - SeafFSManager *mgr = seaf->fs_mgr; - int version = 1; - - dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, id); - if (!dir) { - return; - } - - for (p = dir->entries; p; p = p->next) { - seaf_dent = p->data; - path = g_build_filename (parent_dir, seaf_dent->name, NULL); - - if (S_ISREG(seaf_dent->mode)) { - // create file - create_file (repo_id, seaf_dent->id, path); - } else if (S_ISDIR(seaf_dent->mode)) { - if (g_mkdir (path, 0777) < 0) { - seaf_warning ("Failed to mkdir %s: %s.\n", path, - strerror (errno)); - g_free (path); - continue; - } else { - seaf_message ("Export dir %s.\n", path); - } - - export_repo_files_recursive (repo_id, seaf_dent->id, path); - } - g_free (path); - } - - seaf_dir_free (dir); -} - -static SeafCommit* -get_available_commit (const char *repo_id) -{ - GList *commit_list = NULL; - GList *temp_list = NULL; - GList *next_list = NULL; - SeafCommit *temp_commit = NULL; - gboolean io_error; - - seaf_message ("Scanning available commits for repo %s...\n", repo_id); - - seaf_obj_store_foreach_obj (seaf->commit_mgr->obj_store, repo_id, - 1, fsck_get_repo_commit, &commit_list); - - if (commit_list == NULL) { - seaf_warning ("No available commits for repo %.8s, export failed.\n\n", - repo_id); - return NULL; - } - - commit_list = g_list_sort (commit_list, compare_commit_by_ctime); - temp_list = commit_list; - while (temp_list) { - next_list = temp_list->next; - temp_commit = temp_list->data; - io_error = FALSE; - - if (memcmp (temp_commit->root_id, EMPTY_SHA1, 40) == 0) { - seaf_commit_unref (temp_commit); - temp_commit = NULL; - temp_list = next_list; - continue; - } else if (!fsck_verify_seafobj (repo_id, 1, temp_commit->root_id, - &io_error, VERIFY_DIR, FALSE)) { - seaf_commit_unref (temp_commit); - temp_commit = NULL; - temp_list = next_list; - - if (io_error) { - break; - } - // fs object of this commit is corrupted, - // continue to verify next - continue; - } - - char time_buf[64]; - strftime (time_buf, 64, "%Y-%m-%d %H:%M:%S", localtime((time_t *)&temp_commit->ctime)); - seaf_message ("Find available commit %.8s(created at %s), will export files from it.\n", - temp_commit->commit_id, time_buf); - temp_list = next_list; - break; - } - - while (temp_list) { - seaf_commit_unref (temp_list->data); - temp_list = temp_list->next; - } - g_list_free (commit_list); - - if (!temp_commit && !io_error) { - seaf_warning ("No available commits for repo %.8s, export failed.\n\n", - repo_id); - } - - return temp_commit; -} - -void -export_repo_files (const char *repo_id, - const char *init_path, - GHashTable *enc_repos) -{ - SeafCommit *commit = get_available_commit (repo_id); - if (!commit) { - return; - } - if (commit->encrypted) { - g_hash_table_insert (enc_repos, g_strdup (repo_id), - g_strdup (commit->repo_name)); - seaf_commit_unref (commit); - return; - } - - seaf_message ("Start to export files for repo %.8s(%s).\n", - repo_id, commit->repo_name); - - char *dir_name = g_strdup_printf ("%.8s_%s_%s", repo_id, - commit->repo_name, - commit->creator_name); - char * export_path = g_build_filename (init_path, dir_name, NULL); - g_free (dir_name); - if (g_mkdir (export_path, 0777) < 0) { - seaf_warning ("Failed to create export dir %s: %s, export failed.\n", - export_path, strerror (errno)); - g_free (export_path); - seaf_commit_unref (commit); - return; - } - - export_repo_files_recursive (repo_id, commit->root_id, export_path); - - seaf_message ("Finish exporting files for repo %.8s.\n\n", repo_id); - - g_free (export_path); - seaf_commit_unref (commit); -} - -static GList * -get_repo_ids (const char *seafile_dir) -{ - GList *repo_ids = NULL; - char *commit_path = g_build_filename (seafile_dir, "storage", - "commits", NULL); - GError *error = NULL; - - GDir *dir = g_dir_open (commit_path, 0, &error); - if (!dir) { - seaf_warning ("Open dir %s failed: %s.\n", - commit_path, error->message); - g_clear_error (&error); - g_free (commit_path); - return NULL; - } - - const char *file_name; - while ((file_name = g_dir_read_name (dir)) != NULL) { - repo_ids = g_list_prepend (repo_ids, g_strdup (file_name)); - } - g_dir_close (dir); - - g_free (commit_path); - - return repo_ids; -} - -static void -print_enc_repo (gpointer key, gpointer value, gpointer user_data) -{ - seaf_message ("%s(%s)\n", (char *)key, (char *)value); -} - -void -export_file (GList *repo_id_list, const char *seafile_dir, char *export_path) -{ - struct stat dir_st; - - if (stat (export_path, &dir_st) < 0) { - if (errno == ENOENT) { - if (g_mkdir (export_path, 0777) < 0) { - seaf_warning ("Mkdir %s failed: %s.\n", - export_path, strerror (errno)); - return; - } - } else { - seaf_warning ("Stat path: %s failed: %s.\n", - export_path, strerror (errno)); - return; - } - } else { - if (!S_ISDIR(dir_st.st_mode)) { - seaf_warning ("%s already exist, but it is not a directory.\n", - export_path); - return; - } - } - - if (!repo_id_list) { - repo_id_list = get_repo_ids (seafile_dir); - if (!repo_id_list) - return; - } - - GList *iter = repo_id_list; - char *repo_id; - GHashTable *enc_repos = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - for (; iter; iter=iter->next) { - repo_id = iter->data; - if (!is_uuid_valid (repo_id)) { - seaf_warning ("Invalid repo id: %s.\n", repo_id); - continue; - } - - export_repo_files (repo_id, export_path, enc_repos); - } - - if (g_hash_table_size (enc_repos) > 0) { - seaf_message ("The following repos are encrypted and are not exported:\n"); - g_hash_table_foreach (enc_repos, print_enc_repo, NULL); - } - - while (repo_id_list) { - g_free (repo_id_list->data); - repo_id_list = g_list_delete_link (repo_id_list, repo_id_list); - } - g_hash_table_destroy (enc_repos); - g_free (export_path); -} diff --git a/server/gc/fsck.h b/server/gc/fsck.h deleted file mode 100644 index 9bce69fb..00000000 --- a/server/gc/fsck.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SEAF_FSCK_H -#define SEAF_FSCK_H - -int -seaf_fsck (GList *repo_id_list, gboolean repair); - -void export_file (GList *repo_id_list, const char *seafile_dir, char *export_path); - -#endif diff --git a/server/gc/gc-core.c b/server/gc/gc-core.c deleted file mode 100644 index d4ef5afd..00000000 --- a/server/gc/gc-core.c +++ /dev/null @@ -1,481 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include "seafile-session.h" -#include "bloom-filter.h" -#include "gc-core.h" -#include "utils.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" - -#define MAX_BF_SIZE (((size_t)1) << 29) /* 64 MB */ - -/* Total number of blocks to be scanned. */ -static guint64 total_blocks; -static guint64 removed_blocks; -static guint64 reachable_blocks; - -/* - * The number of bits in the bloom filter is 4 times the number of all blocks. - * Let m be the bits in the bf, n be the number of blocks to be added to the bf - * (the number of live blocks), and k = 3 (closed to optimal for m/n = 4), - * the probability of false-positive is - * - * p = (1 - e^(-kn/m))^k = 0.15 - * - * Because m = 4 * total_blocks >= 4 * (live blocks) = 4n, we should have p <= 0.15. - * Put it another way, we'll clean up at least 85% dead blocks in each gc operation. - * See http://en.wikipedia.org/wiki/Bloom_filter. - * - * Supose we have 8TB space, and the avg block size is 1MB, we'll have 8M blocks, then - * the size of bf is (8M * 4)/8 = 4MB. - * - * If total_blocks is a small number (e.g. < 100), we should try to clean all dead blocks. - * So we set the minimal size of the bf to 1KB. - */ -static Bloom * -alloc_gc_index () -{ - size_t size; - - size = (size_t) MAX(total_blocks << 2, 1 << 13); - size = MIN (size, MAX_BF_SIZE); - - seaf_message ("GC index size is %u Byte.\n", (int)size >> 3); - - return bloom_create (size, 3, 0); -} - -typedef struct { - SeafRepo *repo; - Bloom *index; - GHashTable *visited; - - /* > 0: keep a period of history; - * == 0: only keep data in head commit; - * < 0: keep all history data. - */ - gint64 truncate_time; - gboolean traversed_head; - - int traversed_commits; - gint64 traversed_blocks; - - int verbose; - gint64 traversed_fs_objs; -} GCData; - -static int -add_blocks_to_index (SeafFSManager *mgr, GCData *data, const char *file_id) -{ - SeafRepo *repo = data->repo; - Bloom *index = data->index; - Seafile *seafile; - int i; - - seafile = seaf_fs_manager_get_seafile (mgr, repo->store_id, repo->version, file_id); - if (!seafile) { - seaf_warning ("Failed to find file %s:%s.\n", repo->store_id, file_id); - return -1; - } - - for (i = 0; i < seafile->n_blocks; ++i) { - bloom_add (index, seafile->blk_sha1s[i]); - ++data->traversed_blocks; - } - - seafile_unref (seafile); - - return 0; -} - -static gboolean -fs_callback (SeafFSManager *mgr, - const char *store_id, - int version, - const char *obj_id, - int type, - void *user_data, - gboolean *stop) -{ - GCData *data = user_data; - - if (data->visited != NULL) { - if (g_hash_table_lookup (data->visited, obj_id) != NULL) { - *stop = TRUE; - return TRUE; - } - - char *key = g_strdup(obj_id); - g_hash_table_replace (data->visited, key, key); - } - - ++(data->traversed_fs_objs); - - if (type == SEAF_METADATA_TYPE_FILE && - add_blocks_to_index (mgr, data, obj_id) < 0) - return FALSE; - - return TRUE; -} - -static gboolean -traverse_commit (SeafCommit *commit, void *vdata, gboolean *stop) -{ - GCData *data = vdata; - int ret; - - if (data->truncate_time == 0) - { - *stop = TRUE; - /* Stop after traversing the head commit. */ - } - else if (data->truncate_time > 0 && - (gint64)(commit->ctime) < data->truncate_time && - data->traversed_head) - { - /* Still traverse the first commit older than truncate_time. - * If a file in the child commit of this commit is deleted, - * we need to access this commit in order to restore it - * from trash. - */ - *stop = TRUE; - } - - if (!data->traversed_head) - data->traversed_head = TRUE; - - if (data->verbose) - seaf_message ("Traversing commit %.8s.\n", commit->commit_id); - - ++data->traversed_commits; - - data->traversed_fs_objs = 0; - - ret = seaf_fs_manager_traverse_tree (seaf->fs_mgr, - data->repo->store_id, data->repo->version, - commit->root_id, - fs_callback, - data, FALSE); - if (ret < 0) - return FALSE; - - if (data->verbose) - seaf_message ("Traversed %"G_GINT64_FORMAT" fs objects.\n", - data->traversed_fs_objs); - - return TRUE; -} - -static int -populate_gc_index_for_repo (SeafRepo *repo, Bloom *index, int verbose) -{ - GList *branches, *ptr; - SeafBranch *branch; - GCData *data; - int ret = 0; - - if (!repo->is_virtual) - seaf_message ("Populating index for repo %.8s.\n", repo->id); - else - seaf_message ("Populating index for sub-repo %.8s.\n", repo->id); - - branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); - if (branches == NULL) { - seaf_warning ("[GC] Failed to get branch list of repo %s.\n", repo->id); - return -1; - } - - data = g_new0(GCData, 1); - data->repo = repo; - data->index = index; - data->visited = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - data->verbose = verbose; - - gint64 truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager, - repo->id); - if (truncate_time > 0) { - seaf_repo_manager_set_repo_valid_since (repo->manager, - repo->id, - truncate_time); - } else if (truncate_time == 0) { - /* Only the head commit is valid after GC if no history is kept. */ - SeafCommit *head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (head) - seaf_repo_manager_set_repo_valid_since (repo->manager, - repo->id, - head->ctime); - seaf_commit_unref (head); - } - - data->truncate_time = truncate_time; - - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - branch = ptr->data; - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - branch->commit_id, - traverse_commit, - data, - FALSE); - seaf_branch_unref (branch); - if (!res) { - ret = -1; - break; - } - } - - seaf_message ("Traversed %d commits, %"G_GINT64_FORMAT" blocks.\n", - data->traversed_commits, data->traversed_blocks); - reachable_blocks += data->traversed_blocks; - - g_list_free (branches); - g_hash_table_destroy (data->visited); - g_free (data); - - return ret; -} - -typedef struct { - Bloom *index; - int dry_run; -} CheckBlocksData; - -static gboolean -check_block_liveness (const char *store_id, int version, - const char *block_id, void *vdata) -{ - CheckBlocksData *data = vdata; - Bloom *index = data->index; - - if (!bloom_test (index, block_id)) { - ++removed_blocks; - if (!data->dry_run) - seaf_block_manager_remove_block (seaf->block_mgr, - store_id, version, - block_id); - } - - return TRUE; -} - -static int -populate_gc_index_for_virtual_repos (SeafRepo *repo, Bloom *index, int verbose) -{ - GList *vrepo_ids = NULL, *ptr; - char *repo_id; - SeafRepo *vrepo; - int ret = 0; - - vrepo_ids = seaf_repo_manager_get_virtual_repo_ids_by_origin (seaf->repo_mgr, - repo->id); - for (ptr = vrepo_ids; ptr; ptr = ptr->next) { - repo_id = ptr->data; - vrepo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!vrepo) { - seaf_warning ("Failed to get repo %s.\n", repo_id); - ret = -1; - goto out; - } - - ret = populate_gc_index_for_repo (vrepo, index, verbose); - seaf_repo_unref (vrepo); - if (ret < 0) - goto out; - } - -out: - string_list_free (vrepo_ids); - return ret; -} - -int -gc_v1_repo (SeafRepo *repo, int dry_run, int verbose) -{ - Bloom *index; - int ret; - - total_blocks = seaf_block_manager_get_block_number (seaf->block_mgr, - repo->store_id, repo->version); - removed_blocks = 0; - reachable_blocks = 0; - - if (total_blocks == 0) { - seaf_message ("No blocks. Skip GC.\n\n"); - return 0; - } - - seaf_message ("GC started. Total block number is %"G_GUINT64_FORMAT".\n", total_blocks); - - /* - * Store the index of live blocks in bloom filter to save memory. - * Since bloom filters only have false-positive, we - * may skip some garbage blocks, but we won't delete - * blocks that are still alive. - */ - index = alloc_gc_index (); - if (!index) { - seaf_warning ("GC: Failed to allocate index.\n"); - return -1; - } - - seaf_message ("Populating index.\n"); - - ret = populate_gc_index_for_repo (repo, index, verbose); - if (ret < 0) - goto out; - - /* Since virtual repos share fs and block store with the origin repo, - * it's necessary to do GC for them together. - */ - ret = populate_gc_index_for_virtual_repos (repo, index, verbose); - if (ret < 0) - goto out; - - if (!dry_run) - seaf_message ("Scanning and deleting unused blocks.\n"); - else - seaf_message ("Scanning unused blocks.\n"); - - CheckBlocksData data; - data.index = index; - data.dry_run = dry_run; - - ret = seaf_block_manager_foreach_block (seaf->block_mgr, - repo->store_id, repo->version, - check_block_liveness, - &data); - if (ret < 0) { - seaf_warning ("GC: Failed to clean dead blocks.\n"); - goto out; - } - - ret = removed_blocks; - - if (!dry_run) - seaf_message ("GC finished. %"G_GUINT64_FORMAT" blocks total, " - "about %"G_GUINT64_FORMAT" reachable blocks, " - "%"G_GUINT64_FORMAT" blocks are removed.\n", - total_blocks, reachable_blocks, removed_blocks); - else - seaf_message ("GC finished. %"G_GUINT64_FORMAT" blocks total, " - "about %"G_GUINT64_FORMAT" reachable blocks, " - "%"G_GUINT64_FORMAT" blocks can be removed.\n", - total_blocks, reachable_blocks, removed_blocks); - -out: - printf ("\n"); - - bloom_destroy (index); - return ret; -} - -void -delete_garbaged_repos (int dry_run) -{ - GList *del_repos = NULL; - GList *ptr; - - seaf_message ("=== Repos deleted by users ===\n"); - del_repos = seaf_repo_manager_list_garbage_repos (seaf->repo_mgr); - for (ptr = del_repos; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - - /* Confirm repo doesn't exist before removing blocks. */ - if (!seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id)) { - if (!dry_run) { - seaf_message ("GC deleted repo %.8s.\n", repo_id); - seaf_commit_manager_remove_store (seaf->commit_mgr, repo_id); - seaf_fs_manager_remove_store (seaf->fs_mgr, repo_id); - seaf_block_manager_remove_store (seaf->block_mgr, repo_id); - } else { - seaf_message ("Repo %.8s can be GC'ed.\n", repo_id); - } - } - - if (!dry_run) - seaf_repo_manager_remove_garbage_repo (seaf->repo_mgr, repo_id); - g_free (repo_id); - } - g_list_free (del_repos); -} - -int -gc_core_run (GList *repo_id_list, int dry_run, int verbose) -{ - GList *ptr; - SeafRepo *repo; - GList *corrupt_repos = NULL; - GList *del_block_repos = NULL; - gboolean del_garbage = FALSE; - int gc_ret; - char *repo_id; - - if (repo_id_list == NULL) { - repo_id_list = seaf_repo_manager_get_repo_id_list (seaf->repo_mgr); - del_garbage = TRUE; - } - - for (ptr = repo_id_list; ptr; ptr = ptr->next) { - repo = seaf_repo_manager_get_repo_ex (seaf->repo_mgr, (const gchar *)ptr->data); - - g_free (ptr->data); - - if (!repo) - continue; - - if (repo->is_corrupted) { - corrupt_repos = g_list_prepend (corrupt_repos, g_strdup(repo->id)); - seaf_message ("Repo %s is corrupted, skip GC.\n\n", repo->id); - continue; - } - - if (!repo->is_virtual) { - seaf_message ("GC version %d repo %s(%s)\n", - repo->version, repo->name, repo->id); - gc_ret = gc_v1_repo (repo, dry_run, verbose); - if (gc_ret < 0) { - corrupt_repos = g_list_prepend (corrupt_repos, g_strdup(repo->id)); - } else if (dry_run && gc_ret) { - del_block_repos = g_list_prepend (del_block_repos, g_strdup(repo->id)); - } - } - seaf_repo_unref (repo); - } - g_list_free (repo_id_list); - - if (del_garbage) { - delete_garbaged_repos (dry_run); - } - - seaf_message ("=== GC is finished ===\n"); - - if (corrupt_repos) { - seaf_message ("The following repos are corrupted. " - "You can run seaf-fsck to fix them.\n"); - for (ptr = corrupt_repos; ptr; ptr = ptr->next) { - repo_id = ptr->data; - seaf_message ("%s\n", repo_id); - g_free (repo_id); - } - g_list_free (corrupt_repos); - } - - if (del_block_repos) { - printf("\n"); - seaf_message ("The following repos have blocks to be removed:\n"); - for (ptr = del_block_repos; ptr; ptr = ptr->next) { - repo_id = ptr->data; - seaf_message ("%s\n", repo_id); - g_free (repo_id); - } - g_list_free (del_block_repos); - } - - return 0; -} diff --git a/server/gc/gc-core.h b/server/gc/gc-core.h deleted file mode 100644 index 88a1f1f0..00000000 --- a/server/gc/gc-core.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef GC_CORE_H -#define GC_CORE_H - -int gc_core_run (GList *repo_id_list, int dry_run, int verbose); - -void -delete_garbaged_repos (int dry_run); - -#endif diff --git a/server/gc/repo-mgr.c b/server/gc/repo-mgr.c deleted file mode 100644 index 79822018..00000000 --- a/server/gc/repo-mgr.c +++ /dev/null @@ -1,681 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" -#include - -#include -#include "utils.h" -#include "log.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "fs-mgr.h" -#include "seafile-error.h" - -#include "seaf-db.h" - -#define INDEX_DIR "index" - -struct _SeafRepoManagerPriv { - -}; - -static SeafRepo * -load_repo (SeafRepoManager *manager, const char *repo_id, gboolean ret_corrupt); - -gboolean -is_repo_id_valid (const char *id) -{ - if (!id) - return FALSE; - - return is_uuid_valid (id); -} - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc) -{ - SeafRepo* repo; - - /* valid check */ - - - repo = g_new0 (SeafRepo, 1); - memcpy (repo->id, id, 36); - repo->id[36] = '\0'; - - repo->name = g_strdup(name); - repo->desc = g_strdup(desc); - - repo->ref_cnt = 1; - - return repo; -} - -void -seaf_repo_free (SeafRepo *repo) -{ - if (repo->name) g_free (repo->name); - if (repo->desc) g_free (repo->desc); - if (repo->category) g_free (repo->category); - if (repo->head) seaf_branch_unref (repo->head); - g_free (repo); -} - -void -seaf_repo_ref (SeafRepo *repo) -{ - g_atomic_int_inc (&repo->ref_cnt); -} - -void -seaf_repo_unref (SeafRepo *repo) -{ - if (!repo) - return; - - if (g_atomic_int_dec_and_test (&repo->ref_cnt)) - seaf_repo_free (repo); -} - -static void -set_head_common (SeafRepo *repo, SeafBranch *branch) -{ - if (repo->head) - seaf_branch_unref (repo->head); - repo->head = branch; - seaf_branch_ref(branch); -} - -void -seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit) -{ - repo->name = g_strdup (commit->repo_name); - repo->desc = g_strdup (commit->repo_desc); - repo->encrypted = commit->encrypted; - repo->repaired = commit->repaired; - if (repo->encrypted) { - repo->enc_version = commit->enc_version; - if (repo->enc_version == 1) - memcpy (repo->magic, commit->magic, 32); - else if (repo->enc_version == 2) { - memcpy (repo->magic, commit->magic, 64); - memcpy (repo->random_key, commit->random_key, 96); - } - } - repo->no_local_history = commit->no_local_history; - repo->version = commit->version; -} - -void -seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit) -{ - commit->repo_name = g_strdup (repo->name); - commit->repo_desc = g_strdup (repo->desc); - commit->encrypted = repo->encrypted; - commit->repaired = repo->repaired; - if (commit->encrypted) { - commit->enc_version = repo->enc_version; - if (commit->enc_version == 1) - commit->magic = g_strdup (repo->magic); - else if (commit->enc_version == 2) { - commit->magic = g_strdup (repo->magic); - commit->random_key = g_strdup (repo->random_key); - } - } - commit->no_local_history = repo->no_local_history; - commit->version = repo->version; -} - -static gboolean -collect_commit (SeafCommit *commit, void *vlist, gboolean *stop) -{ - GList **commits = vlist; - - /* The traverse function will unref the commit, so we need to ref it. - */ - seaf_commit_ref (commit); - *commits = g_list_prepend (*commits, commit); - return TRUE; -} - -GList * -seaf_repo_get_commits (SeafRepo *repo) -{ - GList *branches; - GList *ptr; - SeafBranch *branch; - GList *commits = NULL; - - branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); - if (branches == NULL) { - seaf_warning ("Failed to get branch list of repo %s.\n", repo->id); - return NULL; - } - - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - branch = ptr->data; - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - branch->commit_id, - collect_commit, - &commits, - FALSE); - if (!res) { - for (ptr = commits; ptr != NULL; ptr = ptr->next) - seaf_commit_unref ((SeafCommit *)(ptr->data)); - g_list_free (commits); - goto out; - } - } - - commits = g_list_reverse (commits); - -out: - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - seaf_branch_unref ((SeafBranch *)ptr->data); - } - return commits; -} - -SeafRepoManager* -seaf_repo_manager_new (SeafileSession *seaf) -{ - SeafRepoManager *mgr = g_new0 (SeafRepoManager, 1); - - mgr->priv = g_new0 (SeafRepoManagerPriv, 1); - mgr->seaf = seaf; - - return mgr; -} - -int -seaf_repo_manager_init (SeafRepoManager *mgr) -{ - return 0; -} - -int -seaf_repo_manager_start (SeafRepoManager *mgr) -{ - return 0; -} - -static gboolean -repo_exists_in_db (SeafDB *db, const char *id) -{ - char sql[256]; - gboolean db_err = FALSE; - - snprintf (sql, sizeof(sql), "SELECT repo_id FROM Repo WHERE repo_id = '%s'", - id); - return seaf_db_check_for_existence (db, sql, &db_err); -} - -static gboolean -repo_exists_in_db_ex (SeafDB *db, const char *id, gboolean *db_err) -{ - char sql[256]; - - snprintf (sql, sizeof(sql), "SELECT repo_id FROM Repo WHERE repo_id = '%s'", - id); - return seaf_db_check_for_existence (db, sql, db_err); -} - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id) -{ - SeafRepo repo; - int len = strlen(id); - - if (len >= 37) - return NULL; - - memcpy (repo.id, id, len + 1); - - if (repo_exists_in_db (manager->seaf->db, id)) { - SeafRepo *ret = load_repo (manager, id, FALSE); - if (!ret) - return NULL; - /* seaf_repo_ref (ret); */ - return ret; - } - - return NULL; -} - -SeafRepo* -seaf_repo_manager_get_repo_ex (SeafRepoManager *manager, const gchar *id) -{ - int len = strlen(id); - gboolean db_err = FALSE, exists; - SeafRepo *ret = NULL; - - if (len >= 37) - return NULL; - - exists = repo_exists_in_db_ex (manager->seaf->db, id, &db_err); - - if (db_err) { - ret = seaf_repo_new(id, NULL, NULL); - ret->is_corrupted = TRUE; - return ret; - } - - if (exists) { - ret = load_repo (manager, id, TRUE); - return ret; - } - - return NULL; -} - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id) -{ - SeafRepo repo; - memcpy (repo.id, id, 37); - - return repo_exists_in_db (manager->seaf->db, id); -} - -static void -load_repo_commit (SeafRepoManager *manager, - SeafRepo *repo, - SeafBranch *branch) -{ - SeafCommit *commit; - - commit = seaf_commit_manager_get_commit_compatible (manager->seaf->commit_mgr, - repo->id, - branch->commit_id); - if (!commit) { - seaf_warning ("Commit %s is missing\n", branch->commit_id); - repo->is_corrupted = TRUE; - return; - } - - set_head_common (repo, branch); - seaf_repo_from_commit (repo, commit); - - seaf_commit_unref (commit); -} - -static SeafRepo * -load_repo (SeafRepoManager *manager, const char *repo_id, gboolean ret_corrupt) -{ - SeafRepo *repo; - SeafBranch *branch; - SeafVirtRepo *vinfo = NULL; - - repo = seaf_repo_new(repo_id, NULL, NULL); - if (!repo) { - seaf_warning ("[repo mgr] failed to alloc repo.\n"); - return NULL; - } - - repo->manager = manager; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); - if (!branch) { - seaf_warning ("Failed to get master branch of repo %.8s.\n", repo_id); - repo->is_corrupted = TRUE; - } else { - load_repo_commit (manager, repo, branch); - seaf_branch_unref (branch); - } - - if (repo->is_corrupted) { - if (!ret_corrupt) { - seaf_repo_free (repo); - return NULL; - } - return repo; - } - - vinfo = seaf_repo_manager_get_virtual_repo_info (manager, repo_id); - if (vinfo) { - repo->is_virtual = TRUE; - memcpy (repo->store_id, vinfo->origin_repo_id, 36); - } else { - repo->is_virtual = FALSE; - memcpy (repo->store_id, repo->id, 36); - } - seaf_virtual_repo_info_free (vinfo); - - return repo; -} - -static gboolean -collect_repo_id (SeafDBRow *row, void *data) -{ - GList **p_ids = data; - const char *repo_id; - - repo_id = seaf_db_row_get_column_text (row, 0); - *p_ids = g_list_prepend (*p_ids, g_strdup(repo_id)); - - return TRUE; -} - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr) -{ - GList *ret = NULL; - char sql[256]; - - snprintf (sql, 256, "SELECT repo_id FROM Repo"); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &ret) < 0) - return NULL; - - return ret; -} - -GList * -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, - int start, int limit, - gboolean *error) -{ - char sql[256]; - GList *id_list = NULL, *ptr; - GList *ret = NULL; - SeafRepo *repo; - - *error = FALSE; - - if (start == -1 && limit == -1) - snprintf (sql, 256, "SELECT repo_id FROM Repo"); - else - snprintf (sql, 256, "SELECT repo_id FROM Repo LIMIT %d, %d", start, limit); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &id_list) < 0) - goto error; - - for (ptr = id_list; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - repo = seaf_repo_manager_get_repo_ex (mgr, repo_id); - if (repo) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - return ret; - -error: - *error = TRUE; - string_list_free (id_list); - return NULL; -} - -int -seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id, - int days) -{ - SeafVirtRepo *vinfo; - SeafDB *db = mgr->seaf->db; - char sql[256]; - - vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); - if (vinfo) { - seaf_virtual_repo_info_free (vinfo); - return 0; - } - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean err; - snprintf(sql, sizeof(sql), - "SELECT repo_id FROM RepoHistoryLimit " - "WHERE repo_id='%s'", repo_id); - if (seaf_db_check_for_existence(db, sql, &err)) - snprintf(sql, sizeof(sql), - "UPDATE RepoHistoryLimit SET days=%d" - "WHERE repo_id='%s'", days, repo_id); - else - snprintf(sql, sizeof(sql), - "INSERT INTO RepoHistoryLimit VALUES " - "('%s', %d)", repo_id, days); - if (err) - return -1; - return seaf_db_query(db, sql); - } else { - snprintf (sql, sizeof(sql), - "REPLACE INTO RepoHistoryLimit VALUES ('%s', %d)", - repo_id, days); - if (seaf_db_query (db, sql) < 0) - return -1; - } - - return 0; -} - -static gboolean -get_limit (SeafDBRow *row, void *vdays) -{ - int *days = vdays; - - *days = seaf_db_row_get_column_int (row, 0); - - return FALSE; -} - -int -seaf_repo_manager_get_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id) -{ - SeafVirtRepo *vinfo; - const char *r_repo_id = repo_id; - char sql[256]; - int per_repo_days = -1; - int ret; - - vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); - if (vinfo) - r_repo_id = vinfo->origin_repo_id; - - snprintf (sql, sizeof(sql), - "SELECT days FROM RepoHistoryLimit WHERE repo_id='%s'", - r_repo_id); - seaf_virtual_repo_info_free (vinfo); - - /* We don't use seaf_db_get_int() because we need to differ DB error - * from not exist. - * We can't just return global config value if DB error occured, - * since the global value may be smaller than per repo one. - * This can lead to data lose in GC. - */ - ret = seaf_db_foreach_selected_row (mgr->seaf->db, sql, - get_limit, &per_repo_days); - if (ret == 0) { - /* If per repo value is not set, return the global one. */ - return mgr->seaf->keep_history_days; - } - - if (per_repo_days < 0) { - per_repo_days = -1; - } - - return per_repo_days; -} - -int -seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id, - gint64 timestamp) -{ - SeafDB *db = mgr->seaf->db; - char sql[256]; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean err; - snprintf(sql, sizeof(sql), - "SELECT repo_id FROM RepoValidSince WHERE " - "repo_id='%s'", repo_id); - if (seaf_db_check_for_existence(db, sql, &err)) - snprintf(sql, sizeof(sql), - "UPDATE RepoValidSince SET timestamp=%"G_GINT64_FORMAT - " WHERE repo_id='%s'", timestamp, repo_id); - else - snprintf(sql, sizeof(sql), - "INSERT INTO RepoValidSince VALUES " - "('%s', %"G_GINT64_FORMAT")", repo_id, timestamp); - if (err) - return -1; - if (seaf_db_query (db, sql) < 0) - return -1; - } else { - snprintf (sql, sizeof(sql), - "REPLACE INTO RepoValidSince VALUES ('%s', %"G_GINT64_FORMAT")", - repo_id, timestamp); - if (seaf_db_query (db, sql) < 0) - return -1; - } - - return 0; -} - -gint64 -seaf_repo_manager_get_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id) -{ - char sql[256]; - - snprintf (sql, sizeof(sql), - "SELECT timestamp FROM RepoValidSince WHERE repo_id='%s'", - repo_id); - /* Also return -1 if DB error. */ - return seaf_db_get_int64 (mgr->seaf->db, sql); -} - -gint64 -seaf_repo_manager_get_repo_truncate_time (SeafRepoManager *mgr, - const char *repo_id) -{ - int days; - gint64 timestamp; - - days = seaf_repo_manager_get_repo_history_limit (mgr, repo_id); - timestamp = seaf_repo_manager_get_repo_valid_since (mgr, repo_id); - - gint64 now = (gint64)time(NULL); - if (days > 0) - return MAX (now - days * 24 * 3600, timestamp); - else if (days < 0) - return timestamp; - else - return 0; -} - -static gboolean -load_virtual_info (SeafDBRow *row, void *p_vinfo) -{ - SeafVirtRepo *vinfo; - const char *origin_repo_id, *path, *base_commit; - - origin_repo_id = seaf_db_row_get_column_text (row, 0); - path = seaf_db_row_get_column_text (row, 1); - base_commit = seaf_db_row_get_column_text (row, 2); - - vinfo = g_new0 (SeafVirtRepo, 1); - memcpy (vinfo->origin_repo_id, origin_repo_id, 36); - vinfo->path = g_strdup(path); - memcpy (vinfo->base_commit, base_commit, 40); - - *((SeafVirtRepo **)p_vinfo) = vinfo; - - return FALSE; -} - -SeafVirtRepo * -seaf_repo_manager_get_virtual_repo_info (SeafRepoManager *mgr, - const char *repo_id) -{ - char sql[256]; - SeafVirtRepo *vinfo = NULL; - - snprintf (sql, 256, - "SELECT origin_repo, path, base_commit FROM VirtualRepo " - "WHERE repo_id = '%s'", repo_id); - seaf_db_foreach_selected_row (seaf->db, sql, load_virtual_info, &vinfo); - - return vinfo; -} - -void -seaf_virtual_repo_info_free (SeafVirtRepo *vinfo) -{ - if (!vinfo) return; - - g_free (vinfo->path); - g_free (vinfo); -} - -static gboolean -collect_virtual_repo_ids (SeafDBRow *row, void *data) -{ - GList **p_ids = data; - const char *repo_id; - - repo_id = seaf_db_row_get_column_text (row, 0); - *p_ids = g_list_prepend (*p_ids, g_strdup(repo_id)); - - return TRUE; -} - -GList * -seaf_repo_manager_get_virtual_repo_ids_by_origin (SeafRepoManager *mgr, - const char *origin_repo) -{ - GList *ret = NULL; - char sql[256]; - - snprintf (sql, 256, - "SELECT repo_id FROM VirtualRepo WHERE origin_repo='%s'", - origin_repo); - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_virtual_repo_ids, &ret) < 0) { - return NULL; - } - - return g_list_reverse (ret); -} - -static gboolean -get_garbage_repo_id (SeafDBRow *row, void *vid_list) -{ - GList **ret = vid_list; - char *repo_id; - - repo_id = g_strdup(seaf_db_row_get_column_text (row, 0)); - *ret = g_list_prepend (*ret, repo_id); - - return TRUE; -} - -GList * -seaf_repo_manager_list_garbage_repos (SeafRepoManager *mgr) -{ - GList *repo_ids = NULL; - - seaf_db_foreach_selected_row (seaf->db, - "SELECT repo_id FROM GarbageRepos", - get_garbage_repo_id, &repo_ids); - - return repo_ids; -} - -void -seaf_repo_manager_remove_garbage_repo (SeafRepoManager *mgr, const char *repo_id) -{ - char sql[256]; - - snprintf (sql, sizeof(sql), "DELETE FROM GarbageRepos WHERE repo_id='%s'", - repo_id); - seaf_db_query (seaf->db, sql); -} diff --git a/server/gc/repo-mgr.h b/server/gc/repo-mgr.h deleted file mode 100644 index 0368117e..00000000 --- a/server/gc/repo-mgr.h +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAF_REPO_MGR_H -#define SEAF_REPO_MGR_H - -#include - -#include "seafile-object.h" -#include "commit-mgr.h" -#include "branch-mgr.h" - -struct _SeafRepoManager; -typedef struct _SeafRepo SeafRepo; - -typedef struct SeafVirtRepo { - char origin_repo_id[37]; - char *path; - char base_commit[41]; -} SeafVirtRepo; - -struct _SeafRepo { - struct _SeafRepoManager *manager; - - gchar id[37]; - gchar *name; - gchar *desc; - gchar *category; /* not used yet */ - gboolean encrypted; - int enc_version; - gchar magic[65]; /* hash(repo_id + passwd), key stretched. */ - gchar random_key[97]; - gboolean no_local_history; - - SeafBranch *head; - - gboolean is_corrupted; - gboolean repaired; - gboolean delete_pending; - int ref_cnt; - - int version; - /* Used to access fs and block sotre. - * This id is different from repo_id when this repo is virtual. - * Virtual repos share fs and block store with its origin repo. - * However, commit store for each repo is always independent. - * So always use repo_id to access commit store. - */ - gchar store_id[37]; - gboolean is_virtual; -}; - -gboolean is_repo_id_valid (const char *id); - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc); - -void -seaf_repo_free (SeafRepo *repo); - -void -seaf_repo_ref (SeafRepo *repo); - -void -seaf_repo_unref (SeafRepo *repo); - -void -seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit); - -void -seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit); - -void -seaf_virtual_repo_info_free (SeafVirtRepo *vinfo); - -typedef struct _SeafRepoManager SeafRepoManager; -typedef struct _SeafRepoManagerPriv SeafRepoManagerPriv; - -struct _SeafRepoManager { - struct _SeafileSession *seaf; - - SeafRepoManagerPriv *priv; -}; - -SeafRepoManager* -seaf_repo_manager_new (struct _SeafileSession *seaf); - -int -seaf_repo_manager_init (SeafRepoManager *mgr); - -int -seaf_repo_manager_start (SeafRepoManager *mgr); - -int -seaf_repo_manager_add_repo (SeafRepoManager *mgr, SeafRepo *repo); - -int -seaf_repo_manager_del_repo (SeafRepoManager *mgr, SeafRepo *repo); - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id); - -SeafRepo* -seaf_repo_manager_get_repo_ex (SeafRepoManager *manager, const gchar *id); - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id); - -GList* -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, - int start, int limit, - gboolean *error); - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr); - -int -seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id, - int days); - -int -seaf_repo_manager_get_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id); - -int -seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id, - gint64 timestamp); - -gint64 -seaf_repo_manager_get_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id); - -/* - * Return the timestamp to stop traversing history. - * Returns > 0 if traverse a period of history; - * Returns = 0 if only traverse the head commit; - * Returns < 0 if traverse full history. - */ -gint64 -seaf_repo_manager_get_repo_truncate_time (SeafRepoManager *mgr, - const char *repo_id); - -SeafVirtRepo * -seaf_repo_manager_get_virtual_repo_info (SeafRepoManager *mgr, - const char *repo_id); - -void -seaf_virtual_repo_info_free (SeafVirtRepo *vinfo); - -GList * -seaf_repo_manager_get_virtual_repo_ids_by_origin (SeafRepoManager *mgr, - const char *origin_repo); - -GList * -seaf_repo_manager_list_garbage_repos (SeafRepoManager *mgr); - -void -seaf_repo_manager_remove_garbage_repo (SeafRepoManager *mgr, const char *repo_id); - -#endif diff --git a/server/gc/seaf-fsck.c b/server/gc/seaf-fsck.c deleted file mode 100644 index 64b58005..00000000 --- a/server/gc/seaf-fsck.c +++ /dev/null @@ -1,179 +0,0 @@ -#include "common.h" -#include "log.h" - -#include - -#include - -#include "seafile-session.h" -#include "fsck.h" - -#include "utils.h" - -static char *config_dir = NULL; -static char *seafile_dir = NULL; -static char *central_config_dir = NULL; - -CcnetClient *ccnet_client; -SeafileSession *seaf; - -static const char *short_opts = "hvc:d:rE:F:"; -static const struct option long_opts[] = { - { "help", no_argument, NULL, 'h', }, - { "version", no_argument, NULL, 'v', }, - { "repair", no_argument, NULL, 'r', }, - { "export", required_argument, NULL, 'E', }, - { "config-file", required_argument, NULL, 'c', }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "seafdir", required_argument, NULL, 'd', }, -}; - -static void usage () -{ - fprintf (stderr, - "usage: seaf-fsck [-r] [-E exported_path] [-c config_dir] [-d seafile_dir] " - "[repo_id_1 [repo_id_2 ...]]\n"); -} - -#ifdef WIN32 -/* Get the commandline arguments in unicode, then convert them to utf8 */ -static char ** -get_argv_utf8 (int *argc) -{ - int i = 0; - char **argv = NULL; - const wchar_t *cmdline = NULL; - wchar_t **argv_w = NULL; - - cmdline = GetCommandLineW(); - argv_w = CommandLineToArgvW (cmdline, argc); - if (!argv_w) { - printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError()); - return NULL; - } - - argv = (char **)malloc (sizeof(char*) * (*argc)); - for (i = 0; i < *argc; i++) { - argv[i] = wchar_to_utf8 (argv_w[i]); - } - - return argv; -} -#endif - -#ifdef __linux__ - -/* Compare the owner uid of the seafile-data dir with the current uid. */ -static gboolean -check_user (const char *seafile_dir, uid_t *current_user, uid_t *seafile_user) -{ - struct stat st; - uid_t euid; - - if (stat (seafile_dir, &st) < 0) { - seaf_warning ("Failed to stat seafile data dir %s: %s\n", - seafile_dir, strerror(errno)); - return FALSE; - } - - euid = geteuid(); - - *current_user = euid; - *seafile_user = st.st_uid; - - return (euid == st.st_uid); -} - -#endif /* __linux__ */ - -int -main(int argc, char *argv[]) -{ - int c; - gboolean repair = FALSE; - char *export_path = NULL; - -#ifdef WIN32 - argv = get_argv_utf8 (&argc); -#endif - - config_dir = DEFAULT_CONFIG_DIR; - - while ((c = getopt_long(argc, argv, - short_opts, long_opts, NULL)) != EOF) { - switch (c) { - case 'h': - usage(); - exit(0); - case 'v': - exit(-1); - break; - case 'r': - repair = TRUE; - break; - case 'E': - export_path = strdup(optarg); - break; - case 'c': - config_dir = strdup(optarg); - break; - case 'd': - seafile_dir = strdup(optarg); - break; - case 'F': - central_config_dir = strdup(optarg); - break; - default: - usage(); - exit(-1); - } - } - -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif - - if (seafile_log_init ("-", "info", "debug") < 0) { - seaf_warning ("Failed to init log.\n"); - exit (1); - } - - ccnet_client = ccnet_client_new(); - if ((ccnet_client_load_confdir(ccnet_client, central_config_dir, config_dir)) < 0) { - seaf_warning ("Read config dir error\n"); - return -1; - } - - if (seafile_dir == NULL) - seafile_dir = g_build_filename (config_dir, "seafile-data", NULL); - -#ifdef __linux__ - uid_t current_user, seafile_user; - if (!check_user (seafile_dir, ¤t_user, &seafile_user)) { - seaf_message ("Current user (%u) is not the user for running " - "seafile server (%u). Unable to run fsck.\n", - current_user, seafile_user); - exit(1); - } -#endif - - seaf = seafile_session_new(central_config_dir, seafile_dir, ccnet_client, - export_path == NULL); - if (!seaf) { - seaf_warning ("Failed to create seafile session.\n"); - exit (1); - } - - GList *repo_id_list = NULL; - int i; - for (i = optind; i < argc; i++) - repo_id_list = g_list_append (repo_id_list, g_strdup(argv[i])); - - if (export_path) { - export_file (repo_id_list, seafile_dir, export_path); - } else { - seaf_fsck (repo_id_list, repair); - } - - return 0; -} diff --git a/server/gc/seaf-migrate.c b/server/gc/seaf-migrate.c deleted file mode 100644 index 9d41cf24..00000000 --- a/server/gc/seaf-migrate.c +++ /dev/null @@ -1,321 +0,0 @@ -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" - -#include - -#include - -#include "seafile-session.h" - -#include "utils.h" - -static char *config_dir = NULL; -static char *seafile_dir = NULL; -static char *central_config_dir = NULL; - -CcnetClient *ccnet_client; -SeafileSession *seaf; - -static const char *short_opts = "hvc:d:VDiF:"; -static const struct option long_opts[] = { - { "help", no_argument, NULL, 'h', }, - { "version", no_argument, NULL, 'v', }, - { "config-file", required_argument, NULL, 'c', }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "seafdir", required_argument, NULL, 'd', }, -}; - -static int -migrate_v0_repos_to_v1_layout (); - -static void usage () -{ - fprintf (stderr, - "usage: seaf-migrate [-c config_dir] [-d seafile_dir]\n"); -} - -static void -load_history_config () -{ - int keep_history_days; - GError *error = NULL; - - seaf->keep_history_days = -1; - - keep_history_days = g_key_file_get_integer (seaf->config, - "history", "keep_days", - &error); - if (error == NULL) - seaf->keep_history_days = keep_history_days; -} - -#ifdef WIN32 -/* Get the commandline arguments in unicode, then convert them to utf8 */ -static char ** -get_argv_utf8 (int *argc) -{ - int i = 0; - char **argv = NULL; - const wchar_t *cmdline = NULL; - wchar_t **argv_w = NULL; - - cmdline = GetCommandLineW(); - argv_w = CommandLineToArgvW (cmdline, argc); - if (!argv_w) { - printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError()); - return NULL; - } - - argv = (char **)malloc (sizeof(char*) * (*argc)); - for (i = 0; i < *argc; i++) { - argv[i] = wchar_to_utf8 (argv_w[i]); - } - - return argv; -} -#endif - -int -main(int argc, char *argv[]) -{ - int c; - -#ifdef WIN32 - argv = get_argv_utf8 (&argc); -#endif - - config_dir = DEFAULT_CONFIG_DIR; - - while ((c = getopt_long(argc, argv, - short_opts, long_opts, NULL)) != EOF) { - switch (c) { - case 'h': - usage(); - exit(0); - case 'v': - exit(-1); - break; - case 'c': - config_dir = strdup(optarg); - break; - case 'd': - seafile_dir = strdup(optarg); - break; - case 'F': - central_config_dir = strdup(optarg); - break; - default: - usage(); - exit(-1); - } - } - -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif - - if (seafile_log_init ("-", "info", "debug") < 0) { - seaf_warning ("Failed to init log.\n"); - exit (1); - } - - ccnet_client = ccnet_client_new(); - if ((ccnet_client_load_confdir(ccnet_client, central_config_dir, config_dir)) < 0) { - seaf_warning ("Read config dir error\n"); - return -1; - } - - if (seafile_dir == NULL) - seafile_dir = g_build_filename (config_dir, "seafile-data", NULL); - - seaf = seafile_session_new(central_config_dir, seafile_dir, ccnet_client, TRUE); - if (!seaf) { - seaf_warning ("Failed to create seafile session.\n"); - exit (1); - } - - load_history_config (); - - migrate_v0_repos_to_v1_layout (); - - return 0; -} - -typedef struct { - SeafRepo *repo; - GHashTable *visited; - - /* > 0: keep a period of history; - * == 0: only keep data in head commit; - * < 0: keep all history data. - */ - gint64 truncate_time; - gboolean traversed_head; - gboolean stop_copy_blocks; -} MigrationData; - -static int -migrate_file_blocks (SeafFSManager *mgr, MigrationData *data, const char *file_id) -{ - SeafRepo *repo = data->repo; - Seafile *seafile; - int i; - char *block_id; - - seafile = seaf_fs_manager_get_seafile (mgr, repo->store_id, repo->version, file_id); - if (!seafile) { - seaf_warning ("Failed to find file %s.\n", file_id); - return -1; - } - - for (i = 0; i < seafile->n_blocks; ++i) { - block_id = seafile->blk_sha1s[i]; - if (seaf_block_manager_copy_block (seaf->block_mgr, - repo->store_id, repo->version, - repo->store_id, 1, - block_id) < 0) { - seaf_warning ("Failed to copy block %s.\n", block_id); - seafile_unref (seafile); - return -1; - } - } - - seafile_unref (seafile); - - return 0; -} - -static gboolean -fs_callback (SeafFSManager *mgr, - const char *store_id, - int version, - const char *obj_id, - int type, - void *user_data, - gboolean *stop) -{ - MigrationData *data = user_data; - SeafRepo *repo = data->repo; - - if (data->visited != NULL) { - if (g_hash_table_lookup (data->visited, obj_id) != NULL) { - *stop = TRUE; - return TRUE; - } - - char *key = g_strdup(obj_id); - g_hash_table_replace (data->visited, key, key); - } - - if (seaf_obj_store_copy_obj (seaf->fs_mgr->obj_store, - repo->store_id, repo->version, - repo->store_id, 1, - obj_id) < 0) { - seaf_warning ("Failed to copy fs object %s.\n", obj_id); - return FALSE; - } - - if (data->stop_copy_blocks) - return TRUE; - - if (type == SEAF_METADATA_TYPE_FILE && - migrate_file_blocks (mgr, data, obj_id) < 0) - return FALSE; - - return TRUE; -} - -static gboolean -traverse_commit (SeafCommit *commit, void *vdata, gboolean *stop) -{ - MigrationData *data = vdata; - SeafRepo *repo = data->repo; - int ret; - - if (data->truncate_time > 0 && - (gint64)(commit->ctime) < data->truncate_time && - data->traversed_head && !data->stop_copy_blocks) { - data->stop_copy_blocks = TRUE; - } - - if (!data->traversed_head) - data->traversed_head = TRUE; - - if (seaf_obj_store_copy_obj (seaf->commit_mgr->obj_store, - repo->id, repo->version, - repo->id, 1, - commit->commit_id) < 0) { - seaf_warning ("Failed to copy commit %s.\n", commit->commit_id); - return FALSE; - } - - ret = seaf_fs_manager_traverse_tree (seaf->fs_mgr, - data->repo->store_id, data->repo->version, - commit->root_id, - fs_callback, - data, FALSE); - if (ret < 0) - return FALSE; - - if (data->truncate_time == 0 && !data->stop_copy_blocks) { - data->stop_copy_blocks = TRUE; - /* Stop after traversing the head commit. */ - } - - return TRUE; -} - -static int -migrate_repo (SeafRepo *repo) -{ - MigrationData *data; - int ret = 0; - - seaf_message ("Migrating data for repo %.8s.\n", repo->id); - - data = g_new0(MigrationData, 1); - data->repo = repo; - data->visited = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - gint64 truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager, - repo->id); - data->truncate_time = truncate_time; - - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - repo->head->commit_id, - traverse_commit, - data, - FALSE); - if (!res) { - seaf_warning ("Migration of repo %s is not completed.\n", repo->id); - ret = -1; - } - - g_hash_table_destroy (data->visited); - g_free (data); - - return ret; -} - -static int -migrate_v0_repos_to_v1_layout () -{ - GList *repos = NULL, *ptr; - SeafRepo *repo; - gboolean error = FALSE; - - repos = seaf_repo_manager_get_repo_list (seaf->repo_mgr, -1, -1, &error); - for (ptr = repos; ptr; ptr = ptr->next) { - repo = ptr->data; - if (!repo->is_corrupted && repo->version == 0) - migrate_repo (repo); - seaf_repo_unref (repo); - } - g_list_free (repos); - - return 0; -} diff --git a/server/gc/seafile-session.c b/server/gc/seafile-session.c deleted file mode 100644 index d366753c..00000000 --- a/server/gc/seafile-session.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "common.h" - -#include -#include -#include - -#include -#include - -#include "seafile-session.h" -#include "seaf-utils.h" - -#include "log.h" - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - CcnetClient *ccnet_session, - gboolean need_db) -{ - char *abs_central_config_dir = NULL; - char *abs_seafile_dir; - char *tmp_file_dir; - char *config_file_path; - struct stat st; - GKeyFile *config; - SeafileSession *session = NULL; - - if (!ccnet_session) - return NULL; - - abs_seafile_dir = ccnet_expand_path (seafile_dir); - tmp_file_dir = g_build_filename (abs_seafile_dir, "tmpfiles", NULL); - if (central_config_dir) { - abs_central_config_dir = ccnet_expand_path (central_config_dir); - } - const char *confdir = abs_central_config_dir ? abs_central_config_dir : abs_seafile_dir; - config_file_path = g_build_filename(confdir, "seafile.conf", NULL); - - if (g_stat(confdir, &st) < 0 || !S_ISDIR(st.st_mode)) { - seaf_warning ("Config dir dir %s does not exist\n", - abs_seafile_dir); - goto onerror; - } - - if (g_stat(abs_seafile_dir, &st) < 0 || !S_ISDIR(st.st_mode)) { - seaf_warning ("Seafile data dir %s does not exist\n", - abs_seafile_dir); - goto onerror; - } - - if (g_stat(tmp_file_dir, &st) < 0 || !S_ISDIR(st.st_mode)) { - seaf_warning ("Seafile tmp dir %s does not exist\n", - tmp_file_dir); - goto onerror; - } - - GError *error = NULL; - config = g_key_file_new (); - if (!g_key_file_load_from_file (config, config_file_path, - G_KEY_FILE_NONE, &error)) { - seaf_warning ("Failed to load config file.\n"); - g_key_file_free (config); - goto onerror; - } - - session = g_new0(SeafileSession, 1); - session->seaf_dir = abs_seafile_dir; - session->tmp_file_dir = tmp_file_dir; - session->session = ccnet_session; - session->config = config; - - if (need_db) { - if (load_database_config (session) < 0) { - seaf_warning ("Failed to load database config.\n"); - goto onerror; - } - } - - session->fs_mgr = seaf_fs_manager_new (session, abs_seafile_dir); - if (!session->fs_mgr) - goto onerror; - session->block_mgr = seaf_block_manager_new (session, abs_seafile_dir); - if (!session->block_mgr) - goto onerror; - session->commit_mgr = seaf_commit_manager_new (session); - if (!session->commit_mgr) - goto onerror; - session->repo_mgr = seaf_repo_manager_new (session); - if (!session->repo_mgr) - goto onerror; - session->branch_mgr = seaf_branch_manager_new (session); - if (!session->branch_mgr) - goto onerror; - - return session; - -onerror: - free (abs_seafile_dir); - g_free (tmp_file_dir); - g_free (config_file_path); - g_free (session); - return NULL; -} diff --git a/server/gc/seafile-session.h b/server/gc/seafile-session.h deleted file mode 100644 index 2ce9fb99..00000000 --- a/server/gc/seafile-session.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef SEAFILE_SESSION_H -#define SEAFILE_SESSION_H - -#include -#include - -#include "block-mgr.h" -#include "fs-mgr.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "db.h" -#include "seaf-db.h" - -struct _CcnetClient; - -typedef struct _SeafileSession SeafileSession; - -struct _SeafileSession { - struct _CcnetClient *session; - - char *seaf_dir; - char *tmp_file_dir; - /* Config that's only loaded on start */ - GKeyFile *config; - SeafDB *db; - - SeafBlockManager *block_mgr; - SeafFSManager *fs_mgr; - SeafCommitManager *commit_mgr; - SeafBranchManager *branch_mgr; - SeafRepoManager *repo_mgr; - - int keep_history_days; -}; - -extern SeafileSession *seaf; - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - struct _CcnetClient *ccnet, - gboolean need_db); - -#endif diff --git a/server/gc/seafserv-gc.c b/server/gc/seafserv-gc.c deleted file mode 100644 index 0fbe5b99..00000000 --- a/server/gc/seafserv-gc.c +++ /dev/null @@ -1,171 +0,0 @@ -#include "common.h" -#include "log.h" - -#include - -#include - -#include "seafile-session.h" -#include "gc-core.h" -#include "verify.h" - -#include "utils.h" - -static char *config_dir = NULL; -static char *seafile_dir = NULL; -static char *central_config_dir = NULL; - -CcnetClient *ccnet_client; -SeafileSession *seaf; - -static const char *short_opts = "hvc:d:VDrF:"; -static const struct option long_opts[] = { - { "help", no_argument, NULL, 'h', }, - { "version", no_argument, NULL, 'v', }, - { "config-file", required_argument, NULL, 'c', }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "seafdir", required_argument, NULL, 'd', }, - { "verbose", no_argument, NULL, 'V' }, - { "dry-run", no_argument, NULL, 'D' }, - { "rm-deleted", no_argument, NULL, 'r' }, -}; - -static void usage () -{ - fprintf (stderr, - "usage: seafserv-gc [-c config_dir] [-d seafile_dir] " - "[repo_id_1 [repo_id_2 ...]]\n" - "Additional options:\n" - "-r, --rm-deleted: remove garbaged repos\n" - "-D, --dry-run: report blocks that can be remove, but not remove them\n" - "-V, --verbose: verbose output messages\n"); -} - -static void -load_history_config () -{ - int keep_history_days; - GError *error = NULL; - - seaf->keep_history_days = -1; - - keep_history_days = g_key_file_get_integer (seaf->config, - "history", "keep_days", - &error); - if (error == NULL) - seaf->keep_history_days = keep_history_days; -} - -#ifdef WIN32 -/* Get the commandline arguments in unicode, then convert them to utf8 */ -static char ** -get_argv_utf8 (int *argc) -{ - int i = 0; - char **argv = NULL; - const wchar_t *cmdline = NULL; - wchar_t **argv_w = NULL; - - cmdline = GetCommandLineW(); - argv_w = CommandLineToArgvW (cmdline, argc); - if (!argv_w) { - printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError()); - return NULL; - } - - argv = (char **)malloc (sizeof(char*) * (*argc)); - for (i = 0; i < *argc; i++) { - argv[i] = wchar_to_utf8 (argv_w[i]); - } - - return argv; -} -#endif - -int -main(int argc, char *argv[]) -{ - int c; - int verbose = 0; - int dry_run = 0; - int rm_garbage = 0; - -#ifdef WIN32 - argv = get_argv_utf8 (&argc); -#endif - - config_dir = DEFAULT_CONFIG_DIR; - - while ((c = getopt_long(argc, argv, - short_opts, long_opts, NULL)) != EOF) { - switch (c) { - case 'h': - usage(); - exit(0); - case 'v': - exit(-1); - break; - case 'c': - config_dir = strdup(optarg); - break; - case 'd': - seafile_dir = strdup(optarg); - break; - case 'F': - central_config_dir = strdup(optarg); - break; - case 'V': - verbose = 1; - break; - case 'D': - dry_run = 1; - break; - case 'r': - rm_garbage = 1; - break; - default: - usage(); - exit(-1); - } - } - -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif - - if (seafile_log_init ("-", "info", "debug") < 0) { - seaf_warning ("Failed to init log.\n"); - exit (1); - } - - ccnet_client = ccnet_client_new(); - if ((ccnet_client_load_confdir(ccnet_client, central_config_dir, config_dir)) < 0) { - seaf_warning ("Read config dir error\n"); - return -1; - } - - if (seafile_dir == NULL) - seafile_dir = g_build_filename (config_dir, "seafile-data", NULL); - - seaf = seafile_session_new(central_config_dir, seafile_dir, ccnet_client, TRUE); - if (!seaf) { - seaf_warning ("Failed to create seafile session.\n"); - exit (1); - } - - if (rm_garbage) { - delete_garbaged_repos (!rm_garbage); - return 0; - } - - load_history_config (); - - GList *repo_id_list = NULL; - int i; - for (i = optind; i < argc; i++) - repo_id_list = g_list_append (repo_id_list, g_strdup(argv[i])); - - gc_core_run (repo_id_list, dry_run, verbose); - - return 0; -} diff --git a/server/gc/verify.c b/server/gc/verify.c deleted file mode 100644 index d517004c..00000000 --- a/server/gc/verify.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "seafile-session.h" -#include "log.h" - -typedef struct VerifyData { - SeafRepo *repo; - gint64 truncate_time; - gboolean traversed_head; -} VerifyData; - -static int -check_blocks (VerifyData *data, const char *file_id) -{ - SeafRepo *repo = data->repo; - Seafile *seafile; - int i; - - seafile = seaf_fs_manager_get_seafile (seaf->fs_mgr, - repo->store_id, - repo->version, - file_id); - if (!seafile) { - seaf_warning ("Failed to find file %s.\n", file_id); - return -1; - } - - for (i = 0; i < seafile->n_blocks; ++i) { - if (!seaf_block_manager_block_exists (seaf->block_mgr, - repo->store_id, - repo->version, - seafile->blk_sha1s[i])) - g_message ("Block %s is missing.\n", seafile->blk_sha1s[i]); - } - - seafile_unref (seafile); - - return 0; -} - -static gboolean -fs_callback (SeafFSManager *mgr, - const char *store_id, - int version, - const char *obj_id, - int type, - void *user_data, - gboolean *stop) -{ - VerifyData *data = user_data; - - if (type == SEAF_METADATA_TYPE_FILE && check_blocks (data, obj_id) < 0) - return FALSE; - - return TRUE; -} - -static gboolean -traverse_commit (SeafCommit *commit, void *vdata, gboolean *stop) -{ - VerifyData *data = vdata; - SeafRepo *repo = data->repo; - int ret; - - if (data->truncate_time == 0) - { - *stop = TRUE; - /* Stop after traversing the head commit. */ - } - else if (data->truncate_time > 0 && - (gint64)(commit->ctime) < data->truncate_time && - data->traversed_head) - { - *stop = TRUE; - return TRUE; - } - - if (!data->traversed_head) - data->traversed_head = TRUE; - - ret = seaf_fs_manager_traverse_tree (seaf->fs_mgr, - repo->store_id, - repo->version, - commit->root_id, - fs_callback, - vdata, FALSE); - if (ret < 0) - return FALSE; - - return TRUE; -} - -static int -verify_repo (SeafRepo *repo) -{ - GList *branches, *ptr; - SeafBranch *branch; - int ret = 0; - VerifyData data = {0}; - - data.repo = repo; - data.truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager, - repo->id); - - branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); - if (branches == NULL) { - seaf_warning ("[GC] Failed to get branch list of repo %s.\n", repo->id); - return -1; - } - - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - branch = ptr->data; - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - branch->commit_id, - traverse_commit, - &data, FALSE); - seaf_branch_unref (branch); - if (!res) { - ret = -1; - break; - } - } - - g_list_free (branches); - - return ret; -} - -int -verify_repos (GList *repo_id_list) -{ - if (repo_id_list == NULL) - repo_id_list = seaf_repo_manager_get_repo_id_list (seaf->repo_mgr); - - GList *ptr; - SeafRepo *repo; - int ret = 0; - - for (ptr = repo_id_list; ptr != NULL; ptr = ptr->next) { - repo = seaf_repo_manager_get_repo_ex (seaf->repo_mgr, (const gchar *)ptr->data); - - g_free (ptr->data); - - if (!repo) - continue; - - if (repo->is_corrupted) { - seaf_warning ("Repo %s is corrupted.\n", repo->id); - } else { - ret = verify_repo (repo); - seaf_repo_unref (repo); - if (ret < 0) - break; - } - } - - g_list_free (repo_id_list); - - return ret; -} diff --git a/server/gc/verify.h b/server/gc/verify.h deleted file mode 100644 index c3b85e40..00000000 --- a/server/gc/verify.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef GC_VERIFY_H -#define GC_VERIFY_H - -int verify_repos (GList *repo_id_list); - -#endif diff --git a/server/http-server.c b/server/http-server.c deleted file mode 100644 index 5880c227..00000000 --- a/server/http-server.c +++ /dev/null @@ -1,2083 +0,0 @@ -#include "common.h" - -#include -#include -#include -#include -#include - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif - -#include - -#include "utils.h" -#include "log.h" -#include "http-server.h" -#include "seafile-session.h" -#include "diff-simple.h" -#include "merge-new.h" -#include "seaf-db.h" - -#include "access-file.h" -#include "upload-file.h" -#include "fileserver-config.h" - -#include "http-status-codes.h" - -#define DEFAULT_BIND_HOST "0.0.0.0" -#define DEFAULT_BIND_PORT 8082 -#define DEFAULT_THREADS 50 -#define DEFAULT_MAX_DOWNLOAD_DIR_SIZE 100 * ((gint64)1 << 20) /* 100MB */ -#define DEFAULT_MAX_INDEXING_THREADS 1 - -#define HOST "host" -#define PORT "port" - -#define INIT_INFO "If you see this page, Seafile HTTP syncing component works." -#define PROTO_VERSION "{\"version\": 1}" - -#define CLEANING_INTERVAL_SEC 300 /* 5 minutes */ -#define TOKEN_EXPIRE_TIME 7200 /* 2 hours */ -#define PERM_EXPIRE_TIME 7200 /* 2 hours */ -#define VIRINFO_EXPIRE_TIME 7200 /* 2 hours */ - -struct _HttpServer { - evbase_t *evbase; - evhtp_t *evhtp; - pthread_t thread_id; - - GHashTable *token_cache; - pthread_mutex_t token_cache_lock; /* token -> username */ - - GHashTable *perm_cache; - pthread_mutex_t perm_cache_lock; /* repo_id:username -> permission */ - - GHashTable *vir_repo_info_cache; - pthread_mutex_t vir_repo_info_cache_lock; - - uint32_t cevent_id; /* Used for sending activity events. */ - - event_t *reap_timer; -}; -typedef struct _HttpServer HttpServer; - -typedef struct TokenInfo { - char *repo_id; - char *email; - gint64 expire_time; -} TokenInfo; - -typedef struct PermInfo { - char *perm; - gint64 expire_time; -} PermInfo; - -typedef struct VirRepoInfo { - char *store_id; - gint64 expire_time; -} VirRepoInfo; - -typedef struct FsHdr { - char obj_id[40]; - guint32 obj_size; -} __attribute__((__packed__)) FsHdr; - -typedef enum CheckExistType { - CHECK_FS_EXIST, - CHECK_BLOCK_EXIST -} CheckExistType; - -const char *GET_PROTO_PATH = "/protocol-version"; -const char *OP_PERM_CHECK_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/permission-check/.*"; -const char *GET_CHECK_QUOTA_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/quota-check/.*"; -const char *HEAD_COMMIT_OPER_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/commit/HEAD"; -const char *COMMIT_OPER_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/commit/[\\da-z]{40}"; -const char *PUT_COMMIT_INFO_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/commit/[\\da-z]{40}"; -const char *GET_FS_OBJ_ID_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/fs-id-list/.*"; -const char *BLOCK_OPER_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/block/[\\da-z]{40}"; -const char *POST_CHECK_FS_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/check-fs"; -const char *POST_CHECK_BLOCK_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/check-blocks"; -const char *POST_RECV_FS_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/recv-fs"; -const char *POST_PACK_FS_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/pack-fs"; -const char *GET_BLOCK_MAP_REGEX = "^/repo/[\\da-z]{8}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{4}-[\\da-z]{12}/block-map/[\\da-z]{40}"; - -static void -load_http_config (HttpServerStruct *htp_server, SeafileSession *session) -{ - GError *error = NULL; - char *host = NULL; - int port = 0; - int max_upload_size_mb; - int max_download_dir_size_mb; - char *encoding; - int max_indexing_threads; - - host = fileserver_config_get_string (session->config, HOST, &error); - if (!error) { - htp_server->bind_addr = host; - } else { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && - error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) { - seaf_warning ("[conf] Error: failed to read the value of 'host'\n"); - exit (1); - } - - htp_server->bind_addr = g_strdup (DEFAULT_BIND_HOST); - g_clear_error (&error); - } - - port = fileserver_config_get_integer (session->config, PORT, &error); - if (!error) { - htp_server->bind_port = port; - } else { - if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && - error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) { - seaf_warning ("[conf] Error: failed to read the value of 'port'\n"); - exit (1); - } - - htp_server->bind_port = DEFAULT_BIND_PORT; - g_clear_error (&error); - } - - max_upload_size_mb = fileserver_config_get_integer (session->config, - "max_upload_size", - &error); - if (error) { - htp_server->max_upload_size = -1; /* no limit */ - g_clear_error (&error); - } else { - if (max_upload_size_mb <= 0) - htp_server->max_upload_size = -1; /* no limit */ - else - htp_server->max_upload_size = max_upload_size_mb * ((gint64)1 << 20); - } - - max_download_dir_size_mb = fileserver_config_get_integer (session->config, - "max_download_dir_size", - &error); - if (error) { - htp_server->max_download_dir_size = DEFAULT_MAX_DOWNLOAD_DIR_SIZE; - g_clear_error (&error); - } else { - if (max_download_dir_size_mb <= 0) - htp_server->max_download_dir_size = DEFAULT_MAX_DOWNLOAD_DIR_SIZE; - else - htp_server->max_download_dir_size = max_download_dir_size_mb * ((gint64)1 << 20); - } - - max_indexing_threads = fileserver_config_get_integer (session->config, - "max_indexing_threads", - &error); - if (error) { - htp_server->max_indexing_threads = DEFAULT_MAX_INDEXING_THREADS; - g_clear_error (&error); - } else { - if (max_indexing_threads <= 0) - htp_server->max_indexing_threads = DEFAULT_MAX_INDEXING_THREADS; - else - htp_server->max_indexing_threads = max_indexing_threads; - } - - encoding = g_key_file_get_string (session->config, - "zip", "windows_encoding", - &error); - if (encoding) { - htp_server->windows_encoding = encoding; - } else { - g_clear_error (&error); - /* No windows specific encoding is specified. Set the ZIP_UTF8 flag. */ - setlocale (LC_ALL, "en_US.UTF-8"); - } -} - -static int -validate_token (HttpServer *htp_server, evhtp_request_t *req, - const char *repo_id, char **username, - gboolean skip_cache) -{ - char *email = NULL; - TokenInfo *token_info; - - const char *token = evhtp_kv_find (req->headers_in, "Seafile-Repo-Token"); - if (token == NULL) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return EVHTP_RES_BADREQ; - } - - if (!skip_cache) { - pthread_mutex_lock (&htp_server->token_cache_lock); - - token_info = g_hash_table_lookup (htp_server->token_cache, token); - if (token_info) { - if (username) - *username = g_strdup(token_info->email); - pthread_mutex_unlock (&htp_server->token_cache_lock); - return EVHTP_RES_OK; - } - - pthread_mutex_unlock (&htp_server->token_cache_lock); - } - - email = seaf_repo_manager_get_email_by_token (seaf->repo_mgr, - repo_id, token); - if (email == NULL) { - pthread_mutex_lock (&htp_server->token_cache_lock); - g_hash_table_remove (htp_server->token_cache, token); - pthread_mutex_unlock (&htp_server->token_cache_lock); - return EVHTP_RES_FORBIDDEN; - } - - token_info = g_new0 (TokenInfo, 1); - token_info->repo_id = g_strdup (repo_id); - token_info->expire_time = (gint64)time(NULL) + TOKEN_EXPIRE_TIME; - token_info->email = email; - - pthread_mutex_lock (&htp_server->token_cache_lock); - g_hash_table_insert (htp_server->token_cache, g_strdup (token), token_info); - pthread_mutex_unlock (&htp_server->token_cache_lock); - - if (username) - *username = g_strdup(email); - return EVHTP_RES_OK; -} - -static PermInfo * -lookup_perm_cache (HttpServer *htp_server, const char *repo_id, const char *username) -{ - PermInfo *ret = NULL; - char *key = g_strdup_printf ("%s:%s", repo_id, username); - - pthread_mutex_lock (&htp_server->perm_cache_lock); - ret = g_hash_table_lookup (htp_server->perm_cache, key); - pthread_mutex_unlock (&htp_server->perm_cache_lock); - g_free (key); - - return ret; -} - -static void -insert_perm_cache (HttpServer *htp_server, - const char *repo_id, const char *username, - PermInfo *perm) -{ - char *key = g_strdup_printf ("%s:%s", repo_id, username); - - pthread_mutex_lock (&htp_server->perm_cache_lock); - g_hash_table_insert (htp_server->perm_cache, key, perm); - pthread_mutex_unlock (&htp_server->perm_cache_lock); -} - -static void -remove_perm_cache (HttpServer *htp_server, - const char *repo_id, const char *username) -{ - char *key = g_strdup_printf ("%s:%s", repo_id, username); - - pthread_mutex_lock (&htp_server->perm_cache_lock); - g_hash_table_remove (htp_server->perm_cache, key); - pthread_mutex_unlock (&htp_server->perm_cache_lock); - - g_free (key); -} - -static int -check_permission (HttpServer *htp_server, const char *repo_id, const char *username, - const char *op, gboolean skip_cache) -{ - PermInfo *perm_info = NULL; - - if (!skip_cache) - perm_info = lookup_perm_cache (htp_server, repo_id, username); - - if (perm_info) { - if (strcmp(perm_info->perm, "r") == 0 && strcmp(op, "upload") == 0) - return EVHTP_RES_FORBIDDEN; - return EVHTP_RES_OK; - } - - char *perm = seaf_repo_manager_check_permission (seaf->repo_mgr, - repo_id, username, NULL); - if (perm) { - perm_info = g_new0 (PermInfo, 1); - /* Take the reference of perm. */ - perm_info->perm = perm; - perm_info->expire_time = (gint64)time(NULL) + PERM_EXPIRE_TIME; - insert_perm_cache (htp_server, repo_id, username, perm_info); - - if ((strcmp (perm, "r") == 0 && strcmp (op, "upload") == 0)) - return EVHTP_RES_FORBIDDEN; - return EVHTP_RES_OK; - } - - /* Invalidate cache if perm not found in db. */ - remove_perm_cache (htp_server, repo_id, username); - return EVHTP_RES_FORBIDDEN; -} - -static gboolean -get_vir_repo_info (SeafDBRow *row, void *data) -{ - HttpServer *htp_server = data; - - const char *repo_id = seaf_db_row_get_column_text (row, 0); - if (!repo_id) - return FALSE; - const char *origin_id = seaf_db_row_get_column_text (row, 1); - if (!origin_id) - return FALSE; - - VirRepoInfo **vinfo = data; - *vinfo = g_new0 (VirRepoInfo, 1); - if (!*vinfo) - return FALSE; - (*vinfo)->store_id = g_strdup (origin_id); - if (!(*vinfo)->store_id) - return FALSE; - (*vinfo)->expire_time = time (NULL) + VIRINFO_EXPIRE_TIME; - - return TRUE; -} - -static char * -get_store_id_from_vir_repo_info_cache (HttpServer *htp_server, const char *repo_id) -{ - char *store_id = NULL; - VirRepoInfo *vinfo = NULL; - - pthread_mutex_lock (&htp_server->vir_repo_info_cache_lock); - vinfo = g_hash_table_lookup (htp_server->vir_repo_info_cache, repo_id); - - if (vinfo) { - if (vinfo->store_id) - store_id = g_strdup (vinfo->store_id); - else - store_id = g_strdup (repo_id); - - vinfo->expire_time = time (NULL) + VIRINFO_EXPIRE_TIME; - } - - pthread_mutex_unlock (&htp_server->vir_repo_info_cache_lock); - - return store_id; -} - -static void -add_vir_info_to_cache (HttpServer *htp_server, const char *repo_id, - VirRepoInfo *vinfo) -{ - pthread_mutex_lock (&htp_server->vir_repo_info_cache_lock); - g_hash_table_insert (htp_server->vir_repo_info_cache, g_strdup (repo_id), vinfo); - pthread_mutex_unlock (&htp_server->vir_repo_info_cache_lock); -} - -static char * -get_repo_store_id (HttpServer *htp_server, const char *repo_id) -{ - char *store_id = get_store_id_from_vir_repo_info_cache (htp_server, - repo_id); - if (store_id) { - return store_id; - } - - VirRepoInfo *vinfo = NULL; - char *sql = "SELECT repo_id, origin_repo FROM VirtualRepo where repo_id = ?"; - int n_row = seaf_db_statement_foreach_row (seaf->db, sql, get_vir_repo_info, - &vinfo, 1, "string", repo_id); - if (n_row < 0) { - // db error, return NULL - return NULL; - } else if (n_row == 0) { - // repo is not virtual repo - vinfo = g_new0 (VirRepoInfo, 1); - if (!vinfo) - return NULL; - vinfo->expire_time = time (NULL) + VIRINFO_EXPIRE_TIME; - - add_vir_info_to_cache (htp_server, repo_id, vinfo); - - return g_strdup (repo_id); - } else if (!vinfo || !vinfo->store_id) { - // out of memory, return NULL - return NULL; - } - - add_vir_info_to_cache (htp_server, repo_id, vinfo); - - return g_strdup (vinfo->store_id); -} - -static void -default_cb (evhtp_request_t *req, void *arg) -{ - evbuffer_add (req->buffer_out, INIT_INFO, strlen (INIT_INFO)); - evhtp_send_reply (req, EVHTP_RES_OK); -} - -typedef struct { - char *etype; - char *user; - char *ip; - char repo_id[37]; - char *path; - char *client_name; -} RepoEventData; - -static void -free_repo_event_data (RepoEventData *data) -{ - if (!data) - return; - - g_free (data->etype); - g_free (data->user); - g_free (data->ip); - g_free (data->path); - g_free (data->client_name); - g_free (data); -} - -static void -publish_repo_event (CEvent *event, void *data) -{ - RepoEventData *rdata = event->data; - - GString *buf = g_string_new (NULL); - g_string_printf (buf, "%s\t%s\t%s\t%s\t%s\t%s", - rdata->etype, rdata->user, rdata->ip, - rdata->client_name ? rdata->client_name : "", - rdata->repo_id, rdata->path ? rdata->path : "/"); - - seaf_mq_manager_publish_event (seaf->mq_mgr, buf->str); - - g_string_free (buf, TRUE); - free_repo_event_data (rdata); -} - -static void -on_repo_oper (HttpServer *htp_server, const char *etype, - const char *repo_id, char *user, char *ip, char *client_name) -{ - RepoEventData *rdata = g_new0 (RepoEventData, 1); - SeafVirtRepo *vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, - repo_id); - - if (vinfo) { - memcpy (rdata->repo_id, vinfo->origin_repo_id, 36); - rdata->path = g_strdup(vinfo->path); - } else - memcpy (rdata->repo_id, repo_id, 36); - rdata->etype = g_strdup (etype); - rdata->user = g_strdup (user); - rdata->ip = g_strdup (ip); - rdata->client_name = g_strdup(client_name); - - cevent_manager_add_event (seaf->ev_mgr, htp_server->cevent_id, rdata); - - if (vinfo) { - g_free (vinfo->path); - g_free (vinfo); - } -} - -char * -get_client_ip_addr (evhtp_request_t *req) -{ - const char *xff = evhtp_kv_find (req->headers_in, "X-Forwarded-For"); - if (xff) { - struct in_addr addr; - const char *comma = strchr (xff, ','); - char *copy; - if (comma) - copy = g_strndup(xff, comma-xff); - else - copy = g_strdup(xff); - if (evutil_inet_pton (AF_INET, copy, &addr) == 1) - return copy; - g_free (copy); - } - - evhtp_connection_t *conn = req->conn; - char ip_addr[17]; - const char *ip = NULL; - struct sockaddr_in *addr_in = (struct sockaddr_in *)conn->saddr; - - memset (ip_addr, '\0', 17); - ip = evutil_inet_ntop (AF_INET, &addr_in->sin_addr, ip_addr, 16); - - return g_strdup (ip); -} - -static int -validate_client_ver (const char *client_ver) -{ - int n_major; - int n_minor; - int n_build; - char **versions = NULL; - char *next_str = NULL; - - versions = g_strsplit (client_ver, ".", 3); - if (g_strv_length (versions) != 3) { - g_strfreev (versions); - return EVHTP_RES_BADREQ; - } - - n_major = strtoll (versions[0], &next_str, 10); - if (versions[0] == next_str) { - g_strfreev (versions); - return EVHTP_RES_BADREQ; - } - - n_minor = strtoll (versions[1], &next_str, 10); - if (versions[1] == next_str) { - g_strfreev (versions); - return EVHTP_RES_BADREQ; - } - - n_build = strtoll (versions[2], &next_str, 10); - if (versions[2] == next_str) { - g_strfreev (versions); - return EVHTP_RES_BADREQ; - } - - // todo: judge whether version is too old, then return 426 - - g_strfreev (versions); - return EVHTP_RES_OK; -} - -static void -get_check_permission_cb (evhtp_request_t *req, void *arg) -{ - const char *op = evhtp_kv_find (req->uri->query, "op"); - if (op == NULL || (strcmp (op, "upload") != 0 && strcmp (op, "download") != 0)) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - const char *client_id = evhtp_kv_find (req->uri->query, "client_id"); - if (client_id && strlen(client_id) != 40) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - const char *client_ver = evhtp_kv_find (req->uri->query, "client_ver"); - if (client_ver) { - int status = validate_client_ver (client_ver); - if (status != EVHTP_RES_OK) { - evhtp_send_reply (req, status); - return; - } - } - - char *client_name = NULL; - const char *client_name_in = evhtp_kv_find (req->uri->query, "client_name"); - if (client_name_in) - client_name = g_uri_unescape_string (client_name_in, NULL); - - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - HttpServer *htp_server = (HttpServer *)arg; - char *username = NULL; - char *ip = NULL; - const char *token; - SeafRepo *repo = NULL; - - repo = seaf_repo_manager_get_repo_ex (seaf->repo_mgr, repo_id); - if (!repo) { - evhtp_send_reply (req, SEAF_HTTP_RES_REPO_DELETED); - goto out; - } - if (repo->is_corrupted || repo->repaired) { - evhtp_send_reply (req, SEAF_HTTP_RES_REPO_CORRUPTED); - goto out; - } - - int token_status = validate_token (htp_server, req, repo_id, &username, TRUE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - /* We shall actually check the permission from database, don't rely on - * the cache here. - */ - int perm_status = check_permission (htp_server, repo_id, username, op, TRUE); - if (perm_status == EVHTP_RES_FORBIDDEN) { - evhtp_send_reply (req, EVHTP_RES_FORBIDDEN); - goto out; - } - - ip = get_client_ip_addr (req); - if (!ip) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - token = evhtp_kv_find (req->headers_in, "Seafile-Repo-Token"); - seaf_warning ("[%s] Failed to get client ip.\n", token); - goto out; - } - - if (strcmp (op, "download") == 0) { - on_repo_oper (htp_server, "repo-download-sync", repo_id, username, ip, client_name); - } - /* else if (strcmp (op, "upload") == 0) { */ - /* on_repo_oper (htp_server, "repo-upload-sync", repo_id, username, ip, client_name); */ - /* } */ - - if (client_id && client_name) { - token = evhtp_kv_find (req->headers_in, "Seafile-Repo-Token"); - - /* Record the (token, email, ) information, may - * include peer_id, peer_ip, peer_name, etc. - */ - if (!seaf_repo_manager_token_peer_info_exists (seaf->repo_mgr, token)) - seaf_repo_manager_add_token_peer_info (seaf->repo_mgr, - token, - client_id, - ip, - client_name, - (gint64)time(NULL), - client_ver); - else - seaf_repo_manager_update_token_peer_info (seaf->repo_mgr, - token, - ip, - (gint64)time(NULL), - client_ver); - } - - evhtp_send_reply (req, EVHTP_RES_OK); - -out: - g_free (username); - g_strfreev (parts); - g_free (ip); - g_free (client_name); - if (repo) { - seaf_repo_unref (repo); - } -} - -static void -get_protocol_cb (evhtp_request_t *req, void *arg) -{ - evbuffer_add (req->buffer_out, PROTO_VERSION, strlen (PROTO_VERSION)); - evhtp_send_reply (req, EVHTP_RES_OK); -} - -static void -get_check_quota_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - const char *delta = evhtp_kv_find (req->uri->query, "delta"); - if (delta == NULL) { - char *error = "Invalid delta parameter.\n"; - seaf_warning ("%s", error); - evbuffer_add (req->buffer_out, error, strlen (error)); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - char *next_ptr = NULL; - gint64 delta_num = strtoll(delta, &next_ptr, 10); - if (!(*delta != '\0' && *next_ptr == '\0')) { - char *error = "Invalid delta parameter.\n"; - seaf_warning ("%s", error); - evbuffer_add (req->buffer_out, error, strlen (error)); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - int ret = seaf_quota_manager_check_quota_with_delta (seaf->quota_mgr, - repo_id, delta_num); - if (ret < 0) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - } else if (ret == 0) { - evhtp_send_reply (req, EVHTP_RES_OK); - } else { - evhtp_send_reply (req, SEAF_HTTP_RES_NOQUOTA); - } - -out: - g_strfreev (parts); -} - -static gboolean -get_branch (SeafDBRow *row, void *vid) -{ - char *ret = vid; - const char *commit_id; - - commit_id = seaf_db_row_get_column_text (row, 0); - memcpy (ret, commit_id, 41); - - return FALSE; -} - -static void -get_head_commit_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - gboolean db_err = FALSE, exists = TRUE; - int token_status; - char commit_id[41]; - char *sql; - - sql = "SELECT 1 FROM Repo WHERE repo_id=?"; - exists = seaf_db_statement_exists (seaf->db, sql, &db_err, 1, "string", repo_id); - if (!exists) { - if (db_err) { - seaf_warning ("DB error when check repo existence.\n"); - evbuffer_add_printf (req->buffer_out, - "{\"is_corrupted\": 1}"); - evhtp_send_reply (req, EVHTP_RES_OK); - goto out; - } - evhtp_send_reply (req, SEAF_HTTP_RES_REPO_DELETED); - goto out; - } - - token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - commit_id[0] = 0; - - sql = "SELECT commit_id FROM Branch WHERE name='master' AND repo_id=?"; - if (seaf_db_statement_foreach_row (seaf->db, sql, - get_branch, commit_id, - 1, "string", repo_id) < 0) { - seaf_warning ("DB error when get branch master.\n"); - evbuffer_add_printf (req->buffer_out, - "{\"is_corrupted\": 1}"); - evhtp_send_reply (req, EVHTP_RES_OK); - goto out; - } - - if (commit_id[0] == 0) { - evhtp_send_reply (req, SEAF_HTTP_RES_REPO_DELETED); - goto out; - } - - evbuffer_add_printf (req->buffer_out, - "{\"is_corrupted\": 0, \"head_commit_id\": \"%s\"}", - commit_id); - evhtp_send_reply (req, EVHTP_RES_OK); - -out: - g_strfreev (parts); -} - -static char * -gen_merge_description (SeafRepo *repo, - const char *merged_root, - const char *p1_root, - const char *p2_root) -{ - GList *p; - GList *results = NULL; - char *desc; - - diff_merge_roots (repo->store_id, repo->version, - merged_root, p1_root, p2_root, &results, TRUE); - - desc = diff_results_to_description (results); - - for (p = results; p; p = p->next) { - DiffEntry *de = p->data; - diff_entry_free (de); - } - g_list_free (results); - - return desc; -} - -static int -fast_forward_or_merge (const char *repo_id, - SeafCommit *base, - SeafCommit *new_commit) -{ -#define MAX_RETRY_COUNT 3 - - SeafRepo *repo = NULL; - SeafCommit *current_head = NULL, *merged_commit = NULL; - int retry_cnt = 0; - int ret = 0; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - ret = -1; - goto out; - } - -retry: - current_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!current_head) { - seaf_warning ("Failed to find head commit of %s.\n", repo_id); - ret = -1; - goto out; - } - - /* Merge if base and head are not the same. */ - if (strcmp (base->commit_id, current_head->commit_id) != 0) { - MergeOptions opt; - const char *roots[3]; - char *desc = NULL; - - memset (&opt, 0, sizeof(opt)); - opt.n_ways = 3; - memcpy (opt.remote_repo_id, repo_id, 36); - memcpy (opt.remote_head, new_commit->commit_id, 40); - opt.do_merge = TRUE; - - roots[0] = base->root_id; /* base */ - roots[1] = current_head->root_id; /* head */ - roots[2] = new_commit->root_id; /* remote */ - - if (seaf_merge_trees (repo->store_id, repo->version, 3, roots, &opt) < 0) { - seaf_warning ("Failed to merge.\n"); - ret = -1; - goto out; - } - - if (!opt.conflict) - desc = g_strdup("Auto merge by system"); - else { - desc = gen_merge_description (repo, - opt.merged_tree_root, - current_head->root_id, - new_commit->root_id); - if (!desc) - desc = g_strdup("Auto merge by system"); - } - - merged_commit = seaf_commit_new(NULL, repo->id, opt.merged_tree_root, - new_commit->creator_name, EMPTY_SHA1, - desc, - 0); - g_free (desc); - - merged_commit->parent_id = g_strdup (current_head->commit_id); - merged_commit->second_parent_id = g_strdup (new_commit->commit_id); - merged_commit->new_merge = TRUE; - if (opt.conflict) - merged_commit->conflict = TRUE; - seaf_repo_to_commit (repo, merged_commit); - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged_commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - ret = -1; - goto out; - } - } else { - seaf_commit_ref (new_commit); - merged_commit = new_commit; - } - - seaf_branch_set_commit(repo->head, merged_commit->commit_id); - - if (seaf_branch_manager_test_and_update_branch(seaf->branch_mgr, - repo->head, - current_head->commit_id) < 0) - { - seaf_repo_unref (repo); - repo = NULL; - seaf_commit_unref (current_head); - current_head = NULL; - seaf_commit_unref (merged_commit); - merged_commit = NULL; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - ret = -1; - goto out; - } - - if (++retry_cnt <= MAX_RETRY_COUNT) { - /* Sleep random time between 100 and 1000 millisecs. */ - usleep (g_random_int_range(1, 11) * 100 * 1000); - goto retry; - } else { - ret = -1; - goto out; - } - } - -out: - seaf_commit_unref (current_head); - seaf_commit_unref (merged_commit); - seaf_repo_unref (repo); - return ret; -} - -static void -put_update_branch_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts; - char *repo_id; - char *username = NULL; - SeafRepo *repo = NULL; - SeafCommit *new_commit = NULL, *base = NULL; - - const char *new_commit_id = evhtp_kv_find (req->uri->query, "head"); - if (new_commit_id == NULL || !is_object_id_valid (new_commit_id)) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - parts = g_strsplit (req->uri->path->full + 1, "/", 0); - repo_id = parts[1]; - - int token_status = validate_token (htp_server, req, repo_id, &username, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - int perm_status = check_permission (htp_server, repo_id, username, - "upload", FALSE); - if (perm_status == EVHTP_RES_FORBIDDEN) { - evhtp_send_reply (req, EVHTP_RES_FORBIDDEN); - goto out; - } - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s is missing or corrupted.\n", repo_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - /* Since this is the last step of upload procedure, commit should exist. */ - new_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - new_commit_id); - if (!new_commit) { - seaf_warning ("Failed to get commit %s for repo %s.\n", - new_commit_id, repo->id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - base = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - new_commit->parent_id); - if (!base) { - seaf_warning ("Failed to get commit %s for repo %s.\n", - new_commit->parent_id, repo->id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { - evhtp_send_reply (req, SEAF_HTTP_RES_NOQUOTA); - goto out; - } - - if (fast_forward_or_merge (repo_id, base, new_commit) < 0) { - seaf_warning ("Fast forward merge for repo %s is failed.\n", repo_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (seaf->repo_mgr, repo_id); - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, repo_id, NULL); - - schedule_repo_size_computation (seaf->size_sched, repo_id); - - evhtp_send_reply (req, EVHTP_RES_OK); - -out: - seaf_repo_unref (repo); - seaf_commit_unref (new_commit); - seaf_commit_unref (base); - g_free (username); - g_strfreev (parts); -} - -static void -head_commit_oper_cb (evhtp_request_t *req, void *arg) -{ - htp_method req_method = evhtp_request_get_method (req); - - if (req_method == htp_method_GET) { - get_head_commit_cb (req, arg); - } else if (req_method == htp_method_PUT) { - put_update_branch_cb (req, arg); - } -} - -static void -get_commit_info_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - char *commit_id = parts[3]; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - char *data = NULL; - int len; - - int ret = seaf_obj_store_read_obj (seaf->commit_mgr->obj_store, repo_id, 1, - commit_id, (void **)&data, &len); - if (ret < 0) { - seaf_warning ("Get commit info failed: commit %s is missing.\n", commit_id); - evhtp_send_reply (req, EVHTP_RES_NOTFOUND); - goto out; - } - - evbuffer_add (req->buffer_out, data, len); - evhtp_send_reply (req, EVHTP_RES_OK); - g_free (data); - -out: - g_strfreev (parts); -} - -static void -put_commit_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - char *commit_id = parts[3]; - char *username = NULL; - void *data = NULL; - - int token_status = validate_token (htp_server, req, repo_id, &username, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - int perm_status = check_permission (htp_server, repo_id, username, - "upload", FALSE); - if (perm_status == EVHTP_RES_FORBIDDEN) { - evhtp_send_reply (req, EVHTP_RES_FORBIDDEN); - goto out; - } - - int con_len = evbuffer_get_length (req->buffer_in); - if(con_len == 0) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - data = g_new0 (char, con_len); - if (!data) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_warning ("Failed to allocate %d bytes memory.\n", con_len); - goto out; - } - - evbuffer_remove (req->buffer_in, data, con_len); - SeafCommit *commit = seaf_commit_from_data (commit_id, (char *)data, con_len); - if (!commit) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - if (strcmp (commit->repo_id, repo_id) != 0) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, commit) < 0) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - } else { - evhtp_send_reply (req, EVHTP_RES_OK); - } - seaf_commit_unref (commit); - -out: - g_free (username); - g_free (data); - g_strfreev (parts); -} - -static void -commit_oper_cb (evhtp_request_t *req, void *arg) -{ - htp_method req_method = evhtp_request_get_method (req); - - if (req_method == htp_method_PUT) { - put_commit_cb (req, arg); - } else if (req_method == htp_method_GET) { - get_commit_info_cb (req, arg); - } -} - -static int -collect_file_ids (int n, const char *basedir, SeafDirent *files[], void *data) -{ - SeafDirent *file1 = files[0]; - SeafDirent *file2 = files[1]; - GList **pret = data; - - if (file1 && (!file2 || strcmp(file1->id, file2->id) != 0) && - strcmp (file1->id, EMPTY_SHA1) != 0) - *pret = g_list_prepend (*pret, g_strdup(file1->id)); - - return 0; -} - -static int -collect_file_ids_nop (int n, const char *basedir, SeafDirent *files[], void *data) -{ - return 0; -} - -static int -collect_dir_ids (int n, const char *basedir, SeafDirent *dirs[], void *data, - gboolean *recurse) -{ - SeafDirent *dir1 = dirs[0]; - SeafDirent *dir2 = dirs[1]; - GList **pret = data; - - if (dir1 && (!dir2 || strcmp(dir1->id, dir2->id) != 0) && - strcmp (dir1->id, EMPTY_SHA1) != 0) - *pret = g_list_prepend (*pret, g_strdup(dir1->id)); - - return 0; -} - -static int -calculate_send_object_list (SeafRepo *repo, - const char *server_head, - const char *client_head, - gboolean dir_only, - GList **results) -{ - SeafCommit *remote_head = NULL, *master_head = NULL; - char *remote_head_root; - int ret = 0; - - *results = NULL; - - master_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - server_head); - if (!master_head) { - seaf_warning ("Server head commit %s:%s not found.\n", repo->id, server_head); - return -1; - } - - if (client_head) { - remote_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - client_head); - if (!remote_head) { - seaf_warning ("Remote head commit %s:%s not found.\n", - repo->id, client_head); - ret = -1; - goto out; - } - remote_head_root = remote_head->root_id; - } else - remote_head_root = EMPTY_SHA1; - - /* Diff won't traverse the root object itself. */ - if (strcmp (remote_head_root, master_head->root_id) != 0 && - strcmp (master_head->root_id, EMPTY_SHA1) != 0) - *results = g_list_prepend (*results, g_strdup(master_head->root_id)); - - DiffOptions opts; - memset (&opts, 0, sizeof(opts)); - memcpy (opts.store_id, repo->store_id, 36); - opts.version = repo->version; - if (!dir_only) - opts.file_cb = collect_file_ids; - else - opts.file_cb = collect_file_ids_nop; - opts.dir_cb = collect_dir_ids; - opts.data = results; - - const char *trees[2]; - trees[0] = master_head->root_id; - trees[1] = remote_head_root; - if (diff_trees (2, trees, &opts) < 0) { - seaf_warning ("Failed to diff remote and master head for repo %.8s.\n", - repo->id); - string_list_free (*results); - ret = -1; - } - -out: - seaf_commit_unref (remote_head); - seaf_commit_unref (master_head); - return ret; -} - -static void -get_fs_obj_id_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts; - char *repo_id; - SeafRepo *repo = NULL; - gboolean dir_only = FALSE; - - const char *server_head = evhtp_kv_find (req->uri->query, "server-head"); - if (server_head == NULL || !is_object_id_valid (server_head)) { - char *error = "Invalid server-head parameter.\n"; - seaf_warning ("%s", error); - evbuffer_add (req->buffer_out, error, strlen (error)); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - const char *client_head = evhtp_kv_find (req->uri->query, "client-head"); - if (client_head && !is_object_id_valid (client_head)) { - char *error = "Invalid client-head parameter.\n"; - seaf_warning ("%s", error); - evbuffer_add (req->buffer_out, error, strlen (error)); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - const char *dir_only_arg = evhtp_kv_find (req->uri->query, "dir-only"); - if (dir_only_arg) - dir_only = TRUE; - - parts = g_strsplit (req->uri->path->full + 1, "/", 0); - repo_id = parts[1]; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - GList *list = NULL, *ptr; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Failed to find repo %.8s.\n", repo_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - if (calculate_send_object_list (repo, server_head, client_head, dir_only, &list) < 0) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - json_t *obj_array = json_array (); - - for (ptr = list; ptr; ptr = ptr->next) { - json_array_append_new (obj_array, json_string (ptr->data)); - g_free (ptr->data); - } - g_list_free (list); - - char *obj_list = json_dumps (obj_array, JSON_COMPACT); - evbuffer_add (req->buffer_out, obj_list, strlen (obj_list)); - evhtp_send_reply (req, EVHTP_RES_OK); - - g_free (obj_list); - json_decref (obj_array); - -out: - g_strfreev (parts); - seaf_repo_unref (repo); -} - -static void -get_block_cb (evhtp_request_t *req, void *arg) -{ - const char *repo_id = NULL; - char *block_id = NULL; - char *store_id = NULL; - HttpServer *htp_server = arg; - BlockMetadata *blk_meta = NULL; - - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - repo_id = parts[1]; - block_id = parts[3]; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - blk_meta = seaf_block_manager_stat_block (seaf->block_mgr, - store_id, 1, block_id); - if (blk_meta == NULL) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - BlockHandle *blk_handle = NULL; - blk_handle = seaf_block_manager_open_block(seaf->block_mgr, - store_id, 1, block_id, BLOCK_READ); - if (!blk_handle) { - seaf_warning ("Failed to open block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - void *block_con = g_new0 (char, blk_meta->size); - if (!block_con) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_warning ("Failed to allocate %d bytes memeory.\n", blk_meta->size); - goto free_handle; - } - - int rsize = seaf_block_manager_read_block (seaf->block_mgr, - blk_handle, block_con, - blk_meta->size); - if (rsize != blk_meta->size) { - seaf_warning ("Failed to read block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - } else { - evbuffer_add (req->buffer_out, block_con, blk_meta->size); - evhtp_send_reply (req, EVHTP_RES_OK); - } - g_free (block_con); - -free_handle: - seaf_block_manager_close_block (seaf->block_mgr, blk_handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, blk_handle); - -out: - g_free (blk_meta); - g_free (store_id); - g_strfreev (parts); -} - -static void -put_send_block_cb (evhtp_request_t *req, void *arg) -{ - const char *repo_id = NULL; - char *block_id = NULL; - char *store_id = NULL; - char *username = NULL; - HttpServer *htp_server = arg; - char **parts = NULL; - void *blk_con = NULL; - - parts = g_strsplit (req->uri->path->full + 1, "/", 0); - repo_id = parts[1]; - block_id = parts[3]; - - int token_status = validate_token (htp_server, req, repo_id, &username, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - int perm_status = check_permission (htp_server, repo_id, username, - "upload", FALSE); - if (perm_status == EVHTP_RES_FORBIDDEN) { - evhtp_send_reply (req, EVHTP_RES_FORBIDDEN); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - int blk_len = evbuffer_get_length (req->buffer_in); - if (blk_len == 0) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - blk_con = g_new0 (char, blk_len); - if (!blk_con) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_warning ("Failed to allocate %d bytes memory.\n", blk_len); - goto out; - } - - evbuffer_remove (req->buffer_in, blk_con, blk_len); - - BlockHandle *blk_handle = NULL; - blk_handle = seaf_block_manager_open_block (seaf->block_mgr, - store_id, 1, block_id, BLOCK_WRITE); - if (blk_handle == NULL) { - seaf_warning ("Failed to open block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - if (seaf_block_manager_write_block (seaf->block_mgr, blk_handle, - blk_con, blk_len) != blk_len) { - seaf_warning ("Failed to write block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_block_manager_close_block (seaf->block_mgr, blk_handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, blk_handle); - goto out; - } - - if (seaf_block_manager_close_block (seaf->block_mgr, blk_handle) < 0) { - seaf_warning ("Failed to close block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_block_manager_block_handle_free (seaf->block_mgr, blk_handle); - goto out; - } - - if (seaf_block_manager_commit_block (seaf->block_mgr, - blk_handle) < 0) { - seaf_warning ("Failed to commit block %.8s:%s.\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_block_manager_block_handle_free (seaf->block_mgr, blk_handle); - goto out; - } - - seaf_block_manager_block_handle_free (seaf->block_mgr, blk_handle); - - evhtp_send_reply (req, EVHTP_RES_OK); - -out: - g_free (username); - g_free (store_id); - g_strfreev (parts); - g_free (blk_con); -} - -static void -block_oper_cb (evhtp_request_t *req, void *arg) -{ - htp_method req_method = evhtp_request_get_method (req); - - if (req_method == htp_method_GET) { - get_block_cb (req, arg); - } else if (req_method == htp_method_PUT) { - put_send_block_cb (req, arg); - } -} - -static void -post_check_exist_cb (evhtp_request_t *req, void *arg, CheckExistType type) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - char *repo_id = parts[1]; - char *store_id = NULL; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - size_t list_len = evbuffer_get_length (req->buffer_in); - if (list_len == 0) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - char *obj_list_con = g_new0 (char, list_len); - if (!obj_list_con) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_warning ("Failed to allocate %zu bytes memory.\n", list_len); - goto out; - } - - json_error_t jerror; - evbuffer_remove (req->buffer_in, obj_list_con, list_len); - json_t *obj_array = json_loadb (obj_list_con, list_len, 0, &jerror); - g_free (obj_list_con); - - if (!obj_array) { - seaf_warning ("dump obj_id to json failed, error: %s\n", jerror.text); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - return; - } - - json_t *obj = NULL; - gboolean ret = TRUE; - const char *obj_id = NULL; - int index = 0; - - int array_size = json_array_size (obj_array); - json_t *needed_objs = json_array(); - - for (; index < array_size; ++index) { - obj = json_array_get (obj_array, index); - obj_id = json_string_value (obj); - if (!is_object_id_valid (obj_id)) - continue; - - if (type == CHECK_FS_EXIST) { - ret = seaf_fs_manager_object_exists (seaf->fs_mgr, store_id, 1, - obj_id); - } else if (type == CHECK_BLOCK_EXIST) { - ret = seaf_block_manager_block_exists (seaf->block_mgr, store_id, 1, - obj_id); - } - - if (!ret) { - json_array_append (needed_objs, obj); - } - } - - char *ret_array = json_dumps (needed_objs, JSON_COMPACT); - evbuffer_add (req->buffer_out, ret_array, strlen (ret_array)); - evhtp_send_reply (req, EVHTP_RES_OK); - - g_free (ret_array); - json_decref (needed_objs); - json_decref (obj_array); - -out: - g_free (store_id); - g_strfreev (parts); -} - -static void -post_check_fs_cb (evhtp_request_t *req, void *arg) -{ - post_check_exist_cb (req, arg, CHECK_FS_EXIST); -} - -static void -post_check_block_cb (evhtp_request_t *req, void *arg) -{ - post_check_exist_cb (req, arg, CHECK_BLOCK_EXIST); -} - -static void -post_recv_fs_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - const char *repo_id = parts[1]; - char *store_id = NULL; - char *username = NULL; - FsHdr *hdr = NULL; - - int token_status = validate_token (htp_server, req, repo_id, &username, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - int perm_status = check_permission (htp_server, repo_id, username, - "upload", FALSE); - if (perm_status == EVHTP_RES_FORBIDDEN) { - evhtp_send_reply (req, EVHTP_RES_FORBIDDEN); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - int fs_con_len = evbuffer_get_length (req->buffer_in); - if (fs_con_len < sizeof(FsHdr)) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - hdr = g_new0 (FsHdr, 1); - if (!hdr) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - char obj_id[41]; - void *obj_con = NULL; - int con_len; - - while (fs_con_len > 0) { - if (fs_con_len < sizeof(FsHdr)) { - seaf_warning ("Bad fs object content format from %.8s:%s.\n", - repo_id, username); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - break; - } - - evbuffer_remove (req->buffer_in, hdr, sizeof(FsHdr)); - con_len = ntohl (hdr->obj_size); - memcpy (obj_id, hdr->obj_id, 40); - obj_id[40] = 0; - - if (!is_object_id_valid (obj_id)) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - break; - } - - obj_con = g_new0 (char, con_len); - if (!obj_con) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - break; - } - evbuffer_remove (req->buffer_in, obj_con, con_len); - - if (seaf_obj_store_write_obj (seaf->fs_mgr->obj_store, - store_id, 1, obj_id, obj_con, - con_len, FALSE) < 0) { - seaf_warning ("Failed to write fs object %.8s to disk.\n", - obj_id); - g_free (obj_con); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - break; - } - - fs_con_len -= (con_len + sizeof(FsHdr)); - g_free (obj_con); - } - - if (fs_con_len == 0) { - evhtp_send_reply (req, EVHTP_RES_OK); - } - -out: - g_free (store_id); - g_free (hdr); - g_free (username); - g_strfreev (parts); -} - -#define MAX_OBJECT_PACK_SIZE (1 << 20) /* 1MB */ - -static void -post_pack_fs_cb (evhtp_request_t *req, void *arg) -{ - HttpServer *htp_server = arg; - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - const char *repo_id = parts[1]; - char *store_id = NULL; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - int fs_id_list_len = evbuffer_get_length (req->buffer_in); - if (fs_id_list_len == 0) { - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - char *fs_id_list = g_new0 (char, fs_id_list_len); - if (!fs_id_list) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - seaf_warning ("Failed to allocate %d bytes memory.\n", fs_id_list_len); - goto out; - } - - json_error_t jerror; - evbuffer_remove (req->buffer_in, fs_id_list, fs_id_list_len); - json_t *fs_id_array = json_loadb (fs_id_list, fs_id_list_len, 0, &jerror); - - g_free (fs_id_list); - - if (!fs_id_array) { - seaf_warning ("dump fs obj_id from json failed, error: %s\n", jerror.text); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - goto out; - } - - json_t *obj = NULL; - const char *obj_id = NULL; - int index = 0; - void *fs_data = NULL; - int data_len; - int data_len_net; - int total_size = 0; - - int array_size = json_array_size (fs_id_array); - - for (; index < array_size; ++index) { - obj = json_array_get (fs_id_array, index); - obj_id = json_string_value (obj); - - if (!is_object_id_valid (obj_id)) { - seaf_warning ("Invalid fs id %s.\n", obj_id); - evhtp_send_reply (req, EVHTP_RES_BADREQ); - json_decref (fs_id_array); - goto out; - } - if (seaf_obj_store_read_obj (seaf->fs_mgr->obj_store, store_id, 1, - obj_id, &fs_data, &data_len) < 0) { - seaf_warning ("Failed to read seafile object %s:%s.\n", store_id, obj_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - json_decref (fs_id_array); - goto out; - } - - evbuffer_add (req->buffer_out, obj_id, 40); - data_len_net = htonl (data_len); - evbuffer_add (req->buffer_out, &data_len_net, 4); - evbuffer_add (req->buffer_out, fs_data, data_len); - - total_size += data_len; - g_free (fs_data); - - if (total_size >= MAX_OBJECT_PACK_SIZE) - break; - } - - evhtp_send_reply (req, EVHTP_RES_OK); - - json_decref (fs_id_array); -out: - g_free (store_id); - g_strfreev (parts); -} - -static void -get_block_map_cb (evhtp_request_t *req, void *arg) -{ - const char *repo_id = NULL; - char *file_id = NULL; - char *store_id = NULL; - HttpServer *htp_server = arg; - Seafile *file = NULL; - char *block_id; - BlockMetadata *blk_meta = NULL; - json_t *array = NULL; - char *data = NULL; - - char **parts = g_strsplit (req->uri->path->full + 1, "/", 0); - repo_id = parts[1]; - file_id = parts[3]; - - int token_status = validate_token (htp_server, req, repo_id, NULL, FALSE); - if (token_status != EVHTP_RES_OK) { - evhtp_send_reply (req, token_status); - goto out; - } - - store_id = get_repo_store_id (htp_server, repo_id); - if (!store_id) { - evhtp_send_reply (req, EVHTP_RES_SERVERR); - goto out; - } - - file = seaf_fs_manager_get_seafile (seaf->fs_mgr, store_id, 1, file_id); - if (!file) { - evhtp_send_reply (req, EVHTP_RES_NOTFOUND); - goto out; - } - - array = json_array (); - - int i; - for (i = 0; i < file->n_blocks; ++i) { - block_id = file->blk_sha1s[i]; - blk_meta = seaf_block_manager_stat_block (seaf->block_mgr, - store_id, 1, block_id); - if (blk_meta == NULL) { - seaf_warning ("Failed to find block %s/%s\n", store_id, block_id); - evhtp_send_reply (req, EVHTP_RES_SERVERR); - g_free (blk_meta); - goto out; - } - json_array_append_new (array, json_integer(blk_meta->size)); - g_free (blk_meta); - } - - data = json_dumps (array, JSON_COMPACT); - evbuffer_add (req->buffer_out, data, strlen (data)); - evhtp_send_reply (req, EVHTP_RES_OK); - -out: - g_free (store_id); - seafile_unref (file); - if (array) - json_decref (array); - if (data) - free (data); - g_strfreev (parts); -} - -static void -http_request_init (HttpServerStruct *server) -{ - HttpServer *priv = server->priv; - - evhtp_set_cb (priv->evhtp, - GET_PROTO_PATH, get_protocol_cb, - NULL); - - evhtp_set_regex_cb (priv->evhtp, - GET_CHECK_QUOTA_REGEX, get_check_quota_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - OP_PERM_CHECK_REGEX, get_check_permission_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - HEAD_COMMIT_OPER_REGEX, head_commit_oper_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - COMMIT_OPER_REGEX, commit_oper_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - GET_FS_OBJ_ID_REGEX, get_fs_obj_id_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - BLOCK_OPER_REGEX, block_oper_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - POST_CHECK_FS_REGEX, post_check_fs_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - POST_CHECK_BLOCK_REGEX, post_check_block_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - POST_RECV_FS_REGEX, post_recv_fs_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - POST_PACK_FS_REGEX, post_pack_fs_cb, - priv); - - evhtp_set_regex_cb (priv->evhtp, - GET_BLOCK_MAP_REGEX, get_block_map_cb, - priv); - - /* Web access file */ - access_file_init (priv->evhtp); - - /* Web upload file */ - upload_file_init (priv->evhtp, server->http_temp_dir); -} - -static void -token_cache_value_free (gpointer data) -{ - TokenInfo *token_info = (TokenInfo *)data; - if (token_info != NULL) { - g_free (token_info->repo_id); - g_free (token_info->email); - g_free (token_info); - } -} - -static gboolean -is_token_expire (gpointer key, gpointer value, gpointer arg) -{ - TokenInfo *token_info = (TokenInfo *)value; - - if(token_info && token_info->expire_time <= (gint64)time(NULL)) { - return TRUE; - } - - return FALSE; -} - -static void -perm_cache_value_free (gpointer data) -{ - PermInfo *perm_info = data; - g_free (perm_info->perm); - g_free (perm_info); -} - -static gboolean -is_perm_expire (gpointer key, gpointer value, gpointer arg) -{ - PermInfo *perm_info = (PermInfo *)value; - - if(perm_info && perm_info->expire_time <= (gint64)time(NULL)) { - return TRUE; - } - - return FALSE; -} - -static gboolean -is_vir_repo_info_expire (gpointer key, gpointer value, gpointer arg) -{ - VirRepoInfo *vinfo = (VirRepoInfo *)value; - - if(vinfo && vinfo->expire_time <= (gint64)time(NULL)) { - return TRUE; - } - - return FALSE; -} - -static void -free_vir_repo_info (gpointer data) -{ - if (!data) - return; - - VirRepoInfo *vinfo = data; - - if (vinfo->store_id) - g_free (vinfo->store_id); - - g_free (vinfo); -} - -static void -remove_expire_cache_cb (evutil_socket_t sock, short type, void *data) -{ - HttpServer *htp_server = data; - - pthread_mutex_lock (&htp_server->token_cache_lock); - g_hash_table_foreach_remove (htp_server->token_cache, is_token_expire, NULL); - pthread_mutex_unlock (&htp_server->token_cache_lock); - - pthread_mutex_lock (&htp_server->perm_cache_lock); - g_hash_table_foreach_remove (htp_server->perm_cache, is_perm_expire, NULL); - pthread_mutex_unlock (&htp_server->perm_cache_lock); - - pthread_mutex_lock (&htp_server->vir_repo_info_cache_lock); - g_hash_table_foreach_remove (htp_server->vir_repo_info_cache, - is_vir_repo_info_expire, NULL); - pthread_mutex_unlock (&htp_server->vir_repo_info_cache_lock); -} - -static void * -http_server_run (void *arg) -{ - HttpServerStruct *server = arg; - HttpServer *priv = server->priv; - - priv->evbase = event_base_new(); - priv->evhtp = evhtp_new(priv->evbase, NULL); - - if (evhtp_bind_socket(priv->evhtp, - server->bind_addr, - server->bind_port, 128) < 0) { - seaf_warning ("Could not bind socket: %s\n", strerror (errno)); - exit(-1); - } - - http_request_init (server); - - evhtp_use_threads (priv->evhtp, NULL, DEFAULT_THREADS, NULL); - - struct timeval tv; - tv.tv_sec = CLEANING_INTERVAL_SEC; - tv.tv_usec = 0; - priv->reap_timer = event_new (priv->evbase, - -1, - EV_PERSIST, - remove_expire_cache_cb, - priv); - evtimer_add (priv->reap_timer, &tv); - - event_base_loop (priv->evbase, 0); - - return NULL; -} - -HttpServerStruct * -seaf_http_server_new (struct _SeafileSession *session) -{ - HttpServerStruct *server = g_new0 (HttpServerStruct, 1); - HttpServer *priv = g_new0 (HttpServer, 1); - - priv->evbase = NULL; - priv->evhtp = NULL; - - load_http_config (server, session); - - priv->token_cache = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, token_cache_value_free); - pthread_mutex_init (&priv->token_cache_lock, NULL); - - priv->perm_cache = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, perm_cache_value_free); - pthread_mutex_init (&priv->perm_cache_lock, NULL); - - priv->vir_repo_info_cache = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, free_vir_repo_info); - pthread_mutex_init (&priv->vir_repo_info_cache_lock, NULL); - - server->http_temp_dir = g_build_filename (session->seaf_dir, "httptemp", NULL); - - server->seaf_session = session; - server->priv = priv; - - return server; -} - -int -seaf_http_server_start (HttpServerStruct *server) -{ - server->priv->cevent_id = cevent_manager_register (seaf->ev_mgr, - (cevent_handler)publish_repo_event, - NULL); - - int ret = pthread_create (&server->priv->thread_id, NULL, http_server_run, server); - if (ret != 0) - return -1; - - pthread_detach (server->priv->thread_id); - return 0; -} - -int -seaf_http_server_invalidate_tokens (HttpServerStruct *htp_server, - const GList *tokens) -{ - const GList *p; - - pthread_mutex_lock (&htp_server->priv->token_cache_lock); - for (p = tokens; p; p = p->next) { - const char *token = (char *)p->data; - g_hash_table_remove (htp_server->priv->token_cache, token); - } - pthread_mutex_unlock (&htp_server->priv->token_cache_lock); - return 0; -} diff --git a/server/http-server.h b/server/http-server.h deleted file mode 100644 index 2642aa6d..00000000 --- a/server/http-server.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef HTTP_SERVER_H -#define HTTP_SERVER_H - -#include - -struct _SeafileSession; - -struct _HttpServer; - -struct _HttpServerStruct { - struct _SeafileSession *seaf_session; - - struct _HttpServer *priv; - - char *bind_addr; - int bind_port; - char *http_temp_dir; /* temp dir for file upload */ - char *windows_encoding; - gint64 max_upload_size; - gint64 max_download_dir_size; - int max_indexing_threads; -}; - -typedef struct _HttpServerStruct HttpServerStruct; - -HttpServerStruct * -seaf_http_server_new (struct _SeafileSession *session); - -int -seaf_http_server_start (HttpServerStruct *htp_server); - -int -seaf_http_server_invalidate_tokens (HttpServerStruct *htp_server, - const GList *tokens); - -#endif diff --git a/server/http-status-codes.h b/server/http-status-codes.h deleted file mode 100644 index 2cfc97d6..00000000 --- a/server/http-status-codes.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef HTTP_STATUS_CODES_H -#define HTTP_STATUS_CODES_H - -/* Seafile specific http status codes. */ - -#define SEAF_HTTP_RES_BADFILENAME 440 -#define SEAF_HTTP_RES_EXISTS 441 -#define SEAF_HTTP_RES_NOT_EXISTS 441 -#define SEAF_HTTP_RES_TOOLARGE 442 -#define SEAF_HTTP_RES_NOQUOTA 443 -#define SEAF_HTTP_RES_REPO_DELETED 444 -#define SEAF_HTTP_RES_REPO_CORRUPTED 445 -#define SEAF_HTTP_RES_BLOCK_MISSING 446 - - -#endif diff --git a/server/listen-mgr.c b/server/listen-mgr.c deleted file mode 100644 index 6cc2e5dd..00000000 --- a/server/listen-mgr.c +++ /dev/null @@ -1,275 +0,0 @@ -#include "common.h" - -#include -#include - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -#include -#endif - - -#include "seafile-session.h" -#include "utils.h" -#include "net.h" -#include "listen-mgr.h" -#include "block-tx-server.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" - - -#define DEFAULT_SERVER_PORT 12001 - -#define TOKEN_LEN 37 /* a uuid */ -#define CHECK_EXPIRE_INTERVAL 1 -#define READ_TOKEN_TIMEOUT 180 /* bufferevent read timeout */ - -struct _SeafListenManagerPriv { - GHashTable *token_hash; - struct evconnlistener *listener; - CcnetTimer *check_timer; -}; - -typedef struct { - int ttl; - ConnAcceptedCB func; - void *user_data; -} CallBackStruct; - -static void accept_connection (struct evconnlistener *listener, - evutil_socket_t connfd, - struct sockaddr *saddr, - int socklen, - void *vmanager); - -static int token_expire_pulse (void * vmanager); -static void read_cb (struct bufferevent *bufev, void *user_data); -static void error_cb (struct bufferevent *bufev, short what, void *user_data); - -static int -get_listen_port (SeafileSession *session) -{ - char *port_str; - int port = 0; - - port_str = g_key_file_get_string (session->config, "network", "port", NULL); - if (port_str) { - port = atoi(port_str); - - if (port <= 0 || port > 65535) - port = DEFAULT_SERVER_PORT; - - g_free(port_str); - } - - return port; -} - - -SeafListenManager * -seaf_listen_manager_new (SeafileSession *session) -{ - SeafListenManager *mgr; - mgr = g_new0 (SeafListenManager, 1); - mgr->port = get_listen_port(session); - - mgr->priv = g_new0 (SeafListenManagerPriv, 1); - mgr->priv->token_hash = g_hash_table_new_full ( - g_str_hash, g_str_equal, g_free, g_free); - - return mgr; -} - -int -seaf_listen_manager_start (SeafListenManager *mgr) -{ - evutil_socket_t listenfd; - unsigned flags; - SeafListenManagerPriv *priv = mgr->priv; - - if (mgr->port == 0) { - return 0; - } - - listenfd = ccnet_net_bind_tcp (mgr->port, 1); - if (listenfd < 0) { - seaf_warning ("[listen mgr] failed to bind port %d\n", mgr->port); - return -1; - } - - flags = LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_EXEC; - - /* start to listen on block transfer port */ - priv->listener = evconnlistener_new (NULL, /* base */ - accept_connection, mgr, /* cb & arg */ - flags, /* flags */ - -1, /* backlog */ - listenfd); /* socket */ - - if (!priv->listener) { - seaf_warning ("[listen mgr] failed to start evlistener\n"); - evutil_closesocket (listenfd); - return -1; - } - - priv->check_timer = ccnet_timer_new (token_expire_pulse, mgr, - CHECK_EXPIRE_INTERVAL * 1000); - - seaf_message ("listen on port %d for block tranfer\n", mgr->port); - return 0; -} - -static void -accept_connection (struct evconnlistener *listener, - evutil_socket_t connfd, - struct sockaddr *saddr, int socklen, - void *vmanager) -{ - struct bufferevent *bufev; - struct timeval tv; - tv.tv_sec = READ_TOKEN_TIMEOUT; - tv.tv_usec = 0; - - bufev = bufferevent_socket_new (NULL, connfd, 0); - bufferevent_setcb (bufev, read_cb, NULL, error_cb, vmanager); - bufferevent_setwatermark (bufev, EV_READ, TOKEN_LEN, TOKEN_LEN); - bufferevent_set_timeouts (bufev, &tv, NULL); - - bufferevent_enable (bufev, EV_READ); - /* no write is needed here*/ - bufferevent_disable (bufev, EV_WRITE); -} - -static void -read_cb (struct bufferevent *bufev, void *user_data) -{ - char *token; - CallBackStruct *cbstruct; - SeafListenManager *mgr = user_data; - size_t len = EVBUFFER_LENGTH(bufev->input); - evutil_socket_t connfd = bufferevent_getfd(bufev); - - /* we set the high & low watermark to TOKEN_LEN, so the received data can - * only be this length. */ - if (len != TOKEN_LEN) { - seaf_warning ("[listen mgr] token with incorrect length received: %d\n", - (int)len); - goto error; - } - - token = (char *)(EVBUFFER_DATA (bufev->input)); - - /* Switch to new block protocol */ - if (strcmp (token, BLOCK_PROTOCOL_SIGNATURE) == 0) { - if (ccnet_net_make_socket_blocking (connfd) < 0) { - seaf_warning ("[listen mgr] Failed to set socket blocking.\n"); - goto error; - } - if (block_tx_server_start (connfd) < 0) { - seaf_warning ("Failed to start block tx server.\n"); - goto error; - } - bufferevent_free (bufev); - return; - } - - cbstruct = g_hash_table_lookup (mgr->priv->token_hash, token); - if (!cbstruct) { - seaf_warning ("[listen mgr] unknown token received: %s\n", token); - goto error; - } - - /* The connfd should be non-blocking for adding to bufferevent. - * But now we want it to be blocking again. - */ - if (ccnet_net_make_socket_blocking (connfd) < 0) { - seaf_warning ("[listen mgr] Failed to set socket blocking.\n"); - goto error; - } - - /* client is now connected, execute the callback function */ - cbstruct->func (connfd, cbstruct->user_data); - - g_hash_table_remove (mgr->priv->token_hash, token); - bufferevent_free (bufev); - return; - -error: - evutil_closesocket(connfd); - bufferevent_free (bufev); -} - -static void -error_cb (struct bufferevent *bufev, short what, void *user_data) -{ - if (what & BEV_EVENT_TIMEOUT) - seaf_warning ("[listen mgr] client timeout\n"); - else - seaf_warning ("[listen mgr] error when reading token\n"); - - /* We don't specify BEV_OPT_CLOSE_ON_FREE, so we need to close the socket - * manually. */ - evutil_closesocket(bufferevent_getfd(bufev)); - bufferevent_free (bufev); -} - - -int -seaf_listen_manager_register_token (SeafListenManager *mgr, - const char *token, - ConnAcceptedCB cb, - void *cb_arg, - int timeout_sec) -{ - CallBackStruct *cbstruct; - if (!token) - return -1; - - if (timeout_sec <= 0) - return -1; - - cbstruct = g_new0(CallBackStruct, 1); - cbstruct->func = cb; - cbstruct->user_data = cb_arg; - cbstruct->ttl = timeout_sec; - - g_hash_table_insert (mgr->priv->token_hash, g_strdup(token), cbstruct); - return 0; -} - -char * -seaf_listen_manager_generate_token (SeafListenManager *mgr) -{ - return gen_uuid(); -} - -static gboolean -is_token_expired (gpointer key, gpointer value, gpointer user_data) -{ - CallBackStruct *cbstruct = value; - - if (cbstruct->ttl == 0) { - /* client doesn't connect before timeout, so token is expired */ - seaf_warning ("[listen mgr] token timeout\n"); - cbstruct->func (-1, cbstruct->user_data); - return TRUE; - } - - --cbstruct->ttl; - - return FALSE; -} - -static int -token_expire_pulse (void * vmanager) -{ - SeafListenManager *mgr = vmanager; - g_hash_table_foreach_remove (mgr->priv->token_hash, - (GHRFunc)is_token_expired, - NULL); - - return TRUE; -} - diff --git a/server/listen-mgr.h b/server/listen-mgr.h deleted file mode 100644 index 7291608d..00000000 --- a/server/listen-mgr.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef SEAF_LISTEN_MANAGER_H -#define SEAF_LISTEN_MANAGER_H - -/** - * We always listen on the same tcp port for block tx. - * - * This module listens on the port, and when a new connection comes in, tries - * to read a 37-bit uuid(called a `token'), and deliveres the new socket to - * the corresponding block tx processor by calling the callback it provides - * when the token is registered. - * - * The socket accepted by listen-mgr may be closed by either: - * - * 1. By listen manager: - * - if timeout is reached or error occured when waiting for the token. - * - if a token is received, but no corresponding callback is found for - * this token. - * 2. If a valid token is received, the socket would be passed to the - * processor who registered the token, and the processor is now - * responsible for closing the socket. - */ - -typedef struct _SeafListenManager SeafListenManager; -typedef struct _SeafListenManagerPriv SeafListenManagerPriv; - -struct _SeafListenManager { - int port; - SeafListenManagerPriv *priv; -}; - -struct _SeafListenManager * -seaf_listen_manager_new (struct _SeafileSession *session); - -int -seaf_listen_manager_start (SeafListenManager *mgr); - -typedef void (*ConnAcceptedCB) (evutil_socket_t, void *); - -/** - * Register a token to identify a client when it connects later. - * - * @cb: this callback would be called with the connection socket, or with -1 when timeout - * @cb_arg: user supplied argument - * @timeout_sec: must be a positive number, the token would be expired after - * that many seconds. - */ -int -seaf_listen_manager_register_token (SeafListenManager *mgr, - const char *token, - ConnAcceptedCB cb, - void *cb_arg, - int timeout_sec); - -char * -seaf_listen_manager_generate_token (SeafListenManager *mgr); - -#endif diff --git a/server/pack-dir.c b/server/pack-dir.c deleted file mode 100644 index e7fa8e38..00000000 --- a/server/pack-dir.c +++ /dev/null @@ -1,436 +0,0 @@ -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_HTTP -#include "log.h" - -#include - -#include "seafile-object.h" -#include "seafile-crypt.h" -#include "seafile.h" - -#include "utils.h" - -#include "seafile-session.h" -#include "pack-dir.h" - -#include -#include -#include - -#ifdef WIN32 -#define S_IFLNK 0120000 /* Symbolic link */ -#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) -#endif - - -typedef struct { - struct archive *a; - SeafileCrypt *crypt; - const char *top_dir_name; - gboolean is_windows; - time_t mtime; - char store_id[37]; - int repo_version; - int tmp_fd; - char *tmp_zip_file; -} PackDirData; - -static char * -do_iconv (char *fromcode, char *tocode, char *in) -{ - iconv_t conv; - size_t inlen, outlen, len; - char out[1024]; - char *pin = in; - char *pout = out; - - conv = iconv_open (tocode, fromcode); - if (conv == (iconv_t)-1) { - return NULL; - } - - inlen = strlen (in); - outlen = sizeof(out); - - len = iconv (conv, &pin, &inlen, &pout, &outlen); - iconv_close (conv); - - if (len == -1) { - return NULL; - } - - outlen = sizeof(out) - outlen; - - return g_strndup(out, outlen); -} - -static int -add_file_to_archive (PackDirData *data, - const char *parent_dir, - SeafDirent *dent) -{ - struct archive *a = data->a; - struct SeafileCrypt *crypt = data->crypt; - gboolean is_windows = data->is_windows; - const char *top_dir_name = data->top_dir_name; - - struct archive_entry *entry = NULL; - Seafile *file = NULL; - char *pathname = NULL; - char buf[64 * 1024]; - int len = 0; - int n = 0; - int idx = 0; - BlockHandle *handle = NULL; - BlockMetadata *bmd = NULL; - char *blk_id = NULL; - uint32_t remain = 0; - EVP_CIPHER_CTX ctx; - gboolean enc_init = FALSE; - char *dec_out = NULL; - int dec_out_len = -1; - int ret = 0; - - pathname = g_build_filename (top_dir_name, parent_dir, dent->name, NULL); - - file = seaf_fs_manager_get_seafile (seaf->fs_mgr, - data->store_id, data->repo_version, - dent->id); - if (!file) { - ret = -1; - goto out; - } - - entry = archive_entry_new (); - - /* File name fixup for WinRAR */ - if (is_windows && seaf->http_server->windows_encoding) { - char *win_file_name = do_iconv ("UTF-8", - seaf->http_server->windows_encoding, - pathname); - if (!win_file_name) { - seaf_warning ("Failed to convert file name to %s\n", - seaf->http_server->windows_encoding); - ret = -1; - goto out; - } - archive_entry_copy_pathname (entry, win_file_name); - g_free (win_file_name); - - } else { - archive_entry_set_pathname (entry, pathname); - } - - /* FIXME: 0644 should be set when upload files in repo-mgr.c */ - archive_entry_set_mode (entry, dent->mode | 0644); - archive_entry_set_size (entry, file->file_size); - archive_entry_set_mtime (entry, data->mtime, 0); - - n = archive_write_header (a, entry); - if (n != ARCHIVE_OK) { - seaf_warning ("archive_write_header error: %s\n", archive_error_string(a)); - ret = -1; - goto out; - } - - /* Read data of this entry block by block */ - while (idx < file->n_blocks) { - blk_id = file->blk_sha1s[idx]; - handle = seaf_block_manager_open_block (seaf->block_mgr, - data->store_id, - data->repo_version, - blk_id, BLOCK_READ); - if (!handle) { - seaf_warning ("Failed to open block %s:%s\n", data->store_id, blk_id); - ret = -1; - goto out; - } - - bmd = seaf_block_manager_stat_block_by_handle (seaf->block_mgr, - handle); - if (!bmd) { - seaf_warning ("Failed to stat block %s:%s\n", data->store_id, blk_id); - ret = -1; - goto out; - } - remain = bmd->size; - g_free (bmd); - - if (crypt) { - if (seafile_decrypt_init (&ctx, crypt->version, - crypt->key, crypt->iv) < 0) { - seaf_warning ("Failed to init decrypt.\n"); - ret = -1; - goto out; - } - enc_init = TRUE; - } - - while (remain != 0) { - n = seaf_block_manager_read_block (seaf->block_mgr, handle, - buf, sizeof(buf)); - if (n <= 0) { - seaf_warning ("failed to read block %s\n", blk_id); - ret = -1; - goto out; - } - remain -= n; - - /* OK, We're read some data of this block */ - if (crypt == NULL) { - /* not encrypted */ - len = archive_write_data (a, buf, n); - if (len <= 0) { - seaf_warning ("archive_write_data error: %s\n", archive_error_string(a)); - ret = -1; - goto out; - } - - } else { - /* an encrypted block */ - dec_out = g_new (char, n + 16); - if (!dec_out) { - seaf_warning ("Failed to alloc memory.\n"); - ret = -1; - goto out; - } - - int r = EVP_DecryptUpdate (&ctx, - (unsigned char *)dec_out, - &dec_out_len, - (unsigned char *)buf, - n); - - /* EVP_DecryptUpdate returns 1 on success, 0 on failure */ - if (r != 1) { - seaf_warning ("Decrypt block %s failed.\n", blk_id); - ret = -1; - goto out; - } - - if (dec_out_len > 0) { - len = archive_write_data (a, dec_out, dec_out_len); - if (len <= 0) { - seaf_warning ("archive_write_data error: %s\n", archive_error_string(a)); - ret = -1; - goto out; - } - } - - /* If it's the last piece of a block, call decrypt_final() - * to decrypt the possible partial block. */ - if (remain == 0) { - r = EVP_DecryptFinal_ex (&ctx, - (unsigned char *)dec_out, - &dec_out_len); - if (r != 1) { - seaf_warning ("Decrypt block %s failed.\n", blk_id); - ret = -1; - goto out; - } - - if (dec_out_len != 0) { - len = archive_write_data (a, dec_out, dec_out_len); - if (len <= 0) { - seaf_warning ("archive_write_data error: %s\n", archive_error_string(a)); - ret = -1; - goto out; - } - } - } - - g_free (dec_out); - dec_out = NULL; - } - } - - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free (seaf->block_mgr, handle); - handle = NULL; - - /* turn to next block */ - idx++; - } - -out: - g_free (pathname); - if (entry) - archive_entry_free (entry); - if (file) - seafile_unref (file); - if (handle) { - seaf_block_manager_close_block (seaf->block_mgr, handle); - seaf_block_manager_block_handle_free(seaf->block_mgr, handle); - } - if (crypt != NULL && enc_init) - EVP_CIPHER_CTX_cleanup (&ctx); - g_free (dec_out); - - return ret; -} - -static int -archive_dir (PackDirData *data, - const char *root_id, - const char *dirpath, - Progress *progress) -{ - SeafDir *dir = NULL; - SeafDirent *dent; - GList *ptr; - char *subpath = NULL; - int ret = 0; - - dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, - data->store_id, data->repo_version, - root_id); - if (!dir) { - seaf_warning ("failed to get dir %s:%s\n", data->store_id, root_id); - goto out; - } - - for (ptr = dir->entries; ptr; ptr = ptr->next) { - dent = ptr->data; - if (S_ISREG(dent->mode)) { - ret = add_file_to_archive (data, dirpath, dent); - if (ret == 0) { - g_atomic_int_inc (&progress->zipped); - } - } else if (S_ISLNK(dent->mode)) { - if (archive_version_number() >= 3000001) { - /* Symlink in zip arhive is not supported in earlier version - * of libarchive */ - ret = add_file_to_archive (data, dirpath, dent); - } - - } else if (S_ISDIR(dent->mode)) { - subpath = g_build_filename (dirpath, dent->name, NULL); - ret = archive_dir (data, dent->id, subpath, progress); - g_free (subpath); - } - - if (ret < 0) { - goto out; - } - } - -out: - if (dir) - seaf_dir_free (dir); - - return ret; -} - -static PackDirData * -pack_dir_data_new (const char *store_id, - int repo_version, - const char *dirname, - SeafileCrypt *crypt, - gboolean is_windows) -{ - struct archive *a = NULL; - char *tmpfile_name = NULL ; - char *ret = NULL; - int fd = -1; - PackDirData *data = NULL; - - tmpfile_name = g_strdup_printf ("%s/seafile-XXXXXX.zip", - seaf->http_server->http_temp_dir); - fd = g_mkstemp (tmpfile_name); - if (fd < 0) { - seaf_warning ("Failed to open temp file: %s.\n", strerror (errno)); - g_free (tmpfile_name); - return NULL; - } - - a = archive_write_new (); - archive_write_set_compression_none (a); - archive_write_set_format_zip (a); - archive_write_open_fd (a, fd); - - data = g_new0 (PackDirData, 1); - data->crypt = crypt; - data->is_windows = is_windows; - data->a = a; - data->top_dir_name = dirname; - data->mtime = time(NULL); - memcpy (data->store_id, store_id, 36); - data->repo_version = repo_version; - data->tmp_fd = fd; - data->tmp_zip_file = tmpfile_name; - - return data; -} - -static int -archive_multi (PackDirData *data, GList *dirent_list, - Progress *progress) -{ - GList *iter; - SeafDirent *dirent; - - for (iter = dirent_list; iter; iter = iter->next) { - dirent = iter->data; - if (S_ISREG(dirent->mode)) { - if (add_file_to_archive (data, "", dirent) < 0) { - seaf_warning ("Failed to archive file: %s.\n", dirent->name); - return -1; - } - g_atomic_int_inc (&progress->zipped); - } else if (S_ISDIR(dirent->mode)) { - if (archive_dir (data, dirent->id, dirent->name, progress) < 0) { - seaf_warning ("Failed to archive dir: %s.\n", dirent->name); - return -1; - } - } - } - - return 0; -} - -int -pack_files (const char *store_id, - int repo_version, - const char *dirname, - void *internal, - SeafileCrypt *crypt, - gboolean is_windows, - Progress *progress) -{ - int ret = 0; - PackDirData *data = NULL; - - data = pack_dir_data_new (store_id, repo_version, dirname, - crypt, is_windows); - if (!data) { - seaf_warning ("Failed to create pack dir data.\n"); - return -1; - } - - progress->zip_file_path = data->tmp_zip_file; - - if (strcmp (dirname, "") != 0) { - // Pack dir - if (archive_dir (data, (char *)internal, "", progress) < 0) { - seaf_warning ("Failed to archive dir.\n"); - ret = -1; - } - } else { - // Pack multi - if (archive_multi (data, (GList *)internal, progress) < 0) { - seaf_warning ("Failed to archive multi files.\n"); - ret = -1; - } - } - - if (archive_write_finish(data->a) < 0) { - seaf_warning ("Failed to archive write finish.\n"); - ret = -1; - } - - close (data->tmp_fd); - free (data); - - return ret; -} diff --git a/server/pack-dir.h b/server/pack-dir.h deleted file mode 100644 index 79793848..00000000 --- a/server/pack-dir.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PACK_DIR_H -#define PACK_DIR_H - -/* Pack a seafile directory to a zipped archive, saved in a temporary file. - Return the path of this temporary file. - */ - -typedef struct Progress { - int zipped; - int total; - char *zip_file_path; - gint64 expire_ts; -} Progress; - -int -pack_files (const char *store_id, - int repo_version, - const char *dirname, - void *internal, - SeafileCrypt *crypt, - gboolean is_windows, - Progress *progress); - -#endif diff --git a/server/passwd-mgr.c b/server/passwd-mgr.c deleted file mode 100644 index 3fcc0abb..00000000 --- a/server/passwd-mgr.c +++ /dev/null @@ -1,288 +0,0 @@ -#include "common.h" -#include "log.h" - -#include -#include - -#include "seafile-session.h" -#include "seafile-object.h" -#include "seafile-error.h" -#include "seafile-crypt.h" - -#include "utils.h" - -#define REAP_INTERVAL 60 -#define REAP_THRESHOLD 3600 - -typedef struct { - int enc_version; - unsigned char key[32]; - unsigned char iv[16]; - guint64 expire_time; -} DecryptKey; - -struct _SeafPasswdManagerPriv { - GHashTable *decrypt_keys; - CcnetTimer *reap_timer; -}; - -static int reap_expired_passwd (void *vmgr); - -static void -decrypt_key_free (DecryptKey *key) -{ - if (!key) return; - - /* clear sensitive information */ - memset (key->key, 0, sizeof(key->key)); - memset (key->iv, 0, sizeof(key->iv)); - g_free (key); -} - -SeafPasswdManager * -seaf_passwd_manager_new (struct _SeafileSession *session) -{ - SeafPasswdManager *mgr = g_new0 (SeafPasswdManager, 1); - - mgr->session = session; - mgr->priv = g_new0 (struct _SeafPasswdManagerPriv, 1); - mgr->priv->decrypt_keys = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, - (GDestroyNotify)decrypt_key_free); - - return mgr; -} - -int -seaf_passwd_manager_start (SeafPasswdManager *mgr) -{ - mgr->priv->reap_timer = ccnet_timer_new (reap_expired_passwd, - mgr, REAP_INTERVAL * 1000); - return 1; -} - -int -seaf_passwd_manager_check_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *magic, - GError **error) -{ - SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid repo"); - return -1; - } - - if (!repo->encrypted) { - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Repo is not encrypted"); - return -1; - } - - if (strcmp (magic, repo->magic) != 0) { - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Incorrect password"); - return -1; - } - - seaf_repo_unref (repo); - - return 0; -} - -int -seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - const char *passwd, - GError **error) -{ - SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - DecryptKey *crypt_key; - GString *hash_key; - - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid repo"); - return -1; - } - - if (!repo->encrypted) { - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Repo is not encrypted"); - return -1; - } - - if (repo->enc_version != 1 && repo->enc_version != 2) { - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Unsupported encryption version"); - return -1; - } - - if (seafile_verify_repo_passwd (repo->id, passwd, - repo->magic, repo->enc_version) < 0) { - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Incorrect password"); - return -1; - } - - crypt_key = g_new0 (DecryptKey, 1); - if (!crypt_key) { - seaf_warning ("Failed to alloc crypt key struct.\n"); - seaf_repo_unref (repo); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, - "Internal server error"); - return -1; - } - - if (seafile_decrypt_repo_enc_key (repo->enc_version, passwd, repo->random_key, - crypt_key->key, crypt_key->iv) < 0) { - seaf_repo_unref (repo); - g_free (crypt_key); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Incorrect password"); - return -1; - } - crypt_key->expire_time = (guint64)time(NULL) + REAP_THRESHOLD; - crypt_key->enc_version = repo->enc_version; - - hash_key = g_string_new (NULL); - g_string_printf (hash_key, "%s.%s", repo_id, user); - - /* g_debug ("[passwd mgr] Set passwd for %s\n", hash_key->str); */ - - g_hash_table_insert (mgr->priv->decrypt_keys, - g_string_free (hash_key, FALSE), - crypt_key); - seaf_repo_unref (repo); - - return 0; -} - -int -seaf_passwd_manager_unset_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - GError **error) -{ - GString *hash_key; - - hash_key = g_string_new (NULL); - g_string_printf (hash_key, "%s.%s", repo_id, user); - g_hash_table_remove (mgr->priv->decrypt_keys, hash_key->str); - g_string_free (hash_key, TRUE); - - return 0; -} - -gboolean -seaf_passwd_manager_is_passwd_set (SeafPasswdManager *mgr, - const char *repo_id, - const char *user) -{ - GString *key = g_string_new (NULL); - gboolean ret = FALSE; - - g_string_printf (key, "%s.%s", repo_id, user); - /* g_debug ("[passwd mgr] check passwd for %s\n", key->str); */ - if (g_hash_table_lookup (mgr->priv->decrypt_keys, key->str) != NULL) - ret = TRUE; - g_string_free (key, TRUE); - - return ret; -} - -SeafileCryptKey * -seaf_passwd_manager_get_decrypt_key (SeafPasswdManager *mgr, - const char *repo_id, - const char *user) -{ - GString *hash_key; - DecryptKey *crypt_key; - SeafileCryptKey *ret; - char key_hex[65], iv_hex[65]; - - hash_key = g_string_new (NULL); - g_string_printf (hash_key, "%s.%s", repo_id, user); - - /* g_debug ("[passwd mgr] get passwd for %s.\n", hash_key->str); */ - - crypt_key = g_hash_table_lookup (mgr->priv->decrypt_keys, hash_key->str); - if (!crypt_key) { - g_string_free (hash_key, TRUE); - return NULL; - } - - if (crypt_key->enc_version == 2) { - rawdata_to_hex (crypt_key->key, key_hex, 32); - rawdata_to_hex (crypt_key->iv, iv_hex, 16); - } else if (crypt_key->enc_version == 1) { - rawdata_to_hex (crypt_key->key, key_hex, 16); - rawdata_to_hex (crypt_key->iv, iv_hex, 16); - } - - ret = seafile_crypt_key_new (); - g_object_set (ret, "key", key_hex, "iv", iv_hex, NULL); - - g_string_free (hash_key, TRUE); - return ret; -} - -int -seaf_passwd_manager_get_decrypt_key_raw (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - unsigned char *key_out, - unsigned char *iv_out) -{ - GString *hash_key; - DecryptKey *crypt_key; - - hash_key = g_string_new (NULL); - g_string_printf (hash_key, "%s.%s", repo_id, user); - - crypt_key = g_hash_table_lookup (mgr->priv->decrypt_keys, hash_key->str); - if (!crypt_key) { - g_string_free (hash_key, TRUE); - return -1; - } - g_string_free (hash_key, TRUE); - - if (crypt_key->enc_version == 1) { - memcpy (key_out, crypt_key->key, 16); - memcpy (iv_out, crypt_key->iv, 16); - } else if (crypt_key->enc_version == 2) { - memcpy (key_out, crypt_key->key, 32); - memcpy (iv_out, crypt_key->iv, 16); - } - - return 0; -} - -static int -reap_expired_passwd (void *vmgr) -{ - SeafPasswdManager *mgr = vmgr; - GHashTableIter iter; - gpointer key, value; - DecryptKey *crypt_key; - guint64 now = (guint64)time(NULL); - - g_hash_table_iter_init (&iter, mgr->priv->decrypt_keys); - while (g_hash_table_iter_next (&iter, &key, &value)) { - crypt_key = value; - if (crypt_key->expire_time <= now) { - /* g_debug ("[passwd mgr] Remove passwd for %s\n", (char *)key); */ - g_hash_table_iter_remove (&iter); - } - } - - return 1; -} diff --git a/server/passwd-mgr.h b/server/passwd-mgr.h deleted file mode 100644 index 5e12d0c4..00000000 --- a/server/passwd-mgr.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef PASSWD_MGR_H -#define PASSWD_MGR_H - -#include - -struct _SeafileSession; -struct _SeafPasswdManagerPriv; -struct _SeafileCryptKey; - -struct _SeafPasswdManager { - struct _SeafileSession *session; - struct _SeafPasswdManagerPriv *priv; -}; -typedef struct _SeafPasswdManager SeafPasswdManager; - -SeafPasswdManager * -seaf_passwd_manager_new (struct _SeafileSession *session); - -int -seaf_passwd_manager_start (SeafPasswdManager *mgr); - -/** - * Check password @magic to access contents of @repo_id. - * This function: - * 1. check whether @magic is correct; - * - * Returns 0 if password @magic is correct, -1 otherwise. - */ -int -seaf_passwd_manager_check_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *magic, - GError **error); -/** - * Set @passwd for @user to access contents of @repo_id. - * This function: - * 1. check whether @passwd is correct; - * 2. calculate and store decryption key based on @passwd in memory. - * - * Returns 0 if @passwd is correct, -1 otherwise. - */ -int -seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - const char *passwd, - GError **error); - -/** - * Returns 0 if successfully unset user password, -1 otherwise. - */ -int -seaf_passwd_manager_unset_passwd (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - GError **error); - -/** - * Check whether correct passwd has been set for @user - * to access @repo_id. - */ -gboolean -seaf_passwd_manager_is_passwd_set (SeafPasswdManager *mgr, - const char *repo_id, - const char *user); - -/** - * Returns decryption key for @repo_id, NULL if it's not set. - */ -struct _SeafileCryptKey * -seaf_passwd_manager_get_decrypt_key (SeafPasswdManager *mgr, - const char *repo_id, - const char *user); - -int -seaf_passwd_manager_get_decrypt_key_raw (SeafPasswdManager *mgr, - const char *repo_id, - const char *user, - unsigned char *key_out, - unsigned char *iv_out); - -#endif diff --git a/server/permission-mgr.c b/server/permission-mgr.c deleted file mode 100644 index 05c871b0..00000000 --- a/server/permission-mgr.c +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include - -#include "db.h" -#include "seafile-session.h" -#include "permission-mgr.h" - -#define PERM_DB "perm.db" - -struct _SeafPermManagerPriv { - sqlite3 *db; -}; - -static int load_db (SeafPermManager *mgr); - -SeafPermManager * -seaf_perm_manager_new (SeafileSession *seaf) -{ - SeafPermManager *mgr = g_new0 (SeafPermManager, 1); - mgr->priv = g_new0 (SeafPermManagerPriv, 1); - mgr->seaf = seaf; - return mgr; -} - -int -seaf_perm_manager_init (SeafPermManager *mgr) -{ - return load_db (mgr); -} - -static int -load_db (SeafPermManager *mgr) -{ - char *db_path = g_build_filename (mgr->seaf->seaf_dir, PERM_DB, NULL); - if (sqlite_open_db (db_path, &mgr->priv->db) < 0) { - g_critical ("[Permission mgr] Failed to open permission db\n"); - g_free (db_path); - g_free (mgr); - return -1; - } - g_free (db_path); - - const char *sql; - - return 0; -} - diff --git a/server/permission-mgr.h b/server/permission-mgr.h deleted file mode 100644 index 9798277e..00000000 --- a/server/permission-mgr.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAF_PERM_MGR_H -#define SEAF_PERM_MGR_H - -#include - -struct _SeafileSession; - -typedef struct _SeafPermManager SeafPermManager; -typedef struct _SeafPermManagerPriv SeafPermManagerPriv; - -struct _SeafPermManager { - struct _SeafileSession *seaf; - - SeafPermManagerPriv *priv; -}; - -SeafPermManager* -seaf_perm_manager_new (struct _SeafileSession *seaf); - -int -seaf_perm_manager_init (SeafPermManager *mgr); - -int -seaf_perm_manager_set_repo_owner (SeafPermManager *mgr, - const char *repo_id, - const char *user_id); - -char * -seaf_perm_manager_get_repo_owner (SeafPermManager *mgr, - const char *repo_id); - -/* TODO: add start and limit. */ -/* Get repos owned by this user. - */ -GList * -seaf_perm_manager_get_repos_by_owner (SeafPermManager *mgr, - const char *user_id); - -#endif diff --git a/server/processors/check-protocol-slave-proc.c b/server/processors/check-protocol-slave-proc.c deleted file mode 100644 index 9ea0c68d..00000000 --- a/server/processors/check-protocol-slave-proc.c +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include "check-protocol-slave-proc.h" - -G_DEFINE_TYPE (SeafileCheckProtocolSlaveProc, seafile_check_protocol_slave_proc, CCNET_TYPE_PROCESSOR) - -static int -check_protocol_slave_start (CcnetProcessor *processor, int argc, char **argv); - -static void -seafile_check_protocol_slave_proc_class_init (SeafileCheckProtocolSlaveProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "seafile-check-protocol-slave-proc"; - proc_class->start = check_protocol_slave_start; -} - -static void -seafile_check_protocol_slave_proc_init (SeafileCheckProtocolSlaveProc *processor) -{ -} - - -static int -check_protocol_slave_start (CcnetProcessor *processor, int argc, char **argv) -{ - int n; - char buf[10]; - n = snprintf (buf, sizeof(buf), "%d", CURRENT_PROTO_VERSION); - ccnet_processor_send_response (processor, SC_OK, SS_OK, buf, n+1); - ccnet_processor_done (processor, TRUE); - - return 0; -} diff --git a/server/processors/check-protocol-slave-proc.h b/server/processors/check-protocol-slave-proc.h deleted file mode 100644 index 8bd77efa..00000000 --- a/server/processors/check-protocol-slave-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECK_PROTOCOL_SLAVE_PROC_H -#define SEAFILE_CHECK_PROTOCOL_SLAVE_PROC_H - -#include -#include - -#define SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC (seafile_check_protocol_slave_proc_get_type ()) -#define SEAFILE_CHECK_PROTOCOL_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC, SeafileCheckProtocolSlaveProc)) -#define SEAFILE_IS_CHECK_PROTOCOL_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC)) -#define SEAFILE_CHECK_PROTOCOL_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC, SeafileCheckProtocolSlaveProcClass)) -#define IS_SEAFILE_CHECK_PROTOCOL_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC)) -#define SEAFILE_CHECK_PROTOCOL_SLAVE_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC, SeafileCheckProtocolSlaveProcClass)) - -typedef struct _SeafileCheckProtocolSlaveProc SeafileCheckProtocolSlaveProc; -typedef struct _SeafileCheckProtocolSlaveProcClass SeafileCheckProtocolSlaveProcClass; - -struct _SeafileCheckProtocolSlaveProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckProtocolSlaveProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_check_protocol_slave_proc_get_type (); - -#endif diff --git a/server/processors/check-quota-common.h b/server/processors/check-quota-common.h deleted file mode 100644 index d32ff571..00000000 --- a/server/processors/check-quota-common.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef CHECK_QUOTA_COMMON_H -#define CHECK_QUOTA_COMMON_H - -#include -#include -#include - -static SearpcClient * -create_sync_ccnetrpc_client (const char *central_config_dir, const char *config_dir, const char *service) -{ - if (!config_dir || !service) - return NULL; - - CcnetClient *sync_client; - SearpcClient *rpc_client; - - sync_client = ccnet_client_new (); - if ((ccnet_client_load_confdir(sync_client, central_config_dir, config_dir)) < 0 ) { - return NULL; - } - - if (ccnet_client_connect_daemon (sync_client, CCNET_CLIENT_SYNC) < 0) - { - g_object_unref ((GObject *)sync_client); - return NULL; - } - - rpc_client = ccnet_create_rpc_client (sync_client, NULL, service); - - return rpc_client; -} - -static void -free_sync_rpc_client (SearpcClient *rpc_client) -{ - CcnetrpcTransportParam *priv = rpc_client->arg; - CcnetClient *client = priv->session; - - /* No need to call ccnet_client_disconnect_daemon. It's called in object - * finalize function of ccnet client class. */ - g_object_unref ((GObject *)client); - ccnet_rpc_client_free (rpc_client); -} - -static int -check_repo_owner_quota (CcnetProcessor *processor, - SearpcClient *rpc_client, - const char *repo_id) -{ - USE_PRIV; - char *user = NULL; - int org_id; - gint64 quota, usage; - int ret = 0; - - /* repo is guranteed to exist before check_repo_owner_quota */ - user = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, repo_id); - if (user != NULL) { - quota = seaf_quota_manager_get_user_quota (seaf->quota_mgr, user); - if (quota <= 0) - quota = seaf->quota_mgr->default_quota; - } else { - org_id = seaf_repo_manager_get_repo_org (seaf->repo_mgr, repo_id); - if (org_id < 0) { - priv->rsp_code = g_strdup (SC_QUOTA_ERROR); - priv->rsp_msg = g_strdup (SS_QUOTA_ERROR); - ret = -1; - goto out; - } - - quota = seaf_quota_manager_get_org_quota (seaf->quota_mgr, org_id); - if (quota <= 0) - quota = seaf->quota_mgr->default_quota; - } - - if (quota == INFINITE_QUOTA) - return ret; - - if (user) - usage = seaf_quota_manager_get_user_usage (seaf->quota_mgr, user); - else - usage = seaf_quota_manager_get_org_usage (seaf->quota_mgr, org_id); - - g_debug ("quota is %"G_GINT64_FORMAT", usage is %"G_GINT64_FORMAT"\n", - quota, usage); - - if (usage < 0) { - priv->rsp_code = g_strdup (SC_QUOTA_ERROR); - priv->rsp_msg = g_strdup (SS_QUOTA_ERROR); - ret = -1; - goto out; - - } else if (usage >= quota) { - priv->rsp_code = g_strdup (SC_QUOTA_FULL); - priv->rsp_msg = g_strdup (SS_QUOTA_FULL); - ret = -1; - goto out; - } - -out: - g_free (user); - - return ret; -} - -#endif diff --git a/server/processors/check-tx-slave-proc.c b/server/processors/check-tx-slave-proc.c deleted file mode 100644 index 4be7a8d1..00000000 --- a/server/processors/check-tx-slave-proc.c +++ /dev/null @@ -1,377 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include - -#include -#include -#include - -#include "seafile-session.h" -#include "check-tx-slave-proc.h" - -#include "log.h" - -#define SC_GET_TOKEN "301" -#define SS_GET_TOKEN "Get token" -#define SC_PUT_TOKEN "302" -#define SS_PUT_TOKEN "Put token" -#define SC_GET_VERSION "303" -#define SS_GET_VERSION "Get version" -#define SC_VERSION "304" -#define SS_VERSION "Version" - -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "Access denied" -#define SC_SERVER_ERROR "404" -#define SS_SERVER_ERROR "Internal server error" -#define SC_PROTOCOL_MISMATCH "405" -#define SS_PROTOCOL_MISMATCH "Protocol version mismatch" - -/* Only for upload */ -#define SC_QUOTA_ERROR "402" -#define SS_QUOTA_ERROR "Failed to get quota" -#define SC_QUOTA_FULL "403" -#define SS_QUOTA_FULL "storage for the repo's owner is full" - -/* Only for download */ -#define SC_BAD_REPO "406" -#define SS_BAD_REPO "Repo doesn't exist" -#define SC_NO_BRANCH "407" -#define SS_NO_BRANCH "Branch not found" - -enum { - INIT, - ACCESS_GRANTED, -}; - -enum { - CHECK_TX_TYPE_UPLOAD, - CHECK_TX_TYPE_DOWNLOAD, -}; - -typedef struct { - int type; - - char repo_id[37]; - char *branch_name; - char *email; - - char *rsp_code; - char *rsp_msg; - char head_id[41]; - int has_branch; -} SeafileCheckTxSlaveProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC, SeafileCheckTxSlaveProcPriv)) - -#define USE_PRIV \ - SeafileCheckTxSlaveProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafileCheckTxSlaveProc, seafile_check_tx_slave_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void thread_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - /* g_free works fine even if ptr is NULL. */ - g_free (priv->email); - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - - CCNET_PROCESSOR_CLASS (seafile_check_tx_slave_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_check_tx_slave_proc_class_init (SeafileCheckTxSlaveProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "check-tx-slave-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileCheckTxSlaveProcPriv)); -} - -static void -seafile_check_tx_slave_proc_init (SeafileCheckTxSlaveProc *processor) -{ -} - -#include "check-quota-common.h" - -static void -get_branch_head (CcnetProcessor *processor) -{ - SeafBranch *branch; - USE_PRIV; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, - priv->repo_id, priv->branch_name); - if (branch != NULL) { - priv->has_branch = 1; - memcpy (priv->head_id, branch->commit_id, 41); - seaf_branch_unref (branch); - - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else if (priv->type == CHECK_TX_TYPE_UPLOAD) { - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else { - priv->rsp_code = g_strdup(SC_NO_BRANCH); - priv->rsp_msg = g_strdup(SS_NO_BRANCH); - } -} - -static gboolean -check_repo_share_permission (SearpcClient *rpc_client, - const char *repo_id, - const char *user_name) -{ - GList *groups, *pgroup; - GList *repos, *prepo; - CcnetGroup *group; - int group_id; - char *shared_repo_id; - gboolean ret = FALSE; - - if (seaf_share_manager_check_permission (seaf->share_mgr, - repo_id, - user_name) != NULL) - return TRUE; - - groups = ccnet_get_groups_by_user (rpc_client, user_name); - for (pgroup = groups; pgroup != NULL; pgroup = pgroup->next) { - group = pgroup->data; - g_object_get (group, "id", &group_id, NULL); - - repos = seaf_repo_manager_get_group_repoids (seaf->repo_mgr, - group_id, NULL); - for (prepo = repos; prepo != NULL; prepo = prepo->next) { - shared_repo_id = prepo->data; - if (strcmp (shared_repo_id, repo_id) == 0) { - ret = TRUE; - break; - } - } - for (prepo = repos; prepo != NULL; prepo = prepo->next) - g_free (prepo->data); - g_list_free (repos); - if (ret) - break; - } - - for (pgroup = groups; pgroup != NULL; pgroup = pgroup->next) - g_object_unref ((GObject *)pgroup->data); - g_list_free (groups); - return ret; -} - -static void * -check_tx (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - char *owner = NULL; - int org_id; - SearpcClient *rpc_client = NULL; - - char *repo_id = priv->repo_id; - - rpc_client = create_sync_ccnetrpc_client - (seaf->session->central_config_dir, seaf->session->config_dir, "ccnet-threaded-rpcserver"); - - if (!rpc_client) { - priv->rsp_code = g_strdup(SC_SERVER_ERROR); - priv->rsp_msg = g_strdup(SS_SERVER_ERROR); - goto out; - } - - if (!seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id)) { - priv->rsp_code = g_strdup(SC_BAD_REPO); - priv->rsp_msg = g_strdup(SS_BAD_REPO); - goto out; - } - - if (priv->type == CHECK_TX_TYPE_UPLOAD && - check_repo_owner_quota (processor, rpc_client, repo_id) < 0) - goto out; - - owner = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, repo_id); - if (owner != NULL) { - /* If the user is not owner, check share permission */ - if (strcmp (owner, priv->email) != 0) { - if(!check_repo_share_permission (rpc_client, repo_id, priv->email)) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - } - } else { - /* This should be a repo created in an org. */ - org_id = seaf_repo_manager_get_repo_org (seaf->repo_mgr, repo_id); - if (org_id < 0 || - !ccnet_org_user_exists (rpc_client, org_id, priv->email)) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - } - - get_branch_head (processor); - -out: - g_free (owner); - if (rpc_client) - free_sync_rpc_client (rpc_client); - return vprocessor; -} - -static void -thread_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_OK) == 0) { - if (priv->has_branch) { - ccnet_processor_send_response (processor, - SC_OK, SS_OK, - priv->head_id, 41); - } else - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = ACCESS_GRANTED; - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static void -get_email_cb (void *result, void *data, GError *error) -{ - char *email = result; - CcnetProcessor *processor = data; - USE_PRIV; - - if (!email) { - seaf_warning ("[check tx] cannot find email for peer %s.\n", - processor->peer_id); - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - priv->email = g_strdup(email); - - ccnet_processor_thread_create (processor, check_tx, thread_done, processor); -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *repo_id, *branch_name; - USE_PRIV; - - if (argc < 4) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (strcmp (argv[0], "upload") == 0) { - priv->type = CHECK_TX_TYPE_UPLOAD; - } else if (strcmp (argv[0], "download") == 0) { - priv->type = CHECK_TX_TYPE_DOWNLOAD; - } else { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - repo_id = argv[2]; - branch_name = argv[3]; - - if (strlen(repo_id) != 36) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (priv->type == CHECK_TX_TYPE_UPLOAD && - strcmp (branch_name, "master") != 0) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 37); - priv->branch_name = g_strdup(branch_name); - - ccnet_get_binding_email_async (seaf->async_ccnetrpc_client_t, processor->peer_id, - get_email_cb, processor); - - return 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - char *token; - - if (processor->state != ACCESS_GRANTED) { - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (strncmp (code, SC_GET_TOKEN, 3) == 0) { - token = seaf_token_manager_generate_token (seaf->token_mgr, - processor->peer_id, - priv->repo_id); - ccnet_processor_send_response (processor, - SC_PUT_TOKEN, SS_PUT_TOKEN, - token, strlen(token) + 1); - g_free (token); - return; - } else if (strncmp (code, SC_GET_VERSION, 3) == 0) { - char buf[16]; - int len; - len = snprintf (buf, sizeof(buf), "%d", CURRENT_PROTO_VERSION); - ccnet_processor_send_response (processor, - SC_VERSION, SS_VERSION, - buf, len + 1); - ccnet_processor_done (processor, TRUE); - return; - } - - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/check-tx-slave-proc.h b/server/processors/check-tx-slave-proc.h deleted file mode 100644 index 638c4011..00000000 --- a/server/processors/check-tx-slave-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECK_TX_SLAVE_PROC_H -#define SEAFILE_CHECK_TX_SLAVE_PROC_H - -#include -#include - -#define SEAFILE_TYPE_CHECK_TX_SLAVE_PROC (seafile_check_tx_slave_proc_get_type ()) -#define SEAFILE_CHECK_TX_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC, SeafileCheckTxSlaveProc)) -#define SEAFILE_IS_CHECK_TX_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC, SeafileCheckTxSlaveProcClass)) -#define IS_SEAFILE_CHECK_TX_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_PROC, SeafileCheckTxSlaveProcClass)) - -typedef struct _SeafileCheckTxSlaveProc SeafileCheckTxSlaveProc; -typedef struct _SeafileCheckTxSlaveProcClass SeafileCheckTxSlaveProcClass; - -struct _SeafileCheckTxSlaveProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckTxSlaveProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_check_tx_slave_proc_get_type (); - -#endif - diff --git a/server/processors/check-tx-slave-v2-proc.c b/server/processors/check-tx-slave-v2-proc.c deleted file mode 100644 index 14d26bd1..00000000 --- a/server/processors/check-tx-slave-v2-proc.c +++ /dev/null @@ -1,407 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include - -#include -#include -#include - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include "seafile-session.h" -#include "utils.h" - -#include "check-tx-slave-v2-proc.h" - -#define SC_GET_TOKEN "301" -#define SS_GET_TOKEN "Get token" -#define SC_PUT_TOKEN "302" -#define SS_PUT_TOKEN "Put token" -#define SC_GET_VERSION "303" -#define SS_GET_VERSION "Get version" -#define SC_VERSION "304" -#define SS_VERSION "Version" - -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "Access denied" -#define SC_SERVER_ERROR "404" -#define SS_SERVER_ERROR "Internal server error" -#define SC_PROTOCOL_MISMATCH "405" -#define SS_PROTOCOL_MISMATCH "Protocol version mismatch" - -/* Only for upload */ -#define SC_QUOTA_ERROR "402" -#define SS_QUOTA_ERROR "Failed to get quota" -#define SC_QUOTA_FULL "403" -#define SS_QUOTA_FULL "storage for the repo's owner is full" - -/* Only for download */ -#define SC_BAD_REPO "406" -#define SS_BAD_REPO "Repo doesn't exist" -#define SC_NO_BRANCH "407" -#define SS_NO_BRANCH "Branch not found" - -enum { - INIT, - ACCESS_GRANTED, -}; - -enum { - CHECK_TX_TYPE_UPLOAD, - CHECK_TX_TYPE_DOWNLOAD, -}; - -typedef struct { - int type; - - char repo_id[37]; - char *branch_name; - char *token; - char *session_key; - char *peer_addr; - char *peer_name; - - char *rsp_code; - char *rsp_msg; - char head_id[41]; - int has_branch; -} SeafileCheckTxSlaveV2ProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC, SeafileCheckTxSlaveV2ProcPriv)) - -#define USE_PRIV \ - SeafileCheckTxSlaveV2ProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafileCheckTxSlaveV2Proc, seafile_check_tx_slave_v2_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void thread_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - /* g_free works fine even if ptr is NULL. */ - g_free (priv->token); - g_free (priv->session_key); - g_free (priv->peer_addr); - g_free (priv->peer_name); - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - - CCNET_PROCESSOR_CLASS (seafile_check_tx_slave_v2_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_check_tx_slave_v2_proc_class_init (SeafileCheckTxSlaveV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "check-tx-slave-v2-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileCheckTxSlaveV2ProcPriv)); -} - -static void -seafile_check_tx_slave_v2_proc_init (SeafileCheckTxSlaveV2Proc *processor) -{ -} - -static void -get_branch_head (CcnetProcessor *processor) -{ - SeafBranch *branch; - USE_PRIV; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, - priv->repo_id, priv->branch_name); - if (branch != NULL) { - priv->has_branch = 1; - memcpy (priv->head_id, branch->commit_id, 41); - seaf_branch_unref (branch); - - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else if (priv->type == CHECK_TX_TYPE_UPLOAD) { - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else { - priv->rsp_code = g_strdup(SC_NO_BRANCH); - priv->rsp_msg = g_strdup(SS_NO_BRANCH); - } -} - -static int -decrypt_token (CcnetProcessor *processor) -{ - USE_PRIV; - int hex_len, encrypted_len, token_len; - char *encrypted_token = NULL; - SeafileCrypt *crypt = NULL; - unsigned char key[16], iv[16]; - char *token = NULL; - int ret = 0; - - /* raw data is half the length of hexidecimal */ - hex_len = strlen(priv->token); - if (hex_len % 2 != 0) { - seaf_warning ("[check tx slave v2] invalid length of encrypted token\n"); - ret = -1; - goto out; - } - - token = seaf_repo_manager_get_decrypted_token (seaf->repo_mgr, - priv->token, - priv->session_key); - if (token) - goto found; - - encrypted_len = hex_len / 2; - encrypted_token = g_malloc (encrypted_len); - hex_to_rawdata (priv->token, - (unsigned char *)encrypted_token, - encrypted_len); - - seafile_derive_key (priv->session_key, - strlen(priv->session_key), - 1, key, iv); - crypt = seafile_crypt_new (1, key, iv); - - if (seafile_decrypt (&token, &token_len, encrypted_token, - encrypted_len, crypt) < 0) { - seaf_warning ("[check tx slave v2] failed to decrypt token\n"); - ret = -1; - goto out; - } - - /* Add to cache. */ - seaf_repo_manager_add_decrypted_token (seaf->repo_mgr, - priv->token, - priv->session_key, - token); - -found: - g_free (priv->token); - /* we can use the decrypted data directly, since the trailing null byte is - * also included when encrypting in the client */ - priv->token = token; - -out: - g_free (crypt); - g_free (encrypted_token); - - return ret; -} - -static void * -check_tx (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - char *user = NULL; - char *repo_id = priv->repo_id; - - if (!seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id)) { - priv->rsp_code = g_strdup(SC_BAD_REPO); - priv->rsp_msg = g_strdup(SS_BAD_REPO); - goto out; - } - - if (decrypt_token (processor) < 0) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - - user = seaf_repo_manager_get_email_by_token ( - seaf->repo_mgr, repo_id, priv->token); - - if (!user) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - - if (priv->type == CHECK_TX_TYPE_UPLOAD && - seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { - priv->rsp_code = g_strdup(SC_QUOTA_FULL); - priv->rsp_msg = g_strdup(SS_QUOTA_FULL); - goto out; - } - - char *perm = seaf_repo_manager_check_permission (seaf->repo_mgr, - repo_id, user, NULL); - if (!perm || - (strcmp (perm, "r") == 0 && priv->type == CHECK_TX_TYPE_UPLOAD)) - { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - g_free (perm); - goto out; - } - g_free (perm); - - /* Record the (token, email, ) information, may - * include peer_id, peer_ip, peer_name, etc. - */ - if (!seaf_repo_manager_token_peer_info_exists (seaf->repo_mgr, priv->token)) - seaf_repo_manager_add_token_peer_info (seaf->repo_mgr, - priv->token, - processor->peer_id, - priv->peer_addr, - priv->peer_name, - (gint64)time(NULL), NULL); - else - seaf_repo_manager_update_token_peer_info (seaf->repo_mgr, - priv->token, - priv->peer_addr, - (gint64)time(NULL), NULL); - - get_branch_head (processor); - -out: - g_free (user); - return vprocessor; -} - -static void -thread_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_OK) == 0) { - if (priv->has_branch) { - ccnet_processor_send_response (processor, - SC_OK, SS_OK, - priv->head_id, 41); - } else - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = ACCESS_GRANTED; - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *repo_id, *token; - USE_PRIV; - - if (argc != 5) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (strcmp (argv[0], "upload") == 0) { - priv->type = CHECK_TX_TYPE_UPLOAD; - } else if (strcmp (argv[0], "download") == 0) { - priv->type = CHECK_TX_TYPE_DOWNLOAD; - } else { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - repo_id = argv[2]; - token = argv[4]; - - if (!is_uuid_valid (repo_id)) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 37); - priv->branch_name = g_strdup("master"); - - priv->token = g_strdup(token); - - CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, processor->peer_id); - if (!peer || !peer->session_key) { - seaf_warning ("[check tx slave v2] session key of peer %.10s is null\n", - processor->peer_id); - ccnet_processor_send_response (processor, SC_BAD_PEER, SS_BAD_PEER, NULL, 0); - ccnet_processor_done (processor, FALSE); - if (peer) - g_object_unref (peer); - return -1; - } - - priv->session_key = g_strdup(peer->session_key); - priv->peer_addr = g_strdup(peer->addr_str); - priv->peer_name = g_strdup(peer->name); - if (!priv->peer_name) - priv->peer_name = g_strdup("Unknown"); - g_object_unref (peer); - - seaf_debug ("[check-tx] %s repo %.8s.\n", argv[0], repo_id); - - ccnet_processor_thread_create (processor, seaf->job_mgr, - check_tx, thread_done, processor); - - return 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - char *token; - - if (processor->state != ACCESS_GRANTED) { - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (strncmp (code, SC_GET_TOKEN, 3) == 0) { - token = seaf_token_manager_generate_token (seaf->token_mgr, - processor->peer_id, - priv->repo_id); - ccnet_processor_send_response (processor, - SC_PUT_TOKEN, SS_PUT_TOKEN, - token, strlen(token) + 1); - g_free (token); - return; - } else if (strncmp (code, SC_GET_VERSION, 3) == 0) { - char buf[16]; - int len; - len = snprintf (buf, sizeof(buf), "%d", CURRENT_PROTO_VERSION); - ccnet_processor_send_response (processor, - SC_VERSION, SS_VERSION, - buf, len + 1); - ccnet_processor_done (processor, TRUE); - return; - } - - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/check-tx-slave-v2-proc.h b/server/processors/check-tx-slave-v2-proc.h deleted file mode 100644 index b24bf661..00000000 --- a/server/processors/check-tx-slave-v2-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECK_TX_SLAVE_V2_PROC_H -#define SEAFILE_CHECK_TX_SLAVE_V2_PROC_H - -#include -#include - -#define SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC (seafile_check_tx_slave_v2_proc_get_type ()) -#define SEAFILE_CHECK_TX_SLAVE_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC, SeafileCheckTxSlaveV2Proc)) -#define SEAFILE_IS_CHECK_TX_SLAVE_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC, SeafileCheckTxSlaveV2ProcClass)) -#define IS_SEAFILE_CHECK_TX_SLAVE_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V2_PROC, SeafileCheckTxSlaveV2ProcClass)) - -typedef struct _SeafileCheckTxSlaveV2Proc SeafileCheckTxSlaveV2Proc; -typedef struct _SeafileCheckTxSlaveV2ProcClass SeafileCheckTxSlaveV2ProcClass; - -struct _SeafileCheckTxSlaveV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckTxSlaveV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_check_tx_slave_v2_proc_get_type (); - -#endif diff --git a/server/processors/check-tx-slave-v3-proc.c b/server/processors/check-tx-slave-v3-proc.c deleted file mode 100644 index 04e902c8..00000000 --- a/server/processors/check-tx-slave-v3-proc.c +++ /dev/null @@ -1,473 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include "seafile-session.h" -#include "utils.h" - -#include "check-tx-slave-v3-proc.h" - -#define SC_GET_TOKEN "301" -#define SS_GET_TOKEN "Get token" -#define SC_PUT_TOKEN "302" -#define SS_PUT_TOKEN "Put token" -#define SC_GET_VERSION "303" -#define SS_GET_VERSION "Get version" -#define SC_VERSION "304" -#define SS_VERSION "Version" - -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "Access denied" -#define SC_SERVER_ERROR "404" -#define SS_SERVER_ERROR "Internal server error" -#define SC_PROTOCOL_MISMATCH "405" -#define SS_PROTOCOL_MISMATCH "Protocol version mismatch" - -/* Only for upload */ -#define SC_QUOTA_ERROR "402" -#define SS_QUOTA_ERROR "Failed to get quota" -#define SC_QUOTA_FULL "403" -#define SS_QUOTA_FULL "storage for the repo's owner is full" - -/* Only for download */ -#define SC_BAD_REPO "406" -#define SS_BAD_REPO "Repo doesn't exist" -#define SC_NO_BRANCH "407" -#define SS_NO_BRANCH "Branch not found" - -enum { - INIT, - ACCESS_GRANTED, -}; - -enum { - CHECK_TX_TYPE_UPLOAD, - CHECK_TX_TYPE_DOWNLOAD, -}; - -typedef struct { - int type; - - char repo_id[37]; - char *branch_name; - char *token; - char *session_key; - char *peer_addr; - char *peer_name; - int client_version; - - char *rsp_code; - char *rsp_msg; - char head_id[41]; - int has_branch; - - char *user; - char orig_repo_id[37]; - char *orig_path; -} SeafileCheckTxSlaveV3ProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC, SeafileCheckTxSlaveV3ProcPriv)) - -#define USE_PRIV \ - SeafileCheckTxSlaveV3ProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafileCheckTxSlaveV3Proc, seafile_check_tx_slave_v3_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void thread_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - /* g_free works fine even if ptr is NULL. */ - g_free (priv->token); - g_free (priv->session_key); - g_free (priv->peer_addr); - g_free (priv->peer_name); - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - g_free (priv->user); - g_free (priv->orig_path); - - CCNET_PROCESSOR_CLASS (seafile_check_tx_slave_v3_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_check_tx_slave_v3_proc_class_init (SeafileCheckTxSlaveV3ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "check-tx-slave-v3-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileCheckTxSlaveV3ProcPriv)); -} - -static void -seafile_check_tx_slave_v3_proc_init (SeafileCheckTxSlaveV3Proc *processor) -{ -} - -static void -get_branch_head (CcnetProcessor *processor) -{ - SeafBranch *branch; - USE_PRIV; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, - priv->repo_id, priv->branch_name); - if (branch != NULL) { - priv->has_branch = 1; - memcpy (priv->head_id, branch->commit_id, 41); - seaf_branch_unref (branch); - - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else if (priv->type == CHECK_TX_TYPE_UPLOAD) { - priv->rsp_code = g_strdup(SC_OK); - priv->rsp_msg = g_strdup(SS_OK); - } else { - priv->rsp_code = g_strdup(SC_NO_BRANCH); - priv->rsp_msg = g_strdup(SS_NO_BRANCH); - } -} - -static int -decrypt_token (CcnetProcessor *processor) -{ - USE_PRIV; - int hex_len, encrypted_len, token_len; - char *encrypted_token = NULL; - SeafileCrypt *crypt = NULL; - unsigned char key[16], iv[16]; - char *token = NULL; - int ret = 0; - - /* raw data is half the length of hexidecimal */ - hex_len = strlen(priv->token); - if (hex_len % 2 != 0) { - seaf_warning ("[check tx slave v3] invalid length of encrypted token\n"); - ret = -1; - goto out; - } - - encrypted_len = hex_len / 2; - encrypted_token = g_malloc (encrypted_len); - hex_to_rawdata (priv->token, - (unsigned char *)encrypted_token, - encrypted_len); - - EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */ - EVP_sha1(), /* message digest */ - NULL, /* slat */ - (unsigned char*)priv->session_key, - strlen(priv->session_key), - 1, /* iteration times */ - key, /* the derived key */ - iv); /* IV, initial vector */ - - crypt = seafile_crypt_new (1, key, iv); - - if (seafile_decrypt (&token, &token_len, encrypted_token, - encrypted_len, crypt) < 0) { - seaf_warning ("[check tx slave v3] failed to decrypt token\n"); - ret = -1; - goto out; - } - - g_free (priv->token); - /* we can use the decrypted data directly, since the trailing null byte is - * also included when encrypting in the client */ - priv->token = token; - -out: - g_free (crypt); - g_free (encrypted_token); - - return ret; -} - -static void * -check_tx (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - char *user = NULL; - char *repo_id = priv->repo_id; - SeafRepo *repo = NULL; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - priv->rsp_code = g_strdup(SC_BAD_REPO); - priv->rsp_msg = g_strdup(SS_BAD_REPO); - goto out; - } - - if (repo->repaired) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - - if (repo->version > 0 && priv->client_version < 6) { - seaf_warning ("Client protocol version is %d, " - "cannot sync version %d repo %s.\n", - priv->client_version, repo->version, repo_id); - priv->rsp_code = g_strdup(SC_PROTOCOL_MISMATCH); - priv->rsp_msg = g_strdup(SS_PROTOCOL_MISMATCH); - goto out; - } - - if (decrypt_token (processor) < 0) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - - user = seaf_repo_manager_get_email_by_token ( - seaf->repo_mgr, repo_id, priv->token); - - if (!user) { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - goto out; - } - - if (priv->type == CHECK_TX_TYPE_UPLOAD && - seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { - priv->rsp_code = g_strdup(SC_QUOTA_FULL); - priv->rsp_msg = g_strdup(SS_QUOTA_FULL); - goto out; - } - - char *perm = seaf_repo_manager_check_permission (seaf->repo_mgr, - repo_id, user, NULL); - if (!perm || - (strcmp (perm, "r") == 0 && priv->type == CHECK_TX_TYPE_UPLOAD)) - { - priv->rsp_code = g_strdup(SC_ACCESS_DENIED); - priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); - g_free (perm); - goto out; - } - g_free (perm); - - /* Record the (token, email, ) information, may - * include peer_id, peer_ip, peer_name, etc. - */ - if (!seaf_repo_manager_token_peer_info_exists (seaf->repo_mgr, priv->token)) - seaf_repo_manager_add_token_peer_info (seaf->repo_mgr, - priv->token, - processor->peer_id, - priv->peer_addr, - priv->peer_name, - (gint64)time(NULL), NULL); - else - seaf_repo_manager_update_token_peer_info (seaf->repo_mgr, - priv->token, - priv->peer_addr, - (gint64)time(NULL), NULL); - - get_branch_head (processor); - - /* Fill information for sending events. */ - priv->user = g_strdup(user); - if (repo->virtual_info) { - memcpy (priv->orig_repo_id, repo->virtual_info->origin_repo_id, 36); - priv->orig_path = g_strdup(repo->virtual_info->path); - } else - memcpy (priv->orig_repo_id, repo_id, 36); - -out: - seaf_repo_unref (repo); - g_free (user); - return vprocessor; -} - -static void -publish_repo_event (CcnetProcessor *processor, const char *etype) -{ - USE_PRIV; - GString *buf; - - if (!priv->user) - return; - - buf = g_string_new (NULL); - g_string_printf (buf, "%s\t%s\t%s\t%s\t%s\t%s", - etype, priv->user, priv->peer_addr, - priv->peer_name, priv->orig_repo_id, - priv->orig_path ? priv->orig_path : "/"); - - seaf_mq_manager_publish_event (seaf->mq_mgr, buf->str); - - g_string_free (buf, TRUE); -} - -static void -thread_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_OK) == 0) { - if (priv->has_branch) { - ccnet_processor_send_response (processor, - SC_OK, SS_OK, - priv->head_id, 41); - } else - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = ACCESS_GRANTED; - - if (priv->type == CHECK_TX_TYPE_DOWNLOAD) - publish_repo_event (processor, "repo-download-sync"); - else if (priv->type == CHECK_TX_TYPE_UPLOAD) - publish_repo_event (processor, "repo-upload-sync"); - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *repo_id, *token; - USE_PRIV; - - if (argc != 5) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (strcmp (argv[0], "upload") == 0) { - priv->type = CHECK_TX_TYPE_UPLOAD; - } else if (strcmp (argv[0], "download") == 0) { - priv->type = CHECK_TX_TYPE_DOWNLOAD; - } else { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - int client_version = atoi(argv[1]); - if (client_version < 5) { - seaf_debug ("Client protocol version lower than 5, not supported.\n"); - ccnet_processor_send_response (processor, - SC_PROTOCOL_MISMATCH, SS_PROTOCOL_MISMATCH, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - repo_id = argv[2]; - token = argv[4]; - - if (!is_uuid_valid(repo_id)) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 37); - priv->branch_name = g_strdup("master"); - - priv->token = g_strdup(token); - priv->client_version = client_version; - - CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, processor->peer_id); - if (!peer || !peer->session_key) { - seaf_warning ("[check tx slave v3] session key of peer %.10s is null\n", - processor->peer_id); - ccnet_processor_send_response (processor, SC_BAD_PEER, SS_BAD_PEER, NULL, 0); - ccnet_processor_done (processor, FALSE); - if (peer) - g_object_unref (peer); - return -1; - } - - priv->session_key = g_strdup(peer->session_key); - priv->peer_addr = g_strdup(peer->addr_str); - priv->peer_name = g_strdup(peer->name); - if (!priv->peer_name) - priv->peer_name = g_strdup("Unknown"); - g_object_unref (peer); - - seaf_debug ("[check-tx] %s repo %.8s.\n", argv[0], repo_id); - - ccnet_processor_thread_create (processor, seaf->job_mgr, - check_tx, thread_done, processor); - - return 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - char *token; - - if (processor->state != ACCESS_GRANTED) { - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (strncmp (code, SC_GET_TOKEN, 3) == 0) { - token = seaf_token_manager_generate_token (seaf->token_mgr, - processor->peer_id, - priv->repo_id); - ccnet_processor_send_response (processor, - SC_PUT_TOKEN, SS_PUT_TOKEN, - token, strlen(token) + 1); - g_free (token); - return; - } else if (strncmp (code, SC_GET_VERSION, 3) == 0) { - char buf[16]; - int len; - len = snprintf (buf, sizeof(buf), "%d", CURRENT_PROTO_VERSION); - ccnet_processor_send_response (processor, - SC_VERSION, SS_VERSION, - buf, len + 1); - ccnet_processor_done (processor, TRUE); - return; - } - - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} - diff --git a/server/processors/check-tx-slave-v3-proc.h b/server/processors/check-tx-slave-v3-proc.h deleted file mode 100644 index add1b314..00000000 --- a/server/processors/check-tx-slave-v3-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECK_TX_SLAVE_V3_PROC_H -#define SEAFILE_CHECK_TX_SLAVE_V3_PROC_H - -#include -#include - -#define SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC (seafile_check_tx_slave_v3_proc_get_type ()) -#define SEAFILE_CHECK_TX_SLAVE_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC, SeafileCheckTxSlaveV3Proc)) -#define SEAFILE_IS_CHECK_TX_SLAVE_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC, SeafileCheckTxSlaveV3ProcClass)) -#define IS_SEAFILE_CHECK_TX_SLAVE_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC)) -#define SEAFILE_CHECK_TX_SLAVE_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC, SeafileCheckTxSlaveV3ProcClass)) - -typedef struct _SeafileCheckTxSlaveV3Proc SeafileCheckTxSlaveV3Proc; -typedef struct _SeafileCheckTxSlaveV3ProcClass SeafileCheckTxSlaveV3ProcClass; - -struct _SeafileCheckTxSlaveV3Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckTxSlaveV3ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_check_tx_slave_v3_proc_get_type (); - -#endif diff --git a/server/processors/checkbl-proc.c b/server/processors/checkbl-proc.c deleted file mode 100644 index 58ad1c1b..00000000 --- a/server/processors/checkbl-proc.c +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "seafile-session.h" -#include "checkbl-proc.h" -#include "log.h" - -#define SC_BLOCK_LIST "301" -#define SS_BLOCK_LIST "Block list" -#define SC_NEED_BLOCKS "302" -#define SS_NEED_BLOCKS "Needed blocks" -#define SC_BLOCK_LIST_END "303" -#define SS_BLOCK_LIST_END "Block list end" - -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "Access denied" - -typedef struct { - gboolean processing; - char *block_list; - int len; - GString *buf; - gboolean success; - - gboolean no_repo_info; - - /* Used for getting repo info */ - char repo_id[37]; - char store_id[37]; - int repo_version; -} SeafileCheckblProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcPriv)) - -#define USE_PRIV \ - SeafileCheckblProcPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (SeafileCheckblProc, seafile_checkbl_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - g_free (priv->block_list); - if (priv->buf) - g_string_free (priv->buf, TRUE); - - CCNET_PROCESSOR_CLASS (seafile_checkbl_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_checkbl_proc_class_init (SeafileCheckblProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileCheckblProcPriv)); -} - -static void -seafile_checkbl_proc_init (SeafileCheckblProc *processor) -{ -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - memcpy (priv->store_id, repo->store_id, 36); - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - - priv->success = FALSE; -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - - if (argc == 0) { - /* To be compatible with older clients (protocol version < 6). - * However older clients can only sync repos with version 0. - * So there is no need to know the repo id. - */ - priv->no_repo_info = TRUE; - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - return 0; - } else { - priv->no_repo_info = FALSE; - - char *session_token = argv[0]; - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - } - - return 0; -} - -static void * -check_bl (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - priv->buf = g_string_new (""); - int offset = 0; - char block_id[41]; - while (offset < priv->len) { - memcpy (block_id, &priv->block_list[offset], 40); - block_id[40] = 0; - - if (priv->no_repo_info) { - if (!seaf_block_manager_block_exists(seaf->block_mgr, - NULL, 0, - block_id)) - g_string_append (priv->buf, block_id); - } else { - if (!seaf_block_manager_block_exists(seaf->block_mgr, - priv->store_id, - priv->repo_version, - block_id)) - g_string_append (priv->buf, block_id); - } - - offset += 40; - } - - priv->success = TRUE; - return vprocessor; -} - -static void -check_bl_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_NEED_BLOCKS, SS_NEED_BLOCKS, - priv->buf->str, priv->buf->len); - - priv->processing = FALSE; - g_free (priv->block_list); - priv->block_list = NULL; - g_string_free (priv->buf, TRUE); - priv->buf = NULL; - priv->success = FALSE; - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - - if (memcmp (code, SC_BLOCK_LIST, 3) == 0) { - /* We can't process more than one block list segments at the same time. */ - if (priv->processing) { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (clen == 0 || clen % 40 != 0) { - seaf_warning ("Bad block list length %d.\n", priv->len); - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - priv->processing = TRUE; - priv->block_list = g_memdup (content, clen); - priv->len = clen; - ccnet_processor_thread_create (processor, seaf->job_mgr, - check_bl, check_bl_done, processor); - } else if (memcmp (code, SC_BLOCK_LIST_END, 3) == 0) { - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("Bad update: %s %s.\n", code, code_msg); - ccnet_processor_done (processor, FALSE); - } -} diff --git a/server/processors/checkbl-proc.h b/server/processors/checkbl-proc.h deleted file mode 100644 index c67c8378..00000000 --- a/server/processors/checkbl-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECKBL_PROC_H -#define SEAFILE_CHECKBL_PROC_H - -#include - - -#define SEAFILE_TYPE_CHECKBL_PROC (seafile_checkbl_proc_get_type ()) -#define SEAFILE_CHECKBL_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProc)) -#define SEAFILE_IS_CHECKBL_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECKBL_PROC)) -#define SEAFILE_CHECKBL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcClass)) -#define IS_SEAFILE_CHECKBL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECKBL_PROC)) -#define SEAFILE_CHECKBL_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcClass)) - -typedef struct _SeafileCheckblProc SeafileCheckblProc; -typedef struct _SeafileCheckblProcClass SeafileCheckblProcClass; - -struct _SeafileCheckblProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckblProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_checkbl_proc_get_type (); - -#endif - diff --git a/server/processors/checkff-proc.c b/server/processors/checkff-proc.c deleted file mode 100644 index f07315e9..00000000 --- a/server/processors/checkff-proc.c +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include "seafile-session.h" -#include "checkff-proc.h" -#include "log.h" - -typedef struct { - char repo_id[37]; - char root_id[41]; - int result; -} SeafileCheckffProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProcPriv)) - -#define USE_PRIV \ - SeafileCheckffProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafileCheckffProc, seafile_checkff_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void -release_resource(CcnetProcessor *processor) -{ - - CCNET_PROCESSOR_CLASS (seafile_checkff_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_checkff_proc_class_init (SeafileCheckffProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileCheckffProcPriv)); -} - -static void -seafile_checkff_proc_init (SeafileCheckffProc *processor) -{ -} - -typedef struct { - gboolean fast_forward; - char root_id[41]; -} CompareAux; - -static gboolean -compare_root (SeafCommit *commit, void *data, gboolean *stop) -{ - CompareAux *aux = data; - - /* If we've found a match in another branch, stop traversing. */ - if (aux->fast_forward) { - *stop = TRUE; - return TRUE; - } - - if (strcmp (commit->root_id, aux->root_id) == 0) { - aux->fast_forward = TRUE; - *stop = TRUE; - } - - return TRUE; -} - -static gboolean -check_fast_forward (SeafRepo *repo, const char *head_id, const char *root_id) -{ - CompareAux *aux = g_new0 (CompareAux, 1); - gboolean ret; - - memcpy (aux->root_id, root_id, 41); - if (!seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - head_id, - compare_root, - aux, FALSE)) { - g_free (aux); - return FALSE; - } - - ret = aux->fast_forward; - g_free (aux); - return ret; -} - -static void * -check_fast_forward_thread (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Cannot find repo %s.\n", priv->repo_id); - priv->result = 0; - return vdata; - } - - priv->result = check_fast_forward (repo, repo->head->commit_id, priv->root_id); - - seaf_repo_unref (repo); - return vdata; -} - -static void -check_fast_forward_done (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - char res[10]; - - snprintf (res, sizeof(res), "%d", priv->result); - - seaf_message ("res is %s.\n", res); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, res, strlen(res)+1); - ccnet_processor_done (processor, TRUE); -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - char *repo_id, *root_id; - - if (argc < 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - repo_id = argv[0]; - root_id = argv[1]; - if (strlen(repo_id) != 36 || !is_uuid_valid(repo_id) || strlen(root_id) != 40) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 36); - memcpy (priv->root_id, root_id, 40); - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - check_fast_forward_thread, - check_fast_forward_done, - processor); - return 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - -} diff --git a/server/processors/checkff-proc.h b/server/processors/checkff-proc.h deleted file mode 100644 index 0a84bd49..00000000 --- a/server/processors/checkff-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_CHECKFF_PROC_H -#define SEAFILE_CHECKFF_PROC_H - -#include - - -#define SEAFILE_TYPE_CHECKFF_PROC (seafile_checkff_proc_get_type ()) -#define SEAFILE_CHECKFF_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProc)) -#define SEAFILE_IS_CHECKFF_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECKFF_PROC)) -#define SEAFILE_CHECKFF_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProcClass)) -#define IS_SEAFILE_CHECKFF_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECKFF_PROC)) -#define SEAFILE_CHECKFF_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProcClass)) - -typedef struct _SeafileCheckffProc SeafileCheckffProc; -typedef struct _SeafileCheckffProcClass SeafileCheckffProcClass; - -struct _SeafileCheckffProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileCheckffProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_checkff_proc_get_type (); - -#endif - diff --git a/server/processors/heartbeat-proc.c b/server/processors/heartbeat-proc.c deleted file mode 100644 index c9e1cd08..00000000 --- a/server/processors/heartbeat-proc.c +++ /dev/null @@ -1,274 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include "seafile-session.h" -#include "heartbeat-proc.h" - -/* - * Block sizes update algorithm: - * - * 1. When heartbeat starts, it send the list of all current blocks to monitor; - * 2. When a new block is sent to this chunk server, heartbeat will receive - * a signal from block manager. It will add the block metadata into - * priv->block_metadata_new queue. If more than 30 block metadata have been - * queued, heartbeat proc will send the list to monitor. - * 3. On an idle chunk server, it may take long time to queue 30 blocks. - * To keep the monitor up-to-date, a flush timer is scheduled to flush - * block info to monitor every 30 seconds. - */ - -#define FLUSH_INTERVAL_MSEC 30 * 1000 - -#define SC_BLOCK_INFO "301" -#define SS_BLOCK_INFO "Block info" - -/* - Master Slave - - seafile-heartbeat - -----------------------------> - OK - <----------------------------- - - Block Info - -----------------------------> - - Block Info - -----------------------------> - ... - - */ - -typedef struct { - GList *block_metadata_old; - GList *block_metadata_new; - int new_blocks; - CcnetTimer *flush_timer; -} SeafileHeartbeatProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_HEARTBEAT_PROC, SeafileHeartbeatProcPriv)) - -#define USE_PRIV \ - SeafileHeartbeatProcPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (SeafileHeartbeatProc, seafile_heartbeat_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_response (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void *collect_block_sizes (void *vprocessor); -static void collect_block_sizes_done (CcnetProcessor *processor, - int status, - char *message); -static void on_block_added (SeafBlockManager *block_mgr, - const char *block_id, - void *vprocessor); -static int flush_block_sizes (void *vprocessor); -static void free_md_list (GList *md_list); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->block_metadata_old) - free_md_list (priv->block_metadata_old); - if (priv->block_metadata_new) - free_md_list (priv->block_metadata_new); - - g_signal_handlers_disconnect_by_func (seaf->block_mgr, on_block_added, processor); - ccnet_timer_free (&priv->flush_timer); - - CCNET_PROCESSOR_CLASS (seafile_heartbeat_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_heartbeat_proc_class_init (SeafileHeartbeatProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "heartbeat-proc"; - proc_class->start = start; - proc_class->handle_response = handle_response; - proc_class->handle_thread_done = collect_block_sizes_done; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileHeartbeatProcPriv)); -} - -static void -seafile_heartbeat_proc_init (SeafileHeartbeatProc *processor) -{ -} - - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char buf[256]; - - snprintf (buf, sizeof(buf), "remote %s seafile-heartbeat", - processor->peer_id); - ccnet_processor_send_request (processor, buf); - - return 0; -} - - -static void -handle_response (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - int rc; - - if (strncmp (code, SC_OK, 3) == 0) { - rc = ccnet_processor_thread_create (processor, - collect_block_sizes, - NULL); - if (rc < 0) { - g_warning ("[heartbeat] failed to create thread.\n"); - ccnet_processor_done (processor, FALSE); - } - - g_signal_connect (seaf->block_mgr, "block-added", - (GCallback)on_block_added, - processor); - - priv->flush_timer = ccnet_timer_new (flush_block_sizes, - processor, - FLUSH_INTERVAL_MSEC); - } else { - g_warning ("[heartbeat] Bad response: %s %s\n", code, code_msg); - ccnet_processor_done (processor, FALSE); - } -} - -static void -send_block_sizes (CcnetProcessor *processor, GList *metadata) -{ - char buf[2048]; - char *ptr = buf; - int count = 0, n; - GList *md_list = metadata; - BlockMetadata *md; - - while (md_list) { - md = md_list->data; - md_list = g_list_delete_link (md_list, md_list); - - n = snprintf (ptr, 60, "%s %u\n", md->id, md->size); - ptr += n; - - if (++count == 30) { - ccnet_processor_send_update (processor, - SC_BLOCK_INFO, SS_BLOCK_INFO, - buf, (ptr - buf) + 1); - count = 0; - ptr = buf; - } - g_free (md); - } - - if (count) { - ccnet_processor_send_update (processor, - SC_BLOCK_INFO, SS_BLOCK_INFO, - buf, (ptr - buf) + 1); - } -} - -static void * -collect_block_sizes (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - GList *metadata_list; - USE_PRIV; - - metadata_list = seaf_block_manager_get_all_block_metadata (seaf->block_mgr); - /* if (!metadata_list) { */ - /* ccnet_processor_thread_done (processor, -1, NULL); */ - /* return NULL; */ - /* } */ - - priv->block_metadata_old = metadata_list; - ccnet_processor_thread_done (processor, 0, NULL); - return NULL; -} - -static void -collect_block_sizes_done (CcnetProcessor *processor, - int status, - char *message) -{ - USE_PRIV; - - if (status == 0) { - g_message ("[hearbeat] collected block sizes on start.\n"); - send_block_sizes (processor, priv->block_metadata_old); - priv->block_metadata_old = NULL; - } else { - g_warning ("Failed to collect block sizes.\n"); - ccnet_processor_done (processor, FALSE); - } -} - -static void -on_block_added (SeafBlockManager *block_mgr, - const char *block_id, - void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - BlockMetadata *md; - USE_PRIV; - - md = seaf_block_manager_stat_block (block_mgr, block_id); - if (!md) { - g_warning ("[heartbeat] Failed to stat block %s\n", block_id); - return; - } - - g_message ("Queue block %s, size is %u\n", block_id, md->size); - - priv->block_metadata_new = g_list_prepend (priv->block_metadata_new, md); - if (++priv->new_blocks == 30) { - send_block_sizes (processor, priv->block_metadata_new); - priv->block_metadata_new = NULL; - priv->new_blocks = 0; - } -} - -static int -flush_block_sizes (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - if (priv->new_blocks != 0) { - g_message ("Flushing %u blocks to monitor.\n", priv->new_blocks); - send_block_sizes (processor, priv->block_metadata_new); - priv->block_metadata_new = NULL; - priv->new_blocks = 0; - } - - return 1; -} - -static void -free_md_list (GList *md_list) -{ - BlockMetadata *md; - - while (md_list) { - md = md_list->data; - md_list = g_list_delete_link (md_list, md_list); - g_free (md); - } -} diff --git a/server/processors/heartbeat-proc.h b/server/processors/heartbeat-proc.h deleted file mode 100644 index f229e78c..00000000 --- a/server/processors/heartbeat-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_HEARTBEAT_PROC_H -#define SEAFILE_HEARTBEAT_PROC_H - -#include -#include - -#define SEAFILE_TYPE_HEARTBEAT_PROC (seafile_heartbeat_proc_get_type ()) -#define SEAFILE_HEARTBEAT_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_HEARTBEAT_PROC, SeafileHeartbeatProc)) -#define SEAFILE_IS_HEARTBEAT_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_HEARTBEAT_PROC)) -#define SEAFILE_HEARTBEAT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_HEARTBEAT_PROC, SeafileHeartbeatProcClass)) -#define IS_SEAFILE_HEARTBEAT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_HEARTBEAT_PROC)) -#define SEAFILE_HEARTBEAT_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_HEARTBEAT_PROC, SeafileHeartbeatProcClass)) - -typedef struct _SeafileHeartbeatProc SeafileHeartbeatProc; -typedef struct _SeafileHeartbeatProcClass SeafileHeartbeatProcClass; - -struct _SeafileHeartbeatProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileHeartbeatProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_heartbeat_proc_get_type (); - -#endif - diff --git a/server/processors/put-sharedb-proc.c b/server/processors/put-sharedb-proc.c deleted file mode 100644 index 4395b8a6..00000000 --- a/server/processors/put-sharedb-proc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include "db.h" -#include "seafile-session.h" -#include "share-info.h" -#include "share-mgr.h" -#include "share-mgr-priv.h" -#include "put-sharedb-proc.h" - -static int put_sharedb_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -typedef struct { - char *share_id; - GList *sinfos; - GList *ptr; -} PutSharedbPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUT_SHAREDB_PROC, PutSharedbPriv)) - -#define USE_PRIV \ - PutSharedbPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (PutSharedbProc, put_sharedb_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->share_id) - g_free (priv->share_id); - - CCNET_PROCESSOR_CLASS (put_sharedb_proc_parent_class)->release_resource(processor); -} - - -static void -put_sharedb_proc_class_init (PutSharedbProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "put-sharedb-proc"; - proc_class->start = put_sharedb_start; - - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof(PutSharedbPriv)); -} - -static void -put_sharedb_proc_init (PutSharedbProc *processor) -{ -} - -/* return TRUE if more info to send, FALSE otherwise */ -static gboolean -send_share_info (CcnetProcessor *processor) -{ - USE_PRIV; - - if (!priv->ptr) - return FALSE; - - SeafShareInfo *info = priv->ptr->data; - char *s = seaf_share_info_to_json(info); - - ccnet_processor_send_response (processor, "301", "ShareInfo", - s, strlen(s)+1); - priv->ptr = priv->ptr->next; - return TRUE; -} - -static void -prepare_put_share_db (CcnetProcessor *processor) -{ - USE_PRIV; - - priv->sinfos = seaf_share_manager_get_group_share_info ( - seaf->share_mgr, priv->share_id); - priv->ptr = priv->sinfos; -} - -static int -put_sharedb_start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - - if (argc != 1) { - ccnet_processor_send_response (processor, "401", "Bad arguments", - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - priv->share_id = g_strdup(argv[0]); - - prepare_put_share_db (processor); - if (!priv->sinfos) { - /* we do not have any items to send to peer */ - ccnet_processor_send_response (processor, "302", "END", NULL, 0); - ccnet_processor_done (processor, TRUE); - return 0; - } - - send_share_info(processor); - - return 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - - if (memcmp (code, "200", 3) != 0) { - g_warning ("[send-sharedb] received bad respones %s: %s\n", - code, code_msg); - ccnet_processor_done (processor, FALSE); - return; - } - - if (send_share_info(processor) == FALSE) { - ccnet_processor_send_response (processor, "302", "END", NULL, 0); - ccnet_processor_done (processor, TRUE); - } - - return; -} diff --git a/server/processors/put-sharedb-proc.h b/server/processors/put-sharedb-proc.h deleted file mode 100644 index 14fbc6c6..00000000 --- a/server/processors/put-sharedb-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef PUT_SHAREDB_PROC_H -#define PUT_SHAREDB_PROC_H - -#include - -#include - -#define SEAFILE_TYPE_PUT_SHAREDB_PROC (put_sharedb_proc_get_type ()) -#define PUT_SHAREDB_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECKIN_PROC, PutSharedbProc)) -#define SEAFILE_IS_CHECKIN_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECKIN_PROC)) -#define PUT_SHAREDB_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECKIN_PROC, PutSharedbProcClass)) -#define IS_PUT_SHAREDB_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECKIN_PROC)) -#define PUT_SHAREDB_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECKIN_PROC, PutSharedbProcClass)) - -typedef struct _PutSharedbProc PutSharedbProc; -typedef struct _PutSharedbProcClass PutSharedbProcClass; - -struct _PutSharedbProc { - CcnetProcessor parent_instance; -}; - -struct _PutSharedbProcClass { - CcnetProcessorClass parent_class; -}; - -GType put_sharedb_proc_get_type (); - -#endif diff --git a/server/processors/putbranch-proc.c b/server/processors/putbranch-proc.c deleted file mode 100644 index 6e954eb0..00000000 --- a/server/processors/putbranch-proc.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - - -#include "putbranch-proc.h" - -G_DEFINE_TYPE (SeafilePutbranchProc, seafile_putbranch_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void -release_resource(CcnetProcessor *processor) -{ - /* FILL IT */ - - CCNET_PROCESSOR_CLASS (seafile_putbranch_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putbranch_proc_class_init (SeafilePutbranchProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putbranch-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; -} - -static void -seafile_putbranch_proc_init (SeafilePutbranchProc *processor) -{ -} - - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - - - return 0; -} - - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - -} diff --git a/server/processors/putbranch-proc.h b/server/processors/putbranch-proc.h deleted file mode 100644 index 914b7e54..00000000 --- a/server/processors/putbranch-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTBRANCH_PROC_H -#define SEAFILE_PUTBRANCH_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTBRANCH_PROC (seafile_putbranch_proc_get_type ()) -#define SEAFILE_PUTBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTBRANCH_PROC, SeafilePutbranchProc)) -#define SEAFILE_IS_PUTBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTBRANCH_PROC)) -#define SEAFILE_PUTBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTBRANCH_PROC, SeafilePutbranchProcClass)) -#define IS_SEAFILE_PUTBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTBRANCH_PROC)) -#define SEAFILE_PUTBRANCH_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTBRANCH_PROC, SeafilePutbranchProcClass)) - -typedef struct _SeafilePutbranchProc SeafilePutbranchProc; -typedef struct _SeafilePutbranchProcClass SeafilePutbranchProcClass; - -struct _SeafilePutbranchProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutbranchProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putbranch_proc_get_type (); - -#endif - diff --git a/server/processors/putca-proc.c b/server/processors/putca-proc.c deleted file mode 100644 index d8a5755c..00000000 --- a/server/processors/putca-proc.c +++ /dev/null @@ -1,269 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include -#include "utils.h" - -#include "seafile-session.h" -#include "putca-proc.h" - -typedef struct { - char repo_id[37]; - char *token; - GHashTable *commit_hash; - - gboolean token_valid; - char ca_id[41]; -} SeafilePutcaProcPriv; - -#define SC_ID_LIST "301" -#define SS_ID_LIST "Commit id list" -#define SC_ID_LIST_END "302" -#define SS_ID_LIST_END "Commit id list end" -#define SC_CA "303" -#define SS_CA "Common ancestor" - -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "Access denied" -#define SC_NO_CA "404" -#define SS_NO_CA "No common ancestor found" - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTCA_PROC, SeafilePutcaProcPriv)) - -#define USE_PRIV \ - SeafilePutcaProcPriv *priv = GET_PRIV(processor); - -static int put_ca_start (CcnetProcessor *processor, int argc, char **argv); -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -G_DEFINE_TYPE (SeafilePutcaProc, seafile_putca_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource (CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->commit_hash) - g_hash_table_destroy (priv->commit_hash); - if (priv->token) - g_free (priv->token); - - CCNET_PROCESSOR_CLASS (seafile_putca_proc_parent_class)->release_resource (processor); -} - -static void -seafile_putca_proc_class_init (SeafilePutcaProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putca-proc"; - proc_class->start = put_ca_start; - proc_class->release_resource = release_resource; - proc_class->handle_update = handle_update; - - g_type_class_add_private (klass, sizeof (SeafilePutcaProcPriv)); -} - -static void -seafile_putca_proc_init (SeafilePutcaProc *processor) -{ -} - -static void * -check_token_thread (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - char *user; - - user = seaf_repo_manager_get_email_by_token ( - seaf->repo_mgr, priv->repo_id, priv->token); - if (!user) { - priv->token_valid = FALSE; - return vdata; - } - - g_free (user); - priv->token_valid = TRUE; - return vdata; -} - -static void -check_token_thread_done (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - - if (!priv->token_valid) { - ccnet_processor_send_response (processor, SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } else { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - priv->commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - } -} - -static int -put_ca_start (CcnetProcessor *processor, int argc, char **argv) -{ - char *repo_id, *token; - USE_PRIV; - - if (argc < 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - repo_id = argv[0]; - token = argv[1]; - - if (!is_uuid_valid (repo_id)) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 36); - priv->token = g_strdup(token); - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - check_token_thread, - check_token_thread_done, - processor); - - return 0; -} - -static void -process_commit_id_list (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - int offset; - int size = clen - 1; - int dummy; - - if (size % 40 != 0) { - seaf_warning ("Invalid commid id list size %d.\n", size); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - for (offset = 0; offset < size - 1; offset += 40) - g_hash_table_insert (priv->commit_hash, - g_strndup(&content[offset], 40), &dummy); -} - -static gboolean -find_common_ancestor (SeafCommit *commit, void *data, gboolean *stop) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - /* If common ancestor has been found on other branch, stop traversing down. */ - if (priv->ca_id[0] != 0) { - *stop = TRUE; - return TRUE; - } - - if (g_hash_table_lookup (priv->commit_hash, commit->commit_id)) { - memcpy (priv->ca_id, commit->commit_id, 40); - *stop = TRUE; - return TRUE; - } - - return TRUE; -} - -static void * -compute_common_ancestor_thread (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - SeafRepo *repo = NULL; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to find repo %.8s.\n", priv->repo_id); - return vprocessor; - } - - /* Traverse the commit tree. The first commit whose id is in the commit list - * is the common ancestor. - */ - if (seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - repo->head->commit_id, - find_common_ancestor, - processor, - FALSE) < 0) { - seaf_warning ("Failed to find common ancestor.\n"); - seaf_repo_unref (repo); - return vprocessor; - } - - seaf_repo_unref (repo); - return vprocessor; -} - -static void -compute_common_ancestor_done (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - if (priv->ca_id[0] != 0) { - ccnet_processor_send_response (processor, SC_CA, SS_CA, priv->ca_id, 41); - ccnet_processor_done (processor, TRUE); - } else { - ccnet_processor_send_response (processor, SC_NO_CA, SS_NO_CA, NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - - if (!priv->token_valid) { - ccnet_processor_send_response (processor, SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (strncmp (code, SC_ID_LIST, 3) == 0) { - process_commit_id_list (processor, content, clen); - return; - } else if (strncmp (code, SC_ID_LIST_END, 3) == 0) { - ccnet_processor_thread_create (processor, - seaf->job_mgr, - compute_common_ancestor_thread, - compute_common_ancestor_done, - processor); - return; - } - - seaf_warning ("Bad update: %s %s.\n", code, code_msg); - ccnet_processor_send_response (processor, SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/putca-proc.h b/server/processors/putca-proc.h deleted file mode 100644 index 293be9fd..00000000 --- a/server/processors/putca-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCA_PROC_H -#define SEAFILE_PUTCA_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTCA_PROC (seafile_putca_proc_get_type ()) -#define SEAFILE_PUTCA_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCA_PROC, SeafilePutcaProc)) -#define SEAFILE_IS_PUTCA_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCA_PROC)) -#define SEAFILE_PUTCA_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCA_PROC, SeafilePutcaProcClass)) -#define IS_SEAFILE_PUTCA_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCA_PROC)) -#define SEAFILE_PUTCA_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCA_PROC, SeafilePutcaProcClass)) - -typedef struct _SeafilePutcaProc SeafilePutcaProc; -typedef struct _SeafilePutcaProcClass SeafilePutcaProcClass; - -struct _SeafilePutcaProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcaProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putca_proc_get_type (); - -#endif diff --git a/server/processors/putcommit-proc.c b/server/processors/putcommit-proc.c deleted file mode 100644 index 008d8686..00000000 --- a/server/processors/putcommit-proc.c +++ /dev/null @@ -1,230 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include -#include -#include -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "putcommit-proc.h" -#include "processors/objecttx-common.h" -#include "object-list.h" -#include "vc-common.h" - -#include "log.h" - -typedef struct { - char commit_id[41]; - char object_path[SEAF_PATH_MAX]; - gboolean transfer_started; - int fd; -} SeafilePutcommitProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTCOMMIT_PROC, SeafilePutcommitProcPriv)) - -#define USE_PRIV \ - SeafilePutcommitProcPriv *priv = GET_PRIV(processor); - -static int put_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static int send_commit_ids (CcnetProcessor *processor, const char *head); - - -G_DEFINE_TYPE (SeafilePutcommitProc, seafile_putcommit_proc, CCNET_TYPE_PROCESSOR) - -static void -seafile_putcommit_proc_class_init (SeafilePutcommitProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putcommit-proc"; - proc_class->start = put_commit_start; - proc_class->handle_update = handle_update; - - g_type_class_add_private (klass, sizeof (SeafilePutcommitProcPriv)); -} - -static void -seafile_putcommit_proc_init (SeafilePutcommitProc *processor) -{ -} - - -static int -put_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - char *commit_id; - char *session_token; - USE_PRIV; - - if (argc != 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[1]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - processor->peer_id, - session_token, NULL) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - commit_id = argv[0]; - - memcpy (priv->commit_id, commit_id, 41); - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - - return send_commit_ids (processor, commit_id); -} - -static gboolean -commit_collector (SeafCommit *commit, void *data, gboolean *stop) -{ - ObjectList *ol = data; - - object_list_insert (ol, commit->commit_id); - - return TRUE; -} - -static int -send_commit_ids (CcnetProcessor *processor, const char *head) -{ - char buf[2048]; - char *ptr = buf; - int i, count = 0; - int ret; - - ObjectList *ol = object_list_new (); - ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - head, - commit_collector, - ol, FALSE); - if (ret == FALSE) { - object_list_free (ol); - seaf_warning ("[putcommit] Load commits error\n"); - ccnet_processor_send_response ( - processor, SC_NOT_FOUND, SS_NOT_FOUND, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - int ollen = object_list_length(ol); - g_return_val_if_fail (ollen != 0, -1); - - for (i = 0; i < ollen; i++) { - memcpy (ptr, g_ptr_array_index(ol->obj_ids, i), 40); - ptr += 40; - *ptr++ = '\n'; - - if (++count == 48) { - *ptr = '\0'; - ccnet_processor_send_response (processor, SC_COMMIT_IDS, - SS_COMMIT_IDS, buf, 41 * count + 1); - ptr = buf; - count = 0; - } - } - - if (count) { - *ptr = '\0'; - ccnet_processor_send_response (processor, SC_COMMIT_IDS, - SS_COMMIT_IDS, buf, 41 * count + 1); - } - - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - - return 0; -} - - -static gboolean -send_commit (CcnetProcessor *processor, char *object_id) -{ - char *data; - int len; - ObjectPack *pack = NULL; - int pack_size; - - if (seaf_obj_store_read_obj (seaf->commit_mgr->obj_store, - object_id, (void**)&data, &len) < 0) { - seaf_warning ("Failed to read commit %s.\n", object_id); - goto fail; - } - - pack_size = sizeof(ObjectPack) + len; - pack = malloc (pack_size); - memcpy (pack->id, object_id, 41); - memcpy (pack->object, data, len); - - ccnet_processor_send_response (processor, SC_OBJECT, SS_OBJECT, - (char *)pack, pack_size); - - g_free (data); - free (pack); - return TRUE; - -fail: - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - object_id, 41); - ccnet_processor_done (processor, FALSE); - return FALSE; -} - -static void -send_commits (CcnetProcessor *processor, char *content, int clen) -{ - char *object_id; - int n_objects; - int i; - - if (clen % 41 != 1 || content[clen-1] != '\0') { - seaf_warning ("[putcommit] Bad commit object list.\n"); - ccnet_processor_send_response (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - n_objects = clen/41; - - object_id = content; - for (i = 0; i < n_objects; ++i) { - object_id[40] = '\0'; - if (send_commit (processor, object_id) == FALSE) - return; - - object_id += 41; - } -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - if (strncmp(code, SC_GET_OBJECT, 3) == 0) { - send_commits (processor, content, clen); - } else if (strncmp(code, SC_END, 3) == 0) { - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("[putcommit] Bad response: %s %s\n", code, code_msg); - ccnet_processor_done (processor, FALSE); - } -} diff --git a/server/processors/putcommit-proc.h b/server/processors/putcommit-proc.h deleted file mode 100644 index 32bd50cf..00000000 --- a/server/processors/putcommit-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCOMMIT_PROC_H -#define SEAFILE_PUTCOMMIT_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTCOMMIT_PROC (seafile_putcommit_proc_get_type ()) -#define SEAFILE_PUTCOMMIT_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCOMMIT_PROC, SeafilePutcommitProc)) -#define SEAFILE_IS_PUTCOMMIT_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCOMMIT_PROC)) -#define SEAFILE_PUTCOMMIT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCOMMIT_PROC, SeafilePutcommitProcClass)) -#define IS_SEAFILE_PUTCOMMIT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCOMMIT_PROC)) -#define SEAFILE_PUTCOMMIT_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCOMMIT_PROC, SeafilePutcommitProcClass)) - -typedef struct _SeafilePutcommitProc SeafilePutcommitProc; -typedef struct _SeafilePutcommitProcClass SeafilePutcommitProcClass; - -struct _SeafilePutcommitProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcommitProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putcommit_proc_get_type (); - -#endif diff --git a/server/processors/putcommit-v2-proc.c b/server/processors/putcommit-v2-proc.c deleted file mode 100644 index 942078ff..00000000 --- a/server/processors/putcommit-v2-proc.c +++ /dev/null @@ -1,379 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "putcommit-v2-proc.h" -#include "processors/objecttx-common.h" -#include "vc-common.h" - -typedef struct { - char head_commit_id[41]; - char remote_commit_id[41]; - GList *id_list; - GHashTable *commit_hash; - gboolean fast_forward; - - guint32 reader_id; - gboolean registered; - - char repo_id[37]; - int repo_version; -} SeafilePutcommitProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTCOMMIT_V2_PROC, SeafilePutcommitProcPriv)) - -#define USE_PRIV \ - SeafilePutcommitProcPriv *priv = GET_PRIV(processor); - -static int put_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -G_DEFINE_TYPE (SeafilePutcommitV2Proc, seafile_putcommit_v2_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource (CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->id_list) - string_list_free (priv->id_list); - if (priv->commit_hash) - g_hash_table_destroy (priv->commit_hash); - if (priv->registered) - seaf_obj_store_unregister_async_read (seaf->commit_mgr->obj_store, - priv->reader_id); - - CCNET_PROCESSOR_CLASS (seafile_putcommit_v2_proc_parent_class)->release_resource (processor); -} - -static void -seafile_putcommit_v2_proc_class_init (SeafilePutcommitV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putcommit-v2-proc"; - proc_class->start = put_commit_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafilePutcommitProcPriv)); -} - -static void -seafile_putcommit_v2_proc_init (SeafilePutcommitV2Proc *processor) -{ -} - -static void -send_commit (CcnetProcessor *processor, - const char *commit_id, - char *data, int len) -{ - ObjectPack *pack = NULL; - int pack_size; - - pack_size = sizeof(ObjectPack) + len; - pack = malloc (pack_size); - memcpy (pack->id, commit_id, 41); - memcpy (pack->object, data, len); - - ccnet_processor_send_response (processor, SC_OBJECT, SS_OBJECT, - (char *)pack, pack_size); - free (pack); -} - -static int -read_and_send_commit (CcnetProcessor *processor) -{ - char *id; - USE_PRIV; - - id = priv->id_list->data; - priv->id_list = g_list_delete_link (priv->id_list, priv->id_list); - - if (seaf_obj_store_async_read (seaf->commit_mgr->obj_store, - priv->reader_id, - id) < 0) { - seaf_warning ("[putcommit] Failed to start read of %s.\n", id); - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); - g_free (id); - return -1; - } - - g_free (id); - return 0; -} - -static void -read_done_cb (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - USE_PRIV; - - if (!res->success) { - seaf_warning ("[putcommit] Failed to read %s.\n", res->obj_id); - goto bad; - } - - send_commit (processor, res->obj_id, res->data, res->len); - - seaf_debug ("Send commit %.8s.\n", res->obj_id); - - /* Send next commit. */ - if (priv->id_list != NULL) - read_and_send_commit (processor); - else { - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - } - - return; - -bad: - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} - -static gboolean -collect_id_fast_forward (SeafCommit *commit, void *data, gboolean *stop) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (g_strcmp0 (commit->commit_id, priv->remote_commit_id) == 0) { - *stop = TRUE; - return TRUE; - } - - /* In clone remote head is not set but we're alwasy fast-forward. */ - if (priv->remote_commit_id[0] != '\0' && - commit->second_parent_id != NULL) { - *stop = TRUE; - priv->fast_forward = FALSE; - return TRUE; - } - - priv->id_list = g_list_prepend (priv->id_list, g_strdup(commit->commit_id)); - return TRUE; -} - -static gboolean -collect_id_remote (SeafCommit *commit, void *data, gboolean *stop) -{ - CcnetProcessor *processor = data; - USE_PRIV; - char *key; - - if (g_hash_table_lookup (priv->commit_hash, commit->commit_id)) - return TRUE; - - key = g_strdup(commit->commit_id); - g_hash_table_replace (priv->commit_hash, key, key); - return TRUE; -} - -static gboolean -compute_delta (SeafCommit *commit, void *data, gboolean *stop) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (!g_hash_table_lookup (priv->commit_hash, commit->commit_id)) { - priv->id_list = g_list_prepend (priv->id_list, - g_strdup(commit->commit_id)); - } else { - /* Stop traversing down from this commit if it already exists - * in the remote branch. - */ - *stop = TRUE; - } - - return TRUE; -} - -static int -compute_delta_commits (CcnetProcessor *processor, const char *head) -{ - gboolean ret; - USE_PRIV; - - string_list_free (priv->id_list); - priv->id_list = NULL; - - priv->commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - /* When putting commits, the remote head commit must exists. */ - ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - priv->repo_id, - priv->repo_version, - priv->remote_commit_id, - collect_id_remote, - processor, - FALSE); - if (!ret) { - seaf_warning ("[putcommit] Failed to traverse remote branch.\n"); - string_list_free (priv->id_list); - priv->id_list = NULL; - return -1; - } - - ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - priv->repo_id, - priv->repo_version, - head, - compute_delta, - processor, - FALSE); - if (!ret) { - seaf_warning ("[putcommit] Failed to compute delta commits.\n"); - string_list_free (priv->id_list); - priv->id_list = NULL; - return -1; - } - - return 0; -} - -static void * -collect_commit_id_thread (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->id_list = NULL; - return vprocessor; - } - priv->repo_version = repo->version; - - priv->fast_forward = TRUE; - if (seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - priv->head_commit_id, - collect_id_fast_forward, - processor, - FALSE) < 0) { - seaf_warning ("[putcommit] Failed to collect commit id.\n"); - string_list_free (priv->id_list); - priv->id_list = NULL; - goto out; - } - - if (priv->fast_forward) { - seaf_debug ("Send commits after a fast-forward merge.\n"); - goto out; - } - - seaf_debug ("Send commits after a real merge.\n"); - - compute_delta_commits (processor, priv->head_commit_id); - -out: - seaf_repo_unref (repo); - return vprocessor; -} - -static void -collect_commit_id_done (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - if (!priv->id_list) { - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - priv->reader_id = - seaf_obj_store_register_async_read (seaf->commit_mgr->obj_store, - priv->repo_id, - priv->repo_version, - read_done_cb, - processor); - priv->registered = TRUE; - - read_and_send_commit (processor); -} - -static int -put_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - char *head_id, *remote_id = NULL; - char *session_token; - USE_PRIV; - - if (argc < 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (argc == 2) { - head_id = argv[0]; - session_token = argv[1]; - } else if (argc >= 3) { - head_id = argv[0]; - remote_id = argv[1]; - session_token = argv[2]; - } - - if (strlen(head_id) != 40 || (remote_id && strlen(remote_id) != 40)) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->head_commit_id, head_id, 41); - if (remote_id != NULL) - memcpy (priv->remote_commit_id, remote_id, 41); - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - collect_commit_id_thread, - collect_commit_id_done, - processor); - - return 0; -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/putcommit-v2-proc.h b/server/processors/putcommit-v2-proc.h deleted file mode 100644 index 9241d87d..00000000 --- a/server/processors/putcommit-v2-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCOMMIT_V2_PROC_H -#define SEAFILE_PUTCOMMIT_V2_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTCOMMIT_V2_PROC (seafile_putcommit_v2_proc_get_type ()) -#define SEAFILE_PUTCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCOMMIT_V2_PROC, SeafilePutcommitV2Proc)) -#define SEAFILE_IS_PUTCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCOMMIT_V2_PROC)) -#define SEAFILE_PUTCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCOMMIT_V2_PROC, SeafilePutcommitV2ProcClass)) -#define IS_SEAFILE_PUTCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCOMMIT_V2_PROC)) -#define SEAFILE_PUTCOMMIT_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCOMMIT_V2_PROC, SeafilePutcommitV2ProcClass)) - -typedef struct _SeafilePutcommitV2Proc SeafilePutcommitV2Proc; -typedef struct _SeafilePutcommitV2ProcClass SeafilePutcommitV2ProcClass; - -struct _SeafilePutcommitV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcommitV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putcommit_v2_proc_get_type (); - -#endif diff --git a/server/processors/putcommit-v3-proc.c b/server/processors/putcommit-v3-proc.c deleted file mode 100644 index 6d8b8eb3..00000000 --- a/server/processors/putcommit-v3-proc.c +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "putcommit-v3-proc.h" -#include "processors/objecttx-common.h" - -typedef struct { - char head_commit_id[41]; - guint32 reader_id; - gboolean registered; - - /* Used for getting repo info */ - char repo_id[37]; - int repo_version; - gboolean success; -} SeafilePutcommitProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTCOMMIT_V3_PROC, SeafilePutcommitProcPriv)) - -#define USE_PRIV \ - SeafilePutcommitProcPriv *priv = GET_PRIV(processor); - -static int put_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -G_DEFINE_TYPE (SeafilePutcommitV3Proc, seafile_putcommit_v3_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource (CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->registered) - seaf_obj_store_unregister_async_read (seaf->commit_mgr->obj_store, - priv->reader_id); - - CCNET_PROCESSOR_CLASS (seafile_putcommit_v3_proc_parent_class)->release_resource (processor); -} - -static void -seafile_putcommit_v3_proc_class_init (SeafilePutcommitV3ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putcommit-v3-proc"; - proc_class->start = put_commit_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafilePutcommitProcPriv)); -} - -static void -seafile_putcommit_v3_proc_init (SeafilePutcommitV3Proc *processor) -{ -} - -static void -send_commit (CcnetProcessor *processor, - const char *commit_id, - char *data, int len) -{ - ObjectPack *pack = NULL; - int pack_size; - - pack_size = sizeof(ObjectPack) + len; - pack = malloc (pack_size); - memcpy (pack->id, commit_id, 41); - memcpy (pack->object, data, len); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, - (char *)pack, pack_size); - free (pack); -} - -static int -read_and_send_commit (CcnetProcessor *processor, const char *commit_id) -{ - USE_PRIV; - - if (seaf_obj_store_async_read (seaf->commit_mgr->obj_store, - priv->reader_id, - commit_id) < 0) { - seaf_warning ("[putcommit] Failed to start read of %s.\n", commit_id); - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - return 0; -} - -static void -read_done_cb (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - - if (!res->success) { - seaf_warning ("[putcommit] Failed to read %s.\n", res->obj_id); - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - send_commit (processor, res->obj_id, res->data, res->len); - - seaf_debug ("Send commit %.8s.\n", res->obj_id); -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - priv->reader_id = - seaf_obj_store_register_async_read (seaf->commit_mgr->obj_store, - priv->repo_id, - priv->repo_version, - read_done_cb, - processor); - priv->registered = TRUE; - - read_and_send_commit (processor, priv->head_commit_id); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -put_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - char *head_id; - char *session_token; - USE_PRIV; - - if (argc < 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - head_id = argv[0]; - session_token = argv[1]; - - if (strlen(head_id) != 40) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->head_commit_id, head_id, 40); - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - - return 0; -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/putcommit-v3-proc.h b/server/processors/putcommit-v3-proc.h deleted file mode 100644 index afe3f500..00000000 --- a/server/processors/putcommit-v3-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCOMMIT_V3_PROC_H -#define SEAFILE_PUTCOMMIT_V3_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTCOMMIT_V3_PROC (seafile_putcommit_v3_proc_get_type ()) -#define SEAFILE_PUTCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCOMMIT_V3_PROC, SeafilePutcommitV3Proc)) -#define SEAFILE_IS_PUTCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCOMMIT_V3_PROC)) -#define SEAFILE_PUTCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCOMMIT_V3_PROC, SeafilePutcommitV3ProcClass)) -#define IS_SEAFILE_PUTCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCOMMIT_V3_PROC)) -#define SEAFILE_PUTCOMMIT_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCOMMIT_V3_PROC, SeafilePutcommitV3ProcClass)) - -typedef struct _SeafilePutcommitV3Proc SeafilePutcommitV3Proc; -typedef struct _SeafilePutcommitV3ProcClass SeafilePutcommitV3ProcClass; - -struct _SeafilePutcommitV3Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcommitV3ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putcommit_v3_proc_get_type (); - -#endif diff --git a/server/processors/putcs-proc.c b/server/processors/putcs-proc.c deleted file mode 100644 index 84975e1e..00000000 --- a/server/processors/putcs-proc.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include "seafile-session.h" -#include "chunkserv-mgr.h" -#include "putcs-proc.h" - -G_DEFINE_TYPE (SeafilePutcsProc, seafile_putcs_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); - -static void -release_resource(CcnetProcessor *processor) -{ - CCNET_PROCESSOR_CLASS (seafile_putcs_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putcs_proc_class_init (SeafilePutcsProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putcs-proc"; - proc_class->start = start; - proc_class->release_resource = release_resource; -} - -static void -seafile_putcs_proc_init (SeafilePutcsProc *processor) -{ -} - - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - GString *buf = g_string_new(""); - GList *chunk_servers, *cs; - char *cs_id; - - chunk_servers = seaf_cs_manager_get_chunk_servers (seaf->cs_mgr); - cs = chunk_servers; - while (cs) { - cs_id = cs->data; - - /* The public ip of myself is not set. We just send my id to - * clients, they should already have my ip address. - */ - if (strcmp (cs_id, seaf->session->base.id) == 0) { - g_string_append_printf (buf, "%s\n", cs_id); - goto next; - } - - CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, cs_id); - if (!peer || !peer->public_addr) { - /* do nothing */ - if (peer) - g_object_unref (peer); - } else { - g_string_append_printf (buf, "%s %s:%d\n", cs_id, - peer->public_addr, - peer->public_port); - g_object_unref (peer); - } - next: - cs = cs->next; - } - g_list_free (chunk_servers); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, buf->str, buf->len+1); - g_string_free (buf, TRUE); - - ccnet_processor_done (processor, TRUE); - - return 0; -} diff --git a/server/processors/putcs-proc.h b/server/processors/putcs-proc.h deleted file mode 100644 index b9bc9dd3..00000000 --- a/server/processors/putcs-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCS_PROC_H -#define SEAFILE_PUTCS_PROC_H - -#include -#include - -#define SEAFILE_TYPE_PUTCS_PROC (seafile_putcs_proc_get_type ()) -#define SEAFILE_PUTCS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCS_PROC, SeafilePutcsProc)) -#define SEAFILE_IS_PUTCS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCS_PROC)) -#define SEAFILE_PUTCS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCS_PROC, SeafilePutcsProcClass)) -#define IS_SEAFILE_PUTCS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCS_PROC)) -#define SEAFILE_PUTCS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCS_PROC, SeafilePutcsProcClass)) - -typedef struct _SeafilePutcsProc SeafilePutcsProc; -typedef struct _SeafilePutcsProcClass SeafilePutcsProcClass; - -struct _SeafilePutcsProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcsProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putcs_proc_get_type (); - -#endif - diff --git a/server/processors/putcs-v2-proc.c b/server/processors/putcs-v2-proc.c deleted file mode 100644 index be564439..00000000 --- a/server/processors/putcs-v2-proc.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include "seafile-session.h" -#include "putcs-v2-proc.h" - -G_DEFINE_TYPE (SeafilePutcsV2Proc, seafile_putcs_v2_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); - -static void -release_resource(CcnetProcessor *processor) -{ - CCNET_PROCESSOR_CLASS (seafile_putcs_v2_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putcs_v2_proc_class_init (SeafilePutcsV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putcs-v2-proc"; - proc_class->start = start; - proc_class->release_resource = release_resource; -} - -static void -seafile_putcs_v2_proc_init (SeafilePutcsV2Proc *processor) -{ -} - -static char * -hostname_from_service_url (const char *service_url) -{ - const char *start, *end; - - start = strstr (service_url, "//"); - if (!start) - start = service_url; - else - start += 2; - - end = strchr (start, ':'); - if (end) - return g_strndup (start, end - start); - - end = strchr (start, '/'); - if (!end) - return g_strdup (start); - else - return g_strndup (start, end - start); -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *hostname; - GString *buf = g_string_new(""); - - hostname = hostname_from_service_url (seaf->session->base.service_url); - g_string_printf (buf, "%s:%d\n", hostname, seaf->listen_mgr->port); - g_free (hostname); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, buf->str, buf->len+1); - g_string_free (buf, TRUE); - - ccnet_processor_done (processor, TRUE); - - return 0; -} diff --git a/server/processors/putcs-v2-proc.h b/server/processors/putcs-v2-proc.h deleted file mode 100644 index 306791a2..00000000 --- a/server/processors/putcs-v2-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTCS_V2_PROC_H -#define SEAFILE_PUTCS_V2_PROC_H - -#include -#include - -#define SEAFILE_TYPE_PUTCS_V2_PROC (seafile_putcs_v2_proc_get_type ()) -#define SEAFILE_PUTCS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTCS_V2_PROC, SeafilePutcsV2Proc)) -#define SEAFILE_IS_PUTCS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTCS_V2_PROC)) -#define SEAFILE_PUTCS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTCS_V2_PROC, SeafilePutcsV2ProcClass)) -#define IS_SEAFILE_PUTCS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTCS_V2_PROC)) -#define SEAFILE_PUTCS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTCS_V2_PROC, SeafilePutcsV2ProcClass)) - -typedef struct _SeafilePutcsV2Proc SeafilePutcsV2Proc; -typedef struct _SeafilePutcsV2ProcClass SeafilePutcsV2ProcClass; - -struct _SeafilePutcsV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutcsV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putcs_v2_proc_get_type (); - -#endif - diff --git a/server/processors/putfs-proc.c b/server/processors/putfs-proc.c deleted file mode 100644 index 413f08b3..00000000 --- a/server/processors/putfs-proc.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include -#include - -#include -#include "utils.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "fs-mgr.h" -#include "processors/objecttx-common.h" -#include "putfs-proc.h" - -typedef struct { - guint32 reader_id; - gboolean registered; - - /* Used for getting repo info */ - char repo_id[37]; - char store_id[37]; - int repo_version; - gboolean success; -} PutfsProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTFS_PROC, PutfsProcPriv)) - -#define USE_PRIV \ - PutfsProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafilePutfsProc, seafile_putfs_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void -read_done_cb (OSAsyncResult *res, void *cb_data); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->registered) - seaf_obj_store_unregister_async_read (seaf->fs_mgr->obj_store, - priv->reader_id); - - CCNET_PROCESSOR_CLASS (seafile_putfs_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putfs_proc_class_init (SeafilePutfsProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putfs-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (PutfsProcPriv)); -} - -static void -seafile_putfs_proc_init (SeafilePutfsProc *processor) -{ -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - memcpy (priv->store_id, repo->store_id, 36); - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - priv->registered = TRUE; - priv->reader_id = - seaf_obj_store_register_async_read (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - read_done_cb, - processor); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *session_token; - char repo_id[37]; - USE_PRIV; - - if (argc != 1) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[0]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, repo_id) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, repo_id, 36); - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - - return 0; -} - -static void -read_done_cb (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - ObjectPack *pack = NULL; - int pack_size; - - if (!res->success) { - seaf_warning ("[putfs] Failed to read %s.\n", res->obj_id); - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - pack_size = sizeof(ObjectPack) + res->len; - pack = malloc (pack_size); - memcpy (pack->id, res->obj_id, 41); - memcpy (pack->object, res->data, res->len); - - if (pack_size <= MAX_OBJ_SEG_SIZE) { - ccnet_processor_send_response (processor, SC_OBJECT, SS_OBJECT, - (char *)pack, pack_size); - } else { - int offset, n; - - offset = 0; - while (offset < pack_size) { - n = MIN(pack_size - offset, MAX_OBJ_SEG_SIZE); - - if (offset + n < pack_size) { - ccnet_processor_send_response (processor, - SC_OBJ_SEG, SS_OBJ_SEG, - (char *)pack + offset, n); - } else { - ccnet_processor_send_response (processor, - SC_OBJ_SEG_END, SS_OBJ_SEG_END, - (char *)pack + offset, n); - } - seaf_debug ("[putfs] Sent object %s segment\n", - res->obj_id, pack_size, offset, n); - offset += n; - } - } - - free (pack); - - seaf_debug ("Send fs object %.8s.\n", res->obj_id); -} - -static gboolean -send_fs_object (CcnetProcessor *processor, char *object_id) -{ - USE_PRIV; - - if (seaf_obj_store_async_read (seaf->fs_mgr->obj_store, - priv->reader_id, - object_id) < 0) { - seaf_warning ("[putfs] Failed to start async read of %s.\n", object_id); - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return FALSE; - } - - return TRUE; -} - -static void -send_fs_objects (CcnetProcessor *processor, char *content, int clen) -{ - char *object_id; - int n_objects; - int i; - - if (clen % 41 != 1 || content[clen-1] != '\0') { - seaf_warning ("[putfs] Bad fs object list.\n"); - ccnet_processor_send_response (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - n_objects = clen/41; - - object_id = content; - for (i = 0; i < n_objects; ++i) { - object_id[40] = '\0'; - if (send_fs_object (processor, object_id) == FALSE) - return; - object_id += 41; - } -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - if (strncmp(code, SC_GET_OBJECT, 3) == 0) { - send_fs_objects (processor, content, clen); - } else if (strncmp(code, SC_END, 3) == 0) { - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("[putfs] Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} diff --git a/server/processors/putfs-proc.h b/server/processors/putfs-proc.h deleted file mode 100644 index d8a46341..00000000 --- a/server/processors/putfs-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTFS_PROC_H -#define SEAFILE_PUTFS_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTFS_PROC (seafile_putfs_proc_get_type ()) -#define SEAFILE_PUTFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTFS_PROC, SeafilePutfsProc)) -#define SEAFILE_IS_PUTFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTFS_PROC)) -#define SEAFILE_PUTFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTFS_PROC, SeafilePutfsProcClass)) -#define IS_SEAFILE_PUTFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTFS_PROC)) -#define SEAFILE_PUTFS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTFS_PROC, SeafilePutfsProcClass)) - -typedef struct _SeafilePutfsProc SeafilePutfsProc; -typedef struct _SeafilePutfsProcClass SeafilePutfsProcClass; - -struct _SeafilePutfsProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutfsProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putfs_proc_get_type (); - -#endif - diff --git a/server/processors/putfs-v2-proc.c b/server/processors/putfs-v2-proc.c deleted file mode 100644 index 931bbedd..00000000 --- a/server/processors/putfs-v2-proc.c +++ /dev/null @@ -1,500 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include -#include - -#include -#include "utils.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "fs-mgr.h" -#include "processors/objecttx-common.h" -#include "putfs-v2-proc.h" - -#include "diff-simple.h" - -enum { - CHECK_OBJECT_LIST = 0, - SEND_OBJECTS, -}; - -typedef struct { - char server_head[41]; - char client_head[41]; - - /* Used for getting repo info */ - char repo_id[37]; - char store_id[37]; - int repo_version; - gboolean success; - - GList *send_obj_list; - - gboolean registered; - guint32 reader_id; - - gboolean calc_success; -} SeafilePutfsProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTFS_V2_PROC, SeafilePutfsProcPriv)) - -#define USE_PRIV \ - SeafilePutfsProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafilePutfsV2Proc, seafile_putfs_v2_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void * -calculate_send_object_list (void *vdata); - -static void -calculate_send_object_list_done (void *vdata); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - string_list_free (priv->send_obj_list); - - seaf_obj_store_unregister_async_read (seaf->fs_mgr->obj_store, - priv->reader_id); - - CCNET_PROCESSOR_CLASS (seafile_putfs_v2_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putfs_v2_proc_class_init (SeafilePutfsV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "putfs-v2-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof(SeafilePutfsProcPriv)); -} - -static void -seafile_putfs_v2_proc_init (SeafilePutfsV2Proc *processor) -{ -} - -static void -fs_object_read_cb (OSAsyncResult *res, void *data); - -static void -register_async_io (CcnetProcessor *processor) -{ - USE_PRIV; - - priv->registered = TRUE; - priv->reader_id = seaf_obj_store_register_async_read (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - fs_object_read_cb, - processor); -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - memcpy (priv->store_id, repo->store_id, 36); - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - register_async_io (processor); - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - calculate_send_object_list, - calculate_send_object_list_done, - processor); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *session_token; - USE_PRIV; - - if (argc < 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[0]; - - if (strlen(argv[1]) != 40) { - ccnet_processor_send_response (processor, - SC_BAD_ARGS, SS_BAD_ARGS, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - memcpy (priv->server_head, argv[1], 40); - - if (argc >= 3) { - if (strlen(argv[2]) != 40) { - ccnet_processor_send_response (processor, - SC_BAD_ARGS, SS_BAD_ARGS, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - memcpy (priv->client_head, argv[2], 40); - } - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) == 0) { - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -/* Calculate send object list */ - -inline static gboolean -dirent_same (SeafDirent *denta, SeafDirent *dentb) -{ - return (strcmp (dentb->id, denta->id) == 0 && denta->mode == dentb->mode); -} - -static int -collect_file_ids (int n, const char *basedir, SeafDirent *files[], void *data) -{ - SeafDirent *file1 = files[0]; - SeafDirent *file2 = files[1]; - GList **pret = data; - - if (file1 && (!file2 || !dirent_same (file1, file2)) && - strcmp (file1->id, EMPTY_SHA1) != 0) - *pret = g_list_prepend (*pret, g_strdup(file1->id)); - - return 0; -} - -static int -collect_dir_ids (int n, const char *basedir, SeafDirent *dirs[], void *data, - gboolean *recurse) -{ - SeafDirent *dir1 = dirs[0]; - SeafDirent *dir2 = dirs[1]; - GList **pret = data; - - if (dir1 && (!dir2 || !dirent_same (dir1, dir2)) && - strcmp (dir1->id, EMPTY_SHA1) != 0) - *pret = g_list_prepend (*pret, g_strdup(dir1->id)); - - return 0; -} - -static void * -calculate_send_object_list (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - SeafCommit *remote_head = NULL, *master_head = NULL; - char *remote_head_root; - - master_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - priv->repo_id, priv->repo_version, - priv->server_head); - if (!master_head) { - seaf_warning ("Server head commit %s:%s not found.\n", - priv->repo_id, priv->server_head); - priv->calc_success = FALSE; - goto out; - } - - if (priv->client_head[0] != 0) { - remote_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - priv->repo_id, - priv->repo_version, - priv->client_head); - if (!remote_head) { - seaf_warning ("Remote head commit %s:%s not found.\n", - priv->repo_id, priv->client_head); - priv->calc_success = FALSE; - goto out; - } - remote_head_root = remote_head->root_id; - } else - remote_head_root = EMPTY_SHA1; - - /* Diff won't traverse the root object itself. */ - if (strcmp (remote_head_root, master_head->root_id) != 0 && - strcmp (master_head->root_id, EMPTY_SHA1) != 0) - priv->send_obj_list = g_list_prepend (priv->send_obj_list, - g_strdup(master_head->root_id)); - - DiffOptions opts; - memset (&opts, 0, sizeof(opts)); - memcpy (opts.store_id, priv->store_id, 36); - opts.version = priv->repo_version; - opts.file_cb = collect_file_ids; - opts.dir_cb = collect_dir_ids; - opts.data = &priv->send_obj_list; - - const char *trees[2]; - trees[0] = master_head->root_id; - trees[1] = remote_head_root; - if (diff_trees (2, trees, &opts) < 0) { - seaf_warning ("Failed to diff remote and master head for repo %.8s.\n", - priv->repo_id); - priv->calc_success = FALSE; - } - - priv->calc_success = TRUE; - -out: - seaf_commit_unref (remote_head); - seaf_commit_unref (master_head); - return vdata; -} - -#define OBJECT_LIST_SEGMENT_N 1000 -#define OBJECT_LIST_SEGMENT_LEN 40 * 1000 - -static void -send_object_list_segments (CcnetProcessor *processor) -{ - USE_PRIV; - char buf[OBJECT_LIST_SEGMENT_LEN]; - - int i = 0; - char *p = buf; - char *obj_id; - while (priv->send_obj_list != NULL) { - obj_id = priv->send_obj_list->data; - priv->send_obj_list = g_list_delete_link (priv->send_obj_list, - priv->send_obj_list); - - memcpy (p, obj_id, 40); - p += 40; - g_free (obj_id); - if (++i == OBJECT_LIST_SEGMENT_N) { - seaf_debug ("Send %d object ids.\n", i); - ccnet_processor_send_response (processor, - SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG, - buf, i * 40); - i = 0; - p = buf; - } - } - - if (i > 0) { - seaf_debug ("Send %d object ids.\n", i); - ccnet_processor_send_response (processor, - SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG, - buf, i * 40); - } - - ccnet_processor_send_response (processor, - SC_OBJ_LIST_SEG_END, SS_OBJ_LIST_SEG_END, - NULL, 0); -} - -static void -calculate_send_object_list_done (void *vdata) -{ - CcnetProcessor *processor = vdata; - USE_PRIV; - - if (!priv->calc_success) { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - if (priv->send_obj_list == NULL) { - seaf_message ("No fs objects to put. Done.\n"); - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - return; - } - - send_object_list_segments (processor); - - processor->state = SEND_OBJECTS; -} - -/* Send objects */ - -static void -send_fs_object (CcnetProcessor *processor, - const char *object_id, char *data, int len) -{ - ObjectPack *pack = NULL; - int pack_size; - - pack_size = sizeof(ObjectPack) + len; - pack = malloc (pack_size); - memcpy (pack->id, object_id, 41); - memcpy (pack->object, data, len); - - if (pack_size <= MAX_OBJ_SEG_SIZE) { - ccnet_processor_send_response (processor, SC_OBJECT, SS_OBJECT, - (char *)pack, pack_size); - } else { - int offset, n; - - offset = 0; - while (offset < pack_size) { - n = MIN(pack_size - offset, MAX_OBJ_SEG_SIZE); - - if (offset + n < pack_size) { - ccnet_processor_send_response (processor, - SC_OBJ_SEG, SS_OBJ_SEG, - (char *)pack + offset, n); - } else { - ccnet_processor_send_response (processor, - SC_OBJ_SEG_END, SS_OBJ_SEG_END, - (char *)pack + offset, n); - } - - seaf_debug ("Sent object %s segment\n", - object_id, pack_size, offset, n); - - offset += n; - } - } - - seaf_debug ("Send fs object %.8s.\n", object_id); - - free (pack); -} - -static void -fs_object_read_cb (OSAsyncResult *res, void *data) -{ - CcnetProcessor *processor = data; - - if (!res->success) { - seaf_warning ("Failed to read fs object %.8s.\n", res->obj_id); - ccnet_processor_send_response (processor, SC_NOT_FOUND, SS_NOT_FOUND, - res->obj_id, 41); - ccnet_processor_done (processor, FALSE); - return; - } - - send_fs_object (processor, res->obj_id, res->data, res->len); -} - -static void -read_fs_object (CcnetProcessor *processor, const char *obj_id) -{ - USE_PRIV; - - seaf_obj_store_async_read (seaf->fs_mgr->obj_store, - priv->reader_id, - obj_id); -} - -static void -process_object_list_segment (CcnetProcessor *processor, char *content, int clen) -{ - int n, i; - char *p; - - if (clen % 40 != 0) { - seaf_warning ("Invalid object list segment length %d.\n", clen); - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - n = clen/40; - p = content; - - seaf_debug ("%d objects are needed by the client.\n", n); - - char *obj_id; - for (i = 0; i < n; ++i) { - obj_id = g_strndup(p, 40); - read_fs_object (processor, obj_id); - g_free (obj_id); - p += 40; - } -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case SEND_OBJECTS: - if (strncmp (code, SC_OBJ_LIST_SEG, 3) == 0) { - process_object_list_segment (processor, content, clen); - return; - } else if (strncmp (code, SC_END, 3) == 0) { - seaf_debug ("All objects received. Done.\n"); - ccnet_processor_done (processor, TRUE); - return; - } - break; - default: - g_return_if_reached (); - } - - seaf_warning ("Bad update: %s %s.\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/putfs-v2-proc.h b/server/processors/putfs-v2-proc.h deleted file mode 100644 index b17cf812..00000000 --- a/server/processors/putfs-v2-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTFS_V2_PROC_H -#define SEAFILE_PUTFS_V2_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTFS_V2_PROC (seafile_putfs_v2_proc_get_type ()) -#define SEAFILE_PUTFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTFS_V2_PROC, SeafilePutfsV2Proc)) -#define SEAFILE_IS_PUTFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTFS_V2_PROC)) -#define SEAFILE_PUTFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTFS_V2_PROC, SeafilePutfsV2ProcClass)) -#define IS_SEAFILE_PUTFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTFS_V2_PROC)) -#define SEAFILE_PUTFS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTFS_V2_PROC, SeafilePutfsV2ProcClass)) - -typedef struct _SeafilePutfsV2Proc SeafilePutfsV2Proc; -typedef struct _SeafilePutfsV2ProcClass SeafilePutfsV2ProcClass; - -struct _SeafilePutfsV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutfsV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putfs_v2_proc_get_type (); - -#endif - diff --git a/server/processors/putrepoemailtoken-proc.c b/server/processors/putrepoemailtoken-proc.c deleted file mode 100644 index f4432956..00000000 --- a/server/processors/putrepoemailtoken-proc.c +++ /dev/null @@ -1,176 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" -#include "ccnet.h" -#include "log.h" -#include "seafile-session.h" -#include "repo-mgr.h" - -#include "putrepoemailtoken-proc.h" - -#define SC_REPO_EMAIL "300" -#define SS_REPO_EMAIL "email" -#define SC_REPO_TOKEN "301" -#define SS_REPO_TOKEN "token" -#define SC_SERVER_ERROR "400" -#define SS_SERVER_ERROR "server error" -#define SC_ACCESS_DENIED "401" -#define SS_ACCESS_DENIED "access denied" -#define SC_NO_REPO "402" -#define SS_NO_REPO "repo does not exist" - -typedef struct { - char *repo_id; - char *email; - char *token; - char *rsp_code; -} SeafilePutrepoemailtokenProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC, SeafilePutrepoemailtokenProcPriv)) - -#define USE_PRIV \ - SeafilePutrepoemailtokenProcPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (SeafilePutrepoemailtokenProc, seafile_putrepoemailtoken_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void get_email_cb (void *result, void *data, GError *error); -static void *get_repo_token (void *vprocessor); -static void get_repo_token_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - g_free (priv->email); - g_free (priv->token); - - CCNET_PROCESSOR_CLASS (seafile_putrepoemailtoken_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_putrepoemailtoken_proc_class_init (SeafilePutrepoemailtokenProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafilePutrepoemailtokenProcPriv)); -} - -static void -seafile_putrepoemailtoken_proc_init (SeafilePutrepoemailtokenProc *processor) -{ -} - - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - - if (argc != 1) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - priv->repo_id = g_strdup(argv[0]); - ccnet_get_binding_email_async (seaf->async_ccnetrpc_client_t, processor->peer_id, - get_email_cb, processor); - - return 0; -} - -static void -get_email_cb (void *result, void *data, GError *error) -{ - char *email = result; - CcnetProcessor *processor = data; - USE_PRIV; - - if (!email) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } else { - priv->email = g_strdup(email); - ccnet_processor_thread_create (processor, - get_repo_token, - get_repo_token_done, - processor); - } -} - -static void * -get_repo_token (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - priv->rsp_code = SC_OK; - if (!seaf_repo_manager_repo_exists (seaf->repo_mgr, priv->repo_id)) { - priv->rsp_code = SC_NO_REPO; - - } else { - priv->token = seaf_repo_manager_get_repo_token_nonnull ( - seaf->repo_mgr, priv->repo_id, priv->email); - - if (!priv->token) - priv->rsp_code = SC_SERVER_ERROR; - } - - return vprocessor; -} - -static void -get_repo_token_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_NO_REPO) == 0) { - ccnet_processor_send_response (processor, SC_NO_REPO, - SS_NO_REPO, NULL, 0); - ccnet_processor_done (processor, FALSE); - - } else if (strcmp (priv->rsp_code, SC_SERVER_ERROR) == 0) { - ccnet_processor_send_response (processor, SC_SERVER_ERROR, - SS_SERVER_ERROR, NULL, 0); - ccnet_processor_done (processor, FALSE); - } else { - ccnet_processor_send_response (processor, - SC_REPO_EMAIL, SS_REPO_EMAIL, - priv->email, - strlen(priv->email) + 1); - } -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - if (strcmp (code, SC_REPO_TOKEN) == 0) { - ccnet_processor_send_response (processor, - SC_REPO_TOKEN, SS_REPO_TOKEN, - priv->token, - strlen(priv->token) + 1); - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("bad update, %s : %s\n", code, code_msg); - ccnet_processor_done (processor, FALSE); - } - -} diff --git a/server/processors/putrepoemailtoken-proc.h b/server/processors/putrepoemailtoken-proc.h deleted file mode 100644 index 77d90d36..00000000 --- a/server/processors/putrepoemailtoken-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_PUTREPOEMAILTOKEN_PROC_H -#define SEAFILE_PUTREPOEMAILTOKEN_PROC_H - -#include - - -#define SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC (seafile_putrepoemailtoken_proc_get_type ()) -#define SEAFILE_PUTREPOEMAILTOKEN_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC, SeafilePutrepoemailtokenProc)) -#define SEAFILE_IS_PUTREPOEMAILTOKEN_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC)) -#define SEAFILE_PUTREPOEMAILTOKEN_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC, SeafilePutrepoemailtokenProcClass)) -#define IS_SEAFILE_PUTREPOEMAILTOKEN_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC)) -#define SEAFILE_PUTREPOEMAILTOKEN_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_PUTREPOEMAILTOKEN_PROC, SeafilePutrepoemailtokenProcClass)) - -typedef struct _SeafilePutrepoemailtokenProc SeafilePutrepoemailtokenProc; -typedef struct _SeafilePutrepoemailtokenProcClass SeafilePutrepoemailtokenProcClass; - -struct _SeafilePutrepoemailtokenProc { - CcnetProcessor parent_instance; -}; - -struct _SeafilePutrepoemailtokenProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_putrepoemailtoken_proc_get_type (); - -#endif - diff --git a/server/processors/recvblock-proc.c b/server/processors/recvblock-proc.c deleted file mode 100644 index 282116d3..00000000 --- a/server/processors/recvblock-proc.c +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -#include -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "fs-mgr.h" -#include "block-mgr.h" -#include "recvblock-proc.h" -#include "processors/blocktx-common.h" - -#include "log.h" - -enum { - PREPARE, - READY, -}; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVBLOCK_PROC, BlockProcPriv)) - -#define USE_PRIV \ - BlockProcPriv *priv = GET_PRIV(processor); - -static int block_proc_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void recv_block_cb (CEvent *event, void *vprocessor); -static void release_resource (CcnetProcessor *processor); - -G_DEFINE_TYPE (SeafileRecvblockProc, seafile_recvblock_proc, CCNET_TYPE_PROCESSOR) - -static void -seafile_recvblock_proc_class_init (SeafileRecvblockProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvblock-proc"; - proc_class->start = block_proc_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (BlockProcPriv)); -} - -static void -seafile_recvblock_proc_init (SeafileRecvblockProc *processor) -{ -} - -static void -recv_block_cb (CEvent *event, void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - BlockResponse *blk_rsp = event->data; - char buf[32]; - int len; - - len = snprintf (buf, 32, "%d", blk_rsp->block_idx); - ccnet_processor_send_response (processor, SC_ACK, SS_ACK, - buf, len + 1); - - g_free (blk_rsp); -} - -#include "processors/blocktx-common-impl.h" - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case PREPARE: - if (memcmp (code, SC_BLOCKLIST, 3) == 0) { - process_block_list (processor, content, clen); - return; - } else if (memcmp (code, SC_GET_PORT, 3) == 0) { - send_port (processor); - return; - } - break; - } - - seaf_warning ("Bad code: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, SC_BAD_UPDATE_CODE, - SS_BAD_UPDATE_CODE, NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/recvblock-proc.h b/server/processors/recvblock-proc.h deleted file mode 100644 index 3786bd2e..00000000 --- a/server/processors/recvblock-proc.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVBLOCK_PROC_H -#define SEAFILE_RECVBLOCK_PROC_H - -#include - -#define SEAFILE_TYPE_RECVBLOCK_PROC (seafile_recvblock_proc_get_type ()) -#define SEAFILE_RECVBLOCK_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVBLOCK_PROC, SeafileRecvblockProc)) -#define SEAFILE_IS_RECVBLOCK_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVBLOCK_PROC)) -#define SEAFILE_RECVBLOCK_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVBLOCK_PROC, SeafileRecvblockProcClass)) -#define IS_SEAFILE_RECVBLOCK_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVBLOCK_PROC)) -#define SEAFILE_RECVBLOCK_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVBLOCK_PROC, SeafileRecvblockProcClass)) - -typedef struct _SeafileRecvblockProc SeafileRecvblockProc; -typedef struct _SeafileRecvblockProcClass SeafileRecvblockProcClass; - -struct _SeafileRecvblockProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvblockProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvblock_proc_get_type (); - -#endif diff --git a/server/processors/recvblock-v2-proc.c b/server/processors/recvblock-v2-proc.c deleted file mode 100644 index 04d49875..00000000 --- a/server/processors/recvblock-v2-proc.c +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -#include -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "fs-mgr.h" -#include "block-mgr.h" -#include "recvblock-v2-proc.h" - -#include "log.h" - -enum { - PREPARE, - READY, -}; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVBLOCK_V2_PROC, BlockProcPriv)) - -#define USE_PRIV \ - BlockProcPriv *priv = GET_PRIV(processor); - -static int block_proc_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void recv_block_cb (CEvent *event, void *vprocessor); -static void release_resource (CcnetProcessor *processor); - -G_DEFINE_TYPE (SeafileRecvblockV2Proc, seafile_recvblock_v2_proc, CCNET_TYPE_PROCESSOR) - -#define RECVBLOCK_PROC -#include "processors/blocktx-common-impl-v2.h" - -static void -seafile_recvblock_v2_proc_class_init (SeafileRecvblockV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvblock-v2-proc"; - proc_class->start = block_proc_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (BlockProcPriv)); -} - -static void -seafile_recvblock_v2_proc_init (SeafileRecvblockV2Proc *processor) -{ -} - -static int -block_proc_start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - if (verify_session_token (processor, priv->repo_id, argc, argv) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - prepare_thread_data(processor, recv_blocks, recv_block_cb, priv->repo_id); - ccnet_processor_send_response (processor, "200", "OK", NULL, 0); - - return 0; -} - -static void -release_resource (CcnetProcessor *processor) -{ - release_thread (processor); - - CCNET_PROCESSOR_CLASS(seafile_recvblock_v2_proc_parent_class)->release_resource (processor); -} - -static void -recv_block_cb (CEvent *event, void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - BlockResponse *blk_rsp = event->data; - char buf[32]; - int len; - - len = snprintf (buf, 32, "%d", blk_rsp->block_idx); - ccnet_processor_send_response (processor, SC_ACK, SS_ACK, - buf, len + 1); - - g_free (blk_rsp); -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - - switch (priv->tdata->state) { - case PREPARE: - if (memcmp (code, SC_BLOCKLIST, 3) == 0) { - process_block_list (processor, content, clen); - return; - } else if (memcmp (code, SC_GET_PORT, 3) == 0) { - send_port (processor); - return; - } - break; - } - - seaf_warning ("Bad code: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, SC_BAD_UPDATE_CODE, - SS_BAD_UPDATE_CODE, NULL, 0); - ccnet_processor_done (processor, FALSE); -} diff --git a/server/processors/recvblock-v2-proc.h b/server/processors/recvblock-v2-proc.h deleted file mode 100644 index 8718c5d4..00000000 --- a/server/processors/recvblock-v2-proc.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVBLOCK_V2_PROC_H -#define SEAFILE_RECVBLOCK_V2_PROC_H - -#include - -#define SEAFILE_TYPE_RECVBLOCK_V2_PROC (seafile_recvblock_v2_proc_get_type ()) -#define SEAFILE_RECVBLOCK_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVBLOCK_V2_PROC, SeafileRecvblockV2Proc)) -#define SEAFILE_IS_RECVBLOCK_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVBLOCK_V2_PROC)) -#define SEAFILE_RECVBLOCK_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVBLOCK_V2_PROC, SeafileRecvblockV2ProcClass)) -#define IS_SEAFILE_RECVBLOCK_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVBLOCK_V2_PROC)) -#define SEAFILE_RECVBLOCK_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVBLOCK_V2_PROC, SeafileRecvblockV2ProcClass)) - -typedef struct _SeafileRecvblockV2Proc SeafileRecvblockV2Proc; -typedef struct _SeafileRecvblockV2ProcClass SeafileRecvblockV2ProcClass; - -struct _SeafileRecvblockV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvblockV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvblock_v2_proc_get_type (); - -#endif diff --git a/server/processors/recvbranch-proc.c b/server/processors/recvbranch-proc.c deleted file mode 100644 index 1c55078d..00000000 --- a/server/processors/recvbranch-proc.c +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include - -#include "seafile-session.h" -#include "recvbranch-proc.h" -#include "vc-common.h" - -#include "log.h" - -#define SC_BAD_COMMIT "401" -#define SS_BAD_COMMIT "Commit does not exist" -#define SC_NOT_FF "402" -#define SS_NOT_FF "Not fast forward" -#define SC_QUOTA_ERROR "403" -#define SS_QUOTA_ERROR "Failed to get quota" -#define SC_QUOTA_FULL "404" -#define SS_QUOTA_FULL "storage for the repo's owner is full" -#define SC_SERVER_ERROR "405" -#define SS_SERVER_ERROR "Internal server error" -#define SC_BAD_REPO "406" -#define SS_BAD_REPO "Repo does not exist" -#define SC_BAD_BRANCH "407" -#define SS_BAD_BRANCH "Branch does not exist" -#define SC_ACCESS_DENIED "410" -#define SS_ACCESS_DENIED "Access denied" - -typedef struct { - char repo_id[37]; - char *branch_name; - char new_head[41]; - char *email; - - char *rsp_code; - char *rsp_msg; -} SeafileRecvbranchProcPriv; - -G_DEFINE_TYPE (SeafileRecvbranchProc, seafile_recvbranch_proc, CCNET_TYPE_PROCESSOR) - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVBRANCH_PROC, SeafileRecvbranchProcPriv)) - -#define USE_PRIV \ - SeafileRecvbranchProcPriv *priv = GET_PRIV(processor); - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void *update_repo (void *vprocessor); -static void thread_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - - CCNET_PROCESSOR_CLASS (seafile_recvbranch_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_recvbranch_proc_class_init (SeafileRecvbranchProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvbranch-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileRecvbranchProcPriv)); -} - -static void -seafile_recvbranch_proc_init (SeafileRecvbranchProc *processor) -{ -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - char *session_token; - - if (argc != 4) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (!is_uuid_valid(argv[0]) || strlen(argv[2]) != 40) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - memcpy (priv->repo_id, argv[0], 36); - memcpy (priv->new_head, argv[2], 40); - priv->branch_name = g_strdup(argv[1]); - session_token = argv[3]; - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, NULL) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - update_repo, - thread_done, - processor); - - return 0; -} - - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ -} - -static void * -update_repo (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - char *repo_id, *new_head; - SeafRepo *repo = NULL; - SeafBranch *branch = NULL; - SeafCommit *commit = NULL; - char old_commit_id[41]; - - repo_id = priv->repo_id; - new_head = priv->new_head; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - /* repo is deleted on server */ - priv->rsp_code = g_strdup (SC_BAD_REPO); - priv->rsp_msg = g_strdup (SC_BAD_REPO); - goto out; - - } - - /* Since this is the last step of upload procedure, commit should exist. */ - commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - new_head); - if (!commit) { - priv->rsp_code = g_strdup (SC_BAD_COMMIT); - priv->rsp_msg = g_strdup (SS_BAD_COMMIT); - goto out; - } - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { - priv->rsp_code = g_strdup(SC_QUOTA_FULL); - priv->rsp_msg = g_strdup(SS_QUOTA_FULL); - goto out; - } - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); - if (!branch) { - priv->rsp_code = g_strdup (SC_BAD_BRANCH); - priv->rsp_msg = g_strdup (SS_BAD_BRANCH); - goto out; - } - - /* If branch exists, check fast forward. */ - if (strcmp (new_head, branch->commit_id) != 0 && - !is_fast_forward (repo->id, repo->version, new_head, branch->commit_id)) { - seaf_warning ("Upload is not fast forward. Refusing.\n"); - - seaf_repo_unref (repo); - seaf_commit_unref (commit); - seaf_branch_unref (branch); - - priv->rsp_code = g_strdup (SC_NOT_FF); - priv->rsp_msg = g_strdup (SS_NOT_FF); - return vprocessor; - } - - /* Update branch. In case of concurrent update, we must ensure atomicity. - */ - memcpy (old_commit_id, branch->commit_id, 41); - seaf_branch_set_commit (branch, commit->commit_id); - if (seaf_branch_manager_test_and_update_branch (seaf->branch_mgr, - branch, old_commit_id) < 0) - { - priv->rsp_code = g_strdup (SC_NOT_FF); - priv->rsp_msg = g_strdup (SS_NOT_FF); - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (seaf->repo_mgr, repo_id); - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, repo_id, NULL); - -out: - if (repo) seaf_repo_unref (repo); - if (commit) seaf_commit_unref (commit); - if (branch) seaf_branch_unref (branch); - - if (!priv->rsp_code) { - priv->rsp_code = g_strdup (SC_OK); - priv->rsp_msg = g_strdup (SS_OK); - } - - return vprocessor; -} - -static void -thread_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_OK) == 0) { - /* Repo is updated, schedule repo size computation. */ - schedule_repo_size_computation (seaf->size_sched, priv->repo_id); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - ccnet_processor_done (processor, TRUE); - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - diff --git a/server/processors/recvbranch-proc.h b/server/processors/recvbranch-proc.h deleted file mode 100644 index 42bed43d..00000000 --- a/server/processors/recvbranch-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVBRANCH_PROC_H -#define SEAFILE_RECVBRANCH_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVBRANCH_PROC (seafile_recvbranch_proc_get_type ()) -#define SEAFILE_RECVBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVBRANCH_PROC, SeafileRecvbranchProc)) -#define SEAFILE_IS_RECVBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVBRANCH_PROC)) -#define SEAFILE_RECVBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVBRANCH_PROC, SeafileRecvbranchProcClass)) -#define IS_SEAFILE_RECVBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVBRANCH_PROC)) -#define SEAFILE_RECVBRANCH_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVBRANCH_PROC, SeafileRecvbranchProcClass)) - -typedef struct _SeafileRecvbranchProc SeafileRecvbranchProc; -typedef struct _SeafileRecvbranchProcClass SeafileRecvbranchProcClass; - -struct _SeafileRecvbranchProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvbranchProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvbranch_proc_get_type (); - -#endif - diff --git a/server/processors/recvbranch-v2-proc.c b/server/processors/recvbranch-v2-proc.c deleted file mode 100644 index 39905364..00000000 --- a/server/processors/recvbranch-v2-proc.c +++ /dev/null @@ -1,375 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include - -#include "seafile-session.h" -#include "recvbranch-v2-proc.h" -#include "vc-common.h" - -#include "merge-new.h" -#include "diff-simple.h" - -#include "log.h" - -#define SC_BAD_COMMIT "401" -#define SS_BAD_COMMIT "Commit does not exist" -#define SC_NOT_FF "402" -#define SS_NOT_FF "Not fast forward" -#define SC_QUOTA_ERROR "403" -#define SS_QUOTA_ERROR "Failed to get quota" -#define SC_QUOTA_FULL "404" -#define SS_QUOTA_FULL "storage for the repo's owner is full" -#define SC_SERVER_ERROR "405" -#define SS_SERVER_ERROR "Internal server error" -#define SC_BAD_REPO "406" -#define SS_BAD_REPO "Repo does not exist" -#define SC_BAD_BRANCH "407" -#define SS_BAD_BRANCH "Branch does not exist" -#define SC_ACCESS_DENIED "410" -#define SS_ACCESS_DENIED "Access denied" - -typedef struct { - char repo_id[37]; - char *branch_name; - char new_head[41]; - - char *rsp_code; - char *rsp_msg; -} SeafileRecvbranchProcPriv; - -G_DEFINE_TYPE (SeafileRecvbranchV2Proc, seafile_recvbranch_v2_proc, CCNET_TYPE_PROCESSOR) - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVBRANCH_V2_PROC, SeafileRecvbranchProcPriv)) - -#define USE_PRIV \ - SeafileRecvbranchProcPriv *priv = GET_PRIV(processor); - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void *update_repo (void *vprocessor); -static void thread_done (void *result); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - - CCNET_PROCESSOR_CLASS (seafile_recvbranch_v2_proc_parent_class)->release_resource (processor); -} - - -static void -seafile_recvbranch_v2_proc_class_init (SeafileRecvbranchV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvbranch-v2-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileRecvbranchProcPriv)); -} - -static void -seafile_recvbranch_v2_proc_init (SeafileRecvbranchV2Proc *processor) -{ -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - char *session_token; - - if (argc != 4) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (!is_uuid_valid(argv[0]) || strlen(argv[2]) != 40) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - memcpy (priv->repo_id, argv[0], 36); - memcpy (priv->new_head, argv[2], 40); - priv->branch_name = g_strdup(argv[1]); - session_token = argv[3]; - - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, NULL) < 0) { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - ccnet_processor_thread_create (processor, - seaf->job_mgr, - update_repo, - thread_done, - processor); - - return 0; -} - - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ -} - -static char * -gen_merge_description (SeafRepo *repo, - const char *merged_root, - const char *p1_root, - const char *p2_root) -{ - GList *p; - GList *results = NULL; - char *desc; - - diff_merge_roots (repo->store_id, repo->version, - merged_root, p1_root, p2_root, &results, TRUE); - - desc = diff_results_to_description (results); - - for (p = results; p; p = p->next) { - DiffEntry *de = p->data; - diff_entry_free (de); - } - g_list_free (results); - - return desc; -} - -static int -fast_forward_or_merge (const char *repo_id, - SeafCommit *base, - SeafCommit *new_commit) -{ -#define MAX_RETRY_COUNT 3 - - SeafRepo *repo = NULL; - SeafCommit *current_head = NULL, *merged_commit = NULL; - int retry_cnt = 0; - int ret = 0; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - ret = -1; - goto out; - } - -retry: - current_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!current_head) { - seaf_warning ("Failed to find head commit of %s:%s.\n", - repo_id, repo->head->commit_id); - ret = -1; - goto out; - } - - /* Merge if base and head are not the same. */ - if (strcmp (base->commit_id, current_head->commit_id) != 0) { - MergeOptions opt; - const char *roots[3]; - char *desc = NULL; - - memset (&opt, 0, sizeof(opt)); - opt.n_ways = 3; - memcpy (opt.remote_repo_id, repo_id, 36); - memcpy (opt.remote_head, new_commit->commit_id, 40); - opt.do_merge = TRUE; - - roots[0] = base->root_id; /* base */ - roots[1] = current_head->root_id; /* head */ - roots[2] = new_commit->root_id; /* remote */ - - if (seaf_merge_trees (repo->store_id, repo->version, 3, roots, &opt) < 0) { - seaf_warning ("Failed to merge.\n"); - ret = -1; - goto out; - } - - if (!opt.conflict) - desc = g_strdup("Auto merge by system"); - else { - desc = gen_merge_description (repo, - opt.merged_tree_root, - current_head->root_id, - new_commit->root_id); - if (!desc) - desc = g_strdup("Auto merge by system"); - } - - merged_commit = seaf_commit_new(NULL, repo->id, opt.merged_tree_root, - new_commit->creator_name, EMPTY_SHA1, - desc, - 0); - g_free (desc); - - merged_commit->parent_id = g_strdup (current_head->commit_id); - merged_commit->second_parent_id = g_strdup (new_commit->commit_id); - merged_commit->new_merge = TRUE; - if (opt.conflict) - merged_commit->conflict = TRUE; - seaf_repo_to_commit (repo, merged_commit); - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged_commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - ret = -1; - goto out; - } - } else { - seaf_commit_ref (new_commit); - merged_commit = new_commit; - } - - seaf_branch_set_commit(repo->head, merged_commit->commit_id); - - if (seaf_branch_manager_test_and_update_branch(seaf->branch_mgr, - repo->head, - current_head->commit_id) < 0) - { - seaf_repo_unref (repo); - repo = NULL; - seaf_commit_unref (current_head); - current_head = NULL; - seaf_commit_unref (merged_commit); - merged_commit = NULL; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - ret = -1; - goto out; - } - - if (++retry_cnt <= MAX_RETRY_COUNT) { - /* Sleep random time between 100 and 1000 millisecs. */ - usleep (g_random_int_range(1, 11) * 100 * 1000); - goto retry; - } else { - ret = -1; - goto out; - } - } - -out: - seaf_commit_unref (current_head); - seaf_commit_unref (merged_commit); - seaf_repo_unref (repo); - return ret; -} - -static void * -update_repo (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - char *repo_id, *new_head; - SeafRepo *repo = NULL; - SeafCommit *new_commit = NULL, *base = NULL; - - repo_id = priv->repo_id; - new_head = priv->new_head; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - /* repo is deleted on server */ - priv->rsp_code = g_strdup (SC_BAD_REPO); - priv->rsp_msg = g_strdup (SC_BAD_REPO); - goto out; - - } - - /* Since this is the last step of upload procedure, commit should exist. */ - new_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - new_head); - if (!new_commit) { - seaf_warning ("Failed to get commit %s for repo %s.\n", - new_head, repo->id); - priv->rsp_code = g_strdup (SC_BAD_COMMIT); - priv->rsp_msg = g_strdup (SS_BAD_COMMIT); - goto out; - } - - base = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - new_commit->parent_id); - if (!base) { - seaf_warning ("Failed to get commit %s for repo %s.\n", - new_commit->parent_id, repo->id); - priv->rsp_code = g_strdup (SC_BAD_COMMIT); - priv->rsp_msg = g_strdup (SS_BAD_COMMIT); - goto out; - } - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { - priv->rsp_code = g_strdup(SC_QUOTA_FULL); - priv->rsp_msg = g_strdup(SS_QUOTA_FULL); - goto out; - } - - if (fast_forward_or_merge (repo_id, base, new_commit) < 0) { - priv->rsp_code = g_strdup(SC_SERVER_ERROR); - priv->rsp_msg = g_strdup(SS_SERVER_ERROR); - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (seaf->repo_mgr, repo_id); - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, repo_id, NULL); - -out: - seaf_repo_unref (repo); - seaf_commit_unref (new_commit); - seaf_commit_unref (base); - - if (!priv->rsp_code) { - priv->rsp_code = g_strdup (SC_OK); - priv->rsp_msg = g_strdup (SS_OK); - } - - return vprocessor; -} - -static void -thread_done (void *result) -{ - CcnetProcessor *processor = result; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_OK) == 0) { - /* Repo is updated, schedule repo size computation. */ - schedule_repo_size_computation (seaf->size_sched, priv->repo_id); - - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - ccnet_processor_done (processor, TRUE); - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - diff --git a/server/processors/recvbranch-v2-proc.h b/server/processors/recvbranch-v2-proc.h deleted file mode 100644 index d740a09c..00000000 --- a/server/processors/recvbranch-v2-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVBRANCH_V2_PROC_H -#define SEAFILE_RECVBRANCH_V2_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVBRANCH_V2_PROC (seafile_recvbranch_v2_proc_get_type ()) -#define SEAFILE_RECVBRANCH_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVBRANCH_V2_PROC, SeafileRecvbranchV2Proc)) -#define SEAFILE_IS_RECVBRANCH_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVBRANCH_V2_PROC)) -#define SEAFILE_RECVBRANCH_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVBRANCH_V2_PROC, SeafileRecvbranchV2ProcClass)) -#define IS_SEAFILE_RECVBRANCH_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVBRANCH_V2_PROC)) -#define SEAFILE_RECVBRANCH_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVBRANCH_V2_PROC, SeafileRecvbranchV2ProcClass)) - -typedef struct _SeafileRecvbranchV2Proc SeafileRecvbranchV2Proc; -typedef struct _SeafileRecvbranchV2ProcClass SeafileRecvbranchV2ProcClass; - -struct _SeafileRecvbranchV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvbranchV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvbranch_v2_proc_get_type (); - -#endif - diff --git a/server/processors/recvcommit-proc.c b/server/processors/recvcommit-proc.c deleted file mode 100644 index e84350ef..00000000 --- a/server/processors/recvcommit-proc.c +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include -#include -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "recvcommit-proc.h" -#include "processors/objecttx-common.h" -#include "seaf-utils.h" - -#include "log.h" - -#define CHECK_INTERVAL 100 /* 100ms */ - -enum { - RECV_IDS, - FETCH_OBJECT -}; - -typedef struct { - char object_path[SEAF_PATH_MAX]; - char tmp_object_path[SEAF_PATH_MAX]; - char buf[4096]; - char *bufptr; - int pending_objects; -} SeafileRecvcommitProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVCOMMIT_PROC, SeafileRecvcommitProcPriv)) - -#define USE_PRIV \ - SeafileRecvcommitProcPriv *priv = GET_PRIV(processor); - -static int recv_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - - -G_DEFINE_TYPE (SeafileRecvcommitProc, seafile_recvcommit_proc, CCNET_TYPE_PROCESSOR) - -static void -seafile_recvcommit_proc_class_init (SeafileRecvcommitProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvcommit-proc"; - proc_class->start = recv_commit_start; - proc_class->handle_update = handle_update; - - g_type_class_add_private (klass, sizeof (SeafileRecvcommitProcPriv)); -} - -static void -seafile_recvcommit_proc_init (SeafileRecvcommitProc *processor) -{ -} - -inline static void -request_object_batch_begin (SeafileRecvcommitProcPriv *priv) -{ - priv->bufptr = priv->buf; -} - -inline static void -request_object_batch (SeafileRecvcommitProcPriv *priv, const char *id) -{ - memcpy (priv->bufptr, id, 40); - priv->bufptr += 40; - *priv->bufptr = '\n'; - priv->bufptr++; - - ++priv->pending_objects; -} - -inline static void -request_object_batch_flush (CcnetProcessor *processor, - SeafileRecvcommitProcPriv *priv) -{ - if (priv->bufptr == priv->buf) - return; - *priv->bufptr = '\0'; /* add ending '\0' */ - priv->bufptr++; - ccnet_processor_send_response (processor, SC_GET_OBJECT, SS_GET_OBJECT, - priv->buf, priv->bufptr - priv->buf); -} - -static int -recv_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - char *session_token; - - if (argc != 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[1]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - processor->peer_id, - session_token, NULL) == 0) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = RECV_IDS; - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -static void -check_commit (CcnetProcessor *processor, const char *commit_id) -{ - USE_PRIV; - - if (!seaf_commit_manager_commit_exists (seaf->commit_mgr, commit_id)) { - request_object_batch (priv, commit_id); - } -} - -static int -save_commit (ObjectPack *pack, int len) -{ - return seaf_obj_store_write_obj (seaf->commit_mgr->obj_store, - pack->id, - pack->object, - len - 41); -} - -static void -receive_commit (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - ObjectPack *pack = (ObjectPack *)content; - - if (clen < sizeof(ObjectPack)) { - seaf_warning ("invalid object id.\n"); - goto bad; - } - - --priv->pending_objects; - - /* TODO: check commit format here. */ - - if (save_commit (pack, clen) < 0) { - goto bad; - } - - if (priv->pending_objects == 0) { - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - } - - return; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, - SS_BAD_OBJECT, NULL, 0); - seaf_warning ("Bad commit object received.\n"); - ccnet_processor_done (processor, FALSE); -} - -static void -process_commit_list (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - char *object_id; - int n_objects; - int i; - - if (clen % 41 != 1 || content[clen-1] != '\0') { - seaf_warning ("Bad commit id list.\n"); - ccnet_processor_send_response (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - n_objects = clen/41; - - request_object_batch_begin(priv); - - object_id = content; - for (i = 0; i < n_objects; ++i) { - object_id[40] = '\0'; - check_commit (processor, object_id); - object_id += 41; - } - - request_object_batch_flush (processor, priv); - - if (priv->pending_objects == 0) { - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - } -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case RECV_IDS: - if (strncmp(code, SC_COMMIT_IDS, 3) == 0) { - /* add to inspect queue */ - process_commit_list (processor, content, clen); - } else if (strncmp(code, SC_END, 3) == 0) { - /* change state to FETCH_OBJECT */ - processor->state = FETCH_OBJECT; - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - case FETCH_OBJECT: - if (strncmp(code, SC_OBJECT, 3) == 0) { - receive_commit (processor, content, clen); - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - default: - g_return_if_reached (); - } -} diff --git a/server/processors/recvcommit-proc.h b/server/processors/recvcommit-proc.h deleted file mode 100644 index f701677b..00000000 --- a/server/processors/recvcommit-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVCOMMIT_PROC_H -#define SEAFILE_RECVCOMMIT_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVCOMMIT_PROC (seafile_recvcommit_proc_get_type ()) -#define SEAFILE_RECVCOMMIT_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVCOMMIT_PROC, SeafileRecvcommitProc)) -#define SEAFILE_IS_RECVCOMMIT_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVCOMMIT_PROC)) -#define SEAFILE_RECVCOMMIT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVCOMMIT_PROC, SeafileRecvcommitProcClass)) -#define IS_SEAFILE_RECVCOMMIT_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVCOMMIT_PROC)) -#define SEAFILE_RECVCOMMIT_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVCOMMIT_PROC, SeafileRecvcommitProcClass)) - -typedef struct _SeafileRecvcommitProc SeafileRecvcommitProc; -typedef struct _SeafileRecvcommitProcClass SeafileRecvcommitProcClass; - -struct _SeafileRecvcommitProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvcommitProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvcommit_proc_get_type (); - -#endif diff --git a/server/processors/recvcommit-v2-proc.c b/server/processors/recvcommit-v2-proc.c deleted file mode 100644 index 9e243a14..00000000 --- a/server/processors/recvcommit-v2-proc.c +++ /dev/null @@ -1,180 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "recvcommit-v2-proc.h" -#include "processors/objecttx-common.h" -#include "seaf-utils.h" - -#include "log.h" - -enum { - INIT, - RECV_OBJECT -}; - -typedef struct { - guint32 writer_id; - gboolean registered; -} RecvcommitPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVCOMMIT_V2_PROC, RecvcommitPriv)) - -#define USE_PRIV \ - RecvcommitPriv *priv = GET_PRIV(processor); - -static int recv_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void -write_done_cb (OSAsyncResult *res, void *cb_data); - - -G_DEFINE_TYPE (SeafileRecvcommitV2Proc, seafile_recvcommit_v2_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource (CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->registered) - seaf_obj_store_unregister_async_write (seaf->commit_mgr->obj_store, - priv->writer_id); - - CCNET_PROCESSOR_CLASS (seafile_recvcommit_v2_proc_parent_class)->release_resource (processor); -} - -static void -seafile_recvcommit_v2_proc_class_init (SeafileRecvcommitV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvcommit-v2-proc"; - proc_class->start = recv_commit_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (RecvcommitPriv)); -} - -static void -seafile_recvcommit_v2_proc_init (SeafileRecvcommitV2Proc *processor) -{ -} - -static int -recv_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - char *session_token; - - if (argc != 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[1]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - processor->peer_id, - session_token, NULL) == 0) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = RECV_OBJECT; - priv->writer_id = - seaf_obj_store_register_async_write (seaf->commit_mgr->obj_store, - write_done_cb, - processor); - priv->registered = TRUE; - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -static void -write_done_cb (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - - if (!res->success) { - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - seaf_warning ("[recvcommit] Failed to write commit object.\n"); - ccnet_processor_done (processor, FALSE); - } - /* FIXME: need to send ACK if success. */ -} - -static int -save_commit (CcnetProcessor *processor, ObjectPack *pack, int len) -{ - USE_PRIV; - - return seaf_obj_store_async_write (seaf->commit_mgr->obj_store, - priv->writer_id, - pack->id, - pack->object, - len - 41); -} - -static void -receive_commit (CcnetProcessor *processor, char *content, int clen) -{ - ObjectPack *pack = (ObjectPack *)content; - - if (clen < sizeof(ObjectPack)) { - seaf_warning ("[recvcommit] invalid object id.\n"); - goto bad; - } - - g_debug ("[recvcommit] recv commit object %s\n", pack->id); - - if (save_commit (processor, pack, clen) < 0) { - goto bad; - } - - return; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - seaf_warning ("[recvcommit] Failed to write commit object.\n"); - ccnet_processor_done (processor, FALSE); -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case RECV_OBJECT: - if (strncmp(code, SC_OBJECT, 3) == 0) { - receive_commit (processor, content, clen); - } else if (strncmp(code, SC_END, 3) == 0) { - g_debug ("[recvcommit] Recv commit end.\n"); - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("[recvcommit] Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - default: - g_return_if_reached (); - } -} diff --git a/server/processors/recvcommit-v2-proc.h b/server/processors/recvcommit-v2-proc.h deleted file mode 100644 index bf397f81..00000000 --- a/server/processors/recvcommit-v2-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVCOMMIT_V2_PROC_H -#define SEAFILE_RECVCOMMIT_V2_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVCOMMIT_V2_PROC (seafile_recvcommit_v2_proc_get_type ()) -#define SEAFILE_RECVCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVCOMMIT_V2_PROC, SeafileRecvcommitV2Proc)) -#define SEAFILE_IS_RECVCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVCOMMIT_V2_PROC)) -#define SEAFILE_RECVCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVCOMMIT_V2_PROC, SeafileRecvcommitV2ProcClass)) -#define IS_SEAFILE_RECVCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVCOMMIT_V2_PROC)) -#define SEAFILE_RECVCOMMIT_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVCOMMIT_V2_PROC, SeafileRecvcommitV2ProcClass)) - -typedef struct _SeafileRecvcommitV2Proc SeafileRecvcommitV2Proc; -typedef struct _SeafileRecvcommitV2ProcClass SeafileRecvcommitV2ProcClass; - -struct _SeafileRecvcommitV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvcommitV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvcommit_v2_proc_get_type (); - -#endif diff --git a/server/processors/recvcommit-v3-proc.c b/server/processors/recvcommit-v3-proc.c deleted file mode 100644 index c5825a43..00000000 --- a/server/processors/recvcommit-v3-proc.c +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include - -#include -#include "net.h" -#include "utils.h" - -#include "seafile-session.h" -#include "recvcommit-v3-proc.h" -#include "processors/objecttx-common.h" -#include "seaf-utils.h" - -enum { - INIT, - RECV_OBJECT -}; - -typedef struct { - guint32 writer_id; - gboolean registered; - - /* Used for getting repo info */ - char repo_id[37]; - int repo_version; - gboolean success; -} RecvcommitPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVCOMMIT_V3_PROC, RecvcommitPriv)) - -#define USE_PRIV \ - RecvcommitPriv *priv = GET_PRIV(processor); - -static int recv_commit_start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); -static void -write_done_cb (OSAsyncResult *res, void *cb_data); - - -G_DEFINE_TYPE (SeafileRecvcommitV3Proc, seafile_recvcommit_v3_proc, CCNET_TYPE_PROCESSOR) - -static void -release_resource (CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->registered) - seaf_obj_store_unregister_async_write (seaf->commit_mgr->obj_store, - priv->writer_id); - - CCNET_PROCESSOR_CLASS (seafile_recvcommit_v3_proc_parent_class)->release_resource (processor); -} - -static void -seafile_recvcommit_v3_proc_class_init (SeafileRecvcommitV3ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvcommit-v3-proc"; - proc_class->start = recv_commit_start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (RecvcommitPriv)); -} - -static void -seafile_recvcommit_v3_proc_init (SeafileRecvcommitV3Proc *processor) -{ -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = RECV_OBJECT; - priv->writer_id = - seaf_obj_store_register_async_write (seaf->commit_mgr->obj_store, - priv->repo_id, - priv->repo_version, - write_done_cb, - processor); - priv->registered = TRUE; - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -recv_commit_start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - char *session_token; - - if (argc != 2) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[1]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) == 0) { - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -static void -write_done_cb (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - - if (!res->success) { - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - seaf_warning ("[recvcommit] Failed to write commit object.\n"); - ccnet_processor_done (processor, FALSE); - } else { - ccnet_processor_send_response (processor, SC_ACK, SS_ACK, NULL, 0); - } -} - -static int -save_commit (CcnetProcessor *processor, ObjectPack *pack, int len) -{ - USE_PRIV; - - return seaf_obj_store_async_write (seaf->commit_mgr->obj_store, - priv->writer_id, - pack->id, - pack->object, - len - 41, - TRUE); -} - -static void -receive_commit (CcnetProcessor *processor, char *content, int clen) -{ - ObjectPack *pack = (ObjectPack *)content; - - if (clen < sizeof(ObjectPack)) { - seaf_warning ("[recvcommit] invalid object id.\n"); - goto bad; - } - - seaf_debug ("[recvcommit] recv commit object %.8s\n", pack->id); - - if (save_commit (processor, pack, clen) < 0) { - goto bad; - } - - return; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - seaf_warning ("[recvcommit] Failed to write commit object.\n"); - ccnet_processor_done (processor, FALSE); -} - -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case RECV_OBJECT: - if (strncmp(code, SC_OBJECT, 3) == 0) { - receive_commit (processor, content, clen); - } else if (strncmp(code, SC_END, 3) == 0) { - seaf_debug ("[recvcommit] Recv commit end.\n"); - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("[recvcommit] Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - default: - g_return_if_reached (); - } -} diff --git a/server/processors/recvcommit-v3-proc.h b/server/processors/recvcommit-v3-proc.h deleted file mode 100644 index ebbdaddb..00000000 --- a/server/processors/recvcommit-v3-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVCOMMIT_V3_PROC_H -#define SEAFILE_RECVCOMMIT_V3_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVCOMMIT_V3_PROC (seafile_recvcommit_v3_proc_get_type ()) -#define SEAFILE_RECVCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVCOMMIT_V3_PROC, SeafileRecvcommitV3Proc)) -#define SEAFILE_IS_RECVCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVCOMMIT_V3_PROC)) -#define SEAFILE_RECVCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVCOMMIT_V3_PROC, SeafileRecvcommitV3ProcClass)) -#define IS_SEAFILE_RECVCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVCOMMIT_V3_PROC)) -#define SEAFILE_RECVCOMMIT_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVCOMMIT_V3_PROC, SeafileRecvcommitV3ProcClass)) - -typedef struct _SeafileRecvcommitV3Proc SeafileRecvcommitV3Proc; -typedef struct _SeafileRecvcommitV3ProcClass SeafileRecvcommitV3ProcClass; - -struct _SeafileRecvcommitV3Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvcommitV3ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvcommit_v3_proc_get_type (); - -#endif diff --git a/server/processors/recvfs-proc.c b/server/processors/recvfs-proc.c deleted file mode 100644 index 90475ef7..00000000 --- a/server/processors/recvfs-proc.c +++ /dev/null @@ -1,630 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include -#include -#include -#include - -#include -#include "utils.h" - -#include "seafile-session.h" -#include "fs-mgr.h" -#include "processors/objecttx-common.h" -#include "recvfs-proc.h" -#include "seaf-utils.h" - -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_NUM_BATCH 64 -#define MAX_CHECKING_DIRS 1000 - -enum { - RECV_ROOT, - FETCH_OBJECT -}; - -typedef struct { - GList *fs_roots; - int n_roots; - - int inspect_objects; - int pending_objects; - char buf[4096]; - char *bufptr; - int n_batch; - - GHashTable *fs_objects; - - int checking_dirs; - GQueue *dir_queue; - - char *obj_seg; - int obj_seg_len; - - gboolean registered; - guint32 reader_id; - guint32 writer_id; - guint32 stat_id; - - /* Used for getting repo info */ - char repo_id[37]; - char store_id[37]; - int repo_version; - gboolean success; -} SeafileRecvfsProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVFS_PROC, SeafileRecvfsProcPriv)) - -#define USE_PRIV \ - SeafileRecvfsProcPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (SeafileRecvfsProc, seafile_recvfs_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void -free_dir_id (gpointer data, gpointer user_data) -{ - g_free (data); -} - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - if (priv->fs_objects) - g_hash_table_destroy (priv->fs_objects); - - string_list_free (priv->fs_roots); - - g_queue_foreach (priv->dir_queue, free_dir_id, NULL); - g_queue_free (priv->dir_queue); - - g_free (priv->obj_seg); - - if (priv->registered) { - seaf_obj_store_unregister_async_read (seaf->fs_mgr->obj_store, - priv->reader_id); - seaf_obj_store_unregister_async_write (seaf->fs_mgr->obj_store, - priv->writer_id); - seaf_obj_store_unregister_async_stat (seaf->fs_mgr->obj_store, - priv->stat_id); - } - - CCNET_PROCESSOR_CLASS (seafile_recvfs_proc_parent_class)->release_resource (processor); -} - -static void -seafile_recvfs_proc_class_init (SeafileRecvfsProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvfs-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileRecvfsProcPriv)); -} - -static void -seafile_recvfs_proc_init (SeafileRecvfsProc *processor) -{ -} - -inline static void -request_object_batch_begin (SeafileRecvfsProcPriv *priv) -{ - priv->bufptr = priv->buf; - priv->n_batch = 0; -} - -inline static void -request_object_batch_flush (CcnetProcessor *processor, - SeafileRecvfsProcPriv *priv) -{ - if (priv->bufptr == priv->buf) - return; - *priv->bufptr = '\0'; /* add ending '\0' */ - priv->bufptr++; - ccnet_processor_send_response (processor, SC_GET_OBJECT, SS_GET_OBJECT, - priv->buf, priv->bufptr - priv->buf); - - /* Clean state */ - priv->n_batch = 0; - priv->bufptr = priv->buf; -} - -inline static void -request_object_batch (CcnetProcessor *processor, - SeafileRecvfsProcPriv *priv, const char *id) -{ - memcpy (priv->bufptr, id, 40); - priv->bufptr += 40; - *priv->bufptr = '\n'; - priv->bufptr++; - - /* Flush when too many objects batched. */ - if (++priv->n_batch == MAX_NUM_BATCH) - request_object_batch_flush (processor, priv); - ++priv->pending_objects; -} - -static int -check_seafdir (CcnetProcessor *processor, SeafDir *dir) -{ - USE_PRIV; - GList *ptr; - SeafDirent *dent; - - for (ptr = dir->entries; ptr != NULL; ptr = ptr->next) { - dent = ptr->data; - - if (strcmp (dent->id, EMPTY_SHA1) == 0) - continue; - - /* Don't check objects that have been checked before. */ - if (priv->fs_objects && g_hash_table_lookup (priv->fs_objects, dent->id)) - continue; - - if (S_ISDIR(dent->mode)) { - g_queue_push_tail (priv->dir_queue, g_strdup(dent->id)); - } else { -#ifdef DEBUG - seaf_debug ("[recvfs] Inspect file %s.\n", dent->id); -#endif - - /* For file, we just need to check existence. */ - if (seaf_obj_store_async_stat (seaf->fs_mgr->obj_store, - priv->stat_id, - dent->id) < 0) { - seaf_warning ("[recvfs] Failed to start async stat of %s.\n", - dent->id); - goto bad; - } - ++(priv->inspect_objects); - } - - if (priv->fs_objects) - g_hash_table_insert (priv->fs_objects, g_strdup(dent->id), (gpointer)1); - } - - return 0; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; -} - -static void -on_seafdir_read (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - SeafDir *dir; - USE_PRIV; - - --(priv->inspect_objects); - --(priv->checking_dirs); - - if (!res->success) { - request_object_batch (processor, priv, res->obj_id); - return; - } - -#ifdef DEBUG - seaf_debug ("[recvfs] Read seafdir %s.\n", res->obj_id); -#endif - - dir = seaf_dir_from_data (res->obj_id, res->data, res->len, - (priv->repo_version > 0)); - if (!dir) { - seaf_warning ("[recvfs] Corrupt dir object %s.\n", res->obj_id); - request_object_batch (processor, priv, res->obj_id); - return; - } - - int ret = check_seafdir (processor, dir); - seaf_dir_free (dir); - if (ret < 0) - return; -} - -static void -on_seafile_stat (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - USE_PRIV; - - --(priv->inspect_objects); - -#ifdef DEBUG - seaf_debug ("[recvfs] Stat seafile %s.\n", res->obj_id); -#endif - - if (!res->success) - request_object_batch (processor, priv, res->obj_id); -} - -static void -on_fs_write (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - USE_PRIV; - - if (!res->success) { - seaf_warning ("[recvfs] Failed to write %s.\n", res->obj_id); - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - --priv->pending_objects; - -#ifdef DEBUG - seaf_debug ("[recvfs] Wrote fs object %s.\n", res->obj_id); -#endif -} - -static int -check_end_condition (CcnetProcessor *processor) -{ - USE_PRIV; - - char *dir_id; - while (priv->checking_dirs < MAX_CHECKING_DIRS) { - dir_id = g_queue_pop_head (priv->dir_queue); - if (!dir_id) - break; - -#ifdef DEBUG - seaf_debug ("[recvfs] Inspect dir %s.\n", dir_id); -#endif - - if (seaf_obj_store_async_read (seaf->fs_mgr->obj_store, - priv->reader_id, - dir_id) < 0) { - seaf_warning ("[recvfs] Failed to start async read of %s.\n", dir_id); - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return FALSE; - } - g_free (dir_id); - - ++(priv->inspect_objects); - ++(priv->checking_dirs); - } - - if (priv->checking_dirs > 100) - seaf_debug ("Number of checking dirs: %d.\n", priv->checking_dirs); - if (priv->inspect_objects > 1000) - seaf_debug ("Number of inspect objects: %d.\n", priv->inspect_objects); - - /* Flush periodically. */ - request_object_batch_flush (processor, priv); - - if (priv->pending_objects == 0 && priv->inspect_objects == 0) { - seaf_debug ("Recv fs end.\n"); - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - return FALSE; - } else - return TRUE; -} - -static void -register_async_io (CcnetProcessor *processor) -{ - USE_PRIV; - - priv->registered = TRUE; - priv->reader_id = seaf_obj_store_register_async_read (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - on_seafdir_read, - processor); - priv->stat_id = seaf_obj_store_register_async_stat (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - on_seafile_stat, - processor); - priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - on_fs_write, - processor); -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - memcpy (priv->store_id, repo->store_id, 36); - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - processor->state = RECV_ROOT; - priv->dir_queue = g_queue_new (); - register_async_io (processor); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *session_token; - USE_PRIV; - - if (argc != 1) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[0]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) == 0) { - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -static int -save_fs_object (CcnetProcessor *processor, ObjectPack *pack, int len) -{ - USE_PRIV; - - return seaf_obj_store_async_write (seaf->fs_mgr->obj_store, - priv->writer_id, - pack->id, - pack->object, - len - 41, - FALSE); -} - -static int -recv_fs_object (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - ObjectPack *pack = (ObjectPack *)content; - SeafFSObject *fs_obj = NULL; - - if (clen < sizeof(ObjectPack)) { - seaf_warning ("invalid object id.\n"); - goto bad; - } - - seaf_debug ("[recvfs] Recv fs object %.8s.\n", pack->id); - - fs_obj = seaf_fs_object_from_data(pack->id, - pack->object, clen - sizeof(ObjectPack), - (priv->repo_version > 0)); - if (!fs_obj) { - seaf_warning ("Bad fs object %s.\n", pack->id); - goto bad; - } - - if (fs_obj->type == SEAF_METADATA_TYPE_DIR) { - SeafDir *dir = (SeafDir *)fs_obj; - int ret = check_seafdir (processor, dir); - if (ret < 0) - goto bad; - } else if (fs_obj->type == SEAF_METADATA_TYPE_FILE) { - /* TODO: check seafile format. */ -#if 0 - int ret = seafile_check_data_format (pack->object, clen - 41); - if (ret < 0) { - goto bad; - } -#endif - } - - seaf_fs_object_free (fs_obj); - - if (save_fs_object (processor, pack, clen) < 0) { - goto bad; - } - - return 0; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, - SS_BAD_OBJECT, NULL, 0); - seaf_warning ("[recvfs] Bad fs object received.\n"); - ccnet_processor_done (processor, FALSE); - - seaf_fs_object_free (fs_obj); - - return -1; -} - -static void -recv_fs_object_seg (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - - /* Append the received object segment to the end */ - priv->obj_seg = g_realloc (priv->obj_seg, priv->obj_seg_len + clen); - memcpy (priv->obj_seg + priv->obj_seg_len, content, clen); - - seaf_debug ("[recvfs] Get obj seg: \n", - priv->obj_seg, priv->obj_seg_len, clen); - - priv->obj_seg_len += clen; -} - -static void -process_fs_object_seg (CcnetProcessor *processor) -{ - USE_PRIV; - - if (recv_fs_object (processor, priv->obj_seg, priv->obj_seg_len) == 0) { - g_free (priv->obj_seg); - priv->obj_seg = NULL; - priv->obj_seg_len = 0; - } -} - -static void -process_fsroot_list (CcnetProcessor *processor) -{ - GList *ptr; - char *object_id; - USE_PRIV; - - /* When there are more than one fs roots, there may be many - * duplicate fs objects between different commits. - * We remember checked fs objects in a hash table to avoid - * redundant checks. - */ - if (priv->n_roots > 1) - priv->fs_objects = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - request_object_batch_begin (priv); - - for (ptr = priv->fs_roots; ptr != NULL; ptr = ptr->next) { - object_id = ptr->data; - - /* Empty dir or file always exists. */ - if (strcmp (object_id, EMPTY_SHA1) == 0) { - object_id += 41; - continue; - } - -#ifdef DEBUG - seaf_debug ("[recvfs] Inspect object %s.\n", object_id); -#endif - - g_queue_push_tail (priv->dir_queue, g_strdup(object_id)); - - g_free (object_id); - } - - g_list_free (priv->fs_roots); - priv->fs_roots = NULL; -} - -static void -queue_fs_roots (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - char *object_id; - int n_objects; - int i; - - if (clen % 41 != 0) { - seaf_warning ("Bad fs root list.\n"); - ccnet_processor_send_response (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - n_objects = clen/41; - object_id = content; - for (i = 0; i < n_objects; ++i) { - object_id[40] = '\0'; - priv->fs_roots = g_list_prepend (priv->fs_roots, g_strdup(object_id)); - object_id += 41; - ++(priv->n_roots); - } - - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - switch (processor->state) { - case RECV_ROOT: - if (strncmp(code, SC_ROOT, 3) == 0) { - queue_fs_roots (processor, content, clen); - } else if (strncmp(code, SC_ROOT_END, 3) == 0) { - /* change state to FETCH_OBJECT */ - process_fsroot_list (processor); - processor->timer = ccnet_timer_new ( - (TimerCB)check_end_condition, processor, CHECK_INTERVAL); - processor->state = FETCH_OBJECT; - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - case FETCH_OBJECT: - if (strncmp(code, SC_OBJ_SEG, 3) == 0) { - recv_fs_object_seg (processor, content, clen); - - } else if (strncmp(code, SC_OBJ_SEG_END, 3) == 0) { - recv_fs_object_seg (processor, content, clen); - process_fs_object_seg (processor); - } else if (strncmp(code, SC_OBJECT, 3) == 0) { - recv_fs_object (processor, content, clen); - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - default: - g_return_if_reached (); - } -} diff --git a/server/processors/recvfs-proc.h b/server/processors/recvfs-proc.h deleted file mode 100644 index a58f050e..00000000 --- a/server/processors/recvfs-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVFS_PROC_H -#define SEAFILE_RECVFS_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVFS_PROC (seafile_recvfs_proc_get_type ()) -#define SEAFILE_RECVFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVFS_PROC, SeafileRecvfsProc)) -#define SEAFILE_IS_RECVFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVFS_PROC)) -#define SEAFILE_RECVFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVFS_PROC, SeafileRecvfsProcClass)) -#define IS_SEAFILE_RECVFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVFS_PROC)) -#define SEAFILE_RECVFS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVFS_PROC, SeafileRecvfsProcClass)) - -typedef struct _SeafileRecvfsProc SeafileRecvfsProc; -typedef struct _SeafileRecvfsProcClass SeafileRecvfsProcClass; - -struct _SeafileRecvfsProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvfsProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvfs_proc_get_type (); - -#endif - diff --git a/server/processors/recvfs-v2-proc.c b/server/processors/recvfs-v2-proc.c deleted file mode 100644 index ad879da9..00000000 --- a/server/processors/recvfs-v2-proc.c +++ /dev/null @@ -1,420 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER -#include "log.h" - -#include -#include -#include -#include - -#include -#include "utils.h" - -#include "seafile-session.h" -#include "fs-mgr.h" -#include "processors/objecttx-common.h" -#include "recvfs-v2-proc.h" -#include "seaf-utils.h" - -enum { - CHECK_OBJECT_LIST = 0, - RECV_OBJECTS, -}; - -typedef struct { - char *obj_seg; - int obj_seg_len; - - gboolean registered; - guint32 writer_id; - - /* Used for getting repo info */ - char repo_id[37]; - char store_id[37]; - int repo_version; - gboolean success; - - /* Used to check object list */ - char *recv_objs; - int recv_len; - GList *needed_objs; - int n_needed; - - int total_needed; - int n_saved; -} SeafileRecvfsProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_RECVFS_V2_PROC, SeafileRecvfsProcPriv)) - -#define USE_PRIV \ - SeafileRecvfsProcPriv *priv = GET_PRIV(processor); - - -G_DEFINE_TYPE (SeafileRecvfsV2Proc, seafile_recvfs_v2_proc, CCNET_TYPE_PROCESSOR) - -static int start (CcnetProcessor *processor, int argc, char **argv); -static void handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - g_free (priv->obj_seg); - - if (priv->registered) { - seaf_obj_store_unregister_async_write (seaf->fs_mgr->obj_store, - priv->writer_id); - } - - g_free (priv->recv_objs); - string_list_free (priv->needed_objs); - - CCNET_PROCESSOR_CLASS (seafile_recvfs_v2_proc_parent_class)->release_resource (processor); -} - -static void -seafile_recvfs_v2_proc_class_init (SeafileRecvfsV2ProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "recvfs-v2-proc"; - proc_class->start = start; - proc_class->handle_update = handle_update; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileRecvfsProcPriv)); -} - -static void -seafile_recvfs_v2_proc_init (SeafileRecvfsV2Proc *processor) -{ -} - -static void -on_fs_write (OSAsyncResult *res, void *cb_data); - -static void -register_async_io (CcnetProcessor *processor) -{ - USE_PRIV; - - priv->registered = TRUE; - priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store, - priv->store_id, - priv->repo_version, - on_fs_write, - processor); -} - -static void * -get_repo_info_thread (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - SeafRepo *repo; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %s.\n", priv->repo_id); - priv->success = FALSE; - return data; - } - - memcpy (priv->store_id, repo->store_id, 36); - priv->repo_version = repo->version; - priv->success = TRUE; - - seaf_repo_unref (repo); - return data; -} - -static void -get_repo_info_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->success) { - ccnet_processor_send_response (processor, SC_OK, SS_OK, NULL, 0); - register_async_io (processor); - } else { - ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } -} - -static int -start (CcnetProcessor *processor, int argc, char **argv) -{ - char *session_token; - USE_PRIV; - - if (argc != 1) { - ccnet_processor_send_response (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - session_token = argv[0]; - if (seaf_token_manager_verify_token (seaf->token_mgr, - NULL, - processor->peer_id, - session_token, priv->repo_id) == 0) { - ccnet_processor_thread_create (processor, - seaf->job_mgr, - get_repo_info_thread, - get_repo_info_done, - processor); - return 0; - } else { - ccnet_processor_send_response (processor, - SC_ACCESS_DENIED, SS_ACCESS_DENIED, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } -} - -static void -on_fs_write (OSAsyncResult *res, void *cb_data) -{ - CcnetProcessor *processor = cb_data; - USE_PRIV; - - if (!res->success) { - seaf_warning ("[recvfs] Failed to write %s.\n", res->obj_id); - ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - seaf_debug ("[recvfs] Wrote fs object %s.\n", res->obj_id); - - if (++(priv->n_saved) == priv->total_needed) { - seaf_debug ("All objects saved. Done.\n"); - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - } -} - -static int -save_fs_object (CcnetProcessor *processor, ObjectPack *pack, int len) -{ - USE_PRIV; - - return seaf_obj_store_async_write (seaf->fs_mgr->obj_store, - priv->writer_id, - pack->id, - pack->object, - len - 41, - FALSE); -} - -static int -recv_fs_object (CcnetProcessor *processor, char *content, int clen) -{ - ObjectPack *pack = (ObjectPack *)content; - /* SeafFSObject *fs_obj = NULL; */ - - if (clen < sizeof(ObjectPack)) { - seaf_warning ("invalid object id.\n"); - goto bad; - } - - seaf_debug ("[recvfs] Recv fs object %.8s.\n", pack->id); - - /* Check object integrity by parsing it. */ - /* fs_obj = seaf_fs_object_from_data(pack->id, */ - /* pack->object, clen - sizeof(ObjectPack), */ - /* (priv->repo_version > 0)); */ - /* if (!fs_obj) { */ - /* seaf_warning ("Bad fs object %s.\n", pack->id); */ - /* goto bad; */ - /* } */ - - /* seaf_fs_object_free (fs_obj); */ - - if (save_fs_object (processor, pack, clen) < 0) { - goto bad; - } - - return 0; - -bad: - ccnet_processor_send_response (processor, SC_BAD_OBJECT, - SS_BAD_OBJECT, NULL, 0); - seaf_warning ("[recvfs] Bad fs object received.\n"); - ccnet_processor_done (processor, FALSE); - - /* seaf_fs_object_free (fs_obj); */ - - return -1; -} - -static void -recv_fs_object_seg (CcnetProcessor *processor, char *content, int clen) -{ - USE_PRIV; - - /* Append the received object segment to the end */ - priv->obj_seg = g_realloc (priv->obj_seg, priv->obj_seg_len + clen); - memcpy (priv->obj_seg + priv->obj_seg_len, content, clen); - - seaf_debug ("[recvfs] Get obj seg: \n", - priv->obj_seg, priv->obj_seg_len, clen); - - priv->obj_seg_len += clen; -} - -static void -process_fs_object_seg (CcnetProcessor *processor) -{ - USE_PRIV; - - if (recv_fs_object (processor, priv->obj_seg, priv->obj_seg_len) == 0) { - g_free (priv->obj_seg); - priv->obj_seg = NULL; - priv->obj_seg_len = 0; - } -} - -static void * -process_object_list (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - int n, i; - char *p; - char *obj_id; - - n = priv->recv_len/40; - p = priv->recv_objs; - - for (i = 0; i < n; ++i) { - obj_id = g_strndup (p, 40); - - if (!seaf_obj_store_obj_exists (seaf->fs_mgr->obj_store, - priv->store_id, priv->repo_version, - obj_id)) - { - priv->needed_objs = g_list_prepend (priv->needed_objs, obj_id); - ++(priv->n_needed); - ++(priv->total_needed); - } else - g_free (obj_id); - p += 40; - } - - g_free (priv->recv_objs); - priv->recv_objs = NULL; - - return data; -} - -static void -process_object_list_done (void *data) -{ - CcnetProcessor *processor = data; - USE_PRIV; - - if (priv->n_needed == 0) { - ccnet_processor_send_response (processor, - SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG, - NULL, 0); - return; - } - - char *buf = g_malloc (priv->n_needed * 40); - char *p; - char *obj_id; - GList *ptr; - - p = buf; - for (ptr = priv->needed_objs; ptr; ptr = ptr->next) { - obj_id = ptr->data; - memcpy (p, obj_id, 40); - p += 40; - } - - ccnet_processor_send_response (processor, - SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG, - buf, priv->n_needed * 40); - g_free (buf); - string_list_free (priv->needed_objs); - priv->needed_objs = NULL; - priv->n_needed = 0; -} - -static void -handle_update (CcnetProcessor *processor, - char *code, char *code_msg, - char *content, int clen) -{ - USE_PRIV; - - switch (processor->state) { - case CHECK_OBJECT_LIST: - if (strncmp (code, SC_OBJ_LIST_SEG, 3) == 0) { - if (clen % 40 != 0) { - seaf_warning ("Invalid object list segment length %d.\n", clen); - ccnet_processor_send_response (processor, - SC_SHUTDOWN, SS_SHUTDOWN, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return; - } - - priv->recv_objs = g_memdup(content, clen); - priv->recv_len = clen; - ccnet_processor_thread_create (processor, seaf->job_mgr, - process_object_list, - process_object_list_done, - processor); - } else if (strncmp (code, SC_OBJ_LIST_SEG_END, 3) == 0) { - if (priv->total_needed == 0) { - seaf_debug ("No objects are needed. Done.\n"); - ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); - ccnet_processor_done (processor, TRUE); - return; - } - processor->state = RECV_OBJECTS; - } else if (strncmp (code, SC_END, 3) == 0) { - /* The client finds nothing to upload. */ - ccnet_processor_done (processor, TRUE); - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - case RECV_OBJECTS: - if (strncmp(code, SC_OBJ_SEG, 3) == 0) { - recv_fs_object_seg (processor, content, clen); - } else if (strncmp(code, SC_OBJ_SEG_END, 3) == 0) { - recv_fs_object_seg (processor, content, clen); - process_fs_object_seg (processor); - } else if (strncmp(code, SC_OBJECT, 3) == 0) { - recv_fs_object (processor, content, clen); - } else { - seaf_warning ("Bad update: %s %s\n", code, code_msg); - ccnet_processor_send_response (processor, - SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, - NULL, 0); - ccnet_processor_done (processor, FALSE); - } - break; - default: - g_return_if_reached (); - } -} diff --git a/server/processors/recvfs-v2-proc.h b/server/processors/recvfs-v2-proc.h deleted file mode 100644 index a305511e..00000000 --- a/server/processors/recvfs-v2-proc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_RECVFS_V2_PROC_H -#define SEAFILE_RECVFS_V2_PROC_H - -#include - - -#define SEAFILE_TYPE_RECVFS_V2_PROC (seafile_recvfs_v2_proc_get_type ()) -#define SEAFILE_RECVFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_RECVFS_V2_PROC, SeafileRecvfsV2Proc)) -#define SEAFILE_IS_RECVFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_RECVFS_V2_PROC)) -#define SEAFILE_RECVFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_RECVFS_V2_PROC, SeafileRecvfsV2ProcClass)) -#define IS_SEAFILE_RECVFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_RECVFS_V2_PROC)) -#define SEAFILE_RECVFS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_RECVFS_V2_PROC, SeafileRecvfsV2ProcClass)) - -typedef struct _SeafileRecvfsV2Proc SeafileRecvfsV2Proc; -typedef struct _SeafileRecvfsV2ProcClass SeafileRecvfsV2ProcClass; - -struct _SeafileRecvfsV2Proc { - CcnetProcessor parent_instance; -}; - -struct _SeafileRecvfsV2ProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_recvfs_v2_proc_get_type (); - -#endif - diff --git a/server/processors/sync-repo-slave-proc.c b/server/processors/sync-repo-slave-proc.c deleted file mode 100644 index af19918d..00000000 --- a/server/processors/sync-repo-slave-proc.c +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include "seafile-session.h" -#include "repo-mgr.h" -#include "branch-mgr.h" -#include "commit-mgr.h" - -#include "sync-repo-slave-proc.h" -#include "sync-repo-common.h" - -#include "seaf-db.h" -#include "log.h" - -typedef struct { - char repo_id[41]; - char *branch_name; - - char *rsp_code; - char *rsp_msg; - char commit_id[41]; -} SeafileSyncRepoSlaveProcPriv; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC, SeafileSyncRepoSlaveProcPriv)) - -#define USE_PRIV \ - SeafileSyncRepoSlaveProcPriv *priv = GET_PRIV(processor); - -G_DEFINE_TYPE (SeafileSynRepoSlaveProc, seafile_sync_repo_slave_proc, CCNET_TYPE_PROCESSOR) - -static int -sync_repo_slave_start (CcnetProcessor *processor, int argc, char **argv); - -static void * -send_repo_branch_info (void *vprocessor); -static void -thread_done (void *vprocessor); - -static void -release_resource(CcnetProcessor *processor) -{ - USE_PRIV; - - /* g_free works fine even if ptr is NULL. */ - g_free (priv->branch_name); - g_free (priv->rsp_code); - g_free (priv->rsp_msg); - - CCNET_PROCESSOR_CLASS (seafile_sync_repo_slave_proc_parent_class)->release_resource (processor); -} - -static void -seafile_sync_repo_slave_proc_class_init (SeafileSynRepoSlaveProcClass *klass) -{ - CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass); - - proc_class->name = "seafile-sync-repo-slave-proc"; - proc_class->start = sync_repo_slave_start; - proc_class->release_resource = release_resource; - - g_type_class_add_private (klass, sizeof (SeafileSyncRepoSlaveProcPriv)); -} - -static void -seafile_sync_repo_slave_proc_init (SeafileSynRepoSlaveProc *processor) -{ -} - - -static int -sync_repo_slave_start (CcnetProcessor *processor, int argc, char **argv) -{ - USE_PRIV; - - if (argc != 2) { - seaf_warning ("[sync-repo-slave] argc(%d) must be 2\n", argc); - ccnet_processor_done (processor, FALSE); - return -1; - } - - if (!is_uuid_valid(argv[0])) { - seaf_warning ("Invalid repo_id %s.\n", argv[0]); - ccnet_processor_done (processor, FALSE); - return -1; - } - - memcpy (priv->repo_id, argv[0], 37); - priv->branch_name = g_strdup (argv[1]); - - /* send the head commit of the branch */ - if (ccnet_processor_thread_create (processor, - seaf->job_mgr, - send_repo_branch_info, - thread_done, - processor) < 0) { - seaf_warning ("[sync repo] failed to start thread.\n"); - ccnet_processor_send_response (processor, - SC_SERVER_ERROR, SS_SERVER_ERROR, - NULL, 0); - ccnet_processor_done (processor, FALSE); - return -1; - } - - return 0; -} - -static gboolean -get_branch (SeafDBRow *row, void *vid) -{ - char *ret = vid; - const char *commit_id; - - commit_id = seaf_db_row_get_column_text (row, 0); - memcpy (ret, commit_id, 41); - - return FALSE; -} - -static void * -send_repo_branch_info (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - char commit_id[41]; - char *sql; - USE_PRIV; - - commit_id[0] = 0; - - sql = "SELECT commit_id FROM Repo r, Branch b " - "WHERE name='master' AND r.repo_id=? AND r.repo_id = b.repo_id"; - if (seaf_db_statement_foreach_row (seaf->db, sql, - get_branch, commit_id, - 1, "string", priv->repo_id) < 0) { - seaf_warning ("DB error when get branch %s.\n", priv->branch_name); - priv->rsp_code = g_strdup (SC_REPO_CORRUPT); - priv->rsp_msg = g_strdup (SS_REPO_CORRUPT); - return vprocessor; - } - - if (commit_id[0] == 0) { - priv->rsp_code = g_strdup (SC_NO_REPO); - priv->rsp_msg = g_strdup (SS_NO_REPO); - return vprocessor; - } - - priv->rsp_code = g_strdup (SC_COMMIT_ID); - priv->rsp_msg = g_strdup (SS_COMMIT_ID); - memcpy (priv->commit_id, commit_id, 41); - - return vprocessor; -} - -static void -thread_done (void *vprocessor) -{ - CcnetProcessor *processor = vprocessor; - USE_PRIV; - - if (strcmp (priv->rsp_code, SC_COMMIT_ID) == 0) { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - priv->commit_id, 41); - ccnet_processor_done (processor, TRUE); - } else { - ccnet_processor_send_response (processor, - priv->rsp_code, priv->rsp_msg, - NULL, 0); - ccnet_processor_done (processor, TRUE); - } -} diff --git a/server/processors/sync-repo-slave-proc.h b/server/processors/sync-repo-slave-proc.h deleted file mode 100644 index df4e0467..00000000 --- a/server/processors/sync-repo-slave-proc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_SYNC_REPO_SLAVE_PROC_H -#define SEAFILE_SYNC_REPO_SLAVE_PROC_H - -#include -#include - -#define SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC (seafile_sync_repo_slave_proc_get_type ()) -#define SEAFILE_SYNC_REPO_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC, SeafileSynRepoSlaveProc)) -#define SEAFILE_IS_SYNC_REPO_SLAVE_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC)) -#define SEAFILE_SYNC_REPO_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC, SeafileSynRepoSlaveProcClass)) -#define IS_SEAFILE_SYNC_REPO_SLAVE_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC)) -#define SEAFILE_SYNC_REPO_SLAVE_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC, SeafileSynRepoSlaveProcClass)) - -typedef struct _SeafileSynRepoSlaveProc SeafileSynRepoSlaveProc; -typedef struct _SeafileSynRepoSlaveProcClass SeafileSynRepoSlaveProcClass; - -struct _SeafileSynRepoSlaveProc { - CcnetProcessor parent_instance; -}; - -struct _SeafileSynRepoSlaveProcClass { - CcnetProcessorClass parent_class; -}; - -GType seafile_sync_repo_slave_proc_get_type (); - -#endif diff --git a/server/quota-mgr.c b/server/quota-mgr.c deleted file mode 100644 index acd5e805..00000000 --- a/server/quota-mgr.c +++ /dev/null @@ -1,581 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" -#include "utils.h" - -#include -#include - -#include "seafile-session.h" -#include "seaf-db.h" -#include "quota-mgr.h" - -#define KB 1000L -#define MB 1000000L -#define GB 1000000000L -#define TB 1000000000000L - -static gint64 -get_default_quota (GKeyFile *config) -{ - char *quota_str; - char *end; - gint64 quota_int; - gint64 multiplier = GB; - gint64 quota; - - quota_str = g_key_file_get_string (config, "quota", "default", NULL); - if (!quota_str) - return INFINITE_QUOTA; - - quota_int = strtoll (quota_str, &end, 10); - if (quota_int == LLONG_MIN || quota_int == LLONG_MAX) { - seaf_warning ("Default quota value out of range. Use unlimited.\n"); - quota = INFINITE_QUOTA; - goto out; - } - - if (*end != '\0') { - if (strcasecmp(end, "kb") == 0 || strcasecmp(end, "k") == 0) - multiplier = KB; - else if (strcasecmp(end, "mb") == 0 || strcasecmp(end, "m") == 0) - multiplier = MB; - else if (strcasecmp(end, "gb") == 0 || strcasecmp(end, "g") == 0) - multiplier = GB; - else if (strcasecmp(end, "tb") == 0 || strcasecmp(end, "t") == 0) - multiplier = TB; - else { - seaf_warning ("Invalid default quota format %s. Use unlimited.\n", quota_str); - quota = INFINITE_QUOTA; - goto out; - } - } - - quota = quota_int * multiplier; - -out: - g_free (quota_str); - return quota; -} - -SeafQuotaManager * -seaf_quota_manager_new (struct _SeafileSession *session) -{ - SeafQuotaManager *mgr = g_new0 (SeafQuotaManager, 1); - if (!mgr) - return NULL; - mgr->session = session; - - mgr->default_quota = get_default_quota (session->config); - mgr->calc_share_usage = g_key_file_get_boolean (session->config, - "quota", "calc_share_usage", - NULL); - - return mgr; -} - -int -seaf_quota_manager_init (SeafQuotaManager *mgr) -{ - SeafDB *db = mgr->session->db; - const char *sql; - - switch (seaf_db_type(db)) { - case SEAF_DB_TYPE_PGSQL: - sql = "CREATE TABLE IF NOT EXISTS UserQuota (\"user\" VARCHAR(255) PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS UserShareQuota (\"user\" VARCHAR(255) PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgQuota (org_id INTEGER PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgUserQuota (org_id INTEGER," - "\"user\" VARCHAR(255), quota BIGINT, PRIMARY KEY (org_id, \"user\"))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - break; - case SEAF_DB_TYPE_SQLITE: - sql = "CREATE TABLE IF NOT EXISTS UserQuota (user VARCHAR(255) PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS UserShareQuota (user VARCHAR(255) PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgQuota (org_id INTEGER PRIMARY KEY," - "quota BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgUserQuota (org_id INTEGER," - "user VARCHAR(255), quota BIGINT, PRIMARY KEY (org_id, user))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - break; - case SEAF_DB_TYPE_MYSQL: - sql = "CREATE TABLE IF NOT EXISTS UserQuota (user VARCHAR(255) PRIMARY KEY," - "quota BIGINT) ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS UserShareQuota (user VARCHAR(255) PRIMARY KEY," - "quota BIGINT) ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgQuota (org_id INTEGER PRIMARY KEY," - "quota BIGINT) ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS OrgUserQuota (org_id INTEGER," - "user VARCHAR(255), quota BIGINT, PRIMARY KEY (org_id, user))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - break; - } - - return 0; -} - -int -seaf_quota_manager_set_user_quota (SeafQuotaManager *mgr, - const char *user, - gint64 quota) -{ - SeafDB *db = mgr->session->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - int rc; - - exists = seaf_db_statement_exists (db, - "SELECT 1 FROM UserQuota WHERE \"user\"=?", - &err, 1, "string", user); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (db, - "UPDATE UserQuota SET quota=? " - "WHERE \"user\"=?", - 2, "int64", quota, "string", user); - else - rc = seaf_db_statement_query (db, - "INSERT INTO UserQuota VALUES " - "(?, ?)", - 2, "string", user, "int64", quota); - return rc; - } else { - int rc; - rc = seaf_db_statement_query (db, - "REPLACE INTO UserQuota VALUES (?, ?)", - 2, "string", user, "int64", quota); - return rc; - } -} - -gint64 -seaf_quota_manager_get_user_quota (SeafQuotaManager *mgr, - const char *user) -{ - char *sql; - gint64 quota; - - if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL) - sql = "SELECT quota FROM UserQuota WHERE user=?"; - else - sql = "SELECT quota FROM UserQuota WHERE \"user\"=?"; - - quota = seaf_db_statement_get_int64 (mgr->session->db, sql, - 1, "string", user); - if (quota <= 0) - quota = mgr->default_quota; - - return quota; -} - -int -seaf_quota_manager_set_org_quota (SeafQuotaManager *mgr, - int org_id, - gint64 quota) -{ - SeafDB *db = mgr->session->db; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - int rc; - - exists = seaf_db_statement_exists (db, - "SELECT 1 FROM OrgQuota WHERE org_id=?", - &err, 1, "int", org_id); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (db, - "UPDATE OrgQuota SET quota=? WHERE org_id=?", - 2, "int64", quota, "int", org_id); - else - rc = seaf_db_statement_query (db, - "INSERT INTO OrgQuota VALUES (?, ?)", - 2, "int", org_id, "int64", quota); - return rc; - } else { - int rc = seaf_db_statement_query (db, - "REPLACE INTO OrgQuota VALUES (?, ?)", - 2, "int", org_id, "int64", quota); - return rc; - } -} - -gint64 -seaf_quota_manager_get_org_quota (SeafQuotaManager *mgr, - int org_id) -{ - char *sql; - gint64 quota; - - sql = "SELECT quota FROM OrgQuota WHERE org_id=?"; - quota = seaf_db_statement_get_int64 (mgr->session->db, sql, 1, "int", org_id); - if (quota <= 0) - quota = mgr->default_quota; - - return quota; -} - -int -seaf_quota_manager_set_org_user_quota (SeafQuotaManager *mgr, - int org_id, - const char *user, - gint64 quota) -{ - SeafDB *db = mgr->session->db; - int rc; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - - exists = seaf_db_statement_exists (db, - "SELECT 1 FROM OrgUserQuota " - "WHERE org_id=? AND \"user\"=?", - &err, 2, "int", org_id, "string", user); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (db, - "UPDATE OrgUserQuota SET quota=?" - " WHERE org_id=? AND \"user\"=?", - 3, "int64", quota, "int", org_id, - "string", user); - else - rc = seaf_db_statement_query (db, - "INSERT INTO OrgQuota VALUES " - "(?, ?, ?)", - 3, "int", org_id, "string", user, - "int64", quota); - return rc; - } else { - rc = seaf_db_statement_query (db, - "REPLACE INTO OrgUserQuota VALUES (?, ?, ?)", - 3, "int", org_id, "string", user, "int64", quota); - return rc; - } -} - -gint64 -seaf_quota_manager_get_org_user_quota (SeafQuotaManager *mgr, - int org_id, - const char *user) -{ - char *sql; - gint64 quota; - - if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL) - sql = "SELECT quota FROM OrgUserQuota WHERE org_id=? AND user=?"; - else - sql = "SELECT quota FROM OrgUserQuota WHERE org_id=? AND \"user\"=?"; - - quota = seaf_db_statement_get_int64 (mgr->session->db, sql, - 2, "int", org_id, "string", user); - /* return org quota if per user quota is not set. */ - if (quota <= 0) - quota = seaf_quota_manager_get_org_quota (mgr, org_id); - - return quota; -} - -static void -count_group_members (GHashTable *user_hash, GList *members) -{ - GList *p; - CcnetGroupUser *user; - const char *user_name; - int dummy; - - for (p = members; p; p = p->next) { - user = p->data; - user_name = ccnet_group_user_get_user_name (user); - g_hash_table_insert (user_hash, g_strdup(user_name), &dummy); - /* seaf_debug ("Shared to %s.\n", user_name); */ - g_object_unref (user); - } - - g_list_free (members); -} - -static gint -get_num_shared_to (const char *user, const char *repo_id) -{ - GHashTable *user_hash; - int dummy; - GList *personal = NULL, *groups = NULL, *members = NULL, *p; - SearpcClient *client = NULL; - gint n_shared_to = -1; - - /* seaf_debug ("Computing share usage for repo %s.\n", repo_id); */ - - /* If a repo is shared to both a user and a group, and that user is also - * a member of the group, we don't want to count that user twice. - * This also applies to two groups with overlapped members. - * So we have to use a hash table to filter out duplicated users. - */ - user_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - /* First count personal share */ - personal = seaf_share_manager_list_shared_to (seaf->share_mgr, user, repo_id); - for (p = personal; p; p = p->next) { - char *email = p->data; - g_hash_table_insert (user_hash, g_strdup(email), &dummy); - /* seaf_debug ("Shared to %s.\n", email); */ - } - - /* Then groups... */ - client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-threaded-rpcserver"); - if (!client) { - seaf_warning ("Failed to alloc rpc client.\n"); - goto out; - } - - groups = seaf_repo_manager_get_groups_by_repo (seaf->repo_mgr, - repo_id, NULL); - for (p = groups; p; p = p->next) { - members = ccnet_get_group_members (client, (int)(long)p->data); - if (!members) { - seaf_warning ("Cannot get member list for groupd %d.\n", (int)(long)p->data); - goto out; - } - - count_group_members (user_hash, members); - } - - /* Remove myself if i'm in a group. */ - g_hash_table_remove (user_hash, user); - - n_shared_to = g_hash_table_size(user_hash); - /* seaf_debug ("n_shared_to = %u.\n", n_shared_to); */ - -out: - g_hash_table_destroy (user_hash); - string_list_free (personal); - g_list_free (groups); - ccnet_rpc_client_free (client); - - return n_shared_to; -} - -int -seaf_quota_manager_check_quota_with_delta (SeafQuotaManager *mgr, - const char *repo_id, - gint64 delta) -{ - SeafVirtRepo *vinfo; - const char *r_repo_id = repo_id; - char *user = NULL; - gint64 quota, usage; - int ret = 0; - - /* If it's a virtual repo, check quota to origin repo. */ - vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, repo_id); - if (vinfo) - r_repo_id = vinfo->origin_repo_id; - - user = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, r_repo_id); - if (user != NULL) { - quota = seaf_quota_manager_get_user_quota (mgr, user); - } else { - seaf_warning ("Repo %s has no owner.\n", r_repo_id); - ret = -1; - goto out; - } - - if (quota == INFINITE_QUOTA) - goto out; - - usage = seaf_quota_manager_get_user_usage (mgr, user); - if (usage < 0) { - ret = -1; - goto out; - } - - if (delta != 0) { - usage += delta; - } - if (usage >= quota) { - ret = 1; - } - -out: - seaf_virtual_repo_info_free (vinfo); - g_free (user); - return ret; -} - -int -seaf_quota_manager_check_quota (SeafQuotaManager *mgr, - const char *repo_id) -{ - int ret = seaf_quota_manager_check_quota_with_delta (mgr, repo_id, 0); - - if (ret == 1) { - return -1; - } - return ret; -} - -static gboolean -get_total_size (SeafDBRow *row, void *vpsize) -{ - gint64 *psize = vpsize; - - *psize += seaf_db_row_get_column_int64 (row, 0); - - return TRUE; -} - -gint64 -seaf_quota_manager_get_user_usage (SeafQuotaManager *mgr, const char *user) -{ - char *sql; - gint64 total = 0; - - sql = "SELECT size FROM " - "RepoOwner o LEFT JOIN VirtualRepo v ON o.repo_id=v.repo_id, " - "RepoSize WHERE " - "owner_id=? AND o.repo_id=RepoSize.repo_id " - "AND v.repo_id IS NULL"; - if (seaf_db_statement_foreach_row (mgr->session->db, sql, - get_total_size, &total, - 1, "string", user) < 0) - return -1; - - /* Add size of repos in trash. */ - /* sql = "SELECT size FROM RepoTrash WHERE owner_id = ?"; */ - /* if (seaf_db_statement_foreach_row (mgr->session->db, sql, */ - /* get_total_size, &total, */ - /* 1, "string", user) < 0) */ - /* return -1; */ - - return total; -} - -static gint64 -repo_share_usage (const char *user, const char *repo_id) -{ - gint n_shared_to = get_num_shared_to (user, repo_id); - if (n_shared_to < 0) { - return -1; - } else if (n_shared_to == 0) { - return 0; - } - - gint64 size = seaf_repo_manager_get_repo_size (seaf->repo_mgr, repo_id); - if (size < 0) { - seaf_warning ("Cannot get size of repo %s.\n", repo_id); - return -1; - } - - /* share_usage = repo_size * n_shared_to */ - gint64 usage = size * n_shared_to; - - return usage; -} - -gint64 -seaf_quota_manager_get_user_share_usage (SeafQuotaManager *mgr, - const char *user) -{ - GList *repos, *p; - char *repo_id; - gint64 total = 0, per_repo; - - repos = seaf_repo_manager_get_repo_ids_by_owner (seaf->repo_mgr, user); - - for (p = repos; p != NULL; p = p->next) { - repo_id = p->data; - per_repo = repo_share_usage (user, repo_id); - if (per_repo < 0) { - seaf_warning ("Failed to get repo %s share usage.\n", repo_id); - string_list_free (repos); - return -1; - } - - total += per_repo; - } - - string_list_free (repos); - return total; -} - -gint64 -seaf_quota_manager_get_org_usage (SeafQuotaManager *mgr, int org_id) -{ - char *sql; - gint64 ret = 0; - - sql = "SELECT size FROM OrgRepo, RepoSize WHERE " - "org_id=? AND OrgRepo.repo_id=RepoSize.repo_id"; - if (seaf_db_statement_foreach_row (mgr->session->db, sql, - get_total_size, &ret, - 1, "int", org_id) < 0) - return -1; - - return ret; -} - -gint64 -seaf_quota_manager_get_org_user_usage (SeafQuotaManager *mgr, - int org_id, - const char *user) -{ - char *sql; - gint64 ret = 0; - - sql = "SELECT size FROM OrgRepo, RepoSize WHERE " - "org_id=? AND user = ? AND OrgRepo.repo_id=RepoSize.repo_id"; - if (seaf_db_statement_foreach_row (mgr->session->db, sql, - get_total_size, &ret, - 2, "int", org_id, "string", user) < 0) - return -1; - - return ret; -} diff --git a/server/quota-mgr.h b/server/quota-mgr.h deleted file mode 100644 index c5a53021..00000000 --- a/server/quota-mgr.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef QUOTA_MGR_H -#define QUOTA_MGR_H - -#define INFINITE_QUOTA (gint64)-2 - -struct _SeafQuotaManager { - struct _SeafileSession *session; - - gint64 default_quota; - gboolean calc_share_usage; -}; -typedef struct _SeafQuotaManager SeafQuotaManager; - -SeafQuotaManager * -seaf_quota_manager_new (struct _SeafileSession *session); - -int -seaf_quota_manager_init (SeafQuotaManager *mgr); - -/* Set/get quota for a personal account. */ -int -seaf_quota_manager_set_user_quota (SeafQuotaManager *mgr, - const char *user, - gint64 quota); - -gint64 -seaf_quota_manager_get_user_quota (SeafQuotaManager *mgr, - const char *user); - -gint64 -seaf_quota_manager_get_user_share_usage (SeafQuotaManager *mgr, - const char *user); - -/* - * Check if @repo_id still has free space for upload. - */ -int -seaf_quota_manager_check_quota (SeafQuotaManager *mgr, - const char *repo_id); - -// ret = 0 means doesn't exceed quota, -// 1 means exceed quota, -// -1 means internal error -int -seaf_quota_manager_check_quota_with_delta (SeafQuotaManager *mgr, - const char *repo_id, - gint64 delta); - -gint64 -seaf_quota_manager_get_user_usage (SeafQuotaManager *mgr, const char *user); - -#endif diff --git a/server/repo-mgr.c b/server/repo-mgr.c deleted file mode 100644 index d2a83df9..00000000 --- a/server/repo-mgr.c +++ /dev/null @@ -1,3477 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include - -#include -#include - -#include -#include -#include "utils.h" -#include "log.h" -#include "seafile.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "fs-mgr.h" -#include "seafile-error.h" -#include "seafile-crypt.h" - -#include "seaf-db.h" - -#define REAP_TOKEN_INTERVAL 300 /* 5 mins */ -#define DECRYPTED_TOKEN_TTL 3600 /* 1 hour */ -#define SCAN_TRASH_DAYS 1 /* one day */ -#define TRASH_EXPIRE_DAYS 30 /* one month */ - -typedef struct DecryptedToken { - char *token; - gint64 reap_time; -} DecryptedToken; - -struct _SeafRepoManagerPriv { - /* (encrypted_token, session_key) -> decrypted token */ - GHashTable *decrypted_tokens; - pthread_rwlock_t lock; - CcnetTimer *reap_token_timer; - - CcnetTimer *scan_trash_timer; - gint64 trash_expire_interval; -}; - -static const char *ignore_table[] = { - /* tmp files under Linux */ - "*~", - /* Emacs tmp files */ - "#*#", - /* ms office tmp files */ - "~$*", - "~*.tmp", /* for files like ~WRL0001.tmp */ - /* windows image cache */ - "Thumbs.db", - /* For Mac */ - ".DS_Store", - NULL, -}; - -static GPatternSpec** ignore_patterns; - -static void -load_repo (SeafRepoManager *manager, SeafRepo *repo); - -static int create_db_tables_if_not_exist (SeafRepoManager *mgr); - -static int save_branch_repo_map (SeafRepoManager *manager, SeafBranch *branch); - -static int reap_token (void *data); -static void decrypted_token_free (DecryptedToken *token); - -gboolean -is_repo_id_valid (const char *id) -{ - if (!id) - return FALSE; - - return is_uuid_valid (id); -} - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc) -{ - SeafRepo* repo; - - /* valid check */ - - - repo = g_new0 (SeafRepo, 1); - memcpy (repo->id, id, 36); - repo->id[36] = '\0'; - - repo->name = g_strdup(name); - repo->desc = g_strdup(desc); - - repo->ref_cnt = 1; - - return repo; -} - -void -seaf_repo_free (SeafRepo *repo) -{ - if (repo->name) g_free (repo->name); - if (repo->desc) g_free (repo->desc); - if (repo->head) seaf_branch_unref (repo->head); - if (repo->virtual_info) - seaf_virtual_repo_info_free (repo->virtual_info); - g_free (repo); -} - -void -seaf_repo_ref (SeafRepo *repo) -{ - g_atomic_int_inc (&repo->ref_cnt); -} - -void -seaf_repo_unref (SeafRepo *repo) -{ - if (!repo) - return; - - if (g_atomic_int_dec_and_test (&repo->ref_cnt)) - seaf_repo_free (repo); -} - -static void -set_head_common (SeafRepo *repo, SeafBranch *branch) -{ - if (repo->head) - seaf_branch_unref (repo->head); - repo->head = branch; - seaf_branch_ref(branch); -} - -int -seaf_repo_set_head (SeafRepo *repo, SeafBranch *branch) -{ - if (save_branch_repo_map (repo->manager, branch) < 0) - return -1; - set_head_common (repo, branch); - return 0; -} - -void -seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit) -{ - repo->name = g_strdup (commit->repo_name); - repo->desc = g_strdup (commit->repo_desc); - repo->encrypted = commit->encrypted; - repo->repaired = commit->repaired; - repo->last_modify = commit->ctime; - memcpy (repo->root_id, commit->root_id, 40); - if (repo->encrypted) { - repo->enc_version = commit->enc_version; - if (repo->enc_version == 1) - memcpy (repo->magic, commit->magic, 32); - else if (repo->enc_version == 2) { - memcpy (repo->magic, commit->magic, 64); - memcpy (repo->random_key, commit->random_key, 96); - } - } - repo->no_local_history = commit->no_local_history; - repo->version = commit->version; -} - -void -seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit) -{ - commit->repo_name = g_strdup (repo->name); - commit->repo_desc = g_strdup (repo->desc); - commit->encrypted = repo->encrypted; - commit->repaired = repo->repaired; - if (commit->encrypted) { - commit->enc_version = repo->enc_version; - if (commit->enc_version == 1) - commit->magic = g_strdup (repo->magic); - else if (commit->enc_version == 2) { - commit->magic = g_strdup (repo->magic); - commit->random_key = g_strdup (repo->random_key); - } - } - commit->no_local_history = repo->no_local_history; - commit->version = repo->version; -} - -static gboolean -collect_commit (SeafCommit *commit, void *vlist, gboolean *stop) -{ - GList **commits = vlist; - - /* The traverse function will unref the commit, so we need to ref it. - */ - seaf_commit_ref (commit); - *commits = g_list_prepend (*commits, commit); - return TRUE; -} - -GList * -seaf_repo_get_commits (SeafRepo *repo) -{ - GList *branches; - GList *ptr; - SeafBranch *branch; - GList *commits = NULL; - - branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); - if (branches == NULL) { - seaf_warning ("Failed to get branch list of repo %s.\n", repo->id); - return NULL; - } - - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - branch = ptr->data; - gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, - repo->version, - branch->commit_id, - collect_commit, - &commits, - FALSE); - if (!res) { - for (ptr = commits; ptr != NULL; ptr = ptr->next) - seaf_commit_unref ((SeafCommit *)(ptr->data)); - g_list_free (commits); - goto out; - } - } - - commits = g_list_reverse (commits); - -out: - for (ptr = branches; ptr != NULL; ptr = ptr->next) { - seaf_branch_unref ((SeafBranch *)ptr->data); - } - return commits; -} - -gboolean -should_ignore_file(const char *filename, void *data) -{ - /* GPatternSpec **spec = ignore_patterns; */ - - if (!g_utf8_validate (filename, -1, NULL)) { - seaf_warning ("File name %s contains non-UTF8 characters, skip.\n", filename); - return TRUE; - } - - /* Ignore file/dir if its name is too long. */ - if (strlen(filename) >= SEAF_DIR_NAME_LEN) - return TRUE; - - if (strchr (filename, '/')) - return TRUE; - - return FALSE; -} - -static gboolean -collect_repo_id (SeafDBRow *row, void *data); - -static int -scan_trash (void *data) -{ - GList *repo_ids = NULL; - SeafRepoManager *mgr = seaf->repo_mgr; - gint64 expire_time = time(NULL) - mgr->priv->trash_expire_interval; - char *sql = "SELECT repo_id FROM RepoTrash WHERE del_time <= ?"; - - int ret = seaf_db_statement_foreach_row (seaf->db, sql, - collect_repo_id, &repo_ids, - 1, "int64", expire_time); - if (ret < 0) { - seaf_warning ("Get expired repo from trash failed."); - string_list_free (repo_ids); - return TRUE; - } - - GList *iter; - char *repo_id; - for (iter=repo_ids; iter; iter=iter->next) { - repo_id = iter->data; - ret = seaf_repo_manager_del_repo_from_trash (mgr, repo_id, NULL); - if (ret < 0) - break; - } - - string_list_free (repo_ids); - - return TRUE; -} - -static void -init_scan_trash_timer (SeafRepoManagerPriv *priv, GKeyFile *config) -{ - int scan_days; - int expire_days; - GError *error = NULL; - - scan_days = g_key_file_get_integer (config, - "library_trash", "scan_days", - &error); - if (error) { - scan_days = SCAN_TRASH_DAYS; - g_clear_error (&error); - } - - expire_days = g_key_file_get_integer (config, - "library_trash", "expire_days", - &error); - if (error) { - expire_days = TRASH_EXPIRE_DAYS; - g_clear_error (&error); - } - - priv->trash_expire_interval = expire_days * 24 * 3600; - priv->scan_trash_timer = ccnet_timer_new (scan_trash, NULL, - scan_days * 24 * 3600 * 1000); -} - -SeafRepoManager* -seaf_repo_manager_new (SeafileSession *seaf) -{ - SeafRepoManager *mgr = g_new0 (SeafRepoManager, 1); - - mgr->priv = g_new0 (SeafRepoManagerPriv, 1); - mgr->seaf = seaf; - - mgr->priv->decrypted_tokens = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, - (GDestroyNotify)decrypted_token_free); - pthread_rwlock_init (&mgr->priv->lock, NULL); - mgr->priv->reap_token_timer = ccnet_timer_new (reap_token, mgr, - REAP_TOKEN_INTERVAL * 1000); - - init_scan_trash_timer (mgr->priv, seaf->config); - - /* ignore_patterns = g_new0 (GPatternSpec*, G_N_ELEMENTS(ignore_table)); */ - /* int i; */ - /* for (i = 0; ignore_table[i] != NULL; i++) { */ - /* ignore_patterns[i] = g_pattern_spec_new (ignore_table[i]); */ - /* } */ - - return mgr; -} - -int -seaf_repo_manager_init (SeafRepoManager *mgr) -{ - /* On the server, we load repos into memory on-demand, because - * there are too many repos. - */ - if (create_db_tables_if_not_exist (mgr) < 0) { - seaf_warning ("[repo mgr] failed to create tables.\n"); - return -1; - } - - if (seaf_repo_manager_init_merge_scheduler() < 0) { - seaf_warning ("Failed to init merge scheduler.\n"); - return -1; - } - - return 0; -} - -int -seaf_repo_manager_start (SeafRepoManager *mgr) -{ - return 0; -} - -int -seaf_repo_manager_add_repo (SeafRepoManager *manager, - SeafRepo *repo) -{ - SeafDB *db = manager->seaf->db; - - if (seaf_db_statement_query (db, "INSERT INTO Repo VALUES (?)", - 1, "string", repo->id) < 0) - return -1; - - repo->manager = manager; - - return 0; -} - -static int -add_deleted_repo_record (SeafRepoManager *mgr, const char *repo_id) -{ - if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - - exists = seaf_db_statement_exists (seaf->db, - "SELECT repo_id FROM GarbageRepos " - "WHERE repo_id=?", - &err, 1, "string", repo_id); - if (err) - return -1; - - if (!exists) { - return seaf_db_statement_query(seaf->db, - "INSERT INTO GarbageRepos VALUES (?)", - 1, "string", repo_id); - } - - return 0; - } else { - return seaf_db_statement_query (seaf->db, - "REPLACE INTO GarbageRepos VALUES (?)", - 1, "string", repo_id); - } -} - -static int -add_deleted_repo_to_trash (SeafRepoManager *mgr, const char *repo_id, - SeafCommit *commit) -{ - char *owner = NULL; - int ret = -1; - - owner = seaf_repo_manager_get_repo_owner (mgr, repo_id); - if (!owner) { - seaf_warning ("Failed to get owner for repo %.8s.\n", repo_id); - goto out; - } - - gint64 size = seaf_repo_manager_get_repo_size (mgr, repo_id); - if (size == -1) { - seaf_warning ("Failed to get size of repo %.8s.\n", repo_id); - goto out; - } - - ret = seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO RepoTrash (repo_id, repo_name, head_id, " - "owner_id, size, org_id, del_time) " - "values (?, ?, ?, ?, ?, -1, ?)", 6, - "string", repo_id, - "string", commit->repo_name, - "string", commit->commit_id, - "string", owner, - "int64", size, - "int64", time(NULL)); -out: - g_free (owner); - - return ret; -} - -static int -remove_virtual_repo_ondisk (SeafRepoManager *mgr, - const char *repo_id) -{ - SeafDB *db = mgr->seaf->db; - - /* Remove record in repo table first. - * Once this is commited, we can gc the other tables later even if - * we're interrupted. - */ - if (seaf_db_statement_query (db, "DELETE FROM Repo WHERE repo_id = ?", - 1, "string", repo_id) < 0) - return -1; - - /* remove branch */ - GList *p; - GList *branch_list = - seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo_id); - for (p = branch_list; p; p = p->next) { - SeafBranch *b = (SeafBranch *)p->data; - seaf_repo_manager_branch_repo_unmap (mgr, b); - seaf_branch_manager_del_branch (seaf->branch_mgr, repo_id, b->name); - } - seaf_branch_list_free (branch_list); - - seaf_db_statement_query (db, "DELETE FROM RepoOwner WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (db, "DELETE FROM SharedRepo WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (db, "DELETE FROM RepoGroup WHERE repo_id = ?", - 1, "string", repo_id); - - if (!seaf->cloud_mode) { - seaf_db_statement_query (db, "DELETE FROM InnerPubRepo WHERE repo_id = ?", - 1, "string", repo_id); - } - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoUserToken WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoValidSince WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoSize WHERE repo_id = ?", - 1, "string", repo_id); - - /* For GC commit objects for this virtual repo. Fs and blocks are GC - * from the parent repo. - */ - add_deleted_repo_record (mgr, repo_id); - - return 0; -} - -static gboolean -get_branch (SeafDBRow *row, void *vid) -{ - char *ret = vid; - const char *commit_id; - - commit_id = seaf_db_row_get_column_text (row, 0); - memcpy (ret, commit_id, 41); - - return FALSE; -} - -static SeafCommit* -get_head_commit (SeafRepoManager *mgr, const char *repo_id, gboolean *has_err) -{ - char commit_id[41]; - char *sql; - - commit_id[0] = 0; - sql = "SELECT commit_id FROM Branch WHERE name=? AND repo_id=?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - get_branch, commit_id, - 2, "string", "master", "string", repo_id) < 0) { - *has_err = TRUE; - return NULL; - } - - if (commit_id[0] == 0) - return NULL; - - SeafCommit *head_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo_id, - 1, commit_id); - - return head_commit; -} - -int -seaf_repo_manager_del_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - gboolean has_err = FALSE; - - SeafCommit *head_commit = get_head_commit (mgr, repo_id, &has_err); - if (has_err) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get head commit from db"); - return -1; - } - if (!head_commit) { - // head commit is missing, del repo directly - goto del_repo; - } - - if (add_deleted_repo_to_trash (mgr, repo_id, head_commit) < 0) { - // Add repo to trash failed, del repo directly - seaf_warning ("Failed to add repo %.8s to trash, delete directly.\n", - repo_id); - } - - seaf_commit_unref (head_commit); - -del_repo: - if (seaf_db_statement_query (mgr->seaf->db, "DELETE FROM Repo WHERE repo_id = ?", - 1, "string", repo_id) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to delete repo from db"); - return -1; - } - - /* remove branch */ - GList *p; - GList *branch_list = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo_id); - for (p = branch_list; p; p = p->next) { - SeafBranch *b = (SeafBranch *)p->data; - seaf_repo_manager_branch_repo_unmap (mgr, b); - seaf_branch_manager_del_branch (seaf->branch_mgr, repo_id, b->name); - } - seaf_branch_list_free (branch_list); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM RepoOwner WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM SharedRepo WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM RepoGroup WHERE repo_id = ?", - 1, "string", repo_id); - - if (!seaf->cloud_mode) { - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM InnerPubRepo WHERE repo_id = ?", - 1, "string", repo_id); - } - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoUserToken WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoHistoryLimit WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoValidSince WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoSize WHERE repo_id = ?", - 1, "string", repo_id); - - /* Remove virtual repos when origin repo is deleted. */ - GList *vrepos, *ptr; - vrepos = seaf_repo_manager_get_virtual_repo_ids_by_origin (mgr, repo_id); - for (ptr = vrepos; ptr != NULL; ptr = ptr->next) - remove_virtual_repo_ondisk (mgr, (char *)ptr->data); - string_list_free (vrepos); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM VirtualRepo " - "WHERE repo_id=? OR origin_repo=?", - 2, "string", repo_id, "string", repo_id); - - return 0; -} - -int -seaf_repo_manager_del_virtual_repo (SeafRepoManager *mgr, - const char *repo_id) -{ - int ret = remove_virtual_repo_ondisk (mgr, repo_id); - - if (ret < 0) - return ret; - - return seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM VirtualRepo WHERE repo_id = ?", - 1, "string", repo_id); -} - -static gboolean -repo_exists_in_db (SeafDB *db, const char *id, gboolean *db_err) -{ - return seaf_db_statement_exists (db, - "SELECT repo_id FROM Repo WHERE repo_id = ?", - db_err, 1, "string", id); -} - -gboolean -create_repo_fill_size (SeafDBRow *row, void *data) -{ - SeafRepo **repo = data; - - const char *repo_id = seaf_db_row_get_column_text (row, 0); - gint64 size = seaf_db_row_get_column_int64 (row, 1); - - *repo = seaf_repo_new (repo_id, NULL, NULL); - if (!*repo) - return FALSE; - - (*repo)->size = size; - - return TRUE; -} - -static SeafRepo* -get_repo_from_db (SeafRepoManager *mgr, const char *id, gboolean *db_err) -{ - SeafRepo *repo = NULL; - const char *sql = "SELECT r.repo_id, s.size FROM Repo r left join RepoSize s " - "ON r.repo_id = s.repo_id WHERE r.repo_id = ?"; - - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - create_repo_fill_size, &repo, - 1, "string", id); - if (ret < 0) - *db_err = TRUE; - - return repo; -} - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id) -{ - int len = strlen(id); - gboolean db_err = FALSE; - SeafRepo *repo = NULL; - - if (len >= 37) - return NULL; - - repo = get_repo_from_db (manager, id, &db_err); - - if (repo) { - load_repo (manager, repo); - if (repo->is_corrupted) { - seaf_repo_unref (repo); - return NULL; - } - } - - return repo; -} - -SeafRepo* -seaf_repo_manager_get_repo_ex (SeafRepoManager *manager, const gchar *id) -{ - int len = strlen(id); - gboolean db_err = FALSE; - SeafRepo *ret = NULL; - - if (len >= 37) - return NULL; - - ret = get_repo_from_db (manager, id, &db_err); - if (db_err) { - ret = seaf_repo_new(id, NULL, NULL); - ret->is_corrupted = TRUE; - return ret; - } - - if (ret) { - load_repo (manager, ret); - } - - return ret; -} - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id) -{ - gboolean db_err = FALSE; - return repo_exists_in_db (manager->seaf->db, id, &db_err); -} - -static int -save_branch_repo_map (SeafRepoManager *manager, SeafBranch *branch) -{ - if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - int rc; - - exists = seaf_db_statement_exists (seaf->db, - "SELECT repo_id FROM RepoHead WHERE repo_id=?", - &err, 1, "string", branch->repo_id); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (seaf->db, - "UPDATE RepoHead SET branch_name=? " - "WHERE repo_id=?", - 2, "string", branch->name, - "string", branch->repo_id); - else - rc = seaf_db_statement_query (seaf->db, - "INSERT INTO RepoHead VALUES (?, ?)", - 2, "string", branch->repo_id, - "string", branch->name); - return rc; - } else { - return seaf_db_statement_query (seaf->db, - "REPLACE INTO RepoHead VALUES (?, ?)", - 2, "string", branch->repo_id, - "string", branch->name); - } - - return -1; -} - -int -seaf_repo_manager_branch_repo_unmap (SeafRepoManager *manager, SeafBranch *branch) -{ - return seaf_db_statement_query (seaf->db, - "DELETE FROM RepoHead WHERE branch_name = ?" - " AND repo_id = ?", - 2, "string", branch->name, - "string", branch->repo_id); -} - -static void -load_repo_commit (SeafRepoManager *manager, - SeafRepo *repo, - SeafBranch *branch) -{ - SeafCommit *commit; - - commit = seaf_commit_manager_get_commit_compatible (manager->seaf->commit_mgr, - repo->id, - branch->commit_id); - if (!commit) { - seaf_warning ("Commit %s:%s is missing\n", repo->id, branch->commit_id); - repo->is_corrupted = TRUE; - return; - } - - set_head_common (repo, branch); - seaf_repo_from_commit (repo, commit); - - seaf_commit_unref (commit); -} - -static void -load_repo (SeafRepoManager *manager, SeafRepo *repo) -{ - SeafBranch *branch; - - repo->manager = manager; - - branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, "master"); - if (!branch) { - seaf_warning ("Failed to get master branch of repo %.8s.\n", repo->id); - repo->is_corrupted = TRUE; - } else { - load_repo_commit (manager, repo, branch); - seaf_branch_unref (branch); - } - - if (repo->is_corrupted) { - return; - } - - /* Load virtual repo info if any. */ - repo->virtual_info = seaf_repo_manager_get_virtual_repo_info (manager, repo->id); - if (repo->virtual_info) - memcpy (repo->store_id, repo->virtual_info->origin_repo_id, 36); - else - memcpy (repo->store_id, repo->id, 36); -} - -static int -create_tables_mysql (SeafRepoManager *mgr) -{ - SeafDB *db = mgr->seaf->db; - char *sql; - - sql = "CREATE TABLE IF NOT EXISTS Repo (repo_id CHAR(37) PRIMARY KEY)" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoOwner (" - "repo_id CHAR(37) PRIMARY KEY, " - "owner_id VARCHAR(255)," - "INDEX (owner_id))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoGroup (repo_id CHAR(37), " - "group_id INTEGER, user_name VARCHAR(255), permission CHAR(15), " - "UNIQUE INDEX (group_id, repo_id), " - "INDEX (repo_id), INDEX (user_name))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS InnerPubRepo (" - "repo_id CHAR(37) PRIMARY KEY," - "permission CHAR(15))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoUserToken (" - "repo_id CHAR(37), " - "email VARCHAR(255), " - "token CHAR(41), " - "UNIQUE INDEX (repo_id, token), INDEX (email))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoTokenPeerInfo (" - "token CHAR(41) PRIMARY KEY, " - "peer_id CHAR(41), " - "peer_ip VARCHAR(41), " - "peer_name VARCHAR(255), " - "sync_time BIGINT, " - "client_ver VARCHAR(20))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHead (" - "repo_id CHAR(37) PRIMARY KEY, branch_name VARCHAR(10))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoSize (" - "repo_id CHAR(37) PRIMARY KEY," - "size BIGINT UNSIGNED," - "head_id CHAR(41))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHistoryLimit (" - "repo_id CHAR(37) PRIMARY KEY, days INTEGER)" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoValidSince (" - "repo_id CHAR(37) PRIMARY KEY, timestamp BIGINT)" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS WebAP (repo_id CHAR(37) PRIMARY KEY, " - "access_property CHAR(10))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS VirtualRepo (repo_id CHAR(36) PRIMARY KEY," - "origin_repo CHAR(36), path TEXT, base_commit CHAR(40), INDEX(origin_repo))" - "ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id CHAR(36) PRIMARY KEY)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoTrash (repo_id CHAR(36) PRIMARY KEY," - "repo_name VARCHAR(255), head_id CHAR(40), owner_id VARCHAR(255)," - "size BIGINT(20), org_id INTEGER, del_time BIGINT, " - "INDEX(owner_id), INDEX(org_id))ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoFileCount (" - "repo_id CHAR(36) PRIMARY KEY," - "file_count BIGINT UNSIGNED)ENGINE=INNODB"; - if (seaf_db_query (db, sql) < 0) - return -1; - - return 0; -} - -static int -create_tables_sqlite (SeafRepoManager *mgr) -{ - SeafDB *db = mgr->seaf->db; - char *sql; - - sql = "CREATE TABLE IF NOT EXISTS Repo (repo_id CHAR(37) PRIMARY KEY)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - /* Owner */ - - sql = "CREATE TABLE IF NOT EXISTS RepoOwner (" - "repo_id CHAR(37) PRIMARY KEY, " - "owner_id TEXT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - sql = "CREATE INDEX IF NOT EXISTS OwnerIndex ON RepoOwner (owner_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - /* Group repo */ - - sql = "CREATE TABLE IF NOT EXISTS RepoGroup (repo_id CHAR(37), " - "group_id INTEGER, user_name TEXT, permission CHAR(15))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE UNIQUE INDEX IF NOT EXISTS groupid_repoid_indx on " - "RepoGroup (group_id, repo_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS repogroup_repoid_index on " - "RepoGroup (repo_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS repogroup_username_indx on " - "RepoGroup (user_name)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - /* Public repo */ - - sql = "CREATE TABLE IF NOT EXISTS InnerPubRepo (" - "repo_id CHAR(37) PRIMARY KEY," - "permission CHAR(15))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoUserToken (" - "repo_id CHAR(37), " - "email VARCHAR(255), " - "token CHAR(41))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE UNIQUE INDEX IF NOT EXISTS repo_token_indx on " - "RepoUserToken (repo_id, token)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS repo_token_email_indx on " - "RepoUserToken (email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoTokenPeerInfo (" - "token CHAR(41) PRIMARY KEY, " - "peer_id CHAR(41), " - "peer_ip VARCHAR(41), " - "peer_name VARCHAR(255), " - "sync_time BIGINT, " - "client_ver VARCHAR(20))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHead (" - "repo_id CHAR(37) PRIMARY KEY, branch_name VARCHAR(10))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoSize (" - "repo_id CHAR(37) PRIMARY KEY," - "size BIGINT UNSIGNED," - "head_id CHAR(41))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHistoryLimit (" - "repo_id CHAR(37) PRIMARY KEY, days INTEGER)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoValidSince (" - "repo_id CHAR(37) PRIMARY KEY, timestamp BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS WebAP (repo_id CHAR(37) PRIMARY KEY, " - "access_property CHAR(10))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS VirtualRepo (repo_id CHAR(36) PRIMARY KEY," - "origin_repo CHAR(36), path TEXT, base_commit CHAR(40))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS virtualrepo_origin_repo_idx " - "ON VirtualRepo (origin_repo)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id CHAR(36) PRIMARY KEY)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoTrash (repo_id CHAR(36) PRIMARY KEY," - "repo_name VARCHAR(255), head_id CHAR(40), owner_id VARCHAR(255), size BIGINT UNSIGNED," - "org_id INTEGER, del_time BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS repotrash_owner_id_idx ON RepoTrash(owner_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE INDEX IF NOT EXISTS repotrash_org_id_idx ON RepoTrash(org_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoFileCount (" - "repo_id CHAR(36) PRIMARY KEY," - "file_count BIGINT UNSIGNED)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - return 0; -} - -static int -create_tables_pgsql (SeafRepoManager *mgr) -{ - SeafDB *db = mgr->seaf->db; - char *sql; - - sql = "CREATE TABLE IF NOT EXISTS Repo (repo_id CHAR(36) PRIMARY KEY)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoOwner (" - "repo_id CHAR(36) PRIMARY KEY, " - "owner_id VARCHAR(255))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "repoowner_owner_idx")) { - sql = "CREATE INDEX repoowner_owner_idx ON RepoOwner (owner_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - sql = "CREATE TABLE IF NOT EXISTS RepoGroup (repo_id CHAR(36), " - "group_id INTEGER, user_name VARCHAR(255), permission VARCHAR(15), " - "UNIQUE (group_id, repo_id))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "repogroup_repoid_idx")) { - sql = "CREATE INDEX repogroup_repoid_idx ON RepoGroup (repo_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - if (!pgsql_index_exists (db, "repogroup_username_idx")) { - sql = "CREATE INDEX repogroup_username_idx ON RepoGroup (user_name)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - sql = "CREATE TABLE IF NOT EXISTS InnerPubRepo (" - "repo_id CHAR(36) PRIMARY KEY," - "permission VARCHAR(15))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoUserToken (" - "repo_id CHAR(36), " - "email VARCHAR(255), " - "token CHAR(40), " - "UNIQUE (repo_id, token))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "repousertoken_email_idx")) { - sql = "CREATE INDEX repousertoken_email_idx ON RepoUserToken (email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - sql = "CREATE TABLE IF NOT EXISTS RepoTokenPeerInfo (" - "token CHAR(40) PRIMARY KEY, " - "peer_id CHAR(40), " - "peer_ip VARCHAR(40), " - "peer_name VARCHAR(255), " - "sync_time BIGINT, " - "client_ver VARCHAR(20))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHead (" - "repo_id CHAR(36) PRIMARY KEY, branch_name VARCHAR(10))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoSize (" - "repo_id CHAR(36) PRIMARY KEY," - "size BIGINT," - "head_id CHAR(40))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoHistoryLimit (" - "repo_id CHAR(36) PRIMARY KEY, days INTEGER)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoValidSince (" - "repo_id CHAR(36) PRIMARY KEY, timestamp BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS WebAP (repo_id CHAR(36) PRIMARY KEY, " - "access_property VARCHAR(10))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS VirtualRepo (repo_id CHAR(36) PRIMARY KEY," - "origin_repo CHAR(36), path TEXT, base_commit CHAR(40))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "virtualrepo_origin_repo_idx")) { - sql = "CREATE INDEX virtualrepo_origin_repo_idx ON VirtualRepo (origin_repo)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - sql = "CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id CHAR(36) PRIMARY KEY)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - sql = "CREATE TABLE IF NOT EXISTS RepoTrash (repo_id CHAR(36) PRIMARY KEY," - "repo_name VARCHAR(255), head_id CHAR(40), owner_id VARCHAR(255), size bigint," - "org_id INTEGER, del_time BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "repotrash_owner_id")) { - sql = "CREATE INDEX repotrash_owner_id on RepoTrash(owner_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - if (!pgsql_index_exists (db, "repotrash_org_id")) { - sql = "CREATE INDEX repotrash_org_id on RepoTrash(org_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - - sql = "CREATE TABLE IF NOT EXISTS RepoFileCount (" - "repo_id CHAR(36) PRIMARY KEY," - "file_count BIGINT)"; - if (seaf_db_query (db, sql) < 0) - return -1; - - return 0; -} - -static int -create_db_tables_if_not_exist (SeafRepoManager *mgr) -{ - SeafDB *db = mgr->seaf->db; - int db_type = seaf_db_type (db); - - if (db_type == SEAF_DB_TYPE_MYSQL) - return create_tables_mysql (mgr); - else if (db_type == SEAF_DB_TYPE_SQLITE) - return create_tables_sqlite (mgr); - else if (db_type == SEAF_DB_TYPE_PGSQL) - return create_tables_pgsql (mgr); - - g_return_val_if_reached (-1); -} - -/* - * Repo properties functions. - */ - -static inline char * -generate_repo_token () -{ - char *uuid = gen_uuid (); - unsigned char sha1[20]; - char token[41]; - SHA_CTX s; - - SHA1_Init (&s); - SHA1_Update (&s, uuid, strlen(uuid)); - SHA1_Final (sha1, &s); - - rawdata_to_hex (sha1, token, 20); - - g_free (uuid); - - return g_strdup (token); -} - -static int -add_repo_token (SeafRepoManager *mgr, - const char *repo_id, - const char *email, - const char *token, - GError **error) -{ - int rc = seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO RepoUserToken VALUES (?, ?, ?)", - 3, "string", repo_id, "string", email, - "string", token); - - if (rc < 0) { - seaf_warning ("failed to add repo token. repo = %s, email = %s\n", - repo_id, email); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - return -1; - } - - return 0; -} - -char * -seaf_repo_manager_generate_repo_token (SeafRepoManager *mgr, - const char *repo_id, - const char *email, - GError **error) -{ - char *token = generate_repo_token (); - if (add_repo_token (mgr, repo_id, email, token, error) < 0) { - g_free (token); - return NULL; - } - - return token; -} - -int -seaf_repo_manager_add_token_peer_info (SeafRepoManager *mgr, - const char *token, - const char *peer_id, - const char *peer_ip, - const char *peer_name, - gint64 sync_time, - const char *client_ver) -{ - int ret = 0; - - if (seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO RepoTokenPeerInfo VALUES (" - "?, ?, ?, ?, ?, ?)", - 6, "string", token, - "string", peer_id, - "string", peer_ip, - "string", peer_name, - "int64", sync_time, - "string", client_ver) < 0) - ret = -1; - - return ret; -} - -int -seaf_repo_manager_update_token_peer_info (SeafRepoManager *mgr, - const char *token, - const char *peer_ip, - gint64 sync_time, - const char *client_ver) -{ - int ret = 0; - - if (seaf_db_statement_query (mgr->seaf->db, - "UPDATE RepoTokenPeerInfo SET " - "peer_ip=?, sync_time=?, client_ver=? WHERE token=?", - 4, "string", peer_ip, - "int64", sync_time, - "string", client_ver, - "string", token) < 0) - ret = -1; - - return ret; -} - -gboolean -seaf_repo_manager_token_peer_info_exists (SeafRepoManager *mgr, - const char *token) -{ - gboolean db_error = FALSE; - - return seaf_db_statement_exists (mgr->seaf->db, - "SELECT token FROM RepoTokenPeerInfo WHERE token=?", - &db_error, 1, "string", token); -} - -int -seaf_repo_manager_delete_token (SeafRepoManager *mgr, - const char *repo_id, - const char *token, - const char *user, - GError **error) -{ - char *token_owner; - - token_owner = seaf_repo_manager_get_email_by_token (mgr, repo_id, token); - if (!token_owner || strcmp (user, token_owner) != 0) { - seaf_warning ("Requesting user is %s, token owner is %s, " - "refuse to delete token %.10s.\n", user, token_owner, token); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Permission denied"); - return -1; - } - - if (seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoUserToken " - "WHERE repo_id=? and token=?", - 2, "string", repo_id, "string", token) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - return -1; - } - - if (seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoTokenPeerInfo WHERE token=?", - 1, "string", token) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - return -1; - } - - GList *tokens = NULL; - tokens = g_list_append (tokens, g_strdup(token)); - seaf_http_server_invalidate_tokens (seaf->http_server, tokens); - g_list_free_full (tokens, (GDestroyNotify)g_free); - - return 0; -} - -static gboolean -collect_repo_token (SeafDBRow *row, void *data) -{ - GList **ret_list = data; - const char *repo_id, *repo_owner, *email, *token; - const char *peer_id, *peer_ip, *peer_name; - gint64 sync_time; - const char *client_ver; - - repo_id = seaf_db_row_get_column_text (row, 0); - repo_owner = seaf_db_row_get_column_text (row, 1); - email = seaf_db_row_get_column_text (row, 2); - token = seaf_db_row_get_column_text (row, 3); - - peer_id = seaf_db_row_get_column_text (row, 4); - peer_ip = seaf_db_row_get_column_text (row, 5); - peer_name = seaf_db_row_get_column_text (row, 6); - sync_time = seaf_db_row_get_column_int64 (row, 7); - client_ver = seaf_db_row_get_column_text (row, 8); - - char *owner_l = g_ascii_strdown (repo_owner, -1); - char *email_l = g_ascii_strdown (email, -1); - - SeafileRepoTokenInfo *repo_token_info; - repo_token_info = g_object_new (SEAFILE_TYPE_REPO_TOKEN_INFO, - "repo_id", repo_id, - "repo_owner", owner_l, - "email", email_l, - "token", token, - "peer_id", peer_id, - "peer_ip", peer_ip, - "peer_name", peer_name, - "sync_time", sync_time, - "client_ver", client_ver, - NULL); - - *ret_list = g_list_prepend (*ret_list, repo_token_info); - - g_free (owner_l); - g_free (email_l); - - return TRUE; -} - -static void -fill_in_token_info (GList *info_list) -{ - GList *ptr; - SeafileRepoTokenInfo *info; - SeafRepo *repo; - char *repo_name; - - for (ptr = info_list; ptr; ptr = ptr->next) { - info = ptr->data; - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, - seafile_repo_token_info_get_repo_id(info)); - if (repo) - repo_name = g_strdup(repo->name); - else - repo_name = g_strdup("Unknown"); - seaf_repo_unref (repo); - - g_object_set (info, "repo_name", repo_name, NULL); - g_free (repo_name); - } -} - -GList * -seaf_repo_manager_list_repo_tokens (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - GList *ret_list = NULL; - char *sql; - gboolean db_err = FALSE; - - if (!repo_exists_in_db (mgr->seaf->db, repo_id, &db_err)) { - if (db_err) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - } - return NULL; - } - - sql = "SELECT u.repo_id, o.owner_id, u.email, u.token, " - "p.peer_id, p.peer_ip, p.peer_name, p.sync_time, p.client_ver " - "FROM RepoUserToken u LEFT JOIN RepoTokenPeerInfo p " - "ON u.token = p.token, RepoOwner o " - "WHERE u.repo_id = ? and o.repo_id = ? "; - - int n_row = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_token, &ret_list, - 2, "string", repo_id, - "string", repo_id); - if (n_row < 0) { - seaf_warning ("DB error when get token info for repo %.10s.\n", - repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - } - - fill_in_token_info (ret_list); - - return g_list_reverse(ret_list); -} - -GList * -seaf_repo_manager_list_repo_tokens_by_email (SeafRepoManager *mgr, - const char *email, - GError **error) -{ - GList *ret_list = NULL; - char *sql; - - sql = "SELECT u.repo_id, o.owner_id, u.email, u.token, " - "p.peer_id, p.peer_ip, p.peer_name, p.sync_time, p.client_ver " - "FROM RepoUserToken u LEFT JOIN RepoTokenPeerInfo p " - "ON u.token = p.token, RepoOwner o " - "WHERE u.email = ? and u.repo_id = o.repo_id"; - - int n_row = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_token, &ret_list, - 1, "string", email); - if (n_row < 0) { - seaf_warning ("DB error when get token info for email %s.\n", - email); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - } - - fill_in_token_info (ret_list); - - return g_list_reverse(ret_list); -} - -static gboolean -collect_token_list (SeafDBRow *row, void *data) -{ - GList **p_tokens = data; - const char *token; - - token = seaf_db_row_get_column_text (row, 0); - *p_tokens = g_list_prepend (*p_tokens, g_strdup(token)); - - return TRUE; -} - -/** - * Delete all repo tokens for a given user on a given client - */ - -int -seaf_repo_manager_delete_repo_tokens_by_peer_id (SeafRepoManager *mgr, - const char *email, - const char *peer_id, - GList **tokens, - GError **error) -{ - int ret = 0; - const char *template; - GList *token_list = NULL; - GString *token_list_str = g_string_new (""); - GString *sql = g_string_new (""); - GList *ptr; - int rc = 0; - - template = "SELECT u.token " - "FROM RepoUserToken as u, RepoTokenPeerInfo as p " - "WHERE u.token = p.token " - "AND u.email = ? AND p.peer_id = ?"; - rc = seaf_db_statement_foreach_row (mgr->seaf->db, template, - collect_token_list, &token_list, - 2, "string", email, "string", peer_id); - if (rc < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - goto out; - } - - if (rc == 0) - goto out; - - for (ptr = token_list; ptr; ptr = ptr->next) { - const char *token = (char *)ptr->data; - if (token_list_str->len == 0) - g_string_append_printf (token_list_str, "'%s'", token); - else - g_string_append_printf (token_list_str, ",'%s'", token); - } - - /* Note that there is a size limit on sql query. In MySQL it's 1MB by default. - * Normally the token_list won't be that long. - */ - g_string_printf (sql, "DELETE FROM RepoUserToken WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (mgr->seaf->db, sql->str, 0); - if (rc < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - goto out; - } - - g_string_printf (sql, "DELETE FROM RepoTokenPeerInfo WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (mgr->seaf->db, sql->str, 0); - if (rc < 0) - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - -out: - g_string_free (token_list_str, TRUE); - g_string_free (sql, TRUE); - - if (rc < 0) { - ret = -1; - g_list_free_full (token_list, (GDestroyNotify)g_free); - } else { - *tokens = token_list; - } - - return ret; -} - -int -seaf_repo_manager_delete_repo_tokens_by_email (SeafRepoManager *mgr, - const char *email, - GError **error) -{ - int ret = 0; - const char *template; - GList *token_list = NULL; - GList *ptr; - GString *token_list_str = g_string_new (""); - GString *sql = g_string_new (""); - int rc; - - template = "SELECT u.token " - "FROM RepoUserToken as u, RepoTokenPeerInfo as p " - "WHERE u.token = p.token " - "AND u.email = ?"; - rc = seaf_db_statement_foreach_row (mgr->seaf->db, template, - collect_token_list, &token_list, - 1, "string", email); - if (rc < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - goto out; - } - - if (rc == 0) - goto out; - - for (ptr = token_list; ptr; ptr = ptr->next) { - const char *token = (char *)ptr->data; - if (token_list_str->len == 0) - g_string_append_printf (token_list_str, "'%s'", token); - else - g_string_append_printf (token_list_str, ",'%s'", token); - } - - /* Note that there is a size limit on sql query. In MySQL it's 1MB by default. - * Normally the token_list won't be that long. - */ - g_string_printf (sql, "DELETE FROM RepoUserToken WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (mgr->seaf->db, sql->str, 0); - if (rc < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - goto out; - } - - g_string_printf (sql, "DELETE FROM RepoTokenPeerInfo WHERE token in (%s)", - token_list_str->str); - rc = seaf_db_statement_query (mgr->seaf->db, sql->str, 0); - if (rc < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); - goto out; - } - - seaf_http_server_invalidate_tokens (seaf->http_server, token_list); - -out: - g_string_free (token_list_str, TRUE); - g_string_free (sql, TRUE); - g_list_free_full (token_list, (GDestroyNotify)g_free); - - if (rc < 0) { - ret = -1; - } - - return ret; -} - -static gboolean -get_email_by_token_cb (SeafDBRow *row, void *data) -{ - char **email_ptr = data; - - const char *email = (const char *) seaf_db_row_get_column_text (row, 0); - *email_ptr = g_ascii_strdown (email, -1); - /* There should be only one result. */ - return FALSE; -} - -char * -seaf_repo_manager_get_email_by_token (SeafRepoManager *manager, - const char *repo_id, - const char *token) -{ - if (!repo_id || !token) - return NULL; - - char *email = NULL; - char *sql; - - sql = "SELECT email FROM RepoUserToken " - "WHERE repo_id = ? AND token = ?"; - - seaf_db_statement_foreach_row (seaf->db, sql, - get_email_by_token_cb, &email, - 2, "string", repo_id, "string", token); - - return email; -} - -static gboolean -get_repo_size (SeafDBRow *row, void *vsize) -{ - gint64 *psize = vsize; - - *psize = seaf_db_row_get_column_int64 (row, 0); - - return FALSE; -} - -gint64 -seaf_repo_manager_get_repo_size (SeafRepoManager *mgr, const char *repo_id) -{ - gint64 size = 0; - char *sql; - - sql = "SELECT size FROM RepoSize WHERE repo_id=?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - get_repo_size, &size, - 1, "string", repo_id) < 0) - return -1; - - return size; -} - -int -seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id, - int days) -{ - SeafVirtRepo *vinfo; - SeafDB *db = mgr->seaf->db; - - vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); - if (vinfo) { - seaf_virtual_repo_info_free (vinfo); - return 0; - } - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - int rc; - - exists = seaf_db_statement_exists (db, - "SELECT repo_id FROM RepoHistoryLimit " - "WHERE repo_id=?", - &err, 1, "string", repo_id); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (db, - "UPDATE RepoHistoryLimit SET days=%d " - "WHERE repo_id=?", - 2, "int", days, "string", repo_id); - else - rc = seaf_db_statement_query (db, - "INSERT INTO RepoHistoryLimit VALUES " - "(?, ?)", - 2, "string", repo_id, "int", days); - return rc; - } else { - if (seaf_db_statement_query (db, - "REPLACE INTO RepoHistoryLimit VALUES (?, ?)", - 2, "string", repo_id, "int", days) < 0) - return -1; - } - - return 0; -} - -static gboolean -get_history_limit_cb (SeafDBRow *row, void *data) -{ - int *limit = data; - - *limit = seaf_db_row_get_column_int (row, 0); - - return FALSE; -} - -int -seaf_repo_manager_get_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id) -{ - SeafVirtRepo *vinfo; - const char *r_repo_id = repo_id; - char *sql; - int per_repo_days = -1; - int ret; - - vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); - if (vinfo) - r_repo_id = vinfo->origin_repo_id; - - sql = "SELECT days FROM RepoHistoryLimit WHERE repo_id=?"; - - ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_history_limit_cb, - &per_repo_days, 1, "string", r_repo_id); - if (ret == 0) { - // limit not set, return global one - per_repo_days = mgr->seaf->keep_history_days; - } - - // db error or limit set as negative, means keep full history, return -1 - if (per_repo_days < 0) - per_repo_days = -1; - - seaf_virtual_repo_info_free (vinfo); - - return per_repo_days; -} - -int -seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id, - gint64 timestamp) -{ - SeafDB *db = mgr->seaf->db; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean exists, err; - int rc; - - exists = seaf_db_statement_exists (db, - "SELECT repo_id FROM RepoValidSince WHERE " - "repo_id=?", &err, 1, "string", repo_id); - if (err) - return -1; - - if (exists) - rc = seaf_db_statement_query (db, - "UPDATE RepoValidSince SET timestamp=?" - " WHERE repo_id=?", - 2, "int64", timestamp, "string", repo_id); - else - rc = seaf_db_statement_query (db, - "INSERT INTO RepoValidSince VALUES " - "(?, ?)", 2, "string", repo_id, - "int64", timestamp); - if (rc < 0) - return -1; - } else { - if (seaf_db_statement_query (db, - "REPLACE INTO RepoValidSince VALUES (?, ?)", - 2, "string", repo_id, "int64", timestamp) < 0) - return -1; - } - - return 0; -} - -gint64 -seaf_repo_manager_get_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id) -{ - char *sql; - - sql = "SELECT timestamp FROM RepoValidSince WHERE repo_id=?"; - /* Also return -1 if doesn't exist. */ - return seaf_db_statement_get_int64 (mgr->seaf->db, sql, 1, "string", repo_id); -} - -gint64 -seaf_repo_manager_get_repo_truncate_time (SeafRepoManager *mgr, - const char *repo_id) -{ - int days; - gint64 timestamp; - - days = seaf_repo_manager_get_repo_history_limit (mgr, repo_id); - timestamp = seaf_repo_manager_get_repo_valid_since (mgr, repo_id); - - gint64 now = (gint64)time(NULL); - if (days > 0) - return MAX (now - days * 24 * 3600, timestamp); - else if (days < 0) - return timestamp; - else - return 0; -} - -/* - * Permission related functions. - */ - -/* Owner functions. */ - -int -seaf_repo_manager_set_repo_owner (SeafRepoManager *mgr, - const char *repo_id, - const char *email) -{ - SeafDB *db = mgr->seaf->db; - char sql[256]; - char *orig_owner = NULL; - int ret = 0; - - orig_owner = seaf_repo_manager_get_repo_owner (mgr, repo_id); - if (g_strcmp0 (orig_owner, email) == 0) - goto out; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean err; - snprintf(sql, sizeof(sql), - "SELECT repo_id FROM RepoOwner WHERE repo_id='%s'", repo_id); - if (seaf_db_check_for_existence(db, sql, &err)) - snprintf(sql, sizeof(sql), - "UPDATE RepoOwner SET owner_id='%s' WHERE " - "repo_id='%s'", email, repo_id); - else - snprintf(sql, sizeof(sql), - "INSERT INTO RepoOwner VALUES ('%s', '%s')", - repo_id, email); - if (err) { - ret = -1; - goto out; - } - - if (seaf_db_query (db, sql) < 0) { - ret = -1; - goto out; - } - } else { - if (seaf_db_statement_query (db, "REPLACE INTO RepoOwner VALUES (?, ?)", - 2, "string", repo_id, "string", email) < 0) { - ret = -1; - goto out; - } - } - - /* If the repo was newly created, no need to remove share and virtual repos. */ - if (!orig_owner) - goto out; - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM SharedRepo WHERE repo_id = ?", - 1, "string", repo_id); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM RepoGroup WHERE repo_id = ?", - 1, "string", repo_id); - - if (!seaf->cloud_mode) { - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM InnerPubRepo WHERE repo_id = ?", - 1, "string", repo_id); - } - - /* Remove all tokens except for the new owner. */ - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoUserToken WHERE repo_id = ? AND email != ?", - 2, "string", repo_id, "string", email); - - /* Remove virtual repos when repo ownership changes. */ - GList *vrepos, *ptr; - vrepos = seaf_repo_manager_get_virtual_repo_ids_by_origin (mgr, repo_id); - for (ptr = vrepos; ptr != NULL; ptr = ptr->next) - remove_virtual_repo_ondisk (mgr, (char *)ptr->data); - string_list_free (vrepos); - - seaf_db_statement_query (mgr->seaf->db, "DELETE FROM VirtualRepo " - "WHERE repo_id=? OR origin_repo=?", - 2, "string", repo_id, "string", repo_id); - -out: - g_free (orig_owner); - return ret; -} - -static gboolean -get_owner (SeafDBRow *row, void *data) -{ - char **owner_id = data; - - const char *owner = (const char *) seaf_db_row_get_column_text (row, 0); - *owner_id = g_ascii_strdown (owner, -1); - /* There should be only one result. */ - return FALSE; -} - -char * -seaf_repo_manager_get_repo_owner (SeafRepoManager *mgr, - const char *repo_id) -{ - char *sql; - char *ret = NULL; - - sql = "SELECT owner_id FROM RepoOwner WHERE repo_id=?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - get_owner, &ret, - 1, "string", repo_id) < 0) { - seaf_warning ("Failed to get owner id for repo %s.\n", repo_id); - return NULL; - } - - return ret; -} - -static gboolean -collect_repo_id (SeafDBRow *row, void *data) -{ - GList **p_ids = data; - const char *repo_id; - - repo_id = seaf_db_row_get_column_text (row, 0); - *p_ids = g_list_prepend (*p_ids, g_strdup(repo_id)); - - return TRUE; -} - -GList * -seaf_repo_manager_get_orphan_repo_list (SeafRepoManager *mgr) -{ - GList *id_list = NULL, *ptr; - GList *ret = NULL; - char sql[256]; - - snprintf (sql, sizeof(sql), "SELECT Repo.repo_id FROM Repo LEFT JOIN " - "RepoOwner ON Repo.repo_id = RepoOwner.repo_id WHERE " - "RepoOwner.owner_id is NULL"); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &id_list) < 0) - return NULL; - - for (ptr = id_list; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - SeafRepo *repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (repo != NULL) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - - return ret; -} - -GList * -seaf_repo_manager_get_repos_by_owner (SeafRepoManager *mgr, - const char *email, - int ret_corrupted) -{ - GList *id_list = NULL, *ptr; - GList *ret = NULL; - char *sql; - SeafRepo *repo = NULL; - - sql = "SELECT repo_id FROM RepoOwner WHERE owner_id=?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_id, &id_list, - 1, "string", email) < 0) - return NULL; - - for (ptr = id_list; ptr; ptr = ptr->next) { - char *repo_id = ptr->data; - if (ret_corrupted) { - repo = seaf_repo_manager_get_repo_ex (mgr, repo_id); - } else { - repo = seaf_repo_manager_get_repo (mgr, repo_id); - } - if (repo != NULL) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - - return ret; -} - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr) -{ - GList *ret = NULL; - char sql[256]; - - snprintf (sql, 256, "SELECT repo_id FROM Repo"); - - if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, - collect_repo_id, &ret) < 0) - return NULL; - - return ret; -} - -typedef struct FileCount { - char *repo_id; - gint64 file_count; -} FileCount; - -static void -free_file_count (gpointer data) -{ - if (!data) - return; - - FileCount *file_count = data; - g_free (file_count->repo_id); - g_free (file_count); -} - -static gboolean -get_file_count_cb (SeafDBRow *row, void *data) -{ - GList **file_counts = data; - const char *repo_id = seaf_db_row_get_column_text (row, 0); - gint64 fcount = seaf_db_row_get_column_int64 (row, 1); - - FileCount *file_count = g_new0 (FileCount, 1); - file_count->repo_id = g_strdup (repo_id); - file_count->file_count = fcount; - *file_counts = g_list_prepend (*file_counts, file_count); - - return TRUE; -} - -GList * -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit) -{ - GList *file_counts = NULL, *ptr; - GList *ret = NULL; - SeafRepo *repo; - FileCount *file_count; - int rc; - - if (start == -1 && limit == -1) - rc = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT r.repo_id, c.file_count FROM Repo r LEFT JOIN RepoFileCount c " - "ON r.repo_id = c.repo_id", - get_file_count_cb, &file_counts, - 0); - else - rc = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT r.repo_id, c.file_count FROM Repo r LEFT JOIN RepoFileCount c " - "ON r.repo_id = c.repo_id ORDER BY r.repo_id LIMIT ? OFFSET ?", - get_file_count_cb, &file_counts, - 2, "int", limit, "int", start); - - if (rc < 0) - return NULL; - - for (ptr = file_counts; ptr; ptr = ptr->next) { - file_count = ptr->data; - repo = seaf_repo_manager_get_repo_ex (mgr, file_count->repo_id); - if (repo != NULL) { - repo->file_count = file_count->file_count; - ret = g_list_prepend (ret, repo); - } - } - - g_list_free_full (file_counts, free_file_count); - - return ret; -} - -gint64 -seaf_repo_manager_count_repos (SeafRepoManager *mgr, GError **error) -{ - gint64 num = seaf_db_get_int64 (mgr->seaf->db, - "SELECT COUNT(repo_id) FROM Repo"); - if (num < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to count repos from db"); - } - - return num; -} - -GList * -seaf_repo_manager_get_repo_ids_by_owner (SeafRepoManager *mgr, - const char *email) -{ - GList *ret = NULL; - char *sql; - - sql = "SELECT repo_id FROM RepoOwner WHERE owner_id=?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_id, &ret, - 1, "string", email) < 0) { - string_list_free (ret); - return NULL; - } - - return ret; -} - -static gboolean -collect_trash_repo (SeafDBRow *row, void *data) -{ - GList **trash_repos = data; - const char *repo_id; - const char *repo_name; - const char *head_id; - const char *owner_id; - gint64 size; - gint64 del_time; - - repo_id = seaf_db_row_get_column_text (row, 0); - repo_name = seaf_db_row_get_column_text (row, 1); - head_id = seaf_db_row_get_column_text (row, 2); - owner_id = seaf_db_row_get_column_text (row, 3); - size = seaf_db_row_get_column_int64 (row, 4); - del_time = seaf_db_row_get_column_int64 (row, 5); - - - if (!repo_id || !repo_name || !head_id || !owner_id) - return FALSE; - - SeafileTrashRepo *trash_repo = g_object_new (SEAFILE_TYPE_TRASH_REPO, - "repo_id", repo_id, - "repo_name", repo_name, - "head_id", head_id, - "owner_id", owner_id, - "size", size, - "del_time", del_time, - NULL); - if (!trash_repo) - return FALSE; - - *trash_repos = g_list_prepend (*trash_repos, trash_repo); - - return TRUE; -} - -GList * -seaf_repo_manager_get_trash_repo_list (SeafRepoManager *mgr, - int start, - int limit, - GError **error) -{ - GList *trash_repos = NULL; - int rc; - - if (start == -1 && limit == -1) - rc = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT repo_id, repo_name, head_id, owner_id, " - "size, del_time FROM RepoTrash ORDER BY del_time DESC", - collect_trash_repo, &trash_repos, - 0); - else - rc = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT repo_id, repo_name, head_id, owner_id, " - "size, del_time FROM RepoTrash " - "ORDER BY del_time DESC LIMIT ? OFFSET ?", - collect_trash_repo, &trash_repos, - 2, "int", limit, "int", start); - - if (rc < 0) { - while (trash_repos) { - g_object_unref (trash_repos->data); - trash_repos = g_list_delete_link (trash_repos, trash_repos); - } - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get trashed repo from db."); - return NULL; - } - - return g_list_reverse (trash_repos); -} - -GList * -seaf_repo_manager_get_trash_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error) -{ - GList *trash_repos = NULL; - int rc; - - rc = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT repo_id, repo_name, head_id, owner_id, " - "size, del_time FROM RepoTrash WHERE owner_id = ?", - collect_trash_repo, &trash_repos, - 1, "string", owner); - - if (rc < 0) { - while (trash_repos) { - g_object_unref (trash_repos->data); - trash_repos = g_list_delete_link (trash_repos, trash_repos); - } - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get trashed repo from db."); - return NULL; - } - - return trash_repos; -} - -SeafileTrashRepo * -seaf_repo_manager_get_repo_from_trash (SeafRepoManager *mgr, - const char *repo_id) -{ - SeafileTrashRepo *ret = NULL; - GList *trash_repos = NULL; - char *sql; - int rc; - - sql = "SELECT repo_id, repo_name, head_id, owner_id, size, del_time FROM RepoTrash " - "WHERE repo_id = ?"; - rc = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_trash_repo, &trash_repos, - 1, "string", repo_id); - if (rc < 0) - return NULL; - - /* There should be only one results, since repo_id is a PK. */ - ret = trash_repos->data; - - g_list_free (trash_repos); - return ret; -} - -int -seaf_repo_manager_del_repo_from_trash (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - int ret = 0; - - /* As long as the repo is successfully moved into GarbageRepo table, - * we consider this operation successful. - */ - if (add_deleted_repo_record (mgr, repo_id) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Add deleted record"); - return -1; - } - - seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoTrash WHERE repo_id = ?", - 1, "string", repo_id); - - return 0; -} - -int -seaf_repo_manager_empty_repo_trash (SeafRepoManager *mgr, GError **error) -{ - GList *trash_repos = NULL, *ptr; - SeafileTrashRepo *repo; - - trash_repos = seaf_repo_manager_get_trash_repo_list (mgr, -1, -1, error); - if (*error) - return -1; - - for (ptr = trash_repos; ptr; ptr = ptr->next) { - repo = ptr->data; - seaf_repo_manager_del_repo_from_trash (mgr, - seafile_trash_repo_get_repo_id(repo), - NULL); - g_object_unref (repo); - } - - g_list_free (trash_repos); - return 0; -} - -int -seaf_repo_manager_empty_repo_trash_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error) -{ - GList *trash_repos = NULL, *ptr; - SeafileTrashRepo *repo; - - trash_repos = seaf_repo_manager_get_trash_repos_by_owner (mgr, owner, error); - if (*error) - return -1; - - for (ptr = trash_repos; ptr; ptr = ptr->next) { - repo = ptr->data; - seaf_repo_manager_del_repo_from_trash (mgr, - seafile_trash_repo_get_repo_id(repo), - NULL); - g_object_unref (repo); - } - - g_list_free (trash_repos); - return 0; -} - -int -seaf_repo_manager_restore_repo_from_trash (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - SeafileTrashRepo *repo = NULL; - int ret = 0; - gboolean exists = FALSE; - gboolean db_err; - - repo = seaf_repo_manager_get_repo_from_trash (mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %.8s not found in trash.\n", repo_id); - return -1; - } - - SeafDBTrans *trans = seaf_db_begin_transaction (mgr->seaf->db); - - exists = seaf_db_trans_check_for_existence (trans, - "SELECT 1 FROM Repo WHERE repo_id=?", - &db_err, 1, "string", repo_id); - - if (!exists) { - ret = seaf_db_trans_query (trans, - "INSERT INTO Repo(repo_id) VALUES (?)", - 1, "string", repo_id) < 0; - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Insert Repo."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - } - - exists = seaf_db_trans_check_for_existence (trans, - "SELECT 1 FROM RepoOwner WHERE repo_id=?", - &db_err, 1, "string", repo_id); - - if (!exists) { - ret = seaf_db_trans_query (trans, - "INSERT INTO RepoOwner VALUES (?, ?)", - 2, "string", repo_id, - "string", seafile_trash_repo_get_owner_id(repo)); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Insert Repo Owner."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - } - - exists = seaf_db_trans_check_for_existence (trans, - "SELECT 1 FROM Branch WHERE repo_id=?", - &db_err, 1, "string", repo_id); - if (!exists) { - ret = seaf_db_trans_query (trans, - "INSERT INTO Branch VALUES ('master', ?, ?)", - 2, "string", repo_id, - "string", seafile_trash_repo_get_head_id(repo)); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Insert Branch."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - } - - exists = seaf_db_trans_check_for_existence (trans, - "SELECT 1 FROM RepoHead WHERE repo_id=?", - &db_err, 1, "string", repo_id); - if (!exists) { - ret = seaf_db_trans_query (trans, - "INSERT INTO RepoHead VALUES (?, 'master')", - 1, "string", repo_id); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Set RepoHead."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - } - - // Restore repo size - exists = seaf_db_trans_check_for_existence (trans, - "SELECT 1 FROM RepoSize WHERE repo_id=?", - &db_err, 1, "string", repo_id); - - if (!exists) { - ret = seaf_db_trans_query (trans, - "INSERT INTO RepoSize VALUES (?, ?, ?)", - 3, "string", repo_id, - "int64", seafile_trash_repo_get_size (repo), - "string", seafile_trash_repo_get_head_id (repo)); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Insert Repo Size."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - } - - ret = seaf_db_trans_query (trans, - "DELETE FROM RepoTrash WHERE repo_id = ?", - 1, "string", repo_id); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: delete from RepoTrash."); - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - goto out; - } - - if (seaf_db_commit (trans) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "DB error: Failed to commit."); - seaf_db_rollback (trans); - ret = -1; - } - - seaf_db_trans_close (trans); - -out: - g_object_unref (repo); - return ret; -} - -/* Web access permission. */ - -int -seaf_repo_manager_set_access_property (SeafRepoManager *mgr, const char *repo_id, - const char *ap) -{ - int rc; - - if (seaf_repo_manager_query_access_property (mgr, repo_id) == NULL) { - rc = seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO WebAP VALUES (?, ?)", - 2, "string", repo_id, "string", ap); - } else { - rc = seaf_db_statement_query (mgr->seaf->db, - "UPDATE WebAP SET access_property=? " - "WHERE repo_id=?", - 2, "string", ap, "string", repo_id); - } - - if (rc < 0) { - seaf_warning ("DB error when set access property for repo %s, %s.\n", repo_id, ap); - return -1; - } - - return 0; -} - -static gboolean -get_ap (SeafDBRow *row, void *data) -{ - char **ap = data; - - *ap = g_strdup (seaf_db_row_get_column_text (row, 0)); - - return FALSE; -} - -char * -seaf_repo_manager_query_access_property (SeafRepoManager *mgr, const char *repo_id) -{ - char *sql; - char *ret = NULL; - - sql = "SELECT access_property FROM WebAP WHERE repo_id=?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_ap, &ret, - 1, "string", repo_id) < 0) { - seaf_warning ("DB error when get access property for repo %s.\n", repo_id); - return NULL; - } - - return ret; -} - -/* Group repos. */ - -int -seaf_repo_manager_add_group_repo (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - const char *owner, - const char *permission, - GError **error) -{ - if (seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO RepoGroup VALUES (?, ?, ?, ?)", - 4, "string", repo_id, "int", group_id, - "string", owner, "string", permission) < 0) - return -1; - - return 0; -} - -int -seaf_repo_manager_del_group_repo (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - GError **error) -{ - return seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM RepoGroup WHERE group_id=? " - "AND repo_id=?", - 2, "int", group_id, "string", repo_id); -} - -static gboolean -get_group_ids_cb (SeafDBRow *row, void *data) -{ - GList **plist = data; - - int group_id = seaf_db_row_get_column_int (row, 0); - - *plist = g_list_prepend (*plist, (gpointer)(long)group_id); - - return TRUE; -} - -GList * -seaf_repo_manager_get_groups_by_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - char *sql; - GList *group_ids = NULL; - - sql = "SELECT group_id FROM RepoGroup WHERE repo_id = ?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_group_ids_cb, - &group_ids, 1, "string", repo_id) < 0) { - g_list_free (group_ids); - return NULL; - } - - return g_list_reverse (group_ids); -} - -static gboolean -get_group_perms_cb (SeafDBRow *row, void *data) -{ - GList **plist = data; - GroupPerm *perm = g_new0 (GroupPerm, 1); - - perm->group_id = seaf_db_row_get_column_int (row, 0); - const char *permission = seaf_db_row_get_column_text(row, 1); - g_strlcpy (perm->permission, permission, sizeof(perm->permission)); - - *plist = g_list_prepend (*plist, perm); - - return TRUE; -} - -GList * -seaf_repo_manager_get_group_perm_by_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - char *sql; - GList *group_perms = NULL, *p; - - sql = "SELECT group_id, permission FROM RepoGroup WHERE repo_id = ?"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_group_perms_cb, - &group_perms, 1, "string", repo_id) < 0) { - for (p = group_perms; p != NULL; p = p->next) - g_free (p->data); - g_list_free (group_perms); - return NULL; - } - - return g_list_reverse (group_perms); -} - -int -seaf_repo_manager_set_group_repo_perm (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - const char *permission, - GError **error) -{ - return seaf_db_statement_query (mgr->seaf->db, - "UPDATE RepoGroup SET permission=? WHERE " - "repo_id=? AND group_id=?", - 3, "string", permission, "string", repo_id, - "int", group_id); -} - -static gboolean -get_group_repoids_cb (SeafDBRow *row, void *data) -{ - GList **p_list = data; - - char *repo_id = g_strdup ((const char *)seaf_db_row_get_column_text (row, 0)); - - *p_list = g_list_prepend (*p_list, repo_id); - - return TRUE; -} - -GList * -seaf_repo_manager_get_group_repoids (SeafRepoManager *mgr, - int group_id, - GError **error) -{ - char *sql; - GList *repo_ids = NULL; - - sql = "SELECT repo_id FROM RepoGroup WHERE group_id = ?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_group_repoids_cb, - &repo_ids, 1, "int", group_id) < 0) - return NULL; - - return g_list_reverse (repo_ids); -} - -static gboolean -get_group_repos_cb (SeafDBRow *row, void *data) -{ - GList **p_list = data; - SeafileRepo *srepo = NULL; - - const char *repo_id = seaf_db_row_get_column_text (row, 0); - const char *vrepo_id = seaf_db_row_get_column_text (row, 1); - int group_id = seaf_db_row_get_column_int (row, 2); - const char *user_name = seaf_db_row_get_column_text (row, 3); - const char *permission = seaf_db_row_get_column_text (row, 4); - const char *commit_id = seaf_db_row_get_column_text (row, 5); - gint64 size = seaf_db_row_get_column_int64 (row, 6); - - char *user_name_l = g_ascii_strdown (user_name, -1); - - srepo = g_object_new (SEAFILE_TYPE_REPO, - "share_type", "group", - "repo_id", repo_id, - "id", repo_id, - "head_cmmt_id", commit_id, - "group_id", group_id, - "user", user_name_l, - "permission", permission, - "is_virtual", (vrepo_id != NULL), - "size", size, - NULL); - g_free (user_name_l); - - if (srepo != NULL) { - if (vrepo_id) { - const char *origin_repo_id = seaf_db_row_get_column_text (row, 7); - const char *origin_path = seaf_db_row_get_column_text (row, 8); - g_object_set (srepo, "store_id", origin_repo_id, - "origin_repo_id", origin_repo_id, - "origin_path", origin_path, NULL); - } else { - g_object_set (srepo, "store_id", repo_id, NULL); - } - - *p_list = g_list_prepend (*p_list, srepo); - } - - return TRUE; -} - -void -seaf_fill_repo_obj_from_commit (GList **repos) -{ - SeafileRepo *repo; - SeafCommit *commit; - char *repo_id; - char *commit_id; - GList *p = *repos; - GList *next; - - while (p) { - repo = p->data; - g_object_get (repo, "repo_id", &repo_id, "head_cmmt_id", &commit_id, NULL); - commit = seaf_commit_manager_get_commit_compatible (seaf->commit_mgr, - repo_id, commit_id); - if (!commit) { - seaf_warning ("Commit %s not found in repo %s\n", commit_id, repo_id); - g_object_unref (repo); - next = p->next; - *repos = g_list_delete_link (*repos, p); - p = next; - } else { - g_object_set (repo, "name", commit->repo_name, "desc", commit->repo_desc, - "encrypted", commit->encrypted, "magic", commit->magic, - "enc_version", commit->enc_version, "root", commit->root_id, - "version", commit->version, "last_modify", commit->ctime, - NULL); - g_object_set (repo, - "repo_name", commit->repo_name, "repo_desc", commit->repo_desc, - "last_modified", commit->ctime, "repaired", commit->repaired, NULL); - if (commit->encrypted && commit->enc_version == 2) - g_object_set (repo, "random_key", commit->random_key, NULL); - - p = p->next; - } - g_free (repo_id); - g_free (commit_id); - seaf_commit_unref (commit); - } -} - -GList * -seaf_repo_manager_get_repos_by_group (SeafRepoManager *mgr, - int group_id, - GError **error) -{ - char *sql; - GList *repos = NULL; - GList *p; - - sql = "SELECT RepoGroup.repo_id, VirtualRepo.repo_id, " - "group_id, user_name, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path " - "FROM RepoGroup LEFT JOIN VirtualRepo ON " - "RepoGroup.repo_id = VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON RepoGroup.repo_id = s.repo_id, " - "Branch WHERE group_id = ? AND " - "RepoGroup.repo_id = Branch.repo_id AND " - "Branch.name = 'master'"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_group_repos_cb, - &repos, 1, "int", group_id) < 0) { - for (p = repos; p; p = p->next) { - g_object_unref (p->data); - } - g_list_free (repos); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get repos by group from db."); - return NULL; - } - - seaf_fill_repo_obj_from_commit (&repos); - - return g_list_reverse (repos); -} - -GList * -seaf_repo_manager_get_group_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error) -{ - char *sql; - GList *repos = NULL; - GList *p; - - sql = "SELECT RepoGroup.repo_id, VirtualRepo.repo_id, " - "group_id, user_name, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path " - "FROM RepoGroup LEFT JOIN VirtualRepo ON " - "RepoGroup.repo_id = VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON RepoGroup.repo_id = s.repo_id, " - "Branch WHERE user_name = ? AND " - "RepoGroup.repo_id = Branch.repo_id AND " - "Branch.name = 'master'"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_group_repos_cb, - &repos, 1, "string", owner) < 0) { - for (p = repos; p; p = p->next) { - g_object_unref (p->data); - } - g_list_free (repos); - return NULL; - } - - seaf_fill_repo_obj_from_commit (&repos); - - return g_list_reverse (repos); -} - -static gboolean -get_group_repo_owner (SeafDBRow *row, void *data) -{ - char **share_from = data; - - const char *owner = (const char *) seaf_db_row_get_column_text (row, 0); - *share_from = g_ascii_strdown (owner, -1); - /* There should be only one result. */ - return FALSE; -} - -char * -seaf_repo_manager_get_group_repo_owner (SeafRepoManager *mgr, - const char *repo_id, - GError **error) -{ - char *sql; - char *ret = NULL; - - sql = "SELECT user_name FROM RepoGroup WHERE repo_id = ?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - get_group_repo_owner, &ret, - 1, "string", repo_id) < 0) { - seaf_warning ("DB error when get repo share from for repo %s.\n", - repo_id); - return NULL; - } - - return ret; -} - -int -seaf_repo_manager_remove_group_repos (SeafRepoManager *mgr, - int group_id, - const char *owner, - GError **error) -{ - SeafDB *db = mgr->seaf->db; - int rc; - - if (!owner) { - rc = seaf_db_statement_query (db, "DELETE FROM RepoGroup WHERE group_id=?", - 1, "int", group_id); - } else { - rc = seaf_db_statement_query (db, - "DELETE FROM RepoGroup WHERE group_id=? AND " - "user_name = ?", - 2, "int", group_id, "string", owner); - } - - return rc; -} - -/* Inner public repos */ - -int -seaf_repo_manager_set_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *permission) -{ - SeafDB *db = mgr->seaf->db; - char sql[256]; - - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { - gboolean err; - snprintf(sql, sizeof(sql), - "SELECT repo_id FROM InnerPubRepo WHERE repo_id='%s'", - repo_id); - if (seaf_db_check_for_existence(db, sql, &err)) - snprintf(sql, sizeof(sql), - "UPDATE InnerPubRepo SET permission='%s' " - "WHERE repo_id='%s'", permission, repo_id); - else - snprintf(sql, sizeof(sql), - "INSERT INTO InnerPubRepo VALUES " - "('%s', '%s')", repo_id, permission); - if (err) - return -1; - return seaf_db_query (db, sql); - } else { - return seaf_db_statement_query (db, - "REPLACE INTO InnerPubRepo VALUES (?, ?)", - 2, "string", repo_id, "string", permission); - } - - return -1; -} - -int -seaf_repo_manager_unset_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id) -{ - return seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM InnerPubRepo WHERE repo_id = ?", - 1, "string", repo_id); -} - -gboolean -seaf_repo_manager_is_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id) -{ - gboolean db_err = FALSE; - - return seaf_db_statement_exists (mgr->seaf->db, - "SELECT repo_id FROM InnerPubRepo WHERE repo_id=?", - &db_err, 1, "string", repo_id); -} - -static gboolean -collect_public_repos (SeafDBRow *row, void *data) -{ - GList **ret = (GList **)data; - SeafileRepo *srepo; - const char *repo_id, *vrepo_id, *owner, *permission, *commit_id; - gint64 size; - - repo_id = seaf_db_row_get_column_text (row, 0); - vrepo_id = seaf_db_row_get_column_text (row, 1); - owner = seaf_db_row_get_column_text (row, 2); - permission = seaf_db_row_get_column_text (row, 3); - commit_id = seaf_db_row_get_column_text (row, 4); - size = seaf_db_row_get_column_int64 (row, 5); - - char *owner_l = g_ascii_strdown (owner, -1); - - srepo = g_object_new (SEAFILE_TYPE_REPO, - "share_type", "public", - "repo_id", repo_id, - "id", repo_id, - "head_cmmt_id", commit_id, - "permission", permission, - "user", owner_l, - "is_virtual", (vrepo_id != NULL), - "size", size, - NULL); - g_free (owner_l); - - if (srepo) { - if (vrepo_id) { - const char *origin_repo_id = seaf_db_row_get_column_text (row, 6); - const char *origin_path = seaf_db_row_get_column_text (row, 7); - g_object_set (srepo, "store_id", origin_repo_id, - "origin_repo_id", origin_repo_id, - "origin_path", origin_path, NULL); - } else { - g_object_set (srepo, "store_id", repo_id, NULL); - } - - *ret = g_list_prepend (*ret, srepo); - } - - return TRUE; -} - -GList * -seaf_repo_manager_list_inner_pub_repos (SeafRepoManager *mgr) -{ - GList *ret = NULL, *p; - char *sql; - - sql = "SELECT InnerPubRepo.repo_id, VirtualRepo.repo_id, " - "owner_id, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path " - "FROM InnerPubRepo LEFT JOIN VirtualRepo ON " - "InnerPubRepo.repo_id=VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON InnerPubRepo.repo_id = s.repo_id, RepoOwner, Branch " - "WHERE InnerPubRepo.repo_id=RepoOwner.repo_id AND " - "InnerPubRepo.repo_id = Branch.repo_id AND Branch.name = 'master'"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_public_repos, &ret, - 0) < 0) { - for (p = ret; p != NULL; p = p->next) - g_object_unref (p->data); - g_list_free (ret); - return NULL; - } - - seaf_fill_repo_obj_from_commit (&ret); - - return g_list_reverse (ret); -} - -gint64 -seaf_repo_manager_count_inner_pub_repos (SeafRepoManager *mgr) -{ - char sql[256]; - - snprintf (sql, 256, "SELECT COUNT(*) FROM InnerPubRepo"); - - return seaf_db_get_int64(mgr->seaf->db, sql); -} - -GList * -seaf_repo_manager_list_inner_pub_repos_by_owner (SeafRepoManager *mgr, - const char *user) -{ - GList *ret = NULL, *p; - char *sql; - - sql = "SELECT InnerPubRepo.repo_id, VirtualRepo.repo_id, " - "owner_id, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path " - "FROM InnerPubRepo LEFT JOIN VirtualRepo ON " - "InnerPubRepo.repo_id=VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON InnerPubRepo.repo_id = s.repo_id, RepoOwner, Branch " - "WHERE InnerPubRepo.repo_id=RepoOwner.repo_id AND owner_id=? " - "AND InnerPubRepo.repo_id = Branch.repo_id AND Branch.name = 'master'"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_public_repos, &ret, - 1, "string", user) < 0) { - for (p = ret; p != NULL; p = p->next) - g_object_unref (p->data); - g_list_free (ret); - return NULL; - } - - seaf_fill_repo_obj_from_commit (&ret); - - return g_list_reverse (ret); -} - -char * -seaf_repo_manager_get_inner_pub_repo_perm (SeafRepoManager *mgr, - const char *repo_id) -{ - char *sql; - - sql = "SELECT permission FROM InnerPubRepo WHERE repo_id=?"; - return seaf_db_statement_get_string(mgr->seaf->db, sql, 1, "string", repo_id); -} - - -int -seaf_repo_manager_is_valid_filename (SeafRepoManager *mgr, - const char *repo_id, - const char *filename, - GError **error) -{ - if (should_ignore_file(filename, NULL)) - return 0; - else - return 1; -} - -static int -create_repo_common (SeafRepoManager *mgr, - const char *repo_id, - const char *repo_name, - const char *repo_desc, - const char *user, - const char *magic, - const char *random_key, - int enc_version, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *commit = NULL; - SeafBranch *master = NULL; - int ret = -1; - - if (enc_version != 2 && enc_version != -1) { - seaf_warning ("Unsupported enc version %d.\n", enc_version); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Unsupported encryption version"); - return -1; - } - - if (enc_version == 2) { - if (!magic || strlen(magic) != 64) { - seaf_warning ("Bad magic.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Bad magic"); - return -1; - } - if (!random_key || strlen(random_key) != 96) { - seaf_warning ("Bad random key.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Bad random key"); - return -1; - } - } - - repo = seaf_repo_new (repo_id, repo_name, repo_desc); - - repo->no_local_history = TRUE; - if (enc_version == 2) { - repo->encrypted = TRUE; - repo->enc_version = enc_version; - memcpy (repo->magic, magic, 64); - memcpy (repo->random_key, random_key, 96); - } - - repo->version = CURRENT_REPO_VERSION; - memcpy (repo->store_id, repo_id, 36); - - commit = seaf_commit_new (NULL, repo->id, - EMPTY_SHA1, /* root id */ - user, /* creator */ - EMPTY_SHA1, /* creator id */ - repo_desc, /* description */ - 0); /* ctime */ - - seaf_repo_to_commit (repo, commit); - if (seaf_commit_manager_add_commit (seaf->commit_mgr, commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add commit"); - goto out; - } - - master = seaf_branch_new ("master", repo->id, commit->commit_id); - if (seaf_branch_manager_add_branch (seaf->branch_mgr, master) < 0) { - seaf_warning ("Failed to add branch.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add branch"); - goto out; - } - - if (seaf_repo_set_head (repo, master) < 0) { - seaf_warning ("Failed to set repo head.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to set repo head."); - goto out; - } - - if (seaf_repo_manager_add_repo (mgr, repo) < 0) { - seaf_warning ("Failed to add repo.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add repo."); - goto out; - } - - ret = 0; -out: - if (repo) - seaf_repo_unref (repo); - if (commit) - seaf_commit_unref (commit); - if (master) - seaf_branch_unref (master); - - return ret; -} - -char * -seaf_repo_manager_create_new_repo (SeafRepoManager *mgr, - const char *repo_name, - const char *repo_desc, - const char *owner_email, - const char *passwd, - GError **error) -{ - char *repo_id = NULL; - char magic[65], random_key[97]; - - repo_id = gen_uuid (); - - if (passwd && passwd[0] != 0) { - seafile_generate_magic (2, repo_id, passwd, magic); - seafile_generate_random_key (passwd, random_key); - } - - int rc; - if (passwd) - rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - magic, random_key, CURRENT_ENC_VERSION, error); - else - rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - NULL, NULL, -1, error); - if (rc < 0) - goto bad; - - if (seaf_repo_manager_set_repo_owner (mgr, repo_id, owner_email) < 0) { - seaf_warning ("Failed to set repo owner.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to set repo owner."); - goto bad; - } - - return repo_id; - -bad: - if (repo_id) - g_free (repo_id); - return NULL; -} - -char * -seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *repo_name, - const char *repo_desc, - const char *owner_email, - const char *magic, - const char *random_key, - int enc_version, - GError **error) -{ - if (!repo_id || !is_uuid_valid (repo_id)) { - seaf_warning ("Invalid repo_id.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid repo id"); - return NULL; - } - - if (seaf_repo_manager_repo_exists (mgr, repo_id)) { - seaf_warning ("Repo %s exists, refuse to create.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Repo already exists"); - return NULL; - } - - if (create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - magic, random_key, enc_version, error) < 0) - return NULL; - - if (seaf_repo_manager_set_repo_owner (mgr, repo_id, owner_email) < 0) { - seaf_warning ("Failed to set repo owner.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to set repo owner."); - return NULL; - } - - return g_strdup (repo_id); -} - -static int reap_token (void *data) -{ - SeafRepoManager *mgr = data; - GHashTableIter iter; - gpointer key, value; - DecryptedToken *t; - - pthread_rwlock_wrlock (&mgr->priv->lock); - - gint64 now = (gint64)time(NULL); - - g_hash_table_iter_init (&iter, mgr->priv->decrypted_tokens); - while (g_hash_table_iter_next (&iter, &key, &value)) { - t = value; - if (now >= t->reap_time) - g_hash_table_iter_remove (&iter); - } - - pthread_rwlock_unlock (&mgr->priv->lock); - - return TRUE; -} - -static void decrypted_token_free (DecryptedToken *token) -{ - if (!token) - return; - g_free (token->token); - g_free (token); -} - -void -seaf_repo_manager_add_decrypted_token (SeafRepoManager *mgr, - const char *encrypted_token, - const char *session_key, - const char *decrypted_token) -{ - char key[256]; - DecryptedToken *token; - - snprintf (key, sizeof(key), "%s%s", encrypted_token, session_key); - key[255] = 0; - - pthread_rwlock_wrlock (&mgr->priv->lock); - - token = g_new0 (DecryptedToken, 1); - token->token = g_strdup(decrypted_token); - token->reap_time = (gint64)time(NULL) + DECRYPTED_TOKEN_TTL; - - g_hash_table_insert (mgr->priv->decrypted_tokens, - g_strdup(key), - token); - - pthread_rwlock_unlock (&mgr->priv->lock); -} - -char * -seaf_repo_manager_get_decrypted_token (SeafRepoManager *mgr, - const char *encrypted_token, - const char *session_key) -{ - char key[256]; - DecryptedToken *token; - - snprintf (key, sizeof(key), "%s%s", encrypted_token, session_key); - key[255] = 0; - - pthread_rwlock_rdlock (&mgr->priv->lock); - token = g_hash_table_lookup (mgr->priv->decrypted_tokens, key); - pthread_rwlock_unlock (&mgr->priv->lock); - - if (token) - return g_strdup(token->token); - return NULL; -} - -static gboolean -get_shared_users (SeafDBRow *row, void *data) -{ - GList **shared_users = data; - const char *user = seaf_db_row_get_column_text (row, 0); - const char *perm = seaf_db_row_get_column_text (row, 1); - const char *repo_id = seaf_db_row_get_column_text (row, 2); - - SeafileSharedUser *uobj = g_object_new (SEAFILE_TYPE_SHARED_USER, - "repo_id", repo_id, - "user", user, - "perm", perm, - NULL); - *shared_users = g_list_prepend (*shared_users, uobj); - - return TRUE; -} - -GList * -seaf_repo_manager_get_shared_users_for_subdir (SeafRepoManager *mgr, - const char *repo_id, - const char *path, - const char *from_user, - GError **error) -{ - GList *shared_users = NULL; - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT to_email, permission, v.repo_id " - "FROM SharedRepo s, VirtualRepo v " - "WHERE s.repo_id = v.repo_id AND v.origin_repo = ? " - "AND v.path = ? AND s.from_email = ?", - get_shared_users, &shared_users, 3, "string", repo_id, - "string", path, "string", from_user); - if (ret < 0) { - seaf_warning ("Failed to get shared users for %.8s(%s).\n", repo_id, path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get shared users for subdir from db"); - while (shared_users) { - g_object_unref (shared_users->data); - shared_users = g_list_delete_link (shared_users, shared_users); - } - return NULL; - } - - return shared_users; -} - -static gboolean -get_shared_groups (SeafDBRow *row, void *data) -{ - GList **shared_groups = data; - int group = seaf_db_row_get_column_int (row, 0); - const char *perm = seaf_db_row_get_column_text (row, 1); - const char *repo_id = seaf_db_row_get_column_text (row, 2); - - SeafileSharedGroup *gobj = g_object_new (SEAFILE_TYPE_SHARED_GROUP, - "repo_id", repo_id, - "group_id", group, - "perm", perm, - NULL); - - *shared_groups = g_list_prepend (*shared_groups, gobj); - - return TRUE; -} - -GList * -seaf_repo_manager_get_shared_groups_for_subdir (SeafRepoManager *mgr, - const char *repo_id, - const char *path, - const char *from_user, - GError **error) -{ - GList *shared_groups = NULL; - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT group_id, permission, v.repo_id " - "FROM RepoGroup r, VirtualRepo v " - "WHERE r.repo_id = v.repo_id AND v.origin_repo = ? " - "AND v.path = ? AND r.user_name = ?", - get_shared_groups, &shared_groups, 3, "string", repo_id, - "string", path, "string", from_user); - if (ret < 0) { - seaf_warning ("Failed to get shared groups for %.8s(%s).\n", repo_id, path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get shared groups fro subdir from db"); - while (shared_groups) { - g_object_unref (shared_groups->data); - shared_groups = g_list_delete_link (shared_groups, shared_groups); - } - return NULL; - } - - return shared_groups; -} diff --git a/server/repo-mgr.h b/server/repo-mgr.h deleted file mode 100644 index 41f26153..00000000 --- a/server/repo-mgr.h +++ /dev/null @@ -1,769 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAF_REPO_MGR_H -#define SEAF_REPO_MGR_H - -#include "seafile-object.h" -#include "commit-mgr.h" -#include "branch-mgr.h" - -struct _SeafRepoManager; -typedef struct _SeafRepo SeafRepo; - -typedef struct SeafVirtRepo { - char repo_id[37]; - char origin_repo_id[37]; - char *path; - char base_commit[41]; -} SeafVirtRepo; - -struct _SeafRepo { - struct _SeafRepoManager *manager; - - gchar id[37]; - gchar *name; - gchar *desc; - gboolean encrypted; - int enc_version; - gchar magic[65]; /* hash(repo_id + passwd), key stretched. */ - gchar random_key[97]; - gboolean no_local_history; - gint64 last_modify; - gint64 size; - gint64 file_count; - - SeafBranch *head; - gchar root_id[41]; - - gboolean is_corrupted; - gboolean repaired; - int ref_cnt; - - SeafVirtRepo *virtual_info; - - int version; - /* Used to access fs and block sotre. - * This id is different from repo_id when this repo is virtual. - * Virtual repos share fs and block store with its origin repo. - * However, commit store for each repo is always independent. - * So always use repo_id to access commit store. - */ - gchar store_id[37]; -}; - -gboolean is_repo_id_valid (const char *id); - -SeafRepo* -seaf_repo_new (const char *id, const char *name, const char *desc); - -void -seaf_repo_free (SeafRepo *repo); - -void -seaf_repo_ref (SeafRepo *repo); - -void -seaf_repo_unref (SeafRepo *repo); - -int -seaf_repo_set_head (SeafRepo *repo, SeafBranch *branch); - -/* Update repo name, desc, magic etc from commit. - */ -void -seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit); - -void -seaf_fill_repo_obj_from_commit (GList **repos); - -/* Update repo-related fields to commit. - */ -void -seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit); - -/* - * Returns a list of all commits belongs to the repo. - * The commits in the repos are all unique. - */ -GList * -seaf_repo_get_commits (SeafRepo *repo); - -GList * -seaf_repo_diff (SeafRepo *repo, const char *arg1, const char *arg2, int fold_dir_diff, char **error); - -typedef struct _SeafRepoManager SeafRepoManager; -typedef struct _SeafRepoManagerPriv SeafRepoManagerPriv; - -struct _SeafRepoManager { - struct _SeafileSession *seaf; - - SeafRepoManagerPriv *priv; -}; - -SeafRepoManager* -seaf_repo_manager_new (struct _SeafileSession *seaf); - -int -seaf_repo_manager_init (SeafRepoManager *mgr); - -int -seaf_repo_manager_start (SeafRepoManager *mgr); - -/* - * Repo Management functions. - */ - -int -seaf_repo_manager_add_repo (SeafRepoManager *mgr, SeafRepo *repo); - -int -seaf_repo_manager_del_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -int -seaf_repo_manager_del_virtual_repo (SeafRepoManager *mgr, - const char *repo_id); - -SeafRepo* -seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id); - -/* Return repo object even if it's corrupted. */ -SeafRepo* -seaf_repo_manager_get_repo_ex (SeafRepoManager *manager, const gchar *id); - -gboolean -seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id); - -GList* -seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit); - -gint64 -seaf_repo_manager_count_repos (SeafRepoManager *mgr, GError **error); - -GList* -seaf_repo_manager_get_trash_repo_list (SeafRepoManager *mgr, - int start, - int limit, - GError **error); - -GList * -seaf_repo_manager_get_trash_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error); - -int -seaf_repo_manager_del_repo_from_trash (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -/* Remove all entries in the repo trash. */ -int -seaf_repo_manager_empty_repo_trash (SeafRepoManager *mgr, GError **error); - -int -seaf_repo_manager_empty_repo_trash_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error); - -int -seaf_repo_manager_restore_repo_from_trash (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -GList * -seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr); - -int -seaf_repo_manager_branch_repo_unmap (SeafRepoManager *manager, SeafBranch *branch); - -/* - * Repo properties functions. - */ - -#define MAX_REPO_TOKEN 64 -#define DEFAULT_REPO_TOKEN "default" - -char * -seaf_repo_manager_get_email_by_token (SeafRepoManager *manager, - const char *repo_id, - const char *token); -char * -seaf_repo_manager_generate_repo_token (SeafRepoManager *mgr, - const char *repo_id, - const char *email, - GError **error); - -int -seaf_repo_manager_add_token_peer_info (SeafRepoManager *mgr, - const char *token, - const char *peer_id, - const char *peer_ip, - const char *peer_name, - gint64 sync_time, - const char *client_ver); - -int -seaf_repo_manager_update_token_peer_info (SeafRepoManager *mgr, - const char *token, - const char *peer_ip, - gint64 sync_time, - const char *client_ver); - -gboolean -seaf_repo_manager_token_peer_info_exists (SeafRepoManager *mgr, - const char *token); - -int -seaf_repo_manager_delete_token (SeafRepoManager *mgr, - const char *repo_id, - const char *token, - const char *user, - GError **error); - -GList * -seaf_repo_manager_list_repo_tokens (SeafRepoManager *mgr, - const char *repo_id, - GError **error); -GList * -seaf_repo_manager_list_repo_tokens_by_email (SeafRepoManager *mgr, - const char *email, - GError **error); -int -seaf_repo_manager_delete_repo_tokens_by_peer_id (SeafRepoManager *mgr, - const char *email, - const char *peer_id, - GList **tokens, - GError **error); - -int -seaf_repo_manager_delete_repo_tokens_by_email (SeafRepoManager *mgr, - const char *email, - GError **error); - -gint64 -seaf_repo_manager_get_repo_size (SeafRepoManager *mgr, const char *repo_id); - -int -seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id, - int days); - -/* - * > 0: keep a period of history; - * = 0: don't keep history; - * < 0: keep full history. - */ -int -seaf_repo_manager_get_repo_history_limit (SeafRepoManager *mgr, - const char *repo_id); - -int -seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id, - gint64 timestamp); - -gint64 -seaf_repo_manager_get_repo_valid_since (SeafRepoManager *mgr, - const char *repo_id); - -/* - * Return the timestamp to stop traversing history. - * Returns > 0 if traverse a period of history; - * Returns = 0 if only traverse the head commit; - * Returns < 0 if traverse full history. - */ -gint64 -seaf_repo_manager_get_repo_truncate_time (SeafRepoManager *mgr, - const char *repo_id); - -/* - * Repo Operations. - */ - -int -seaf_repo_manager_revert_on_server (SeafRepoManager *mgr, - const char *repo_id, - const char *commit_id, - const char *user_name, - GError **error); - -/** - * Add a new file in a repo. - * The content of the file is stored in a temporary file. - * @repo_id: id of the repo - * @temp_file_path: path of the temporary file - * @parent_dir: the directory to add this file - * @file_name: the name of the new file - * @user: author of this operation - */ -int -seaf_repo_manager_post_file (SeafRepoManager *mgr, - const char *repo_id, - const char *temp_file_path, - const char *parent_dir, - const char *file_name, - const char *user, - GError **error); - -int -seaf_repo_manager_post_multi_files (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *filenames_json, - const char *paths_json, - const char *user, - int replace_existed, - char **new_ids, - GError **error); - -int -seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *paths_json, - const char *user, - gint64 file_size, - int replace_existed, - char **new_id, - GError **error); -int -seaf_repo_manager_post_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *blockids_json, - const char *paths_json, - const char *user, - GError **error); - -int -seaf_repo_manager_commit_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *user, - gint64 file_size, - int replace_existed, - char **new_id, - GError **error); - -int -seaf_repo_manager_post_empty_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *new_file_name, - const char *user, - GError **error); - -int -seaf_repo_manager_post_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *new_dir_name, - const char *user, - GError **error); - -/** - * Update an existing file in a repo - * @params: same as seaf_repo_manager_post_file - * @head_id: the commit id for the original file version. - * It's optional. If it's NULL, the current repo head will be used. - * @new_file_id: The return location of the new file id - */ -int -seaf_repo_manager_put_file (SeafRepoManager *mgr, - const char *repo_id, - const char *temp_file_path, - const char *parent_dir, - const char *file_name, - const char *user, - const char *head_id, - char **new_file_id, - GError **error); - -int -seaf_repo_manager_put_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *paths_json, - const char *user, - const char *head_id, - gint64 file_size, - char **new_file_id, - GError **error); - -int -seaf_repo_manager_del_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *user, - GError **error); - -SeafileCopyResult * -seaf_repo_manager_copy_file (SeafRepoManager *mgr, - const char *src_repo_id, - const char *src_dir, - const char *src_filename, - const char *dst_repo_id, - const char *dst_dir, - const char *dst_filename, - const char *user, - int need_progress, - int synchronous, - GError **error); - -SeafileCopyResult * -seaf_repo_manager_move_file (SeafRepoManager *mgr, - const char *src_repo_id, - const char *src_dir, - const char *src_filename, - const char *dst_repo_id, - const char *dst_dir, - const char *dst_filename, - int replace, - const char *user, - int need_progress, - int synchronous, - GError **error); - -int -seaf_repo_manager_rename_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *oldname, - const char *newname, - const char *user, - GError **error); - -int -seaf_repo_manager_is_valid_filename (SeafRepoManager *mgr, - const char *repo_id, - const char *filename, - GError **error); - -char * -seaf_repo_manager_create_new_repo (SeafRepoManager *mgr, - const char *repo_name, - const char *repo_desc, - const char *owner_email, - const char *passwd, - GError **error); - -char * -seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *repo_name, - const char *repo_desc, - const char *owner_email, - const char *magic, - const char *random_key, - int enc_version, - GError **error); - -/* Give a repo and a path in this repo, returns a list of commits, where every - * commit contains a unique version of the file. The commits are sorted in - * ascending order of commit time. */ -GList * -seaf_repo_manager_list_file_revisions (SeafRepoManager *mgr, - const char *repo_id, - const char *start_commit_id, - const char *path, - int max_revision, - int limit, - int show_days, - gboolean got_latest, - GError **error); - -GList * -seaf_repo_manager_calc_files_last_modified (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - int limit, - GError **error); - -int -seaf_repo_manager_revert_file (SeafRepoManager *mgr, - const char *repo_id, - const char *commit_id, - const char *path, - const char *user, - GError **error); - -int -seaf_repo_manager_revert_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *old_commit_id, - const char *dir_path, - const char *user, - GError **error); - -/* - * Return deleted files/dirs. - */ -GList * -seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, - const char *repo_id, - int show_days, - const char *path, - const char *scan_stat, - int limit, - GError **error); - -/* - * Set the dir_id of @dir_path to @new_dir_id. - * @new_commit_id: The new head commit id after the update. - */ -int -seaf_repo_manager_update_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *dir_path, - const char *new_dir_id, - const char *user, - const char *head_id, - char *new_commit_id, - GError **error); - -/* - * Permission related functions. - */ - -/* Owner functions. */ - -int -seaf_repo_manager_set_repo_owner (SeafRepoManager *mgr, - const char *repo_id, - const char *email); - -char * -seaf_repo_manager_get_repo_owner (SeafRepoManager *mgr, - const char *repo_id); - -GList * -seaf_repo_manager_get_orphan_repo_list (SeafRepoManager *mgr); - -/* TODO: add start and limit. */ -/* Get repos owned by this user. - */ -GList * -seaf_repo_manager_get_repos_by_owner (SeafRepoManager *mgr, - const char *email, - int ret_corrupted); - -GList * -seaf_repo_manager_get_repo_ids_by_owner (SeafRepoManager *mgr, - const char *email); - -/* Group repos. */ - -int -seaf_repo_manager_add_group_repo (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - const char *owner, - const char *permission, - GError **error); -int -seaf_repo_manager_del_group_repo (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - GError **error); - -GList * -seaf_repo_manager_get_groups_by_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -typedef struct GroupPerm { - int group_id; - char permission[16]; -} GroupPerm; - -GList * -seaf_repo_manager_get_group_perm_by_repo (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -int -seaf_repo_manager_set_group_repo_perm (SeafRepoManager *mgr, - const char *repo_id, - int group_id, - const char *permission, - GError **error); - -char * -seaf_repo_manager_get_group_repo_owner (SeafRepoManager *mgr, - const char *repo_id, - GError **error); - -GList * -seaf_repo_manager_get_group_repoids (SeafRepoManager *mgr, - int group_id, - GError **error); - -GList * -seaf_repo_manager_get_repos_by_group (SeafRepoManager *mgr, - int group_id, - GError **error); - -GList * -seaf_repo_manager_get_group_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error); - -int -seaf_repo_manager_remove_group_repos (SeafRepoManager *mgr, - int group_id, - const char *owner, - GError **error); - -/* Inner public repos */ - -int -seaf_repo_manager_set_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *permission); - -int -seaf_repo_manager_unset_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id); - -gboolean -seaf_repo_manager_is_inner_pub_repo (SeafRepoManager *mgr, - const char *repo_id); - -GList * -seaf_repo_manager_list_inner_pub_repos (SeafRepoManager *mgr); - -gint64 -seaf_repo_manager_count_inner_pub_repos (SeafRepoManager *mgr); - -GList * -seaf_repo_manager_list_inner_pub_repos_by_owner (SeafRepoManager *mgr, - const char *user); - -char * -seaf_repo_manager_get_inner_pub_repo_perm (SeafRepoManager *mgr, - const char *repo_id); - -/* - * Comprehensive repo permission checker. - * It checks if @user have permission to access @repo_id. - */ -char * -seaf_repo_manager_check_permission (SeafRepoManager *mgr, - const char *repo_id, - const char *user, - GError **error); - -GList * -seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr, - const char *repo_id, - const char *dir_path, - const char *dir_id, - const char *user, - int offset, - int limit, - GError **error); - -/* Web access permission. */ - -int -seaf_repo_manager_set_access_property (SeafRepoManager *mgr, const char *repo_id, - const char *ap); - -char * -seaf_repo_manager_query_access_property (SeafRepoManager *mgr, const char *repo_id); - -/* Decrypted repo token cache. */ - -void -seaf_repo_manager_add_decrypted_token (SeafRepoManager *mgr, - const char *encrypted_token, - const char *session_key, - const char *decrypted_token); - -char * -seaf_repo_manager_get_decrypted_token (SeafRepoManager *mgr, - const char *encrypted_token, - const char *session_key); - -/* Virtual repo related. */ - -char * -seaf_repo_manager_create_virtual_repo (SeafRepoManager *mgr, - const char *origin_repo_id, - const char *path, - const char *repo_name, - const char *repo_desc, - const char *owner, - const char *passwd, - GError **error); - -SeafVirtRepo * -seaf_repo_manager_get_virtual_repo_info (SeafRepoManager *mgr, - const char *repo_id); - -GList * -seaf_repo_manager_get_virtual_info_by_origin (SeafRepoManager *mgr, - const char *origin_repo); - -void -seaf_virtual_repo_info_free (SeafVirtRepo *vinfo); - -gboolean -seaf_repo_manager_is_virtual_repo (SeafRepoManager *mgr, const char *repo_id); - -char * -seaf_repo_manager_get_virtual_repo_id (SeafRepoManager *mgr, - const char *origin_repo, - const char *path, - const char *owner); - -GList * -seaf_repo_manager_get_virtual_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error); - -GList * -seaf_repo_manager_get_virtual_repo_ids_by_origin (SeafRepoManager *mgr, - const char *origin_repo); - -/* - * if @repo_id is a virtual repo, try to merge with origin; - * if not, try to merge with its virtual repos. - */ -int -seaf_repo_manager_merge_virtual_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *exclude_repo); - -/* - * Check each virtual repo of @origin_repo_id, if the path corresponds to it - * doesn't exist, delete the virtual repo. - */ -void -seaf_repo_manager_cleanup_virtual_repos (SeafRepoManager *mgr, - const char *origin_repo_id); - -int -seaf_repo_manager_init_merge_scheduler (); - -GList * -seaf_repo_manager_get_shared_users_for_subdir (SeafRepoManager *mgr, - const char *repo_id, - const char *path, - const char *from_user, - GError **error); - -GList * -seaf_repo_manager_get_shared_groups_for_subdir (SeafRepoManager *mgr, - const char *repo_id, - const char *path, - const char *from_user, - GError **error); -#endif diff --git a/server/repo-op.c b/server/repo-op.c deleted file mode 100644 index eeefd7b4..00000000 --- a/server/repo-op.c +++ /dev/null @@ -1,5425 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include - -#include -#include - -#include -#include -#include "utils.h" -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" -#include "seafile.h" -#include "seafile-object.h" - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "fs-mgr.h" -#include "seafile-error.h" -#include "seafile-crypt.h" -#include "diff-simple.h" -#include "merge-new.h" - -#include "seaf-db.h" - -#define INDEX_DIR "index" - -#define PREFIX_DEL_FILE "Deleted \"" -#define PREFIX_DEL_DIR "Removed directory \"" -#define PREFIX_DEL_DIRS "Removed \"" - -gboolean -should_ignore_file(const char *filename, void *data); - -/* - * Repo operations. - */ - -static gint -compare_dirents (gconstpointer a, gconstpointer b) -{ - const SeafDirent *ent_a = a, *ent_b = b; - - return strcmp (ent_b->name, ent_a->name); -} - -static inline GList * -dup_seafdir_entries (const GList *entries) -{ - const GList *p; - GList *newentries = NULL; - SeafDirent *dent; - - for (p = entries; p; p = p->next) { - dent = p->data; - newentries = g_list_prepend (newentries, seaf_dirent_dup(dent)); - } - - return g_list_reverse(newentries); -} - -static gboolean -filename_exists (GList *entries, const char *filename) -{ - GList *ptr; - SeafDirent *dent; - - for (ptr = entries; ptr != NULL; ptr = ptr->next) { - dent = ptr->data; - if (strcmp (dent->name, filename) == 0) - return TRUE; - } - - return FALSE; -} - -static void -split_filename (const char *filename, char **name, char **ext) -{ - char *dot; - - dot = strrchr (filename, '.'); - if (dot) { - *ext = g_strdup (dot + 1); - *name = g_strndup (filename, dot - filename); - } else { - *name = g_strdup (filename); - *ext = NULL; - } -} - -static char * -generate_unique_filename (const char *file, GList *entries) -{ - int i = 1; - char *name, *ext, *unique_name; - - unique_name = g_strdup(file); - split_filename (unique_name, &name, &ext); - while (filename_exists (entries, unique_name) && i <= 16) { - g_free (unique_name); - if (ext) - unique_name = g_strdup_printf ("%s (%d).%s", name, i, ext); - else - unique_name = g_strdup_printf ("%s (%d)", name, i); - i++; - } - - g_free (name); - g_free (ext); - - if (i <= 16) - return unique_name; - else { - g_free (unique_name); - return NULL; - } -} - -/* We need to call this function recursively because every dirs in canon_path - * need to be updated. - */ -static char * -post_file_recursive (SeafRepo *repo, - const char *dir_id, - const char *to_path, - int replace_existed, - SeafDirent *newdent) -{ - SeafDir *olddir, *newdir; - SeafDirent *dent; - GList *ptr; - char *slash; - char *to_path_dup = NULL; - char *remain = NULL; - char *id = NULL; - char *ret = NULL; - - olddir = seaf_fs_manager_get_seafdir_sorted(seaf->fs_mgr, - repo->store_id, repo->version, - dir_id); - if (!olddir) - return NULL; - - /* we reach the target dir. new dir entry is added */ - if (*to_path == '\0') { - GList *newentries = NULL; - char *unique_name; - SeafDirent *dent_dup; - if (replace_existed && filename_exists(olddir->entries, newdent->name)) { - GList *p; - SeafDirent *dent; - - for (p = olddir->entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, newdent->name) == 0) { - newentries = g_list_prepend (newentries, seaf_dirent_dup(newdent)); - } else { - newentries = g_list_prepend (newentries, seaf_dirent_dup(dent)); - } - } - newentries = g_list_reverse (newentries); - newdir = seaf_dir_new (NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) { - ret = g_strdup (newdir->dir_id); - } - seaf_dir_free (newdir); - goto out; - } - - unique_name = generate_unique_filename (newdent->name, olddir->entries); - if (!unique_name) - goto out; - dent_dup = seaf_dirent_new (newdent->version, - newdent->id, newdent->mode, unique_name, - newdent->mtime, newdent->modifier, newdent->size); - g_free (unique_name); - - newentries = dup_seafdir_entries (olddir->entries); - - newentries = g_list_insert_sorted (newentries, - dent_dup, - compare_dirents); - - newdir = seaf_dir_new (NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup (newdir->dir_id); - seaf_dir_free (newdir); - - goto out; - } - - to_path_dup = g_strdup (to_path); - slash = strchr (to_path_dup, '/'); - - if (!slash) { - remain = to_path_dup + strlen(to_path_dup); - } else { - *slash = '\0'; - remain = slash + 1; - } - - for (ptr = olddir->entries; ptr; ptr = ptr->next) { - dent = (SeafDirent *)ptr->data; - - if (strcmp(dent->name, to_path_dup) != 0) - continue; - - id = post_file_recursive (repo, dent->id, remain, replace_existed, newdent); - if (id != NULL) { - memcpy(dent->id, id, 40); - dent->id[40] = '\0'; - if (repo->version > 0) - dent->mtime = (guint64)time(NULL); - } - break; - } - - if (id != NULL) { - /* Create a new SeafDir. */ - GList *new_entries; - - new_entries = dup_seafdir_entries (olddir->entries); - newdir = seaf_dir_new (NULL, new_entries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strndup (newdir->dir_id, 40); - seaf_dir_free (newdir); - } - -out: - g_free (to_path_dup); - g_free (id); - seaf_dir_free(olddir); - return ret; -} - -static char * -do_post_file_replace (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - int replace_existed, - SeafDirent *dent) -{ - /* if parent_dir is a absolutely path, we will remove the first '/' */ - if (*parent_dir == '/') - parent_dir = parent_dir + 1; - - return post_file_recursive(repo, root_id, parent_dir, replace_existed, dent); -} - -static char * -do_post_file (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - SeafDirent *dent) -{ - return do_post_file_replace(repo, root_id, parent_dir, 0, dent); -} - -static char * -get_canonical_path (const char *path) -{ - char *ret = g_strdup (path); - char *p; - - for (p = ret; *p != 0; ++p) { - if (*p == '\\') - *p = '/'; - } - - /* Remove trailing slashes from dir path. */ - int len = strlen(ret); - int i = len - 1; - while (i >= 0 && ret[i] == '/') - ret[i--] = 0; - - return ret; -} - -/* Return TRUE if @filename already existing in @parent_dir. If exists, and - @mode is not NULL, set its value to the mode of the dirent. -*/ -static gboolean -check_file_exists (const char *store_id, - int repo_version, - const char *root_id, - const char *parent_dir, - const char *filename, - int *mode) -{ - SeafDir *dir; - GList *p; - SeafDirent *dent; - int ret = FALSE; - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - store_id, repo_version, - root_id, - parent_dir, NULL); - if (!dir) { - seaf_warning ("parent_dir %s doesn't exist in repo %s.\n", - parent_dir, store_id); - return FALSE; - } - - for (p = dir->entries; p != NULL; p = p->next) { - dent = p->data; - int r = strcmp (dent->name, filename); - if (r == 0) { - ret = TRUE; - if (mode) { - *mode = dent->mode; - } - break; - } - } - - seaf_dir_free (dir); - - return ret; -} - -/** - Various online file/directory operations: - - Put a file: - 1. find parent seafdir - 2. add a new dirent to parent seafdir - 2. recursively update all seafdir in the path, in a bottom-up manner - 3. commit it - - Del a file/dir: - basically the same as put a file - - copy a file/dir: - 1. get src dirent from src repo - 2. duplicate src dirent with the new file name - 3. put the new dirent to dst repo and commit it. - - Move a file/dir: - basically the same as a copy operation. Just one more step: - 4. remove src dirent from src repo and commit it - - Rename a file/dir: - 1. find parent seafdir - 2. update this seafdir with the old dirent replaced by a new dirent. - 3. recursively update all seafdir in the path - - NOTE: - - All operations which add a new dirent would check if a dirent with the same - name already exists. If found, they would raise errors. - - All operations which remove a dirent would check if the dirent to be removed - already exists. If not, they would do nothing and just return OK. - -*/ - -#define GET_REPO_OR_FAIL(repo_var,repo_id) \ - do { \ - repo_var = seaf_repo_manager_get_repo (seaf->repo_mgr, (repo_id)); \ - if (!(repo_var)) { \ - seaf_warning ("Repo %s doesn't exist.\n", (repo_id)); \ - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo"); \ - ret = -1; \ - goto out; \ - } \ - } while (0); - -#define GET_COMMIT_OR_FAIL(commit_var,repo_id,repo_version,commit_id) \ - do { \ - commit_var = seaf_commit_manager_get_commit(seaf->commit_mgr, (repo_id), (repo_version), (commit_id)); \ - if (!(commit_var)) { \ - seaf_warning ("commit %s:%s doesn't exist.\n", (repo_id), (commit_id)); \ - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid commit"); \ - ret = -1; \ - goto out; \ - } \ - } while (0); - -#define FAIL_IF_FILE_EXISTS(store_id,repo_version,root_id,parent_dir,filename,mode) \ - do { \ - if (check_file_exists ((store_id), (repo_version), (root_id), (parent_dir), (filename), (mode))) { \ - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, \ - "file already exists"); \ - ret = -1; \ - goto out; \ - } \ - } while (0); - -#define FAIL_IF_FILE_NOT_EXISTS(store_id,repo_version,root_id,parent_dir,filename,mode) \ - do { \ - if (!check_file_exists ((store_id), (repo_version), (root_id), (parent_dir), (filename), (mode))) { \ - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, \ - "file does not exist"); \ - ret = -1; \ - goto out; \ - } \ - } while (0); - -#define STD_FILE_MODE (S_IFREG | 0644) - -static char * -gen_merge_description (SeafRepo *repo, - const char *merged_root, - const char *p1_root, - const char *p2_root) -{ - GList *p; - GList *results = NULL; - char *desc; - - diff_merge_roots (repo->store_id, repo->version, - merged_root, p1_root, p2_root, &results, TRUE); - - desc = diff_results_to_description (results); - - for (p = results; p; p = p->next) { - DiffEntry *de = p->data; - diff_entry_free (de); - } - g_list_free (results); - - return desc; -} - -static int -gen_new_commit (const char *repo_id, - SeafCommit *base, - const char *new_root, - const char *user, - const char *desc, - char *new_commit_id, - GError **error) -{ -#define MAX_RETRY_COUNT 3 - - SeafRepo *repo = NULL; - SeafCommit *new_commit = NULL, *current_head = NULL, *merged_commit = NULL; - int retry_cnt = 0; - int ret = 0; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Invalid repo"); - ret = -1; - goto out; - } - - /* Create a new commit pointing to new_root. */ - new_commit = seaf_commit_new(NULL, repo->id, new_root, - user, EMPTY_SHA1, - desc, 0); - new_commit->parent_id = g_strdup (base->commit_id); - seaf_repo_to_commit (repo, new_commit); - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, new_commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add commit"); - ret = -1; - goto out; - } - -retry: - current_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!current_head) { - seaf_warning ("Failed to find head commit %s of %s.\n", - repo->head->commit_id, repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Invalid repo"); - ret = -1; - goto out; - } - - /* Merge if base and head are not the same. */ - if (strcmp (base->commit_id, current_head->commit_id) != 0) { - MergeOptions opt; - const char *roots[3]; - char *desc = NULL; - - memset (&opt, 0, sizeof(opt)); - opt.n_ways = 3; - memcpy (opt.remote_repo_id, repo_id, 36); - memcpy (opt.remote_head, new_commit->commit_id, 40); - opt.do_merge = TRUE; - - roots[0] = base->root_id; /* base */ - roots[1] = current_head->root_id; /* head */ - roots[2] = new_root; /* remote */ - - if (seaf_merge_trees (repo->store_id, repo->version, 3, roots, &opt) < 0) { - seaf_warning ("Failed to merge.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Internal error"); - ret = -1; - goto out; - } - - seaf_debug ("Number of dirs visted in merge %.8s: %d.\n", - repo_id, opt.visit_dirs); - - if (!opt.conflict) - desc = g_strdup("Auto merge by system"); - else { - desc = gen_merge_description (repo, - opt.merged_tree_root, - current_head->root_id, - new_root); - if (!desc) - desc = g_strdup("Auto merge by system"); - } - - merged_commit = seaf_commit_new(NULL, repo->id, opt.merged_tree_root, - user, EMPTY_SHA1, - desc, - 0); - g_free (desc); - - merged_commit->parent_id = g_strdup (current_head->commit_id); - merged_commit->second_parent_id = g_strdup (new_commit->commit_id); - merged_commit->new_merge = TRUE; - if (opt.conflict) - merged_commit->conflict = TRUE; - seaf_repo_to_commit (repo, merged_commit); - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged_commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add commit"); - ret = -1; - goto out; - } - } else { - seaf_commit_ref (new_commit); - merged_commit = new_commit; - } - - seaf_branch_set_commit(repo->head, merged_commit->commit_id); - - if (seaf_branch_manager_test_and_update_branch(seaf->branch_mgr, - repo->head, - current_head->commit_id) < 0) - { - seaf_repo_unref (repo); - repo = NULL; - seaf_commit_unref (current_head); - current_head = NULL; - seaf_commit_unref (merged_commit); - merged_commit = NULL; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Repo %s doesn't exist.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Invalid repo"); - ret = -1; - goto out; - } - - if (++retry_cnt <= MAX_RETRY_COUNT) { - /* Sleep random time between 100 and 1000 millisecs. */ - usleep (g_random_int_range(1, 11) * 100 * 1000); - goto retry; - } else { - ret = -1; - goto out; - } - } - - if (new_commit_id) - memcpy (new_commit_id, merged_commit->commit_id, 41); - -out: - seaf_commit_unref (new_commit); - seaf_commit_unref (current_head); - seaf_commit_unref (merged_commit); - seaf_repo_unref (repo); - return ret; -} - -static void -update_repo_size(const char *repo_id) -{ - schedule_repo_size_computation (seaf->size_sched, repo_id); -} - -int -seaf_repo_manager_post_file (SeafRepoManager *mgr, - const char *repo_id, - const char *temp_file_path, - const char *parent_dir, - const char *file_name, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - unsigned char sha1[20]; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafileCrypt *crypt = NULL; - SeafDirent *new_dent = NULL; - char hex[41]; - int ret = 0; - - if (g_access (temp_file_path, R_OK) != 0) { - seaf_warning ("[post file] File %s doesn't exist or not readable.\n", - temp_file_path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid input file"); - return -1; - } - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (file_name, NULL)) { - seaf_debug ("[post file] Invalid filename %s.\n", file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_debug ("[post file] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - /* Write blocks. */ - if (repo->encrypted) { - unsigned char key[32], iv[16]; - if (seaf_passwd_manager_get_decrypt_key_raw (seaf->passwd_mgr, - repo_id, user, - key, iv) < 0) { - seaf_debug ("Passwd for repo %s is not set.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Passwd is not set"); - ret = -1; - goto out; - } - crypt = seafile_crypt_new (repo->enc_version, key, iv); - } - - gint64 size; - if (seaf_fs_manager_index_blocks (seaf->fs_mgr, - repo->store_id, repo->version, - temp_file_path, - sha1, &size, crypt, TRUE, FALSE) < 0) { - seaf_warning ("failed to index blocks"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - new_dent = seaf_dirent_new (dir_version_from_repo_version (repo->version), - hex, STD_FILE_MODE, file_name, - (gint64)time(NULL), user, size); - - root_id = do_post_file (repo, - head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[post file] Failed to post file %s to %s in repo %s.\n", - file_name, canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to post file"); - ret = -1; - goto out; - } - - snprintf(buf, SEAF_PATH_MAX, "Added \"%s\"", file_name); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - g_free (crypt); - - if (ret == 0) - update_repo_size(repo_id); - - return ret; -} - -static int -add_new_entries (SeafRepo *repo, const char *user, - GList **entries, GList *filenames, GList *id_list, - GList *size_list, int replace_existed, GList **name_list) -{ - GList *ptr1, *ptr2, *ptr3; - char *file, *id; - gint64 *size; - - for (ptr1 = filenames, ptr2 = id_list, ptr3 = size_list; - ptr1 && ptr2 && ptr3; - ptr1 = ptr1->next, ptr2 = ptr2->next, ptr3 = ptr3->next) - { - file = ptr1->data; - id = ptr2->data; - size = ptr3->data; - - char *unique_name; - SeafDirent *newdent; - gboolean replace = FALSE; - - if (replace_existed) { - GList *p; - SeafDirent *dent; - - for (p = *entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, file) == 0) { - replace = TRUE; - *entries = g_list_delete_link (*entries, p); - seaf_dirent_free (dent); - break; - } - } - } - - if (replace) - unique_name = g_strdup (file); - else - unique_name = generate_unique_filename (file, *entries); - - if (unique_name != NULL) { - newdent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - id, STD_FILE_MODE, unique_name, - (gint64)time(NULL), user, *size); - *entries = g_list_insert_sorted (*entries, newdent, compare_dirents); - *name_list = g_list_append (*name_list, unique_name); - /* No need to free unique_name */ - } else { - return -1; - } - } - - return 0; -} - -static char * -post_multi_files_recursive (SeafRepo *repo, - const char *dir_id, - const char *to_path, - GList *filenames, - GList *id_list, - GList *size_list, - const char *user, - int replace_existed, - GList **name_list) -{ - SeafDir *olddir, *newdir; - SeafDirent *dent; - GList *ptr; - char *slash; - char *to_path_dup = NULL; - char *remain = NULL; - char *id = NULL; - char *ret = NULL; - - olddir = seaf_fs_manager_get_seafdir_sorted(seaf->fs_mgr, - repo->store_id, - repo->version, - dir_id); - if (!olddir) - return NULL; - - /* we reach the target dir. new dir entry is added */ - if (*to_path == '\0') { - GList *newentries; - - newentries = dup_seafdir_entries (olddir->entries); - - if (add_new_entries (repo, user, - &newentries, filenames, id_list, size_list, - replace_existed, name_list) < 0) - goto out; - - newdir = seaf_dir_new (NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup (newdir->dir_id); - seaf_dir_free (newdir); - - goto out; - } - - to_path_dup = g_strdup (to_path); - slash = strchr (to_path_dup, '/'); - - if (!slash) { - remain = to_path_dup + strlen(to_path_dup); - } else { - *slash = '\0'; - remain = slash + 1; - } - - for (ptr = olddir->entries; ptr; ptr = ptr->next) { - dent = (SeafDirent *)ptr->data; - - if (strcmp(dent->name, to_path_dup) != 0) - continue; - - id = post_multi_files_recursive (repo, dent->id, remain, filenames, - id_list, size_list, user, - replace_existed, name_list); - if (id != NULL) { - memcpy(dent->id, id, 40); - dent->id[40] = '\0'; - if (repo->version > 0) - dent->mtime = (guint64)time(NULL); - } - break; - } - - if (id != NULL) { - /* Create a new SeafDir. */ - GList *new_entries; - - new_entries = dup_seafdir_entries (olddir->entries); - newdir = seaf_dir_new (NULL, new_entries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup (newdir->dir_id); - seaf_dir_free (newdir); - } - -out: - g_free (to_path_dup); - g_free (id); - seaf_dir_free(olddir); - return ret; -} - -static char * -do_post_multi_files (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - GList *filenames, - GList *id_list, - GList *size_list, - const char *user, - int replace_existed, - GList **name_list) -{ - /* if parent_dir is a absolutely path, we will remove the first '/' */ - if (*parent_dir == '/') - parent_dir = parent_dir + 1; - - return post_multi_files_recursive(repo, root_id, parent_dir, - filenames, id_list, size_list, - user, replace_existed, name_list); -} - -static GList * -json_to_file_list (const char *files_json) -{ - json_t *array; - GList *files = NULL; - json_error_t jerror; - size_t index; - json_t *value; - const char *file; - char *norm_file; - - array = json_loadb (files_json, strlen(files_json), 0, &jerror); - if (!array) { - seaf_warning ("Failed to load json file list: %s.\n", jerror.text); - return NULL; - } - - size_t n = json_array_size (array); - for (index = 0; index < n; index++) { - value = json_array_get (array, index); - file = json_string_value (value); - if (!file) { - g_list_free_full (files, g_free); - files = NULL; - break; - } - - norm_file = normalize_utf8_path (file); - if (!norm_file) { - g_list_free_full (files, g_free); - files = NULL; - break; - } - - files = g_list_prepend (files, norm_file); - } - - json_decref (array); - return files; -} - -/* - * Return [{'name': 'file1', 'id': 'id1', 'size': num1}, {'name': 'file2', 'id': 'id2', 'size': num2}] - */ -static char * -format_json_ret (GList *name_list, GList *id_list, GList *size_list) -{ - json_t *array, *obj; - GList *ptr, *ptr2; - GList *sptr; - char *filename, *id; - gint64 *size; - char *json_data; - char *ret; - - array = json_array (); - - for (ptr = name_list, ptr2 = id_list, sptr = size_list; - ptr && ptr2 && sptr; - ptr = ptr->next, ptr2 = ptr2->next, sptr = sptr->next) { - filename = ptr->data; - id = ptr2->data; - size = sptr->data; - obj = json_object (); - json_object_set_string_member (obj, "name", filename); - json_object_set_string_member (obj, "id", id); - json_object_set_int_member (obj, "size", *size); - json_array_append_new (array, obj); - } - - json_data = json_dumps (array, 0); - json_decref (array); - - ret = g_strdup (json_data); - free (json_data); - return ret; -} - -int -seaf_repo_manager_post_multi_files (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *filenames_json, - const char *paths_json, - const char *user, - int replace_existed, - char **ret_json, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - GList *filenames = NULL, *paths = NULL, *id_list = NULL, *name_list = NULL, - *size_list = NULL, *ptr; - char *filename, *path; - unsigned char sha1[20]; - GString *buf = g_string_new (NULL); - char *root_id = NULL; - SeafileCrypt *crypt = NULL; - char hex[41]; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - canon_path = get_canonical_path (parent_dir); - - /* Decode file name and tmp file paths from json. */ - filenames = json_to_file_list (filenames_json); - paths = json_to_file_list (paths_json); - if (!filenames || !paths) { - seaf_debug ("[post files] Invalid filenames or paths.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid files"); - ret = -1; - goto out; - } - - /* Check inputs. */ - for (ptr = filenames; ptr; ptr = ptr->next) { - filename = ptr->data; - if (should_ignore_file (filename, NULL)) { - seaf_debug ("[post files] Invalid filename %s.\n", filename); - g_set_error (error, SEAFILE_DOMAIN, POST_FILE_ERR_FILENAME, - "%s", filename); - ret = -1; - goto out; - } - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_debug ("[post file] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - /* Index tmp files and get file id list. */ - if (repo->encrypted) { - unsigned char key[32], iv[16]; - if (seaf_passwd_manager_get_decrypt_key_raw (seaf->passwd_mgr, - repo_id, user, - key, iv) < 0) { - seaf_debug ("Passwd for repo %s is not set.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Passwd is not set"); - ret = -1; - goto out; - } - crypt = seafile_crypt_new (repo->enc_version, key, iv); - } - - gint64 *size; - for (ptr = paths; ptr; ptr = ptr->next) { - path = ptr->data; - - size = g_new (gint64, 1); - if (seaf_fs_manager_index_blocks (seaf->fs_mgr, - repo->store_id, repo->version, - path, sha1, size, crypt, TRUE, FALSE) < 0) { - seaf_warning ("failed to index blocks"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - id_list = g_list_prepend (id_list, g_strdup(hex)); - size_list = g_list_prepend (size_list, size); - } - id_list = g_list_reverse (id_list); - size_list = g_list_reverse (size_list); - - /* Add the files to parent dir and commit. */ - root_id = do_post_multi_files (repo, head_commit->root_id, canon_path, - filenames, id_list, size_list, user, - replace_existed, &name_list); - if (!root_id) { - seaf_warning ("[post multi-file] Failed to post files to %s in repo %s.\n", - canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, - "Failed to put file"); - ret = -1; - goto out; - } - - guint len = g_list_length (filenames); - if (len > 1) - g_string_printf (buf, "Added \"%s\" and %u more files.", - (char *)(filenames->data), len - 1); - else - g_string_printf (buf, "Added \"%s\".", (char *)(filenames->data)); - - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf->str, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - - if (ret_json) - *ret_json = format_json_ret (name_list, id_list, size_list); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - string_list_free (filenames); - string_list_free (paths); - string_list_free (id_list); - string_list_free (name_list); - for (ptr = size_list; ptr; ptr = ptr->next) - g_free (ptr->data); - g_list_free (size_list); - g_string_free (buf, TRUE); - g_free (root_id); - g_free (canon_path); - g_free (crypt); - - if (ret == 0) - update_repo_size(repo_id); - - return ret; -} - -int -seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *paths_json, - const char *user, - gint64 file_size, - int replace_existed, - char **new_id, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - unsigned char sha1[20]; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafDirent *new_dent = NULL; - GList *blockids = NULL, *paths = NULL, *ptr; - char hex[41]; - int ret = 0; - - blockids = json_to_file_list (blockids_json); - paths = json_to_file_list (paths_json); - if (g_list_length(blockids) != g_list_length(paths)) { - seaf_debug ("[post-blks] Invalid blockids or paths.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid files"); - ret = -1; - goto out; - } - - for (ptr = paths; ptr; ptr = ptr->next) { - char *temp_file_path = ptr->data; - if (g_access (temp_file_path, R_OK) != 0) { - seaf_warning ("[post-blks] File block %s doesn't exist or not readable.\n", - temp_file_path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid input file"); - ret = -1; - goto out; - } - } - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (file_name, NULL)) { - seaf_debug ("[post-blks] Invalid filename %s.\n", file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_debug ("[post-blks] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - /* Write blocks. */ - if (seaf_fs_manager_index_file_blocks (seaf->fs_mgr, - repo->store_id, repo->version, - paths, - blockids, sha1, file_size) < 0) { - seaf_warning ("Failed to index file blocks"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - hex, STD_FILE_MODE, file_name, - (gint64)time(NULL), user, file_size); - - root_id = do_post_file_replace (repo, head_commit->root_id, - canon_path, replace_existed, new_dent); - if (!root_id) { - seaf_warning ("[post-blks] Failed to post file to %s in repo %s.\n", - canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put file"); - ret = -1; - goto out; - } - - *new_id = g_strdup(hex); - snprintf(buf, SEAF_PATH_MAX, "Added \"%s\"", file_name); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) - ret = -1; - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - string_list_free (blockids); - string_list_free (paths); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - - if (ret == 0) - update_repo_size(repo_id); - - return ret; -} - -int -seaf_repo_manager_post_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *blockids_json, - const char *paths_json, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - char buf[SEAF_PATH_MAX]; - GList *blockids = NULL, *paths = NULL, *ptr; - int ret = 0; - - blockids = json_to_file_list (blockids_json); - paths = json_to_file_list (paths_json); - if (g_list_length(blockids) != g_list_length(paths)) { - seaf_warning ("[post-blks] Invalid blockids or paths.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid files"); - ret = -1; - goto out; - } - - for (ptr = paths; ptr; ptr = ptr->next) { - char *temp_file_path = ptr->data; - if (g_access (temp_file_path, R_OK) != 0) { - seaf_warning ("[post-blks] File block %s doesn't exist or not readable.\n", - temp_file_path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid input file"); - ret = -1; - goto out; - } - } - - GET_REPO_OR_FAIL(repo, repo_id); - - /* Write blocks. */ - if (seaf_fs_manager_index_raw_blocks (seaf->fs_mgr, - repo->store_id, - repo->version, - paths, - blockids) < 0) { - seaf_warning ("Failed to index file blocks.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - -out: - if (repo) - seaf_repo_unref (repo); - string_list_free (blockids); - string_list_free (paths); - - if (ret == 0) - update_repo_size(repo_id); - - return ret; -} - -int -seaf_repo_manager_commit_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *user, - gint64 file_size, - int replace_existed, - char **new_id, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - unsigned char sha1[20]; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafDirent *new_dent = NULL; - GList *blockids = NULL; - char hex[41]; - int ret = 0; - - blockids = json_to_file_list (blockids_json); - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (file_name, NULL)) { - seaf_warning ("[post-blks] Invalid filename %s.\n", file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_warning ("[post-blks] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - /* Write blocks. */ - if (seaf_fs_manager_index_existed_file_blocks ( - seaf->fs_mgr, repo->store_id, repo->version, - blockids, sha1, file_size) < 0) { - seaf_warning ("Failed to index existed file blocks.\n"); - g_set_error (error, SEAFILE_DOMAIN, POST_FILE_ERR_BLOCK_MISSING, - "Failed to index file blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - hex, STD_FILE_MODE, file_name, - (gint64)time(NULL), user, file_size); - - root_id = do_post_file_replace (repo, head_commit->root_id, - canon_path, replace_existed, new_dent); - if (!root_id) { - seaf_warning ("[post-blks] Failed to post file to %s in repo %s.\n", - canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put file"); - ret = -1; - goto out; - } - - *new_id = g_strdup(hex); - snprintf(buf, SEAF_PATH_MAX, "Added \"%s\"", file_name); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) - ret = -1; - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - string_list_free (blockids); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - - if (ret == 0) - update_repo_size(repo_id); - - return ret; -} - -static char * -del_file_recursive(SeafRepo *repo, - const char *dir_id, - const char *to_path, - const char *filename) -{ - SeafDir *olddir, *newdir; - SeafDirent *dent; - GList *ptr; - char *to_path_dup = NULL; - char *remain = NULL; - char *slash; - char *id = NULL; - char *ret = NULL; - - olddir = seaf_fs_manager_get_seafdir_sorted(seaf->fs_mgr, - repo->store_id, repo->version, - dir_id); - if (!olddir) - return NULL; - - /* we reach the target dir. Remove the given entry from it. */ - if (*to_path == '\0') { - SeafDirent *old, *new; - GList *newentries = NULL, *p; - - for (p = olddir->entries; p != NULL; p = p->next) { - old = p->data; - if (strcmp(old->name, filename) != 0) { - new = seaf_dirent_dup (old); - newentries = g_list_prepend (newentries, new); - } - } - - newentries = g_list_reverse (newentries); - - newdir = seaf_dir_new(NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save(seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup(newdir->dir_id); - seaf_dir_free(newdir); - - goto out; - } - - to_path_dup = g_strdup (to_path); - slash = strchr (to_path_dup, '/'); - - if (!slash) { - remain = to_path_dup + strlen(to_path_dup); - } else { - *slash = '\0'; - remain = slash + 1; - } - - for (ptr = olddir->entries; ptr; ptr = ptr->next) { - dent = (SeafDirent *)ptr->data; - - if (strcmp(dent->name, to_path_dup) != 0) - continue; - - id = del_file_recursive(repo, dent->id, remain, filename); - if (id != NULL) { - memcpy(dent->id, id, 40); - dent->id[40] = '\0'; - if (repo->version > 0) - dent->mtime = (guint64)time(NULL); - } - break; - } - if (id != NULL) { - /* Create a new SeafDir. */ - GList *new_entries; - - new_entries = dup_seafdir_entries (olddir->entries); - newdir = seaf_dir_new (NULL, new_entries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup (newdir->dir_id); - seaf_dir_free (newdir); - } - -out: - g_free (to_path_dup); - g_free (id); - seaf_dir_free(olddir); - return ret; -} - -static char * -do_del_file(SeafRepo *repo, - const char *root_id, - const char *parent_dir, - const char *file_name) -{ - /* if parent_dir is a absolutely path, we will remove the first '/' */ - if (*parent_dir == '/') - parent_dir = parent_dir + 1; - - return del_file_recursive(repo, root_id, parent_dir, file_name); -} - -int -seaf_repo_manager_del_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - int mode = 0; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (!check_file_exists(repo->store_id, repo->version, - head_commit->root_id, canon_path, file_name, &mode)) { - goto out; - } - - root_id = do_del_file (repo, - head_commit->root_id, canon_path, file_name); - if (!root_id) { - seaf_warning ("[del file] Failed to del file %s from %s in repo %s.\n", - file_name, canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to del file"); - ret = -1; - goto out; - } - - /* Commit. */ - if (S_ISDIR(mode)) { - snprintf(buf, SEAF_PATH_MAX, "Removed directory \"%s\"", file_name); - } else { - snprintf(buf, SEAF_PATH_MAX, "Deleted \"%s\"", file_name); - } - - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (mgr, repo_id); - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - g_free (root_id); - g_free (canon_path); - - if (ret == 0) { - update_repo_size (repo_id); - } - - return ret; -} - -static SeafDirent * -get_dirent_by_path (SeafRepo *repo, - const char *root_id, - const char *path, - const char *file_name, - GError **error) -{ - SeafCommit *head_commit = NULL; - SeafDirent *dent = NULL; - SeafDir *dir = NULL; - - if (!root_id) { - head_commit = seaf_commit_manager_get_commit(seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!head_commit) { - seaf_warning ("commit %s:%s doesn't exist.\n", - repo->id, repo->head->commit_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid commit"); - goto out; - } - root_id = head_commit->root_id; - } - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - root_id, - path, NULL); - if (!dir) { - seaf_warning ("dir %s doesn't exist in repo %s.\n", path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid dir"); - goto out; - } - - GList *p; - for (p = dir->entries; p; p = p->next) { - SeafDirent *d = p->data; - int r = strcmp (d->name, file_name); - if (r == 0) { - dent = seaf_dirent_dup(d); - break; - } - } - - if (!dent && error && !(*error)) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "failed to get dirent"); - } - -out: - if (head_commit) - seaf_commit_unref (head_commit); - if (dir) - seaf_dir_free (dir); - - return dent; -} - -static int -put_dirent_and_commit (SeafRepo *repo, - const char *path, - SeafDirent *dent, - int replace, - const char *user, - GError **error) -{ - SeafCommit *head_commit = NULL; - char *root_id = NULL; - char buf[SEAF_PATH_MAX]; - int ret = 0; - - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - root_id = do_post_file_replace (repo, - head_commit->root_id, path, - replace, dent); - if (!root_id) { - seaf_warning ("[cp file] Failed to cp file %s to %s in repo %s.\n", - dent->name, path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to cp file"); - ret = -1; - goto out; - } - - /* Commit. */ - if (S_ISDIR(dent->mode)) { - snprintf(buf, sizeof(buf), "Added directory \"%s\"", dent->name); - } else { - snprintf(buf, sizeof(buf), "Added \"%s\"", dent->name); - } - - if (gen_new_commit (repo->id, head_commit, root_id, - user, buf, NULL, error) < 0) - ret = -1; - -out: - if (head_commit) - seaf_commit_unref (head_commit); - if (root_id) - g_free (root_id); - - return ret; -} - -static char * -copy_seafile (SeafRepo *src_repo, SeafRepo *dst_repo, const char *file_id, - CopyTask *task, guint64 *size) -{ - Seafile *file; - - file = seaf_fs_manager_get_seafile (seaf->fs_mgr, - src_repo->store_id, src_repo->version, - file_id); - if (!file) { - seaf_warning ("Failed to get file object %s from repo %s.\n", - file_id, src_repo->id); - return NULL; - } - - /* We may be copying from v0 repo to v1 repo or vise versa. */ - file->version = seafile_version_from_repo_version(dst_repo->version); - - if (seafile_save (seaf->fs_mgr, - dst_repo->store_id, - dst_repo->version, - file) < 0) { - seaf_warning ("Failed to copy file object %s from repo %s to %s.\n", - file_id, src_repo->id, dst_repo->id); - seafile_unref (file); - return NULL; - } - - int i; - char *block_id; - for (i = 0; i < file->n_blocks; ++i) { - /* Check cancel before copying a block. */ - if (task && g_atomic_int_get (&task->canceled)) { - seafile_unref (file); - return NULL; - } - - block_id = file->blk_sha1s[i]; - if (seaf_block_manager_copy_block (seaf->block_mgr, - src_repo->store_id, src_repo->version, - dst_repo->store_id, dst_repo->version, - block_id) < 0) { - seaf_warning ("Failed to copy block %s from repo %s to %s.\n", - block_id, src_repo->id, dst_repo->id); - seafile_unref (file); - return NULL; - } - } - - if (task) - ++(task->done); - - *size = file->file_size; - char *ret = g_strdup(file->file_id); - - seafile_unref (file); - return ret; -} - -static char * -copy_recursive (SeafRepo *src_repo, SeafRepo *dst_repo, - const char *obj_id, guint32 mode, const char *modifier, - CopyTask *task, guint64 *size) -{ - if (S_ISREG(mode)) { - return copy_seafile (src_repo, dst_repo, obj_id, task, size); - } else if (S_ISDIR(mode)) { - SeafDir *src_dir = NULL, *dst_dir = NULL; - GList *dst_ents = NULL, *ptr; - char *new_id = NULL; - SeafDirent *dent, *new_dent = NULL; - - src_dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, - src_repo->store_id, - src_repo->version, - obj_id); - if (!src_dir) { - seaf_warning ("Seafdir %s doesn't exist in repo %s.\n", - obj_id, src_repo->id); - return NULL; - } - - for (ptr = src_dir->entries; ptr; ptr = ptr->next) { - dent = ptr->data; - - guint64 new_size = 0; - new_id = copy_recursive (src_repo, dst_repo, - dent->id, dent->mode, modifier, task, &new_size); - if (!new_id) { - seaf_dir_free (src_dir); - return NULL; - } - - new_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version), - new_id, dent->mode, dent->name, - dent->mtime, modifier, new_size); - dst_ents = g_list_prepend (dst_ents, new_dent); - g_free (new_id); - } - dst_ents = g_list_reverse (dst_ents); - - seaf_dir_free (src_dir); - - dst_dir = seaf_dir_new (NULL, dst_ents, - dir_version_from_repo_version(dst_repo->version)); - if (seaf_dir_save (seaf->fs_mgr, - dst_repo->store_id, dst_repo->version, - dst_dir) < 0) { - seaf_warning ("Failed to save new dir.\n"); - seaf_dir_free (dst_dir); - return NULL; - } - - char *ret = g_strdup(dst_dir->dir_id); - *size = 0; - seaf_dir_free (dst_dir); - return ret; - } - - return NULL; -} - -static int -cross_repo_copy (const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - int replace, - const char *modifier, - CopyTask *task) -{ - SeafRepo *src_repo = NULL, *dst_repo = NULL; - SeafDirent *src_dent = NULL, *dst_dent = NULL; - int ret = 0; - - src_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, src_repo_id); - if (!src_repo) { - ret = -1; - goto out; - } - - dst_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, dst_repo_id); - if (!dst_repo) { - ret = -1; - goto out; - } - - src_dent = get_dirent_by_path (src_repo, NULL, - src_path, src_filename, NULL); - if (!src_dent) { - ret = -1; - goto out; - } - - guint64 new_size = 0; - char *new_id = copy_recursive (src_repo, dst_repo, - src_dent->id, src_dent->mode, modifier, task, - &new_size); - if (!new_id) { - ret = -1; - goto out; - } - - dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version), - new_id, src_dent->mode, dst_filename, - src_dent->mtime, modifier, new_size); - g_free (new_id); - - if (put_dirent_and_commit (dst_repo, - dst_path, - dst_dent, - replace, - modifier, - NULL) < 0) { - ret = -1; - goto out; - } - - if (task) - task->successful = TRUE; - - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, dst_repo_id, NULL); - -out: - if (src_repo) - seaf_repo_unref (src_repo); - if (dst_repo) - seaf_repo_unref (dst_repo); - if (src_dent) - seaf_dirent_free(src_dent); - if (dst_dent) - seaf_dirent_free(dst_dent); - - if (ret == 0) { - update_repo_size (dst_repo_id); - } else { - if (task && !task->canceled) - task->failed = TRUE; - } - - return ret; -} - -static gboolean -is_virtual_repo_and_origin (SeafRepo *repo1, SeafRepo *repo2) -{ - if (repo1->virtual_info && - strcmp (repo1->virtual_info->origin_repo_id, repo2->id) == 0) - return TRUE; - if (repo2->virtual_info && - strcmp (repo2->virtual_info->origin_repo_id, repo1->id) == 0) - return TRUE; - return FALSE; -} - -static gboolean -check_file_count_and_size (SeafRepo *repo, SeafDirent *dent, gint64 total_files, - GError **error) -{ - if (seaf->copy_mgr->max_files > 0 && - total_files > seaf->copy_mgr->max_files) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Too many files"); - return FALSE; - } - - if (seaf->copy_mgr->max_size > 0) { - gint64 size = -1; - - if (S_ISREG(dent->mode)) { - if (repo->version > 0) - size = dent->size; - else - size = seaf_fs_manager_get_file_size (seaf->fs_mgr, - repo->store_id, - repo->version, - dent->id); - } else { - size = seaf_fs_manager_get_fs_size (seaf->fs_mgr, - repo->store_id, - repo->version, - dent->id); - } - if (size < 0) { - seaf_warning ("Failed to get dir size of %s:%s.\n", - repo->store_id, dent->id); - return FALSE; - } - - if (size > seaf->copy_mgr->max_size) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Folder or file size is too large"); - return FALSE; - } - } - - return TRUE; -} - -/** - * Copy a SeafDirent from a SeafDir to another. - * - * 1. When @src_repo and @dst_repo are not the same repo, neither of them - * should be encrypted. - * - * 2. the file being copied must not exist in the dst path of the dst repo. - */ -SeafileCopyResult * -seaf_repo_manager_copy_file (SeafRepoManager *mgr, - const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - const char *user, - int need_progress, - int synchronous, - GError **error) -{ - SeafRepo *src_repo = NULL, *dst_repo = NULL; - SeafDirent *src_dent = NULL, *dst_dent = NULL; - char *src_canon_path = NULL, *dst_canon_path = NULL; - SeafCommit *dst_head_commit = NULL; - int ret = 0; - gboolean background = FALSE; - char *task_id = NULL; - SeafileCopyResult *res= NULL; - - GET_REPO_OR_FAIL(src_repo, src_repo_id); - - if (strcmp(src_repo_id, dst_repo_id) != 0) { - GET_REPO_OR_FAIL(dst_repo, dst_repo_id); - - if (src_repo->encrypted || dst_repo->encrypted) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Can't copy files between encrypted repo(s)"); - ret = -1; - goto out; - } - - } else { - seaf_repo_ref (src_repo); - dst_repo = src_repo; - } - - src_canon_path = get_canonical_path (src_path); - dst_canon_path = get_canonical_path (dst_path); - - /* first check whether a file with file_name already exists in destination dir */ - GET_COMMIT_OR_FAIL(dst_head_commit, - dst_repo->id, dst_repo->version, - dst_repo->head->commit_id); - - FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version, - dst_head_commit->root_id, dst_canon_path, dst_filename, NULL); - - /* get src dirent */ - src_dent = get_dirent_by_path (src_repo, NULL, - src_canon_path, src_filename, error); - if (!src_dent) { - ret = -1; - goto out; - } - - if (strcmp (src_repo_id, dst_repo_id) == 0 || - is_virtual_repo_and_origin (src_repo, dst_repo)) { - - gint64 file_size = (src_dent->version > 0) ? src_dent->size : -1; - - /* duplicate src dirent with new name */ - dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version), - src_dent->id, src_dent->mode, dst_filename, - src_dent->mtime, user, file_size); - - if (put_dirent_and_commit (dst_repo, - dst_canon_path, - dst_dent, - 0, - user, - error) < 0) { - if (!error) - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to put dirent"); - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, dst_repo_id, NULL); - - update_repo_size (dst_repo_id); - } else if (!synchronous) { - background = TRUE; - - gint64 total_files = -1; - if (S_ISDIR(src_dent->mode)) - total_files = seaf_fs_manager_count_fs_files (seaf->fs_mgr, - src_repo->store_id, - src_repo->version, - src_dent->id); - else - total_files = 1; - if (total_files < 0) { - seaf_warning ("Failed to get file count.\n"); - ret = -1; - goto out; - } - - if (!check_file_count_and_size (src_repo, src_dent, total_files, error)) { - ret = -1; - goto out; - } - - task_id = seaf_copy_manager_add_task (seaf->copy_mgr, - src_repo_id, - src_canon_path, - src_filename, - dst_repo_id, - dst_canon_path, - dst_filename, - 0, - user, - total_files, - cross_repo_copy, - need_progress); - if (need_progress && !task_id) { - seaf_warning ("Failed to start copy task.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to start copy task"); - ret = -1; - goto out; - } - } else { - /* Synchronous for cross-repo move */ - if (cross_repo_copy (src_repo_id, - src_canon_path, - src_filename, - dst_repo_id, - dst_canon_path, - dst_filename, - 0, - user, - NULL) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to move"); - ret = -1; - goto out; - } - } - -out: - if (src_repo) - seaf_repo_unref (src_repo); - if (dst_repo) - seaf_repo_unref (dst_repo); - if (dst_head_commit) - seaf_commit_unref(dst_head_commit); - if (src_canon_path) - g_free (src_canon_path); - if (dst_canon_path) - g_free (dst_canon_path); - if (src_dent) - seaf_dirent_free(src_dent); - if (dst_dent) - seaf_dirent_free(dst_dent); - - if (ret == 0) { - res = seafile_copy_result_new (); - g_object_set (res, "background", background, "task_id", task_id, NULL); - g_free (task_id); - } - - return res; -} - -static int -move_file_same_repo (const char *repo_id, - const char *src_path, SeafDirent *src_dent, - const char *dst_path, SeafDirent *dst_dent, - int replace, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *root_id_after_put = NULL, *root_id = NULL; - char buf[SEAF_PATH_MAX]; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - root_id_after_put = do_post_file_replace (repo, - head_commit->root_id, dst_path, - replace, dst_dent); - if (!root_id_after_put) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "move file failed"); - ret = -1; - goto out; - } - - root_id = do_del_file (repo, root_id_after_put, src_path, src_dent->name); - if (!root_id) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "move file failed"); - ret = -1; - goto out; - } - - /* Commit. */ - if (S_ISDIR(src_dent->mode)) { - snprintf(buf, SEAF_PATH_MAX, "Moved directory \"%s\"", src_dent->name); - } else { - snprintf(buf, SEAF_PATH_MAX, "Moved \"%s\"", src_dent->name); - } - - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) - ret = -1; - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref (head_commit); - g_free (root_id_after_put); - g_free (root_id); - - return ret; -} - -static int -cross_repo_move (const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - int replace, - const char *modifier, - CopyTask *task) -{ - SeafRepo *src_repo = NULL, *dst_repo = NULL; - SeafDirent *src_dent = NULL, *dst_dent = NULL; - int ret = 0; - - src_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, src_repo_id); - if (!src_repo) { - ret = -1; - goto out; - } - - dst_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, dst_repo_id); - if (!dst_repo) { - ret = -1; - goto out; - } - - src_dent = get_dirent_by_path (src_repo, NULL, - src_path, src_filename, NULL); - if (!src_dent) { - ret = -1; - goto out; - } - - guint64 new_size = 0; - char *new_id = copy_recursive (src_repo, dst_repo, - src_dent->id, src_dent->mode, modifier, task, - &new_size); - if (!new_id) { - ret = -1; - goto out; - } - - dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version), - new_id, src_dent->mode, dst_filename, - src_dent->mtime, modifier, new_size); - g_free (new_id); - - if (put_dirent_and_commit (dst_repo, - dst_path, - dst_dent, - replace, - modifier, - NULL) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, dst_repo_id, NULL); - - if (seaf_repo_manager_del_file (seaf->repo_mgr, src_repo_id, src_path, - src_filename, modifier, NULL) < 0) { - ret = -1; - goto out; - } - - if (task) - task->successful = TRUE; - - seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, src_repo_id, NULL); - -out: - if (src_repo) - seaf_repo_unref (src_repo); - if (dst_repo) - seaf_repo_unref (dst_repo); - if (src_dent) - seaf_dirent_free(src_dent); - if (dst_dent) - seaf_dirent_free(dst_dent); - - if (ret == 0) { - update_repo_size (dst_repo_id); - } else { - if (task && !task->canceled) - task->failed = TRUE; - } - - return ret; -} - -SeafileCopyResult * -seaf_repo_manager_move_file (SeafRepoManager *mgr, - const char *src_repo_id, - const char *src_path, - const char *src_filename, - const char *dst_repo_id, - const char *dst_path, - const char *dst_filename, - int replace, - const char *user, - int need_progress, - int synchronous, - GError **error) -{ - SeafRepo *src_repo = NULL, *dst_repo = NULL; - SeafDirent *src_dent = NULL, *dst_dent = NULL; - char *src_canon_path = NULL, *dst_canon_path = NULL; - SeafCommit *dst_head_commit = NULL; - int ret = 0; - gboolean background = FALSE; - char *task_id = NULL; - SeafileCopyResult *res = NULL; - - GET_REPO_OR_FAIL(src_repo, src_repo_id); - - if (strcmp(src_repo_id, dst_repo_id) != 0) { - GET_REPO_OR_FAIL(dst_repo, dst_repo_id); - - if (src_repo->encrypted || dst_repo->encrypted) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Can't copy files between encrypted repo(s)"); - ret = -1; - goto out; - } - - } else { - seaf_repo_ref (src_repo); - dst_repo = src_repo; - } - - src_canon_path = get_canonical_path (src_path); - dst_canon_path = get_canonical_path (dst_path); - /* first check whether a file with file_name already exists in destination dir */ - GET_COMMIT_OR_FAIL(dst_head_commit, - dst_repo->id, dst_repo->version, - dst_repo->head->commit_id); - /*FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version, - dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);*/ - - /* get src dirent */ - src_dent = get_dirent_by_path (src_repo, NULL, - src_canon_path, src_filename, error); - if (!src_dent) { - ret = -1; - goto out; - } - - gint64 file_size = (src_dent->version > 0) ? src_dent->size : -1; - - if (src_repo == dst_repo) { - /* duplicate src dirent with new name */ - dst_dent = seaf_dirent_new (dir_version_from_repo_version (dst_repo->version), - src_dent->id, src_dent->mode, dst_filename, - src_dent->mtime, user, file_size); - - /* move file within the same repo */ - if (move_file_same_repo (src_repo_id, - src_canon_path, src_dent, - dst_canon_path, dst_dent, - replace, user, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (mgr, src_repo_id); - seaf_repo_manager_merge_virtual_repo (mgr, src_repo_id, NULL); - - update_repo_size (dst_repo_id); - } else { - /* move between different repos */ - - if (is_virtual_repo_and_origin (src_repo, dst_repo)) { - /* duplicate src dirent with new name */ - dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version), - src_dent->id, src_dent->mode, dst_filename, - src_dent->mtime, user, file_size); - - /* add this dirent to dst repo */ - if (put_dirent_and_commit (dst_repo, - dst_canon_path, - dst_dent, - replace, - user, - error) < 0) { - if (!error) - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to put dirent"); - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, dst_repo_id, NULL); - - if (seaf_repo_manager_del_file (mgr, src_repo_id, src_path, - src_filename, user, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, src_repo_id, NULL); - - update_repo_size (dst_repo_id); - } else if (!synchronous) { - background = TRUE; - - gint64 total_files = -1; - if (S_ISDIR(src_dent->mode)) - total_files = seaf_fs_manager_count_fs_files (seaf->fs_mgr, - src_repo->store_id, - src_repo->version, - src_dent->id); - else - total_files = 1; - if (total_files < 0) { - seaf_warning ("Failed to get file count.\n"); - ret = -1; - goto out; - } - - if (!check_file_count_and_size (src_repo, src_dent, total_files, error)) { - ret = -1; - goto out; - } - - task_id = seaf_copy_manager_add_task (seaf->copy_mgr, - src_repo_id, - src_canon_path, - src_filename, - dst_repo_id, - dst_canon_path, - dst_filename, - replace, - user, - total_files, - cross_repo_move, - need_progress); - if (need_progress && !task_id) { - seaf_warning ("Failed to start copy task.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to start copy task"); - ret = -1; - goto out; - } - } else { - /* Synchronous for cross-repo move */ - if (cross_repo_move (src_repo_id, - src_canon_path, - src_filename, - dst_repo_id, - dst_canon_path, - dst_filename, - replace, - user, - NULL) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to move"); - ret = -1; - goto out; - } - } - } - -out: - if (src_repo) seaf_repo_unref (src_repo); - if (dst_repo) seaf_repo_unref (dst_repo); - - if (dst_head_commit) seaf_commit_unref(dst_head_commit); - - if (src_canon_path) g_free (src_canon_path); - if (dst_canon_path) g_free (dst_canon_path); - - seaf_dirent_free(src_dent); - seaf_dirent_free(dst_dent); - - if (ret == 0) { - res = seafile_copy_result_new (); - g_object_set (res, "background", background, "task_id", task_id, NULL); - g_free (task_id); - } - - return res; -} - -int -seaf_repo_manager_post_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *new_dir_name, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafDirent *new_dent = NULL; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (new_dir_name, NULL)) { - seaf_warning ("[post dir] Invalid dir name %s.\n", new_dir_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid dir name"); - ret = -1; - goto out; - } - - FAIL_IF_FILE_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, new_dir_name, NULL); - - if (!new_dent) { - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - EMPTY_SHA1, S_IFDIR, new_dir_name, - (gint64)time(NULL), NULL, -1); - } - - root_id = do_post_file (repo, - head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[put dir] Failed to put dir %s to %s in repo %s.\n", - new_dir_name, canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put dir"); - ret = -1; - goto out; - } - - /* Commit. */ - snprintf(buf, SEAF_PATH_MAX, "Added directory \"%s\"", new_dir_name); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - - return ret; -} - -int -seaf_repo_manager_post_empty_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *new_file_name, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafDirent *new_dent = NULL; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - /* no need to call get_canonical_path again when retry */ - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (new_file_name, NULL)) { - seaf_warning ("[post file] Invalid file name %s.\n", new_file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid file name"); - ret = -1; - goto out; - } - - FAIL_IF_FILE_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, new_file_name, NULL); - - if (!new_dent) { - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - EMPTY_SHA1, STD_FILE_MODE, new_file_name, - (gint64)time(NULL), user, 0); - } - - root_id = do_post_file (repo, - head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[put dir] Failed to create empty file dir.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put dir"); - ret = -1; - goto out; - } - - /* Commit. */ - snprintf(buf, SEAF_PATH_MAX, "Added \"%s\"", new_file_name); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - - return ret; -} - -static char * -rename_file_recursive(SeafRepo *repo, - const char *dir_id, - const char *to_path, - const char *oldname, - const char *newname) -{ - SeafDir *olddir, *newdir; - SeafDirent *dent; - GList *ptr; - char *to_path_dup = NULL; - char *remain = NULL; - char *slash; - char *id = NULL; - char *ret = NULL; - - olddir = seaf_fs_manager_get_seafdir_sorted(seaf->fs_mgr, - repo->store_id, repo->version, - dir_id); - if (!olddir) - return NULL; - - /* we reach the target dir. */ - if (*to_path == '\0') { - SeafDirent *old, *newdent = NULL; - GList *newentries = NULL, *p; - - /* When renameing, there is a pitfall: we can't simply rename the - * dirent, since the dirents are required to be sorted in descending - * order. We need to copy all old dirents except the target dirent, - * and then rename the target dirent, and then insert the new - * dirent, so that we can maintain the descending order of dirents. */ - for (p = olddir->entries; p != NULL; p = p->next) { - old = p->data; - if (strcmp(old->name, oldname) != 0) { - newentries = g_list_prepend (newentries, seaf_dirent_dup(old)); - } else { - newdent = seaf_dirent_new (old->version, old->id, old->mode, - newname, old->mtime, - old->modifier, old->size); - } - } - - newentries = g_list_reverse (newentries); - - if (newdent) { - newentries = g_list_insert_sorted(newentries, newdent, compare_dirents); - } - - newdir = seaf_dir_new (NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strndup (newdir->dir_id, 40); - seaf_dir_free (newdir); - - goto out; - } - - to_path_dup = g_strdup (to_path); - slash = strchr (to_path_dup, '/'); - - if (!slash) { - remain = to_path_dup + strlen(to_path_dup); - } else { - *slash = '\0'; - remain = slash + 1; - } - - for (ptr = olddir->entries; ptr; ptr = ptr->next) { - dent = (SeafDirent *)ptr->data; - - if (strcmp(dent->name, to_path_dup) != 0) - continue; - - id = rename_file_recursive (repo, dent->id, remain, oldname, newname); - if (id != NULL) { - memcpy(dent->id, id, 40); - dent->id[40] = '\0'; - } - break; - } - - if (id != NULL) { - /* Create a new SeafDir. */ - GList *new_entries; - - new_entries = dup_seafdir_entries (olddir->entries); - newdir = seaf_dir_new (NULL, new_entries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup(newdir->dir_id); - seaf_dir_free (newdir); - } - -out: - g_free (to_path_dup); - g_free (id); - seaf_dir_free(olddir); - return ret; -} - -static char * -do_rename_file(SeafRepo *repo, - const char *root_id, - const char *parent_dir, - const char *oldname, - const char *newname) -{ - /* if parent_dir is a absolutely path, we will remove the first '/' */ - if (*parent_dir == '/') - parent_dir = parent_dir + 1; - - return rename_file_recursive(repo, root_id, parent_dir, oldname, newname); -} - - -int -seaf_repo_manager_rename_file (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *oldname, - const char *newname, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *root_id = NULL; - char *canon_path = NULL; - char buf[SEAF_PATH_MAX]; - int mode = 0; - int ret = 0; - - if (strcmp(oldname, newname) == 0) - return 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (newname, NULL)) { - seaf_warning ("[rename file] Invalid filename %s.\n", newname); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - FAIL_IF_FILE_NOT_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, oldname, &mode); - FAIL_IF_FILE_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, newname, NULL); - - root_id = do_rename_file (repo, head_commit->root_id, canon_path, - oldname, newname); - if (!root_id) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "faile to rename file %s", oldname); - ret = -1; - goto out; - } - - /* Commit. */ - if (S_ISDIR(mode)) { - snprintf(buf, SEAF_PATH_MAX, "Renamed directory \"%s\"", oldname); - } else { - snprintf(buf, SEAF_PATH_MAX, "Renamed \"%s\"", oldname); - } - - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_cleanup_virtual_repos (mgr, repo_id); - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref (head_commit); - g_free (canon_path); - g_free (root_id); - - return ret; -} - -static char * -put_file_recursive(SeafRepo *repo, - const char *dir_id, - const char *to_path, - SeafDirent *newdent) -{ - SeafDir *olddir, *newdir; - SeafDirent *dent; - GList *ptr; - char *to_path_dup = NULL; - char *remain = NULL; - char *slash; - char *id = NULL; - char *ret = NULL; - - olddir = seaf_fs_manager_get_seafdir_sorted(seaf->fs_mgr, - repo->store_id, repo->version, - dir_id); - if (!olddir) - return NULL; - - /* we reach the target dir. Update the target dirent. */ - if (*to_path == '\0') { - GList *newentries = NULL, *p; - SeafDirent *dent; - - for (p = olddir->entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, newdent->name) == 0) { - newentries = g_list_prepend (newentries, seaf_dirent_dup(newdent)); - } else { - newentries = g_list_prepend (newentries, seaf_dirent_dup(dent)); - } - } - - newentries = g_list_reverse (newentries); - newdir = seaf_dir_new (NULL, newentries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup (newdir->dir_id); - seaf_dir_free (newdir); - - goto out; - } - - to_path_dup = g_strdup (to_path); - slash = strchr (to_path_dup, '/'); - - if (!slash) { - remain = to_path_dup + strlen(to_path_dup); - } else { - *slash = '\0'; - remain = slash + 1; - } - - for (ptr = olddir->entries; ptr; ptr = ptr->next) { - dent = (SeafDirent *)ptr->data; - - if (strcmp(dent->name, to_path_dup) != 0) - continue; - - id = put_file_recursive (repo, dent->id, remain, newdent); - if (id != NULL) { - memcpy(dent->id, id, 40); - dent->id[40] = '\0'; - if (repo->version > 0) - dent->mtime = (guint64)time(NULL); - } - break; - } - - if (id != NULL) { - /* Create a new SeafDir. */ - GList *new_entries; - - new_entries = dup_seafdir_entries (olddir->entries); - newdir = seaf_dir_new (NULL, new_entries, - dir_version_from_repo_version(repo->version)); - if (seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir) == 0) - ret = g_strdup(newdir->dir_id); - seaf_dir_free (newdir); - } - -out: - g_free (to_path_dup); - g_free (id); - seaf_dir_free(olddir); - return ret; -} - -static char * -do_put_file (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - SeafDirent *dent) -{ - /* if parent_dir is a absolutely path, we will remove the first '/' */ - if (*parent_dir == '/') - parent_dir = parent_dir + 1; - - return put_file_recursive(repo, root_id, parent_dir, dent); -} - -int -seaf_repo_manager_put_file (SeafRepoManager *mgr, - const char *repo_id, - const char *temp_file_path, - const char *parent_dir, - const char *file_name, - const char *user, - const char *head_id, - char **new_file_id, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - unsigned char sha1[20]; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafileCrypt *crypt = NULL; - SeafDirent *new_dent = NULL; - char hex[41]; - char *old_file_id = NULL, *fullpath = NULL; - int ret = 0; - - if (g_access (temp_file_path, R_OK) != 0) { - seaf_warning ("[put file] File %s doesn't exist or not readable.\n", - temp_file_path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid input file"); - return -1; - } - - GET_REPO_OR_FAIL(repo, repo_id); - const char *base = head_id ? head_id : repo->head->commit_id; - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, base); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (file_name, NULL)) { - seaf_warning ("[put file] Invalid filename %s.\n", file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_warning ("[put file] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - FAIL_IF_FILE_NOT_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, file_name, NULL); - - /* Write blocks. */ - if (repo->encrypted) { - unsigned char key[32], iv[16]; - if (seaf_passwd_manager_get_decrypt_key_raw (seaf->passwd_mgr, - repo_id, user, - key, iv) < 0) { - seaf_warning ("Passwd for repo %s is not set.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Passwd is not set"); - ret = -1; - goto out; - } - crypt = seafile_crypt_new (repo->enc_version, key, iv); - } - - gint64 size; - if (seaf_fs_manager_index_blocks (seaf->fs_mgr, - repo->store_id, repo->version, - temp_file_path, - sha1, &size, crypt, TRUE, FALSE) < 0) { - seaf_warning ("failed to index blocks"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - hex, STD_FILE_MODE, file_name, - (gint64)time(NULL), user, size); - - if (!fullpath) - fullpath = g_build_filename(parent_dir, file_name, NULL); - - old_file_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, - repo->store_id, repo->version, - head_commit->root_id, - fullpath, NULL, NULL); - - if (g_strcmp0(old_file_id, new_dent->id) == 0) { - if (new_file_id) - *new_file_id = g_strdup(new_dent->id); - goto out; - } - - root_id = do_put_file (repo, head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[put file] Failed to put file %s to %s in repo %s.\n", - file_name, canon_path, repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put file"); - ret = -1; - goto out; - } - - /* Commit. */ - snprintf(buf, SEAF_PATH_MAX, "Modified \"%s\"", file_name); - if (gen_new_commit (repo_id, head_commit, root_id, user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - if (new_file_id) - *new_file_id = g_strdup(new_dent->id); - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - g_free (crypt); - g_free (old_file_id); - g_free (fullpath); - - if (ret == 0) { - update_repo_size (repo_id); - } - - return ret; -} - -static char * -gen_commit_description (SeafRepo *repo, - const char *root, - const char *parent_root) -{ - GList *p; - GList *results = NULL; - char *desc; - - diff_commit_roots (repo->store_id, repo->version, - parent_root, root, &results, TRUE); - - desc = diff_results_to_description (results); - - for (p = results; p; p = p->next) { - DiffEntry *de = p->data; - diff_entry_free (de); - } - g_list_free (results); - - return desc; -} - -int -seaf_repo_manager_update_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *dir_path, - const char *new_dir_id, - const char *user, - const char *head_id, - char *new_commit_id, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - char *parent = NULL, *dirname = NULL; - SeafDirent *new_dent = NULL; - char *root_id = NULL; - char *commit_desc = NULL; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - const char *base = head_id ? head_id : repo->head->commit_id; - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, base); - - /* Are we updating the root? */ - if (strcmp (dir_path, "/") == 0) { - commit_desc = gen_commit_description (repo, new_dir_id, head_commit->root_id); - if (!commit_desc) - commit_desc = g_strdup("Auto merge by system"); - - if (gen_new_commit (repo_id, head_commit, new_dir_id, - user, commit_desc, new_commit_id, error) < 0) - ret = -1; - g_free (commit_desc); - goto out; - } - - parent = g_path_get_dirname (dir_path); - canon_path = get_canonical_path (parent); - g_free (parent); - - dirname = g_path_get_basename (dir_path); - - FAIL_IF_FILE_NOT_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, dirname, NULL); - - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - new_dir_id, S_IFDIR, dirname, - (gint64)time(NULL), NULL, -1); - - root_id = do_put_file (repo, head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[update dir] Failed to put file.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to update dir"); - ret = -1; - goto out; - } - - commit_desc = gen_commit_description (repo, root_id, head_commit->root_id); - if (!commit_desc) - commit_desc = g_strdup("Auto merge by system"); - - if (gen_new_commit (repo_id, head_commit, root_id, - user, commit_desc, new_commit_id, error) < 0) { - ret = -1; - g_free (commit_desc); - goto out; - } - g_free (commit_desc); - -out: - seaf_repo_unref (repo); - seaf_commit_unref (head_commit); - seaf_dirent_free (new_dent); - g_free (canon_path); - g_free (dirname); - g_free (root_id); - - if (ret == 0) - update_repo_size (repo_id); - - return ret; -} - -int -seaf_repo_manager_put_file_blocks (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - const char *file_name, - const char *blockids_json, - const char *paths_json, - const char *user, - const char *head_id, - gint64 file_size, - char **new_file_id, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - char *canon_path = NULL; - unsigned char sha1[20]; - char buf[SEAF_PATH_MAX]; - char *root_id = NULL; - SeafDirent *new_dent = NULL; - char hex[41]; - GList *blockids = NULL, *paths = NULL, *ptr; - char *old_file_id = NULL, *fullpath = NULL; - int ret = 0; - - blockids = json_to_file_list (blockids_json); - paths = json_to_file_list (paths_json); - if (g_list_length(blockids) != g_list_length(paths)) { - seaf_warning ("[put-blks] Invalid blockids or paths.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid files"); - ret = -1; - goto out; - } - - - for (ptr = paths; ptr; ptr = ptr->next) { - char *temp_file_path = ptr->data; - if (g_access (temp_file_path, R_OK) != 0) { - seaf_warning ("[put-blks] File block %s doesn't exist or not readable.\n", - temp_file_path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid input file"); - ret = -1; - goto out; - } - } - - GET_REPO_OR_FAIL(repo, repo_id); - const char *base = head_id ? head_id : repo->head->commit_id; - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, base); - - if (!canon_path) - canon_path = get_canonical_path (parent_dir); - - if (should_ignore_file (file_name, NULL)) { - seaf_warning ("[put-blks] Invalid filename %s.\n", file_name); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid filename"); - ret = -1; - goto out; - } - - if (strstr (parent_dir, "//") != NULL) { - seaf_warning ("[put-blks] parent_dir cantains // sequence.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Invalid parent dir"); - ret = -1; - goto out; - } - - FAIL_IF_FILE_NOT_EXISTS(repo->store_id, repo->version, - head_commit->root_id, canon_path, file_name, NULL); - - /* Write blocks. */ - if (seaf_fs_manager_index_file_blocks (seaf->fs_mgr, - repo->store_id, repo->version, - paths, - blockids, sha1, file_size) < 0) { - seaf_warning ("failed to index blocks"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to index blocks"); - ret = -1; - goto out; - } - - rawdata_to_hex(sha1, hex, 20); - new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version), - hex, STD_FILE_MODE, file_name, - (gint64)time(NULL), user, file_size); - - if (!fullpath) - fullpath = g_build_filename(parent_dir, file_name, NULL); - - old_file_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, - repo->store_id, repo->version, - head_commit->root_id, - fullpath, NULL, NULL); - - if (g_strcmp0(old_file_id, new_dent->id) == 0) { - if (new_file_id) - *new_file_id = g_strdup(new_dent->id); - goto out; - } - - root_id = do_put_file (repo, head_commit->root_id, canon_path, new_dent); - if (!root_id) { - seaf_warning ("[put-blks] Failed to put file.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to put file"); - ret = -1; - goto out; - } - - /* Commit. */ - snprintf(buf, SEAF_PATH_MAX, "Modified \"%s\"", file_name); - if (gen_new_commit (repo_id, head_commit, root_id, user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - if (new_file_id) - *new_file_id = g_strdup(new_dent->id); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - string_list_free (blockids); - string_list_free (paths); - seaf_dirent_free (new_dent); - g_free (root_id); - g_free (canon_path); - g_free (old_file_id); - g_free (fullpath); - - if (ret == 0) { - update_repo_size (repo_id); - } - - return ret; -} - -/* split filename into base and extension */ -static void -filename_splitext (const char *filename, - char **base, - char **ext) -{ - char *dot = strrchr(filename, '.'); - if (!dot) { - *base = g_strdup(filename); - *ext = NULL; - } else { - *dot = '\0'; - *base = g_strdup(filename); - *dot = '.'; - - *ext = g_strdup(dot); - } -} - -static char * -revert_file_to_root (SeafRepo *repo, - const char *root_id, - SeafDirent *old_dent, - gboolean *skipped, - GError **error) -{ - SeafDir *dir = NULL; - SeafDirent *dent = NULL, *newdent = NULL; - char *basename = NULL, *ext = NULL; - char new_file_name[SEAF_PATH_MAX]; - char *new_root_id = NULL; - int i = 1; - GList *p; - - *skipped = FALSE; - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - root_id, - "/", error); - if (*error) { - return NULL; - } - - snprintf (new_file_name, sizeof(new_file_name), "%s", old_dent->name); - - filename_splitext(old_dent->name, &basename, &ext); - for (;;) { - for (p = dir->entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, new_file_name) != 0) - continue; - - if (S_ISREG(dent->mode)) { - /* same named file */ - if (strcmp(dent->id, old_dent->id) == 0) { - *skipped = TRUE; - goto out; - } else { - /* rename and retry */ - snprintf (new_file_name, sizeof(new_file_name), "%s (%d)%s", - basename, i++, ext); - break; - } - - } else if (S_ISDIR(dent->mode)) { - /* rename and retry */ - snprintf (new_file_name, sizeof(new_file_name), "%s (%d)%s", - basename, i++, ext); - break; - } - } - - if (p == NULL) - break; - } - - newdent = seaf_dirent_new (old_dent->version, - old_dent->id, STD_FILE_MODE, new_file_name, - old_dent->mtime, old_dent->modifier, old_dent->size); - new_root_id = do_post_file (repo, root_id, "/", newdent); - -out: - if (dir) - seaf_dir_free (dir); - - g_free (basename); - g_free (ext); - seaf_dirent_free (newdent); - - return new_root_id; -} - -static char * -revert_file_to_parent_dir (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - SeafDirent *old_dent, - gboolean *skipped, - GError **error) -{ - SeafDir *dir = NULL; - SeafDirent *dent = NULL, *newdent = NULL; - char *basename = NULL, *ext = NULL; - char new_file_name[SEAF_PATH_MAX]; - char *new_root_id = NULL; - gboolean is_overwrite = FALSE; - int i = 1; - GList *p; - - *skipped = FALSE; - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - root_id, - parent_dir, error); - if (*error) { - return NULL; - } - - snprintf (new_file_name, sizeof(new_file_name), "%s", old_dent->name); - filename_splitext(old_dent->name, &basename, &ext); - while(TRUE) { - for (p = dir->entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, new_file_name) != 0) - continue; - - if (S_ISREG(dent->mode)) { - /* same named file */ - if (strcmp(dent->id, old_dent->id) == 0) { - *skipped = TRUE; - goto out; - } else { - /* same name, different id: just overwrite */ - is_overwrite = TRUE; - goto do_revert; - } - - } else if (S_ISDIR(dent->mode)) { - /* rename and retry */ - snprintf (new_file_name, sizeof(new_file_name), "%s (%d)%s", - basename, i++, ext); - break; - } - } - - if (p == NULL) - break; - } - -do_revert: - newdent = seaf_dirent_new (old_dent->version, - old_dent->id, STD_FILE_MODE, new_file_name, - old_dent->mtime, old_dent->modifier, old_dent->size); - if (is_overwrite) { - new_root_id = do_put_file (repo, - root_id, parent_dir, newdent); - } else { - new_root_id = do_post_file (repo, - root_id, parent_dir, newdent); - } - -out: - if (dir) - seaf_dir_free (dir); - - g_free (basename); - g_free (ext); - seaf_dirent_free (newdent); - - return new_root_id; -} - -static gboolean -detect_path_exist (SeafRepo *repo, - const char *root_id, - const char *path, - GError **error) -{ - SeafDir *dir; - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - root_id, path, error); - if (*error) { - if (g_error_matches(*error, SEAFILE_DOMAIN, SEAF_ERR_PATH_NO_EXIST)) { - /* path does not exist */ - g_clear_error(error); - return FALSE; - } else { - /* Other error */ - return FALSE; - } - } - - seaf_dir_free(dir); - return TRUE; -} - -int -seaf_repo_manager_revert_file (SeafRepoManager *mgr, - const char *repo_id, - const char *old_commit_id, - const char *file_path, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL, *old_commit = NULL; - char *parent_dir = NULL, *filename = NULL; - SeafDirent *old_dent = NULL; - char *canon_path = NULL, *root_id = NULL; - char buf[SEAF_PATH_MAX]; - char time_str[512]; - gboolean parent_dir_exist = FALSE; - gboolean revert_to_root = FALSE; - gboolean skipped = FALSE; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - /* If old_commit_id is head commit, do nothing. */ - if (strcmp(repo->head->commit_id, old_commit_id) == 0) { - g_debug ("[revert file] commit is head, do nothing\n"); - goto out; - } - - if (!old_commit) { - GET_COMMIT_OR_FAIL(old_commit, repo->id, repo->version, old_commit_id); - if (strcmp(old_commit->repo_id, repo_id) != 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_COMMIT, - "bad commit id"); - ret = -1; - goto out; - } - } - - if (!canon_path) { - canon_path = get_canonical_path (file_path); - if (canon_path[strlen(canon_path) -1 ] == '/') { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_COMMIT, - "bad target file path"); - ret = -1; - goto out; - } - - parent_dir = g_path_get_dirname(canon_path); - filename = g_path_get_basename(canon_path); - - old_dent = get_dirent_by_path (repo, old_commit->root_id, - parent_dir, filename, error); - if (*error) { - seaf_warning ("[revert file] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - } - - parent_dir_exist = detect_path_exist (repo, - head_commit->root_id, - parent_dir, error); - if (*error) { - seaf_warning ("[revert file] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - - if (!parent_dir_exist) { - /* When parent dir does not exist, revert this file to root dir. */ - revert_to_root = TRUE; - root_id = revert_file_to_root (repo, - head_commit->root_id, - old_dent, - &skipped, error); - } else { - revert_to_root = FALSE; - root_id = revert_file_to_parent_dir (repo, - head_commit->root_id, parent_dir, - old_dent, - &skipped, error); - } - - if (*error) { - seaf_warning ("[revert file] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - - if (skipped) { - goto out; - } - - if (!root_id) { - seaf_warning ("[revert file] Failed to revert file.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to revert file"); - ret = -1; - goto out; - } - - /* Commit. */ -#ifndef WIN32 - strftime (time_str, sizeof(time_str), "%F %T", - localtime((time_t *)(&old_commit->ctime))); -#else - strftime (time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", - localtime((time_t *)(&old_commit->ctime))); -#endif - snprintf(buf, SEAF_PATH_MAX, "Reverted file \"%s\" to status at %s", filename, time_str); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref (head_commit); - if (old_commit) - seaf_commit_unref (old_commit); - - g_free (root_id); - g_free (parent_dir); - g_free (filename); - - g_free (canon_path); - seaf_dirent_free (old_dent); - -#define REVERT_TO_ROOT 0x1 - if (ret == 0) { - if (revert_to_root) - ret |= REVERT_TO_ROOT; - - update_repo_size (repo_id); - } - - return ret; -} - -static char * -revert_dir (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - SeafDirent *old_dent, - gboolean *skipped, - GError **error) -{ - SeafDir *dir = NULL; - SeafDirent *dent = NULL, *newdent = NULL; - char new_dir_name[SEAF_PATH_MAX]; - char *new_root_id = NULL; - int i = 1; - GList *p; - - *skipped = FALSE; - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - root_id, - parent_dir, error); - if (*error) { - return NULL; - } - - snprintf (new_dir_name, sizeof(new_dir_name), "%s", old_dent->name); - - for (;;) { - for (p = dir->entries; p; p = p->next) { - dent = p->data; - if (strcmp(dent->name, new_dir_name) != 0) - continue; - - /* the same dir */ - if (S_ISDIR(dent->mode) && strcmp(dent->id, old_dent->id) == 0) { - *skipped = TRUE; - goto out; - } else { - /* rename and retry */ - snprintf (new_dir_name, sizeof(new_dir_name), "%s (%d)", - old_dent->name, i++); - break; - } - } - - if (p == NULL) - break; - } - - newdent = seaf_dirent_new (old_dent->version, - old_dent->id, S_IFDIR, new_dir_name, - old_dent->mtime, NULL, -1); - new_root_id = do_post_file (repo, root_id, parent_dir, newdent); - -out: - if (dir) - seaf_dir_free (dir); - - seaf_dirent_free (newdent); - - return new_root_id; -} - -int -seaf_repo_manager_revert_dir (SeafRepoManager *mgr, - const char *repo_id, - const char *old_commit_id, - const char *dir_path, - const char *user, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL, *old_commit = NULL; - char *parent_dir = NULL, *dirname = NULL; - SeafDirent *old_dent = NULL; - char *canon_path = NULL, *root_id = NULL; - char buf[SEAF_PATH_MAX]; - gboolean parent_dir_exist = FALSE; - gboolean revert_to_root = FALSE; - gboolean skipped = FALSE; - int ret = 0; - - GET_REPO_OR_FAIL(repo, repo_id); - GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id); - - /* If old_commit_id is head commit, do nothing. */ - if (strcmp(repo->head->commit_id, old_commit_id) == 0) { - g_debug ("[revert dir] commit is head, do nothing\n"); - goto out; - } - - if (!old_commit) { - GET_COMMIT_OR_FAIL(old_commit, repo->id, repo->version, old_commit_id); - if (strcmp(old_commit->repo_id, repo_id) != 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_COMMIT, - "bad commit id"); - ret = -1; - goto out; - } - } - - if (!canon_path) { - canon_path = get_canonical_path (dir_path); - - parent_dir = g_path_get_dirname(canon_path); - dirname = g_path_get_basename(canon_path); - - old_dent = get_dirent_by_path (repo, old_commit->root_id, - parent_dir, dirname, error); - if (*error) { - seaf_warning ("[revert dir] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - } - - parent_dir_exist = detect_path_exist (repo, - head_commit->root_id, - parent_dir, error); - if (*error) { - seaf_warning ("[revert dir] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - - if (!parent_dir_exist) { - /* When parent dir does not exist, revert this file to root dir. */ - revert_to_root = TRUE; - root_id = revert_dir (repo, - head_commit->root_id, - "/", - old_dent, - &skipped, error); - } else { - revert_to_root = FALSE; - root_id = revert_dir (repo, - head_commit->root_id, - parent_dir, - old_dent, - &skipped, error); - } - - if (*error) { - seaf_warning ("[revert dir] error: %s\n", (*error)->message); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "internal error"); - ret = -1; - goto out; - } - - if (skipped) { - goto out; - } - - if (!root_id) { - seaf_warning ("[revert dir] Failed to revert dir.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to revert dir"); - ret = -1; - goto out; - } - - /* Commit. */ - snprintf(buf, SEAF_PATH_MAX, "Recovered deleted directory \"%s\"", dirname); - if (gen_new_commit (repo_id, head_commit, root_id, - user, buf, NULL, error) < 0) { - ret = -1; - goto out; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref (head_commit); - if (old_commit) - seaf_commit_unref (old_commit); - - g_free (root_id); - g_free (parent_dir); - g_free (dirname); - - g_free (canon_path); - seaf_dirent_free (old_dent); - -#define REVERT_TO_ROOT 0x1 - if (ret == 0) { - if (revert_to_root) - ret |= REVERT_TO_ROOT; - - update_repo_size (repo_id); - } - - return ret; -} - -typedef struct CollectRevisionParam CollectRevisionParam; - -struct CollectRevisionParam { - SeafRepo *repo; - const char *path; - GList *wanted_commits; - GList *file_id_list; - GList *file_size_list; - int n_commits; - GHashTable *file_info_cache; - - /* - * > 0: stop collect when this amount of revisions are collected. - * <= 0: no limit - */ - int max_revision; - - /* > 0: keep a period of history; - * == 0: N/A - * < 0: keep all history data. - */ - gint64 truncate_time; - gboolean got_latest; - - GError **error; -}; - -typedef struct FileInfo { - gint64 file_size; - char *file_id; - GList *dir_ids; -} FileInfo; - -static void -free_file_info (gpointer info) -{ - if (!info) - return; - - FileInfo *file_info = info; - g_free (file_info->file_id); - g_list_free_full (file_info->dir_ids, g_free); - g_free (file_info); -} - -// compare current commit dir_id with pre commit -// if dir_id doesn't change, it means subdir doesn't change, append all sub_dir ids of prev to current -// that is it is no need to traverse all sub dir, if root doesn't change -static gboolean -compare_or_add_id (GList *dir_ids, - GList **cur_dir_ids, - const char *dir_id) -{ - gboolean ret = FALSE; - GList *tmp = dir_ids; - - if (tmp == NULL || - strcmp ((char *)tmp->data, dir_id) != 0) { - *cur_dir_ids = g_list_append (*cur_dir_ids, g_strdup (dir_id)); - } else { - // file doesn't changed, append all dir ids to this commit cache - while (tmp) { - *cur_dir_ids = g_list_append (*cur_dir_ids, - g_strdup ((char *)tmp->data)); - tmp = tmp->next; - } - ret = TRUE; - } - - return ret; -} - -// dir_ids: all dir_ids in prev commit, in the order of fs tree -// cur_dir_ids: all dir_ids in current commit -// if no error and returned seafdir is NULL, then it means -// searched dir doesn't change in pre and current commit -static SeafDir* -get_seafdir_by_path (const char *repo_id, - int version, - const char *root_id, - const char *path, - GList *dir_ids, - GList **cur_dir_ids, - GError **error) -{ - SeafDir *dir = NULL; - SeafDirent *dent; - const char *dir_id = root_id; - char *name, *saveptr; - char *tmp_path = NULL; - GList *tmp = dir_ids; - - dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo_id, version, dir_id); - if (!dir) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_DIR_MISSING, "directory is missing"); - goto out; - } - - if (compare_or_add_id (tmp, cur_dir_ids, dir_id)) { - seaf_dir_free (dir); - dir = NULL; - goto out; - } else if (tmp) { - tmp = tmp->next; - } - - if (strcmp (path, ".") == 0 || - strcmp (path, "/") == 0) { - goto out; - } else { - tmp_path = g_strdup (path); - } - - name = strtok_r (tmp_path, "/", &saveptr); - while (name != NULL) { - GList *l; - for (l = dir->entries; l != NULL; l = l->next) { - dent = l->data; - - if (strcmp(dent->name, name) == 0 && S_ISDIR(dent->mode)) { - dir_id = dent->id; - break; - } - } - - if (!l) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_PATH_NO_EXIST, - "Path does not exists %s", path); - seaf_dir_free (dir); - dir = NULL; - break; - } - - if (compare_or_add_id (tmp, cur_dir_ids, dir_id)) { - seaf_dir_free (dir); - dir = NULL; - goto out; - } else if (tmp) { - tmp = tmp->next; - } - - SeafDir *prev = dir; - dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo_id, version, dir_id); - seaf_dir_free (prev); - - if (!dir) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_DIR_MISSING, - "directory is missing"); - break; - } - - name = strtok_r (NULL, "/", &saveptr); - } - -out: - g_free (tmp_path); - return dir; -} - -/* - * Return NULL if file is not found, error is still NULL; - * If we have IO errors, error is set. - */ -static FileInfo* -get_file_info (SeafRepo *repo, - SeafCommit *commit, - const char *path, - GHashTable *file_info_cache, - FileInfo *last_info, - GError **error) -{ - SeafDir *dir = NULL; - SeafDirent *dirent = NULL; - FileInfo *file_info = NULL; - GList *tmp; - - file_info = g_hash_table_lookup (file_info_cache, commit->commit_id); - if (file_info) - return file_info; - - char *dir_name = g_path_get_dirname (path); - char *file_name = g_path_get_basename (path); - GList *cur_dir_ids = NULL; - GList *dir_ids = last_info ? last_info->dir_ids : NULL; - - dir = get_seafdir_by_path (repo->store_id, repo->version, - commit->root_id, dir_name, dir_ids, - &cur_dir_ids, error); - if (*error) { - if ((*error)->code == SEAF_ERR_PATH_NO_EXIST) - g_clear_error (error); - goto out; - } - - if (!dir) { - // if no error and return is null from get_seafdir_by_path, it means dir doesn't - // change in pre and current commit, so the last_info (file info of pre commit) - // is also the current file info - file_info = g_new0 (FileInfo, 1); - file_info->file_id = g_strdup (last_info->file_id); - file_info->dir_ids = cur_dir_ids; - file_info->file_size = last_info->file_size; - g_hash_table_insert (file_info_cache, g_strdup (commit->commit_id), - file_info); - } else { - for (tmp = dir->entries; tmp; tmp = tmp->next) { - dirent = tmp->data; - if (strcmp (file_name, dirent->name) == 0 && - S_ISREG (dirent->mode)) { - break; - } - } - if (tmp) { - // from parent dir find the file, cache file info for the next compare - file_info = g_new0 (FileInfo, 1); - file_info->file_id = g_strdup (dirent->id); - file_info->dir_ids = cur_dir_ids; - if (repo->version > 0) { - file_info->file_size = dirent->size; - } else { - file_info->file_size = seaf_fs_manager_get_file_size (seaf->fs_mgr, - repo->store_id, - repo->version, - dirent->id); - } - g_hash_table_insert (file_info_cache, g_strdup (commit->commit_id), - file_info); - } - } - -out: - if (dir) - seaf_dir_free (dir); - if (!file_info) { - g_list_free_full (cur_dir_ids, g_free); - } - g_free (file_name); - g_free (dir_name); - - return file_info; -} - -static void -add_revision_info (CollectRevisionParam *data, - SeafCommit *commit, const char *file_id, gint64 file_size) -{ - seaf_commit_ref (commit); - data->wanted_commits = g_list_prepend (data->wanted_commits, commit); - data->file_id_list = g_list_prepend (data->file_id_list, g_strdup(file_id)); - gint64 *size = g_malloc(sizeof(gint64)); - *size = file_size; - data->file_size_list = g_list_prepend (data->file_size_list, size); - ++(data->n_commits); -} - -static gboolean -collect_file_revisions (SeafCommit *commit, void *vdata, gboolean *stop) -{ - CollectRevisionParam *data = vdata; - SeafRepo *repo = data->repo; - const char *path = data->path; - GError **error = data->error; - GHashTable *file_info_cache = data->file_info_cache; - FileInfo *file_info = NULL; - FileInfo *parent1_info = NULL; - FileInfo *parent2_info = NULL; - - SeafCommit *parent_commit = NULL; - SeafCommit *parent_commit2 = NULL; - - gboolean ret = TRUE; - - /* At least find the latest revision. */ - if (data->got_latest && data->truncate_time == 0) { - *stop = TRUE; - return TRUE; - } - - if (data->got_latest && - data->truncate_time > 0 && - (gint64)(commit->ctime) < data->truncate_time) - { - *stop = TRUE; - return TRUE; - } - - if (data->max_revision > 0 && data->n_commits > data->max_revision) { - *stop = TRUE; - return TRUE; - } - - g_clear_error (error); - - file_info = get_file_info (data->repo, commit, path, - file_info_cache, NULL, error); - if (*error) { - seaf_warning ("Error when finding %s under %s:%s\n", - path, data->repo->id, commit->commit_id); - ret = FALSE; - goto out; - } - - if (!file_info) { - /* Target file is not present in this commit. - * Stop traversing after finding the initial version. - * Deleted files with the same path are not included in history. - */ - *stop = TRUE; - goto out; - } - - if (!commit->parent_id) { - /* Initial commit */ - add_revision_info (data, commit, file_info->file_id, file_info->file_size); - goto out; - } - - parent_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - commit->parent_id); - if (!parent_commit) { - seaf_warning ("Failed to get commit %s:%s\n", repo->id, commit->parent_id); - ret = FALSE; - goto out; - } - - parent1_info = get_file_info (data->repo, parent_commit, path, - file_info_cache, file_info, error); - if (*error) { - seaf_warning ("Error when finding %s under %s:%s\n", - path, data->repo->id, parent_commit->commit_id); - ret = FALSE; - goto out; - } - - if (parent1_info && - g_strcmp0 (parent1_info->file_id, file_info->file_id) == 0) { - /* This commit does not modify the target file */ - goto out; - } - - /* In case of a merge, the second parent also need compare */ - if (commit->second_parent_id) { - parent_commit2 = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - commit->second_parent_id); - if (!parent_commit2) { - seaf_warning ("Failed to get commit %s:%s\n", - repo->id, commit->second_parent_id); - ret = FALSE; - goto out; - } - - parent2_info = get_file_info (data->repo, parent_commit2, path, - file_info_cache, file_info, error); - if (*error) { - seaf_warning ("Error when finding %s under %s:%s\n", - path, data->repo->id, parent_commit2->commit_id); - ret = FALSE; - goto out; - } - - if (parent2_info && - g_strcmp0 (parent2_info->file_id, file_info->file_id) == 0) { - /* This commit does not modify the target file */ - goto out; - } - } - - if (!data->got_latest) - data->got_latest = TRUE; - - add_revision_info (data, commit, file_info->file_id, file_info->file_size); - -out: - if (parent_commit) seaf_commit_unref (parent_commit); - if (parent_commit2) seaf_commit_unref (parent_commit2); - - g_hash_table_remove (file_info_cache, commit->commit_id); - - return ret; -} - -static gboolean -path_exists_in_commit (SeafRepo *repo, const char *commit_id, const char *path) -{ - SeafCommit *c = NULL; - char *obj_id; - guint32 mode; - - c = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - commit_id); - if (!c) { - seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, commit_id); - return FALSE; - } - obj_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, - repo->store_id, - repo->version, - c->root_id, - path, - &mode, - NULL); - seaf_commit_unref (c); - if (!obj_id) - return FALSE; - g_free (obj_id); - return TRUE; -} - -static gboolean -detect_rename_revision (SeafRepo *repo, - SeafCommit *commit, - const char *path, - char **parent_id, - char **old_path) -{ - GList *diff_res = NULL; - SeafCommit *p1 = NULL; - int rc; - gboolean is_renamed = FALSE; - - while (*path == '/' && *path != 0) - ++path; - - if (!commit->second_parent_id) { - p1 = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - commit->parent_id); - if (!p1) { - seaf_warning ("Failed to get commit %s:%.8s.\n", - repo->id, commit->parent_id); - return FALSE; - } - /* Don't fold diff results for directories. We need to know a file was - * renamed when its parent folder was renamed. - */ - rc = diff_commits (p1, commit, &diff_res, FALSE); - seaf_commit_unref (p1); - if (rc < 0) { - seaf_warning ("Failed to diff.\n"); - return FALSE; - } - } else { - rc = diff_merge (commit, &diff_res, FALSE); - if (rc < 0) { - seaf_warning ("Failed to diff merge.\n"); - return FALSE; - } - } - - GList *ptr; - DiffEntry *de; - for (ptr = diff_res; ptr; ptr = ptr->next) { - de = ptr->data; - if (de->status == DIFF_STATUS_RENAMED && strcmp (de->new_name, path) == 0) { - *old_path = g_strdup(de->name); - is_renamed = TRUE; - break; - } - } - for (ptr = diff_res; ptr; ptr = ptr->next) - diff_entry_free ((DiffEntry *)ptr->data); - g_list_free (diff_res); - - if (!is_renamed) - return FALSE; - - /* Determine parent commit containing the old path. */ - if (!commit->second_parent_id) - *parent_id = g_strdup(commit->parent_id); - else { - if (path_exists_in_commit (repo, commit->parent_id, *old_path)) - *parent_id = g_strdup(commit->parent_id); - else if (path_exists_in_commit (repo, commit->second_parent_id, *old_path)) - *parent_id = g_strdup(commit->second_parent_id); - else { - g_free (*old_path); - *old_path = NULL; - return FALSE; - } - } - - return TRUE; -} - -static SeafileCommit * -convert_to_seafile_commit (SeafCommit *c) -{ - SeafileCommit *commit = seafile_commit_new (); - g_object_set (commit, - "id", c->commit_id, - "creator_name", c->creator_name, - "creator", c->creator_id, - "desc", c->desc, - "ctime", c->ctime, - "repo_id", c->repo_id, - "root_id", c->root_id, - "parent_id", c->parent_id, - "second_parent_id", c->second_parent_id, - "version", c->version, - "new_merge", c->new_merge, - "conflict", c->conflict, - "device_name", c->device_name, - NULL); - return commit; -} - -static GList * -convert_rpc_commit_list (GList *commit_list, - GList *file_id_list, - GList *file_size_list, - gboolean is_renamed, - const char *renamed_old_path) -{ - GList *ret = NULL; - GList *ptr1, *ptr2, *ptr3; - SeafCommit *c; - char *file_id; - gint64 *file_size; - SeafileCommit *commit; - - for (ptr1 = commit_list, ptr2 = file_id_list, ptr3 = file_size_list; - ptr1 && ptr2 && ptr3; - ptr1 = ptr1->next, ptr2 = ptr2->next, ptr3 = ptr3->next) { - c = ptr1->data; - file_id = ptr2->data; - file_size = ptr3->data; - commit = convert_to_seafile_commit (c); - g_object_set (commit, "rev_file_id", file_id, "rev_file_size", *file_size, - NULL); - if (ptr1->next == NULL && is_renamed) - g_object_set (commit, "rev_renamed_old_path", renamed_old_path, NULL); - ret = g_list_prepend (ret, commit); - } - - ret = g_list_reverse (ret); - return ret; -} - -GList * -seaf_repo_manager_list_file_revisions (SeafRepoManager *mgr, - const char *repo_id, - const char *start_commit_id, - const char *path, - int max_revision, - int limit, - int show_days, - gboolean got_latest, - GError **error) -{ - SeafRepo *repo = NULL; - GList *commit_list = NULL, *file_id_list = NULL, *file_size_list = NULL; - GList *ret = NULL, *ptr; - CollectRevisionParam data = {0}; - SeafCommit *last_commit = NULL; - const char *head_id; - gboolean is_renamed = FALSE; - char *parent_id = NULL, *old_path = NULL; - GList *old_revisions = NULL; - gint64 truncate_time; - gint64 show_time; - - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "No such repo %s", repo_id); - goto out; - } - - data.repo = repo; - - if (!start_commit_id) - head_id = repo->head->commit_id; - else - head_id = start_commit_id; - - data.path = path; - data.error = error; - data.max_revision = max_revision; - - truncate_time = seaf_repo_manager_get_repo_truncate_time (mgr, repo_id); - if (truncate_time == 0) { - // Don't keep history - data.truncate_time = 0; - } else { - show_time = show_days > 0 ? time(NULL) - show_days*24*3600 : -1; - data.truncate_time = MAX (truncate_time, show_time); - } - - data.wanted_commits = NULL; - data.file_id_list = NULL; - data.file_size_list = NULL; - data.got_latest = got_latest; - - /* A hash table to cache caculated file info of in */ - data.file_info_cache = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, free_file_info); - - if (!seaf_commit_manager_traverse_commit_tree_with_limit (seaf->commit_mgr, - repo->id, - repo->version, - head_id, - (CommitTraverseFunc)collect_file_revisions, - limit, &data, TRUE)) { - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to traverse commit of repo %s", repo_id); - goto out; - } - - if (!data.wanted_commits) { - g_clear_error (error); - goto out; - } - - /* commit list in descending commit time order. */ - last_commit = data.wanted_commits->data; - - is_renamed = detect_rename_revision (repo, - last_commit, path, &parent_id, &old_path); - - commit_list = g_list_reverse (data.wanted_commits); - file_id_list = g_list_reverse (data.file_id_list); - file_size_list = g_list_reverse (data.file_size_list); - - ret = convert_rpc_commit_list (commit_list, file_id_list, file_size_list, - is_renamed, old_path); - - if (is_renamed) { - if (ret) { - // if previous scan got revision then set got_latest True for renamend scan - /* Get the revisions of the old path, starting from parent commit. */ - old_revisions = seaf_repo_manager_list_file_revisions (mgr, repo_id, - parent_id, old_path, - -1, -1, show_days, - TRUE, error); - } else { - /* Get the revisions of the old path, starting from parent commit. */ - old_revisions = seaf_repo_manager_list_file_revisions (mgr, repo_id, - parent_id, old_path, - -1, -1, show_days, - FALSE, error); - } - ret = g_list_concat (ret, old_revisions); - g_free (parent_id); - g_free (old_path); - } - - g_clear_error (error); - -out: - if (repo) - seaf_repo_unref (repo); - for (ptr = commit_list; ptr; ptr = ptr->next) - seaf_commit_unref ((SeafCommit *)ptr->data); - g_list_free (commit_list); - string_list_free (file_id_list); - for (ptr = file_size_list; ptr; ptr = ptr->next) - g_free (ptr->data); - g_list_free (file_size_list); - if (data.file_info_cache) - g_hash_table_destroy (data.file_info_cache); - - return ret; -} - -typedef struct CalcFilesLastModifiedParam CalcFilesLastModifiedParam; - -struct CalcFilesLastModifiedParam { - SeafRepo *repo; - GError **error; - const char *parent_dir; - GHashTable *last_modified_hash; - GHashTable *current_file_id_hash; - SeafCommit *current_commit; -}; - -static gboolean -check_non_existing_files (void *key, void *value, void *vdata) -{ - CalcFilesLastModifiedParam *data = vdata; - gboolean remove = FALSE; - - char *file_name = key; - gint64 *ctime = g_hash_table_lookup (data->last_modified_hash, file_name); - if (!ctime) { - /* Impossible */ - remove = TRUE; - } else if (*ctime != data->current_commit->ctime) { - /* This file does not exist in this commit. So it's last modified in - * the previous commit. - */ - remove = TRUE; - } - - return remove; -} - -static gboolean -collect_files_last_modified (SeafCommit *commit, void *vdata, gboolean *stop) -{ - CalcFilesLastModifiedParam *data = vdata; - GError **error = data->error; - SeafDirent *dent = NULL; - char *file_id = NULL; - SeafDir *dir = NULL; - GList *ptr; - gboolean ret = TRUE; - - data->current_commit = commit; - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - data->repo->store_id, - data->repo->version, - commit->root_id, - data->parent_dir, - error); - if (*error) { - if (!g_error_matches(*error, SEAFILE_DOMAIN, SEAF_ERR_PATH_NO_EXIST)) { - *stop = TRUE; - ret = FALSE; - goto out; - } else { - g_clear_error (error); - } - } - - if (!dir) { - /* The directory does not exist in this commit. So all files are last - * modified in the previous commit; - */ - *stop = TRUE; - goto out; - } - - for (ptr = dir->entries; ptr; ptr = ptr->next) { - dent = ptr->data; - file_id = g_hash_table_lookup (data->current_file_id_hash, dent->name); - if (file_id) { - if (strcmp(file_id, dent->id) != 0) { - g_hash_table_remove (data->current_file_id_hash, dent->name); - } else { - gint64 *ctime = g_new (gint64, 1); - *ctime = commit->ctime; - g_hash_table_replace (data->last_modified_hash, g_strdup(dent->name), ctime); - } - } - - if (g_hash_table_size(data->current_file_id_hash) == 0) { - *stop = TRUE; - goto out; - } - } - - /* Files not found in the current commit are last modified in the previous - * commit */ - g_hash_table_foreach_remove (data->current_file_id_hash, - check_non_existing_files, data); - - if (g_hash_table_size(data->current_file_id_hash) == 0) { - /* All files under this diretory have been calculated */ - *stop = TRUE; - goto out; - } - -out: - seaf_dir_free (dir); - - return ret; -} - -/** - * Give a directory, return the last modification timestamps of all the files - * under this directory. - * - * First we record the current id of every file, then traverse the commit - * tree. Give a commit, for each file, if the file id in that commit is - * different than its current id, then this file is last modified in the - * commit previous to that commit. - */ -GList * -seaf_repo_manager_calc_files_last_modified (SeafRepoManager *mgr, - const char *repo_id, - const char *parent_dir, - int limit, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *head_commit = NULL; - SeafDir *dir = NULL; - GList *ptr = NULL; - SeafDirent *dent = NULL; - CalcFilesLastModifiedParam data = {0}; - GList *ret_list = NULL; - - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "No such repo %s", repo_id); - goto out; - } - - head_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!head_commit) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get commit %s", repo->head->commit_id); - goto out; - } - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - head_commit->root_id, - parent_dir, error); - if (*error || !dir) { - goto out; - } - - data.repo = repo; - - /* A hash table of pattern (file_name, current_file_id) */ - data.current_file_id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - /* A (file_name, last_modified) hashtable. is a heap - allocated gint64 - */ - data.last_modified_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - for (ptr = dir->entries; ptr; ptr = ptr->next) { - dent = ptr->data; - g_hash_table_insert (data.current_file_id_hash, - g_strdup(dent->name), - g_strdup(dent->id)); - - gint64 *ctime = g_new (gint64, 1); - *ctime = head_commit->ctime; - g_hash_table_insert (data.last_modified_hash, - g_strdup(dent->name), - ctime); - } - - if (g_hash_table_size (data.current_file_id_hash) == 0) { - /* An empty directory, no need to traverse */ - goto out; - } - - data.parent_dir = parent_dir; - data.error = error; - - if (!seaf_commit_manager_traverse_commit_tree_with_limit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id, - (CommitTraverseFunc)collect_files_last_modified, - limit, &data, FALSE)) { - if (*error) - seaf_warning ("error when traversing commits: %s\n", (*error)->message); - else - seaf_warning ("error when traversing commits.\n"); - g_clear_error (error); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "failed to traverse commit of repo %s", repo_id); - goto out; - } - - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, data.last_modified_hash); - while (g_hash_table_iter_next (&iter, &key, &value)) { - SeafileFileLastModifiedInfo *info; - gint64 last_modified = *(gint64 *)value; - info = g_object_new (SEAFILE_TYPE_FILE_LAST_MODIFIED_INFO, - "file_name", key, - "last_modified", last_modified, - NULL); - ret_list = g_list_prepend (ret_list, info); - } - -out: - if (repo) - seaf_repo_unref (repo); - if (head_commit) - seaf_commit_unref(head_commit); - if (data.last_modified_hash) - g_hash_table_destroy (data.last_modified_hash); - if (data.current_file_id_hash) - g_hash_table_destroy (data.current_file_id_hash); - if (dir) - seaf_dir_free (dir); - - return g_list_reverse(ret_list); -} - -int -seaf_repo_manager_revert_on_server (SeafRepoManager *mgr, - const char *repo_id, - const char *commit_id, - const char *user_name, - GError **error) -{ - SeafRepo *repo; - SeafCommit *commit = NULL, *new_commit = NULL; - char desc[512]; - int ret = 0; - -retry: - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "No such repo"); - return -1; - } - - commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - commit_id); - if (!commit) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Commit doesn't exist"); - ret = -1; - goto out; - } - -#ifndef WIN32 - strftime (desc, sizeof(desc), "Reverted repo to status at %F %T.", - localtime((time_t *)(&commit->ctime))); -#else - strftime (desc, sizeof(desc), "Reverted repo to status at %Y-%m-%d %H:%M:%S.", - localtime((time_t *)(&commit->ctime))); -#endif - - new_commit = seaf_commit_new (NULL, repo->id, commit->root_id, - user_name, EMPTY_SHA1, - desc, 0); - - new_commit->parent_id = g_strdup (repo->head->commit_id); - seaf_repo_to_commit (repo, new_commit); - - if (seaf_commit_manager_add_commit (seaf->commit_mgr, new_commit) < 0) { - ret = -1; - goto out; - } - - seaf_branch_set_commit (repo->head, new_commit->commit_id); - if (seaf_branch_manager_test_and_update_branch (seaf->branch_mgr, - repo->head, - new_commit->parent_id) < 0) - { - seaf_repo_unref (repo); - seaf_commit_unref (commit); - seaf_commit_unref (new_commit); - repo = NULL; - commit = new_commit = NULL; - goto retry; - } - - seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL); - -out: - if (new_commit) - seaf_commit_unref (new_commit); - if (commit) - seaf_commit_unref (commit); - if (repo) - seaf_repo_unref (repo); - - if (ret == 0) { - update_repo_size (repo_id); - } - - return ret; -} - -static void -add_deleted_entry (SeafRepo *repo, - GHashTable *entries, - SeafDirent *dent, - const char *base, - SeafCommit *child, - SeafCommit *parent) -{ - char *path = g_strconcat (base, dent->name, NULL); - SeafileDeletedEntry *entry; - Seafile *file; - - if (g_hash_table_lookup (entries, path) != NULL) { - /* g_debug ("found dup deleted entry for %s.\n", path); */ - g_free (path); - return; - } - - /* g_debug ("Add deleted entry for %s.\n", path); */ - - entry = g_object_new (SEAFILE_TYPE_DELETED_ENTRY, - "commit_id", parent->commit_id, - "obj_id", dent->id, - "obj_name", dent->name, - "basedir", base, - "mode", dent->mode, - "delete_time", child->ctime, - NULL); - - if (S_ISREG(dent->mode)) { - file = seaf_fs_manager_get_seafile (seaf->fs_mgr, - repo->store_id, repo->version, - dent->id); - if (!file) { - g_free (path); - g_object_unref (entry); - return; - } - g_object_set (entry, "file_size", file->file_size, NULL); - seafile_unref (file); - } - - g_hash_table_insert (entries, path, entry); -} - -static int -find_deleted_recursive (SeafRepo *repo, - SeafDir *d1, - SeafDir *d2, - const char *base, - SeafCommit *child, - SeafCommit *parent, - GHashTable *entries) -{ - GList *p1, *p2; - SeafDirent *dent1, *dent2; - int res, ret = 0; - - p1 = d1->entries; - p2 = d2->entries; - - /* Since dirents are sorted in descending order, we can use merge - * algorithm to find out deleted entries. - * Deleted entries are those: - * 1. exists in d2 but absent in d1. - * 2. exists in both d1 and d2 but with different type. - */ - - while (p1 && p2) { - dent1 = p1->data; - dent2 = p2->data; - - res = g_strcmp0 (dent1->name, dent2->name); - if (res < 0) { - /* exists in d2 but absent in d1. */ - add_deleted_entry (repo, entries, dent2, base, child, parent); - p2 = p2->next; - } else if (res == 0) { - if ((dent1->mode & S_IFMT) != (dent2->mode & S_IFMT)) { - /* both exists but with diffent type. */ - add_deleted_entry (repo, entries, dent2, base, child, parent); - } else if (S_ISDIR(dent1->mode) && strcmp(dent1->id, dent2->id) != 0) { - SeafDir *n1 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, - repo->id, - repo->version, - dent1->id); - if (!n1) { - seaf_warning ("Failed to find dir %s:%s.\n", repo->id, dent1->id); - return -1; - } - - SeafDir *n2 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, - repo->id, - repo->version, - dent2->id); - if (!n2) { - seaf_warning ("Failed to find dir %s:%s.\n", repo->id, dent2->id); - seaf_dir_free (n1); - return -1; - } - - char *new_base = g_strconcat (base, dent1->name, "/", NULL); - ret = find_deleted_recursive (repo, n1, n2, new_base, - child, parent, entries); - g_free (new_base); - seaf_dir_free (n1); - seaf_dir_free (n2); - if (ret < 0) - return ret; - } - p1 = p1->next; - p2 = p2->next; - } else { - p1 = p1->next; - } - } - - for ( ; p2 != NULL; p2 = p2->next) { - dent2 = p2->data; - add_deleted_entry (repo, entries, dent2, base, child, parent); - } - - return ret; -} - -static int -find_deleted (SeafRepo *repo, - SeafCommit *child, - SeafCommit *parent, - const char *base, - GHashTable *entries) -{ - SeafDir *d1, *d2; - int ret = 0; - - d1 = seaf_fs_manager_get_seafdir_sorted_by_path (seaf->fs_mgr, - repo->id, - repo->version, - child->root_id, base); - if (!d1) { - return ret; - } - - d2 = seaf_fs_manager_get_seafdir_sorted_by_path (seaf->fs_mgr, - repo->id, - repo->version, - parent->root_id, base); - if (!d2) { - seaf_dir_free (d1); - return ret; - } - - ret = find_deleted_recursive (repo, d1, d2, base, child, parent, entries); - - seaf_dir_free (d2); - seaf_dir_free (d1); - - return ret; -} - -typedef struct CollectDelData { - SeafRepo *repo; - GHashTable *entries; - gint64 truncate_time; - char *path; -} CollectDelData; - -#define DEFAULT_RECYCLE_DAYS 7 - -static gboolean -collect_deleted (SeafCommit *commit, void *vdata, gboolean *stop) -{ - CollectDelData *data = vdata; - SeafRepo *repo = data->repo; - GHashTable *entries = data->entries; - gint64 truncate_time = data->truncate_time; - SeafCommit *p1, *p2; - - /* We use <= here. This is for handling clean trash and history. - * If the user cleans all history, truncate time will be equal to - * the head commit's ctime. In such case, we don't actually want to display - * any deleted file. - */ - if ((gint64)(commit->ctime) <= truncate_time) { - *stop = TRUE; - return TRUE; - } - - if (commit->parent_id == NULL) - return TRUE; - - if (!(strstr (commit->desc, PREFIX_DEL_FILE) != NULL || - strstr (commit->desc, PREFIX_DEL_DIR) != NULL || - strstr (commit->desc, PREFIX_DEL_DIRS) != NULL)) { - return TRUE; - } - - p1 = seaf_commit_manager_get_commit (commit->manager, - repo->id, repo->version, - commit->parent_id); - if (!p1) { - seaf_warning ("Failed to find commit %s:%s.\n", repo->id, commit->parent_id); - return FALSE; - } - - if (find_deleted (data->repo, commit, p1, data->path, entries) < 0) { - seaf_commit_unref (p1); - return FALSE; - } - - seaf_commit_unref (p1); - - if (commit->second_parent_id) { - p2 = seaf_commit_manager_get_commit (commit->manager, - repo->id, repo->version, - commit->second_parent_id); - if (!p2) { - seaf_warning ("Failed to find commit %s:%s.\n", - repo->id, commit->second_parent_id); - return FALSE; - } - - if (find_deleted (data->repo, commit, p2, data->path, entries) < 0) { - seaf_commit_unref (p2); - return FALSE; - } - - seaf_commit_unref (p2); - } - - return TRUE; -} - -typedef struct RemoveExistingParam { - SeafRepo *repo; - SeafCommit *head; -} RemoveExistingParam; - -static gboolean -remove_existing (gpointer key, gpointer value, gpointer user_data) -{ - SeafileDeletedEntry *e = value; - RemoveExistingParam *param = user_data; - SeafRepo *repo = param->repo; - SeafCommit *head = param->head; - guint32 mode = seafile_deleted_entry_get_mode(e), mode_out = 0; - char *path = key; - - char *obj_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, - repo->store_id, repo->version, - head->root_id, - path, &mode_out, NULL); - if (obj_id == NULL) - return FALSE; - g_free (obj_id); - - /* If path exist in head commit and with the same type, - * remove it from deleted entries. - */ - if ((mode & S_IFMT) == (mode_out & S_IFMT)) { - /* g_debug ("%s exists in head commit.\n", path); */ - return TRUE; - } - - return FALSE; -} - -static int -filter_out_existing_entries (GHashTable *entries, - SeafRepo *repo, - const char *head_id) -{ - SeafCommit *head; - RemoveExistingParam param; - - head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - head_id); - if (!head) { - seaf_warning ("Failed to find head commit %s of repo %s.\n", - head_id, repo->id); - return -1; - } - - param.repo = repo; - param.head = head; - - g_hash_table_foreach_remove (entries, remove_existing, ¶m); - - seaf_commit_unref (head); - return 0; -} - -static gboolean -hash_to_list (gpointer key, gpointer value, gpointer user_data) -{ - GList **plist = (GList **)user_data; - - g_free (key); - *plist = g_list_prepend (*plist, value); - - return TRUE; -} - -static gint -compare_commit_by_time (gconstpointer a, gconstpointer b, gpointer unused) -{ - const SeafCommit *commit_a = a; - const SeafCommit *commit_b = b; - - /* Latest commit comes first in the list. */ - return (commit_b->ctime - commit_a->ctime); -} - -static int -insert_parent_commit (GList **list, GHashTable *hash, - const char *repo_id, int version, - const char *parent_id) -{ - SeafCommit *p; - char *key; - - if (g_hash_table_lookup (hash, parent_id) != NULL) - return 0; - - p = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo_id, version, - parent_id); - if (!p) { - seaf_warning ("Failed to find commit %s\n", parent_id); - return -1; - } - - *list = g_list_insert_sorted_with_data (*list, p, - compare_commit_by_time, - NULL); - - key = g_strdup (parent_id); - g_hash_table_replace (hash, key, key); - - return 0; -} - -static int -scan_commits_for_collect_deleted (CollectDelData *data, - const char *prev_scan_stat, - int limit, - char **next_scan_stat) -{ - GList *list = NULL; - SeafCommit *commit; - GHashTable *commit_hash; - SeafRepo *repo = data->repo; - int scan_num = 0; - gboolean ret = TRUE; - - /* A hash table for recording id of traversed commits. */ - commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - char *key; - if (prev_scan_stat == NULL) { - commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, - repo->version, repo->head->commit_id); - if (!commit) { - ret = FALSE; - goto out; - } - list = g_list_prepend (list, commit); - key = g_strdup (commit->commit_id); - g_hash_table_replace (commit_hash, key, key); - } else { - commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, - repo->version, prev_scan_stat); - if (!commit) { - ret = FALSE; - goto out; - } - list = g_list_append (list, commit); - key = g_strdup (commit->commit_id); - g_hash_table_replace (commit_hash, key, key); - } - - while (list) { - gboolean stop = FALSE; - commit = list->data; - list = g_list_delete_link (list, list); - - if (!collect_deleted (commit, data, &stop)) { - seaf_warning("[comit-mgr] CommitTraverseFunc failed\n"); - seaf_commit_unref (commit); - ret = FALSE; - goto out; - } - - if (stop) { - seaf_commit_unref (commit); - /* stop traverse down from this commit, - * but not stop traversing the tree - */ - continue; - } - - if (commit->parent_id) { - if (insert_parent_commit (&list, commit_hash, repo->id, - repo->version, - commit->parent_id) < 0) { - seaf_warning("[comit-mgr] insert parent commit failed\n"); - seaf_commit_unref (commit); - ret = FALSE; - goto out; - } - } - if (commit->second_parent_id) { - if (insert_parent_commit (&list, commit_hash, repo->id, - repo->version, - commit->second_parent_id) < 0) { - seaf_warning("[comit-mgr]insert second parent commit failed\n"); - seaf_commit_unref (commit); - ret = FALSE; - goto out; - } - } - seaf_commit_unref (commit); - - if (++scan_num == limit && (!list || !list->next)) { - break; - } - } - - // two scenarios: - // 1. list is empty, indicate scan end - // 2. list only have one commit, as start for next scan - if (list) { - commit = list->data; - *next_scan_stat = g_strdup (commit->commit_id); - seaf_commit_unref (commit); - list = g_list_delete_link (list, list); - } - g_hash_table_destroy (commit_hash); - - return ret; - -out: - g_hash_table_destroy (commit_hash); - while (list) { - commit = list->data; - seaf_commit_unref (commit); - list = g_list_delete_link (list, list); - } - - return ret; -} - -GList * -seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, - const char *repo_id, - int show_days, - const char *path, - const char *scan_stat, - int limit, - GError **error) -{ - SeafRepo *repo; - gint64 truncate_time, show_time; - GList *ret = NULL; - char *next_scan_stat = NULL; - - truncate_time = seaf_repo_manager_get_repo_truncate_time (mgr, repo_id); - if (truncate_time == 0) { - // Don't keep history, set scan_stat as NULL, indicate no need for next scan - ret = g_list_append (ret, g_object_new (SEAFILE_TYPE_DELETED_ENTRY, - "scan_stat", NULL, - NULL)); - return ret; - } - - if (show_days <= 0) - show_time = -1; - else - show_time = (gint64)time(NULL) - show_days * 24 * 3600; - - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Invalid repo id"); - return NULL; - } - - CollectDelData data = {0}; - GHashTable *entries = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - data.repo = repo; - data.entries = entries; - data.truncate_time = MAX (show_time, truncate_time); - if (path) { - if (path[strlen(path) - 1] == '/') { - data.path = g_strdup (path); - } else { - data.path = g_strconcat (path, "/", NULL); - } - } else { - data.path = g_strdup ("/"); - } - - if (!scan_commits_for_collect_deleted (&data, scan_stat, limit, &next_scan_stat)) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, - "Internal error"); - g_hash_table_destroy (entries); - seaf_repo_unref (repo); - g_free (data.path); - return NULL; - } - - /* Remove entries exist in the current commit. - * This is necessary because some files may be added back after deletion. - */ - if (filter_out_existing_entries (entries, repo, - repo->head->commit_id) == 0) { - // filter success, then add collected result to list - g_hash_table_foreach_steal (entries, hash_to_list, &ret); - } - - // Append scan_stat entry to the end to indicate the end of scan result - ret = g_list_append (ret, g_object_new (SEAFILE_TYPE_DELETED_ENTRY, - "scan_stat", next_scan_stat, - NULL)); - - g_hash_table_destroy (entries); - - seaf_repo_unref (repo); - g_free (data.path); - - return ret; -} - -static SeafCommit * -get_commit(SeafRepo *repo, const char *branch_or_commit) -{ - SeafBranch *b; - SeafCommit *c; - - b = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, - branch_or_commit); - if (!b) { - if (strcmp(branch_or_commit, "HEAD") == 0) - c = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - else - c = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - branch_or_commit); - } else { - c = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - b->commit_id); - } - - if (b) - seaf_branch_unref (b); - - return c; -} - -GList * -seaf_repo_diff (SeafRepo *repo, const char *old, const char *new, int fold_dir_diff, char **error) -{ - SeafCommit *c1 = NULL, *c2 = NULL; - int ret = 0; - GList *diff_entries = NULL; - - g_return_val_if_fail (*error == NULL, NULL); - - c2 = get_commit (repo, new); - if (!c2) { - *error = g_strdup("Can't find new commit"); - return NULL; - } - - if (old == NULL || old[0] == '\0') { - if (c2->parent_id && c2->second_parent_id) { - ret = diff_merge (c2, &diff_entries, fold_dir_diff); - seaf_commit_unref (c2); - if (ret < 0) { - *error = g_strdup("Failed to do diff"); - g_list_free_full (diff_entries, (GDestroyNotify)diff_entry_free); - return NULL; - } - return diff_entries; - } - - if (!c2->parent_id) { - seaf_commit_unref (c2); - return NULL; - } - c1 = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - c2->parent_id); - } else { - c1 = get_commit (repo, old); - } - - if (!c1) { - *error = g_strdup("Can't find old commit"); - seaf_commit_unref (c2); - return NULL; - } - - /* do diff */ - ret = diff_commits (c1, c2, &diff_entries, fold_dir_diff); - if (ret < 0) { - g_list_free_full (diff_entries, (GDestroyNotify)diff_entry_free); - diff_entries = NULL; - *error = g_strdup("Failed to do diff"); - } - - seaf_commit_unref (c1); - seaf_commit_unref (c2); - - return diff_entries; -} diff --git a/server/repo-perm.c b/server/repo-perm.c deleted file mode 100644 index c3d1b063..00000000 --- a/server/repo-perm.c +++ /dev/null @@ -1,297 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include "utils.h" -#include "log.h" -#include "seafile.h" - -#include "seafile-session.h" -#include "repo-mgr.h" - -#include "seafile-error.h" - -/* - * Permission priority: owner --> personal share --> group share --> public. - * Permission with higher priority overwrites those with lower priority. - */ -static char * -check_repo_share_permission (SeafRepoManager *mgr, - const char *repo_id, - const char *user_name) -{ - SearpcClient *rpc_client; - GList *groups, *p1; - GList *group_perms, *p2; - CcnetGroup *group; - GroupPerm *perm; - int group_id; - char *permission; - - permission = seaf_share_manager_check_permission (seaf->share_mgr, - repo_id, - user_name); - if (permission != NULL) - return permission; - g_free (permission); - - rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool, - NULL, - "ccnet-threaded-rpcserver"); - if (!rpc_client) - return NULL; - - /* Get the groups this user belongs to. */ - groups = ccnet_get_groups_by_user (rpc_client, user_name); - - ccnet_rpc_client_free (rpc_client); - - /* Get the groups this repo shared to. */ - group_perms = seaf_repo_manager_get_group_perm_by_repo (mgr, repo_id, NULL); - - permission = NULL; - /* Check if any one group overlaps. */ - for (p1 = groups; p1 != NULL; p1 = p1->next) { - group = p1->data; - g_object_get (group, "id", &group_id, NULL); - - for (p2 = group_perms; p2 != NULL; p2 = p2->next) { - perm = p2->data; - if (group_id == perm->group_id) { - /* If the repo is shared to more than 1 groups, - * and user is in more than 1 of these groups, - * "rw" permission will overwrite "ro" permission. - */ - if (g_strcmp0(perm->permission, "rw") == 0) { - permission = perm->permission; - goto group_out; - } else if (g_strcmp0(perm->permission, "r") == 0 && - !permission) { - permission = perm->permission; - } - } - } - } - -group_out: - if (permission != NULL) - permission = g_strdup(permission); - - for (p1 = groups; p1 != NULL; p1 = p1->next) - g_object_unref ((GObject *)p1->data); - g_list_free (groups); - for (p2 = group_perms; p2 != NULL; p2 = p2->next) - g_free (p2->data); - g_list_free (group_perms); - - if (permission != NULL) - return permission; - - if (!mgr->seaf->cloud_mode) - return seaf_repo_manager_get_inner_pub_repo_perm (mgr, repo_id); - - return NULL; -} - -static char * -check_virtual_repo_permission (SeafRepoManager *mgr, - const char *repo_id, - const char *origin_repo_id, - const char *user, - GError **error) -{ - char *owner = NULL; - char *permission = NULL; - - /* If I'm the owner of origin repo, I have full access to sub-repos. */ - owner = seaf_repo_manager_get_repo_owner (mgr, origin_repo_id); - if (g_strcmp0 (user, owner) == 0) { - permission = g_strdup("rw"); - return permission; - } - g_free (owner); - - /* If I'm not the owner of origin repo, this sub-repo can be created - * from a shared repo by me or directly shared by others to me. - * The priority of shared sub-folder is higher than top-level repo. - */ - permission = check_repo_share_permission (mgr, repo_id, user); - if (permission) - return permission; - - permission = check_repo_share_permission (mgr, origin_repo_id, user); - return permission; -} - -/* - * Comprehensive repo access permission checker. - * - * Returns read/write permission. - */ -char * -seaf_repo_manager_check_permission (SeafRepoManager *mgr, - const char *repo_id, - const char *user, - GError **error) -{ - SeafVirtRepo *vinfo; - char *owner = NULL; - char *permission = NULL; - - /* This is a virtual repo.*/ - vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); - if (vinfo) { - permission = check_virtual_repo_permission (mgr, repo_id, - vinfo->origin_repo_id, - user, error); - goto out; - } - - owner = seaf_repo_manager_get_repo_owner (mgr, repo_id); - if (owner != NULL) { - if (strcmp (owner, user) == 0) - permission = g_strdup("rw"); - else - permission = check_repo_share_permission (mgr, repo_id, user); - } - -out: - seaf_virtual_repo_info_free (vinfo); - g_free (owner); - return permission; -} - -/* - * Directories are always before files. Otherwise compare the names. - */ -static gint -comp_dirent_func (gconstpointer a, gconstpointer b) -{ - const SeafDirent *dent_a = a, *dent_b = b; - - if (S_ISDIR(dent_a->mode) && S_ISREG(dent_b->mode)) - return -1; - - if (S_ISREG(dent_a->mode) && S_ISDIR(dent_b->mode)) - return 1; - - return strcasecmp (dent_a->name, dent_b->name); -} - -GList * -seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr, - const char *repo_id, - const char *dir_path, - const char *dir_id, - const char *user, - int offset, - int limit, - GError **error) -{ - SeafRepo *repo; - char *perm = NULL; - SeafDir *dir; - SeafDirent *dent; - SeafileDirent *d; - GList *res = NULL; - GList *p; - - if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); - return NULL; - } - - perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error); - if (!perm) { - if (*error == NULL) - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied"); - return NULL; - } - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id"); - g_free (perm); - return NULL; - } - - dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, - repo->store_id, repo->version, dir_id); - if (!dir) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); - seaf_repo_unref (repo); - g_free (perm); - return NULL; - } - - dir->entries = g_list_sort (dir->entries, comp_dirent_func); - - if (offset < 0) { - offset = 0; - } - - int index = 0; - gboolean is_shared; - char *cur_path; - GHashTable *shared_sub_dirs = NULL; - - if (!repo->virtual_info) { - char *repo_owner = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, repo_id); - if (repo_owner && strcmp (user, repo_owner) == 0) { - shared_sub_dirs = seaf_share_manager_get_shared_sub_dirs (seaf->share_mgr, - repo->store_id, - dir_path); - } - g_free (repo_owner); - } - - for (p = dir->entries; p != NULL; p = p->next, index++) { - if (index < offset) { - continue; - } - - if (limit > 0) { - if (index >= offset + limit) - break; - } - - dent = p->data; - - if (!is_object_id_valid (dent->id)) - continue; - - d = g_object_new (SEAFILE_TYPE_DIRENT, - "obj_id", dent->id, - "obj_name", dent->name, - "mode", dent->mode, - "version", dent->version, - "mtime", dent->mtime, - "size", dent->size, - "permission", perm, - NULL); - - if (shared_sub_dirs && S_ISDIR(dent->mode)) { - if (strcmp (dir_path, "/") == 0) { - cur_path = g_strconcat (dir_path, dent->name, NULL); - } else { - cur_path = g_strconcat (dir_path, "/", dent->name, NULL); - } - is_shared = g_hash_table_lookup (shared_sub_dirs, cur_path) ? TRUE : FALSE; - g_free (cur_path); - g_object_set (d, "is_shared", is_shared, NULL); - } - res = g_list_prepend (res, d); - } - - if (shared_sub_dirs) - g_hash_table_destroy (shared_sub_dirs); - seaf_dir_free (dir); - seaf_repo_unref (repo); - g_free (perm); - if (res) - res = g_list_reverse (res); - - return res; -} diff --git a/server/seaf-server.c b/server/seaf-server.c deleted file mode 100644 index 4a7cb03e..00000000 --- a/server/seaf-server.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "seafile-session.h" -#include "seafile-rpc.h" -#include -#include -#include "log.h" -#include "utils.h" - -#include "processors/check-tx-slave-v3-proc.h" -#include "processors/recvfs-proc.h" -#include "processors/putfs-proc.h" -#include "processors/recvbranch-proc.h" -#include "processors/sync-repo-slave-proc.h" -#include "processors/putcommit-v2-proc.h" -#include "processors/putcommit-v3-proc.h" -#include "processors/recvcommit-v3-proc.h" -#include "processors/putcs-v2-proc.h" -#include "processors/checkbl-proc.h" -#include "processors/checkff-proc.h" -#include "processors/putca-proc.h" -#include "processors/check-protocol-slave-proc.h" -#include "processors/recvfs-v2-proc.h" -#include "processors/recvbranch-v2-proc.h" -#include "processors/putfs-v2-proc.h" - -#include "cdc/cdc.h" - -SeafileSession *seaf; -SearpcClient *ccnetrpc_client; -SearpcClient *ccnetrpc_client_t; -SearpcClient *async_ccnetrpc_client; -SearpcClient *async_ccnetrpc_client_t; - -char *pidfile = NULL; - -static const char *short_options = "hvc:d:l:fg:G:P:mCD:F:"; -static struct option long_options[] = { - { "help", no_argument, NULL, 'h', }, - { "version", no_argument, NULL, 'v', }, - { "config-file", required_argument, NULL, 'c' }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "seafdir", required_argument, NULL, 'd' }, - { "log", required_argument, NULL, 'l' }, - { "debug", required_argument, NULL, 'D' }, - { "foreground", no_argument, NULL, 'f' }, - { "ccnet-debug-level", required_argument, NULL, 'g' }, - { "seafile-debug-level", required_argument, NULL, 'G' }, - { "master", no_argument, NULL, 'm'}, - { "pidfile", required_argument, NULL, 'P' }, - { "cloud-mode", no_argument, NULL, 'C'}, - { NULL, 0, NULL, 0, }, -}; - -static void usage () -{ - fprintf (stderr, "usage: seaf-server [-c config_dir] [-d seafile_dir]\n"); -} - -static void register_processors (CcnetClient *client) -{ - ccnet_register_service (client, "seafile-check-tx-slave-v3", "basic", - SEAFILE_TYPE_CHECK_TX_SLAVE_V3_PROC, NULL); - ccnet_register_service (client, "seafile-recvfs", "basic", - SEAFILE_TYPE_RECVFS_PROC, NULL); - ccnet_register_service (client, "seafile-putfs", "basic", - SEAFILE_TYPE_PUTFS_PROC, NULL); - ccnet_register_service (client, "seafile-recvbranch", "basic", - SEAFILE_TYPE_RECVBRANCH_PROC, NULL); - ccnet_register_service (client, "seafile-sync-repo-slave", "basic", - SEAFILE_TYPE_SYNC_REPO_SLAVE_PROC, NULL); - ccnet_register_service (client, "seafile-putcommit-v2", "basic", - SEAFILE_TYPE_PUTCOMMIT_V2_PROC, NULL); - ccnet_register_service (client, "seafile-putcommit-v3", "basic", - SEAFILE_TYPE_PUTCOMMIT_V3_PROC, NULL); - ccnet_register_service (client, "seafile-recvcommit-v3", "basic", - SEAFILE_TYPE_RECVCOMMIT_V3_PROC, NULL); - ccnet_register_service (client, "seafile-putcs-v2", "basic", - SEAFILE_TYPE_PUTCS_V2_PROC, NULL); - ccnet_register_service (client, "seafile-checkbl", "basic", - SEAFILE_TYPE_CHECKBL_PROC, NULL); - ccnet_register_service (client, "seafile-checkff", "basic", - SEAFILE_TYPE_CHECKFF_PROC, NULL); - ccnet_register_service (client, "seafile-putca", "basic", - SEAFILE_TYPE_PUTCA_PROC, NULL); - ccnet_register_service (client, "seafile-check-protocol-slave", "basic", - SEAFILE_TYPE_CHECK_PROTOCOL_SLAVE_PROC, NULL); - ccnet_register_service (client, "seafile-recvfs-v2", "basic", - SEAFILE_TYPE_RECVFS_V2_PROC, NULL); - ccnet_register_service (client, "seafile-recvbranch-v2", "basic", - SEAFILE_TYPE_RECVBRANCH_V2_PROC, NULL); - ccnet_register_service (client, "seafile-putfs-v2", "basic", - SEAFILE_TYPE_PUTFS_V2_PROC, NULL); -} - -#include -#include "searpc-signature.h" -#include "searpc-marshal.h" - -static void start_rpc_service (CcnetClient *client, int cloud_mode) -{ - searpc_server_init (register_marshals); - - searpc_create_service ("seafserv-rpcserver"); - ccnet_register_service (client, "seafserv-rpcserver", "rpc-inner", - CCNET_TYPE_RPCSERVER_PROC, NULL); - - searpc_create_service ("seafserv-threaded-rpcserver"); - ccnet_register_service (client, "seafserv-threaded-rpcserver", "rpc-inner", - CCNET_TYPE_THREADED_RPCSERVER_PROC, NULL); - - /* threaded services */ - - /* repo manipulation */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_repo, - "seafile_get_repo", - searpc_signature_object__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_destroy_repo, - "seafile_destroy_repo", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_repo_list, - "seafile_get_repo_list", - searpc_signature_objlist__int_int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_count_repos, - "seafile_count_repos", - searpc_signature_int64__void()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_repo_owner, - "seafile_set_repo_owner", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_repo_owner, - "seafile_get_repo_owner", - searpc_signature_string__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_orphan_repo_list, - "seafile_get_orphan_repo_list", - searpc_signature_objlist__void()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_edit_repo, - "seafile_edit_repo", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_change_repo_passwd, - "seafile_change_repo_passwd", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_is_repo_owner, - "seafile_is_repo_owner", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_owned_repos, - "seafile_list_owned_repos", - searpc_signature_objlist__string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_server_repo_size, - "seafile_server_repo_size", - searpc_signature_int64__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_repo_set_access_property, - "seafile_repo_set_access_property", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_repo_query_access_property, - "seafile_repo_query_access_property", - searpc_signature_string__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_revert_on_server, - "seafile_revert_on_server", - searpc_signature_int__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_diff, - "seafile_diff", - searpc_signature_objlist__string_string_string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_post_file, - "seafile_post_file", - searpc_signature_int__string_string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_post_file_blocks, - "seafile_post_file_blocks", - searpc_signature_string__string_string_string_string_string_string_int64_int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_post_multi_files, - "seafile_post_multi_files", - searpc_signature_string__string_string_string_string_string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_put_file, - "seafile_put_file", - searpc_signature_string__string_string_string_string_string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_put_file_blocks, - "seafile_put_file_blocks", - searpc_signature_string__string_string_string_string_string_string_string_int64()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_post_empty_file, - "seafile_post_empty_file", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_post_dir, - "seafile_post_dir", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_del_file, - "seafile_del_file", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_copy_file, - "seafile_copy_file", - searpc_signature_object__string_string_string_string_string_string_string_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_move_file, - "seafile_move_file", - searpc_signature_object__string_string_string_string_string_string_int_string_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_rename_file, - "seafile_rename_file", - searpc_signature_int__string_string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_is_valid_filename, - "seafile_is_valid_filename", - searpc_signature_int__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_create_repo, - "seafile_create_repo", - searpc_signature_string__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_create_enc_repo, - "seafile_create_enc_repo", - searpc_signature_string__string_string_string_string_string_string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_commit, - "seafile_get_commit", - searpc_signature_object__string_int_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_dir, - "seafile_list_dir", - searpc_signature_objlist__string_string_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_dir_with_perm, - "list_dir_with_perm", - searpc_signature_objlist__string_string_string_string_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_file_blocks, - "seafile_list_file_blocks", - searpc_signature_string__string_string_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_file_size, - "seafile_get_file_size", - searpc_signature_int64__string_int_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_dir_size, - "seafile_get_dir_size", - searpc_signature_int64__string_int_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_dir_by_path, - "seafile_list_dir_by_path", - searpc_signature_objlist__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_dir_id_by_commit_and_path, - "seafile_get_dir_id_by_commit_and_path", - searpc_signature_string__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_file_id_by_path, - "seafile_get_file_id_by_path", - searpc_signature_string__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_dir_id_by_path, - "seafile_get_dir_id_by_path", - searpc_signature_string__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_dirent_by_path, - "seafile_get_dirent_by_path", - searpc_signature_object__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_file_revisions, - "seafile_list_file_revisions", - searpc_signature_objlist__string_string_int_int_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_calc_files_last_modified, - "seafile_calc_files_last_modified", - searpc_signature_objlist__string_string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_revert_file, - "seafile_revert_file", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_revert_dir, - "seafile_revert_dir", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_check_repo_blocks_missing, - "seafile_check_repo_blocks_missing", - searpc_signature_string__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_deleted, - "get_deleted", - searpc_signature_objlist__string_int_string_string_int()); - - /* share repo to user */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_add_share, - "seafile_add_share", - searpc_signature_int__string_string_string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_share_repos, - "seafile_list_share_repos", - searpc_signature_objlist__string_string_int_int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_repo_shared_to, - "seafile_list_repo_shared_to", - searpc_signature_objlist__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_remove_share, - "seafile_remove_share", - searpc_signature_int__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_share_permission, - "set_share_permission", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_share_subdir_to_user, - "share_subdir_to_user", - searpc_signature_int__string_string_string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_unshare_subdir_for_user, - "unshare_subdir_for_user", - searpc_signature_int__string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_update_share_subdir_perm_for_user, - "update_share_subdir_perm_for_user", - searpc_signature_int__string_string_string_string_string()); - - /* share repo to group */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_group_share_repo, - "seafile_group_share_repo", - searpc_signature_int__string_int_string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_group_unshare_repo, - "seafile_group_unshare_repo", - searpc_signature_int__string_int_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_shared_groups_by_repo, - "seafile_get_shared_groups_by_repo", - searpc_signature_string__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_share_subdir_to_group, - "share_subdir_to_group", - searpc_signature_int__string_string_string_int_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_unshare_subdir_for_group, - "unshare_subdir_for_group", - searpc_signature_int__string_string_string_int()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_update_share_subdir_perm_for_group, - "update_share_subdir_perm_for_group", - searpc_signature_int__string_string_string_int_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_group_repoids, - "seafile_get_group_repoids", - searpc_signature_string__int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_repo_shared_group, - "seafile_list_repo_shared_group", - searpc_signature_objlist__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_repos_by_group, - "seafile_get_repos_by_group", - searpc_signature_objlist__int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_group_repos_by_owner, - "get_group_repos_by_owner", - searpc_signature_objlist__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_group_repo_owner, - "get_group_repo_owner", - searpc_signature_string__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_remove_repo_group, - "seafile_remove_repo_group", - searpc_signature_int__int_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_group_repo_permission, - "set_group_repo_permission", - searpc_signature_int__int_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_shared_users_for_subdir, - "seafile_get_shared_users_for_subdir", - searpc_signature_objlist__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_shared_groups_for_subdir, - "seafile_get_shared_groups_for_subdir", - searpc_signature_objlist__string_string_string()); - - /* branch and commit */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_branch_gets, - "seafile_branch_gets", - searpc_signature_objlist__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_commit_list, - "seafile_get_commit_list", - searpc_signature_objlist__string_int_int()); - - /* token */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_generate_repo_token, - "seafile_generate_repo_token", - searpc_signature_string__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_delete_repo_token, - "seafile_delete_repo_token", - searpc_signature_int__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_repo_tokens, - "seafile_list_repo_tokens", - searpc_signature_objlist__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_repo_tokens_by_email, - "seafile_list_repo_tokens_by_email", - searpc_signature_objlist__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_delete_repo_tokens_by_peer_id, - "seafile_delete_repo_tokens_by_peer_id", - searpc_signature_int__string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_delete_repo_tokens_by_email, - "delete_repo_tokens_by_email", - searpc_signature_int__string()); - - /* quota */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_user_quota_usage, - "seafile_get_user_quota_usage", - searpc_signature_int64__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_user_share_usage, - "seafile_get_user_share_usage", - searpc_signature_int64__string()); - - /* virtual repo */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_create_virtual_repo, - "create_virtual_repo", - searpc_signature_string__string_string_string_string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_virtual_repos_by_owner, - "get_virtual_repos_by_owner", - searpc_signature_objlist__string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_virtual_repo, - "get_virtual_repo", - searpc_signature_object__string_string_string()); - - /* Clean trash */ - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_clean_up_repo_history, - "clean_up_repo_history", - searpc_signature_int__string_int()); - - /* -------- rpc services -------- */ - /* token for web access to repo */ - searpc_server_register_function ("seafserv-rpcserver", - seafile_web_get_access_token, - "seafile_web_get_access_token", - searpc_signature_string__string_string_string_string_int()); - searpc_server_register_function ("seafserv-rpcserver", - seafile_web_query_access_token, - "seafile_web_query_access_token", - searpc_signature_object__string()); - - searpc_server_register_function ("seafserv-rpcserver", - seafile_query_zip_progress, - "seafile_query_zip_progress", - searpc_signature_string__string()); - - /* Copy task related. */ - - searpc_server_register_function ("seafserv-rpcserver", - seafile_get_copy_task, - "get_copy_task", - searpc_signature_object__string()); - - searpc_server_register_function ("seafserv-rpcserver", - seafile_cancel_copy_task, - "cancel_copy_task", - searpc_signature_int__string()); - - /* chunk server manipulation */ - searpc_server_register_function ("seafserv-rpcserver", - seafile_add_chunk_server, - "seafile_add_chunk_server", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-rpcserver", - seafile_del_chunk_server, - "seafile_del_chunk_server", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-rpcserver", - seafile_list_chunk_servers, - "seafile_list_chunk_servers", - searpc_signature_string__void()); - - /* password management */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_check_passwd, - "seafile_check_passwd", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_passwd, - "seafile_set_passwd", - searpc_signature_int__string_string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_unset_passwd, - "seafile_unset_passwd", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-rpcserver", - seafile_is_passwd_set, - "seafile_is_passwd_set", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-rpcserver", - seafile_get_decrypt_key, - "seafile_get_decrypt_key", - searpc_signature_object__string_string()); - - /* quota management */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_user_quota, - "set_user_quota", - searpc_signature_int__string_int64()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_user_quota, - "get_user_quota", - searpc_signature_int64__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_check_quota, - "check_quota", - searpc_signature_int__string()); - - /* repo permission */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_check_permission, - "check_permission", - searpc_signature_string__string_string()); - - /* folder permission */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_check_permission_by_path, - "check_permission_by_path", - searpc_signature_string__string_string_string()); - - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_file_id_by_commit_and_path, - "seafile_get_file_id_by_commit_and_path", - searpc_signature_string__string_string_string()); - - if (!cloud_mode) { - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_inner_pub_repo, - "set_inner_pub_repo", - searpc_signature_int__string_string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_unset_inner_pub_repo, - "unset_inner_pub_repo", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_is_inner_pub_repo, - "is_inner_pub_repo", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_inner_pub_repos, - "list_inner_pub_repos", - searpc_signature_objlist__void()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_count_inner_pub_repos, - "count_inner_pub_repos", - searpc_signature_int64__void()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_list_inner_pub_repos_by_owner, - "list_inner_pub_repos_by_owner", - searpc_signature_objlist__string()); - } - - /* History */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_set_repo_history_limit, - "set_repo_history_limit", - searpc_signature_int__string_int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_repo_history_limit, - "get_repo_history_limit", - searpc_signature_int__string()); - - /* System default library */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_system_default_repo_id, - "get_system_default_repo_id", - searpc_signature_string__void()); - - /* Trashed repos. */ - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_trash_repo_list, - "get_trash_repo_list", - searpc_signature_objlist__int_int()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_del_repo_from_trash, - "del_repo_from_trash", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_restore_repo_from_trash, - "restore_repo_from_trash", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_get_trash_repos_by_owner, - "get_trash_repos_by_owner", - searpc_signature_objlist__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_empty_repo_trash, - "empty_repo_trash", - searpc_signature_int__void()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_empty_repo_trash_by_owner, - "empty_repo_trash_by_owner", - searpc_signature_int__string()); - searpc_server_register_function ("seafserv-threaded-rpcserver", - seafile_generate_magic_and_random_key, - "generate_magic_and_random_key", - searpc_signature_object__int_string_string()); -} - -static struct event sigusr1; - -static void sigusr1Handler (int fd, short event, void *user_data) -{ - seafile_log_reopen (); -} - -static void -set_signal_handlers (SeafileSession *session) -{ -#ifndef WIN32 - signal (SIGPIPE, SIG_IGN); - - /* design as reopen log */ - event_set(&sigusr1, SIGUSR1, EV_SIGNAL | EV_PERSIST, sigusr1Handler, NULL); - event_add(&sigusr1, NULL); -#endif -} - -static void -create_sync_rpc_clients (const char *central_config_dir, const char *config_dir) -{ - CcnetClient *sync_client; - - /* sync client and rpc client */ - sync_client = ccnet_client_new (); - if ( (ccnet_client_load_confdir(sync_client, central_config_dir, config_dir)) < 0 ) { - seaf_warning ("Read config dir error\n"); - exit(1); - } - - if (ccnet_client_connect_daemon (sync_client, CCNET_CLIENT_SYNC) < 0) - { - seaf_warning ("Connect to server fail: %s\n", strerror(errno)); - exit(1); - } - - ccnetrpc_client = ccnet_create_rpc_client (sync_client, NULL, "ccnet-rpcserver"); - ccnetrpc_client_t = ccnet_create_rpc_client (sync_client, - NULL, - "ccnet-threaded-rpcserver"); -} - -static void -create_async_rpc_clients (CcnetClient *client) -{ - async_ccnetrpc_client = ccnet_create_async_rpc_client ( - client, NULL, "ccnet-rpcserver"); - async_ccnetrpc_client_t = ccnet_create_async_rpc_client ( - client, NULL, "ccnet-threaded-rpcserver"); -} - -static void -remove_pidfile (const char *pidfile) -{ - if (pidfile) { - g_unlink (pidfile); - } -} - -static int -write_pidfile (const char *pidfile_path) -{ - if (!pidfile_path) - return -1; - - pid_t pid = getpid(); - - FILE *pidfile = g_fopen(pidfile_path, "w"); - if (!pidfile) { - seaf_warning ("Failed to fopen() pidfile %s: %s\n", - pidfile_path, strerror(errno)); - return -1; - } - - char buf[32]; - snprintf (buf, sizeof(buf), "%d\n", pid); - if (fputs(buf, pidfile) < 0) { - seaf_warning ("Failed to write pidfile %s: %s\n", - pidfile_path, strerror(errno)); - fclose (pidfile); - return -1; - } - - fflush (pidfile); - fclose (pidfile); - return 0; -} - -static void -load_history_config () -{ - int keep_history_days; - GError *error = NULL; - - seaf->keep_history_days = -1; - - keep_history_days = g_key_file_get_integer (seaf->config, - "history", "keep_days", - &error); - if (error == NULL) - seaf->keep_history_days = keep_history_days; - else - g_clear_error (&error); -} - -static void -on_seaf_server_exit(void) -{ - if (pidfile) - remove_pidfile (pidfile); -} - -#ifdef WIN32 -/* Get the commandline arguments in unicode, then convert them to utf8 */ -static char ** -get_argv_utf8 (int *argc) -{ - int i = 0; - char **argv = NULL; - const wchar_t *cmdline = NULL; - wchar_t **argv_w = NULL; - - cmdline = GetCommandLineW(); - argv_w = CommandLineToArgvW (cmdline, argc); - if (!argv_w) { - printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError()); - return NULL; - } - - argv = (char **)malloc (sizeof(char*) * (*argc)); - for (i = 0; i < *argc; i++) { - argv[i] = wchar_to_utf8 (argv_w[i]); - } - - return argv; -} -#endif - -int -main (int argc, char **argv) -{ - int c; - char *config_dir = DEFAULT_CONFIG_DIR; - char *seafile_dir = NULL; - char *central_config_dir = NULL; - char *logfile = NULL; - const char *debug_str = NULL; - int daemon_mode = 1; - int is_master = 0; - CcnetClient *client; - char *ccnet_debug_level_str = "info"; - char *seafile_debug_level_str = "debug"; - int cloud_mode = 0; - -#ifdef WIN32 - argv = get_argv_utf8 (&argc); -#endif - - while ((c = getopt_long (argc, argv, short_options, - long_options, NULL)) != EOF) - { - switch (c) { - case 'h': - exit (1); - break; - case 'v': - exit (1); - break; - case 'c': - config_dir = optarg; - break; - case 'd': - seafile_dir = g_strdup(optarg); - break; - case 'F': - central_config_dir = g_strdup(optarg); - break; - case 'f': - daemon_mode = 0; - break; - case 'l': - logfile = g_strdup(optarg); - break; - case 'D': - debug_str = optarg; - break; - case 'g': - ccnet_debug_level_str = optarg; - break; - case 'G': - seafile_debug_level_str = optarg; - break; - case 'm': - is_master = 1; - break; - case 'P': - pidfile = optarg; - break; - case 'C': - cloud_mode = 1; - break; - default: - usage (); - exit (1); - } - } - - argc -= optind; - argv += optind; - -#ifndef WIN32 - if (daemon_mode) { -#ifndef __APPLE__ - daemon (1, 0); -#else /* __APPLE */ - /* daemon is deprecated under APPLE - * use fork() instead - * */ - switch (fork ()) { - case -1: - seaf_warning ("Failed to daemonize"); - exit (-1); - break; - case 0: - /* all good*/ - break; - default: - /* kill origin process */ - exit (0); - } -#endif /* __APPLE */ - } -#endif /* !WIN32 */ - - cdc_init (); - -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif -#if !GLIB_CHECK_VERSION(2,32,0) - g_thread_init (NULL); -#endif - - if (!debug_str) - debug_str = g_getenv("SEAFILE_DEBUG"); - seafile_debug_set_flags_string (debug_str); - - if (seafile_dir == NULL) - seafile_dir = g_build_filename (config_dir, "seafile", NULL); - if (logfile == NULL) - logfile = g_build_filename (seafile_dir, "seafile.log", NULL); - - if (seafile_log_init (logfile, ccnet_debug_level_str, - seafile_debug_level_str) < 0) { - seaf_warning ("Failed to init log.\n"); - exit (1); - } - - client = ccnet_init (central_config_dir, config_dir); - if (!client) - exit (1); - - register_processors (client); - - start_rpc_service (client, cloud_mode); - - create_sync_rpc_clients (central_config_dir, config_dir); - create_async_rpc_clients (client); - - seaf = seafile_session_new (central_config_dir, seafile_dir, client); - if (!seaf) { - seaf_warning ("Failed to create seafile session.\n"); - exit (1); - } - seaf->is_master = is_master; - seaf->ccnetrpc_client = ccnetrpc_client; - seaf->async_ccnetrpc_client = async_ccnetrpc_client; - seaf->ccnetrpc_client_t = ccnetrpc_client_t; - seaf->async_ccnetrpc_client_t = async_ccnetrpc_client_t; - seaf->client_pool = ccnet_client_pool_new (central_config_dir, config_dir); - seaf->cloud_mode = cloud_mode; - - load_history_config (); - -#ifndef WIN32 - set_syslog_config (seaf->config); -#endif - - g_free (seafile_dir); - g_free (logfile); - - set_signal_handlers (seaf); - - /* Create pid file before connecting to database. - * Connecting to database and creating tables may take long if the db - * is on a remote host. This may make controller think seaf-server fails - * to start and restart it. - */ - if (pidfile) { - if (write_pidfile (pidfile) < 0) { - ccnet_message ("Failed to write pidfile\n"); - return -1; - } - } - - /* init seaf */ - if (seafile_session_init (seaf) < 0) - exit (1); - - if (seafile_session_start (seaf) < 0) - exit (1); - - atexit (on_seaf_server_exit); - - /* Create a system default repo to contain the tutorial file. */ - schedule_create_system_default_repo (seaf); - - ccnet_main (client); - - return 0; -} diff --git a/server/seafile-session.c b/server/seafile-session.c deleted file mode 100644 index 9b1afb8d..00000000 --- a/server/seafile-session.c +++ /dev/null @@ -1,425 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include "utils.h" - -#include "seafile-session.h" - -#include "seaf-db.h" -#include "seaf-utils.h" - -#include "log.h" - -#define CONNECT_INTERVAL_MSEC 10 * 1000 - -#define DEFAULT_THREAD_POOL_SIZE 500 -#define DEFAULT_RPC_THREAD_POOL_SIZE 50 - -static int -load_thread_pool_config (SeafileSession *session); - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - CcnetClient *ccnet_session) -{ - char *abs_central_config_dir = NULL; - char *abs_seafile_dir; - char *tmp_file_dir; - char *config_file_path; - GKeyFile *config; - SeafileSession *session = NULL; - - if (!ccnet_session) - return NULL; - - abs_seafile_dir = ccnet_expand_path (seafile_dir); - tmp_file_dir = g_build_filename (abs_seafile_dir, "tmpfiles", NULL); - if (central_config_dir) { - abs_central_config_dir = ccnet_expand_path (central_config_dir); - } - config_file_path = g_build_filename( - abs_central_config_dir ? abs_central_config_dir : abs_seafile_dir, - "seafile.conf", NULL); - - if (checkdir_with_mkdir (abs_seafile_dir) < 0) { - seaf_warning ("Config dir %s does not exist and is unable to create\n", - abs_seafile_dir); - goto onerror; - } - - if (checkdir_with_mkdir (tmp_file_dir) < 0) { - seaf_warning ("Temp file dir %s does not exist and is unable to create\n", - tmp_file_dir); - goto onerror; - } - - GError *error = NULL; - config = g_key_file_new (); - if (!g_key_file_load_from_file (config, config_file_path, - G_KEY_FILE_NONE, &error)) { - seaf_warning ("Failed to load config file.\n"); - g_key_file_free (config); - goto onerror; - } - g_free (config_file_path); - - session = g_new0(SeafileSession, 1); - session->seaf_dir = abs_seafile_dir; - session->tmp_file_dir = tmp_file_dir; - session->session = ccnet_session; - session->config = config; - - if (load_database_config (session) < 0) { - seaf_warning ("Failed to load database config.\n"); - goto onerror; - } - - if (load_thread_pool_config (session) < 0) { - seaf_warning ("Failed to load thread pool config.\n"); - goto onerror; - } - - session->fs_mgr = seaf_fs_manager_new (session, abs_seafile_dir); - if (!session->fs_mgr) - goto onerror; - session->block_mgr = seaf_block_manager_new (session, abs_seafile_dir); - if (!session->block_mgr) - goto onerror; - session->commit_mgr = seaf_commit_manager_new (session); - if (!session->commit_mgr) - goto onerror; - session->repo_mgr = seaf_repo_manager_new (session); - if (!session->repo_mgr) - goto onerror; - session->branch_mgr = seaf_branch_manager_new (session); - if (!session->branch_mgr) - goto onerror; - - session->cs_mgr = seaf_cs_manager_new (session); - if (!session->cs_mgr) - goto onerror; - - session->share_mgr = seaf_share_manager_new (session); - if (!session->share_mgr) - goto onerror; - - session->web_at_mgr = seaf_web_at_manager_new (session); - if (!session->web_at_mgr) - goto onerror; - - session->token_mgr = seaf_token_manager_new (session); - if (!session->token_mgr) - goto onerror; - - session->passwd_mgr = seaf_passwd_manager_new (session); - if (!session->passwd_mgr) - goto onerror; - - session->quota_mgr = seaf_quota_manager_new (session); - if (!session->quota_mgr) - goto onerror; - - session->listen_mgr = seaf_listen_manager_new (session); - if (!session->listen_mgr) - goto onerror; - - session->copy_mgr = seaf_copy_manager_new (session); - if (!session->copy_mgr) - goto onerror; - - session->job_mgr = ccnet_job_manager_new (session->sync_thread_pool_size); - ccnet_session->job_mgr = ccnet_job_manager_new (session->rpc_thread_pool_size); - - session->size_sched = size_scheduler_new (session); - - session->ev_mgr = cevent_manager_new (); - if (!session->ev_mgr) - goto onerror; - - session->mq_mgr = seaf_mq_manager_new (session); - if (!session->mq_mgr) - goto onerror; - - session->http_server = seaf_http_server_new (session); - if (!session->http_server) - goto onerror; - - session->zip_download_mgr = zip_download_mgr_new (); - if (!session->zip_download_mgr) - goto onerror; - - return session; - -onerror: - free (abs_seafile_dir); - g_free (tmp_file_dir); - g_free (config_file_path); - g_free (session); - return NULL; -} - -int -seafile_session_init (SeafileSession *session) -{ - if (seaf_commit_manager_init (session->commit_mgr) < 0) - return -1; - - if (seaf_fs_manager_init (session->fs_mgr) < 0) - return -1; - - if (seaf_branch_manager_init (session->branch_mgr) < 0) - return -1; - - if (seaf_repo_manager_init (session->repo_mgr) < 0) - return -1; - - if (seaf_quota_manager_init (session->quota_mgr) < 0) - return -1; - - seaf_mq_manager_init (session->mq_mgr); - seaf_mq_manager_set_heartbeat_name (session->mq_mgr, - "seaf_server.heartbeat"); - - return 0; -} - -int -seafile_session_start (SeafileSession *session) -{ - if (cevent_manager_start (session->ev_mgr) < 0) { - seaf_warning ("Failed to start event manager.\n"); - return -1; - } - - if (seaf_cs_manager_start (session->cs_mgr) < 0) { - seaf_warning ("Failed to start chunk server manager.\n"); - return -1; - } - - if (seaf_share_manager_start (session->share_mgr) < 0) { - seaf_warning ("Failed to start share manager.\n"); - return -1; - } - - if (seaf_web_at_manager_start (session->web_at_mgr) < 0) { - seaf_warning ("Failed to start web access check manager.\n"); - return -1; - } - - if (seaf_passwd_manager_start (session->passwd_mgr) < 0) { - seaf_warning ("Failed to start password manager.\n"); - return -1; - } - - if (seaf_mq_manager_start (session->mq_mgr) < 0) { - seaf_warning ("Failed to start mq manager.\n"); - return -1; - } - - if (seaf_listen_manager_start (session->listen_mgr) < 0) { - seaf_warning ("Failed to start listen manager.\n"); - return -1; - } - - if (size_scheduler_start (session->size_sched) < 0) { - seaf_warning ("Failed to start size scheduler.\n"); - return -1; - } - - if (seaf_copy_manager_start (session->copy_mgr) < 0) { - seaf_warning ("Failed to start copy manager.\n"); - return -1; - } - - if (seaf_http_server_start (session->http_server) < 0) { - seaf_warning ("Failed to start http server thread.\n"); - return -1; - } - - return 0; -} - -static int -load_thread_pool_config (SeafileSession *session) -{ - int rpc_tp_size, sync_tp_size; - - rpc_tp_size = g_key_file_get_integer (session->config, - "thread pool size", "rpc", - NULL); - sync_tp_size = g_key_file_get_integer (session->config, - "thread pool size", "sync", - NULL); - - if (rpc_tp_size > 0) - session->rpc_thread_pool_size = rpc_tp_size; - else - session->rpc_thread_pool_size = DEFAULT_RPC_THREAD_POOL_SIZE; - - if (sync_tp_size > 0) - session->sync_thread_pool_size = sync_tp_size; - else - session->sync_thread_pool_size = DEFAULT_THREAD_POOL_SIZE; - - return 0; -} - -char * -get_system_default_repo_id (SeafileSession *session) -{ - char *sql = "SELECT info_value FROM SystemInfo WHERE info_key='default_repo_id'"; - return seaf_db_get_string (session->db, sql); -} - -int -set_system_default_repo_id (SeafileSession *session, const char *repo_id) -{ - char sql[256]; - snprintf (sql, sizeof(sql), - "INSERT INTO SystemInfo VALUES ('default_repo_id', '%s')", - repo_id); - return seaf_db_query (session->db, sql); -} - -static int -del_system_default_repo_id (SeafileSession *session) -{ - const char *sql = "DELETE FROM SystemInfo WHERE info_key='default_repo_id'"; - return seaf_db_query (session->db, sql); -} - -#define DEFAULT_TEMPLATE_DIR "library-template" - -static void -copy_template_files_recursive (SeafileSession *session, - const char *repo_id, - const char *repo_dir_path, - const char *dir_path) -{ - GDir *dir; - const char *name; - char *sub_path, *repo_sub_path; - SeafStat st; - GError *error = NULL; - int rc; - - dir = g_dir_open (dir_path, 0, &error); - if (!dir) { - seaf_warning ("Failed to open template dir %s: %s.\n", - dir_path, error->message); - return; - } - - while ((name = g_dir_read_name(dir)) != NULL) { - sub_path = g_build_filename (dir_path, name, NULL); - if (seaf_stat (sub_path, &st) < 0) { - seaf_warning ("Failed to stat %s: %s.\n", sub_path, strerror(errno)); - g_free (sub_path); - continue; - } - - if (S_ISREG(st.st_mode)) { - rc = seaf_repo_manager_post_file (session->repo_mgr, - repo_id, - sub_path, - repo_dir_path, - name, - "System", - NULL); - if (rc < 0) - seaf_warning ("Failed to add template file %s.\n", sub_path); - } else if (S_ISDIR(st.st_mode)) { - rc = seaf_repo_manager_post_dir (session->repo_mgr, - repo_id, - repo_dir_path, - name, - "System", - NULL); - if (rc < 0) { - seaf_warning ("Failed to add template dir %s.\n", sub_path); - g_free (sub_path); - continue; - } - - repo_sub_path = g_build_path ("/", repo_dir_path, name, NULL); - copy_template_files_recursive (session, repo_id, - repo_sub_path, sub_path); - g_free (repo_sub_path); - } - g_free (sub_path); - } -} - -static void * -create_system_default_repo (void *data) -{ - SeafileSession *session = data; - char *repo_id; - char *template_path; - - /* If default repo is not set or doesn't exist, create a new one. */ - repo_id = get_system_default_repo_id (session); - if (repo_id != NULL) { - SeafRepo *repo; - repo = seaf_repo_manager_get_repo (session->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Failed to get system default repo. Create a new one.\n"); - del_system_default_repo_id (session); - seaf_repo_manager_del_repo (session->repo_mgr, repo_id, NULL); - g_free (repo_id); - } else { - seaf_repo_unref (repo); - g_free (repo_id); - return data; - } - } - - repo_id = seaf_repo_manager_create_new_repo (session->repo_mgr, - "My Library Template", - "Template for creating 'My Libray' for users", - "System", - NULL, NULL); - if (!repo_id) { - seaf_warning ("Failed to create system default repo.\n"); - return data; - } - - set_system_default_repo_id (session, repo_id); - - template_path = g_build_filename (session->seaf_dir, DEFAULT_TEMPLATE_DIR, NULL); - copy_template_files_recursive (session, repo_id, "/", template_path); - - g_free (repo_id); - g_free (template_path); - return data; -} - -void -schedule_create_system_default_repo (SeafileSession *session) -{ - char *sql = "CREATE TABLE IF NOT EXISTS SystemInfo " - "(info_key VARCHAR(256), info_value VARCHAR(1024))"; - if (seaf_db_query (session->db, sql) < 0) - return; - - ccnet_job_manager_schedule_job (session->job_mgr, - create_system_default_repo, - NULL, session); -} diff --git a/server/seafile-session.h b/server/seafile-session.h deleted file mode 100644 index e6ef12f1..00000000 --- a/server/seafile-session.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAFILE_SESSION_H -#define SEAFILE_SESSION_H - -#include -#include -#include - -#include "block-mgr.h" -#include "fs-mgr.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "db.h" -#include "seaf-db.h" - -#include "chunkserv-mgr.h" -#include "share-mgr.h" -#include "token-mgr.h" -#include "web-accesstoken-mgr.h" -#include "passwd-mgr.h" -#include "quota-mgr.h" -#include "listen-mgr.h" -#include "size-sched.h" -#include "copy-mgr.h" - -#include "mq-mgr.h" - -#include "http-server.h" -#include "zip-download-mgr.h" - -#include - -struct _CcnetClient; - -typedef struct _SeafileSession SeafileSession; - - -struct _SeafileSession { - struct _CcnetClient *session; - - SearpcClient *ccnetrpc_client; - SearpcClient *ccnetrpc_client_t; - /* Use async rpc client on server. */ - SearpcClient *async_ccnetrpc_client; - SearpcClient *async_ccnetrpc_client_t; - - /* Used in threads. */ - CcnetClientPool *client_pool; - - char *central_config_dir; - char *seaf_dir; - char *tmp_file_dir; - /* Config that's only loaded on start */ - GKeyFile *config; - SeafDB *db; - - SeafBlockManager *block_mgr; - SeafFSManager *fs_mgr; - SeafCommitManager *commit_mgr; - SeafBranchManager *branch_mgr; - SeafRepoManager *repo_mgr; - SeafCSManager *cs_mgr; - SeafShareManager *share_mgr; - SeafTokenManager *token_mgr; - SeafPasswdManager *passwd_mgr; - SeafQuotaManager *quota_mgr; - SeafListenManager *listen_mgr; - SeafCopyManager *copy_mgr; - - SeafWebAccessTokenManager *web_at_mgr; - - SeafMqManager *mq_mgr; - - CEventManager *ev_mgr; - CcnetJobManager *job_mgr; - - SizeScheduler *size_sched; - - int is_master; - - int cloud_mode; - int keep_history_days; - - int rpc_thread_pool_size; - int sync_thread_pool_size; - - HttpServerStruct *http_server; - ZipDownloadMgr *zip_download_mgr; -}; - -extern SeafileSession *seaf; - -SeafileSession * -seafile_session_new(const char *central_config_dir, - const char *seafile_dir, - struct _CcnetClient *ccnet_session); -int -seafile_session_init (SeafileSession *session); - -int -seafile_session_start (SeafileSession *session); - -char * -seafile_session_get_tmp_file_path (SeafileSession *session, - const char *basename, - char path[]); - -void -schedule_create_system_default_repo (SeafileSession *session); - -char * -get_system_default_repo_id (SeafileSession *session); - -int -set_system_default_repo_id (SeafileSession *session, const char *repo_id); - -#endif /* SEAFILE_H */ diff --git a/server/share-mgr.c b/server/share-mgr.c deleted file mode 100644 index f88f45b8..00000000 --- a/server/share-mgr.c +++ /dev/null @@ -1,526 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" -#include "utils.h" - -#include "log.h" - -#include "seafile-session.h" -#include "share-mgr.h" - -#include "seaf-db.h" -#include "log.h" -#include "seafile-error.h" - -SeafShareManager * -seaf_share_manager_new (SeafileSession *seaf) -{ - SeafShareManager *mgr = g_new0 (SeafShareManager, 1); - - mgr->seaf = seaf; - - return mgr; -} - -int -seaf_share_manager_start (SeafShareManager *mgr) -{ - SeafDB *db = mgr->seaf->db; - const char *sql; - - int db_type = seaf_db_type (db); - if (db_type == SEAF_DB_TYPE_MYSQL) { - sql = "CREATE TABLE IF NOT EXISTS SharedRepo " - "(id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT," - "repo_id CHAR(37) , from_email VARCHAR(255), to_email VARCHAR(255), " - "permission CHAR(15), INDEX (repo_id), " - "INDEX(from_email), INDEX(to_email)) ENGINE=INNODB"; - - if (seaf_db_query (db, sql) < 0) - return -1; - } else if (db_type == SEAF_DB_TYPE_SQLITE) { - sql = "CREATE TABLE IF NOT EXISTS SharedRepo " - "(repo_id CHAR(37) , from_email VARCHAR(255), to_email VARCHAR(255), " - "permission CHAR(15))"; - if (seaf_db_query (db, sql) < 0) - return -1; - sql = "CREATE INDEX IF NOT EXISTS RepoIdIndex on SharedRepo (repo_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - sql = "CREATE INDEX IF NOT EXISTS FromEmailIndex on SharedRepo (from_email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - sql = "CREATE INDEX IF NOT EXISTS ToEmailIndex on SharedRepo (to_email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } else if (db_type == SEAF_DB_TYPE_PGSQL) { - sql = "CREATE TABLE IF NOT EXISTS SharedRepo " - "(repo_id CHAR(36) , from_email VARCHAR(255), to_email VARCHAR(255), " - "permission VARCHAR(15))"; - if (seaf_db_query (db, sql) < 0) - return -1; - - if (!pgsql_index_exists (db, "sharedrepo_repoid_idx")) { - sql = "CREATE INDEX sharedrepo_repoid_idx ON SharedRepo (repo_id)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - if (!pgsql_index_exists (db, "sharedrepo_from_email_idx")) { - sql = "CREATE INDEX sharedrepo_from_email_idx ON SharedRepo (from_email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - if (!pgsql_index_exists (db, "sharedrepo_to_email_idx")) { - sql = "CREATE INDEX sharedrepo_to_email_idx ON SharedRepo (to_email)"; - if (seaf_db_query (db, sql) < 0) - return -1; - } - } - - return 0; -} - -int -seaf_share_manager_add_share (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email, - const char *permission) -{ - gboolean db_err = FALSE; - int ret = 0; - - char *from_email_l = g_ascii_strdown (from_email, -1); - char *to_email_l = g_ascii_strdown (to_email, -1); - - if (seaf_db_statement_exists (mgr->seaf->db, - "SELECT repo_id from SharedRepo " - "WHERE repo_id=? AND " - "from_email=? AND to_email=?", - &db_err, 3, "string", repo_id, - "string", from_email_l, "string", to_email_l)) - goto out; - - if (seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO SharedRepo (repo_id, from_email, " - "to_email, permission) VALUES (?, ?, ?, ?)", - 4, "string", repo_id, "string", from_email_l, - "string", to_email_l, "string", permission) < 0) { - ret = -1; - goto out; - } - -out: - g_free (from_email_l); - g_free (to_email_l); - return ret; -} - -int -seaf_share_manager_set_permission (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email, - const char *permission) -{ - char *sql; - int ret; - - char *from_email_l = g_ascii_strdown (from_email, -1); - char *to_email_l = g_ascii_strdown (to_email, -1); - sql = "UPDATE SharedRepo SET permission=? WHERE " - "repo_id=? AND from_email=? AND to_email=?"; - - ret = seaf_db_statement_query (mgr->seaf->db, sql, - 4, "string", permission, "string", repo_id, - "string", from_email_l, "string", to_email_l); - - g_free (from_email_l); - g_free (to_email_l); - return ret; -} - -static gboolean -collect_repos (SeafDBRow *row, void *data) -{ - GList **p_repos = data; - const char *repo_id; - const char *vrepo_id; - const char *email; - const char *permission; - const char *commit_id; - gint64 size; - SeafileRepo *repo; - - repo_id = seaf_db_row_get_column_text (row, 0); - vrepo_id = seaf_db_row_get_column_text (row, 1); - email = seaf_db_row_get_column_text (row, 2); - permission = seaf_db_row_get_column_text (row, 3); - commit_id = seaf_db_row_get_column_text (row, 4); - size = seaf_db_row_get_column_int64 (row, 5); - - char *email_l = g_ascii_strdown (email, -1); - - repo = g_object_new (SEAFILE_TYPE_REPO, - "share_type", "personal", - "repo_id", repo_id, - "id", repo_id, - "head_cmmt_id", commit_id, - "user", email_l, - "permission", permission, - "is_virtual", (vrepo_id != NULL), - "size", size, - NULL); - g_free (email_l); - - if (repo) { - if (vrepo_id) { - const char *origin_repo_id = seaf_db_row_get_column_text (row, 6); - const char *origin_path = seaf_db_row_get_column_text (row, 7); - g_object_set (repo, "store_id", origin_repo_id, - "origin_repo_id", origin_repo_id, - "origin_path", origin_path, NULL); - } else { - g_object_set (repo, "store_id", repo_id, NULL); - } - *p_repos = g_list_prepend (*p_repos, repo); - } - - return TRUE; -} - -GList* -seaf_share_manager_list_share_repos (SeafShareManager *mgr, const char *email, - const char *type, int start, int limit) -{ - GList *ret = NULL, *p; - char *sql; - - if (start == -1 && limit == -1) { - if (g_strcmp0 (type, "from_email") == 0) { - sql = "SELECT SharedRepo.repo_id, VirtualRepo.repo_id, " - "to_email, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path FROM " - "SharedRepo LEFT JOIN VirtualRepo ON " - "SharedRepo.repo_id=VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON SharedRepo.repo_id = s.repo_id, Branch " - "WHERE from_email=? AND " - "SharedRepo.repo_id = Branch.repo_id AND " - "Branch.name = 'master'"; - } else if (g_strcmp0 (type, "to_email") == 0) { - sql = "SELECT SharedRepo.repo_id, VirtualRepo.repo_id, " - "from_email, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path FROM " - "SharedRepo LEFT JOIN VirtualRepo on SharedRepo.repo_id = VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON SharedRepo.repo_id = s.repo_id, Branch " - "WHERE to_email=? AND " - "SharedRepo.repo_id = Branch.repo_id AND " - "Branch.name = 'master'"; - } else { - /* should never reach here */ - seaf_warning ("[share mgr] Wrong column type"); - return NULL; - } - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repos, &ret, - 1, "string", email) < 0) { - seaf_warning ("[share mgr] DB error when get shared repo id and email " - "for %s.\n", email); - for (p = ret; p; p = p->next) - g_object_unref (p->data); - g_list_free (ret); - return NULL; - } - } - else { - if (g_strcmp0 (type, "from_email") == 0) { - sql = "SELECT SharedRepo.repo_id, VirtualRepo.repo_id, " - "to_email, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path FROM " - "SharedRepo LEFT JOIN VirtualRepo ON " - "SharedRepo.repo_id=VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON SharedRepo.repo_id = s.repo_id, Branch " - "WHERE from_email=? " - "AND SharedRepo.repo_id = Branch.repo_id " - "AND Branch.name = 'master' " - "ORDER BY SharedRepo.repo_id " - "LIMIT ? OFFSET ?"; - } else if (g_strcmp0 (type, "to_email") == 0) { - sql = "SELECT SharedRepo.repo_id, VirtualRepo.repo_id, " - "from_email, permission, commit_id, s.size, " - "VirtualRepo.origin_repo, VirtualRepo.path FROM " - "SharedRepo LEFT JOIN VirtualRepo on SharedRepo.repo_id = VirtualRepo.repo_id " - "LEFT JOIN RepoSize s ON SharedRepo.repo_id = s.repo_id, " - "Branch WHERE to_email=? " - "AND SharedRepo.repo_id = Branch.repo_id " - "AND Branch.name = 'master' " - "ORDER BY SharedRepo.repo_id " - "LIMIT ? OFFSET ?"; - } else { - /* should never reach here */ - seaf_warning ("[share mgr] Wrong column type"); - return NULL; - } - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repos, &ret, - 3, "string", email, - "int", limit, "int", start) < 0) { - seaf_warning ("[share mgr] DB error when get shared repo id and email " - "for %s.\n", email); - for (p = ret; p; p = p->next) - g_object_unref (p->data); - g_list_free (ret); - return NULL; - } - } - - seaf_fill_repo_obj_from_commit (&ret); - - return g_list_reverse (ret); -} - -static gboolean -collect_shared_to (SeafDBRow *row, void *data) -{ - GList **plist = data; - const char *to_email; - - to_email = seaf_db_row_get_column_text (row, 0); - *plist = g_list_prepend (*plist, g_ascii_strdown(to_email, -1)); - - return TRUE; -} - -GList * -seaf_share_manager_list_shared_to (SeafShareManager *mgr, - const char *owner, - const char *repo_id) -{ - char *sql; - GList *ret = NULL; - - sql = "SELECT to_email FROM SharedRepo WHERE " - "from_email=? AND repo_id=?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_shared_to, &ret, - 2, "string", owner, "string", repo_id) < 0) { - seaf_warning ("[share mgr] DB error when list shared to.\n"); - string_list_free (ret); - return NULL; - } - - return ret; -} - -static gboolean -collect_repo_shared_to (SeafDBRow *row, void *data) -{ - GList **shared_to = data; - const char *to_email = seaf_db_row_get_column_text (row, 0); - char *email_down = g_ascii_strdown(to_email, -1); - const char *perm = seaf_db_row_get_column_text (row, 1); - const char *repo_id = seaf_db_row_get_column_text (row, 2); - - SeafileSharedUser *uobj = g_object_new (SEAFILE_TYPE_SHARED_USER, - "repo_id", repo_id, - "user", email_down, - "perm", perm, - NULL); - *shared_to = g_list_prepend (*shared_to, uobj); - g_free (email_down); - - return TRUE; -} - -GList * -seaf_share_manager_list_repo_shared_to (SeafShareManager *mgr, - const char *from_email, - const char *repo_id, - GError **error) -{ - GList *shared_to = NULL; - char *sql = "SELECT to_email, permission, repo_id FROM SharedRepo WHERE " - "from_email=? AND repo_id=?"; - - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_shared_to, &shared_to, - 2, "string", from_email, "string", repo_id); - if (ret < 0) { - seaf_warning ("Failed to list repo %s shared to from db.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to list repo shared to from db"); - while (shared_to) { - g_object_unref (shared_to->data); - shared_to = g_list_delete_link (shared_to, shared_to); - } - return NULL; - } - - return shared_to; -} - -static gboolean -collect_repo_shared_group (SeafDBRow *row, void *data) -{ - GList **shared_group = data; - int group_id = seaf_db_row_get_column_int (row, 0); - const char *perm = seaf_db_row_get_column_text (row, 1); - const char *repo_id = seaf_db_row_get_column_text (row, 2); - - SeafileSharedGroup *gobj = g_object_new (SEAFILE_TYPE_SHARED_GROUP, - "repo_id", repo_id, - "group_id", group_id, - "perm", perm, - NULL); - *shared_group = g_list_prepend (*shared_group, gobj); - - return TRUE; -} - -GList * -seaf_share_manager_list_repo_shared_group (SeafShareManager *mgr, - const char *from_email, - const char *repo_id, - GError **error) -{ - GList *shared_group = NULL; - char *sql = "SELECT group_id, permission, repo_id FROM RepoGroup WHERE " - "user_name=? AND repo_id=?"; - - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_repo_shared_group, &shared_group, - 2, "string", from_email, "string", repo_id); - if (ret < 0) { - seaf_warning ("Failed to list repo %s shared group from db.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to list repo shared group from db"); - while (shared_group) { - g_object_unref (shared_group->data); - shared_group = g_list_delete_link (shared_group, shared_group); - } - return NULL; - } - - return shared_group; -} - -int -seaf_share_manager_remove_share (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email) -{ - if (seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM SharedRepo WHERE repo_id = ? AND from_email =" - " ? AND to_email = ?", - 3, "string", repo_id, "string", from_email, - "string", to_email) < 0) - return -1; - - return 0; -} - -int -seaf_share_manager_remove_repo (SeafShareManager *mgr, const char *repo_id) -{ - if (seaf_db_statement_query (mgr->seaf->db, - "DELETE FROM SharedRepo WHERE repo_id = ?", - 1, "string", repo_id) < 0) - return -1; - - return 0; -} - -char * -seaf_share_manager_check_permission (SeafShareManager *mgr, - const char *repo_id, - const char *email) -{ - char *sql; - - sql = "SELECT permission FROM SharedRepo WHERE repo_id=? AND to_email=?"; - return seaf_db_statement_get_string (mgr->seaf->db, sql, - 2, "string", repo_id, "string", email); -} - -static gboolean -get_shared_sub_dirs (SeafDBRow *row, void *data) -{ - GHashTable *sub_dirs = data; - int dummy; - - const char *sub_dir = seaf_db_row_get_column_text (row, 0); - g_hash_table_replace (sub_dirs, g_strdup(sub_dir), &dummy); - - return TRUE; -} - -GHashTable * -seaf_share_manager_get_shared_sub_dirs (SeafShareManager *mgr, - const char *repo_id, - const char *path) -{ - GHashTable *sub_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - char *pattern; - if (strcmp (path, "/") == 0) { - pattern = g_strdup_printf("%s%%", path); - } else { - pattern = g_strdup_printf ("%s/%%", path); - } - int ret = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT v.path FROM VirtualRepo v, SharedRepo s " - "WHERE v.repo_id = s.repo_id and " - "v.origin_repo = ? AND v.path LIKE ?", - get_shared_sub_dirs, sub_dirs, - 2, "string", repo_id, "string", pattern); - - if (ret < 0) { - g_free (pattern); - seaf_warning ("Failed to get shared sub dirs from db.\n"); - g_hash_table_destroy (sub_dirs); - return NULL; - } - - ret = seaf_db_statement_foreach_row (mgr->seaf->db, - "SELECT v.path FROM VirtualRepo v, RepoGroup r " - "WHERE v.repo_id = r.repo_id and " - "v.origin_repo = ? AND v.path LIKE ?", - get_shared_sub_dirs, sub_dirs, - 2, "string", repo_id, "string", pattern); - g_free (pattern); - - if (ret < 0) { - seaf_warning ("Failed to get shared sub dirs from db.\n"); - g_hash_table_destroy (sub_dirs); - return NULL; - } - - return sub_dirs; -} - -int -seaf_share_manager_is_repo_shared (SeafShareManager *mgr, - const char *repo_id) -{ - gboolean ret; - gboolean db_err = FALSE; - - ret = seaf_db_statement_exists (mgr->seaf->db, - "SELECT repo_id FROM SharedRepo WHERE " - "repo_id = ?", &db_err, - 1, "string", repo_id); - if (db_err) { - seaf_warning ("DB error when check repo exist in SharedRepo.\n"); - return -1; - } - - if (!ret) { - ret = seaf_db_statement_exists (mgr->seaf->db, - "SELECT repo_id FROM RepoGroup WHERE " - "repo_id = ?", &db_err, - 1, "string", repo_id); - if (db_err) { - seaf_warning ("DB error when check repo exist in RepoGroup.\n"); - return -1; - } - } - - return ret; -} diff --git a/server/share-mgr.h b/server/share-mgr.h deleted file mode 100644 index bd2850f6..00000000 --- a/server/share-mgr.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SHARE_MGR_H -#define SHARE_MGR_H - -#include - -struct _SeafileSession; - -typedef struct _SeafShareManager SeafShareManager; -typedef struct _SeafShareManagerPriv SeafShareManagerPriv; -typedef struct _ShareRepoInfo ShareRepoInfo; - -struct _SeafShareManager { - struct _SeafileSession *seaf; - -}; - -SeafShareManager* -seaf_share_manager_new (struct _SeafileSession *seaf); - -int -seaf_share_manager_start (SeafShareManager *mgr); - -int -seaf_share_manager_add_share (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email, - const char *permission); - -int -seaf_share_manager_set_permission (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email, - const char *permission); - -GList* -seaf_share_manager_list_share_repos (SeafShareManager *mgr, const char *email, - const char *type, int start, int limit); - -GList * -seaf_share_manager_list_shared_to (SeafShareManager *mgr, - const char *owner, - const char *repo_id); - -GList * -seaf_share_manager_list_repo_shared_to (SeafShareManager *mgr, - const char *owner, - const char *repo_id, - GError **error); - -GList * -seaf_share_manager_list_repo_shared_group (SeafShareManager *mgr, - const char *from_email, - const char *repo_id, - GError **error); - -int -seaf_share_manager_remove_share (SeafShareManager *mgr, const char *repo_id, - const char *from_email, const char *to_email); - -/* Remove all share info of a repo. */ -int -seaf_share_manager_remove_repo (SeafShareManager *mgr, const char *repo_id); - -char * -seaf_share_manager_check_permission (SeafShareManager *mgr, - const char *repo_id, - const char *email); - -GHashTable * -seaf_share_manager_get_shared_sub_dirs (SeafShareManager *mgr, - const char *repo_id, - const char *path); - -int -seaf_share_manager_is_repo_shared (SeafShareManager *mgr, - const char *repo_id); - -#endif /* SHARE_MGR_H */ - diff --git a/server/size-sched.c b/server/size-sched.c deleted file mode 100644 index f6f21e40..00000000 --- a/server/size-sched.c +++ /dev/null @@ -1,309 +0,0 @@ -#include "common.h" - -#include -#include - -#include "seafile-session.h" -#include "size-sched.h" - -#include "log.h" - -typedef struct SizeSchedulerPriv { - pthread_mutex_t q_lock; - GQueue *repo_size_job_queue; - int n_running_repo_size_jobs; - - CcnetTimer *sched_timer; -} SizeSchedulerPriv; - -typedef struct RepoSizeJob { - SizeScheduler *sched; - char repo_id[37]; -} RepoSizeJob; - -#define SCHEDULER_INTV 1000 /* 1s */ -#define CONCURRENT_JOBS 1 - -static int -schedule_pulse (void *vscheduler); -static void* -compute_repo_size (void *vjob); -static void -compute_repo_size_done (void *vjob); - -SizeScheduler * -size_scheduler_new (SeafileSession *session) -{ - SizeScheduler *sched = g_new0 (SizeScheduler, 1); - - if (!sched) - return NULL; - - sched->priv = g_new0 (SizeSchedulerPriv, 1); - if (!sched->priv) { - g_free (sched); - return NULL; - } - - sched->seaf = session; - - pthread_mutex_init (&sched->priv->q_lock, NULL); - - sched->priv->repo_size_job_queue = g_queue_new (); - - return sched; -} - -int -size_scheduler_start (SizeScheduler *scheduler) -{ - scheduler->priv->sched_timer = ccnet_timer_new (schedule_pulse, - scheduler, - SCHEDULER_INTV); - - return 0; -} - -void -schedule_repo_size_computation (SizeScheduler *scheduler, const char *repo_id) -{ - RepoSizeJob *job = g_new0(RepoSizeJob, 1); - - job->sched = scheduler; - memcpy (job->repo_id, repo_id, 37); - - pthread_mutex_lock (&scheduler->priv->q_lock); - g_queue_push_tail (scheduler->priv->repo_size_job_queue, job); - pthread_mutex_unlock (&scheduler->priv->q_lock); -} - -static int -schedule_pulse (void *vscheduler) -{ - SizeScheduler *sched = vscheduler; - RepoSizeJob *job; - - while (sched->priv->n_running_repo_size_jobs < CONCURRENT_JOBS) { - pthread_mutex_lock (&sched->priv->q_lock); - job = (RepoSizeJob *)g_queue_pop_head (sched->priv->repo_size_job_queue); - pthread_mutex_unlock (&sched->priv->q_lock); - - if (!job) - break; - - int ret = ccnet_job_manager_schedule_job (sched->seaf->job_mgr, - compute_repo_size, - compute_repo_size_done, - job); - if (ret < 0) { - seaf_warning ("[scheduler] failed to start compute job.\n"); - pthread_mutex_lock (&sched->priv->q_lock); - g_queue_push_head (sched->priv->repo_size_job_queue, job); - pthread_mutex_unlock (&sched->priv->q_lock); - break; - } - ++(sched->priv->n_running_repo_size_jobs); - } - - return 1; -} - -static gboolean get_head_id (SeafDBRow *row, void *data) -{ - char *head_id_out = data; - const char *head_id; - - head_id = seaf_db_row_get_column_text (row, 0); - memcpy (head_id_out, head_id, 40); - - return FALSE; -} - -#define SET_SIZE_ERROR -1 -#define SET_SIZE_CONFLICT -2 - -static int -set_repo_size (SeafDB *db, - const char *repo_id, - const char *old_head_id, - const char *new_head_id, - gint64 size) -{ - SeafDBTrans *trans; - char *sql; - char cached_head_id[41] = {0}; - int ret = 0; - - trans = seaf_db_begin_transaction (db); - if (!trans) - return -1; - - switch (seaf_db_type (db)) { - case SEAF_DB_TYPE_MYSQL: - case SEAF_DB_TYPE_PGSQL: - sql = "SELECT head_id FROM RepoSize WHERE repo_id=? FOR UPDATE"; - break; - case SEAF_DB_TYPE_SQLITE: - sql = "SELECT head_id FROM RepoSize WHERE repo_id=?"; - break; - default: - g_return_val_if_reached (-1); - } - - int n = seaf_db_trans_foreach_selected_row (trans, sql, - get_head_id, - cached_head_id, - 1, "string", repo_id); - if (n < 0) { - ret = SET_SIZE_ERROR; - goto rollback; - } - - if (n == 0) { - /* Size not set before. */ - sql = "INSERT INTO RepoSize VALUES (?, ?, ?)"; - if (seaf_db_trans_query (trans, sql, 3, "string", repo_id, "int64", size, - "string", new_head_id) < 0) { - ret = SET_SIZE_ERROR; - goto rollback; - } - } else { - if (strcmp (old_head_id, cached_head_id) != 0) { - g_message ("[size sched] Size update conflict for repo %s, rollback.\n", - repo_id); - ret = SET_SIZE_CONFLICT; - goto rollback; - } - - sql = "UPDATE RepoSize SET size = ?, head_id = ? WHERE repo_id = ?"; - if (seaf_db_trans_query (trans, sql, 3, "int64", size, "string", new_head_id, - "string", repo_id) < 0) { - ret = SET_SIZE_ERROR; - goto rollback; - } - } - - if (seaf_db_commit (trans) < 0) { - ret = SET_SIZE_ERROR; - goto rollback; - } - - seaf_db_trans_close (trans); - - return ret; - -rollback: - seaf_db_rollback (trans); - seaf_db_trans_close (trans); - return ret; -} - -static char * -get_cached_head_id (SeafDB *db, const char *repo_id) -{ - char *sql; - - sql = "SELECT head_id FROM RepoSize WHERE repo_id=?"; - return seaf_db_statement_get_string (db, sql, 1, "string", repo_id); -} - -static void -set_file_count (SeafDB *db, const char *repo_id, gint64 file_count) -{ - gboolean exist; - gboolean db_err; - - exist = seaf_db_statement_exists (db, - "SELECT 1 FROM RepoFileCount WHERE repo_id=?", - &db_err, 1, "string", repo_id); - if (db_err) - return; - - if (exist) { - seaf_db_statement_query (db, - "UPDATE RepoFileCount SET file_count=? WHERE repo_id=?", - 2, "int64", file_count, "string", repo_id); - } else { - seaf_db_statement_query (db, - "INSERT INTO RepoFileCount (repo_id,file_count) VALUES (?,?)", - 2, "string", repo_id, "int64", file_count); - } -} - -static void* -compute_repo_size (void *vjob) -{ - RepoSizeJob *job = vjob; - SizeScheduler *sched = job->sched; - SeafRepo *repo = NULL; - SeafCommit *head = NULL; - char *cached_head_id = NULL; - gint64 size = 0; - -retry: - repo = seaf_repo_manager_get_repo (sched->seaf->repo_mgr, job->repo_id); - if (!repo) { - seaf_warning ("[scheduler] failed to get repo %s.\n", job->repo_id); - return vjob; - } - - cached_head_id = get_cached_head_id (sched->seaf->db, job->repo_id); - if (g_strcmp0 (cached_head_id, repo->head->commit_id) == 0) - goto out; - - head = seaf_commit_manager_get_commit (sched->seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!head) { - seaf_warning ("[scheduler] failed to get head commit %s.\n", - repo->head->commit_id); - goto out; - } - - size = seaf_fs_manager_get_fs_size (sched->seaf->fs_mgr, - repo->store_id, repo->version, - head->root_id); - if (size < 0) { - seaf_warning ("[scheduler] Failed to compute size of repo %.8s.\n", - repo->id); - goto out; - } - - int ret = set_repo_size (sched->seaf->db, - job->repo_id, - cached_head_id, - repo->head->commit_id, - size); - if (ret == SET_SIZE_ERROR) - seaf_warning ("[scheduler] failed to store repo size %s.\n", job->repo_id); - else if (ret == SET_SIZE_CONFLICT) { - size = 0; - seaf_repo_unref (repo); - seaf_commit_unref (head); - g_free (cached_head_id); - repo = NULL; - head = NULL; - cached_head_id = NULL; - goto retry; - } else { - gint64 file_count = seaf_fs_manager_count_fs_files (sched->seaf->fs_mgr, - repo->store_id, repo->version, - head->root_id); - set_file_count (sched->seaf->db, repo->id, file_count); - } - -out: - seaf_repo_unref (repo); - seaf_commit_unref (head); - g_free (cached_head_id); - - return vjob; -} - -static void -compute_repo_size_done (void *vjob) -{ - RepoSizeJob *job = vjob; - --(job->sched->priv->n_running_repo_size_jobs); - g_free (job); -} diff --git a/server/size-sched.h b/server/size-sched.h deleted file mode 100644 index 5fb9db7c..00000000 --- a/server/size-sched.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SIZE_SCHEDULER_H -#define SIZE_SCHEDULER_H - -struct _SeafileSession; - -struct SizeSchedulerPriv; - -typedef struct SizeScheduler { - struct _SeafileSession *seaf; - - struct SizeSchedulerPriv *priv; -} SizeScheduler; - -SizeScheduler * -size_scheduler_new (struct _SeafileSession *session); - -int -size_scheduler_start (SizeScheduler *scheduler); - -void -schedule_repo_size_computation (SizeScheduler *scheduler, const char *repo_id); - -#endif diff --git a/server/token-mgr.c b/server/token-mgr.c deleted file mode 100644 index 268b14d3..00000000 --- a/server/token-mgr.c +++ /dev/null @@ -1,169 +0,0 @@ -#include - -#include "common.h" -#include "seafile-session.h" -#include "utils.h" - -/* - * Token format: - * - * master_id - * client_id - * repo_id - * timestamp - * signature - */ - -#define TOKEN_TIME_TO_EXPIRE 24 * 3600 /* a token is valid in 1 day. */ - -struct TokenManagerPriv { - /* (master, client, repo) --> timestamp */ - GHashTable *token_hash; -}; - -SeafTokenManager * -seaf_token_manager_new (struct _SeafileSession *session) -{ - SeafTokenManager *mgr = g_new0(SeafTokenManager, 1); - struct TokenManagerPriv *priv = g_new0(struct TokenManagerPriv, 1); - - mgr->seaf = session; - mgr->priv = priv; - - /* mgr->priv->token_hash = g_hash_table_new_full (g_str_hash, g_str_equal, */ - /* g_free, g_free); */ - - return mgr; -} - -char * -seaf_token_manager_generate_token (SeafTokenManager *mgr, - const char *client_id, - const char *repo_id) -{ - GString *token = g_string_new (NULL); - char *sig_base64; - - g_string_append_printf (token, "%s\n%s\n%s\n%"G_GUINT64_FORMAT, - seaf->session->base.id, - client_id, - repo_id, - (guint64)time(NULL)); - - /* Create signature with my private key. */ - sig_base64 = ccnet_sign_message (seaf->ccnetrpc_client, token->str); - g_string_append_printf (token, "\n%s", sig_base64); - g_free (sig_base64); - - return g_string_free (token, FALSE); -} - -int -seaf_token_manager_verify_token (SeafTokenManager *mgr, - SearpcClient *rpc_client, - const char *peer_id, - char *token, - char *ret_repo_id) -{ - char **keys; - char *master_id, *client_id, *repo_id, *ts_str, *signature; - guint64 timestamp; - char *sep; - int ret = 0; - - if (token[0] == '\0') - return -1; - - keys = g_strsplit (token, "\n", 5); - if (g_strv_length(keys) != 5) { - ret = -1; - goto out; - } - - master_id = keys[0]; - client_id = keys[1]; - repo_id = keys[2]; - ts_str = keys[3]; - signature = keys[4]; - - if (strlen(master_id) != 40 || - strlen(client_id) != 40 || - strlen(repo_id) != 36) { - ret = -1; - goto out; - } - - sep = strrchr (token, '\n'); - sep[0] = '\0'; - - if (!rpc_client) - rpc_client = seaf->ccnetrpc_client; - - /* Verify signature. - * TODO: we should first check whether master_id is a master server. - */ - if (ccnet_verify_message (rpc_client, - token, signature, master_id) < 0) { - ret = -1; - goto out; - } - - sep[0] = '\n'; - - /* Check whether this token is assigned to the peer. */ - if (peer_id && strcmp (peer_id, client_id) != 0) { - ret = -1; - goto out; - } - - timestamp = strtoul(ts_str, NULL, 10); - - /* The timestamp contained in the token cannot be smaller than - * the last one received, and should not be older than 1 hour. - */ - if (timestamp + TOKEN_TIME_TO_EXPIRE <= (guint64)time(NULL)) { - ret = -1; - goto out; - } - - /* OK, the token is valid. */ - if (ret_repo_id != NULL) - memcpy (ret_repo_id, repo_id, 37); - -out: - g_strfreev (keys); - return ret; -} - -#if 0 -void -seaf_token_manager_invalidate_token (SeafTokenManager *mgr, - char *token) -{ - char **keys; - char *master_id, *client_id, *repo_id, *ts_str; - char hash_key[128]; - guint64 timestamp; - - /* We assume that the token has been verified. */ - - keys = g_strsplit (token, "\n", 5); - - master_id = keys[0]; - client_id = keys[1]; - repo_id = keys[2]; - ts_str = keys[3]; - - snprintf (hash_key, sizeof(hash_key), "%s%s%s", - master_id, client_id, repo_id); - - timestamp = strtoul(ts_str, NULL, 10); - - /* Record the timestamp so that it cannot be reused. */ - guint64 *new_ts = g_new0(guint64, 1); - *new_ts = timestamp; - g_hash_table_insert (mgr->priv->token_hash, g_strdup(hash_key), new_ts); - - g_strfreev (keys); -} -#endif diff --git a/server/token-mgr.h b/server/token-mgr.h deleted file mode 100644 index d510baa7..00000000 --- a/server/token-mgr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef SEAF_TOKEN_MGR_H -#define SEAF_TOKEN_MGR_H - -#include - -struct _SeafileSession; -struct TokenManagerPriv; - -struct _SeafTokenManager { - struct _SeafileSession *seaf; - struct TokenManagerPriv *priv; -}; -typedef struct _SeafTokenManager SeafTokenManager; - -SeafTokenManager * -seaf_token_manager_new (struct _SeafileSession *session); - -/* Generate a token, signed by me. - * This is called by a master server. - */ -char * -seaf_token_manager_generate_token (SeafTokenManager *mgr, - const char *client_id, - const char *repo_id); - -/* Verify whether a token is valid. - * - * @peer_id: the peer who presents this token to me. - * If the token is valid, repo id will be stored in @ret_repo_id. - */ -int -seaf_token_manager_verify_token (SeafTokenManager *mgr, - SearpcClient *rpc_client, - const char *peer_id, - char *token, - char *ret_repo_id); - -#if 0 -/* Record a used token so that it cannot be reused. - * This function should only be called after the token has been verified. - */ -void -seaf_token_manager_invalidate_token (SeafTokenManager *mgr, - char *token); -#endif - -#endif diff --git a/server/upload-file.c b/server/upload-file.c deleted file mode 100644 index 42d79d7c..00000000 --- a/server/upload-file.c +++ /dev/null @@ -1,2285 +0,0 @@ -#include "common.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_HTTP -#include "log.h" - -#include -#include - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif - -#include - -#include - -#include - -#include "seafile-object.h" - -#include "utils.h" - -#include "seafile-session.h" -#include "upload-file.h" -#include "http-status-codes.h" - -enum RecvState { - RECV_INIT, - RECV_HEADERS, - RECV_CONTENT, - RECV_ERROR, -}; - -enum UploadError { - ERROR_FILENAME, - ERROR_EXISTS, - ERROR_NOT_EXIST, - ERROR_SIZE, - ERROR_QUOTA, - ERROR_RECV, - ERROR_BLOCK_MISSING, - ERROR_INTERNAL, -}; - -typedef struct Progress { - gint64 uploaded; - gint64 size; -} Progress; - -typedef struct RecvFSM { - int state; - - char *repo_id; - char *user; - char *boundary; /* boundary of multipart form-data. */ - char *input_name; /* input name of the current form field. */ - evbuf_t *line; /* buffer for a line */ - - GHashTable *form_kvs; /* key/value of form fields */ - GList *filenames; /* uploaded file names */ - GList *files; /* paths for completely uploaded tmp files. */ - - gboolean recved_crlf; /* Did we recv a CRLF when write out the last line? */ - char *file_name; - char *tmp_file; - int fd; - GList *tmp_files; /* tmp files for each uploading file */ - - /* For upload progress. */ - char *progress_id; - Progress *progress; -} RecvFSM; - -#define MAX_CONTENT_LINE 10240 - -#define POST_FILE_ERR_FILENAME 401 -#define POST_FILE_ERR_BLOCK_MISSING 402 - -static GHashTable *upload_progress; -static pthread_mutex_t pg_lock; - -/* IE8 will set filename to the full path of the uploaded file. - * So we need to strip out the basename from it. - */ -static char * -get_basename (const char *path) -{ - int i = strlen(path) - 1; - - while (i >= 0) { - if (path[i] == '/' || path[i] == '\\') - break; - --i; - } - - if (i < 0) - return g_strdup(path); - - return g_strdup(&path[i+1]); -} - -/* It's a bug of libevhtp that it doesn't set Content-Length automatically - * in response to a multipart request. - * Just add it in our code. - */ -static void -set_content_length_header (evhtp_request_t *req) -{ - char lstr[128]; - - snprintf(lstr, sizeof(lstr), "%zu", evbuffer_get_length(req->buffer_out)); - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Content-Length", lstr, 1, 1)); -} - -static void -send_error_reply (evhtp_request_t *req, evhtp_res code, char *error) -{ - if (error) - evbuffer_add_printf (req->buffer_out, "{\"error\": \"%s\"}", error); - set_content_length_header (req); - evhtp_headers_add_header ( - req->headers_out, - evhtp_header_new("Content-Type", "application/json; charset=utf-8", 1, 1)); - evhtp_send_reply (req, code); -} - -static void -send_success_reply (evhtp_request_t *req) -{ - set_content_length_header (req); - evhtp_headers_add_header ( - req->headers_out, - evhtp_header_new("Content-Type", "application/json; charset=utf-8", 1, 1)); - evhtp_send_reply (req, EVHTP_RES_OK); -} - -static void -send_redirect_reply (evhtp_request_t *req) -{ - set_content_length_header (req); - evhtp_headers_add_header ( - req->headers_out, - evhtp_header_new("Content-Type", "text/html; charset=utf-8", 1, 1)); - evhtp_send_reply(req, EVHTP_RES_SEEOTHER); -} - -static void -redirect_to_upload_error (evhtp_request_t *req, - const char *repo_id, - const char *parent_dir, - const char *filename, - int error_code) -{ - char *seahub_url, *escaped_path, *escaped_fn = NULL; - char url[1024]; - - seahub_url = seaf->session->base.service_url; - escaped_path = g_uri_escape_string (parent_dir, NULL, FALSE); - if (filename) { - escaped_fn = g_uri_escape_string (filename, NULL, FALSE); - snprintf(url, 1024, "%s/repo/upload_error/%s?p=%s&fn=%s&err=%d", - seahub_url, repo_id, escaped_path, escaped_fn, error_code); - } else { - snprintf(url, 1024, "%s/repo/upload_error/%s?p=%s&err=%d", - seahub_url, repo_id, escaped_path, error_code); - } - g_free (escaped_path); - g_free (escaped_fn); - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Location", - url, 1, 1)); - - send_redirect_reply (req); -} - -static void -redirect_to_update_error (evhtp_request_t *req, - const char *repo_id, - const char *target_file, - int error_code) -{ - char *seahub_url, *escaped_path; - char url[1024]; - - seahub_url = seaf->session->base.service_url; - escaped_path = g_uri_escape_string (target_file, NULL, FALSE); - snprintf(url, 1024, "%s/repo/update_error/%s?p=%s&err=%d", - seahub_url, repo_id, escaped_path, error_code); - g_free (escaped_path); - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Location", - url, 1, 1)); - - send_redirect_reply (req); -} - -static void -redirect_to_success_page (evhtp_request_t *req, - const char *repo_id, - const char *parent_dir) -{ - char *seahub_url, *escaped_path; - char url[1024]; - - seahub_url = seaf->session->base.service_url; - escaped_path = g_uri_escape_string (parent_dir, NULL, FALSE); - snprintf(url, 1024, "%s/repo/%s?p=%s", seahub_url, repo_id, escaped_path); - g_free (escaped_path); - - evhtp_headers_add_header(req->headers_out, - evhtp_header_new("Location", - url, 1, 1)); - /* Firefox expects Content-Length header. */ - send_redirect_reply (req); -} - -static gboolean -check_tmp_file_list (GList *tmp_files, int *error_code) -{ - GList *ptr; - char *tmp_file; - SeafStat st; - gint64 total_size = 0; - - for (ptr = tmp_files; ptr; ptr = ptr->next) { - tmp_file = ptr->data; - - if (seaf_stat (tmp_file, &st) < 0) { - seaf_warning ("[upload] Failed to stat temp file %s.\n", tmp_file); - *error_code = ERROR_RECV; - return FALSE; - } - - total_size += (gint64)st.st_size; - } - - if (seaf->http_server->max_upload_size != -1 && - total_size > seaf->http_server->max_upload_size) { - seaf_debug ("[upload] File size is too large.\n"); - *error_code = ERROR_SIZE; - return FALSE; - } - - return TRUE; -} - -static char * -get_canonical_path (const char *path) -{ - char *ret = g_strdup (path); - char *p; - - for (p = ret; *p != 0; ++p) { - if (*p == '\\') - *p = '/'; - } - - /* Remove trailing slashes from dir path. */ - int len = strlen(ret); - int i = len - 1; - while (i >= 0 && ret[i] == '/') - ret[i--] = 0; - - return ret; -} - -static gboolean -check_parent_dir (evhtp_request_t *req, const char *repo_id, - const char *parent_dir) -{ - char *canon_path = NULL; - SeafRepo *repo = NULL; - SeafCommit *commit = NULL; - SeafDir *dir = NULL; - GError *error = NULL; - gboolean ret = TRUE; - - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("[upload] Failed to get repo %.8s.\n", repo_id); - send_error_reply (req, EVHTP_RES_SERVERR, "Failed to get repo.\n"); - return FALSE; - } - - commit = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!commit) { - seaf_warning ("[upload] Failed to get head commit for repo %.8s.\n", repo_id); - send_error_reply (req, EVHTP_RES_SERVERR, "Failed to get head commit.\n"); - seaf_repo_unref (repo); - return FALSE; - } - - canon_path = get_canonical_path (parent_dir); - - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, repo->version, - commit->root_id, - canon_path, &error); - if (dir) { - seaf_dir_free (dir); - } else { - send_error_reply (req, EVHTP_RES_BADREQ, "Parent dir doesn't exist.\n"); - ret = FALSE; - } - - g_clear_error (&error); - g_free (canon_path); - seaf_commit_unref (commit); - seaf_repo_unref (repo); - - return ret; -} - -static char * -file_list_to_json (GList *files) -{ - json_t *array; - GList *ptr; - char *file; - char *json_data; - char *ret; - - array = json_array (); - - for (ptr = files; ptr; ptr = ptr->next) { - file = ptr->data; - json_array_append_new (array, json_string(file)); - } - - json_data = json_dumps (array, 0); - json_decref (array); - - ret = g_strdup (json_data); - free (json_data); - return ret; -} - -static void -upload_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *parent_dir; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *err_file = NULL; - char *filenames_json, *tmp_files_json; - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[upload] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); - if (!parent_dir) { - seaf_debug ("[upload] No parent dir given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - filenames_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filenames_json, - tmp_files_json, - fsm->user, - 0, - NULL, - &error); - g_free (filenames_json); - g_free (tmp_files_json); - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - err_file = g_strdup(error->message); - } - g_clear_error (&error); - } - goto error; - } - - /* Redirect to repo dir page after upload finishes. */ - redirect_to_success_page (req, fsm->repo_id, parent_dir); - return; - -error: - redirect_to_upload_error (req, fsm->repo_id, parent_dir, - err_file, error_code); - g_free (err_file); -} - -static char * -file_id_list_from_json (const char *ret_json) -{ - json_t *array, *obj, *value; - json_error_t err; - size_t index; - GString *id_list; - - array = json_loadb (ret_json, strlen(ret_json), 0, &err); - if (!array) { - seaf_warning ("Failed to load ret_json: %s.\n", err.text); - return NULL; - } - - id_list = g_string_new (NULL); - size_t n = json_array_size (array); - for (index = 0; index < n; index++) { - obj = json_array_get (array, index); - value = json_object_get (obj, "id"); - const char *id = json_string_value (value); - g_string_append (id_list, id); - if (index != n - 1) - g_string_append (id_list, "\t"); - } - - json_decref (array); - return g_string_free (id_list, FALSE); -} - -static void -upload_api_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *parent_dir, *replace_str; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *filenames_json, *tmp_files_json; - int replace = 0; - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - /* If CORS preflight header, then create an empty body response (200 OK) - * and return it. - */ - send_success_reply (req); - return; - } - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[upload] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - replace_str = g_hash_table_lookup (fsm->form_kvs, "replace"); - if (replace_str) { - replace = atoi(replace_str); - if (replace != 0 && replace != 1) { - seaf_debug ("[Upload] Invalid argument replace: %s.\n", replace_str); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid argument.\n"); - return; - } - } - parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); - if (!parent_dir) { - seaf_debug ("[upload] No parent dir given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - filenames_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - char *ret_json = NULL; - int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filenames_json, - tmp_files_json, - fsm->user, - replace, - &ret_json, - &error); - g_free (filenames_json); - g_free (tmp_files_json); - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - } - g_clear_error (&error); - } - goto error; - } - - const char *use_json = evhtp_kv_find (req->uri->query, "ret-json"); - if (use_json) { - evbuffer_add (req->buffer_out, ret_json, strlen(ret_json)); - } else { - char *new_ids = file_id_list_from_json (ret_json); - if (new_ids) - evbuffer_add (req->buffer_out, new_ids, strlen(new_ids)); - g_free (new_ids); - } - g_free (ret_json); - - send_success_reply (req); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error\n"); - break; - } -} - - -static void -upload_raw_blks_api_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *blockids_json, *tmp_files_json; - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - blockids_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - int rc = seaf_repo_manager_post_blocks (seaf->repo_mgr, - fsm->repo_id, - blockids_json, - tmp_files_json, - fsm->user, - &error); - g_free (blockids_json); - g_free (tmp_files_json); - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - } - g_clear_error (&error); - } - goto error; - } - - evbuffer_add (req->buffer_out, "\"OK\"", 4); - send_success_reply (req); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static void -upload_blks_api_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - const char *parent_dir, *file_name, *size_str, *replace_str, *commitonly_str; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *blockids_json, *tmp_files_json; - gint64 file_size = -1; - int replace = 0; - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - replace_str = g_hash_table_lookup (fsm->form_kvs, "replace"); - if (replace_str) { - replace = atoi(replace_str); - if (replace != 0 && replace != 1) { - seaf_debug ("[Upload-blks] Invalid argument replace: %s.\n", replace_str); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid argument.\n"); - return; - } - } - parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); - file_name = g_hash_table_lookup (fsm->form_kvs, "file_name"); - size_str = g_hash_table_lookup (fsm->form_kvs, "file_size"); - if (size_str) - file_size = atoll(size_str); - - if (!file_name || !parent_dir || !size_str || file_size < 0) { - seaf_debug ("[upload-blks] No parent dir or file name given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - char *new_file_id = NULL; - int rc = 0; - commitonly_str = evhtp_kv_find (req->uri->query, "commitonly"); - if (!commitonly_str) { - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - blockids_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - rc = seaf_repo_manager_post_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - file_name, - blockids_json, - tmp_files_json, - fsm->user, - file_size, - replace, - &new_file_id, - &error); - g_free (blockids_json); - g_free (tmp_files_json); - } else { - blockids_json = g_hash_table_lookup (fsm->form_kvs, "blockids"); - if (blockids_json == NULL) { - seaf_debug ("[upload-blks] No blockids given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - rc = seaf_repo_manager_commit_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - file_name, - blockids_json, - fsm->user, - file_size, - replace, - &new_file_id, - &error); - } - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - } else if (error->code == POST_FILE_ERR_BLOCK_MISSING) { - error_code = ERROR_BLOCK_MISSING; - } - g_clear_error (&error); - } - goto error; - } - - const char *use_json = evhtp_kv_find (req->uri->query, "ret-json"); - if (use_json) { - json_t *json = json_object (); - json_object_set_string_member(json, "id", new_file_id); - char *json_data = json_dumps (json, 0); - evbuffer_add (req->buffer_out, json_data, strlen(json_data)); - json_decref (json); - free (json_data); - } else { - evbuffer_add (req->buffer_out, "\"", 1); - evbuffer_add (req->buffer_out, new_file_id, strlen(new_file_id)); - evbuffer_add (req->buffer_out, "\"", 1); - } - g_free (new_file_id); - send_success_reply (req); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_BLOCK_MISSING: - send_error_reply (req, SEAF_HTTP_RES_BLOCK_MISSING, "Block missing.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static void -upload_blks_ajax_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *parent_dir, *file_name, *size_str; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *blockids_json, *tmp_files_json; - gint64 file_size = -1; - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Headers", - "x-requested-with, content-type, accept, origin, authorization", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Methods", - "GET, POST, PUT, PATCH, DELETE, OPTIONS", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Max-Age", - "86400", 1, 1)); - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - /* If CORS preflight header, then create an empty body response (200 OK) - * and return it. - */ - send_success_reply (req); - return; - } - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); - file_name = g_hash_table_lookup (fsm->form_kvs, "file_name"); - size_str = g_hash_table_lookup (fsm->form_kvs, "file_size"); - if (size_str) - file_size = atoll(size_str); - if (!file_name || !parent_dir || !size_str || file_size < 0) { - seaf_debug ("[upload-blks] No parent dir or file name given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - blockids_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - int rc = seaf_repo_manager_post_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - file_name, - blockids_json, - tmp_files_json, - fsm->user, - file_size, - 0, - NULL, - &error); - g_free (blockids_json); - g_free (tmp_files_json); - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - } - g_clear_error (&error); - } - goto error; - } - - send_success_reply (req); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename."); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists."); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large."); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota."); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -/* - Handle AJAX file upload. - @return an array of json data, e.g. [{"name": "foo.txt"}] - */ -static void -upload_ajax_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *parent_dir; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *filenames_json, *tmp_files_json; - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Headers", - "x-requested-with, content-type, accept, origin, authorization", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Methods", - "GET, POST, PUT, PATCH, DELETE, OPTIONS", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Max-Age", - "86400", 1, 1)); - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - /* If CORS preflight header, then create an empty body response (200 OK) - * and return it. - */ - send_success_reply (req); - return; - } - - /* After upload_headers_cb() returns an error, libevhtp may still - * receive data from the web browser and call into this cb. - * In this case fsm will be NULL. - */ - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[upload] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); - if (!parent_dir) { - seaf_debug ("[upload] No parent dir given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL."); - return; - } - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - filenames_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - - char *ret_json = NULL; - int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filenames_json, - tmp_files_json, - fsm->user, - 0, - &ret_json, - &error); - g_free (filenames_json); - g_free (tmp_files_json); - if (rc < 0) { - if (error) { - if (error->code == POST_FILE_ERR_FILENAME) { - error_code = ERROR_FILENAME; - } - g_clear_error (&error); - } - goto error; - } - - evbuffer_add (req->buffer_out, ret_json, strlen(ret_json)); - g_free (ret_json); - - // send_success_reply (req); - set_content_length_header (req); - - const char *accept = evhtp_kv_find (req->headers_in, "Accept"); - if (accept && strstr (accept, "application/json") != NULL) { - evhtp_headers_add_header ( - req->headers_out, - evhtp_header_new("Content-Type", "application/json; charset=utf-8", 1, 1)); - } else { - evhtp_headers_add_header ( - req->headers_out, - evhtp_header_new("Content-Type", "text/plain", 1, 1)); - } - evhtp_send_reply (req, EVHTP_RES_OK); - - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename."); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists."); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large."); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota."); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static void -update_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *target_file, *parent_dir = NULL, *filename = NULL; - const char *head_id = NULL; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[update] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - target_file = g_hash_table_lookup (fsm->form_kvs, "target_file"); - if (!target_file) { - seaf_debug ("[Update] No target file given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - parent_dir = g_path_get_dirname (target_file); - filename = g_path_get_basename (target_file); - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - head_id = evhtp_kv_find (req->uri->query, "head"); - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - int rc = seaf_repo_manager_put_file (seaf->repo_mgr, - fsm->repo_id, - (char *)(fsm->files->data), - parent_dir, - filename, - fsm->user, - head_id, - NULL, - &error); - if (rc < 0) { - if (error) { - if (g_strcmp0 (error->message, "file does not exist") == 0) { - error_code = ERROR_NOT_EXIST; - } - g_clear_error (&error); - } - goto error; - } - - /* Redirect to repo dir page after upload finishes. */ - redirect_to_success_page (req, fsm->repo_id, parent_dir); - g_free (parent_dir); - g_free (filename); - return; - -error: - redirect_to_update_error (req, fsm->repo_id, target_file, error_code); - g_free (parent_dir); - g_free (filename); -} - -static void -update_api_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *target_file, *parent_dir = NULL, *filename = NULL; - const char *head_id = NULL; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *new_file_id = NULL; - - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[update] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - target_file = g_hash_table_lookup (fsm->form_kvs, "target_file"); - if (!target_file) { - seaf_debug ("[Update] No target file given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - parent_dir = g_path_get_dirname (target_file); - filename = g_path_get_basename (target_file); - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - head_id = evhtp_kv_find (req->uri->query, "head"); - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - int rc = seaf_repo_manager_put_file (seaf->repo_mgr, - fsm->repo_id, - (char *)(fsm->files->data), - parent_dir, - filename, - fsm->user, - head_id, - &new_file_id, - &error); - g_free (parent_dir); - g_free (filename); - - if (rc < 0) { - if (error) { - if (g_strcmp0 (error->message, "file does not exist") == 0) { - error_code = ERROR_NOT_EXIST; - } - g_clear_error (&error); - } - goto error; - } - - /* Send back the new file id, so that the mobile client can update local cache */ - evbuffer_add(req->buffer_out, new_file_id, strlen(new_file_id)); - send_success_reply (req); - - g_free (new_file_id); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_NOT_EXIST: - send_error_reply (req, SEAF_HTTP_RES_NOT_EXISTS, "File does not exist.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - default: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static void -update_blks_api_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *target_file, *parent_dir = NULL, *filename = NULL, *size_str = NULL; - const char *commitonly_str; - const char *head_id = NULL; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *new_file_id = NULL; - char *blockids_json, *tmp_files_json; - gint64 file_size = -1; - - if (!fsm || fsm->state == RECV_ERROR) - return; - target_file = g_hash_table_lookup (fsm->form_kvs, "target_file"); - size_str = g_hash_table_lookup (fsm->form_kvs, "file_size"); - if (size_str) file_size = atoll(size_str); - if (!target_file || !size_str || file_size < 0) { - seaf_debug ("[Update-blks] No target file given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - parent_dir = g_path_get_dirname (target_file); - filename = g_path_get_basename (target_file); - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - head_id = evhtp_kv_find (req->uri->query, "head"); - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - - int rc = 0; - commitonly_str = evhtp_kv_find (req->uri->query, "commitonly"); - if (!commitonly_str) { - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - blockids_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - rc = seaf_repo_manager_put_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filename, - blockids_json, - tmp_files_json, - fsm->user, - head_id, - file_size, - &new_file_id, - &error); - g_free (blockids_json); - g_free (tmp_files_json); - } else { - blockids_json = g_hash_table_lookup (fsm->form_kvs, "blockids"); - if (blockids_json == NULL) { - seaf_debug ("[upload-blks] No blockids given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - rc = seaf_repo_manager_commit_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filename, - blockids_json, - fsm->user, - file_size, - 1, - &new_file_id, - &error); - } - g_free (parent_dir); - g_free (filename); - - if (rc < 0) { - if (error) { - if (g_strcmp0 (error->message, "file does not exist") == 0) { - error_code = ERROR_NOT_EXIST; - } - g_clear_error (&error); - } - goto error; - } - - /* Send back the new file id, so that the mobile client can update local cache */ - evbuffer_add(req->buffer_out, new_file_id, strlen(new_file_id)); - send_success_reply (req); - - g_free (new_file_id); - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_NOT_EXIST: - send_error_reply (req, SEAF_HTTP_RES_NOT_EXISTS, "File does not exist.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - default: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static void -update_blks_ajax_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *target_file, *parent_dir = NULL, *filename = NULL, *size_str = NULL; - const char *head_id = NULL; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *blockids_json, *tmp_files_json; - gint64 file_size = -1; - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Headers", - "x-requested-with, content-type, accept, origin, authorization", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Methods", - "GET, POST, PUT, PATCH, DELETE, OPTIONS", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Max-Age", - "86400", 1, 1)); - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - /* If CORS preflight header, then create an empty body response (200 OK) - * and return it. - */ - send_success_reply (req); - return; - } - - if (!fsm || fsm->state == RECV_ERROR) - return; - target_file = g_hash_table_lookup (fsm->form_kvs, "target_file"); - size_str = g_hash_table_lookup (fsm->form_kvs, "file_size"); - if (size_str) file_size = atoll(size_str); - if (!target_file || !size_str || file_size < 0) { - seaf_debug ("[Update-blks] No target file given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL.\n"); - return; - } - - parent_dir = g_path_get_dirname (target_file); - filename = g_path_get_basename (target_file); - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - head_id = evhtp_kv_find (req->uri->query, "head"); - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - blockids_json = file_list_to_json (fsm->filenames); - tmp_files_json = file_list_to_json (fsm->files); - int rc = seaf_repo_manager_put_file_blocks (seaf->repo_mgr, - fsm->repo_id, - parent_dir, - filename, - blockids_json, - tmp_files_json, - fsm->user, - head_id, - file_size, - NULL, - &error); - g_free (blockids_json); - g_free (tmp_files_json); - g_free (parent_dir); - g_free (filename); - - if (rc < 0) { - if (error) { - if (g_strcmp0 (error->message, "file does not exist") == 0) { - error_code = ERROR_NOT_EXIST; - } - g_clear_error (&error); - } - goto error; - } - - send_success_reply (req); - - return; - -error: - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename.\n"); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists.\n"); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large.\n"); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota.\n"); - break; - case ERROR_NOT_EXIST: - send_error_reply (req, SEAF_HTTP_RES_NOT_EXISTS, "File does not exist.\n"); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - default: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static char * -format_update_json_ret (const char *filename, const char *file_id, gint64 size) -{ - json_t *array, *obj; - char *json_data; - char *ret; - - array = json_array (); - - obj = json_object (); - json_object_set_string_member (obj, "name", filename); - json_object_set_string_member (obj, "id", file_id); - json_object_set_int_member (obj, "size", size); - json_array_append_new (array, obj); - - json_data = json_dumps (array, 0); - json_decref (array); - - ret = g_strdup (json_data); - free (json_data); - return ret; -} - -static void -update_ajax_cb(evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - char *target_file, *parent_dir = NULL, *filename = NULL; - const char *head_id = NULL; - GError *error = NULL; - int error_code = ERROR_INTERNAL; - char *new_file_id = NULL; - gint64 size; - - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Headers", - "x-requested-with, content-type, accept, origin, authorization", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Methods", - "GET, POST, PUT, PATCH, DELETE, OPTIONS", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Allow-Origin", - "*", 1, 1)); - evhtp_headers_add_header (req->headers_out, - evhtp_header_new("Access-Control-Max-Age", - "86400", 1, 1)); - - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - /* If CORS preflight header, then create an empty body response (200 OK) - * and return it. - */ - send_success_reply (req); - return; - } - - if (!fsm || fsm->state == RECV_ERROR) - return; - - if (!fsm->files) { - seaf_debug ("[update] No file uploaded.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "No file.\n"); - return; - } - - target_file = g_hash_table_lookup (fsm->form_kvs, "target_file"); - if (!target_file) { - seaf_debug ("[Update] No target file given.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Invalid URL."); - return; - } - - parent_dir = g_path_get_dirname (target_file); - filename = g_path_get_basename (target_file); - - if (!check_parent_dir (req, fsm->repo_id, parent_dir)) - return; - - if (!check_tmp_file_list (fsm->files, &error_code)) - goto error; - - SeafStat st; - char *tmp_file_path = fsm->files->data; - if (seaf_stat (tmp_file_path, &st) < 0) { - seaf_warning ("Failed to stat tmp file %s.\n", tmp_file_path); - goto error; - } - size = (gint64)st.st_size; - - head_id = evhtp_kv_find (req->uri->query, "head"); - - if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) { - error_code = ERROR_QUOTA; - goto error; - } - - int rc = seaf_repo_manager_put_file (seaf->repo_mgr, - fsm->repo_id, - (char *)(fsm->files->data), - parent_dir, - filename, - fsm->user, - head_id, - &new_file_id, - &error); - g_free (parent_dir); - - if (rc < 0) { - if (error) { - if (g_strcmp0 (error->message, "file does not exist") == 0) { - error_code = ERROR_NOT_EXIST; - } - g_clear_error (&error); - } - goto error; - } - - char *json_ret = format_update_json_ret (filename, new_file_id, size); - - evbuffer_add (req->buffer_out, json_ret, strlen(json_ret)); - send_success_reply (req); - - g_free (new_file_id); - g_free (filename); - g_free (json_ret); - - return; - -error: - g_free (new_file_id); - g_free (filename); - - switch (error_code) { - case ERROR_FILENAME: - send_error_reply (req, SEAF_HTTP_RES_BADFILENAME, "Invalid filename."); - break; - case ERROR_EXISTS: - send_error_reply (req, SEAF_HTTP_RES_EXISTS, "File already exists."); - break; - case ERROR_SIZE: - send_error_reply (req, SEAF_HTTP_RES_TOOLARGE, "File size is too large."); - break; - case ERROR_QUOTA: - send_error_reply (req, SEAF_HTTP_RES_NOQUOTA, "Out of quota."); - break; - case ERROR_NOT_EXIST: - send_error_reply (req, SEAF_HTTP_RES_NOT_EXISTS, "File does not exist."); - break; - case ERROR_RECV: - case ERROR_INTERNAL: - default: - send_error_reply (req, EVHTP_RES_SERVERR, "Internal error.\n"); - break; - } -} - -static evhtp_res -upload_finish_cb (evhtp_request_t *req, void *arg) -{ - RecvFSM *fsm = arg; - GList *ptr; - - if (!fsm) - return EVHTP_RES_OK; - - /* Clean up FSM struct no matter upload succeed or not. */ - - g_free (fsm->repo_id); - g_free (fsm->user); - g_free (fsm->boundary); - g_free (fsm->input_name); - - g_hash_table_destroy (fsm->form_kvs); - - g_free (fsm->file_name); - if (fsm->tmp_file) { - close (fsm->fd); - } - g_free (fsm->tmp_file); - - for (ptr = fsm->tmp_files; ptr; ptr = ptr->next) - g_unlink ((char *)(ptr->data)); - string_list_free (fsm->tmp_files); - string_list_free (fsm->filenames); - string_list_free (fsm->files); - - evbuffer_free (fsm->line); - - if (fsm->progress_id) { - pthread_mutex_lock (&pg_lock); - g_hash_table_remove (upload_progress, fsm->progress_id); - pthread_mutex_unlock (&pg_lock); - - /* fsm->progress has been free'd by g_hash_table_remove(). */ - g_free (fsm->progress_id); - } - - g_free (fsm); - - return EVHTP_RES_OK; -} - -static char * -get_mime_header_param_value (const char *param) -{ - char *first_quote, *last_quote; - char *value; - - first_quote = strchr (param, '\"'); - last_quote = strrchr (param, '\"'); - if (!first_quote || !last_quote || first_quote == last_quote) { - seaf_debug ("[upload] Invalid mime param %s.\n", param); - return NULL; - } - - value = g_strndup (first_quote + 1, last_quote - first_quote - 1); - return value; -} - -static int -parse_mime_header (char *header, RecvFSM *fsm) -{ - char *colon; - char **params, **p; - - colon = strchr (header, ':'); - if (!colon) { - seaf_debug ("[upload] bad mime header format.\n"); - return -1; - } - - *colon = 0; - if (strcmp (header, "Content-Disposition") == 0) { - params = g_strsplit (colon + 1, ";", 0); - for (p = params; *p != NULL; ++p) - *p = g_strstrip (*p); - - if (g_strv_length (params) < 2) { - seaf_debug ("[upload] Too little params for mime header.\n"); - g_strfreev (params); - return -1; - } - if (strcasecmp (params[0], "form-data") != 0) { - seaf_debug ("[upload] Invalid Content-Disposition\n"); - g_strfreev (params); - return -1; - } - - for (p = params; *p != NULL; ++p) { - if (strncasecmp (*p, "name", strlen("name")) == 0) { - fsm->input_name = get_mime_header_param_value (*p); - break; - } - } - if (!fsm->input_name) { - seaf_debug ("[upload] No input-name given.\n"); - g_strfreev (params); - return -1; - } - - if (strcmp (fsm->input_name, "file") == 0) { - char *file_name; - for (p = params; *p != NULL; ++p) { - if (strncasecmp (*p, "filename", strlen("filename")) == 0) { - file_name = get_mime_header_param_value (*p); - fsm->file_name = normalize_utf8_path (file_name); - if (!fsm->file_name) - seaf_debug ("File name is not valid utf8 encoding.\n"); - g_free (file_name); - break; - } - } - if (!fsm->file_name) { - seaf_debug ("[upload] No filename given.\n"); - g_strfreev (params); - return -1; - } - } - g_strfreev (params); - } - - return 0; -} - -static int -open_temp_file (RecvFSM *fsm) -{ - GString *temp_file = g_string_new (NULL); - char *base_name = get_basename(fsm->file_name); - - g_string_printf (temp_file, "%s/%sXXXXXX", - seaf->http_server->http_temp_dir, base_name); - g_free (base_name); - - fsm->fd = g_mkstemp (temp_file->str); - if (fsm->fd < 0) { - g_string_free (temp_file, TRUE); - return -1; - } - - fsm->tmp_file = g_string_free (temp_file, FALSE); - /* For clean up later. */ - fsm->tmp_files = g_list_prepend (fsm->tmp_files, g_strdup(fsm->tmp_file)); - - return 0; -} - -static evhtp_res -recv_form_field (RecvFSM *fsm, gboolean *no_line) -{ - char *line, *norm_line; - size_t len; - - *no_line = FALSE; - - line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); - if (line != NULL) { - if (strstr (line, fsm->boundary) != NULL) { - seaf_debug ("[upload] form field ends.\n"); - - g_free (fsm->input_name); - fsm->input_name = NULL; - fsm->state = RECV_HEADERS; - } else { - seaf_debug ("[upload] form field is %s.\n", line); - - norm_line = normalize_utf8_path (line); - if (norm_line) { - g_hash_table_insert (fsm->form_kvs, - g_strdup(fsm->input_name), - norm_line); - } - } - free (line); - } else { - *no_line = TRUE; - } - - return EVHTP_RES_OK; -} - -static void -add_uploaded_file (RecvFSM *fsm) -{ - fsm->filenames = g_list_prepend (fsm->filenames, - get_basename(fsm->file_name)); - fsm->files = g_list_prepend (fsm->files, g_strdup(fsm->tmp_file)); - - g_free (fsm->file_name); - g_free (fsm->tmp_file); - close (fsm->fd); - fsm->file_name = NULL; - fsm->tmp_file = NULL; - fsm->recved_crlf = FALSE; -} - -static evhtp_res -recv_file_data (RecvFSM *fsm, gboolean *no_line) -{ - char *line; - size_t len; - - *no_line = FALSE; - - line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); - if (!line) { - /* If we haven't read an entire line, but the line - * buffer gets too long, flush the content to file. - * It should be safe to assume the boundary line is - * no longer than 10240 bytes. - */ - if (evbuffer_get_length (fsm->line) >= MAX_CONTENT_LINE) { - seaf_debug ("[upload] recv file data %d bytes.\n", - evbuffer_get_length(fsm->line)); - if (fsm->recved_crlf) { - if (writen (fsm->fd, "\r\n", 2) < 0) { - seaf_warning ("[upload] Failed to write temp file: %s.\n", - strerror(errno)); - return EVHTP_RES_SERVERR; - } - } - - size_t size = evbuffer_get_length (fsm->line); - char *buf = g_new (char, size); - evbuffer_remove (fsm->line, buf, size); - if (writen (fsm->fd, buf, size) < 0) { - seaf_warning ("[upload] Failed to write temp file: %s.\n", - strerror(errno)); - g_free (buf); - return EVHTP_RES_SERVERR; - } - g_free (buf); - fsm->recved_crlf = FALSE; - } - *no_line = TRUE; - } else if (strstr (line, fsm->boundary) != NULL) { - seaf_debug ("[upload] file data ends.\n"); - - add_uploaded_file (fsm); - - g_free (fsm->input_name); - fsm->input_name = NULL; - fsm->state = RECV_HEADERS; - free (line); - } else { - seaf_debug ("[upload] recv file data %d bytes.\n", len + 2); - if (fsm->recved_crlf) { - if (writen (fsm->fd, "\r\n", 2) < 0) { - seaf_warning ("[upload] Failed to write temp file: %s.\n", - strerror(errno)); - return EVHTP_RES_SERVERR; - } - } - if (writen (fsm->fd, line, len) < 0) { - seaf_warning ("[upload] Failed to write temp file: %s.\n", - strerror(errno)); - free (line); - return EVHTP_RES_SERVERR; - } - free (line); - fsm->recved_crlf = TRUE; - } - - return EVHTP_RES_OK; -} - -/* - Example multipart form-data request content format: - - --AaB03x - Content-Disposition: form-data; name="submit-name" - - Larry - --AaB03x - Content-Disposition: form-data; name="file"; filename="file1.txt" - Content-Type: text/plain - - ... contents of file1.txt ... - --AaB03x-- -*/ -static evhtp_res -upload_read_cb (evhtp_request_t *req, evbuf_t *buf, void *arg) -{ - RecvFSM *fsm = arg; - char *line; - size_t len; - gboolean no_line = FALSE; - int res = EVHTP_RES_OK; - - if (fsm->state == RECV_ERROR) - return EVHTP_RES_OK; - - /* Update upload progress. */ - if (fsm->progress) { - fsm->progress->uploaded += (gint64)evbuffer_get_length(buf); - - seaf_debug ("progress: %lld/%lld\n", - fsm->progress->uploaded, fsm->progress->size); - } - - evbuffer_add_buffer (fsm->line, buf); - /* Drain the buffer so that evhtp don't copy it to another buffer - * after this callback returns. - */ - evbuffer_drain (buf, evbuffer_get_length (buf)); - - while (!no_line) { - switch (fsm->state) { - case RECV_INIT: - line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); - if (line != NULL) { - seaf_debug ("[upload] boundary line: %s.\n", line); - if (!strstr (line, fsm->boundary)) { - seaf_debug ("[upload] no boundary found in the first line.\n"); - free (line); - res = EVHTP_RES_BADREQ; - goto out; - } else { - fsm->state = RECV_HEADERS; - free (line); - } - } else { - no_line = TRUE; - } - break; - case RECV_HEADERS: - line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); - if (line != NULL) { - seaf_debug ("[upload] mime header line: %s.\n", line); - if (len == 0) { - /* Read an blank line, headers end. */ - free (line); - if (g_strcmp0 (fsm->input_name, "file") == 0) { - if (open_temp_file (fsm) < 0) { - seaf_warning ("[upload] Failed open temp file.\n"); - res = EVHTP_RES_SERVERR; - goto out; - } - } - seaf_debug ("[upload] Start to recv %s.\n", fsm->input_name); - fsm->state = RECV_CONTENT; - } else if (parse_mime_header (line, fsm) < 0) { - free (line); - res = EVHTP_RES_BADREQ; - goto out; - } else { - free (line); - } - } else { - no_line = TRUE; - } - break; - case RECV_CONTENT: - if (g_strcmp0 (fsm->input_name, "file") == 0) - res = recv_file_data (fsm, &no_line); - else - res = recv_form_field (fsm, &no_line); - - if (res != EVHTP_RES_OK) - goto out; - - break; - } - } - -out: - if (res != EVHTP_RES_OK) { - /* Don't receive any data before the connection is closed. */ - evhtp_request_pause (req); - - /* Set keepalive to 0. This will cause evhtp to close the - * connection after sending the reply. - */ - req->keepalive = 0; - - fsm->state = RECV_ERROR; - } - - if (res == EVHTP_RES_BADREQ) { - send_error_reply (req, EVHTP_RES_BADREQ, "Bad request.\n"); - } else if (res == EVHTP_RES_SERVERR) { - send_error_reply (req, EVHTP_RES_SERVERR, "Internal server error\n"); - } - return EVHTP_RES_OK; -} - -static char * -get_http_header_param_value (const char *param) -{ - char *equal; - char *value; - - equal = strchr (param, '='); - if (!equal) { - seaf_debug ("[upload] Invalid http header param %s.\n", param); - return NULL; - } - - value = g_strdup (equal + 1); - return value; -} - -static char * -get_boundary (evhtp_headers_t *hdr) -{ - const char *content_type; - char **params, **p; - char *boundary = NULL; - - content_type = evhtp_kv_find (hdr, "Content-Type"); - if (!content_type) { - seaf_debug ("[upload] Missing Content-Type header\n"); - return boundary; - } - - params = g_strsplit (content_type, ";", 0); - for (p = params; *p != NULL; ++p) - *p = g_strstrip (*p); - - if (!params || g_strv_length (params) < 2) { - seaf_debug ("[upload] Too little params Content-Type header\n"); - g_strfreev (params); - return boundary; - } - if (strcasecmp (params[0], "multipart/form-data") != 0) { - seaf_debug ("[upload] Invalid Content-Type\n"); - g_strfreev (params); - return boundary; - } - - for (p = params; *p != NULL; ++p) { - if (strncasecmp (*p, "boundary", strlen("boundary")) == 0) { - boundary = get_http_header_param_value (*p); - break; - } - } - g_strfreev (params); - if (!boundary) { - seaf_debug ("[upload] boundary not given\n"); - } - - return boundary; -} - -static int -check_access_token (const char *token, - const char *url_op, - char **repo_id, - char **user) -{ - SeafileWebAccess *webaccess; - const char *op; - - webaccess = (SeafileWebAccess *) - seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token); - if (!webaccess) - return -1; - - /* token with op = "upload" can only be used for "upload-*" operations; - * token with op = "update" can only be used for "update-*" operations. - */ - op = seafile_web_access_get_op (webaccess); - if (strncmp (url_op, op, strlen(op)) != 0) { - g_object_unref (webaccess); - return -1; - } - - *repo_id = g_strdup (seafile_web_access_get_repo_id (webaccess)); - *user = g_strdup (seafile_web_access_get_username (webaccess)); - - g_object_unref (webaccess); - - return 0; -} - -static int -get_progress_info (evhtp_request_t *req, - evhtp_headers_t *hdr, - gint64 *content_len, - char **progress_id) -{ - const char *content_len_str; - const char *uuid; - - uuid = evhtp_kv_find (req->uri->query, "X-Progress-ID"); - /* If progress id is not given, we don't need content-length either. */ - if (!uuid) - return 0; - *progress_id = g_strdup(uuid); - - content_len_str = evhtp_kv_find (hdr, "Content-Length"); - if (!content_len_str) { - seaf_debug ("[upload] Content-Length not found.\n"); - return -1; - } - *content_len = strtoll (content_len_str, NULL, 10); - - return 0; -} - -static evhtp_res -upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg) -{ - char **parts = NULL; - char *token, *repo_id = NULL, *user = NULL; - char *boundary = NULL; - gint64 content_len; - char *progress_id = NULL; - char *err_msg = NULL; - RecvFSM *fsm = NULL; - Progress *progress = NULL; - - if (evhtp_request_get_method(req) == htp_method_OPTIONS) { - return EVHTP_RES_OK; - } - - /* URL format: http://host:port/[upload|update]/?X-Progress-ID= */ - token = req->uri->path->file; - if (!token) { - seaf_debug ("[upload] No token in url.\n"); - err_msg = "Invalid URL"; - goto err; - } - - parts = g_strsplit (req->uri->path->full + 1, "/", 0); - if (!parts || g_strv_length (parts) < 2) { - err_msg = "Invalid URL"; - goto err; - } - char *url_op = parts[0]; - - if (check_access_token (token, url_op, &repo_id, &user) < 0) { - err_msg = "Access denied"; - goto err; - } - - boundary = get_boundary (hdr); - if (!boundary) { - goto err; - } - - if (get_progress_info (req, hdr, &content_len, &progress_id) < 0) - goto err; - - if (progress_id != NULL) { - pthread_mutex_lock (&pg_lock); - if (g_hash_table_lookup (upload_progress, progress_id)) { - pthread_mutex_unlock (&pg_lock); - err_msg = "Duplicate progress id.\n"; - goto err; - } - pthread_mutex_unlock (&pg_lock); - } - - fsm = g_new0 (RecvFSM, 1); - fsm->boundary = boundary; - fsm->repo_id = repo_id; - fsm->user = user; - fsm->line = evbuffer_new (); - fsm->form_kvs = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - if (progress_id != NULL) { - progress = g_new0 (Progress, 1); - progress->size = content_len; - fsm->progress_id = progress_id; - fsm->progress = progress; - - pthread_mutex_lock (&pg_lock); - g_hash_table_insert (upload_progress, g_strdup(progress_id), progress); - pthread_mutex_unlock (&pg_lock); - } - - /* Set up per-request hooks, so that we can read file data piece by piece. */ - evhtp_set_hook (&req->hooks, evhtp_hook_on_read, upload_read_cb, fsm); - evhtp_set_hook (&req->hooks, evhtp_hook_on_request_fini, upload_finish_cb, fsm); - /* Set arg for upload_cb or update_cb. */ - req->cbarg = fsm; - - g_strfreev (parts); - - return EVHTP_RES_OK; - -err: - /* Don't receive any data before the connection is closed. */ - evhtp_request_pause (req); - - /* Set keepalive to 0. This will cause evhtp to close the - * connection after sending the reply. - */ - req->keepalive = 0; - send_error_reply (req, EVHTP_RES_BADREQ, err_msg); - - g_free (repo_id); - g_free (user); - g_free (boundary); - g_free (progress_id); - g_strfreev (parts); - return EVHTP_RES_OK; -} - -static void -upload_progress_cb(evhtp_request_t *req, void *arg) -{ - const char *progress_id; - const char *callback; - Progress *progress; - GString *buf; - - progress_id = evhtp_kv_find (req->uri->query, "X-Progress-ID"); - if (!progress_id) { - seaf_debug ("[get pg] Progress id not found in url.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Progress id not found"); - return; - } - - callback = evhtp_kv_find (req->uri->query, "callback"); - if (!callback) { - seaf_debug ("[get pg] callback not found in url.\n"); - send_error_reply (req, EVHTP_RES_BADREQ, "Callback not found"); - return; - } - - pthread_mutex_lock (&pg_lock); - progress = g_hash_table_lookup (upload_progress, progress_id); - pthread_mutex_unlock (&pg_lock); - - if (!progress) { - /* seaf_warning ("[get pg] No progress found for %s.\n", progress_id); */ - send_error_reply (req, EVHTP_RES_BADREQ, "No progress found.\n"); - return; - } - - /* Return JSONP formated data. */ - buf = g_string_new (NULL); - g_string_append_printf (buf, - "%s({\"uploaded\": %"G_GINT64_FORMAT", \"length\": %"G_GINT64_FORMAT"});", - callback, progress->uploaded, progress->size); - evbuffer_add (req->buffer_out, buf->str, buf->len); - - seaf_debug ("JSONP: %s\n", buf->str); - - send_success_reply (req); - g_string_free (buf, TRUE); -} - -int -upload_file_init (evhtp_t *htp, const char *http_temp_dir) -{ - evhtp_callback_t *cb; - - if (g_mkdir_with_parents (http_temp_dir, 0777) < 0) { - seaf_warning ("Failed to create temp file dir %s.\n", - http_temp_dir); - return -1; - } - - cb = evhtp_set_regex_cb (htp, "^/upload/.*", upload_cb, NULL); - /* upload_headers_cb() will be called after evhtp parsed all http headers. */ - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/upload-api/.*", upload_api_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/upload-raw-blks-api/.*", - upload_raw_blks_api_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/upload-blks-api/.*", upload_blks_api_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/upload-blks-aj/.*", upload_blks_ajax_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/upload-aj/.*", upload_ajax_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/update/.*", update_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/update-api/.*", update_api_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/update-blks-api/.*", update_blks_api_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/update-blks-aj/.*", update_blks_ajax_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - cb = evhtp_set_regex_cb (htp, "^/update-aj/.*", update_ajax_cb, NULL); - evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL); - - evhtp_set_regex_cb (htp, "^/upload_progress.*", upload_progress_cb, NULL); - - upload_progress = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - pthread_mutex_init (&pg_lock, NULL); - - return 0; -} diff --git a/server/upload-file.h b/server/upload-file.h deleted file mode 100644 index d2cac087..00000000 --- a/server/upload-file.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UPLOAD_FILE_H -#define UPLOAD_FILE_H - -int -upload_file_init (evhtp_t *evhtp, const char *http_temp_dir); - -#endif diff --git a/server/virtual-repo.c b/server/virtual-repo.c deleted file mode 100644 index 1fd1e319..00000000 --- a/server/virtual-repo.c +++ /dev/null @@ -1,988 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include "utils.h" - -#define DEBUG_FLAG SEAFILE_DEBUG_OTHER -#include "log.h" - -#include -#include -#include - -#include "seafile-session.h" -#include "commit-mgr.h" -#include "branch-mgr.h" -#include "repo-mgr.h" -#include "fs-mgr.h" -#include "seafile-error.h" -#include "seafile-crypt.h" -#include "merge-new.h" -#include "seafile-error.h" - -#include "seaf-db.h" -#include "diff-simple.h" - -#define MAX_RUNNING_TASKS 5 -#define SCHEDULE_INTERVAL 1000 /* 1s */ - -typedef struct MergeTask { - char repo_id[37]; -} MergeTask; - -typedef struct MergeScheduler { - pthread_mutex_t q_lock; - GQueue *queue; - GHashTable *running; - CcnetJobManager *tpool; - CcnetTimer *timer; -} MergeScheduler; - -static MergeScheduler *scheduler = NULL; - -static void -add_merge_task (const char *repo_id); - -static int -save_virtual_repo_info (SeafRepoManager *mgr, - const char *repo_id, - const char *origin_repo_id, - const char *path, - const char *base_commit) -{ - int ret = 0; - - if (seaf_db_statement_query (mgr->seaf->db, - "INSERT INTO VirtualRepo VALUES (?, ?, ?, ?)", - 4, "string", repo_id, "string", origin_repo_id, - "string", path, "string", base_commit) < 0) - ret = -1; - - return ret; -} - -static int -do_create_virtual_repo (SeafRepoManager *mgr, - SeafRepo *origin_repo, - const char *repo_id, - const char *repo_name, - const char *repo_desc, - const char *root_id, - const char *user, - const char *passwd, - GError **error) -{ - SeafRepo *repo = NULL; - SeafCommit *commit = NULL; - SeafBranch *master = NULL; - int ret = 0; - - repo = seaf_repo_new (repo_id, repo_name, repo_desc); - - repo->no_local_history = TRUE; - if (passwd != NULL && passwd[0] != '\0') { - repo->encrypted = TRUE; - repo->enc_version = origin_repo->enc_version; - seafile_generate_magic (repo->enc_version, repo_id, passwd, repo->magic); - if (repo->enc_version == 2) - memcpy (repo->random_key, origin_repo->random_key, 96); - } - - /* Virtual repos share fs and block store with origin repo and - * have the same version as the origin. - */ - repo->version = origin_repo->version; - memcpy (repo->store_id, origin_repo->id, 36); - - commit = seaf_commit_new (NULL, repo->id, - root_id, /* root id */ - user, /* creator */ - EMPTY_SHA1, /* creator id */ - repo_desc, /* description */ - 0); /* ctime */ - - seaf_repo_to_commit (repo, commit); - if (seaf_commit_manager_add_commit (seaf->commit_mgr, commit) < 0) { - seaf_warning ("Failed to add commit.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add commit"); - ret = -1; - goto out; - } - - master = seaf_branch_new ("master", repo->id, commit->commit_id); - if (seaf_branch_manager_add_branch (seaf->branch_mgr, master) < 0) { - seaf_warning ("Failed to add branch.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add branch"); - ret = -1; - goto out; - } - - if (seaf_repo_set_head (repo, master) < 0) { - seaf_warning ("Failed to set repo head.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to set repo head."); - ret = -1; - goto out; - } - - if (seaf_repo_manager_add_repo (mgr, repo) < 0) { - seaf_warning ("Failed to add repo.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to add repo."); - ret = -1; - goto out; - } - -out: - if (repo) - seaf_repo_unref (repo); - if (commit) - seaf_commit_unref (commit); - if (master) - seaf_branch_unref (master); - - return ret; -} - -static void -update_repo_size(const char *repo_id) -{ - schedule_repo_size_computation (seaf->size_sched, repo_id); -} - -static char * -get_existing_virtual_repo (SeafRepoManager *mgr, - const char *origin_repo_id, - const char *path) -{ - char *sql = "SELECT repo_id FROM VirtualRepo WHERE origin_repo = ? AND path = ?"; - - return seaf_db_statement_get_string (mgr->seaf->db, sql, 2, - "string", origin_repo_id, "string", path); -} - -char * -seaf_repo_manager_create_virtual_repo (SeafRepoManager *mgr, - const char *origin_repo_id, - const char *path, - const char *repo_name, - const char *repo_desc, - const char *owner, - const char *passwd, - GError **error) -{ - SeafRepo *origin_repo = NULL; - SeafCommit *origin_head = NULL; - char *repo_id = NULL; - char *dir_id = NULL; - char *orig_owner = NULL; - - if (seaf_repo_manager_is_virtual_repo (mgr, origin_repo_id)) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Cannot create sub-library from a sub-library"); - return NULL; - } - - repo_id = get_existing_virtual_repo (mgr, origin_repo_id, path); - if (repo_id) { - return repo_id; - } - - origin_repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); - if (!origin_repo) { - seaf_warning ("Failed to get origin repo %.10s\n", origin_repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Origin library not exists"); - return NULL; - } - - if (origin_repo->encrypted) { - if (origin_repo->enc_version < 2) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Library encryption version must be higher than 2"); - seaf_repo_unref (origin_repo); - return NULL; - } - - if (!passwd || passwd[0] == 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, - "Password is not set"); - seaf_repo_unref (origin_repo); - return NULL; - } - - if (seafile_verify_repo_passwd (origin_repo_id, - passwd, - origin_repo->magic, - origin_repo->enc_version) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Incorrect password"); - seaf_repo_unref (origin_repo); - return NULL; - } - } - - origin_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - origin_repo->id, - origin_repo->version, - origin_repo->head->commit_id); - if (!origin_head) { - seaf_warning ("Failed to get head commit %.8s of repo %s.\n", - origin_repo->head->commit_id, origin_repo->id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Bad origin repo head"); - goto error; - } - - dir_id = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, - origin_repo->store_id, - origin_repo->version, - origin_head->root_id, - path, NULL); - if (!dir_id) { - seaf_warning ("Path %s doesn't exist or is not a dir in repo %.10s.\n", - path, origin_repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad path"); - goto error; - } - - repo_id = gen_uuid(); - - /* Save virtual repo info before actually create the repo. - */ - if (save_virtual_repo_info (mgr, repo_id, origin_repo_id, - path, origin_head->commit_id) < 0) { - seaf_warning ("Failed to save virtual repo info for %.10s:%s", - origin_repo_id, path); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Internal error"); - goto error; - } - - orig_owner = seaf_repo_manager_get_repo_owner (mgr, origin_repo_id); - - if (do_create_virtual_repo (mgr, origin_repo, repo_id, repo_name, repo_desc, - dir_id, orig_owner, passwd, error) < 0) - goto error; - - if (seaf_repo_manager_set_repo_owner (mgr, repo_id, orig_owner) < 0) { - seaf_warning ("Failed to set repo owner for %.10s.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to set repo owner."); - goto error; - } - - /* The size of virtual repo is non-zero at the beginning. */ - update_repo_size (repo_id); - - seaf_repo_unref (origin_repo); - seaf_commit_unref (origin_head); - g_free (dir_id); - g_free (orig_owner); - return repo_id; - -error: - seaf_repo_unref (origin_repo); - seaf_commit_unref (origin_head); - g_free (repo_id); - g_free (dir_id); - g_free (orig_owner); - return NULL; -} - -static gboolean -load_virtual_info (SeafDBRow *row, void *p_vinfo) -{ - SeafVirtRepo *vinfo; - const char *repo_id, *origin_repo_id, *path, *base_commit; - - repo_id = seaf_db_row_get_column_text (row, 0); - origin_repo_id = seaf_db_row_get_column_text (row, 1); - path = seaf_db_row_get_column_text (row, 2); - base_commit = seaf_db_row_get_column_text (row, 3); - - vinfo = g_new0 (SeafVirtRepo, 1); - memcpy (vinfo->repo_id, repo_id, 36); - memcpy (vinfo->origin_repo_id, origin_repo_id, 36); - vinfo->path = g_strdup(path); - memcpy (vinfo->base_commit, base_commit, 40); - - *((SeafVirtRepo **)p_vinfo) = vinfo; - - return FALSE; -} - -SeafVirtRepo * -seaf_repo_manager_get_virtual_repo_info (SeafRepoManager *mgr, - const char *repo_id) -{ - char *sql; - SeafVirtRepo *vinfo = NULL; - - sql = "SELECT repo_id, origin_repo, path, base_commit FROM VirtualRepo " - "WHERE repo_id = ?"; - seaf_db_statement_foreach_row (seaf->db, sql, load_virtual_info, &vinfo, - 1, "string", repo_id); - - return vinfo; -} - -void -seaf_virtual_repo_info_free (SeafVirtRepo *vinfo) -{ - if (!vinfo) return; - - g_free (vinfo->path); - g_free (vinfo); -} - -gboolean -seaf_repo_manager_is_virtual_repo (SeafRepoManager *mgr, const char *repo_id) -{ - gboolean db_err; - - char *sql = "SELECT 1 FROM VirtualRepo WHERE repo_id = ?"; - return seaf_db_statement_exists (seaf->db, sql, &db_err, - 1, "string", repo_id); -} - -char * -seaf_repo_manager_get_virtual_repo_id (SeafRepoManager *mgr, - const char *origin_repo, - const char *path, - const char *owner) -{ - char *sql; - char *ret; - - sql = "SELECT RepoOwner.repo_id FROM RepoOwner, VirtualRepo " - "WHERE owner_id=? AND origin_repo=? AND path=? " - "AND RepoOwner.repo_id = VirtualRepo.repo_id"; - - ret = seaf_db_statement_get_string (mgr->seaf->db, sql, - 3, "string", owner, "string", origin_repo, - "string", path); - - return ret; -} - -static gboolean -collect_virtual_repo_ids (SeafDBRow *row, void *data) -{ - GList **p_ids = data; - const char *repo_id; - - repo_id = seaf_db_row_get_column_text (row, 0); - *p_ids = g_list_prepend (*p_ids, g_strdup(repo_id)); - - return TRUE; -} - -GList * -seaf_repo_manager_get_virtual_repos_by_owner (SeafRepoManager *mgr, - const char *owner, - GError **error) -{ - GList *id_list = NULL, *ptr; - GList *ret = NULL; - char *sql; - - sql = "SELECT RepoOwner.repo_id FROM RepoOwner, VirtualRepo " - "WHERE owner_id=? " - "AND RepoOwner.repo_id = VirtualRepo.repo_id"; - - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_virtual_repo_ids, &id_list, - 1, "string", owner) < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "DB error"); - return NULL; - } - - char *repo_id; - SeafRepo *repo; - for (ptr = id_list; ptr; ptr = ptr->next) { - repo_id = ptr->data; - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (repo != NULL) - ret = g_list_prepend (ret, repo); - } - - string_list_free (id_list); - return ret; -} - -GList * -seaf_repo_manager_get_virtual_repo_ids_by_origin (SeafRepoManager *mgr, - const char *origin_repo) -{ - GList *ret = NULL; - char *sql; - - sql = "SELECT repo_id FROM VirtualRepo WHERE origin_repo=?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_virtual_repo_ids, &ret, - 1, "string", origin_repo) < 0) { - return NULL; - } - - return g_list_reverse (ret); -} - -static gboolean -collect_virtual_info (SeafDBRow *row, void *plist) -{ - GList **pret = plist; - SeafVirtRepo *vinfo; - const char *repo_id, *origin_repo_id, *path, *base_commit; - - repo_id = seaf_db_row_get_column_text (row, 0); - origin_repo_id = seaf_db_row_get_column_text (row, 1); - path = seaf_db_row_get_column_text (row, 2); - base_commit = seaf_db_row_get_column_text (row, 3); - - vinfo = g_new0 (SeafVirtRepo, 1); - memcpy (vinfo->repo_id, repo_id, 36); - memcpy (vinfo->origin_repo_id, origin_repo_id, 36); - vinfo->path = g_strdup(path); - memcpy (vinfo->base_commit, base_commit, 40); - - *pret = g_list_prepend (*pret, vinfo); - - return TRUE; -} - -GList * -seaf_repo_manager_get_virtual_info_by_origin (SeafRepoManager *mgr, - const char *origin_repo) -{ - GList *ret = NULL; - char *sql; - - sql = "SELECT repo_id, origin_repo, path, base_commit " - "FROM VirtualRepo WHERE origin_repo=?"; - if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, - collect_virtual_info, &ret, - 1, "string", origin_repo) < 0) { - return NULL; - } - - return g_list_reverse (ret); -} - -static void -set_virtual_repo_base_commit_path (const char *vrepo_id, const char *base_commit_id, - const char *new_path) -{ - seaf_db_statement_query (seaf->db, - "UPDATE VirtualRepo SET base_commit=?, path=? WHERE repo_id=?", - 3, "string", base_commit_id, "string", new_path, - "string", vrepo_id); -} - -int -seaf_repo_manager_merge_virtual_repo (SeafRepoManager *mgr, - const char *repo_id, - const char *exclude_repo) -{ - GList *vrepos = NULL, *ptr; - char *vrepo_id; - int ret = 0; - - if (seaf_repo_manager_is_virtual_repo (mgr, repo_id)) { - add_merge_task (repo_id); - return 0; - } - - vrepos = seaf_repo_manager_get_virtual_repo_ids_by_origin (mgr, repo_id); - for (ptr = vrepos; ptr; ptr = ptr->next) { - vrepo_id = ptr->data; - - if (g_strcmp0 (exclude_repo, vrepo_id) == 0) - continue; - - add_merge_task (vrepo_id); - } - - string_list_free (vrepos); - return ret; -} - -/* - * If the missing virtual repo is renamed, update database entry; - * otherwise delete the virtual repo. - */ -static void -handle_missing_virtual_repo (SeafRepoManager *mgr, - SeafRepo *repo, SeafCommit *head, SeafVirtRepo *vinfo) -{ - SeafCommit *parent = NULL; - char *old_dir_id = NULL; - GList *diff_res = NULL, *ptr; - DiffEntry *de; - - parent = seaf_commit_manager_get_commit (seaf->commit_mgr, - head->repo_id, head->version, - head->parent_id); - if (!parent) { - seaf_warning ("Failed to find commit %s:%s.\n", head->repo_id, head->parent_id); - return; - } - - int rc = diff_commits (parent, head, &diff_res, TRUE); - if (rc < 0) { - seaf_warning ("Failed to diff commit %s to %s.\n", - parent->commit_id, head->commit_id); - seaf_commit_unref (parent); - return; - } - - char *path = vinfo->path, *sub_path, *p, *par_path; - gboolean is_renamed = FALSE; - p = &path[strlen(path)]; - par_path = g_strdup(path); - sub_path = NULL; - - while (1) { - GError *error = NULL; - old_dir_id = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, - repo->store_id, - repo->version, - parent->root_id, - par_path, &error); - if (!old_dir_id) { - if (error && error->code == SEAF_ERR_PATH_NO_EXIST) { - seaf_warning ("Failed to find %s under commit %s in repo %s.\n", - par_path, parent->commit_id, repo->store_id); - seaf_debug ("Delete virtual repo %.10s.\n", vinfo->repo_id); - seaf_repo_manager_del_virtual_repo (mgr, vinfo->repo_id); - g_clear_error (&error); - } - goto out; - } - - char de_id[41]; - char *new_path; - - for (ptr = diff_res; ptr; ptr = ptr->next) { - de = ptr->data; - if (de->status == DIFF_STATUS_DIR_RENAMED) { - rawdata_to_hex (de->sha1, de_id, 20); - if (strcmp (de_id, old_dir_id) == 0) { - if (sub_path != NULL) - new_path = g_strconcat ("/", de->new_name, "/", sub_path, NULL); - else - new_path = g_strconcat ("/", de->new_name, NULL); - seaf_debug ("Updating path of virtual repo %s to %s.\n", - vinfo->repo_id, new_path); - set_virtual_repo_base_commit_path (vinfo->repo_id, - head->commit_id, new_path); - is_renamed = TRUE; - break; - } - } - } - g_free (old_dir_id); - - if (is_renamed) - break; - - while (--p != path && *p != '/'); - - if (p == path) - break; - - g_free (par_path); - g_free (sub_path); - par_path = g_strndup (path, p - path); - sub_path = g_strdup (p + 1); - } - - if (!is_renamed) { - seaf_debug ("Delete virtual repo %.10s.\n", vinfo->repo_id); - seaf_repo_manager_del_virtual_repo (mgr, vinfo->repo_id); - } - -out: - g_free (par_path); - g_free (sub_path); - - for (ptr = diff_res; ptr; ptr = ptr->next) - diff_entry_free ((DiffEntry *)ptr->data); - g_list_free (diff_res); - - seaf_commit_unref (parent); -} - -void -seaf_repo_manager_cleanup_virtual_repos (SeafRepoManager *mgr, - const char *origin_repo_id) -{ - SeafRepo *repo = NULL; - SeafCommit *head = NULL; - GList *vinfo_list = NULL, *ptr; - SeafVirtRepo *vinfo; - SeafDir *dir; - GError *error = NULL; - - repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %.10s.\n", origin_repo_id); - goto out; - } - - head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, - repo->version, - repo->head->commit_id); - if (!head) { - seaf_warning ("Failed to get commit %s:%.8s.\n", - repo->id, repo->head->commit_id); - goto out; - } - - vinfo_list = seaf_repo_manager_get_virtual_info_by_origin (mgr, - origin_repo_id); - for (ptr = vinfo_list; ptr; ptr = ptr->next) { - vinfo = ptr->data; - dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, - repo->store_id, - repo->version, - head->root_id, - vinfo->path, - &error); - if (error) { - if (error->code == SEAF_ERR_PATH_NO_EXIST) { - handle_missing_virtual_repo (mgr, repo, head, vinfo); - } - g_clear_error (&error); - } else - seaf_dir_free (dir); - seaf_virtual_repo_info_free (vinfo); - } - -out: - seaf_repo_unref (repo); - seaf_commit_unref (head); - g_list_free (vinfo_list); -} - -static void *merge_virtual_repo (void *vtask) -{ - MergeTask *task = vtask; - SeafRepoManager *mgr = seaf->repo_mgr; - char *repo_id = task->repo_id; - SeafVirtRepo *vinfo; - SeafRepo *repo = NULL, *orig_repo = NULL; - SeafCommit *head = NULL, *orig_head = NULL, *base = NULL; - char *root = NULL, *orig_root = NULL, *base_root = NULL; - char new_base_commit[41] = {0}; - int ret = 0; - - /* repos */ - repo = seaf_repo_manager_get_repo (mgr, repo_id); - if (!repo) { - seaf_warning ("Failed to get virt repo %.10s.\n", repo_id); - ret = -1; - goto out; - } - - vinfo = repo->virtual_info; - - orig_repo = seaf_repo_manager_get_repo (mgr, vinfo->origin_repo_id); - if (!orig_repo) { - seaf_warning ("Failed to get orig repo %.10s.\n", vinfo->origin_repo_id); - ret = -1; - goto out; - } - - /* commits */ - head = seaf_commit_manager_get_commit (seaf->commit_mgr, - repo->id, repo->version, - repo->head->commit_id); - if (!head) { - seaf_warning ("Failed to get commit %s:%.8s.\n", - repo->id, repo->head->commit_id); - ret = -1; - goto out; - } - - orig_head = seaf_commit_manager_get_commit (seaf->commit_mgr, - orig_repo->id, orig_repo->version, - orig_repo->head->commit_id); - if (!orig_head) { - seaf_warning ("Failed to get commit %s:%.8s.\n", - orig_repo->id, orig_repo->head->commit_id); - ret = -1; - goto out; - } - - base = seaf_commit_manager_get_commit (seaf->commit_mgr, - orig_repo->id, orig_repo->version, - vinfo->base_commit); - if (!base) { - seaf_warning ("Failed to get commit %s:%.8s.\n", - orig_repo->id, vinfo->base_commit); - ret = -1; - goto out; - } - - /* fs roots */ - root = head->root_id; - - base_root = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, - orig_repo->store_id, - orig_repo->version, - base->root_id, - vinfo->path, - NULL); - if (!base_root) { - seaf_warning ("Cannot find seafdir for repo %.10s path %s.\n", - vinfo->origin_repo_id, vinfo->path); - ret = -1; - goto out; - } - - orig_root = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, - orig_repo->store_id, - orig_repo->version, - orig_head->root_id, - vinfo->path, - NULL); - if (!orig_root) { - seaf_warning ("Cannot find seafdir for repo %.10s path %s.\n", - vinfo->origin_repo_id, vinfo->path); - ret = -1; - goto out; - } - - if (strcmp (root, orig_root) == 0) { - /* Nothing to merge. */ - seaf_debug ("Nothing to merge.\n"); - } else if (strcmp (base_root, root) == 0) { - /* Origin changed, virtual repo not changed. */ - seaf_debug ("Origin changed, virtual repo not changed.\n"); - ret = seaf_repo_manager_update_dir (mgr, - repo_id, - "/", - orig_root, - orig_head->creator_name, - head->commit_id, - NULL, - NULL); - if (ret < 0) { - seaf_warning ("Failed to update root of virtual repo %.10s.\n", - repo_id); - goto out; - } - - set_virtual_repo_base_commit_path (repo->id, orig_repo->head->commit_id, - vinfo->path); - } else if (strcmp (base_root, orig_root) == 0) { - /* Origin not changed, virutal repo changed. */ - seaf_debug ("Origin not changed, virutal repo changed.\n"); - ret = seaf_repo_manager_update_dir (mgr, - vinfo->origin_repo_id, - vinfo->path, - root, - head->creator_name, - orig_head->commit_id, - new_base_commit, - NULL); - if (ret < 0) { - seaf_warning ("Failed to update origin repo %.10s path %s.\n", - vinfo->origin_repo_id, vinfo->path); - goto out; - } - - set_virtual_repo_base_commit_path (repo->id, new_base_commit, vinfo->path); - - /* Since origin repo is updated, we have to merge it with other - * virtual repos if necessary. But we don't need to merge with - * the current virtual repo again. - */ - seaf_repo_manager_cleanup_virtual_repos (mgr, vinfo->origin_repo_id); - seaf_repo_manager_merge_virtual_repo (mgr, - vinfo->origin_repo_id, - repo_id); - } else { - /* Both origin and virtual repo are changed. */ - seaf_debug ("Both origin and virtual repo are changed.\n"); - MergeOptions opt; - const char *roots[3]; - - memset (&opt, 0, sizeof(opt)); - opt.n_ways = 3; - memcpy (opt.remote_repo_id, repo_id, 36); - memcpy (opt.remote_head, head->commit_id, 40); - opt.do_merge = TRUE; - - roots[0] = base_root; /* base */ - roots[1] = orig_root; /* head */ - roots[2] = root; /* remote */ - - /* Merge virtual into origin */ - if (seaf_merge_trees (orig_repo->store_id, orig_repo->version, - 3, roots, &opt) < 0) { - seaf_warning ("Failed to merge virtual repo %.10s.\n", repo_id); - ret = -1; - goto out; - } - - seaf_debug ("Number of dirs visted in merge: %d.\n", opt.visit_dirs); - - /* Update virtual repo root. */ - ret = seaf_repo_manager_update_dir (mgr, - repo_id, - "/", - opt.merged_tree_root, - orig_head->creator_name, - head->commit_id, - NULL, - NULL); - if (ret < 0) { - seaf_warning ("Failed to update root of virtual repo %.10s.\n", - repo_id); - goto out; - } - - /* Update origin repo path. */ - ret = seaf_repo_manager_update_dir (mgr, - vinfo->origin_repo_id, - vinfo->path, - opt.merged_tree_root, - head->creator_name, - orig_head->commit_id, - new_base_commit, - NULL); - if (ret < 0) { - seaf_warning ("Failed to update origin repo %.10s path %s.\n", - vinfo->origin_repo_id, vinfo->path); - goto out; - } - - set_virtual_repo_base_commit_path (repo->id, new_base_commit, vinfo->path); - - seaf_repo_manager_cleanup_virtual_repos (mgr, vinfo->origin_repo_id); - seaf_repo_manager_merge_virtual_repo (mgr, - vinfo->origin_repo_id, - repo_id); - } - -out: - seaf_repo_unref (repo); - seaf_repo_unref (orig_repo); - seaf_commit_unref (head); - seaf_commit_unref (orig_head); - seaf_commit_unref (base); - g_free (base_root); - g_free (orig_root); - return vtask; -} - -static void merge_virtual_repo_done (void *vtask) -{ - MergeTask *task = vtask; - - seaf_debug ("Task %.8s done.\n", task->repo_id); - - g_hash_table_remove (scheduler->running, task->repo_id); -} - -static int -schedule_merge_tasks (void *vscheduler) -{ - MergeScheduler *scheduler = vscheduler; - int n_running = g_hash_table_size (scheduler->running); - MergeTask *task; - - /* seaf_debug ("Waiting tasks %d, running tasks %d.\n", */ - /* g_queue_get_length (scheduler->queue), n_running); */ - - if (n_running >= MAX_RUNNING_TASKS) - return TRUE; - - pthread_mutex_lock (&scheduler->q_lock); - - while (n_running < MAX_RUNNING_TASKS) { - task = g_queue_pop_head (scheduler->queue); - if (!task) - break; - - if (!g_hash_table_lookup (scheduler->running, task->repo_id)) { - int ret = ccnet_job_manager_schedule_job (scheduler->tpool, - merge_virtual_repo, - merge_virtual_repo_done, - task); - if (ret < 0) { - g_queue_push_tail (scheduler->queue, task); - break; - } - - g_hash_table_insert (scheduler->running, - g_strdup(task->repo_id), - task); - n_running++; - - seaf_debug ("Run task for repo %.8s.\n", task->repo_id); - } else { - seaf_debug ("A task for repo %.8s is already running.\n", task->repo_id); - - g_queue_push_tail (scheduler->queue, task); - break; - } - } - - pthread_mutex_unlock (&scheduler->q_lock); - - return TRUE; -} - -static gint task_cmp (gconstpointer a, gconstpointer b) -{ - const MergeTask *task_a = a; - const MergeTask *task_b = b; - - return strcmp (task_a->repo_id, task_b->repo_id); -} - -static void -add_merge_task (const char *repo_id) -{ - MergeTask *task = g_new0 (MergeTask, 1); - - seaf_debug ("Add merge task for repo %.8s.\n", repo_id); - - memcpy (task->repo_id, repo_id, 36); - - pthread_mutex_lock (&scheduler->q_lock); - - if (g_queue_find_custom (scheduler->queue, task, task_cmp) != NULL) { - seaf_debug ("Task for repo %.8s is already queued.\n", repo_id); - g_free (task); - } else - g_queue_push_tail (scheduler->queue, task); - - pthread_mutex_unlock (&scheduler->q_lock); -} - -int -seaf_repo_manager_init_merge_scheduler () -{ - scheduler = g_new0 (MergeScheduler, 1); - if (!scheduler) - return -1; - - pthread_mutex_init (&scheduler->q_lock, NULL); - - scheduler->queue = g_queue_new (); - scheduler->running = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - scheduler->tpool = ccnet_job_manager_new (MAX_RUNNING_TASKS); - scheduler->timer = ccnet_timer_new (schedule_merge_tasks, - scheduler, - SCHEDULE_INTERVAL); - return 0; -} diff --git a/server/web-accesstoken-mgr.c b/server/web-accesstoken-mgr.c deleted file mode 100644 index f321fee2..00000000 --- a/server/web-accesstoken-mgr.c +++ /dev/null @@ -1,238 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "common.h" - -#include - -#include - -#include "seafile-session.h" -#include "web-accesstoken-mgr.h" -#include "seafile-error.h" - -#include "utils.h" - -#include "log.h" - -#define CLEANING_INTERVAL_MSEC 1000*300 /* 5 minutes */ -#define TOKEN_EXPIRE_TIME 3600 /* 1 hour */ -#define TOKEN_LEN 36 - -struct WebATPriv { - GHashTable *access_token_hash; /* token -> access info */ - pthread_mutex_t lock; - - gboolean cluster_mode; - struct ObjCache *cache; -}; -typedef struct WebATPriv WebATPriv; - -/* #define DEBUG 1 */ - -typedef struct { - char *repo_id; - char *obj_id; - char *op; - char *username; - long expire_time; - gboolean use_onetime; -} AccessInfo; - -static void -free_access_info (AccessInfo *info) -{ - if (!info) - return; - - g_free (info->repo_id); - g_free (info->obj_id); - g_free (info->op); - g_free (info->username); - g_free (info); -} - -SeafWebAccessTokenManager* -seaf_web_at_manager_new (SeafileSession *session) -{ - SeafWebAccessTokenManager *mgr = g_new0 (SeafWebAccessTokenManager, 1); - - mgr->seaf = session; - - mgr->priv = g_new0(WebATPriv, 1); - mgr->priv->access_token_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, - (GDestroyNotify)free_access_info); - pthread_mutex_init (&mgr->priv->lock, NULL); - - return mgr; -} - -static gboolean -remove_expire_info (gpointer key, gpointer value, gpointer user_data) -{ - AccessInfo *info = (AccessInfo *)value; - long now = *((long*)user_data); - - if (info && now >= info->expire_time) { - return TRUE; - } - - return FALSE; -} - -static int -clean_pulse (void *vmanager) -{ - SeafWebAccessTokenManager *manager = vmanager; - long now = (long)time(NULL); - - pthread_mutex_lock (&manager->priv->lock); - - g_hash_table_foreach_remove (manager->priv->access_token_hash, - remove_expire_info, &now); - - pthread_mutex_unlock (&manager->priv->lock); - - return TRUE; -} - -int -seaf_web_at_manager_start (SeafWebAccessTokenManager *mgr) -{ - ccnet_timer_new (clean_pulse, mgr, CLEANING_INTERVAL_MSEC); - - return 0; -} - -static char * -gen_new_token (GHashTable *token_hash) -{ - char uuid[37]; - char *token; - - while (1) { - gen_uuid_inplace (uuid); - token = g_strndup(uuid, TOKEN_LEN); - - /* Make sure the new token doesn't conflict with an existing one. */ - if (g_hash_table_lookup (token_hash, token) != NULL) - g_free (token); - else - return token; - } -} - -char * -seaf_web_at_manager_get_access_token (SeafWebAccessTokenManager *mgr, - const char *repo_id, - const char *obj_id, - const char *op, - const char *username, - int use_onetime, - GError **error) -{ - GString *key; - AccessInfo *info; - long now = (long)time(NULL); - long expire; - char *t; - SeafileWebAccess *webaccess; - - if (strcmp(op, "view") != 0 && - strcmp(op, "download") != 0 && - strcmp(op, "downloadblks") != 0 && - strcmp(op, "download-dir") != 0 && - strcmp(op, "download-multi") != 0 && - strcmp(op, "upload") != 0 && - strcmp(op, "update") != 0 && - strcmp(op, "upload-blks-api") != 0 && - strcmp(op, "upload-blks-aj") != 0 && - strcmp(op, "update-blks-api") != 0 && - strcmp(op, "update-blks-aj") != 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Invalid operation type."); - return NULL; - } - - pthread_mutex_lock (&mgr->priv->lock); - - t = gen_new_token (mgr->priv->access_token_hash); - expire = now + TOKEN_EXPIRE_TIME; - - info = g_new0 (AccessInfo, 1); - info->repo_id = g_strdup (repo_id); - info->obj_id = g_strdup (obj_id); - info->op = g_strdup (op); - info->username = g_strdup (username); - info->expire_time = expire; - if (use_onetime) { - info->use_onetime = TRUE; - } - - g_hash_table_insert (mgr->priv->access_token_hash, g_strdup(t), info); - - pthread_mutex_unlock (&mgr->priv->lock); - - if (strcmp(op, "download-dir") == 0 || - strcmp(op, "download-multi") == 0) { - - webaccess = g_object_new (SEAFILE_TYPE_WEB_ACCESS, - "repo_id", info->repo_id, - "obj_id", info->obj_id, - "op", info->op, - "username", info->username, - NULL); - - if (zip_download_mgr_start_zip_task (seaf->zip_download_mgr, - t, webaccess, error) < 0) { - pthread_mutex_lock (&mgr->priv->lock); - g_hash_table_remove (mgr->priv->access_token_hash, t); - pthread_mutex_unlock (&mgr->priv->lock); - - g_object_unref (webaccess); - g_free (t); - return NULL; - } - g_object_unref (webaccess); - } - - return t; -} - -SeafileWebAccess * -seaf_web_at_manager_query_access_token (SeafWebAccessTokenManager *mgr, - const char *token) -{ - SeafileWebAccess *webaccess; - AccessInfo *info; - - pthread_mutex_lock (&mgr->priv->lock); - info = g_hash_table_lookup (mgr->priv->access_token_hash, token); - pthread_mutex_unlock (&mgr->priv->lock); - - if (info != NULL) { - long expire_time = info->expire_time; - long now = (long)time(NULL); - - if (now - expire_time >= 0) { - return NULL; - } else { - webaccess = g_object_new (SEAFILE_TYPE_WEB_ACCESS, - "repo_id", info->repo_id, - "obj_id", info->obj_id, - "op", info->op, - "username", info->username, - NULL); - - if (info->use_onetime) { - pthread_mutex_lock (&mgr->priv->lock); - g_hash_table_remove (mgr->priv->access_token_hash, token); - pthread_mutex_unlock (&mgr->priv->lock); - } - - return webaccess; - } - } - - return NULL; -} diff --git a/server/web-accesstoken-mgr.h b/server/web-accesstoken-mgr.h deleted file mode 100644 index b2d310f5..00000000 --- a/server/web-accesstoken-mgr.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#ifndef WEB_ACCESSTOKEN_MGR_H -#define WEB_ACCESSTOKEN_MGR_H - -struct _SeafileSession; - -struct WebATPriv; - -struct _SeafWebAccessTokenManager { - struct _SeafileSession *seaf; - struct WebATPriv *priv; -}; -typedef struct _SeafWebAccessTokenManager SeafWebAccessTokenManager; - -SeafWebAccessTokenManager* seaf_web_at_manager_new (struct _SeafileSession *seaf); - -int -seaf_web_at_manager_start (SeafWebAccessTokenManager *mgr); - -/* - * Returns an access token for the given access info. - * If a token doesn't exist or has expired, generate and return a new one. - */ -char * -seaf_web_at_manager_get_access_token (SeafWebAccessTokenManager *mgr, - const char *repo_id, - const char *obj_id, - const char *op, - const char *username, - int use_onetime, - GError **error); - -/* - * Returns access info for the given token. - */ -SeafileWebAccess * -seaf_web_at_manager_query_access_token (SeafWebAccessTokenManager *mgr, - const char *token); - -#endif /* WEB_ACCESSTOKEN_MGR_H */ - diff --git a/server/zip-download-mgr.c b/server/zip-download-mgr.c deleted file mode 100644 index 7ae8b443..00000000 --- a/server/zip-download-mgr.c +++ /dev/null @@ -1,604 +0,0 @@ -#include -#include - -#include - -#include "common.h" -#include "utils.h" -#include "log.h" -#include "seafile-error.h" -#include "seafile-session.h" -#include "pack-dir.h" -#include "web-accesstoken-mgr.h" -#include "zip-download-mgr.h" - -#define MAX_ZIP_THREAD_NUM 5 -#define SCAN_PROGRESS_INTERVAL 24 * 3600 // 1 day -#define PROGRESS_TTL 5 * 3600 // 5 hours - -typedef struct ZipDownloadMgrPriv { - pthread_mutex_t progress_lock; - GHashTable *progress_store; - GThreadPool *zip_tpool; - // Abnormal behavior lead to no download request for the zip finished progress, - // so related progress will not be removed, - // this timer is used to scan progress and remove invalid progress. - CcnetTimer *scan_progress_timer; -} ZipDownloadMgrPriv; - -void -free_progress (Progress *progress) -{ - if (!progress) - return; - - if (g_file_test (progress->zip_file_path, G_FILE_TEST_EXISTS)) { - g_unlink (progress->zip_file_path); - } - g_free (progress->zip_file_path); - g_free (progress); -} - -typedef enum DownloadType { - DOWNLOAD_DIR, - DOWNLOAD_MULTI -} DownloadType; - -typedef struct DownloadObj { - char *token; - DownloadType type; - SeafRepo *repo; - char *user; - gboolean is_windows; - // download-dir: top dir name; download-multi: "" - char *dir_name; - // download-dir: obj_id; download-multi: dirent list - void *internal; - Progress *progress; -} DownloadObj; - -static void -free_download_obj (DownloadObj *obj) -{ - if (!obj) - return; - - g_free (obj->token); - seaf_repo_unref (obj->repo); - g_free (obj->user); - g_free (obj->dir_name); - if (obj->type == DOWNLOAD_DIR) { - g_free ((char *)obj->internal); - } else { - g_list_free_full ((GList *)obj->internal, (GDestroyNotify)seaf_dirent_free); - } - g_free (obj); -} - -static void -start_zip_task (gpointer data, gpointer user_data); - -static int -scan_progress (void *data); - -ZipDownloadMgr * -zip_download_mgr_new () -{ - GError *error = NULL; - ZipDownloadMgr *mgr = g_new0 (ZipDownloadMgr, 1); - ZipDownloadMgrPriv *priv = g_new0 (ZipDownloadMgrPriv, 1); - - priv->zip_tpool = g_thread_pool_new (start_zip_task, priv, MAX_ZIP_THREAD_NUM, FALSE, &error); - if (!priv->zip_tpool) { - if (error) { - seaf_warning ("Failed to create zip task thread pool: %s.\n", error->message); - g_clear_error (&error); - } else { - seaf_warning ("Failed to create zip task thread pool.\n"); - } - g_free (priv); - g_free (mgr); - return NULL; - } - - pthread_mutex_init (&priv->progress_lock, NULL); - priv->progress_store = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GDestroyNotify)free_progress); - priv->scan_progress_timer = ccnet_timer_new (scan_progress, priv, - SCAN_PROGRESS_INTERVAL * 1000); - mgr->priv = priv; - - return mgr; -} - -static void -remove_progress_by_token (ZipDownloadMgrPriv *priv, const char *token) -{ - pthread_mutex_lock (&priv->progress_lock); - g_hash_table_remove (priv->progress_store, token); - pthread_mutex_unlock (&priv->progress_lock); -} - -static int -scan_progress (void *data) -{ - time_t now = time(NULL); - ZipDownloadMgrPriv *priv = data; - GHashTableIter iter; - gpointer key, value; - Progress *progress; - - pthread_mutex_lock (&priv->progress_lock); - - g_hash_table_iter_init (&iter, priv->progress_store); - while (g_hash_table_iter_next (&iter, &key, &value)) { - progress = value; - if (now >= progress->expire_ts) { - g_hash_table_iter_remove (&iter); - } - } - - pthread_mutex_unlock (&priv->progress_lock); - - return TRUE; -} - -static SeafileCrypt * -get_seafile_crypt (SeafRepo *repo, const char *user) -{ - SeafileCryptKey *key = NULL; - char *key_hex, *iv_hex; - unsigned char enc_key[32], enc_iv[16]; - SeafileCrypt *crypt = NULL; - - key = seaf_passwd_manager_get_decrypt_key (seaf->passwd_mgr, - repo->id, user); - if (!key) { - seaf_warning ("Failed to get derypt key for repo %.8s.\n", repo->id); - return NULL; - } - - g_object_get (key, "key", &key_hex, "iv", &iv_hex, NULL); - if (repo->enc_version == 1) - hex_to_rawdata (key_hex, enc_key, 16); - else - hex_to_rawdata (key_hex, enc_key, 32); - hex_to_rawdata (iv_hex, enc_iv, 16); - crypt = seafile_crypt_new (repo->enc_version, enc_key, enc_iv); - g_free (key_hex); - g_free (iv_hex); - g_object_unref (key); - - return crypt; -} - -static void -start_zip_task (gpointer data, gpointer user_data) -{ - DownloadObj *obj = data; - ZipDownloadMgrPriv *priv = user_data; - SeafRepo *repo = obj->repo; - SeafileCrypt *crypt = NULL; - int ret = 0; - - if (repo->encrypted) { - crypt = get_seafile_crypt (repo, obj->user); - if (!crypt) { - ret = -1; - goto out; - } - } - - ret = pack_files (repo->store_id, repo->version, obj->dir_name, - obj->internal, crypt, obj->is_windows, obj->progress); - -out: - if (crypt) { - g_free (crypt); - } - if (ret == -1) { - remove_progress_by_token (priv, obj->token); - } - free_download_obj (obj); -} - -static int -parse_download_dir_data (DownloadObj *obj, const char *data) -{ - json_t *jobj; - json_error_t jerror; - const char *dir_name; - const char *obj_id; - - jobj = json_loadb (data, strlen(data), 0, &jerror); - if (!jobj) { - seaf_warning ("Failed to parse download dir data: %s.\n", jerror.text); - return -1; - } - - obj->is_windows = json_object_get_int_member (jobj, "is_windows"); - - dir_name = json_object_get_string_member (jobj, "dir_name"); - if (!dir_name || strcmp (dir_name, "") == 0) { - seaf_warning ("Invalid download dir data: miss dir_name filed.\n"); - json_decref (jobj); - return -1; - } - - obj_id = json_object_get_string_member (jobj, "obj_id"); - if (!obj_id || strcmp (obj_id, "") == 0) { - seaf_warning ("Invalid download dir data: miss obj_id filed.\n"); - json_decref (jobj); - return -1; - } - - obj->dir_name = g_strdup (dir_name); - obj->internal = g_strdup (obj_id); - - json_decref (jobj); - - return 0; -} - -static int -parse_download_multi_data (DownloadObj *obj, const char *data) -{ - json_t *jobj; - SeafRepo *repo = obj->repo; - const char *tmp_parent_dir; - char *parent_dir; - gboolean is_root_dir; - json_t *name_array; - json_error_t jerror; - int i; - int len; - const char *file_name; - char *file_path; - SeafDirent *dirent; - GList *dirent_list = NULL; - GError *error = NULL; - - jobj = json_loadb (data, strlen(data), 0, &jerror); - if (!jobj) { - seaf_warning ("Failed to parse download multi data: %s.\n", jerror.text); - return -1; - } - - obj->is_windows = json_object_get_int_member (jobj, "is_windows"); - - tmp_parent_dir = json_object_get_string_member (jobj, "parent_dir"); - if (!tmp_parent_dir || strcmp (tmp_parent_dir, "") == 0) { - seaf_warning ("Invalid download multi data, miss parent_dir field.\n"); - json_decref (jobj); - return -1; - } - name_array = json_object_get (jobj, "file_list"); - if (!name_array) { - seaf_warning ("Invalid download multi data, miss file_list field.\n"); - json_decref (jobj); - return -1; - } - len = json_array_size (name_array); - if (len == 0) { - seaf_warning ("Invalid download multi data, miss download file name.\n"); - json_decref (jobj); - return -1; - } - parent_dir = format_dir_path (tmp_parent_dir); - is_root_dir = strcmp (parent_dir, "/") == 0; - - for (i = 0; i < len; i++) { - file_name = json_string_value (json_array_get (name_array, i)); - if (strcmp (file_name, "") == 0 || strchr (file_name, '/') != NULL) { - seaf_warning ("Invalid download file name: %s.\n", file_name); - if (dirent_list) { - g_list_free_full (dirent_list, (GDestroyNotify)seaf_dirent_free); - dirent_list = NULL; - } - break; - } - - if (is_root_dir) { - file_path = g_strconcat (parent_dir, file_name, NULL); - } else { - file_path = g_strconcat (parent_dir, "/", file_name, NULL); - } - - dirent = seaf_fs_manager_get_dirent_by_path (seaf->fs_mgr, repo->store_id, - repo->version, repo->root_id, - file_path, &error); - if (!dirent) { - if (error) { - seaf_warning ("Failed to get dirent for %s: %s.\n", - file_path, error->message); - g_clear_error (&error); - } else { - seaf_warning ("Failed to get dirent for %s.\n", - file_path); - } - g_free (file_path); - if (dirent_list) { - g_list_free_full (dirent_list, (GDestroyNotify)seaf_dirent_free); - dirent_list = NULL; - } - break; - } - - g_free (file_path); - dirent_list = g_list_prepend (dirent_list, dirent); - } - - g_free (parent_dir); - json_decref (jobj); - - if (!dirent_list) { - return -1; - } - obj->dir_name = g_strdup (""); - obj->internal = dirent_list; - return 0; -} - -static gint64 -calcuate_download_multi_size (SeafRepo *repo, GList *dirent_list) -{ - GList *iter = dirent_list; - SeafDirent *dirent; - gint64 size; - gint64 total_size = 0; - - for (; iter; iter = iter->next) { - dirent = iter->data; - if (S_ISREG(dirent->mode)) { - if (repo->version > 0) { - size = dirent->size; - } else { - size = seaf_fs_manager_get_file_size (seaf->fs_mgr, repo->store_id, - repo->version, dirent->id); - } - if (size < 0) { - seaf_warning ("Failed to get file %s size.\n", dirent->name); - return -1; - } - total_size += size; - } else if (S_ISDIR(dirent->mode)) { - size = seaf_fs_manager_get_fs_size (seaf->fs_mgr, repo->store_id, - repo->version, dirent->id); - if (size < 0) { - seaf_warning ("Failed to get dir %s size.\n", dirent->name); - return -1; - } - total_size += size; - } - } - - return total_size; -} - -static int -calcuate_download_multi_file_count (SeafRepo *repo, GList *dirent_list) -{ - GList *iter = dirent_list; - SeafDirent *dirent; - int cur_count; - int count = 0; - - for (; iter; iter = iter->next) { - dirent = iter->data; - if (S_ISREG(dirent->mode)) { - count += 1; - } else if (S_ISDIR(dirent->mode)) { - cur_count = seaf_fs_manager_count_fs_files (seaf->fs_mgr, repo->store_id, - repo->version, dirent->id); - if (cur_count < 0) { - seaf_warning ("Failed to get dir %s file count.\n", dirent->name); - return -1; - } - count += cur_count; - } - } - - return count; -} - -static gboolean -validate_download_size (DownloadObj *obj, GError **error) -{ - SeafRepo *repo = obj->repo; - gint64 download_size; - - if (obj->type == DOWNLOAD_DIR) { - download_size = seaf_fs_manager_get_fs_size (seaf->fs_mgr, - repo->store_id, repo->version, - (char *)obj->internal); - } else { - download_size = calcuate_download_multi_size (repo, (GList *)obj->internal); - } - - if (download_size < 0) { - seaf_warning ("Failed to get download size.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get download size."); - return FALSE; - } else if (download_size > seaf->http_server->max_download_dir_size) { - seaf_warning ("Total download size %"G_GINT64_FORMAT - ", exceed max download dir size %"G_GINT64_FORMAT".\n", - download_size, seaf->http_server->max_download_dir_size); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Download size exceed max download dir size."); - return FALSE; - } - - return TRUE; -} - -static int -get_download_file_count (DownloadObj *obj, GError **error) -{ - int file_count; - SeafRepo *repo = obj->repo; - - if (obj->type == DOWNLOAD_DIR) { - file_count = seaf_fs_manager_count_fs_files (seaf->fs_mgr, repo->store_id, - repo->version, (char *)obj->internal); - } else { - file_count = calcuate_download_multi_file_count (repo, (GList *)obj->internal); - } - - if (file_count < 0) { - seaf_warning ("Failed to get download file count.\n"); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get download file count."); - return -1; - } - - return file_count; -} - -int -zip_download_mgr_start_zip_task (ZipDownloadMgr *mgr, - const char *token, - SeafileWebAccess *info, - GError **error) -{ - const char *repo_id; - const char *data; - const char *operation; - SeafRepo *repo; - void *internal; - DownloadObj *obj; - Progress *progress; - int file_count; - int ret = 0; - ZipDownloadMgrPriv *priv = mgr->priv; - - repo_id = seafile_web_access_get_repo_id (info); - repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); - if (!repo) { - seaf_warning ("Failed to get repo %.8s.\n", repo_id); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to get repo."); - return -1; - } - data = seafile_web_access_get_obj_id (info); - operation = seafile_web_access_get_op (info); - - obj = g_new0 (DownloadObj, 1); - obj->token = g_strdup (token); - obj->repo = repo; - obj->user = g_strdup (seafile_web_access_get_username (info)); - - if (strcmp (operation, "download-dir") == 0) { - obj->type = DOWNLOAD_DIR; - ret = parse_download_dir_data (obj, data); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to parse download dir data."); - goto out; - } - if (!seaf_fs_manager_object_exists (seaf->fs_mgr, - repo->store_id, repo->version, - (char *)obj->internal)) { - seaf_warning ("Dir %s doesn't exist.\n", (char *)obj->internal); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Dir doesn't exist."); - ret = -1; - goto out; - } - } else { - obj->type = DOWNLOAD_MULTI; - ret = parse_download_multi_data (obj, data); - if (ret < 0) { - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Failed to parse download multi data."); - goto out; - } - } - - if (!validate_download_size (obj, error)) { - ret = -1; - goto out; - } - - file_count = get_download_file_count (obj, error); - if (file_count < 0) { - ret = -1; - goto out; - } - - progress = g_new0 (Progress, 1); - progress->total = file_count; - progress->expire_ts = time(NULL) + PROGRESS_TTL; - obj->progress = progress; - - pthread_mutex_lock (&priv->progress_lock); - g_hash_table_replace (priv->progress_store, g_strdup (token), progress); - pthread_mutex_unlock (&priv->progress_lock); - - g_thread_pool_push (priv->zip_tpool, obj, NULL); - -out: - if (ret < 0) { - free_download_obj (obj); - } - - return ret; -} - -static Progress * -get_progress_obj (ZipDownloadMgrPriv *priv, const char *token) -{ - Progress *progress; - - pthread_mutex_lock (&priv->progress_lock); - progress = g_hash_table_lookup (priv->progress_store, token); - pthread_mutex_unlock (&priv->progress_lock); - - return progress; -} - -char * -zip_download_mgr_query_zip_progress (ZipDownloadMgr *mgr, - const char *token, GError **error) -{ - Progress *progress; - json_t *obj; - char *info; - - progress = get_progress_obj (mgr->priv, token); - if (!progress) { - seaf_warning ("Zip progress info not found for token %s: " - "invalid token or related zip task failed.\n", token); - g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, - "Zip progress info not found."); - return NULL; - } - - obj = json_object (); - json_object_set_int_member (obj, "zipped", g_atomic_int_get (&progress->zipped)); - json_object_set_int_member (obj, "total", progress->total); - info = json_dumps (obj, JSON_COMPACT); - json_decref (obj); - - return info; -} - -char * -zip_download_mgr_get_zip_file_path (struct ZipDownloadMgr *mgr, - const char *token) -{ - Progress *progress; - - progress = get_progress_obj (mgr->priv, token); - if (!progress) { - return NULL; - } - return progress->zip_file_path; -} - -void -zip_download_mgr_del_zip_progress (ZipDownloadMgr *mgr, - const char *token) -{ - remove_progress_by_token (mgr->priv, token); -} diff --git a/server/zip-download-mgr.h b/server/zip-download-mgr.h deleted file mode 100644 index 716515d9..00000000 --- a/server/zip-download-mgr.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ZIP_DOWNLOAD_MGR_H -#define ZIP_DOWNLOAD_MGR_H - -#include "seafile-object.h" - -struct ZipDownloadMgrPriv; - -typedef struct ZipDownloadMgr { - struct ZipDownloadMgrPriv *priv; -} ZipDownloadMgr; - -ZipDownloadMgr * -zip_download_mgr_new (); - -int -zip_download_mgr_start_zip_task (ZipDownloadMgr *mgr, - const char *token, - SeafileWebAccess *info, - GError **error); - -char * -zip_download_mgr_query_zip_progress (ZipDownloadMgr *mgr, - const char *token, GError **error); - -char * -zip_download_mgr_get_zip_file_path (ZipDownloadMgr *mgr, - const char *token); - -void -zip_download_mgr_del_zip_progress (ZipDownloadMgr *mgr, - const char *token); - -#endif diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index b8bf007c..00000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ - -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ - @CCNET_CFLAGS@ \ - @GLIB2_CFLAGS@ - -check_PROGRAMS = test-seafile-fmt test-cdc test-index - -test_seafile_fmt_SOURCES = test-seafile-fmt.c - -test_seafile_fmt_CFLAGS = -I$(top_srcdir)/daemon \ - -I$(top_srcdir)/common \ - -I$(top_srcdir)/lib \ - @GLIB2_CFLAGS@ - -test_seafile_fmt_LDADD = @CCNET_LIBS@ \ - $(top_builddir)/lib/libseafile_common.la \ - @SSL_LIBS@ @LIBEVENT_LIBS@ @GLIB2_LIBS@ - -test_cdc_SOURCES = test-cdc.c - -test_cdc_CFLAGS = -I$(top_srcdir)/common/cdc \ - -I$(top_srcdir)/common \ - @GLIB2_CFLAGS@ - -test_cdc_LDADD = $(top_builddir)/common/cdc/libcdc.la \ - @GLIB2_LIBS@ \ - -lcrypto - -test_cdc_LDFLAGS = @STATIC_COMPILE@ - -test_index_SOURCES = test-index.c - -test_index_CFLAGS = -I$(top_srcdir)/common/index \ - -I$(top_srcdir)/common \ - -I$(top_srcdir)/lib \ - @GLIB2_CFLAGS@ - -test_index_LDADD = $(top_builddir)/common/index/libindex.la \ - -lcrypto - -test_index_LDFLAGS = @STATIC_COMPILE@ - -TESTS = diff --git a/tests/README b/tests/README deleted file mode 100644 index a0aac395..00000000 --- a/tests/README +++ /dev/null @@ -1,4 +0,0 @@ - -Test Cases -========== - diff --git a/tests/basic/clean.sh b/tests/basic/clean.sh deleted file mode 100755 index 3f728656..00000000 --- a/tests/basic/clean.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -CLEANFILE="seafile-data" - -for d in conf1 conf2 conf3 conf4; do - for file in $CLEANFILE; do - rm -rf $d/$file - done -done - -rm -rf worktree/* diff --git a/tests/basic/conf1/ccnet.conf b/tests/basic/conf1/ccnet.conf deleted file mode 100644 index 9d698244..00000000 --- a/tests/basic/conf1/ccnet.conf +++ /dev/null @@ -1,13 +0,0 @@ - -[General] -USER_NAME=plt -ID=eed994152b231c673eeb5f586c06cd20cf9d10e8 -NAME=plt - -[Network] - -DEFAULT_RELAY=8e4b13b49ca79f35732d9f44a0804940d985627c -PORT=10001 - -[Client] -PORT=10000 diff --git a/tests/basic/conf1/mykey.peer b/tests/basic/conf1/mykey.peer deleted file mode 100644 index e8fcbec4..00000000 --- a/tests/basic/conf1/mykey.peer +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEoQIBAAKCAQEA1nXvjm57j9JfPf6zbjzMXhR0rz/xw4ZlX2XT5X1UZtAHe/rt -m7YNjlmxUT3XSU2xC+x+RCwCdCwZdm2xvwOeBHyS783TwdX9q3aFmVMppmYJ7b2C -rhzLIO7jQYy27TivP3TuUG/LILoYW16RIMvdnLWuZ+zF0PCUOZsbP041Tc6DNZ9D -nPbpRG4gzgcrlxLeKCF5qz0EYFQak7nuk0P+qz/DwTHCnNFcqLzcsmRiLrK9XqgS -2qi6U5nJApsILY4+Ep6EiiGGjdlSAVDpE5pHbte0hYWqO5ueLJ1RCHaXjYixLE+E -92SN4GFkTLPekHUcAqVIv23OZGhOPuKOwu1gJQIBIwKCAQAkw8Kqs9qq8N0gkhAh -hsPy3u9uf/2PO5xZfyujrxXIe27/T5ZydvsCdcagNnytewhoca8+4vkbOsKJVKIg -vsqhrvSeI0jfZoNB9w+WoIrMEX4Lf5K+wxuB/RED7DydsfIoIqyC0VYFnD6wk95d -ZMbnqh3l7hNIY8GjeazmR+vhc4uV3kpDiP1GNZPiX4J7y8mUFWwNTH4MlIevNMkz -ZY7SzOn105CLuT7iax+wcXLqDHIHYqqHVVnaHbc3hXGDvSVcYUHtUza7bsNvWJXn -uxTy2kAUlFRMLrbcYQXMH/U93V8Stu6fAID0OY+S8Zye272oJHDNzEH0B+rAGmhf -E55LAoGBAPNhYSYGBO/nBZTSHrw/ld5HBW8cQyaj4or00kmrg79tsb+osjBkRtDS -jX2hG4snCxu2+foXuUELlf52xFx9bjqknSS75KGvORjMZmON+u5cFAIAGEJT5pIh -twkokljkgApQcY9RsuzaS5gQKDtTBKCESHt3u/66mg9nkLlxJrPpAoGBAOGUrWxi -Ut6ZMAKou0uFWD1WnxRBZlPIZHgg3mSRRSjFOASpLXG0J0etaSY2sw4HtF3R7otY -KEJ6VnMdTEAvpf7TH187LNBD72/WEHBohrQ0ypINYXwrTzawBaYOfygVfVGZXYWw -2Vt1cLFjX5Gew/5+3ZCXNPmaSrrMDR8nKZDdAoGAFNx2CpLNOSJuMVPWv62twphf -jS5O5g4MGooDZWZ5AceS5IrNcdy1nN7Y7YLWeaRCx9x705uiKiWQg4aF3ArATitd -7TStMm4a1j1n3KXFDR3V1Ekmppl6KchgJVs/vnn8WKfPOCuS/lvamAFiiL35FRKn -IIabFdV662CmAUQ2hHMCgYEA1LDAxUbDKaZgd4klnvoRXmedTZy/kNLiYqKlzIj4 -EH9vVNoGRqKLb3edp6/qptQQdbdOoKOTrGS36OEcAgEKOWf5AgSX95CCq0YswcGj -k/dCpvasXyGFM5AFU2zBCIlKRZ8668QAIwhUT3rztS9LFIY+nkVsdk+li40w8Xyy -KX8CgYADMlGFSWfVKZAu2WQMUs0SgJIEV9Z/G2kU15hvu2herSDil6oPy2cUb1L8 -UF+y99upFndusiskaDOyxxtMESr7r3rlCeuOcvcHaLZyL/fam81YIG4Hc5HG7w+Y -Lw/Y4SYkYIUhQgjs/ZlS7jSuqmOtveRh0tB4IHi2v8CbTsH/hQ== ------END RSA PRIVATE KEY----- diff --git a/tests/basic/conf2/ccnet.conf b/tests/basic/conf2/ccnet.conf deleted file mode 100644 index 9bcab641..00000000 --- a/tests/basic/conf2/ccnet.conf +++ /dev/null @@ -1,11 +0,0 @@ -[General] -USER_NAME = server -ID = 8e4b13b49ca79f35732d9f44a0804940d985627c -NAME = server -SERVICE_URL = http://127.0.0.1:8000 - -[Network] -PORT = 10002 - -[Client] -PORT = 9999 diff --git a/tests/basic/conf2/mykey.peer b/tests/basic/conf2/mykey.peer deleted file mode 100644 index d9dd50c5..00000000 --- a/tests/basic/conf2/mykey.peer +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAuZFwgxkKQGaqYyFMxIUz1JHnZPaOgEQ+fX/jRVYbGMiHkSbX -K9X3XUHUGEjUt8b3zW6UZJGjgyV5S08YuaN0eE5z6Q6bnuWEhkTmgZgXaybc9Hiu -y2WAHpKj+qbXcmewE0WEys/Ov9AIe0TRXmvL6r1793VcLSzgb/aIQA2WFg97DfEA -hGAHo5BesKRfEEvXL6ZB9cGxXP9qIy0ObTvLXlOgbYchfV4rrXJk0u9xWjRyXABv -2Myv3fgxmGmTR+TAw2G5GCKeh9IoIuWVMGPyjSlERGMqQYymNz3NgyWFayyZ5HQS -tihCnflOGEiMHRkOwIczB16YZhan2YqKpsjHGwIBIwKCAQEArvbXzBBLfoyvR4XM -Cb9rYgXozOh3usQAZ7MYHM2HQ0C6VahHN/WgFhl+1RF4Gv1tTKoW4nqwHJEL9oxn -xPkzTNxBZrYAcT7NaKdc/diLG+LQVDdFuHWkrxyL+vUUR0vR5kjcSjGlrYmhmMvb -WQaNEIbFVwhA92TTnMPfjNmcI2wRKI1K9NEKDAMIPSwW/sgkls2h4KW3Y7DooJ0k -l0apjN/rlaR4ohZp6oMVifW8GFY43Xau+4dIrYTnvvSyvGvtB+8cWuhqqvWHRZdM -rFjgOJoZH5l0zxt2dYW2WFiqgT7xXsvu6L+nylXktEMxC33rehYdPrd427J409A6 -caO5cwKBgQDyrBQ8UXu7cDAktiKTwH7+pA0wNyTvKsGYw0RcFILccpxty2r5gYhI -eLFPVyjoYxwauW6vX3cSAYLKR+2PlYvkPpEvBQIJbaurx++ejez/KxYD65ZeFTfs -Kb9A08hgMxCvJmnRvojhez1OZmmmWYPT57XeZXnCiNoyJWKA0mMNvwKBgQDDwn02 -o5n7ugetXIlV1PiStVogPPTBobh9jsXooQFh4fB+lsrO082hapMlbVVNG1gLzvTY -V0oDM/AzdnC6feZlAEdM+IcruinVnMnbnhiwPVDInCJIhvmJ/XScvkTsgHwRiAss -Tlf8wH/uGXiaeVV/KMlkKRK6h54znTPq37/VpQKBgQDkziG1NuJgRTS05j3bxB/3 -Z3omJV1Wh2YTsMtswuHIiVGpWWTcnrOyC2VZb2+2iVUDQR83oycfmwZJsYg27BYu -+SnNPzxvSiWEtTJiS00rGf7QfwoeMUNbAspEb+jPux5b/6WZ34hfkXRRO/02cagu -Mj3DDzhJtDtxG+8pAOEM9QKBgQC+KqWFiPv72UlJUpQKPJmzFpIQsD44cTbgXs7h -+32viwbhX0irqS4nxp2SEnAfBJ6sYqS05xSyp3uftOKJRxpTfJ0I8W1drYe5kP6a -1Bf7qUcpRzc/JAhaKWn3Wb9MJQrPM7MVGOfCVJmINgAhCCcrEa2xwX/oZnxsp1cB -a6RpIwKBgQDW15IebNwVOExTqtfh6UvIjMSrk9OoHDyjoPLI3eyPt3ujKdXFJ8qF -CWg9ianQyE5Y8vfDI+x1YRCOwq2WapeXzkSO8CzVFHgz5kFqJQolr4+o6wr5mLLC -+6iW9u81/X3bMAWshtNfsWbRSFLT1WNVTKRg+xO7YG/3wcyeIeqigA== ------END RSA PRIVATE KEY----- diff --git a/tests/basic/conf3/ccnet.conf b/tests/basic/conf3/ccnet.conf deleted file mode 100644 index 0cee6654..00000000 --- a/tests/basic/conf3/ccnet.conf +++ /dev/null @@ -1,10 +0,0 @@ -[General] -USER_NAME = freeplant -ID = e19d1070b6d9ae7bf453d124ff4e775076553906 -NAME = freeplant - -[Network] -PORT = 10003 - -[Client] -PORT = 9998 diff --git a/tests/basic/conf3/mykey.peer b/tests/basic/conf3/mykey.peer deleted file mode 100644 index d604b2b7..00000000 --- a/tests/basic/conf3/mykey.peer +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEoQIBAAKCAQEAntQ0Wds67rFiy5/Wq30EzOpRYFPGC7xOCS+tBTwC+YUl9fSE -5kzicoC699EDf5N6Ky4u4j2KhXIkwCwQO6EOxTQjG7Gyxj3YS63lU/zgGaGI9L3G -xkkCPvqpYCuxHYELClud/3Zb/xA0aZr4EZiLHs21nUSuchVftN8URG6OJxf18Tji -1nysBmaZ9jLbuHpaELV1Rc+lGsECslfpjITm/bRcsW1VgrjJXv1dtekIRzpoKMVB -u89nO3YhRbC2qpQR27BsfeldIQYxWiD4jNC9LfvCsxgfEYpo/W5Y/rImCaNatqff -wQ0rUCWjwvAypU1iLhPlL6fG75iU5dDgCKuYKwIBIwKCAQBs6Uh4IUz7clJfvg+L -iO1ZUDfNBj6o9ibhukrBwsA2Eiiop6uWmx7vbjcQVM8y6MjNJvuT0m2dVZWLFuaP -Sd4+FR9jcok3et11uRJIOF8nhLWvIwv1rmfwq+Hbi6ymhF9Xj0fFHfXwuqeY30sE -wF9llF9HRQnn1CRexNqylPPDCAkiEclXyBOhpk7TIkVhCfKagDtivjORRF2OBKUb -A8x7mei/AjbqovYbWNUmsX++PpUiau7y4WumiTFOPVhtynQv7DVRAC2lw+NUNFU0 -4/JhYyTvx/KbVzpwhMfTHE1bEErqzQrZsXH9rkrq5/tm3QeCfYZVsNyjaAOR3kxK -HAPLAoGBAMpVOxCF9q4kQWLzRMW+NwDGN0HNKZqfrbtJebQeqeRQPbfDAPJIITfh -TfMP5XtGL/rCA/sTHOlMi9Dr0a6229q8BNjtDBEi+HeK7OS8O1mCDt8mQ5npTfO9 -FY3ZShJvKIhHgWKtc/tkXwGG/DesLSJVWxpQsyaQhjEVArxAewJNAoGBAMj0+Tdb -LOFBEq65sXDMv4IpLdzd+1Scj5RPF29RICMj4NwtM9MkaeqVzd54QLK2RH6Uj/+G -fxZGt5MdGub+Rk2vHcXQEl7BpWOfEmzjc6IzPE2vJkNbB+qxlye8NCLLAw/Yu3fr -dmmvKHT6twGtyJTlFxGh/V6bcAlGv0ncHRBXAoGBAL7FY5M8et60eCoYkUy6qON5 -D4cvJzoERLfmMOun4gMnFZ6h6vMQztzqX3Ak7k+ok6NJNvQKtNv3twbPtxJx5Tvz -GoNjKKJxbe0N9Uyxeclr/2SvDInNWCBTMZRfKJUJuIB97wVEdKsyv/ogL6I0n5Vm -a9b7oZljsbk/sh81e0tPAoGAROZG0SaTC2bEk61haIC2sEiiApVAOkROe/3cJipx -ayI+d1/0gufpzMWlq1xt9CE8DiROoMBmFkQhrsgmexVZ7r+yb7UNnNStu8GCqP2G -u0TEN+RHohCVAAJftdoggPUlnwh6ygeWUB7MCtmd1LCcitIzy4f/GR9ZnMfMjloY -l+MCgYAmpvxULeaYSrA00iZM2mfyXk6Jlm01IVXd7LR0qswghjzGGyJxgyU90FMg -KTW+wzDWMWD1AegyeLNjRwWDLtvF+HJlvT2O6P9hQLlZQnLuM+yOQtAjb0vzbued -LoXUAsUJP8LIAbY8WgO4F7w5j71HBekJZRndlU+4/m/uajiLsg== ------END RSA PRIVATE KEY----- diff --git a/tests/basic/conf4/ccnet.conf b/tests/basic/conf4/ccnet.conf deleted file mode 100644 index 71fa46f0..00000000 --- a/tests/basic/conf4/ccnet.conf +++ /dev/null @@ -1,10 +0,0 @@ -[General] -USER_NAME = server2 -ID = 9b7adea2e0a954196734af25837751bb833336e6 -NAME = server2 - -[Network] -PORT = 10004 - -[Client] -PORT = 9997 diff --git a/tests/basic/conf4/mykey.peer b/tests/basic/conf4/mykey.peer deleted file mode 100644 index 26ab960f..00000000 --- a/tests/basic/conf4/mykey.peer +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA0uSgFWuzO3fWwf4pAes+Nfd9ebBmPjNrKks4oVEZ3pXMWu+u -iCE9az6gBmhxYDPXLXkldK9gh7qG7/Ma3wL+3pQ4jvdvI5PXY23n36K+Uww2iTEb -HLz8AM/BfN2hIxZxYy4DDWMeWj3njquSyw0Lk843Rkay1w9ZRj968cQTzwSKelVG -gkH+SR03VSFn7lcnCZ3fsncK19KDXagwjIWizYszYfmI6LbImcko24fQwp7MyrhH -tMJ6R/GFsRs9F7QTe+IUJCnOTCJfFIl/TaWnHLA9g6DN/M+v4PBAbaR5xtCkWVuF -/azRdeKZDvS0MKSMQxtT4RThp2FBt8xdXyPZrwIBIwKCAQByfBxjZln7thV/QNRu -wYgr7MB1QoClbF6/MCYObdrX6utHTum3nQQVpadT744BBjL7baaebdVQ/tuJkpmP -AaBM8WCIH+vgHQ6Gbtz1vr8XI+MXRosPmcqhWtbAIIqspciGTC2K7KoTuzSPRzJu -OkgdCYu4b4Wn8mOpyrB0naRabzF3F+tC/T1QlZt8mHbpmKAMTLhjh1B39v2aemaa -v1mv3dRFeJb6YAPr91YXzVN+ZAEtKbda7guCPdswzFh+y2UsHTASb9NGOYjl+CKm -Jh1PJFqQOMjlPSFFpbwut99l8BvAAiayq2wf6o1cdvsLDxxrbJ35Tmv0+DpFS2Uk -hjM7AoGBAPFRSOw7w9sLuFaHtKA5/otqEbbBgsSybj0+QGhZ8lMn9bMTMTkha/SO -nWK0dYGNl3xefGbDcmaS+EVq5jgSkwwnbZODC7MP2YpeXs6QHoJO1bv1KR9qBFPo -iLSCK9TQy8BgXCGUZU4q1Hz3d3sUgsJoD6YF8WmEiQ8HoiF76OmJAoGBAN+5dIB6 -P9q2bDukidG1MfuI4+LAWVOZPvmx/5HtF+BUJUofps3fILHfO7vFVLVnJqySTVlJ -z3fFDgrRXkcOFiSJ7eS1DL53jgDzl35jCwnCzW7wldC2nh6uAFmwW9OLFLDaqpZj -hP98DTKjDdZzjLBzeX1gu23mUk4Vkd/jUTN3AoGAfBss0UNOyGxtblRrhZorIyCb -ZU2TtZ2Xx7mdd363I3Oi7mGkSURjZ9RQ8O8X3Dowplx6ff4dk9aOT5YP/5SGI4H9 -1tWuPtTziP1VVEoeUaTi8vMcdo5LXlpU7x5fr0bPL7yHJzZf/FCKiWlTY96ppc8d -/ZyoCmFrDws9cE5ahrsCgYEAzIxNQkPinBSANofOdpcJIH0oH8XOA0pINL//m1xt -meaIfkjTBV5JxzJ/wZ55VWWfs7j2QwGnvfX+Nca8mLxsBCZV2GsEVl6tt7okG8hE -mzXDI5oikvAbicOojIP8LyAS6taNVkxcV0zY3dboFIbnB7oIrSU9pk7sKiJZfD2M -EcsCgYEA4U2nISZLqt4ti+ruy4URVRJXK8WLSAm42c4MtpR6Z/2dlNvPGxPSdWra -hUYl6x8AOITNkthkLp0+oDewO8iXI5U3RnrrKm7Uuu6df0F/sr0XW/Nh+DrG2o70 -xgVv7UlOE2h/VQklxYj/smSIT6TQh/7cemMFexICIOkOAI4e57E= ------END RSA PRIVATE KEY----- diff --git a/tests/basic/lan.sh b/tests/basic/lan.sh deleted file mode 100755 index 34126211..00000000 --- a/tests/basic/lan.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic - -conf1=${testdir}/conf1 -conf2=${testdir}/conf2 -conf3=${testdir}/conf3 -conf4=${testdir}/conf4 - -debug=Message,Requirement,Other,Peer,Group,Kvitem - -if [ ! -d ${conf1}/logs ]; then - mkdir ${conf1}/logs -fi -if [ ! -d ${conf3}/logs ]; then - mkdir ${conf3}/logs -fi - -gnome-terminal -e "${ccnet} -c ${conf1} -D ${debug} -f -" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -d ${conf1}/seafile-data -w worktree/wt1 -D all -l -" - -gnome-terminal -e "${ccnet} -c ${conf3} -D ${debug} -f -" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf3} -d ${conf3}/seafile-data -w worktree/wt3 -D all -l -" diff --git a/tests/basic/seafile.sh b/tests/basic/seafile.sh deleted file mode 100755 index cf5dca76..00000000 --- a/tests/basic/seafile.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -conf1=conf1 -conf2=conf2 -conf3=conf3 -conf4=conf4 - -debug=Message,Other,Peer - -if [ ! -d ${conf1}/logs ]; then - mkdir ${conf1}/logs -fi -if [ ! -d ${conf3}/logs ]; then - mkdir ${conf3}/logs -fi -if [ ! -d ${conf4}/logs ]; then - mkdir ${conf4}/logs -fi - -while [ $# -ge 1 ]; do - case $1 in - "1" ) - gnome-terminal -e "${ccnet} -c ${conf1} -D ${debug} -f -" - sleep 3 - gnome-terminal -e "${seaf_daemon} -c ${conf1} -d ${conf1}/seafile-data -w worktree/wt1 -D all -l -" - ;; - "2" ) - # Use sqlite as database in testing - ../../tools/seaf-server-init -d ${conf2}/seafile-data > /dev/null - - gnome-terminal -e "${ccnet_server} -c ${conf2} -D ${debug} -f -" - sleep 3 - gnome-terminal -e "${seaf_server} -c ${conf2} -d ${conf2}/seafile-data -D all -f -l -" - ;; - "3" ) - gnome-terminal -e "${ccnet} -c ${conf3} -D ${debug} -f -" - sleep 3 - gnome-terminal -e "${seaf_daemon} -c ${conf3} -d ${conf3}/seafile-data -w worktree/wt3 -D all -l -" - ;; - "4" ) - gnome-terminal -e "${ccnet} -c ${conf4} -D ${debug} -f -" - sleep 3 - gnome-terminal -e "${seaf_daemon} -c ${conf4} -d ${conf4}/seafile-data -w worktree/wt4 -D all -l -" - ;; - esac - shift -done diff --git a/tests/basic/teardown.sh b/tests/basic/teardown.sh deleted file mode 100755 index 203c677d..00000000 --- a/tests/basic/teardown.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -CLEANFILE="requirement-db object-db peer-db group-db \ - user-db GroupMgr PeerMgr ccnet.log \ - seafile-data misc logs" - -for d in conf1 conf2 conf3 conf4; do - for file in $CLEANFILE; do - rm -rf $d/$file - done -done - -rm -rf conf2/ccnet.db -rm -rf worktree/* diff --git a/tests/basic/test-branch-name-whitespace.sh b/tests/basic/test-branch-name-whitespace.sh deleted file mode 100755 index e53eec83..00000000 --- a/tests/basic/test-branch-name-whitespace.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} -cp ${top_srcdir}/autogen.sh ${worktree}/wt1/${repo_id}/test1 -cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# include space -${seafile_app} -c ${conf1} branch add ${repo_id} "test test" -# include tab -${seafile_app} -c ${conf1} branch add ${repo_id} "test test" -# include enter -${seafile_app} -c ${conf1} branch add ${repo_id} "test test" - -# show branch -${seafile_app} -c ${conf1} branch show ${repo_id} diff --git a/tests/basic/test-branch-show.sh b/tests/basic/test-branch-show.sh deleted file mode 100755 index b9071976..00000000 --- a/tests/basic/test-branch-show.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} -cp ${top_srcdir}/autogen.sh ${worktree}/wt1/${repo_id}/test1 -cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add branch -${seafile_app} -c ${conf1} branch add ${repo_id} test - -# show branch -${seafile_app} -c ${conf1} branch show ${repo_id} diff --git a/tests/basic/test-diff-rename.sh b/tests/basic/test-diff-rename.sh deleted file mode 100755 index 899fbe27..00000000 --- a/tests/basic/test-diff-rename.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -PWD=`pwd` - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/ | grep -v "checkout-files"` - -# create some files -mkdir -p ${worktree}/wt1/${repo_id}/test/test -echo "rename" >>${worktree}/wt1/${repo_id}/test/test/rename -#cp -rf /tmp/ccnet ${worktree}/wt1/${repo_id}/ -sleep 1 - -# add some files -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add branch -${seafile_app} -c ${conf1} branch add ${repo_id} test -sleep 1 - -# checkout to test branch -${seafile_app} -c ${conf1} checkout ${repo_id} test -sleep 1 - -# modify file -#mv -f ${worktree}/wt1/${repo_id}/ccnet ${worktree}/wt1/${repo_id}/xx -mv -f ${worktree}/wt1/${repo_id}/test ${worktree}/wt1/${repo_id}/test1 -sleep 1 - -# add file -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit2 -sleep 1 - -# diff -${seafile_app} -c ${conf1} diff ${repo_id} test local diff --git a/tests/basic/test-diff.sh b/tests/basic/test-diff.sh deleted file mode 100755 index db0361cb..00000000 --- a/tests/basic/test-diff.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -repo_name="test-repo" - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/systems` - -# create some files -echo "modify" >> ${worktree}/wt1/works/${repo_name}/modify -echo "remove" >> ${worktree}/wt1/works/${repo_name}/remove -echo "unmerge" >> ${worktree}/wt1/works/${repo_name}/unmerge -sleep 1 - -# add some files -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add branch -${seafile_app} -c ${conf1} branch add ${repo_id} test -sleep 1 - -# checkout to test branch -${seafile_app} -c ${conf1} checkout ${repo_id} test -sleep 1 - -# modify file -echo "add" >> ${worktree}/wt1/works/${repo_name}/add -echo "modify" >> ${worktree}/wt1/works/${repo_name}/modify -rm ${worktree}/wt1/works/${repo_name}/remove -echo "merge conflict" > ${worktree}/wt1/works/${repo_name}/unmerge -sleep 1 - -# add file -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit2 -sleep 1 - -# diff -${seafile_app} -c ${conf1} diff ${repo_id} test local diff --git a/tests/basic/test-diff2.sh b/tests/basic/test-diff2.sh deleted file mode 100755 index 67557282..00000000 --- a/tests/basic/test-diff2.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -# mkdir -mkdir ${worktree}/wt1/${repo_id}/diff - -# create some files -echo "modify" >> ${worktree}/wt1/${repo_id}/diff/modify -echo "remove" >> ${worktree}/wt1/${repo_id}/diff/remove -echo "unmerge" >> ${worktree}/wt1/${repo_id}/diff/unmerge -sleep 1 - -# add some files -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add branch -${seafile_app} -c ${conf1} branch add ${repo_id} test -sleep 1 - -# checkout to test branch -${seafile_app} -c ${conf1} checkout ${repo_id} test -sleep 1 - -# modify file -echo "add" >> ${worktree}/wt1/${repo_id}/diff/add -echo "modify" >> ${worktree}/wt1/${repo_id}/diff/modify -rm ${worktree}/wt1/${repo_id}/diff/remove -echo "merge conflict" > ${worktree}/wt1/${repo_id}/diff/unmerge -sleep 1 - -# add file -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit2 -sleep 1 - -# diff -${seafile_app} -c ${conf1} diff ${repo_id} test local diff --git a/tests/basic/test-diff3.sh b/tests/basic/test-diff3.sh deleted file mode 100755 index 3fbd54d0..00000000 --- a/tests/basic/test-diff3.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -PWD=`pwd` - -./clean.sh -./teardown.sh - -rm -rf ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -# create some files -cp -rf ~/projects/gonggeng/ccnet ${worktree}/wt1/${repo_id}/ -sleep 1 - -# add some files -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add branch -${seafile_app} -c ${conf1} branch add ${repo_id} test -sleep 1 - -# checkout to test branch -${seafile_app} -c ${conf1} checkout ${repo_id} test -sleep 1 - -# modify file -cd ${worktree}/wt1/${repo_id}/ccnet -git checkout master -cd $PWD -sleep 1 - -# add file -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit2 -sleep 1 - -# diff -${seafile_app} -c ${conf1} diff ${repo_id} test local diff --git a/tests/basic/test-duplicate-repo-name.sh b/tests/basic/test-duplicate-repo-name.sh deleted file mode 100755 index 787e6e5a..00000000 --- a/tests/basic/test-duplicate-repo-name.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -repo_name="test-repo" - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 -rm ${conf1}/seafile/repo.db - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet1` -repoid1=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet2` -repoid2=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet3` -repoid3=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet4` -repoid4=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet5` -repoid5=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet6` -repoid6=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` - -ls /tmp -sleep 2 - -${seafile_app} -c ${conf1} repo-rm ${repoid1} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid2} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid3} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid4} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid5} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid6} > /dev/null - -ls /tmp - -# create a repo -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid1=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid2=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid3=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid4=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid5=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test` -repoid6=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` - -ls /tmp/worktree/wt1/systems -sleep 2 - -${seafile_app} -c ${conf1} repo-rm ${repoid1} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid2} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid3} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid4} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid5} > /dev/null -sleep 1 -${seafile_app} -c ${conf1} repo-rm ${repoid6} > /dev/null - -ls /tmp/worktree/wt1/systems diff --git a/tests/basic/test-encrypt.README b/tests/basic/test-encrypt.README deleted file mode 100644 index 95acc8fa..00000000 --- a/tests/basic/test-encrypt.README +++ /dev/null @@ -1,20 +0,0 @@ -Objectives -=== - -Test the repo-encryption functionality. One should be able to upload -an encrypt repo, and fetch it elsewhere, and can checkout this repo -correctly as long as the right passwd is set. - - -Test -=== - -The test flow is 90% the same as the basic test. Only two steps are -different: - -1. Use `seafile create --encrypt` to create an encrypted repo, rather - than using a plain `seafile create`. You need to input the passwd - manually. - -2. After fetching is finished, use `seafile set-passwd` to set the - passwd for the encrypted repo, and then checkout it. diff --git a/tests/basic/test-encrypt.sh b/tests/basic/test-encrypt.sh deleted file mode 100755 index 80d4a372..00000000 --- a/tests/basic/test-encrypt.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -conf3=${testdir}/conf3 -worktree=${testdir}/worktree -seafile_app=${seafile_dir}/app/seafile - - -echo "+++ start seafile" -./seafile.sh 1 2 3 4 - -repo_id=`ls ${worktree}/wt1/` -if [ x${repo_id} != x ]; then - echo "Worktree is not empty, perform ./clean.sh first" - exit 1 -fi - -function create_repo -{ - # create a repo - ${seafile_app} -c ${conf1} create --encrypt --passwd=1234 test-repo test > /dev/null - sleep 3 - repo_id=`ls ${worktree}/wt1/ | tail -n 1` - if [ -z ${repo_id} ]; then - echo "create repo failed" - exit 1 - fi - - mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 - cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} - cp ${top_srcdir}/autogen.sh ${worktree}/wt1/${repo_id}/test1 - cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 - sleep 1 - - # add files - ${seafile_app} -c ${conf1} add ${repo_id} > /dev/null - sleep 1 - - # commit - ${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -} - -echo "+++ create repo" -create_repo - -repo_id=`ls ${worktree}/wt1/` -echo "+++ upload ${repo_id}" -${seafile_app} -c ${conf1} upload ${repo_id} local master -sleep 10 - -echo "+++ fetch ${repo_id}" -${seafile_app} -c ${conf3} fetch ${repo_id} master master -sleep 10 - -echo "+++ checkout" -${seafile_app} -c ${conf3} branch add ${repo_id} local master -${seafile_app} -c ${conf3} set-passwd ${repo_id} 1234 -${seafile_app} -c ${conf3} checkout ${repo_id} local - -echo "+++ check diff" -if diff ${worktree}/wt3/${repo_id}/test1/test2/configure.ac \ - ${worktree}/wt1/${repo_id}/test1/test2/configure.ac > /dev/null ; then - echo "+++ Success" -else - echo "+++ failed" -fi - -echo "+++ cleanup" -pkill ccnet \ No newline at end of file diff --git a/tests/basic/test-merge-conflict-status.sh b/tests/basic/test-merge-conflict-status.sh deleted file mode 100755 index 76272fba..00000000 --- a/tests/basic/test-merge-conflict-status.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -rf ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} -sleep 1 - -${seafile_app} -c ${conf1} status ${repo_id} - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# add two branches -${seafile_app} -c ${conf1} branch add ${repo_id} test1 -sleep 1 -${seafile_app} -c ${conf1} branch add ${repo_id} test2 -sleep 1 - -# checkout to test1 -${seafile_app} -c ${conf1} checkout ${repo_id} test1 -sleep 1 -# modify file content -echo "test1" >> ${worktree}/wt1/${repo_id}/README -sleep 1 -# add README -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 -# commit -${seafile_app} -c ${conf1} commit ${repo_id} test1-commit1 -sleep 1 - -# checkout to test2 -${seafile_app} -c ${conf1} checkout ${repo_id} test2 -sleep 1 -# modify file content -echo "test2" >> ${worktree}/wt1/${repo_id}/README -sleep 1 -# add README -${seafile_app} -c ${conf1} add ${repo_id} -sleep 1 -# commit -${seafile_app} -c ${conf1} commit ${repo_id} test2-commit2 -sleep 1 - -# status -${seafile_app} -c ${conf1} status ${repo_id} - -# -# all above should be OK -# - -# merge test1 into test2 -${seafile_app} -c ${conf1} merge ${repo_id} test1 - -# status -${seafile_app} -c ${conf1} status ${repo_id} \ No newline at end of file diff --git a/tests/basic/test-new-checkout.sh b/tests/basic/test-new-checkout.sh deleted file mode 100755 index fbed829a..00000000 --- a/tests/basic/test-new-checkout.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -repo_name="test-repo" - -./clean.sh -./teardown.sh - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 -rm ${conf1}/seafile/repo.db -rm -rf /tmp/ccnet1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -tmp=`${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnet1` -repoid1=`echo $tmp | awk '{print $6}' | awk -F. '{print $1}'` -sleep 1 - -cp README /tmp/ccnet1/ - -${seafile_app} -c ${conf1} add ${repoid1} >/dev/null -sleep 1 -${seafile_app} -c ${conf1} commit ${repoid1} "init" >/dev/null -sleep 1 - -echo "----" -ls /tmp/ccnet1/ -sleep 1 - -rm -rf /tmp/ccnet1/ -sleep 1 -${seafile_app} -c ${conf1} checkout ${repoid1} local /tmp/haha/ >/dev/null -sleep 1 -echo "----" -ls /tmp/haha diff --git a/tests/basic/test-refactor-worktree.sh b/tests/basic/test-refactor-worktree.sh deleted file mode 100755 index 75e48dcb..00000000 --- a/tests/basic/test-refactor-worktree.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -repo_name="test-repo" - -./clean.sh -./teardown.sh - -# create dir -if [ $1 = "create" ]; then - rm -r ${worktree}/wt1 - mkdir -p ${worktree}/wt1 - rm ${conf1}/seafile/repo.db -fi - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 - -# for debug -if [ $1 = "debug" ]; then - read tmp -else - gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" - sleep 3 -fi - -# create a repo -if [ $1 = "create" ] -then - #${seafile_app} -c ${conf1} create ${repo_name} test > /dev/null - #mkdir /tmp/ccnet-test - ${seafile_app} -c ${conf1} create ${repo_name} test /tmp/ccnett > /dev/null -fi - -repo_id=`ls ${worktree}/wt1/systems` - -ls -R ${worktree} - -# add file -cp README ${worktree}/wt1/works/${repo_name}/ -${seafile_app} -c ${conf1} add ${repo_id} >/dev/null - -# commit file -${seafile_app} -c ${conf1} commit ${repo_id} "init" >/dev/null diff --git a/tests/basic/test-restful-put-file.sh b/tests/basic/test-restful-put-file.sh deleted file mode 100755 index 98bce827..00000000 --- a/tests/basic/test-restful-put-file.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=${testdir}/worktree -seafile_app=${seafile_dir}/app/seafile - - -echo "+++ start seafile" -./seafile.sh 1 2 - -sleep 1 -# create a new repo -res=`${seafile_app} -c ${conf1} create test-repo test ${worktree}/wt1` - -# get repo id -repo_id=`echo ${res} | awk '{print $6}' | awk -F. '{print $1}'` - -sleep 1 -# add some files -mkdir ${worktree}/wt1/1/ -cp ${top_srcdir}/configure ${worktree}/wt1/ -cp ${top_srcdir}/configure ${worktree}/wt1/1/ - -sleep 1 -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 - -# start to test put-file API -echo "+++ start to stest put-file API ..." - -# success -echo "+++ pass" -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README ./ -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README / -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README 1 -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README 1/ -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README /1 -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README /1/ -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README ./1/ -sleep 1 - -# failure -echo "++++ failures -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README ./1/2 -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README ./1// -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README ./1/2// -sleep 1 -${seafile_app} -c ${conf1} put-file ${repo_id} ${top_srcdir}/README .//1/ -sleep 1 - -echo "+++ cleanup" -pkill ccnet diff --git a/tests/basic/test-rm.sh b/tests/basic/test-rm.sh deleted file mode 100755 index 4b3f1bcd..00000000 --- a/tests/basic/test-rm.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/` - -mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} -cp ${top_srcdir}/autogen.sh ${worktree}/wt1/${repo_id}/test1 -cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null -${seafile_app} -c ${conf1} add ${repo_id} test1/autogen.sh > /dev/null -${seafile_app} -c ${conf1} add ${repo_id} test1/test2/configure.ac > /dev/null - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null - -rm ${worktree}/wt1/${repo_id}/README - -${seafile_app} -c ${conf1} rm ${repo_id} README -${seafile_app} -c ${conf1} rm ${repo_id} test1/autogen.sh - -${seafile_app} -c ${conf1} status ${repo_id} - -${seafile_app} -c ${conf1} commit ${repo_id} commit2 - -cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 - -${seafile_app} -c ${conf1} status ${repo_id} - -echo "hello" >> ${worktree}/wt1/${repo_id}/test1/test2/configure.ac - -${seafile_app} -c ${conf1} rm ${repo_id} test1/test2/configure.ac - -rm -rf ${worktree} diff --git a/tests/basic/test-share.sh b/tests/basic/test-share.sh deleted file mode 100755 index 85d22d05..00000000 --- a/tests/basic/test-share.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -function create_repo -{ - # create a repo - ${seafile_app} -c ${conf1} create test-repo test > /dev/null - sleep 3 - repo_id=`ls ${worktree}/wt1/` - - mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 - cp ${top_srcdir}/README ${worktree}/wt1/${repo_id} - cp ${top_srcdir}/autogen.sh ${worktree}/wt1/${repo_id}/test1 - cp ${top_srcdir}/configure.ac ${worktree}/wt1/${repo_id}/test1/test2 - sleep 1 - - # add a file - ${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null - sleep 1 - - # commit - ${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -} - -rm -r ${worktree}/wt1 -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# find the group id -group_id=`ls ${conf1}/group-db/ | tail -n 1` -if [ -z $group_id ]; then - echo "no group exists. You may forget to run ./setup.sh" - exit 1 -fi - -# find a repo -repo_id=`ls ${worktree}/wt1/` -if [ -z $repo_id ]; then - create_repo - repo_id=`ls ${worktree}/wt1/` -fi - -echo "repo id is $repo_id" - -echo "+++ share item" -item_id=`${seafile_app} -c ${conf1} share ${repo_id} ${group_id}` - -echo "+++ unshare item" -${seafile_app} -c ${conf1} unshare ${item_id} diff --git a/tests/basic/test-status-rename.sh b/tests/basic/test-status-rename.sh deleted file mode 100755 index 484d62d2..00000000 --- a/tests/basic/test-status-rename.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -rf ${worktree} -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 -#read tmp - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/ | grep -v "checkout-files"` - -mkdir -p ${worktree}/wt1/${repo_id}/test1/test2 -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id}/test1/test2 -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -# rename file -mv ${worktree}/wt1/${repo_id}/test1 ${worktree}/wt1/${repo_id}/"1ts et" -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} diff --git a/tests/basic/test-status-timestamp.sh b/tests/basic/test-status-timestamp.sh deleted file mode 100755 index f289b20e..00000000 --- a/tests/basic/test-status-timestamp.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile - -./clean.sh -./teardown.sh - -rm -rf ${worktree} -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create test-repo test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/ | grep -v "checkout-files"` - -cp ${top_srcdir}/README ${worktree}/wt1/${repo_id}/ -touch -t 191305091843 ${worktree}/wt1/${repo_id}/README -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} -sleep 1 - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} > /dev/null -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} -sleep 1 - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null -sleep 1 - -echo "----------------------" -${seafile_app} -c ${conf1} status ${repo_id} diff --git a/tests/basic/test-status.sh b/tests/basic/test-status.sh deleted file mode 100755 index 533f4356..00000000 --- a/tests/basic/test-status.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -. ../common-conf.sh - -testdir=${seafile_dir}/tests/basic -conf1=${testdir}/conf1 -worktree=/tmp/worktree -seafile_app=${seafile_dir}/app/seafile -repo_name="test-repo" - -./clean.sh -./teardown.sh - -mkdir -p ${worktree}/wt1 - -gnome-terminal -e "${ccnet} -c ${conf1} -D all -f - --no-multicast" -sleep 3 -gnome-terminal -e "${seaf_daemon} -c ${conf1} -w ${worktree}/wt1 -l -" -sleep 3 - -# create a repo -${seafile_app} -c ${conf1} create ${repo_name} test > /dev/null -sleep 3 -repo_id=`ls ${worktree}/wt1/systems` - -mkdir -p ${worktree}/wt1/works/${repo_name}/test1/test2 -cp ${top_srcdir}/README ${worktree}/wt1/works/${repo_name} -cp ${top_srcdir}/autogen.sh ${worktree}/wt1/works/${repo_name}/test1 -cp ${top_srcdir}/configure.ac ${worktree}/wt1/works/${repo_name}/test1/test2 -sleep 1 - -${seafile_app} -c ${conf1} status ${repo_id} - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} README > /dev/null - -${seafile_app} -c ${conf1} status ${repo_id} - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit1 > /dev/null - -# add a file -${seafile_app} -c ${conf1} add ${repo_id} test1/autogen.sh > /dev/null -${seafile_app} -c ${conf1} add ${repo_id} test1/test2/configure.ac > /dev/null - -${seafile_app} -c ${conf1} status ${repo_id} - -# commit -${seafile_app} -c ${conf1} commit ${repo_id} commit2 > /dev/null - -rm ${worktree}/wt1/works/${repo_name}/README -echo "hello" >> ${worktree}/wt1/works/${repo_name}/test1/test2/configure.ac - -${seafile_app} -c ${conf1} status ${repo_id} - -echo "hello" >> ${worktree}/wt1/works/${repo_name}/test1/autogen.sh -sleep 1 - -${seafile_app} -c ${conf1} add ${repo_id} test1/autogen.sh - -${seafile_app} -c ${conf1} status ${repo_id} - -rm -rf ${worktree} diff --git a/tests/common-conf.sh.in b/tests/common-conf.sh.in deleted file mode 100644 index 03e00edc..00000000 --- a/tests/common-conf.sh.in +++ /dev/null @@ -1,12 +0,0 @@ - -top_srcdir=@abs_top_srcdir@ - -ccnet=ccnet -ccnet_server=ccnet-server -ccnet_servtool=ccnet-servtool -ccnet_tool=ccnet-tool - -seafile_dir=${top_srcdir} -seaf_daemon=${seafile_dir}/daemon/seaf-daemon -seaf_server=${seafile_dir}/server/seaf-server -seaf_monitor=${seafile_dir}/monitor/seaf-mon diff --git a/tests/common.py b/tests/common.py deleted file mode 100644 index 7a6cabef..00000000 --- a/tests/common.py +++ /dev/null @@ -1,78 +0,0 @@ -import sys -#sys.path = ['../../python', '../../python/ccnet/.libs', '../../python/pyccnetevent/.libs', '../python', '../python/seafile/.libs', '../../lib/searpc', '../../lib/searpc/pysearpc/.libs'] + sys.path - -from datetime import datetime -import os -import sqlite3 - -import ccnet - -class CcnetDaemon(object): - - def __init__(self, confdir): - self.confdir = confdir - - - def start(self, *args): - self.child_pid = os.fork() - if not self.child_pid: - # child - #os.execl("../net/ccnet", "ccnet", "-c", self.confdir, - # "-D", "All", "-f", "-") - os.execl("../../net/ccnet", "ccnet", "-c", self.confdir, - "-D", "All", *args) - - def stop(self): - os.kill(self.child_pid, 2) - -class SeafileDaemon(object): - - def __init__(self, confdir): - self.confdir = confdir - - def start(self, *args): - self.child_pid = os.fork() - if not self.child_pid: - # child - #os.execl("../net/ccnet", "ccnet", "-c", self.confdir, - # "-D", "All", "-f", "-") - os.execl("../daemon/seaf-daemon", "seaf-daemon", "-c", - self.confdir, *args) - - def stop(self): - os.kill(self.child_pid, 2) - - -def get_client_sync(confdir): - client = ccnet.Client() - client.load_confdir(confdir) - client.connect_daemon(ccnet.CLIENT_SYNC) - return client - -def get_client_async(confdir): - client = ccnet.Client() - client.load_confdir(confdir) - sockfd = client.connect_daemon(ccnet.CLIENT_ASYNC) - if sockfd < 0: - print "Can't connect to daemon" - exit() - client.run_synchronizer() - client.sockfd = sockfd - return client - -def print_cmsg(msg): - print >>sys.stderr, "[**Control %s] %s" % ( - datetime.now().strftime("%H:%M:%S.%f"), msg) - -def db_item_exists(dbfile, sql): - """Check whether `sql` returns any records in sqlite db `dbfile`.""" - - conn = sqlite3.connect(dbfile) - c = conn.cursor() - c.execute(sql) - if c.fetchone(): - ret = True - else: - ret = False - conn.close() - return ret diff --git a/tests/test-cdc.c b/tests/test-cdc.c deleted file mode 100644 index fcd24361..00000000 --- a/tests/test-cdc.c +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cdc/cdc.h" - -char *dest_dir = NULL; - -static void rawdata_to_hex (const unsigned char *rawdata, - char *hex_str, int n_bytes) -{ - static const char hex[] = "0123456789abcdef"; - int i; - - for (i = 0; i < n_bytes; i++) { - unsigned int val = *rawdata++; - *hex_str++ = hex[val >> 4]; - *hex_str++ = hex[val & 0xf]; - } - *hex_str = '\0'; -} - -int test_chunks (CDCFileDescriptor *file_descriptor) -{ - struct stat sb; - char chksum_str[CHECKSUM_LENGTH *2 + 1]; - char filename[NAME_MAX_SZ]; - uint8_t *ptr = file_descriptor->blk_sha1s; - int i = 0; - - int max_sz = -1, min_sz = INT_MAX, total_sz = 0; - - printf ("%d chunks.\n", file_descriptor->block_nr); - - while (i < file_descriptor->block_nr) { - rawdata_to_hex (ptr, chksum_str, CHECKSUM_LENGTH); - snprintf (filename, NAME_MAX_SZ, "%s/%s", dest_dir, chksum_str); - if (g_stat (filename, &sb) < 0) { - perror ("stat"); - return -1; - } - - if (sb.st_size < min_sz) - min_sz = sb.st_size; - if (sb.st_size > max_sz) - max_sz = sb.st_size; - total_sz += sb.st_size; - - printf ("%s: %u bytes\n", chksum_str, (uint32_t)sb.st_size); - - if (sb.st_size > file_descriptor->block_max_sz) { - fprintf (stderr, "chunk size too large: %s.\n", chksum_str); - return -1; - } - if (sb.st_size < file_descriptor->block_min_sz && - i != file_descriptor->block_nr - 1) { - fprintf (stderr, "chunk size too small: %s.\n", chksum_str); - return -1; - } - - ptr += CHECKSUM_LENGTH; - ++i; - } - - printf ("max size: %d\n", max_sz); - printf ("min size: %d\n", min_sz); - printf ("avg size: %d\n", total_sz/file_descriptor->block_nr); - - return 0; -} - -int test_write_chunk (const char *repo_id, - int version, - CDCDescriptor *chunk_descr, - struct SeafileCrypt *crypt, - uint8_t *checksum, - gboolean write_data) -{ - char filename[NAME_MAX_SZ]; - char chksum_str[CHECKSUM_LENGTH *2 + 1]; - int fd_chunk, ret; - SHA_CTX ctx; - - SHA1_Init (&ctx); - SHA1_Update (&ctx, chunk_descr->block_buf, chunk_descr->len); - SHA1_Final (checksum, &ctx); - - rawdata_to_hex (chunk_descr->checksum, chksum_str, CHECKSUM_LENGTH); - snprintf (filename, NAME_MAX_SZ, "%s/%s", dest_dir, chksum_str); - fd_chunk = g_open (filename, O_WRONLY | O_CREAT | O_BINARY, 0644); - if (fd_chunk < 0) - return -1; - - ret = write (fd_chunk, chunk_descr->block_buf, chunk_descr->len); - return ret; -} - -int main (int argc, char *argv[]) -{ - char *src_filename = NULL; - int ret = 0, fd_src; - CDCFileDescriptor file_descr; - - if (argc < 3) { - fprintf(stderr, "%s SOURCE DEST \n", argv[0]); - exit(0); - } else { - src_filename = argv[1]; - dest_dir = argv[2]; - } - - cdc_init (); - - memset (&file_descr, 0, sizeof (file_descr)); - file_descr.write_block = test_write_chunk; - ret = filename_chunk_cdc (src_filename, &file_descr, NULL, TRUE); - if (ret == -1) { - fprintf(stderr, "file chunk failed\n"); - exit(1); - } - - ret = test_chunks (&file_descr); - if (ret < 0) { - fprintf (stderr, "chunk test failed.\n"); - exit(1); - } - - printf ("test passed.\n"); - return 0; -} diff --git a/tests/test-crypt.c b/tests/test-crypt.c deleted file mode 100644 index cbef9471..00000000 --- a/tests/test-crypt.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include "seafile-crypt.h" - - -#define CODE "this_is_user_passwd" - -static int crypt_test (unsigned int len) -{ - - if (len <= 0) { - g_printf (" [%s] line %d: len must be positive.\n", __func__, __LINE__); - return -1; - } - - char *msg = "Hello World!\n"; - - GString *gstr = g_string_new (NULL); - - while (gstr->len < len) { - g_string_append (gstr, msg); - } - - char *enc_out = NULL; - int enc_out_len; - - g_printf ("[setup] The input is %d bytes\n", len); - - int res = seafile_encrypt (&enc_out, - &enc_out_len, - gstr->str, - len, - CODE, - strlen(CODE)); - - if (res == 0 && enc_out_len != -1) - g_printf ("[ENC] [PASS] Encrypted output length is %d bytes\n", enc_out_len); - else { - g_printf ("[ENC] FAILED.\n"); - goto error; - } - - char *dec_out = NULL; - int dec_len; - - res = seafile_decrypt (&dec_out, - &dec_len, - enc_out, - enc_out_len, - CODE, - strlen(CODE)); - - - if (res != 0 || (unsigned int)dec_len != len || - strncmp (dec_out, gstr->str, len) != 0) { - - g_printf ("[DEC] FAILED.\n"); - goto error; - } - else - g_printf ("[DEC] [PASS] Decrypted output is the totally same as input\n"); - - g_string_free (gstr, TRUE); - g_free (enc_out); - g_free (dec_out); - - g_printf ("[TEST] Finished Successfully.\n"); - - return 0; - - -error: - - g_string_free (gstr, TRUE); - g_free (enc_out); - g_free (dec_out); - - g_printf ("[TEST] FAILED.\n"); - - return -1; - -} - - -int main (void) -{ - unsigned int len[7] = {1, 8, 16, 50, 111, 1111, 11111}; - - int i; - - for (i = 0; i < 7; i ++) { - if (crypt_test (len[i]) != 0) { - g_printf ("TEST FAILED.\n"); - return -1; - } - } - - - g_printf ("ALL TESTS FINISHED SUCCESSFULLY.\n"); - - return 0; -} - - diff --git a/tests/test-index.c b/tests/test-index.c deleted file mode 100644 index 9f2e51f5..00000000 --- a/tests/test-index.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include "index.h" - -/* static void rawdata_to_hex (const unsigned char *rawdata, */ -/* char *hex_str, int n_bytes) */ -/* { */ -/* static const char hex[] = "0123456789abcdef"; */ -/* int i; */ - -/* for (i = 0; i < n_bytes; i++) { */ -/* unsigned int val = *rawdata++; */ -/* *hex_str++ = hex[val >> 4]; */ -/* *hex_str++ = hex[val & 0xf]; */ -/* } */ -/* *hex_str = '\0'; */ -/* } */ - -int main (int argc, char *argv[]) -{ - char *index_file; - struct index_state istate; - - if (argc < 2) { - fprintf (stderr, "%s index_file\n", argv[0]); - exit (-1); - } - index_file = argv[1]; - - memset (&istate, 0, sizeof(istate)); - if (read_index_from (&istate, index_file) < 0) { - fprintf (stderr, "Corrupt index file %s\n", index_file); - exit (-1); - } - - int i; - struct cache_entry *ce; - char id[41]; - printf ("Totally %u entries in index.\n", istate.cache_nr); - for (i = 0; i < istate.cache_nr; ++i) { - ce = istate.cache[i]; - rawdata_to_hex (ce->sha1, id, 20); - printf ("%s\t%d\t%s\n", ce->name, ce_stage(ce), id); - } - - printf ("Index file format OK.\n"); - return 0; -} diff --git a/tests/test-rpc.py b/tests/test-rpc.py deleted file mode 100644 index 8a3fee31..00000000 --- a/tests/test-rpc.py +++ /dev/null @@ -1,10 +0,0 @@ -import ccnet -import seafile - -pool = ccnet.ClientPool("basic/conf1") -seafile_rpc = seafile.RpcClient(pool) - -repos = seafile_rpc.get_repo_list("", 100) -for repo in repos: - print repo - diff --git a/tests/test-seafile-fmt.c b/tests/test-seafile-fmt.c deleted file mode 100644 index 6c1888c7..00000000 --- a/tests/test-seafile-fmt.c +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils.h" - -/* SHA1 calculate */ -void -sha1( uint8_t * setme, - const void * content, - int content_len) -{ - SHA_CTX sha; - - SHA1_Init (&sha); - SHA1_Update (&sha, content, content_len); - SHA1_Final (setme, &sha); -} - -int main (int argc, char **argv) -{ - char *seafile_path, *file_path; - uint64_t file_size, block_size; - uint32_t n_blocks; - int fd; - FILE *fp; - - if (argc != 3) { - printf ("seafile-fmt-test seafile original-file\n"); - exit (1); - } - - seafile_path = argv[1]; - file_path = argv[2]; - - fd = g_open (seafile_path, O_RDONLY | O_BINARY); - if (fd < 0) { - printf ("Failed to open seafile.\n"); - exit (1); - } - - fp = fopen (file_path, "rb"); - if (!fp) { - printf ("Failed to open original file.\n"); - exit (1); - } - - if (readn (fd, &file_size, sizeof(file_size)) < 0) { - printf ("Failed to read file size.\n"); - exit (1); - } - - if (readn (fd, &block_size, sizeof(block_size)) < 0) { - printf ("Failed to read block_size.\n"); - exit (1); - } - - n_blocks = (uint32_t) ((file_size + block_size -1) / block_size); - - printf ("file size is %lld, block size is %lld, %d blocks.\n", - (long long int)file_size, (long long int)block_size, n_blocks); - - uint8_t *blocks = (uint8_t *) malloc (n_blocks * 20); - if (readn (fd, blocks, n_blocks * 20) < n_blocks * 20) { - printf ("Failed to read blocks.\n"); - exit (1); - } - - int i; - char *block = valloc (block_size); - uint8_t sha1_buf[20]; - for (i = 0; i < n_blocks; ++i) { - int n = fread (block, 1, block_size, fp); - if (n <= 0) { - printf ("Failed to read original file\n"); - exit (1); - } - - sha1 (sha1_buf, block, n); - - if (memcmp (sha1_buf, blocks, 20) != 0) { - printf ("Error in blocks sha1\n"); - exit (1); - } - - blocks += 20; - } - - printf ("Check OK\n"); - return 0; -} diff --git a/tests/test-share.py b/tests/test-share.py deleted file mode 100755 index c7eda998..00000000 --- a/tests/test-share.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python - -from datetime import datetime -import os -import time -import shutil - -import common -from common import CcnetDaemon, SeafileDaemon, print_cmsg, db_item_exists -import ccnet -from pysearpc import * -import seafile - -def cleanup_and_exit(): - os.system("""pkill ccnet""") -# os.system("""cd basic; ./clean.sh""") - exit() - -ccnet_daemon1 = CcnetDaemon("basic/conf1") -ccnet_daemon1.start("--no-multicast") -ccnet_daemon2 = CcnetDaemon("basic/conf2") -ccnet_daemon2.start("--relay") -ccnet_daemon3 = CcnetDaemon("basic/conf3") -ccnet_daemon3.start("--no-multicast") -ccnet_daemon4 = CcnetDaemon("basic/conf4") -ccnet_daemon4.start("--no-multicast") - -print_cmsg("Wait for ccnet daemon starting") -time.sleep(3) - -if not os.access("basic/worktree", os.F_OK): - try: - os.mkdir("basic/worktree") - except OSError as e: - print_cmsg("Failed to create worktree: " + e.strerror) - cleanup_and_exit() - -seaf_daemon1 = SeafileDaemon("basic/conf1") -seaf_daemon1.start("-w", "basic/worktree/wt1") -seaf_daemon2 = SeafileDaemon("basic/conf2") -seaf_daemon2.start("-r") -seaf_daemon3 = SeafileDaemon("basic/conf3") -seaf_daemon3.start("-w", "basic/worktree/wt3") -seaf_daemon4 = SeafileDaemon("basic/conf4") -seaf_daemon4.start("-w", "basic/worktree/wt4") - -print_cmsg("sleep") -time.sleep(15) - -os.system(""" -cd basic; -./seafserv-tool -c conf2 add-server server -./seafserv-tool -c conf2 add-server server2 -""") - -pool1 = ccnet.ClientPool("basic/conf1") -ccnet_rpc1 = ccnet.CcnetRpcClient(pool1) -seaf_rpc1 = seafile.RpcClient(pool1) -seaf_rpc3 = seafile.RpcClient(ccnet.ClientPool("basic/conf3")) - -repo_id = seaf_rpc1.create_repo("test-repo", "test") -if not repo_id: - print_cmsg("Failed to create repo") - cleanup_and_exit() - -print_cmsg("Created repo " + repo_id) - -print_cmsg("Copy data into basic/worktree/wt1") -try: - if not os.access("basic/worktree/wt1/%s/data" % repo_id, os.F_OK): - shutil.copytree("basic/data", "basic/worktree/wt1/%s/data" % repo_id) -except OSError as e: - print_cmsg("Failed to copy data: " + e.strerror) - cleanup_and_exit() - -print_cmsg("Add and commit") - -if seaf_rpc1.add(repo_id, "") < 0: - print_cmsg("Failed to add") - cleanup_and_exit() - -if not seaf_rpc1.commit(repo_id, "commit1"): - print_cmsg("Failed to commit") - cleanup_and_exit() - -print_cmsg("Get group id") - -group_ids = ccnet_rpc1.list_groups() -if not group_ids: - print_cmsg("No group set up") - cleanup_and_exit() -test_group_id = '' -for group_id in group_ids.split("\n"): - if group_id == '': - break - group = ccnet_rpc1.get_group(group_id) - if group.props.name == "ccnet-dev": - test_group_id = group.props.id - break -if not test_group_id: - print_cmsg("Group ccnet-dev cannot be found") - cleanup_and_exit() - -print_cmsg("Share %s to group %s" % (repo_id, test_group_id)) - -try: - if seaf_rpc1.share_repo(repo_id, test_group_id) < 0: - print_cmsg("Failed to share") - cleanup_and_exit() -except SearpcError as e: - print >>sys.stderr, "RPC error: %s" % str(e) - cleanup_and_exit() - -print_cmsg("Wait for share info synchronized") -time.sleep(120) - -share_info = seaf_rpc3.get_repo_sinfo(repo_id) -if not share_info: - print_cmsg("Failed to synchronize share info") - cleanup_and_exit() - -cleanup_and_exit() diff --git a/tests/test-transfer.py b/tests/test-transfer.py deleted file mode 100755 index f3bfcf98..00000000 --- a/tests/test-transfer.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python - -from datetime import datetime -import os -import time -import shutil - -import common -from common import CcnetDaemon, SeafileDaemon, print_cmsg, db_item_exists -import ccnet -from pysearpc import * -import seafile - -def cleanup_and_exit(): - os.system("""pkill ccnet""") -# os.system("""cd basic; ./clean.sh""") - exit() - -ccnet_daemon1 = CcnetDaemon("basic/conf1") -ccnet_daemon1.start("--no-multicast") -ccnet_daemon2 = CcnetDaemon("basic/conf2") -ccnet_daemon2.start("--relay") -ccnet_daemon3 = CcnetDaemon("basic/conf3") -ccnet_daemon3.start("--no-multicast") -ccnet_daemon4 = CcnetDaemon("basic/conf4") -ccnet_daemon4.start("--no-multicast") - -print_cmsg("Wait for ccnet daemon starting") -time.sleep(3) - -if not os.access("basic/worktree", os.F_OK): - try: - os.mkdir("basic/worktree") - except OSError as e: - print_cmsg("Failed to create worktree: " + e.strerror) - cleanup_and_exit() - -seaf_daemon1 = SeafileDaemon("basic/conf1") -seaf_daemon1.start("-w", "basic/worktree/wt1") -seaf_daemon2 = SeafileDaemon("basic/conf2") -seaf_daemon2.start("-r") -seaf_daemon3 = SeafileDaemon("basic/conf3") -seaf_daemon3.start("-w", "basic/worktree/wt3") -seaf_daemon4 = SeafileDaemon("basic/conf4") -seaf_daemon4.start("-w", "basic/worktree/wt4") - -print_cmsg("sleep") -time.sleep(15) - -os.system(""" -cd basic; -./seafserv-tool -c conf2 add-server server -./seafserv-tool -c conf2 add-server server2 -""") - -pool1 = ccnet.ClientPool("basic/conf1") -ccnet_rpc1 = ccnet.CcnetRpcClient(pool1) -seaf_rpc1 = seafile.RpcClient(pool1) -seaf_rpc3 = seafile.RpcClient(ccnet.ClientPool("basic/conf3")) - -repo_id = seaf_rpc1.create_repo("test-repo", "test") -if not repo_id: - print_cmsg("Failed to create repo") - cleanup_and_exit() - -print_cmsg("Created repo " + repo_id) - -print_cmsg("Copy data into basic/worktree/wt1") -try: - if not os.access("basic/worktree/wt1/%s/data" % repo_id, os.F_OK): - shutil.copytree("basic/data", "basic/worktree/wt1/%s/data" % repo_id) -except OSError as e: - print_cmsg("Failed to copy data: " + e.strerror) - cleanup_and_exit() - -print_cmsg("Add and commit") - -try: - seaf_rpc1.add(repo_id, "") -except SearpcError as e: - print_cmsg("Failed to add: " + str(e)) - cleanup_and_exit() - -try: - seaf_rpc1.commit(repo_id, "commit1") -except SearpcError as e: - print_cmsg("Failed to commit: " + str(e)) - cleanup_and_exit() - -print_cmsg("Start upload") - -try: - upload_tx_id = seaf_rpc1.upload(repo_id, "master", "master"); -except SearpcError as e: - print_cmsg("Failed to start upload: " + str(e)) - cleanup_and_exit() - -print_cmsg("Wait for upload") -time.sleep(20) - -try: - fetch_tx_id = seaf_rpc3.fetch(repo_id, "master", "master") -except SearpcError as e: - print_cmsg("Failed to start fetch: " + str(e)) - cleanup_and_exit() - -print_cmsg("Wait for fetch") -time.sleep(20) - -print_cmsg("Initial checkout") -try: - seaf_rpc3.checkout(repo_id, "master") -except SearpcError as e: - print_cmsg("Failed to check out: " + str(e)) - cleanup_and_exit() - -seaf_rpc1.remove_task(upload_tx_id, 1) -seaf_rpc3.remove_task(fetch_tx_id, 0) - -cleanup_and_exit() diff --git a/tools/Makefile.am b/tools/Makefile.am deleted file mode 100644 index 2541f5c3..00000000 --- a/tools/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ - -#AM_CPPFLAGS = @GLIB2_CFLAGS@ - -bin_PROGRAMS = seaf-server-init - -seaf_server_init_SOURCES = seaf-server-init.c ../common/seaf-db.c - -seaf_server_init_LDADD = @GLIB2_LIBS@ @ZDB_LIBS@ -lpthread -seaf_server_init_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@ - -seaf_server_init_CPPFLAGS = @GLIB2_CFLAGS@ @ZDB_CFLAGS@ @MSVC_CFLAGS@ - -EXTRA_DIST = seafile-admin - -if COMPILE_SERVER -bin_SCRIPTS = seafile-admin -endif diff --git a/tools/seaf-server-init.c b/tools/seaf-server-init.c deleted file mode 100644 index 5851af61..00000000 --- a/tools/seaf-server-init.c +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../common/seaf-db.h" - -static int -save_config_file (GKeyFile *key_file, const char *path) -{ - GError *error = NULL; - char *config = g_key_file_to_data (key_file, NULL, &error); - if (error) { - fprintf (stderr, "Failed to save config file to %s: %s\n", - path, error->message); - return -1; - } - - FILE *fp = g_fopen (path, "w"); - if (fp == NULL) { - fprintf (stderr, "Failed to save config file: %s %s.\n", - path, strerror(errno)); - return -1; - } - - fputs (config, fp); - fclose (fp); - - return 0; -} - -static const char *short_opts = "hvd:p:P:F:"; -static const struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'v' }, - { "seafile-dir", required_argument, NULL, 'd' }, - { "central-config-dir", required_argument, NULL, 'F' }, - { "port", required_argument, NULL, 'p' }, - { "fileserver-port", required_argument, NULL, 'P' }, - { 0, 0, 0, 0 }, -}; - -struct seaf_server_config { - char *central_config_dir; - char *seafile_dir; - char *port; - char *fileserver_port; -}; - -static struct seaf_server_config config = { - NULL, - NULL, -}; - - -void usage(int code) { - fprintf (stderr, -"\nUsage: seaf-server-init [OPTIONS]\n" -"Initialize your seafile server configuration\n\n" -"Required arguments are:\n\n" -" -h, --help output help and quit\n" -" -v, --verbose output more information\n" -" -d, --seafile-dir specify a directory to put your seafile server config and data\n" -" -F, --central-config-dir specify a central config dir\n" -" -p, --port specify a port to to transmit data\n" -" -P, --fileserver-port specify the port to use by fileserver\n" - ); - exit(code); -} - -int main (int argc, char **argv) -{ - gboolean verbose = FALSE; - - if (argc == 1) - usage(1); - - int c; - while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != EOF) { - switch (c) { - case 'h': - usage(0); - break; - case 'v': - verbose = TRUE; - break; - case 'F': - config.central_config_dir = strdup(optarg); - break; - case 'd': - config.seafile_dir = strdup(optarg); - break; - case 'p': - config.port = strdup(optarg); - break; - case 'P': - config.fileserver_port = strdup(optarg); - break; - default: - usage(1); - } - } - - if (!config.seafile_dir && !config.central_config_dir) { - fprintf (stderr, "You must specify seafile data dir\n"); - usage(1); - } - - /* Generate config file. */ - GKeyFile *key_file = g_key_file_new (); - - if (config.port) { - g_key_file_set_string (key_file, "network", "port", config.port); - } - - if (config.fileserver_port) { - g_key_file_set_string (key_file, "fileserver", "port", config.fileserver_port); - } else { - /* fileserver port defaults to 8082 */ - g_key_file_set_string (key_file, "fileserver", "port", "8082"); - } - - struct stat st; - if (g_lstat (config.seafile_dir, &st) < 0) { - if (g_mkdir (config.seafile_dir, 0700) < 0) { - fprintf (stderr, "Directory %s cannot be created.\n", config.seafile_dir); - return 1; - } - } - - if (config.central_config_dir && g_lstat (config.central_config_dir, &st) < 0) { - if (g_mkdir (config.central_config_dir, 0700) < 0) { - fprintf (stderr, "Directory %s cannot be created.\n", config.central_config_dir); - return 1; - } - } - - const char *confdir = config.central_config_dir ? config.central_config_dir : config.seafile_dir; - char *seafile_conf = g_build_filename (confdir, "seafile.conf", NULL); - - if (verbose) - printf ("Generating config files: %s\n", seafile_conf); - - if (save_config_file (key_file, seafile_conf) < 0) - return 1; - - printf ("Done.\n"); - - return 0; -} diff --git a/tools/seafile-admin b/tools/seafile-admin deleted file mode 100755 index 5e3658b0..00000000 --- a/tools/seafile-admin +++ /dev/null @@ -1,972 +0,0 @@ -#!/usr/bin/env python -# coding: UTF-8 -'''This is the helper script to setup/manage your seafile server -''' - -import sys - -#################### -### Requires Python 2.6+ -#################### -if sys.version_info.major == 3: - print 'Python 3 not supported yet. Quit now' - sys.exit(1) -if sys.version_info.minor < 6: - print 'Python 2.6 or above is required. Quit now' - sys.exit(1) - -import os -import time -import re -import shutil -import subprocess -import argparse -import uuid - -try: - import readline - # Avoid pylint 'unused import' warning - dummy = readline -except ImportError: - pass - -#################### -### Cosntants -#################### -SERVER_MANUAL_HTTP = 'https://github.com/haiwen/seafile/wiki' -SEAFILE_GOOGLE_GROUP = 'https://groups.google.com/forum/?fromgroups#!forum/seafile' -SEAFILE_WEBSITE = 'http://www.seafile.com' -SEAHUB_DOWNLOAD_URL = 'https://seafile.com.cn/downloads/seahub-latest.tar.gz' - -#################### -### Global variables -#################### -cwd = os.getcwd() -SCRIPT_NAME = os.path.basename(sys.argv[0]) - -PYTHON = sys.executable - -conf = {} -CONF_SERVER_NAME = 'server_name' -CONF_CCNET_DIR = 'ccnet_dir' -CONF_SEAFILE_DIR = 'seafile_dir' -CONF_SEAHUB_DIR = 'seafile_dir' -CONF_CCNET_PORT = 'ccnet_port' -CONF_SEAFILE_PORT = 'seafile_port' -CONF_FILESERVER_PORT = 'fileserver_port' -CONF_IP_OR_DOMAIN = 'ip_or_domain' - -CONF_SEAHUB_CONF = 'seahub_conf' -CONF_SEAHUB_DIR = 'seahub_dir' -CONF_SEAHUB_PORT = 'seahub_port' - -CONF_SEAHUB_PIDFILE = 'seahub_pidfile' -CONF_SEAHUB_OUTLOG = 'seahub_outlog' -CONF_SEAHUB_ERRLOG = 'seahub_errlog' - -CONF_CCNET_CONF_EXISTS = 'ccnet_conf_exists' -CONF_SEAFILE_CONF_EXISTS = 'seafile_conf_exists' - -CONF_ADMIN_EMAIL = 'admin_email' -CONF_ADMIN_PASSWORD = 'admin_password' -CONF_SEAFILE_CENTRAL_CONF_DIR = 'central_config_dir' - -#################### -### Common helper functions - - -def highlight(content): - '''Add ANSI color to content to get it highlighted on terminal''' - return '\x1b[33m%s\x1b[m' % content - - -def info(msg): - print msg - - -def error(msg): - print 'Error: ' + msg - sys.exit(1) - - -def ask_question(desc, - key=None, - note=None, - default=None, - validate=None, - yes_or_no=False, - invalidate_msg=None): - '''Ask a question, return the answer. The optional validate param is a - function used to validate the answer. If yes_or_no is True, then a boolean - value would be returned. - - ''' - assert key or yes_or_no - desc = highlight(desc) - if note: - desc += ' (%s)' % note - if default: - desc += '\n' + ('[default %s ]' % default) - else: - if yes_or_no: - desc += '\n[yes or no]' - else: - desc += '\n' + ('[%s ]' % key) - - desc += ' ' - while True: - answer = raw_input(desc) - if not answer: - if default: - print '' - return default - else: - continue - - answer = answer.strip() - - if yes_or_no: - if answer != 'yes' and answer != 'no': - print '\nPlease answer yes or no\n' - continue - else: - return answer == 'yes' - else: - if validate and not validate(answer): - if invalidate_msg: - print '\n%s\n' % invalidate_msg - else: - print '\n"%s" is not a valid %s\n' % (answer, key) - continue - - print '' - return answer - - -def run_argv(argv, - cwd=None, - env=None, - suppress_stdout=False, - suppress_stderr=False): - '''Run a program and wait it to finish, and return its exit code. The - standard output of this program is supressed. - - ''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(argv, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env) - return proc.wait() - - -def run(cmdline, - cwd=None, - env=None, - suppress_stdout=False, - suppress_stderr=False): - '''Like run_argv but specify a command line string instead of argv''' - with open(os.devnull, 'w') as devnull: - if suppress_stdout: - stdout = devnull - else: - stdout = sys.stdout - - if suppress_stderr: - stderr = devnull - else: - stderr = sys.stderr - - proc = subprocess.Popen(cmdline, - cwd=cwd, - stdout=stdout, - stderr=stderr, - env=env, - shell=True) - return proc.wait() - - -def is_running(process): - '''Detect if there is a process with the given name running''' - argv = ['pgrep', '-f', process] - - return run_argv(argv, suppress_stdout=True) == 0 - - -def pkill(process): - '''Kill the program with the given name''' - argv = ['pkill', '-f', process] - - run_argv(argv) - - -def kill(pid): - '''Kill the program with the given pid''' - argv = ['kill', pid] - - run_argv(argv) - - -def must_mkdir(path): - '''Create a directory, exit on failure''' - try: - os.mkdir(path) - except OSError, e: - error('failed to create directory %s:%s' % (path, e)) - -### END of Common helper functions -#################### - - -def check_seafile_install(): - '''Check if seafile has been correctly built and installed in this - system - - ''' - dirs = os.environ['PATH'].split(':') - - def exist_in_path(prog): - '''Test whether prog exists in system path''' - for d in dirs: - if d == '': - continue - path = os.path.join(d, prog) - if os.path.exists(path): - return True - - return False - - def check_prog(name): - if not exist_in_path(name): - error( - '%s not found in PATH. Have you built and installed seafile server?' - % name) - - progs = [ - 'ccnet-init', - 'seaf-server-init', - 'seaf-server', - 'ccnet-server', - 'seafile-controller', - ] - - for prog in progs: - check_prog(prog) - - -def get_seahub_env(): - '''And PYTHONPATH and CCNET_CONF_DIR/SEAFILE_CONF_DIR to env, which is - needed by seahub - - ''' - seahub_dir = conf[CONF_SEAHUB_DIR] - seahub_thirdpart_dir = os.path.join(seahub_dir, 'thirdpart') - - env = dict(os.environ) - pypath = env.get('PYTHONPATH', '') - - pathlist = [p for p in pypath.split(':') if p != ''] - pathlist.append(seahub_thirdpart_dir) - newpypath = ':'.join(pathlist) - env['PYTHONPATH'] = newpypath - env['CCNET_CONF_DIR'] = conf[CONF_CCNET_DIR] - env['SEAFILE_CONF_DIR'] = conf[CONF_SEAFILE_DIR] - env['SEAFILE_CENTRAL_CONF_DIR'] = conf[CONF_SEAFILE_CENTRAL_CONF_DIR] - return env - - -#################### -### command -#################### -def welcome(): - '''Show welcome message when running the command''' - welcome_msg = '''\ ------------------------------------------------------------------ -This script will guide you to config and setup your seafile server. -Make sure you have read seafile server manual at - - %s - -Press [ENTER] to continue ------------------------------------------------------------------ -''' % SERVER_MANUAL_HTTP - print welcome_msg - raw_input() - - -def get_server_name(): - def validate(name): - r = re.compile(r'^[\w]{3,15}$') - return bool(r.match(name)) - - question = 'What is the name of the server?' - key = 'server name' - note = '3 - 15 letters or digits' - conf[CONF_SERVER_NAME] = ask_question(question, - key=key, - note=note, - validate=validate) - - -def get_server_ip_or_domain(): - def validate(s): - r = r'^[^.].+\..+[^.]$' - return bool(re.match(r, s)) - - question = 'What is the ip of the server?' - key = 'ip or domain' - note = 'For example: www.mycompany.com, 192.168.1.101' - conf[CONF_IP_OR_DOMAIN] = ask_question(question, - key=key, - note=note, - validate=validate) - - -def get_ccnet_conf_dir(): - ccnet_conf_dir = os.path.join(cwd, 'ccnet') - - if os.path.exists(ccnet_conf_dir): - question = 'It seems there already exists ccnet config files in %s, Do you want to use them?' % ccnet_conf_dir - yesno = ask_question(question, yes_or_no=True) - if not yesno: - print highlight( - '\nRemove the directory %s first, and run the script again.\n' - % ccnet_conf_dir) - sys.exit(1) - else: - conf[CONF_CCNET_CONF_EXISTS] = True - else: - conf[CONF_CCNET_CONF_EXISTS] = False - - conf[CONF_CCNET_DIR] = ccnet_conf_dir - - -def get_ccnet_port(): - def validate(s): - try: - port = int(s) - except ValueError: - return False - - return port > 0 and port < 65536 - - question = 'Which port do you want to use for the ccnet server?' - key = 'ccnet server port' - default = '10001' - conf[CONF_CCNET_PORT] = ask_question(question, - key=key, - default=default, - validate=validate) - - -def get_seafile_port(): - def validate(s): - try: - port = int(s) - except ValueError: - return False - - return port > 0 and port < 65536 - - question = 'Which port do you want to use for the seafile server?' - key = 'seafile server port' - default = '12001' - conf[CONF_SEAFILE_PORT] = ask_question(question, - key=key, - default=default, - validate=validate) - - -def get_fileserver_port(): - def validate(s): - try: - port = int(s) - except ValueError: - return False - - return port > 0 and port < 65536 - - question = 'Which port do you want to use for the seafile fileserver?' - key = 'seafile fileserver port' - default = '8082' - conf[CONF_FILESERVER_PORT] = ask_question(question, - key=key, - default=default, - validate=validate) - - -def get_seafile_data_dir(): - question = 'Where do you want to put your seafile data?' - key = 'seafile-data' - note = 'Please use a volume with enough free space' - default = os.path.join(cwd, 'seafile-data') - seafile_data_dir = ask_question(question, - key=key, - note=note, - default=default) - - if os.path.exists(seafile_data_dir): - question = 'It seems there already exists seafile data in %s, Do you want to use them?' % seafile_data_dir - yesno = ask_question(question, yes_or_no=True) - if not yesno: - print highlight( - '\nRemove the directory %s first, and run the script again.\n' - % seafile_data_dir) - sys.exit(1) - else: - conf[CONF_SEAFILE_CONF_EXISTS] = True - else: - conf[CONF_SEAFILE_CONF_EXISTS] = False - - conf[CONF_SEAFILE_DIR] = seafile_data_dir - - -def create_gunicorn_conf(): - runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime') - confpath = os.path.join(runtime_dir, 'seahub.conf') - - if os.path.exists(confpath): - return - - if not os.path.exists(runtime_dir): - must_mkdir(runtime_dir) - - content = '''\ -import os -daemon = True -workers = 3 - -# Logging -runtime_dir = os.path.dirname(__file__) -pidfile = os.path.join(runtime_dir, 'seahub.pid') -errorlog = os.path.join(runtime_dir, 'error.log') -accesslog = os.path.join(runtime_dir, 'access.log') -''' - - try: - with open(confpath, 'w') as fp: - fp.write(content) - except: - error('Failed to write seahub config') - - -def gen_seahub_secret_key(): - data = str(uuid.uuid4()) + str(uuid.uuid4()) - return data[:40] - - -def create_seahub_settings_py(): - seahub_settings_py = os.path.join(cwd, 'conf', 'seahub_settings.py') - try: - with open(seahub_settings_py, 'w') as fp: - line = "SECRET_KEY = '%s'" % gen_seahub_secret_key() - fp.write(line) - except Exception, e: - error('failed to create %s: %s' % (seahub_settings_py, e)) - - -def move_avatar(): - seahub_data_dir = os.path.join(cwd, 'seahub-data') - outside_avatar_dir = os.path.join(seahub_data_dir, 'avatars') - seahub_avatar_dir = os.path.join(conf[CONF_SEAHUB_DIR], 'media', 'avatars') - - if os.path.exists(outside_avatar_dir): - return - - if not os.path.exists(seahub_data_dir): - must_mkdir(seahub_data_dir) - - # move the avatars dir outside - shutil.move(seahub_avatar_dir, outside_avatar_dir) - # make the the original avatars dir a symlink pointing to the outside dir - os.symlink(outside_avatar_dir, seahub_avatar_dir) - - -def init_seahub(): - seahub_dir = conf[CONF_SEAHUB_DIR] - - # create seahub_settings.py - create_seahub_settings_py() - - argv = [PYTHON, 'manage.py', 'syncdb'] - # Set proper PYTHONPATH before run django syncdb command - env = get_seahub_env() - - print - print - info('Now initializing seahub database, please wait...') - print - - if run_argv(argv, cwd=seahub_dir, env=env) != 0: - error('Seahub syncdb failed') - - info('done') - - move_avatar() - create_gunicorn_conf() - - -def check_django_version(): - '''Requires django 1.8''' - import django - if django.VERSION[0] != 1 or django.VERSION[1] != 8: - error('Django 1.8 is required') - del django - - -def check_python_module(import_name, package_name=None, silent=False): - package_name = package_name or import_name - if not silent: - info('checking %s' % package_name) - try: - __import__(import_name) - except ImportError: - error('Python module "%s" not found. Please install it first' % - package_name) - - -def check_python_dependencies(silent=False): - '''Ensure all python libraries we need are installed''' - - if not silent: - info('check python modules ...') - check_django_version() - def check(*a, **kw): - kw.setdefault('silent', silent) - check_python_module(*a, **kw) - pkgs = [ - 'sqlite3', - 'chardet', - 'six', - 'pytz', - 'rest_framework', - 'compressor', - 'statici18n', - 'jsonfield', - 'dateutil', - 'constance', - 'openpyxl', - ] # yapf: disable - for pkg in pkgs: - check(pkg) - check('PIL', 'python imaging library(PIL)') - - print - - -def config_ccnet_seafile(): - get_ccnet_conf_dir() - if not conf[CONF_CCNET_CONF_EXISTS]: - get_server_name() - get_server_ip_or_domain() - get_ccnet_port() - - get_seafile_data_dir() - if not conf[CONF_SEAFILE_CONF_EXISTS]: - get_seafile_port() - get_fileserver_port() - - info('This is your configuration') - info('------------------------------------------') - if conf[CONF_CCNET_CONF_EXISTS]: - info('ccnet config: use existing config in %s' % - highlight(conf[CONF_CCNET_DIR])) - else: - info('ccnet conf dir: %s' % highlight(conf[CONF_CCNET_DIR])) - info('server name: %s' % - highlight(conf[CONF_SERVER_NAME])) - info('server host: %s' % - highlight(conf[CONF_IP_OR_DOMAIN])) - info('ccnet port: %s' % highlight(conf[CONF_CCNET_PORT])) - - if conf[CONF_SEAFILE_CONF_EXISTS]: - info('seafile: use existing config in %s' % - highlight(conf[CONF_SEAFILE_DIR])) - else: - info('seafile data dir: %s' % - highlight(conf[CONF_SEAFILE_DIR])) - info('seafile port: %s' % - highlight(conf[CONF_SEAFILE_PORT])) - info('seafile fileserver port: %s' % - highlight(conf[CONF_FILESERVER_PORT])) - - info('------------------------------------------') - info('Press ENTER if the config is right, or anything else to re-config ') - - if raw_input() != '': - config_ccnet_seafile() - else: - return - - -def init_ccnet_seafile(): - if not conf[CONF_CCNET_CONF_EXISTS]: - info('Generating ccnet configuration...') - argv = [ - 'ccnet-init', - '-F', - conf[CONF_SEAFILE_CENTRAL_CONF_DIR], - '-c', - conf[CONF_CCNET_DIR], - '--name', - conf[CONF_SERVER_NAME], - '--port', - conf[CONF_CCNET_PORT], - '--host', - conf[CONF_IP_OR_DOMAIN], - ] - - if run_argv(argv) != 0: - error('failed to init ccnet configuration') - - info('done') - - if not conf[CONF_SEAFILE_CONF_EXISTS]: - info('Generating seafile configuration...') - argv = [ - 'seaf-server-init', - '-F', - conf[CONF_SEAFILE_CENTRAL_CONF_DIR], - '--seafile-dir', - conf[CONF_SEAFILE_DIR], - '--port', - conf[CONF_SEAFILE_PORT], - '--fileserver-port', - conf[CONF_FILESERVER_PORT], - ] - - if run_argv(argv) != 0: - error('failed to init seafile configuration') - - info('done') - - seafile_ini = os.path.join(conf[CONF_CCNET_DIR], 'seafile.ini') - with open(seafile_ini, 'w') as fp: - fp.write(conf[CONF_SEAFILE_DIR]) - - -#################### -### command -#################### -def start_controller(): - argv = [ - 'seafile-controller', - '-c', - conf[CONF_CCNET_DIR], - '-d', - conf[CONF_SEAFILE_DIR], - '-F', - conf[CONF_SEAFILE_CENTRAL_CONF_DIR], - ] - - info('Starting seafile-server...') - if run_argv(argv) != 0: - error('Failed to start seafile') - - # check again after several seconds - time.sleep(10) - - if not is_running('seafile-controller'): - error('Failed to start seafile') - - -def start_seahub_gunicorn(): - argv = [ - 'gunicorn', - 'seahub.wsgi:application', - '-c', - conf[CONF_SEAHUB_CONF], - '-b', - '0.0.0.0:%s' % conf[CONF_SEAHUB_PORT], - ] - - info('Starting seahub...') - env = get_seahub_env() - if run_argv(argv, cwd=conf[CONF_SEAHUB_DIR], env=env) != 0: - error('Failed to start seahub') - - info('Seahub running on port %s' % conf[CONF_SEAHUB_PORT]) - - -def start_seahub_fastcgi(): - info('Starting seahub in fastcgi mode...') - argv = [ - PYTHON, - 'manage.py', - 'runfcgi', - 'host=%(host)s', - 'port=%(port)s', - 'pidfile=%(pidfile)s', - 'outlog=%(outlog)s', - 'errlog=%(errlog)s', - ] - - host = os.environ.get('SEAFILE_FASTCGI_HOST', '127.0.0.1') - cmdline = ' '.join(argv) % \ - dict(host=host, - port=conf[CONF_SEAHUB_PORT], - pidfile=conf[CONF_SEAHUB_PIDFILE], - outlog=conf[CONF_SEAHUB_OUTLOG], - errlog=conf[CONF_SEAHUB_ERRLOG]) - - env = get_seahub_env() - - if run(cmdline, cwd=conf[CONF_SEAHUB_DIR], env=env) != 0: - error('Failed to start seahub in fastcgi mode') - - info('Seahub running on port %s (fastcgi)' % conf[CONF_SEAHUB_PORT]) - - -def read_seafile_data_dir(ccnet_conf_dir): - '''Read the location of seafile-data from seafile.ini, also consider the - upgrade from older version which do not has the seafile.ini feature - - ''' - seafile_ini = os.path.join(ccnet_conf_dir, 'seafile.ini') - if os.path.exists(seafile_ini): - with open(seafile_ini, 'r') as fp: - seafile_data_dir = fp.read().strip() - else: - # In previous seafile-admin, seafiled-data folder must be under - # the top level directory, so we do not store the location of - # seafile-data folder in seafile.ini - seafile_data_dir = os.path.join(cwd, 'seafile-data') - if os.path.exists(seafile_data_dir): - with open(seafile_ini, 'w') as fp: - fp.write(seafile_data_dir) - - return seafile_data_dir - - -def check_layout(args): - def error_not_found(path): - error('%s not found' % path) - - ccnet_conf_dir = os.path.join(cwd, 'ccnet') - if not os.path.exists(ccnet_conf_dir): - error_not_found(ccnet_conf_dir) - - central_config_dir = os.path.join(cwd, 'conf') - - ccnet_conf = os.path.join(central_config_dir, 'ccnet.conf') - if not os.path.exists(ccnet_conf): - error_not_found(ccnet_conf) - - seafile_data_dir = read_seafile_data_dir(ccnet_conf_dir) - if not os.path.exists(seafile_data_dir): - error_not_found(seafile_data_dir) - - seafile_conf = os.path.join(central_config_dir, 'seafile.conf') - if not os.path.exists(seafile_conf): - error_not_found(seafile_conf) - - runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime') - seahub_conf = os.path.join(runtime_dir, 'seahub.conf') - if not os.path.exists(seahub_conf): - error_not_found(seahub_conf) - - seahub_dir = os.path.join(cwd, 'seafile-server', 'seahub') - if not os.path.exists(seahub_conf): - error_not_found(seahub_dir) - - conf[CONF_SEAFILE_CENTRAL_CONF_DIR] = central_config_dir - conf[CONF_CCNET_DIR] = ccnet_conf_dir - conf[CONF_SEAFILE_DIR] = seafile_data_dir - conf[CONF_SEAHUB_DIR] = seahub_dir - conf[CONF_SEAHUB_CONF] = seahub_conf - conf[CONF_SEAHUB_PIDFILE] = os.path.join(runtime_dir, 'seahub.pid') - conf[CONF_SEAHUB_OUTLOG] = os.path.join(runtime_dir, 'access.log') - conf[CONF_SEAHUB_ERRLOG] = os.path.join(runtime_dir, 'error.log') - - -def check_config(args): - check_layout(args) - - try: - port = int(args.port) - except ValueError: - error('invalid port: %s' % args.port) - else: - if port <= 0 or port > 65535: - error('invalid port: %s' % args.port) - - conf[CONF_SEAHUB_PORT] = port - - -def check_directory_layout(): - seaf_server_dir = os.path.join(cwd, 'seafile-server') - if not os.path.exists(seaf_server_dir): - error( - '"seafile-server/" not found in current directory. \nPlease run seafile-admin in the correct directory.') - - seahub_dir = os.path.join(seaf_server_dir, 'seahub') - if not os.path.exists(seahub_dir): - error( - '"seafile-server/seahub/" not found. \nPlease download seahub first.') - - conf[CONF_SEAHUB_DIR] = seahub_dir - - -def setup_seafile(args): - # avoid pylint "unused variable" warning - dummy = args - - welcome() - check_python_dependencies() - conf[CONF_SEAFILE_CENTRAL_CONF_DIR] = os.path.join(cwd, 'conf') - config_ccnet_seafile() - init_ccnet_seafile() - init_seahub() - - print - print '-----------------------------------------------------------------' - print '-----------------------------------------------------------------' - print 'Your seafile server configuration has been finished successfully.' - print '-----------------------------------------------------------------' - print '-----------------------------------------------------------------' - print - print 'To start/stop seafile server:' - print - print highlight(' $ cd %s' % cwd) - print highlight(' $ %s { start | stop }' % SCRIPT_NAME) - print - print 'If you have any problem, refer to\n' - print - print ' Seafile server manual: %s' % SERVER_MANUAL_HTTP - print - print ' Seafile discussion group: %s' % SEAFILE_GOOGLE_GROUP - print - print ' Seafile website: %s' % SEAFILE_WEBSITE - print - print 'for more information.' - print - - -def check_necessary_files(): - files = [ - os.path.join(cwd, 'conf', 'ccnet.conf'), - os.path.join(cwd, 'seafile-server', 'runtime', 'seahub.conf'), - os.path.join(cwd, 'seahub.db'), - os.path.join(cwd, 'conf', 'seahub_settings.py'), - ] - - for fpath in files: - if not os.path.exists(fpath): - error('%s not found' % fpath) - - -def start_seafile(args): - '''start ccnet/seafile/seahub/fileserver''' - if is_running('seafile-controller'): - error(highlight('NOTE: Seafile is already running')) - - check_python_dependencies(silent=True) - if args.fastcgi: - check_python_module('flup', 'flup', silent=True) - else: - check_python_module('gunicorn', 'gunicorn', silent=True) - - check_necessary_files() - - check_config(args) - - start_controller() - - if args.port: - try: - port = int(args.port) - except ValueError: - error('invalid port: %s' % args.port) - else: - if port <= 0 or port > 65535: - error('invalid port: %s' % args.port) - - if args.fastcgi: - start_seahub_fastcgi() - else: - start_seahub_gunicorn() - - info('Done') - - -def stop_seafile(dummy): - info('Stopping seafile server') - pkill('seafile-controller') - runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime') - pidfile = os.path.join(runtime_dir, 'seahub.pid') - try: - with open(pidfile, 'r') as fp: - pid = fp.read().strip('\n ') - if pid: - kill(pid) - except: - pass - - info('done') - - -def reset_admin(args): - '''reset seafile admin account''' - check_layout(args) - env = get_seahub_env() - - argv = [PYTHON, 'manage.py', 'createsuperuser'] - - env = get_seahub_env() - seahub_dir = conf[CONF_SEAHUB_DIR] - run_argv(argv, cwd=seahub_dir, env=env) - - -def main(): - check_seafile_install() - check_directory_layout() - - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(title='subcommands', description='') - - parser_setup = subparsers.add_parser('setup', - help='setup the seafile server') - parser_setup.set_defaults(func=setup_seafile) - - parser_start = subparsers.add_parser('start', - help='start the seafile server') - parser_start.set_defaults(func=start_seafile) - - parser_start.add_argument('--fastcgi', - help='start seahub in fastcgi mode', - action='store_true') - - parser_start.add_argument('--port', - help='start seahub in fastcgi mode', - default='8000') - - parser_stop = subparsers.add_parser('stop', help='stop the seafile server') - parser_stop.set_defaults(func=stop_seafile) - - parser_reset_admin = subparsers.add_parser( - 'reset-admin', - help='reset seafile admin account') - parser_reset_admin.set_defaults(func=reset_admin) - - parser_create_admin = subparsers.add_parser( - 'create-admin', - help='create seafile admin account') - parser_create_admin.set_defaults(func=reset_admin) - - args = parser.parse_args() - args.func(args) - - -if __name__ == '__main__': - main()