unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment, unsigned goal, unsigned count, int * err ) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct buffer_head * bh; unsigned cgno, oldcount, newcount, tmp, request, i, result; unsigned swab; UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) sb = inode->i_sb; swab = sb->u.ufs_sb.s_swab; uspi = sb->u.ufs_sb.s_uspi; usb1 = ubh_get_usb_first(USPI_UBH); *err = -ENOSPC; lock_super (sb); tmp = SWAB32(*p); if (count + ufs_fragnum(fragment) > uspi->s_fpb) { ufs_warning (sb, "ufs_new_fragments", "internal warning" " fragment %u, count %u", fragment, count); count = uspi->s_fpb - ufs_fragnum(fragment); } oldcount = ufs_fragnum (fragment); newcount = oldcount + count; /* * Somebody else has just allocated our fragments */ if (oldcount) { if (!tmp) { ufs_error (sb, "ufs_new_fragments", "internal error, " "fragment %u, tmp %u\n", fragment, tmp); return (unsigned)-1; } if (fragment < inode->u.ufs_i.i_lastfrag) { UFSD(("EXIT (ALREADY ALLOCATED)\n")) unlock_super (sb); return 0; } } else { if (tmp) { UFSD(("EXIT (ALREADY ALLOCATED)\n")) unlock_super(sb); return 0; } } /* * There is not enough space for user on the device */ if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) { unlock_super (sb); UFSD(("EXIT (FAILED)\n")) return 0; }
int xiafs_rmdir(struct inode * dir, const char * name, int len) { int retval; struct inode * inode; struct buffer_head * bh; struct xiafs_direct * de, * de_pre; inode = NULL; bh = xiafs_find_entry(dir, name, len, &de, &de_pre); retval = -ENOENT; if (!bh) goto end_rmdir; retval = -EPERM; if (!(inode = iget(dir->i_sb, de->d_ino))) goto end_rmdir; if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto end_rmdir; if (!S_ISDIR(inode->i_mode)) { retval = -ENOTDIR; goto end_rmdir; } if (!empty_dir(inode)) { retval = -ENOTEMPTY; goto end_rmdir; } if (inode->i_count > 1) { retval = -EBUSY; goto end_rmdir; } if (inode->i_nlink != 2) printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR); xiafs_rm_entry(de, de_pre); mark_buffer_dirty(bh, 1); inode->i_nlink=0; inode->i_dirt=1; dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt=1; retval = 0; end_rmdir: iput(dir); iput(inode); brelse(bh); return retval; }
int xiafs_unlink(struct inode * dir, const char * name, int len) { int retval; struct inode * inode; struct buffer_head * bh; struct xiafs_direct * de, * de_pre; repeat: retval = -ENOENT; inode = NULL; bh = xiafs_find_entry(dir, name, len, &de, &de_pre); if (!bh) goto end_unlink; if (!(inode = iget(dir->i_sb, de->d_ino))) goto end_unlink; retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; if (de->d_ino != inode->i_ino) { iput(inode); brelse(bh); current->counter = 0; schedule(); goto repeat; } if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) goto end_unlink; if (!inode->i_nlink) { printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR); inode->i_nlink=1; } xiafs_rm_entry(de, de_pre); mark_buffer_dirty(bh, 1); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; inode->i_nlink--; inode->i_dirt = 1; retval = 0; end_unlink: brelse(bh); iput(inode); iput(dir); return retval; }
asmlinkage int sys_chroot(const char * filename) { struct inode * inode; int error; error = namei(filename,&inode); if (error) return error; if (!S_ISDIR(inode->i_mode)) { iput(inode); return -ENOTDIR; } if (!fsuser()) { iput(inode); return -EPERM; } iput(current->fs->root); current->fs->root = inode; return (0); }
int rmdir_not_allowed (struct inode * dir, struct reiserfs_dir_entry * de, struct inode * inode) { if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) return -EPERM; if (inode->i_dev != dir->i_dev) return -EPERM; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ return -EPERM; if (!S_ISDIR(inode->i_mode)) return -ENOTDIR; if (!reiserfs_empty_dir(inode)) return -ENOTEMPTY; if (de->de_objectid != inode->i_ino) return -ENOENT; return 0; }
/* * process, that is going to call fix_nodes/do_balance must hold only * one path. If it holds 2 or more, it can get into endless waiting in * get_empty_nodes or its clones */ static int do_reiserfs_rename (struct reiserfs_transaction_handle *th, struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry) { int retval; struct path old_entry_path, new_entry_path, dot_dot_entry_path; struct reiserfs_dir_entry old_de, new_de, dot_dot_de; struct inode * old_inode, * new_inode; int new_entry_added = 0; init_path (&old_entry_path); init_path (&new_entry_path); init_path (&dot_dot_entry_path); goto start_up; try_again: current->policy |= SCHED_YIELD; schedule(); start_up: old_inode = new_inode = NULL; dot_dot_de.de_bh = 0; new_de.de_bh = 0; /* * look for the old name in old directory */ retval = -ENOENT; old_de.de_gen_number_bit_string = 0; if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND) goto end_rename; pathrelse (&old_entry_path); old_inode = old_dentry->d_inode; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && current->fsuid != old_dir->i_uid && !fsuser()) goto end_rename; new_inode = new_dentry->d_inode; /* look for the new entry in target directory */ new_de.de_gen_number_bit_string = 0; if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_FOUND) { if (!new_inode) { printk ("do_reiserfs_rename: new entry found, inode == 0 though\n"); } /* this entry already exists, we can just set key of object */ new_entry_added = 1; } else { #ifdef REISERFS_CHECK if (new_entry_added) { if (new_de.de_namelen != new_dentry->d_name.len || memcmp (new_de.de_name, new_dentry->d_name.name, new_de.de_namelen) || de_visible (new_de.de_deh)) reiserfs_panic (old_dir->i_sb, "vs-7045: reiserfs_rename: suspicious entry found"); } #endif /* REISERFS_CHECK */ } pathrelse (&new_entry_path); if (new_inode == old_inode) { retval = 0; goto end_rename; } if (new_inode && S_ISDIR(new_inode->i_mode)) { /* new name exists and points to directory */ retval = -EISDIR; if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; if (is_subdir (new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!reiserfs_empty_dir (new_inode)) goto end_rename; retval = -EBUSY; if (new_inode->i_count > 1) goto end_rename; } retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && current->fsuid != new_dir->i_uid && !fsuser()) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { /* old name points to directory */ retval = -ENOTDIR; if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; if (is_subdir(new_dentry, old_dentry)) goto end_rename; retval = -EIO; /* directory is renamed, its parent directory will be changed, so find ".." entry */ dot_dot_de.de_gen_number_bit_string = 0; if (reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND) goto end_rename; if (dot_dot_de.de_objectid != old_dir->i_ino) goto end_rename; pathrelse (&dot_dot_entry_path); retval = -EMLINK; if (!new_inode && new_dir->i_nlink >= REISERFS_LINK_MAX) goto end_rename; } if (new_entry_added == 0) { /* add new entry if we did not do it, but do not mark it as visible */ retval = reiserfs_add_entry (th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, INODE_PKEY (old_inode), &new_de, 0); if (retval) goto end_rename; if_in_ram_update_sd (th, new_dir); new_entry_added = 1; goto try_again; } /* * look for old name, new name and ".." when renaming directories again */ if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND) reiserfs_panic (old_dir->i_sb, "vs-7050: reiserfs_rename: old name not found"); if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_NOT_FOUND) reiserfs_panic (old_dir->i_sb, "vs-7055: reiserfs_rename: new name not found"); if (S_ISDIR(old_inode->i_mode) && reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND) reiserfs_panic (old_dir->i_sb, "vs-7060: reiserfs_rename: \"..\" name not found"); /* sanity checking before doing the rename - avoid races */ if (!entry_points_to_object (new_dentry->d_name.name, new_dentry->d_name.len, &new_de, new_inode)) goto try_again; if (!entry_points_to_object (old_dentry->d_name.name, old_dentry->d_name.len, &old_de, old_inode)) /* go to re-looking for old entry */ goto try_again; if (S_ISDIR(old_inode->i_mode) && !entry_points_to_object ("..", 2, &dot_dot_de, old_dir)) /* go to re-looking for ".." entry of renamed directory */ goto try_again; /* ok, all the changes can be done in one fell swoop when we have claimed all the buffers needed.*/ /* make old name hidden */ mark_de_hidden (old_de.de_deh); journal_mark_dirty(th, old_dir->i_sb, old_de.de_bh) ; /* make new name visible and set key of old object (if entry existed, it is already visible, if not, key is correct already) */ mark_de_visible (new_de.de_deh); new_de.de_deh->deh_dir_id = INODE_PKEY (old_inode)->k_dir_id; new_de.de_deh->deh_objectid = INODE_PKEY (old_inode)->k_objectid; journal_mark_dirty(th, old_dir->i_sb, new_de.de_bh) ; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; if_in_ram_update_sd (th, old_dir); new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; if_in_ram_update_sd (th, new_dir); if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; if_in_ram_update_sd (th, new_inode); } if (dot_dot_de.de_bh) { set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir)); journal_mark_dirty(th, old_dir->i_sb, dot_dot_de.de_bh) ; old_dir->i_nlink--; if_in_ram_update_sd (th, old_dir); if (new_inode) { new_inode->i_nlink--; if_in_ram_update_sd (th, new_inode); } else { new_dir->i_nlink++; if_in_ram_update_sd (th, new_dir); } } /* ok, renaming done */ decrement_counters_in_path (&new_entry_path); decrement_counters_in_path (&dot_dot_entry_path); /* remove old name (it is hidden now) */ if (reiserfs_cut_from_item (th, old_dir, old_dir->i_sb, &old_entry_path, &(old_de.de_entry_num), &(old_de.de_entry_key), 0, PRESERVE_RENAMING) == 0) printk ("reiserfs_rename: could not remove old name\n"); else { old_dir->i_size -= DEH_SIZE + old_de.de_entrylen; old_dir->i_blocks = old_dir->i_size / 512 + ((old_dir->i_size % 512) ? 1 : 0); if_in_ram_update_sd (th, old_dir); } /* Update the dcache */ d_move(old_dentry, new_dentry); retval = 0; end_rename: pathrelse (&old_entry_path); return retval; }
int reiserfs_unlink (struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; struct reiserfs_dir_entry de; struct path path; int windex ; int call_journal_end = 1 ; struct reiserfs_transaction_handle th ; int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; init_path (&path); retval = -ENOENT; journal_begin(&th, dir->i_sb, jbegin_count) ; windex = push_journal_writer("reiserfs_unlink") ; /* free preserve list if we should */ /* maybe_free_preserve_list (dir->i_sb);*/ de.de_gen_number_bit_string = 0; if (reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de) == POSITION_NOT_FOUND) { goto end_unlink; } inode = dentry->d_inode; reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(dir) ; retval = -EPERM; if (S_ISDIR (inode->i_mode)) { goto end_unlink; } if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) { goto end_unlink; } retval = -ENOENT; if (comp_short_keys ((struct key *)&(de.de_dir_id), INODE_PKEY (inode))) { goto end_unlink; } if (!inode->i_nlink) { printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } if (reiserfs_cut_from_item (&th, dir, dir->i_sb, &path, &(de.de_entry_num), &(de.de_entry_key), 0, NOTHING_SPECIAL) == 0) { retval = -ENOENT; goto end_unlink; } inode->i_nlink--; inode->i_ctime = CURRENT_TIME; if_in_ram_update_sd (&th, inode); dir->i_size -= (de.de_entrylen + DEH_SIZE); dir->i_ctime = dir->i_mtime = CURRENT_TIME; if_in_ram_update_sd (&th, dir) ; pop_journal_writer(windex) ; journal_end(&th, dir->i_sb, jbegin_count) ; call_journal_end = 0 ; d_delete(dentry); retval = 0; end_unlink: pathrelse (&path); pop_journal_writer(windex) ; if (call_journal_end) journal_end(&th, dir->i_sb, jbegin_count) ; return retval; }
/* * rename uses retry to avoid race-conditions: at least they should be minimal. * it tries to allocate all the blocks, then sanity-checks, and if the sanity- * checks fail, it tries to restart itself again. Very practical - no changes * are done until we know everything works ok.. and then all the changes can be * done in one fell swoop when we have claimed all the buffers needed. * * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */ static int do_xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre; int retval; try_again: old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre); retval = -ENOENT; if (!old_bh) goto end_rename; old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && current->fsuid != old_dir->i_uid && !fsuser()) goto end_rename; new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL); if (new_bh) { new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0); if (!new_inode) { brelse(new_bh); new_bh = NULL; } } if (new_inode == old_inode) { retval = 0; goto end_rename; } if (new_inode && S_ISDIR(new_inode->i_mode)) { retval = -EEXIST; goto end_rename; } retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && current->fsuid != new_dir->i_uid && !fsuser()) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -EEXIST; if (new_bh) goto end_rename; if ((retval = permission(old_inode, MAY_WRITE)) != 0) goto end_rename; retval = -EINVAL; if (subdir(new_dir, old_inode)) goto end_rename; retval = -EIO; dir_bh = xiafs_bread(old_inode,0,0); if (!dir_bh) goto end_rename; if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) goto end_rename; retval = -EMLINK; if (new_dir->i_nlink > 64000) goto end_rename; } if (!new_bh) new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre); retval = -ENOSPC; if (!new_bh) goto end_rename; /* sanity checking */ if ( (new_inode && (new_de->d_ino != new_inode->i_ino)) || (new_de->d_ino && !new_inode) || (old_de->d_ino != old_inode->i_ino)) { xiafs_rm_entry(new_de, new_de_pre); brelse(old_bh); brelse(new_bh); brelse(dir_bh); iput(old_inode); iput(new_inode); current->counter=0; schedule(); goto try_again; } xiafs_rm_entry(old_de, old_de_pre); new_de->d_ino = old_inode->i_ino; if (new_inode) { new_inode->i_nlink--; new_inode->i_dirt = 1; } mark_buffer_dirty(old_bh, 1); mark_buffer_dirty(new_bh, 1); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; new_dir->i_nlink++; old_dir->i_dirt = 1; new_dir->i_dirt = 1; } retval = 0; end_rename: brelse(dir_bh); brelse(old_bh); brelse(new_bh); iput(old_inode); iput(new_inode); iput(old_dir); iput(new_dir); return retval; }
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { int err; unsigned long flags; ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { case EXT2_IOC_GETFLAGS: err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int)); if (err) return err; put_user(inode->u.ext2_i.i_flags, (int *) arg); return 0; case EXT2_IOC_SETFLAGS: err = verify_area(VERIFY_READ, (int *) arg, sizeof(int)); if (err) return err; flags = get_user((int *) arg); /* * The IMMUTABLE and APPEND_ONLY flags can only be changed by * the super user when the security level is zero. */ if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^ (inode->u.ext2_i.i_flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { /* This test looks nicer. Thanks to Pauline Middelink */ if (!fsuser() || securelevel > 0) return -EPERM; } else if ((current->fsuid != inode->i_uid) && !fsuser()) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; inode->u.ext2_i.i_flags = flags; if (flags & EXT2_APPEND_FL) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; if (flags & EXT2_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; if (flags & EXT2_NOATIME_FL) inode->i_flags |= MS_NOATIME; else inode->i_flags &= ~MS_NOATIME; inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; return 0; case EXT2_IOC_GETVERSION: err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int)); if (err) return err; put_user(inode->u.ext2_i.i_version, (int *) arg); return 0; case EXT2_IOC_SETVERSION: if ((current->fsuid != inode->i_uid) && !fsuser()) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; err = verify_area(VERIFY_READ, (int *) arg, sizeof(int)); if (err) return err; inode->u.ext2_i.i_version = get_user((int *) arg); inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; return 0; default: return -ENOTTY; } }