[9] | 1 | /* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
|
---|
| 2 | * 23 Dec 1991
|
---|
| 3 | * Based on readfs by Paul Polderman
|
---|
| 4 | */
|
---|
| 5 | #define nil 0
|
---|
| 6 | #define _POSIX_SOURCE 1
|
---|
| 7 | #define _MINIX 1
|
---|
| 8 | #include <sys/types.h>
|
---|
| 9 | #include <sys/stat.h>
|
---|
| 10 | #include <stdlib.h>
|
---|
| 11 | #include <limits.h>
|
---|
| 12 | #include <string.h>
|
---|
| 13 | #include <errno.h>
|
---|
| 14 | #include <minix/config.h>
|
---|
| 15 | #include <minix/const.h>
|
---|
| 16 | #include <minix/type.h>
|
---|
| 17 | #include <servers/fs/const.h>
|
---|
| 18 | #include <servers/fs/type.h>
|
---|
| 19 | #include <servers/fs/buf.h>
|
---|
| 20 | #include <servers/fs/super.h>
|
---|
| 21 | #include <servers/fs/inode.h>
|
---|
| 22 | #include "rawfs.h"
|
---|
| 23 |
|
---|
| 24 | void readblock(off_t blockno, char *buf, int);
|
---|
| 25 |
|
---|
| 26 | /* The following code handles two file system types: Version 1 with small
|
---|
| 27 | * inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
|
---|
| 28 | * disk addresses.
|
---|
| 29 | #ifdef FLEX
|
---|
| 30 | * To make matters worse, Minix-vmd knows about the normal Unix Version 7
|
---|
| 31 | * directories and directories with flexible entries.
|
---|
| 32 | #endif
|
---|
| 33 | */
|
---|
| 34 |
|
---|
| 35 | /* File system parameters. */
|
---|
| 36 | static unsigned nr_dzones; /* Fill these in after reading superblock. */
|
---|
| 37 | static unsigned nr_indirects;
|
---|
| 38 | static unsigned inodes_per_block;
|
---|
| 39 | static int block_size;
|
---|
| 40 | #ifdef FLEX
|
---|
| 41 | #include <dirent.h>
|
---|
| 42 | #define direct _v7_direct
|
---|
| 43 | #else
|
---|
| 44 | #include <sys/dir.h>
|
---|
| 45 | #endif
|
---|
| 46 |
|
---|
| 47 | #if __minix_vmd
|
---|
| 48 | static struct v12_super_block super; /* Superblock of file system */
|
---|
| 49 | #define s_log_zone_size s_dummy /* Zones are obsolete. */
|
---|
| 50 | #else
|
---|
| 51 | static struct super_block super; /* Superblock of file system */
|
---|
| 52 | #define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
|
---|
| 53 | #endif
|
---|
| 54 |
|
---|
| 55 | static struct inode curfil; /* Inode of file under examination */
|
---|
| 56 | static char indir[_MAX_BLOCK_SIZE]; /* Single indirect block. */
|
---|
| 57 | static char dindir[_MAX_BLOCK_SIZE]; /* Double indirect block. */
|
---|
| 58 | static char dirbuf[_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
|
---|
| 59 | #define scratch dirbuf
|
---|
| 60 |
|
---|
| 61 | static block_t a_indir, a_dindir; /* Addresses of the indirects. */
|
---|
| 62 | static off_t dirpos; /* Reading pos in a dir. */
|
---|
| 63 |
|
---|
| 64 | #define fsbuf(b) (* (struct buf *) (b))
|
---|
| 65 |
|
---|
| 66 | #define zone_shift (super.s_log_zone_size) /* zone to block ratio */
|
---|
| 67 |
|
---|
| 68 | off_t r_super(int *bs)
|
---|
| 69 | /* Initialize variables, return size of file system in blocks,
|
---|
| 70 | * (zero on error).
|
---|
| 71 | */
|
---|
| 72 | {
|
---|
| 73 | /* Read superblock. (The superblock is always at 1kB offset,
|
---|
| 74 | * that's why we lie to readblock and say the block size is 1024
|
---|
| 75 | * and we want block number 1 (the 'second block', at offset 1kB).)
|
---|
| 76 | */
|
---|
| 77 | readblock(1, scratch, 1024);
|
---|
| 78 |
|
---|
| 79 | memcpy(&super, scratch, sizeof(super));
|
---|
| 80 |
|
---|
| 81 | /* Is it really a MINIX file system ? */
|
---|
| 82 | if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
---|
| 83 | if(super.s_magic == SUPER_V2)
|
---|
| 84 | super.s_block_size = 1024;
|
---|
| 85 | *bs = block_size = super.s_block_size;
|
---|
| 86 | if(block_size < _MIN_BLOCK_SIZE ||
|
---|
| 87 | block_size > _MAX_BLOCK_SIZE) {
|
---|
| 88 | return 0;
|
---|
| 89 | }
|
---|
| 90 | nr_dzones= V2_NR_DZONES;
|
---|
| 91 | nr_indirects= V2_INDIRECTS(block_size);
|
---|
| 92 | inodes_per_block= V2_INODES_PER_BLOCK(block_size);
|
---|
| 93 | return (off_t) super.s_zones << zone_shift;
|
---|
| 94 | } else
|
---|
| 95 | if (super.s_magic == SUPER_V1) {
|
---|
| 96 | *bs = block_size = 1024;
|
---|
| 97 | nr_dzones= V1_NR_DZONES;
|
---|
| 98 | nr_indirects= V1_INDIRECTS;
|
---|
| 99 | inodes_per_block= V1_INODES_PER_BLOCK;
|
---|
| 100 | return (off_t) super.s_nzones << zone_shift;
|
---|
| 101 | } else {
|
---|
| 102 | /* Filesystem not recognized as Minix. */
|
---|
| 103 | return 0;
|
---|
| 104 | }
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 | void r_stat(Ino_t inum, struct stat *stp)
|
---|
| 108 | /* Return information about a file like stat(2) and remember it. */
|
---|
| 109 | {
|
---|
| 110 | block_t block;
|
---|
| 111 | block_t ino_block;
|
---|
| 112 | ino_t ino_offset;
|
---|
| 113 |
|
---|
| 114 | /* Calculate start of i-list */
|
---|
| 115 | block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
|
---|
| 116 |
|
---|
| 117 | /* Calculate block with inode inum */
|
---|
| 118 | ino_block = ((inum - 1) / inodes_per_block);
|
---|
| 119 | ino_offset = ((inum - 1) % inodes_per_block);
|
---|
| 120 | block += ino_block;
|
---|
| 121 |
|
---|
| 122 | /* Fetch the block */
|
---|
| 123 | readblock(block, scratch, block_size);
|
---|
| 124 |
|
---|
| 125 | if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
---|
| 126 | d2_inode *dip;
|
---|
| 127 | int i;
|
---|
| 128 |
|
---|
| 129 | dip= &fsbuf(scratch).b_v2_ino[ino_offset];
|
---|
| 130 |
|
---|
| 131 | curfil.i_mode= dip->d2_mode;
|
---|
| 132 | curfil.i_nlinks= dip->d2_nlinks;
|
---|
| 133 | curfil.i_uid= dip->d2_uid;
|
---|
| 134 | curfil.i_gid= dip->d2_gid;
|
---|
| 135 | curfil.i_size= dip->d2_size;
|
---|
| 136 | curfil.i_atime= dip->d2_atime;
|
---|
| 137 | curfil.i_mtime= dip->d2_mtime;
|
---|
| 138 | curfil.i_ctime= dip->d2_ctime;
|
---|
| 139 | for (i= 0; i < V2_NR_TZONES; i++)
|
---|
| 140 | curfil.i_zone[i]= dip->d2_zone[i];
|
---|
| 141 | } else {
|
---|
| 142 | d1_inode *dip;
|
---|
| 143 | int i;
|
---|
| 144 |
|
---|
| 145 | dip= &fsbuf(scratch).b_v1_ino[ino_offset];
|
---|
| 146 |
|
---|
| 147 | curfil.i_mode= dip->d1_mode;
|
---|
| 148 | curfil.i_nlinks= dip->d1_nlinks;
|
---|
| 149 | curfil.i_uid= dip->d1_uid;
|
---|
| 150 | curfil.i_gid= dip->d1_gid;
|
---|
| 151 | curfil.i_size= dip->d1_size;
|
---|
| 152 | curfil.i_atime= dip->d1_mtime;
|
---|
| 153 | curfil.i_mtime= dip->d1_mtime;
|
---|
| 154 | curfil.i_ctime= dip->d1_mtime;
|
---|
| 155 | for (i= 0; i < V1_NR_TZONES; i++)
|
---|
| 156 | curfil.i_zone[i]= dip->d1_zone[i];
|
---|
| 157 | }
|
---|
| 158 | curfil.i_dev= -1; /* Can't fill this in alas. */
|
---|
| 159 | curfil.i_num= inum;
|
---|
| 160 |
|
---|
| 161 | stp->st_dev= curfil.i_dev;
|
---|
| 162 | stp->st_ino= curfil.i_num;
|
---|
| 163 | stp->st_mode= curfil.i_mode;
|
---|
| 164 | stp->st_nlink= curfil.i_nlinks;
|
---|
| 165 | stp->st_uid= curfil.i_uid;
|
---|
| 166 | stp->st_gid= curfil.i_gid;
|
---|
| 167 | stp->st_rdev= (dev_t) curfil.i_zone[0];
|
---|
| 168 | stp->st_size= curfil.i_size;
|
---|
| 169 | stp->st_atime= curfil.i_atime;
|
---|
| 170 | stp->st_mtime= curfil.i_mtime;
|
---|
| 171 | stp->st_ctime= curfil.i_ctime;
|
---|
| 172 |
|
---|
| 173 | a_indir= a_dindir= 0;
|
---|
| 174 | dirpos= 0;
|
---|
| 175 | }
|
---|
| 176 |
|
---|
| 177 | ino_t r_readdir(char *name)
|
---|
| 178 | /* Read next directory entry at "dirpos" from file "curfil". */
|
---|
| 179 | {
|
---|
| 180 | ino_t inum= 0;
|
---|
| 181 | int blkpos;
|
---|
| 182 | struct direct *dp;
|
---|
| 183 |
|
---|
| 184 | if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
|
---|
| 185 |
|
---|
| 186 | if(!block_size) { errno = 0; return -1; }
|
---|
| 187 |
|
---|
| 188 | while (inum == 0 && dirpos < curfil.i_size) {
|
---|
| 189 | if ((blkpos= (int) (dirpos % block_size)) == 0) {
|
---|
| 190 | /* Need to fetch a new directory block. */
|
---|
| 191 |
|
---|
| 192 | readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
|
---|
| 193 | }
|
---|
| 194 | #ifdef FLEX
|
---|
| 195 | if (super.s_flags & S_FLEX) {
|
---|
| 196 | struct _fl_direct *dp;
|
---|
| 197 |
|
---|
| 198 | dp= (struct _fl_direct *) (dirbuf + blkpos);
|
---|
| 199 | if ((inum= dp->d_ino) != 0) strcpy(name, dp->d_name);
|
---|
| 200 |
|
---|
| 201 | dirpos+= (1 + dp->d_extent) * FL_DIR_ENTRY_SIZE;
|
---|
| 202 | continue;
|
---|
| 203 | }
|
---|
| 204 | #endif
|
---|
| 205 | /* Let dp point to the next entry. */
|
---|
| 206 | dp= (struct direct *) (dirbuf + blkpos);
|
---|
| 207 |
|
---|
| 208 | if ((inum= dp->d_ino) != 0) {
|
---|
| 209 | /* This entry is occupied, return name. */
|
---|
| 210 | strncpy(name, dp->d_name, sizeof(dp->d_name));
|
---|
| 211 | name[sizeof(dp->d_name)]= 0;
|
---|
| 212 | }
|
---|
| 213 | dirpos+= DIR_ENTRY_SIZE;
|
---|
| 214 | }
|
---|
| 215 | return inum;
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | off_t r_vir2abs(off_t virblk)
|
---|
| 219 | /* Translate a block number in a file to an absolute disk block number.
|
---|
| 220 | * Returns 0 for a hole and -1 if block is past end of file.
|
---|
| 221 | */
|
---|
| 222 | {
|
---|
| 223 | block_t b= virblk;
|
---|
| 224 | zone_t zone, ind_zone;
|
---|
| 225 | block_t z, zone_index;
|
---|
| 226 | int i;
|
---|
| 227 |
|
---|
| 228 | if(!block_size) return -1;
|
---|
| 229 |
|
---|
| 230 | /* Check if virblk within file. */
|
---|
| 231 | if (virblk * block_size >= curfil.i_size) return -1;
|
---|
| 232 |
|
---|
| 233 | /* Calculate zone in which the datablock number is contained */
|
---|
| 234 | zone = (zone_t) (b >> zone_shift);
|
---|
| 235 |
|
---|
| 236 | /* Calculate index of the block number in the zone */
|
---|
| 237 | zone_index = b - ((block_t) zone << zone_shift);
|
---|
| 238 |
|
---|
| 239 | /* Go get the zone */
|
---|
| 240 | if (zone < (zone_t) nr_dzones) { /* direct block */
|
---|
| 241 | zone = curfil.i_zone[(int) zone];
|
---|
| 242 | z = ((block_t) zone << zone_shift) + zone_index;
|
---|
| 243 | return z;
|
---|
| 244 | }
|
---|
| 245 |
|
---|
| 246 | /* The zone is not a direct one */
|
---|
| 247 | zone -= (zone_t) nr_dzones;
|
---|
| 248 |
|
---|
| 249 | /* Is it single indirect ? */
|
---|
| 250 | if (zone < (zone_t) nr_indirects) { /* single indirect block */
|
---|
| 251 | ind_zone = curfil.i_zone[nr_dzones];
|
---|
| 252 | } else { /* double indirect block */
|
---|
| 253 | /* Fetch the double indirect block */
|
---|
| 254 | if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
|
---|
| 255 |
|
---|
| 256 | z = (block_t) ind_zone << zone_shift;
|
---|
| 257 | if (a_dindir != z) {
|
---|
| 258 | readblock(z, dindir, block_size);
|
---|
| 259 | a_dindir= z;
|
---|
| 260 | }
|
---|
| 261 | /* Extract the indirect zone number from it */
|
---|
| 262 | zone -= (zone_t) nr_indirects;
|
---|
| 263 |
|
---|
| 264 | i = zone / (zone_t) nr_indirects;
|
---|
| 265 | ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
---|
| 266 | ? fsbuf(dindir).b_v2_ind[i]
|
---|
| 267 | : fsbuf(dindir).b_v1_ind[i];
|
---|
| 268 | zone %= (zone_t) nr_indirects;
|
---|
| 269 | }
|
---|
| 270 | if (ind_zone == 0) return 0;
|
---|
| 271 |
|
---|
| 272 | /* Extract the datablock number from the indirect zone */
|
---|
| 273 | z = (block_t) ind_zone << zone_shift;
|
---|
| 274 | if (a_indir != z) {
|
---|
| 275 | readblock(z, indir, block_size);
|
---|
| 276 | a_indir= z;
|
---|
| 277 | }
|
---|
| 278 | zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
---|
| 279 | ? fsbuf(indir).b_v2_ind[(int) zone]
|
---|
| 280 | : fsbuf(indir).b_v1_ind[(int) zone];
|
---|
| 281 |
|
---|
| 282 | /* Calculate absolute datablock number */
|
---|
| 283 | z = ((block_t) zone << zone_shift) + zone_index;
|
---|
| 284 | return z;
|
---|
| 285 | }
|
---|
| 286 |
|
---|
| 287 | ino_t r_lookup(Ino_t cwd, char *path)
|
---|
| 288 | /* Translates a pathname to an inode number. This is just a nice utility
|
---|
| 289 | * function, it only needs r_stat and r_readdir.
|
---|
| 290 | */
|
---|
| 291 | {
|
---|
| 292 | char name[NAME_MAX+1], r_name[NAME_MAX+1];
|
---|
| 293 | char *n;
|
---|
| 294 | struct stat st;
|
---|
| 295 | ino_t ino;
|
---|
| 296 |
|
---|
| 297 | ino= path[0] == '/' ? ROOT_INO : cwd;
|
---|
| 298 |
|
---|
| 299 | for (;;) {
|
---|
| 300 | if (ino == 0) {
|
---|
| 301 | errno= ENOENT;
|
---|
| 302 | return 0;
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | while (*path == '/') path++;
|
---|
| 306 |
|
---|
| 307 | if (*path == 0) return ino;
|
---|
| 308 |
|
---|
| 309 | r_stat(ino, &st);
|
---|
| 310 |
|
---|
| 311 | if (!S_ISDIR(st.st_mode)) {
|
---|
| 312 | errno= ENOTDIR;
|
---|
| 313 | return 0;
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | n= name;
|
---|
| 317 | while (*path != 0 && *path != '/')
|
---|
| 318 | if (n < name + NAME_MAX) *n++ = *path++;
|
---|
| 319 | *n= 0;
|
---|
| 320 |
|
---|
| 321 | while ((ino= r_readdir(r_name)) != 0
|
---|
| 322 | && strcmp(name, r_name) != 0) {
|
---|
| 323 | }
|
---|
| 324 | }
|
---|
| 325 | }
|
---|
| 326 |
|
---|
| 327 | /*
|
---|
| 328 | * $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
|
---|
| 329 | */
|
---|