From: Ethan Benson <erbenson@alaska.net>

Currently Linux allows the use of the utime() and utimes() syscalls on
immutable or append-only files, this is incorrect.

utime{s}() is not supposed to work if you lack write access to a file,
in the case of an immutable file NOBODY has write access.

for an append-only file it only makes sense to be able to update its
time to present, not the past.

I have checked BSD, and they implement the behavior I propose, for
immutable files utime() and utimes() fail.  for append-only files they
fail if the time argument is not NULL.



 25-akpm/fs/open.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+)

diff -puN fs/open.c~utime-on-immutable-file-fix fs/open.c
--- 25/fs/open.c~utime-on-immutable-file-fix	Thu Sep  4 11:14:12 2003
+++ 25-akpm/fs/open.c	Thu Sep  4 11:14:12 2003
@@ -354,6 +354,10 @@ asmlinkage long sys_utime(char __user * 
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (times) {
+		error = -EPERM;
+		if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+			goto dput_and_out;
+
 		error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
 		newattrs.ia_atime.tv_nsec = 0;
 		if (!error) 
@@ -364,6 +368,10 @@ asmlinkage long sys_utime(char __user * 
 
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
+                error = -EACCES;
+                if (IS_IMMUTABLE(inode))
+                        goto dput_and_out;
+
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE,&nd)) != 0)
 			goto dput_and_out;
@@ -403,12 +411,20 @@ long do_utimes(char __user * filename, s
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (times) {
+		error = -EPERM;
+                if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+                        goto dput_and_out;
+
 		newattrs.ia_atime.tv_sec = times[0].tv_sec;
 		newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
 		newattrs.ia_mtime.tv_sec = times[1].tv_sec;
 		newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
+		error = -EACCES;
+                if (IS_IMMUTABLE(inode))
+                        goto dput_and_out;
+
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE,&nd)) != 0)
 			goto dput_and_out;

_