diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ext2_ioctl.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_ext2_ioctl.h --- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ext2_ioctl.h Wed Dec 31 14:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_ext2_ioctl.h Mon Jul 21 15:57:33 2003 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_EXT2_IOCTL_H__ +#define __XFS_EXT2_IOCTL_H__ + +/* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support + * chattr/lsattr */ +#define XFS_IOC_EXT2_GETFLAGS _IOR('f', 1, long) +#define XFS_IOC_EXT2_SETFLAGS _IOW('f', 2, long) + +#define EXT2_FLAG_SYNC 0x00000008 /* Synchronous updates */ +#define EXT2_FLAG_IMMUTABLE 0x00000010 /* Immutable file */ +#define EXT2_FLAG_APPEND 0x00000020 /* writes to file may only append */ +#define EXT2_FLAG_NOATIME 0x00000080 /* do not update atime */ + +#endif /* __XFS_EXT2_IOCTL_H__ */ diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ioctl.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c --- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_ioctl.c Mon Jul 21 15:12:50 2003 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c Mon Jul 21 15:19:13 2003 @@ -66,6 +66,7 @@ #include "xfs_utils.h" #include "xfs_dfrag.h" #include "xfs_fsops.h" +#include "xfs_ext2_ioctl.h" #include #include @@ -327,6 +328,13 @@ if (permflag & O_TRUNC) permflag |= 2; + if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && + (permflag & FMODE_WRITE) && IS_APPEND(inode)) + return -XFS_ERROR(EPERM); + + if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) + return -XFS_ERROR(EACCES); + /* Can't write directories. */ if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { iput(inode); @@ -447,6 +455,9 @@ if (error) return -error; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -XFS_ERROR(EPERM); + if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { VN_RELE(vp); return -XFS_ERROR(EFAULT); @@ -532,11 +543,21 @@ NULL, ops[i].am_error); break; case ATTR_OP_SET: + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + kfree(ops); + VN_RELE(vp); + return -XFS_ERROR(EPERM); + } VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags, NULL, ops[i].am_error); break; case ATTR_OP_REMOVE: + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + kfree(ops); + VN_RELE(vp); + return -XFS_ERROR(EPERM); + } VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags, NULL, ops[i].am_error); break; @@ -842,6 +863,75 @@ error = xfs_errortag_clearall(mp); return -error; + case XFS_IOC_EXT2_GETFLAGS: { + unsigned int flags = 0; + + if (vp->v_inode.i_flags & S_IMMUTABLE) + flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */ + if (vp->v_inode.i_flags & S_APPEND) + flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */ + if (vp->v_inode.i_flags & S_SYNC) + flags |= EXT2_FLAG_SYNC; /* EXT2_SYNC_FL */ + if (vp->v_inode.i_flags & S_NOATIME) + flags |= EXT2_FLAG_NOATIME; /* EXT2_NOATIME_FL */ + + if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_EXT2_SETFLAGS: { + vattr_t va; + unsigned int flags; + int attr_flags = 0; + + if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags))) + return -XFS_ERROR(EFAULT); + + /* we need to do getattr to preserve XFS xflags ext2 + * has no knowledge of */ + + va.va_mask = XFS_AT_XFLAGS; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return -error; + + if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) || + va.va_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND)) + if (!capable(CAP_LINUX_IMMUTABLE)) + return -XFS_ERROR(EPERM); + + /* don't silently ignore unsupported ext2 flags */ + if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND| + EXT2_FLAG_SYNC|EXT2_FLAG_NOATIME)) + return -XFS_ERROR(EOPNOTSUPP); + + if (flags & EXT2_FLAG_IMMUTABLE) /* EXT2_IMMUTABLE_FL */ + va.va_xflags |= XFS_XFLAG_IMMUTABLE; + else + va.va_xflags &= ~XFS_XFLAG_IMMUTABLE; + if (flags & EXT2_FLAG_APPEND) /* EXT2_APPEND_FL */ + va.va_xflags |= XFS_XFLAG_APPEND; + else + va.va_xflags &= ~XFS_XFLAG_APPEND; + if (flags & EXT2_FLAG_SYNC) /* EXT2_SYNC_FL */ + va.va_xflags |= XFS_XFLAG_SYNC; + else + va.va_xflags &= ~XFS_XFLAG_SYNC; + if (flags & EXT2_FLAG_NOATIME) /* EXT2_NOATIME_FL */ + va.va_xflags |= XFS_XFLAG_NOATIME; + else + va.va_xflags &= ~XFS_XFLAG_NOATIME; + + if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + attr_flags |= ATTR_NONBLOCK; + + VOP_SETATTR(vp, &va, attr_flags, NULL, error); + if (!error) + vn_revalidate(vp); /* push immutable/append flags into vfs inode */ + return -error; + } + default: return -ENOTTY; } @@ -859,6 +949,9 @@ int attr_flags = 0; int error; + if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) + return -XFS_ERROR(EPERM); + if (filp->f_flags & O_RDONLY) return -XFS_ERROR(EBADF); @@ -1012,6 +1105,11 @@ if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) return -XFS_ERROR(EFAULT); + if (fa.fsx_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND) || + va.va_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND)) + if (!capable(CAP_LINUX_IMMUTABLE)) + return -XFS_ERROR(EPERM); + va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; va.va_xflags = fa.fsx_xflags; va.va_extsize = fa.fsx_extsize; @@ -1020,6 +1118,8 @@ attr_flags |= ATTR_NONBLOCK; VOP_SETATTR(vp, &va, attr_flags, NULL, error); + if (!error) + vn_revalidate(vp); /* push immutable/append flags into vfs inode */ return -error; } diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_iops.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c --- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_iops.c Mon Jul 21 15:12:55 2003 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c Mon Jul 21 15:19:13 2003 @@ -617,6 +617,9 @@ return error; } + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + /* Convert Linux syscall to XFS internal ATTR flags */ if (flags & XATTR_CREATE) xflags |= ATTR_CREATE; @@ -766,6 +769,9 @@ error = xfs_cap_vremove(vp); return error; } + + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, xfs_namespaces[ROOT_NAMES].namelen) == 0) { diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_super.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c --- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_super.c Mon Jul 21 15:13:02 2003 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c Mon Jul 21 15:19:13 2003 @@ -181,6 +181,22 @@ inode->i_atime = ip->i_d.di_atime.t_sec; inode->i_mtime = ip->i_d.di_mtime.t_sec; inode->i_ctime = ip->i_d.di_ctime.t_sec; + if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (ip->i_d.di_flags & XFS_DIFLAG_SYNC) + inode->i_flags |= S_SYNC; + else + inode->i_flags &= ~S_SYNC; + if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME) + inode->i_flags |= S_NOATIME; + else + inode->i_flags &= ~S_NOATIME; vp->v_flag &= ~VMODIFIED; } diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_vnode.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c --- linux-2.4-xfs.orig/linux/fs/xfs/linux/xfs_vnode.c Mon Jul 21 15:13:07 2003 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c Mon Jul 21 15:19:13 2003 @@ -224,6 +224,23 @@ inode->i_mtime = va.va_mtime.tv_sec; inode->i_ctime = va.va_ctime.tv_sec; inode->i_atime = va.va_atime.tv_sec; + if (va.va_xflags & XFS_XFLAG_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (va.va_xflags & XFS_XFLAG_APPEND) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (va.va_xflags & XFS_XFLAG_SYNC) + inode->i_flags |= S_SYNC; + else + inode->i_flags &= ~S_SYNC; + if (va.va_xflags & XFS_XFLAG_NOATIME) + inode->i_flags |= S_NOATIME; + else + inode->i_flags &= ~S_NOATIME; + VUNMODIFY(vp); } return -error; diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_acl.c linux-2.4-xfs/linux/fs/xfs/xfs_acl.c --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_acl.c Mon Jul 21 15:06:54 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_acl.c Mon Jul 21 15:19:13 2003 @@ -388,6 +388,8 @@ vattr_t va; int error; + if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) + return EPERM; if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR) return ENOTDIR; if (vp->v_vfsp->vfs_flag & VFS_RDONLY) diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_cap.c linux-2.4-xfs/linux/fs/xfs/xfs_cap.c --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_cap.c Mon Jul 21 15:08:15 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_cap.c Mon Jul 21 15:19:13 2003 @@ -192,6 +192,8 @@ if (vp->v_vfsp->vfs_flag & VFS_RDONLY) return EROFS; + if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) + return EPERM; if ((error = _MAC_VACCESS(vp, NULL, VWRITE))) return error; va.va_mask = XFS_AT_UID; diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_dinode.h linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_dinode.h Mon Jul 21 15:08:29 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h Mon Jul 21 15:19:13 2003 @@ -468,13 +468,23 @@ * There should be a one-to-one correspondence between these flags and the * XFS_XFLAG_s. */ -#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ -#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ -#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ -#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) -#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) -#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) +#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ +#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ +#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ +#define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */ +#define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */ +#define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ +#define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ +#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) +#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) +#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) +#define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) +#define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) +#define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) +#define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) #define XFS_DIFLAG_ALL \ - (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) + (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM| \ + XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND|XFS_DIFLAG_SYNC| \ + XFS_DIFLAG_NOATIME) #endif /* __XFS_DINODE_H__ */ diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_fs.h linux-2.4-xfs/linux/fs/xfs/xfs_fs.h --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_fs.h Mon Jul 21 15:09:27 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_fs.h Mon Jul 21 15:19:13 2003 @@ -71,9 +71,14 @@ */ #define XFS_XFLAG_REALTIME 0x00000001 #define XFS_XFLAG_PREALLOC 0x00000002 +#define XFS_XFLAG_IMMUTABLE 0x00000008 +#define XFS_XFLAG_APPEND 0x00000010 +#define XFS_XFLAG_SYNC 0x00000020 +#define XFS_XFLAG_NOATIME 0x00000040 #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ #define XFS_XFLAG_ALL \ - ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR ) + ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_IMMUTABLE| \ + XFS_XFLAG_APPEND|XFS_XFLAG_SYNC|XFS_XFLAG_NOATIME|XFS_XFLAG_HASATTR ) /* diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_inode.c linux-2.4-xfs/linux/fs/xfs/xfs_inode.c --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_inode.c Sat Aug 2 18:10:39 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inode.c Sun Aug 3 22:02:37 2003 @@ -1207,6 +1207,8 @@ break; case IFREG: case IFDIR: + if (pip->i_d.di_flags & XFS_DIFLAG_SYNC) + ip->i_d.di_flags |= XFS_DIFLAG_SYNC; case IFLNK: ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS; @@ -3486,6 +3488,9 @@ if (IS_RDONLY(inode) && (S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode))) return XFS_ERROR(EROFS); + + if (IS_IMMUTABLE(inode)) + return XFS_ERROR(EACCES); } /* @@ -3609,7 +3614,7 @@ * Don't update access timestamps on reads if mounted "noatime" * Throw it away if anyone asks us. */ - if (ip->i_mount->m_flags & XFS_MOUNT_NOATIME && + if ((ip->i_mount->m_flags & XFS_MOUNT_NOATIME || IS_NOATIME(inode)) && ((flags & (XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD|XFS_ICHGTIME_CHG)) == XFS_ICHGTIME_ACC)) return; diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_itable.c linux-2.4-xfs/linux/fs/xfs/xfs_itable.c --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_itable.c Mon Jul 21 15:10:06 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_itable.c Mon Jul 21 15:19:13 2003 @@ -163,6 +163,14 @@ XFS_XFLAG_REALTIME : 0) | ((di_flags & XFS_DIFLAG_PREALLOC) ? XFS_XFLAG_PREALLOC : 0) | + ((di_flags & XFS_DIFLAG_IMMUTABLE) ? + XFS_XFLAG_IMMUTABLE : 0) | + ((di_flags & XFS_DIFLAG_APPEND) ? + XFS_XFLAG_APPEND : 0) | + ((di_flags & XFS_DIFLAG_SYNC) ? + XFS_XFLAG_SYNC : 0) | + ((di_flags & XFS_DIFLAG_NOATIME) ? + XFS_XFLAG_NOATIME : 0) | (XFS_CFORK_Q_ARCH(dic, arch) ? XFS_XFLAG_HASATTR : 0); diff -urN -xCVS linux-2.4-xfs.orig/linux/fs/xfs/xfs_vnodeops.c linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c --- linux-2.4-xfs.orig/linux/fs/xfs/xfs_vnodeops.c Mon Jul 21 15:11:41 2003 +++ linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c Mon Jul 21 15:19:13 2003 @@ -266,6 +266,14 @@ XFS_XFLAG_REALTIME : 0) | ((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ? XFS_XFLAG_PREALLOC : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) ? + XFS_XFLAG_IMMUTABLE : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_APPEND) ? + XFS_XFLAG_APPEND : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_SYNC) ? + XFS_XFLAG_SYNC : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_NOATIME) ? + XFS_XFLAG_NOATIME : 0) | (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; @@ -833,6 +841,14 @@ ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; ip->i_iocore.io_flags |= XFS_IOCORE_RT; } + if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) + ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; + if (vap->va_xflags & XFS_XFLAG_APPEND) + ip->i_d.di_flags |= XFS_DIFLAG_APPEND; + if (vap->va_xflags & XFS_XFLAG_SYNC) + ip->i_d.di_flags |= XFS_DIFLAG_SYNC; + if (vap->va_xflags & XFS_XFLAG_NOATIME) + ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; /* can't set PREALLOC this way, just ignore it */ } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);