diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index ecf2297b74..eed16d95df 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -87,6 +87,7 @@ status_t vfs_entry_ref_to_vnode(dev_t mountID, ino_t directoryID, const char *name, struct vnode **_vnode); void vfs_vnode_to_node_ref(struct vnode *vnode, dev_t *_mountID, ino_t *_vnodeID); +struct fs_vnode* vfs_fsnode_for_vnode(struct vnode* vnode); int vfs_open_vnode(struct vnode* vnode, int openMode, bool kernel); status_t vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, diff --git a/src/add-ons/kernel/file_systems/Jamfile b/src/add-ons/kernel/file_systems/Jamfile index d62fd6295d..e592797738 100644 --- a/src/add-ons/kernel/file_systems/Jamfile +++ b/src/add-ons/kernel/file_systems/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems ; SubInclude HAIKU_TOP src add-ons kernel file_systems bfs ; +SubInclude HAIKU_TOP src add-ons kernel file_systems bindfs ; SubInclude HAIKU_TOP src add-ons kernel file_systems cdda ; SubInclude HAIKU_TOP src add-ons kernel file_systems ext2 ; SubInclude HAIKU_TOP src add-ons kernel file_systems fat ; diff --git a/src/add-ons/kernel/file_systems/bindfs/DebugSupport.cpp b/src/add-ons/kernel/file_systems/bindfs/DebugSupport.cpp new file mode 100644 index 0000000000..8377cf340c --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/DebugSupport.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "DebugSupport.h" + +#include +#include +#include +#include +#include +#include + +#include + + +/*! + \file Debug.cpp + \brief Defines debug output function with printf() signature printing + into a file. + + \note The initialization is not thread safe! +*/ + + +// locking support +static int32 init_counter = 0; +static sem_id dbg_printf_sem = -1; +static thread_id dbg_printf_thread = -1; +static int dbg_printf_nesting = 0; + + +#if DEBUG_PRINT +static int out = -1; +#endif + + +status_t +init_debugging() +{ + status_t error = B_OK; + if (init_counter++ == 0) { + // open the file + #if DEBUG_PRINT + out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC); + if (out < 0) { + error = errno; + init_counter--; + } + #endif // DEBUG_PRINT + // allocate the semaphore + if (error == B_OK) { + dbg_printf_sem = create_sem(1, "dbg_printf"); + if (dbg_printf_sem < 0) + error = dbg_printf_sem; + } + if (error == B_OK) { + #if DEBUG + __out("##################################################\n"); + #endif + } else + exit_debugging(); + } + return error; +} + + +status_t +exit_debugging() +{ + status_t error = B_OK; + if (--init_counter == 0) { + #if DEBUG_PRINT + close(out); + out = -1; + #endif // DEBUG_PRINT + delete_sem(dbg_printf_sem); + } else + error = B_NO_INIT; + return error; +} + + +static inline bool +dbg_printf_lock() +{ + thread_id thread = find_thread(NULL); + if (thread != dbg_printf_thread) { + if (acquire_sem(dbg_printf_sem) != B_OK) + return false; + dbg_printf_thread = thread; + } + dbg_printf_nesting++; + return true; +} + + +static inline void +dbg_printf_unlock() +{ + thread_id thread = find_thread(NULL); + if (thread != dbg_printf_thread) + return; + dbg_printf_nesting--; + if (dbg_printf_nesting == 0) { + dbg_printf_thread = -1; + release_sem(dbg_printf_sem); + } +} + + +void +dbg_printf_begin() +{ + dbg_printf_lock(); +} + + +void +dbg_printf_end() +{ + dbg_printf_unlock(); +} + + +#if DEBUG_PRINT + +void +dbg_printf(const char *format,...) +{ + if (!dbg_printf_lock()) + return; + char buffer[1024]; + va_list args; + va_start(args, format); + // no vsnprintf() on PPC and in kernel + #if defined(__INTEL__) && USER + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + #else + vsprintf(buffer, format, args); + #endif + va_end(args); + buffer[sizeof(buffer) - 1] = '\0'; + write(out, buffer, strlen(buffer)); + dbg_printf_unlock(); +} + +#endif // DEBUG_PRINT diff --git a/src/add-ons/kernel/file_systems/bindfs/DebugSupport.h b/src/add-ons/kernel/file_systems/bindfs/DebugSupport.h new file mode 100644 index 0000000000..394e1ba69c --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/DebugSupport.h @@ -0,0 +1,180 @@ +/* + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 200?, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEBUG_SUPPORT_H +#define DEBUG_SUPPORT_H + + +#include + + +#if !USER +# include +#endif +#include +#include + + +// define all macros we work with -- undefined macros are set to defaults +#ifndef USER +# define USER 0 +#endif +#ifndef DEBUG +# define DEBUG 0 +#endif +#if !DEBUG +# undef DEBUG_PRINT +# define DEBUG_PRINT 0 +#endif +#ifndef DEBUG_PRINT +# define DEBUG_PRINT 0 +#endif +#ifndef DEBUG_APP +# define DEBUG_APP "bindfs" +#endif +#ifndef DEBUG_PRINT_FILE +# define DEBUG_PRINT_FILE "/var/log/" DEBUG_APP ".log" +#endif + + +// define the debug output function +#if USER +# include +# if DEBUG_PRINT +# define __out dbg_printf +# else +# define __out printf +# endif +#else +# include +# include +# if DEBUG_PRINT +# define __out dbg_printf +# else +# define __out dprintf +# endif +#endif + + +// define the PANIC() macro +#ifndef PANIC +# if USER +# define PANIC(str) debugger(str) +# else +# define PANIC(str) panic(str) +# endif +#endif + + +// functions exported by this module +status_t init_debugging(); +status_t exit_debugging(); +void dbg_printf_begin(); +void dbg_printf_end(); +#if DEBUG_PRINT + void dbg_printf(const char *format,...); +#else + static inline void dbg_printf(const char *,...) {} +#endif + + +// Short overview over the debug output macros: +// PRINT() +// is for general messages that very unlikely should appear in a release +// build +// FATAL() +// this is for fatal messages, when something has really gone wrong +// INFORM() +// general information, as disk size, etc. +// REPORT_ERROR(status_t) +// prints out error information +// RETURN_ERROR(status_t) +// calls REPORT_ERROR() and return the value +// D() +// the statements in D() are only included if DEBUG is defined + + +#define DEBUG_THREAD find_thread(NULL) +#define DEBUG_CONTEXT(x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] ", system_time(), DEBUG_THREAD); \ + x; \ + dbg_printf_end(); \ +} +#define DEBUG_CONTEXT_FUNCTION(prefix, x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] %s" prefix, system_time(), DEBUG_THREAD, \ + __PRETTY_FUNCTION__); \ + x; \ + dbg_printf_end(); \ +} +#define DEBUG_CONTEXT_LINE(x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] %s:%d: ", system_time(), DEBUG_THREAD, \ + __PRETTY_FUNCTION__, __LINE__); \ + x; \ + dbg_printf_end(); \ +} + +#define TPRINT(x...) DEBUG_CONTEXT( __out(x) ) +#define TREPORT_ERROR(status) \ + DEBUG_CONTEXT_LINE( __out("%s\n", strerror(status)) ) +#define TRETURN_ERROR(err) \ +{ \ + status_t _status = err; \ + if (_status < B_OK) \ + TREPORT_ERROR(_status); \ + return _status; \ +} +#define TSET_ERROR(var, err) \ +{ \ + status_t _status = err; \ + if (_status < B_OK) \ + TREPORT_ERROR(_status); \ + var = _status; \ +} +#define TFUNCTION(x...) DEBUG_CONTEXT_FUNCTION( ": ", __out(x) ) +#define TFUNCTION_START() DEBUG_CONTEXT_FUNCTION( "\n", ) +#define TFUNCTION_END() DEBUG_CONTEXT_FUNCTION( " done\n", ) + +#if DEBUG + #define PRINT(x...) TPRINT(x) + #define REPORT_ERROR(status) TREPORT_ERROR(status) + #define RETURN_ERROR(err) TRETURN_ERROR(err) + #define SET_ERROR(var, err) TSET_ERROR(var, err) + #define FATAL(x...) DEBUG_CONTEXT( __out(x) ) + #define ERROR(x...) DEBUG_CONTEXT( __out(x) ) + #define WARN(x...) DEBUG_CONTEXT( __out(x) ) + #define INFORM(x...) DEBUG_CONTEXT( __out(x) ) + #define FUNCTION(x...) TFUNCTION(x) + #define FUNCTION_START() TFUNCTION_START() + #define FUNCTION_END() TFUNCTION_END() + #define DARG(x) x + #define D(x) {x;}; +#else + #define PRINT(x...) ; + #define REPORT_ERROR(status) ; + #define RETURN_ERROR(status) return status; + #define SET_ERROR(var, err) var = err; + #define FATAL(x...) DEBUG_CONTEXT( __out(x) ) + #define ERROR(x...) DEBUG_CONTEXT( __out(x) ) + #define WARN(x...) DEBUG_CONTEXT( __out(x) ) + #define INFORM(x...) DEBUG_CONTEXT( __out(x) ) + #define FUNCTION(x...) ; + #define FUNCTION_START() ; + #define FUNCTION_END() ; + #define DARG(x) + #define D(x) ; +#endif + +#ifndef TOUCH +#define TOUCH(var) (void)var +#endif + + +#endif // DEBUG_SUPPORT_H diff --git a/src/add-ons/kernel/file_systems/bindfs/Jamfile b/src/add-ons/kernel/file_systems/bindfs/Jamfile new file mode 100644 index 0000000000..dd5d19091e --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Jamfile @@ -0,0 +1,23 @@ +SubDir HAIKU_TOP src add-ons kernel file_systems bindfs ; + + +UsePrivateKernelHeaders ; +# UsePrivateHeaders shared ; + + +HAIKU_BIND_FS_SOURCES = + DebugSupport.cpp + kernel_interface.cpp + Node.cpp + Volume.cpp +; + + +KernelAddon bindfs + : + $(HAIKU_BIND_FS_SOURCES) + : $(HAIKU_STATIC_LIBSUPC++) +; + + +#HaikuSubInclude userland ; diff --git a/src/add-ons/kernel/file_systems/bindfs/Node.cpp b/src/add-ons/kernel/file_systems/bindfs/Node.cpp new file mode 100644 index 0000000000..26534e587c --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Node.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include "Node.h" + + +Node::Node(ino_t id, mode_t mode) + : + fSourceID(id), + fMode(mode) +{ +} + + +Node::~Node() +{ +} diff --git a/src/add-ons/kernel/file_systems/bindfs/Node.h b/src/add-ons/kernel/file_systems/bindfs/Node.h new file mode 100644 index 0000000000..8c146a8144 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Node.h @@ -0,0 +1,29 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef NODE_H +#define NODE_H + + +#include + + +class Node { +public: + Node(ino_t sourceID, mode_t mode); + ~Node(); + + ino_t ID() const { return fSourceID; } + // currently, we reuse the source-ID + + ino_t SourceID() const { return fSourceID; } + mode_t Mode() const { return fMode; } + +protected: + ino_t fSourceID; + mode_t fMode; +}; + + +#endif // NODE_H diff --git a/src/add-ons/kernel/file_systems/bindfs/Utils.h b/src/add-ons/kernel/file_systems/bindfs/Utils.h new file mode 100644 index 0000000000..aaf71a3ff0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Utils.h @@ -0,0 +1,34 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef UTILS_H +#define UTILS_H + + +#include + +#include + + +using BPrivate::AutoDeleter; + + +struct VnodePut +{ + inline void operator()(vnode* _vnode) + { + if (_vnode != NULL) + vfs_put_vnode(_vnode); + } +}; + +struct VnodePutter : AutoDeleter +{ + VnodePutter() : AutoDeleter() {} + + VnodePutter(vnode* _vnode) : AutoDeleter(_vnode) {} +}; + + +#endif // UTILS_H diff --git a/src/add-ons/kernel/file_systems/bindfs/Volume.cpp b/src/add-ons/kernel/file_systems/bindfs/Volume.cpp new file mode 100644 index 0000000000..ec4f52db15 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Volume.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include "Volume.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include "DebugSupport.h" +#include "kernel_interface.h" +#include "Node.h" +#include "Utils.h" + + +// #pragma mark - Volume + + +Volume::Volume(fs_volume* fsVolume) + : + fFSVolume(fsVolume), + fSourceFSVolume(NULL), + fRootNode(NULL) +{ +} + + +Volume::~Volume() +{ + delete fRootNode; +} + + +status_t +Volume::Mount(const char* parameterString) +{ + const char* source = NULL; + void* parameterHandle = parse_driver_settings_string(parameterString); + if (parameterHandle != NULL) { + source = get_driver_parameter(parameterHandle, "source", NULL, NULL); + delete_driver_settings(parameterHandle); + } + if (source == NULL || source[0] == '\0') { + ERROR("need source folder ('source' parameter)!\n"); + RETURN_ERROR(B_BAD_VALUE); + } + + struct vnode* sourceVnode; + status_t error = vfs_get_vnode_from_path(source, true, &sourceVnode); + if (error != B_OK) + RETURN_ERROR(error); + if (sourceVnode == NULL) + RETURN_ERROR(B_ENTRY_NOT_FOUND); + fs_vnode* sourceFSNode = vfs_fsnode_for_vnode(sourceVnode); + fSourceFSVolume = volume_for_vnode(sourceFSNode); + + struct stat st; + if ((stat(source, &st)) != 0) + RETURN_ERROR(B_ERROR); + + strlcpy(fName, "bindfs:", sizeof(fName)); + strlcpy(fName, source, sizeof(fName)); + + // create the root node + fRootNode = new(std::nothrow) Node(st.st_ino, st.st_mode); + if (fRootNode == NULL) + RETURN_ERROR(B_NO_MEMORY); + + _InitVnodeOpsFrom(sourceFSNode); + + // publish the root node + error = publish_vnode(fFSVolume, fRootNode->ID(), fRootNode, &fVnodeOps, + fRootNode->Mode() & S_IFMT, 0); + if (error != B_OK) { + delete fRootNode; + fRootNode = NULL; + return error; + } + + return B_OK; +} + + +void +Volume::Unmount() +{ +} + + +status_t +Volume::_InitVnodeOpsFrom(fs_vnode* sourceNode) +{ + // vnode ops + int opsCount = sizeof(fVnodeOps) / sizeof(void*); + for (int i = 0; i < opsCount; ++i) { + if (((void**)sourceNode->ops)[i] == NULL) + ((void**)&fVnodeOps)[i] = NULL; + else + ((void**)&fVnodeOps)[i] = ((void**)&gBindFSVnodeOps)[i]; + } + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/bindfs/Volume.h b/src/add-ons/kernel/file_systems/bindfs/Volume.h new file mode 100644 index 0000000000..bacaba3036 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/Volume.h @@ -0,0 +1,52 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef VOLUME_H +#define VOLUME_H + + +#include + + +class Node; + + +class Volume { +public: + Volume(fs_volume* fsVolume); + ~Volume(); + + fs_volume* FSVolume() const { return fFSVolume; } + dev_t ID() const { return fFSVolume->id; } + + fs_volume* SourceFSVolume() const + { return fSourceFSVolume; } + + Node* RootNode() const { return fRootNode; } + const char* Name() const { return fName; } + + status_t Mount(const char* parameterString); + void Unmount(); + + const fs_vnode_ops* VnodeOps() const { return &fVnodeOps; } + +private: + struct VolumeListener; + friend struct VolumeListener; + +private: + status_t _InitVnodeOpsFrom(fs_vnode* sourceNode); + +private: + fs_volume* fFSVolume; + fs_volume* fSourceFSVolume; + Node* fRootNode; + + fs_vnode_ops fVnodeOps; + + char fName[B_PATH_NAME_LENGTH]; +}; + + +#endif // VOLUME_H diff --git a/src/add-ons/kernel/file_systems/bindfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bindfs/kernel_interface.cpp new file mode 100644 index 0000000000..72d642dd29 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/kernel_interface.cpp @@ -0,0 +1,1182 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + +#include + +#include + +#include "DebugSupport.h" +#include "kernel_interface.h" +#include "Node.h" +#include "Utils.h" +#include "Volume.h" + + +/*! \brief Binds an arbitrary folder to a given path (which must be that of a + folder, too). All requests to the mounted path will be passed to the + corresponding node of the bound (source) filesystem. + + TODO: node monitoring! + + TODO: path filter, such that /dev can be bind-mounted with only a subset + of entries +*/ + + +// #pragma mark - helper macros + + +#define FETCH_SOURCE_VOLUME_AND_NODE(volume, nodeID) \ + fs_volume* sourceVolume = volume->SourceFSVolume(); \ + if (sourceVolume == NULL) \ + RETURN_ERROR(B_ERROR); \ + vnode* sourceVnode; \ + status_t error = vfs_get_vnode(volume->SourceFSVolume()->id, \ + nodeID, true, &sourceVnode); \ + if (error != B_OK) \ + RETURN_ERROR(error); \ + VnodePutter putter(sourceVnode); \ + fs_vnode* sourceNode = vfs_fsnode_for_vnode(sourceVnode); \ + if (sourceNode == NULL) \ + RETURN_ERROR(B_ERROR); + + +// #pragma mark - Volume + + +static status_t +bindfs_mount(fs_volume* fsVolume, const char* device, uint32 flags, + const char* parameters, ino_t* _rootID) +{ + FUNCTION("fsVolume: %p, device: \"%s\", flags: %#lx, parameters: \"%s\"\n", + fsVolume, device, flags, parameters); + + // create a Volume object + Volume* volume = new(std::nothrow) Volume(fsVolume); + if (volume == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter volumeDeleter(volume); + + status_t error = volume->Mount(parameters); + if (error != B_OK) + return error; + + // set return values + *_rootID = volume->RootNode()->ID(); + fsVolume->private_volume = volumeDeleter.Detach(); + fsVolume->ops = &gBindFSVolumeOps; + + return B_OK; +} + + +static status_t +bindfs_unmount(fs_volume* fsVolume) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + + FUNCTION("volume: %p\n", volume); + + volume->Unmount(); + delete volume; + + return B_OK; +} + + +static status_t +bindfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + + FUNCTION("volume: %p, info: %p\n", volume, info); + + fs_volume* sourceVolume = volume->SourceFSVolume(); + + if (sourceVolume->ops->read_fs_info != NULL) { + status_t error = sourceVolume->ops->read_fs_info(sourceVolume, info); + if (error != B_OK) + RETURN_ERROR(error); + } else { + info->block_size = 512; + info->io_size = 64 * 1024; + } + + info->dev = volume->ID(); + info->root = volume->RootNode()->ID(); + info->total_blocks = info->free_blocks = 0; + info->total_nodes = info->free_nodes = 0; + + strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name)); + + return B_OK; +} + + +// #pragma mark - VNodes + + +static status_t +bindfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName, + ino_t* _vnid) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsDir->private_node; + + FUNCTION("volume: %p, dir: %p (%lld), entry: \"%s\"\n", volume, node, + node->ID(), entryName); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + error = sourceNode->ops->lookup(sourceVolume, sourceNode, entryName, _vnid); + if (error != B_OK) + RETURN_ERROR(error); + + return get_vnode(fsVolume, *_vnid, NULL); +} + + +static status_t +bindfs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode, + int* _type, uint32* _flags, bool reenter) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + + FUNCTION("volume: %p, vnid: %lld\n", volume, vnid); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, vnid); + + struct stat st; + error = sourceNode->ops->read_stat(sourceVolume, sourceNode, &st); + + Node* node = new(std::nothrow) Node(vnid, st.st_mode); + if (node == NULL) + RETURN_ERROR(B_NO_MEMORY); + + fsNode->private_node = node; + fsNode->ops = const_cast(volume->VnodeOps()); + *_type = node->Mode() & S_IFMT; + *_flags = 0; + + return B_OK; +} + + +static status_t +bindfs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, + size_t bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p\n", volume, node); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->get_vnode_name(sourceVolume, sourceNode, buffer, + bufferSize); +} + +static status_t +bindfs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p\n", volume, node); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + delete node; + + return B_OK; +} + + +static status_t +bindfs_remove_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p\n", volume, node); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + delete node; + + return sourceNode->ops->remove_vnode(sourceVolume, sourceNode, reenter); +} + + +// #pragma mark - VM access + + +static bool +bindfs_can_page(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, + node, node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->can_page(sourceVolume, sourceNode, cookie); +} + + +static status_t +bindfs_read_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, " + "count: %ld\n", + volume, node, node->ID(), cookie, pos, vecs, count); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read_pages(sourceVolume, sourceNode, cookie, pos, + vecs, count, _numBytes); +} + + +static status_t +bindfs_write_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, " + "count: %ld\n", + volume, node, node->ID(), cookie, pos, vecs, count); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->write_pages(sourceVolume, sourceNode, cookie, pos, + vecs, count, _numBytes); +} + + +// #pragma mark - Request I/O + + +static status_t +bindfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + io_request* request) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, + node, node->ID(), cookie, request); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->io(sourceVolume, sourceNode, cookie, request); +} + + +static status_t +bindfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + io_request* request) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, + node, node->ID(), cookie, request); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->cancel_io(sourceVolume, sourceNode, cookie, + request); +} + + +// #pragma mark - File Map + + +static status_t +bindfs_get_file_map(fs_volume* fsVolume, fs_vnode* fsNode, off_t offset, + size_t size, struct file_io_vec* vecs, size_t* _count) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), offset: %lld, size: %ld, vecs: %p\n", + volume, node, node->ID(), offset, size, vecs); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->get_file_map(sourceVolume, sourceNode, offset, size, + vecs, _count); +} + + +// #pragma mark - Special + + +static status_t +bindfs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint32 op, + void* buffer, size_t length) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, op: %lx, buffer: %p, " + "length: %ld\n", + volume, node, node->ID(), cookie, op, buffer, length); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->ioctl(sourceVolume, sourceNode, cookie, op, buffer, + length); +} + + +static status_t +bindfs_set_flags(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, int flags) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, flags: %x\n", + volume, node, node->ID(), cookie, flags); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->set_flags(sourceVolume, sourceNode, cookie, flags); +} + + +static status_t +bindfs_select(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint8 event, + selectsync* sync) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n", + volume, node, node->ID(), cookie, event, sync); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->select(sourceVolume, sourceNode, cookie, event, + sync); +} + + +static status_t +bindfs_deselect(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + uint8 event, selectsync* sync) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n", + volume, node, node->ID(), cookie, event, sync); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->deselect(sourceVolume, sourceNode, cookie, event, + sync); +} + + +static status_t +bindfs_fsync(fs_volume* fsVolume, fs_vnode* fsNode) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->fsync(sourceVolume, sourceNode); +} + + +// #pragma mark - Nodes + + +static status_t +bindfs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, + size_t* _bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read_symlink(sourceVolume, sourceNode, buffer, + _bufferSize); +} + + +static status_t +bindfs_create_symlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + const char* path, int mode) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s, path: %s, mode: %x\n", + volume, node, node->ID(), name, path, mode); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->create_symlink(sourceVolume, sourceNode, name, path, + mode); +} + + +static status_t +bindfs_link(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + fs_vnode* toNode) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s, tonode: %p\n", + volume, node, node->ID(), name, toNode); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->link(sourceVolume, sourceNode, name, toNode); +} + + +static status_t +bindfs_unlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s\n", + volume, node, node->ID(), name); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->unlink(sourceVolume, sourceNode, name); +} + + +static status_t +bindfs_rename(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, + fs_vnode* toDir, const char* toName) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n", + volume, node, node->ID(), fromName, toDir, toName); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->rename(sourceVolume, sourceNode, fromName, toDir, + toName); +} + + +static status_t +bindfs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->access(sourceVolume, sourceNode, mode); +} + + +static status_t +bindfs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + error = sourceNode->ops->read_stat(sourceVolume, sourceNode, st); + if (error != B_OK) + RETURN_ERROR(error); + + st->st_dev = volume->ID(); + + return B_OK; +} + + +static status_t +bindfs_write_stat(fs_volume* fsVolume, fs_vnode* fsNode, + const struct stat* _st, uint32 statMask) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + struct stat st; + memcpy(&st, _st, sizeof(st)); + st.st_dev = sourceVolume->id; + + return sourceNode->ops->write_stat(sourceVolume, sourceNode, &st, statMask); +} + + +static status_t +bindfs_preallocate(fs_volume* fsVolume, fs_vnode* fsNode, off_t pos, + off_t length) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), pos: %lld, length: %lld\n", + volume, node, node->ID(), pos, length); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->preallocate(sourceVolume, sourceNode, pos, length); +} + + +// #pragma mark - Files + + +static status_t +bindfs_create(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + int openMode, int perms, void** _cookie, ino_t* _newVnodeID) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s, openMode %#x, perms: %x\n", + volume, node, node->ID(), name, openMode, perms); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->create(sourceVolume, sourceNode, name, openMode, + perms, _cookie, _newVnodeID); +} + + +static status_t +bindfs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, + void** _cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume, node, + node->ID(), openMode); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->open(sourceVolume, sourceNode, openMode, _cookie); +} + + +static status_t +bindfs_close(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->close(sourceVolume, sourceNode, cookie); +} + + +static status_t +bindfs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->free_cookie(sourceVolume, sourceNode, cookie); +} + + +static status_t +bindfs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t offset, void* buffer, size_t* bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " + "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, + buffer, *bufferSize); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read(sourceVolume, sourceNode, cookie, offset, + buffer, bufferSize); +} + + +static status_t +bindfs_write(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t offset, const void* buffer, size_t* bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " + "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, + buffer, *bufferSize); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->write(sourceVolume, sourceNode, cookie, offset, + buffer, bufferSize); +} + + +// #pragma mark - Directories + + +static status_t +bindfs_create_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + int perms) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s, perms: %x\n", volume, node, + node->ID(), name, perms); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->create_dir(sourceVolume, sourceNode, name, perms); +} + + +static status_t +bindfs_remove_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume, node, + node->ID(), name); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->remove_dir(sourceVolume, sourceNode, name); +} + + +static status_t +bindfs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->open_dir(sourceVolume, sourceNode, _cookie); +} + + +static status_t +bindfs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->close_dir(sourceVolume, sourceNode, cookie); +} + + +static status_t +bindfs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->free_dir_cookie(sourceVolume, sourceNode, cookie); +} + + +static status_t +bindfs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + struct dirent* buffer, size_t bufferSize, uint32* _count) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read_dir(sourceVolume, sourceNode, cookie, buffer, + bufferSize, _count); +} + + +static status_t +bindfs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->rewind_dir(sourceVolume, sourceNode, cookie); +} + + +// #pragma mark - Attribute Directories + + +status_t +bindfs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->open_attr_dir(sourceVolume, sourceNode, _cookie); +} + + +status_t +bindfs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->close_attr_dir(sourceVolume, sourceNode, cookie); +} + + +status_t +bindfs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, + void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->free_attr_dir_cookie(sourceVolume, sourceNode, + cookie); +} + + +status_t +bindfs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + struct dirent* buffer, size_t bufferSize, uint32* _count) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read_attr_dir(sourceVolume, sourceNode, cookie, + buffer, bufferSize, _count); +} + + +status_t +bindfs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->rewind_attr_dir(sourceVolume, sourceNode, cookie); +} + + +// #pragma mark - Attribute Operations + + +status_t +bindfs_create_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + uint32 type, int openMode, void** _cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", type: %lx, " + "openMode %#x\n", + volume, node, node->ID(), name, type, openMode); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->create_attr(sourceVolume, sourceNode, name, type, + openMode, _cookie); +} + + +status_t +bindfs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, + int openMode, void** _cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", openMode %#x\n", + volume, node, node->ID(), name, openMode); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->open_attr(sourceVolume, sourceNode, name, openMode, + _cookie); +} + + +status_t +bindfs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->close_attr(sourceVolume, sourceNode, cookie); +} + + +status_t +bindfs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->free_attr_cookie(sourceVolume, sourceNode, cookie); +} + + +status_t +bindfs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t offset, void* buffer, size_t* bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->read_attr(sourceVolume, sourceNode, cookie, offset, + buffer, bufferSize); +} + + +status_t +bindfs_write_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + off_t offset, const void* buffer, size_t* bufferSize) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->write_attr(sourceVolume, sourceNode, cookie, offset, + buffer, bufferSize); +} + + +status_t +bindfs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + struct stat* st) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + error + = sourceNode->ops->read_attr_stat(sourceVolume, sourceNode, cookie, st); + if (error != B_OK) + RETURN_ERROR(error); + + st->st_dev = volume->ID(); + + return B_OK; +} + + +status_t +bindfs_write_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + const struct stat* _st, int statMask) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + struct stat st; + memcpy(&st, _st, sizeof(st)); + st.st_dev = sourceVolume->id; + + return sourceNode->ops->write_attr_stat(sourceVolume, sourceNode, cookie, + &st, statMask); +} + + +static status_t +bindfs_rename_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, + fs_vnode* toDir, const char* toName) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n", + volume, node, node->ID(), fromName, toDir, toName); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->rename_attr(sourceVolume, sourceNode, fromName, + toDir, toName); +} + + +static status_t +bindfs_remove_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume, node, + node->ID(), name); + + FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); + + return sourceNode->ops->remove_attr(sourceVolume, sourceNode, name); +} + + +// #pragma mark - Module Interface + + +static status_t +bindfs_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + { + init_debugging(); + PRINT("bindfs_std_ops(): B_MODULE_INIT\n"); + + return B_OK; + } + + case B_MODULE_UNINIT: + { + PRINT("bind_std_ops(): B_MODULE_UNINIT\n"); + exit_debugging(); + return B_OK; + } + + default: + return B_ERROR; + } +} + + +static file_system_module_info sBindFSModuleInfo = { + { + "file_systems/bindfs" B_CURRENT_FS_API_VERSION, + 0, + bindfs_std_ops, + }, + + "bindfs", // short_name + "Bind File System", // pretty_name + 0, // DDM flags + + + // scanning + NULL, // identify_partition, + NULL, // scan_partition, + NULL, // free_identify_partition_cookie, + NULL, // free_partition_content_cookie() + + &bindfs_mount +}; + + +fs_volume_ops gBindFSVolumeOps = { + &bindfs_unmount, + &bindfs_read_fs_info, + NULL, // write_fs_info, + NULL, // sync, + + &bindfs_get_vnode + + // TODO: index operations + // TODO: query operations + // TODO: FS layer operations +}; + + +fs_vnode_ops gBindFSVnodeOps = { + // vnode operations + &bindfs_lookup, + &bindfs_get_vnode_name, + &bindfs_put_vnode, + &bindfs_remove_vnode, + + // VM file access + &bindfs_can_page, + &bindfs_read_pages, + &bindfs_write_pages, + + &bindfs_io, + &bindfs_cancel_io, + + &bindfs_get_file_map, + + &bindfs_ioctl, + &bindfs_set_flags, + &bindfs_select, + &bindfs_deselect, + &bindfs_fsync, + + &bindfs_read_symlink, + &bindfs_create_symlink, + + &bindfs_link, + &bindfs_unlink, + &bindfs_rename, + + &bindfs_access, + &bindfs_read_stat, + &bindfs_write_stat, + &bindfs_preallocate, + + // file operations + &bindfs_create, + &bindfs_open, + &bindfs_close, + &bindfs_free_cookie, + &bindfs_read, + &bindfs_write, + + // directory operations + &bindfs_create_dir, + &bindfs_remove_dir, + &bindfs_open_dir, + &bindfs_close_dir, + &bindfs_free_dir_cookie, + &bindfs_read_dir, + &bindfs_rewind_dir, + + // attribute directory operations + &bindfs_open_attr_dir, + &bindfs_close_attr_dir, + &bindfs_free_attr_dir_cookie, + &bindfs_read_attr_dir, + &bindfs_rewind_attr_dir, + + // attribute operations + &bindfs_create_attr, + &bindfs_open_attr, + &bindfs_close_attr, + &bindfs_free_attr_cookie, + &bindfs_read_attr, + &bindfs_write_attr, + + &bindfs_read_attr_stat, + &bindfs_write_attr_stat, + &bindfs_rename_attr, + &bindfs_remove_attr, + + // TODO: FS layer operations +}; + + +module_info *modules[] = { + (module_info *)&sBindFSModuleInfo, + NULL, +}; diff --git a/src/add-ons/kernel/file_systems/bindfs/kernel_interface.h b/src/add-ons/kernel/file_systems/bindfs/kernel_interface.h new file mode 100644 index 0000000000..dff8e6d99b --- /dev/null +++ b/src/add-ons/kernel/file_systems/bindfs/kernel_interface.h @@ -0,0 +1,16 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_INTERFACE_H +#define KERNEL_INTERFACE_H + + +#include + + +extern fs_volume_ops gBindFSVolumeOps; +extern fs_vnode_ops gBindFSVnodeOps; + + +#endif // KERNEL_INTERFACE_H diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 437cb04fa0..4f3262ff0c 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -4100,6 +4100,18 @@ vfs_vnode_to_node_ref(struct vnode* vnode, dev_t* _mountID, ino_t* _vnodeID) } +/*! + Helper function abstracting the process of "converting" a given + vnode-pointer to a fs_vnode-pointer. + Currently only used in bindfs. +*/ +extern "C" fs_vnode* +vfs_fsnode_for_vnode(struct vnode* vnode) +{ + return vnode; +} + + /*! Calls fs_open() on the given vnode and returns a new file descriptor for it