winix/winixd/core/mountparser.cpp

541 lines
9.5 KiB
C++
Raw Normal View History

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2010-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 "mountparser.h"
#include "log.h"
#include "misc.h"
namespace Winix
{
MountParser::MountParser()
{
dirs = 0;
skip_static = false;
mount_type_tab = 0;
mount_fs_tab = 0;
mount_par_tab = 0;
static_mount_id = -1;
}
void MountParser::SkipStaticDirs(bool skip)
{
skip_static = skip;
}
void MountParser::SetStaticMountId(int id)
{
static_mount_id = id;
}
void MountParser::SetDirs(Dirs * pdirs)
{
dirs = pdirs;
}
void MountParser::SetMountTypeTab(const std::vector<std::wstring> & tab)
{
mount_type_tab = &tab;
}
void MountParser::SetMountFsTab(const std::vector<std::wstring> & tab)
{
mount_fs_tab = &tab;
}
void MountParser::SetMountParTab(const std::vector<std::wstring> & tab)
{
mount_par_tab = &tab;
}
bool MountParser::IsWhite(int c)
{
if( c==' ' || c=='\t' || c==13 || c==160 )
return true;
return false;
}
void MountParser::SkipWhite()
{
while( IsWhite(*pinput) )
++pinput;
}
void MountParser::SkipLine()
{
while( *pinput && *pinput != 10 )
++pinput;
if( *pinput == 10 )
++pinput;
}
void MountParser::ReadWordQuote(std::wstring & res)
{
++pinput;
while( *pinput && *pinput!=10 && *pinput!='\"' )
{
if( pinput[0]=='\\' && pinput[1]=='\"' )
{
res += '\"';
pinput += 2;
}
else
if( pinput[0]=='\\' && pinput[1]=='\\' )
{
res += '\\';
pinput += 2;
}
else
{
res += *pinput;
pinput += 1;
}
}
if( *pinput == '"' )
++pinput;
}
// a white character is the separator
void MountParser::ReadWordWhite(std::wstring & res)
{
while( *pinput && *pinput!=10 && !IsWhite(*pinput) )
{
res += *pinput;
++pinput;
}
}
// the comma or the second bracket ')' are the separators
void MountParser::ReadWordComma(std::wstring & res)
{
while( *pinput && *pinput!=10 && *pinput!=',' && *pinput!=')' )
{
res += *pinput;
++pinput;
}
// trimming last white characters
// (white characters can be in the middle of the string)
TrimWhite(res);
}
void MountParser::ReadWord(std::wstring & res, bool comma_bracket_separator)
{
res.clear();
SkipWhite();
if( *pinput == '"' )
{
ReadWordQuote(res);
}
else
if( comma_bracket_separator )
{
ReadWordComma(res);
}
else
{
ReadWordWhite(res);
}
}
void MountParser::ReadParamArgsLoop(Mount::ParamRow::ParamArg & args)
{
SkipWhite();
while( *pinput && *pinput!=10 && *pinput!=')' )
{
ReadWord(temp_arg, true);
if( !temp_arg.empty() )
args.push_back(temp_arg);
if( *pinput == ',' )
++pinput;
}
}
void MountParser::ReadParamArgs(Mount::ParamRow::ParamArg & args)
{
SkipWhite();
args.clear();
if( *pinput == '(' )
{
++pinput;
ReadParamArgsLoop(args);
if( *pinput != ')' )
{
// there should be ')' at the end
// temporarily we do nothing
}
else
{
++pinput;
}
}
}
void MountParser::ReadParamName(std::wstring & res)
{
SkipWhite();
res.clear();
while( *pinput && *pinput!=10 && *pinput!=',' && *pinput!='(' && !IsWhite(*pinput) )
{
res += *pinput;
++pinput;
}
}
void MountParser::ReadParam(std::wstring & res, Mount::ParamRow::ParamArg & args)
{
ReadParamName(res);
if( res.empty() )
return;
ReadParamArgs(args);
SkipWhite();
if( *pinput == ',' )
++pinput;
}
int MountParser::FindIndex(const std::vector<std::wstring> * tab, const std::wstring & value)
{
for(size_t i=0 ; i < tab->size() ; ++i)
{
if( (*tab)[i] == value )
return static_cast<int>(i);
}
return -1;
}
bool MountParser::ReadMountType()
{
ReadWord(temp);
if( temp.empty() )
{
// an empty line (some white characters only)
return false;
}
mount.type = FindIndex(mount_type_tab, temp);
if( mount.type != -1 )
{
log << log3 << "MP: mount type: " << (*mount_type_tab)[mount.type] << logend;
}
else
{
log << log1 << "MP: unknown mount type: " << temp << logend;
// IMPROVE ME there is no slog now
//slog << logerror << T("unknown_mount_type") << ": " << temp << logend;
}
return mount.type != -1;
}
bool MountParser::ReadMountPoint()
{
ReadWord(last_dir);
pdir = dirs->GetDir(last_dir);
if( pdir )
{
mount.dir_id = pdir->id;
log << log3 << "MP: mount point (directory): " << last_dir << logend;
}
else
{
log << log1 << "MP: there is no such a mount point (directory): " << last_dir << logend;
// IMPROVE ME there is no slog now
//slog << logerror << T("no_such_dir") << ": " << last_dir << logend;
}
return pdir != 0;
}
bool MountParser::ReadFs()
{
ReadWord(temp);
mount.fs = FindIndex(mount_fs_tab, temp);
if( mount.fs != -1 )
{
log << log2 << "MP: file system: " << (*mount_fs_tab)[mount.fs] << logend;
}
else
{
log << log1 << "MP: unknown filesystem: " << temp << logend;
// IMPROVE ME there is no slog now
//slog << logerror << T("unknown_filesystem") << ": " << temp << " (" << last_dir << ")" << logend;
}
return mount.fs != -1;
}
void MountParser::LogMountParams()
{
size_t i;
log << log3 << "MP: mount param: " << temp << "(";
for(i=0 ; i<param_args.size() ; ++i)
{
log << param_args[i];
if( i != param_args.size()-1 )
log << ",";
}
log << ")" << logend;
}
void MountParser::ReadMountParams()
{
mount.ClearParams();
for( ReadParam(temp, param_args) ; !temp.empty() ; ReadParam(temp, param_args) )
{
int code = FindIndex(mount_par_tab, temp);
if( code != -1 )
{
mount.param[code].defined = true;
mount.param[code].arg = param_args;
LogMountParams();
}
else
{
log << log1 << "MP: unknown mount param: " << temp << logend;
// IMPROVE ME there is no slog now
//slog << logwarning << T("unknown_mount_param") << ": " << temp << " (" << T("skipped") << ")" << logend;
}
}
}
void MountParser::AddParams(Mount::Param & src, Mount::Param & dst)
{
if( src.size() != dst.size() )
{
log << log1 << "MP: addparams: incorrect sizes" << logend;
return;
}
for(size_t p=0 ; p < src.size() ; ++p)
{
if( src[p].defined && !dst[p].defined )
dst[p] = src[p];
}
}
bool MountParser::AddParamsBefore(long dir_id)
{
std::map<long, Mount>::iterator i = poutput->find(dir_id);
if( i == poutput->end() )
return false;
AddParams(i->second.param, mount_inserted.first->second.param);
return true;
}
/*
adding all non-existing parameters to this mount point from parents
*/
void MountParser::AddParamsBefore()
{
if( !pdir )
return;
Item * dir;
long dir_id = pdir->parent_id;
while( dir_id != -1 )
{
if( AddParamsBefore(dir_id) )
{
// we don't have to check others parents
// the parameters are already copied
break;
}
dir = dirs->GetDir(dir_id);
if( !dir )
break;
dir_id = dir->parent_id;
}
}
/*
adding all non-existing parameters to childs (childs to this mount point)
*/
void MountParser::AddParamsAfter()
{
std::map<long, Mount>::iterator i = poutput->begin();
for( ; i != poutput->end() ; ++i)
{
if( dirs->IsChild(mount_inserted.first->second.dir_id, i->first) )
AddParams(mount_inserted.first->second.param, i->second.param);
}
}
void MountParser::ReadRow()
{
if( ReadMountType() && ReadMountPoint() && ReadFs() )
{
ReadMountParams();
if( skip_static && mount.type==static_mount_id )
{
log << log1 << "MP: static mount points are skipped (dont_use_static_dirs in config is true)" << logend;
// IMPROVE ME there is no slog now
//slog << logwarning << T("skipped_static_mount") << ": " << last_dir << logend;
}
else
{
mount_inserted = poutput->insert( std::make_pair(mount.dir_id, mount) );
if( mount_inserted.second )
{
AddParamsBefore();
AddParamsAfter();
}
else
{
log << log1 << "MP: this mount point exists (skipped)" << logend;
// IMPROVE ME there is no slog now
//slog << logwarning << T("mount_exists") << ": " << last_dir << " (" << T("skipped") << ")" << logend;
}
}
}
SkipLine();
}
void MountParser::Parse(const std::wstring & input, std::map<long, Mount> & output)
{
if( !dirs || !mount_type_tab || !mount_fs_tab || !mount_par_tab )
{
log << log1 << "MP: input tables not set" << logend;
return;
}
pinput = input.c_str();
poutput = &output;
mount.param.resize(mount_par_tab->size());
mount.ClearParams();
poutput->clear();
while( *pinput )
ReadRow();
}
} // namespace Winix