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:
Umer Saleem
2022-03-08 06:52:03 +05:00
committed by GitHub
parent 9955b9ba2e
commit 39a4daf742
24 changed files with 804 additions and 62 deletions
@@ -10,7 +10,5 @@ dist_pkgdata_SCRIPTS = \
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/off
if BUILD_FREEBSD
pkgexec_PROGRAMS = dosmode_readonly_write
dosmode_readonly_write_SOURCES = dosmode_readonly_write.c
endif
@@ -31,8 +31,6 @@
# DESCRIPTION:
# Verify that DOS mode flags function correctly.
#
# These flags are not currently exposed on Linux, so the test is
# only useful on FreeBSD.
#
# STRATEGY:
# 1. ARCHIVE
@@ -56,7 +54,13 @@ function hasflag
typeset flag=$1
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"
@@ -67,6 +71,12 @@ testfile=$TESTDIR/testfile
owner=$ZFS_ACL_STAFF1
other=$ZFS_ACL_STAFF2
if is_linux; then
changeflags=write_dos_attributes
else
changeflags=chflags
fi
#
# ARCHIVE
#
@@ -75,36 +85,40 @@ other=$ZFS_ACL_STAFF2
#
log_must touch $testfile
log_must hasflag uarch $testfile
log_must chflags nouarch $testfile
log_must $changeflags nouarch $testfile
log_must hasflag - $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 user_run $owner touch $testfile
log_must hasflag uarch $testfile
log_must user_run $owner chflags nouarch $testfile
log_mustnot user_run $other chflags uarch $testfile
log_must user_run $owner $changeflags nouarch $testfile
log_mustnot user_run $other $changeflags uarch $testfile
log_must hasflag - $testfile
log_must user_run $owner touch $testfile
log_mustnot user_run $other chflags nouarch $testfile
log_must hasflag uarch $testfile
log_mustnot user_run $other $changeflags nouarch $testfile
if ! is_linux; then
log_must hasflag uarch $testfile
fi
log_must user_run $owner rm $testfile
#
# HIDDEN
#
log_must touch $testfile
log_must chflags hidden $testfile
log_must $changeflags hidden $testfile
log_must hasflag hidden $testfile
log_must chflags 0 $testfile
log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
log_must user_run $owner chflags hidden $testfile
log_mustnot user_run $other chflags nohidden $testfile
log_must user_run $owner $changeflags hidden $testfile
log_mustnot user_run $other $changeflags nohidden $testfile
log_must hasflag hidden $testfile
log_must user_run $owner chflags 0 $testfile
log_mustnot user_run $other chflags hidden $testfile
log_must user_run $owner $changeflags 0 $testfile
log_mustnot user_run $other $changeflags hidden $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -113,17 +127,17 @@ log_must user_run $owner rm $testfile
# OFFLINE
#
log_must touch $testfile
log_must chflags offline $testfile
log_must $changeflags offline $testfile
log_must hasflag offline $testfile
log_must chflags 0 $testfile
log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
log_must user_run $owner chflags offline $testfile
log_mustnot user_run $other chflags nooffline $testfile
log_must user_run $owner $changeflags offline $testfile
log_mustnot user_run $other $changeflags nooffline $testfile
log_must hasflag offline $testfile
log_must user_run $owner chflags 0 $testfile
log_mustnot user_run $other chflags offline $testfile
log_must user_run $owner $changeflags 0 $testfile
log_mustnot user_run $other $changeflags offline $testfile
log_must hasflag - $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.
#
log_must touch $testfile
log_must chflags rdonly $testfile
log_must $changeflags rdonly $testfile
log_must hasflag rdonly $testfile
log_must eval "echo 'root write allowed' >> $testfile"
log_must cat $testfile
log_must chflags 0 $testfile
log_must hasflag - $tesfile
log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
# 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.
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_mustnot user_run $other chflags nordonly $testfile
log_mustnot user_run $other $changeflags nordonly $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"
# We are still allowed to read and remove the file when READONLY is set.
log_must user_run $owner cat $testfile
@@ -157,24 +173,23 @@ log_must user_run $owner rm $testfile
#
# REPARSE
#
# FIXME: does not work, not sure if broken or testing wrong
#
# not allowed to be changed
#
# SPARSE
#
log_must truncate -s 1m $testfile
log_must chflags sparse $testfile
log_must $changeflags sparse $testfile
log_must hasflag sparse $testfile
log_must chflags 0 $testfile
log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner truncate -s 1m $testfile
log_must user_run $owner chflags sparse $testfile
log_mustnot user_run $other chflags nosparse $testfile
log_must user_run $owner $changeflags sparse $testfile
log_mustnot user_run $other $changeflags nosparse $testfile
log_must hasflag sparse $testfile
log_must user_run $owner chflags 0 $testfile
log_mustnot user_run $other chflags sparse $testfile
log_must user_run $owner $changeflags 0 $testfile
log_mustnot user_run $other $changeflags sparse $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -182,17 +197,17 @@ log_must user_run $owner rm $testfile
# SYSTEM
#
log_must touch $testfile
log_must chflags system $testfile
log_must $changeflags system $testfile
log_must hasflag system $testfile
log_must chflags 0 $testfile
log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
log_must user_run $owner chflags system $testfile
log_mustnot user_run $other chflags nosystem $testfile
log_must user_run $owner $changeflags system $testfile
log_mustnot user_run $other $changeflags nosystem $testfile
log_must hasflag system $testfile
log_must user_run $owner chflags 0 $testfile
log_mustnot user_run $other chflags system $testfile
log_must user_run $owner $changeflags 0 $testfile
log_mustnot user_run $other $changeflags system $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -36,6 +36,11 @@
#include <string.h>
#include <unistd.h>
#ifdef __linux__
#include <stdint.h>
#include <sys/fs/zfs.h>
#endif
int
main(int argc, const char *argv[])
{
@@ -51,8 +56,14 @@ main(int argc, const char *argv[])
fd = open(path, O_CREAT|O_RDWR, 0777);
if (fd == -1)
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)
err(EXIT_FAILURE, "%s: chflags failed", path);
#endif
if (write(fd, buf, strlen(buf)) == -1)
err(EXIT_FAILURE, "%s: write failed", path);
if (close(fd) == -1)