VBoxFUSE.cpp revision aa661f4da86000f8b7f0c1ff172cb9105380d793
ece9652d971886b99a269656ea4782319637e75avboxsync * VBoxFUSE - Disk Image Flattening FUSE Program.
ece9652d971886b99a269656ea4782319637e75avboxsync * Copyright (C) 2009 Oracle Corporation
ece9652d971886b99a269656ea4782319637e75avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ece9652d971886b99a269656ea4782319637e75avboxsync * available from http://www.virtualbox.org. This file is free software;
ece9652d971886b99a269656ea4782319637e75avboxsync * you can redistribute it and/or modify it under the terms of the GNU
ece9652d971886b99a269656ea4782319637e75avboxsync * General Public License (GPL) as published by the Free Software
ece9652d971886b99a269656ea4782319637e75avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ece9652d971886b99a269656ea4782319637e75avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ece9652d971886b99a269656ea4782319637e75avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ece9652d971886b99a269656ea4782319637e75avboxsync/*******************************************************************************
ece9652d971886b99a269656ea4782319637e75avboxsync* Header Files *
ece9652d971886b99a269656ea4782319637e75avboxsync*******************************************************************************/
ece9652d971886b99a269656ea4782319637e75avboxsync#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo log group */
ece9652d971886b99a269656ea4782319637e75avboxsync#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX)
e7f5b62e52275099a4d14501306063e23876b771vboxsync# undef PVM /* Blasted old BSD mess still hanging around darwin. */
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync//# elif defined(EXYZ)
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync//# define EDOOFUS EXYZ
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync# error "Choose an unlikely and (if possible) fun error number for EDOOFUS."
ece9652d971886b99a269656ea4782319637e75avboxsync/*******************************************************************************
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync* Structures and Typedefs *
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync*******************************************************************************/
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * Node type.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Stuff common to both directories and files.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsynctypedef struct VBOXFUSENODE
ece9652d971886b99a269656ea4782319637e75avboxsync /** The directory name. */
e7f5b62e52275099a4d14501306063e23876b771vboxsync const char *pszName;
ece9652d971886b99a269656ea4782319637e75avboxsync /** The name length. */
e7f5b62e52275099a4d14501306063e23876b771vboxsync /** The node type. */
e7f5b62e52275099a4d14501306063e23876b771vboxsync /** The number of references.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * The directory linking this node will always retain one. */
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync /** Critical section serializing access to the node data. */
ece9652d971886b99a269656ea4782319637e75avboxsync /** Pointer to the directory (parent). */
ece9652d971886b99a269656ea4782319637e75avboxsync /** The mode mask. */
ece9652d971886b99a269656ea4782319637e75avboxsync /** The User ID of the directory owner. */
ece9652d971886b99a269656ea4782319637e75avboxsync /** The Group ID of the directory. */
ece9652d971886b99a269656ea4782319637e75avboxsync /** The link count. */
e7f5b62e52275099a4d14501306063e23876b771vboxsync /** The inode number. */
ece9652d971886b99a269656ea4782319637e75avboxsync /** The size of the primary stream. */
ece9652d971886b99a269656ea4782319637e75avboxsync * A flat image file.
0be1c98f1388ddc063a7e830f53e2018f658b348vboxsync /** The standard bits. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The virtual disk container. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The format name. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The number of readers.
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * Read only images will have this set to INT32_MAX/2 on creation. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The number of writers. (Just 1 or 0 really.) */
e7f5b62e52275099a4d14501306063e23876b771vboxsync * A control pipe (file).
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The standard bits. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * A Directory.
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * This is just a container of files and subdirectories, nothing special.
f910333674d7dd65ca746ec010ef354fd239cea4vboxsynctypedef struct VBOXFUSEDIR
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The standard bits. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** The number of directory entries. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync /** Array of pointers to directory entries.
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * Whether what's being pointed to is a file, directory or something else can be
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * determined by the enmType field. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync/** The number of elements to grow VBOXFUSEDIR::paEntries by. */
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync/*******************************************************************************
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync* Global Variables *
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync*******************************************************************************/
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync/** The root of the file hierarchy. */
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync/** The next inode number. */
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync/*******************************************************************************
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync* Internal Functions *
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync*******************************************************************************/
f910333674d7dd65ca746ec010ef354fd239cea4vboxsyncstatic int vboxfuseTreeLookupParent(const char *pszPath, const char **ppszName, PVBOXFUSEDIR *ppDir);
f910333674d7dd65ca746ec010ef354fd239cea4vboxsyncstatic int vboxfuseTreeLookupParentForInsert(const char *pszPath, const char **ppszName, PVBOXFUSEDIR *ppDir);
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * Node destructor.
f910333674d7dd65ca746ec010ef354fd239cea4vboxsync * @returns true.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * @param pNode The node.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * @param fLocked Whether it's locked.
e7f5b62e52275099a4d14501306063e23876b771vboxsyncstatic bool vboxfuseNodeDestroy(PVBOXFUSENODE pNode, bool fLocked)
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * Type specific cleanups.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync PVBOXFUSEFLATIMAGE pFlatImage = (PVBOXFUSEFLATIMAGE)pNode;
ece9652d971886b99a269656ea4782319637e75avboxsync int rc2 = VDClose(pFlatImage->pDisk, false /* fDelete */); AssertRC(rc2);
ece9652d971886b99a269656ea4782319637e75avboxsync * Generic cleanup.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Unlock and destroy the lock, before we finally frees the node.
e7f5b62e52275099a4d14501306063e23876b771vboxsync return true;
ece9652d971886b99a269656ea4782319637e75avboxsync * Locks a FUSE node.
ece9652d971886b99a269656ea4782319637e75avboxsync * @param pNode The node.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * Unlocks a FUSE node.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * @param pNode The node.
ece9652d971886b99a269656ea4782319637e75avboxsync * Retain a VBoxFUSE node.
36ec4b6f42e209d010ade084a96f46ce763345eavboxsync * @param pNode The node.
e7f5b62e52275099a4d14501306063e23876b771vboxsync * Releases a VBoxFUSE node reference.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @returns true if deleted, false if not.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @param pNode The node.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsyncstatic bool vboxfuseNodeRelease(PVBOXFUSENODE pNode)
e7f5b62e52275099a4d14501306063e23876b771vboxsync return vboxfuseNodeDestroy(pNode, false /* fLocked */);
e7f5b62e52275099a4d14501306063e23876b771vboxsync return false;
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * Locks and retains a VBoxFUSE node.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * @param pNode The node.
992ef02987d71b2b9f73a50265997c7f8e384886vboxsyncstatic void vboxfuseNodeLockAndRetain(PVBOXFUSENODE pNode)
992ef02987d71b2b9f73a50265997c7f8e384886vboxsync * Releases a VBoxFUSE node reference and unlocks it.
ece9652d971886b99a269656ea4782319637e75avboxsync * @returns true if deleted, false if not.
#ifndef RT_OS_LINUX
static int vboxfuseNodeAlloc(size_t cbNode, const char *pszName, VBOXFUSETYPE enmType, PVBOXFUSEDIR pDir,
if (!pNode)
return VERR_NO_MEMORY;
return rc;
return VINF_SUCCESS;
if (!pDir)
void *pvNew = RTMemRealloc(pDir->paEntries, sizeof(*pDir->paEntries) * (pDir->cEntries + VBOXFUSE_DIR_GROW_BY));
if (!pvNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
const char *pszName;
return rc;
rc = vboxfuseNodeAlloc(sizeof(*pNewDir), pszName, VBOXFUSETYPE_DIRECTORY, pParent, (PVBOXFUSENODE *)&pNewDir);
&& ppDir)
if (pParent)
return rc;
static int vboxfuseFlatImageCreate(const char *pszPath, const char *pszImage, PVBOXFUSEFLATIMAGE *ppFile)
const char *pszName;
return rc;
if (pParent)
char *pszFormat;
return rc;
return rc;
rc = vboxfuseNodeAlloc(sizeof(*pNewFlatImage), pszName, VBOXFUSETYPE_FLAT_IMAGE, pParent, (PVBOXFUSENODE *)&pNewFlatImage);
&& ppFile)
if (pParent)
return rc;
return VERR_FILE_NOT_FOUND;
do psz++;
if (!*psz)
return VINF_SUCCESS;
if (!psz)
psz++;
if (!pNode)
if ( fMustBeDir
return VERR_NOT_A_DIRECTORY;
if (!*psz)
return VINF_SUCCESS;
static int vboxfuseTreeLookupParent(const char *pszPath, const char **ppszName, PVBOXFUSEDIR *ppDir)
return VERR_INVALID_PARAMETER;
do psz++;
if (!*psz)
return VINF_SUCCESS;
if (!psz)
return VINF_SUCCESS;
psz++;
if (!*psz)
return VERR_INVALID_PARAMETER;
if (!pNode)
return VERR_FILE_NOT_FOUND;
if ( fMustBeDir
return VERR_PATH_NOT_FOUND;
static int vboxfuseTreeLookupParentForInsert(const char *pszPath, const char **ppszName, PVBOXFUSEDIR *ppDir)
const char *pszName;
if (pDir)
return rc;
if (!rc)
return rc;
if (!rc)
if (rc)
return rc;
int rc = 0;
if (!offDir)
&& !rc)
while ( !rc
#ifdef RT_OS_DARWIN
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
if (!rc)
case VBOXFUSETYPE_DIRECTORY:
AssertFailed();
case VBOXFUSETYPE_FLAT_IMAGE:
#ifdef O_DIRECTORY
if (!rc)
return rc;
case VBOXFUSETYPE_DIRECTORY:
case VBOXFUSETYPE_FLAT_IMAGE:
AssertFailed();
return -EDOOFUS;
case VBOXFUSETYPE_DIRECTORY:
return -ENOTSUP;
case VBOXFUSETYPE_FLAT_IMAGE:
LogFlow(("vboxfuseOp_read: offFile=%#llx cbBuf=%#zx pszPath=\"%s\"\n", (uint64_t)offFile, cbBuf, pszPath));
int rc;
rc = 0;
else if (!cbBuf)
rc = 0;
int rc2;
return rc;
return -ENOTSUP;
return -EDOOFUS;
case VBOXFUSETYPE_DIRECTORY:
return -ENOTSUP;
case VBOXFUSETYPE_FLAT_IMAGE:
LogFlow(("vboxfuseOp_write: offFile=%#llx cbBuf=%#zx pszPath=\"%s\"\n", (uint64_t)offFile, cbBuf, pszPath));
int rc;
rc = 0;
else if (!cbBuf)
rc = 0;
int rc2;
return rc;
return -ENOTSUP;
return -EDOOFUS;
return rc;