diff --git a/headers/os/drivers/fs_interface.h b/headers/os/drivers/fs_interface.h index a758c79b48..6b3ec1c936 100644 --- a/headers/os/drivers/fs_interface.h +++ b/headers/os/drivers/fs_interface.h @@ -43,6 +43,7 @@ struct file_io_vec { // flags for publish_vnode() and fs_volume_ops::get_vnode() #define B_VNODE_PUBLISH_REMOVED 0x01 #define B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE 0x02 +#define B_VNODE_WANTS_OVERLAY_SUB_NODE 0x04 #ifdef __cplusplus @@ -307,7 +308,7 @@ extern status_t publish_vnode(fs_volume *volume, ino_t vnodeID, void *privateNode, fs_vnode_ops *ops, int type, uint32 flags); extern status_t get_vnode(fs_volume *volume, ino_t vnodeID, - void **_privateNode); + void **_privateNode, fs_vnode_ops **_vnodeOps); extern status_t put_vnode(fs_volume *volume, ino_t vnodeID); extern status_t acquire_vnode(fs_volume *volume, ino_t vnodeID); extern status_t remove_vnode(fs_volume *volume, ino_t vnodeID); diff --git a/headers/private/fs_shell/fssh_fs_interface.h b/headers/private/fs_shell/fssh_fs_interface.h index d4d406c9c8..23f6f521b1 100644 --- a/headers/private/fs_shell/fssh_fs_interface.h +++ b/headers/private/fs_shell/fssh_fs_interface.h @@ -344,7 +344,8 @@ extern fssh_status_t fssh_publish_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, void *privateNode, fssh_fs_vnode_ops *ops, int type, uint32_t flags); extern fssh_status_t fssh_get_vnode(fssh_fs_volume *volume, - fssh_vnode_id vnodeID, void **_privateNode); + fssh_vnode_id vnodeID, void **_privateNode, + fssh_fs_vnode_ops **_vnodeOps); extern fssh_status_t fssh_put_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID); extern fssh_status_t fssh_acquire_vnode(fssh_fs_volume *volume, diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index 1e0b25d8a8..7733d72c25 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -2701,7 +2701,7 @@ AttributeIterator::GetNext(char* name, size_t* _length, uint32* _type, // if you haven't yet access to the attributes directory, get it if (fAttributes == NULL) { if (get_vnode(volume->FSVolume(), volume->ToVnode(fInode->Attributes()), - (void**)&fAttributes) != B_OK) { + (void**)&fAttributes, NULL) != B_OK) { FATAL(("get_vnode() failed in AttributeIterator::GetNext(ino_t" " = %Ld,name = \"%s\")\n", fInode->ID(), name)); return B_ENTRY_NOT_FOUND; diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h b/src/add-ons/kernel/file_systems/bfs/Inode.h index 3547011ba2..e06efc17a8 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.h +++ b/src/add-ons/kernel/file_systems/bfs/Inode.h @@ -354,7 +354,8 @@ public: { Unset(); - return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode); + return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode, + NULL); } status_t SetTo(Volume* volume, block_run run) diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index 81682ee15b..49f693c541 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -556,7 +556,7 @@ bfs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* file, locker.Unlock(); Inode* inode; - status = get_vnode(volume->FSVolume(), *_vnodeID, (void**)&inode); + status = get_vnode(volume->FSVolume(), *_vnodeID, (void**)&inode, NULL); if (status != B_OK) { REPORT_ERROR(status); return B_ENTRY_NOT_FOUND; diff --git a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp index 91e2da77f6..e30a6f3172 100644 --- a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp @@ -1493,7 +1493,7 @@ cdda_lookup(fs_volume* _volume, fs_vnode* _dir, const char* name, ino_t* _id) if (inode == NULL) return B_ENTRY_NOT_FOUND; - status = get_vnode(volume->FSVolume(), inode->ID(), NULL); + status = get_vnode(volume->FSVolume(), inode->ID(), NULL, NULL); if (status < B_OK) return status; diff --git a/src/add-ons/kernel/file_systems/ext2/Volume.cpp b/src/add-ons/kernel/file_systems/ext2/Volume.cpp index 0a30ab77dc..480e67d689 100644 --- a/src/add-ons/kernel/file_systems/ext2/Volume.cpp +++ b/src/add-ons/kernel/file_systems/ext2/Volume.cpp @@ -310,7 +310,7 @@ Volume::Mount(const char* deviceName, uint32 flags) if ((fBlockCache = opener.InitCache(NumBlocks(), fBlockSize)) == NULL) return B_ERROR; - status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode); + status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode, NULL); if (status != B_OK) { TRACE("could not create root node: get_vnode() failed!\n"); return status; diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index 5804d1f9ab..4268a80fdb 100644 --- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp @@ -319,7 +319,7 @@ ext2_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name, break; } - return get_vnode(volume->FSVolume(), *_vnodeID, NULL); + return get_vnode(volume->FSVolume(), *_vnodeID, NULL, NULL); } diff --git a/src/add-ons/kernel/file_systems/fat/dir.c b/src/add-ons/kernel/file_systems/fat/dir.c index e0ce4d2c40..4fba295480 100644 --- a/src/add-ons/kernel/file_systems/fat/dir.c +++ b/src/add-ons/kernel/file_systems/fat/dir.c @@ -433,7 +433,7 @@ findfile(nspace *vol, vnode *dir, const char *file, ino_t *vnid, if (vnid) *vnid = found_vnid; if (node) - result = get_vnode(vol->volume, found_vnid, (void **)node); + result = get_vnode(vol->volume, found_vnid, (void **)node, NULL); result = B_OK; } else { result = ENOENT; diff --git a/src/add-ons/kernel/file_systems/fat/file.c b/src/add-ons/kernel/file_systems/fat/file.c index 8f14df5f48..88e6f8799e 100644 --- a/src/add-ons/kernel/file_systems/fat/file.c +++ b/src/add-ons/kernel/file_systems/fat/file.c @@ -890,7 +890,7 @@ dosfs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode, *vnid = dummy.vnid; dummy.magic = ~VNODE_MAGIC; - result = get_vnode(_vol, *vnid, (void **)&file); + result = get_vnode(_vol, *vnid, (void **)&file, NULL); if (result < B_OK) { if (vol->fs_flags & FS_FLAGS_OP_SYNC) _dosfs_sync(vol); @@ -1155,7 +1155,7 @@ dosfs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname, if (vnid == vol->root_vnode.vnid) break; - result = get_vnode(_vol, vnid, (void **)&dir); + result = get_vnode(_vol, vnid, (void **)&dir, NULL); if (result < B_OK) goto bi1; parent = dir->dir_vnid; diff --git a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp index 9d1082a942..32e43c0c3d 100644 --- a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp @@ -224,12 +224,12 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID) // base directory TRACE(("fs_walk - found \".\" file.\n")); *_vnodeID = baseNode->id; - return get_vnode(_vol, *_vnodeID, (void **)&newNode); + return get_vnode(_vol, *_vnodeID, NULL, NULL); } else if (strcmp(file, "..") == 0) { // parent directory TRACE(("fs_walk - found \"..\" file.\n")); *_vnodeID = baseNode->parID; - return get_vnode(_vol, *_vnodeID, (void **)&newNode); + return get_vnode(_vol, *_vnodeID, NULL, NULL); } // look up file in the directory @@ -272,7 +272,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID) TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); result = get_vnode(_vol, *_vnodeID, - (void **)&newNode); + (void **)&newNode, NULL); if (result == B_OK) { newNode->parID = baseNode->id; done = true; @@ -349,7 +349,7 @@ fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, _node->private_node = newNode; _node->ops = &gISO9660VnodeOps; *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); - *_flags = 0; + *_flags = B_VNODE_WANTS_OVERLAY_SUB_NODE; if ((newNode->flags & ISO_ISDIR) == 0) { newNode->cache = file_cache_create(ns->id, vnodeID, diff --git a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c index a327c8de39..31d3ad1017 100644 --- a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c +++ b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c @@ -898,7 +898,7 @@ fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid) isLink=S_ISLNK(st.st_mode); } - if ((result=get_vnode (_volume,*vnid,(void **)&dummy))volume, device->id, (void**)&partition->raw_device); + status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device, + NULL); if (status < B_OK) goto err1; @@ -937,7 +938,7 @@ devfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id) { struct devfs *fs = (struct devfs *)_volume->private_volume; struct devfs_vnode *dir = (struct devfs_vnode *)_dir->private_node; - struct devfs_vnode *vnode, *vdummy; + struct devfs_vnode *vnode; status_t status; TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name)); @@ -958,7 +959,7 @@ devfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id) return B_ENTRY_NOT_FOUND; } - status = get_vnode(fs->volume, vnode->id, (void**)&vdummy); + status = get_vnode(fs->volume, vnode->id, NULL, NULL); if (status < B_OK) return status; @@ -1062,7 +1063,7 @@ devfs_create(fs_volume* _volume, fs_vnode* _dir, const char* name, int openMode, if (openMode & O_EXCL) return B_FILE_EXISTS; - status = get_vnode(fs->volume, vnode->id, NULL); + status = get_vnode(fs->volume, vnode->id, NULL, NULL); if (status < B_OK) return status; @@ -2091,7 +2092,7 @@ devfs_unpublish_device(BaseDevice* device, bool disconnect) { devfs_vnode* node; status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(), - (void**)&node); + (void**)&node, NULL); if (status != B_OK) return status; diff --git a/src/system/kernel/fs/Jamfile b/src/system/kernel/fs/Jamfile index 6cb6fa7a4f..7b8f2411ac 100644 --- a/src/system/kernel/fs/Jamfile +++ b/src/system/kernel/fs/Jamfile @@ -12,6 +12,7 @@ KernelMergeObject kernel_fs.o : fifo.cpp KPath.cpp node_monitor.cpp + overlay.cpp rootfs.cpp socket.cpp vfs.cpp diff --git a/src/system/kernel/fs/overlay.cpp b/src/system/kernel/fs/overlay.cpp new file mode 100644 index 0000000000..b8fc5ee604 --- /dev/null +++ b/src/system/kernel/fs/overlay.cpp @@ -0,0 +1,1097 @@ +/* + * Copyright 2009, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "overlay.h" + + +//#define TRACE_OVERLAY +#ifdef TRACE_OVERLAY +#define TRACE(x...) dprintf("overlay: " x) +#define TRACE_ALWAYS(x...) dprintf("overlay: " x) +#else +#define TRACE(x...) /* nothing */ +#define TRACE_ALWAYS(x...) dprintf("overlay: " x) +#endif + + +namespace overlay { + +class AttributeFile; +class AttributeEntry; + + +class OverlayInode { +public: + OverlayInode(fs_volume *superVolume, + fs_vnode *superVnode); + ~OverlayInode(); + + status_t InitCheck(); + + fs_vnode * SuperVnode() { return &fSuperVnode; } + + AttributeFile * GetAttributeFile(); + +private: + fs_volume fSuperVolume; + fs_vnode fSuperVnode; + AttributeFile * fAttributeFile; +}; + + +class AttributeFile { +public: + AttributeFile(fs_volume *volume, fs_vnode *vnode); + ~AttributeFile(); + + status_t InitCheck() { return fStatus; } + + dev_t VolumeID() { return fVolumeID; } + ino_t ParentInode() { return fParentInode; } + + uint32 CountAttributes(); + AttributeEntry * FindAttribute(const char *name); + + status_t ReadAttributeDir(struct dirent *dirent, + size_t bufferSize, uint32 *numEntries); + status_t RewindAttributeDir() + { + fAttributeDirIndex = 0; + return B_OK; + } + +private: + #define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr' + #define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME "_HAIKU" + + struct attribute_file { + uint32 magic; // 'attr' + uint32 entry_count; + uint8 entries[1]; + } _PACKED; + + status_t fStatus; + dev_t fVolumeID; + ino_t fParentInode; + attribute_file * fFile; + uint32 fAttributeDirIndex; + AttributeEntry ** fEntries; +}; + + +class AttributeEntry { +public: + AttributeEntry(AttributeFile *parent, + uint8 *buffer); + ~AttributeEntry(); + + size_t EntrySize(); + + uint8 NameLength() { return fEntry->name_length; } + const char * Name() { return fEntry->name; } + + status_t FillDirent(struct dirent *dirent, + size_t bufferSize, uint32 *numEntries); + + status_t Read(off_t position, void *buffer, size_t *length); + status_t ReadStat(struct stat *stat); + +private: + struct attribute_entry { + type_code type; + uint32 size; + uint8 name_length; // including 0 byte + char name[1]; // 0 terminated, followed by data + } _PACKED; + + AttributeFile * fParent; + attribute_entry * fEntry; + uint8 * fData; +}; + + +// #pragma mark OverlayInode + + +OverlayInode::OverlayInode(fs_volume *superVolume, fs_vnode *superVnode) + : fSuperVolume(*superVolume), + fSuperVnode(*superVnode), + fAttributeFile(NULL) +{ + TRACE("inode created\n"); +} + + +OverlayInode::~OverlayInode() +{ + TRACE("inode destroyed\n"); + delete fAttributeFile; +} + + +status_t +OverlayInode::InitCheck() +{ + return B_OK; +} + + +AttributeFile * +OverlayInode::GetAttributeFile() +{ + if (fAttributeFile == NULL) { + fAttributeFile = new(std::nothrow) AttributeFile(&fSuperVolume, + &fSuperVnode); + if (fAttributeFile == NULL) { + TRACE_ALWAYS("no memory to allocate attribute file\n"); + return NULL; + } + } + + if (fAttributeFile->InitCheck() != B_OK) + return NULL; + + return fAttributeFile; +} + + +// #pragma mark AttributeFile + + +AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) + : fStatus(B_NO_INIT), + fVolumeID(volume->id), + fParentInode(0), + fFile(NULL), + fAttributeDirIndex(0), + fEntries(NULL) +{ + if (vnode->ops->get_vnode_name == NULL) { + TRACE_ALWAYS("cannot get vnode name, hook missing\n"); + fStatus = B_UNSUPPORTED; + return; + } + + char nameBuffer[B_FILE_NAME_LENGTH]; + nameBuffer[sizeof(nameBuffer) - 1] = 0; + fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, + sizeof(nameBuffer) - 1); + if (fStatus != B_OK) { + TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus)); + return; + } + + if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { + // we don't want attribute overlays on the attribute dir itself + fStatus = B_UNSUPPORTED; + return; + } + + struct stat stat; + if (vnode->ops->read_stat != NULL + && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { + fParentInode = stat.st_ino; + } + + // TODO: the ".." lookup is not actually valid for non-directory vnodes. + // we make use of the fact that a filesystem probably still provides the + // lookup hook and has hardcoded ".." to resolve to the parent entry. if we + // wanted to do this correctly we need some other way to relate this vnode + // to its parent directory vnode. + const char *lookup[] + = { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer }; + int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]); + fs_vnode currentVnode = *vnode; + ino_t lastInodeNumber = 0; + + for (int32 i = 0; i < lookupCount; i++) { + if (currentVnode.ops->lookup == NULL) { + TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); + fStatus = B_UNSUPPORTED; + if (i > 0) + put_vnode(volume, lastInodeNumber); + return; + } + + ino_t inodeNumber; + fStatus = currentVnode.ops->lookup(volume, ¤tVnode, lookup[i], + &inodeNumber); + + if (i > 0) + put_vnode(volume, lastInodeNumber); + + if (fStatus != B_OK) { + if (fStatus != B_ENTRY_NOT_FOUND) { + TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i], + strerror(fStatus)); + } + return; + } + + fStatus = get_vnode(volume, inodeNumber, ¤tVnode.private_node, + ¤tVnode.ops); + if (fStatus != B_OK) { + TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus)); + return; + } + + lastInodeNumber = inodeNumber; + } + + if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL + || currentVnode.ops->read == NULL) { + TRACE_ALWAYS("can't use attribute file, hooks missing\n"); + put_vnode(volume, lastInodeNumber); + fStatus = B_UNSUPPORTED; + return; + } + + fStatus = currentVnode.ops->read_stat(volume, ¤tVnode, &stat); + if (fStatus != B_OK) { + TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus)); + put_vnode(volume, lastInodeNumber); + return; + } + + void *attrFileCookie = NULL; + fStatus = currentVnode.ops->open(volume, ¤tVnode, O_RDONLY, + &attrFileCookie); + if (fStatus != B_OK) { + TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus)); + put_vnode(volume, lastInodeNumber); + return; + } + + size_t readLength = stat.st_size; + uint8 *buffer = (uint8 *)malloc(readLength); + if (buffer == NULL) { + TRACE_ALWAYS("cannot allocate memory for read buffer\n"); + put_vnode(volume, lastInodeNumber); + fStatus = B_NO_MEMORY; + return; + } + + fStatus = currentVnode.ops->read(volume, ¤tVnode, attrFileCookie, 0, + buffer, &readLength); + if (fStatus != B_OK) { + TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus)); + put_vnode(volume, lastInodeNumber); + return; + } + + if (currentVnode.ops->close != NULL) + currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); + if (currentVnode.ops->free_cookie != NULL) + currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); + + put_vnode(volume, lastInodeNumber); + + fFile = (attribute_file *)buffer; + if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) { + TRACE_ALWAYS("attribute file has bad magic\n"); + fStatus = B_BAD_VALUE; + return; + } + + fEntries = new(std::nothrow) AttributeEntry *[fFile->entry_count]; + if (fEntries == NULL) { + TRACE_ALWAYS("no memory to allocate entry pointers\n"); + fStatus = B_NO_MEMORY; + return; + } + + for (uint32 i = 0; i < fFile->entry_count; i++) + fEntries[i] = NULL; + + size_t totalSize = 0; + readLength -= sizeof(attribute_file) - 1; + for (uint32 i = 0; i < fFile->entry_count; i++) { + fEntries[i] = new(std::nothrow) AttributeEntry(this, + fFile->entries + totalSize); + if (fEntries[i] == NULL) { + TRACE_ALWAYS("no memory to allocate attribute entry\n"); + fStatus = B_NO_MEMORY; + return; + } + + totalSize += fEntries[i]->EntrySize(); + if (totalSize > readLength) { + TRACE_ALWAYS("attribute entries are too large for buffer\n"); + fStatus = B_BAD_VALUE; + return; + } + } +} + + +AttributeFile::~AttributeFile() +{ + if (fFile == NULL) + return; + + if (fEntries != NULL) { + for (uint32 i = 0; i < fFile->entry_count; i++) + delete fEntries[i]; + + delete [] fEntries; + } + + free(fFile); +} + + +uint32 +AttributeFile::CountAttributes() +{ + if (fFile == NULL) + return 0; + + return fFile->entry_count; +} + + +AttributeEntry * +AttributeFile::FindAttribute(const char *name) +{ + if (fFile == NULL) + return NULL; + + for (uint32 i = 0; i < fFile->entry_count; i++) { + if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) + return fEntries[i]; + } + + return NULL; +} + + +status_t +AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, + uint32 *numEntries) +{ + if (fFile == NULL || fAttributeDirIndex >= fFile->entry_count) { + *numEntries = 0; + return B_OK; + } + + return fEntries[fAttributeDirIndex++]->FillDirent(dirent, bufferSize, + numEntries); +} + + +// #pragma mark AttributeEntry + + +AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) + : fParent(parent), + fEntry(NULL), + fData(NULL) +{ + fEntry = (attribute_entry *)buffer; + fData = (uint8 *)fEntry->name + fEntry->name_length; +} + + +AttributeEntry::~AttributeEntry() +{ +} + + +size_t +AttributeEntry::EntrySize() +{ + return sizeof(attribute_entry) - 1 + fEntry->name_length + fEntry->size; +} + + +status_t +AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, + uint32 *numEntries) +{ + dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); + dirent->d_ino = (ino_t)this; + dirent->d_pino = fParent->ParentInode(); + dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; + if (bufferSize < dirent->d_reclen) { + *numEntries = 0; + return B_BAD_VALUE; + } + + strncpy(dirent->d_name, fEntry->name, fEntry->name_length); + dirent->d_name[fEntry->name_length - 1] = 0; + *numEntries = 1; + return B_OK; +} + + +status_t +AttributeEntry::Read(off_t position, void *buffer, size_t *length) +{ + *length = min_c(*length, fEntry->size); + if (*length <= position) { + *length = 0; + return B_OK; + } + + *length -= position; + memcpy(buffer, fData + position, *length); + return B_OK; +} + + +status_t +AttributeEntry::ReadStat(struct stat *stat) +{ + stat->st_dev = fParent->VolumeID(); + stat->st_ino = (ino_t)this; + stat->st_nlink = 1; + stat->st_blksize = 512; + stat->st_uid = 1; + stat->st_gid = 1; + stat->st_size = fEntry->size; + stat->st_mode = S_ATTR | 0x0777; + stat->st_type = fEntry->type; + stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL); + stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize; + return B_OK; +} + + +// #pragma mark - + + +static status_t +overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) +{ + OverlayInode *node = (OverlayInode *)vnode->private_node; + fs_vnode *superVnode = node->SuperVnode(); + + status_t result = B_OK; + if (superVnode->ops->put_vnode != NULL) + result = superVnode->ops->put_vnode(volume, superVnode, reenter); + + delete node; + return result; +} + + +static status_t +overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) +{ + OverlayInode *node = (OverlayInode *)vnode->private_node; + fs_vnode *superVnode = node->SuperVnode(); + + status_t result = B_OK; + if (superVnode->ops->remove_vnode != NULL) + result = superVnode->ops->remove_vnode(volume, superVnode, reenter); + + delete node; + return result; +} + + +static status_t +overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, + fs_volume *superVolume, fs_vnode *_superVnode) +{ + OverlayInode *node = (OverlayInode *)vnode->private_node; + fs_vnode *superVnode = node->SuperVnode(); + + if (superVnode->ops->get_super_vnode != NULL) { + return superVnode->ops->get_super_vnode(volume, superVnode, superVolume, + _superVnode); + } + + *_superVnode = *superVnode; + return B_OK; +} + + +// #pragma mark - + + +#define OVERLAY_CALL(op, params...) \ + TRACE("relaying op: " #op "\n"); \ + OverlayInode *node = (OverlayInode *)vnode->private_node; \ + fs_vnode *superVnode = node->SuperVnode(); \ + if (superVnode->ops->op != NULL) \ + return superVnode->ops->op(volume, superVnode, params); + + +static status_t +overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) +{ + OVERLAY_CALL(lookup, name, id) + return B_UNSUPPORTED; +} + + +static status_t +overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, + size_t bufferSize) +{ + OVERLAY_CALL(get_vnode_name, buffer, bufferSize) + return B_UNSUPPORTED; +} + + +static bool +overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(can_page, cookie) + return false; +} + + +static status_t +overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const iovec *vecs, size_t count, size_t *numBytes) +{ + OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes) + return B_UNSUPPORTED; +} + + +static status_t +overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const iovec *vecs, size_t count, size_t *numBytes) +{ + OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes) + return B_UNSUPPORTED; +} + + +#if 0 +static status_t +overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, + io_request *request) +{ + OVERLAY_CALL(io, cookie, request) + return B_UNSUPPORTED; +} +#endif + + +static status_t +overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, + io_request *request) +{ + OVERLAY_CALL(cancel_io, cookie, request) + return B_UNSUPPORTED; +} + + +static status_t +overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, + size_t size, struct file_io_vec *vecs, size_t *count) +{ + OVERLAY_CALL(get_file_map, offset, size, vecs, count) + return B_UNSUPPORTED; +} + + +static status_t +overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op, + void *buffer, size_t length) +{ + OVERLAY_CALL(ioctl, cookie, op, buffer, length) + return B_UNSUPPORTED; +} + + +static status_t +overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, + int flags) +{ + OVERLAY_CALL(set_flags, cookie, flags) + return B_UNSUPPORTED; +} + + +static status_t +overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, + selectsync *sync) +{ + OVERLAY_CALL(select, cookie, event, sync) + return B_UNSUPPORTED; +} + + +static status_t +overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, + selectsync *sync) +{ + OVERLAY_CALL(deselect, cookie, event, sync) + return B_UNSUPPORTED; +} + + +static status_t +overlay_fsync(fs_volume *volume, fs_vnode *vnode) +{ + OverlayInode *node = (OverlayInode *)vnode->private_node; + fs_vnode *superVnode = node->SuperVnode(); + + if (superVnode->ops->fsync != NULL) + return superVnode->ops->fsync(volume, superVnode); + + return B_OK; +} + + +static status_t +overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, + size_t *bufferSize) +{ + OVERLAY_CALL(read_symlink, buffer, bufferSize) + return B_UNSUPPORTED; +} + + +static status_t +overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, + const char *path, int mode) +{ + OVERLAY_CALL(create_symlink, name, path, mode) + return B_UNSUPPORTED; +} + + +static status_t +overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, + fs_vnode *target) +{ + OVERLAY_CALL(link, name, target) + return B_UNSUPPORTED; +} + + +static status_t +overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + OVERLAY_CALL(unlink, name) + return B_UNSUPPORTED; +} + + +static status_t +overlay_rename(fs_volume *volume, fs_vnode *vnode, + const char *fromName, fs_vnode *toDir, const char *toName) +{ + OVERLAY_CALL(rename, fromName, toDir, toName) + return B_UNSUPPORTED; +} + + +static status_t +overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) +{ + OVERLAY_CALL(access, mode) + return B_UNSUPPORTED; +} + + +static status_t +overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) +{ + OVERLAY_CALL(read_stat, stat) + return B_UNSUPPORTED; +} + + +static status_t +overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, + uint32 statMask) +{ + OVERLAY_CALL(write_stat, stat, statMask) + return B_UNSUPPORTED; +} + + +static status_t +overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, + int openMode, int perms, void **cookie, ino_t *newVnodeID) +{ + OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID) + return B_UNSUPPORTED; +} + + +static status_t +overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) +{ + OVERLAY_CALL(open, openMode, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(close, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(free_cookie, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + void *buffer, size_t *length) +{ + OVERLAY_CALL(read, cookie, pos, buffer, length) + return B_UNSUPPORTED; +} + + +static status_t +overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const void *buffer, size_t *length) +{ + OVERLAY_CALL(write, cookie, pos, buffer, length) + return B_UNSUPPORTED; +} + + +static status_t +overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, + int perms, ino_t *newVnodeID) +{ + OVERLAY_CALL(create_dir, name, perms, newVnodeID) + return B_UNSUPPORTED; +} + + +static status_t +overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + OVERLAY_CALL(remove_dir, name) + return B_UNSUPPORTED; +} + + +static status_t +overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) +{ + OVERLAY_CALL(open_dir, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(close_dir, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(free_dir_cookie, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct dirent *buffer, size_t bufferSize, uint32 *num) +{ + OVERLAY_CALL(read_dir, cookie, buffer, bufferSize, num) + return B_UNSUPPORTED; +} + + +static status_t +overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(rewind_dir, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) +{ + OVERLAY_CALL(open_attr_dir, cookie) + AttributeFile *attributeFile = node->GetAttributeFile(); + if (attributeFile == NULL) + return B_UNSUPPORTED; + + *cookie = attributeFile; + return B_OK; +} + + +static status_t +overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(close_attr_dir, cookie) + return B_OK; +} + + +static status_t +overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(free_attr_dir_cookie, cookie) + return B_OK; +} + + +static status_t +overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct dirent *buffer, size_t bufferSize, uint32 *num) +{ + OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num) + AttributeFile *attributeFile = (AttributeFile *)cookie; + return attributeFile->ReadAttributeDir(buffer, bufferSize, num); +} + + +static status_t +overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(rewind_attr_dir, cookie) + AttributeFile *attributeFile = (AttributeFile *)cookie; + return attributeFile->RewindAttributeDir(); +} + + +static status_t +overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, + uint32 type, int openMode, void **cookie) +{ + OVERLAY_CALL(create_attr, name, type, openMode, cookie) + return B_UNSUPPORTED; +} + + +static status_t +overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, + int openMode, void **cookie) +{ + OVERLAY_CALL(open_attr, name, openMode, cookie) + + AttributeFile *attributeFile = node->GetAttributeFile(); + if (attributeFile == NULL) + return B_UNSUPPORTED; + + AttributeEntry *entry = attributeFile->FindAttribute(name); + if (entry == NULL) + return B_ENTRY_NOT_FOUND; + + *cookie = entry; + return B_OK; +} + + +static status_t +overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(close_attr, cookie) + return B_OK; +} + + +static status_t +overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + OVERLAY_CALL(free_attr_cookie, cookie) + return B_OK; +} + + +static status_t +overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + void *buffer, size_t *length) +{ + OVERLAY_CALL(read_attr, cookie, pos, buffer, length) + AttributeEntry *entry = (AttributeEntry *)cookie; + return entry->Read(pos, buffer, length); +} + + +static status_t +overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const void *buffer, size_t *length) +{ + OVERLAY_CALL(write_attr, cookie, pos, buffer, length) + return B_UNSUPPORTED; +} + + +static status_t +overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct stat *stat) +{ + OVERLAY_CALL(read_attr_stat, cookie, stat) + AttributeEntry *entry = (AttributeEntry *)cookie; + return entry->ReadStat(stat); +} + + +static status_t +overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, + const struct stat *stat, int statMask) +{ + OVERLAY_CALL(write_attr_stat, cookie, stat, statMask) + return B_UNSUPPORTED; +} + + +static status_t +overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, + const char *fromName, fs_vnode *toVnode, const char *toName) +{ + OVERLAY_CALL(rename_attr, fromName, toVnode, toName) + return B_UNSUPPORTED; +} + + +static status_t +overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + OVERLAY_CALL(remove_attr, name) + return B_UNSUPPORTED; +} + + +static status_t +overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, + const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, + fs_vnode *_superVnode, ino_t *nodeID) +{ + OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID) + return B_UNSUPPORTED; +} + + +// #pragma mark - + + +static fs_vnode_ops sOverlayVnodeOps = { + &overlay_lookup, + &overlay_get_vnode_name, + + &overlay_put_vnode, + &overlay_remove_vnode, + + &overlay_can_page, + &overlay_read_pages, + &overlay_write_pages, + + // TODO: the io scheduler uses it when available but we may simply + // return B_UNSUPPORTED and I'm not sure it then falls back correctly + NULL, //&overlay_io, + &overlay_cancel_io, + + &overlay_get_file_map, + + /* common */ + &overlay_ioctl, + &overlay_set_flags, + &overlay_select, + &overlay_deselect, + &overlay_fsync, + + &overlay_read_symlink, + &overlay_create_symlink, + &overlay_link, + &overlay_unlink, + &overlay_rename, + + &overlay_access, + &overlay_read_stat, + &overlay_write_stat, + + /* file */ + &overlay_create, + &overlay_open, + &overlay_close, + &overlay_free_cookie, + &overlay_read, + &overlay_write, + + /* directory */ + &overlay_create_dir, + &overlay_remove_dir, + &overlay_open_dir, + &overlay_close_dir, + &overlay_free_dir_cookie, + &overlay_read_dir, + &overlay_rewind_dir, + + /* attribute directory operations */ + &overlay_open_attr_dir, + &overlay_close_attr_dir, + &overlay_free_attr_dir_cookie, + &overlay_read_attr_dir, + &overlay_rewind_attr_dir, + + /* attribute operations */ + &overlay_create_attr, + &overlay_open_attr, + &overlay_close_attr, + &overlay_free_attr_cookie, + &overlay_read_attr, + &overlay_write_attr, + + &overlay_read_attr_stat, + &overlay_write_attr_stat, + &overlay_rename_attr, + &overlay_remove_attr, + + /* support for node and FS layers */ + &overlay_create_special_node, + &overlay_get_super_vnode +}; + + +} // namespace _overlay + +using namespace overlay; + + +// #pragma mark - + + +status_t +create_overlay_vnode(fs_volume *superVolume, fs_vnode *vnode) +{ + OverlayInode *node = new(std::nothrow) OverlayInode(superVolume, vnode); + if (node == NULL) + return B_NO_MEMORY; + + status_t status = node->InitCheck(); + if (status != B_OK) { + delete node; + return status; + } + + vnode->private_node = node; + vnode->ops = &sOverlayVnodeOps; + return B_OK; +} diff --git a/src/system/kernel/fs/overlay.h b/src/system/kernel/fs/overlay.h new file mode 100644 index 0000000000..0cf27fcb43 --- /dev/null +++ b/src/system/kernel/fs/overlay.h @@ -0,0 +1,16 @@ +/* + * Copyright 2009, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#ifndef _VFS_OVERLAY_H +#define _VFS_OVERLAY_H + +#include + +status_t create_overlay_vnode(fs_volume *superVolume, fs_vnode *vnode); + +#endif // _VFS_OVERLAY_H diff --git a/src/system/kernel/fs/rootfs.cpp b/src/system/kernel/fs/rootfs.cpp index 93a4fefc13..d7d2ef1ef8 100644 --- a/src/system/kernel/fs/rootfs.cpp +++ b/src/system/kernel/fs/rootfs.cpp @@ -284,8 +284,7 @@ remove_node(struct rootfs *fs, struct rootfs_vnode *directory, { // schedule this vnode to be removed when it's ref goes to zero - void* dummy; - bool gotNode = (get_vnode(fs->volume, vnode->id, &dummy) == B_OK); + bool gotNode = (get_vnode(fs->volume, vnode->id, NULL, NULL) == B_OK); status_t status = B_OK; if (gotNode) @@ -432,7 +431,7 @@ rootfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id) { struct rootfs *fs = (struct rootfs *)_volume->private_volume; struct rootfs_vnode *dir = (struct rootfs_vnode *)_dir->private_node; - struct rootfs_vnode *vnode,*vdummy; + struct rootfs_vnode *vnode; status_t status; TRACE(("rootfs_lookup: entry dir %p, name '%s'\n", dir, name)); @@ -448,7 +447,7 @@ rootfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id) goto err; } - status = get_vnode(fs->volume, vnode->id, (void**)&vdummy); + status = get_vnode(fs->volume, vnode->id, NULL, NULL); if (status < B_OK) goto err; diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 5676311667..ef1d7fded4 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -54,6 +54,7 @@ #include "fifo.h" #include "io_requests.h" +#include "overlay.h" //#define TRACE_VFS @@ -1180,6 +1181,9 @@ create_special_sub_node(struct vnode* vnode, uint32 flags) if (S_ISFIFO(vnode->type)) return create_fifo_vnode(vnode->mount->volume, vnode); + if ((flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0) + return create_overlay_vnode(vnode->mount->volume, vnode); + return B_BAD_VALUE; } @@ -1253,7 +1257,8 @@ restart: bool publishSpecialSubNode = false; if (gotNode) { vnode->type = type; - publishSpecialSubNode = is_special_node_type(type) + publishSpecialSubNode = (is_special_node_type(type) + || (flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0) && (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0; } @@ -2485,8 +2490,9 @@ get_vnode_name(struct vnode *vnode, struct vnode *parent, struct dirent *buffer, if (HAS_FS_CALL(vnode, get_vnode_name)) { // The FS supports getting the name of a vnode. - return FS_CALL(vnode, get_vnode_name, buffer->d_name, - (char*)buffer + bufferSize - buffer->d_name); + if (FS_CALL(vnode, get_vnode_name, buffer->d_name, + (char*)buffer + bufferSize - buffer->d_name) == B_OK) + return B_OK; } // The FS doesn't support getting the name of a vnode. So we search the @@ -3584,7 +3590,8 @@ publish_vnode(fs_volume *volume, ino_t vnodeID, void *privateNode, extern "C" status_t -get_vnode(fs_volume *volume, ino_t vnodeID, void **_fsNode) +get_vnode(fs_volume *volume, ino_t vnodeID, void **_privateNode, + fs_vnode_ops **_vnodeOps) { struct vnode *vnode; @@ -3608,10 +3615,16 @@ get_vnode(fs_volume *volume, ino_t vnodeID, void **_fsNode) return status; } - if (_fsNode != NULL) - *_fsNode = resolvedNode.private_node; - } else if (_fsNode != NULL) - *_fsNode = vnode->private_node; + if (_privateNode != NULL) + *_privateNode = resolvedNode.private_node; + if (_vnodeOps != NULL) + *_vnodeOps = resolvedNode.ops; + } else { + if (_privateNode != NULL) + *_privateNode = vnode->private_node; + if (_vnodeOps != NULL) + *_vnodeOps = vnode->ops; + } return B_OK; } @@ -4005,7 +4018,7 @@ vfs_get_fs_node_from_path(fs_volume *volume, const char *path, bool kernel, } // Use get_vnode() to resolve the cookie for the right layer. - status = get_vnode(volume, vnode->id, _node); + status = get_vnode(volume, vnode->id, _node, NULL); put_vnode(vnode); return status; diff --git a/src/system/kernel/fs/vfs_request_io.cpp b/src/system/kernel/fs/vfs_request_io.cpp index b91f7b66cf..c7be98a405 100644 --- a/src/system/kernel/fs/vfs_request_io.cpp +++ b/src/system/kernel/fs/vfs_request_io.cpp @@ -401,14 +401,16 @@ synchronous_io(io_request* request, DoIO& io) status_t vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request) { - if (!HAS_FS_CALL(vnode, io)) { + status_t result = B_ERROR; + if (!HAS_FS_CALL(vnode, io) + || (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) { // no io() call -- fall back to synchronous I/O IOBuffer* buffer = request->Buffer(); VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, cookie); return synchronous_io(request, io); } - return FS_CALL(vnode, io, cookie, request); + return result; } diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp index 8d14b8621f..fb5eeacbb3 100644 --- a/src/tools/fs_shell/vfs.cpp +++ b/src/tools/fs_shell/vfs.cpp @@ -1985,7 +1985,8 @@ fssh_publish_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, extern "C" fssh_status_t -fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, void **fsNode) +fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, + void **privateNode, fssh_fs_vnode_ops **vnodeOps) { struct vnode *vnode; @@ -2009,9 +2010,16 @@ fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, void **fsNode) return status; } - *fsNode = resolvedNode.private_node; - } else - *fsNode = vnode->private_node; + if (privateNode != NULL) + *privateNode = resolvedNode.private_node; + if (vnodeOps != NULL) + *vnodeOps = resolvedNode.ops; + } else { + if (privateNode != NULL) + *privateNode = vnode->private_node; + if (vnodeOps != NULL) + *vnodeOps = vnode->ops; + } return FSSH_B_OK; } @@ -2443,7 +2451,7 @@ vfs_get_fs_node_from_path(fssh_fs_volume *volume, const char *path, bool kernel, } // Use get_vnode() to resolve the cookie for the right layer. - status = ::fssh_get_vnode(volume, vnode->id, _node); + status = ::fssh_get_vnode(volume, vnode->id, _node, NULL); put_vnode(vnode); return FSSH_B_OK;