/* * This file is a part of Winix * and is not publicly distributed * * Copyright (c) 2008-2010, Tomasz Sowa * All rights reserved. * */ #include "dirs.h" #include "error.h" #include "log.h" void Dirs::SetDb(Db * pdb) { db = pdb; } void Dirs::SetRequest(Request * prequest) { request = prequest; } void Dirs::SetNotify(Notify * pnotify) { notify = pnotify; } void Dirs::Clear() { dir_tab.Clear(); } bool Dirs::HasReadExecAccessForRoot(const Item & item) { // there must be at least one 'x' (for the root) return (item.privileges & 01111) != 0; // !! in the future there'll be another 'x' } void Dirs::CheckRootDir() { DirContainer::Iterator i = dir_tab.GetRoot(); if( i != dir_tab.End() ) { if( !HasReadExecAccessForRoot(*i) ) { i->privileges = 0755; log << log1 << "Dirs: there is no access for root (admin) to the root dir, setting 0755 for root dir" << logend; db->EditPrivById(*i, i->id); } 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) == WINIX_ERR_OK ) { dir_tab.PushBack(root); } } void Dirs::ReadDirs() { Clear(); db->GetDirs(dir_tab); CheckRootDir(); dir_tab.FindSpecialFolders(); } bool Dirs::ExtractName(const wchar_t * & s, std::wstring & name) { name.clear(); // skipping first slashes (can be more than one) for( ; *s == '/' ; ++s); for( ; *s != 0 && *s != '/' ; ++s) name += *s; return !name.empty(); } bool Dirs::IsDir(long id) { DirContainer::Iterator i = dir_tab.FindId(id); if( i == dir_tab.End() ) return false; return true; } // !! dac clearowanie childs_tab // !! ewentualnie mozna dodac trzeci domyslny parametr bool clear_tab = true bool Dirs::GetDirChilds(long parent, std::vector & childs_tab) { if( parent != -1 && !IsDir(parent) ) return false; DirContainer::ParentIterator i = dir_tab.FindFirstParent(parent); for( ; i != dir_tab.ParentEnd() ; i = dir_tab.NextParent(i) ) childs_tab.push_back( &(*i->second) ); return true; } DirContainer::ParentIterator Dirs::FindFirstParent(long parent_id) { DirContainer::ParentIterator i = dir_tab.FindFirstParent(parent_id); return i; } DirContainer::ParentIterator Dirs::NextParent(DirContainer::ParentIterator i) { return dir_tab.NextParent(i); } DirContainer::ParentIterator Dirs::ParentEnd() { return dir_tab.ParentEnd(); } // 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') // path with a slash at the end bool Dirs::MakePath(long id, std::wstring & path) { DirContainer::Iterator i; path = '/'; while( true ) { i = dir_tab.FindId(id); if( i == dir_tab.End() || i->parent_id == id ) // means a loop (something wrong in the db) return false; if( i->parent_id == -1 ) return true; id = i->parent_id; path.insert(0, i->url); path.insert(path.begin(), '/'); } } bool Dirs::ChangeParent(long dir_id, long new_parent_id) { return dir_tab.ChangeParent(dir_id, new_parent_id); } /* checking whether dir_id has a parent parent_id (somewhere in the path) */ bool Dirs::HasParent(long dir_id, long parent_id) { DirContainer::Iterator i; while( true ) { i = dir_tab.FindId(dir_id); if( i==dir_tab.End() || i->parent_id==-1 ) return false; if( i->parent_id == parent_id ) return true; dir_id = i->parent_id; } } Item * Dirs::GetRootDir() { DirContainer::Iterator root = dir_tab.GetRoot(); if( root == dir_tab.End() ) return 0; return &(*root); } Item * Dirs::GetEtcDir() { DirContainer::Iterator etc = dir_tab.GetEtc(); if( etc == dir_tab.End() ) return 0; return &(*etc); } Item * Dirs::GetVarDir() { DirContainer::Iterator etc = dir_tab.GetVar(); if( etc == dir_tab.End() ) return 0; return &(*etc); } Item * Dirs::GetDir(const std::wstring & name, long parent) { DirContainer::ParentIterator i = dir_tab.FindFirstParent(parent); for( ; i!=dir_tab.ParentEnd() ; i = dir_tab.NextParent(i) ) if( i->second->url == name ) return &(*i->second); return 0; } Item * Dirs::GetDir(const std::wstring & path) { DirContainer::Iterator root = dir_tab.GetRoot(); if( root == dir_tab.End() ) // ops, we do not have a root dir return 0; Item * pitem = &(*root); std::wstring name; const wchar_t * 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_tab.FindId(id); if( i == dir_tab.End() ) return 0; return &(*i); } Item * Dirs::AddDir(const Item & item) { return &(*dir_tab.PushBack(item)); } size_t Dirs::AnalyzeDir(Item * pdir, const std::wstring & path, long & dir_id, std::wstring & dir) { size_t i = 0; size_t old_i; while( true ) { dir_id = pdir->id; // skipping slashes for( ; iid); if( !pdir ) return old_i; // analyze_temp is not a directory dir += analyze_temp; dir += '/'; } } /* the path should begin with a slash return values: 0 - directory exists dir_id - id of the directory dir - the path to the directory (with a slash at the end) file - if not empty means a file name (we don't check if the file really exists) 1 - there is not a root dir 2 - the path is empty 3 - there is not such a directory */ int Dirs::AnalyzePath(const std::wstring & path, long & dir_id, std::wstring & dir, std::wstring & file) { Item * pdir = GetRootDir(); dir = '/'; file.clear(); if( !pdir ) return 1; if( path.empty() ) return 2; if( path[0] != '/' ) return 3; size_t i = AnalyzeDir(pdir, path, dir_id, dir); if( i < path.size() ) { // checking if at least one slash has left for(size_t a=i ; a < path.size() ; ++a) if( path[a] == '/' ) return 3; // there is not such a directory // the rest of the path is a file name file = path.c_str() + i; } return 0; } void Dirs::SplitPath(const std::wstring & path, std::wstring & dir, std::wstring & file) { std::wstring::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); } // !! dodac kasowanie z bazy bool Dirs::DelDir(long dir_id) { return dir_tab.DelById(dir_id); } Error Dirs::AddDirectory(Item & item, bool add_to_dir_tab, Item ** pdir, int notify_code) { if( pdir ) *pdir = 0; if( item.type != Item::dir ) return WINIX_ERR_DIR_EXPECTED; Error status = db->AddItem(item); if( status == WINIX_ERR_OK ) { Item * d = AddDir(item); if( add_to_dir_tab && !request->dir_tab.empty() && request->dir_tab.back()->id == item.parent_id ) request->dir_tab.push_back(d); if( pdir ) *pdir = d; if( notify_code ) notify->ItemChanged(notify_code, item); } return status; } Item * Dirs::CreateVarDir() { Item * var = GetVarDir(); if( var ) return var; Item v; Item * root = GetRootDir(); if( root ) { v.parent_id = root->id; v.user_id = -1; v.group_id = -1; v.privileges = 0755; v.subject = L"var"; v.url = L"var"; v.type = Item::dir; AddDirectory(v, false, &var); } return var; }