winix/functions/mv.cpp

410 lines
7.3 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <errno.h>
#include "mv.h"
#include "functions.h"
namespace Fun
{
Mv::Mv()
{
fun.url = L"mv";
follow_symlinks = false;
}
bool Mv::HasAccess()
{
return CheckAccessFrom();
}
bool Mv::CheckAccessFromToDir()
{
Item * last;
Item * last_but_one = 0;
size_t dir_tab_size;
last = cur->request->dir_tab.back();
dir_tab_size = cur->request->dir_tab.size();
if( dir_tab_size <= 1 )
return false; // you cannot move the root directory
last_but_one = cur->request->dir_tab[dir_tab_size - 2];
if( cur->request->method != Request::post )
{
// used in GET or HEAD
// we don't now whether we move the last directory or the last but one
// it depends on the 'onlycontent' parameter
if( !system->HasWriteAccess(*last) && !system->HasWriteAccess(*last_but_one) )
return false;
}
else
{
// used in POST when the moving is performed
if( cur->request->IsPostVar(L"onlycontent") )
return system->HasWriteAccess(*last);
else
return system->HasWriteAccess(*last_but_one);
}
return true;
}
bool Mv::CheckAccessFrom()
{
if( cur->request->is_item )
{
// moving a file
if( !system->HasWriteAccess(*cur->request->dir_tab.back()) )
{
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
return false;
}
}
else
{
if( !CheckAccessFromToDir() )
{
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
return false;
}
}
return true;
}
bool Mv::CheckAccessTo()
{
if( dir_tab.empty() ||
!system->HasReadExecAccessToPath(dir_tab) ||
!system->HasWriteAccess(*dir_tab.back()) )
{
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
return false;
}
return true;
}
bool Mv::ParseDir()
{
const std::wstring & new_dir = cur->request->PostVar(L"to");
int res = system->dirs.FollowLink(cur->request->dir_tab, new_dir, dir_tab, file);
if( res == 3 )
cur->request->status = WINIX_ERR_NO_ROOT_DIR;
else
if( res != 0 && res != 1 )
cur->request->status = WINIX_ERR_INCORRECT_DIR;
return res == 0 || res == 1;
}
bool Mv::MoveStaticFile(const std::wstring & from, const std::wstring & to)
{
if( from == to )
{
log << log3 << "Mv: the same path to a static file: " << to << " (skipped)" << logend;
return true;
}
if( RenameFile(from, to) )
{
log << log2 << "Mv: moved static file from: " << from << ", to: " << to << logend;
return true;
}
else
{
log << log1 << "Mv: can't move a file from: " << from << ", to: " << to << logend;
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
return false;
}
}
void Mv::MoveStaticFile(Item & item)
{
bool res1, res2, res3, res4, res5;
res1 = system->MakeFilePath(item, old_path, false);
res2 = !item.has_thumb || system->MakeFilePath(item, old_path_thumb, true);
res3 = system->CreateNewFile(item);
res4 = system->MakeFilePath(item, new_path, false, true, config->upload_dirs_chmod);
res5 = !item.has_thumb || system->MakeFilePath(item, new_path_thumb, true, true, config->upload_dirs_chmod);
if( !res1 || !res2 || !res3 || !res4 || !res5 )
{
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
return;
}
if( MoveStaticFile(old_path, new_path) )
{
cur->request->status = db->EditFileById(item, item.id);
if( item.has_thumb )
MoveStaticFile(old_path_thumb, new_path_thumb);
}
}
void Mv::MoveFileOrSymlink(Item & item)
{
old_url = item.url;
if( !file.empty() )
{
item.url = file;
functions->PrepareUrl(item);
file.clear();
}
item.parent_id = dir_tab.back()->id;
cur->request->status = db->EditParentUrlById(item, item.id);
if( cur->request->status == WINIX_ERR_OK )
{
if( item.type == Item::file )
log << log3 << "Mv: file: ";
else
log << log3 << "Mv: symlink: ";
log << old_url << " was moved to: ";
system->dirs.LogDir(dir_tab);
log << item.url << logend;
if( item.file_type != WINIX_ITEM_FILETYPE_NONE )
MoveStaticFile(item);
}
}
void Mv::MoveDirContent(const Item & dir)
{
content_dir_iq.WhereParentId(dir.id);
db->GetItems(item_tab, content_dir_iq);
for(size_t i=0 ; i<item_tab.size() ; ++i)
{
if( item_tab[i].type == Item::dir )
MoveDir(item_tab[i]);
else
MoveFileOrSymlink(item_tab[i]);
}
}
void Mv::Prepare()
{
content_dir_iq.SetAll(false, false);
content_dir_iq.sel_parent_id = true;
content_dir_iq.sel_type = true;
content_dir_iq.sel_url = true;
content_dir_iq.sel_file = true;
static_iq.SetAll(false, false);
static_iq.sel_parent_id = true;
static_iq.sel_type = true;
static_iq.sel_url = true;
static_iq.sel_file = true;
static_iq.WhereType(Item::file);
static_iq.WhereFileType(WINIX_ITEM_FILETYPE_NONE, false);
}
void Mv::Clear()
{
dir_tab.clear();
static_item_tab.clear();
item_tab.clear();
}
void Mv::MoveStaticFilesTree(const Item & dir)
{
DirContainer::ParentIterator i = system->dirs.FindFirstChild(dir.id);
// go through all directories
for( ; i != system->dirs.ParentEnd() ; i = system->dirs.NextChild(i) )
MoveStaticFilesTree(*(i->second));
static_iq.WhereParentId(dir.id);
db->GetItems(static_item_tab, static_iq);
for(size_t i=0 ; i<static_item_tab.size() ; ++i)
MoveStaticFile(static_item_tab[i]);
}
void Mv::MoveDir(Item & dir)
{
long dst_dir_id = dir_tab.back()->id;
old_url = dir.url;
if( dst_dir_id == dir.id || system->dirs.HasParent(dst_dir_id, dir.id) )
{
log << log1 << "Mv: cannot move directory to inside it" << logend;
cur->request->status = WINIX_ERR_INCORRECT_DIR;
return;
}
if( !system->dirs.ChangeParent(dir.id, dst_dir_id) )
{
cur->request->status = WINIX_ERR_INCORRECT_DIR;
return;
}
dir.parent_id = dst_dir_id;
if( !file.empty() )
{
dir.url = file;
functions->PrepareUrl(dir);
file.clear();
}
cur->request->status = db->EditParentUrlById(dir, dir.id);
if( cur->request->status == WINIX_ERR_OK )
{
log << log3 << "Mv: directory: " << old_url << " was moved to: ";
system->dirs.LogDir(dir_tab);
log << dir.url << logend;
MoveStaticFilesTree(dir);
}
}
bool Mv::IsTheSameFile(const Item & item)
{
if( file.empty() )
{
if( item.parent_id == dir_tab.back()->id )
return true; // nothing to do
}
else
{
if( item.parent_id == dir_tab.back()->id && item.url == file )
return true; // nothing to do
}
return false;
}
void Mv::PostMoveFile()
{
if( IsTheSameFile(cur->request->item) )
return;
MoveFileOrSymlink(cur->request->item);
if( cur->request->status == WINIX_ERR_OK )
system->RedirectTo(cur->request->item);
}
void Mv::PostMoveDirContent()
{
if( !file.empty() )
{
cur->request->status = WINIX_ERR_INCORRECT_DIR;
return;
}
if( cur->request->dir_tab.back()->id == dir_tab.back()->id )
return; // nothing to do
MoveDirContent(*cur->request->dir_tab.back());
system->RedirectToLastDir();
}
void Mv::PostMoveDir()
{
Item & last_dir = *cur->request->dir_tab.back();
Item & new_dir = *dir_tab.back();
if( file.empty() && new_dir.id == last_dir.id )
return; // nothing to do
MoveDir(last_dir);
if( cur->request->status == WINIX_ERR_OK )
system->RedirectToLastDir();
}
void Mv::MakePost()
{
if( CheckAccessFrom() &&
ParseDir() &&
CheckAccessTo() )
{
Prepare();
if( cur->request->is_item )
{
PostMoveFile();
}
else
{
if( cur->request->IsPostVar(L"onlycontent") )
PostMoveDirContent();
else
PostMoveDir();
}
Clear();
}
}
} // namespace