/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. 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. * * 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 "cp.h" #include "core/misc.h" #include "functions.h" namespace Winix { namespace Fun { Cp::Cp() { fun.url = L"cp"; } bool Cp::HasAccess() { return CheckAccessFrom(); } bool Cp::CheckAccessFrom() { if( cur->request->is_item ) { if( !system->HasReadAccess(cur->request->item) || cur->request->item.type == Item::symlink ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; return false; } } else if( !cur->request->IsParam(L"r") ) { // directories need 'r' parameter cur->request->status = WINIX_ERR_PERMISSION_DENIED; } return true; } bool Cp::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 Cp::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 Cp::CopyStaticFile(const std::wstring & from, const std::wstring & to) { if( from == to ) { log << log3 << "Cp: the same path to a static file: " << to << logend; return true; } if( Winix::CopyFile(from, to) ) { log << log2 << "Cp: copied a static file from: " << from << ", to: " << to << logend; return true; } else { log << log1 << "Cp: can't copy a file from: " << from << ", to: " << to << logend; cur->request->status = WINIX_ERR_PERMISSION_DENIED; return false; } } void Cp::CopyStaticFile(Item & item) { bool ok = true; ok = ok && system->MakeFilePath(item, old_path, false); ok = ok && (!item.item_content.file_has_thumb || system->MakeFilePath(item, old_path_thumb, true)); ok = ok && system->CreateNewFile(item); ok = ok && system->MakeFilePath(item, new_path, false, true, config->upload_dirs_chmod); ok = ok && (!item.item_content.file_has_thumb || system->MakeFilePath(item, new_path_thumb, true, true, config->upload_dirs_chmod)); if( !ok ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; return; } if( CopyStaticFile(old_path, new_path) ) { //cur->request->status = db->EditFileById(item, item.id); item.propagate_connector(); if( !item.item_content.update() ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; } if( item.item_content.file_has_thumb ) CopyStaticFile(old_path_thumb, new_path_thumb); } } void Cp::SetNewAttributes(Item & item) { item.item_content.user_id = new_user; item.item_content.group_id = new_group; item.item_content.SetDateModifyToNow(); } void Cp::CopyFile(Item & item, long dst_dir_id) { if( !preserve_attr ) SetNewAttributes(item); item.parent_id = dst_dir_id; // cur->request->status = db->AddItem(item); // if( cur->request->status == WINIX_ERR_OK ) if( item.insert() ) { if( item.item_content.file_type != WINIX_ITEM_FILETYPE_NONE ) CopyStaticFile(item); plugin->Call(WINIX_FILE_COPIED, &item); } } void Cp::CopyFileOrSymlink(Item & item, long dst_dir_id) { if( !system->HasReadAccess(item) ) return; // !! w przyszlosci bedziemy dodawac komunikaty do specjalnej tablicy (narazie nie zaimplementowane) if( item.type == Item::symlink && follow_symlinks ) { if( system->dirs.CreateDirTab(item.parent_id, symlink_dir_tab) ) { int res = system->FollowAllLinks(symlink_dir_tab, item.item_content.link_to, symlink_dir_tab, item); if( res == 0 ) CopyDirTree(*symlink_dir_tab.back(), dst_dir_id); else if( res == 1 ) CopyFile(item, dst_dir_id); } } else { CopyFile(item, dst_dir_id); } } void Cp::Prepare() { // iq.SetAll(true, false); // iq.WhereType(Item::dir, false); new_user = -1; new_group = dir_tab.back()->item_content.group_id; if( cur->session->puser ) new_user = cur->session->puser->id; loop_checker.clear(); } void Cp::CopyFilesInDir(const Item & dir, long dst_dir_id) { morm::Finder finder(model_connector); item_tab = finder. select(). where(). neq(L"type", static_cast(Item::dir)). eq(L"parent_id", dir.id). get_vector(); //iq.WhereParentId(dir.id); //db->GetItems(item_tab, iq); for(size_t i=0 ; idirs.FindFirstChild(dir.id); // go through all directories for( ; i != system->dirs.ParentEnd() ; i = system->dirs.NextChild(i) ) CopyDirTree(*(i->second), dst_dir_id); CopyFilesInDir(dir, dst_dir_id); } bool Cp::WasThisDir(const Item & dir) { for(size_t i=0 ; iPrepareUrl(temp); file.clear(); } if( !preserve_attr ) SetNewAttributes(temp); if( remove_defaults ) { temp.item_content.link_to.clear(); temp.item_content.link_redirect = 0; } bool status = system->dirs.AddDirectory(temp); if( !status ) cur->request->status = WINIX_ERR_PERMISSION_DENIED; loop_checker.push_back(temp.id); // remember the new dir_id because temp can be changed // this method is called in recurrences long new_dir_id = temp.id; if( system->HasReadExecAccess(dir) ) CopyDirContentTree(dir, temp.id); return new_dir_id; // and return it } bool Cp::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; } // here 'item' can be changed in place void Cp::PostCopyFile(Item & item, bool redirect) { if( IsTheSameFile(item) ) return; if( !file.empty() ) { item.url = file; functions->PrepareUrl(item); file.clear(); } CopyFileOrSymlink(item, dir_tab.back()->id); if( cur->request->status == WINIX_ERR_OK && redirect ) system->RedirectTo(item); } void Cp::PostCopyDirContent(const Item & dir, bool redirect) { if( !file.empty() ) { cur->request->status = WINIX_ERR_INCORRECT_DIR; return; } if( dir_tab.back()->id == dir.id ) return; // nothing to do CopyDirContentTree(dir, dir_tab.back()->id); if( cur->request->status == WINIX_ERR_OK && redirect ) system->RedirectTo(dir_tab.back()->id); } void Cp::PostCopyDir(const Item & dir, bool redirect) { long dir_id = dir_tab.back()->id; if( file.empty() && dir_id == dir.id ) return; // nothing to do long new_dir_id = CopyDirTree(dir, dir_id); if( new_dir_id != -1 && cur->request->status == WINIX_ERR_OK && redirect ) system->RedirectTo(new_dir_id); } void Cp::Clear() { loop_checker.clear(); dir_tab.clear(); item_tab.clear(); symlink_dir_tab.clear(); } void Cp::MakePost() { if( ParseDir() && CheckAccessTo() ) { Prepare(); preserve_attr = cur->request->IsPostVar(L"preserveattr"); remove_defaults = cur->request->IsPostVar(L"removedefaults"); follow_symlinks = cur->request->IsPostVar(L"followsymlinks"); if( cur->request->is_item ) { PostCopyFile(cur->request->item); } else { if( cur->request->IsPostVar(L"onlycontent") ) PostCopyDirContent(*cur->request->dir_tab.back()); else PostCopyDir(*cur->request->dir_tab.back()); } Clear(); } } } // namespace } // namespace Winix