VirtualBox

Changeset 99085 in vbox


Ignore:
Timestamp:
Mar 21, 2023 12:15:00 PM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
156450
Message:

Guest Control: Added directory listing support via IDirectory::list(). Added (randomized) testcase support for it. bugref:9783

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/GuestHost/GuestControl.h

    r98824 r99085  
    432432/** GSTCTL_PATH_F_XXX flag valid mask. */
    433433#define GSTCTL_PATH_F_VALID_MASK         UINT32_C(0x00000007)
     434/** @} */
     435
     436/** @name GSTCTL_DIRLIST_F_XXX - Flags for guest directory listings.
     437 * @{ */
     438/** No guest listing flags specified. */
     439#define GSTCTL_DIRLIST_F_NONE               UINT32_C(0)
     440/** GSTCTL_DIRLIST_F_XXX valid mask. */
     441#define GSTCTL_DIRLIST_F_VALID_MASK         UINT32_C(0x00000000)
    434442/** @} */
    435443
     
    553561
    554562/** The maximum size (in bytes) of an entry file name (at least RT_UOFFSETOF(GSTCTLDIRENTRYEX, szName[2]). */
    555 #define GSTCTL_DIRENTRY_MAX_SIZE    4096
    556 
     563#define GSTCTL_DIRENTRY_MAX_SIZE                4096
     564/** Maximum characters of the resolved user name. Including terminator. */
     565#define GSTCTL_DIRENTRY_MAX_USER_NAME           255
     566/** Maximum characters of the resolved user groups list. Including terminator. */
     567#define GSTCTL_DIRENTRY_MAX_USER_GROUPS         _1K
     568/** The resolved user groups delimiter as a string. */
     569#define GSTCTL_DIRENTRY_GROUPS_DELIMITER_STR    "\r\n"
     570
     571/**
     572 * Guest directory entry header.
     573 *
     574 * This is needed for (un-)packing multiple directory entries with its resolved user name + groups
     575 * with the HOST_MSG_DIR_LIST command.
     576 *
     577 * The order of the attributes also mark their packed order, so be careful when changing this!
     578 *
     579 * @since 7.1.
     580 */
     581#pragma pack(1)
     582typedef struct GSTCTLDIRENTRYLISTHDR
     583{
     584    /** Size (in bytes) of the directory header). */
     585    uint32_t          cbDirEntryEx;
     586    /** Size (in bytes) of the resolved user name as a string
     587     *  Includes terminator. */
     588    uint32_t          cbUser;
     589    /** Size (in bytes) of the resolved user groups as a string.
     590     *  Delimited by GSTCTL_DIRENTRY_GROUPS_DELIMITER_STR. Includes terminator. */
     591    uint32_t          cbGroups;
     592} GSTCTLDIRENTRYBLOCK;
     593/** Pointer to a guest directory header entry. */
     594typedef GSTCTLDIRENTRYLISTHDR *PGSTCTLDIRENTRYLISTHDR;
     595#pragma pack()
    557596} /* namespace guestControl */
    558597
  • trunk/include/VBox/HostServices/GuestControlSvc.h

    r98824 r99085  
    232232     */
    233233    HOST_MSG_DIR_CREATE = 314,
     234    /**
     235     * Lists one or multiple directory entries at once.
     236     *
     237     * @since   7.1
     238     */
     239    HOST_MSG_DIR_LIST = 315,
    234240#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
    235241    /**
     
    302308        RT_CASE_RET_STR(HOST_MSG_DIR_REWIND);
    303309        RT_CASE_RET_STR(HOST_MSG_DIR_CREATE);
     310        RT_CASE_RET_STR(HOST_MSG_DIR_LIST);
    304311#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
    305312        RT_CASE_RET_STR(HOST_MSG_DIR_REMOVE);
     
    729736    /** Guest directory was rewind. */
    730737    GUEST_DIR_NOTIFYTYPE_REWIND = 22,
     738    /** Guest directory listing. */
     739    GUEST_DIR_NOTIFYTYPE_LIST = 23,
    731740#endif
    732741    /** Information about an open guest directory. */
     
    10921101    HGCMFunctionParameter flags;
    10931102} HGCMMsgDirCreate;
     1103
     1104/**
     1105 * Lists the entries of a directory on the guest.
     1106 */
     1107typedef struct HGCMMsgDirList
     1108{
     1109    VBGLIOCHGCMCALL hdr;
     1110    /** Context ID. */
     1111    HGCMFunctionParameter context;
     1112    /** Handle of directory listing to list. */
     1113    HGCMFunctionParameter handle;
     1114    /** Number of entries to read at once.
     1115     *  Specify UINT32_MAX to read as much as possible. 0 is not allowed. */
     1116    HGCMFunctionParameter num_entries;
     1117    /** Listing flags (GSTCTL_DIRLIST_F_XXX). */
     1118    HGCMFunctionParameter flags;
     1119} HGCMMsgDirList;
    10941120#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
    10951121
     
    15281554    {
    15291555        /**
    1530          * Parameters used for \a type GUEST_DIR_NOTIFYTYPE_OPEN.
     1556         * Parameters used for \a reply_hdr.type GUEST_DIR_NOTIFYTYPE_OPEN.
    15311557         *
    15321558         * @since 7.1
     
    15381564        } open;
    15391565        /**
    1540          * Parameters used for \a type GUEST_DIR_NOTIFYTYPE_READ.
     1566         * Parameters used for \a reply_hdr.type GUEST_DIR_NOTIFYTYPE_READ.
    15411567         *
    15421568         * @since 7.1
     
    15501576            /** Resolved group IDs as a string.
    15511577             *
    1552              *  Multiple groups are delimited by "\r\n", whereas
     1578             *  Multiple groups are delimited by GSTCTL_DIRENTRY_GROUPS_DELIMITER_STR, whereas
    15531579             *  the first group always is the primary group. */
    15541580            HGCMFunctionParameter groups;
    15551581        } read;
     1582        /**
     1583         * Parameters used for \a reply_hdr.type GUEST_DIR_NOTIFYTYPE_LIST.
     1584         *
     1585         * @since 7.1
     1586         */
     1587        struct
     1588        {
     1589            /** Number of entries in \a buffer. */
     1590            HGCMFunctionParameter num_entries;
     1591            /** Buffer containing the GSTCTLDIRENTRYEX entries, immediately followed
     1592             *  by resolved user + groups as a string (empty strings if not resolved).
     1593             *
     1594             *  Only will be sent if \a num_entries > 0. */
     1595            HGCMFunctionParameter buffer;
     1596        } list;
    15561597    } u;
    15571598} HGCMReplyDirNotify;
     
    15821623            /** Resolved group IDs as a string.
    15831624             *
    1584              *  Multiple groups are delimited by "\r\n", whereas
     1625             *  Multiple groups are delimited by GSTCTL_DIRENTRY_GROUPS_DELIMITER_STR, whereas
    15851626             *  the first group always is the primary group. */
    15861627            HGCMFunctionParameter groups;
  • trunk/include/VBox/VBoxGuestLib.h

    r98824 r99085  
    11221122VBGLR3DECL(int) VbglR3GuestCtrlDirGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
    11231123VBGLR3DECL(int) VbglR3GuestCtrlDirGetRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
     1124VBGLR3DECL(int) VbglR3GuestCtrlDirGetList(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *pcEntries, uint32_t *pfFlags);
    11241125/** @} */
    11251126#  endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
     
    11551156VBGLR3DECL(int) VbglR3GuestCtrlDirCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLDIRENTRYEX pEntry, uint32_t cbSize);
    11561157VBGLR3DECL(int) VbglR3GuestCtrlDirCbRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc);
     1158VBGLR3DECL(int) VbglR3GuestCtrlDirCbList(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cEntries, void *pvBuf, uint32_t cbBuf);
    11571159/** @} */
    11581160#  endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp

    r98824 r99085  
    11291129    return rc;
    11301130}
     1131
     1132
     1133/**
     1134 * Retrieves a HOST_MSG_DIR_LIST message.
     1135 *
     1136 * @returns VBox status code.
     1137 * @param   pCtx                Guest control command context to use.
     1138 * @param   puHandle            Where to return the directory handle to rewind.
     1139 * @param   pcEntries           Where to return the number of directory entries to read.
     1140 * @param   pfFlags             Where to return the directory listing flags.
     1141 */
     1142VBGLR3DECL(int) VbglR3GuestCtrlDirGetList(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *pcEntries, uint32_t *pfFlags)
     1143{
     1144    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1145    AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
     1146
     1147    AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
     1148    AssertPtrReturn(pcEntries, VERR_INVALID_POINTER);
     1149    AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
     1150
     1151    int rc;
     1152    do
     1153    {
     1154        HGCMMsgDirList Msg;
     1155        VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
     1156        VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_LIST);
     1157        VbglHGCMParmUInt32Set(&Msg.handle, 0);
     1158        VbglHGCMParmUInt32Set(&Msg.num_entries, 0);
     1159        VbglHGCMParmUInt32Set(&Msg.flags, 0);
     1160
     1161        rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     1162        if (RT_SUCCESS(rc))
     1163        {
     1164            Msg.context.GetUInt32(&pCtx->uContextID);
     1165            Msg.handle.GetUInt32(puHandle);
     1166            Msg.num_entries.GetUInt32(pcEntries);
     1167            Msg.flags.GetUInt32(pfFlags);
     1168        }
     1169    } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
     1170    return rc;
     1171}
    11311172#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
    11321173
     
    22802321{
    22812322    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    2282     AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
    2283     AssertPtrReturn(pszGroups, VERR_INVALID_POINTER);
    22842323
    22852324    HGCMReplyDirNotify Msg;
     
    23322371
    23332372    return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u));
     2373}
     2374
     2375
     2376/**
     2377 * Replies to a HOST_MSG_DIR_LIST message.
     2378 *
     2379 * @returns VBox status code.
     2380 * @param   pCtx                Guest control command context to use.
     2381 * @param   uRc                 Guest rc of operation (note: IPRT-style signed int).
     2382 * @þaram   cEntries            Number of directory entries to send.
     2383 * @param   pvBuf               Buffer of directory entries to send.
     2384 * @param   cbBuf               Size (in bytes) of \a pvBuf.
     2385 */
     2386VBGLR3DECL(int) VbglR3GuestCtrlDirCbList(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc,
     2387                                         uint32_t cEntries, void *pvBuf, uint32_t cbBuf)
     2388{
     2389    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     2390
     2391    HGCMReplyDirNotify Msg;
     2392    VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_DIR_NOTIFY, GSTCTL_HGCM_REPLY_HDR_PARMS + 2);
     2393    VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
     2394    VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_DIR_NOTIFYTYPE_LIST);
     2395    VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
     2396
     2397    VbglHGCMParmUInt32Set(&Msg.u.list.num_entries, cEntries);
     2398    VbglHGCMParmPtrSet(&Msg.u.list.buffer, pvBuf, cbBuf);
     2399
     2400    return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u.list));
    23342401}
    23352402#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h

    r98824 r99085  
    8787    /** Additional attributes enumeration to use for reading directory entries. */
    8888    GSTCTLFSOBJATTRADD              enmReadAttrAdd;
     89    /** Scratch buffer for holding the directory reading entry.
     90     *  Currently NOT serialized, i.e. only can be used for one read at a time. */
     91    PRTDIRENTRYEX                   pDirEntryEx;
     92    /** Size (in bytes) of \a pDirEntryEx. */
     93    size_t                          cbDirEntryEx;
    8994} VBOXSERVICECTRLDIR;
    9095/** Pointer to a guest directory. */
     
    233238    /** The gid cache for this session. */
    234239    VGSVCIDCACHE                    GidCache;
    235     /** Scratch buffer for holding the directory reading entry.
    236      *  Currently NOT serialized, i.e. only can be used for one read at a time. */
    237     PRTDIRENTRYEX                   pDirEntryEx;
    238     /** Size (in bytes) of \a pDirEntryEx. */
    239     size_t                          cbDirEntryEx;
    240240#endif
    241241} VBOXSERVICECTRLSESSION;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r98831 r99085  
    113113    if (!pDir)
    114114        return VINF_SUCCESS;
     115
     116    RTMemFree(pDir->pDirEntryEx);
    115117
    116118    int rc;
     
    10381040            pDir->enmReadAttrAdd = enmAttrAdd;
    10391041
     1042            pDir->cbDirEntryEx = GSTCTL_DIRENTRY_MAX_SIZE;
     1043            pDir->pDirEntryEx  = (PRTDIRENTRYEX)RTMemAlloc(pDir->cbDirEntryEx);
     1044            AssertPtrReturn(pDir->pDirEntryEx, VERR_NO_MEMORY);
     1045
    10401046            if (RT_SUCCESS(rc))
    10411047            {
     
    11341140
    11351141
     1142/**
     1143 * Worker function for reading a next guest directory entry.
     1144 *
     1145 * @returns VBox status code.
     1146 * @param   pSession            Guest Control session to use.
     1147 * @param   pDir                Guest directory to read the next entry for.
     1148 * @param   ppDirEntryEx        Where to store the pointer to the next guest directory entry on success.
     1149 * @param   pcbDirEntryEx       Where to return the size (in bytes) of \a ppGstCtlDirEntryEx on success.
     1150 * @param   ppszUser            Where to return the resolved user name string.
     1151 * @param   ppszGroups          Where to return the resolved groups string.
     1152 */
     1153static int vgsvcGstCtrlSessionDirReadNext(const PVBOXSERVICECTRLSESSION pSession,
     1154                                          PVBOXSERVICECTRLDIR pDir,
     1155                                          PGSTCTLDIRENTRYEX *ppDirEntryEx, size_t *pcbDirEntryEx,
     1156                                          const char **ppszUser, const char **ppszGroups)
     1157{
     1158    PRTDIRENTRYEX pDirEntryEx = pDir->pDirEntryEx;
     1159
     1160    size_t cbDirEntryEx = pDir->cbDirEntryEx;
     1161    int rc = RTDirReadEx(pDir->hDir, pDir->pDirEntryEx, &cbDirEntryEx, (RTFSOBJATTRADD)pDir->enmReadAttrAdd, pDir->fRead);
     1162
     1163    VGSvcVerbose(2, "[Dir %s] Read next entry '%s' -> %Rrc (%zu bytes)\n",
     1164                 pDir->pszPathAbs, RT_SUCCESS(rc) ? pDirEntryEx->szName : "<None>", rc, cbDirEntryEx);
     1165
     1166    if (RT_FAILURE(rc))
     1167        return rc;
     1168
     1169    /* Paranoia. */
     1170    AssertReturn(cbDirEntryEx <= pDir->cbDirEntryEx, VERR_BUFFER_OVERFLOW);
     1171
     1172    *ppszUser   = VGSvcIdCacheGetUidName(&pSession->UidCache,
     1173                                         pDirEntryEx->Info.Attr.u.Unix.uid, pDirEntryEx->szName, pDir->pszPathAbs);
     1174    *ppszGroups = VGSvcIdCacheGetGidName(&pSession->GidCache,
     1175                                         pDirEntryEx->Info.Attr.u.Unix.gid, pDirEntryEx->szName, pDir->pszPathAbs);
     1176
     1177    VGSvcVerbose(2, "[Dir %s] Entry '%s': %zu bytes, uid=%s (%d), gid=%s (%d)\n",
     1178                 pDir->pszPathAbs, pDirEntryEx->szName, pDirEntryEx->Info.cbObject,
     1179                 *ppszUser, pDirEntryEx->Info.Attr.u.UnixOwner.uid,
     1180                 *ppszGroups, pDirEntryEx->Info.Attr.u.UnixGroup.gid);
     1181
     1182    /*
     1183     * For now we ASSUME that RTDIRENTRYEX == GSTCTLDIRENTRYEX, which implies that we simply can cast RTDIRENTRYEX
     1184     * to GSTCTLDIRENTRYEX. This might change in the future, however, so be extra cautious here.
     1185     *
     1186     * Ditto for RTFSOBJATTRADD == GSTCTLFSOBJATTRADD.
     1187     */
     1188    AssertCompile(sizeof(GSTCTLDIRENTRYEX)              == sizeof(RTDIRENTRYEX));
     1189    AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, Info)   == RT_OFFSETOF(RTDIRENTRYEX, Info));
     1190    AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, cbName) == RT_OFFSETOF(RTDIRENTRYEX, cbName));
     1191    AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, szName) == RT_OFFSETOF(RTDIRENTRYEX, szName));
     1192    AssertCompile(RT_OFFSETOF(GSTCTLFSOBJINFO,  Attr)   == RT_OFFSETOF(RTFSOBJINFO,  Attr));
     1193
     1194    if (RT_SUCCESS(rc))
     1195    {
     1196        *ppDirEntryEx  = (PGSTCTLDIRENTRYEX)pDirEntryEx;
     1197        *pcbDirEntryEx = cbDirEntryEx;
     1198    }
     1199
     1200    return rc;
     1201}
     1202
     1203
    11361204static int vgsvcGstCtrlSessionHandleDirRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
    11371205{
     
    11491217        if (pDir)
    11501218        {
    1151             PRTDIRENTRYEX pDirEntryEx = pSession->pDirEntryEx;
    1152 
    1153             size_t cbDirEntry = pSession->cbDirEntryEx;
    1154             rc = RTDirReadEx(pDir->hDir, pDirEntryEx, &cbDirEntry, (RTFSOBJATTRADD)pDir->enmReadAttrAdd, pDir->fRead);
    1155 
    1156             /* Paranoia. */
    1157             AssertStmt(cbDirEntry <= pSession->cbDirEntryEx, rc = VERR_BUFFER_OVERFLOW);
    1158 
    1159             VGSvcVerbose(2, "[Dir %s] Read next entry '%s' -> %Rrc (%zu bytes)\n",
    1160                          pDir->pszPathAbs, RT_SUCCESS(rc) ? pDirEntryEx->szName : "<None>", rc, cbDirEntry);
    1161 
    1162             const char *pszUser  = VGSvcIdCacheGetUidName(&pSession->UidCache,
    1163                                                           pDirEntryEx->Info.Attr.u.Unix.uid, pDirEntryEx->szName, pDir->pszPathAbs);
    1164             const char *pszGroup = VGSvcIdCacheGetGidName(&pSession->GidCache,
    1165                                                           pDirEntryEx->Info.Attr.u.Unix.gid, pDirEntryEx->szName, pDir->pszPathAbs);
    1166 
    1167             VGSvcVerbose(2, "[Dir %s] Entry '%s': %zu bytes, uid=%s (%d), gid=%s (%d)\n",
    1168                          pDir->pszPathAbs, pDirEntryEx->szName, pDirEntryEx->Info.cbObject,
    1169                          pszUser ? pszUser : "", pDirEntryEx->Info.Attr.u.UnixOwner.uid,
    1170                          pszGroup ? pszGroup : "", pDirEntryEx->Info.Attr.u.UnixGroup.gid);
    1171 
    1172             /*
    1173              * For now we ASSUME that RTDIRENTRYEX == GSTCTLDIRENTRYEX, which implies that we simply can cast RTDIRENTRYEX
    1174              * to GSTCTLDIRENTRYEX. This might change in the future, however, so be extra cautious here.
    1175              *
    1176              * Ditto for RTFSOBJATTRADD == GSTCTLFSOBJATTRADD.
    1177              */
    1178             AssertCompile(sizeof(GSTCTLDIRENTRYEX)              == sizeof(RTDIRENTRYEX));
    1179             AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, Info)   == RT_OFFSETOF(RTDIRENTRYEX, Info));
    1180             AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, cbName) == RT_OFFSETOF(RTDIRENTRYEX, cbName));
    1181             AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, szName) == RT_OFFSETOF(RTDIRENTRYEX, szName));
    1182             AssertCompile(RT_OFFSETOF(GSTCTLFSOBJINFO,  Attr)   == RT_OFFSETOF(RTFSOBJINFO,  Attr));
    1183 
    1184             PGSTCTLDIRENTRYEX pGstCtlDirEntryEx = (PGSTCTLDIRENTRYEX)pDirEntryEx;
    1185 
    1186             int rc2 = VbglR3GuestCtrlDirCbReadEx(pHostCtx, rc, pGstCtlDirEntryEx, (uint32_t)cbDirEntry, pszUser, pszGroup);
     1219            PGSTCTLDIRENTRYEX pDirEntryEx;
     1220            size_t            cbDirEntryEx;
     1221            const char       *pszUser   = NULL;
     1222            const char       *pszGroups = NULL;
     1223            rc = vgsvcGstCtrlSessionDirReadNext(pSession, pDir,
     1224                                                &pDirEntryEx, &cbDirEntryEx, &pszUser, &pszGroups);
     1225
     1226            VGSvcVerbose(2, "[Dir %s] %Rrc\n", pDir->pszPathAbs, rc);
     1227
     1228            int rc2;
     1229            if (RT_SUCCESS(rc))
     1230                rc2 = VbglR3GuestCtrlDirCbReadEx(pHostCtx, rc, pDirEntryEx, cbDirEntryEx, pszUser, pszGroups);
     1231            else
     1232                rc2 = VbglR3GuestCtrlDirCbRead(pHostCtx, rc, NULL /* pEntry */, 0 /* cbSize */);
    11871233            if (RT_FAILURE(rc2))
    11881234                VGSvcError("Failed to report directory read status (%Rrc), rc=%Rrc\n", rc, rc2);
     1235
     1236            VGSvcVerbose(2, "[Dir %s] 2 %Rrc\n", pDir->pszPathAbs, rc);
    11891237
    11901238            if (rc == VERR_NO_MORE_FILES) /* Directory reading done. */
     
    13081356    }
    13091357    VGSvcVerbose(5, "Creating directory returned rc=%Rrc\n", rc);
     1358    return rc;
     1359}
     1360
     1361static int vgsvcGstCtrlSessionHandleDirList(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
     1362{
     1363    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1364    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     1365
     1366    /*
     1367     * Retrieve the request.
     1368     */
     1369    uint32_t uHandle;
     1370    uint32_t cEntries;
     1371    uint32_t cEntriesRead = 0;
     1372    uint32_t fFlags;
     1373    int rc = VbglR3GuestCtrlDirGetList(pHostCtx, &uHandle, &cEntries, &fFlags);
     1374    if (RT_SUCCESS(rc))
     1375    {
     1376        size_t cbGrowSize = _64K;
     1377        void  *pvBuf      = RTMemAlloc(cbGrowSize);
     1378        if (!pvBuf)
     1379            rc = VERR_NO_MEMORY;
     1380        size_t cbBufUsed  = 0;
     1381        if (RT_SUCCESS(rc))
     1382        {
     1383            if (!(fFlags & ~GSTCTL_DIRLIST_F_VALID_MASK))
     1384            {
     1385                size_t cbBufSize = cbGrowSize;
     1386
     1387                PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
     1388                if (pDir)
     1389                {
     1390                    PGSTCTLDIRENTRYEX pDirEntryEx;
     1391                    size_t            cbDirEntryEx;
     1392                    const char       *pszUser   = NULL;
     1393                    const char       *pszGroups = NULL;
     1394
     1395                    while (cEntries--)
     1396                    {
     1397                        rc = vgsvcGstCtrlSessionDirReadNext(pSession, pDir,
     1398                                                            &pDirEntryEx, &cbDirEntryEx, &pszUser, &pszGroups);
     1399                        if (RT_FAILURE(rc)) /* Might be VERR_NO_MORE_FILES. */
     1400                            break;
     1401
     1402                        size_t const cbHdr    = sizeof(GSTCTLDIRENTRYLISTHDR);
     1403                        size_t const cbUser   = strlen(pszUser)   + 1; /* Include terminator. */
     1404                        size_t const cbGroups = strlen(pszGroups) + 1; /* Ditto. */
     1405                        size_t const cbTotal  = cbHdr + cbDirEntryEx + cbUser + cbGroups;
     1406
     1407                        if (cbBufSize - cbBufUsed < cbTotal) /* Grow buffer, if needed. */
     1408                        {
     1409                            AssertBreakStmt(cbTotal <= cbGrowSize, VERR_BUFFER_OVERFLOW);
     1410                            pvBuf      = RTMemRealloc(pvBuf, cbBufSize + cbGrowSize);
     1411                            AssertPtrBreakStmt(pvBuf, VERR_NO_MEMORY);
     1412                            cbBufSize += cbGrowSize;
     1413                        }
     1414
     1415                        GSTCTLDIRENTRYLISTHDR Hdr;
     1416                        Hdr.cbDirEntryEx = cbDirEntryEx;
     1417                        Hdr.cbUser       = cbUser;
     1418                        Hdr.cbGroups     = cbGroups;
     1419
     1420                        memcpy((uint8_t *)pvBuf + cbBufUsed, &Hdr, cbHdr);
     1421                        cbBufUsed += cbHdr;
     1422                        memcpy((uint8_t *)pvBuf + cbBufUsed, pDirEntryEx, cbDirEntryEx);
     1423                        cbBufUsed += cbDirEntryEx;
     1424                        memcpy((uint8_t *)pvBuf + cbBufUsed, pszUser, cbUser);
     1425                        cbBufUsed += cbUser;
     1426                        memcpy((uint8_t *)pvBuf + cbBufUsed, pszGroups, cbGroups);
     1427                        cbBufUsed += cbGroups;
     1428
     1429                        Assert(cbBufUsed <= cbBufSize);
     1430                        cEntriesRead++;
     1431                    }
     1432
     1433                    vgsvcGstCtrlSessionDirRelease(pDir);
     1434                }
     1435
     1436                VGSvcVerbose(4, "Read %RU32 directory entries (requested %RU32 entries) -> %zu bytes, rc=%Rrc\n",
     1437                             cEntriesRead, cEntries, cbBufUsed, rc);
     1438
     1439                /* Directory reading done? */
     1440                if (   cEntriesRead
     1441                    && rc == VERR_NO_MORE_FILES)
     1442                    rc = VINF_SUCCESS;
     1443
     1444                /* Note: Subsequent calls will return VERR_NO_MORE_FILES to the host. */
     1445            }
     1446            else
     1447            {
     1448                VGSvcError("Unsupported directory listing flags: %#x (all %#x)\n", (fFlags & ~GSTCTL_DIRLIST_F_VALID_MASK), fFlags);
     1449                rc = VERR_NOT_SUPPORTED;
     1450            }
     1451        }
     1452
     1453        /*
     1454         * Report result back to host.
     1455         */
     1456        int rc2 = VbglR3GuestCtrlDirCbList(pHostCtx, rc, cEntriesRead, pvBuf, (uint32_t)cbBufUsed);
     1457        if (RT_FAILURE(rc2))
     1458            VGSvcError("Failed to report directory listing (%Rrc), rc=%Rrc\n", rc, rc2);
     1459
     1460        if (rc == VERR_NO_MORE_FILES) /* Directory reading done? */
     1461            rc = VINF_SUCCESS;
     1462
     1463        RTMemFree(pvBuf);
     1464    }
     1465    else
     1466    {
     1467        VGSvcError("Error fetching parameters for directory listing operation: %Rrc\n", rc);
     1468        VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
     1469    }
     1470    VGSvcVerbose(5, "Listing directory returned rc=%Rrc\n", rc);
    13101471    return rc;
    13111472}
     
    21232284                rc = vgsvcGstCtrlSessionHandleDirCreate(pSession, pHostCtx);
    21242285            break;
     2286
     2287        case HOST_MSG_DIR_LIST:
     2288            if (fImpersonated)
     2289                rc = vgsvcGstCtrlSessionHandleDirList(pSession, pHostCtx);
     2290            break;
    21252291#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
    21262292
     
    27262892    int rc = VGSvcGstCtrlSessionClose(pSession);
    27272893
    2728 #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
    2729     RTMemFree(pSession->pDirEntryEx);
    2730 #endif
    2731 
    27322894    /* Destroy critical section. */
    27332895    RTCritSectDelete(&pSession->CritSect);
     
    27552917    RT_ZERO(pSession->UidCache);
    27562918    RT_ZERO(pSession->GidCache);
    2757 
    2758     pSession->cbDirEntryEx = GSTCTL_DIRENTRY_MAX_SIZE;
    2759     pSession->pDirEntryEx  = (PRTDIRENTRYEX)RTMemAlloc(pSession->cbDirEntryEx);
    2760     AssertPtrReturn(pSession->pDirEntryEx, VERR_NO_MEMORY);
    27612919#endif
    27622920
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r98964 r99085  
    1642516425  <interface
    1642616426    name="IDirectory" extends="$unknown"
    16427     uuid="c7b24ad6-dba7-486c-b1ed-5f16d8d6da22"
     16427    uuid="a508e094-bf24-4eca-80c6-467766a1e4c0"
    1642816428    wsmap="managed"
    1642916429    reservedMethods="4" reservedAttributes="8"
     
    1646416464        directory entry will not be possible anymore.
    1646516465      </desc>
     16466    </method>
     16467
     16468    <method name="list">
     16469      <desc>
     16470        Lists directory entries of this directory.
     16471        <result name="VBOX_E_OBJECT_NOT_FOUND">
     16472          No more directory entries to read.
     16473        </result>
     16474      </desc>
     16475      <param name="maxEntries" type="unsigned long" dir="in">
     16476        <desc>Maximum entries to return per call. The guest might decide to return less than the given maximum, depending on
     16477          the guest OS.</desc>
     16478      </param>
     16479      <param name="objInfo" type="IFsObjInfo" safearray="yes" dir="return">
     16480        <desc>Array of object information of the current directory entry read. Also see
     16481          <link to="IFsObjInfo"/>.</desc>
     16482      </param>
    1646616483    </method>
    1646716484
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r99011 r99085  
    14571457
    14581458
    1459 /*******************************************************************************
    1460 * Callback data structures.                                                    *
    1461 *                                                                              *
    1462 * These structures make up the actual low level HGCM callback data sent from   *
    1463 * the guest back to the host.                                                  *
    1464 *******************************************************************************/
     1459/*********************************************************************************************************************************
     1460 * Callback data structures.                                                                                                     *
     1461 *                                                                                                                               *
     1462 * These structures make up the actual low level HGCM callback data sent from                                                    *
     1463 * the guest back to the host.                                                                                                   *
     1464 ********************************************************************************************************************************/
    14651465
    14661466/**
     
    16361636
    16371637/**
     1638 * Callback data for a single GSTCTLDIRENTRYEX entry.
     1639 */
     1640typedef struct CALLBACKDATA_DIR_ENTRY
     1641{
     1642    /** Pointer to directory entry information. */
     1643    PGSTCTLDIRENTRYEX pDirEntryEx;
     1644    /** Size (in bytes) of directory entry information. */
     1645    uint32_t          cbDirEntryEx;
     1646    /** Resolved user name.
     1647     *  This is the object owner for UNIX-y Oses. */
     1648    char             *pszUser;
     1649    /** Size (in bytes) of \a pszUser. */
     1650    uint32_t          cbUser;
     1651    /** Resolved user group(s). */
     1652    char             *pszGroups;
     1653    /** Size (in bytes) of \a pszGroups. */
     1654    uint32_t          cbGroups;
     1655} CALLBACKDATA_DIR_ENTRY;
     1656/** Pointer to a CALLBACKDATA_DIR_ENTRY struct. */
     1657typedef CALLBACKDATA_DIR_ENTRY *PCALLBACKDATA_DIR_ENTRY;
     1658
     1659/**
    16381660 * Callback data for guest directory operations.
    16391661 */
     
    16611683        struct
    16621684        {
    1663             /** Pointer to directory entry information. */
    1664             PGSTCTLDIRENTRYEX pEntry;
    1665             /** Size (in bytes) of directory entry information. */
    1666             uint32_t          cbEntry;
    1667             /** Resolved user name.
    1668              *  This is the object owner for UNIX-y Oses. */
    1669             char             *pszUser;
    1670             /** Size (in bytes) of \a pszUser. */
    1671             uint32_t          cbUser;
    1672             /** Resolved user group(s). */
    1673             char             *pszGroups;
    1674             /** Size (in bytes) of \a pszGroups. */
    1675             uint32_t          cbGroups;
     1685            /** Single entry read. */
     1686            CALLBACKDATA_DIR_ENTRY Entry;
    16761687        } read;
     1688        struct
     1689        {
     1690            /** Number of entries in \a paEntries. */
     1691            uint32_t                 cEntries;
     1692            /** Array of entries read. */
     1693            CALLBACKDATA_DIR_ENTRY **paEntries;
     1694        } list;
    16771695    } u;
    16781696} CALLBACKDATA_DIR_NOTIFY;
  • trunk/src/VBox/Main/include/GuestDirectoryImpl.h

    r98709 r99085  
    7272    EventSource   *i_getEventSource(void) { return mEventSource; }
    7373    int            i_onDirNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     74    int            i_listInternal(uint32_t cMaxEntries, uint32_t fFlags, std::vector<GuestFsObjData> &vecObjData, int *pvrcGuest);
     75    int            i_listEx(uint32_t cMaxEntries, uint32_t fFlags, std::vector<ComObjPtr<GuestFsObjInfo>> &vecObjInfo, int *pvrcGuest);
     76    int            i_list(uint32_t cMaxEntries, std::vector<ComObjPtr<GuestFsObjInfo>> &vecObjInfo, int *pvrcGuest);
    7477    int            i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *pvrcGuest);
    7578    int            i_readInternal(GuestFsObjData &objData, int *pvrcGuest);
     
    8992     * @{ */
    9093    static Utf8Str i_guestErrorToString(int vrcGuest, const char *pcszWhat);
     94    static void    i_dirNotifyDataDestroy(PCALLBACKDATA_DIR_NOTIFY pDirNotify);
    9195    /** @}  */
    9296
     
    105109    HRESULT getId(ULONG *aId);
    106110    HRESULT getStatus(DirectoryStatus_T *aStatus);
     111    HRESULT list(ULONG aMaxEntries, std::vector<ComPtr<IFsObjInfo> > &aObjInfos);
    107112    HRESULT read(ComPtr<IFsObjInfo> &aObjInfo);
    108113    HRESULT rewind(void);
  • trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp

    r99073 r99085  
    467467    HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
    468468
    469     int vrcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
     469    int const vrcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
    470470
    471471    LogFlowThisFunc(("uType=%RU32, vrcGuest=%Rrc\n", dataCb.uType, vrcGuest));
     
    523523                                        ("type=%u\n", pSvcCbData->mpaParms[idx].type),
    524524                                        vrc = VERR_WRONG_PARAMETER_TYPE);
    525             PGSTCTLDIRENTRYEX pEntry;
    526             uint32_t          cbEntry;
    527             vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], (void **)&pEntry, &cbEntry);
     525            PGSTCTLDIRENTRYEX pDirEntryEx;
     526            uint32_t          cbDirEntryEx;
     527            vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], (void **)&pDirEntryEx, &cbDirEntryEx);
    528528            AssertRCBreak(vrc);
    529             AssertBreakStmt(   cbEntry >= RT_UOFFSETOF(GSTCTLDIRENTRYEX, szName[2])
    530                             && cbEntry <= GSTCTL_DIRENTRY_MAX_SIZE, VERR_INVALID_PARAMETER);
    531             dataCb.u.read.pEntry  = (PGSTCTLDIRENTRYEX)RTMemDup(pEntry, cbEntry);
    532             AssertPtrBreakStmt(dataCb.u.read.pEntry, vrc = VERR_NO_MEMORY);
    533             dataCb.u.read.cbEntry = cbEntry;
     529            AssertBreakStmt(   cbDirEntryEx >= RT_UOFFSETOF(GSTCTLDIRENTRYEX, szName[2])
     530                            && cbDirEntryEx <= GSTCTL_DIRENTRY_MAX_SIZE, vrc = VERR_INVALID_PARAMETER);
     531            dataCb.u.read.Entry.pDirEntryEx  = (PGSTCTLDIRENTRYEX)RTMemDup(pDirEntryEx, cbDirEntryEx);
     532            AssertPtrBreakStmt(dataCb.u.read.Entry.pDirEntryEx, vrc = VERR_NO_MEMORY);
     533            dataCb.u.read.Entry.cbDirEntryEx = cbDirEntryEx;
    534534
    535535            char    *pszUser;
     
    537537            vrc = HGCMSvcGetStr(&pSvcCbData->mpaParms[idx++], &pszUser, &cbUser);
    538538            AssertRCBreak(vrc);
    539             dataCb.u.read.pszUser = RTStrDup(pszUser);
    540             AssertPtrBreakStmt(dataCb.u.read.pszUser, vrc = VERR_NO_MEMORY);
    541             dataCb.u.read.cbUser  = cbUser;
     539            AssertBreakStmt(cbUser <= GSTCTL_DIRENTRY_MAX_USER_NAME, vrc = VERR_TOO_MUCH_DATA);
     540            dataCb.u.read.Entry.pszUser = RTStrDup(pszUser);
     541            AssertPtrBreakStmt(dataCb.u.read.Entry.pszUser, vrc = VERR_NO_MEMORY);
     542            dataCb.u.read.Entry.cbUser  = cbUser;
    542543
    543544            char    *pszGroups;
     
    545546            vrc = HGCMSvcGetStr(&pSvcCbData->mpaParms[idx++], &pszGroups, &cbGroups);
    546547            AssertRCBreak(vrc);
    547             dataCb.u.read.pszGroups = RTStrDup(pszGroups);
    548             AssertPtrBreakStmt(dataCb.u.read.pszGroups, vrc = VERR_NO_MEMORY);
    549             dataCb.u.read.cbGroups  = cbGroups;
     548            AssertBreakStmt(cbGroups <= GSTCTL_DIRENTRY_MAX_USER_GROUPS, vrc = VERR_TOO_MUCH_DATA);
     549            dataCb.u.read.Entry.pszGroups = RTStrDup(pszGroups);
     550            AssertPtrBreakStmt(dataCb.u.read.Entry.pszGroups, vrc = VERR_NO_MEMORY);
     551            dataCb.u.read.Entry.cbGroups  = cbGroups;
    550552
    551553            /** @todo ACLs not implemented yet. */
    552554
    553             GuestFsObjData fsObjData(dataCb.u.read.pEntry->szName);
    554             vrc = fsObjData.FromGuestFsObjInfo(&dataCb.u.read.pEntry->Info);
     555            GuestFsObjData fsObjData(dataCb.u.read.Entry.pDirEntryEx->szName);
     556            vrc = fsObjData.FromGuestFsObjInfo(&dataCb.u.read.Entry.pDirEntryEx->Info);
    555557            AssertRCBreak(vrc);
    556558            ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
     
    561563
    562564            ::FireGuestDirectoryReadEvent(mEventSource, mSession, this,
    563                                           dataCb.u.read.pEntry->szName, ptrFsObjInfo, dataCb.u.read.pszUser, dataCb.u.read.pszGroups);
     565                                          dataCb.u.read.Entry.pDirEntryEx->szName, ptrFsObjInfo,
     566                                          dataCb.u.read.Entry.pszUser, dataCb.u.read.Entry.pszGroups);
    564567            break;
    565568        }
     
    569572            /* Note: This does not change the overall status of the directory (i.e. open). */
    570573            ::FireGuestDirectoryStateChangedEvent(mEventSource, mSession, this, DirectoryStatus_Rewind, errorInfo);
     574            break;
     575        }
     576
     577        case GUEST_DIR_NOTIFYTYPE_LIST:
     578        {
     579            ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms >= 4, ("mParms=%u\n", pSvcCbData->mParms),
     580                                        vrc = VERR_WRONG_PARAMETER_COUNT);
     581            ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_32BIT,
     582                                        ("type=%u\n", pSvcCbData->mpaParms[idx].type),
     583                                        vrc = VERR_WRONG_PARAMETER_TYPE);
     584
     585            vrc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.list.cEntries);
     586            AssertRCBreak(vrc);
     587            /* We limit this for now to 64K entries max per call.
     588             * The guest does not do this check, so we could de/increase this limit in the future. */
     589            AssertBreakStmt(dataCb.u.list.cEntries <= _64K, vrc = VERR_TOO_MUCH_DATA);
     590
     591            if (!dataCb.u.list.cEntries) /* No entries sent? Bail out early. */
     592                break;
     593
     594            /*
     595             * Fetch buffer with packed directory entries.
     596             */
     597            ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 5, ("mParms=%u\n", pSvcCbData->mParms),
     598                                        vrc = VERR_WRONG_PARAMETER_COUNT);
     599            ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
     600                                        ("type=%u\n", pSvcCbData->mpaParms[idx].type),
     601                                        vrc = VERR_WRONG_PARAMETER_TYPE);
     602            void    *pvBuf;
     603            uint32_t cbBuf;
     604            vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx], &pvBuf, &cbBuf);
     605            AssertRCBreak(vrc);
     606            AssertBreakStmt(cbBuf >= sizeof(GSTCTLDIRENTRYEX), vrc = VERR_INVALID_PARAMETER);
     607            dataCb.u.list.paEntries = (PCALLBACKDATA_DIR_ENTRY *)RTMemAllocZ(dataCb.u.list.cEntries * sizeof(PCALLBACKDATA_DIR_ENTRY));
     608            AssertPtrBreakStmt(dataCb.u.list.paEntries, vrc = VERR_NO_MEMORY);
     609
     610            /*
     611             * Unpack directory entries.
     612             */
     613            size_t offBuf = 0;
     614            for (uint32_t i = 0; i < dataCb.u.list.cEntries; i++)
     615            {
     616                dataCb.u.list.paEntries[i] = (PCALLBACKDATA_DIR_ENTRY)RTMemAlloc(sizeof(CALLBACKDATA_DIR_ENTRY));
     617                AssertPtrBreakStmt(dataCb.u.list.paEntries[i], vrc = VERR_NO_MEMORY);
     618
     619                PCALLBACKDATA_DIR_ENTRY pEntry = dataCb.u.list.paEntries[i];
     620
     621                PGSTCTLDIRENTRYLISTHDR  const pHdr   = (PGSTCTLDIRENTRYLISTHDR)((uint8_t *)pvBuf + offBuf);
     622                AssertBreakStmt(pHdr->cbDirEntryEx <= GSTCTL_DIRENTRY_MAX_SIZE, vrc = VERR_TOO_MUCH_DATA);
     623                AssertBreakStmt(pHdr->cbUser <= GSTCTL_DIRENTRY_MAX_USER_NAME, vrc = VERR_TOO_MUCH_DATA);
     624                AssertBreakStmt(pHdr->cbGroups <= GSTCTL_DIRENTRY_MAX_USER_GROUPS, vrc = VERR_TOO_MUCH_DATA);
     625                offBuf += sizeof(GSTCTLDIRENTRYLISTHDR);
     626
     627                AssertBreakStmt(   pHdr->cbDirEntryEx >= RT_UOFFSETOF(GSTCTLDIRENTRYEX, szName[2])
     628                                && pHdr->cbDirEntryEx <= GSTCTL_DIRENTRY_MAX_SIZE, vrc = VERR_INVALID_PARAMETER);
     629                pEntry->pDirEntryEx  = (PGSTCTLDIRENTRYEX)RTMemDup((uint8_t *)pvBuf + offBuf, pHdr->cbDirEntryEx);
     630                AssertPtrBreakStmt(pEntry->pDirEntryEx, vrc = VERR_NO_MEMORY);
     631                pEntry->cbDirEntryEx = pHdr->cbDirEntryEx;
     632                offBuf += pHdr->cbDirEntryEx;
     633
     634                if (pHdr->cbUser)
     635                {
     636                    pEntry->pszUser = (char *)RTMemDup((uint8_t *)pvBuf + offBuf, pHdr->cbUser);
     637                    AssertPtrBreakStmt(pEntry->pszUser, vrc = VERR_NO_MEMORY);
     638                    pEntry->cbUser  = pHdr->cbUser;
     639                    offBuf += pHdr->cbUser;
     640                }
     641
     642                if (pHdr->cbGroups)
     643                {
     644                    pEntry->pszGroups = (char *)RTMemDup((uint8_t *)pvBuf + offBuf, pHdr->cbGroups);
     645                    AssertPtrBreakStmt(pEntry->pszGroups, vrc = VERR_NO_MEMORY);
     646                    pEntry->cbGroups  = pHdr->cbGroups;
     647                    offBuf += pHdr->cbGroups;
     648                }
     649
     650#ifdef DEBUG
     651                GuestFsObjData obj;
     652                AssertRC(obj.FromGuestFsObjInfo(&pEntry->pDirEntryEx->Info, pEntry->pszUser, pEntry->pszGroups));
     653                AssertRC(RTStrValidateEncodingEx(pEntry->pszUser,   pHdr->cbUser,   RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED));
     654                AssertRC(RTStrValidateEncodingEx(pEntry->pszGroups, pHdr->cbGroups, RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED));
     655#endif
     656            }
     657
     658            if (RT_SUCCESS(vrc))
     659            {
     660                Assert(offBuf == cbBuf);
     661            }
     662            else /* Roll back on error. */
     663            {
     664               GuestDirectory::i_dirNotifyDataDestroy(&dataCb);
     665            }
    571666            break;
    572667        }
     
    606701
    607702/**
    608  * Converts a given guest directory error to a string.
     703 * Static helper function to convert a given guest directory error to a string.
    609704 *
    610705 * @returns Error string.
     
    627722        CASE_MSG(VERR_CANT_CREATE,    tr("Guest directory \"%s\" cannot be created"), pcszWhat);
    628723        CASE_MSG(VERR_DIR_NOT_EMPTY,  tr("Guest directory \"%s\" is not empty"), pcszWhat);
     724        CASE_MSG(VERR_NO_MORE_FILES,  tr("Guest directory \"%s\" has no more entries"), pcszWhat);
     725        CASE_MSG(VERR_PATH_NOT_FOUND, tr("Path of guest directory \"%s\" not found"), pcszWhat);
    629726        default:
    630727            strErr.printf(tr("Error %Rrc for guest directory \"%s\" occurred\n"), vrcGuest, pcszWhat);
     
    635732
    636733    return strErr;
     734}
     735
     736/**
     737 * Static helper function to destroy direction notification callback data.
     738 *
     739 * @param   pDirNotify          Pointer to direction notification callback data to destroy.
     740 */
     741/* static */
     742void GuestDirectory::i_dirNotifyDataDestroy(PCALLBACKDATA_DIR_NOTIFY pDirNotify)
     743{
     744    if (!pDirNotify)
     745        return;
     746
     747    switch (pDirNotify->uType)
     748    {
     749        case GUEST_DIR_NOTIFYTYPE_LIST:
     750        {
     751            for (uint32_t i = 0; i < pDirNotify->u.list.cEntries; i++)
     752            {
     753                PCALLBACKDATA_DIR_ENTRY const pEntry = pDirNotify->u.list.paEntries[i];
     754                AssertPtrBreak(pEntry);
     755                RTStrFree(pEntry->pszUser);
     756                RTStrFree(pEntry->pszGroups);
     757                RTMemFree(pEntry->pDirEntryEx);
     758                RTMemFree(pEntry);
     759            }
     760            RTMemFree(pDirNotify->u.list.paEntries);
     761            pDirNotify->u.list.paEntries = NULL;
     762            pDirNotify->u.list.cEntries  = 0;
     763            break;
     764        }
     765
     766        default:
     767            break;
     768    }
    637769}
    638770
     
    745877 * Reads the next directory entry, internal version.
    746878 *
    747  * @return VBox status code. Will return VERR_NO_MORE_FILES if no more entries are available.
     879 * @return VBox status code.
     880 * @retval VERR_GSTCTL_GUEST_ERROR / VERR_NO_MORE_FILES if no more entries are available.
    748881 * @param  objData              Where to store the read directory entry as internal object data.
    749882 * @param  pvrcGuest            Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
     
    790923                {
    791924                    AssertReturn(pDirNotify->uType == GUEST_DIR_NOTIFYTYPE_READ, VERR_INVALID_PARAMETER);
    792                     AssertPtrReturn(pDirNotify->u.read.pEntry, VERR_INVALID_POINTER);
    793                     objData.Init(pDirNotify->u.read.pEntry->szName);
    794                     vrc = objData.FromGuestFsObjInfo(&pDirNotify->u.read.pEntry->Info,
    795                                                      pDirNotify->u.read.pszUser, pDirNotify->u.read.pszGroups);
    796                     RTMemFree(pDirNotify->u.read.pEntry);
    797                     RTStrFree(pDirNotify->u.read.pszUser);
    798                     RTStrFree(pDirNotify->u.read.pszGroups);
     925                    AssertPtrReturn(pDirNotify->u.read.Entry.pDirEntryEx, VERR_INVALID_POINTER);
     926                    objData.Init(pDirNotify->u.read.Entry.pDirEntryEx->szName);
     927                    vrc = objData.FromGuestFsObjInfo(&pDirNotify->u.read.Entry.pDirEntryEx->Info,
     928                                                     pDirNotify->u.read.Entry.pszUser, pDirNotify->u.read.Entry.pszGroups);
     929                    RTMemFree(pDirNotify->u.read.Entry.pDirEntryEx);
     930                    RTStrFree(pDirNotify->u.read.Entry.pszUser);
     931                    RTStrFree(pDirNotify->u.read.Entry.pszGroups);
    799932                }
    800933                else
    801934                {
    802                     if (pvrcGuest)
    803                         *pvrcGuest = vrcGuest;
     935                    *pvrcGuest = vrcGuest;
    804936                    vrc = VERR_GSTCTL_GUEST_ERROR;
    805937                }
     
    851983                }
    852984                else
     985                {
     986#ifdef DEBUG
     987                    curBlock.DumpToLog();
     988#endif
    853989                    vrc = VERR_PATH_NOT_FOUND;
     990                }
    854991            }
    855992            else
     
    8661003
    8671004/**
     1005 * Worker for listing the next directory entries.
     1006 *
     1007 * @return VBox status code.
     1008 * @retval VERR_GSTCTL_GUEST_ERROR / VERR_NO_MORE_FILES if no more entries are available after this iteration.
     1009 *         \a vecObjData will contain the rest of the entries then (if any).
     1010 * @param  cMaxEntries          How many directory entries to read at max.
     1011 * @param  fFlags               Flags of type GSTCTL_DIRLIST_F_XXX.
     1012 * @param  vecObjData           Where to store the read directory entries on success.
     1013 * @param  pvrcGuest            Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
     1014 */
     1015int GuestDirectory::i_listInternal(uint32_t cMaxEntries, uint32_t fFlags, std::vector<GuestFsObjData> &vecObjData, int *pvrcGuest)
     1016{
     1017    int vrc;
     1018
     1019#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
     1020    if (mSession->i_getParent()->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
     1021    {
     1022        GuestWaitEvent *pEvent = NULL;
     1023        GuestEventTypes eventTypes;
     1024        try
     1025        {
     1026            vrc = registerWaitEvent(eventTypes, &pEvent);
     1027        }
     1028        catch (std::bad_alloc &)
     1029        {
     1030            vrc = VERR_NO_MEMORY;
     1031        }
     1032
     1033        if (RT_FAILURE(vrc))
     1034            return vrc;
     1035
     1036        /* Prepare HGCM call. */
     1037        VBOXHGCMSVCPARM paParms[4];
     1038        int i = 0;
     1039        HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
     1040        HGCMSvcSetU32(&paParms[i++], mObjectID /* Directory handle */);
     1041        HGCMSvcSetU32(&paParms[i++], cMaxEntries);
     1042        HGCMSvcSetU32(&paParms[i++], 0 /* Flags */);
     1043
     1044        vrc = sendMessage(HOST_MSG_DIR_LIST, i, paParms);
     1045        if (RT_SUCCESS(vrc))
     1046        {
     1047            vrc = pEvent->Wait(30 * 1000);
     1048            if (RT_SUCCESS(vrc))
     1049            {
     1050                PCALLBACKDATA_DIR_NOTIFY const pDirNotify = (PCALLBACKDATA_DIR_NOTIFY)pEvent->Payload().Raw();
     1051                AssertPtrReturn(pDirNotify, VERR_INVALID_POINTER);
     1052                int vrcGuest = (int)pDirNotify->rc;
     1053                if (   RT_SUCCESS(vrcGuest)
     1054                    /* Guest indicates that there are no more entries to read.
     1055                     * We still need to check if we have read something with this iteration though. */
     1056                    || vrcGuest == VERR_NO_MORE_FILES)
     1057                {
     1058                    AssertReturn(pDirNotify->uType == GUEST_DIR_NOTIFYTYPE_LIST, VERR_INVALID_PARAMETER);
     1059
     1060                    try
     1061                    {
     1062                        vecObjData.resize(pDirNotify->u.list.cEntries);
     1063                    }
     1064                    catch (std::bad_alloc &)
     1065                    {
     1066                        vrc = VERR_NO_MEMORY;
     1067                    }
     1068
     1069                    if (RT_SUCCESS(vrc))
     1070                    {
     1071                        for (size_t a = 0; a < pDirNotify->u.list.cEntries; a++)
     1072                        {
     1073                            PCALLBACKDATA_DIR_ENTRY const pEntry = pDirNotify->u.list.paEntries[a];
     1074                            AssertPtr(pEntry);
     1075
     1076                            AssertPtr(pEntry->pDirEntryEx);
     1077                            vecObjData[a].Init(pEntry->pDirEntryEx->szName);
     1078                            int vrc2 = vecObjData[a].FromGuestFsObjInfo(&pEntry->pDirEntryEx->Info, pEntry->pszUser, pEntry->pszGroups);
     1079                            if (RT_SUCCESS(vrc))
     1080                                vrc = vrc2;
     1081                        }
     1082                    }
     1083                }
     1084                else
     1085                {
     1086                    *pvrcGuest = vrcGuest;
     1087                    vrc = VERR_GSTCTL_GUEST_ERROR;
     1088                }
     1089
     1090                GuestDirectory::i_dirNotifyDataDestroy(pDirNotify);
     1091            }
     1092            else if (pEvent->HasGuestError())
     1093                *pvrcGuest = pEvent->GuestResult();
     1094        }
     1095    }
     1096    else
     1097#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
     1098    {
     1099        RT_NOREF(cMaxEntries, fFlags, vecObjData, pvrcGuest);
     1100        vrc = VERR_NOT_SUPPORTED;
     1101    }
     1102
     1103    return vrc;
     1104}
     1105
     1106/**
     1107 * Lists the next directory entries.
     1108 *
     1109 * @return VBox status code.
     1110 * @retval VERR_GSTCTL_GUEST_ERROR / VERR_NO_MORE_FILES if no more entries are available after this iteration.
     1111 *         \a vecObjData will contain the rest of the entries then (if any).
     1112 * @param  cMaxEntries          How many directory entries to read at max.
     1113 * @param  fFlags               Flags of type GSTCTL_DIRLIST_F_XXX.
     1114 * @param  vecObjInfo           Where to store the read directory entries on success.
     1115 * @param  pvrcGuest            Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
     1116 */
     1117int GuestDirectory::i_listEx(uint32_t cMaxEntries, uint32_t fFlags, std::vector<ComObjPtr<GuestFsObjInfo>> &vecObjInfo,
     1118                             int *pvrcGuest)
     1119{
     1120    AssertPtrReturn(pvrcGuest, VERR_INVALID_POINTER);
     1121    AssertReturn(!(fFlags & ~GSTCTL_DIRLIST_F_VALID_MASK), VERR_INVALID_PARAMETER);
     1122
     1123    std::vector<GuestFsObjData> vecObjDataInt;
     1124    int vrc = i_listInternal(cMaxEntries, fFlags, vecObjDataInt, pvrcGuest);
     1125    if (   RT_SUCCESS(vrc)
     1126        || (     vrc       == VERR_GSTCTL_GUEST_ERROR
     1127             && *pvrcGuest == VERR_NO_MORE_FILES))
     1128    {
     1129        try
     1130        {
     1131            vecObjInfo.resize(vecObjDataInt.size());
     1132            for (size_t i = 0; i < vecObjDataInt.size(); i++)
     1133            {
     1134                HRESULT hrc = vecObjInfo[i].createObject();
     1135                ComAssertComRCBreak(hrc, vrc = VERR_COM_UNEXPECTED);
     1136
     1137                vrc = vecObjInfo[i]->init(vecObjDataInt[i]);
     1138                if (RT_FAILURE(vrc))
     1139                    break;
     1140            }
     1141        }
     1142        catch (std::bad_alloc &)
     1143        {
     1144            vrc = VERR_NO_MEMORY;
     1145        }
     1146    }
     1147
     1148    return vrc;
     1149}
     1150
     1151/**
     1152 * Lists the next directory entries.
     1153 *
     1154 * @return VBox status code.
     1155 * @retval VERR_GSTCTL_GUEST_ERROR / VERR_NO_MORE_FILES if no more entries are available after this iteration.
     1156 *         \a vecObjData will contain the rest of the entries then (if any).
     1157 * @param  cMaxEntries          How many directory entries to read at max.
     1158 * @param  vecObjInfo           Where to store the read directory entries on success.
     1159 * @param  pvrcGuest            Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
     1160 */
     1161int GuestDirectory::i_list(uint32_t cMaxEntries, std::vector<ComObjPtr<GuestFsObjInfo>> &vecObjInfo, int *pvrcGuest)
     1162{
     1163    return i_listEx(cMaxEntries, GSTCTL_DIRLIST_F_NONE, vecObjInfo, pvrcGuest);
     1164}
     1165
     1166/**
    8681167 * Reads the next directory entry.
    8691168 *
    870  * @return VBox status code. Will return VERR_NO_MORE_FILES if no more entries are available.
     1169 * @return VBox status code.
     1170 * @retval VERR_GSTCTL_GUEST_ERROR / VERR_NO_MORE_FILES if no more entries are available.
    8711171 * @param  fsObjInfo            Where to store the read directory entry.
    8721172 * @param  pvrcGuest            Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
     
    8941194    else /* Otherwise ask the guest for the next object data. */
    8951195    {
    896 
    8971196        GuestFsObjData objData;
    8981197        vrc = i_readInternal(objData, pvrcGuest);
     
    11241423}
    11251424
     1425HRESULT GuestDirectory::list(ULONG aMaxEntries, std::vector<ComPtr<IFsObjInfo> > &aObjInfos)
     1426{
     1427    AutoCaller autoCaller(this);
     1428    if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
     1429
     1430    LogFlowThisFuncEnter();
     1431
     1432    HRESULT hrc = S_OK;
     1433
     1434    std::vector<ComObjPtr<GuestFsObjInfo> > vecObjInfo;
     1435    int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
     1436    int vrc = i_list(aMaxEntries, vecObjInfo, &vrcGuest);
     1437
     1438    /* Don't propagate an error to API callers when this is the last listing (i.e. no more files).
     1439     * For subsequent reads the API caller gets an appropriate error then. */
     1440    if (    vrc      == VERR_GSTCTL_GUEST_ERROR
     1441         && vrcGuest == VERR_NO_MORE_FILES
     1442         && vecObjInfo.size())
     1443            vrc = VINF_SUCCESS;
     1444
     1445    if (RT_SUCCESS(vrc))
     1446    {
     1447        try
     1448        {
     1449            aObjInfos.resize(vecObjInfo.size());
     1450
     1451            for (size_t i = 0; i < vecObjInfo.size(); i++)
     1452            {
     1453                hrc = vecObjInfo[i].queryInterfaceTo(aObjInfos[i].asOutParam());
     1454                ComAssertComRCBreakRC(hrc);
     1455            }
     1456        }
     1457        catch (std::bad_alloc &)
     1458        {
     1459            hrc = E_OUTOFMEMORY;
     1460        }
     1461    }
     1462    else
     1463    {
     1464        switch (vrc)
     1465        {
     1466            case VERR_GSTCTL_GUEST_ERROR:
     1467            {
     1468                GuestErrorInfo ge(GuestErrorInfo::Type_Directory, vrcGuest, mData.mOpenInfo.mPath.c_str());
     1469                hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Listing guest directory failed: %s"),
     1470                                   GuestBase::getErrorAsString(ge).c_str());
     1471
     1472                /* Return a dedicated error code when directory reading is done. See SDK reference. */
     1473                if (vrcGuest == VERR_NO_MORE_FILES)
     1474                    hrc = VBOX_E_OBJECT_NOT_FOUND;
     1475                break;
     1476            }
     1477
     1478            default:
     1479                hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Listing guest directory \"%s\" returned unhandled error: %Rrc\n"),
     1480                                   mData.mOpenInfo.mPath.c_str(), vrc);
     1481                break;
     1482        }
     1483    }
     1484
     1485    LogFlowThisFunc(("Returning hrc=%Rhrc / vrc=%Rrc\n", hrc, vrc));
     1486    return hrc;
     1487}
     1488
    11261489HRESULT GuestDirectory::read(ComPtr<IFsObjInfo> &aObjInfo)
    11271490{
     
    11511514                                  GuestErrorInfo::Type_ToolLs
    11521515#else
    1153                                   GuestErrorInfo::Type_Fs
     1516                                  GuestErrorInfo::Type_Directory
    11541517#endif
    11551518                , vrcGuest, mData.mOpenInfo.mPath.c_str());
    11561519                hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Reading guest directory failed: %s"),
    11571520                                   GuestBase::getErrorAsString(ge).c_str());
     1521
     1522                /* Return a dedicated error code when directory reading is done. See SDK reference. */
     1523                if (vrcGuest == VERR_NO_MORE_FILES)
     1524                    hrc = VBOX_E_OBJECT_NOT_FOUND;
    11581525                break;
    11591526            }
     
    11641531                                   mData.mOpenInfo.mPath.c_str(), mData.mProcessTool.getRc());
    11651532                break;
    1166 #endif
     1533
    11671534            case VERR_PATH_NOT_FOUND:
    11681535                hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" failed: Path not found"),
     
    11751542                                   mData.mOpenInfo.mPath.c_str());
    11761543                break;
    1177 
     1544#endif
    11781545            default:
    11791546                hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" returned unhandled error: %Rrc\n"),
  • trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py

    r98655 r99085  
    20242024        return True;
    20252025
    2026     def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, sSubDir = None):
     2026    def gctrlReadDirTree(self, oTest, oGuestSession, fIsError, fUseDirList = False, cEntriesPerRead = 0, sSubDir = None):
    20272027        """
    20282028        Helper function to recursively read a guest directory tree specified in the current test.
     
    20392039        cOthers  = 0;    # Other files.
    20402040
     2041        cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
     2042        aFsObjInfo     = [];
     2043
    20412044        # Open the directory:
    2042         reporter.log2('Directory="%s", filter="%s", afFlags="%s"' % (limitString(sCurDir), sFilter, afFlags));
     2045        reporter.log2('Directory="%s", filter="%s", afFlags="%s", fUseDirList=%s, cEntriesPerRead=%d'
     2046                      % (limitString(sCurDir), sFilter, afFlags, fUseDirList, cEntriesPerRead));
    20432047        try:
    20442048            oCurDir = oGuestSession.directoryOpen(sCurDir, sFilter, afFlags);
     
    20482052
    20492053        # Read the directory.
     2054        fDone = False;
    20502055        while fRc is True:
     2056            reporter.log3('Reading next batch ...');
     2057            aFsObjInfo = [];
    20512058            try:
    2052                 oFsObjInfo = oCurDir.read();
     2059                if not fUseDirList:
     2060                    aFsObjInfo.append(oCurDir.read());
     2061                else:
     2062                    if not cEntriesToRead:
     2063                        cEntriesToRead = random.randrange(1, 32768);
     2064                    aFsObjInfo = oCurDir.list(cEntriesToRead);
    20532065            except Exception as oXcpt:
    20542066                if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
    2055                     if self.oTstDrv.fpApiVer > 5.2:
    2056                         reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
     2067                    if fUseDirList:
     2068                        fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (sCurDir, cEntriesToRead));
    20572069                    else:
    2058                         # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
    2059                         reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
     2070                        if self.oTstDrv.fpApiVer > 5.2:
     2071                            reporter.errorXcpt('Error reading directory "%s":' % (sCurDir,));
     2072                        else:
     2073                            # Unlike fileOpen, directoryOpen will not fail if the directory does not exist.
     2074                            reporter.maybeErrXcpt(fIsError, 'Error reading directory "%s":' % (sCurDir,));
    20602075                    fRc = False;
    20612076                else:
    20622077                    reporter.log2('\tNo more directory entries for "%s"' % (limitString(sCurDir),));
     2078                    fDone = True;
    20632079                break;
    20642080
    2065             try:
    2066                 sName = oFsObjInfo.name;
    2067                 eType = oFsObjInfo.type;
    2068             except:
    2069                 fRc = reporter.errorXcpt();
     2081            if fDone or not fRc: # Abort reading?
    20702082                break;
    20712083
    2072             if sName in ('.', '..', ):
    2073                 if eType != vboxcon.FsObjType_Directory:
    2074                     fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
    2075                                          % (sName, eType, vboxcon.FsObjType_Directory));
    2076             elif eType == vboxcon.FsObjType_Directory:
    2077                 reporter.log2('  Directory "%s"' % limitString(oFsObjInfo.name));
    2078                 aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
    2079                                                    oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
    2080                 fRc      = aSubResult[0];
    2081                 cDirs   += aSubResult[1] + 1;
    2082                 cFiles  += aSubResult[2];
    2083                 cOthers += aSubResult[3];
    2084             elif eType is vboxcon.FsObjType_File:
    2085                 reporter.log4('  File "%s"' % oFsObjInfo.name);
    2086                 cFiles += 1;
    2087             elif eType is vboxcon.FsObjType_Symlink:
    2088                 reporter.log4('  Symlink "%s" -- not tested yet' % oFsObjInfo.name);
    2089                 cOthers += 1;
    2090             elif    oTestVm.isWindows() \
    2091                  or oTestVm.isOS2() \
    2092                  or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
    2093                                   vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
    2094                 fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
    2095                                      (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
    2096             else:
    2097                 cOthers += 1;
     2084            reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
     2085            for oFsObjInfo in aFsObjInfo:
     2086                try:
     2087                    sName = oFsObjInfo.name;
     2088                    eType = oFsObjInfo.type;
     2089                except:
     2090                    fRc = reporter.errorXcpt();
     2091                    break;
     2092
     2093                if sName in ('.', '..', ):
     2094                    if eType != vboxcon.FsObjType_Directory:
     2095                        fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
     2096                                            % (sName, eType, vboxcon.FsObjType_Directory));
     2097                elif eType == vboxcon.FsObjType_Directory:
     2098                    reporter.log2('  Directory "%s"' % limitString(oFsObjInfo.name));
     2099                    aSubResult = self.gctrlReadDirTree(oTest, oGuestSession, fIsError,
     2100                                                       fUseDirList, cEntriesPerRead,
     2101                                                       oTestVm.pathJoin(sSubDir, sName) if sSubDir else sName);
     2102                    fRc      = aSubResult[0];
     2103                    cDirs   += aSubResult[1] + 1;
     2104                    cFiles  += aSubResult[2];
     2105                    cOthers += aSubResult[3];
     2106                elif eType is vboxcon.FsObjType_File:
     2107                    reporter.log4('  File "%s"' % oFsObjInfo.name);
     2108                    cFiles += 1;
     2109                elif eType is vboxcon.FsObjType_Symlink:
     2110                    reporter.log4('  Symlink "%s" -- not tested yet' % oFsObjInfo.name);
     2111                    cOthers += 1;
     2112                elif    oTestVm.isWindows() \
     2113                    or oTestVm.isOS2() \
     2114                    or eType not in (vboxcon.FsObjType_Fifo, vboxcon.FsObjType_DevChar, vboxcon.FsObjType_DevBlock,
     2115                                    vboxcon.FsObjType_Socket, vboxcon.FsObjType_WhiteOut):
     2116                    fRc = reporter.error('Directory "%s" contains invalid directory entry "%s" (type %d)' %
     2117                                        (sCurDir, oFsObjInfo.name, oFsObjInfo.type,));
     2118                else:
     2119                    cOthers += 1;
    20982120
    20992121        # Close the directory
     
    21052127        return (fRc, cDirs, cFiles, cOthers);
    21062128
    2107     def gctrlReadDirTree2(self, oGuestSession, oDir): # type: (testfileset.TestDir) -> bool
     2129    def gctrlReadDirTree2(self, oGuestSession, oDir, fUseDirList = False, cEntriesPerRead = 0): # type: (testfileset.TestDir) -> bool
    21082130        """
    21092131        Helper function to recursively read a guest directory tree specified in the current test.
     
    21212143
    21222144        # Read the directory.
    2123         dLeftUpper = dict(oDir.dChildrenUpper);
    2124         cDot       = 0;
    2125         cDotDot    = 0;
    2126         fRc = True;
     2145        dLeftUpper     = dict(oDir.dChildrenUpper);
     2146        cDot           = 0;
     2147        cDotDot        = 0;
     2148        fRc            = True;
     2149        cEntriesToRead = cEntriesPerRead; # Only used when listing directories.
     2150        aFsObjInfo     = [];
    21272151        while True:
     2152            reporter.log3('Reading next batch ...');
     2153            aFsObjInfo = [];
    21282154            try:
    2129                 oFsObjInfo = oCurDir.read();
     2155                if not fUseDirList:
     2156                    aFsObjInfo.append(oCurDir.read());
     2157                else:
     2158                    if not cEntriesToRead:
     2159                        cEntriesToRead = random.randrange(1, 32768);
     2160                    aFsObjInfo = oCurDir.list(cEntriesToRead);
    21302161            except Exception as oXcpt:
    21312162                if vbox.ComError.notEqual(oXcpt, vbox.ComError.VBOX_E_OBJECT_NOT_FOUND):
    2132                     fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath,));
     2163                    if fUseDirList:
     2164                        fRc = reporter.errorXcpt('Error listing directory "%s" (cEntriesToRead=%d):' % (oDir.sPath, cEntriesToRead));
     2165                    else:
     2166                        fRc = reporter.errorXcpt('Error reading directory "%s":' % (oDir.sPath));
     2167                else:
     2168                    reporter.log2('\tNo more directory entries for "%s"' % (limitString(oDir.sPath),));
    21332169                break;
    21342170
    2135             try:
    2136                 sName  = oFsObjInfo.name;
    2137                 eType  = oFsObjInfo.type;
    2138                 cbFile = oFsObjInfo.objectSize;
    2139                 ## @todo check further attributes.
    2140             except:
    2141                 fRc = reporter.errorXcpt();
    2142                 break;
    2143 
    2144             # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
    2145             if sName in ('.', '..', ):
    2146                 if eType != vboxcon.FsObjType_Directory:
    2147                     fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
    2148                                          % (sName, eType, vboxcon.FsObjType_Directory));
    2149                 if sName == '.': cDot    += 1;
    2150                 else:            cDotDot += 1;
    2151             else:
    2152                 # Find the child and remove it from the dictionary.
    2153                 sNameUpper = sName.upper();
    2154                 oFsObj = dLeftUpper.get(sNameUpper);
    2155                 if oFsObj is None:
    2156                     fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
    2157                                          % (sName, oDir.sPath, eType, cbFile,));
     2171            reporter.log3('Processing next batch (%d items)...' % (len(aFsObjInfo)));
     2172            for oFsObjInfo in aFsObjInfo:
     2173                try:
     2174                    sName  = oFsObjInfo.name;
     2175                    eType  = oFsObjInfo.type;
     2176                    cbFile = oFsObjInfo.objectSize;
     2177                    ## @todo check further attributes.
     2178                except:
     2179                    fRc = reporter.errorXcpt();
     2180                    break;
     2181
     2182                # '.' and '..' entries are not present in oDir.aoChildren, so special treatment:
     2183                if sName in ('.', '..', ):
     2184                    if eType != vboxcon.FsObjType_Directory:
     2185                        fRc = reporter.error('Wrong type for "%s": %d, expected %d (Directory)'
     2186                                            % (sName, eType, vboxcon.FsObjType_Directory));
     2187                    if sName == '.': cDot    += 1;
     2188                    else:            cDotDot += 1;
    21582189                else:
    2159                     del dLeftUpper[sNameUpper];
    2160 
    2161                     # Check type
    2162                     if isinstance(oFsObj, testfileset.TestDir):
    2163                         if eType != vboxcon.FsObjType_Directory:
    2164                             fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
    2165                                                  % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
    2166                     elif isinstance(oFsObj, testfileset.TestFile):
    2167                         if eType != vboxcon.FsObjType_File:
    2168                             fRc = reporter.error('%s: expected file (%d), got eType=%d!'
    2169                                                  % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
     2190                    # Find the child and remove it from the dictionary.
     2191                    sNameUpper = sName.upper();
     2192                    oFsObj = dLeftUpper.get(sNameUpper);
     2193                    if oFsObj is None:
     2194                        fRc = reporter.error('Unknown object "%s" found in "%s" (type %s, size %s)!'
     2195                                            % (sName, oDir.sPath, eType, cbFile,));
    21702196                    else:
    2171                         fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
    2172 
    2173                     # Check the name.
    2174                     if oFsObj.sName != sName:
    2175                         fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % (oFsObj.sPath, oFsObj.sName, sName,));
    2176 
    2177                     # Check the size if a file.
    2178                     if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
    2179                         fRc = reporter.error('%s: expected size %s, got %s instead!' % (oFsObj.sPath, oFsObj.cbContent, cbFile,));
    2180 
    2181                     ## @todo check timestamps and attributes.
     2197                        del dLeftUpper[sNameUpper];
     2198
     2199                        # Check type
     2200                        if isinstance(oFsObj, testfileset.TestDir):
     2201                            if eType != vboxcon.FsObjType_Directory:
     2202                                fRc = reporter.error('%s: expected directory (%d), got eType=%d!'
     2203                                                    % (oFsObj.sPath, vboxcon.FsObjType_Directory, eType,));
     2204                        elif isinstance(oFsObj, testfileset.TestFile):
     2205                            if eType != vboxcon.FsObjType_File:
     2206                                fRc = reporter.error('%s: expected file (%d), got eType=%d!'
     2207                                                    % (oFsObj.sPath, vboxcon.FsObjType_File, eType,));
     2208                        else:
     2209                            fRc = reporter.error('%s: WTF? type=%s' % (oFsObj.sPath, type(oFsObj),));
     2210
     2211                        # Check the name.
     2212                        if oFsObj.sName != sName:
     2213                            fRc = reporter.error('%s: expected name "%s", got "%s" instead!' % (oFsObj.sPath, oFsObj.sName, sName,));
     2214
     2215                        # Check the size if a file.
     2216                        if isinstance(oFsObj, testfileset.TestFile) and cbFile != oFsObj.cbContent:
     2217                            fRc = reporter.error('%s: expected size %s, got %s instead!' % (oFsObj.sPath, oFsObj.cbContent, cbFile,));
     2218
     2219                        ## @todo check timestamps and attributes.
    21822220
    21832221        # Close the directory
     
    22032241        for oFsObj in oDir.aoChildren:
    22042242            if isinstance(oFsObj, testfileset.TestDir):
    2205                 fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj) and fRc;
     2243                fRc = self.gctrlReadDirTree2(oGuestSession, oFsObj, fUseDirList, cEntriesPerRead) and fRc;
    22062244
    22072245        return fRc;
     
    38233861            if fRc is not True:
    38243862                break;
    3825             (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc);
     3863            fUseDirList = False;
     3864            cEntriesPerRead = random.randrange(1, 32768);
     3865            if self.oTstDrv.fpApiVer >= 7.1: # Listing directories only is available for >= VBox 7.1.
     3866                fUseDirList = random.choice( [True, False] );
     3867            (fRc2, cDirs, cFiles, cOthers) = self.gctrlReadDirTree(oCurTest, oCurGuestSession, oCurRes.fRc,
     3868                                                                   fUseDirList, cEntriesPerRead);
    38263869            fRc = oCurTest.closeSession() and fRc;
    38273870
     
    38673910                for oDir in (self.oTestFiles.oEmptyDir, self.oTestFiles.oManyDir, self.oTestFiles.oTreeDir):
    38683911                    reporter.log('Checking "%s" ...' % (oDir.sPath,));
    3869                     fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir) and fRc;
     3912                    fUseDirList = False;
     3913                    cEntriesPerRead = random.randrange(1, 32768);
     3914                    if self.oTstDrv.fpApiVer >= 7.1: # Listing directories only is available for >= VBox 7.1.
     3915                        fUseDirList = random.choice( [True, False] );
     3916                    fRc = self.gctrlReadDirTree2(oCurGuestSession, oDir, fUseDirList, cEntriesPerRead) and fRc;
    38703917                fRc = oCurTest.closeSession() and fRc;
    38713918
Note: See TracChangeset for help on using the changeset viewer.

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