文件目录结构,首先预览一下源码目录文件夹下的大致文件布局。
![](/images/cppblog_com/eamon100/17733/o_AllFiles.JPG)
源代码目录包含7个子目录:
子目录
|
功能
|
hash_algorithms |
MD5,SHA等哈希算法的实现 |
includes |
只有一个子目录openssl,安全套接层协议,提供安全数据传输 |
install |
安装脚本和资源 |
interface |
服务器管理客户端 |
misc |
混杂类,比较重要的如md5,StdString等 |
res |
程序编译资源,目前只有一个icon,程序的图标 |
tinyxml |
著名的一款基于DOM模型小巧开源的xml解析器 |
当前source目录下源码按实现功能大致又分为以下几种类型:
功能分类
|
包括的文件
|
网络相关 |
全体文件名含socket的,Server.* |
多线程相关 |
文件名包含Thread的文件 |
辅助
|
version.*,MFC64bitFix.*,conversion.*,config.h,service.cpp
等除去网络和线程的文件 |
文件目录结构分析完了。下面从VC生成的C++代码中最常出现的两个文件stdafx.h和stdafx.cpp开始,我们首先要弄清楚它们到底包含了哪些头文件,定义了哪些宏,什么了哪些函数以及结构体。在头文件stdafx.h中包含了config.h,misc\stdstring.h,MFC64bitFix.h,conversion.h,AsyncSocketEx.h等
config.h:
检查是否定义了两个常量。
强制使用unicode编译和检测是否安装了最新SDK。
misc\stdstring.h:定义了
CStdStr模板类,对标准模板库的basic_string<> 进行封装,提供了许多新功能
非常棒的封装类,作者:Joe O'Leary,主页:
http://home.earthlink.net/~jmoleary参考codeproject上的页面获得最新版本:
http://www.codeproject.com/KB/string/stdstring.aspx提供方便使用的字符串类,有MFC类CString的所有函数,CStdStringA和CStdStringW对于多字节和Unicode字符串,这个类比较大,需要慢慢分析
MFC64bitFix.h:定义了几个获得文件状态的函数(大小,文件属性,文件指针位置,64位,支持大型文件)
定义了文件状态的结构体CFileStatus64,包含文件大小,创建时间,最后修改和访问时间,文件属性(CFile::Attribute枚举值的OR)。定义了三个函数:
GetLength64:获得文件的大小,通过FindFirstFile获得文件属性,然后通过属性的移位运算获得文件大小(64位)
GetStatus64:获得文件的属性,通过FindFirstFile获得文件属性,复制到结构体CFileStatus64中。
GetPosition64:获得文件指针的当前位置,使用SetFilePointer函数移动文件指针,对于大文件可以使用SetFilePointerEx,比较方便,参考MSDN。
Conversion.h:用于ANSI和UTF8字符的互相转换
ConvFromNetwork: 用于网络字节的转换,从网络字节转换为Unicode字节,使用MultiByteToWideChar函数,先尝试CP_UTF8(UTF-8 code page),若失败则用CP_ACP(ANSI code page)。
ConvToNetworkW/ConvToNetworkA:用于网络字节的转换,WideCharToMultiByte
ConvToLocal:用于本地,从wchar_t转换位char,WideCharToMultiByte
ConvFromLocal:用于本地,从char转换位wchar_t,MultiByteToWideChar
AsyncSocketEx.h:异步Scoket类的定义,它是大多数Socket类的基类
网络相关的头文件,定义了CAsyncSocketEx类,以后再详细分析。
第55行遇到了条件宏#ifdef MMGR,编译条件中有定义,包含misc/mmgr.h文件。mmgr是用于管理和跟踪内存的代码,之后会重点详细分析。
至此,stdafx.h中头文件包含全部结束,下面就是宏定义了。
先看一下各消息的值范围和作用,见下图:
![](/images/cppblog_com/eamon100/17733/o_message.JPG)
注册了WM_FILEZILLA_THREADMSG消息用来线程间通信,使用RegisterWindowMessage在系统中定义新的窗口消息,并确保在系统中是唯一的。返回值为0xC000 至 0xFFFF。通常用于两个合作进程之间的通信。仅在多个进程需要处理相同消息时使用这个函数。
定义了WM_FILEZILLA_SERVERMSG用于进程间通信,(WM_APP + 1); 即FileZilla server.exe和FileZilla Server Interface.exe。
下面一些宏如下:
FSM_STATUSMESSAGE:在管理窗口或log中显示并记录状态信息
FSM_CONNECTIONDATA:和连接相关的信息,如新用户连接,登录,退出等
FSM_THREADCANQUIT:退出线程
FSM_SEND:发送数据时用于管理窗口统计发送字节数
FSM_RECV:接受数据时用于管理窗口统计接收字节数
其余的就不多写了,宏名比较直观的显示出意思。后面是一些结构体的定义:
t_controlmessage
t_statusmsg
t_connectiondata
t_connectiondata_add
t_connectiondata_changeuser
t_connectiondata_transferinfo
t_connectiondata_transferoffsets
t_connop
extern HWND hMainWnd:定义了全局的CServer的窗口类句柄。
最后定义了一个CCriticalSectionWrapper类和两个帮助检测临界区死锁的函数,尤其是前者,DEBUG版本时错误的使用将导致当前线程挂起。
其他一些辅助头文件和类定义。
Version.h:用于获取程序的版本信息
定义了GetVersionString函数,返回程序版本信息的字符串,GetModuleFileName()获取可执行文件的全路径, GetFileVersionInfoSize()获得版本信息的大小。GetFileVersionInfo()获得文件的版本信息,VerQueryValue查询某个选项的值,有三种路径形式:\ , \StringFileInfo\lang-codepage\string-name 和\VarFileInfo\Translation。
Defs.h:这个类定义了服务器的状态,如在线、离线、锁住等
定义了一些服务器状态的宏。
SpeedLimit.h:速度限制(包括时间段限制)
这里针对UI性比较强,定义了CSpeedLimit类,对应配置文件中,<SpeedLimits>下的一条Rule规则。Load函数加载一个<Rule>对应的选项,并把它保存在成员变量中。Save保存一个限制规则到TiXmlElement的对象中。GetRequiredBufferLen返回一个规则需要的字节数。IsItActive()判断谋一时间是否有起效的规则。FillBuffer这个函数将所有限制条件格式化成一个13个字节的字符串,ParseBuffer则是解析这个字符串,采用这个类,可以轻松实现强大的自定义限速功能。
SPEEDLIMITSLIST为规则数组,一个用户可以对应很多条速度限制规则
Options.h, OptionTypes.h:系统配置选项设置
OptionTypes.h中定义了一个结构t_Option,包括选项名,类型和是否只能本地连接修改。0表示字符串类型,1为数字类型。数组m_Optinons,保存所有配置项信息,如是否使用SSL,同时在线最大用户数量,上传下载限速等等,所有这些大部分都被使用在Option那个对话框UI上。数组中与Admin相关的选项以及Server name 和 server display name为TRUE。定义了SERVER_VERSION和PROTOCOL_VERSION常量,用于AdminSocket。
Options类就是操作配置文件的实体类(使用tinyXML),服务器的配置文件存储在exe同级目录下,叫FileZilla Srver.xml。Options的主要操作是针对内存中的配置,只有与默认值不同的项才会存入配置文件中。
Options类中定义了五个类变量:
m_Sync:用于多线程修改类变量的同步。
m_InstanceList:类实例的链表。
m_sOptionsCache:选项值在内存中的缓存。
m_bInitialized:是否已经初始化。
m_sSpeedLimits:速度限制设置数组。
定义了四个类函数:
IsNumeric:判断一个字符串是否是由0~9的数字组成的无符号数字。
GetXML:打开XML配置文件,返回XML文档的根节点。整个程序中对配置文件的访问都要通过这个函数,可以保证只有一个实例在访问XML配置文件,保持同步。
FreeXML:释放打开的XML文档,根据需要保存修改后的配置到配置文件中。
UpdateInstances:通过给每个实例的Helper Window发送异步消息,更新所有实例的值,将选项缓存更新为False,速度限制数组更新为类变量对应的值。
成员变量只有2个:
m_SpeedLimits:速度限制设置数组。
m_OptionsCache:缓存的各个选项值。
成员函数:
在构造函数中初始化了选项缓存,和Helper Window指针,将自身加入到类的实例链表中。初始化速度限制数组为类中对应的值。
析构函数从类的实例链表中删除自己,并释放Helper Window对象。
ReadSpeedLimits:读取配置文件中的速度限制配置。读取Download和Upload的选项内容,对每个规则生成SpeedLimit的一个对象,并放入到类变量m_sSpeedLimits数组想应的vector中。(此处没有使用同步变量,应该在同步环境中调用它)
SaveSpeedLimits:将类变量m_sSpeedLimits数组中的速度限制规则写入配置文件的XML树中。(此处没有使用同步变量,应该在同步环境中调用它)
SaveOptions:将选项保存到XML配置文件中。(为什么使用的是m_OptionsCache?可能是该变量与类变量的值相同?)
ReloadConfig:重新加载配置,如果配置文件不存在则创建一个新的空配置文件,若存在则加载它,通过SetOption设置到变量中。
Init: 初始化配置,如果已经初始化(m_bInitialized==true),则直接返回。如果配置文件不存在则创建一个新的空配置文件,若存在则加载它。如果选项值在类中没有缓存,通过SetOption设置到类变量和对象变量中。
GetOptionVal\GetOption:获得一个配置的值,如果对象的已经缓存则直接返回该值,否则看类变量中是否缓存,如没有则返回该选项的默认值,同时在该对象中缓存该值。
SetOption:将一个选项值设置到类变量和对象变量中,并根据参数保存到配置文件。如果类没有初始化则调用Init函数先初始化。
GetCurrentSpeedLimit:获得当前时间的速度限制的值,-1表示没有速度限制。参数为限制类型,0为下载,1为上传。速度限制有三种类型:0无限制,1限制总速度,2基于规则的限制。
GetAsCommand:将选项值转换为一个字节串供网络传输,前两个字节为选项的个数,高字节在前,低字节在后。每个选项的第一个字节表示选项类型,字符串和数字。对于字符串选项,每个选项的前三个字节表示该选项值的长度,管理员的密码选项做了特殊处理,不通过网络传输;对于数字选项,用8个字节表示数字的值。最后保存速度限制规则,前2个字节为规则的条数。
ParseOptionsCommand:解析从网络传输的选项字符串,通过SetOption保存到变量中,通过SaveOptions()保存到配置文件中。基本上是GetAsCommand的逆向操作。
Options还有一个隐藏的friend窗体类 COptionsHelperWindow,定义在cpp文件中,这个类用于通过用post WM_USER给窗体消息这种异步的方式去更新option实例,而不是options类自身。
有了Options类和OptionTypes.h中定义的配置类型,就可以通过诸如 m_pOptions->GetOptionVal(OPTION_ENABLELOGGING)这样的方法方便的获取到配置。
OptionLimits.h:选项值设置的范围限制
定义了两个宏:OPTION_AUTOBAN_ATTEMPTS_MIN和OPTION_AUTOBAN_ATTEMPTS_MAX,自动禁用功能启用的次数限制。
FileLogger.h:系统的日志功能
这个类中包含Options类的一个对象指针,用来读取日志文件的相关配置。CheckLogFile函数检查是否启用了日志记录功能,创建日志目录和日志文件,目前有两种日志方式:所有日志共有同一个文件和每天一个日志文件,nLogType对应为0和1。根据程序选项,删除老日志文件以及大小超过限制的文件。Log函数记录系统日志,首先ConvToNetwork将Unicode字符串转换为char*,后调用WriteFile写日志,日志文件为UTF-8格式文本文件。
iputils.h:判断IP合法性以及是否处于某个过滤范围
与IP地址相关的辅助函数,支持IPV6,共包含8个函数。这些函数较以前的版本有较大的修改,取消了boost库中的regex类的使用,转而使用cidr表示法,支持IPV6。
IPv6地址(
http://baike.baidu.com/view/5228.htm)为128位长,但通常写作8组,每组为四个十六进制数的形式。2001:0db8:85a3:08d3:1319:8a2e:0370:7344是一个合法的IPv6地址。如果四个数字都是零,可以被省略。
例如:2001:0db8:85a3:0000:1319:8a2e:0370:7344等价于2001:0db8:85a3::1319:8a2e:0370:7344。
IPv6 地址有两种短格式:
•省略前导零
通过省略前导零指定 IPv6 地址。例如,IPv6 地址 1050:0000:0000:0000:0005:0600:300c:326b 可写为 1050:0:0:0:5:600:300c:326b。
•双冒号
通过使用双冒号(::)代替一系列零来指定 IPv6 地址。例如,IPv6 地址 ff06:0:0:0:0:0:0:c3 可写为 ff06::c3。一个 IP 地址中只可使用一次双冒号。
bool IsLocalhost(const CStdString& ip):判断ip是否为本地地址,IPV4以"127."开头,IPV6短地址为"::1"。
CStdString GetIPV6LongForm(CStdString short_address):获得短地址的IPV6长形式,每个IPV6长地址对应39个字符。首先去除地址的"[]"中括号,改为小写字母形式。然后查找"::",分别对前后两部分处理。
bool IsIpAddress(const CStdString& address):检查是否是一个IP地址,可以是IPV6地址或IPV4地址,(不包括CIDR格式的后面部分)
CStdString GetIPV6ShortForm(const CStdString& ip):获得最短的IPV6形式,此处先将ip转换为标准的IPV6长形式,去除前导0,合并一系列的0。
bool IsValidAddressFilter(CStdString& filter):判断是否是合法的地址过滤字符串。filter可以是单个地址或采用cidr表示的地址段(ipv4或v6),掩码位为1~127.前部为一个IPV4地址或IPV6地址。若为IPV6地址则转换为标准的短格式。
bool IsRoutableAddress(const CStdString& address):判断一个IP地址是否是可路由的IP。对IPV4,127,10. ,192.168,169.254,以及172.(16~32)部分均为不可路由地址。对IPV6有4类:(http://zh.wikipedia.org/wiki/IPv6)
未指定地址
::/128- 所有比特皆为零的地址称作未指定地址。这个地址不可指定给某个网络接口,并且只有在主机尚未知道其来源IP时,才会用于软件中。路由器不可转送包含未指定地址的分组。
Link local地址
::1/128- 是一种单播绕回地址。如果一个应用程序将分组送到此地址,IPv6堆栈会转送这些分组绕回到同样的虚拟接口(相当于IPv4中的127.0.0.1)。
fe80::/10- 这些link-local地址指明,这些地址只在区域连接中是合法的,这有点类似于IPv4中的169.254.0.0/16。
唯一区域位域
fc00::/7-唯一区域地址(ULA,unique local address)只可在一群网站中绕送。这定义在RFC 4193中,是用来取代site-local位域。这地址包含一个40比特的伪随机数,以减少当网站合并或分组误传到网络时碰撞的风险。这些地址除了只能用于区域外,还具备全局性的范畴,这点违反了唯一区域位域所取代的site-local地址的定义。
IPv4转译地址
::ffff:x.x.x.x/96- 用于IPv4映射地址。(参见以下的Transition mechanisms)。
2001::/32- 用于Teredo tunneling。
2002::/16- 用于6to4。
bool MatchesFilter(CStdString filter, CStdString ip):判断ip是否与filter过滤器匹配。filter的IPV6为短格式。对单个IP地址过滤器比较简单,只需要比较两个字符串是否相同,如果ip是V6版本则要先转换为短格式。对地址范围,V6版本将两个地址均转换为长格式再比较,对于网络段长度不是4的倍数还需要使用掩码比较多余的位。V4版本则先讲地址通过inet_addr和ntohl函数转换为长整数,再通过掩码比较。
bool ParseIPFilter(CStdString in, std::list<CStdString>* output = 0):讲过滤器字符串解析为一个过滤规则链表。首先将输入串的分隔符转换为单个空格,再最后输入串最后再添加一个空格。循环处理每个规则块。规则块可以是*和任何有效的地址过滤器(符合IsValidAddressFilter要求)。
autobanmanager.h:阻止用户继续登录的方法类
AutoBan这个设置项是一个非常浪费资源的,因为它对每一个失败的ip都要记录查询内存中的两个map
定义了CAutoBanManager类,包含一个COptions指针,根据系统设置对用户进行限制,m_banMap用于记录已禁止的用户,及禁止时间。m_attemptMap则用于记录用户已经尝试的次数。m_sync是一个线程同步变量。m_refCount为该类实例的个数,当一个对象被构造时,该值加一,析构时减一,最后一个对象析构时清空两个map。
IsBanned 查询一个IP是否被禁用了。
RegisterAttempt 记录一个IP一次新的尝试,如果超过最大次数则禁止该用户,并在m_banMap添加该IP,并从m_attemptMap中删除,目前禁止类型只有0,为1的代码还是空的,不执行禁止操作。
PurgeOutdated 根据设置的自动禁止时间,查看是否超过时常的,就从禁止列表和尝试列表中删除。
Accounts.h:账户类
Accounts.h中声明了3个类,t_directory,t_group,还有继承于t_group的t_user。sltype用于区别上传和下载,0表示下载。
t_directory 对应目录的选项,仅仅含有一些权限声明,相当于一个struct,被t_group和t_user使用。包含字符串dir,表示一个目录或文件,一个别名链表aliases,文件权限,目录权限和一个是否自动创建的变量,在构造函数中的默认值为false。
对应于<Permissions>的一条Permission 规则,用户和组均有多条这种规则。
剩余两个类主要做的事是对配置的读取分析,所有的数据都是基于字符串的。
t_group类对应组设置,每个组包括一个组名(group),目录的一个数组(permissions),
nBypassUserLimit,绕过服务器的用户限制
nUserLimit,:最大允许连接数量
nIpLimit: 每个Ip最大连接数量
forceSsl:用户登录时,强制使用SSL连接
int nSpeedLimitType[2]; 速度限制类型,包括无限制,默认,固定速度,使用规则等。
int nSpeedLimit[2];固定速度时的速度值
SPEEDLIMITSLIST SpeedLimits[2];
int nBypassServerSpeedLimit[2]; 是否绕过限制
nEnabled:是否允许组内用于访问服务器。IP过滤规则,速度限制规则(包括上传和下载)等,该类还有一个指向自身的指针,用于链接归属的组(用于用户)。
成员函数:
AccessAllowed:判断一个IP是否在IP过滤规则中,允许规则具有优先性,对于用户,如果自身规则不包含该IP还要查看归属组的IP过滤规则。
BypassServerSpeedLimit:返回是否绕过服务器的速度限制,1为是,0为否,其他值则看父节点的值。
GetCurrentSpeedLimit:根据速度限制类型nSpeedLimitType的值返回速度限制的值。0表示默认值,父节点的继承值,父节点不存在则没有限制,返回0。1表示无限制。2表示固定速度值,返回nSpeedLimit的值。3表示采用速度限制规则。
IsEnabled,ForceSsl,GetIpLimit,GetUserLimit,BypassUserLimit返回相应的属性值,或父节点的值
GetRequiredStringBufferLen:返回将一个字符串转换为网络传输的串需要的缓冲区的长度,比需要的长度加2个字节(在字符串的前面表示该字符串的字符个数)。
GetRequiredBufferLen:计算将一个实例通过网络传输需要的缓冲区长度。初始为9个字节,加上组名,加4个字节后开始计算IP规则的字节数,然后加2个字节开始计算目录的字节数。对于每个目录,最开始为2个字节,目录名的字节数,加两个字节开始目录别名的字节数。后是速度限制字节数,6个字节为基本限制,4个字节为规则的数量,然后是每个规则需要的字节数,最后加上备注的字节数和SSL设置的一个字节。
FillString:将一个字符串(Unicode)拷贝到缓冲区(需要字节转换)。
FillBuffer:将实例的设置转换到字节数组P中,首先是组名,然后是nIpLimit,nUserLimit各4个字节,nBypassUserLimit和nEnabled通过移位合用1个字节。然后是IP规则(包括允许和禁止规则),首先是规则的数量,2个字节,然后是每条规则复制。2个字节,permissions数组的大小,然后对该数组的每个元素,首先填充目录名,2个字节表示别名的数量,然后是填充每个别名。最后把目录的权限组合为2个字节。然后是速度限制,对上传和下载分别计算,nSpeedLimitType和nBypassServerSpeedLimit合用1个字节,速度限制值nSpeedLimit使用2个字节,后2个字节为规则的数量,然后填充每个规则。最后填充备注和SSL设置1个字节。
ParseString:解析并转换一个网络字符串,开始两个字节为字符串的长度。
ParseBuffer:解析网络传输过来的设置字符串,基本上是FillBuffer的逆操作。
t_user类继承自t_group类,多了一个用户名和密码。GetRequiredBufferLen,FillBuffer和ParseBuffer只针对用户名和密码修改了相应的函数,比较直观。
permission.h:对用户、群组访问资源进行鉴权,对应整个程序对Group和User的权限设置
权限配置信息记录在FileZilla Server.xml中。
服务器对每一个group和user都有权限限制,group权限优先于user权限,在CheckFilePermissions 函数中可以看出。
定义了CUser类继承自t_user类,表示一个用户。
homedir表示用户的主目录
结构体t_alias定义了别名,包括targetFolder目标文件夹和name别名名称。
两个multimap 映射对象:aliasMap,virtualAliasNames
一个 map映射对象: virtualAliases。
其中aliasMap用于物理地址的别名映射,其他两个用于虚拟地址别名映射,即别名以‘/’开头。
DoReplacements函数将参数路径中的:u替换为用户名,:g替换为组名(如果指定了组)。
PrepareAliasMap函数准备好别名映射。首先将aliasMap和virtualAliases清空。然后循环处理用户每个目录对应的每个别名设置。每个目录的别名分为两种情况:1是以'/'开头的别名,2是不以'/'开头 但是包含'\\'的别名。
对第一种情况:以最后一个'/'将别名分为两个部分,若前部分为空,这前部分设置为'/'。virtualAliasNames的第一个值为前部分,第二个值为后一部分。virtualAliases插入第一个值为别名+'/',第二个值为正在处理的目录。这是一个Map,后面会覆盖前面的值。
对第二种情况:以最后一个'\\'将别名分为两个部分,后半部分不能为空。其值为t_alias结构的name值,targetFolder对应正在处理的目录。aliasMap的第一个值为前半部分,第二个值为这个t_alias结构。
GetAliasTarget函数,返回别名对应的目标文件夹。如果别名找不到则返回空串。首先看aliasMap,如果path和name与
aliasMap的值相同则返回目标文件夹。如果找不到则看virtualAliases,如果virtualPath的值与virtualAliases的值相同,则返回目标文件夹。
CPermissions比较复杂,与前面的COption类的定义方式有些类似,均定义了一个辅助Helper类。
CPermissions还有一个隐藏的friend窗体类 CPermissionsHelperWindow,定义在cpp文件中,这个类用于通过用post WM_USER给窗体消息这种异步的方式去更新permissions实例的m_GroupsList和m_UsersList为类对应的值,而不是permissions类自身。
CPermissions类的分析:
类变量:
m_sync 同步变量。
m_sUsersList 用户数组
m_sGroupsList 组数组
m_sInstanceList 所有实例的链表
类函数:
AddLongListingEntry 将文件的属性信息、目录信息添加到pResult链表中,每个项以'\r\n'结束。I4I64D表示14个字符的64位整数。
AddShortListingEntry只将文件名、目录名添加到pResult链表中,每个项以'\r\n'结束。
AddFactsListingEntry根据enabledFacts将文件或文件夹的特定项添加到pResult链表中,每个项以'\r\n'结束。enabledFacts[0]为类型,2为修改时间,1为文件大小,3为权限设置
GetHomeDir 获得用户的Home目录,如果physicalPath为true则返回主目录对应的本地文件系统的目录。
CheckDirectoryPermissions
CheckFilePermissions 检查文件或目录对用户的OP操作是否有效(具有相应的权限),有效则返回0。
GetUser 查找当前系统中是否存在名为username的用户,有则将用户信息复制到userdata中,并返回true。
CheckUserLogin 检查用户名,密码是否匹配。noPasswordCheck为0时进行密码比对,否则仅检查用户名是否存在。
GetAsCommand 将所有用户的信息作为命令字符串返回给管理客户端。将m_sGroupList和m_sUserList的信息填充到pBuffer中,nBufferLength为填充的字节数。
ParseUsersCommand 为GetAsCommand 的逆向操作,将命令字符串还原为所有账户的信息。更新所有实例的链表,并更新类的链表和配置文件XML。
AutoCreateDirs自动创建username对应的用户设置了AutoCreate属性的文件夹的目录结构(该路径下的所有文件夹),以及所在群组的具有该属性的文件夹目录结构。
ReloadConfig 重新从配置文件中加载配置,先将用户和组列表清空,通过ReadSetting读取配置文件到该对象以及类属性。最后通过UpdateInstances更新所有实例的属性。
GetFact 获得特定目录、文件的Facts信息。首先获得对应的本地文件系统目录,如果是文件,则先获得它上一级目录的本地目录,再加上文件名。enabledFacts[0]为类型,2为修改时间,1为文件大小,3为权限设置
DestroyDirlisting 删除pListing中的所有项。
成员变量:
m_UsersList: 用户数组
m_GroupsList:Group数组
m_pPermissionsHelperWindow:CPermissionsHelperWindow的指针。
成员函数:
protected成员函数。
Init()函数在构造函数中被调用。初始化系统设置的值。首先创建一个 CPermissionsHelperWindow 实例并将this指数传递给它。如果是第一次调用该函数则调用ReadSettings函数初始化类变量,否则,用类变量初始化成员变量m_GroupsList和m_UsersList。最后将自身添加到实例链表中。
ReadSettings()函数,打开XML配置文件用到了COptions::GetXML()方法。读取Groups下每个Group的各个选项,ReadIpFilter()读取每个IpFilter的设置,ReadPermissions()读取Permissions下每个Permission的设置。如果没有设置Home目录,则将第一个目录设为Home目录。ReadSpeedLimits()读取该组内的每个速度限制规则。然后对Users做相似的操作,用户中多了一个Pass的选项,为用户设置的密码。如果提供的密码不是32位的MD5 hash值,则通过MD5类转换为hash值,并将该节点的值设置为MD5变换后的值。ReadPermissions后调用CUser类的PrepareAliasMap,初始化别名的映射。设置Home目录。最后将读取的值设置的类变量中。
ReadIpFilter
ReadPermissions
ReadSpeedLimits 这三个函数及相应的Save函数均读取配置文件中相应的设置,更新到user或group中。
UpdateInstances 更新所有实例的grouplist和userlist为类的值。
SetKey 设置XML树中的某个元素的属性和对应的值。
GetRealDirectory将服务器的绝对地址转换为本地文件系统的绝对地址。首先将服务器的绝对地址按照/字符分段。获得用户的本地文件系统的Home目录。如果目录不在Home目录的文件树中,则通过别名查找是否在别名设定的文件夹中(包括用户和组设置的别名)。找到后分析文件夹的权限设置,并返回该权限设置值。
WildcardMatch 判断String是否符合pattern模式,pattern可以包含*通配符。
CanonifyServerDir 规范化目录字符串,如果newDir为空则返回currentDir。将所有\\转换为/,然后将连续的两个//变为一个/。如果newDir为/,则返回/。如果newDir为相对路径(不以/开头),则将CurrentDir作为基目录。去除路径中的 ...,区别对待包含点的文件和全为点的目录。检查目录中是否有Windows系统保留的文件名(目录名),有则返回空值。再检查是否是保留文件名后加点的形式(如COM1.sd),是则返回空值。最后返回合并的文件目录。
public 成员函数(接口)
ChangeCurrentDir 更改用户的当前路径(服务器路径),检查是否具有目录读写和列目录的权限。
GetDirectoryListing 获得一个目录的列表,最后一个参数为格式化字符串的函数指针,该函数支持*通配符。获得显示目录的本地文件夹,如果是一个文件或本地目录不存在,则将需要显示的目录dirToDisplay中的反斜杠变为斜杠,并将连续的两个斜杠合并为一个。变换后,如果目录以斜杠结束则返回错误代码,如果文件夹不存在,且目录最后一个部分包含*,则显示去除最后一部分后的文件夹的内容,然后获得系统当前时区的设置,使显示目录以/结尾,并转换为网络传输格式。然后,循环该用户的别名映射aliasMap,如果存在该别名,且该别名的name与最后一部分相匹配则调用addfunc函数添加该行,最后处理目录下的文件和文件夹,通过addFunc添加到列表中。
ConvertFilename 当useUTF8为true时将文件名转为网络格式,否则转换为多字节格式。
Platform.h:
针对amd64等的未对齐内存访问的宏定义,对X86结构计算机无影响。 定义了三个宏将一个地址转换为16位、32位、64位地址。