/filesystems/unixfs/ancientfs/ancientfs_v7.c

http://macfuse.googlecode.com/ · C · 601 lines · 461 code · 117 blank · 23 comment · 117 complexity · de91655a2e40ad4fc21296a2b7fa8147 MD5 · raw file

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