VirtualBox

Changeset 99085 in vbox for trunk/src/VBox/Additions/common


Ignore:
Timestamp:
Mar 21, 2023 12:15:00 PM (23 months ago)
Author:
vboxsync
Message:

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

Location:
trunk/src/VBox/Additions/common
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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
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