/filesystems/unixfs/ancientfs/ancientfs_dtp.c

http://macfuse.googlecode.com/ · C · 515 lines · 415 code · 87 blank · 13 comment · 86 complexity · 1feb032bec07b3ae11d7cb49c35bd455 MD5 · raw file

  1. /*
  2. * Ancient UNIX File Systems for MacFUSE
  3. * Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ancientfs_dtp.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("UNIX dtp", dtp);
  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, j;
  27. struct stat stbuf;
  28. struct super_block* sb = (struct super_block*)0;
  29. struct filsys* fs = (struct filsys*)0;
  30. uint32_t tapedir_begin_block = 0, tapedir_end_block = 0, last_block = 0;
  31. if ((err = fstat(fd, &stbuf)) != 0) {
  32. perror("fstat");
  33. goto out;
  34. }
  35. if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
  36. err = EINVAL;
  37. fprintf(stderr, "%s is not a tape image file\n", dmg);
  38. goto out;
  39. }
  40. if (flags & ANCIENTFS_DECTAPE) {
  41. tapedir_begin_block = 0;
  42. tapedir_end_block = TAPEDIR_END_BLOCK_DEC;
  43. } else if (flags & ANCIENTFS_MAGTAPE) {
  44. tapedir_begin_block = 0;
  45. tapedir_end_block = TAPEDIR_END_BLOCK_MAG;
  46. } else if (flags & ANCIENTFS_GENTAPE) {
  47. tapedir_begin_block = 0;
  48. tapedir_end_block = TAPEDIR_END_BLOCK_GENERIC;
  49. } else {
  50. err = EINVAL;
  51. fprintf(stderr, "unrecognized tape type\n");
  52. goto out;
  53. }
  54. if (S_ISREG(stbuf.st_mode))
  55. last_block = stbuf.st_size / BSIZE;
  56. else
  57. last_block = tapedir_end_block;
  58. sb = malloc(sizeof(struct super_block));
  59. if (!sb) {
  60. err = ENOMEM;
  61. goto out;
  62. }
  63. assert(sizeof(struct filsys) <= BSIZE);
  64. fs = calloc(1, BSIZE);
  65. if (!fs) {
  66. free(sb);
  67. err = ENOMEM;
  68. goto out;
  69. }
  70. unixfs = sb;
  71. unixfs->s_flags = flags;
  72. unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_PDP : fse;
  73. unixfs->s_fs_info = (void*)fs;
  74. unixfs->s_bdev = fd;
  75. /* must initialize the inode layer before sanity checking */
  76. if ((err = unixfs_inodelayer_init(sizeof(struct tap_node_info))) != 0)
  77. goto out;
  78. struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO);
  79. if (!rootip) {
  80. fprintf(stderr, "*** fatal error: no root inode\n");
  81. abort();
  82. }
  83. rootip->I_mode = S_IFDIR | 0755;
  84. rootip->I_uid = getuid();
  85. rootip->I_gid = getgid();
  86. rootip->I_size = 2;
  87. rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0);
  88. struct tap_node_info* rootti = (struct tap_node_info*)rootip->I_private;
  89. rootti->ti_self = rootip;
  90. rootti->ti_name[0] = '\0';
  91. rootti->ti_parent = NULL;
  92. rootti->ti_children = NULL;
  93. rootti->ti_next_sibling = NULL;
  94. unixfs_inodelayer_isucceeded(rootip);
  95. fs->s_fsize = stbuf.st_size / BSIZE;
  96. fs->s_files = 0;
  97. fs->s_directories = 1 + 1 + 1;
  98. fs->s_rootip = rootip;
  99. fs->s_lastino = ROOTINO;
  100. char tapeblock[BSIZE];
  101. for (i = tapedir_begin_block; i < tapedir_end_block; i++) {
  102. if (pread(fd, tapeblock, BSIZE, (off_t)(i * BSIZE)) != BSIZE) {
  103. fprintf(stderr, "*** fatal error: cannot read tape block %llu\n",
  104. (off_t)i);
  105. err = EIO;
  106. goto out;
  107. }
  108. struct dinode_dtp* di = (struct dinode_dtp*)tapeblock;
  109. int inopb = INOPB;
  110. if (i == 0) { /* special case block 0 */
  111. uint8_t* doff = (uint8_t*)tapeblock;
  112. fs->s_dataoffset = 64 * (256 * doff[6] + doff[7]);
  113. di = (struct dinode_dtp*)((char*)tapeblock + 128);
  114. inopb--;
  115. } else if ((i * BSIZE) >= fs->s_dataoffset) {
  116. i = tapedir_end_block;
  117. j = inopb;
  118. break;
  119. }
  120. for (j = 0; j < inopb; j++, di++) {
  121. /* no checksum? */
  122. if (!di->di_path[0]) {
  123. if (flags & ANCIENTFS_GENTAPE) {
  124. i = tapedir_end_block;
  125. j = inopb;
  126. }
  127. continue;
  128. }
  129. ino_t parent_ino = ROOTINO;
  130. char* path = (char*)di->di_path;
  131. size_t pathlen = strlen(path);
  132. if ((*path == '.') && ((pathlen == 1) ||
  133. ((pathlen == 2) && (*(path + 1) == '/')))) {
  134. /* root */
  135. rootip->I_mode = fs16_to_host(unixfs->s_endian, di->di_mode);
  136. rootip->I_atime_sec = \
  137. rootip->I_mtime_sec = \
  138. rootip->I_ctime_sec = \
  139. fs32_to_host(unixfs->s_endian, di->di_mtime);
  140. continue;
  141. }
  142. /* we don't deal with many fancy paths here: just '/' and './' */
  143. if (*path == '/')
  144. path++;
  145. else if (*path == '.' && *(path + 1) == '/')
  146. path += 2;
  147. char *cnp, *term;
  148. for (cnp = strtok_r(path, "/", &term); cnp;
  149. cnp = strtok_r(NULL, "/", &term)) {
  150. /* we have { parent_ino, cnp } */
  151. struct stat stbuf;
  152. int missing = unixfs_internal_namei(parent_ino, cnp, &stbuf);
  153. if (!missing) {
  154. parent_ino = stbuf.st_ino;
  155. continue;
  156. }
  157. struct inode* ip =
  158. unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1));
  159. if (!ip) {
  160. fprintf(stderr, "*** fatal error: no inode for %llu\n",
  161. (ino64_t)(fs->s_lastino + 1));
  162. abort();
  163. }
  164. ip->I_mode = fs16_to_host(unixfs->s_endian, di->di_mode);
  165. ip->I_uid = di->di_uid;
  166. ip->I_gid = di->di_gid;
  167. ip->I_size = di->di_size0 << 16 |
  168. fs16_to_host(unixfs->s_endian, di->di_size1);
  169. ip->I_daddr[0] = (uint32_t)fs16_to_host(unixfs->s_endian,
  170. di->di_addr);
  171. ip->I_nlink = 1;
  172. ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec =
  173. fs32_to_host(unixfs->s_endian, di->di_mtime);
  174. struct tap_node_info* ti = (struct tap_node_info*)ip->I_private;
  175. memcpy(ti->ti_name, cnp, strlen(cnp));
  176. ti->ti_self = ip;
  177. ti->ti_children = NULL;
  178. /* this should work out as long as we have no corruption */
  179. struct inode* parent_ip = unixfs_internal_iget(parent_ino);
  180. parent_ip->I_size += 1;
  181. ti->ti_parent = (struct tap_node_info*)(parent_ip->I_private);
  182. ti->ti_next_sibling = ti->ti_parent->ti_children;
  183. ti->ti_parent->ti_children = ti;
  184. if (S_ISDIR(ancientfs_dtp_mode(ip->I_mode, flags))) {
  185. fs->s_directories++;
  186. parent_ino = fs->s_lastino + 1;
  187. ip->I_size = 2;
  188. ip->I_daddr[0] = 0;
  189. } else
  190. fs->s_files++;
  191. fs->s_lastino++;
  192. unixfs_internal_iput(parent_ip);
  193. unixfs_inodelayer_isucceeded(ip);
  194. /* no put */
  195. }
  196. }
  197. }
  198. unixfs->s_statvfs.f_bsize = BSIZE;
  199. unixfs->s_statvfs.f_frsize = BSIZE;
  200. unixfs->s_statvfs.f_ffree = 0;
  201. unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories;
  202. unixfs->s_statvfs.f_blocks = fs->s_fsize;
  203. unixfs->s_statvfs.f_bfree = 0;
  204. unixfs->s_statvfs.f_bavail = 0;
  205. unixfs->s_dentsize = 1;
  206. unixfs->s_statvfs.f_namemax = DIRSIZ;
  207. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "UNIX dtp");
  208. char* dmg_basename = basename((char*)dmg);
  209. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (tape=%s)",
  210. unixfs_fstype, (dmg_basename) ? dmg_basename : "Tape Image");
  211. *fsname = unixfs->s_fsname;
  212. *volname = unixfs->s_volname;
  213. out:
  214. if (err) {
  215. if (fd >= 0)
  216. close(fd);
  217. if (fs)
  218. free(fs);
  219. if (sb)
  220. free(sb);
  221. return NULL;
  222. }
  223. return sb;
  224. }
  225. static void
  226. unixfs_internal_fini(void* filsys)
  227. {
  228. struct super_block* sb = (struct super_block*)filsys;
  229. struct filsys* fs = (struct filsys*)sb->s_fs_info;
  230. ino_t i = fs->s_lastino;
  231. for (; i >= ROOTINO; i--) {
  232. struct inode* tmp = unixfs_internal_iget(i);
  233. if (tmp) {
  234. unixfs_internal_iput(tmp);
  235. unixfs_internal_iput(tmp);
  236. }
  237. }
  238. unixfs_inodelayer_fini();
  239. if (sb) {
  240. if (sb->s_bdev >= 0)
  241. close(sb->s_bdev);
  242. sb->s_bdev = -1;
  243. if (sb->s_fs_info)
  244. free(sb->s_fs_info);
  245. }
  246. }
  247. static off_t
  248. unixfs_internal_alloc(void)
  249. {
  250. return (off_t)0;
  251. }
  252. static off_t
  253. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  254. {
  255. off_t nblocks = (off_t)((ip->I_size + (BSIZE - 1)) / BSIZE);
  256. if (lblkno >= nblocks) {
  257. *error = EFBIG;
  258. return (off_t)0;
  259. }
  260. return (off_t)(ip->I_daddr[0] + lblkno +
  261. (((struct filsys*)unixfs->s_fs_info)->s_dataoffset / BSIZE));
  262. }
  263. static int
  264. unixfs_internal_bread(off_t blkno, char* blkbuf)
  265. {
  266. if (blkno >= ((struct filsys*)unixfs->s_fs_info)->s_fsize) {
  267. fprintf(stderr,
  268. "***fatal error: bread failed for block %llu\n", blkno);
  269. abort();
  270. /* NOTREACHED */
  271. }
  272. if (pread(unixfs->s_bdev, blkbuf, UNIXFS_IOSIZE(unixfs),
  273. blkno * (off_t)BSIZE) != UNIXFS_IOSIZE(unixfs))
  274. return EIO;
  275. return 0;
  276. }
  277. static struct inode*
  278. unixfs_internal_iget(ino_t ino)
  279. {
  280. struct inode* ip = unixfs_inodelayer_iget(ino);
  281. if (!ip) {
  282. fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)ino);
  283. abort();
  284. }
  285. if (ip->I_initialized)
  286. return ip;
  287. unixfs_inodelayer_ifailed(ip);
  288. return NULL;
  289. }
  290. static void
  291. unixfs_internal_iput(struct inode* ip)
  292. {
  293. unixfs_inodelayer_iput(ip);
  294. }
  295. static int
  296. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  297. {
  298. struct inode* ip = unixfs_internal_iget(ino);
  299. if (!ip)
  300. return ENOENT;
  301. unixfs_internal_istat(ip, stbuf);
  302. unixfs_internal_iput(ip);
  303. return 0;
  304. }
  305. static void
  306. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  307. {
  308. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  309. stbuf->st_mode = ancientfs_dtp_mode(ip->I_mode, unixfs->s_flags);
  310. }
  311. static int
  312. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  313. {
  314. int ret = ENOENT;
  315. stbuf->st_ino = 0;
  316. size_t namelen = strlen(name);
  317. if (namelen > DIRSIZ)
  318. return ENAMETOOLONG;
  319. struct inode* dp = unixfs_internal_iget(parentino);
  320. if (!dp)
  321. return ENOENT;
  322. if (!S_ISDIR(ancientfs_dtp_mode(dp->I_mode, unixfs->s_flags))) {
  323. ret = ENOTDIR;
  324. goto out;
  325. }
  326. struct tap_node_info* child =
  327. ((struct tap_node_info*)dp->I_private)->ti_children;;
  328. if (!child) {
  329. ret = ENOENT;
  330. goto out;
  331. }
  332. int found = 0;
  333. do {
  334. size_t target_namelen = strlen((const char*)child->ti_name);
  335. if ((namelen == target_namelen) &&
  336. (memcmp(name, child->ti_name, target_namelen) == 0)) {
  337. found = 1;
  338. break;
  339. }
  340. child = child->ti_next_sibling;
  341. } while (child);
  342. if (found)
  343. ret = unixfs_internal_igetattr((ino_t)child->ti_self->I_ino, stbuf);
  344. out:
  345. unixfs_internal_iput(dp);
  346. return ret;
  347. }
  348. static int
  349. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  350. off_t* offset, struct unixfs_direntry* dent)
  351. {
  352. if (*offset >= dp->I_size)
  353. return -1;
  354. if (*offset < 2) {
  355. int idx = 0;
  356. dent->name[idx++] = '.';
  357. dent->ino = ROOTINO;
  358. if (*offset == 1) {
  359. if (dp->I_ino != ROOTINO) {
  360. struct inode* pdp = unixfs_internal_iget(dp->I_ino);
  361. if (pdp) {
  362. dent->ino = pdp->I_ino;
  363. unixfs_internal_iput(pdp);
  364. }
  365. }
  366. dent->name[idx++] = '.';
  367. }
  368. dent->name[idx++] = '\0';
  369. goto out;
  370. }
  371. struct tap_node_info* child =
  372. ((struct tap_node_info*)dp->I_private)->ti_children;;
  373. off_t i;
  374. for (i = 0; i < (*offset - 2); i++)
  375. child = child->ti_next_sibling;
  376. dent->ino = (ino_t)child->ti_self->I_ino;
  377. size_t dirnamelen = min(DIRSIZ, UNIXFS_MAXNAMLEN);
  378. memcpy(dent->name, child->ti_name, dirnamelen);
  379. dent->name[dirnamelen] = '\0';
  380. out:
  381. *offset += 1;
  382. return 0;
  383. }
  384. static ssize_t
  385. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  386. int* error)
  387. {
  388. ssize_t done = 0;
  389. size_t tomove = 0;
  390. ssize_t remaining = nbyte;
  391. ssize_t iosize = UNIXFS_IOSIZE(unixfs);
  392. char blkbuf[iosize];
  393. char* p = buf;
  394. while (remaining > 0) {
  395. off_t lbn = offset / BSIZE;
  396. off_t bn = unixfs_internal_bmap(ip, lbn, error);
  397. if (UNIXFS_BADBLOCK(bn, *error))
  398. break;
  399. *error = unixfs_internal_bread(bn, blkbuf);
  400. if (*error != 0)
  401. break;
  402. tomove = (remaining > iosize) ? iosize : remaining;
  403. memcpy(p, blkbuf, tomove);
  404. remaining -= tomove;
  405. done += tomove;
  406. offset += tomove;
  407. p += tomove;
  408. }
  409. if ((done == 0) && *error)
  410. return -1;
  411. return done;
  412. }
  413. static int
  414. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  415. {
  416. return ENOSYS;
  417. }
  418. static int
  419. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  420. {
  421. return 0;
  422. }
  423. static int
  424. unixfs_internal_statvfs(struct statvfs* svb)
  425. {
  426. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  427. return 0;
  428. }