diff -urN --exclude-from /home/mkp/bin/dontdiff linux-2.4.20pre10/fs/namei.c linux-trunc/fs/namei.c --- linux-2.4.20pre10/fs/namei.c Fri Oct 11 12:37:39 2002 +++ linux-trunc/fs/namei.c Fri Oct 11 13:02:04 2002 @@ -982,47 +982,89 @@ return error; } -/* - * open_namei() - * - * namei for open - this is in fact almost the whole open-routine. - * - * Note that the low bits of "flag" aren't the same as in the open - * system call - they are 00 - no permissions needed - * 01 - read permission needed - * 10 - write permission needed - * 11 - read/write permissions needed - * which is a lot more logical, and also allows the "no perm" needed - * for symlinks (where the permissions are checked later). - * SMP-safe - */ -int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) +int may_open(struct nameidata *nd, int acc_mode, int flag) +{ + struct dentry *dentry = nd->dentry; + struct inode *inode = dentry->d_inode; + int error; + + if (!inode) + return -ENOENT; + + if (S_ISLNK(inode->i_mode)) + return -ELOOP; + + if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) + return -EISDIR; + + error = permission(inode, acc_mode); + if (error) + return error; + + /* + * FIFO's, sockets and device files are special: they don't + * actually live on the filesystem itself, and as such you + * can write to them even if the filesystem is read-only. + */ + if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + flag &= ~O_TRUNC; + } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { + if (nd->mnt->mnt_flags & MNT_NODEV) + return -EACCES; + + flag &= ~O_TRUNC; + } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) + return -EROFS; + /* + * An append-only file must be opened in append mode for writing. + */ + if (IS_APPEND(inode)) { + if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) + return -EPERM; + if (flag & O_TRUNC) + return -EPERM; + } + + /* + * Ensure there are no outstanding leases on the file. + */ + return get_lease(inode, flag); +} + +struct file *filp_open(const char * pathname, int open_flags, int mode) { int acc_mode, error = 0; struct inode *inode; struct dentry *dentry; struct dentry *dir; + int flag = open_flags; + struct nameidata nd; int count = 0; + if ((flag+1) & O_ACCMODE) + flag++; + if (flag & O_TRUNC) + flag |= 2; + acc_mode = ACC_MODE(flag); /* * The simplest case - just a plain lookup. */ if (!(flag & O_CREAT)) { - error = path_lookup(pathname, lookup_flags(flag), nd); + error = path_lookup(pathname, lookup_flags(flag), &nd); if (error) - return error; - dentry = nd->dentry; + return ERR_PTR(error); + dentry = nd.dentry; goto ok; } /* * Create - we need to know the parent. */ - error = path_lookup(pathname, LOOKUP_PARENT, nd); + error = path_lookup(pathname, LOOKUP_PARENT, &nd); if (error) - return error; + return ERR_PTR(error); /* * We have the parent and last component. First of all, check @@ -1030,12 +1072,12 @@ * will not do. */ error = -EISDIR; - if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len]) + if (nd.last_type != LAST_NORM || nd.last.name[nd.last.len]) goto exit; - dir = nd->dentry; + dir = nd.dentry; down(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); + dentry = lookup_hash(&nd.last, nd.dentry); do_last: error = PTR_ERR(dentry); @@ -1049,13 +1091,14 @@ error = vfs_create(dir->d_inode, dentry, mode & ~current->fs->umask); up(&dir->d_inode->i_sem); - dput(nd->dentry); - nd->dentry = dentry; + dput(nd.dentry); + nd.dentry = dentry; if (error) goto exit; /* Don't check for write permission, don't truncate */ acc_mode = 0; flag &= ~O_TRUNC; + open_flags &= ~O_TRUNC; goto ok; } @@ -1072,7 +1115,7 @@ error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; - while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); + while (__follow_down(&nd.mnt,&dentry) && d_mountpoint(dentry)); } error = -ENOENT; if (!dentry->d_inode) @@ -1080,93 +1123,25 @@ if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) goto do_link; - dput(nd->dentry); - nd->dentry = dentry; + dput(nd.dentry); + nd.dentry = dentry; error = -EISDIR; if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) goto exit; ok: - error = -ENOENT; - inode = dentry->d_inode; - if (!inode) - goto exit; - - error = -ELOOP; - if (S_ISLNK(inode->i_mode)) - goto exit; - - error = -EISDIR; - if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) - goto exit; - - error = permission(inode,acc_mode); - if (error) - goto exit; - - /* - * FIFO's, sockets and device files are special: they don't - * actually live on the filesystem itself, and as such you - * can write to them even if the filesystem is read-only. - */ - if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { - flag &= ~O_TRUNC; - } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { - error = -EACCES; - if (nd->mnt->mnt_flags & MNT_NODEV) - goto exit; - - flag &= ~O_TRUNC; - } else { - error = -EROFS; - if (IS_RDONLY(inode) && (flag & 2)) - goto exit; - } - /* - * An append-only file must be opened in append mode for writing. - */ - error = -EPERM; - if (IS_APPEND(inode)) { - if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) - goto exit; - if (flag & O_TRUNC) - goto exit; - } - - /* - * Ensure there are no outstanding leases on the file. - */ - error = get_lease(inode, flag); + error = may_open(&nd, acc_mode, flag); if (error) goto exit; + if (!S_ISREG(nd.dentry->d_inode->i_mode)) + open_flags &= ~O_TRUNC; - if (flag & O_TRUNC) { - error = get_write_access(inode); - if (error) - goto exit; - - /* - * Refuse to truncate files with mandatory locks held on them. - */ - error = locks_verify_locked(inode); - if (!error) { - DQUOT_INIT(inode); - - error = do_truncate(dentry, 0); - } - put_write_access(inode); - if (error) - goto exit; - } else - if (flag & FMODE_WRITE) - DQUOT_INIT(inode); - - return 0; + return dentry_open(nd.dentry, nd.mnt, open_flags); exit_dput: dput(dentry); exit: - path_release(nd); - return error; + path_release(&nd); + return ERR_PTR(error); do_link: error = -ELOOP; @@ -1179,34 +1154,34 @@ * After that we have the parent and last component, i.e. * we are in the same situation as after the first path_walk(). * Well, almost - if the last component is normal we get its copy - * stored in nd->last.name and we will have to putname() it when we + * stored in nd.last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ UPDATE_ATIME(dentry->d_inode); - error = dentry->d_inode->i_op->follow_link(dentry, nd); + error = dentry->d_inode->i_op->follow_link(dentry, &nd); dput(dentry); if (error) return error; - if (nd->last_type == LAST_BIND) { - dentry = nd->dentry; + if (nd.last_type == LAST_BIND) { + dentry = nd.dentry; goto ok; } error = -EISDIR; - if (nd->last_type != LAST_NORM) + if (nd.last_type != LAST_NORM) goto exit; - if (nd->last.name[nd->last.len]) { - putname(nd->last.name); + if (nd.last.name[nd.last.len]) { + putname(nd.last.name); goto exit; } error = -ELOOP; if (count++==32) { - putname(nd->last.name); + putname(nd.last.name); goto exit; } - dir = nd->dentry; + dir = nd.dentry; down(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); - putname(nd->last.name); + dentry = lookup_hash(&nd.last, nd.dentry); + putname(nd.last.name); goto do_last; } diff -urN --exclude-from /home/mkp/bin/dontdiff linux-2.4.20pre10/fs/open.c linux-trunc/fs/open.c --- linux-2.4.20pre10/fs/open.c Fri Oct 11 12:37:40 2002 +++ linux-trunc/fs/open.c Fri Oct 11 13:05:27 2002 @@ -624,38 +624,6 @@ return error; } -/* - * Note that while the flag value (low two bits) for sys_open means: - * 00 - read-only - * 01 - write-only - * 10 - read-write - * 11 - special - * it is changed into - * 00 - no permissions needed - * 01 - read-permission - * 10 - write-permission - * 11 - read-write - * for the internal routines (ie open_namei()/follow_link() etc). 00 is - * used by symlinks. - */ -struct file *filp_open(const char * filename, int flags, int mode) -{ - int namei_flags, error; - struct nameidata nd; - - namei_flags = flags; - if ((namei_flags+1) & O_ACCMODE) - namei_flags++; - if (namei_flags & O_TRUNC) - namei_flags |= 2; - - error = open_namei(filename, namei_flags, mode, &nd); - if (!error) - return dentry_open(nd.dentry, nd.mnt, flags); - - return ERR_PTR(error); -} - struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; @@ -670,10 +638,24 @@ f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; - if (f->f_mode & FMODE_WRITE) { + if (flags & O_TRUNC) { + error = get_write_access(inode); + if (error) + goto cleanup_file; + error = locks_verify_locked(inode); + if (!error) { + DQUOT_INIT(inode); + error = do_truncate(dentry, 0); + } + if (error || !(f->f_mode & FMODE_WRITE)) + put_write_access(inode); + if (error) + goto cleanup_file; + } else if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; + DQUOT_INIT(inode); } f->f_dentry = dentry; diff -urN --exclude-from /home/mkp/bin/dontdiff linux-2.4.20pre10/include/linux/fs.h linux-trunc/include/linux/fs.h --- linux-2.4.20pre10/include/linux/fs.h Fri Oct 11 12:37:42 2002 +++ linux-trunc/include/linux/fs.h Fri Oct 11 13:07:06 2002 @@ -1258,7 +1258,7 @@ } extern int do_pipe(int *); -extern int open_namei(const char *, int, int, struct nameidata *); +extern int may_open(struct nameidata *, int, int); extern int kernel_read(struct file *, unsigned long, char *, unsigned long); extern struct file * open_exec(const char *);