diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp index 8dd3dc0f18..95381da14a 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp @@ -345,35 +345,23 @@ FUSEFileSystem::_InitCapabilities() fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true); // emulated -// // index directory & index operations -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, -// fFS->ops.open_indexdir); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR, -// fFS->ops.close_indexdir); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE, -// fFS->ops.free_indexdircookie); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, -// fFS->ops.read_indexdir); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, -// fFS->ops.rewind_indexdir); -// -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_CREATE_INDEX, -// fFS->ops.create_index); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_REMOVE_INDEX, -// fFS->ops.remove_index); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, -// fFS->ops.stat_index); + // index directory & index operations + // missing: FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR + // missing: FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR + // missing: FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE + // missing: FS_VOLUME_CAPABILITY_READ_INDEX_DIR + // missing: FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR + + // missing: FS_VOLUME_CAPABILITY_CREATE_INDEX + // missing: FS_VOLUME_CAPABILITY_REMOVE_INDEX + // missing: FS_VOLUME_CAPABILITY_READ_INDEX_STAT // query operations -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_OPEN_QUERY, -// fFS->ops.open_query); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_CLOSE_QUERY, -// fFS->ops.close_query); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE, -// fFS->ops.free_querycookie); -// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_QUERY, -// fFS->ops.read_query); -// // missing: FS_VOLUME_CAPABILITY_REWIND_QUERY, + // missing: FS_VOLUME_CAPABILITY_OPEN_QUERY + // missing: FS_VOLUME_CAPABILITY_CLOSE_QUERY + // missing: FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE + // missing: FS_VOLUME_CAPABILITY_READ_QUERY + // missing: FS_VOLUME_CAPABILITY_REWIND_QUERY // vnode operations fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, true); @@ -386,25 +374,25 @@ FUSEFileSystem::_InitCapabilities() // emulated // VM file access - // missing: FS_VNODE_CAPABILITY_CAN_PAGE, - // missing: FS_VNODE_CAPABILITY_READ_PAGES, - // missing: FS_VNODE_CAPABILITY_WRITE_PAGES, + // missing: FS_VNODE_CAPABILITY_CAN_PAGE + // missing: FS_VNODE_CAPABILITY_READ_PAGES + // missing: FS_VNODE_CAPABILITY_WRITE_PAGES // cache file access - // missing: FS_VNODE_CAPABILITY_GET_FILE_MAP, + // missing: FS_VNODE_CAPABILITY_GET_FILE_MAP // common operations -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_IOCTL, fFS->ops.ioctl); + // missing: FS_VNODE_CAPABILITY_IOCTL // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, fFS->ops.setflags); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_SELECT, fFS->ops.select); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_DESELECT, fFS->ops.deselect); + // missing: FS_VNODE_CAPABILITY_SELECT + // missing: FS_VNODE_CAPABILITY_DESELECT // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fFS->ops.fsync); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fFS->ops.readlink); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFS->ops.symlink); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFS->ops.symlink); // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fFS->ops.link); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFS->ops.unlink); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFS->ops.unlink); // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fFS->ops.rename); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fFS->ops.access); @@ -420,13 +408,12 @@ FUSEFileSystem::_InitCapabilities() fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write); // directory operations -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFS->ops.rmdir); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFS->ops.rmdir); bool readDirSupport = fFS->ops.opendir != NULL || fFS->ops.readdir != NULL || fFS->ops.getdir; fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_DIR, true); - // not needed + // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport); @@ -434,8 +421,7 @@ FUSEFileSystem::_InitCapabilities() // attribute directory operations bool hasAttributes = fFS->ops.listxattr != NULL; fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, true); - // not needed + // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, hasAttributes); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.cpp index aeecf27408..74b2dfaadd 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.cpp @@ -483,6 +483,7 @@ printf("FUSEVolume::Mount()\n"); RETURN_ERROR(B_NO_MEMORY); } + node->refCount++; // for the entry node->entries.Add(entry); fRootNode = node; @@ -684,15 +685,6 @@ FUSEVolume::IterativeIOFinished(void* cookie, int32 requestID, status_t status, // #pragma mark - nodes -status_t -FUSEVolume::IOCtl(void* node, void* cookie, uint32 command, void *buffer, - size_t size) -{ - // TODO: Implement! - return B_UNSUPPORTED; -} - - status_t FUSEVolume::SetFlags(void* node, void* cookie, int flags) { @@ -701,22 +693,6 @@ FUSEVolume::SetFlags(void* node, void* cookie, int flags) } -status_t -FUSEVolume::Select(void* node, void* cookie, uint8 event, selectsync* sync) -{ - // TODO: Implement! - return B_UNSUPPORTED; -} - - -status_t -FUSEVolume::Deselect(void* node, void* cookie, uint8 event, selectsync* sync) -{ - // TODO: Implement! - return B_UNSUPPORTED; -} - - status_t FUSEVolume::FSync(void* node) { @@ -764,11 +740,39 @@ FUSEVolume::ReadSymlink(void* _node, char* buffer, size_t bufferSize, status_t -FUSEVolume::CreateSymlink(void* dir, const char* name, const char* target, +FUSEVolume::CreateSymlink(void* _dir, const char* name, const char* target, int mode) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* dir = (FUSENode*)_dir; +PRINT(("FUSEVolume::CreateSymlink(%p (%lld), \"%s\" -> \"%s\", %#x)\n", dir, +dir->id, name, target, mode)); + + // lock the directory + NodeWriteLocker nodeLocker(this, dir, false); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + AutoLocker locker(fLock); + + // get a path for the entry + char path[B_PATH_NAME_LENGTH]; + size_t pathLen; + status_t error = _BuildPath(dir, name, path, pathLen); + if (error != B_OK) + RETURN_ERROR(error); + + locker.Unlock(); + + // create the dir + int fuseError = fuse_fs_symlink(fFS, target, path); + if (fuseError != 0) + RETURN_ERROR(fuseError); + +// TODO: Set the mode?! + +// TODO: Node monitoring! + + return B_OK; } @@ -781,10 +785,39 @@ FUSEVolume::Link(void* dir, const char* name, void* node) status_t -FUSEVolume::Unlink(void* dir, const char* name) +FUSEVolume::Unlink(void* _dir, const char* name) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* dir = (FUSENode*)_dir; +PRINT(("FUSEVolume::Unlink(%p (%lld), \"%s\")\n", dir, dir->id, name)); + + // lock the directory + NodeWriteLocker nodeLocker(this, dir, false); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + AutoLocker locker(fLock); + + // get a path for the entry + char path[B_PATH_NAME_LENGTH]; + size_t pathLen; + status_t error = _BuildPath(dir, name, path, pathLen); + if (error != B_OK) + RETURN_ERROR(error); + + locker.Unlock(); + + // unlink + int fuseError = fuse_fs_unlink(fFS, path); + if (fuseError != 0) + RETURN_ERROR(fuseError); + + // remove the entry + locker.Lock(); + _RemoveEntry(dir, name); + +// TODO: Node monitoring! + + return B_OK; } @@ -904,6 +937,8 @@ openMode, mode)); if (fuseError != 0) RETURN_ERROR(fuseError); +// TODO: Node monitoring! + // get the node FUSENode* node; error = _GetNode(dir, name, &node); @@ -968,6 +1003,7 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode)); fuse_fs_release(fFS, path, cookie); RETURN_ERROR(fuseError); } +// TODO: Node monitoring! } cookieDeleter.Detach(); @@ -1067,7 +1103,6 @@ FUSEVolume::Read(void* _node, void* _cookie, off_t pos, void* buffer, locker.Unlock(); // read the file - int bytesRead = fuse_fs_read(fFS, path, (char*)buffer, bufferSize, pos, cookie); if (bytesRead < 0) @@ -1103,13 +1138,14 @@ FUSEVolume::Write(void* _node, void* _cookie, off_t pos, const void* buffer, locker.Unlock(); - // read the file - + // write the file int bytesWritten = fuse_fs_write(fFS, path, (const char*)buffer, bufferSize, pos, cookie); if (bytesWritten < 0) return bytesWritten; +// TODO: Node monitoring? + *_bytesWritten = bytesWritten; return B_OK; } @@ -1119,18 +1155,76 @@ FUSEVolume::Write(void* _node, void* _cookie, off_t pos, const void* buffer, status_t -FUSEVolume::CreateDir(void* dir, const char* name, int mode, ino_t *newDir) +FUSEVolume::CreateDir(void* _dir, const char* name, int mode, ino_t *newDir) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* dir = (FUSENode*)_dir; +PRINT(("FUSEVolume::CreateDir(%p (%lld), \"%s\", %#x)\n", dir, dir->id, name, +mode)); + + // lock the directory + NodeWriteLocker nodeLocker(this, dir, false); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + AutoLocker locker(fLock); + + // get a path for the entry + char path[B_PATH_NAME_LENGTH]; + size_t pathLen; + status_t error = _BuildPath(dir, name, path, pathLen); + if (error != B_OK) + RETURN_ERROR(error); + + locker.Unlock(); + + // create the dir + int fuseError = fuse_fs_mkdir(fFS, path, mode); + if (fuseError != 0) + RETURN_ERROR(fuseError); + +// TODO: Node monitoring! + + *newDir = 0; + // TODO: This is really superfluous! + + return B_OK; } status_t -FUSEVolume::RemoveDir(void* dir, const char* name) +FUSEVolume::RemoveDir(void* _dir, const char* name) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* dir = (FUSENode*)_dir; +PRINT(("FUSEVolume::RemoveDir(%p (%lld), \"%s\")\n", dir, dir->id, name)); + + // lock the directory + NodeWriteLocker nodeLocker(this, dir, false); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + AutoLocker locker(fLock); + + // get a path for the entry + char path[B_PATH_NAME_LENGTH]; + size_t pathLen; + status_t error = _BuildPath(dir, name, path, pathLen); + if (error != B_OK) + RETURN_ERROR(error); + + locker.Unlock(); + + // remove the dir + int fuseError = fuse_fs_rmdir(fFS, path); + if (fuseError != 0) + RETURN_ERROR(fuseError); + + // remove the entry + locker.Lock(); + _RemoveEntry(dir, name); + +// TODO: Node monitoring! + + return B_OK; } @@ -1604,6 +1698,9 @@ FUSEVolume::_InternalGetNode(FUSENode* dir, const char* entryName, RETURN_ERROR(B_NO_MEMORY); } + dir->refCount++; + // dir reference for the entry + fEntries.Insert(entry); node->entries.Add(entry); @@ -1635,6 +1732,33 @@ FUSEVolume::_PutNodes(FUSENode* const* nodes, int32 count) } +/*! Volume must be locked. The entry's directory must be write locked. + */ +void +FUSEVolume::_RemoveEntry(FUSEEntry* entry) +{ + fEntries.Remove(entry); + entry->node->entries.Remove(entry); + _PutNode(entry->node); + _PutNode(entry->parent); + delete entry; +} + + +/*! Volume must be locked. The directory must be write locked. + */ +status_t +FUSEVolume::_RemoveEntry(FUSENode* dir, const char* name) +{ + FUSEEntry* entry = fEntries.Lookup(FUSEEntryRef(dir->id, name)); + if (entry == NULL) + return B_ENTRY_NOT_FOUND; + + _RemoveEntry(entry); + return B_OK; +} + + /*! Locks the given node and all of its ancestors up to the root. The given node is write-locked, if \a writeLock is \c true, read-locked otherwise. All ancestors are always read-locked in either case. @@ -1901,6 +2025,9 @@ PRINT((" -> create node: %p, id: %lld\n", node, nodeID)); return 1; } + buffer->directory->refCount++; + // dir reference for the entry + fEntries.Insert(entry); node->entries.Add(entry); } else { diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.h b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.h index b7ea5389b2..38709aa8ae 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.h @@ -65,14 +65,8 @@ public: size_t bytesTransferred); // nodes - virtual status_t IOCtl(void* node, void* cookie, - uint32 command, void* buffer, size_t size); virtual status_t SetFlags(void* node, void* cookie, int flags); - virtual status_t Select(void* node, void* cookie, - uint8 event, selectsync* sync); - virtual status_t Deselect(void* node, void* cookie, - uint8 event, selectsync* sync); virtual status_t FSync(void* node); @@ -157,6 +151,9 @@ private: void _PutNode(FUSENode* node); void _PutNodes(FUSENode* const* nodes, int32 count); + void _RemoveEntry(FUSEEntry* entry); + status_t _RemoveEntry(FUSENode* dir, const char* name); + status_t _LockNodeChain(FUSENode* node, bool parent, bool writeLock); void _UnlockNodeChain(FUSENode* node, bool parent,