winix/core/dirs.cpp

488 lines
8.0 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 "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<Item*> & 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( ; i<path.size() && path[i] == '/' ; ++i );
if( i == path.size() )
return i; // end of the path
// creating a name
old_i = i;
analyze_temp.clear();
for( ; i<path.size() && path[i] != '/' ; ++i)
analyze_temp += path[i];
pdir = GetDir(analyze_temp, pdir->id);
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;
}