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

http://macfuse.googlecode.com/ · C · 599 lines · 457 code · 119 blank · 23 comment · 115 complexity · 02439c2f6d2a3d40dbcf37b11d99590b MD5 · raw file

  1. /*
  2. * Ancient UNIX File Systems for MacFUSE
  3. * Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ancientfs_2.9bsd.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.9BSD", 29bsd);
  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 filsys* fs = (struct filsys*)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 filsys) <= BSIZE);
  45. fs = malloc(BSIZE);
  46. if (!fs) {
  47. free(sb);
  48. err = ENOMEM;
  49. goto out;
  50. }
  51. if (pread(fd, fs, BSIZE, (off_t)BSIZE) != BSIZE) {
  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 = BSIZE;
  71. unixfs->s_statvfs.f_frsize = 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 = DIRSIZ + 2;
  109. unixfs->s_statvfs.f_namemax = DIRSIZ;
  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 filsys* fs = (struct filsys*)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 address from the inode
  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 filsys*)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)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_mode = fs16_to_host(unixfs->s_endian, dip->di_mode);
  278. ip->I_nlink = fs16_to_host(unixfs->s_endian, dip->di_nlink);
  279. ip->I_uid = fs16_to_host(unixfs->s_endian, dip->di_uid);
  280. ip->I_gid = fs16_to_host(unixfs->s_endian, dip->di_gid);
  281. ip->I_size = fs32_to_host(unixfs->s_endian, dip->di_size);
  282. ip->I_atime_sec = fs32_to_host(unixfs->s_endian, dip->di_atime);
  283. ip->I_mtime_sec = fs32_to_host(unixfs->s_endian, dip->di_mtime);
  284. ip->I_ctime_sec = fs32_to_host(unixfs->s_endian, dip->di_ctime);
  285. int i;
  286. char* p1 = (char*)(ip->I_daddr);
  287. char* p2 = (char*)(dip->di_addr);
  288. for (i = 0; i < NADDR; i++) {
  289. *p1++ = *p2++;
  290. *p1++ = 0;
  291. *p1++ = *p2++;
  292. *p1++ = *p2++;
  293. }
  294. for (i = 0; i < NADDR; i++)
  295. ip->I_daddr[i] = fs32_to_host(unixfs->s_endian, ip->I_daddr[i]);
  296. if (S_ISCHR(ip->I_mode) || S_ISBLK(ip->I_mode)) {
  297. uint32_t rdev = ip->I_daddr[0];
  298. ip->I_rdev = makedev((rdev >> 8) & 255, rdev & 255);
  299. }
  300. unixfs_inodelayer_isucceeded(ip);
  301. return ip;
  302. }
  303. static void
  304. unixfs_internal_iput(struct inode* ip)
  305. {
  306. unixfs_inodelayer_iput(ip);
  307. }
  308. static int
  309. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  310. {
  311. if (ino == MACFUSE_ROOTINO)
  312. ino = ROOTINO;
  313. struct inode* ip = unixfs_internal_iget(ino);
  314. if (!ip)
  315. return ENOENT;
  316. unixfs_internal_istat(ip, stbuf);
  317. unixfs_internal_iput(ip);
  318. return 0;
  319. }
  320. static void
  321. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  322. {
  323. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  324. }
  325. static int
  326. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  327. {
  328. if (parentino == MACFUSE_ROOTINO)
  329. parentino = ROOTINO;
  330. stbuf->st_ino = 0;
  331. struct inode* dp = unixfs_internal_iget(parentino);
  332. if (!dp)
  333. return ENOENT;
  334. if (!S_ISDIR(dp->I_mode)) {
  335. unixfs_internal_iput(dp);
  336. return ENOTDIR;
  337. }
  338. int ret = ENOENT, eo = 0, count = dp->I_size / unixfs->s_dentsize;
  339. a_int offset = 0;
  340. char ubuf[UNIXFS_IOSIZE(unixfs)];
  341. struct dent udent;
  342. eloop:
  343. if (count == 0) {
  344. ret = ENOENT;
  345. goto out;
  346. }
  347. if ((offset & BMASK) == 0) {
  348. off_t blkno = unixfs_internal_bmap(dp, (off_t)(offset/BSIZE), &ret);
  349. if (UNIXFS_BADBLOCK(blkno, ret))
  350. goto out;
  351. if (unixfs_internal_bread(blkno, ubuf) != 0)
  352. goto out;
  353. }
  354. memset(&udent, 0, sizeof(udent));
  355. memcpy(&udent, ubuf + (offset & BMASK), unixfs->s_dentsize);
  356. udent.u_ino = fs16_to_host(unixfs->s_endian, udent.u_ino);
  357. offset += unixfs->s_dentsize;
  358. count--;
  359. if (udent.u_ino == 0) {
  360. if (eo == 0)
  361. eo = offset;
  362. goto eloop;
  363. }
  364. if (strncmp(name, udent.u_name, DIRSIZ) != 0)
  365. goto eloop;
  366. /* matched */
  367. ret = unixfs_internal_igetattr((ino_t)(udent.u_ino), stbuf);
  368. out:
  369. unixfs_internal_iput(dp);
  370. return ret;
  371. }
  372. static int
  373. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  374. off_t* offset, struct unixfs_direntry* dent)
  375. {
  376. if ((*offset + unixfs->s_dentsize) > dp->I_size)
  377. return -1;
  378. if (!dirbuf->flags.initialized || ((*offset & BMASK) == 0)) {
  379. int ret;
  380. off_t blkno = unixfs_internal_bmap(dp, (off_t)(*offset / BSIZE), &ret);
  381. if (UNIXFS_BADBLOCK(blkno, ret))
  382. return ret;
  383. ret = unixfs_internal_bread(blkno, dirbuf->data);
  384. if (ret != 0)
  385. return ret;
  386. dirbuf->flags.initialized = 1;
  387. }
  388. struct dent udent;
  389. size_t dirnamelen = min(DIRSIZ, UNIXFS_MAXNAMLEN);
  390. memset(&udent, 0, sizeof(udent));
  391. memcpy(&udent, dirbuf->data + (*offset & BMASK), unixfs->s_dentsize);
  392. udent.u_ino = fs16_to_host(unixfs->s_endian, udent.u_ino);
  393. dent->ino = udent.u_ino;
  394. memcpy(dent->name, udent.u_name, dirnamelen);
  395. dent->name[dirnamelen] = '\0';
  396. *offset += unixfs->s_dentsize;
  397. return 0;
  398. }
  399. static ssize_t
  400. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  401. int* error)
  402. {
  403. ssize_t done = 0;
  404. size_t tomove = 0;
  405. ssize_t remaining = nbyte;
  406. ssize_t iosize = UNIXFS_IOSIZE(unixfs);
  407. char blkbuf[iosize];
  408. char* p = buf;
  409. while (remaining > 0) {
  410. off_t lbn = offset / BSIZE;
  411. off_t bn = unixfs_internal_bmap(ip, lbn, error);
  412. if (UNIXFS_BADBLOCK(bn, *error))
  413. break;
  414. *error = unixfs_internal_bread(bn, blkbuf);
  415. if (*error != 0)
  416. break;
  417. tomove = (remaining > iosize) ? iosize : remaining;
  418. memcpy(p, blkbuf, tomove);
  419. remaining -= tomove;
  420. done += tomove;
  421. offset += tomove;
  422. p += tomove;
  423. }
  424. if ((done == 0) && *error)
  425. return -1;
  426. return done;
  427. }
  428. static int
  429. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  430. {
  431. return ENOSYS;
  432. }
  433. static int
  434. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  435. {
  436. struct filsys* fs = (struct filsys*)filsys;
  437. if ((off_t)(fs->s_fsize * BSIZE) > disksize) {
  438. fprintf(stderr, "*** disk image seems smaller than the volume\n");
  439. return -1;
  440. }
  441. if (fs->s_nfree > NICFREE) {
  442. fprintf(stderr, "*** warning: implausible s_nfree %hu\n", fs->s_nfree);
  443. return -1;
  444. }
  445. if (fs->s_ninode > NICINOD) {
  446. fprintf(stderr,
  447. "*** warning: implausible s_ninode %hu\n", fs->s_ninode);
  448. return -1;
  449. }
  450. if (fs->s_time == 0) {
  451. fprintf(stderr, "*** warning: implausible timestamp of 0\n");
  452. return -1;
  453. }
  454. struct stat stbuf;
  455. int ret = unixfs_internal_igetattr((ino_t)ROOTINO, &stbuf);
  456. if (ret) {
  457. fprintf(stderr, "*** warning: failed to get root inode\n");
  458. return -1;
  459. }
  460. if (!S_ISDIR(stbuf.st_mode)) {
  461. fprintf(stderr, "*** warning: root inode is not a directory\n");
  462. return -1;
  463. }
  464. if (stbuf.st_size == 0) {
  465. fprintf(stderr, "*** warning: root inode has zero size\n");
  466. return -1;
  467. }
  468. if (stbuf.st_size % (off_t)sizeof(struct dent)) {
  469. fprintf(stderr, "*** warning: root inode's size (%llu) is suspicious\n",
  470. stbuf.st_size);
  471. return -1;
  472. }
  473. return 0;
  474. }
  475. static int
  476. unixfs_internal_statvfs(struct statvfs* svb)
  477. {
  478. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  479. return 0;
  480. }