patch-2.1.71 linux/fs/affs/namei.c
Next file: linux/fs/affs/super.c
Previous file: linux/fs/affs/inode.c
Back to the patch index
Back to the overall index
- Lines: 819
- Date:
Tue Dec 2 22:25:07 1997
- Orig file:
v2.1.70/linux/fs/affs/namei.c
- Orig date:
Mon Aug 18 18:19:46 1997
diff -u --recursive --new-file v2.1.70/linux/fs/affs/namei.c linux/fs/affs/namei.c
@@ -8,6 +8,7 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
+#define DEBUG 0
#include <linux/sched.h>
#include <linux/affs_fs.h>
#include <linux/kernel.h>
@@ -20,8 +21,6 @@
#include <linux/errno.h>
-static int affs_fixup(struct buffer_head *bh, struct inode *inode);
-
/* Simple toupper() for DOS\1 */
static inline unsigned int
@@ -45,7 +44,7 @@
*/
static int
-affs_match(const char *name, int len, const char *compare, int dlen, int intl)
+affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
{
if (!compare)
return 0;
@@ -62,14 +61,14 @@
return 0;
if (intl) {
while (dlen--) {
- if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
+ if (affs_intl_toupper(*name) != affs_intl_toupper(*compare))
return 0;
name++;
compare++;
}
} else {
while (dlen--) {
- if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
+ if (affs_toupper(*name) != affs_toupper(*compare))
return 0;
name++;
compare++;
@@ -79,7 +78,7 @@
}
int
-affs_hash_name(const char *name, int len, int intl, int hashsize)
+affs_hash_name(const unsigned char *name, int len, int intl, int hashsize)
{
unsigned int i, x;
@@ -97,14 +96,15 @@
}
static struct buffer_head *
-affs_find_entry(struct inode *dir, const char *name, int namelen,
- unsigned long *ino)
+affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
- struct buffer_head *bh;
- int intl;
- s32 key;
+ struct buffer_head *bh;
+ int intl;
+ s32 key;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
- pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
+ pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
intl = AFFS_I2FSTYPE(dir);
bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
@@ -123,7 +123,7 @@
key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
for (;;) {
- char *cname;
+ unsigned char *cname;
int cnamelen;
affs_brelse(bh);
@@ -137,154 +137,127 @@
cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
if (affs_match(name,namelen,cname,cnamelen,intl))
break;
- key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
+ key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
}
*ino = key;
return bh;
}
int
-affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
+affs_lookup(struct inode *dir, struct dentry *dentry)
{
- int res;
- unsigned long ino;
- struct buffer_head *bh;
-
- pr_debug("AFFS: lookup(%.*s)\n",len,name);
+ unsigned long ino;
+ struct buffer_head *bh;
+ struct inode *inode;
- *result = NULL;
- if (!dir)
- return -ENOENT;
+ pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
- res = -ENOENT;
- if (S_ISDIR(dir->i_mode)) {
- if ((bh = affs_find_entry(dir,name,len,&ino))) {
- if (FILE_END(bh->b_data,dir)->original)
- ino = htonl(FILE_END(bh->b_data,dir)->original);
- affs_brelse(bh);
- if ((*result = iget(dir->i_sb,ino)))
- res = 0;
- else
- res = -EACCES;
- }
+ 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 -EACCES;
}
- iput(dir);
- return res;
+ d_add(dentry,inode);
+ return 0;
}
int
-affs_unlink(struct inode *dir, const char *name, int len)
+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,len,name);
+ pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
bh = NULL;
- inode = NULL;
retval = -ENOENT;
- if (!(bh = affs_find_entry(dir,name,len,&ino))) {
- goto unlink_done;
- }
- if (!(inode = iget(dir->i_sb,ino))) {
+ if (!dir)
goto unlink_done;
- }
- if (S_ISDIR(inode->i_mode)) {
- retval = -EPERM;
+ if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto unlink_done;
- }
- if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
- AFFS_I2HSIZE(dir)) + 6,ino,
- FILE_END(bh->b_data,dir)->hash_chain)))
+ inode = dentry->d_inode;
+ retval = -EPERM;
+ if (S_ISDIR(inode->i_mode))
goto unlink_done;
-
- if ((retval = affs_fixup(bh,inode)))
+ if (current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
goto unlink_done;
- inode->i_nlink=0;
- mark_inode_dirty(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(dir);
+ mark_inode_dirty(inode);
+ retval = 0;
+ d_delete(dentry);
unlink_done:
affs_brelse(bh);
- iput(inode);
- iput(dir);
return retval;
}
int
-affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
+affs_create(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int error;
- pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+ pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
+ dentry->d_name.name,mode);
- *result = NULL;
- if (!dir || !dir->i_sb) {
- iput(dir);
- return -EINVAL;
- }
+ if (!dir)
+ return -ENOENT;
inode = affs_new_inode(dir);
- if (!inode) {
- iput (dir);
+ if (!inode)
return -ENOSPC;
- }
- inode->i_mode = mode;
+
+ pr_debug(" -- ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
inode->i_op = &affs_file_inode_operations_ofs;
else
inode->i_op = &affs_file_inode_operations;
- error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
if (error) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
- return -ENOSPC;
+ return error;
}
+ inode->i_mode = mode;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-
- iput(dir);
- *result = inode;
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry,inode);
return 0;
}
int
-affs_mkdir(struct inode *dir, const char *name, int len, int mode)
+affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
- struct buffer_head *bh;
- unsigned long i;
int error;
- pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+ pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name,mode);
- if (!dir || !dir->i_sb) {
- iput(dir);
- return -EINVAL;
- }
- bh = affs_find_entry(dir,name,len,&i);
- if (bh) {
- affs_brelse(bh);
- iput(dir);
- return -EEXIST;
- }
inode = affs_new_inode(dir);
- if (!inode) {
- iput (dir);
+ if (!inode)
return -ENOSPC;
- }
+
inode->i_op = &affs_dir_inode_operations;
- error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
if (error) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
@@ -292,9 +265,9 @@
}
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-
- iput(dir);
- iput(inode);
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry,inode);
return 0;
}
@@ -310,26 +283,29 @@
}
int
-affs_rmdir(struct inode *dir, const char *name, int len)
+affs_rmdir(struct inode *dir, struct dentry *dentry)
{
int retval;
unsigned long ino;
struct inode *inode;
struct buffer_head *bh;
- pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
+ pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
inode = NULL;
+ bh = NULL;
retval = -ENOENT;
- if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+ if (!dir)
goto rmdir_done;
- }
- if (!(inode = iget(dir->i_sb,ino))) {
+ if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto rmdir_done;
- }
+
+ inode = dentry->d_inode;
+
retval = -EPERM;
- if (!fsuser() && current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid)
+ if (current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
goto rmdir_done;
if (inode->i_dev != dir->i_dev)
goto rmdir_done;
@@ -339,6 +315,11 @@
retval = -ENOTDIR;
goto rmdir_done;
}
+ down(&inode->i_sem);
+ if (dentry->d_count > 1) {
+ shrink_dcache_parent(dentry);
+ }
+ up(&inode->i_sem);
if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
retval = -ENOTEMPTY;
goto rmdir_done;
@@ -347,28 +328,21 @@
retval = -EBUSY;
goto rmdir_done;
}
- if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
- AFFS_I2HSIZE(dir)) + 6,ino,
- FILE_END(bh->b_data,dir)->hash_chain)))
+ if ((retval = affs_remove_header(bh,inode)) < 0)
goto rmdir_done;
-
- if ((retval = affs_fixup(bh,inode)))
- goto rmdir_done;
-
- inode->i_nlink=0;
- mark_inode_dirty(inode);
+
+ inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_version = ++event;
- mark_inode_dirty(dir);
+ retval = 0;
+ mark_inode_dirty(inode);
+ d_delete(dentry);
rmdir_done:
- iput(dir);
- iput(inode);
affs_brelse(bh);
return retval;
}
int
-affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
+affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct buffer_head *bh;
struct inode *inode;
@@ -377,20 +351,19 @@
int i, maxlen;
char c, lc;
- pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+ 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;
inode = affs_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
+
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);
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
if (!bh) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
@@ -427,157 +400,135 @@
mark_buffer_dirty(bh,1);
affs_brelse(bh);
mark_inode_dirty(inode);
- bh = affs_find_entry(dir,name,len,&tmp);
+ bh = affs_find_entry(dir,dentry,&tmp);
if (bh) {
inode->i_nlink = 0;
iput(inode);
affs_brelse(bh);
- iput(dir);
return -EEXIST;
}
- i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
+ i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
if (i) {
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
affs_brelse(bh);
- iput(dir);
return i;
}
- iput(dir);
- iput(inode);
+ dir->i_version = ++event;
+ d_instantiate(dentry,inode);
return 0;
}
int
-affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
+affs_link(struct inode *oldinode, struct inode *dir, struct dentry *dentry)
{
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,len,name);
+ pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
- bh = affs_find_entry(dir,name,len,&i);
+ bh = affs_find_entry(dir,dentry,&i);
if (bh) {
affs_brelse(bh);
- iput(oldinode);
- iput(dir);
return -EEXIST;
}
- if (oldinode->u.affs_i.i_hlink) {
- i = oldinode->u.affs_i.i_original;
- iput(oldinode);
- oldinode = iget(dir->i_sb,i);
- if (!oldinode) {
- affs_error(oldinode->i_sb,"link","Cannot get original from link");
- iput(dir);
- return -ENOENT;
- }
+ if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */
+ affs_warning(dir->i_sb,"link","Impossible link to link");
+ return -EINVAL;
}
- inode = affs_new_inode(dir);
- if (!inode) {
- iput(oldinode);
- iput(dir);
+ if (!(inode = affs_new_inode(dir)))
return -ENOSPC;
- }
+
inode->i_op = oldinode->i_op;
- inode->i_mode = oldinode->i_mode;
- inode->i_uid = oldinode->i_uid;
- inode->i_gid = oldinode->i_gid;
- inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ 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,name,len,ST_LINKDIR);
+ error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR);
else
- error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
- if (error) {
+ error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE);
+ if (error)
inode->i_nlink = 0;
- mark_inode_dirty(inode);
+ else {
+ dir->i_version = ++event;
+ mark_inode_dirty(oldinode);
+ oldinode->i_count++;
+ d_instantiate(dentry,oldinode);
}
- iput(dir);
+ mark_inode_dirty(inode);
iput(inode);
- iput(oldinode);
return error;
}
+/* This is copied from the ext2 fs. No need to reinvent the wheel. */
+
static int
-subdir(struct inode *new_inode, struct inode *old_inode)
+subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
- int result;
+ int result;
- new_inode->i_count++;
- result = 0;
- for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
- }
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (affs_lookup(new_inode,"..",2,&new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
- }
- iput(new_inode);
- return result;
+ result = 0;
+ for (;;) {
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
+ }
+ result = 1;
+ break;
+ }
+ return result;
}
-/* I'm afraid this might not be race proof. Maybe next time. */
-
int
-affs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len)
+affs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode *old_inode;
- struct inode *new_inode;
+ 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\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
- new_dir->i_ino,new_len,new_name);
+ 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 (new_len > 30)
- new_len = 30;
- goto start_up;
-retry:
- affs_brelse(old_bh);
- affs_brelse(new_bh);
- iput(new_inode);
- iput(old_inode);
- current->counter = 0;
- schedule();
-start_up:
- old_inode = new_inode = NULL;
- old_bh = new_bh = NULL;
- retval = -ENOENT;
+ if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
+ return retval;
- old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
+ new_bh = NULL;
+ retval = -ENOENT;
+ old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_sb,old_ino);
- if (!old_inode)
+
+ 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;
- new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
- if (new_bh) {
- new_inode = iget(new_dir->i_sb,new_ino);
- if (!new_inode) { /* What does this mean? */
- affs_brelse(new_bh);
- new_bh = NULL;
- }
}
- if (new_inode == old_inode) { /* Won't happen */
+ if (new_inode == old_inode) {
+ if (old_ino == new_ino) { /* Filename might have changed case */
+ retval = new_dentry->d_name.len < 31 ? new_dentry->d_name.len : 30;
+ strncpy(DIR_END(old_bh->b_data,old_inode)->dir_name + 1,
+ new_dentry->d_name.name,retval);
+ DIR_END(old_bh->b_data,old_inode)->dir_name[0] = retval;
+ goto new_checksum;
+ }
retval = 0;
goto end_rename;
}
@@ -586,13 +537,13 @@
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_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (new_dentry->d_count > 1)
goto end_rename;
}
if (S_ISDIR(old_inode->i_mode)) {
@@ -600,142 +551,43 @@
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;
if (affs_parent_ino(old_inode) != old_dir->i_ino)
goto end_rename;
}
- /* Unlink destination if existent */
+ /* Unlink destination if it already exists */
if (new_inode) {
- if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
- AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
- new_ino,
- FILE_END(new_bh->b_data,new_dir)->hash_chain)))
- goto retry;
- if ((retval = affs_fixup(new_bh,new_inode)))
- goto retry;
- mark_buffer_dirty(new_bh,1);
- new_dir->i_version = ++event;
- mark_inode_dirty(new_dir);
- new_inode->i_nlink = 0;
+ 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;
}
- retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
- AFFS_I2HSIZE(old_dir)) + 6,old_ino,
- FILE_END(old_bh->b_data,old_dir)->hash_chain);
- if (retval)
- goto retry;
-
- retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
- htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
+ /* 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;
+new_checksum:
+ 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_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);
+ d_move(old_dentry,new_dentry);
end_rename:
affs_brelse(old_bh);
affs_brelse(new_bh);
- iput(new_inode);
- iput(old_inode);
- iput(old_dir);
- iput(new_dir);
return retval;
-}
-
-static int
-affs_fixup(struct buffer_head *bh, struct inode *inode)
-{
- s32 key, link_key;
- s32 type;
- struct buffer_head *nbh;
- struct inode *ofinode;
-
- type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
- if (type == ST_LINKFILE || type == ST_LINKDIR) {
- key = htonl(LINK_END(bh->b_data,inode)->original);
- LINK_END(bh->b_data,inode)->original = 0;
- if (!key) {
- affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu",
- inode->i_ino);
- return -ENOENT;
- }
- if (!(ofinode = iget(inode->i_sb,key)))
- return -ENOENT;
- type = affs_fix_link_pred(ofinode,inode->i_ino,
- FILE_END(bh->b_data,inode)->link_chain);
- iput(ofinode);
- return type;
- } else if (type == ST_FILE || type == ST_USERDIR) {
- if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
- /* Get first link, turn it to a file */
- if (!(ofinode = iget(inode->i_sb,key))) {
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- return -ENOENT;
- }
- if (!ofinode->u.affs_i.i_hlink) {
- affs_error(inode->i_sb,"fixup",
- "First link to %lu (%d) is not a link",
- inode->i_ino,key);
- iput(ofinode);
- return -ENOENT;
- }
- if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- iput(ofinode);
- return -ENOENT;
- }
- lock_super(inode->i_sb);
- memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
- FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
- byte_size;
- FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
- extension;
- FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
- secondary_type;
- FILE_END(nbh->b_data,inode)->original = 0;
-
- ofinode->u.affs_i.i_original = 0;
- ofinode->u.affs_i.i_hlink = 0;
- ofinode->i_size = inode->i_size;
- ofinode->i_uid = inode->i_uid;
- ofinode->i_gid = inode->i_gid;
- mark_inode_dirty(ofinode);
- link_key = ofinode->i_ino;
-
- /* Let all remaining links point to the new file */
- while (1) {
- affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
- mark_buffer_dirty(nbh,1);
- key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
- affs_brelse(nbh);
- iput(ofinode);
- if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
- break;
- if ((ofinode = iget(inode->i_sb,key))) {
- if (!ofinode->u.affs_i.i_hlink)
- affs_error(inode->i_sb,"fixup",
- "Inode %d in link chain is not a link",
- key);
- ofinode->u.affs_i.i_original = link_key;
- mark_inode_dirty(ofinode);
- FILE_END(nbh->b_data,inode)->original = htonl(link_key);
- } else
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- }
- /* Turn old inode to a link */
- inode->u.affs_i.i_hlink = 1;
- unlock_super(inode->i_sb);
- }
- return 0;
- } else if (type == ST_SOFTLINK) {
- return 0;
- } else {
- affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type);
- return -EBADF;
- }
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov