pcloudcc-lneely/pCloudCC/lib/pclsync/pfsfolder.c

462 lines
12 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 "pfsfolder.h"
#include "plibs.h"
#include "psettings.h"
#include "pfstasks.h"
#include "pfolder.h"
#include "pcloudcrypto.h"
#include "pfs.h"
#include <string.h>
static PSYNC_THREAD int cryptoerr=0;
static char *get_encname_for_folder(psync_fsfolderid_t folderid, const char *path, size_t len){
char *name, *encname;
psync_crypto_aes256_text_encoder_t enc;
enc=psync_cloud_crypto_get_folder_encoder(folderid);
if (psync_crypto_is_error(enc)){
cryptoerr=psync_crypto_to_error(enc);
return NULL;
}
name=psync_strndup(path, len);
encname=psync_cloud_crypto_encode_filename(enc, name);
psync_cloud_crypto_release_folder_encoder(folderid, enc);
psync_free(name);
return encname;
}
static psync_fspath_t *ret_folder_data(psync_fsfolderid_t folderid, const char *name, uint32_t permissions, uint32_t flags, uint32_t shareid){
psync_fspath_t *ret;
if (flags&PSYNC_FOLDER_FLAG_ENCRYPTED && strncmp(psync_fake_prefix, name, psync_fake_prefix_len)){
psync_crypto_aes256_text_encoder_t enc;
char *encname;
size_t len;
enc=psync_cloud_crypto_get_folder_encoder(folderid);
if (psync_crypto_is_error(enc)){
cryptoerr=psync_crypto_to_error(enc);
return NULL;
}
encname=psync_cloud_crypto_encode_filename(enc, name);
psync_cloud_crypto_release_folder_encoder(folderid, enc);
len=strlen(encname);
ret=(psync_fspath_t *)psync_malloc(sizeof(psync_fspath_t)+len+1);
memcpy(ret+1, encname, len+1);
psync_free(encname);
ret->folderid=folderid;
ret->name=(char *)(ret+1);
ret->shareid=shareid;
ret->permissions=permissions;
ret->flags=flags;
}
else{
ret=psync_new(psync_fspath_t);
ret->folderid=folderid;
ret->name=name;
ret->shareid=shareid;
ret->permissions=permissions;
ret->flags=flags;
}
return ret;
}
char *get_decname_for_folder(psync_fsfolderid_t folderid, const char *path, size_t len){
char *name, *decname;
psync_crypto_aes256_text_decoder_t dec;
dec=psync_cloud_crypto_get_folder_decoder(folderid);
if (psync_crypto_is_error(dec)){
cryptoerr=psync_crypto_to_error(dec);
return NULL;
}
name=psync_strndup(path, len);
decname=psync_cloud_crypto_decode_filename(dec, name);
psync_cloud_crypto_release_folder_decoder(folderid, dec);
psync_free(name);
return decname;
}
PSYNC_NOINLINE void do_check_userid(uint64_t userid, uint64_t folderid, uint32_t *shareid){
psync_sql_res *res;
psync_uint_row row;
res=psync_sql_query_rdlock("SELECT id FROM sharedfolder WHERE userid=? AND folderid=?");
psync_sql_bind_uint(res, 1, userid);
psync_sql_bind_uint(res, 2, folderid);
if ((row=psync_sql_fetch_rowint(res)))
*shareid=row[0];
else
debug(D_WARNING, "came up to a folder %lu owned by userid %lu but can't find it in sharedfolder", (unsigned long)folderid, (unsigned long)userid);
psync_sql_free_result(res);
}
static void check_userid(uint64_t userid, uint64_t folderid, uint32_t *shareid){
if (userid==psync_my_userid || *shareid)
return;
else
do_check_userid(userid, folderid, shareid);
}
psync_fspath_t *psync_fsfolder_resolve_path(const char *path){
psync_fsfolderid_t cfolderid;
const char *sl;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_sql_res *res;
psync_uint_row row;
char *ename;
size_t len, elen;
uint32_t permissions, flags, shareid;
int hasit;
cryptoerr=0;
res=NULL;
if (*path!='/')
return NULL;
cfolderid=0;
shareid=0;
permissions=PSYNC_PERM_ALL;
flags=0;
while (1){
while (*path=='/')
path++;
if (*path==0){
if (res)
psync_sql_free_result(res);
return NULL;
}
sl=strchr(path, '/');
if (sl)
len=sl-path;
else{
if (res)
psync_sql_free_result(res);
return ret_folder_data(cfolderid, path, permissions, flags, shareid);
}
if (!res)
res=psync_sql_query_rdlock("SELECT id, permissions, flags, userid FROM folder WHERE parentfolderid=? AND name=?");
else
psync_sql_reset(res);
psync_sql_bind_int(res, 1, cfolderid);
if (flags&PSYNC_FOLDER_FLAG_ENCRYPTED){
ename=get_encname_for_folder(cfolderid, path, len);
if (!ename)
break;
elen=strlen(ename);
psync_sql_bind_lstring(res, 2, ename, elen);
}
else{
psync_sql_bind_lstring(res, 2, path, len);
ename=(char *)path;
elen=len;
}
row=psync_sql_fetch_rowint(res);
folder=psync_fstask_get_folder_tasks_rdlocked(cfolderid);
if (folder){
char *name=psync_strndup(ename, elen);
if ((mk=psync_fstask_find_mkdir(folder, name, 0))){
if (mk->flags&PSYNC_FOLDER_FLAG_INVISIBLE){
psync_free(name);
break;
}
cfolderid=mk->folderid;
flags=mk->flags;
hasit=1;
}
else if (row && !psync_fstask_find_rmdir(folder, name, 0)){
cfolderid=row[0];
permissions&=row[1];
flags=row[2];
hasit=1;
check_userid(row[3], row[0], &shareid);
}
else
hasit=0;
psync_free(name);
}
else{
if (row){
cfolderid=row[0];
permissions=row[1];
flags=row[2];
check_userid(row[3], row[0], &shareid);
hasit=1;
}
else
hasit=0;
}
if (ename!=path)
psync_free(ename);
if (!hasit)
break;
path+=len;
}
if (res)
psync_sql_free_result(res);
return NULL;
}
psync_fsfolderid_t psync_fsfolderid_by_path(const char *path, uint32_t *pflags){
psync_fsfolderid_t cfolderid;
const char *sl;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_sql_res *res;
psync_uint_row row;
char *ename;
size_t len, elen;
uint32_t flags;
int hasit;
res=NULL;
cryptoerr=0;
if (*path!='/')
return PSYNC_INVALID_FSFOLDERID;
cfolderid=0;
flags=0;
while (1){
while (*path=='/')
path++;
if (*path==0){
if (res)
psync_sql_free_result(res);
if (pflags)
*pflags=flags;
return cfolderid;
}
sl=strchr(path, '/');
if (sl)
len=sl-path;
else
len=strlen(path);
if (!res)
res=psync_sql_query_rdlock("SELECT id, flags, permissions FROM folder WHERE parentfolderid=? AND name=?");
else
psync_sql_reset(res);
psync_sql_bind_int(res, 1, cfolderid);
if (flags&PSYNC_FOLDER_FLAG_ENCRYPTED){
ename=get_encname_for_folder(cfolderid, path, len);
if (!ename)
break;
elen=strlen(ename);
psync_sql_bind_lstring(res, 2, ename, elen);
}
else{
psync_sql_bind_lstring(res, 2, path, len);
ename=(char *)path;
elen=len;
}
row=psync_sql_fetch_rowint(res);
folder=psync_fstask_get_folder_tasks_rdlocked(cfolderid);
if (folder){
char *name=psync_strndup(ename, elen);
if ((mk=psync_fstask_find_mkdir(folder, name, 0))){
cfolderid=mk->folderid;
flags=mk->flags;
hasit=1;
}
else if (row && !psync_fstask_find_rmdir(folder, name, 0)){
cfolderid=row[0];
flags=row[1];
hasit=1;
}
else
hasit=0;
psync_free(name);
}
else{
if (row){
cfolderid=row[0];
flags=row[1];
hasit=1;
}
else
hasit=0;
}
if (ename!=path)
psync_free(ename);
if (!hasit)
break;
path+=len;
}
if (res)
psync_sql_free_result(res);
return PSYNC_INVALID_FSFOLDERID;
}
psync_fsfolderid_t psync_fsfolderidperm_by_path(const char *path, uint32_t *pflags, uint32_t *pPermissions){
psync_fsfolderid_t cfolderid;
const char *sl;
psync_fstask_folder_t *folder;
psync_fstask_mkdir_t *mk;
psync_sql_res *res;
psync_uint_row row;
char *ename;
size_t len, elen;
uint32_t flags;
int hasit;
res=NULL;
cryptoerr=0;
if (*path!='/')
return PSYNC_INVALID_FSFOLDERID;
cfolderid=0;
flags=0;
*pPermissions=0;
while (1){
while (*path=='/')
path++;
if (*path==0){
if (res)
psync_sql_free_result(res);
if (pflags)
*pflags=flags;
return cfolderid;
}
sl=strchr(path, '/');
if (sl)
len=sl-path;
else
len=strlen(path);
if (!res)
res=psync_sql_query_rdlock("SELECT id, flags, permissions FROM folder WHERE parentfolderid=? AND name=?");
else
psync_sql_reset(res);
psync_sql_bind_int(res, 1, cfolderid);
if (flags&PSYNC_FOLDER_FLAG_ENCRYPTED){
ename=get_encname_for_folder(cfolderid, path, len);
if (!ename)
break;
elen=strlen(ename);
psync_sql_bind_lstring(res, 2, ename, elen);
}
else{
psync_sql_bind_lstring(res, 2, path, len);
ename=(char *)path;
elen=len;
}
row=psync_sql_fetch_rowint(res);
folder=psync_fstask_get_folder_tasks_rdlocked(cfolderid);
if (folder){
char *name=psync_strndup(ename, elen);
if ((mk=psync_fstask_find_mkdir(folder, name, 0))){
cfolderid=mk->folderid;
flags=mk->flags;
hasit=1;
}
else if (row && !psync_fstask_find_rmdir(folder, name, 0)){
cfolderid=row[0];
flags=row[1];
*pPermissions=row[2];
hasit=1;
}
else
hasit=0;
psync_free(name);
}
else{
if (row){
cfolderid=row[0];
flags=row[1];
*pPermissions=row[2];
hasit=1;
}
else
hasit=0;
}
if (ename!=path)
psync_free(ename);
if (!hasit)
break;
path+=len;
}
if (res)
psync_sql_free_result(res);
return PSYNC_INVALID_FSFOLDERID;
}
int psync_fsfolder_crypto_error(){
return cryptoerr;
}
uint32_t psync_fsfolderflags_by_id(psync_fsfolderid_t folderid, uint32_t *pperm){
psync_sql_res *res;
psync_uint_row row;
uint32_t ret=0;
if (pperm)
*pperm=0;
retry:
if (psync_sql_trylock()){
psync_milisleep(1);
goto retry;
}
res=psync_sql_query_nolock("SELECT flags, permissions FROM folder WHERE id=?");
psync_sql_bind_int(res, 1, folderid);
row=psync_sql_fetch_rowint(res);
if(!row){
debug(D_NOTICE, "Error reading flags by file id!");
psync_sql_free_result(res);
psync_sql_unlock();
return 0;
}
if (pperm)
*pperm=row[1];
ret=row[0];
psync_sql_free_result(res);
psync_sql_unlock();
return ret;
}
/*********************************************************************************************************************/
psync_fsfolderid_t psync_get_folderid(psync_fsfolderid_t parent_fid, const char* name) {
psync_fsfolderid_t folder_id = -1;
psync_sql_res* res;
psync_uint_row row;
res = psync_sql_query_nolock("SELECT id FROM folder WHERE parentfolderid=? AND name=?");
psync_sql_bind_uint(res, 1, parent_fid);
psync_sql_bind_string(res, 2, name);
row = psync_sql_fetch_rowint(res);
if (row) {
folder_id = row[0];
psync_sql_free_result(res);
}
return folder_id;
}
/*********************************************************************************************************************/