ufs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1993 Carnegie Mellon University
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. /*
  27. * HISTORY
  28. * $Log: ufs.c,v $
  29. * Revision 1.1.1.2 2007/08/16 07:04:23 vorlon
  30. * Import upstream "release" 1.0pre20040408 to CVS to facilitate rebasing
  31. * against the current upstream work and avoid copying patches one-by-one.
  32. *
  33. * Revision 1.2 2003/11/08 00:03:36 wgwoods
  34. * Reverted changes from 0.10, merged doc changes
  35. *
  36. * Revision 1.1.1.1.2.1 2003/03/21 23:32:23 wgwoods
  37. * Warning cleanups
  38. *
  39. * Revision 1.1.1.1 2001/10/08 23:03:52 wgwoods
  40. * initial import of CVS source from alphalinux.org, plus a couple bugfixes
  41. *
  42. * Revision 1.1.1.1 2000/05/03 03:58:22 dhd
  43. * Initial import (from 0.7 release)
  44. *
  45. * Revision 2.2 93/02/05 08:01:36 danner
  46. * Adapted for alpha.
  47. * [93/02/04 af]
  48. *
  49. */
  50. /*
  51. * File: ufs.c
  52. * Author: David Golub, Carnegie Mellon University
  53. * Date: 12/90
  54. *
  55. * Stand-alone file reading package.
  56. *
  57. * Modified for use by Linux/Alpha by David Mosberger
  58. * (davidm@cs.arizona.edu)
  59. */
  60. #include <linux/kernel.h>
  61. #include <asm/stat.h>
  62. #include "aboot.h"
  63. #include "bootfs.h"
  64. #include "cons.h"
  65. #include "disklabel.h"
  66. #include "ufs.h"
  67. #include "utils.h"
  68. #include "string.h"
  69. #define MAX_OPEN_FILES 1
  70. extern struct bootfs ufs;
  71. static long dev;
  72. static long partition_offset;
  73. static struct fs *fs;
  74. static struct file {
  75. int inuse;
  76. struct icommon i_ic; /* copy of on-disk inode */
  77. int f_nindir[NIADDR+1];
  78. /* number of blocks mapped by
  79. indirect block at level i */
  80. void *f_blk[NIADDR]; /* buffer for indir block at level i */
  81. long f_blksize[NIADDR];
  82. /* size of buffer */
  83. __kernel_daddr_t f_blkno[NIADDR];
  84. /* disk address of block in buffer */
  85. void *f_buf; /* buffer for data block */
  86. long f_buf_size; /* size of data block */
  87. __kernel_daddr_t f_buf_blkno; /* block number of data block */
  88. } inode_table[MAX_OPEN_FILES];
  89. static int read_inode(__kernel_ino_t inumber, struct file *fp)
  90. {
  91. __kernel_daddr_t disk_block;
  92. long offset;
  93. struct dinode *dp;
  94. int level;
  95. disk_block = itod(fs, inumber);
  96. offset = fsbtodb(fs, disk_block) * DEV_BSIZE + partition_offset;
  97. if (cons_read(dev, fp->f_buf, fs->fs_bsize, offset) != fs->fs_bsize) {
  98. printf("ufs_read_inode: read error\n");
  99. return 1;
  100. }
  101. dp = (struct dinode *)fp->f_buf;
  102. dp += itoo(fs, inumber);
  103. fp->i_ic = dp->di_ic;
  104. /*
  105. * Clear out the old buffers
  106. */
  107. for (level = 0; level < NIADDR; level++) {
  108. if (fp->f_blk[level]) {
  109. free(fp->f_blk[level]);
  110. fp->f_blk[level] = 0;
  111. }
  112. fp->f_blkno[level] = -1;
  113. }
  114. return 0;
  115. }
  116. /*
  117. * Given an offset in a file, find the disk block number that
  118. * contains that block.
  119. */
  120. static __kernel_daddr_t block_map(struct file *fp, __kernel_daddr_t file_block)
  121. {
  122. __kernel_daddr_t ind_block_num, *ind_p;
  123. int level, idx;
  124. long offset;
  125. /*
  126. * Index structure of an inode:
  127. *
  128. * i_db[0..NDADDR-1] hold block numbers for blocks
  129. * 0..NDADDR-1
  130. *
  131. * i_ib[0] index block 0 is the single indirect
  132. * block
  133. * holds block numbers for blocks
  134. * NDADDR .. NDADDR + NINDIR(fs)-1
  135. *
  136. * i_ib[1] index block 1 is the double indirect
  137. * block
  138. * holds block numbers for INDEX blocks
  139. * for blocks
  140. * NDADDR + NINDIR(fs) ..
  141. * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
  142. *
  143. * i_ib[2] index block 2 is the triple indirect
  144. * block
  145. * holds block numbers for double-indirect
  146. * blocks for blocks
  147. * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
  148. * NDADDR + NINDIR(fs) + NINDIR(fs)**2
  149. * + NINDIR(fs)**3 - 1
  150. */
  151. if (file_block < NDADDR) {
  152. /* Direct block. */
  153. return fp->i_db[file_block];
  154. }
  155. file_block -= NDADDR;
  156. /*
  157. * nindir[0] = NINDIR
  158. * nindir[1] = NINDIR**2
  159. * nindir[2] = NINDIR**3
  160. * etc
  161. */
  162. for (level = 0; level < NIADDR; level++) {
  163. if (file_block < fp->f_nindir[level])
  164. break;
  165. file_block -= fp->f_nindir[level];
  166. }
  167. if (level == NIADDR) {
  168. printf("ufs_block_map: block number too high\n");
  169. return -1;
  170. }
  171. ind_block_num = fp->i_ib[level];
  172. for (; level >= 0; level--) {
  173. if (ind_block_num == 0) {
  174. return 0;
  175. }
  176. if (fp->f_blkno[level] != ind_block_num) {
  177. if (fp->f_blk[level]) {
  178. free(fp->f_blk[level]);
  179. }
  180. offset = fsbtodb(fs, ind_block_num) * DEV_BSIZE
  181. + partition_offset;
  182. fp->f_blk[level] = malloc(fs->fs_bsize);
  183. if (cons_read(dev, fp->f_blk[level], fs->fs_bsize,
  184. offset)
  185. != fs->fs_bsize)
  186. {
  187. printf("ufs_block_map: read error\n");
  188. return -1;
  189. }
  190. fp->f_blkno[level] = ind_block_num;
  191. }
  192. ind_p = (__kernel_daddr_t *)fp->f_blk[level];
  193. if (level > 0) {
  194. idx = file_block / fp->f_nindir[level-1];
  195. file_block %= fp->f_nindir[level-1];
  196. } else {
  197. idx = file_block;
  198. }
  199. ind_block_num = ind_p[idx];
  200. }
  201. return ind_block_num;
  202. }
  203. static int breadi(struct file *fp, long blkno, long nblks, char *buffer)
  204. {
  205. long block_size, offset, tot_bytes, nbytes, ncontig;
  206. __kernel_daddr_t disk_block;
  207. tot_bytes = 0;
  208. while (nblks) {
  209. /*
  210. * Contiguous reads are a lot faster, so we try to group
  211. * as many blocks as possible:
  212. */
  213. ncontig = 0; /* # of *fragments* that are contiguous */
  214. nbytes = 0;
  215. disk_block = block_map(fp, blkno);
  216. do {
  217. block_size = blksize(fs, fp, blkno);
  218. nbytes += block_size;
  219. ncontig += numfrags(fs, block_size);
  220. ++blkno; --nblks;
  221. } while (nblks &&
  222. block_map(fp, blkno) == disk_block + ncontig);
  223. if (!disk_block) {
  224. /* it's a hole... */
  225. memset(buffer, 0, nbytes);
  226. } else {
  227. offset = fsbtodb(fs, disk_block) * DEV_BSIZE
  228. + partition_offset;
  229. if (cons_read(dev, buffer, nbytes, offset) != nbytes) {
  230. printf("ufs_breadi: read error\n");
  231. return -1;
  232. }
  233. }
  234. buffer += nbytes;
  235. tot_bytes += nbytes;
  236. }
  237. return tot_bytes;
  238. }
  239. /*
  240. * Search a directory for a name and return its
  241. * i_number.
  242. */
  243. static int search_dir(const char *name, struct file *fp, __kernel_ino_t *inumber_p)
  244. {
  245. long offset, blockoffset;
  246. struct direct *dp;
  247. int len;
  248. len = strlen(name);
  249. offset = 0;
  250. while (offset < fp->i_size) {
  251. blockoffset = 0;
  252. if (breadi(fp, offset / fs->fs_bsize, 1, fp->f_buf) < 0) {
  253. return -1;
  254. }
  255. while (blockoffset < fs->fs_bsize) {
  256. dp = (struct direct *)((char*)fp->f_buf + blockoffset);
  257. if (dp->d_ino) {
  258. if (dp->d_namlen == len
  259. && strcmp(name, dp->d_name) == 0)
  260. {
  261. /* found entry */
  262. *inumber_p = dp->d_ino;
  263. return 0;
  264. }
  265. }
  266. blockoffset += dp->d_reclen;
  267. }
  268. offset += fs->fs_bsize;
  269. }
  270. return -1;
  271. }
  272. /*
  273. * Initialize a BSD FFS partition starting at offset P_OFFSET; this is
  274. * sort-of the same idea as "mounting" it. Read in the relevant
  275. * control structures and make them available to the user. Returns 0
  276. * if successful, -1 on failure.
  277. */
  278. static int ufs_mount(long cons_dev, long p_offset, long quiet)
  279. {
  280. static char buf[SBSIZE]; /* minimize frame size */
  281. long rc;
  282. memset(&inode_table, 0, sizeof(inode_table));
  283. dev = cons_dev;
  284. partition_offset = p_offset;
  285. rc = cons_read(dev, buf, SBSIZE, SBLOCK*DEV_BSIZE + partition_offset);
  286. if (rc != SBSIZE)
  287. {
  288. printf("ufs_mount: superblock read failed (retval=%ld)\n", rc);
  289. return -1;
  290. }
  291. fs = (struct fs *)buf;
  292. if (fs->fs_magic != FS_MAGIC ||
  293. fs->fs_bsize > MAXBSIZE ||
  294. fs->fs_bsize < (int) sizeof(struct fs))
  295. {
  296. if (!quiet) {
  297. printf("ufs_mount: invalid superblock "
  298. "(magic=%x, bsize=%d)\n",
  299. fs->fs_magic, fs->fs_bsize);
  300. }
  301. return -1;
  302. }
  303. ufs.blocksize = fs->fs_bsize;
  304. /* don't read cylinder groups - we aren't modifying anything */
  305. return 0;
  306. }
  307. static int ufs_open(const char *path)
  308. {
  309. char *cp = 0, *component;
  310. int fd;
  311. __kernel_ino_t inumber, parent_inumber;
  312. int nlinks = 0;
  313. struct file *fp;
  314. static char namebuf[MAXPATHLEN+1];
  315. if (!path || !*path) {
  316. return -1;
  317. }
  318. for (fd = 0; inode_table[fd].inuse; ++fd) {
  319. if (fd >= MAX_OPEN_FILES) {
  320. return -1;
  321. }
  322. }
  323. fp = &inode_table[fd];
  324. fp->f_buf_size = fs->fs_bsize;
  325. fp->f_buf = malloc(fp->f_buf_size);
  326. /* copy name into buffer to allow modifying it: */
  327. memcpy(namebuf, path, (unsigned)(strlen(path) + 1));
  328. inumber = (__kernel_ino_t) ROOTINO;
  329. if (read_inode(inumber, fp) < 0) {
  330. return -1;
  331. }
  332. component = strtok(namebuf, "/");
  333. while (component) {
  334. /* verify that current node is a directory: */
  335. if ((fp->i_mode & IFMT) != IFDIR) {
  336. return -1;
  337. }
  338. /*
  339. * Look up component in current directory.
  340. * Save directory inumber in case we find a
  341. * symbolic link.
  342. */
  343. parent_inumber = inumber;
  344. if (search_dir(component, fp, &inumber))
  345. return -1;
  346. /* open next component: */
  347. if (read_inode(inumber, fp))
  348. return -1;
  349. /* check for symbolic link: */
  350. if ((fp->i_mode & IFMT) == IFLNK) {
  351. int link_len = fp->i_size;
  352. int len;
  353. len = strlen(cp) + 1;
  354. if (link_len + len >= MAXPATHLEN - 1) {
  355. return -1;
  356. }
  357. if (++nlinks > MAXSYMLINKS) {
  358. return FS_SYMLINK_LOOP;
  359. }
  360. memcpy(&namebuf[link_len], cp, len);
  361. #ifdef IC_FASTLINK
  362. if ((fp->i_flags & IC_FASTLINK) != 0) {
  363. memcpy(namebuf, fp->i_symlink, link_len);
  364. } else
  365. #endif /* IC_FASTLINK */
  366. {
  367. /* read file for symbolic link: */
  368. long rc, offset;
  369. __kernel_daddr_t disk_block;
  370. disk_block = block_map(fp, (__kernel_daddr_t)0);
  371. offset = fsbtodb(fs, disk_block) * DEV_BSIZE
  372. + partition_offset;
  373. rc = cons_read(dev, namebuf, sizeof(namebuf),
  374. offset);
  375. if (rc != sizeof(namebuf)) {
  376. return -1;
  377. }
  378. }
  379. /*
  380. * If relative pathname, restart at parent directory.
  381. * If absolute pathname, restart at root.
  382. */
  383. cp = namebuf;
  384. if (*cp != '/') {
  385. inumber = parent_inumber;
  386. } else
  387. inumber = (__kernel_ino_t)ROOTINO;
  388. if (read_inode(inumber, fp))
  389. return -1;
  390. }
  391. component = strtok(NULL, "/");
  392. }
  393. /* calculate indirect block levels: */
  394. {
  395. register int mult;
  396. register int level;
  397. mult = 1;
  398. for (level = 0; level < NIADDR; level++) {
  399. mult *= NINDIR(fs);
  400. fp->f_nindir[level] = mult;
  401. }
  402. }
  403. return fd;
  404. }
  405. static int ufs_bread(int fd, long blkno, long nblks, char *buffer)
  406. {
  407. struct file *fp;
  408. fp = &inode_table[fd];
  409. return breadi(fp, blkno, nblks, buffer);
  410. }
  411. static void ufs_close(int fd)
  412. {
  413. inode_table[fd].inuse = 0;
  414. }
  415. static const char *
  416. ufs_readdir(int fd, int rewind)
  417. {
  418. return NULL;
  419. }
  420. static int
  421. ufs_fstat(int fd, struct stat* buf)
  422. {
  423. return -1;
  424. }
  425. struct bootfs ufs = {
  426. FS_BSDFFS, 0,
  427. ufs_mount,
  428. ufs_open, ufs_bread, ufs_close, ufs_readdir, ufs_fstat
  429. };