|
|
1.1 root 1: /*
2: * GRUB -- GRand Unified Bootloader
3: * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU General Public License for more details.
14: *
15: * You should have received a copy of the GNU General Public License
16: * along with this program; if not, write to the Free Software
17: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18: * MA 02110-1301, USA.
19: */
20:
21: /* Restrictions:
22: This is MINIX V1 only (yet)
23: Disk creation is like:
24: mkfs.minix -c DEVICE
25: */
26:
27: #ifdef FSYS_MINIX
28:
29: #include "shared.h"
30: #include "filesys.h"
31:
32: /* #define DEBUG_MINIX */
33:
34: /* indirect blocks */
35: static int mapblock1, mapblock2, namelen;
36:
37: /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
38: #define DEV_BSIZE 512
39:
40: /* include/linux/fs.h */
41: #define BLOCK_SIZE_BITS 10
42: #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
43:
44: /* made up, defaults to 1 but can be passed via mount_opts */
45: #define WHICH_SUPER 1
46: /* kind of from fs/ext2/super.c (is OK for minix) */
47: #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
48:
49: /* include/asm-i386/type.h */
50: typedef __signed__ char __s8;
51: typedef unsigned char __u8;
52: typedef __signed__ short __s16;
53: typedef unsigned short __u16;
54: typedef __signed__ int __s32;
55: typedef unsigned int __u32;
56:
57: /* include/linux/minix_fs.h */
58: #define MINIX_ROOT_INO 1
59:
60: /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
61: #define MINIX_LINK_MAX 250
62: #define MINIX2_LINK_MAX 65530
63:
64: #define MINIX_I_MAP_SLOTS 8
65: #define MINIX_Z_MAP_SLOTS 64
66: #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
67: #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
68: #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
69: #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
70: #define MINIX_VALID_FS 0x0001 /* Clean fs. */
71: #define MINIX_ERROR_FS 0x0002 /* fs has errors. */
72:
73: #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
74: #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
75:
76: #define MINIX_V1 0x0001 /* original minix fs */
77: #define MINIX_V2 0x0002 /* minix V2 fs */
78:
79: /* originally this is :
80: #define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
81: here we have */
82: #define INODE_VERSION(inode) (SUPERBLOCK->s_version)
83:
84: /*
85: * This is the original minix inode layout on disk.
86: * Note the 8-bit gid and atime and ctime.
87: */
88: struct minix_inode {
89: __u16 i_mode;
90: __u16 i_uid;
91: __u32 i_size;
92: __u32 i_time;
93: __u8 i_gid;
94: __u8 i_nlinks;
95: __u16 i_zone[9];
96: };
97:
98: /*
99: * The new minix inode has all the time entries, as well as
100: * long block numbers and a third indirect block (7+1+1+1
101: * instead of 7+1+1). Also, some previously 8-bit values are
102: * now 16-bit. The inode is now 64 bytes instead of 32.
103: */
104: struct minix2_inode {
105: __u16 i_mode;
106: __u16 i_nlinks;
107: __u16 i_uid;
108: __u16 i_gid;
109: __u32 i_size;
110: __u32 i_atime;
111: __u32 i_mtime;
112: __u32 i_ctime;
113: __u32 i_zone[10];
114: };
115:
116: /*
117: * minix super-block data on disk
118: */
119: struct minix_super_block {
120: __u16 s_ninodes;
121: __u16 s_nzones;
122: __u16 s_imap_blocks;
123: __u16 s_zmap_blocks;
124: __u16 s_firstdatazone;
125: __u16 s_log_zone_size;
126: __u32 s_max_size;
127: __u16 s_magic;
128: __u16 s_state;
129: __u32 s_zones;
130: };
131:
132: struct minix_dir_entry {
133: __u16 inode;
134: char name[0];
135: };
136:
137: /* made up, these are pointers into FSYS_BUF */
138: /* read once, always stays there: */
139: #define SUPERBLOCK \
140: ((struct minix_super_block *)(FSYS_BUF))
141: #define INODE \
142: ((struct minix_inode *)((char *) SUPERBLOCK + BLOCK_SIZE))
143: #define DATABLOCK1 \
144: ((char *)((char *)INODE + sizeof(struct minix_inode)))
145: #define DATABLOCK2 \
146: ((char *)((char *)DATABLOCK1 + BLOCK_SIZE))
147:
148: /* linux/stat.h */
149: #define S_IFMT 00170000
150: #define S_IFLNK 0120000
151: #define S_IFREG 0100000
152: #define S_IFDIR 0040000
153: #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
154: #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
155: #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
156:
157: #define PATH_MAX 1024 /* include/linux/limits.h */
158: #define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
159:
160: /* check filesystem types and read superblock into memory buffer */
161: int
162: minix_mount (void)
163: {
164: if (((current_drive & 0x80) || current_slice != 0)
165: && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
166: && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
167: return 0; /* The partition is not of MINIX type */
168:
169: if (part_length < (SBLOCK +
170: (sizeof (struct minix_super_block) / DEV_BSIZE)))
171: return 0; /* The partition is too short */
172:
173: if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
174: (char *) SUPERBLOCK))
175: return 0; /* Cannot read superblock */
176:
177: switch (SUPERBLOCK->s_magic)
178: {
179: case MINIX_SUPER_MAGIC:
180: namelen = 14;
181: break;
182: case MINIX_SUPER_MAGIC2:
183: namelen = 30;
184: break;
185: default:
186: return 0; /* Unsupported type */
187: }
188:
189: return 1;
190: }
191:
192: /* Takes a file system block number and reads it into BUFFER. */
193: static int
194: minix_rdfsb (int fsblock, char *buffer)
195: {
196: return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
197: BLOCK_SIZE, buffer);
198: }
199:
200: /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
201: a physical block (the location in the file system) via an inode. */
202: static int
203: minix_block_map (int logical_block)
204: {
205: int i;
206:
207: if (logical_block < 7)
208: return INODE->i_zone[logical_block];
209:
210: logical_block -= 7;
211: if (logical_block < 512)
212: {
213: i = INODE->i_zone[7];
214:
215: if (!i || ((mapblock1 != 1)
216: && !minix_rdfsb (i, DATABLOCK1)))
217: {
218: errnum = ERR_FSYS_CORRUPT;
219: return -1;
220: }
221: mapblock1 = 1;
222: return ((__u16 *) DATABLOCK1) [logical_block];
223: }
224:
225: logical_block -= 512;
226: i = INODE->i_zone[8];
227: if (!i || ((mapblock1 != 2)
228: && !minix_rdfsb (i, DATABLOCK1)))
229: {
230: errnum = ERR_FSYS_CORRUPT;
231: return -1;
232: }
233: mapblock1 = 2;
234: i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
235: if (!i || ((mapblock2 != i)
236: && !minix_rdfsb (i, DATABLOCK2)))
237: {
238: errnum = ERR_FSYS_CORRUPT;
239: return -1;
240: }
241: mapblock2 = i;
242: return ((__u16 *) DATABLOCK2)[logical_block & 511];
243: }
244:
245: /* read from INODE into BUF */
246: int
247: minix_read (char *buf, int len)
248: {
249: int logical_block;
250: int offset;
251: int map;
252: int ret = 0;
253: int size = 0;
254:
255: while (len > 0)
256: {
257: /* find the (logical) block component of our location */
258: logical_block = filepos >> BLOCK_SIZE_BITS;
259: offset = filepos & (BLOCK_SIZE - 1);
260: map = minix_block_map (logical_block);
261: #ifdef DEBUG_MINIX
262: printf ("map=%d\n", map);
263: #endif
264: if (map < 0)
265: break;
266:
267: size = BLOCK_SIZE;
268: size -= offset;
269: if (size > len)
270: size = len;
271:
272: disk_read_func = disk_read_hook;
273:
274: devread (map * (BLOCK_SIZE / DEV_BSIZE),
275: offset, size, buf);
276:
277: disk_read_func = NULL;
278:
279: buf += size;
280: len -= size;
281: filepos += size;
282: ret += size;
283: }
284:
285: if (errnum)
286: ret = 0;
287:
288: return ret;
289: }
290:
291: /* preconditions: minix_mount already executed, therefore supblk in buffer
292: known as SUPERBLOCK
293: returns: 0 if error, nonzero iff we were able to find the file successfully
294: postconditions: on a nonzero return, buffer known as INODE contains the
295: inode of the file we were trying to look up
296: side effects: none yet */
297: int
298: minix_dir (char *dirname)
299: {
300: int current_ino = MINIX_ROOT_INO; /* start at the root */
301: int updir_ino = current_ino; /* the parent of the current directory */
302: int ino_blk; /* fs pointer of the inode's info */
303:
304: int str_chk = 0; /* used ot hold the results of a string
305: compare */
306:
307: struct minix_inode * raw_inode; /* inode info for current_ino */
308:
309: char linkbuf[PATH_MAX]; /* buffer for following sym-links */
310: int link_count = 0;
311:
312: char * rest;
313: char ch;
314:
315: int off; /* offset within block of directory
316: entry */
317: int loc; /* location within a directory */
318: int blk; /* which data blk within dir entry */
319: long map; /* fs pointer of a particular block from
320: dir entry */
321: struct minix_dir_entry * dp; /* pointer to directory entry */
322:
323: /* loop invariants:
324: current_ino = inode to lookup
325: dirname = pointer to filename component we are cur looking up within
326: the directory known pointed to by current_ino (if any) */
327:
328: #ifdef DEBUG_MINIX
329: printf ("\n");
330: #endif
331:
332: while (1)
333: {
334: #ifdef DEBUG_MINIX
335: printf ("inode %d, dirname %s\n", current_ino, dirname);
336: #endif
337:
338: ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
339: + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
340: if (! minix_rdfsb (ino_blk, (char *) INODE))
341: return 0;
342:
343: /* reset indirect blocks! */
344: mapblock2 = mapblock1 = -1;
345:
346: raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
347:
348: /* copy inode to fixed location */
349: memmove ((void *) INODE, (void *) raw_inode,
350: sizeof (struct minix_inode));
351:
352: /* If we've got a symbolic link, then chase it. */
353: if (S_ISLNK (INODE->i_mode))
354: {
355: int len;
356:
357: if (++link_count > MAX_LINK_COUNT)
358: {
359: errnum = ERR_SYMLINK_LOOP;
360: return 0;
361: }
362: #ifdef DEBUG_MINIX
363: printf ("S_ISLNK (%s)\n", dirname);
364: #endif
365:
366: /* Find out how long our remaining name is. */
367: len = 0;
368: while (dirname[len] && !isspace (dirname[len]))
369: len++;
370:
371: /* Get the symlink size. */
372: filemax = (INODE->i_size);
373: if (filemax + len > sizeof (linkbuf) - 2)
374: {
375: errnum = ERR_FILELENGTH;
376: return 0;
377: }
378:
379: if (len)
380: {
381: /* Copy the remaining name to the end of the symlink data.
382: Note that DIRNAME and LINKBUF may overlap! */
383: memmove (linkbuf + filemax, dirname, len);
384: }
385: linkbuf[filemax + len] = '\0';
386:
387: /* Read the necessary blocks, and reset the file pointer. */
388: len = grub_read (linkbuf, filemax);
389: filepos = 0;
390: if (!len)
391: return 0;
392:
393: #ifdef DEBUG_MINIX
394: printf ("symlink=%s\n", linkbuf);
395: #endif
396:
397: dirname = linkbuf;
398: if (*dirname == '/')
399: {
400: /* It's an absolute link, so look it up in root. */
401: current_ino = MINIX_ROOT_INO;
402: updir_ino = current_ino;
403: }
404: else
405: {
406: /* Relative, so look it up in our parent directory. */
407: current_ino = updir_ino;
408: }
409:
410: /* Try again using the new name. */
411: continue;
412: }
413:
414: /* If end of filename, INODE points to the file's inode */
415: if (!*dirname || isspace (*dirname))
416: {
417: if (!S_ISREG (INODE->i_mode))
418: {
419: errnum = ERR_BAD_FILETYPE;
420: return 0;
421: }
422:
423: filemax = (INODE->i_size);
424: return 1;
425: }
426:
427: /* else we have to traverse a directory */
428: updir_ino = current_ino;
429:
430: /* skip over slashes */
431: while (*dirname == '/')
432: dirname++;
433:
434: /* if this isn't a directory of sufficient size to hold our file,
435: abort */
436: if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
437: {
438: errnum = ERR_BAD_FILETYPE;
439: return 0;
440: }
441:
442: /* skip to next slash or end of filename (space) */
443: for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
444: rest++);
445:
446: /* look through this directory and find the next filename component */
447: /* invariant: rest points to slash after the next filename component */
448: *rest = 0;
449: loc = 0;
450:
451: do
452: {
453: #ifdef DEBUG_MINIX
454: printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
455: #endif
456:
457: /* if our location/byte offset into the directory exceeds the size,
458: give up */
459: if (loc >= INODE->i_size)
460: {
461: if (print_possibilities < 0)
462: {
463: #if 0
464: putchar ('\n');
465: #endif
466: }
467: else
468: {
469: errnum = ERR_FILE_NOT_FOUND;
470: *rest = ch;
471: }
472: return (print_possibilities < 0);
473: }
474:
475: /* else, find the (logical) block component of our location */
476: blk = loc >> BLOCK_SIZE_BITS;
477:
478: /* we know which logical block of the directory entry we are looking
479: for, now we have to translate that to the physical (fs) block on
480: the disk */
481: map = minix_block_map (blk);
482: #ifdef DEBUG_MINIX
483: printf ("fs block=%d\n", map);
484: #endif
485: mapblock2 = -1;
486: if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
487: {
488: errnum = ERR_FSYS_CORRUPT;
489: *rest = ch;
490: return 0;
491: }
492: off = loc & (BLOCK_SIZE - 1);
493: dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
494: /* advance loc prematurely to next on-disk directory entry */
495: loc += sizeof (dp->inode) + namelen;
496:
497: /* NOTE: minix filenames are NULL terminated if < NAMELEN
498: else exact */
499:
500: #ifdef DEBUG_MINIX
501: printf ("directory entry ino=%d\n", dp->inode);
502: if (dp->inode)
503: printf ("entry=%s\n", dp->name);
504: #endif
505:
506: if (dp->inode)
507: {
508: int saved_c = dp->name[namelen];
509:
510: dp->name[namelen] = 0;
511: str_chk = substring (dirname, dp->name);
512:
513: # ifndef STAGE1_5
514: if (print_possibilities && ch != '/'
515: && (!*dirname || str_chk <= 0))
516: {
517: if (print_possibilities > 0)
518: print_possibilities = -print_possibilities;
519: print_a_completion (dp->name);
520: }
521: # endif
522:
523: dp->name[namelen] = saved_c;
524: }
525:
526: }
527: while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
528:
529: current_ino = dp->inode;
530: *(dirname = rest) = ch;
531: }
532: /* never get here */
533: }
534:
535: #endif /* FSYS_MINIX */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.