rawfs.c

Go to the documentation of this file.
00001 /*      rawfs.c - Raw Minix file system support.        Author: Kees J. Bot
00002  *                                                              23 Dec 1991
00003  *                                           Based on readfs by Paul Polderman
00004  */
00005 #define nil 0
00006 #define _POSIX_SOURCE   1
00007 #define _MINIX          1
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <stdlib.h>
00011 #include <limits.h>
00012 #include <string.h>
00013 #include <errno.h>
00014 #include <minix/config.h>
00015 #include <minix/const.h>
00016 #include <minix/type.h>
00017 #include <servers/fs/const.h>
00018 #include <servers/fs/type.h>
00019 #include <servers/fs/buf.h>
00020 #include <servers/fs/super.h>
00021 #include <servers/fs/inode.h>
00022 #include "rawfs.h"
00023 
00024 void readblock(off_t blockno, char *buf, int);
00025 
00026 /* The following code handles two file system types: Version 1 with small
00027  * inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
00028  * disk addresses.
00029 #ifdef FLEX
00030  * To make matters worse, Minix-vmd knows about the normal Unix Version 7
00031  * directories and directories with flexible entries.
00032 #endif
00033  */
00034 
00035 /* File system parameters. */
00036 static unsigned nr_dzones;      /* Fill these in after reading superblock. */
00037 static unsigned nr_indirects;
00038 static unsigned inodes_per_block;
00039 static int block_size;
00040 #ifdef FLEX
00041 #include <dirent.h>
00042 #define direct _v7_direct
00043 #else
00044 #include <sys/dir.h>
00045 #endif
00046 
00047 #if __minix_vmd
00048 static struct v12_super_block super;    /* Superblock of file system */
00049 #define s_log_zone_size s_dummy         /* Zones are obsolete. */
00050 #else
00051 static struct super_block super;        /* Superblock of file system */
00052 #define SUPER_V1 SUPER_MAGIC            /* V1 magic has a weird name. */
00053 #endif
00054 
00055 static struct inode curfil;             /* Inode of file under examination */
00056 static char indir[_MAX_BLOCK_SIZE];     /* Single indirect block. */
00057 static char dindir[_MAX_BLOCK_SIZE];    /* Double indirect block. */
00058 static char dirbuf[_MAX_BLOCK_SIZE];    /* Scratch/Directory block. */
00059 #define scratch dirbuf
00060 
00061 static block_t a_indir, a_dindir;       /* Addresses of the indirects. */
00062 static off_t dirpos;                    /* Reading pos in a dir. */
00063 
00064 #define fsbuf(b)        (* (struct buf *) (b))
00065 
00066 #define zone_shift      (super.s_log_zone_size) /* zone to block ratio */
00067 
00068 off_t r_super(int *bs)
00069 /* Initialize variables, return size of file system in blocks,
00070  * (zero on error).
00071  */
00072 {
00073         /* Read superblock. (The superblock is always at 1kB offset,
00074          * that's why we lie to readblock and say the block size is 1024
00075          * and we want block number 1 (the 'second block', at offset 1kB).)
00076          */
00077         readblock(1, scratch, 1024);
00078 
00079         memcpy(&super, scratch, sizeof(super));
00080 
00081         /* Is it really a MINIX file system ? */
00082         if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
00083                 if(super.s_magic == SUPER_V2)
00084                         super.s_block_size = 1024;
00085                 *bs = block_size = super.s_block_size;
00086                 if(block_size < _MIN_BLOCK_SIZE ||
00087                         block_size > _MAX_BLOCK_SIZE) {
00088                         return 0;
00089                 }
00090                 nr_dzones= V2_NR_DZONES;
00091                 nr_indirects= V2_INDIRECTS(block_size);
00092                 inodes_per_block= V2_INODES_PER_BLOCK(block_size);
00093                 return (off_t) super.s_zones << zone_shift;
00094         } else
00095         if (super.s_magic == SUPER_V1) {
00096                 *bs = block_size = 1024;
00097                 nr_dzones= V1_NR_DZONES;
00098                 nr_indirects= V1_INDIRECTS;
00099                 inodes_per_block= V1_INODES_PER_BLOCK;
00100                 return (off_t) super.s_nzones << zone_shift;
00101         } else {
00102                 /* Filesystem not recognized as Minix. */
00103                 return 0;
00104         }
00105 }
00106 
00107 void r_stat(Ino_t inum, struct stat *stp)
00108 /* Return information about a file like stat(2) and remember it. */
00109 {
00110         block_t block;
00111         block_t ino_block;
00112         ino_t ino_offset;
00113 
00114         /* Calculate start of i-list */
00115         block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
00116 
00117         /* Calculate block with inode inum */
00118         ino_block = ((inum - 1) / inodes_per_block);
00119         ino_offset = ((inum - 1) % inodes_per_block);
00120         block += ino_block;
00121 
00122         /* Fetch the block */
00123         readblock(block, scratch, block_size);
00124 
00125         if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
00126                 d2_inode *dip;
00127                 int i;
00128 
00129                 dip= &fsbuf(scratch).b_v2_ino[ino_offset];
00130 
00131                 curfil.i_mode= dip->d2_mode;
00132                 curfil.i_nlinks= dip->d2_nlinks;
00133                 curfil.i_uid= dip->d2_uid;
00134                 curfil.i_gid= dip->d2_gid;
00135                 curfil.i_size= dip->d2_size;
00136                 curfil.i_atime= dip->d2_atime;
00137                 curfil.i_mtime= dip->d2_mtime;
00138                 curfil.i_ctime= dip->d2_ctime;
00139                 for (i= 0; i < V2_NR_TZONES; i++)
00140                         curfil.i_zone[i]= dip->d2_zone[i];
00141         } else {
00142                 d1_inode *dip;
00143                 int i;
00144 
00145                 dip= &fsbuf(scratch).b_v1_ino[ino_offset];
00146 
00147                 curfil.i_mode= dip->d1_mode;
00148                 curfil.i_nlinks= dip->d1_nlinks;
00149                 curfil.i_uid= dip->d1_uid;
00150                 curfil.i_gid= dip->d1_gid;
00151                 curfil.i_size= dip->d1_size;
00152                 curfil.i_atime= dip->d1_mtime;
00153                 curfil.i_mtime= dip->d1_mtime;
00154                 curfil.i_ctime= dip->d1_mtime;
00155                 for (i= 0; i < V1_NR_TZONES; i++)
00156                         curfil.i_zone[i]= dip->d1_zone[i];
00157         }
00158         curfil.i_dev= -1;       /* Can't fill this in alas. */
00159         curfil.i_num= inum;
00160 
00161         stp->st_dev= curfil.i_dev;
00162         stp->st_ino= curfil.i_num;
00163         stp->st_mode= curfil.i_mode;
00164         stp->st_nlink= curfil.i_nlinks;
00165         stp->st_uid= curfil.i_uid;
00166         stp->st_gid= curfil.i_gid;
00167         stp->st_rdev= (dev_t) curfil.i_zone[0];
00168         stp->st_size= curfil.i_size;
00169         stp->st_atime= curfil.i_atime;
00170         stp->st_mtime= curfil.i_mtime;
00171         stp->st_ctime= curfil.i_ctime;
00172 
00173         a_indir= a_dindir= 0;
00174         dirpos= 0;
00175 }
00176 
00177 ino_t r_readdir(char *name)
00178 /* Read next directory entry at "dirpos" from file "curfil". */
00179 {
00180         ino_t inum= 0;
00181         int blkpos;
00182         struct direct *dp;
00183 
00184         if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
00185 
00186         if(!block_size) { errno = 0; return -1; }
00187 
00188         while (inum == 0 && dirpos < curfil.i_size) {
00189                 if ((blkpos= (int) (dirpos % block_size)) == 0) {
00190                         /* Need to fetch a new directory block. */
00191 
00192                         readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
00193                 }
00194 #ifdef FLEX
00195                 if (super.s_flags & S_FLEX) {
00196                         struct _fl_direct *dp;
00197 
00198                         dp= (struct _fl_direct *) (dirbuf + blkpos);
00199                         if ((inum= dp->d_ino) != 0) strcpy(name, dp->d_name);
00200 
00201                         dirpos+= (1 + dp->d_extent) * FL_DIR_ENTRY_SIZE;
00202                         continue;
00203                 }
00204 #endif
00205                 /* Let dp point to the next entry. */
00206                 dp= (struct direct *) (dirbuf + blkpos);
00207 
00208                 if ((inum= dp->d_ino) != 0) {
00209                         /* This entry is occupied, return name. */
00210                         strncpy(name, dp->d_name, sizeof(dp->d_name));
00211                         name[sizeof(dp->d_name)]= 0;
00212                 }
00213                 dirpos+= DIR_ENTRY_SIZE;
00214         }
00215         return inum;
00216 }
00217 
00218 off_t r_vir2abs(off_t virblk)
00219 /* Translate a block number in a file to an absolute disk block number.
00220  * Returns 0 for a hole and -1 if block is past end of file.
00221  */
00222 {
00223         block_t b= virblk;
00224         zone_t zone, ind_zone;
00225         block_t z, zone_index;
00226         int i;
00227 
00228         if(!block_size) return -1;
00229 
00230         /* Check if virblk within file. */
00231         if (virblk * block_size >= curfil.i_size) return -1;
00232 
00233         /* Calculate zone in which the datablock number is contained */
00234         zone = (zone_t) (b >> zone_shift);
00235 
00236         /* Calculate index of the block number in the zone */
00237         zone_index = b - ((block_t) zone << zone_shift);
00238 
00239         /* Go get the zone */
00240         if (zone < (zone_t) nr_dzones) {        /* direct block */
00241                 zone = curfil.i_zone[(int) zone];
00242                 z = ((block_t) zone << zone_shift) + zone_index;
00243                 return z;
00244         }
00245 
00246         /* The zone is not a direct one */
00247         zone -= (zone_t) nr_dzones;
00248 
00249         /* Is it single indirect ? */
00250         if (zone < (zone_t) nr_indirects) {     /* single indirect block */
00251                 ind_zone = curfil.i_zone[nr_dzones];
00252         } else {                        /* double indirect block */
00253                 /* Fetch the double indirect block */
00254                 if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
00255 
00256                 z = (block_t) ind_zone << zone_shift;
00257                 if (a_dindir != z) {
00258                         readblock(z, dindir, block_size);
00259                         a_dindir= z;
00260                 }
00261                 /* Extract the indirect zone number from it */
00262                 zone -= (zone_t) nr_indirects;
00263 
00264                 i = zone / (zone_t) nr_indirects;
00265                 ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
00266                                 ? fsbuf(dindir).b_v2_ind[i]
00267                                 : fsbuf(dindir).b_v1_ind[i];
00268                 zone %= (zone_t) nr_indirects;
00269         }
00270         if (ind_zone == 0) return 0;
00271 
00272         /* Extract the datablock number from the indirect zone */
00273         z = (block_t) ind_zone << zone_shift;
00274         if (a_indir != z) {
00275                 readblock(z, indir, block_size);
00276                 a_indir= z;
00277         }
00278         zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
00279                 ? fsbuf(indir).b_v2_ind[(int) zone]
00280                 : fsbuf(indir).b_v1_ind[(int) zone];
00281 
00282         /* Calculate absolute datablock number */
00283         z = ((block_t) zone << zone_shift) + zone_index;
00284         return z;
00285 }
00286 
00287 ino_t r_lookup(Ino_t cwd, char *path)
00288 /* Translates a pathname to an inode number.  This is just a nice utility
00289  * function, it only needs r_stat and r_readdir.
00290  */
00291 {
00292         char name[NAME_MAX+1], r_name[NAME_MAX+1];
00293         char *n;
00294         struct stat st;
00295         ino_t ino;
00296 
00297         ino= path[0] == '/' ? ROOT_INO : cwd;
00298 
00299         for (;;) {
00300                 if (ino == 0) {
00301                         errno= ENOENT;
00302                         return 0;
00303                 }
00304 
00305                 while (*path == '/') path++;
00306 
00307                 if (*path == 0) return ino;
00308 
00309                 r_stat(ino, &st);
00310 
00311                 if (!S_ISDIR(st.st_mode)) {
00312                         errno= ENOTDIR;
00313                         return 0;
00314                 }
00315 
00316                 n= name;
00317                 while (*path != 0 && *path != '/')
00318                         if (n < name + NAME_MAX) *n++ = *path++;
00319                 *n= 0;
00320 
00321                 while ((ino= r_readdir(r_name)) != 0
00322                                         && strcmp(name, r_name) != 0) {
00323                 }
00324         }
00325 }
00326 
00327 /*
00328  * $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
00329  */

Generated on Fri Apr 14 22:56:37 2006 for minix by  doxygen 1.4.6