/* * This file is a part of CMSLU -- Content Management System like Unix * and is not publicly distributed * * Copyright (c) 2008-2009, Tomasz Sowa * All rights reserved. * */ #include "dirs.h" #include "error.h" #include "log.h" #include "db.h" void Dirs::Clear() { dir_table.Clear(); } void Dirs::CheckRootDir() { DirContainer::Iterator i = dir_table.GetRoot(); if( i != dir_table.End() ) return; log << log1 << "Dirs: there is no a root dir in the database (creating one)" << logend; Item root; root.type = Item::dir; root.parent_id = -1; root.user_id = -1; root.group_id = -1; root.privileges = 0755; root.default_item = -1; // !! upewnic sie ze baza nie zmieni url (gdyby wczesniej juz byl w bazie pusty url) // !! zrobic jakis wyjatek do wprowadzania roota? if( db.AddItem(root) == Error::ok ) { dir_table.PushBack(root); } } void Dirs::ReadDirs() { Clear(); db.GetDirs(dir_table); CheckRootDir(); } bool Dirs::GetRootDir(Item ** item) { DirContainer::Iterator root = dir_table.GetRoot(); if( root == dir_table.End() ) return false; *item = &(*root); return true; } bool Dirs::GetDir(const std::string & name, long parent, Item ** item) { DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); for( ; i!=dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) if( i->second->url == name ) { *item = &(*i->second); return true; } return false; } bool Dirs::ExtractName(const char * & s, std::string & name) { name.clear(); // skipping first slashes (can be more than one) for( ; *s == '/' ; ++s); for( ; *s != 0 && *s != '/' ; ++s) name += *s; return !name.empty(); } // !! moze lepiej zwracac wskaznik do Item i kiedy nie ma katalogu to zwracac 0 ? bool Dirs::GetDir(const std::string & path, Item ** item) { DirContainer::Iterator root = dir_table.GetRoot(); if( root == dir_table.End() ) // ops, we do not have a root dir return false; Item * pitem = &(*root); std::string name; const char * s = path.c_str(); while( ExtractName(s, name) ) { if( !GetDir(name, pitem->id, &pitem) ) return false; } *item = pitem; return true; } // !! ten interfejs jes bylejaki // !! moze lepiej zwracac id i kiedy nie ma katalogu to -1 (przeciez to jest wartosc ktora nie moze pojawic sie w indeksie) bool Dirs::GetDirId(const std::string & path, long * id) { Item * pitem; if( !GetDir(path, &pitem) ) return false; *id = pitem->id; return true; } bool Dirs::GetDirId(const std::string & name, long parent, long * id) { Item * pitem; if( !GetDir(name, parent, &pitem) ) return false; *id = pitem->id; return true; } bool Dirs::IsDir(long id) { DirContainer::Iterator i = dir_table.FindId(id); if( i == dir_table.End() ) return false; return true; } bool Dirs::GetDirChilds(long parent, std::vector & childs_table) { if( parent != -1 && !IsDir(parent) ) return false; DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); for( ; i != dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) childs_table.push_back( *i->second ); return true; } bool Dirs::GetDirChilds(long parent, std::vector & childs_table) { if( parent != -1 && !IsDir(parent) ) return false; DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); for( ; i != dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) childs_table.push_back( &(*i->second) ); return true; } // dodatkowo moze metoda AppendPath dodajaca sciezke do biezacego stringa? // albo tutaj stringa nie czyscic? // O(m * log n) (m- how many parts are in 'id') bool Dirs::MakePath(long id, std::string & path) { DirContainer::Iterator i; path = '/'; while( true ) { i = dir_table.FindId(id); if( i == dir_table.End() ) return false; if( i->parent_id == -1 ) return true; id = i->parent_id; path.insert(0, i->url); path.insert(path.begin(), '/'); } } // with exceptions Item * Dirs::GetDirT(const std::string & path) { Item * pitem; if( !GetDir(path, &pitem) ) throw Error(Error::incorrect_dir); return pitem; } Item * Dirs::GetDirT(const std::string & name, long parent) { Item * pitem; if( !GetDir(name, parent, &pitem) ) throw Error(Error::incorrect_dir); return pitem; } long Dirs::GetDirIdT(const std::string & path) { long id; if( !GetDirId(path, &id) ) throw Error(Error::incorrect_dir); return id; } long Dirs::GetDirIdT(const std::string & name, long parent) { long id; if( !GetDirId(name, parent, &id) ) throw Error(Error::incorrect_dir); return id; } // !! nowy interfejs Item * Dirs::GetRootDir() { DirContainer::Iterator root = dir_table.GetRoot(); if( root == dir_table.End() ) return 0; return &(*root); } Item * Dirs::GetDir(const std::string & name, long parent) { DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); for( ; i!=dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) if( i->second->url == name ) return &(*i->second); return 0; } Item * Dirs::GetDir(const std::string & path) { DirContainer::Iterator root = dir_table.GetRoot(); if( root == dir_table.End() ) // ops, we do not have a root dir return 0; Item * pitem = &(*root); std::string name; const char * s = path.c_str(); while( ExtractName(s, name) ) { pitem = GetDir(name, pitem->id); if( !pitem ) return 0; } return pitem; } Item * Dirs::GetDir(long id) { DirContainer::Iterator i = dir_table.FindId(id); if( i == dir_table.End() ) return 0; return &(*i); } Item * Dirs::AddDir(const Item & item) { return &(*dir_table.PushBack(item)); } void Dirs::SplitPath(const std::string & path, std::string & dir, std::string & file) { std::string::size_type i; dir.clear(); file.clear(); if( path.empty() ) // !! moze dir ustawic na '/' ? return; for( i=path.size()-1 ; i>0 && path[i]!='/' ; --i); if( path[i] != '/' ) { // we do not have any slashes '/' file = path; return; } dir.assign(path, 0, i + 1); // +1 means with a slash at the end if( i < path.size() - 1 ) file.assign(path, i+1, path.size() - i - 1); } void Dirs::DeleteDir(long id) { DirContainer::ParentIterator pnext, p = dir_table.FindFirstParent(id); for( ; p != dir_table.ParentEnd() ; p = pnext ) { // this iterator p will be deleted by the next DeleteDir(p->second->id) // (the next iterator we must calculate beforehand) pnext = dir_table.NextParent(p); DeleteDir(p->second->id); } if( db.DelDirById(id) == Error::ok ) dir_table.DelById(id); }