@@ -196,16 +196,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
196196 struct iovec * iov = iov_page ;
197197
198198 iov -> iov_base = (void __user * )arg ;
199-
200- switch (cmd ) {
201- case FS_IOC_GETFLAGS :
202- case FS_IOC_SETFLAGS :
203- iov -> iov_len = sizeof (int );
204- break ;
205- default :
206- iov -> iov_len = _IOC_SIZE (cmd );
207- break ;
208- }
199+ iov -> iov_len = _IOC_SIZE (cmd );
209200
210201 if (_IOC_DIR (cmd ) & _IOC_WRITE ) {
211202 in_iov = iov ;
@@ -364,3 +355,136 @@ long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
364355{
365356 return fuse_ioctl_common (file , cmd , arg , FUSE_IOCTL_COMPAT );
366357}
358+
359+ static int fuse_priv_ioctl (struct inode * inode , struct fuse_file * ff ,
360+ unsigned int cmd , void * ptr , size_t size )
361+ {
362+ struct fuse_mount * fm = ff -> fm ;
363+ struct fuse_ioctl_in inarg ;
364+ struct fuse_ioctl_out outarg ;
365+ FUSE_ARGS (args );
366+ int err ;
367+
368+ memset (& inarg , 0 , sizeof (inarg ));
369+ inarg .fh = ff -> fh ;
370+ inarg .cmd = cmd ;
371+
372+ #if BITS_PER_LONG == 32
373+ inarg .flags |= FUSE_IOCTL_32BIT ;
374+ #endif
375+ if (S_ISDIR (inode -> i_mode ))
376+ inarg .flags |= FUSE_IOCTL_DIR ;
377+
378+ if (_IOC_DIR (cmd ) & _IOC_READ )
379+ inarg .out_size = size ;
380+ if (_IOC_DIR (cmd ) & _IOC_WRITE )
381+ inarg .in_size = size ;
382+
383+ args .opcode = FUSE_IOCTL ;
384+ args .nodeid = ff -> nodeid ;
385+ args .in_numargs = 2 ;
386+ args .in_args [0 ].size = sizeof (inarg );
387+ args .in_args [0 ].value = & inarg ;
388+ args .in_args [1 ].size = inarg .in_size ;
389+ args .in_args [1 ].value = ptr ;
390+ args .out_numargs = 2 ;
391+ args .out_args [0 ].size = sizeof (outarg );
392+ args .out_args [0 ].value = & outarg ;
393+ args .out_args [1 ].size = inarg .out_size ;
394+ args .out_args [1 ].value = ptr ;
395+
396+ err = fuse_simple_request (fm , & args );
397+ if (!err && outarg .flags & FUSE_IOCTL_RETRY )
398+ err = - EIO ;
399+
400+ return err ;
401+ }
402+
403+ static struct fuse_file * fuse_priv_ioctl_prepare (struct inode * inode )
404+ {
405+ struct fuse_mount * fm = get_fuse_mount (inode );
406+ bool isdir = S_ISDIR (inode -> i_mode );
407+
408+ if (!S_ISREG (inode -> i_mode ) && !isdir )
409+ return ERR_PTR (- ENOTTY );
410+
411+ return fuse_file_open (fm , get_node_id (inode ), O_RDONLY , isdir );
412+ }
413+
414+ static void fuse_priv_ioctl_cleanup (struct inode * inode , struct fuse_file * ff )
415+ {
416+ fuse_file_release (inode , ff , O_RDONLY , NULL , S_ISDIR (inode -> i_mode ));
417+ }
418+
419+ int fuse_fileattr_get (struct dentry * dentry , struct fileattr * fa )
420+ {
421+ struct inode * inode = d_inode (dentry );
422+ struct fuse_file * ff ;
423+ unsigned int flags ;
424+ struct fsxattr xfa ;
425+ int err ;
426+
427+ ff = fuse_priv_ioctl_prepare (inode );
428+ if (IS_ERR (ff ))
429+ return PTR_ERR (ff );
430+
431+ if (fa -> flags_valid ) {
432+ err = fuse_priv_ioctl (inode , ff , FS_IOC_GETFLAGS ,
433+ & flags , sizeof (flags ));
434+ if (err )
435+ goto cleanup ;
436+
437+ fileattr_fill_flags (fa , flags );
438+ } else {
439+ err = fuse_priv_ioctl (inode , ff , FS_IOC_FSGETXATTR ,
440+ & xfa , sizeof (xfa ));
441+ if (err )
442+ goto cleanup ;
443+
444+ fileattr_fill_xflags (fa , xfa .fsx_xflags );
445+ fa -> fsx_extsize = xfa .fsx_extsize ;
446+ fa -> fsx_nextents = xfa .fsx_nextents ;
447+ fa -> fsx_projid = xfa .fsx_projid ;
448+ fa -> fsx_cowextsize = xfa .fsx_cowextsize ;
449+ }
450+ cleanup :
451+ fuse_priv_ioctl_cleanup (inode , ff );
452+
453+ return err ;
454+ }
455+
456+ int fuse_fileattr_set (struct user_namespace * mnt_userns ,
457+ struct dentry * dentry , struct fileattr * fa )
458+ {
459+ struct inode * inode = d_inode (dentry );
460+ struct fuse_file * ff ;
461+ unsigned int flags = fa -> flags ;
462+ struct fsxattr xfa ;
463+ int err ;
464+
465+ ff = fuse_priv_ioctl_prepare (inode );
466+ if (IS_ERR (ff ))
467+ return PTR_ERR (ff );
468+
469+ if (fa -> flags_valid ) {
470+ err = fuse_priv_ioctl (inode , ff , FS_IOC_SETFLAGS ,
471+ & flags , sizeof (flags ));
472+ if (err )
473+ goto cleanup ;
474+ } else {
475+ memset (& xfa , 0 , sizeof (xfa ));
476+ xfa .fsx_xflags = fa -> fsx_xflags ;
477+ xfa .fsx_extsize = fa -> fsx_extsize ;
478+ xfa .fsx_nextents = fa -> fsx_nextents ;
479+ xfa .fsx_projid = fa -> fsx_projid ;
480+ xfa .fsx_cowextsize = fa -> fsx_cowextsize ;
481+
482+ err = fuse_priv_ioctl (inode , ff , FS_IOC_FSSETXATTR ,
483+ & xfa , sizeof (xfa ));
484+ }
485+
486+ cleanup :
487+ fuse_priv_ioctl_cleanup (inode , ff );
488+
489+ return err ;
490+ }
0 commit comments