FUSE: file type bits not set in calls to mknod and create callbacks
Bug Report
When a new file is created on a mounted FUSE file system either the mknod or create callback is called (depending on what the file system implements) the mode argument is expected to hold not only the file mode bits but also the file type, e.g. S_IFREG. This does not seem to be the case on WinFSP/FUSE but works as expected on e.g. Linux.
How to Reproduce
Create a new file using e.g. touch and watch the mode bits in calls to mknod or create.
Behaviors
Expected the file type bits to be set in the mode argument as is the case on e.g. Linux.
Environment
- OS version and build: CYGWIN_NT-10.0 xxxx 3.0.7(0.338/5/3) 2019-04-30 18:08 x86_64 Cygwin
- WinFsp version and build: 2019.2
- fuse2
Seems like also open suffers from a similar problem, there it is the the struct fuse_file_info * fi, and the flags that are not set as expected. Note that in this example create is not registered as a callback. If it is it seems to work a lot better, the fi->flags still being a bit different from Linux though. See below.
E.g. doing an operation like this on Linux works fine inside the mount point when fee does not exist
$ cp foo fee
$ ls -l fee
-rw-rw-r-- 1 hasse hasse 0 Oct 12 15:22 fee
But on Cygwin and WinFSP (the error is unexpected since fee does not exist yet)
$ cp foo fee
cp: cannot create regular file 'fee': File exists
$ ls -l fee
-rwx------ 1 Hasse None 0 Oct 12 15:22 fee*
We can see from some simple traces that WinFSP calls open with completely different flags than on Linux.
Linux:
OPEN /foo 100000
MKNOD 100664
OPEN /fee 100001
WinFSP:
OPEN /foo 0
OPEN /foo 0
OPEN /foo 0
OPEN /foo 0
MKNOD 700
OPEN /fee 5002
OPEN /fee 0
OPEN /fee 0
OPEN /fee 0
WinFSP (with create implemented, works as expected except for the flags)
OPEN /foo 0
OPEN /foo 0
OPEN /foo 0
OPEN /foo 0
CREATE 700
OPEN /fee 0
The flags set to 5002 above is octal and represented in hex as 0xa02. If decoded that mean following flag bits are set:
- O_RDWR
- O_CREAT
- O_EXCL
None of O_CREAT and O_EXCL should be possible to receive in the open callback, as also confirmed by the FUSE definition of open:
/** File open operation
*
* No creation (O_CREAT, O_EXCL) and by default also no
* truncation (O_TRUNC) flags will be passed to open(). If an
* application specifies O_TRUNC, fuse first calls truncate()
* and then open(). Only if 'atomic_o_trunc' has been
* specified and kernel version is 2.6.24 or later, O_TRUNC is
* passed on to open.
*
* Unless the 'default_permissions' mount option is given,
* open should check if the operation is permitted for the
* given flags. Optionally open may also return an arbitrary
* filehandle in the fuse_file_info structure, which will be
* passed to all file operations.
*
* Changed in version 2.2
*/
int (*open) (const char *, struct fuse_file_info *);
I believe it is the O_CREAT flag that results in the error here since fi->flags are basically passed on unmodified to the open(2) system call by my file system.
Should I file the last observation in a new bug or can we handle that in the same context as this one? They are related but not exactly the same.
Btw, I did a brute force hack in my file system and masked O_CREAT and O_EXCL from fi->flags in the open callback and then the copy operation completed without any errors.