/filesystems/unixfs/ancientfs/ancientfs_2.11bsd.c

http://macfuse.googlecode.com/ · C · 664 lines · 509 code · 130 blank · 25 comment · 122 complexity · e0e2eb9945c4406ba59eede63b2054a2 MD5 · raw file

  1. /*
  2. * Ancient UNIX File Systems for MacFUSE
  3. * Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ancientfs_2.11bsd.h"
  7. #include "unixfs_common.h"
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/stat.h>
  16. DECL_UNIXFS("2.11BSD", 211bsd);
  17. static void*
  18. unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse,
  19. char** fsname, char** volname)
  20. {
  21. int fd = -1;
  22. if ((fd = open(dmg, O_RDONLY)) < 0) {
  23. perror("open");
  24. return NULL;
  25. }
  26. int err, i;
  27. struct stat stbuf;
  28. struct super_block* sb = (struct super_block*)0;
  29. struct fs* fs = (struct fs*)0;
  30. if ((err = fstat(fd, &stbuf)) != 0) {
  31. perror("fstat");
  32. goto out;
  33. }
  34. if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
  35. err = EINVAL;
  36. fprintf(stderr, "%s is not a disk image file\n", dmg);
  37. goto out;
  38. }
  39. sb = malloc(sizeof(struct super_block));
  40. if (!sb) {
  41. err = ENOMEM;
  42. goto out;
  43. }
  44. assert(sizeof(struct fs) <= DEV_BSIZE);
  45. fs = malloc(DEV_BSIZE);
  46. if (!fs) {
  47. free(sb);
  48. err = ENOMEM;
  49. goto out;
  50. }
  51. if (pread(fd, fs, SBSIZE, (off_t)(DEV_BSIZE * SUPERB)) != SBSIZE) {
  52. perror("pread");
  53. err = EIO;
  54. goto out;
  55. }
  56. unixfs = sb;
  57. unixfs->s_flags = flags;
  58. unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_PDP : fse;
  59. unixfs->s_fs_info = (void*)fs;
  60. unixfs->s_bdev = fd;
  61. fs->s_isize = fs16_to_host(unixfs->s_endian, fs->s_isize);
  62. fs->s_fsize = fs32_to_host(unixfs->s_endian, fs->s_fsize);
  63. fs->s_nfree = fs16_to_host(unixfs->s_endian, fs->s_nfree);
  64. for (i = 0; i < NICFREE; i++)
  65. fs->s_free[i] = fs32_to_host(unixfs->s_endian, fs->s_free[i]);
  66. fs->s_ninode = fs16_to_host(unixfs->s_endian, fs->s_ninode);
  67. for (i = 0; i < NICINOD; i++)
  68. fs->s_inode[i] = fs16_to_host(unixfs->s_endian, fs->s_inode[i]);
  69. fs->s_time = fs32_to_host(unixfs->s_endian, fs->s_time);
  70. unixfs->s_statvfs.f_bsize = DEV_BSIZE;
  71. unixfs->s_statvfs.f_frsize = DEV_BSIZE;
  72. /* must initialize the inode layer before sanity checking */
  73. if ((err = unixfs_inodelayer_init(0)) != 0)
  74. goto out;
  75. if (unixfs_internal_sanitycheck(fs, stbuf.st_size) != 0) {
  76. if (!(flags & UNIXFS_FORCE)) {
  77. fprintf(stderr,
  78. "retry with the --force option to see if it will work anyway\n");
  79. err = EINVAL;
  80. goto out;
  81. }
  82. }
  83. int iblock;
  84. unixfs->s_statvfs.f_files = 0;
  85. unixfs->s_statvfs.f_ffree = 0;
  86. char* ubuf = malloc(UNIXFS_IOSIZE(unixfs));
  87. if (!ubuf) {
  88. err = ENOMEM;
  89. goto out;
  90. }
  91. for (iblock = 2; iblock < fs->s_isize; iblock++) {
  92. if (unixfs_internal_bread((off_t)iblock, ubuf) != 0)
  93. continue;
  94. struct dinode* dip = (struct dinode*)ubuf;
  95. for (i = 0; i < INOPB; i++, dip++) {
  96. if (fs16_to_host(unixfs->s_endian, dip->di_nlink) == 0)
  97. unixfs->s_statvfs.f_ffree++;
  98. else
  99. unixfs->s_statvfs.f_files++;
  100. }
  101. }
  102. free(ubuf);
  103. unixfs->s_statvfs.f_blocks = fs->s_fsize;
  104. unixfs->s_statvfs.f_bfree = 0;
  105. while (unixfs_internal_alloc())
  106. unixfs->s_statvfs.f_bfree++;
  107. unixfs->s_statvfs.f_bavail = unixfs->s_statvfs.f_bfree;
  108. unixfs->s_dentsize = 0; /* no fixed size */
  109. unixfs->s_statvfs.f_namemax = MAXNAMLEN;
  110. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s", unixfs_fstype);
  111. char* dmg_basename = basename((char*)dmg);
  112. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (disk=%s)",
  113. unixfs_fstype, (dmg_basename) ? dmg_basename : "Disk Image");
  114. *fsname = unixfs->s_fsname;
  115. *volname = unixfs->s_volname;
  116. out:
  117. if (err) {
  118. if (fd >= 0)
  119. close(fd);
  120. if (fs)
  121. free(fs);
  122. if (sb)
  123. free(sb);
  124. return NULL;
  125. }
  126. return sb;
  127. }
  128. static void
  129. unixfs_internal_fini(void* filsys)
  130. {
  131. unixfs_inodelayer_fini();
  132. struct super_block* sb = (struct super_block*)filsys;
  133. if (sb) {
  134. if (sb->s_bdev >= 0)
  135. close(sb->s_bdev);
  136. sb->s_bdev = -1;
  137. if (sb->s_fs_info)
  138. free(sb->s_fs_info);
  139. }
  140. }
  141. static off_t
  142. unixfs_internal_alloc(void)
  143. {
  144. struct fs* fs = (struct fs*)unixfs->s_fs_info;
  145. a_int i = --fs->s_nfree;
  146. if (i < 0)
  147. goto nospace;
  148. if (i > NICFREE) /* bad free count */
  149. return (off_t)0;
  150. a_daddr_t bno = fs->s_free[i];
  151. if (bno == 0)
  152. return (off_t)0;
  153. if (bno < fs->s_isize || bno >= fs->s_fsize)
  154. return (off_t)0; /* bad free block <bno> */
  155. if (fs->s_nfree <= 0) {
  156. char ubuf[UNIXFS_IOSIZE(unixfs)];
  157. int ret = unixfs_internal_bread((off_t)bno, ubuf);
  158. if (ret == 0) {
  159. struct fblk* fblk = (struct fblk*)ubuf;
  160. fs->s_nfree = fs16_to_host(unixfs->s_endian, fblk->df_nfree);
  161. for (i = 0; i < NICFREE; i++)
  162. fs->s_free[i] = fs32_to_host(unixfs->s_endian, fblk->df_free[i]);
  163. } else
  164. return (off_t)0;
  165. }
  166. return (off_t)bno;
  167. nospace:
  168. fs->s_nfree = 0;
  169. return (off_t)0; /* ENOSPC */
  170. }
  171. static off_t
  172. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  173. {
  174. a_daddr_t bn = (a_daddr_t)lblkno;
  175. if (bn < 0) {
  176. *error = EFBIG;
  177. return (off_t)0;
  178. }
  179. *error = EROFS;
  180. /*
  181. * blocks 0..NADDR-4 are direct blocks
  182. */
  183. int i;
  184. a_daddr_t nb;
  185. if (bn < (NADDR - 3)) {
  186. i = bn;
  187. nb = ip->I_daddr[i];
  188. if (nb == 0)
  189. return (off_t)0; /* !writable; should be -1 rather */
  190. *error = 0;
  191. return (off_t)nb;
  192. }
  193. /*
  194. * addresses NADDR - 3, NADDR - 2, and NADDR - 1 have single, double,
  195. * and triple indirect blocks. the first step is to determine how many
  196. * levels of indirection.
  197. */
  198. int j, sh = 0;
  199. nb = 1;
  200. bn -= NADDR - 3;
  201. for (j = 3; j > 0; j--) {
  202. sh += NSHIFT;
  203. nb <<= NSHIFT;
  204. if (bn < nb)
  205. break;
  206. bn -= nb;
  207. }
  208. if (j == 0) {
  209. *error = EFBIG;
  210. return (off_t)0;
  211. }
  212. /*
  213. * fetch the first indirect block
  214. */
  215. nb = ip->I_daddr[NADDR - j];
  216. if (nb == 0)
  217. return (off_t)0; /* !writable; should be -1 rather */
  218. /*
  219. * fetch through the indirect blocks
  220. */
  221. for (; j <= 3; j++) {
  222. char ubuf[UNIXFS_IOSIZE(unixfs)];
  223. int ret = unixfs_internal_bread((off_t)nb, ubuf);
  224. if (ret) {
  225. *error = ret;
  226. return (off_t)0;
  227. }
  228. a_daddr_t* bap = (a_daddr_t*)ubuf;
  229. sh -= NSHIFT;
  230. i = (bn >> sh) & NMASK;
  231. nb = fs32_to_host(unixfs->s_endian, bap[i]);
  232. if (nb == 0)
  233. return (off_t)0; /* !writable; should be -1 rather */
  234. }
  235. /* calculate read-ahead here. */
  236. *error = 0;
  237. return (off_t)nb;
  238. }
  239. static int
  240. unixfs_internal_bread(off_t blkno, char* blkbuf)
  241. {
  242. if (blkno >= ((struct fs*)unixfs->s_fs_info)->s_fsize) {
  243. fprintf(stderr,
  244. "***fatal error: bread failed for block %llu\n", blkno);
  245. abort();
  246. /* NOTREACHED */
  247. }
  248. if (blkno == 0) { /* zero fill */
  249. memset(blkbuf, 0, UNIXFS_IOSIZE(unixfs));
  250. return 0;
  251. }
  252. if (pread(unixfs->s_bdev, blkbuf, UNIXFS_IOSIZE(unixfs),
  253. blkno * (off_t)DEV_BSIZE) != UNIXFS_IOSIZE(unixfs))
  254. return EIO;
  255. return 0;
  256. }
  257. static struct inode*
  258. unixfs_internal_iget(ino_t ino)
  259. {
  260. if (ino == MACFUSE_ROOTINO)
  261. ino = ROOTINO;
  262. struct inode* ip = unixfs_inodelayer_iget(ino);
  263. if (!ip) {
  264. fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)ino);
  265. abort();
  266. }
  267. if (ip->I_initialized)
  268. return ip;
  269. char ubuf[UNIXFS_IOSIZE(unixfs)];
  270. if (unixfs_internal_bread((off_t)itod((a_ino_t)ino), ubuf) != 0) {
  271. unixfs_inodelayer_ifailed(ip);
  272. return NULL;
  273. }
  274. struct dinode* dip = (struct dinode*)ubuf;
  275. dip += itoo((a_ino_t)ino);
  276. ip->I_number = ino;
  277. /* ip->I_ic1 = dip->di_ic1 */
  278. ip->I_mode = fs16_to_host(unixfs->s_endian, dip->di_mode);
  279. ip->I_nlink = fs16_to_host(unixfs->s_endian, dip->di_nlink);
  280. ip->I_uid = fs16_to_host(unixfs->s_endian, dip->di_uid);
  281. ip->I_gid = fs16_to_host(unixfs->s_endian, dip->di_gid);
  282. ip->I_size = fs32_to_host(unixfs->s_endian, dip->di_size);
  283. #ifndef EXTERNALTIMES
  284. /* ip->I_ic2 = dip->di_ic2 */
  285. ip->I_atime_sec = fs32_to_host(unixfs->s_endian, dip->di_atime);
  286. ip->I_mtime_sec = fs32_to_host(unixfs->s_endian, dip->di_mtime);
  287. ip->I_ctime_sec = fs32_to_host(unixfs->s_endian, dip->di_ctime);
  288. #endif
  289. int i;
  290. for (i = 0; i < NADDR; i++)
  291. ip->I_daddr[i] = fs32_to_host(unixfs->s_endian, dip->di_addr[i]);
  292. if (S_ISCHR(ip->I_mode) || S_ISBLK(ip->I_mode)) {
  293. uint32_t rdev = ip->I_daddr[0];
  294. ip->I_rdev = makedev((rdev >> 8) & 255, rdev & 255);
  295. }
  296. unixfs_inodelayer_isucceeded(ip);
  297. return ip;
  298. }
  299. static void
  300. unixfs_internal_iput(struct inode* ip)
  301. {
  302. unixfs_inodelayer_iput(ip);
  303. }
  304. static int
  305. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  306. {
  307. if (ino == MACFUSE_ROOTINO)
  308. ino = ROOTINO;
  309. struct inode* ip = unixfs_internal_iget(ino);
  310. if (!ip)
  311. return ENOENT;
  312. unixfs_internal_istat(ip, stbuf);
  313. unixfs_internal_iput(ip);
  314. return 0;
  315. }
  316. static void
  317. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  318. {
  319. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  320. }
  321. #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
  322. static int
  323. __unixfs_internal_blkatoff(struct inode* ip, off_t offset, char* ubuf)
  324. {
  325. int error;
  326. off_t lbn = lblkno(offset);
  327. off_t bn = unixfs_internal_bmap(ip, lbn, &error);
  328. if (bn == 0)
  329. return error;
  330. return unixfs_internal_bread(bn, ubuf);
  331. }
  332. static int
  333. __unixfs_internal_dirbadentry(struct direct* ep, int entryoffsetinblock)
  334. {
  335. int i;
  336. if ((ep->d_reclen & 0x3) != 0 ||
  337. ep->d_reclen > ANCIENTFS_211BSD_DIRBLKSIZ - \
  338. (entryoffsetinblock & (ANCIENTFS_211BSD_DIRBLKSIZ - 1)) ||
  339. ep->d_reclen < ANCIENTFS_211BSD_DIRSIZ(ep) ||
  340. ep->d_namlen > UNIXFS_MAXNAMLEN)
  341. return 1;
  342. for (i = 0; i < ep->d_namlen; i++)
  343. if (ep->d_name[i] == '\0')
  344. return 1;
  345. return ep->d_name[i];
  346. }
  347. static int
  348. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  349. {
  350. if (parentino == MACFUSE_ROOTINO)
  351. parentino = ROOTINO;
  352. stbuf->st_ino = 0;
  353. struct inode* dp = unixfs_internal_iget(parentino);
  354. if (!dp)
  355. return ENOENT;
  356. if (!S_ISDIR(dp->I_mode)) {
  357. unixfs_internal_iput(dp);
  358. return ENOTDIR;
  359. }
  360. int ret = ENOENT, i, found = 0;
  361. off_t ni_offset = 0, entryoffsetinblock = 0;
  362. int endsearch = roundup(dp->I_size, ANCIENTFS_211BSD_DIRBLKSIZ);
  363. struct direct* ep;
  364. char ubuf[UNIXFS_IOSIZE(unixfs)];
  365. size_t namlen = strlen(name);
  366. while (ni_offset < endsearch) {
  367. if (blkoff(ni_offset) == 0) {
  368. ret = __unixfs_internal_blkatoff(dp, ni_offset, ubuf);
  369. if (ret) {
  370. ret = ENOENT;
  371. goto out;
  372. }
  373. entryoffsetinblock = 0;
  374. }
  375. ep = (struct direct*)((char*)ubuf + entryoffsetinblock);
  376. ep->d_ino = fs16_to_host(unixfs->s_endian, ep->d_ino);
  377. ep->d_reclen = fs16_to_host(unixfs->s_endian, ep->d_reclen);
  378. ep->d_namlen = fs16_to_host(unixfs->s_endian, ep->d_namlen);
  379. if (ep->d_reclen == 0 ||
  380. __unixfs_internal_dirbadentry(ep, entryoffsetinblock)) {
  381. i = ANCIENTFS_211BSD_DIRBLKSIZ -
  382. (entryoffsetinblock & (ANCIENTFS_211BSD_DIRBLKSIZ - 1));
  383. ni_offset += i;
  384. entryoffsetinblock += i;
  385. continue;
  386. }
  387. if (ep->d_ino) {
  388. if ((namlen == ep->d_namlen) &&
  389. bcmp(name, ep->d_name, ep->d_namlen) == 0) {
  390. found = 1;
  391. break;
  392. }
  393. }
  394. ni_offset += ep->d_reclen;
  395. entryoffsetinblock += ep->d_reclen;
  396. } /* while */
  397. out:
  398. unixfs_internal_iput(dp);
  399. if (found) /* matched */
  400. ret = unixfs_internal_igetattr((ino_t)(ep->d_ino), stbuf);
  401. return ret;
  402. }
  403. static int
  404. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  405. off_t* offset, struct unixfs_direntry* dent)
  406. {
  407. struct direct* ep;
  408. off_t ni_offset = *offset;
  409. off_t entryoffsetinblock = blkoff(ni_offset);
  410. int endsearch = roundup(dp->I_size, ANCIENTFS_211BSD_DIRBLKSIZ);
  411. if (ni_offset >= endsearch)
  412. return -1;
  413. if (!dirbuf->flags.initialized || (blkoff(ni_offset) == 0)) {
  414. int ret = __unixfs_internal_blkatoff(dp, ni_offset, dirbuf->data);
  415. if (ret)
  416. return ret;
  417. entryoffsetinblock = 0;
  418. dirbuf->flags.initialized = 1;
  419. }
  420. ep = (struct direct*)((char*)dirbuf->data + entryoffsetinblock);
  421. ep->d_ino = fs16_to_host(unixfs->s_endian, ep->d_ino);
  422. ep->d_reclen = fs16_to_host(unixfs->s_endian, ep->d_reclen);
  423. ep->d_namlen = fs16_to_host(unixfs->s_endian, ep->d_namlen);
  424. if (ep->d_reclen == 0 ||
  425. __unixfs_internal_dirbadentry(ep, entryoffsetinblock)) {
  426. int i =
  427. ANCIENTFS_211BSD_DIRBLKSIZ - (entryoffsetinblock &
  428. (ANCIENTFS_211BSD_DIRBLKSIZ - 1));
  429. ni_offset += i;
  430. entryoffsetinblock += i;
  431. dent->ino = 0;
  432. } else {
  433. dent->ino = (ino_t)ep->d_ino;
  434. memcpy(dent->name, ep->d_name, ep->d_namlen);
  435. dent->name[ep->d_namlen] = '\0';
  436. ni_offset += ep->d_reclen;
  437. entryoffsetinblock += ep->d_reclen;
  438. }
  439. *offset = ni_offset;
  440. return 0;
  441. }
  442. static ssize_t
  443. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  444. int* error)
  445. {
  446. ssize_t done = 0;
  447. size_t tomove = 0;
  448. ssize_t remaining = nbyte;
  449. ssize_t iosize = UNIXFS_IOSIZE(unixfs);
  450. char blkbuf[iosize];
  451. char* p = buf;
  452. while (remaining > 0) {
  453. off_t lbn = offset / DEV_BSIZE;
  454. off_t bn = unixfs_internal_bmap(ip, lbn, error);
  455. if (UNIXFS_BADBLOCK(bn, *error))
  456. break;
  457. *error = unixfs_internal_bread(bn, blkbuf);
  458. if (*error != 0)
  459. break;
  460. tomove = (remaining > iosize) ? iosize : remaining;
  461. memcpy(p, blkbuf, tomove);
  462. remaining -= tomove;
  463. done += tomove;
  464. offset += tomove;
  465. p += tomove;
  466. }
  467. if ((done == 0) && *error)
  468. return -1;
  469. return done;
  470. }
  471. static int
  472. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  473. {
  474. struct inode* ip = unixfs_internal_iget(ino);
  475. if (!ip)
  476. return ENOENT;
  477. int error;
  478. off_t bn = unixfs_internal_bmap(ip, (off_t)0, &error);
  479. if (UNIXFS_BADBLOCK(bn, error))
  480. goto out;
  481. /* we know MAXPATHLEN (256) < DEV_BSIZE (1024) == UNIXFS_MAXPATHLEN */
  482. error = unixfs_internal_bread(bn, path);
  483. if (error)
  484. goto out;
  485. size_t linklen = (ip->I_size > DEV_BSIZE - 1) ? DEV_BSIZE - 1: ip->I_size;
  486. path[linklen] = '\0';
  487. error = 0;
  488. out:
  489. unixfs_internal_iput(ip);
  490. return error;
  491. }
  492. static int
  493. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  494. {
  495. struct fs* fs = (struct fs*)filsys;
  496. if ((off_t)(fs->s_fsize * DEV_BSIZE) > disksize) {
  497. fprintf(stderr, "*** disk image seems smaller than the volume\n");
  498. return -1;
  499. }
  500. if (fs->s_nfree > NICFREE) {
  501. fprintf(stderr, "*** warning: implausible s_nfree %hu\n", fs->s_nfree);
  502. return -1;
  503. }
  504. if (fs->s_ninode > NICINOD) {
  505. fprintf(stderr,
  506. "*** warning: implausible s_ninode %hu\n", fs->s_ninode);
  507. return -1;
  508. }
  509. if (fs->s_time == 0) {
  510. fprintf(stderr, "*** warning: implausible timestamp of 0\n");
  511. return -1;
  512. }
  513. struct stat stbuf;
  514. int ret = unixfs_internal_igetattr((ino_t)ROOTINO, &stbuf);
  515. if (ret) {
  516. fprintf(stderr, "*** warning: failed to get root inode\n");
  517. return -1;
  518. }
  519. if (!S_ISDIR(stbuf.st_mode)) {
  520. fprintf(stderr, "*** warning: root inode is not a directory\n");
  521. return -1;
  522. }
  523. if (stbuf.st_size == 0) {
  524. fprintf(stderr, "*** warning: root inode has zero size\n");
  525. return -1;
  526. }
  527. return 0;
  528. }
  529. static int
  530. unixfs_internal_statvfs(struct statvfs* svb)
  531. {
  532. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  533. return 0;
  534. }