VirtualBox

Changeset 82723 in vbox for trunk


Ignore:
Timestamp:
Jan 13, 2020 10:26:27 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
135661
Message:

IPRT/FTP: More protocol handling and callback work. bugref:9437

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/ftp.h

    r82715 r82723  
    3131#endif
    3232
     33#include <iprt/fs.h>
    3334#include <iprt/types.h>
    3435
     
    130131    /** Not logged in. */
    131132    RTFTPSERVER_REPLY_NOT_LOGGED_IN                  = 530,
     133    /** Requested action not taken. */
     134    RTFTPSERVER_REPLY_REQ_ACTION_NOT_TAKEN           = 550,
    132135    /** The usual 32-bit hack. */
    133136    RTFTPSERVER_REPLY_32BIT_HACK                     = 0x7fffffff
     
    179182     *
    180183     * @returns VBox status code.
     184     * @param   pData           Pointer to generic callback data.
    181185     * @param   pcszUser        User name.
    182186     */
     
    186190     *
    187191     * @returns VBox status code.
     192     * @param   pData           Pointer to generic callback data.
    188193     * @param   pcszUser        User name to authenticate.
    189194     * @param   pcszPassword    Password to authenticate with.
     
    194199     *
    195200     * @returns VBox status code.
    196      * @param   pcszUser        User name which disconnected.
     201     * @param   pData           Pointer to generic callback data.
    197202     */
    198203    DECLCALLBACKMEMBER(int,  pfnOnUserDisconnect)(PRTFTPCALLBACKDATA pData);
    199204    /**
     205     * Callback which gets invoked when the client wants to retrieve the size of a specific file.
     206     *
     207     * @returns VBox status code.
     208     * @param   pData           Pointer to generic callback data.
     209     * @param   pcszPath        Path of file to retrieve size for.
     210     * @param   puSize          Where to store the file size on success.
     211     */
     212    DECLCALLBACKMEMBER(int,  pfnOnFileGetSize)(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint64_t *puSize);
     213    /**
     214     * Callback which gets invoked when the client wants to retrieve information about a file.
     215     *
     216     * @param   pData           Pointer to generic callback data.
     217     * @param   pcszPath        Path of file / directory to "stat". Optional. If NULL, the current directory will be used.
     218     * @param   pFsObjInfo      Where to return the RTFSOBJINFO data on success.
     219     * @returns VBox status code.
     220     */
     221    DECLCALLBACKMEMBER(int,  pfnOnFileStat)(PRTFTPCALLBACKDATA pData, const char *pcszPath, PRTFSOBJINFO pFsObjInfo);
     222    /**
    200223     * Callback which gets invoked when setting the current working directory.
    201224     *
    202225     * @returns VBox status code.
     226     * @param   pData           Pointer to generic callback data.
    203227     * @param   pcszCWD         Current working directory to set.
    204228     */
     
    208232     *
    209233     * @returns VBox status code.
     234     * @param   pData           Pointer to generic callback data.
    210235     * @param   pszPWD          Where to store the current working directory.
    211236     * @param   cbPWD           Size of buffer in bytes.
     
    216241     *
    217242     * @returns VBox status code.
     243     * @param   pData           Pointer to generic callback data.
    218244     */
    219245    DECLCALLBACKMEMBER(int,  pfnOnPathUp)(PRTFTPCALLBACKDATA pData);
     
    221247     * Callback which gets invoked when the client wants to list a directory or file.
    222248     *
     249     * @param   pData           Pointer to generic callback data.
    223250     * @param   pcszPath        Path of file / directory to list. Optional. If NULL, the current directory will be listed.
    224251     * @param   ppvData         Where to return the listing data. Must be free'd by the caller.
  • trunk/src/VBox/Runtime/generic/ftp-server.cpp

    r82716 r82723  
    22/** @file
    33 * Generic FTP server (RFC 959) implementation.
     4 * Partly also implements RFC 3659 (Extensions to FTP, for "SIZE", ++).
    45 */
    56
     
    129130    /** Recursively gets a directory (and its contents). */
    130131    RTFTPSERVER_CMD_RGET,
     132    /** Retrieves the size of a file. */
     133    RTFTPSERVER_CMD_SIZE,
    131134    /** Retrieves the current status of a transfer. */
    132135    RTFTPSERVER_CMD_STAT,
     
    234237static FNRTFTPSERVERCMD rtFtpServerHandleRETR;
    235238static FNRTFTPSERVERCMD rtFtpServerHandleRGET;
     239static FNRTFTPSERVERCMD rtFtpServerHandleSIZE;
    236240static FNRTFTPSERVERCMD rtFtpServerHandleSTAT;
    237241static FNRTFTPSERVERCMD rtFtpServerHandleSYST;
     
    269273    { RTFTPSERVER_CMD_RETR,     "RETR",         rtFtpServerHandleRETR },
    270274    { RTFTPSERVER_CMD_RGET,     "RGET",         rtFtpServerHandleRGET },
     275    { RTFTPSERVER_CMD_SIZE,     "SIZE",         rtFtpServerHandleSIZE },
    271276    { RTFTPSERVER_CMD_STAT,     "STAT",         rtFtpServerHandleSTAT },
    272277    { RTFTPSERVER_CMD_SYST,     "SYST",         rtFtpServerHandleSYST },
     
    301306 * @returns VBox status code.
    302307 * @param   pClient             Client to reply to.
    303  * @param   pcszStr             String to reply.
    304  */
    305 static int rtFtpServerSendReplyStr(PRTFTPSERVERCLIENT pClient, const char *pcszStr)
    306 {
    307     char *pszReply;
    308     int rc = RTStrAPrintf(&pszReply, "%s\r\n", pcszStr);
    309     if (RT_SUCCESS(rc))
    310     {
    311         rc = RTTcpWrite(pClient->hSocket, pszReply, strlen(pszReply) + 1);
    312         RTStrFree(pszReply);
    313         return rc;
    314     }
    315 
    316     return VERR_NO_MEMORY;
     308 * @param   pcszFormat          Format to reply.
     309 * @param   ...                 Format arguments.
     310 */
     311static int rtFtpServerSendReplyStr(PRTFTPSERVERCLIENT pClient, const char *pcszFormat, ...)
     312{
     313    va_list args;
     314    va_start(args, pcszFormat);
     315    char *psz = NULL;
     316    const int cch = RTStrAPrintfV(&psz, pcszFormat, args);
     317    va_end(args);
     318    AssertReturn(cch > 0, VERR_NO_MEMORY);
     319
     320    int rc = RTStrAAppend(&psz, "\r\n");
     321    AssertRCReturn(rc, rc);
     322
     323    rc = RTTcpWrite(pClient->hSocket, psz, strlen(psz) + 1 /* Include termination */);
     324
     325    RTStrFree(psz);
     326
     327    return rc;
    317328}
    318329
     
    342353}
    343354
     355/**
     356 * Converts a RTFSOBJINFO struct to a string.
     357 *
     358 * @returns VBox status code.
     359 * @param   pObjInfo            RTFSOBJINFO object to convert.
     360 * @param   pszFsObjInfo        Where to store the output string.
     361 * @param   cbFsObjInfo         Size of the output string in bytes.
     362 */
     363static int rtFtpServerFsObjInfoToStr(PRTFSOBJINFO pObjInfo, char *pszFsObjInfo, size_t cbFsObjInfo)
     364{
     365    RTFMODE fMode = pObjInfo->Attr.fMode;
     366    char chFileType;
     367    switch (fMode & RTFS_TYPE_MASK)
     368    {
     369        case RTFS_TYPE_FIFO:        chFileType = 'f'; break;
     370        case RTFS_TYPE_DEV_CHAR:    chFileType = 'c'; break;
     371        case RTFS_TYPE_DIRECTORY:   chFileType = 'd'; break;
     372        case RTFS_TYPE_DEV_BLOCK:   chFileType = 'b'; break;
     373        case RTFS_TYPE_FILE:        chFileType = '-'; break;
     374        case RTFS_TYPE_SYMLINK:     chFileType = 'l'; break;
     375        case RTFS_TYPE_SOCKET:      chFileType = 's'; break;
     376        case RTFS_TYPE_WHITEOUT:    chFileType = 'w'; break;
     377        default:                    chFileType = '?'; break;
     378    }
     379
     380    char szTimeBirth[RTTIME_STR_LEN];
     381    char szTimeChange[RTTIME_STR_LEN];
     382    char szTimeModification[RTTIME_STR_LEN];
     383    char szTimeAccess[RTTIME_STR_LEN];
     384
     385#define INFO_TO_STR(a_Format, ...) \
     386    do \
     387    { \
     388        const ssize_t cchSize = RTStrPrintf2(szTemp, sizeof(szTemp), a_Format, __VA_ARGS__); \
     389        AssertReturn(cchSize > 0, VERR_BUFFER_OVERFLOW); \
     390        const int rc2 = RTStrCat(pszFsObjInfo, cbFsObjInfo, szTemp); \
     391        AssertRCReturn(rc2, rc2); \
     392    } while (0);
     393
     394    char szTemp[32];
     395
     396    INFO_TO_STR("%c", chFileType);
     397    INFO_TO_STR("%c%c%c",
     398                fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
     399                fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
     400                fMode & RTFS_UNIX_IXUSR ? 'x' : '-');
     401    INFO_TO_STR("%c%c%c",
     402                fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
     403                fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
     404                fMode & RTFS_UNIX_IXGRP ? 'x' : '-');
     405    INFO_TO_STR("%c%c%c",
     406                fMode & RTFS_UNIX_IROTH ? 'r' : '-',
     407                fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
     408                fMode & RTFS_UNIX_IXOTH ? 'x' : '-');
     409
     410    INFO_TO_STR( " %c%c%c%c%c%c%c%c%c%c%c%c%c%c",
     411                fMode & RTFS_DOS_READONLY          ? 'R' : '-',
     412                fMode & RTFS_DOS_HIDDEN            ? 'H' : '-',
     413                fMode & RTFS_DOS_SYSTEM            ? 'S' : '-',
     414                fMode & RTFS_DOS_DIRECTORY         ? 'D' : '-',
     415                fMode & RTFS_DOS_ARCHIVED          ? 'A' : '-',
     416                fMode & RTFS_DOS_NT_DEVICE         ? 'd' : '-',
     417                fMode & RTFS_DOS_NT_NORMAL         ? 'N' : '-',
     418                fMode & RTFS_DOS_NT_TEMPORARY      ? 'T' : '-',
     419                fMode & RTFS_DOS_NT_SPARSE_FILE    ? 'P' : '-',
     420                fMode & RTFS_DOS_NT_REPARSE_POINT  ? 'J' : '-',
     421                fMode & RTFS_DOS_NT_COMPRESSED     ? 'C' : '-',
     422                fMode & RTFS_DOS_NT_OFFLINE        ? 'O' : '-',
     423                fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
     424                fMode & RTFS_DOS_NT_ENCRYPTED      ? 'E' : '-');
     425
     426    INFO_TO_STR( " %d %4d %4d %10lld %10lld",
     427                pObjInfo->Attr.u.Unix.cHardlinks,
     428                pObjInfo->Attr.u.Unix.uid,
     429                pObjInfo->Attr.u.Unix.gid,
     430                pObjInfo->cbObject,
     431                pObjInfo->cbAllocated);
     432
     433    INFO_TO_STR( " %s %s %s %s",
     434                RTTimeSpecToString(&pObjInfo->BirthTime,        szTimeBirth,        sizeof(szTimeBirth)),
     435                RTTimeSpecToString(&pObjInfo->ChangeTime,       szTimeChange,       sizeof(szTimeChange)),
     436                RTTimeSpecToString(&pObjInfo->ModificationTime, szTimeModification, sizeof(szTimeModification)),
     437                RTTimeSpecToString(&pObjInfo->AccessTime,       szTimeAccess,       sizeof(szTimeAccess)) );
     438
     439#undef INFO_TO_STR
     440
     441    return VINF_SUCCESS;
     442}
     443
    344444
    345445/*********************************************************************************************************************************
     
    497597}
    498598
     599static int rtFtpServerHandleSIZE(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
     600{
     601    if (cArgs != 1)
     602        return VERR_INVALID_PARAMETER;
     603
     604    int rc;
     605
     606    const char *pcszPath = apcszArgs[0];
     607    uint64_t uSize = 0;
     608
     609    RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnFileGetSize, pcszPath, &uSize);
     610
     611    if (RT_SUCCESS(rc))
     612    {
     613        rc = rtFtpServerSendReplyStr(pClient, "213 %RU64\r\n", uSize);
     614    }
     615    else
     616    {
     617        int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_REQ_ACTION_NOT_TAKEN);
     618        AssertRC(rc2);
     619    }
     620
     621    return rc;
     622}
     623
    499624static int rtFtpServerHandleSTAT(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs)
    500625{
    501     RT_NOREF(pClient, cArgs, apcszArgs);
    502 
    503     /** @todo Anything to do here? */
    504     return VERR_NOT_IMPLEMENTED;
     626    if (cArgs != 1)
     627        return VERR_INVALID_PARAMETER;
     628
     629    int rc;
     630
     631    RTFSOBJINFO objInfo;
     632    RT_ZERO(objInfo);
     633
     634    const char *pcszPath = apcszArgs[0];
     635
     636    RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnFileStat, pcszPath, &objInfo);
     637
     638    if (RT_SUCCESS(rc))
     639    {
     640        char szFsObjInfo[_4K]; /** @todo Check this size. */
     641        rc = rtFtpServerFsObjInfoToStr(&objInfo, szFsObjInfo, sizeof(szFsObjInfo));
     642        if (RT_SUCCESS(rc))
     643        {
     644            char szFsPathInfo[RTPATH_MAX + 16];
     645            const ssize_t cchPathInfo = RTStrPrintf2(szFsPathInfo, sizeof(szFsPathInfo), " %2zu %s\n", strlen(pcszPath), pcszPath);
     646            if (cchPathInfo > 0)
     647            {
     648                rc = RTStrCat(szFsObjInfo, sizeof(szFsObjInfo), szFsPathInfo);
     649                if (RT_SUCCESS(rc))
     650                    rc = rtFtpServerSendReplyStr(pClient, szFsObjInfo);
     651            }
     652            else
     653                rc = VERR_BUFFER_OVERFLOW;
     654        }
     655    }
     656
     657    if (RT_FAILURE(rc))
     658    {
     659        int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_REQ_ACTION_NOT_TAKEN);
     660        AssertRC(rc2);
     661    }
     662
     663    return rc;
    505664}
    506665
  • trunk/src/VBox/Runtime/tools/RTFTPServer.cpp

    r82715 r82723  
    4848#include <iprt/ctype.h>
    4949#include <iprt/errcore.h>
     50#include <iprt/file.h>
    5051#include <iprt/getopt.h>
    5152#include <iprt/initterm.h>
     
    191192
    192193    return VINF_SUCCESS;
     194}
     195
     196static DECLCALLBACK(int) onFileGetSize(PRTFTPCALLBACKDATA pData, const char *pcszPath, uint64_t *puSize)
     197{
     198    RT_NOREF(pData);
     199
     200    RTPrintf("Retrieving file size for '%s' ...\n", pcszPath);
     201
     202    RTFILE hFile;
     203    int rc = RTFileOpen(&hFile, pcszPath,
     204                        RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     205    if (RT_SUCCESS(rc))
     206    {
     207        rc = RTFileQuerySize(hFile, puSize);
     208        if (RT_SUCCESS(rc))
     209            RTPrintf("File size is: %RU64\n", *puSize);
     210        RTFileClose(hFile);
     211    }
     212
     213    return rc;
     214}
     215
     216static DECLCALLBACK(int) onFileStat(PRTFTPCALLBACKDATA pData, const char *pcszPath, PRTFSOBJINFO pFsObjInfo)
     217{
     218    RT_NOREF(pData);
     219
     220    RTFILE hFile;
     221    int rc = RTFileOpen(&hFile, pcszPath,
     222                        RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     223    if (RT_SUCCESS(rc))
     224    {
     225        rc = RTFileQueryInfo(hFile, pFsObjInfo, RTFSOBJATTRADD_NOTHING);
     226        RTFileClose(hFile);
     227    }
     228
     229    return rc;
    193230}
    194231
     
    337374        Callbacks.pfnOnUserAuthenticate = onUserAuthenticate;
    338375        Callbacks.pfnOnUserDisconnect   = onUserDisonnect;
     376        Callbacks.pfnOnFileGetSize      = onFileGetSize;
     377        Callbacks.pfnOnFileStat         = onFileStat;
    339378        Callbacks.pfnOnPathSetCurrent   = onPathSetCurrent;
    340379        Callbacks.pfnOnPathGetCurrent   = onPathGetCurrent;
    341380        Callbacks.pfnOnPathUp           = onPathUp;
    342         Callbacks.pfnOnList             = onList;
    343381        Callbacks.pfnOnList             = onList;
    344382
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette