summaryrefslogtreecommitdiff
path: root/ext2fs
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1995-04-11 21:48:12 +0000
committerMiles Bader <miles@gnu.org>1995-04-11 21:48:12 +0000
commite7f7fab95b2b37aa4498cadd4a3ccdd85eb192eb (patch)
tree1f08504c796522900df3efd07a86d5c529161565 /ext2fs
parent5188ba726e4f8cfd5e0f80a93c8f0a79ccbdd782 (diff)
Initial revision
Diffstat (limited to 'ext2fs')
-rw-r--r--ext2fs/hyper.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/ext2fs/hyper.c b/ext2fs/hyper.c
new file mode 100644
index 00000000..8a556cef
--- /dev/null
+++ b/ext2fs/hyper.c
@@ -0,0 +1,193 @@
+/* Fetching and storing the hypermetadata (superblock and cg summary info).
+ Copyright (C) 1994 Free Software Foundation
+
+ 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 "ufs.h"
+#include <string.h>
+#include <stdio.h>
+
+static int oldformat = 0;
+
+void
+get_hypermetadata (void)
+{
+ sblock = malloc (SBSIZE);
+
+ assert (!diskfs_catch_exception ());
+ bcopy (disk_image + SBOFF, sblock, SBSIZE);
+ diskfs_end_catch_exception ();
+
+ if (sblock->fs_magic != FS_MAGIC)
+ {
+ fprintf (stderr, "Bad magic number %#lx (should be %#x)\n",
+ sblock->fs_magic, FS_MAGIC);
+ exit (1);
+ }
+ if (sblock->fs_bsize > 8192)
+ {
+ fprintf (stderr, "Block size %ld is too big (max is 8192 bytes)\n",
+ sblock->fs_bsize);
+ exit (1);
+ }
+ if (sblock->fs_bsize < sizeof (struct fs))
+ {
+ fprintf (stderr, "Block size %ld is too small (min is %ld bytes)\n",
+ sblock->fs_bsize, sizeof (struct fs));
+ exit (1);
+ }
+
+ if (sblock->fs_maxsymlinklen > (long)MAXSYMLINKLEN)
+ {
+ fprintf (stderr, "Max shortcut symlinklen %ld is too big (max is %ld)\n",
+ sblock->fs_maxsymlinklen, MAXSYMLINKLEN);
+ exit (1);
+ }
+
+ assert ((__vm_page_size % DEV_BSIZE) == 0);
+ assert ((sblock->fs_bsize % DEV_BSIZE) == 0);
+ assert (__vm_page_size <= sblock->fs_bsize);
+
+ /* If this is an old filesystem, then we have some more
+ work to do; some crucial constants might not be set; we
+ are therefore forced to set them here. */
+
+ if (sblock->fs_npsect < sblock->fs_nsect)
+ sblock->fs_npsect = sblock->fs_nsect;
+
+ if (sblock->fs_interleave < 1)
+ sblock->fs_interleave = 1;
+
+ if (sblock->fs_postblformat == FS_42POSTBLFMT)
+ sblock->fs_nrpos = 8;
+
+ if (sblock->fs_inodefmt < FS_44INODEFMT)
+ {
+ quad_t sizepb = sblock->fs_bsize;
+ int i;
+
+ oldformat = 1;
+ sblock->fs_maxfilesize = sblock->fs_bsize * NDADDR - 1;
+ for (i = 0; i < NIADDR; i++)
+ {
+ sizepb *= NINDIR (sblock);
+ sblock->fs_maxfilesize += sizepb;
+ }
+ sblock->fs_qbmask = ~sblock->fs_bmask;
+ sblock->fs_qfmask = ~sblock->fs_fmask;
+ }
+
+ /* Find out if we support the 4.4 symlink/dirtype extension */
+ if (sblock->fs_maxsymlinklen > 0)
+ direct_symlink_extension = 1;
+ else
+ direct_symlink_extension = 0;
+
+ csum = malloc (fsaddr (sblock, howmany (sblock->fs_cssize,
+ sblock->fs_fsize)));
+
+ assert (!diskfs_catch_exception ());
+ bcopy (disk_image + fsaddr (sblock, sblock->fs_csaddr),
+ csum,
+ fsaddr (sblock, howmany (sblock->fs_cssize, sblock->fs_fsize)));
+ diskfs_end_catch_exception ();
+}
+
+/* Write the csum data. This isn't backed by a pager because it is
+ taken from ordinary data blocks and might not be an even number
+ of pages; in that case writing it through the pager would nuke whatever
+ pages came after it on the disk and were backed by file pagers. */
+void
+diskfs_set_hypermetadata (int wait, int clean)
+{
+ vm_address_t buf;
+ vm_size_t bufsize;
+ error_t err;
+
+ spin_lock (&alloclock);
+
+ if (!csum_dirty)
+ {
+ spin_unlock (&alloclock);
+ return;
+ }
+
+ /* Copy into a page-aligned buffer to avoid bugs in kernel device code. */
+
+ bufsize = round_page (fragroundup (sblock, sblock->fs_cssize));
+
+ err = dev_read_sync (fsbtodb (sblock, sblock->fs_csaddr), &buf, bufsize);
+ if (!err)
+ {
+ bcopy (csum, (void *) buf, sblock->fs_cssize);
+ dev_write_sync (fsbtodb (sblock, sblock->fs_csaddr), buf, bufsize);
+ csum_dirty = 0;
+ vm_deallocate (mach_task_self (), buf, bufsize);
+ }
+
+ spin_unlock (&alloclock);
+}
+
+/* Copy the sblock into the disk */
+void
+copy_sblock ()
+{
+ int clean = 1; /* XXX wrong... */
+
+ assert (!diskfs_catch_exception ());
+
+ spin_lock (&alloclock);
+
+ if (clean && !diskfs_readonly)
+ {
+ sblock->fs_clean = 1;
+ sblock_dirty = 1;
+ }
+
+ if (sblock_dirty)
+ {
+ if (sblock->fs_postblformat == FS_42POSTBLFMT
+ || oldformat)
+ {
+ char sblockcopy[SBSIZE];
+ struct fs *sbcopy = (struct fs *)sblockcopy;
+ bcopy (sblock, sblockcopy, SBSIZE);
+ if (sblock->fs_postblformat == FS_42POSTBLFMT)
+ sbcopy->fs_nrpos = -1;
+ if (oldformat)
+ {
+ sbcopy->fs_maxfilesize = -1;
+ sbcopy->fs_qbmask = -1;
+ sbcopy->fs_qfmask = -1;
+ }
+ bcopy (sbcopy, disk_image + SBOFF, SBSIZE);
+ }
+ else
+ bcopy (sblock, disk_image + SBOFF, SBSIZE);
+ record_poke (disk_image + SBOFF, SBSIZE);
+ sblock_dirty = 0;
+ }
+
+ if (clean && !diskfs_readonly)
+ {
+ sblock->fs_clean = 0;
+ sblock_dirty = 1;
+ }
+
+ spin_unlock (&alloclock);
+ diskfs_end_catch_exception ();
+}
+
+