[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Fatfs patch for writing support
From: |
Marco Gerards |
Subject: |
Fatfs patch for writing support |
Date: |
08 Jul 2003 01:19:46 +0200 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.2 |
Hi,
(I'm having some mail problems... I hope this mail wasn't send to
bug-hurd more often... if that happened, please forgive me.)
Here is the first patch for writing support. Writing doesn't use after
applying this patch, but this is a huge step in the right direction ;)
Please notice readonly is off by default after applying this
patch. Please use "-r" to be save.
I will send some other patches for write fatfs soon. (I guess after
this one is applied ;)).
Thanks,
Marco
Changelog entry:
2003-07-07 Marco Gerards <metgerards@student.han.nl>
* Makefile (SRCS): Added node-created.c.
* dir.c: Include <hurd/fsys.h>.
(diskfs_direnter_hard): Initialize a new block with zeros.
(diskfs_direnter_hard): Enter direntry and setup the virtual
inode. Also handle directories correctly.
(diskfs_rewrite_hard): Function rewritten.
(diskfs_dirempty): Return error code properly.
* fat.c (fat_extend_chain): Move spin_lock to prevent deadlock.
(fat_extend_chain): Set dn->last to 0 when deallocating the
complete file.
(fat_extend_chain): Update dn->last when not deallocating the
complete file.
(fat_extend_chain): Set dn->first to zero when the complete file
was deallocated. Also update dn->length_of_chain to the new amount
of clusters in the chain.
* main.c (diskfs_readonly): Remove global variable.
(diskfs_hard_readonly): Likewise.
* node-create.c: New file. This file was copied from libdiskfs and
changed for fatfs because in fatfs. For fatfs "." and ".." must be
created after the directory was created.
Patch:
Common subdirectories: /home/marco/src/hurdcvs/hurd/fatfs/CVS and fatfs/CVS
diff -BNup /home/marco/src/hurdcvs/hurd/fatfs/Makefile fatfs/Makefile
--- /home/marco/src/hurdcvs/hurd/fatfs/Makefile 2002-12-03 21:52:59.000000000
+0100
+++ fatfs/Makefile 2003-07-07 19:19:23.000000000 +0200
@@ -19,7 +19,7 @@ dir := fatfs
makemode := server
target = fatfs
-SRCS = inode.c main.c dir.c pager.c fat.c virt-inode.c
+SRCS = inode.c main.c dir.c pager.c fat.c virt-inode.c node-create.c
LCLHDRS = fat.h fatfs.h virt-inode.h
DIST_FILES = EXTENSIONS
diff -BNup /home/marco/src/hurdcvs/hurd/fatfs/dir.c fatfs/dir.c
--- /home/marco/src/hurdcvs/hurd/fatfs/dir.c 2003-05-10 02:12:29.000000000
+0200
+++ fatfs/dir.c 2003-07-07 22:10:48.000000000 +0200
@@ -1,5 +1,7 @@
-/* main.c - FAT filesystem.
- Copyright (C) 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
+/* dir.c - Directory management routines.
+ Copyright (C) 1997, 1998, 1999, 2002, 2003 Free Software
+ Foundation, Inc.
+
Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -22,6 +24,7 @@
#include <string.h>
#include <dirent.h>
#include "fatfs.h"
+#include <hurd/fsys.h>
/* The size of a directory block is usually just the cluster size.
However, the root directory of FAT12/16 file systems is stored in
@@ -617,7 +620,8 @@ diskfs_direnter_hard (struct node *dp, c
munmap ((caddr_t) ds->mapbuf, ds->mapextent);
return err;
}
- }
+ memset ((caddr_t) ds->mapbuf + oldsize, 0, bytes_per_cluster);
+ }
new = (struct dirrect *) ((char *) ds->mapbuf + oldsize);
@@ -642,8 +646,28 @@ diskfs_direnter_hard (struct node *dp, c
memcpy (new->name, " ", 11);
memcpy (new->name, name, namelen % 11); /* XXX */
- /* XXX We need to do much, much more here. */
- /* XXX What about creating . and .. for dirs? */
+
+ write_word (new->first_cluster_low, np->dn->start_cluster & 0xffff);
+ write_word (new->first_cluster_high, np->dn->start_cluster >> 16);
+ write_dword (new->file_size, np->dn_stat.st_size);
+
+ if (!(name[0] == '.' && (name[1] == '\0' ||
+ (name[1] == '.' && name[2] =='\0'))))
+ {
+ vi_key_t entry_key;
+
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = ((int) ds->entry) - ((int) ds->mapbuf);
+
+ /* Set the key for this inode now because it wasn't know when
+ the inode was initialized. */
+ vi_change (vi_lookup (np->cache_id), entry_key);
+
+ if (np->dn_stat.st_mode & S_IFDIR)
+ new->attribute = FAT_DIR_ATTR_DIR;
+ }
+ else
+ new->attribute = FAT_DIR_ATTR_DIR;
/* Mark the directory inode has having been written. */
dp->dn_set_mtime = 1;
@@ -692,19 +716,48 @@ diskfs_dirremove_hard (struct node *dp,
error_t
diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds)
{
+ error_t err;
+ vi_key_t entry_key;
+ mach_port_t control = MACH_PORT_NULL;
+ struct node *oldnp;
+ ino_t inode;
+ inode_t vinode;
+
+ /* We need the inode and vinode of the old node. */
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = ((int) ds->entry) - ((int) ds->mapbuf);
+ err = vi_rlookup (entry_key, &inode, &vinode, 0);
+
+ assert (err != EINVAL);
+
+ /* Lookup the node, we already have a reference. */
+ oldnp = ifind (inode);
+
assert (ds->type == RENAME);
assert (ds->stat == HERE_TIS);
assert (!diskfs_readonly);
- /* XXX We have to reimplement rename completely. */
- /*
- ds->entry->inode = np->cache_id;
- */
- dp->dn_set_mtime = 1;
-
+ /* The link count must be 0 so the file will be removed and
+ the node will be dropped. */
+ oldnp->dn_stat.st_nlink--;
+ assert (!oldnp->dn_stat.st_nlink);
+
+ /* Close the file, free the referenced held by clients. */
+ fshelp_fetch_control (&oldnp->transbox, &control);
+
+ if (control)
+ {
+ fsys_goaway (control, FSYS_GOAWAY_UNLINK);
+ mach_port_deallocate (mach_task_self (), control);
+ }
+
+ /* Put the new key in the vinode. */
+ vi_change (vi_lookup (np->cache_id), entry_key);
+
munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+ dp->dn_set_mtime = 1;
diskfs_file_update (dp, 1);
return 0;
@@ -741,7 +794,7 @@ diskfs_dirempty (struct node *dp, struct
if (entry->name[0] == FAT_DIR_NAME_LAST)
break;
- if (!entry->name[0] == FAT_DIR_NAME_DELETED
+ if ((char) entry->name[0] != FAT_DIR_NAME_DELETED
&& memcmp (entry->name, FAT_DIR_NAME_DOT, 11)
&& memcmp (entry->name, FAT_DIR_NAME_DOTDOT, 11))
hit = 1;
@@ -754,7 +807,7 @@ diskfs_dirempty (struct node *dp, struct
munmap ((caddr_t) buf, dp->dn_stat.st_size);
- return !hit;
+ return (!hit ? ENOTEMPTY : 0);
}
/* Make DS an invalid dirstat. */
diff -BNup /home/marco/src/hurdcvs/hurd/fatfs/fat.c fatfs/fat.c
--- /home/marco/src/hurdcvs/hurd/fatfs/fat.c 2002-12-03 21:52:59.000000000
+0100
+++ fatfs/fat.c 2003-07-08 00:04:00.000000000 +0200
@@ -1,5 +1,5 @@
/* fat.c - Support for FAT filesystems.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -386,15 +386,15 @@ fat_extend_chain (struct node *node, clu
dn->last = dn->first = *table;
return 0;
}
-
- spin_lock(&dn->chain_extension_lock);
-
+
/* If we already have what we need, or we have all clusters that are
available without allocating new ones, go out. */
if (new_last_cluster < dn->length_of_chain
|| (!create && dn->chain_complete))
return 0;
+ spin_lock(&dn->chain_extension_lock);
+
left = new_last_cluster + 1 - dn->length_of_chain;
table = dn->last;
@@ -502,9 +502,11 @@ fat_truncate_node (struct node *node, cl
/* The root dir of a FAT12/16 fs is of fixed size, while the root
dir of a FAT32 fs must never decease to exist. */
- assert (! (((fat_type == FAT12 || fat_type == FAT16) && node ==
diskfs_root_node)
- || (fat_type == FAT32 && node == diskfs_root_node &&
clusters_to_keep == 0)));
-
+ assert (! (((fat_type == FAT12 || fat_type == FAT16) &&
+ node == diskfs_root_node)
+ || (fat_type == FAT32 && node == diskfs_root_node &&
+ clusters_to_keep == 0)));
+
/* Expand the cluster chain, because we have to know the complete tail. */
fat_extend_chain (node, FAT_EOC, 0);
if (clusters_to_keep == node->dn->length_of_chain)
@@ -518,6 +520,7 @@ fat_truncate_node (struct node *node, cl
/* Deallocate the complete file. */
node->dn->start_cluster = 0;
pos = count = offs = 0;
+ node->dn->last = 0;
}
else
{
@@ -526,6 +529,11 @@ fat_truncate_node (struct node *node, cl
while (count-- > 0)
{
assert (next);
+
+ /* This cluster is now the last cluster in the chain. */
+ if (count == 0)
+ node->dn->last = next;
+
next = next->next;
}
assert (next);
@@ -567,6 +575,11 @@ fat_truncate_node (struct node *node, cl
free (next);
next = next_next;
}
+
+ if (clusters_to_keep == 0)
+ node->dn->first = 0;
+
+ node->dn->length_of_chain = clusters_to_keep;
}
diff -BNup /home/marco/src/hurdcvs/hurd/fatfs/main.c fatfs/main.c
--- /home/marco/src/hurdcvs/hurd/fatfs/main.c 2003-05-10 02:12:29.000000000
+0200
+++ fatfs/main.c 2003-07-07 22:14:10.000000000 +0200
@@ -42,9 +42,6 @@ int diskfs_link_max = 1;
int diskfs_name_max = FAT_NAME_MAX;
int diskfs_maxsymlinks = 8; /* XXX */
-/* This filesystem is not capable of writing yet. */
-int diskfs_readonly = 1, diskfs_hard_readonly = 1;
-
/* Handy source of zeroes. */
vm_address_t zerocluster;
@@ -228,7 +225,8 @@ main (int argc, char **argv)
create_fat_pager ();
- zerocluster = (vm_address_t) mmap (0, bytes_per_cluster,
PROT_READ|PROT_WRITE,
+ zerocluster = (vm_address_t) mmap (0, bytes_per_cluster,
+ PROT_READ|PROT_WRITE,
MAP_ANON, 0, 0);
fetch_root ();
diff -BNup /home/marco/src/hurdcvs/hurd/fatfs/node-create.c fatfs/node-create.c
--- /home/marco/src/hurdcvs/hurd/fatfs/node-create.c 1970-01-01
01:00:00.000000000 +0100
+++ fatfs/node-create.c 2003-07-07 22:14:20.000000000 +0200
@@ -0,0 +1,191 @@
+/* Making new files
+ Copyright (C) 1992,93,94,96,98,2001, 2003 Free Software Foundation
+ Modified for fatfs by Marco Gerards.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/diskfs.h>
+
+/* This enables SysV style group behaviour. New nodes inherit the GID
+ of the user creating them unless the SGID bit is set of the parent
+ directory. */
+int _diskfs_no_inherit_dir_group;
+
+/* Create a new node. Give it MODE; if that includes IFDIR, also
+ initialize `.' and `..' in the new directory. Return the node in NPP.
+ CRED identifies the user responsible for the call. If NAME is nonzero,
+ then link the new node into DIR with name NAME; DS is the result of a
+ prior diskfs_lookup for creation (and DIR has been held locked since).
+ DIR must always be provided as at least a hint for disk allocation
+ strategies. */
+error_t
+diskfs_create_node (struct node *dir,
+ const char *name,
+ mode_t mode,
+ struct node **newnode,
+ struct protid *cred,
+ struct dirstat *ds)
+{
+ struct node *np;
+ error_t err;
+ uid_t newuid;
+ gid_t newgid;
+
+ if (diskfs_check_readonly ())
+ {
+ *newnode = NULL;
+ return EROFS;
+ }
+
+ /* Make the node */
+ err = diskfs_alloc_node (dir, mode, newnode);
+ if (err)
+ {
+ if (name)
+ diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
+ return err;
+ }
+
+ np = *newnode;
+
+ /* Initialize the on-disk fields. */
+ if (cred->user->uids->num)
+ newuid = cred->user->uids->ids[0];
+ else
+ {
+ newuid = dir->dn_stat.st_uid;
+ mode &= ~S_ISUID;
+ }
+ err = diskfs_validate_owner_change (np, newuid);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_uid = newuid;
+ if (np->author_tracks_uid)
+ np->dn_stat.st_author = newuid;
+
+ if (!_diskfs_no_inherit_dir_group)
+ {
+ newgid = dir->dn_stat.st_gid;
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ else
+ {
+ if (dir->dn_stat.st_mode & S_ISGID)
+ {
+ /* If the parent dir has the sgid bit set, inherit its gid.
+ If the new node is a directory, also inherit the sgid bit
+ set. */
+ newgid = dir->dn_stat.st_gid;
+ if (S_ISDIR (mode))
+ mode |= S_ISGID;
+ else
+ {
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ }
+ else
+ {
+ if (cred->user->gids->num)
+ newgid = cred->user->gids->ids[0];
+ else
+ {
+ newgid = dir->dn_stat.st_gid;
+ mode &= ~S_ISGID;
+ }
+ }
+ }
+
+ err = diskfs_validate_group_change (np, newgid);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_gid = newgid;
+
+ np->dn_stat.st_rdev = 0;
+ np->dn_stat.st_nlink = !!name;
+ err = diskfs_validate_mode_change (np, mode);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_mode = mode;
+
+ np->dn_stat.st_blocks = 0;
+ np->dn_stat.st_size = 0;
+ np->dn_stat.st_flags = 0;
+ np->dn_set_atime = 1;
+ np->dn_set_mtime = 1;
+ np->dn_set_ctime = 1;
+
+ diskfs_node_update (np, 1);
+
+ if (err)
+ {
+ change_err:
+ np->dn_stat.st_mode = 0;
+ np->dn_stat.st_nlink = 0;
+ if (name)
+ diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
+ return err;
+ }
+
+ if (name)
+ {
+ err = diskfs_direnter (dir, name, np, ds, cred);
+ if (err)
+ {
+ np->dn_stat.st_nlink = 0;
+ np->dn_set_ctime = 1;
+ diskfs_nput (np);
+ }
+
+ if (S_ISDIR (mode))
+ err = diskfs_init_dir (np, dir, cred);
+
+ if (err)
+ {
+ struct dirstat *ds = alloca (diskfs_dirstat_size);
+ struct node *foo;
+ /* Keep old error intact. */
+ error_t err;
+
+ np->dn_stat.st_nlink = 0;
+
+ err = diskfs_lookup (dir, name, REMOVE, &foo, ds, cred);
+ if (err)
+ {
+ /* The new node couldn't be removed, we have a big
+ problem now. */
+ *newnode = NULL;
+ return err;
+ }
+
+ err = diskfs_dirremove (dir, foo, name, ds);
+ if (err)
+ {
+ diskfs_nput (np);
+ *newnode = NULL;
+ return err;
+ }
+ }
+
+ diskfs_node_update (np, 1);
+ }
+ if (err)
+ *newnode = NULL;
+
+ return err;
+}
- Fatfs patch for writing support,
Marco Gerards <=