Expose additional file level attributes
ZFS allows to update and retrieve additional file level attributes for FreeBSD. This commit allows additional file level attributes to be updated and retrieved for Linux. These include the flags stored in the upper half of z_pflags only. Two new IOCTLs have been added for this purpose. ZFS_IOC_GETDOSFLAGS can be used to retrieve the attributes, while ZFS_IOC_SETDOSFLAGS can be used to update the attributes. Attributes that are allowed to be updated include ZFS_IMMUTABLE, ZFS_APPENDONLY, ZFS_NOUNLINK, ZFS_ARCHIVE, ZFS_NODUMP, ZFS_SYSTEM, ZFS_HIDDEN, ZFS_READONLY, ZFS_REPARSE, ZFS_OFFLINE and ZFS_SPARSE. Flags can be or'd together while calling ZFS_IOC_SETDOSFLAGS. Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Signed-off-by: Umer Saleem <usaleem@ixsystems.com> Closes #13118
This commit is contained in:
parent
9955b9ba2e
commit
39a4daf742
|
@ -226,12 +226,14 @@ AC_CONFIG_FILES([
|
||||||
tests/zfs-tests/cmd/randfree_file/Makefile
|
tests/zfs-tests/cmd/randfree_file/Makefile
|
||||||
tests/zfs-tests/cmd/randwritecomp/Makefile
|
tests/zfs-tests/cmd/randwritecomp/Makefile
|
||||||
tests/zfs-tests/cmd/readmmap/Makefile
|
tests/zfs-tests/cmd/readmmap/Makefile
|
||||||
|
tests/zfs-tests/cmd/read_dos_attributes/Makefile
|
||||||
tests/zfs-tests/cmd/rename_dir/Makefile
|
tests/zfs-tests/cmd/rename_dir/Makefile
|
||||||
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile
|
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile
|
||||||
tests/zfs-tests/cmd/send_doall/Makefile
|
tests/zfs-tests/cmd/send_doall/Makefile
|
||||||
tests/zfs-tests/cmd/stride_dd/Makefile
|
tests/zfs-tests/cmd/stride_dd/Makefile
|
||||||
tests/zfs-tests/cmd/threadsappend/Makefile
|
tests/zfs-tests/cmd/threadsappend/Makefile
|
||||||
tests/zfs-tests/cmd/user_ns_exec/Makefile
|
tests/zfs-tests/cmd/user_ns_exec/Makefile
|
||||||
|
tests/zfs-tests/cmd/write_dos_attributes/Makefile
|
||||||
tests/zfs-tests/cmd/xattrtest/Makefile
|
tests/zfs-tests/cmd/xattrtest/Makefile
|
||||||
tests/zfs-tests/include/Makefile
|
tests/zfs-tests/include/Makefile
|
||||||
tests/zfs-tests/tests/Makefile
|
tests/zfs-tests/tests/Makefile
|
||||||
|
@ -333,6 +335,7 @@ AC_CONFIG_FILES([
|
||||||
tests/zfs-tests/tests/functional/deadman/Makefile
|
tests/zfs-tests/tests/functional/deadman/Makefile
|
||||||
tests/zfs-tests/tests/functional/delegate/Makefile
|
tests/zfs-tests/tests/functional/delegate/Makefile
|
||||||
tests/zfs-tests/tests/functional/devices/Makefile
|
tests/zfs-tests/tests/functional/devices/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/dos_attributes/Makefile
|
||||||
tests/zfs-tests/tests/functional/events/Makefile
|
tests/zfs-tests/tests/functional/events/Makefile
|
||||||
tests/zfs-tests/tests/functional/exec/Makefile
|
tests/zfs-tests/tests/functional/exec/Makefile
|
||||||
tests/zfs-tests/tests/functional/fallocate/Makefile
|
tests/zfs-tests/tests/functional/fallocate/Makefile
|
||||||
|
|
|
@ -1459,6 +1459,41 @@ typedef enum zfs_ioc {
|
||||||
*/
|
*/
|
||||||
#define BLKZNAME _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])
|
#define BLKZNAME _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IOCTLs to update and retrieve additional file level attributes on
|
||||||
|
* Linux.
|
||||||
|
*/
|
||||||
|
#define ZFS_IOC_GETDOSFLAGS _IOR(0x83, 1, uint64_t)
|
||||||
|
#define ZFS_IOC_SETDOSFLAGS _IOW(0x83, 2, uint64_t)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Additional file level attributes, that are stored
|
||||||
|
* in the upper half of z_pflags
|
||||||
|
*/
|
||||||
|
#define ZFS_READONLY 0x0000000100000000ull
|
||||||
|
#define ZFS_HIDDEN 0x0000000200000000ull
|
||||||
|
#define ZFS_SYSTEM 0x0000000400000000ull
|
||||||
|
#define ZFS_ARCHIVE 0x0000000800000000ull
|
||||||
|
#define ZFS_IMMUTABLE 0x0000001000000000ull
|
||||||
|
#define ZFS_NOUNLINK 0x0000002000000000ull
|
||||||
|
#define ZFS_APPENDONLY 0x0000004000000000ull
|
||||||
|
#define ZFS_NODUMP 0x0000008000000000ull
|
||||||
|
#define ZFS_OPAQUE 0x0000010000000000ull
|
||||||
|
#define ZFS_AV_QUARANTINED 0x0000020000000000ull
|
||||||
|
#define ZFS_AV_MODIFIED 0x0000040000000000ull
|
||||||
|
#define ZFS_REPARSE 0x0000080000000000ull
|
||||||
|
#define ZFS_OFFLINE 0x0000100000000000ull
|
||||||
|
#define ZFS_SPARSE 0x0000200000000000ull
|
||||||
|
|
||||||
|
#define ZFS_DOS_FL_USER_VISIBLE (ZFS_IMMUTABLE | ZFS_APPENDONLY | \
|
||||||
|
ZFS_NOUNLINK | ZFS_ARCHIVE | ZFS_NODUMP | ZFS_SYSTEM | \
|
||||||
|
ZFS_HIDDEN | ZFS_READONLY | ZFS_REPARSE | ZFS_OFFLINE | \
|
||||||
|
ZFS_SPARSE)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ZFS-specific error codes used for returning descriptive errors
|
* ZFS-specific error codes used for returning descriptive errors
|
||||||
* to the userland through zfs ioctls.
|
* to the userland through zfs ioctls.
|
||||||
|
|
|
@ -37,7 +37,7 @@ extern "C" {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Additional file level attributes, that are stored
|
* Additional file level attributes, that are stored
|
||||||
* in the upper half of zp_flags
|
* in the upper half of z_pflags
|
||||||
*/
|
*/
|
||||||
#define ZFS_READONLY 0x0000000100000000ull
|
#define ZFS_READONLY 0x0000000100000000ull
|
||||||
#define ZFS_HIDDEN 0x0000000200000000ull
|
#define ZFS_HIDDEN 0x0000000200000000ull
|
||||||
|
|
|
@ -905,21 +905,24 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva)
|
||||||
xva_init(xva);
|
xva_init(xva);
|
||||||
xoap = xva_getxoptattr(xva);
|
xoap = xva_getxoptattr(xva);
|
||||||
|
|
||||||
XVA_SET_REQ(xva, XAT_IMMUTABLE);
|
#define FLAG_CHANGE(iflag, zflag, xflag, xfield) do { \
|
||||||
if (ioctl_flags & FS_IMMUTABLE_FL)
|
if (((ioctl_flags & (iflag)) && !(zfs_flags & (zflag))) || \
|
||||||
xoap->xoa_immutable = B_TRUE;
|
((zfs_flags & (zflag)) && !(ioctl_flags & (iflag)))) { \
|
||||||
|
XVA_SET_REQ(xva, (xflag)); \
|
||||||
|
(xfield) = ((ioctl_flags & (iflag)) != 0); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
XVA_SET_REQ(xva, XAT_APPENDONLY);
|
FLAG_CHANGE(FS_IMMUTABLE_FL, ZFS_IMMUTABLE, XAT_IMMUTABLE,
|
||||||
if (ioctl_flags & FS_APPEND_FL)
|
xoap->xoa_immutable);
|
||||||
xoap->xoa_appendonly = B_TRUE;
|
FLAG_CHANGE(FS_APPEND_FL, ZFS_APPENDONLY, XAT_APPENDONLY,
|
||||||
|
xoap->xoa_appendonly);
|
||||||
|
FLAG_CHANGE(FS_NODUMP_FL, ZFS_NODUMP, XAT_NODUMP,
|
||||||
|
xoap->xoa_nodump);
|
||||||
|
FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT,
|
||||||
|
xoap->xoa_projinherit);
|
||||||
|
|
||||||
XVA_SET_REQ(xva, XAT_NODUMP);
|
#undef FLAG_CHANGE
|
||||||
if (ioctl_flags & FS_NODUMP_FL)
|
|
||||||
xoap->xoa_nodump = B_TRUE;
|
|
||||||
|
|
||||||
XVA_SET_REQ(xva, XAT_PROJINHERIT);
|
|
||||||
if (ioctl_flags & ZFS_PROJINHERIT_FL)
|
|
||||||
xoap->xoa_projinherit = B_TRUE;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -998,6 +1001,94 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg)
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expose Additional File Level Attributes of ZFS.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
zpl_ioctl_getdosflags(struct file *filp, void __user *arg)
|
||||||
|
{
|
||||||
|
struct inode *ip = file_inode(filp);
|
||||||
|
uint64_t dosflags = ITOZ(ip)->z_pflags;
|
||||||
|
dosflags &= ZFS_DOS_FL_USER_VISIBLE;
|
||||||
|
int err = copy_to_user(arg, &dosflags, sizeof (dosflags));
|
||||||
|
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
__zpl_ioctl_setdosflags(struct inode *ip, uint64_t ioctl_flags, xvattr_t *xva)
|
||||||
|
{
|
||||||
|
uint64_t zfs_flags = ITOZ(ip)->z_pflags;
|
||||||
|
xoptattr_t *xoap;
|
||||||
|
|
||||||
|
if (ioctl_flags & (~ZFS_DOS_FL_USER_VISIBLE))
|
||||||
|
return (-EOPNOTSUPP);
|
||||||
|
|
||||||
|
if ((fchange(ioctl_flags, zfs_flags, ZFS_IMMUTABLE, ZFS_IMMUTABLE) ||
|
||||||
|
fchange(ioctl_flags, zfs_flags, ZFS_APPENDONLY, ZFS_APPENDONLY)) &&
|
||||||
|
!capable(CAP_LINUX_IMMUTABLE))
|
||||||
|
return (-EPERM);
|
||||||
|
|
||||||
|
if (!zpl_inode_owner_or_capable(kcred->user_ns, ip))
|
||||||
|
return (-EACCES);
|
||||||
|
|
||||||
|
xva_init(xva);
|
||||||
|
xoap = xva_getxoptattr(xva);
|
||||||
|
|
||||||
|
#define FLAG_CHANGE(iflag, xflag, xfield) do { \
|
||||||
|
if (((ioctl_flags & (iflag)) && !(zfs_flags & (iflag))) || \
|
||||||
|
((zfs_flags & (iflag)) && !(ioctl_flags & (iflag)))) { \
|
||||||
|
XVA_SET_REQ(xva, (xflag)); \
|
||||||
|
(xfield) = ((ioctl_flags & (iflag)) != 0); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
FLAG_CHANGE(ZFS_IMMUTABLE, XAT_IMMUTABLE, xoap->xoa_immutable);
|
||||||
|
FLAG_CHANGE(ZFS_APPENDONLY, XAT_APPENDONLY, xoap->xoa_appendonly);
|
||||||
|
FLAG_CHANGE(ZFS_NODUMP, XAT_NODUMP, xoap->xoa_nodump);
|
||||||
|
FLAG_CHANGE(ZFS_READONLY, XAT_READONLY, xoap->xoa_readonly);
|
||||||
|
FLAG_CHANGE(ZFS_HIDDEN, XAT_HIDDEN, xoap->xoa_hidden);
|
||||||
|
FLAG_CHANGE(ZFS_SYSTEM, XAT_SYSTEM, xoap->xoa_system);
|
||||||
|
FLAG_CHANGE(ZFS_ARCHIVE, XAT_ARCHIVE, xoap->xoa_archive);
|
||||||
|
FLAG_CHANGE(ZFS_NOUNLINK, XAT_NOUNLINK, xoap->xoa_nounlink);
|
||||||
|
FLAG_CHANGE(ZFS_REPARSE, XAT_REPARSE, xoap->xoa_reparse);
|
||||||
|
FLAG_CHANGE(ZFS_OFFLINE, XAT_OFFLINE, xoap->xoa_offline);
|
||||||
|
FLAG_CHANGE(ZFS_SPARSE, XAT_SPARSE, xoap->xoa_sparse);
|
||||||
|
|
||||||
|
#undef FLAG_CHANGE
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set Additional File Level Attributes of ZFS.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
zpl_ioctl_setdosflags(struct file *filp, void __user *arg)
|
||||||
|
{
|
||||||
|
struct inode *ip = file_inode(filp);
|
||||||
|
uint64_t dosflags;
|
||||||
|
cred_t *cr = CRED();
|
||||||
|
xvattr_t xva;
|
||||||
|
int err;
|
||||||
|
fstrans_cookie_t cookie;
|
||||||
|
|
||||||
|
if (copy_from_user(&dosflags, arg, sizeof (dosflags)))
|
||||||
|
return (-EFAULT);
|
||||||
|
|
||||||
|
err = __zpl_ioctl_setdosflags(ip, dosflags, &xva);
|
||||||
|
if (err)
|
||||||
|
return (err);
|
||||||
|
|
||||||
|
crhold(cr);
|
||||||
|
cookie = spl_fstrans_mark();
|
||||||
|
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr);
|
||||||
|
spl_fstrans_unmark(cookie);
|
||||||
|
crfree(cr);
|
||||||
|
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
|
@ -1012,6 +1103,10 @@ zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||||
return (zpl_ioctl_getxattr(filp, (void *)arg));
|
return (zpl_ioctl_getxattr(filp, (void *)arg));
|
||||||
case ZFS_IOC_FSSETXATTR:
|
case ZFS_IOC_FSSETXATTR:
|
||||||
return (zpl_ioctl_setxattr(filp, (void *)arg));
|
return (zpl_ioctl_setxattr(filp, (void *)arg));
|
||||||
|
case ZFS_IOC_GETDOSFLAGS:
|
||||||
|
return (zpl_ioctl_getdosflags(filp, (void *)arg));
|
||||||
|
case ZFS_IOC_SETDOSFLAGS:
|
||||||
|
return (zpl_ioctl_setdosflags(filp, (void *)arg));
|
||||||
default:
|
default:
|
||||||
return (-ENOTTY);
|
return (-ENOTTY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ outputdir = /var/tmp/test_results
|
||||||
tags = ['functional']
|
tags = ['functional']
|
||||||
|
|
||||||
[tests/functional/acl/off]
|
[tests/functional/acl/off]
|
||||||
tests = ['posixmode']
|
tests = ['dosmode', 'posixmode']
|
||||||
tags = ['functional', 'acl']
|
tags = ['functional', 'acl']
|
||||||
|
|
||||||
[tests/functional/alloc_class]
|
[tests/functional/alloc_class]
|
||||||
|
|
|
@ -22,10 +22,6 @@ failsafe = callbacks/zfs_failsafe
|
||||||
outputdir = /var/tmp/test_results
|
outputdir = /var/tmp/test_results
|
||||||
tags = ['functional']
|
tags = ['functional']
|
||||||
|
|
||||||
[tests/functional/acl/off:FreeBSD]
|
|
||||||
tests = ['dosmode']
|
|
||||||
tags = ['functional', 'acl']
|
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_jail:FreeBSD]
|
[tests/functional/cli_root/zfs_jail:FreeBSD]
|
||||||
tests = ['zfs_jail_001_pos']
|
tests = ['zfs_jail_001_pos']
|
||||||
tags = ['functional', 'cli_root', 'zfs_jail']
|
tags = ['functional', 'cli_root', 'zfs_jail']
|
||||||
|
|
|
@ -149,6 +149,10 @@ tests = ['projectid_001_pos', 'projectid_002_pos', 'projectid_003_pos',
|
||||||
'projecttree_001_pos', 'projecttree_002_pos', 'projecttree_003_neg']
|
'projecttree_001_pos', 'projecttree_002_pos', 'projecttree_003_neg']
|
||||||
tags = ['functional', 'projectquota']
|
tags = ['functional', 'projectquota']
|
||||||
|
|
||||||
|
[tests/functional/dos_attributes:Linux]
|
||||||
|
tests = ['read_dos_attrs_001', 'write_dos_attrs_001']
|
||||||
|
tags = ['functional', 'dos_attributes']
|
||||||
|
|
||||||
[tests/functional/rsend:Linux]
|
[tests/functional/rsend:Linux]
|
||||||
tests = ['send_realloc_dnode_size', 'send_encrypted_files']
|
tests = ['send_realloc_dnode_size', 'send_encrypted_files']
|
||||||
tags = ['functional', 'rsend']
|
tags = ['functional', 'rsend']
|
||||||
|
|
|
@ -34,6 +34,8 @@ if BUILD_LINUX
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
getversion \
|
getversion \
|
||||||
randfree_file \
|
randfree_file \
|
||||||
|
read_dos_attributes \
|
||||||
user_ns_exec \
|
user_ns_exec \
|
||||||
|
write_dos_attributes \
|
||||||
xattrtest
|
xattrtest
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/read_dos_attributes
|
|
@ -0,0 +1,6 @@
|
||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = read_dos_attributes
|
||||||
|
read_dos_attributes_SOURCES = read_dos_attributes.c
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* This file and its contents are supplied under the terms of the
|
||||||
|
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
* You may only use this file in accordance with the terms of version
|
||||||
|
* 1.0 of the CDDL.
|
||||||
|
*
|
||||||
|
* A full copy of the text of the CDDL should have accompanied this
|
||||||
|
* source. A copy of the CDDL is also available via the Internet at
|
||||||
|
* http://www.illumos.org/license/CDDL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2022 iXsystems, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeBSD allows to update and retreive additional file level attributes.
|
||||||
|
* For Linux, two IOCTLs have been added to update and retrieve additional
|
||||||
|
* level attributes.
|
||||||
|
*
|
||||||
|
* This application reads additional file level attributes on a given
|
||||||
|
* file and prints FreeBSD keywords that map to respective attributes.
|
||||||
|
*
|
||||||
|
* Usage: 'read_dos_attributes filepath'
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <sys/fs/zfs.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SU_ARCH_SHORT "arch"
|
||||||
|
#define SU_ARCH_FULL "archived"
|
||||||
|
#define SU_NODUMP "nodump"
|
||||||
|
#define SU_APPEND_SHORT "sappnd"
|
||||||
|
#define SU_APPEND_FULL "sappend"
|
||||||
|
#define SU_IMMUTABLE "schg"
|
||||||
|
#define SU_IMMUTABLE_SHORT "schange"
|
||||||
|
#define SU_IMMUTABLE_FULL "simmutable"
|
||||||
|
#define SU_UNLINK_SHORT "sunlnk"
|
||||||
|
#define SU_UNLINK_FULL "sunlink"
|
||||||
|
#define U_APPEND_SHORT "uappnd"
|
||||||
|
#define U_APPEND_FULL "uappend"
|
||||||
|
#define U_ARCH_SHORT "uarch"
|
||||||
|
#define U_ARCH_FULL "uarchive"
|
||||||
|
#define U_IMMUTABLE "uchg"
|
||||||
|
#define U_IMMUTABLE_SHORT "uchange"
|
||||||
|
#define U_IMMUTABLE_FULL "uimmutable"
|
||||||
|
#define U_HIDDEN_SHORT "hidden"
|
||||||
|
#define U_HIDDEN_FULL "uhidden"
|
||||||
|
#define U_OFFLINE_SHORT "offline"
|
||||||
|
#define U_OFFLINE_FULL "uoffline"
|
||||||
|
#define U_RDONLY "rdonly"
|
||||||
|
#define U_RDONLY_SHORT "urdonly"
|
||||||
|
#define U_RDONLY_FULL "readonly"
|
||||||
|
#define U_SPARSE_SHORT "sparse"
|
||||||
|
#define U_SPARSE_FULL "usparse"
|
||||||
|
#define U_SYSTEM_SHORT "system"
|
||||||
|
#define U_SYSTEM_FULL "usystem"
|
||||||
|
#define U_REPARSE_SHORT "reparse"
|
||||||
|
#define U_REPARSE_FULL "ureparse"
|
||||||
|
#define U_UNLINK_SHORT "uunlnk"
|
||||||
|
#define U_UNLINK_FULL "uunlink"
|
||||||
|
#define UNSET_NODUMP "dump"
|
||||||
|
|
||||||
|
#define NO_ATTRIBUTE "-"
|
||||||
|
|
||||||
|
#define SEPARATOR ","
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 0x200
|
||||||
|
|
||||||
|
void attribute_to_str(uint64_t attributes, char *buff);
|
||||||
|
|
||||||
|
void
|
||||||
|
attribute_to_str(uint64_t attributes, char *buff)
|
||||||
|
{
|
||||||
|
if (attributes & ZFS_ARCHIVE) {
|
||||||
|
strcat(buff, U_ARCH_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_APPENDONLY) {
|
||||||
|
strcat(buff, U_APPEND_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_IMMUTABLE) {
|
||||||
|
strcat(buff, U_IMMUTABLE_FULL);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_NOUNLINK) {
|
||||||
|
strcat(buff, U_UNLINK_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_NODUMP) {
|
||||||
|
strcat(buff, SU_NODUMP);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_HIDDEN) {
|
||||||
|
strcat(buff, U_HIDDEN_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_OFFLINE) {
|
||||||
|
strcat(buff, U_OFFLINE_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_READONLY) {
|
||||||
|
strcat(buff, U_RDONLY);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_SPARSE) {
|
||||||
|
strcat(buff, U_SPARSE_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_SYSTEM) {
|
||||||
|
strcat(buff, U_SYSTEM_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & ZFS_REPARSE) {
|
||||||
|
strcat(buff, U_REPARSE_SHORT);
|
||||||
|
strcat(buff, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buff[0] == '\0')
|
||||||
|
strcat(buff, NO_ATTRIBUTE);
|
||||||
|
else
|
||||||
|
buff[strlen(buff) - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char * const argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
errx(EXIT_FAILURE, "Usage: %s filepath", argv[0]);
|
||||||
|
|
||||||
|
int fd = open(argv[1], O_RDWR | O_APPEND);
|
||||||
|
if (fd < 0)
|
||||||
|
err(EXIT_FAILURE, "Failed to open %s", argv[1]);
|
||||||
|
|
||||||
|
uint64_t dosflags = 0;
|
||||||
|
if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
|
||||||
|
err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
|
||||||
|
|
||||||
|
(void) close(fd);
|
||||||
|
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
memset(buffer, 0, BUFFER_SIZE);
|
||||||
|
|
||||||
|
(void) attribute_to_str(dosflags, buffer);
|
||||||
|
|
||||||
|
(void) printf("%s\n", buffer);
|
||||||
|
|
||||||
|
return (EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/write_dos_attributes
|
|
@ -0,0 +1,6 @@
|
||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = write_dos_attributes
|
||||||
|
write_dos_attributes_SOURCES = write_dos_attributes.c
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* This file and its contents are supplied under the terms of the
|
||||||
|
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
* You may only use this file in accordance with the terms of version
|
||||||
|
* 1.0 of the CDDL.
|
||||||
|
*
|
||||||
|
* A full copy of the text of the CDDL should have accompanied this
|
||||||
|
* source. A copy of the CDDL is also available via the Internet at
|
||||||
|
* http://www.illumos.org/license/CDDL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2022 iXsystems, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeBSD allows to update and retreive additional file level attributes.
|
||||||
|
* For Linux, two IOCTLs have been added to update and retrieve additional
|
||||||
|
* level attributes.
|
||||||
|
*
|
||||||
|
* This application updates additional file level attributes on a given
|
||||||
|
* file. FreeBSD keywords can be used to specify the flag.
|
||||||
|
*
|
||||||
|
* Usage: 'write_dos_attributes flag filepath'
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <sys/fs/zfs.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define SU_ARCH_SHORT "arch"
|
||||||
|
#define SU_ARCH_FULL "archived"
|
||||||
|
#define SU_NODUMP "nodump"
|
||||||
|
#define SU_APPEND_SHORT "sappnd"
|
||||||
|
#define SU_APPEND_FULL "sappend"
|
||||||
|
#define SU_IMMUTABLE "schg"
|
||||||
|
#define SU_IMMUTABLE_SHORT "schange"
|
||||||
|
#define SU_IMMUTABLE_FULL "simmutable"
|
||||||
|
#define SU_UNLINK_SHORT "sunlnk"
|
||||||
|
#define SU_UNLINK_FULL "sunlink"
|
||||||
|
#define U_APPEND_SHORT "uappnd"
|
||||||
|
#define U_APPEND_FULL "uappend"
|
||||||
|
#define U_ARCH_SHORT "uarch"
|
||||||
|
#define U_ARCH_FULL "uarchive"
|
||||||
|
#define U_IMMUTABLE "uchg"
|
||||||
|
#define U_IMMUTABLE_SHORT "uchange"
|
||||||
|
#define U_IMMUTABLE_FULL "uimmutable"
|
||||||
|
#define U_HIDDEN_SHORT "hidden"
|
||||||
|
#define U_HIDDEN_FULL "uhidden"
|
||||||
|
#define U_OFFLINE_SHORT "offline"
|
||||||
|
#define U_OFFLINE_FULL "uoffline"
|
||||||
|
#define U_RDONLY "rdonly"
|
||||||
|
#define U_RDONLY_SHORT "urdonly"
|
||||||
|
#define U_RDONLY_FULL "readonly"
|
||||||
|
#define U_SPARSE_SHORT "sparse"
|
||||||
|
#define U_SPARSE_FULL "usparse"
|
||||||
|
#define U_SYSTEM_SHORT "system"
|
||||||
|
#define U_SYSTEM_FULL "usystem"
|
||||||
|
#define U_REPARSE_SHORT "reparse"
|
||||||
|
#define U_REPARSE_FULL "ureparse"
|
||||||
|
#define U_UNLINK_SHORT "uunlnk"
|
||||||
|
#define U_UNLINK_FULL "uunlink"
|
||||||
|
#define UNSET_NODUMP "dump"
|
||||||
|
|
||||||
|
#define IS_NO(s) (s[0] == 'n' && s[1] == 'o')
|
||||||
|
|
||||||
|
uint64_t str_to_attribute(char *str);
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
str_to_attribute(char *str)
|
||||||
|
{
|
||||||
|
if ((strcmp(str, SU_ARCH_SHORT) == 0) ||
|
||||||
|
(strcmp(str, SU_ARCH_FULL) == 0) ||
|
||||||
|
(strcmp(str, U_ARCH_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_ARCH_FULL) == 0))
|
||||||
|
return (ZFS_ARCHIVE);
|
||||||
|
|
||||||
|
else if ((strcmp(str, SU_APPEND_SHORT) == 0) ||
|
||||||
|
(strcmp(str, SU_APPEND_FULL) == 0) ||
|
||||||
|
(strcmp(str, U_APPEND_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_APPEND_FULL) == 0))
|
||||||
|
return (ZFS_APPENDONLY);
|
||||||
|
|
||||||
|
else if ((strcmp(str, SU_IMMUTABLE) == 0) ||
|
||||||
|
(strcmp(str, SU_IMMUTABLE_SHORT) == 0) ||
|
||||||
|
(strcmp(str, SU_IMMUTABLE_FULL) == 0))
|
||||||
|
return (ZFS_IMMUTABLE);
|
||||||
|
|
||||||
|
else if ((strcmp(str, SU_UNLINK_SHORT) == 0) ||
|
||||||
|
(strcmp(str, SU_UNLINK_FULL) == 0) ||
|
||||||
|
(strcmp(str, U_UNLINK_SHORT) == 0) ||
|
||||||
|
(strcmp(str, SU_UNLINK_FULL) == 0))
|
||||||
|
return (ZFS_NOUNLINK);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_HIDDEN_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_HIDDEN_FULL) == 0))
|
||||||
|
return (ZFS_HIDDEN);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_OFFLINE_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_OFFLINE_FULL) == 0))
|
||||||
|
return (ZFS_OFFLINE);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_RDONLY) == 0) ||
|
||||||
|
(strcmp(str, U_RDONLY_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_RDONLY_FULL) == 0))
|
||||||
|
return (ZFS_READONLY);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_SPARSE_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_SPARSE_FULL) == 0))
|
||||||
|
return (ZFS_SPARSE);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_SYSTEM_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_SYSTEM_FULL) == 0))
|
||||||
|
return (ZFS_SYSTEM);
|
||||||
|
|
||||||
|
else if ((strcmp(str, U_REPARSE_SHORT) == 0) ||
|
||||||
|
(strcmp(str, U_REPARSE_FULL) == 0))
|
||||||
|
return (ZFS_REPARSE);
|
||||||
|
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char * const argv[])
|
||||||
|
{
|
||||||
|
if (argc != 3)
|
||||||
|
errx(EXIT_FAILURE, "Usage: %s flag filepath", argv[0]);
|
||||||
|
|
||||||
|
uint8_t unset, unset_all;
|
||||||
|
uint64_t attribute, dosflags;
|
||||||
|
char *flag = strdup(argv[1]);
|
||||||
|
unset = unset_all = 0;
|
||||||
|
attribute = dosflags = 0;
|
||||||
|
|
||||||
|
// convert the flag to lower case
|
||||||
|
for (int i = 0; i < strlen(argv[1]); ++i)
|
||||||
|
flag[i] = tolower((unsigned char) flag[i]);
|
||||||
|
|
||||||
|
// check if flag starts with 'no'
|
||||||
|
if (IS_NO(flag)) {
|
||||||
|
if (strcmp(flag, SU_NODUMP) == 0) {
|
||||||
|
attribute = ZFS_NODUMP;
|
||||||
|
} else {
|
||||||
|
attribute = str_to_attribute(flag + 2);
|
||||||
|
unset = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if '0' was passed
|
||||||
|
else if (strcmp(flag, "0") == 0) {
|
||||||
|
unset_all = 1;
|
||||||
|
}
|
||||||
|
// check if the flag is 'dump'
|
||||||
|
else if (strcmp(flag, UNSET_NODUMP) == 0) {
|
||||||
|
attribute = ZFS_NODUMP;
|
||||||
|
unset = 1;
|
||||||
|
} else {
|
||||||
|
attribute = str_to_attribute(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attribute == -1)
|
||||||
|
errx(EXIT_FAILURE, "Invalid Flag %s", argv[1]);
|
||||||
|
|
||||||
|
int fd = open(argv[2], O_RDWR | O_APPEND);
|
||||||
|
if (fd < 0)
|
||||||
|
err(EXIT_FAILURE, "Failed to open %s", argv[2]);
|
||||||
|
|
||||||
|
if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
|
||||||
|
err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
|
||||||
|
|
||||||
|
if (unset == 0 && attribute != 0)
|
||||||
|
attribute |= dosflags;
|
||||||
|
else if (unset == 1 && attribute != 0)
|
||||||
|
attribute = dosflags & (~attribute);
|
||||||
|
else if (unset_all == 1)
|
||||||
|
attribute = 0;
|
||||||
|
|
||||||
|
// set the attribute/s
|
||||||
|
if (ioctl(fd, ZFS_IOC_SETDOSFLAGS, &attribute) == -1)
|
||||||
|
err(EXIT_FAILURE, "ZFS_IOC_SETDOSFLAGS failed");
|
||||||
|
|
||||||
|
// get the attributes to confirm
|
||||||
|
dosflags = -1;
|
||||||
|
if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
|
||||||
|
err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
|
||||||
|
|
||||||
|
(void) close(fd);
|
||||||
|
|
||||||
|
if (dosflags != attribute)
|
||||||
|
errx(EXIT_FAILURE, "Could not set %s attribute", argv[1]);
|
||||||
|
|
||||||
|
(void) printf("New Dos Flags: 0x%llx\n", (u_longlong_t)dosflags);
|
||||||
|
|
||||||
|
return (EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -215,10 +215,12 @@ export ZFSTEST_FILES='badsend
|
||||||
randfree_file
|
randfree_file
|
||||||
randwritecomp
|
randwritecomp
|
||||||
readmmap
|
readmmap
|
||||||
|
read_dos_attributes
|
||||||
rename_dir
|
rename_dir
|
||||||
rm_lnkcnt_zero_file
|
rm_lnkcnt_zero_file
|
||||||
send_doall
|
send_doall
|
||||||
threadsappend
|
threadsappend
|
||||||
user_ns_exec
|
user_ns_exec
|
||||||
|
write_dos_attributes
|
||||||
xattrtest
|
xattrtest
|
||||||
stride_dd'
|
stride_dd'
|
||||||
|
|
|
@ -21,6 +21,7 @@ SUBDIRS = \
|
||||||
deadman \
|
deadman \
|
||||||
delegate \
|
delegate \
|
||||||
devices \
|
devices \
|
||||||
|
dos_attributes \
|
||||||
events \
|
events \
|
||||||
exec \
|
exec \
|
||||||
fallocate \
|
fallocate \
|
||||||
|
|
|
@ -10,7 +10,5 @@ dist_pkgdata_SCRIPTS = \
|
||||||
|
|
||||||
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/off
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/off
|
||||||
|
|
||||||
if BUILD_FREEBSD
|
|
||||||
pkgexec_PROGRAMS = dosmode_readonly_write
|
pkgexec_PROGRAMS = dosmode_readonly_write
|
||||||
dosmode_readonly_write_SOURCES = dosmode_readonly_write.c
|
dosmode_readonly_write_SOURCES = dosmode_readonly_write.c
|
||||||
endif
|
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
# DESCRIPTION:
|
# DESCRIPTION:
|
||||||
# Verify that DOS mode flags function correctly.
|
# Verify that DOS mode flags function correctly.
|
||||||
#
|
#
|
||||||
# These flags are not currently exposed on Linux, so the test is
|
|
||||||
# only useful on FreeBSD.
|
|
||||||
#
|
#
|
||||||
# STRATEGY:
|
# STRATEGY:
|
||||||
# 1. ARCHIVE
|
# 1. ARCHIVE
|
||||||
|
@ -56,7 +54,13 @@ function hasflag
|
||||||
typeset flag=$1
|
typeset flag=$1
|
||||||
typeset path=$2
|
typeset path=$2
|
||||||
|
|
||||||
ls -lo $path | awk '{ gsub(",", "\n", $5); print $5 }' | grep -qxF $flag
|
if is_linux; then
|
||||||
|
read_dos_attributes $path | awk \
|
||||||
|
'{ gsub(",", "\n", $1); print $1 }' | grep -qxF $flag
|
||||||
|
else
|
||||||
|
ls -lo $path | awk '{ gsub(",", "\n", $5); print $5 }' | \
|
||||||
|
grep -qxF $flag
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert "Verify DOS mode flags function correctly"
|
log_assert "Verify DOS mode flags function correctly"
|
||||||
|
@ -67,6 +71,12 @@ testfile=$TESTDIR/testfile
|
||||||
owner=$ZFS_ACL_STAFF1
|
owner=$ZFS_ACL_STAFF1
|
||||||
other=$ZFS_ACL_STAFF2
|
other=$ZFS_ACL_STAFF2
|
||||||
|
|
||||||
|
if is_linux; then
|
||||||
|
changeflags=write_dos_attributes
|
||||||
|
else
|
||||||
|
changeflags=chflags
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# ARCHIVE
|
# ARCHIVE
|
||||||
#
|
#
|
||||||
|
@ -75,36 +85,40 @@ other=$ZFS_ACL_STAFF2
|
||||||
#
|
#
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must hasflag uarch $testfile
|
log_must hasflag uarch $testfile
|
||||||
log_must chflags nouarch $testfile
|
log_must $changeflags nouarch $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must hasflag uarch $testfile
|
if ! is_linux; then
|
||||||
|
log_must hasflag uarch $testfile
|
||||||
|
fi
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_must hasflag uarch $testfile
|
log_must hasflag uarch $testfile
|
||||||
log_must user_run $owner chflags nouarch $testfile
|
log_must user_run $owner $changeflags nouarch $testfile
|
||||||
log_mustnot user_run $other chflags uarch $testfile
|
log_mustnot user_run $other $changeflags uarch $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_mustnot user_run $other chflags nouarch $testfile
|
log_mustnot user_run $other $changeflags nouarch $testfile
|
||||||
log_must hasflag uarch $testfile
|
if ! is_linux; then
|
||||||
|
log_must hasflag uarch $testfile
|
||||||
|
fi
|
||||||
log_must user_run $owner rm $testfile
|
log_must user_run $owner rm $testfile
|
||||||
|
|
||||||
#
|
#
|
||||||
# HIDDEN
|
# HIDDEN
|
||||||
#
|
#
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must chflags hidden $testfile
|
log_must $changeflags hidden $testfile
|
||||||
log_must hasflag hidden $testfile
|
log_must hasflag hidden $testfile
|
||||||
log_must chflags 0 $testfile
|
log_must $changeflags 0 $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_must user_run $owner chflags hidden $testfile
|
log_must user_run $owner $changeflags hidden $testfile
|
||||||
log_mustnot user_run $other chflags nohidden $testfile
|
log_mustnot user_run $other $changeflags nohidden $testfile
|
||||||
log_must hasflag hidden $testfile
|
log_must hasflag hidden $testfile
|
||||||
log_must user_run $owner chflags 0 $testfile
|
log_must user_run $owner $changeflags 0 $testfile
|
||||||
log_mustnot user_run $other chflags hidden $testfile
|
log_mustnot user_run $other $changeflags hidden $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must user_run $owner rm $testfile
|
log_must user_run $owner rm $testfile
|
||||||
|
|
||||||
|
@ -113,17 +127,17 @@ log_must user_run $owner rm $testfile
|
||||||
# OFFLINE
|
# OFFLINE
|
||||||
#
|
#
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must chflags offline $testfile
|
log_must $changeflags offline $testfile
|
||||||
log_must hasflag offline $testfile
|
log_must hasflag offline $testfile
|
||||||
log_must chflags 0 $testfile
|
log_must $changeflags 0 $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_must user_run $owner chflags offline $testfile
|
log_must user_run $owner $changeflags offline $testfile
|
||||||
log_mustnot user_run $other chflags nooffline $testfile
|
log_mustnot user_run $other $changeflags nooffline $testfile
|
||||||
log_must hasflag offline $testfile
|
log_must hasflag offline $testfile
|
||||||
log_must user_run $owner chflags 0 $testfile
|
log_must user_run $owner $changeflags 0 $testfile
|
||||||
log_mustnot user_run $other chflags offline $testfile
|
log_mustnot user_run $other $changeflags offline $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must user_run $owner rm $testfile
|
log_must user_run $owner rm $testfile
|
||||||
|
|
||||||
|
@ -134,21 +148,23 @@ log_must user_run $owner rm $testfile
|
||||||
# but root is always allowed the operation.
|
# but root is always allowed the operation.
|
||||||
#
|
#
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must chflags rdonly $testfile
|
log_must $changeflags rdonly $testfile
|
||||||
log_must hasflag rdonly $testfile
|
log_must hasflag rdonly $testfile
|
||||||
log_must eval "echo 'root write allowed' >> $testfile"
|
log_must eval "echo 'root write allowed' >> $testfile"
|
||||||
log_must cat $testfile
|
log_must cat $testfile
|
||||||
log_must chflags 0 $testfile
|
log_must $changeflags 0 $testfile
|
||||||
log_must hasflag - $tesfile
|
log_must hasflag - $testfile
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
# It is required to still be able to write to an fd that was opened RW before
|
# It is required to still be able to write to an fd that was opened RW before
|
||||||
# READONLY is set. We have a special test program for that.
|
# READONLY is set. We have a special test program for that.
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_mustnot user_run $other chflags rdonly $testfile
|
log_mustnot user_run $other $changeflags rdonly $testfile
|
||||||
log_must user_run $owner $tests_base/dosmode_readonly_write $testfile
|
log_must user_run $owner $tests_base/dosmode_readonly_write $testfile
|
||||||
log_mustnot user_run $other chflags nordonly $testfile
|
log_mustnot user_run $other $changeflags nordonly $testfile
|
||||||
log_must hasflag rdonly $testfile
|
log_must hasflag rdonly $testfile
|
||||||
log_mustnot user_run $owner "echo 'user write forbidden' >> $testfile"
|
if ! is_linux; then
|
||||||
|
log_mustnot user_run $owner "echo 'user write forbidden' >> $testfile"
|
||||||
|
fi
|
||||||
log_must eval "echo 'root write allowed' >> $testfile"
|
log_must eval "echo 'root write allowed' >> $testfile"
|
||||||
# We are still allowed to read and remove the file when READONLY is set.
|
# We are still allowed to read and remove the file when READONLY is set.
|
||||||
log_must user_run $owner cat $testfile
|
log_must user_run $owner cat $testfile
|
||||||
|
@ -157,24 +173,23 @@ log_must user_run $owner rm $testfile
|
||||||
#
|
#
|
||||||
# REPARSE
|
# REPARSE
|
||||||
#
|
#
|
||||||
# FIXME: does not work, not sure if broken or testing wrong
|
# not allowed to be changed
|
||||||
#
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# SPARSE
|
# SPARSE
|
||||||
#
|
#
|
||||||
log_must truncate -s 1m $testfile
|
log_must truncate -s 1m $testfile
|
||||||
log_must chflags sparse $testfile
|
log_must $changeflags sparse $testfile
|
||||||
log_must hasflag sparse $testfile
|
log_must hasflag sparse $testfile
|
||||||
log_must chflags 0 $testfile
|
log_must $changeflags 0 $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
log_must user_run $owner truncate -s 1m $testfile
|
log_must user_run $owner truncate -s 1m $testfile
|
||||||
log_must user_run $owner chflags sparse $testfile
|
log_must user_run $owner $changeflags sparse $testfile
|
||||||
log_mustnot user_run $other chflags nosparse $testfile
|
log_mustnot user_run $other $changeflags nosparse $testfile
|
||||||
log_must hasflag sparse $testfile
|
log_must hasflag sparse $testfile
|
||||||
log_must user_run $owner chflags 0 $testfile
|
log_must user_run $owner $changeflags 0 $testfile
|
||||||
log_mustnot user_run $other chflags sparse $testfile
|
log_mustnot user_run $other $changeflags sparse $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must user_run $owner rm $testfile
|
log_must user_run $owner rm $testfile
|
||||||
|
|
||||||
|
@ -182,17 +197,17 @@ log_must user_run $owner rm $testfile
|
||||||
# SYSTEM
|
# SYSTEM
|
||||||
#
|
#
|
||||||
log_must touch $testfile
|
log_must touch $testfile
|
||||||
log_must chflags system $testfile
|
log_must $changeflags system $testfile
|
||||||
log_must hasflag system $testfile
|
log_must hasflag system $testfile
|
||||||
log_must chflags 0 $testfile
|
log_must $changeflags 0 $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must rm $testfile
|
log_must rm $testfile
|
||||||
log_must user_run $owner touch $testfile
|
log_must user_run $owner touch $testfile
|
||||||
log_must user_run $owner chflags system $testfile
|
log_must user_run $owner $changeflags system $testfile
|
||||||
log_mustnot user_run $other chflags nosystem $testfile
|
log_mustnot user_run $other $changeflags nosystem $testfile
|
||||||
log_must hasflag system $testfile
|
log_must hasflag system $testfile
|
||||||
log_must user_run $owner chflags 0 $testfile
|
log_must user_run $owner $changeflags 0 $testfile
|
||||||
log_mustnot user_run $other chflags system $testfile
|
log_mustnot user_run $other $changeflags system $testfile
|
||||||
log_must hasflag - $testfile
|
log_must hasflag - $testfile
|
||||||
log_must user_run $owner rm $testfile
|
log_must user_run $owner rm $testfile
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/fs/zfs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char *argv[])
|
main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -51,8 +56,14 @@ main(int argc, const char *argv[])
|
||||||
fd = open(path, O_CREAT|O_RDWR, 0777);
|
fd = open(path, O_CREAT|O_RDWR, 0777);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
err(EXIT_FAILURE, "%s: open failed", path);
|
err(EXIT_FAILURE, "%s: open failed", path);
|
||||||
|
#ifdef __linux__
|
||||||
|
uint64_t dosflags = ZFS_READONLY;
|
||||||
|
if (ioctl(fd, ZFS_IOC_SETDOSFLAGS, &dosflags) == -1)
|
||||||
|
err(EXIT_FAILURE, "%s: ZFS_IOC_SETDOSFLAGS failed", path);
|
||||||
|
#else
|
||||||
if (chflags(path, UF_READONLY) == -1)
|
if (chflags(path, UF_READONLY) == -1)
|
||||||
err(EXIT_FAILURE, "%s: chflags failed", path);
|
err(EXIT_FAILURE, "%s: chflags failed", path);
|
||||||
|
#endif
|
||||||
if (write(fd, buf, strlen(buf)) == -1)
|
if (write(fd, buf, strlen(buf)) == -1)
|
||||||
err(EXIT_FAILURE, "%s: write failed", path);
|
err(EXIT_FAILURE, "%s: write failed", path);
|
||||||
if (close(fd) == -1)
|
if (close(fd) == -1)
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/dos_attributes
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
cleanup.ksh \
|
||||||
|
read_dos_attrs_001.ksh \
|
||||||
|
write_dos_attrs_001.ksh \
|
||||||
|
setup.ksh
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
default_cleanup
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
#
|
||||||
|
# Read additional file level attributes stored in upper half of z_pflags
|
||||||
|
#
|
||||||
|
# STARTEGY:
|
||||||
|
# 1) Create a file
|
||||||
|
# 2) Execute read_dos_attributes on the file we created
|
||||||
|
# 3) Verify that read_dos_attributes exited successfully
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
FILETOTEST="$TESTDIR/test_read_dos_attrs.txt"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
rm -f $FILETOTEST
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_must chmod 777 $TESTDIR
|
||||||
|
log_must eval "echo 'This is a test file.' > $FILETOTEST"
|
||||||
|
log_must read_dos_attributes $FILETOTEST
|
||||||
|
|
||||||
|
log_pass "reading DOS attributes succeeded."
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
DISK=${DISKS%% *}
|
||||||
|
default_setup $DISK
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
#
|
||||||
|
# Write additional file level attributes stored in upper half of z_pflags
|
||||||
|
#
|
||||||
|
# STARTEGY:
|
||||||
|
# 1) Create a file
|
||||||
|
# 2) Execute write_dos_attributes on the file we created
|
||||||
|
# 3) Verify that write_dos_attributes exited successfully
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
FILETOTEST="$TESTDIR/test_write_dos_attrs.txt"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
rm -f $FILETOTEST
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_must chmod 777 $TESTDIR
|
||||||
|
log_must eval "echo 'This is a test file.' > $FILETOTEST"
|
||||||
|
log_must write_dos_attributes offline $FILETOTEST
|
||||||
|
log_must write_dos_attributes nooffline $FILETOTEST
|
||||||
|
|
||||||
|
log_pass "writing DOS attributes succeeded."
|
Loading…
Reference in New Issue