From d16ba4b9575c3699cb3dd3d1519cb009ffec66f8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 25 Mar 2009 01:07:00 +0000 Subject: [PATCH] Added support for O_TRUNC, file creation, and writing to files. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29689 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../userlandfs/server/fuse/FUSEFileSystem.cpp | 4 +- .../userlandfs/server/fuse/FUSEVolume.cpp | 106 +++++++++++++++--- 2 files changed, 95 insertions(+), 15 deletions(-) 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 c281b668fe..8dd3dc0f18 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 @@ -412,12 +412,12 @@ FUSEFileSystem::_InitCapabilities() // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, fFS->ops.wstat); // file operations -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFS->ops.create); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFS->ops.create); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fFS->ops.open); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fFS->ops.flush); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fFS->ops.release); fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fFS->ops.read); -// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write); + fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write); // directory operations // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir); 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 e4466a8265..aeecf27408 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 @@ -870,11 +870,57 @@ FUSEVolume::WriteStat(void* node, const struct stat *st, uint32 mask) status_t -FUSEVolume::Create(void* dir, const char* name, int openMode, int mode, - void** cookie, ino_t* vnid) +FUSEVolume::Create(void* _dir, const char* name, int openMode, int mode, + void** _cookie, ino_t* _vnid) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* dir = (FUSENode*)_dir; +PRINT(("FUSEVolume::Create(%p (%lld), \"%s\", %#x, %#x)\n", dir, dir->id, name, +openMode, mode)); + + // lock the directory + NodeWriteLocker nodeLocker(this, dir, false); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + // allocate a file cookie + FileCookie* cookie = new(std::nothrow) FileCookie(openMode); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter cookieDeleter(cookie); + + AutoLocker locker(fLock); + + // get a path for the node + 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 file + int fuseError = fuse_fs_create(fFS, path, mode, cookie); + if (fuseError != 0) + RETURN_ERROR(fuseError); + + // get the node + FUSENode* node; + error = _GetNode(dir, name, &node); + if (error != B_OK) { + // This is bad. We've create the file successfully, but couldn't get + // the node. Close the file and delete the entry. + fuse_fs_flush(fFS, path, cookie); + fuse_fs_release(fFS, path, cookie); + fuse_fs_unlink(fFS, path); + RETURN_ERROR(error); + } + + cookieDeleter.Detach(); + *_cookie = cookie; + *_vnid = node->id; + + return B_OK; } @@ -892,10 +938,6 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode)); bool truncate = (openMode & O_TRUNC) != 0; openMode &= ~O_TRUNC; - // TODO: Support truncation! - if (truncate) - RETURN_ERROR(B_NOT_ALLOWED); - // allocate a file cookie FileCookie* cookie = new(std::nothrow) FileCookie(openMode); if (cookie == NULL) @@ -916,7 +958,17 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode)); // open the file int fuseError = fuse_fs_open(fFS, path, cookie); if (fuseError != 0) - return fuseError; + RETURN_ERROR(fuseError); + + // truncate the file, if requested + if (truncate) { + fuseError = fuse_fs_ftruncate(fFS, path, 0, cookie); + if (fuseError != 0) { + fuse_fs_flush(fFS, path, cookie); + fuse_fs_release(fFS, path, cookie); + RETURN_ERROR(fuseError); + } + } cookieDeleter.Detach(); *_cookie = cookie; @@ -1027,11 +1079,39 @@ FUSEVolume::Read(void* _node, void* _cookie, off_t pos, void* buffer, status_t -FUSEVolume::Write(void* node, void* cookie, off_t pos, const void* buffer, - size_t bufferSize, size_t* bytesWritten) +FUSEVolume::Write(void* _node, void* _cookie, off_t pos, const void* buffer, + size_t bufferSize, size_t* _bytesWritten) { - // TODO: Implement! - return B_UNSUPPORTED; + FUSENode* node = (FUSENode*)_node; + FileCookie* cookie = (FileCookie*)_cookie; + + *_bytesWritten = 0; + + // lock the directory + NodeReadLocker nodeLocker(this, node, true); + if (nodeLocker.Status() != B_OK) + RETURN_ERROR(nodeLocker.Status()); + + AutoLocker locker(fLock); + + // get a path for the node + char path[B_PATH_NAME_LENGTH]; + size_t pathLen; + status_t error = _BuildPath(node, path, pathLen); + if (error != B_OK) + RETURN_ERROR(error); + + locker.Unlock(); + + // read the file + + int bytesWritten = fuse_fs_write(fFS, path, (const char*)buffer, bufferSize, + pos, cookie); + if (bytesWritten < 0) + return bytesWritten; + + *_bytesWritten = bytesWritten; + return B_OK; }