FileZilla Server源码解析之LIST命令
如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033
FileZilla版本:FileZilla_Server-0_9_60_2
使用工具:NotePad++
在使用LIST命令进行FTP目录获取时,发现了一个奇怪的现象:
获取的时间信息中有的是年月,有的是小时分钟
-rw-r--r-- 1 ftp ftp 154168 Jan 20 18:53 00008d38072c01ba00e41507ba1bcb20.mdat
-rw-r--r-- 1 ftp ftp 154168 Feb 23 09:36 03258da63bccf1b387185bdd0b7afd76.mdat
-rw-r--r-- 1 ftp ftp 110120 Jan 16 2018 0751bd09cc83028eb6737131cc64c245.mdat
如果我们要获得时间数据,这种不统一的格式对于解析造成很大困难。
因此,决定查看源码来找到问题原因。
注意:
FileZilla的源码在EXE安装时是有选项的,默认是不安装源码。
源代码就在FileZilla Server\source中
1.查找LIST命令
用NotePad++打开source中的任意文件,使用Ctrl+Shif+F进行文件查找,关键词为LIST,匹配大小写和全词匹配。
搜索结果:
2.通过函数指针找到实际的执行函数
if( cmd.id == commands::LIST ) {
addFunc = CPermissions::AddLongListingEntry;
}
再次搜索AddLongListingEntry,在Permissions.cpp中找到了函数
void CPermissions::AddLongListingEntry(std::list<t_dirlisting> &result, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char*, bool *)
3.解析AddLongListingEntry函数
void CPermissions::AddLongListingEntry(std::list<t_dirlisting> &result, bool isDir, const char* name, const t_directory& directory, __int64 size, FILETIME* pTime, const char*, bool *)
{
WIN32_FILE_ATTRIBUTE_DATA status{};
if (!pTime && GetStatus64(directory.dir, status)) {
size = GetLength64(status);
pTime = &status.ftLastWriteTime;
}
unsigned int nameLen = strlen(name);
// This wastes some memory but keeps the whole thing fast
if (result.empty() || (8192 - result.back().len) < (60 + nameLen)) {
result.push_back(t_dirlisting());
}
if (isDir) {
memcpy(result.back().buffer + result.back().len, "drwxr-xr-x", 10);
result.back().len += 10;
}
else {
result.back().buffer[result.back().len++] = '-';
result.back().buffer[result.back().len++] = directory.bFileRead ? 'r' : '-';
result.back().buffer[result.back().len++] = directory.bFileWrite ? 'w' : '-';
BOOL isexe = FALSE;
if (nameLen > 4) {
CStdStringA ext = name + nameLen - 4;
if (ext.ReverseFind('.') != -1) {
ext.MakeLower();
if (ext == ".exe")
isexe = TRUE;
else if (ext == ".bat")
isexe = TRUE;
else if (ext == ".com")
isexe = TRUE;
}
}
result.back().buffer[result.back().len++] = isexe ? 'x' : '-';
result.back().buffer[result.back().len++] = directory.bFileRead ? 'r' : '-';
result.back().buffer[result.back().len++] = '-';
result.back().buffer[result.back().len++] = isexe ? 'x' : '-';
result.back().buffer[result.back().len++] = directory.bFileRead ? 'r' : '-';
result.back().buffer[result.back().len++] = '-';
result.back().buffer[result.back().len++] = isexe ? 'x' : '-';
}
memcpy(result.back().buffer + result.back().len, " 1 ftp ftp ", 11);
result.back().len += 11;
result.back().len += sprintf(result.back().buffer + result.back().len, "% 14I64d", size);
// Adjust time zone info and output file date/time
SYSTEMTIME sLocalTime;
GetLocalTime(&sLocalTime);
FILETIME fTime;
VERIFY(SystemTimeToFileTime(&sLocalTime, &fTime));
FILETIME mtime;
if (pTime)
mtime = *pTime;
else
mtime = fTime;
TIME_ZONE_INFORMATION tzInfo;
int tzRes = GetTimeZoneInformation(&tzInfo);
_int64 offset = tzInfo.Bias+((tzRes==TIME_ZONE_ID_DAYLIGHT)?tzInfo.DaylightBias:tzInfo.StandardBias);
offset *= 60 * 10000000;
long long t1 = (static_cast<long long>(mtime.dwHighDateTime) << 32) + mtime.dwLowDateTime;
t1 -= offset;
mtime.dwHighDateTime = static_cast<DWORD>(t1 >> 32);
mtime.dwLowDateTime = static_cast<DWORD>(t1 & 0xFFFFFFFF);
SYSTEMTIME sFileTime;
FileTimeToSystemTime(&mtime, &sFileTime);
long long t2 = (static_cast<long long>(fTime.dwHighDateTime) << 32) + fTime.dwLowDateTime;
const char months[][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
result.back().len += sprintf(result.back().buffer + result.back().len, " %s %02d ", months[sFileTime.wMonth-1], sFileTime.wDay);
if (t1 > t2 || (t2-t1) > (1000000ll*60*60*24*350))
result.back().len += sprintf(result.back().buffer + result.back().len, " %d ", sFileTime.wYear);
else
result.back().len += sprintf(result.back().buffer + result.back().len, "%02d:%02d ", sFileTime.wHour, sFileTime.wMinute);
memcpy(result.back().buffer + result.back().len, name, nameLen);
result.back().len += nameLen;
result.back().buffer[result.back().len++] = '\r';
result.back().buffer[result.back().len++] = '\n';
}
我们看到了如下代码,其中t1为FTP文件的修改时间,t2为FTP所在服务器的当前时间
if (t1 > t2 || (t2-t1) > (1000000ll*60*60*24*350))
result.back().len += sprintf(result.back().buffer + result.back().len, " %d ", sFileTime.wYear);
else
result.back().len += sprintf(result.back().buffer + result.back().len, "%02d:%02d ", sFileTime.wHour, sFileTime.wMinute);
通过上述代码,我们知道了:
- 当t1>t2或t2-t1的时间差大于35天时,返回年份
- 其他情况,返回小时分钟
注意:
FILETIME是以100纳秒(ns)为单位
所以1000000ll*60*60*24*350*100 = 35天
4.结论
当本地时间大于文件修改时间或文件修改时间减去本地时间的时间差大于35天时,返回年份
其他情况,返回小时分钟
觉得文章对你有帮助,可以用微信扫描二维码捐赠给博主,谢谢!
如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033