VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 45
+SUBLEVEL = 46
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
goto end_coredump;
if (get_write_access(inode))
goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_dentry = dentry;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto done_coredump;
+ if (init_private_file(&file, dentry, 3))
+ goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_dentry = dentry;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_coredump;
+ if (init_private_file(&file, dentry, 3))
+ goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_readexec;
- file.f_mode = 1;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_dentry = dentry;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_readexec;
- if (!file.f_op || !file.f_op->read)
+ if (init_private_file(&file, dentry, 1))
+ goto end_readexec;
+ if (!file.f_op->read)
goto close_readexec;
if (file.f_op->llseek) {
if (file.f_op->llseek(inode,&file,offset,0) != offset)
return 0;
}
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
void ext2_free_inode (struct inode * inode)
{
int is_directory;
is_directory = S_ISDIR(inode->i_mode);
+ /* Do this BEFORE marking the inode not in use */
if (sb->dq_op)
sb->dq_op->free_inode (inode, 1);
clear_inode (inode);
+ /* Ok, now we can actually update the inode bitmaps.. */
if (!ext2_clear_bit (bit, bh->b_data))
ext2_warning (sb, "ext2_free_inode",
"bit already cleared for inode %lu", ino);
return f;
}
+/*
+ * Clear and initialize a (private) struct file for the given dentry,
+ * and call the open function (if any). The caller must verify that
+ * inode->i_op and inode->i_op->default_file_ops are not NULL.
+ */
+int init_private_file(struct file *filp, struct dentry *dentry, int mode)
+{
+ memset(filp, 0, sizeof(*filp));
+ filp->f_mode = mode;
+ filp->f_count = 1;
+ filp->f_dentry = dentry;
+ filp->f_op = dentry->d_inode->i_op->default_file_ops;
+ if (filp->f_op->open)
+ return filp->f_op->open(dentry->d_inode, filp);
+ else
+ return 0;
+}
+
#ifdef CONFIG_QUOTA
void add_dquot_ref(kdev_t dev, short type)
memset(&inode->u, 0, sizeof(inode->u));
inode->i_sock = 0;
inode->i_op = NULL;
- inode->i_nlink = 0;
+ inode->i_nlink = 1;
inode->i_writecount = 0;
inode->i_size = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
#include <asm/uaccess.h>
#include <asm/bitops.h>
-void minix_put_inode(struct inode *inode)
+static void minix_delete_inode(struct inode *inode)
{
- if (inode->i_nlink)
- return;
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
static struct super_operations minix_sops = {
minix_read_inode,
- NULL,
minix_write_inode,
- minix_put_inode,
+ NULL, /* put_inode */
+ minix_delete_inode,
+ NULL, /* notify_change */
minix_put_super,
minix_write_super,
minix_statfs,
*offset += info->s_dirsize;
if (!de->inode || len > info->s_namelen)
return 0;
- /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
- if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
- return 1;
return namecompare(len,info->s_namelen,name,de->name);
}
return NULL;
}
-int minix_lookup(struct inode * dir, struct qstr *name,
- struct inode ** result)
+int minix_lookup(struct inode * dir, struct dentry *dentry)
{
- int ino;
+ struct inode * inode = NULL;
struct minix_dir_entry * de;
struct buffer_head * bh;
- *result = NULL;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode))
- return -ENOENT;
- if (!(bh = minix_find_entry(dir, name->name, name->len, &de)))
- return -ENOENT;
- ino = de->inode;
- brelse(bh);
- if (!(*result = iget(dir->i_sb,ino)))
- return -EACCES;
+ bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
+ brelse (bh);
+ inode = iget(dir->i_sb, ino);
+
+ if (!inode)
+ return -EACCES;
+ }
+ d_add(dentry, inode);
return 0;
}
return 0;
}
-static int subdir(struct inode * new_inode, struct inode * old_inode)
+static int subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
- int result;
+ int result = 0;
- new_inode->i_count++;
- result = 0;
for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
}
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (minix_lookup(new_inode,
- &(struct qstr) { "..", 2, 0 },
- &new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
+ result = 1;
+ break;
}
- iput(new_inode);
return result;
}
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -EIO;
dir_bh = minix_bread(old_inode,0,0);
}
if (!*name)
- return base;
+ goto return_base;
/* At this point we know we have a real path component. */
for(;;) {
struct qstr this;
char c, follow;
- dentry = base;
- if (IS_ERR(base))
- break;
dentry = ERR_PTR(-ENOENT);
if (!base->d_inode)
break;
break;
base = do_follow_link(base, dentry);
- if (c)
+ if (c && !IS_ERR(base))
continue;
+return_base:
return base;
}
dput(base);
struct inode *dir;
struct dentry *dentry;
- dentry = lookup_dentry(name, NULL, 1);
+ dentry = lookup_dentry(name, NULL, 0);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto exit;
struct inode * old_dir, * new_dir;
struct dentry * old_dentry, *new_dentry;
- old_dentry = lookup_dentry(oldname, NULL, 1);
+ old_dentry = lookup_dentry(oldname, NULL, 0);
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit;
- new_dentry = lookup_dentry(newname, NULL, 1);
+ new_dentry = lookup_dentry(newname, NULL, 0);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
return error;
}
-asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
{
struct inode * inode;
- struct dentry * dentry;
- struct file * file;
struct iattr newattrs;
- int error = -EBADF;
+ int error;
- lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out;
- if (!(inode = dentry->d_inode))
+ if (!(inode = dentry->d_inode)) {
+ printk("chown_common: NULL inode\n");
goto out;
+ }
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
} else
error = notify_change(inode, &newattrs);
out:
- unlock_kernel();
return error;
}
+asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = lnamei(filename);
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+
+ error = chown_common(dentry, user, group);
+
+ dput(dentry);
+out:
+ unlock_kernel();
+ return(error);
+}
+
asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
{
struct dentry * dentry;
- struct inode * inode;
int error;
- struct iattr newattrs;
lock_kernel();
dentry = namei(filename);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
- inode = dentry->d_inode;
- error = -EROFS;
- if (IS_RDONLY(inode))
- goto dput_and_out;
+ error = chown_common(dentry, user, group);
- error = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto dput_and_out;
-
- if (user == (uid_t) -1)
- user = inode->i_uid;
- if (group == (gid_t) -1)
- group = inode->i_gid;
- newattrs.ia_mode = inode->i_mode;
- newattrs.ia_uid = user;
- newattrs.ia_gid = group;
- newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
- /*
- * If the owner has been changed, remove the setuid bit
- */
- if (inode->i_mode & S_ISUID) {
- newattrs.ia_mode &= ~S_ISUID;
- newattrs.ia_valid |= ATTR_MODE;
- }
- /*
- * If the group has been changed, remove the setgid bit
- *
- * Don't remove the setgid bit if no group execute bit.
- * This is a file marked for mandatory locking.
- */
- if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
- newattrs.ia_mode &= ~S_ISGID;
- newattrs.ia_valid |= ATTR_MODE;
- }
- if (inode->i_sb->dq_op) {
- inode->i_sb->dq_op->initialize(inode, -1);
- error = -EDQUOT;
- if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
- goto dput_and_out;
- error = notify_change(inode, &newattrs);
- if (error)
- inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
- } else
- error = notify_change(inode, &newattrs);
-dput_and_out:
dput(dentry);
out:
unlock_kernel();
return(error);
}
+asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+{
+ struct dentry * dentry;
+ struct file * file;
+ int error = -EBADF;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ goto out;
+ error = -ENOENT;
+ if (!(dentry = file->f_dentry))
+ goto out;
+
+ error = chown_common(dentry, user, group);
+
+out:
+ unlock_kernel();
+ return error;
+}
+
/*
* Note that while the flag value (low two bits) for sys_open means:
* 00 - read-only
void *private_data;
};
+extern int init_private_file(struct file *, struct dentry *, int);
+
#define FL_POSIX 1
#define FL_FLOCK 2
#define FL_BROKEN 4 /* broken flock() emulation */
#ifdef __KERNEL__
-extern int minix_lookup(struct inode * dir, struct qstr *name,
- struct inode ** result);
+extern int minix_lookup(struct inode * dir, struct dentry *dentry);
extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
extern int minix_remount (struct super_block * sb, int * flags, char * data);
extern void minix_read_inode(struct inode *);
extern void minix_write_inode(struct inode *);
-extern void minix_put_inode(struct inode *);
extern int minix_statfs(struct super_block *, struct statfs *, int);
extern int minix_sync_inode(struct inode *);
extern int minix_sync_file(struct inode *, struct file *);
EXPORT_SYMBOL(close_fp);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
+EXPORT_SYMBOL(d_add);
+EXPORT_SYMBOL(d_move);
+EXPORT_SYMBOL(d_instantiate);
+EXPORT_SYMBOL(__mark_inode_dirty);
EXPORT_SYMBOL(insert_file_free);
EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(invalidate_buffers);
* Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
*/
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>