patch-2.4.19 linux-2.4.19/fs/jffs2/dir.c

Next file: linux-2.4.19/fs/jffs2/erase.c
Previous file: linux-2.4.19/fs/jffs2/build.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/fs/jffs2/dir.c linux-2.4.19/fs/jffs2/dir.c
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: dir.c,v 1.45 2001/12/27 22:43:20 dwmw2 Exp $
+ * $Id: dir.c,v 1.45.2.6 2002/06/20 23:54:48 dwmw2 Exp $
  *
  */
 
@@ -177,11 +177,11 @@
 		}
 		D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, fd->name, fd->ino, fd->type));
 		if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
-			goto out;
+			break;
 		offset++;
 	}
- out:
 	up(&f->sem);
+ out:
 	filp->f_pos = offset;
 	return 0;
 }
@@ -293,7 +293,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -304,16 +304,20 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -359,7 +363,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = 0;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = dentry->d_name.len;
@@ -446,7 +450,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = old_dentry->d_inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = dentry->d_name.len;
@@ -483,7 +487,12 @@
 
 static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
 {
-	int ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
+	int ret;
+
+	if (S_ISDIR(old_dentry->d_inode->i_mode))
+		return -EPERM;
+
+	ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
 	if (!ret) {
 		d_instantiate(dentry, old_dentry->d_inode);
 		atomic_inc(&old_dentry->d_inode->i_count);
@@ -600,7 +609,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -611,16 +620,20 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -730,7 +743,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -741,16 +754,20 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -794,8 +811,7 @@
 	
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 	
-	if ((mode & S_IFMT) == S_IFBLK ||
-	    (mode & S_IFMT) == S_IFCHR) {
+	if (S_ISBLK(mode) || S_ISCHR(mode)) {
 		dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev));
 		devlen = sizeof(dev);
 	}
@@ -881,7 +897,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -895,22 +911,27 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
 	up(&dir_f->sem);
 
 	d_instantiate(dentry, inode);
+
 	return 0;
 }
 
@@ -918,6 +939,29 @@
                         struct inode *new_dir_i, struct dentry *new_dentry)
 {
 	int ret;
+	struct jffs2_inode_info *victim_f = NULL;
+
+	/* The VFS will check for us and prevent trying to rename a 
+	 * file over a directory and vice versa, but if it's a directory,
+	 * the VFS can't check whether the victim is empty. The filesystem
+	 * needs to do that for itself.
+	 */
+	if (new_dentry->d_inode) {
+		victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
+		if (S_ISDIR(new_dentry->d_inode->i_mode)) {
+			struct jffs2_full_dirent *fd;
+
+			down(&victim_f->sem);
+			for (fd = victim_f->dents; fd; fd = fd->next) {
+				if (fd->ino) {
+					up(&victim_f->sem);
+					return -ENOTEMPTY;
+				}
+			}
+			up(&victim_f->sem);
+		}
+	}
+
 	/* XXX: We probably ought to alloc enough space for
 	   both nodes at the same time. Writing the new link, 
 	   then getting -ENOSPC, is quite bad :)
@@ -928,6 +972,18 @@
 	if (ret)
 		return ret;
 
+	if (victim_f) {
+		/* There was a victim. Kill it off nicely */
+		new_dentry->d_inode->i_nlink--;
+		/* Don't oops if the victim was a dirent pointing to an
+		   inode which didn't exist. */
+		if (victim_f->inocache) {
+			down(&victim_f->sem);
+			victim_f->inocache->nlink--;
+			up(&victim_f->sem);
+		}
+	}
+
 	/* Unlink the original */
 	ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
 	

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)