pcloudcc-lneely/pclsync/pfstasks.c

2286 lines
70 KiB
C

/*
Copyright (c) 2014 Anton Titov.
Copyright (c) 2014 pCloud Ltd. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met: Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution. Neither the name of pCloud Ltd nor the
names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <errno.h>
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "pcache.h"
#include "pcryptofolder.h"
#include "pfoldersync.h"
#include "pfs.h"
#include "pfstasks.h"
#include "pfsupload.h"
#include "plibs.h"
#include "ppathstatus.h"
#include "psettings.h"
#include "psql.h"
#include "ptimer.h"
#include "putil.h"
typedef struct {
psync_folderid_t folderid;
char name[];
} file_history_record;
psync_tree *folders = PSYNC_TREE_EMPTY;
static uint64_t psync_local_taskid = UINT64_MAX;
static inline int psync_crypto_is_error(const void *ptr) {
return (uintptr_t)ptr <= PSYNC_CRYPTO_MAX_ERROR;
}
static inline int psync_crypto_to_error(const void *ptr) {
return -((int)(uintptr_t)ptr);
}
psync_fstask_folder_t *
pfs_task_get_or_create_folder_tasks(psync_fsfolderid_t folderid) {
psync_fstask_folder_t *folder;
psql_lock();
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
psql_unlock();
return folder;
}
psync_fstask_folder_t *
pfs_task_get_folder_tasks(psync_fsfolderid_t folderid) {
psync_fstask_folder_t *folder;
psql_lock();
folder = pfs_task_get_folder_tasks_locked(folderid);
psql_unlock();
return folder;
}
void pfs_task_release_folder_tasks(psync_fstask_folder_t *folder) {
psql_lock();
pfs_task_release_folder_tasks_locked(folder);
psql_unlock();
}
psync_fstask_folder_t *
pfs_task_get_ref_locked(psync_fstask_folder_t *folder) {
folder->refcnt++;
return folder;
}
psync_fstask_folder_t *
pfs_task_get_or_create_folder_tasks_locked(psync_fsfolderid_t folderid) {
psync_fstask_folder_t *folder;
psync_tree *tr;
int64_t d;
tr = folders;
d = -1;
while (tr) {
folder = ptree_element(tr, psync_fstask_folder_t, tree);
d = folderid - folder->folderid;
if (d < 0) {
if (tr->left)
tr = tr->left;
else
break;
} else if (d > 0)
if (tr->right)
tr = tr->right;
else
break;
else {
folder->refcnt++;
return folder;
}
}
folder = malloc(sizeof(psync_fstask_folder_t));
if (!folder)
return NULL;
memset(folder, 0, sizeof(psync_fstask_folder_t));
if (d < 0)
ptree_add_before(&folders, tr, &folder->tree);
else
ptree_add_after(&folders, tr, &folder->tree);
folder->folderid = folderid;
folder->refcnt = 1;
return folder;
}
psync_fstask_folder_t *
pfs_task_get_folder_tasks_locked(psync_fsfolderid_t folderid) {
psync_fstask_folder_t *folder;
psync_tree *tr;
tr = folders;
while (tr) {
folder = ptree_element(tr, psync_fstask_folder_t, tree);
if (folderid < folder->folderid)
tr = tr->left;
else if (folderid > folder->folderid)
tr = tr->right;
else {
folder->refcnt++;
return folder;
}
}
return NULL;
}
psync_fstask_folder_t *
pfs_task_get_folder_tasks_rdlocked(psync_fsfolderid_t folderid) {
psync_fstask_folder_t *folder;
psync_tree *tr;
tr = folders;
while (tr) {
folder = ptree_element(tr, psync_fstask_folder_t, tree);
if (folderid < folder->folderid)
tr = tr->left;
else if (folderid > folder->folderid)
tr = tr->right;
else
return folder;
}
return NULL;
}
__attribute__((weak)) void pfstasks_debug_check_folder_consistency(psync_fstask_folder_t *folder) {}
__attribute__((weak)) void pfs_task_dump_state() {}
void pfs_task_release_folder_tasks_locked(psync_fstask_folder_t *folder) {
pfstasks_debug_check_folder_consistency(folder);
if (--folder->refcnt == 0 && !folder->taskscnt) {
pdbg_logf(D_NOTICE, "releasing folder id %ld", (long int)folder->folderid);
ptree_del(&folders, &folder->tree);
free(folder);
}
}
static psync_tree *pfs_task_search_tree(psync_tree *tree, size_t nameoff,
const char *name, uint64_t taskid,
size_t taskidoff) {
int c;
while (tree) {
c = strcmp(name, ((char *)tree) + nameoff);
if (c < 0)
tree = tree->left;
else if (c > 0)
tree = tree->right;
else
break;
}
if (!tree || !taskid || *((uint64_t *)(((char *)tree) + taskidoff)) == taskid)
return tree;
else {
psync_tree *tn;
tn = ptree_get_prev(tree);
while (tn) {
if (strcmp(name, ((char *)tn) + nameoff))
break;
if (*((uint64_t *)(((char *)tn) + taskidoff)) == taskid)
return tn;
tn = ptree_get_prev(tn);
}
tn = ptree_get_next(tree);
while (tn) {
if (strcmp(name, ((char *)tn) + nameoff))
break;
if (*((uint64_t *)(((char *)tn) + taskidoff)) == taskid)
return tn;
tn = ptree_get_next(tn);
}
return NULL;
}
}
static psync_tree *pfs_task_walk_tree(psync_tree *tree, uint64_t taskid,
size_t taskidoff) {
tree = ptree_get_first(tree);
while (tree) {
if (*((uint64_t *)(((char *)tree) + taskidoff)) == taskid)
return tree;
tree = ptree_get_next(tree);
}
return NULL;
}
static void pfs_task_insert_into_tree(psync_tree **tree, size_t nameoff,
psync_tree *element) {
const char *name;
psync_tree *node;
int c;
if (!*tree) {
ptree_add_after(tree, NULL, element);
return;
}
name = ((char *)element) + nameoff;
node = *tree;
while (1) {
c = strcmp(name, ((char *)node) + nameoff);
if (c < 0) {
if (node->left)
node = node->left;
else {
ptree_add_before(tree, node, element);
return;
}
} else {
if (c == 0)
pdbg_logf(D_WARNING, "duplicate entry %s, should not happen", name);
if (node->right)
node = node->right;
else {
ptree_add_after(tree, node, element);
return;
}
}
}
}
psync_fstask_mkdir_t *pfs_task_find_mkdir(psync_fstask_folder_t *folder,
const char *name,
uint64_t taskid) {
return ptree_element(
pfs_task_search_tree(folder->mkdirs,
offsetof(psync_fstask_mkdir_t, name), name,
taskid, offsetof(psync_fstask_mkdir_t, taskid)),
psync_fstask_mkdir_t, tree);
}
psync_fstask_rmdir_t *pfs_task_find_rmdir(psync_fstask_folder_t *folder,
const char *name,
uint64_t taskid) {
return ptree_element(
pfs_task_search_tree(folder->rmdirs,
offsetof(psync_fstask_rmdir_t, name), name,
taskid, offsetof(psync_fstask_rmdir_t, taskid)),
psync_fstask_rmdir_t, tree);
}
psync_fstask_creat_t *pfs_task_find_creat(psync_fstask_folder_t *folder,
const char *name,
uint64_t taskid) {
return ptree_element(
pfs_task_search_tree(folder->creats,
offsetof(psync_fstask_creat_t, name), name,
taskid, offsetof(psync_fstask_creat_t, taskid)),
psync_fstask_creat_t, tree);
}
psync_fstask_unlink_t *pfs_task_find_unlink(psync_fstask_folder_t *folder,
const char *name,
uint64_t taskid) {
return ptree_element(
pfs_task_search_tree(folder->unlinks,
offsetof(psync_fstask_unlink_t, name), name,
taskid, offsetof(psync_fstask_unlink_t, taskid)),
psync_fstask_unlink_t, tree);
}
psync_fstask_mkdir_t *
pfs_task_find_mkdir_by_folderid(psync_fstask_folder_t *folder,
psync_fsfolderid_t folderid) {
return ptree_element(
pfs_task_walk_tree(folder->mkdirs, folderid,
offsetof(psync_fstask_mkdir_t, folderid)),
psync_fstask_mkdir_t, tree);
}
psync_fstask_creat_t *
pfs_task_find_creat_by_fileid(psync_fstask_folder_t *folder,
psync_fsfileid_t fileid) {
return ptree_element(
pfs_task_walk_tree(folder->creats, fileid,
offsetof(psync_fstask_creat_t, fileid)),
psync_fstask_creat_t, tree);
}
static void pfs_task_depend(uint64_t taskid, uint64_t dependontaskid) {
psync_sql_res *res;
res = psql_prepare("INSERT OR IGNORE INTO fstaskdepend "
"(fstaskid, dependfstaskid) VALUES (?, ?)");
psql_bind_uint(res, 1, taskid);
psql_bind_uint(res, 2, dependontaskid);
psql_run_free(res);
}
static uint32_t pfs_task_depend_on_name(uint64_t taskid,
psync_fsfolderid_t folderid,
const char *name, size_t len) {
psync_sql_res *res;
res = psql_prepare(
"INSERT OR IGNORE INTO fstaskdepend (fstaskid, dependfstaskid) SELECT ?, "
"id FROM fstask "
"WHERE folderid=? AND text1=? AND id!=? AND status!=3");
psql_bind_uint(res, 1, taskid);
psql_bind_int(res, 2, folderid);
psql_bind_lstr(res, 3, name, len);
psql_bind_uint(res, 4, taskid);
psql_run_free(res);
return psql_affected();
}
static uint32_t pfs_task_depend_on_name2(uint64_t taskid, uint64_t taskid2,
psync_fsfolderid_t folderid,
const char *name, size_t len) {
psync_sql_res *res;
res = psql_prepare(
"INSERT OR IGNORE INTO fstaskdepend (fstaskid, dependfstaskid) SELECT ?, "
"id FROM fstask "
"WHERE folderid=? AND text1=? AND id NOT IN (?, ?) AND status!=3");
psql_bind_uint(res, 1, taskid);
psql_bind_int(res, 2, folderid);
psql_bind_lstr(res, 3, name, len);
psql_bind_uint(res, 4, taskid);
psql_bind_uint(res, 5, taskid2);
psql_run_free(res);
return psql_affected();
}
int pfs_task_mkdir(psync_fsfolderid_t folderid, const char *name,
uint32_t folderflags) {
psync_sql_res *res;
psync_uint_row row;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *task;
uint64_t taskid;
char *key;
size_t len, klen;
time_t ctime;
uint32_t depend;
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
len = strlen(name);
if (folderid >= 0) {
res = psql_query(
"SELECT id FROM folder WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
psql_free(res);
if (row && !pfs_task_find_rmdir(folder, name, 0)) {
pfs_task_release_folder_tasks_locked(folder);
return -pdbg_return_const(EEXIST);
}
}
if ((task = pfs_task_find_mkdir(folder, name, 0))) {
depend = task->flags;
pfs_task_release_folder_tasks_locked(folder);
if (depend & PSYNC_FOLDER_FLAG_INVISIBLE)
return -pdbg_return_const(EACCES);
else
return -pdbg_return_const(EEXIST);
}
ctime = ptimer_time();
if (folderflags & PSYNC_FOLDER_FLAG_ENCRYPTED) {
key = pcryptofolder_filencoder_key_new(PSYNC_CRYPTO_SYM_FLAG_ISDIR,
&klen);
if (psync_crypto_is_error(key)) {
pfs_task_release_folder_tasks_locked(folder);
return -pfs_crypto_err_to_errno(psync_crypto_to_error(key));
}
} else
key = NULL;
psql_start();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, sfolderid, text1, text2, "
"int1) VALUES (" NTO_STR(PSYNC_FS_TASK_MKDIR) ", 0, ?, ?, ?, ?, ?)");
psql_bind_int(res, 1, folderid);
psql_bind_int(res, 2, folderid);
psql_bind_lstr(res, 3, name, len);
if (key)
psql_bind_lstr(res, 4, key, klen);
else
psql_bind_null(res, 4);
psql_bind_uint(res, 5, ctime);
psql_run_free(res);
taskid = psql_insertid();
if (folderid < 0) {
pfs_task_depend(taskid, -folderid);
depend = 1;
} else
depend = 0;
depend += pfs_task_depend_on_name(taskid, folderid, name, len);
if (pdbg_unlikely(psql_commit())) {
pfs_task_release_folder_tasks_locked(folder);
return -EIO;
}
len++;
task = (psync_fstask_mkdir_t *)malloc(
offsetof(psync_fstask_mkdir_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
task->taskid = taskid;
task->ctime = task->mtime = ctime;
task->folderid = -(psync_fsfolderid_t)taskid;
task->subdircnt = 0;
task->flags = folderflags & PSYNC_FOLDER_FLAG_ENCRYPTED;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->mkdirs, offsetof(psync_fstask_mkdir_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
if (!depend)
pfs_upld_wake();
if (folderid >= 0)
ppathstatus_drive_fldr_changed(folderid);
return 0;
}
int pfs_task_can_rmdir(psync_fsfolderid_t folderid, uint32_t parentflags,
const char *name) {
psync_sql_res *res;
psync_uint_row row;
psync_str_row srow;
psync_fstask_folder_t *folder, *cfolder;
psync_fstask_mkdir_t *mk;
psync_fsfolderid_t cfolderid;
size_t len;
len = strlen(name);
folder = pfs_task_get_folder_tasks_locked(folderid);
if (folder && (mk = pfs_task_find_mkdir(folder, name, 0)))
cfolderid = mk->folderid;
else {
res = psql_query(
"SELECT id, flags FROM folder WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
if (!row || (folder && pfs_task_find_rmdir(folder, name, 0))) {
psql_free(res);
pfs_task_release_folder_tasks_locked(folder);
return -ENOENT;
}
cfolderid = row[0];
if ((row[1] & PSYNC_FOLDER_FLAG_ENCRYPTED) &&
!(parentflags & PSYNC_FOLDER_FLAG_ENCRYPTED)) {
psql_free(res);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_WARNING,
"attempt to delete encrypted folder %s in folderid %lu rejected",
name, (unsigned long)folderid);
return -EACCES;
}
psql_free(res);
}
cfolder = pfs_task_get_folder_tasks_locked(cfolderid);
if (cfolder && (cfolder->creats || cfolder->mkdirs)) {
pfs_task_release_folder_tasks_locked(cfolder);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
if (cfolderid >= 0) {
res = psql_query("SELECT name FROM file WHERE parentfolderid=?");
psql_bind_uint(res, 1, cfolderid);
while ((srow = psql_fetch_str(res)))
if (!cfolder || !pfs_task_find_unlink(cfolder, srow[0], 0)) {
psql_free(res);
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
psql_free(res);
res = psql_query("SELECT name FROM folder WHERE parentfolderid=?");
psql_bind_uint(res, 1, cfolderid);
while ((srow = psql_fetch_str(res)))
if (!cfolder || !pfs_task_find_rmdir(cfolder, srow[0], 0)) {
psql_free(res);
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
psql_free(res);
}
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
return 0;
}
int pfs_task_rmdir(psync_fsfolderid_t folderid, uint32_t parentflags,
const char *name) {
psync_sql_res *res;
psync_uint_row row;
psync_str_row srow;
psync_fstask_folder_t *folder, *cfolder;
psync_fstask_rmdir_t *task;
psync_fstask_mkdir_t *mk;
uint64_t depend, taskid;
psync_fsfolderid_t cfolderid;
size_t len;
len = strlen(name);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
mk = pfs_task_find_mkdir(folder, name, 0);
if (mk == NULL) {
res = psql_query(
"SELECT id, flags FROM folder WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
if (!row || pfs_task_find_rmdir(folder, name, 0)) {
psql_free(res);
pfs_task_release_folder_tasks_locked(folder);
return -ENOENT;
}
cfolderid = row[0];
if ((row[1] & PSYNC_FOLDER_FLAG_ENCRYPTED) &&
!(parentflags & PSYNC_FOLDER_FLAG_ENCRYPTED)) {
psql_free(res);
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_WARNING,
"attempt to delete encrypted folder %s in folderid %lu rejected",
name, (unsigned long)folderid);
return -EACCES;
}
psql_free(res);
depend = 0;
} else {
depend = mk->taskid;
cfolderid = mk->folderid;
folder->taskscnt--;
}
cfolder = pfs_task_get_folder_tasks_locked(cfolderid);
if (cfolder && (cfolder->creats || cfolder->mkdirs)) {
pfs_task_release_folder_tasks_locked(cfolder);
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
if (cfolderid >= 0) {
res = psql_query("SELECT name FROM file WHERE parentfolderid=?");
psql_bind_uint(res, 1, cfolderid);
while ((srow = psql_fetch_str(res)))
if (!cfolder || !pfs_task_find_unlink(cfolder, srow[0], 0)) {
psql_free(res);
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
psql_free(res);
res = psql_query("SELECT name FROM folder WHERE parentfolderid=?");
psql_bind_uint(res, 1, cfolderid);
while ((srow = psql_fetch_str(res)))
if (!cfolder || !pfs_task_find_rmdir(cfolder, srow[0], 0)) {
psql_free(res);
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
pfs_task_release_folder_tasks_locked(folder);
pdbg_logf(D_NOTICE, "returning ENOTEMPTY for folder name %s", name);
return -ENOTEMPTY;
}
psql_free(res);
}
if (mk) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
}
if (cfolder)
pfs_task_release_folder_tasks_locked(cfolder);
psql_start();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, sfolderid, text1) VALUES "
"(" NTO_STR(PSYNC_FS_TASK_RMDIR) ", 0, ?, ?, ?)");
psql_bind_int(res, 1, folderid);
psql_bind_int(res, 2, cfolderid);
psql_bind_lstr(res, 3, name, len);
psql_run_free(res);
taskid = psql_insertid();
if (depend)
pfs_task_depend(taskid, depend);
res = psql_query("SELECT id FROM fstask WHERE folderid=?");
psql_bind_int(res, 1, cfolderid);
while ((row = psql_fetch_int(res))) {
pfs_task_depend(taskid, row[0]);
depend++;
}
psql_free(res);
pfs_task_depend_on_name(taskid, folderid, name, len);
if (pdbg_unlikely(psql_commit())) {
pfs_task_release_folder_tasks_locked(folder);
return -EIO;
}
len++;
task = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
task->taskid = taskid;
task->folderid = cfolderid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
if (depend == 0)
pfs_upld_wake();
return 0;
}
psync_fstask_creat_t *pfs_task_add_creat(psync_fstask_folder_t *folder,
const char *name,
psync_fsfileid_t fileid,
const char *encsymkey,
size_t encsymkeylen) {
psync_sql_res *res;
psync_fstask_creat_t *task;
psync_fstask_unlink_t *un;
uint64_t taskid;
size_t len;
pdbg_assert(fileid >= 0);
len = strlen(name);
psql_start();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, sfolderid, text1, "
"text2, int1) "
"VALUES (" NTO_STR(PSYNC_FS_TASK_CREAT) ", 1, ?, ?, ?, ?, ?, 0)");
psql_bind_int(res, 1, folder->folderid);
psql_bind_int(res, 2, fileid);
psql_bind_int(res, 3, folder->folderid);
psql_bind_lstr(res, 4, name, len);
if (encsymkey)
psql_bind_lstr(res, 5, encsymkey, encsymkeylen);
else
psql_bind_null(res, 5);
psql_run_free(res);
taskid = psql_insertid();
if (folder->folderid < 0)
pfs_task_depend(taskid, -folder->folderid);
pfs_task_depend_on_name(taskid, folder->folderid, name, len);
if (pdbg_unlikely(psql_commit()))
return NULL;
len++;
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un)
return NULL;
un->fileid = -(psync_fsfileid_t)taskid;
un->taskid = taskid;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &un->tree);
task = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + len);
if (!task) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
return NULL;
}
task->fileid = -(psync_fsfileid_t)taskid;
task->rfileid = fileid;
task->taskid = taskid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &task->tree);
folder->taskscnt += 2;
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
return task;
}
void pfs_task_inject_creat(psync_fstask_folder_t *folder,
psync_fstask_creat_t *cr) {
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &cr->tree);
folder->taskscnt++;
}
void pfs_task_inject_unlink(psync_fstask_folder_t *folder,
psync_fstask_unlink_t *un) {
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_creat_t, name), &un->tree);
folder->taskscnt++;
}
psync_fstask_creat_t *
pfs_task_add_modified_file(psync_fstask_folder_t *folder, const char *name,
psync_fsfileid_t fileid, uint64_t hash,
const char *encsymkey, size_t encsymkeylen) {
psync_sql_res *res;
psync_fstask_unlink_t *un;
psync_fstask_creat_t *task;
uint64_t taskid;
size_t len;
len = strlen(name);
pdbg_assert(fileid > 0);
psql_start();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, sfolderid, text1, "
"text2, int1, int2) "
"VALUES (" NTO_STR(PSYNC_FS_TASK_MODIFY) ", 1, ?, ?, ?, ?, ?, 0, ?)");
psql_bind_int(res, 1, folder->folderid);
psql_bind_int(res, 2, fileid);
psql_bind_int(res, 3, folder->folderid);
psql_bind_lstr(res, 4, name, len);
if (encsymkey)
psql_bind_lstr(res, 5, encsymkey, encsymkeylen);
else
psql_bind_null(res, 5);
psql_bind_uint(res, 6, hash);
psql_run_free(res);
taskid = psql_insertid();
if (folder->folderid < 0)
pfs_task_depend(taskid, -folder->folderid);
pfs_task_depend_on_name(taskid, folder->folderid, name, len);
task = pfs_task_find_creat(folder, name, 0);
if (task) {
pfs_task_depend(taskid, task->taskid);
ptree_del(&folder->creats, &task->tree);
free(task);
folder->taskscnt--;
}
if (pdbg_unlikely(psql_commit()))
return NULL;
len++;
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un)
return NULL;
un->fileid = fileid;
un->taskid = taskid;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &un->tree);
task = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + len);
if (!task) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
return NULL;
}
task->fileid = -(psync_fsfileid_t)taskid;
task->rfileid = fileid;
task->taskid = taskid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &task->tree);
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
folder->taskscnt += 2;
return task;
}
int pfs_task_set_mtime(psync_fileid_t fileid, uint64_t oldtm,
uint64_t newtm, int is_ctime) {
psync_sql_res *res;
psql_start();
if (is_ctime)
res = psql_prepare("UPDATE file SET ctime=? WHERE id=?");
else
res = psql_prepare("UPDATE file SET mtime=? WHERE id=?");
psql_bind_uint(res, 1, newtm);
psql_bind_uint(res, 2, fileid);
psql_run_free(res);
// folderid is ignored for these tasks
res =
psql_prepare("INSERT INTO fstask (type, status, folderid, "
"fileid, int1, int2) VALUES (?, 0, 0, ?, ?, ?)");
psql_bind_int(res, 1,
is_ctime ? PSYNC_FS_TASK_SET_FILE_CR
: PSYNC_FS_TASK_SET_FILE_MOD);
psql_bind_int(res, 2, fileid);
psql_bind_int(res, 3, oldtm);
psql_bind_int(res, 4, newtm);
psql_run_free(res);
if (pdbg_unlikely(psql_commit()))
return -EIO;
pfs_upld_wake();
return 0;
}
int pfs_task_add_local_creat_static(psync_fsfolderid_t folderid,
const char *name, const void *data,
size_t datalen) {
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *un;
psync_fstask_local_creat_t *lc;
psync_sql_res *res;
psync_uint_row row;
size_t len, addlen;
int ret;
ret = -1;
len = strlen(name);
psql_lock();
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
cr = pfs_task_find_creat(folder, name, 0);
if (cr) {
pdbg_logf(D_NOTICE,
"not adding file %s to folderid %ld as creat already exists", name,
(long)folderid);
goto ex;
}
if (folderid >= 0 && !pfs_task_find_unlink(folder, name, 0)) {
res = psql_query(
"SELECT id FROM file WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
psql_free(res);
if (row) {
pdbg_logf(D_NOTICE,
"not adding file %s to folderid %ld as it already exists in the "
"database",
name, (long)folderid);
goto ex;
}
}
pdbg_logf(D_NOTICE, "adding file %s to folderid %ld, datalen %lu", name,
(long)folderid, (unsigned long)datalen);
len++;
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un) {
ret = -ENOMEM;
goto ex;
}
un->taskid = psync_local_taskid;
un->fileid = 0;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &un->tree);
addlen = pfs_task_creat_local_offset(len - 1);
cr = (psync_fstask_creat_t *)malloc(addlen +
sizeof(psync_fstask_local_creat_t));
if (!cr) {
ret = -ENOMEM;
goto ex;
}
cr->fileid = 0;
cr->rfileid = 0;
cr->taskid = psync_local_taskid;
memcpy(cr->name, name, len);
lc = (psync_fstask_local_creat_t *)(((char *)cr) + addlen);
lc->data = data;
lc->datalen = datalen;
lc->ctime = ptimer_time();
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &cr->tree);
psync_local_taskid--;
folder->taskscnt += 2;
ret = 0;
ex:
pfs_task_release_folder_tasks_locked(folder);
psql_unlock();
return ret;
}
static psync_fsfileid_t get_file_at_old_location(psync_fsfileid_t fileid) {
file_history_record *rec;
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_sql_res *res;
psync_uint_row row;
psync_fsfileid_t ret;
char key[16];
if (fileid < 0)
return 0;
psync_get_string_id(key, "HLOC", fileid);
rec = (file_history_record *)pcache_get(key);
if (!rec)
return 0;
folder = pfs_task_get_folder_tasks_locked(rec->folderid);
if (folder) {
cr = pfs_task_find_creat(folder, rec->name, 0);
if (cr) {
free(rec);
pfs_task_release_folder_tasks_locked(folder);
return cr->fileid;
}
if (pfs_task_find_unlink(folder, rec->name, 0)) {
free(rec);
pfs_task_release_folder_tasks_locked(folder);
return 0;
}
pfs_task_release_folder_tasks_locked(folder);
}
res =
psql_query("SELECT id FROM file WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, rec->folderid);
psql_bind_str(res, 2, rec->name);
if ((row = psql_fetch_int(res)))
ret = row[0];
else
ret = 0;
psql_free(res);
free(rec);
return ret;
}
void pfs_task_stop_and_delete_file(psync_fsfileid_t fileid) {
psync_sql_res *res;
pdbg_logf(D_NOTICE, "trying to stop upload of task %lu", (unsigned long)-fileid);
if (pfs_upld_in_current_small_uploads_batch_locked(-fileid)) {
pdbg_logf(D_NOTICE, "file is in current small uploads batch");
return;
}
pfs_upld_stop_upload_locked(-fileid);
res = psql_prepare("UPDATE fstask SET status=11 WHERE id=?");
psql_bind_uint(res, 1, -fileid);
psql_run_free(res);
res = psql_prepare(
"UPDATE fstask SET status=11 WHERE fileid=? AND status!=10");
psql_bind_int(res, 1, fileid);
psql_run_free(res);
pfs_mark_openfile_deleted(-fileid);
}
int pfs_task_can_unlink(psync_fsfolderid_t folderid, const char *name) {
psync_sql_res *res;
psync_uint_row row;
psync_fstask_folder_t *folder;
size_t len;
len = strlen(name);
folder = pfs_task_get_folder_tasks_locked(folderid);
if (folder && pfs_task_find_creat(folder, name, 0))
pfs_task_release_folder_tasks_locked(folder);
else {
res = psql_query(
"SELECT id FROM file WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
if (!row || (folder && pfs_task_find_unlink(folder, name, 0))) {
psql_free(res);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
return -ENOENT;
}
psql_free(res);
if (folder)
pfs_task_release_folder_tasks_locked(folder);
}
return 0;
}
int pfs_task_unlink(psync_fsfolderid_t folderid, const char *name) {
psync_sql_res *res;
psync_uint_row row;
psync_fstask_folder_t *folder;
psync_fstask_unlink_t *task;
psync_fstask_creat_t *cr;
uint64_t depend, taskid;
psync_fsfileid_t fileid, revoffileid;
psync_fileid_t rfileid;
size_t len;
len = strlen(name);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
cr = pfs_task_find_creat(folder, name, 0);
if (cr == NULL) {
res = psql_query(
"SELECT id FROM file WHERE parentfolderid=? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_lstr(res, 2, name, len);
row = psql_fetch_int(res);
if (!row || pfs_task_find_unlink(folder, name, 0)) {
psql_free(res);
pfs_task_release_folder_tasks_locked(folder);
return -ENOENT;
}
fileid = row[0];
psql_free(res);
depend = 0;
rfileid = 0;
} else {
rfileid = cr->rfileid;
if (unlikely(cr->fileid == 0)) {
task = pfs_task_find_unlink(folder, cr->name, cr->taskid);
if (pdbg_likely(task)) {
ptree_del(&folder->unlinks, &task->tree);
folder->taskscnt--;
free(task);
}
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
pfs_task_release_folder_tasks_locked(folder);
return 0;
}
depend = cr->taskid;
fileid = cr->fileid;
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
}
revoffileid = get_file_at_old_location(fileid);
psql_start();
if (fileid < 0)
pfs_task_stop_and_delete_file(fileid);
if (revoffileid) {
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, int1, text1, "
"int2) VALUES "
"(" NTO_STR(PSYNC_FS_TASK_UN_SET_REV) ", 0, ?, ?, ?, ?, ?)");
psql_bind_int(res, 1, folderid);
psql_bind_int(res, 2, revoffileid);
psql_bind_int(res, 3, fileid);
psql_bind_lstr(res, 4, name, len);
psql_bind_uint(res, 5, rfileid);
psql_run_free(res);
} else {
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, text1, int2) "
"VALUES (" NTO_STR(PSYNC_FS_TASK_UNLINK) ", ?, ?, ?, ?, ?)");
psql_bind_int(res, 1, fileid < 0 ? 11 : 0);
psql_bind_int(res, 2, folderid);
psql_bind_int(res, 3, fileid);
psql_bind_lstr(res, 4, name, len);
psql_bind_uint(res, 5, rfileid);
psql_run_free(res);
}
taskid = psql_insertid();
if (depend)
pfs_task_depend(taskid, depend);
if (revoffileid < 0)
pfs_task_depend(taskid, -revoffileid);
if (fileid < 0 && -fileid != depend)
pfs_task_depend(taskid, -fileid);
pfs_task_depend_on_name(taskid, folderid, name, len);
if (pdbg_unlikely(psql_commit())) {
pfs_task_release_folder_tasks_locked(folder);
return -EIO;
}
len++;
task = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
task->taskid = taskid;
task->fileid = fileid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
if (depend == 0 || fileid < 0)
pfs_upld_wake();
return 0;
}
static void add_history_record(psync_fileid_t fileid, psync_folderid_t folderid,
const char *name) {
file_history_record *rec;
size_t len;
char key[16];
psync_get_string_id(key, "HLOC", fileid);
while ((rec = (file_history_record *)pcache_get(key)))
free(rec);
len = strlen(name) + 1;
rec = (file_history_record *)malloc(
offsetof(file_history_record, name) + len);
if (!rec)
return;
rec->folderid = folderid;
memcpy(rec->name, name, len);
pcache_add(key, rec, PSYNC_FS_FILE_LOC_HIST_SEC, free, 1);
}
int pfs_task_rename_file(psync_fsfileid_t fileid,
psync_fsfolderid_t parentfolderid,
const char *name, psync_fsfolderid_t to_folderid,
const char *new_name) {
psync_sql_res *res;
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *rm;
psync_fileid_t rfileid;
size_t nlen, nnlen;
uint64_t ftaskid, ttaskid;
nlen = strlen(name);
if (new_name)
nnlen = strlen(new_name);
else {
new_name = name;
nnlen = nlen;
}
folder = pfs_task_get_or_create_folder_tasks_locked(parentfolderid);
cr = pfs_task_find_creat(folder, name, 0);
if (cr)
rfileid = cr->rfileid;
else
rfileid = 0;
pdbg_logf(D_NOTICE, "renaming file %ld from %ld/%s to %ld/%s", (long)fileid,
(long)parentfolderid, name, (long)to_folderid, new_name);
psql_start();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, text1) VALUES "
"(" NTO_STR(PSYNC_FS_TASK_RENFILE_FROM) ", 10, ?, ?, ?)");
psql_bind_int(res, 1, parentfolderid);
psql_bind_int(res, 2, fileid);
psql_bind_lstr(res, 3, name, nlen);
psql_run_free(res);
ftaskid = psql_insertid();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, fileid, text1, int1, int2) "
"VALUES (" NTO_STR(PSYNC_FS_TASK_RENFILE_TO) ", 0, ?, ?, ?, ?, ?)");
psql_bind_int(res, 1, to_folderid);
psql_bind_int(res, 2, fileid);
psql_bind_lstr(res, 3, new_name, nnlen);
psql_bind_uint(res, 4, ftaskid);
psql_bind_uint(res, 5, rfileid);
psql_run_free(res);
ttaskid = psql_insertid();
if (fileid < 0) {
res = psql_prepare("UPDATE fstask SET sfolderid=? WHERE id=?");
psql_bind_int(res, 1, to_folderid);
psql_bind_uint(res, 2, -fileid);
psql_run_free(res);
pfs_task_depend(ttaskid, -fileid);
}
if (parentfolderid < 0)
pfs_task_depend(ttaskid, -parentfolderid);
if (to_folderid < 0 && to_folderid != parentfolderid)
pfs_task_depend(ttaskid, -to_folderid);
pfs_task_depend_on_name2(ttaskid, ftaskid, parentfolderid, name, nlen);
pfs_task_depend_on_name(ttaskid, to_folderid, new_name, nnlen);
if (cr)
pfs_task_depend(ttaskid, cr->taskid);
if (pdbg_unlikely(psql_commit())) {
pfs_task_release_folder_tasks_locked(folder);
return -EIO;
}
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
}
pfs_rename_openfile_locked(fileid, to_folderid, new_name);
nlen++;
rm = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + nlen);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
rm->taskid = ftaskid;
rm->fileid = fileid;
memcpy(rm->name, name, nlen);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &rm->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
folder = pfs_task_get_or_create_folder_tasks_locked(to_folderid);
nnlen++;
cr = pfs_task_find_creat(folder, new_name, 0);
if (cr) {
pdbg_logf(D_NOTICE, "renaming over creat of file %s(%ld) in folder %lu",
new_name, (long)cr->fileid, (unsigned long)to_folderid);
if (cr->fileid < 0)
pfs_task_stop_and_delete_file(cr->fileid);
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
rm = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + nnlen);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
rm->fileid = fileid;
rm->taskid = ttaskid;
memcpy(rm->name, new_name, nnlen);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &rm->tree);
cr = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + nnlen);
if (!cr) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
cr->fileid = fileid;
cr->rfileid = rfileid;
cr->taskid = ttaskid;
memcpy(cr->name, new_name, nnlen);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &cr->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
pfs_upld_wake();
if (fileid > 0 && parentfolderid >= 0)
add_history_record(fileid, parentfolderid, name);
else if (rfileid > 0 && parentfolderid >= 0)
add_history_record(rfileid, parentfolderid, name);
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
return 0;
}
static void fill_mkdir_data(psync_fsfolderid_t folderid,
psync_fstask_mkdir_t *mkdir) {
psync_sql_res *res;
psync_uint_row row;
mkdir->ctime = mkdir->mtime = ptimer_time();
mkdir->subdircnt = 0;
if (folderid < 0) {
res = psql_query("SELECT int1 FROM fstask WHERE id=?");
psql_bind_uint(res, 1, -folderid);
if ((row = psql_fetch_int(res)))
mkdir->ctime = mkdir->mtime = row[0];
psql_free(res);
} else {
res = psql_query(
"SELECT ctime, mtime, subdircnt FROM folder WHERE id=?");
psql_bind_uint(res, 1, folderid);
if ((row = psql_fetch_int(res))) {
mkdir->ctime = row[0];
mkdir->mtime = row[1];
mkdir->subdircnt = row[2];
}
psql_free(res);
}
}
static uint64_t pfs_task_delete_folder_if_ex(psync_fsfolderid_t folderid,
const char *name,
psync_fsfolderid_t from_fid) {
psync_sql_res *res;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_fsfolderid_t cfolderid;
psync_uint_row row;
uint64_t depend, taskid;
size_t len;
cfolderid = 0;
depend = 0;
folder = pfs_task_get_folder_tasks_locked(folderid);
if (folder) {
if ((mk = pfs_task_find_mkdir(folder, name, 0))) {
cfolderid = mk->folderid;
depend = mk->taskid;
} else if (pfs_task_find_rmdir(folder, name, 0)) {
pfs_task_release_folder_tasks_locked(folder);
return 0;
}
pfs_task_release_folder_tasks_locked(folder);
}
len = strlen(name);
if (cfolderid == 0) {
if (folderid < 0) {
return 0;
}
res = psql_query(
"SELECT id FROM folder WHERE parentfolderid=? AND id != ? AND name=?");
psql_bind_uint(res, 1, folderid);
psql_bind_uint(res, 2, from_fid);
psql_bind_lstr(res, 3, name, len);
if ((row = psql_fetch_int(res))) {
cfolderid = row[0];
}
psql_free(res);
if (cfolderid == 0) {
pdbg_logf(D_NOTICE, "Skip creation of a delete task.");
return 0;
}
}
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, sfolderid, text1) VALUES "
"(" NTO_STR(PSYNC_FS_TASK_RMDIR) ", 0, ?, ?, ?)");
psql_bind_int(res, 1, folderid);
psql_bind_int(res, 2, cfolderid);
psql_bind_lstr(res, 3, name, len);
psql_run_free(res);
taskid = psql_insertid();
if (depend)
pfs_task_depend(taskid, depend);
if (cfolderid < 0)
pfs_task_depend(taskid, -cfolderid);
return taskid;
}
int pfs_task_rename_folder(psync_fsfolderid_t folderid,
psync_fsfolderid_t parentfolderid,
const char *name, psync_fsfolderid_t to_folderid,
const char *new_name, uint32_t targetflags) {
psync_sql_res *res;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_fstask_rmdir_t *rm;
size_t nlen, nnlen;
uint64_t ftaskid, ttaskid, rmtask;
nlen = strlen(name);
if (new_name)
nnlen = strlen(new_name);
else {
new_name = name;
nnlen = nlen;
}
psql_start();
rmtask = pfs_task_delete_folder_if_ex(to_folderid, new_name, folderid);
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, sfolderid, text1) VALUES "
"(" NTO_STR(PSYNC_FS_TASK_RENFOLDER_FROM) ", 10, ?, ?, ?)");
psql_bind_int(res, 1, parentfolderid);
psql_bind_int(res, 2, folderid);
psql_bind_lstr(res, 3, name, nlen);
psql_run_free(res);
ftaskid = psql_insertid();
res = psql_prepare(
"INSERT INTO fstask (type, status, folderid, sfolderid, text1, int1, "
"int2) VALUES (" NTO_STR(
PSYNC_FS_TASK_RENFOLDER_TO) ", 0, ?, ?, ?, ?, ?)");
psql_bind_int(res, 1, to_folderid);
psql_bind_int(res, 2, folderid);
psql_bind_lstr(res, 3, new_name, nnlen);
psql_bind_uint(res, 4, ftaskid);
psql_bind_uint(res, 5, targetflags);
psql_run_free(res);
ttaskid = psql_insertid();
if (folderid < 0) {
res = psql_prepare("UPDATE fstask SET sfolderid=? WHERE id=?");
psql_bind_int(res, 1, to_folderid);
psql_bind_int(res, 2, -folderid);
psql_run_free(res);
pfs_task_depend(ttaskid, -folderid);
}
if (rmtask)
pfs_task_depend(ttaskid, rmtask);
if (parentfolderid < 0)
pfs_task_depend(ttaskid, -parentfolderid);
if (to_folderid < 0 && to_folderid != parentfolderid)
pfs_task_depend(ttaskid, -to_folderid);
pfs_task_depend_on_name2(ttaskid, ftaskid, parentfolderid, name, nlen);
pfs_task_depend_on_name(ttaskid, folderid, new_name, nnlen);
folder = pfs_task_get_or_create_folder_tasks_locked(parentfolderid);
mk = pfs_task_find_mkdir(folder, name, 0);
if (mk)
pfs_task_depend(ttaskid, mk->taskid);
if (pdbg_unlikely(psql_commit())) {
pfs_task_release_folder_tasks_locked(folder);
return -EIO;
}
if (mk) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
}
nlen++;
rm = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + nlen);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
rm->taskid = ftaskid;
rm->folderid = folderid;
memcpy(rm->name, name, nlen);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &rm->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
folder = pfs_task_get_or_create_folder_tasks_locked(to_folderid);
mk = pfs_task_find_mkdir(folder, name, 0);
if (mk) {
pdbg_logf(D_NOTICE, "renaming over mkdir %s", name);
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
}
nnlen++;
rm = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + nnlen);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
rm->taskid = ttaskid;
rm->folderid = folderid;
memcpy(rm->name, new_name, nnlen);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &rm->tree);
mk = (psync_fstask_mkdir_t *)malloc(
offsetof(psync_fstask_mkdir_t, name) + nnlen);
if (!mk) {
pfs_task_release_folder_tasks_locked(folder);
return -ENOMEM;
}
mk->taskid = ttaskid;
mk->folderid = folderid;
mk->flags = targetflags;
memcpy(mk->name, new_name, nnlen);
fill_mkdir_data(folderid, mk);
pfs_task_insert_into_tree(
&folder->mkdirs, offsetof(psync_fstask_mkdir_t, name), &mk->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
pfs_upld_wake();
if (to_folderid >= 0) {
ppathstatus_drive_fldr_changed(to_folderid);
}
return 0;
}
static int folder_cmp(const psync_tree *t1, const psync_tree *t2) {
int64_t d = ptree_element(t1, psync_fstask_folder_t, tree)->folderid -
ptree_element(t2, psync_fstask_folder_t, tree)->folderid;
if (d < 0)
return -1;
else if (d > 0)
return 1;
else
return 0;
}
void pfs_task_folder_created(psync_folderid_t parentfolderid,
uint64_t taskid, psync_folderid_t folderid,
const char *name) {
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
int pchg;
pchg = 0;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
mk = pfs_task_find_mkdir(folder, name, taskid);
if (mk) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
pchg = 1;
}
pfs_task_release_folder_tasks_locked(folder);
}
if (!folder || !mk) {
psync_sql_res *res;
psync_uint_row row;
psync_fsfolderid_t sfolderid;
pdbg_logf(
D_NOTICE,
"could not find mkdir (taskid %lu) for created folder %s in folder %lu",
(unsigned long)taskid, name, (unsigned long)parentfolderid);
res = psql_query("SELECT sfolderid FROM fstask WHERE id=?");
psql_bind_uint(res, 1, taskid);
row = psql_fetch_int(res);
if (pdbg_unlikely(!row))
psql_free(res);
else {
sfolderid = row[0];
psql_free(res);
folder = pfs_task_get_folder_tasks_locked(sfolderid);
if (folder) {
mk = pfs_task_find_mkdir_by_folderid(folder,
-(psync_fsfolderid_t)taskid);
if (mk) {
pdbg_logf(D_NOTICE, "found taskid %lu in folderid %ld as %s",
(unsigned long)taskid, (long)sfolderid, mk->name);
mk->folderid = folderid;
}
pfs_task_release_folder_tasks_locked(folder);
}
}
}
folder = pfs_task_get_folder_tasks_locked(-(psync_fsfolderid_t)taskid);
if (folder) {
pdbg_logf(D_NOTICE, "re-inserting into tree folder diffs of folder %ld as %lu",
(long)folder->folderid, (unsigned long)folderid);
ptree_del(&folders, &folder->tree);
folder->folderid = folderid;
ptree_add(&folders, &folder->tree, folder_cmp);
pfs_task_release_folder_tasks_locked(folder);
ppathstatus_drive_fldr_changed(folderid);
}
if (pchg)
ppathstatus_drive_fldr_changed(parentfolderid);
}
void pfs_task_folder_deleted(psync_folderid_t parentfolderid,
uint64_t taskid, const char *name) {
psync_fstask_folder_t *folder;
psync_fstask_rmdir_t *rm;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
rm = pfs_task_find_rmdir(folder, name, taskid);
if (rm) {
ptree_del(&folder->rmdirs, &rm->tree);
free(rm);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
}
}
static void pfs_task_look_for_creat_in_db(psync_folderid_t parentfolderid,
uint64_t taskid, const char *name,
psync_fileid_t fileid) {
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_sql_res *res;
psync_uint_row row;
psync_fsfolderid_t sfolderid;
pdbg_logf(D_NOTICE,
"could not find creat (taskid %lu) for uploaded file %s in folder %lu",
(unsigned long)taskid, name, (unsigned long)parentfolderid);
res = psql_query("SELECT sfolderid FROM fstask WHERE id=?");
psql_bind_uint(res, 1, taskid);
row = psql_fetch_int(res);
if (pdbg_unlikely(!row)) {
psql_free(res);
return;
}
sfolderid = row[0];
psql_free(res);
folder = pfs_task_get_folder_tasks_locked(sfolderid);
if (folder) {
cr = pfs_task_find_creat_by_fileid(folder, -(psync_fsfileid_t)taskid);
if (cr) {
pdbg_logf(D_NOTICE, "found taskid %lu in folderid %ld as %s",
(unsigned long)taskid, (long)sfolderid, cr->name);
cr->fileid = fileid;
} else
pdbg_logf(D_NOTICE,
"could not find creat (taskid %lu) for uploaded file %s in folder "
"%lu even after looking in db",
(unsigned long)taskid, name, (unsigned long)parentfolderid);
pfs_task_release_folder_tasks_locked(folder);
}
}
void pfs_task_file_created(psync_folderid_t parentfolderid, uint64_t taskid,
const char *name, psync_fileid_t fileid) {
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *un;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
cr = pfs_task_find_creat(folder, name, taskid);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
un = pfs_task_find_unlink(folder, name, taskid);
if (un) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
folder->taskscnt--;
} else
pdbg_logf(D_NOTICE, "could not find unlink for file %s in folderid %lu", name,
(unsigned long)parentfolderid);
pfs_task_release_folder_tasks_locked(folder);
if (cr)
ppathstatus_drive_fldr_changed(parentfolderid);
} else
pdbg_logf(D_NOTICE, "could not find unlink for file %s in folderid %lu", name,
(unsigned long)parentfolderid);
if (!folder || !cr)
pfs_task_look_for_creat_in_db(parentfolderid, taskid, name, fileid);
}
void pfs_task_file_modified(psync_folderid_t parentfolderid,
uint64_t taskid, const char *name,
psync_fileid_t fileid) {
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *un;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
cr = pfs_task_find_creat(folder, name, taskid);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
un = pfs_task_find_unlink(folder, name, taskid);
if (un) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
if (cr)
ppathstatus_drive_fldr_changed(parentfolderid);
}
if (!folder || !cr)
pfs_task_look_for_creat_in_db(parentfolderid, taskid, name, fileid);
}
void pfs_task_file_deleted(psync_folderid_t parentfolderid, uint64_t taskid,
const char *name) {
psync_fstask_folder_t *folder;
psync_fstask_unlink_t *un;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
un = pfs_task_find_unlink(folder, name, taskid);
if (un) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
}
}
void pfs_task_file_renamed(psync_folderid_t folderid, uint64_t taskid,
const char *name, uint64_t frtaskid) {
psync_sql_res *res;
psync_fstask_folder_t *folder;
psync_fstask_unlink_t *un;
psync_fstask_creat_t *cr;
psync_variant_row row;
folder = pfs_task_get_folder_tasks_locked(folderid);
if (folder) {
un = pfs_task_find_unlink(folder, name, taskid);
if (un) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
folder->taskscnt--;
}
cr = pfs_task_find_creat(folder, name, taskid);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
if (cr)
ppathstatus_drive_fldr_changed(folderid);
}
res = psql_query("SELECT id, folderid, text1 FROM fstask WHERE id=?");
psql_bind_uint(res, 1, frtaskid);
if (pdbg_likely(row = psql_fetch(res))) {
folder = pfs_task_get_folder_tasks_locked(psync_get_snumber(row[1]));
if (folder) {
un = pfs_task_find_unlink(folder, psync_get_string(row[2]),
psync_get_number(row[0]));
if (un) {
ptree_del(&folder->unlinks, &un->tree);
free(un);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
}
}
psql_free(res);
res = psql_prepare(
"DELETE FROM fstaskdepend WHERE dependfstaskid=?");
psql_bind_uint(res, 1, frtaskid);
psql_run_free(res);
if (psql_affected())
pfs_upld_wake();
res = psql_prepare("DELETE FROM fstask WHERE id=?");
psql_bind_uint(res, 1, frtaskid);
psql_run_free(res);
}
void pfs_task_folder_renamed(psync_folderid_t parentfolderid,
uint64_t taskid, const char *name,
uint64_t frtaskid) {
psync_sql_res *res;
psync_fstask_folder_t *folder;
psync_fstask_rmdir_t *rm;
psync_fstask_mkdir_t *mk;
psync_variant_row row;
folder = pfs_task_get_folder_tasks_locked(parentfolderid);
if (folder) {
mk = pfs_task_find_mkdir(folder, name, taskid);
if (mk) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
}
rm = pfs_task_find_rmdir(folder, name, taskid);
if (rm) {
ptree_del(&folder->rmdirs, &rm->tree);
free(rm);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
if (mk)
ppathstatus_drive_fldr_changed(parentfolderid);
}
res = psql_query("SELECT id, folderid, text1 FROM fstask WHERE id=?");
psql_bind_uint(res, 1, frtaskid);
if (pdbg_likely(row = psql_fetch(res))) {
folder = pfs_task_get_folder_tasks_locked(psync_get_snumber(row[1]));
if (folder) {
rm = pfs_task_find_rmdir(folder, psync_get_string(row[2]),
psync_get_number(row[0]));
if (rm) {
ptree_del(&folder->rmdirs, &rm->tree);
free(rm);
folder->taskscnt--;
}
pfs_task_release_folder_tasks_locked(folder);
}
}
psql_free(res);
res = psql_prepare(
"DELETE FROM fstaskdepend WHERE dependfstaskid=?");
psql_bind_uint(res, 1, frtaskid);
psql_run_free(res);
if (psql_affected())
pfs_upld_wake();
res = psql_prepare("DELETE FROM fstask WHERE id=?");
psql_bind_uint(res, 1, frtaskid);
psql_run_free(res);
}
static void psync_init_task_mkdir(psync_variant_row row) {
uint64_t taskid;
psync_fsfolderid_t folderid;
const char *name;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *task;
time_t ctime;
size_t len;
taskid = psync_get_number(row[0]);
folderid = psync_get_snumber(row[2]);
name = psync_get_lstring(row[4], &len);
ctime = psync_get_number(row[6]);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
len++;
task = (psync_fstask_mkdir_t *)malloc(
offsetof(psync_fstask_mkdir_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
task->taskid = taskid;
task->ctime = task->mtime = ctime;
task->folderid = -(psync_fsfolderid_t)taskid;
task->subdircnt = 0;
task->flags = psync_is_null(row[5]) ? 0 : PSYNC_FOLDER_FLAG_ENCRYPTED;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->mkdirs, offsetof(psync_fstask_mkdir_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
if (folderid >= 0)
ppathstatus_drive_fldr_changed(folderid);
}
static void psync_init_task_rmdir(psync_variant_row row) {
uint64_t taskid;
psync_fsfolderid_t cfolderid, folderid;
const char *name;
psync_fstask_folder_t *folder;
psync_fstask_rmdir_t *task;
psync_fstask_mkdir_t *mk;
size_t len;
taskid = psync_get_number(row[0]);
folderid = psync_get_snumber(row[2]);
name = psync_get_lstring(row[4], &len);
cfolderid = psync_get_snumber(row[8]);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
mk = pfs_task_find_mkdir(folder, name, 0);
if (mk) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
}
len++;
task = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
task->taskid = taskid;
task->folderid = cfolderid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
}
static void psync_init_task_creat(psync_variant_row row) {
uint64_t taskid;
psync_fstask_unlink_t *un;
psync_fstask_creat_t *task;
psync_fstask_folder_t *folder;
const char *name;
psync_fsfolderid_t folderid;
size_t len;
taskid = psync_get_number(row[0]);
folderid = psync_get_snumber(row[2]);
name = psync_get_lstring(row[4], &len);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
len++;
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
un->fileid = -(psync_fsfileid_t)taskid;
un->taskid = taskid;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &un->tree);
task = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + len);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
task->fileid = -(psync_fsfileid_t)taskid;
task->rfileid = psync_get_number(row[3]);
task->taskid = taskid;
memcpy(task->name, name, len);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &task->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
if (folderid >= 0)
ppathstatus_drive_fldr_changed(folderid);
}
static void psync_init_do_task_unlink(uint64_t taskid,
psync_fsfolderid_t folderid,
const char *name, size_t namelen,
psync_fsfileid_t fileid) {
psync_fstask_folder_t *folder;
psync_fstask_unlink_t *task;
psync_fstask_creat_t *cr;
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
cr = pfs_task_find_creat(folder, name, 0);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
namelen++;
task = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + namelen);
if (!task) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
task->taskid = taskid;
task->fileid = fileid;
memcpy(task->name, name, namelen);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &task->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
}
static void psync_init_task_unlink(psync_variant_row row) {
const char *name;
size_t len;
name = psync_get_lstring(row[4], &len);
psync_init_do_task_unlink(psync_get_number(row[0]), psync_get_snumber(row[2]),
name, len, psync_get_snumber(row[3]));
}
static void psync_init_task_unlink_set_rev(psync_variant_row row) {
const char *name;
size_t len;
name = psync_get_lstring(row[4], &len);
psync_init_do_task_unlink(psync_get_number(row[0]), psync_get_snumber(row[2]),
name, len, psync_get_snumber(row[6]));
}
static void psync_init_task_renfile_from(psync_variant_row row) {
const char *name;
psync_fstask_folder_t *folder;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *rm;
size_t len;
name = psync_get_lstring(row[4], &len);
folder =
pfs_task_get_or_create_folder_tasks_locked(psync_get_number(row[2]));
if ((cr = pfs_task_find_creat(folder, name, 0))) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
len++;
rm = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
rm->taskid = psync_get_number(row[0]);
rm->fileid = psync_get_snumber(row[3]);
memcpy(rm->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &rm->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
}
static void psync_init_task_renfile_to(psync_variant_row row) {
const char *name;
psync_fstask_creat_t *cr;
psync_fstask_unlink_t *un;
psync_fstask_folder_t *folder;
psync_fsfolderid_t folderid;
uint64_t taskid;
psync_fsfileid_t fileid;
size_t len;
name = psync_get_lstring(row[4], &len);
folderid = psync_get_snumber(row[2]);
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
cr = pfs_task_find_creat(folder, name, 0);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
folder->taskscnt--;
free(cr);
}
len++;
taskid = psync_get_number(row[0]);
fileid = psync_get_snumber(row[3]);
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
un->fileid = fileid;
un->taskid = taskid;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_creat_t, name), &un->tree);
cr = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + len);
if (!cr) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
cr->fileid = fileid;
cr->rfileid = psync_get_number(row[7]);
cr->taskid = taskid;
memcpy(cr->name, name, len);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &cr->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
pfs_rename_openfile_locked(cr->fileid, folderid, name);
if (folderid >= 0)
ppathstatus_drive_fldr_changed(folderid);
}
static void psync_init_task_renfolder_from(psync_variant_row row) {
const char *name;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_fstask_rmdir_t *rm;
size_t len;
name = psync_get_lstring(row[4], &len);
folder =
pfs_task_get_or_create_folder_tasks_locked(psync_get_number(row[2]));
if ((mk = pfs_task_find_mkdir(folder, name, 0))) {
ptree_del(&folder->mkdirs, &mk->tree);
free(mk);
folder->taskscnt--;
}
len++;
rm = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + len);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
rm->taskid = psync_get_number(row[0]);
rm->folderid = psync_get_snumber(row[8]);
memcpy(rm->name, name, len);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &rm->tree);
folder->taskscnt++;
pfs_task_release_folder_tasks_locked(folder);
}
static void psync_init_task_renfolder_to(psync_variant_row row) {
const char *name;
psync_fstask_mkdir_t *mk;
psync_fstask_rmdir_t *rm;
psync_fstask_folder_t *folder;
psync_fsfolderid_t folderid;
uint64_t taskid;
size_t len;
name = psync_get_lstring(row[4], &len);
folder =
pfs_task_get_or_create_folder_tasks_locked(psync_get_number(row[2]));
len++;
taskid = psync_get_number(row[0]);
folderid = psync_get_snumber(row[8]);
rm = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + len);
if (!rm) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
rm->taskid = taskid;
rm->folderid = folderid;
memcpy(rm->name, name, len);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &rm->tree);
mk = (psync_fstask_mkdir_t *)malloc(
offsetof(psync_fstask_mkdir_t, name) + len);
if (!mk) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
mk->taskid = taskid;
mk->folderid = folderid;
mk->flags = psync_get_number(row[7]);
memcpy(mk->name, name, len);
fill_mkdir_data(mk->folderid, mk);
pfs_task_insert_into_tree(
&folder->mkdirs, offsetof(psync_fstask_mkdir_t, name), &mk->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
if (folderid >= 0)
ppathstatus_drive_fldr_changed(folderid);
}
static void psync_init_task_modify(psync_variant_row row) {
psync_fstask_unlink_t *un;
psync_fstask_creat_t *cr;
psync_fstask_folder_t *folder;
uint64_t taskid;
const char *name;
size_t len;
name = psync_get_lstring(row[4], &len);
folder =
pfs_task_get_or_create_folder_tasks_locked(psync_get_number(row[2]));
taskid = psync_get_number(row[0]);
cr = pfs_task_find_creat(folder, name, 0);
if (cr) {
ptree_del(&folder->creats, &cr->tree);
free(cr);
folder->taskscnt--;
}
len++;
un = (psync_fstask_unlink_t *)malloc(
offsetof(psync_fstask_unlink_t, name) + len);
if (!un) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
un->fileid = psync_get_snumber(row[3]);
un->taskid = taskid;
memcpy(un->name, name, len);
pfs_task_insert_into_tree(
&folder->unlinks, offsetof(psync_fstask_unlink_t, name), &un->tree);
cr = (psync_fstask_creat_t *)malloc(
offsetof(psync_fstask_creat_t, name) + len);
if (!cr) {
pfs_task_release_folder_tasks_locked(folder);
return;
}
cr->fileid = -(psync_fsfileid_t)cr->taskid;
cr->rfileid = psync_get_number(row[3]);
cr->taskid = taskid;
memcpy(cr->name, name, len);
pfs_task_insert_into_tree(
&folder->creats, offsetof(psync_fstask_creat_t, name), &cr->tree);
folder->taskscnt += 2;
if (folder->folderid >= 0)
ppathstatus_drive_fldr_changed(folder->folderid);
pfs_task_release_folder_tasks_locked(folder);
}
typedef void (*psync_init_task_ptr)(psync_variant_row);
static psync_init_task_ptr psync_init_task_func[] = {
NULL,
psync_init_task_mkdir,
psync_init_task_rmdir,
psync_init_task_creat,
psync_init_task_unlink,
psync_init_task_renfile_from,
psync_init_task_renfile_to,
psync_init_task_renfolder_from,
psync_init_task_renfolder_to,
psync_init_task_modify,
psync_init_task_unlink_set_rev};
static void pfs_task_free_tree(psync_tree *tr) {
psync_tree *ntr;
tr = ptree_get_first_safe(tr);
while (tr) {
ntr = ptree_get_next_safe(tr);
free(tr);
tr = ntr;
}
}
void pfs_task_clean() {
psync_fstask_folder_t *folder;
psync_tree *tr;
psql_lock();
tr = ptree_get_first(folders);
while (tr) {
folder = ptree_element(tr, psync_fstask_folder_t, tree);
tr = ptree_get_next(tr);
pfs_task_free_tree(folder->creats);
pfs_task_free_tree(folder->unlinks);
pfs_task_free_tree(folder->mkdirs);
pfs_task_free_tree(folder->rmdirs);
if (folder->refcnt == 0) {
ptree_del(&folders, &folder->tree);
free(folder);
} else {
folder->creats = PSYNC_TREE_EMPTY;
folder->unlinks = PSYNC_TREE_EMPTY;
folder->mkdirs = PSYNC_TREE_EMPTY;
folder->rmdirs = PSYNC_TREE_EMPTY;
folder->taskscnt = 0;
}
}
psql_unlock();
}
void pfs_task_add_banned_folder(psync_fsfolderid_t folderid,
const char *name) {
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_fstask_rmdir_t *rm;
size_t len;
len = strlen(name) + 1;
mk = (psync_fstask_mkdir_t *)malloc(
offsetof(psync_fstask_mkdir_t, name) + len);
if (!mk)
return;
mk->taskid = 0;
mk->ctime = mk->mtime = 0;
mk->folderid = 0;
mk->subdircnt = 0;
mk->flags = PSYNC_FOLDER_FLAG_INVISIBLE;
memcpy(mk->name, name, len);
rm = (psync_fstask_rmdir_t *)malloc(
offsetof(psync_fstask_rmdir_t, name) + len);
if (!rm) {
free(mk);
return;
}
rm->taskid = 0;
rm->folderid = 0;
memcpy(rm->name, name, len);
psql_lock();
folder = pfs_task_get_or_create_folder_tasks_locked(folderid);
pfs_task_insert_into_tree(
&folder->mkdirs, offsetof(psync_fstask_mkdir_t, name), &mk->tree);
pfs_task_insert_into_tree(
&folder->rmdirs, offsetof(psync_fstask_rmdir_t, name), &rm->tree);
folder->taskscnt += 2;
pfs_task_release_folder_tasks_locked(folder);
psql_unlock();
}
void pfs_task_add_banned_folders() {
// noop
}
void pfs_task_init() {
unsigned long tp;
psync_sql_res *res;
psync_variant_row row;
res = psql_prepare(
"UPDATE fstask SET status=0 WHERE status IN (1, 2)");
psql_run_free(res);
res = psql_prepare("UPDATE fstask SET status=11 WHERE status=12");
psql_run_free(res);
res = psql_query(
"SELECT id, type, folderid, fileid, text1, text2, int1, int2, sfolderid "
"FROM fstask WHERE status NOT IN (3) ORDER BY id");
while ((row = psql_fetch(res))) {
tp = psync_get_number(row[1]);
if (!tp || tp >= ARRAY_SIZE(psync_init_task_func)) {
pdbg_logf(D_BUG, "invalid fstask type %lu", (long unsigned)tp);
continue;
}
psync_init_task_func[tp](row);
}
psql_free(res);
pfs_upld_init();
}