Files
seaweedFS/weed/mount/weedfs_file_io.go
Chris Lu cca1555cc7 mount: implement create for rsync temp files (#8749)
* mount: implement create for rsync temp files

* mount: move access implementation out of unsupported

* mount: tighten access checks

* mount: log access group lookup failures

* mount: reset dirty pages on truncate

* mount: tighten create and root access handling

* mount: handle existing creates before quota checks

* mount: restrict access fallback when group lookup fails

When lookupSupplementaryGroupIDs returns an error, the previous code
fell through to checking only the "other" permission bits, which could
overgrant access.  Require both group and other permission classes to
satisfy the mask so access is never broader than intended.

* mount: guard against nil entry in Create existing-file path

maybeLoadEntry can return OK with a nil entry or nil Attributes in
edge cases.  Check before dereferencing to prevent a panic.

* mount: reopen existing file on create race without O_EXCL

When createRegularFile returns EEXIST because another process won the
race, and O_EXCL is not set, reload the winner's entry and open it
instead of propagating the error to the caller.

* mount: check parent directory permission in createRegularFile

Verify the caller has write+search (W_OK|X_OK) permission on the
parent directory before creating a file.  This applies to both
Create and Mknod.  Update test fixture mount mode to 0o777 so the
existing tests pass with the new check.

* mount: enforce file permission bits in AcquireHandle

Map the open flags (O_RDONLY/O_WRONLY/O_RDWR) to an access mask and
call hasAccess before handing out a file handle.  This makes
AcquireHandle the single source of truth for mode-based access
control across Open, Create-existing, and Create-new paths.

---------

Co-authored-by: Copilot <copilot@github.com>
2026-03-24 11:43:41 -07:00

103 lines
3.5 KiB
Go

package mount
import "github.com/seaweedfs/go-fuse/v2/fuse"
/**
* Open a file
*
* Open flags are available in fi->flags. The following rules
* apply.
*
* - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
* filtered out / handled by the kernel.
*
* - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
* by the filesystem to check if the operation is
* permitted. If the ``-o default_permissions`` mount
* option is given, this check is already done by the
* kernel before calling open() and may thus be omitted by
* the filesystem.
*
* - When writeback caching is enabled, the kernel may send
* read requests even for files opened with O_WRONLY. The
* filesystem should be prepared to handle this.
*
* - When writeback caching is disabled, the filesystem is
* expected to properly handle the O_APPEND flag and ensure
* that each write is appending to the end of the file.
*
* - When writeback caching is enabled, the kernel will
* handle O_APPEND. However, unless all changes to the file
* come through the kernel this will not work reliably. The
* filesystem should thus either ignore the O_APPEND flag
* (and let the kernel handle it), or return an error
* (indicating that reliably O_APPEND is not available).
*
* Filesystem may store an arbitrary file handle (pointer,
* index, etc) in fi->fh, and use this in other all other file
* operations (read, write, flush, release, fsync).
*
* Filesystem may also implement stateless file I/O and not store
* anything in fi->fh.
*
* There are also some flags (direct_io, keep_cache) which the
* filesystem may set in fi, to change the way the file is opened.
* See fuse_file_info structure in <fuse_common.h> for more details.
*
* If this request is answered with an error code of ENOSYS
* and FUSE_CAP_NO_OPEN_SUPPORT is set in
* `fuse_conn_info.capable`, this is treated as success and
* future calls to open and release will also succeed without being
* sent to the filesystem process.
*
* Valid replies:
* fuse_reply_open
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param fi file information
*/
func (wfs *WFS) Open(cancel <-chan struct{}, in *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
var fileHandle *FileHandle
fileHandle, status = wfs.AcquireHandle(in.NodeId, in.Flags, in.Uid, in.Gid)
if status == fuse.OK {
out.Fh = uint64(fileHandle.fh)
out.OpenFlags = 0
// TODO https://github.com/libfuse/libfuse/blob/master/include/fuse_common.h#L64
}
return status
}
/**
* Release an open file
*
* Release is called when there are no more references to an open
* file: all file descriptors are closed and all memory mappings
* are unmapped.
*
* For every open call there will be exactly one release call (unless
* the filesystem is force-unmounted).
*
* The filesystem may reply with an error, but error values are
* not returned to close() or munmap() which triggered the
* release.
*
* fi->fh will contain the value set by the open method, or will
* be undefined if the open method didn't set any value.
* fi->flags will contain the same flags as for open.
*
* Valid replies:
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param fi file information
*/
func (wfs *WFS) Release(cancel <-chan struct{}, in *fuse.ReleaseIn) {
if in.ReleaseFlags&fuse.FUSE_RELEASE_FLOCK_UNLOCK != 0 {
wfs.posixLocks.ReleaseFlockOwner(in.NodeId, in.LockOwner)
}
wfs.ReleaseHandle(FileHandleId(in.Fh))
}