struct dentry * affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct inode *inode = NULL; pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); affs_lock_dir(dir); bh = affs_find_entry(dir, dentry); affs_unlock_dir(dir); if (IS_ERR(bh)) return ERR_CAST(bh); if (bh) { u32 ino = bh->b_blocknr; /* store the real header ino in d_fsdata for faster lookups */ dentry->d_fsdata = (void *)(long)ino; switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { //link to dirs disabled //case ST_LINKDIR: case ST_LINKFILE: ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original); } affs_brelse(bh); inode = affs_iget(sb, ino); if (IS_ERR(inode)) return ERR_PTR(PTR_ERR(inode)); } dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations; d_add(dentry, inode); return NULL; }
int affs_unlink(struct inode *dir, struct dentry *dentry) { int retval; struct buffer_head *bh; unsigned long ino; struct inode *inode; pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); retval = -ENOENT; if (!(bh = affs_find_entry(dir,dentry,&ino))) goto unlink_done; inode = dentry->d_inode; if ((retval = affs_remove_header(bh,inode)) < 0) goto unlink_done; inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_version = ++event; mark_inode_dirty(inode); d_delete(dentry); mark_inode_dirty(dir); retval = 0; unlink_done: affs_brelse(bh); return retval; }
struct dentry * affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct inode *inode = NULL; pr_debug("%s(\"%pd\")\n", __func__, dentry); affs_lock_dir(dir); bh = affs_find_entry(dir, dentry); affs_unlock_dir(dir); if (IS_ERR(bh)) return ERR_CAST(bh); if (bh) { u32 ino = bh->b_blocknr; /* store the real header ino in d_fsdata for faster lookups */ dentry->d_fsdata = (void *)(long)ino; switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { //link to dirs disabled //case ST_LINKDIR: case ST_LINKFILE: ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original); } affs_brelse(bh); inode = affs_iget(sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } d_add(dentry, inode); return NULL; }
int affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct inode *oldinode = old_dentry->d_inode; struct inode *inode; struct buffer_head *bh; unsigned long i; int error; pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); /* N.B. Do we need this test? The dentry must be negative ... */ bh = affs_find_entry(dir,dentry,&i); if (bh) { affs_brelse(bh); return -EEXIST; } if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */ affs_warning(dir->i_sb,"link","Impossible link to link"); return -EINVAL; } error = -ENOSPC; if (!(inode = affs_new_inode(dir))) goto out; inode->i_op = oldinode->i_op; inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode); inode->u.affs_i.i_original = oldinode->i_ino; inode->u.affs_i.i_hlink = 1; inode->i_mtime = oldinode->i_mtime; if (S_ISDIR(oldinode->i_mode)) error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR); else error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE); if (error) inode->i_nlink = 0; else { dir->i_version = ++event; mark_inode_dirty(dir); mark_inode_dirty(oldinode); oldinode->i_count++; d_instantiate(dentry,oldinode); } mark_inode_dirty(inode); iput(inode); out: return error; }
int affs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; int retval; unsigned long ino; struct buffer_head *bh; pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); retval = -ENOENT; if (!(bh = affs_find_entry(dir,dentry,&ino))) goto rmdir_done; /* * Make sure the directory is empty and the dentry isn't busy. */ retval = -ENOTEMPTY; if (!empty_dir(bh,AFFS_I2HSIZE(inode))) goto rmdir_done; retval = -EBUSY; if (!list_empty(&dentry->d_hash)) goto rmdir_done; if ((retval = affs_remove_header(bh,inode)) < 0) goto rmdir_done; inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; retval = 0; dir->i_version = ++event; mark_inode_dirty(dir); mark_inode_dirty(inode); d_delete(dentry); rmdir_done: affs_brelse(bh); return retval; }
struct dentry * affs_lookup(struct inode *dir, struct dentry *dentry) { unsigned long ino; struct buffer_head *bh; struct inode *inode; pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); inode = NULL; bh = affs_find_entry(dir,dentry,&ino); if (bh) { if (FILE_END(bh->b_data,dir)->original) ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original); affs_brelse(bh); inode = iget(dir->i_sb,ino); if (!inode) return ERR_PTR(-EACCES); } dentry->d_op = &affs_dentry_operations; d_add(dentry,inode); return NULL; }
int affs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct buffer_head *old_bh; struct buffer_head *new_bh; unsigned long old_ino; unsigned long new_ino; int retval; pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n", old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode, new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode); if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) goto out; new_bh = NULL; retval = -ENOENT; old_bh = affs_find_entry(old_dir,old_dentry,&old_ino); if (!old_bh) goto end_rename; new_bh = affs_find_entry(new_dir,new_dentry,&new_ino); if (new_bh && !new_inode) { affs_error(old_inode->i_sb,"affs_rename", "No inode for entry found (key=%lu)\n",new_ino); goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { if (new_inode) { retval = -ENOTEMPTY; if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; } retval = -ENOENT; if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; } /* Unlink destination if it already exists */ if (new_inode) { if ((retval = affs_remove_header(new_bh,new_dir)) < 0) goto end_rename; new_inode->i_nlink = retval; mark_inode_dirty(new_inode); if (new_inode->i_ino == new_ino) new_inode->i_nlink = 0; } /* Remove header from its parent directory. */ if ((retval = affs_remove_hash(old_bh,old_dir))) goto end_rename; /* And insert it into the new directory with the new name. */ affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name); if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir))) goto end_rename; affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5); new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; new_dir->i_version = ++event; old_dir->i_version = ++event; retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); mark_buffer_dirty(old_bh,1); end_rename: affs_brelse(old_bh); affs_brelse(new_bh); out: return retval; }
int affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct buffer_head *bh; struct inode *inode; char *p; unsigned long tmp; int i, maxlen, error; char c, lc; pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name,symname); maxlen = 4 * AFFS_I2HSIZE(dir) - 1; error = -ENOSPC; inode = affs_new_inode(dir); if (!inode) goto out; inode->i_op = &affs_symlink_inode_operations; inode->i_mode = S_IFLNK | 0777; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); error = -EIO; bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); if (!bh) goto out_iput; i = 0; p = ((struct slink_front *)bh->b_data)->symname; lc = '/'; if (*symname == '/') { while (*symname == '/') symname++; while (inode->i_sb->u.affs_sb.s_volume[i]) /* Cannot overflow */ *p++ = inode->i_sb->u.affs_sb.s_volume[i++]; } while (i < maxlen && (c = *symname++)) { if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { *p++ = '/'; i++; symname += 2; lc = '/'; } else if (c == '.' && lc == '/' && *symname == '/') { symname++; lc = '/'; } else { *p++ = c; lc = c; i++; } if (lc == '/') while (*symname == '/') symname++; } *p = 0; mark_buffer_dirty(bh,1); affs_brelse(bh); mark_inode_dirty(inode); /* N.B. This test shouldn't be necessary ... dentry must be negative */ error = -EEXIST; bh = affs_find_entry(dir,dentry,&tmp); if (bh) goto out_release; /* N.B. Shouldn't we add the entry before dirtying the buffer? */ error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK); if (error) goto out_release; d_instantiate(dentry,inode); dir->i_version = ++event; mark_inode_dirty(dir); out: return error; out_release: affs_brelse(bh); out_iput: inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); goto out; }