/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2014, 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 "dircontainer.h" #include "log.h" namespace Winix { std::wstring DirContainer::dir_etc = L"etc"; std::wstring DirContainer::dir_var = L"var"; DirContainer::DirContainer() { is_root = false; is_etc = false; is_var = false; } DirContainer::Iterator DirContainer::GetRoot() { if( !is_root ) return table.end(); return root_iter; } DirContainer::Iterator DirContainer::GetEtc() { if( !is_etc ) return table.end(); return etc_iter; } DirContainer::Iterator DirContainer::GetVar() { if( !is_var ) return table.end(); return var_iter; } DirContainer::ConstIterator DirContainer::Begin() const { return table.begin(); } DirContainer::ConstIterator DirContainer::End() const { return table.end(); } DirContainer::SizeType DirContainer::Size() { return table.size(); // !! warning: it has O(n) } bool DirContainer::Empty() { return table.empty(); } bool DirContainer::IsNameOfSpecialFolder(const std::wstring & name) { return name == dir_etc || name == dir_var; } // looking for '/etc' // 'root' is found beforehand // CheckSpecialFolder() may not find everything (when the first is a special folder and then the root) void DirContainer::FindSpecialFolders() { is_etc = false; is_var = false; if( !is_root ) return; DirContainer::ParentIterator i = FindFirstChild(root_iter->id); for( ; i!=ParentEnd() ; i = NextChild(i) ) { if( i->second->url == dir_etc ) { is_etc = true; etc_iter = i->second; } else if( i->second->url == dir_var ) { is_var = true; var_iter = i->second; } } } // this is used with PushBack() method void DirContainer::CheckSpecialFolder(const Item & item, Iterator iter) { if( item.parent_id == -1 ) { is_root = true; root_iter = iter; } if( !is_root ) return; if( item.parent_id==root_iter->id && item.url==dir_etc ) { is_etc = true; etc_iter = iter; log << log2 << "DirCont: added special folder: /etc" << logend; } if( item.parent_id==root_iter->id && item.url==dir_var ) { is_var = true; var_iter = iter; log << log2 << "DirCont: added special folder: /var" << logend; } } DirContainer::Iterator DirContainer::PushBack(const Item & item) { if( item.parent_id == -1 && is_root ) { log << log1 << "DirCont: more than one root dir - skipped, id: " << item.id << logend; return root_iter; } Iterator last_iter = table.insert(table.end(), item); CheckSpecialFolder(item, last_iter); log << log2 << "DirCont: added dir, url: " << item.url << ", id: " << item.id << ", parent_id: " << item.parent_id << logend; table_id.insert( std::make_pair(last_iter->id, last_iter) ); table_parent.insert( std::make_pair(last_iter->parent_id, last_iter) ); log << log3 << "DirCont: added indexes to dir, id: " << last_iter->id << ", parent_id: " << last_iter->parent_id << logend; return last_iter; } bool DirContainer::ChangeParent(long dir_id, long new_parent_id) { Iterator i = FindId(dir_id); if( i == table.end() ) return false; if( i->parent_id == new_parent_id ) return true; // nothing to do ParentIterator p = FindFirstChild(i->parent_id); bool found = false; for( ; p != table_parent.end() ; p = NextChild(p) ) { if( p->second->id == dir_id ) { table_parent.erase(p); log << log3 << "DirCont: removed parent index to dir: " << i->id << logend; i->parent_id = new_parent_id; table_parent.insert( std::make_pair(new_parent_id, i) ); log << log3 << "DirCont: added parent index to dir, id: " << i->id << ", parent_id: " << i->parent_id << logend; found = true; if( IsNameOfSpecialFolder(i->url) ) FindSpecialFolders(); break; // that iterator (p) is only one } } if( !found ) log << log1 << "DirCont: cannot find parent_id: " << i->parent_id << " in parent indexes" << logend; return found; } void DirContainer::Clear() { table.clear(); table_id.clear(); table_parent.clear(); is_root = false; } DirContainer::Iterator DirContainer::FindId(long id) { TableId::iterator i = table_id.find(id); if( i == table_id.end() ) return table.end(); return i->second; } DirContainer::ConstIterator DirContainer::FindId(long id) const { TableId::const_iterator i = table_id.find(id); if( i == table_id.end() ) return table.end(); return i->second; } DirContainer::ParentIterator DirContainer::ParentBegin() { return table_parent.begin(); } DirContainer::ParentIterator DirContainer::ParentEnd() { return table_parent.end(); } DirContainer::ParentSizeType DirContainer::ParentSize() { return table_parent.size(); } bool DirContainer::ParentEmpty() { return table_parent.empty(); } DirContainer::ParentIterator DirContainer::FindFirstChild(long parent) { ParentIterator i = table_parent.lower_bound(parent); if( i == table_parent.end() || i->first != parent ) return table_parent.end(); return i; } DirContainer::ParentIterator DirContainer::NextChild(ParentIterator i) { if( i == table_parent.end() ) return table_parent.end(); long parent = i->first; ++i; if( i == table_parent.end() || i->first != parent ) return table_parent.end(); return i; } bool DirContainer::DelById(long id) { TableId::iterator i = table_id.find(id); if( i == table_id.end() ) { log << log1 << "DirCont: delete: there is no directory with id: " << id << logend; return false; } long parent_id = i->second->parent_id; TableParent::iterator z = table_parent.lower_bound(parent_id); bool found = false; for( ; z != table_parent.end() && z->first == parent_id ; ++z ) { if( z->second == i->second ) { log << log2 << "DirCont: deleted directory id: " << id << ", url: " << i->second->url; if( i->second->parent_id == -1 ) { log << log2 << " (root directory)"; is_root = false; } log << log2 << logend; table.erase(i->second); log << log3 << "DirCont: deleted indexes into directory id: " << id << logend; table_id.erase(i); table_parent.erase(z); found = true; break; } } if( !found ) { log << log1 << "DirCont: can't find an index_parent into directory id: " << id << ", url: " << i->second->url << " (deleting skipped)" << logend; return false; } return true; } } // namespace Winix