Inspired by Pranith, I thought I would try to add to the directory
functions in namei.c. Attached is a patch for rename and rmdir, I cant
really vouch for the 'correctness' of it, but I tested it out for a
while in UML and it seems to work correctly.

This is really my first patch for low level file system operations, so
I won't be offended if you point out any flaws.

Cheers,
Michael Pattrick
diff -r 47e5409786d4 user/kernel/dir.c
--- a/user/kernel/dir.c	Fri Dec 05 19:24:40 2008 -0800
+++ b/user/kernel/dir.c	Sat Dec 06 22:52:05 2008 -0500
@@ -157,6 +157,59 @@
 	return (block << blockbits) + offset; /* only needed for xattr create */
 }
 
+int tux_add_link(struct dentry *dentry, struct inode *inode)
+{
+	struct inode *dir = dentry->d_parent->d_inode;
+	tux_dirent *entry;
+	struct buffer_head *buffer;
+	unsigned reclen = TUX_REC_LEN(dentry->d_name.len), rec_len, name_len, offset;
+	unsigned blockbits = tux_sb(dir->i_sb)->blockbits, blocksize = 1 << blockbits;
+	unsigned blocks = dir->i_size >> blockbits, block;
+	for (block = 0; block < blocks; block++) {
+		buffer = blockread(mapping(dir), block);
+		if (!buffer)
+			return -EIO;
+		entry = bufdata(buffer);
+		tux_dirent *limit = bufdata(buffer) + blocksize - reclen;
+		while (entry <= limit) {
+			if (entry->rec_len == 0) {
+				warn("zero-length directory entry");
+				brelse(buffer);
+				return -EIO;
+			}
+			name_len = TUX_REC_LEN(entry->name_len);
+			rec_len = tux_rec_len_from_disk(entry->rec_len);
+			if (is_deleted(entry) && rec_len >= reclen)
+				goto create;
+			if (rec_len >= name_len + reclen)
+				goto create;
+			entry = (tux_dirent *)((char *)entry + rec_len);
+		}
+		brelse(buffer);
+	}
+	buffer = blockget(mapping(dir), block = blocks);
+	entry = bufdata(buffer);
+	name_len = 0;
+	rec_len = blocksize;
+	*entry = (tux_dirent){ .rec_len = tux_rec_len_to_disk(blocksize) };
+	dir->i_size += blocksize;
+create:
+	if (!is_deleted(entry)) {
+		tux_dirent *newent = (tux_dirent *)((char *)entry + name_len);
+		newent->rec_len = tux_rec_len_to_disk(rec_len - name_len);
+		entry->rec_len = tux_rec_len_to_disk(name_len);
+		entry = newent;
+	}
+	entry->name_len = dentry->d_name.len;
+	memcpy(entry->name, dentry->d_name.name, dentry->d_name.len);
+	entry->inum = to_be_u32(tux_inode(inode)->inum);
+	//FIXME I may have the mode (S_IFDIR & S_IFMT) wrong
+	entry->type = tux_type_by_mode[(S_IFDIR & S_IFMT) >> STAT_SHIFT];
+	dir->i_mtime = dir->i_ctime = gettime();
+	brelse_dirty(buffer);
+	return 0;
+}
+
 tux_dirent *tux_find_entry(struct inode *dir, const char *name, int len, struct buffer_head **result)
 {
 	unsigned reclen = TUX_REC_LEN(len);
diff -r 47e5409786d4 user/kernel/namei.c
--- a/user/kernel/namei.c	Fri Dec 05 19:24:40 2008 -0800
+++ b/user/kernel/namei.c	Sat Dec 06 22:52:05 2008 -0500
@@ -43,6 +43,68 @@
 	return err;
 }
 
+static int tux3_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_buffer, * new_buffer;
+	tux_dirent * old_de, *new_de=NULL;
+	int err = -ENOENT;
+
+	old_de =tux_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_buffer);
+	if (!old_dir)
+		goto out;
+
+	if (new_inode) {
+		err = -ENOTEMPTY;
+		if (!tux_dir_is_empty (new_inode))
+			goto out;
+		err = -ENOENT;
+		new_de = tux_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_buffer);
+		if (!new_de)
+			goto out;
+		tux_delete_entry (new_buffer, new_de);
+		inode_dec_link_count(new_inode);
+	}
+
+	inode_inc_link_count(old_inode);
+
+
+	err = tux_add_link(new_dentry, old_inode);
+	if (err) {
+		inode_dec_link_count(old_inode);
+		goto out;
+	}
+
+	old_inode->i_ctime = CURRENT_TIME_SEC;
+
+	tux_delete_entry (old_buffer, old_de);
+
+out:
+	return err;
+}
+
+static int tux3_rmdir (struct inode *dir, struct dentry *dentry)
+{
+	struct inode * inode = dentry->d_inode;
+	int err = -ENOTEMPTY;
+	struct buffer_head *buffer;
+	tux_dirent *de;
+	if (tux_dir_is_empty(inode)) {
+		de = tux_find_entry (dir, dentry->d_name.name, 
+			dentry->d_name.len, &buffer);
+		err = tux_delete_entry (buffer, de);
+
+		if (!err) {
+			inode->i_size = 0;
+			inode_dec_link_count(inode);
+			inode_dec_link_count(dir);
+		}
+	}
+	return err;
+}
+
 const struct file_operations tux_dir_fops = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
@@ -56,15 +118,15 @@
 //	.unlink		= ext3_unlink,
 //	.symlink	= ext3_symlink,
 //	.mkdir		= ext3_mkdir,
-//	.rmdir		= ext3_rmdir,
+	.rmdir		= tux3_rmdir,
 //	.mknod		= ext3_mknod,
-//	.rename		= ext3_rename,
+	.rename		= tux3_rename,
 //	.setattr	= ext3_setattr,
 //	.setxattr	= generic_setxattr,
 //	.getxattr	= generic_getxattr,
 //	.listxattr	= ext3_listxattr,
 //	.removexattr	= generic_removexattr,
-//	.permission	= ext3_permission,
+//	.permission	= ext3_permission,int err
 	/* FIXME: why doesn't ext4 support this for directory? */
 //	.fallocate	= ext4_fallocate,
 //	.fiemap		= ext4_fiemap,
_______________________________________________
Tux3 mailing list
[email protected]
http://mailman.tux3.org/cgi-bin/mailman/listinfo/tux3

Reply via email to