Ticket #5071: FixTicket5071_ZeroSecondsForSFTP.diff

File FixTicket5071_ZeroSecondsForSFTP.diff, 13.7 KB (added by Jeremy Braun, 10 years ago)

A proposed patch to fix this issue.

  • src/include/directorylisting.h

     
    2020        flag_timestamp_date = 0x10,
    2121        flag_timestamp_time = 0x20,
    2222        flag_timestamp_seconds = 0x40,
    23 
    24         flag_timestamp_mask = 0x70
     23        flag_timestamp_utc = 0x80,
     24       
     25        flag_timestamp_mask = 0xF0
    2526    };
    2627    int flags;
    2728
     
    5152    {
    5253        return (flags & flag_timestamp_seconds) != 0;
    5354    }
     55    inline bool is_utc() const
     56    {
     57        return (flags & flag_timestamp_utc) != 0;
     58    }
     59    inline void AdjustTimeToUTC ( const wxTimeSpan &span )
     60    {
     61        if (has_time() && !is_utc())
     62        {
     63            time.Add(span);
     64            flags |= flag_timestamp_utc;
     65        }
     66    }
     67    inline void AdjustTimeToUTC ( const int offset )
     68    {
     69        if (offset) {
     70            const wxTimeSpan span(0, offset, 0, 0);
     71            AdjustTimeToUTC(span);
     72        }
     73    }
     74       
     75   
    5476
    55 
    5677    wxString target; // Set to linktarget it link is true
    5778
    5879    wxDateTime time;
  • src/engine/directorylisting.cpp

     
    151151        if (iter->is_dir())
    152152            m_hasDirs = true;
    153153        if (!iter->permissions.empty())
     154            m_has_perms = true;
     155        if (!iter->ownerGroup.empty())
    154156            m_has_usergroup = true;
    155         if (!iter->ownerGroup.empty())
    156             m_has_perms = true;
    157157        own_entries.push_back(CRefcountObject<CDirentry>(*iter));
    158158    }
    159159
  • src/engine/directorylistingparser.h

     
    4949    void Reset();
    5050
    5151    void SetTimezoneOffset(const wxTimeSpan& span) { m_timezoneOffset = span; }
     52   
     53    void SetFilezillaDataFormat(const bool filezilla_format) { m_attributeState = attr_file_next; }
    5254
    5355    void SetServer(const CServer& server) { m_server = server; };
    5456
    5557protected:
     58
     59    enum attributeStates
     60    {
     61        attr_disabled = 0,
     62        attr_file_next,
     63        attr_keep_next,
     64        attr_skip_next,
     65    };
     66
    5667    CLine *GetLine(bool breakAtEnd, bool& error);
    5768
    5869    bool ParseData(bool partial);
     
    8293    // with other formats.
    8394    bool ParseAsHPNonstop(CLine *pLine, CDirentry &entry);
    8495
     96    // When used with the Filezilla output format, parses attribute information
     97    // provided by Filezilla's helper applications
     98    bool ParseAsFilezillaAttributes(CLine *pLine, CDirentry &entry, bool ignoreBadPermissions);
     99   
    85100    // Date / time parsers
    86101    bool ParseUnixDateTime(CLine *pLine, int &index, CDirentry &entry);
    87102    bool ParseShortDate(CToken &token, CDirentry &entry, bool saneFieldOrder = false);
     
    115130   
    116131    bool m_maybeMultilineVms;
    117132
     133    int  m_attributeState;
     134   
    118135    wxTimeSpan m_timezoneOffset;
    119136};
    120137
  • src/engine/sftpcontrolsocket.cpp

     
    10831083                    for (int i = 0; i < count; ++i)
    10841084                    {
    10851085                        CDirentry& entry = pData->directoryListing[i];
    1086                         if (!entry.has_time())
    1087                             continue;
    10881086
    1089                         entry.time += span;
     1087                        entry.AdjustTimeToUTC (span);
    10901088                    }
    10911089
    10921090                    // TODO: Correct cached listings
     
    12611259    {
    12621260        pData->pParser = new CDirectoryListingParser(this, *m_pCurrentServer);
    12631261        pData->pParser->SetTimezoneOffset(GetTimezoneOffset());
    1264         if (!Send(_T("ls")))
     1262        pData->pParser->SetFilezillaDataFormat(true);
     1263        if (!Send(_T("ls-fz")))
    12651264            return FZ_REPLY_ERROR;
    12661265        return FZ_REPLY_WOULDBLOCK;
    12671266    }
  • src/engine/directorylistingparser.cpp

     
    11#include <filezilla.h>
     2#include <inttypes.h>
    23#include "directorylistingparser.h"
    34#include "ControlSocket.h"
    45
     
    67#define new DEBUG_NEW
    78#endif
    89
     10
    911std::map<wxString, int> CDirectoryListingParser::m_MonthNamesMap;
    1012
    1113//#define LISTDEBUG_MVS
     
    273275                    else if (c >= 'a' && c <= 'f')
    274276                    {
    275277                        number *= 16;
    276                         number += c - '0' + 10;
     278                        number += c - 'a' + 10;
    277279                    }
    278280                    else if (c >= 'A' && c <= 'F')
    279281                    {
     
    454456    m_prevLine = 0;
    455457    m_fileListOnly = true;
    456458    m_maybeMultilineVms = false;
     459    m_attributeState = attr_disabled;
    457460
    458461    if (m_MonthNamesMap.empty())
    459462    {
     
    765768    CDirentry entry;
    766769    bool res;
    767770    int ires;
    768 
     771   
     772    if (m_attributeState != attr_disabled &&
     773        m_attributeState != attr_file_next)
     774    {
     775        switch (m_attributeState)
     776        {
     777        case attr_keep_next:
     778            {
     779                entry = m_entryList.back();
     780               
     781                res = ParseAsFilezillaAttributes(pLine, entry, false);
     782               
     783                if (res) {
     784                    m_entryList.pop_back();
     785                    m_entryList.push_back(entry);
     786                }
     787            }
     788            break;
     789        case attr_skip_next:
     790            {
     791                // "." and ".." don't get pushed onto m_entryList
     792                res = ParseAsFilezillaAttributes(pLine, entry, true);
     793            }
     794            break;
     795        default:
     796            res = false;
     797            break;
     798        }
     799       
     800        m_attributeState = attr_file_next;
     801        if (res)
     802            return res;
     803        // On failure fall through to ensure that no directory lines are skipped
     804    }
     805   
    769806    if (serverType == ZVM)
    770807    {
    771808        res = ParseAsZVM(pLine, entry);
     
    864901    m_fileList.clear();
    865902    m_fileListOnly = false;
    866903
     904    if (m_attributeState)
     905        m_attributeState = attr_keep_next;
     906   
    867907    // Don't add . or ..
    868908    if (entry.name == _T(".") || entry.name == _T(".."))
     909    {
     910        if (m_attributeState)
     911            m_attributeState = attr_skip_next;
    869912        return true;
     913    }
    870914
    871915    if (serverType == VMS && entry.is_dir())
    872916    {
     
    876920            entry.name = entry.name.Left(pos);
    877921    }
    878922
    879     {
    880         int offset = m_server.GetTimezoneOffset();
    881         if (offset && entry.has_time())
    882         {
    883             // Apply timezone offset
    884             wxTimeSpan span(0, offset, 0, 0);
    885             entry.time.Add(span);
    886         }
    887     }
     923    entry.AdjustTimeToUTC(m_server.GetTimezoneOffset());
    888924
    889925    m_entryList.push_back(entry);
    890926
     
    10101046            }
    10111047        }
    10121048
    1013         if (entry.has_time())
    1014             entry.time.Add(m_timezoneOffset);
     1049        entry.AdjustTimeToUTC(m_timezoneOffset);
    10151050
    10161051        return true;
    10171052    }
     
    14801515    entry.ownerGroup = _T("");
    14811516    entry.permissions = _T("");
    14821517
    1483     if (entry.has_time())
    1484         entry.time.Add(m_timezoneOffset);
     1518    entry.AdjustTimeToUTC(m_timezoneOffset);
    14851519
    14861520    return true;
    14871521}
     
    15501584    return true;
    15511585}
    15521586
     1587bool CDirectoryListingParser::ParseAsFilezillaAttributes(CLine *pLine, CDirentry &entry, bool ignoreBadPermissions)
     1588{
     1589    int index = 0;
     1590    CToken token;
     1591
     1592    bool begin = false;
     1593    while (1) {
     1594        wxString s;
     1595        if (!pLine->GetToken(index, token))
     1596            return false;
     1597        ++index;
     1598       
     1599        s = token.GetString();
     1600       
     1601        if (s == _T("FZ_ATTR_END"))
     1602            break;
     1603       
     1604        if (begin) {
     1605            CToken dataToken;
     1606           
     1607            if (!pLine->GetToken(index, dataToken))
     1608                return false;
     1609            ++index;
     1610
     1611            if (s == _T("SIZE"))
     1612            {
     1613                entry.size = dataToken.GetNumber(CToken::hex);
     1614            }
     1615            else if (s == _T("UID"))
     1616            {
     1617                // Cdirentry doesn't have a UID member
     1618            }
     1619            else if (s == _T("GID"))
     1620            {
     1621                // Cdirentry doesn't have a GID member
     1622            }
     1623            else if (s == _T("PERM"))
     1624            {
     1625                wxString permissions;
     1626                wxLongLong perms = dataToken.GetNumber(CToken::hex);
     1627
     1628                bool isDir = 0 != (perms & 0040000);
     1629               
     1630                permissions += isDir ? 'd' : '-';
     1631                if  (!ignoreBadPermissions &&
     1632                 (isDir !=
     1633                  (0 != (entry.flags & CDirentry::flag_dir))))
     1634                {
     1635                    // BUGBUG: log error?
     1636                    return false;
     1637                }
     1638               
     1639                const wxString rwx = _("rwxrwxrwx");
     1640                const int len = rwx.length();
     1641
     1642                for (int i = 0; i < len; ++i) {
     1643                if ( 0 != (perms & (1 << (len - 1 - i))) ) {
     1644                    permissions += rwx[i];
     1645                } else {
     1646                    permissions += '-';
     1647                }
     1648                }
     1649
     1650                // setuid
     1651                if (0 != (perms & 04000))
     1652                {
     1653                    permissions[3] = (permissions[3] == '-') ? 'S' : 's';
     1654                }
     1655
     1656                // setgid
     1657                if (0 != (perms & 02000))
     1658                {
     1659                    permissions[6] = (permissions[6] == '-') ? 'S' : 's';
     1660                }
     1661
     1662                // sticky bit
     1663                if (0 != (perms & 01000))
     1664                {
     1665                    permissions[9] = (permissions[9] == '-') ? 'T' : 't';                   
     1666                }
     1667               
     1668                if (entry.permissions != permissions && !ignoreBadPermissions) {
     1669                    // BUGBUG: log error?
     1670                    return false;
     1671                }
     1672            }
     1673            else if (s == _T("ATIME"))
     1674            {
     1675                // Cdirentry doesn't have an ATIME member
     1676            }
     1677            else if (s == _T("MTIME"))
     1678            {
     1679                wxLongLong number = dataToken.GetNumber(CToken::hex);
     1680
     1681                entry.time = wxDateTime((time_t)number.GetValue());
     1682
     1683                entry.flags |= CDirentry::flag_timestamp_utc
     1684                    | CDirentry::flag_timestamp_date
     1685                    | CDirentry::flag_timestamp_time
     1686                    | CDirentry::flag_timestamp_seconds;
     1687
     1688            }
     1689            else if (s == _T("CTIME"))
     1690            {
     1691                // Cdirentry doesn't have an CTIME member
     1692            }
     1693            else
     1694            {
     1695                return false;
     1696            }
     1697        }
     1698        else if (s == _T("FZ_ATTR_BEGIN"))
     1699        {
     1700            begin = true;
     1701            continue;
     1702        }           
     1703    }   
     1704    return true;
     1705}
     1706
    15531707bool CDirectoryListingParser::ParseAsEplf(CLine *pLine, CDirentry &entry)
    15541708{
    15551709    CToken token;
     
    17861940        }
    17871941    }
    17881942
    1789     if (entry.has_time())
    1790         entry.time.Add(m_timezoneOffset);
     1943    entry.AdjustTimeToUTC(m_timezoneOffset);
    17911944
    17921945    return true;
    17931946}
     
    18391992        entry.flags |= CDirentry::flag_dir;
    18401993    }
    18411994   
    1842     if (entry.has_time())
    1843         entry.time.Add(m_timezoneOffset);
     1995    entry.AdjustTimeToUTC(m_timezoneOffset);
    18441996
    18451997    return true;
    18461998}
     
    20162168        entry.ownerGroup = _T("");
    20172169        entry.permissions = _T("");
    20182170
    2019         if (entry.has_time())
    2020             entry.time.Add(m_timezoneOffset);
     2171        entry.AdjustTimeToUTC(m_timezoneOffset);
    20212172    }
    20222173
    20232174    return true;
     
    22462397    entry.ownerGroup = _T("");
    22472398    entry.permissions = _T("");
    22482399
    2249     if (entry.has_time())
    2250         entry.time.Add(m_timezoneOffset);
     2400    entry.AdjustTimeToUTC(m_timezoneOffset);
    22512401
    22522402    return true;
    22532403}
     
    24122562    entry.ownerGroup = _T("");
    24132563    entry.permissions = _T("");
    24142564
    2415     if (entry.has_time())
    2416         entry.time.Add(m_timezoneOffset);
    2417 
     2565    entry.AdjustTimeToUTC(m_timezoneOffset);
     2566   
    24182567    return true;
    24192568}
    24202569
     
    29253074    entry.permissions = _T("");
    29263075    entry.target = _T("");
    29273076
    2928     if (entry.has_time())
    2929         entry.time.Add(m_timezoneOffset);
    2930 
     3077    entry.AdjustTimeToUTC(m_timezoneOffset);
     3078   
    29313079    return true;
    29323080}
    29333081
  • src/putty/psftp.c

     
    77#include <stdarg.h>
    88#include <assert.h>
    99#include <limits.h>
     10#include <inttypes.h>
    1011
    1112#ifndef _WINDOWS
    1213#include <locale.h>
     
    11531154 * List a directory. If no arguments are given, list pwd; otherwise
    11541155 * list the directory given in words[1].
    11551156 */
    1156 int sftp_cmd_ls(struct sftp_command *cmd)
     1157int sftp_cmd_ls_ex(struct sftp_command *cmd, int extrainfo)
    11571158{
    11581159    struct fxp_handle *dirh;
    11591160    struct fxp_names *names;
     
    12651266     * And print them.
    12661267     */
    12671268    for (i = 0; i < nnames; i++) {
     1269        struct fxp_attrs *attrs = &ournames[i]->attrs;
    12681270        fzprintf(sftpListentry, "%s", ournames[i]->longname);
     1271       
     1272        if (extrainfo) {
     1273        fzprintf_raw(sftpListentry, "FZ_ATTR_BEGIN");
     1274        if (attrs->flags & SSH_FILEXFER_ATTR_SIZE) {
     1275            printf(" SIZE %08l" PRIx32 "%08l" PRIx32, attrs->size.hi, attrs->size.lo);
     1276        }
     1277        if (attrs->flags & SSH_FILEXFER_ATTR_UIDGID) {
     1278            printf(" UID %08l" PRIx32, attrs->uid);
     1279            printf(" GID %08l" PRIx32, attrs->gid);
     1280        }
     1281        if (attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
     1282            printf(" PERM %08l" PRIx32, attrs->permissions);
     1283        }
     1284/*FZ: Does not work
     1285        if (attrs->flags & (SSH_FILEXFER_ATTR_CREATETIME | SSH_FILEXFER_ATTR_MODIFICATIONTIME)) {
     1286            if (attrs->flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
     1287            printf(" ATIME %08l" PRIx32 "%08l" PRIx32, attrs->atime.hi, attrs->atime.lo);
     1288            }
     1289            if (attrs->flags & SSH_FILEXFER_ATTR_CREATETIME) {
     1290            printf(" CTIME %08l" PRIx32 "%08l" PRIx32, attrs->ctime.hi, attrs->ctime.lo);
     1291            }
     1292            if (attrs->flags & SSH_FILEXFER_ATTR_MODIFICATIONTIME) {
     1293            printf(" MTIME %08l" PRIx32 "%08l" PRIx32, attrs->mtime.hi, attrs->mtime.lo);
     1294            }
     1295        }
     1296        else
     1297*/
     1298        if (attrs->flags & SSH_FILEXFER_ATTR_ACMODTIME) {
     1299            printf(" ATIME %08l" PRIx32 "%08l" PRIx32, attrs->atime.hi, attrs->atime.lo);
     1300            printf(" MTIME %08l" PRIx32 "%08l" PRIx32, attrs->mtime.hi, attrs->mtime.lo);
     1301            printf(" CTIME %08l" PRIx32 "%08l" PRIx32, 0L, 0L);
     1302        }
     1303        printf(" FZ_ATTR_END\n");
     1304        fflush(stdout);
     1305        }
     1306
    12691307        fxp_free_name(ournames[i]);
    12701308    }
    12711309    sfree(ournames);
     
    12801318
    12811319    return 1;
    12821320}
     1321int sftp_cmd_lsfz(struct sftp_command *cmd)
     1322{
     1323    return sftp_cmd_ls_ex (cmd, 1);
     1324}
     1325int sftp_cmd_ls(struct sftp_command *cmd)
     1326{
     1327    return sftp_cmd_ls_ex (cmd, 0);
     1328}
    12831329
    12841330/*
    12851331 * Change directories. We do this by canonifying the new name, then
     
    23502396        sftp_cmd_ls
    23512397    },
    23522398    {
     2399    "dir-fz", TRUE, "list remote files",
     2400        " [ <directory-name> ]/[ <wildcard> ]\n"
     2401        "  List the contents of a specified directory on the server.\n"
     2402        "  If <directory-name> is not given, the current working directory\n"
     2403        "  is assumed.\n"
     2404        "  If <wildcard> is given, it is treated as a set of files to\n"
     2405        "  list; otherwise, all files are listed.\n"
     2406        "  Special attribute information for each file is returned on\n"
     2407        "  a second line for each file\n",
     2408        sftp_cmd_lsfz
     2409    },
     2410    {
    23532411    "exit", TRUE, "bye", NULL, sftp_cmd_quit
    23542412    },
    23552413    {
     
    23982456        sftp_cmd_ls
    23992457    },
    24002458    {
     2459    "ls-fz", TRUE, "dir-fz", NULL,
     2460        sftp_cmd_lsfz
     2461    },
     2462    {
    24012463    "mget", TRUE, "download multiple files at once",
    24022464        " [ -r ] [ -- ] <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
    24032465        "  Downloads many files from the server, storing each one under\n"