VirtualBox

Ignore:
Timestamp:
Aug 30, 2019 5:04:46 PM (5 years ago)
Author:
vboxsync
Message:

vboximg-mount: Working on accessing filesystems inside images directly using our own VFS implementations

Location:
trunk/src/VBox/ImageMounter/vboximg-mount
Files:
2 edited

Legend:

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

    r80513 r80517  
    105105    /** The VFS file associated with the volume. */
    106106    RTVFSFILE                   hVfsFileVol;
     107    /** Handle to the VFS root if supported and specified. */
     108    RTVFS                       hVfsRoot;
     109    /** Handle to the root directory. */
     110    RTVFSDIR                    hVfsDirRoot;
    107111} VBOXIMGMOUNTVOL;
    108112/** Pointer to a volume data structure. */
     
    133137
    134138static struct fuse_opt vboximgOptDefs[] = {
    135     OPTION("--image %s",      pszImageUuidOrPath,   0),
    136     OPTION("-i %s",           pszImageUuidOrPath,   0),
    137     OPTION("--rw",            fRW,                  1),
    138     OPTION("--root",          fAllowRoot,           0),
    139     OPTION("--vm %s",         pszVm,                0),
    140     OPTION("--partition %d",  idxPartition,         1),
    141     OPTION("-p %d",           idxPartition,         1),
    142     OPTION("--offset %d",     offset,               1),
    143     OPTION("-o %d",           offset,               1),
    144     OPTION("--size %d",       size,                 1),
    145     OPTION("-s %d",           size,                 1),
    146     OPTION("-l",              fList,                1),
    147     OPTION("--list",          fList,                1),
    148     OPTION("--verbose",       fVerbose,             1),
    149     OPTION("-v",              fVerbose,             1),
    150     OPTION("--wide",          fWide,                1),
    151     OPTION("-w",              fWide,                1),
    152     OPTION("-lv",             fVerboseList,         1),
    153     OPTION("-vl",             fVerboseList,         1),
    154     OPTION("-lw",             fWideList,            1),
    155     OPTION("-wl",             fWideList,            1),
    156     OPTION("-h",              fBriefUsage,          1),
    157     FUSE_OPT_KEY("--help",    USAGE_FLAG),
    158     FUSE_OPT_KEY("-vm",       FUSE_OPT_KEY_NONOPT),
     139    OPTION("--image %s",         pszImageUuidOrPath,   0),
     140    OPTION("-i %s",              pszImageUuidOrPath,   0),
     141    OPTION("--rw",               fRW,                  1),
     142    OPTION("--root",             fAllowRoot,           0),
     143    OPTION("--vm %s",            pszVm,                0),
     144    OPTION("-l",                 fList,                1),
     145    OPTION("--list",             fList,                1),
     146    OPTION("-g",                 fGstFs,               1),
     147    OPTION("--guest-filesystem", fGstFs,               1),
     148    OPTION("--verbose",          fVerbose,             1),
     149    OPTION("-v",                 fVerbose,             1),
     150    OPTION("--wide",             fWide,                1),
     151    OPTION("-w",                 fWide,                1),
     152    OPTION("-lv",                fVerboseList,         1),
     153    OPTION("-vl",                fVerboseList,         1),
     154    OPTION("-lw",                fWideList,            1),
     155    OPTION("-wl",                fWideList,            1),
     156    OPTION("-h",                 fBriefUsage,          1),
     157    FUSE_OPT_KEY("--help",       USAGE_FLAG),
     158    FUSE_OPT_KEY("-vm",          FUSE_OPT_KEY_NONOPT),
    159159    FUSE_OPT_END
    160160};
     
    220220        "                                     wider than standard 80 column window)\n"
    221221        "\n"
     222        "  [ { -g | --guest-filesystem } ]    Exposes supported guest filesystems directly\n"
     223        "                                     in the mounted directory without the need\n"
     224        "                                     for a filesystem driver on the host\n"
     225        "\n"
    222226        "  [ --vm UUID ]                      Restrict media list to specified vm.\n"
    223         "\n"
    224         "  [ { -p | --partition } <part #> ]  Expose only specified partition via FUSE.\n"
    225         "\n"
    226         "  [ { -o | --offset } <byte #> ]     Bias disk I/O by offset from disk start.\n"
    227         "                                     (incompatible with -p, --partition)\n"
    228         "\n"
    229         "  [ { -s | --size <bytes> } ]        Specify size of mounted disk.\n"
    230         "                                     (incompatible with -p, --partition)\n"
    231227        "\n"
    232228        "  [ --rw ]                           Make image writeable (default = readonly)\n"
     
    252248      "The virtual disk is exposed as a device node within a FUSE-based filesystem\n"
    253249      "that overlays the user-provided mount point. The FUSE filesystem consists of a\n"
    254       "directory containing two files: A pseudo HDD device node and a symbolic\n"
    255       "link. The device node, named 'vhdd', is the access point to the virtual disk\n"
    256       "(i.e. the OS-mountable raw binary). The symbolic link has the same basename(1)\n"
     250      "directory containing a number of files and possibly other directories:"
     251      "    * vhdd:      Provides access to the raw disk image data as a flat image\n"
     252      "    * vol<id>:   Provides access to individual volumes on the accessed disk image\n"
     253      "    * fs<id>:    Provides access to a supported filesystem without the need for a"
     254      "                 host filesystem driver\n"
     255      "\n"
     256      "The directory will also contain a symbolic link which has the same basename(1)\n"
    257257      "as the virtual disk base image and points to the location of the\n"
    258       "virtual disk base image. If the --partition, --offset, or --size\n"
    259       "options are provided, the boundaries of the FUSE-mounted subsection of the\n"
    260       "virtual disk will be described as a numeric range in brackets appended to the\n"
    261       "symbolic link name.\n"
     258      "virtual disk base image.\n"
    262259      "\n"
    263260    );
     
    299296    {
    300297        if (   RTPATH_PROP_HAS_ROOT_SPEC(pPathSplit->fProps)
    301             && pPathSplit->cComps == 2)
     298            && pPathSplit->cComps >= 2)
    302299        {
    303300            /* Skip the root specifier and start with the component coming afterwards. */
    304301            if (!RTStrCmp(pPathSplit->apszComps[1], "vhdd"))
    305302                *phVfsObj = RTVfsObjFromFile(g_hVfsFileDisk);
    306             else if (!RTStrNCmp(&pszPath[1], "vol", sizeof("vol") - 1))
     303            else if (!RTStrNCmp(pPathSplit->apszComps[1], "vol", sizeof("vol") - 1))
    307304            {
    308305                /* Retrieve the accessed volume and return the stat data. */
    309306                uint32_t idxVol;
    310                 int rcIprt = RTStrToUInt32Full(&pszPath[4], 10, &idxVol);
     307                int rcIprt = RTStrToUInt32Full(&pPathSplit->apszComps[1][3], 10, &idxVol);
    311308                if (   rcIprt == VINF_SUCCESS
    312309                    && idxVol < g_cVolumes)
     
    314311                else
    315312                    rc = VERR_NOT_FOUND;
     313            }
     314            else if (!RTStrNCmp(pPathSplit->apszComps[1], "fs", sizeof("fs") - 1))
     315            {
     316                /* Retrieve the accessed volume and return the stat data. */
     317                uint32_t idxVol;
     318                int rcIprt = RTStrToUInt32Full(&pPathSplit->apszComps[1][5], 10, &idxVol);
     319                if (   rcIprt == VINF_SUCCESS
     320                    && idxVol < g_cVolumes
     321                    && g_paVolumes[idxVol].hVfsDirRoot != NIL_RTVFSDIR)
     322                    *phVfsObj = RTVfsObjFromDir(g_paVolumes[idxVol].hVfsDirRoot);
     323                else
     324                    rc = VERR_NOT_FOUND;
     325
     326                /* Is an object inside the guest filesystem requested? */
     327                if (pPathSplit->cComps > 2)
     328                {
     329                    PRTPATHSPLIT pPathSplitVfs = (PRTPATHSPLIT)RTMemTmpAllocZ(RT_UOFFSETOF_DYN(RTPATHSPLIT, apszComps[pPathSplit->cComps - 1]));
     330                    if (RT_LIKELY(pPathSplitVfs))
     331                    {
     332                        pPathSplitVfs->cComps       = pPathSplit->cComps - 1;
     333                        pPathSplitVfs->fProps       = pPathSplit->fProps;
     334                        pPathSplitVfs->cchPath      = pPathSplit->cchPath - strlen(pPathSplit->apszComps[1]) - 1;
     335                        pPathSplitVfs->cbNeeded     = pPathSplit->cbNeeded;
     336                        pPathSplitVfs->pszSuffix    = pPathSplit->pszSuffix;
     337                        pPathSplitVfs->apszComps[0] = pPathSplit->apszComps[0];
     338                        for (uint32_t i = 1; i < pPathSplitVfs->cComps; i++)
     339                            pPathSplitVfs->apszComps[i] = pPathSplit->apszComps[i + 1];
     340
     341                        /* Reassemble the path. */
     342                        char *pszPathVfs = (char *)RTMemTmpAllocZ(pPathSplitVfs->cbNeeded);
     343                        if (RT_LIKELY(pszPathVfs))
     344                        {
     345                            rc = RTPathSplitReassemble(pPathSplitVfs, RTPATH_STR_F_STYLE_HOST, pszPathVfs, pPathSplitVfs->cbNeeded);
     346                            if (RT_SUCCESS(rc))
     347                            {
     348                                rc = RTVfsObjOpen(g_paVolumes[idxVol].hVfsRoot, pszPathVfs,
     349                                                  RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
     350                                                  RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
     351                                                  phVfsObj);
     352                            }
     353                            RTMemTmpFree(pszPathVfs);
     354                        }
     355
     356                        RTMemTmpFree(pPathSplitVfs);
     357                    }
     358                    else
     359                        rc = VERR_NO_MEMORY;
     360                }
    316361            }
    317362            else
     
    496541        stbuf->st_mode = S_IFDIR | 0755;
    497542        stbuf->st_nlink = 2;
    498     }
    499     else if (RTStrCmp(pszPath + 1, "vhdd") == 0)
    500     {
    501         rc = stat(g_pszImagePath, stbuf);
    502         if (rc < 0)
    503             return rc;
    504         /*
    505          * st_size represents the size of the FUSE FS-mounted portion of the disk.
    506          * By default it is the whole disk, but can be a partition or specified
    507          * (or overridden) directly by the { -s | --size } option on the command line.
    508          */
    509         uint64_t cbFile = 0;
    510         int rcIprt = RTVfsFileGetSize(g_hVfsFileDisk, &cbFile);
    511         if (RT_SUCCESS(rcIprt))
    512             stbuf->st_size = cbFile;
    513         else
    514             rc = -RTErrConvertToErrno(rcIprt);
    515         stbuf->st_nlink = 1;
    516     }
    517     else if (!RTStrNCmp(&pszPath[1], "vol", sizeof("vol") - 1))
    518     {
    519         /* Retrieve the accessed volume and return the stat data. */
    520         uint32_t idxVol;
    521         int rcIprt = RTStrToUInt32Full(&pszPath[4], 10, &idxVol);
    522         if (   rcIprt == VINF_SUCCESS
    523             && idxVol < g_cVolumes)
    524         {
    525             rc = stat(g_pszImagePath, stbuf);
    526             if (rc < 0)
    527                 return rc;
    528             /*
    529              * st_size represents the size of the FUSE FS-mounted portion of the disk.
    530              * By default it is the whole disk, but can be a partition or specified
    531              * (or overridden) directly by the { -s | --size } option on the command line.
    532              */
    533             stbuf->st_size = RTDvmVolumeGetSize(g_paVolumes[idxVol].hVol);
    534             stbuf->st_nlink = 1;
    535         }
    536         else
    537             rc = -ENOENT;
    538543    }
    539544    else if (RTStrNCmp(pszPath + 1, g_pszImageName, strlen(g_pszImageName)) == 0)
     
    555560        stbuf->st_uid = 0;
    556561        stbuf->st_gid = 0;
    557     } else
    558         rc = -ENOENT;
     562    }
     563    else
     564    {
     565        /* Query the VFS object and fill in the data. */
     566        RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
     567        int rcIprt = vboxImgMntVfsObjQueryFromPath(pszPath, &hVfsObj);
     568        if (RT_SUCCESS(rcIprt))
     569        {
     570            switch (RTVfsObjGetType(hVfsObj))
     571            {
     572                case RTVFSOBJTYPE_FILE:
     573                {
     574                    RTVFSFILE hVfsFile = RTVfsObjToFile(hVfsObj);
     575                    uint64_t cb;
     576                    rcIprt = RTVfsFileGetSize(hVfsFile, &cb); AssertRC(rcIprt);
     577                    RTVfsFileRelease(hVfsFile);
     578
     579                    stbuf->st_mode = S_IFREG | 0644;
     580                    stbuf->st_size = (off_t)cb;
     581                    stbuf->st_nlink = 1;
     582                    break;
     583                }
     584                case RTVFSOBJTYPE_DIR:
     585                {
     586                    stbuf->st_mode = S_IFDIR | 0755;
     587                    stbuf->st_nlink = 2;
     588                    break;
     589                }
     590                default:
     591                    rc = -EINVAL;
     592            }
     593
     594            stbuf->st_uid = 0;
     595            stbuf->st_gid = 0;
     596            RTVfsObjRelease(hVfsObj);
     597        }
     598        else if (rcIprt == VERR_NOT_FOUND)
     599            rc = -ENOENT;
     600        else
     601            rc = -RTErrConvertToErrno(rcIprt);
     602    }
    559603
    560604    return rc;
     
    567611
    568612{
    569     NOREF(offset);
    570     NOREF(pInfo);
    571 
    572     if (RTStrCmp(pszPath, "/") != 0)
    573         return -ENOENT;
    574 
    575     /*
    576      *  mandatory '.', '..', ...
    577      */
    578     pfnFiller(pvBuf, ".", NULL, 0);
    579     pfnFiller(pvBuf, "..", NULL, 0);
    580 
    581     /*
    582      * Create FUSE FS dir entry that is depicted here (and exposed via stat()) as
    583      * a symbolic link back to the resolved path to the VBox virtual disk image,
    584      * whose symlink name is basename that path. This is a convenience so anyone
    585      * listing the dir can figure out easily what the vhdd FUSE node entry
    586      * represents.
    587      */
    588     pfnFiller(pvBuf, g_pszImageName, NULL, 0);
    589 
    590     /*
    591      * Create entry named "vhdd" denoting the whole disk, which getattr() will describe as a
    592      * regular file, and thus will go through the open/release/read/write vectors
    593      * to access the VirtualBox image as processed by the IRPT VD API.
    594      */
    595     pfnFiller(pvBuf, "vhdd", NULL, 0);
    596 
    597     /* Create entries for the individual volumes. */
    598     for (uint32_t i = 0; i < g_cVolumes; i++)
    599     {
    600         char tmp[64];
    601         RTStrPrintf(tmp, sizeof (tmp), "vol%u", i);
    602         pfnFiller(pvBuf, tmp, NULL, 0);
    603     }
    604     return 0;
     613    RT_NOREF(offset);
     614    RT_NOREF(pInfo);
     615
     616    int rc = 0;
     617
     618    /* Special root directory handling?. */
     619    if (!RTStrCmp(pszPath, "/"))
     620    {
     621        /*
     622         *  mandatory '.', '..', ...
     623         */
     624        pfnFiller(pvBuf, ".", NULL, 0);
     625        pfnFiller(pvBuf, "..", NULL, 0);
     626
     627        /*
     628         * Create FUSE FS dir entry that is depicted here (and exposed via stat()) as
     629         * a symbolic link back to the resolved path to the VBox virtual disk image,
     630         * whose symlink name is basename that path. This is a convenience so anyone
     631         * listing the dir can figure out easily what the vhdd FUSE node entry
     632         * represents.
     633         */
     634        pfnFiller(pvBuf, g_pszImageName, NULL, 0);
     635
     636        /*
     637         * Create entry named "vhdd" denoting the whole disk, which getattr() will describe as a
     638         * regular file, and thus will go through the open/release/read/write vectors
     639         * to access the VirtualBox image as processed by the IRPT VD API.
     640         */
     641        pfnFiller(pvBuf, "vhdd", NULL, 0);
     642
     643        /* Create entries for the individual volumes. */
     644        for (uint32_t i = 0; i < g_cVolumes; i++)
     645        {
     646            char tmp[64];
     647            RTStrPrintf(tmp, sizeof (tmp), "vol%u", i);
     648            pfnFiller(pvBuf, tmp, NULL, 0);
     649
     650            if (g_paVolumes[i].hVfsRoot != NIL_RTVFS)
     651            {
     652                RTStrPrintf(tmp, sizeof (tmp), "fs%u", i);
     653                pfnFiller(pvBuf, tmp, NULL, 0);
     654            }
     655        }
     656    }
     657    else
     658    {
     659        /* Query the VFS object and fill in the data. */
     660        RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
     661        int rcIprt = vboxImgMntVfsObjQueryFromPath(pszPath, &hVfsObj);
     662        if (RT_SUCCESS(rcIprt))
     663        {
     664            switch (RTVfsObjGetType(hVfsObj))
     665            {
     666                case RTVFSOBJTYPE_DIR:
     667                {
     668                    RTVFSDIR hVfsDir = RTVfsObjToDir(hVfsObj);
     669                    RTDIRENTRYEX DirEntry;
     670
     671                    rcIprt = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
     672                    while (RT_SUCCESS(rcIprt))
     673                    {
     674                        pfnFiller(pvBuf, DirEntry.szName, NULL, 0);
     675                        rcIprt = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
     676                    }
     677                    RTVfsDirRelease(hVfsDir);
     678                    break;
     679                }
     680                default:
     681                    rc = -EINVAL;
     682            }
     683
     684            RTVfsObjRelease(hVfsObj);
     685        }
     686        else
     687            rc = -RTErrConvertToErrno(rcIprt);
     688    }
     689
     690    return rc;
    605691}
    606692
     
    696782                if (RT_LIKELY(g_paVolumes))
    697783                {
     784                    g_paVolumes[0].hVfsRoot = NIL_RTVFS;
     785
    698786                    rc = RTDvmMapQueryFirstVolume(g_hDvmMgr, &g_paVolumes[0].hVol);
    699787                    if (RT_SUCCESS(rc))
     
    704792                    for (uint32_t i = 1; i < g_cVolumes && RT_SUCCESS(rc); i++)
    705793                    {
     794                        g_paVolumes[i].hVfsRoot = NIL_RTVFS;
    706795                        rc = RTDvmMapQueryNextVolume(g_hDvmMgr, g_paVolumes[i-1].hVol, &g_paVolumes[i].hVol);
    707796                        if (RT_SUCCESS(rc))
     
    759848    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    760849    memset(&g_vboximgOpts, 0, sizeof(g_vboximgOpts));
    761 
    762     g_vboximgOpts.idxPartition = -1;
    763850
    764851    rc = fuse_opt_parse(&args, &g_vboximgOpts, vboximgOptDefs, vboximgOptHandler);
     
    11161203    }
    11171204
     1205    /* Try to "mount" supported filesystems inside the disk image if specified. */
     1206    if (g_vboximgOpts.fGstFs)
     1207    {
     1208        for (uint32_t i = 0; i < g_cVolumes; i++)
     1209        {
     1210            rc = RTVfsMountVol(g_paVolumes[i].hVfsFileVol,
     1211                               g_vboximgOpts.fRW ? 0 : RTVFSMNT_F_READ_ONLY,
     1212                               &g_paVolumes[i].hVfsRoot,
     1213                               NULL);
     1214            if (RT_SUCCESS(rc))
     1215            {
     1216                rc = RTVfsOpenRoot(g_paVolumes[i].hVfsRoot, &g_paVolumes[i].hVfsDirRoot);
     1217                if (RT_FAILURE(rc))
     1218                {
     1219                    RTPrintf("\nvboximg-mount: Failed to access filesystem on volume %u, ignoring\n", i);
     1220                    RTVfsRelease(g_paVolumes[i].hVfsRoot);
     1221                    g_paVolumes[i].hVfsRoot = NIL_RTVFS;
     1222                }
     1223            }
     1224            else
     1225                RTPrintf("\nvboximg-mount: Failed to access filesystem on volume %u, ignoring\n", i);
     1226        }
     1227    }
     1228
    11181229    /*
    11191230     * Hand control over to libfuse.
  • trunk/src/VBox/ImageMounter/vboximg-mount/vboximgOpts.h

    r76585 r80517  
    2828     char         *pszVm;                   /** optional VM UUID */
    2929     char         *pszImageUuidOrPath;      /** Virtual Disk image UUID or path */
    30      int32_t       idxPartition;            /** Number of partition to constrain FUSE based FS to (optional) 0 - whole disk*/
    31      int32_t       offset;                  /** Offset to base virtual disk reads and writes from (altnerative to partition) */
    32      int32_t       size;                    /** Size of accessible disk region, starting at offset, default = offset 0 */
    3330     uint32_t      fListMediaLong;          /** Flag to list virtual disks of all known VMs */
    3431     uint32_t      fVerboseList;            /** FUSE parsing doesn't understand combined flags (-lv, -vl), so we kludge it */
     
    3633     uint32_t      fList;                   /** Flag to list virtual disks of all known VMs */
    3734     uint32_t      fListParts;              /** Flag to summarily list partitions associated with pszImage */
     35     uint32_t      fGstFs;                  /** Flag to try to exposes supported filesystems directly in the mountpoint inside a subdirectory */
    3836     uint32_t      fAllowRoot;              /** Flag to allow root to access this FUSE FS */
    3937     uint32_t      fRW;                     /** Flag to allow changes to FUSE-mounted Virtual Disk image */
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