bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Fatfs patch for writing support


From: Marco Gerards
Subject: Re: Fatfs patch for writing support
Date: 19 Jul 2003 16:50:42 +0200
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

Here is a new version of this patch. I've included some GCS related
updates and removed something that is not relevant form the last
patch. I've also changed the changelog entry a bit so the changes are
grouped.

Can some please have a look at this patch too? (Alfred? :)).

Now there are two fatfs patches that aren't checked in yet. This one
and the one that should fix fat32/reading support. If they can't be
checked in because they conflict please check one in and ask me to
resend the other patch.

Thanks,
Marco



2003-07-07  Marco Gerards  <metgerards@student.han.nl>

        * node-create.c: New file.
        * 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): Change logic to test if a file was deleted.
        
        * 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.

Common subdirectories: /home/marco/src/hurdcvs/hurd/fatfs/CVS and fatfs/CVS
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-19 18:43:14.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.
@@ -21,6 +23,8 @@
 #include <ctype.h>
 #include <string.h>
 #include <dirent.h>
+#include <hurd/fsys.h>
+
 #include "fatfs.h"
 
 /* The size of a directory block is usually just the cluster size.
@@ -617,7 +621,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 +647,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 +717,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 +795,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;
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-19 18:46:16.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.
@@ -73,7 +73,7 @@ fat_read_sblock (void)
   sblock = malloc (sizeof (struct boot_sector));
   store_read (store, 0, sizeof (struct boot_sector), (void **) &sblock, &read);
 
-  if (read_word(sblock->id) != BOOT_SECTOR_ID)
+  if (read_word (sblock->id) != BOOT_SECTOR_ID)
     error (1, 0, "Could not find valid superblock");
 
   /* Parse some important bits of the superblock.  */
@@ -205,7 +205,7 @@ fat_read_sblock (void)
    You must call this from inside diskfs_catch_exception.
    Returns 0 (always succeeds).  */
 error_t
-fat_write_next_cluster(cluster_t cluster, cluster_t next_cluster)
+fat_write_next_cluster (cluster_t cluster, cluster_t next_cluster)
 {
   loff_t fat_entry_offset;
   cluster_t data;
@@ -259,7 +259,7 @@ fat_write_next_cluster(cluster_t cluster
    You must call this from inside diskfs_catch_exception.
    Returns 0 (always succeeds).  */
 error_t
-fat_get_next_cluster(cluster_t cluster, cluster_t *next_cluster)
+fat_get_next_cluster (cluster_t cluster, cluster_t *next_cluster)
 {
   loff_t fat_entry_offset;
 
@@ -348,12 +348,12 @@ fat_allocate_cluster (cluster_t content,
   if (found_cluster != FAT_FREE_CLUSTER)
     {
       *cluster = found_cluster;
-      fat_write_next_cluster(found_cluster, content);
+      fat_write_next_cluster (found_cluster, content);
     }
   else 
     err = ENOSPC;
 
-  spin_unlock(&allocate_free_cluster_lock);
+  spin_unlock (&allocate_free_cluster_lock);
   return err;
 }
 
@@ -371,7 +371,7 @@ fat_extend_chain (struct node *node, clu
   int offs;
   cluster_t left, prev_cluster, cluster;
 
-  error_t allocate_new_table(struct cluster_chain **table)
+  error_t allocate_new_table (struct cluster_chain **table)
     {
       struct cluster_chain *t;
 
@@ -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;
@@ -413,11 +413,11 @@ fat_extend_chain (struct node *node, clu
      {
        if (dn->chain_complete)
         {
-          err = fat_allocate_cluster(FAT_EOC, &cluster);
+          err = fat_allocate_cluster (FAT_EOC, &cluster);
           if (err)
             break;
           if (prev_cluster)
-            fat_write_next_cluster(prev_cluster, cluster);
+            fat_write_next_cluster (prev_cluster, cluster);
           else
             /* XXX: Also write this to dirent structure!  */
             dn->start_cluster = cluster;
@@ -425,7 +425,7 @@ fat_extend_chain (struct node *node, clu
        else
         {
           if (prev_cluster != FAT_FREE_CLUSTER)
-            err = fat_get_next_cluster(prev_cluster, &cluster);
+            err = fat_get_next_cluster (prev_cluster, &cluster);
           else
             cluster = dn->start_cluster;
           if (cluster == FAT_EOC || cluster == FAT_FREE_CLUSTER)
@@ -442,7 +442,7 @@ fat_extend_chain (struct node *node, clu
        if (offs == CLUSTERS_PER_TABLE)
         {
           offs = 0;
-          err = allocate_new_table(&table);
+          err = allocate_new_table (&table);
           if (err)
             break;
         }
@@ -454,7 +454,7 @@ fat_extend_chain (struct node *node, clu
    if (dn->length_of_chain << log2_bytes_per_cluster > node->allocsize)
      node->allocsize = dn->length_of_chain << log2_bytes_per_cluster;
 
-   spin_unlock(&dn->chain_extension_lock);
+   spin_unlock (&dn->chain_extension_lock);
    return err;
 }
    
@@ -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);
@@ -541,9 +549,9 @@ fat_truncate_node (struct node *node, cl
        {
          offs = 0;
          next = next->next;
-         assert(next);
+         assert (next);
        }
-      fat_write_next_cluster(next->cluster[offs++], 0);
+      fat_write_next_cluster (next->cluster[offs++], 0);
       pos++;
     }
  
@@ -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; 
 }
 
 
@@ -598,7 +611,7 @@ fat_get_freespace (void)
 
 
 /* FILE must be a buffer with 13 characters.  */
-void fat_to_unix_filename(const char *name, char *file)
+void fat_to_unix_filename (const char *name, char *file)
 {
   int npos;
   int fpos = 0;
@@ -639,7 +652,7 @@ void fat_to_unix_filename(const char *na
 }
 
 void
-fat_from_unix_filename(char *fn, const char *un, int ul)
+fat_from_unix_filename (char *fn, const char *un, int ul)
 {
   int fp = 0;
   int up = 0;
@@ -670,7 +683,7 @@ fat_from_unix_filename(char *fn, const c
                  ext = 1;
                }
              else
-                 fn[fp++] = toupper(un[ul++]);
+                 fn[fp++] = toupper (un[ul++]);
            }
          else
            {
@@ -680,7 +693,7 @@ fat_from_unix_filename(char *fn, const c
                    fn[fp++] = ' ';
                }
              else
-               fn[fp++] = toupper(un[up++]);
+               fn[fp++] = toupper (un[up++]);
            }
        }
     }
@@ -722,7 +735,7 @@ fat_from_epoch (char *date, char *time, 
 {
   struct tm *tm;
 
-  spin_lock(&epoch_to_time_lock);
+  spin_lock (&epoch_to_time_lock);
   tm = gmtime (tp);
 
   /* Date format:
@@ -736,9 +749,9 @@ fat_from_epoch (char *date, char *time, 
      Bits 11-15: Hours (0-23).
   */
 
-  write_word(date, tm->tm_mday | ((tm->tm_mon + 1) << 5)
-            | ((tm->tm_year - 80) << 9));
-  write_word(time, (tm->tm_hour << 11) | (tm->tm_min << 5)
-            | (tm->tm_sec >> 1));
-  spin_unlock(&epoch_to_time_lock);
+  write_word (date, tm->tm_mday | ((tm->tm_mon + 1) << 5)
+             | ((tm->tm_year - 80) << 9));
+  write_word (time, (tm->tm_hour << 11) | (tm->tm_min << 5)
+             | (tm->tm_sec >> 1));
+  spin_unlock (&epoch_to_time_lock);
 }
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-19 13:58:09.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/Makefile fatfs/Makefile
--- /home/marco/src/hurdcvs/hurd/fatfs/Makefile 2002-12-03 21:52:59.000000000 
+0100
+++ fatfs/Makefile      2003-07-19 13:58:09.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/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-19 16:27:07.000000000 +0200
@@ -0,0 +1,194 @@
+/* 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);
+       }
+
+      /* For fatfs the "." and ".." directory entries should be
+        created after the directory was created and not before the
+        directory was created.  */
+      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;
+}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]