1 /* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
3 * Based on readfs by Paul Polderman
6 #define _POSIX_SOURCE 1
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>
24 void readblock(off_t blockno
, char *buf
, int);
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
30 * To make matters worse, Minix-vmd knows about the normal Unix Version 7
31 * directories and directories with flexible entries.
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
;
42 #define direct _v7_direct
48 static struct v12_super_block super
; /* Superblock of file system */
49 #define s_log_zone_size s_dummy /* Zones are obsolete. */
51 static struct super_block super
; /* Superblock of file system */
52 #define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
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
61 static block_t a_indir
, a_dindir
; /* Addresses of the indirects. */
62 static off_t dirpos
; /* Reading pos in a dir. */
64 #define fsbuf(b) (* (struct buf *) (b))
66 #define zone_shift (super.s_log_zone_size) /* zone to block ratio */
68 off_t
r_super(int *bs
)
69 /* Initialize variables, return size of file system in blocks,
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).)
77 readblock(1, scratch
, 1024);
79 memcpy(&super
, scratch
, sizeof(super
));
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
) {
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
;
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
;
102 /* Filesystem not recognized as Minix. */
107 void r_stat(Ino_t inum
, struct stat
*stp
)
108 /* Return information about a file like stat(2) and remember it. */
114 /* Calculate start of i-list */
115 block
= START_BLOCK
+ super
.s_imap_blocks
+ super
.s_zmap_blocks
;
117 /* Calculate block with inode inum */
118 ino_block
= ((inum
- 1) / inodes_per_block
);
119 ino_offset
= ((inum
- 1) % inodes_per_block
);
122 /* Fetch the block */
123 readblock(block
, scratch
, block_size
);
125 if (super
.s_magic
== SUPER_V2
|| super
.s_magic
== SUPER_V3
) {
129 dip
= &fsbuf(scratch
).b_v2_ino
[ino_offset
];
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
];
145 dip
= &fsbuf(scratch
).b_v1_ino
[ino_offset
];
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
];
158 curfil
.i_dev
= -1; /* Can't fill this in alas. */
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
;
173 a_indir
= a_dindir
= 0;
177 ino_t
r_readdir(char *name
)
178 /* Read next directory entry at "dirpos" from file "curfil". */
184 if (!S_ISDIR(curfil
.i_mode
)) { errno
= ENOTDIR
; return -1; }
186 if(!block_size
) { errno
= 0; return -1; }
188 while (inum
== 0 && dirpos
< curfil
.i_size
) {
189 if ((blkpos
= (int) (dirpos
% block_size
)) == 0) {
190 /* Need to fetch a new directory block. */
192 readblock(r_vir2abs(dirpos
/ block_size
), dirbuf
, block_size
);
195 if (super
.s_flags
& S_FLEX
) {
196 struct _fl_direct
*dp
;
198 dp
= (struct _fl_direct
*) (dirbuf
+ blkpos
);
199 if ((inum
= dp
->d_ino
) != 0) strcpy(name
, dp
->d_name
);
201 dirpos
+= (1 + dp
->d_extent
) * FL_DIR_ENTRY_SIZE
;
205 /* Let dp point to the next entry. */
206 dp
= (struct direct
*) (dirbuf
+ blkpos
);
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;
213 dirpos
+= DIR_ENTRY_SIZE
;
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.
224 zone_t zone
, ind_zone
;
225 block_t z
, zone_index
;
228 if(!block_size
) return -1;
230 /* Check if virblk within file. */
231 if (virblk
* block_size
>= curfil
.i_size
) return -1;
233 /* Calculate zone in which the datablock number is contained */
234 zone
= (zone_t
) (b
>> zone_shift
);
236 /* Calculate index of the block number in the zone */
237 zone_index
= b
- ((block_t
) zone
<< zone_shift
);
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
;
246 /* The zone is not a direct one */
247 zone
-= (zone_t
) nr_dzones
;
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;
256 z
= (block_t
) ind_zone
<< zone_shift
;
258 readblock(z
, dindir
, block_size
);
261 /* Extract the indirect zone number from it */
262 zone
-= (zone_t
) nr_indirects
;
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
;
270 if (ind_zone
== 0) return 0;
272 /* Extract the datablock number from the indirect zone */
273 z
= (block_t
) ind_zone
<< zone_shift
;
275 readblock(z
, indir
, block_size
);
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
];
282 /* Calculate absolute datablock number */
283 z
= ((block_t
) zone
<< zone_shift
) + zone_index
;
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.
292 char name
[NAME_MAX
+1], r_name
[NAME_MAX
+1];
297 ino
= path
[0] == '/' ? ROOT_INO
: cwd
;
305 while (*path
== '/') path
++;
307 if (*path
== 0) return ino
;
311 if (!S_ISDIR(st
.st_mode
)) {
317 while (*path
!= 0 && *path
!= '/')
318 if (n
< name
+ NAME_MAX
) *n
++ = *path
++;
321 while ((ino
= r_readdir(r_name
)) != 0
322 && strcmp(name
, r_name
) != 0) {
328 * $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $