FileZilla Server源码解析之LIST命令

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itas109

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值