Skip to content

Commit

Permalink
Add support for statvfs() to FUSE
Browse files Browse the repository at this point in the history
Some desktop environments are now checking for free space before
copying files to a destination.

To support this, the FUSE filesystem needs to convert the statvfs()
system call to the relevent PDUs from [MS-RDPEFS]
  • Loading branch information
matt335672 committed Nov 8, 2024
1 parent 9c0a0a8 commit 5dc4fdb
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 4 deletions.
1 change: 1 addition & 0 deletions common/ms-erref.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum NTSTATUS
STATUS_NO_MORE_FILES = 0x80000006,

STATUS_UNSUCCESSFUL = 0xc0000001,
STATUS_INFO_LENGTH_MISMATCH = 0xc0000004,
STATUS_NO_SUCH_FILE = 0xc000000f,
STATUS_ACCESS_DENIED = 0xc0000022,
STATUS_OBJECT_NAME_INVALID = 0xc0000033,
Expand Down
22 changes: 21 additions & 1 deletion common/ms-fscc.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
/*
* File information classes (section 2.4)
*/
enum FS_INFORMATION_CLASS
enum FILE_INFORMATION_CLASS
{
FileAllocationInformation = 19, /* Set */
FileBasicInformation = 4, /* Query, Set */
Expand All @@ -52,6 +52,26 @@ enum FS_INFORMATION_CLASS
#define FILE_STD_INFORMATION_SIZE 22
#define FILE_END_OF_FILE_INFORMATION_SIZE 8

/*
* File System information classes (section 2.5)
*/
enum FILE_SYSTEM_INFORMATION_CLASS
{
FileFsVolumeInformation = 1,
FileFsSizeInformation = 3,
FileFsDeviceInformation = 4,
FileFsAttributeInformation = 5,
FileFsFullSizeInformation = 7
};

/*
* Size of structs above without trailing RESERVED fields (MS-RDPEFS
* 2.2.3.3.6)
*/
#define FILE_FS_SIZE_INFORMATION_SIZE 24
#define FILE_FS_DEVICE_INFORMATION_SIZE 8
#define FILE_FS_FULL_SIZE_INFORMATION_SIZE 32

/* Windows file attributes (section 2.6) */
#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define W_FILE_ATTRIBUTE_READONLY 0x00000001
Expand Down
90 changes: 90 additions & 0 deletions sesman/chansrv/chansrv_fuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,
void xfuse_devredir_cb_file_close(struct state_close *fip)
{}

void xfuse_devredir_cb_statfs(struct state_statfs *fip,
const struct statvfs *fss,
enum NTSTATUS IoStatus)
{}

int xfuse_path_in_xfuse_fs(const char *path)
{
return 0;
Expand Down Expand Up @@ -303,6 +308,15 @@ struct state_close
fuse_ino_t inum; /* inum of file to open */
};

/*
* Record type used to maintain state when running a statfs
*/
struct state_statfs
{
fuse_req_t req; /* Original FUSE request from statfs */
};


struct xfuse_handle
{
tui32 DeviceId;
Expand Down Expand Up @@ -409,6 +423,8 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);

static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino);

/* miscellaneous functions */
static void xfs_inode_to_fuse_entry_param(const XFS_INODE *xinode,
struct fuse_entry_param *e);
Expand Down Expand Up @@ -611,6 +627,7 @@ xfuse_init(void)
g_xfuse_ops.setattr = xfuse_cb_setattr;
g_xfuse_ops.opendir = xfuse_cb_opendir;
g_xfuse_ops.releasedir = xfuse_cb_releasedir;
g_xfuse_ops.statfs = xfuse_cb_statfs;

fuse_opt_add_arg(&args, "xrdp-chansrv");
fuse_opt_add_arg(&args, "-o");
Expand Down Expand Up @@ -1570,6 +1587,26 @@ void xfuse_devredir_cb_file_close(struct state_close *fip)
free(fip);
}

void xfuse_devredir_cb_statfs(struct state_statfs *fip,
const struct statvfs *fss,
enum NTSTATUS IoStatus)
{
int status;
if (IoStatus != STATUS_SUCCESS)
{
status =
(IoStatus == STATUS_ACCESS_DENIED) ? EACCES :
/* default */ EIO ;
fuse_reply_err(fip->req, status);
}
else
{
fuse_reply_statfs(fip->req, fss);
}

free(fip);
}

/*
* Determine is a file is in the FUSE filesystem
*
Expand Down Expand Up @@ -2686,6 +2723,59 @@ static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino,
fuse_reply_err(req, 0);
}

/*****************************************************************************/
static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino)
{
XFS_INODE *xinode;

LOG_DEVEL(LOG_LEVEL_DEBUG, "entered: ino=%ld", ino);

if (!(xinode = xfs_get(g_xfs, ino)))
{
LOG_DEVEL(LOG_LEVEL_ERROR, "inode %ld is not valid", ino);
fuse_reply_err(req, ENOENT);
}
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
struct statvfs vfs_stats = {0};
fuse_reply_statfs(req, &vfs_stats);
}
else
{
/* specified file resides on redirected share */

struct state_statfs *fip = g_new0(struct state_statfs, 1);
char *full_path = xfs_get_full_path(g_xfs, ino);
if (full_path == NULL || fip == NULL)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "system out of memory");
fuse_reply_err(req, ENOMEM);
free(full_path);
free(fip);
}
else
{
const char *cptr;
fip->req = req;

/* get devredir to statfs the filesystem for the file
*
* If this call succeeds, further request processing happens in
* xfuse_devredir_cb_statfs()
*/
cptr = filename_on_device(full_path);
if (devredir_statfs(fip, xinode->device_id, cptr))
{
LOG_DEVEL(LOG_LEVEL_ERROR, "failed to send devredir_statfs() cmd");
fuse_reply_err(req, EREMOTEIO);
free(fip);
}
free(full_path);
}
}
}

/******************************************************************************
* miscellaneous functions
*****************************************************************************/
Expand Down
6 changes: 6 additions & 0 deletions sesman/chansrv/chansrv_fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ struct state_write;
struct state_remove;
struct state_rename;
struct state_close;
struct statvfs; // OS structure defined in <sys/statvfs.h>
struct state_statfs;


/* functions that are invoked from devredir */
Expand Down Expand Up @@ -114,6 +116,10 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,

void xfuse_devredir_cb_file_close(struct state_close *fip);

void xfuse_devredir_cb_statfs(struct state_statfs *fip,
const struct statvfs *fss,
enum NTSTATUS IoStatus);

/*
* Returns true if a filesystem path lies in the FUSE filesystem
*
Expand Down
Loading

0 comments on commit 5dc4fdb

Please sign in to comment.