VirtualBox

Ignore:
Timestamp:
Dec 23, 2021 11:27:42 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
149072
Message:

vboximg-mount: Allow mounting arbitrary IPRT VFS chains

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ImageMounter/vboximg-mount/vboximg-mount.cpp

    r91840 r93065  
    121121
    122122/* Global variables */
    123 static RTVFSFILE             g_hVfsFileDisk;        /** Disk as VFS file handle. */
    124 static uint32_t              g_cbSector;            /** Disk sector size. */
    125 static RTDVM                 g_hDvmMgr;             /** Handle to the volume manager. */
    126 static char                 *g_pszDiskUuid;         /** UUID of image (if known, otherwise NULL) */
    127 static PVDINTERFACE          g_pVdIfs;              /** @todo Remove when VD I/O becomes threadsafe */
    128 static VDINTERFACETHREADSYNC g_VDIfThreadSync;      /** @todo Remove when VD I/O becomes threadsafe */
    129 static RTCRITSECT            g_vdioLock;            /** @todo Remove when VD I/O becomes threadsafe */
    130 static char                 *g_pszImageName;        /** Base filename for current VD image */
    131 static char                 *g_pszImagePath;        /** Full path to current VD image */
    132 static char                 *g_pszBaseImagePath;    /** Base image known after parsing */
    133 static char                 *g_pszBaseImageName;    /** Base image known after parsing */
    134 static uint32_t              g_cImages;             /** Number of images in diff chain */
     123static RTVFSFILE             g_hVfsFileDisk = NIL_RTVFSFILE;        /** Disk as VFS file handle. */
     124static uint32_t              g_cbSector;                            /** Disk sector size. */
     125static RTDVM                 g_hDvmMgr;                             /** Handle to the volume manager. */
     126static char                 *g_pszDiskUuid;                         /** UUID of image (if known, otherwise NULL) */
     127static PVDINTERFACE          g_pVdIfs;                              /** @todo Remove when VD I/O becomes threadsafe */
     128static VDINTERFACETHREADSYNC g_VDIfThreadSync;                      /** @todo Remove when VD I/O becomes threadsafe */
     129static RTCRITSECT            g_vdioLock;                            /** @todo Remove when VD I/O becomes threadsafe */
     130static char                 *g_pszImageName = NULL;                 /** Base filename for current VD image */
     131static char                 *g_pszImagePath;                        /** Full path to current VD image */
     132static char                 *g_pszBaseImagePath;                    /** Base image known after parsing */
     133static char                 *g_pszBaseImageName;                    /** Base image known after parsing */
     134static uint32_t              g_cImages;                             /** Number of images in diff chain */
    135135
    136136/** Pointer to the detected volumes. */
     
    306306        {
    307307            /* Skip the root specifier and start with the component coming afterwards. */
    308             if (!RTStrCmp(pPathSplit->apszComps[1], "vhdd"))
     308            if (   !RTStrCmp(pPathSplit->apszComps[1], "vhdd")
     309                && g_hVfsFileDisk != NIL_RTVFSFILE)
    309310                *phVfsObj = RTVfsObjFromFile(g_hVfsFileDisk);
    310311            else if (!RTStrNCmp(pPathSplit->apszComps[1], "vol", sizeof("vol") - 1))
     
    314315                int rcIprt = RTStrToUInt32Full(&pPathSplit->apszComps[1][3], 10, &idxVol);
    315316                if (   rcIprt == VINF_SUCCESS
    316                     && idxVol < g_cVolumes)
     317                    && idxVol < g_cVolumes
     318                    && g_paVolumes[idxVol].hVfsFileVol != NIL_RTVFSFILE)
    317319                    *phVfsObj = RTVfsObjFromFile(g_paVolumes[idxVol].hVfsFileVol);
    318320                else
     
    471473        case RTVFSOBJTYPE_FILE:
    472474        {
     475            size_t cbRead = 0;
    473476            RTVFSFILE hVfsFile = RTVfsObjToFile(hVfsObj);
    474             int rcIprt = RTVfsFileReadAt(hVfsFile, offset, pbBuf, cbBuf, NULL);
    475             if (RT_FAILURE(rc))
    476                 rc = -RTErrConvertToErrno(rcIprt);
    477             else
    478                 rc = cbBuf;
     477            int rcIprt = RTVfsFileReadAt(hVfsFile, offset, pbBuf, cbBuf, &cbRead);
     478            if (cbRead)
     479                rc = cbRead;
     480            else if (rcIprt == VINF_EOF)
     481                rc = -RTErrConvertToErrno(VERR_EOF);
    479482            RTVfsFileRelease(hVfsFile);
    480483            break;
     
    515518        case RTVFSOBJTYPE_FILE:
    516519        {
     520            size_t cbWritten = 0;
    517521            RTVFSFILE hVfsFile = RTVfsObjToFile(hVfsObj);
    518             int rcIprt = RTVfsFileWriteAt(hVfsFile, offset, pbBuf, cbBuf, NULL);
    519             if (RT_FAILURE(rc))
    520                 rc = -RTErrConvertToErrno(rcIprt);
    521             else
    522                 rc = cbBuf;
     522            int rcIprt = RTVfsFileWriteAt(hVfsFile, offset, pbBuf, cbBuf, &cbWritten);
     523            if (cbWritten)
     524                rc = cbWritten;
     525            else if (rcIprt == VINF_EOF)
     526                rc = -RTErrConvertToErrno(VERR_EOF);
    523527            RTVfsFileRelease(hVfsFile);
    524528            break;
     
    549553        stbuf->st_nlink = 2;
    550554    }
    551     else if (RTStrNCmp(pszPath + 1, g_pszImageName, strlen(g_pszImageName)) == 0)
     555    else if (   g_pszImageName
     556             && RTStrNCmp(pszPath + 1, g_pszImageName, strlen(g_pszImageName)) == 0)
    552557    {
    553558        /* When the disk is partitioned, the symbolic link named from `basename` of
     
    720725        pfnFiller(pvBuf, "..", NULL, 0);
    721726
    722         /*
    723          * Create FUSE FS dir entry that is depicted here (and exposed via stat()) as
    724          * a symbolic link back to the resolved path to the VBox virtual disk image,
    725          * whose symlink name is basename that path. This is a convenience so anyone
    726          * listing the dir can figure out easily what the vhdd FUSE node entry
    727          * represents.
    728          */
    729         pfnFiller(pvBuf, g_pszImageName, NULL, 0);
    730 
    731         /*
    732          * Create entry named "vhdd" denoting the whole disk, which getattr() will describe as a
    733          * regular file, and thus will go through the open/release/read/write vectors
    734          * to access the VirtualBox image as processed by the IRPT VD API.
    735          */
    736         pfnFiller(pvBuf, "vhdd", NULL, 0);
     727        if (g_pszImageName)
     728        {
     729            /*
     730             * Create FUSE FS dir entry that is depicted here (and exposed via stat()) as
     731             * a symbolic link back to the resolved path to the VBox virtual disk image,
     732             * whose symlink name is basename that path. This is a convenience so anyone
     733             * listing the dir can figure out easily what the vhdd FUSE node entry
     734             * represents.
     735             */
     736            pfnFiller(pvBuf, g_pszImageName, NULL, 0);
     737        }
     738
     739        if (g_hVfsFileDisk != NIL_RTVFSFILE)
     740        {
     741            /*
     742             * Create entry named "vhdd" denoting the whole disk, which getattr() will describe as a
     743             * regular file, and thus will go through the open/release/read/write vectors
     744             * to access the VirtualBox image as processed by the IRPT VD API.
     745             */
     746            pfnFiller(pvBuf, "vhdd", NULL, 0);
     747        }
    737748
    738749        /* Create entries for the individual volumes. */
     
    740751        {
    741752            char tmp[64];
    742             RTStrPrintf(tmp, sizeof (tmp), "vol%u", i);
    743             pfnFiller(pvBuf, tmp, NULL, 0);
     753            if (g_paVolumes[i].hVfsFileVol != NIL_RTVFSFILE)
     754            {
     755                RTStrPrintf(tmp, sizeof (tmp), "vol%u", i);
     756                pfnFiller(pvBuf, tmp, NULL, 0);
     757            }
    744758
    745759            if (g_paVolumes[i].hVfsRoot != NIL_RTVFS)
     
    922936}
    923937
    924 int
    925 main(int argc, char **argv)
    926 {
    927 
    928     int rc = RTR3InitExe(argc, &argv, 0);
    929     if (RT_FAILURE(rc))
    930         return RTMsgErrorExitFailure("RTR3InitExe failed, rc=%Rrc\n", rc);
    931 
    932     rc = VDInit();
    933     if (RT_FAILURE(rc))
    934         return RTMsgErrorExitFailure("VDInit failed, rc=%Rrc\n", rc);
    935 
    936     rc = RTFuseLoadLib();
    937     if (RT_FAILURE(rc))
    938         return RTMsgErrorExitFailure("Failed to load the fuse library, rc=%Rrc\n", rc);
    939 
    940     memset(&g_vboximgOps, 0, sizeof(g_vboximgOps));
    941     g_vboximgOps.open        = vboximgOp_open;
    942     g_vboximgOps.read        = vboximgOp_read;
    943     g_vboximgOps.write       = vboximgOp_write;
    944     g_vboximgOps.getattr     = vboximgOp_getattr;
    945     g_vboximgOps.release     = vboximgOp_release;
    946     g_vboximgOps.readdir     = vboximgOp_readdir;
    947     g_vboximgOps.readlink    = vboximgOp_readlink;
    948 
    949     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    950     memset(&g_vboximgOpts, 0, sizeof(g_vboximgOpts));
    951 
    952     rc = fuse_opt_parse(&args, &g_vboximgOpts, vboximgOptDefs, vboximgOptHandler);
    953     if (rc < 0 || argc < 2 || RTStrCmp(argv[1], "-?" ) == 0 || g_vboximgOpts.fBriefUsage)
    954     {
    955         briefUsage();
    956         return 0;
    957     }
    958 
    959     if (g_vboximgOpts.fAllowRoot)
    960         fuse_opt_add_arg(&args, "-oallow_root");
    961 
    962     /*
    963      * FUSE doesn't seem to like combining options with one hyphen, as traditional UNIX
    964      * command line utilities allow. The following flags, fWideList and fVerboseList,
    965      * and their respective option definitions give the appearance of combined opts,
    966      * so that -vl, -lv, -wl, -lw options are allowed, since those in particular would
    967      * tend to conveniently facilitate some of the most common use cases.
    968      */
    969     if (g_vboximgOpts.fWideList)
    970     {
    971         g_vboximgOpts.fWide = true;
    972         g_vboximgOpts.fList = true;
    973     }
    974     if (g_vboximgOpts.fVerboseList)
    975     {
    976         g_vboximgOpts.fVerbose = true;
    977         g_vboximgOpts.fList    = true;
    978     }
    979     if (g_vboximgOpts.fAllowRoot)
    980         fuse_opt_add_arg(&args, "-oallow_root");
    981 
     938
     939static int vboxImgMntImageSetup(struct fuse_args *args)
     940{
    982941    /*
    983942     * Initialize COM.
     
    1031990    if (g_vboximgOpts.pszImageUuidOrPath)
    1032991    {
     992        HRESULT rc;
     993
    1033994        /* compiler was too fussy about access mode's data type in conditional expr, so... */
    1034995        if (g_vboximgOpts.fRW)
     
    10401001                AccessMode_ReadOnly, false /* forceNewUuid */, pVDiskMedium.asOutParam()));
    10411002
    1042         if (FAILED(rc))
     1003        if (FAILED(hrc))
    10431004            return RTMsgErrorExitFailure("\nCould't find specified VirtualBox base or snapshot disk image:\n%s",
    10441005                 g_vboximgOpts.pszImageUuidOrPath);
     
    11151076    Bstr pBase64EncodedKeyStore;
    11161077
    1117     rc = pVDiskBaseMedium->GetProperty(Bstr("CRYPT/KeyStore").raw(), pBase64EncodedKeyStore.asOutParam());
    1118     if (SUCCEEDED(rc) && strlen(CSTR(pBase64EncodedKeyStore)) != 0)
     1078    hrc = pVDiskBaseMedium->GetProperty(Bstr("CRYPT/KeyStore").raw(), pBase64EncodedKeyStore.asOutParam());
     1079    if (SUCCEEDED(hrc) && strlen(CSTR(pBase64EncodedKeyStore)) != 0)
    11191080    {
    11201081        RTPrintf("\nvboximgMount: Encrypted disks not supported in this version\n\n");
     
    12281189/* **************** END IFDEF'D (STUBBED-OUT) CODE ***************** */
    12291190
    1230     rc = RTCritSectInit(&g_vdioLock);
     1191    int rc = RTCritSectInit(&g_vdioLock);
    12311192    if (RT_SUCCESS(rc))
    12321193    {
     
    13371298        RTPrintf("\nvboximg-mount: Going into background...\n");
    13381299
    1339     rc = fuse_main_real(args.argc, args.argv, &g_vboximgOps, sizeof(g_vboximgOps), NULL);
     1300    rc = fuse_main_real(args->argc, args->argv, &g_vboximgOps, sizeof(g_vboximgOps), NULL);
    13401301
    13411302    int rc2 = RTVfsFileRelease(g_hVfsFileDisk);
     
    13451306}
    13461307
     1308
     1309int main(int argc, char **argv)
     1310{
     1311
     1312    int rc = RTR3InitExe(argc, &argv, 0);
     1313    if (RT_FAILURE(rc))
     1314        return RTMsgErrorExitFailure("RTR3InitExe failed, rc=%Rrc\n", rc);
     1315
     1316    rc = VDInit();
     1317    if (RT_FAILURE(rc))
     1318        return RTMsgErrorExitFailure("VDInit failed, rc=%Rrc\n", rc);
     1319
     1320    rc = RTFuseLoadLib();
     1321    if (RT_FAILURE(rc))
     1322        return RTMsgErrorExitFailure("Failed to load the fuse library, rc=%Rrc\n", rc);
     1323
     1324    memset(&g_vboximgOps, 0, sizeof(g_vboximgOps));
     1325    g_vboximgOps.open        = vboximgOp_open;
     1326    g_vboximgOps.read        = vboximgOp_read;
     1327    g_vboximgOps.write       = vboximgOp_write;
     1328    g_vboximgOps.getattr     = vboximgOp_getattr;
     1329    g_vboximgOps.release     = vboximgOp_release;
     1330    g_vboximgOps.readdir     = vboximgOp_readdir;
     1331    g_vboximgOps.readlink    = vboximgOp_readlink;
     1332
     1333    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
     1334    memset(&g_vboximgOpts, 0, sizeof(g_vboximgOpts));
     1335
     1336    rc = fuse_opt_parse(&args, &g_vboximgOpts, vboximgOptDefs, vboximgOptHandler);
     1337    if (rc < 0 || argc < 2 || RTStrCmp(argv[1], "-?" ) == 0 || g_vboximgOpts.fBriefUsage)
     1338    {
     1339        briefUsage();
     1340        return 0;
     1341    }
     1342
     1343    if (g_vboximgOpts.fAllowRoot)
     1344        fuse_opt_add_arg(&args, "-oallow_root");
     1345
     1346    /*
     1347     * FUSE doesn't seem to like combining options with one hyphen, as traditional UNIX
     1348     * command line utilities allow. The following flags, fWideList and fVerboseList,
     1349     * and their respective option definitions give the appearance of combined opts,
     1350     * so that -vl, -lv, -wl, -lw options are allowed, since those in particular would
     1351     * tend to conveniently facilitate some of the most common use cases.
     1352     */
     1353    if (g_vboximgOpts.fWideList)
     1354    {
     1355        g_vboximgOpts.fWide = true;
     1356        g_vboximgOpts.fList = true;
     1357    }
     1358    if (g_vboximgOpts.fVerboseList)
     1359    {
     1360        g_vboximgOpts.fVerbose = true;
     1361        g_vboximgOpts.fList    = true;
     1362    }
     1363    if (g_vboximgOpts.fAllowRoot)
     1364        fuse_opt_add_arg(&args, "-oallow_root");
     1365
     1366    if (   !g_vboximgOpts.pszImageUuidOrPath
     1367        || !RTVfsChainIsSpec(g_vboximgOpts.pszImageUuidOrPath))
     1368        return vboxImgMntImageSetup(&args);
     1369
     1370    /* Mount the VFS chain. */
     1371    RTVFSOBJ hVfsObj;
     1372    rc = RTVfsChainOpenObj(g_vboximgOpts.pszImageUuidOrPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
     1373                           RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
     1374                           &hVfsObj, NULL, NULL);
     1375    if (   RT_SUCCESS(rc)
     1376        && RTVfsObjGetType(hVfsObj) == RTVFSOBJTYPE_VFS)
     1377    {
     1378        g_paVolumes = (PVBOXIMGMOUNTVOL)RTMemAllocZ(sizeof(*g_paVolumes));
     1379        if (RT_LIKELY(g_paVolumes))
     1380        {
     1381            g_cVolumes = 1;
     1382            g_paVolumes[0].hVfsRoot = RTVfsObjToVfs(hVfsObj);
     1383            g_paVolumes[0].hVfsFileVol = NIL_RTVFSFILE;
     1384            RTVfsObjRelease(hVfsObj);
     1385
     1386            rc = RTVfsOpenRoot(g_paVolumes[0].hVfsRoot, &g_paVolumes[0].hVfsDirRoot);
     1387            if (RT_SUCCESS(rc))
     1388            {
     1389                /*
     1390                 * Hand control over to libfuse.
     1391                 */
     1392                if (VERBOSE)
     1393                    RTPrintf("\nvboximg-mount: Going into background...\n");
     1394
     1395                rc = fuse_main_real(args.argc, args.argv, &g_vboximgOps, sizeof(g_vboximgOps), NULL);
     1396                RTVfsDirRelease(g_paVolumes[0].hVfsDirRoot);
     1397                RTVfsRelease(g_paVolumes[0].hVfsRoot);
     1398            }
     1399
     1400            RTMemFree(g_paVolumes);
     1401            g_paVolumes = NULL;
     1402            g_cVolumes  = 0;
     1403        }
     1404        else
     1405            rc = VERR_NO_MEMORY;
     1406
     1407        RTVfsObjRelease(hVfsObj);
     1408    }
     1409
     1410    return rc;
     1411}
     1412
Note: See TracChangeset for help on using the changeset viewer.

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