/filesystems/unixfs/ancientfs/ancientfs_bcpio.c

http://macfuse.googlecode.com/ · C · 668 lines · 524 code · 126 blank · 18 comment · 117 complexity · 0044d1f50c208e08f0569b4599c34e91 MD5 · raw file

  1. /*
  2. * Ancient UNIX File Systems for MacFUSE
  3. * Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ancientfs_bcpio.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 bcpio", bcpio);
  17. struct bcpio_entry {
  18. char name[UNIXFS_MAXPATHLEN + 1];
  19. char linktargetname[UNIXFS_MAXPATHLEN + 1];
  20. off_t daddr;
  21. struct stat stat;
  22. };
  23. static int ancientfs_bcpio_readheader(int fd, struct bcpio_entry* ce);
  24. static int
  25. ancientfs_bcpio_readheader(int fd, struct bcpio_entry* ce)
  26. {
  27. int nr;
  28. struct bcpio_header _hdr, *hdr = &_hdr;
  29. nr = read(fd, hdr, sizeof(struct bcpio_header));
  30. if (nr != sizeof(struct bcpio_header)) {
  31. if (!nr)
  32. return 1;
  33. if (nr < 0)
  34. return -1;
  35. }
  36. if (fs16_to_host(unixfs->s_endian, hdr->h_magic) != BCPIO_MAGIC) {
  37. fprintf(stderr, "*** fatal error: bad magic in record @ %llu\n",
  38. lseek(fd, (off_t)0, SEEK_CUR));
  39. return -1;
  40. }
  41. memset(ce, 0, sizeof(*ce));
  42. /* nothing to do with h_dev */
  43. ce->stat.st_ino = fs16_to_host(unixfs->s_endian, hdr->h_ino);
  44. ce->stat.st_mode =
  45. ancientfs_bcpio_mode(fs16_to_host(unixfs->s_endian, hdr->h_mode),
  46. unixfs->s_flags);
  47. ce->stat.st_uid = fs16_to_host(unixfs->s_endian, hdr->h_uid);
  48. ce->stat.st_gid = fs16_to_host(unixfs->s_endian, hdr->h_gid);
  49. ce->stat.st_nlink = fs16_to_host(unixfs->s_endian, hdr->h_nlink);
  50. uint16_t rdev = fs16_to_host(unixfs->s_endian, hdr->h_majmin);
  51. ce->stat.st_rdev = makedev((rdev >> 8) & 255, rdev & 255);
  52. int16_t tmsb16 = fs16_to_host(unixfs->s_endian, hdr->h_mtime_msb16);
  53. int16_t tlsb16 = fs16_to_host(unixfs->s_endian, hdr->h_mtime_lsb16);
  54. ce->stat.st_atime = ce->stat.st_ctime = ce->stat.st_mtime =
  55. (int32_t)(tmsb16 << 16 | (tlsb16 & 0xFFFF));
  56. uint16_t szmsb16 = fs16_to_host(unixfs->s_endian, hdr->h_filesize_msb16);
  57. uint16_t szlsb16 = fs16_to_host(unixfs->s_endian, hdr->h_filesize_lsb16);
  58. ce->stat.st_size = (uint32_t)(szmsb16 << 16 | (szlsb16 & 0xFFFF));
  59. uint16_t namesize = fs16_to_host(unixfs->s_endian, hdr->h_namesize);
  60. if (namesize < 2) {
  61. fprintf(stderr, "*** fatal error: file name too small\n");
  62. return -1;
  63. }
  64. if (namesize > UNIXFS_MAXPATHLEN) {
  65. fprintf(stderr, "*** fatal error: file name too large (%#hx) @ %llu\n",
  66. namesize, lseek(fd, (off_t)0, SEEK_CUR));
  67. return -1;
  68. }
  69. if (read(fd, &ce->name, namesize) != namesize)
  70. return -1;
  71. if (ce->name[0] == '\0' || ce->name[namesize - 1] != '\0') { /* corrupt */
  72. fprintf(stderr, "*** fatal error: file name corrupt @ %llu\n",
  73. lseek(fd, (off_t)0, SEEK_CUR));
  74. return -1;
  75. }
  76. /* header + namesize aligned to 2-byte boundary */
  77. ce->daddr = lseek(fd, (off_t)0, SEEK_CUR);
  78. if (ce->daddr < 0) {
  79. fprintf(stderr, "*** fatal error: cannot read archive\n");
  80. return -1;
  81. }
  82. if (ce->daddr & (off_t)1) {
  83. ce->daddr++;
  84. (void)lseek(fd, (off_t)1, SEEK_CUR);
  85. }
  86. /* ce->daddr now contains the start of data */
  87. if (!ce->stat.st_size && (namesize == BCPIO_TRAILER_LEN) &&
  88. !memcmp(ce->name, BCPIO_TRAILER, BCPIO_TRAILER_LEN))
  89. return 1;
  90. if (!S_ISLNK(ce->stat.st_mode) || !ce->stat.st_size) {
  91. off_t dataend = ce->stat.st_size;
  92. dataend += (dataend & 1) ? 1 : 0;
  93. (void)lseek(fd, dataend, SEEK_CUR);
  94. return 0;
  95. }
  96. /* link */
  97. if (ce->stat.st_size < 2) {
  98. fprintf(stderr, "*** fatal error: link target name too small\n");
  99. return -1;
  100. }
  101. if (ce->stat.st_size > UNIXFS_MAXPATHLEN) {
  102. fprintf(stderr, "*** fatal error: link target name too large\n");
  103. return -1;
  104. }
  105. if (read(fd, ce->linktargetname, ce->stat.st_size) != ce->stat.st_size)
  106. return -1;
  107. if (ce->linktargetname[0] == '\0') {
  108. fprintf(stderr, "*** fatal error: link target name corrupt\n");
  109. return -1;
  110. }
  111. ce->linktargetname[ce->stat.st_size] = '\0';
  112. if ((ce->daddr + ce->stat.st_size) & 1)
  113. (void)lseek(fd, (off_t)1, SEEK_CUR);
  114. return 0;
  115. }
  116. static void*
  117. unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse,
  118. char** fsname, char** volname)
  119. {
  120. int fd = -1;
  121. if ((fd = open(dmg, O_RDONLY)) < 0) {
  122. perror("open");
  123. return NULL;
  124. }
  125. int err;
  126. fs_endian_t mye, e = UNIXFS_FS_INVALID;
  127. struct stat stbuf;
  128. struct super_block* sb = (struct super_block*)0;
  129. struct filsys* fs = (struct filsys*)0;
  130. if ((err = fstat(fd, &stbuf)) != 0) {
  131. perror("fstat");
  132. goto out;
  133. }
  134. if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
  135. err = EINVAL;
  136. fprintf(stderr, "%s is not a bcpio image file\n", dmg);
  137. goto out;
  138. }
  139. struct bcpio_header hdr;
  140. if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
  141. fprintf(stderr, "failed to read data from file\n");
  142. err = EIO;
  143. goto out;
  144. }
  145. #ifdef __LITTLE_ENDIAN__
  146. mye = UNIXFS_FS_LITTLE;
  147. e = UNIXFS_FS_BIG;
  148. #else
  149. #ifdef __BIG_ENDIAN__
  150. mye = UNIXFS_FS_BIG;
  151. e = UNIXFS_FS_LITTLE;
  152. #else
  153. #error Endian Problem
  154. #endif
  155. #endif
  156. uint16_t magic = hdr.h_magic;
  157. if (magic == BCPIO_MAGIC) {
  158. e = mye;
  159. } else if (fs16_to_host(e, magic) == BCPIO_MAGIC) {
  160. /* needs swap */
  161. } else {
  162. e = UNIXFS_FS_INVALID;
  163. }
  164. if (e == UNIXFS_FS_INVALID) {
  165. fprintf(stderr, "not recognized as a bcpio archive\n");
  166. err = EINVAL;
  167. goto out;
  168. }
  169. sb = malloc(sizeof(struct super_block));
  170. if (!sb) {
  171. err = ENOMEM;
  172. goto out;
  173. }
  174. assert(sizeof(struct filsys) <= BCBLOCK);
  175. fs = calloc(1, BCBLOCK);
  176. if (!fs) {
  177. free(sb);
  178. err = ENOMEM;
  179. goto out;
  180. }
  181. unixfs = sb;
  182. unixfs->s_flags = flags;
  183. unixfs->s_endian = e;
  184. if (e != mye)
  185. fs->s_needsswap = 1;
  186. unixfs->s_fs_info = (void*)fs;
  187. unixfs->s_bdev = fd;
  188. /* must initialize the inode layer before sanity checking */
  189. if ((err = unixfs_inodelayer_init(sizeof(struct bcpio_node_info))) != 0)
  190. goto out;
  191. struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO);
  192. if (!rootip) {
  193. fprintf(stderr, "*** fatal error: no root inode\n");
  194. abort();
  195. }
  196. rootip->I_mode = S_IFDIR | 0755;
  197. rootip->I_uid = getuid();
  198. rootip->I_gid = getgid();
  199. rootip->I_size = 2;
  200. rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0);
  201. struct bcpio_node_info* rootci = (struct bcpio_node_info*)rootip->I_private;
  202. rootci->ci_self = rootip;
  203. rootci->ci_parent = NULL;
  204. rootci->ci_children = NULL;
  205. rootci->ci_next_sibling = NULL;
  206. unixfs_inodelayer_isucceeded(rootip);
  207. fs->s_fsize = stbuf.st_size / BCBLOCK;
  208. fs->s_files = 0;
  209. fs->s_directories = 1 + 1 + 1;
  210. fs->s_rootip = rootip;
  211. fs->s_lastino = ROOTINO;
  212. lseek(fd, (off_t)0, SEEK_SET); /* rewind archive */
  213. struct bcpio_entry _ce, *ce = &_ce;
  214. for (;;) {
  215. if ((err = ancientfs_bcpio_readheader(fd, ce)) != 0) {
  216. if (err == 1)
  217. break;
  218. else {
  219. fprintf(stderr,
  220. "*** fatal error: cannot read block (error %d)\n", err);
  221. err = EIO;
  222. goto out;
  223. }
  224. }
  225. char* path = ce->name;
  226. ino_t parent_ino = ROOTINO;
  227. size_t pathlen = strlen(ce->name);
  228. if ((*path == '.') && ((pathlen == 1) ||
  229. ((pathlen == 2) && (*(path + 1) == '/')))) {
  230. /* root */
  231. rootip->I_mode = ce->stat.st_mode;
  232. rootip->I_atime_sec = \
  233. rootip->I_mtime_sec = \
  234. rootip->I_ctime_sec = ce->stat.st_mtime;
  235. continue;
  236. }
  237. /* we don't deal with many fancy paths here: just '/' and './' */
  238. if (*path == '/')
  239. path++;
  240. else if (*path == '.' && *(path + 1) == '/')
  241. path += 2;
  242. char *cnp, *term;
  243. for (cnp = strtok_r(path, "/", &term); cnp;
  244. cnp = strtok_r(NULL, "/", &term)) {
  245. /* we have { parent_ino, cnp } */
  246. struct stat stbuf;
  247. int missing = unixfs_internal_namei(parent_ino, cnp, &stbuf);
  248. if (!missing) {
  249. parent_ino = stbuf.st_ino;
  250. if (!term) { /* out of order */
  251. struct inode* dirp = unixfs_inodelayer_iget(parent_ino);
  252. if (!dirp || !dirp->I_initialized) {
  253. fprintf(stderr,
  254. "*** fatal error: inode %llu inconsistent\n",
  255. (ino64_t)parent_ino);
  256. abort();
  257. }
  258. dirp->I_mode = ce->stat.st_mode;
  259. dirp->I_uid = ce->stat.st_uid;
  260. dirp->I_gid = ce->stat.st_gid;
  261. unixfs_inodelayer_iput(dirp);
  262. }
  263. continue;
  264. }
  265. struct inode* ip =
  266. unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1));
  267. if (!ip) {
  268. fprintf(stderr, "*** fatal error: no inode for %llu\n",
  269. (ino64_t)(fs->s_lastino + 1));
  270. abort();
  271. }
  272. ip->I_mode = ce->stat.st_mode;
  273. ip->I_uid = ce->stat.st_uid;
  274. ip->I_gid = ce->stat.st_gid;
  275. ip->I_size = ce->stat.st_size;
  276. ip->I_nlink = ce->stat.st_nlink;
  277. ip->I_rdev = ce->stat.st_rdev;
  278. ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec =
  279. ce->stat.st_mtime;
  280. struct bcpio_node_info* ci = (struct bcpio_node_info*)ip->I_private;
  281. size_t namelen = strlen(cnp);
  282. ci->ci_name = malloc(namelen + 1);
  283. if (!ci->ci_name) {
  284. fprintf(stderr, "*** fatal error: cannot allocate memory\n");
  285. abort();
  286. }
  287. memcpy(ci->ci_name, cnp, namelen);
  288. ci->ci_name[namelen] = '\0';
  289. ip->I_daddr[0] = 0;
  290. if (S_ISLNK(ip->I_mode)) {
  291. namelen = strlen(ce->linktargetname);
  292. ci->ci_linktargetname = malloc(namelen + 1);
  293. if (!ci->ci_name) {
  294. fprintf(stderr,
  295. "*** fatal error: cannot allocate memory\n");
  296. abort();
  297. }
  298. memcpy(ci->ci_linktargetname, ce->linktargetname, namelen);
  299. ci->ci_linktargetname[namelen] = '\0';
  300. } else if (S_ISREG(ip->I_mode)) {
  301. ip->I_daddr[0] = ce->daddr;
  302. }
  303. ci->ci_self = ip;
  304. ci->ci_children = NULL;
  305. struct inode* parent_ip = unixfs_internal_iget(parent_ino);
  306. parent_ip->I_size += 1;
  307. ci->ci_parent = (struct bcpio_node_info*)(parent_ip->I_private);
  308. ci->ci_next_sibling = ci->ci_parent->ci_children;
  309. ci->ci_parent->ci_children = ci;
  310. if (term && !S_ISDIR(ip->I_mode)) /* out of order */
  311. ip->I_mode = S_IFDIR | 0755;
  312. if (S_ISDIR(ip->I_mode)) {
  313. fs->s_directories++;
  314. parent_ino = fs->s_lastino + 1;
  315. ip->I_size = 2;
  316. } else
  317. fs->s_files++;
  318. fs->s_lastino++;
  319. //if (ip->I_ino > fs->s_lastino)
  320. //fs->s_lastino = ip->I_ino;
  321. unixfs_internal_iput(parent_ip);
  322. unixfs_inodelayer_isucceeded(ip);
  323. /* no put */
  324. } /* for each component */
  325. } /* for each block */
  326. err = 0;
  327. unixfs->s_statvfs.f_bsize = BCBLOCK;
  328. unixfs->s_statvfs.f_frsize = BCBLOCK;
  329. unixfs->s_statvfs.f_ffree = 0;
  330. unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories;
  331. unixfs->s_statvfs.f_blocks = fs->s_fsize;
  332. unixfs->s_statvfs.f_bfree = 0;
  333. unixfs->s_statvfs.f_bavail = 0;
  334. unixfs->s_dentsize = 1;
  335. unixfs->s_statvfs.f_namemax = UNIXFS_MAXNAMLEN;
  336. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "Old (binary) bcpio");
  337. char* dmg_basename = basename((char*)dmg);
  338. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (archive=%s)",
  339. unixfs_fstype, (dmg_basename) ? dmg_basename : "bcpio Image");
  340. *fsname = unixfs->s_fsname;
  341. *volname = unixfs->s_volname;
  342. out:
  343. if (err) {
  344. if (fd >= 0)
  345. close(fd);
  346. if (fs)
  347. free(fs);
  348. if (sb)
  349. free(sb);
  350. return NULL;
  351. }
  352. return sb;
  353. }
  354. static void
  355. unixfs_internal_fini(void* filsys)
  356. {
  357. struct super_block* sb = (struct super_block*)filsys;
  358. struct filsys* fs = (struct filsys*)sb->s_fs_info;
  359. ino_t i = fs->s_lastino;
  360. for (; i >= ROOTINO; i--) {
  361. struct inode* tmp = unixfs_internal_iget(i);
  362. if (tmp) {
  363. struct bcpio_node_info* ci = (struct bcpio_node_info*)tmp->I_private;
  364. if (ci) {
  365. free(ci->ci_name);
  366. if (ci->ci_linktargetname)
  367. free(ci->ci_linktargetname);
  368. }
  369. unixfs_internal_iput(tmp);
  370. unixfs_internal_iput(tmp);
  371. }
  372. }
  373. unixfs_inodelayer_fini();
  374. if (sb) {
  375. if (sb->s_bdev >= 0)
  376. close(sb->s_bdev);
  377. sb->s_bdev = -1;
  378. if (sb->s_fs_info)
  379. free(sb->s_fs_info);
  380. }
  381. }
  382. static off_t
  383. unixfs_internal_alloc(void)
  384. {
  385. return (off_t)0;
  386. }
  387. static off_t
  388. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  389. {
  390. return (off_t)0;
  391. }
  392. static int
  393. unixfs_internal_bread(off_t blkno, char* blkbuf)
  394. {
  395. return EIO;
  396. }
  397. static struct inode*
  398. unixfs_internal_iget(ino_t ino)
  399. {
  400. struct inode* ip = unixfs_inodelayer_iget(ino);
  401. if (!ip) {
  402. fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)ino);
  403. abort();
  404. }
  405. if (ip->I_initialized)
  406. return ip;
  407. unixfs_inodelayer_ifailed(ip);
  408. return NULL;
  409. }
  410. static void
  411. unixfs_internal_iput(struct inode* ip)
  412. {
  413. unixfs_inodelayer_iput(ip);
  414. }
  415. static int
  416. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  417. {
  418. struct inode* ip = unixfs_internal_iget(ino);
  419. if (!ip)
  420. return ENOENT;
  421. unixfs_internal_istat(ip, stbuf);
  422. unixfs_internal_iput(ip);
  423. return 0;
  424. }
  425. static void
  426. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  427. {
  428. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  429. }
  430. static int
  431. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  432. {
  433. int ret = ENOENT;
  434. stbuf->st_ino = 0;
  435. size_t namelen = strlen(name);
  436. if (namelen > UNIXFS_MAXNAMLEN)
  437. return ENAMETOOLONG;
  438. struct inode* dp = unixfs_internal_iget(parentino);
  439. if (!dp)
  440. return ENOENT;
  441. if (!S_ISDIR(dp->I_mode)) {
  442. ret = ENOTDIR;
  443. goto out;
  444. }
  445. struct bcpio_node_info* child =
  446. ((struct bcpio_node_info*)dp->I_private)->ci_children;;
  447. if (!child) {
  448. ret = ENOENT;
  449. goto out;
  450. }
  451. int found = 0;
  452. do {
  453. size_t target_namelen = strlen((const char*)child->ci_name);
  454. if ((namelen == target_namelen) &&
  455. (memcmp(name, child->ci_name, target_namelen) == 0)) {
  456. found = 1;
  457. break;
  458. }
  459. child = child->ci_next_sibling;
  460. } while (child);
  461. if (found)
  462. ret = unixfs_internal_igetattr((ino_t)child->ci_self->I_ino, stbuf);
  463. out:
  464. unixfs_internal_iput(dp);
  465. return ret;
  466. }
  467. static int
  468. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  469. off_t* offset, struct unixfs_direntry* dent)
  470. {
  471. if (*offset >= dp->I_size)
  472. return -1;
  473. if (*offset < 2) {
  474. int idx = 0;
  475. dent->name[idx++] = '.';
  476. dent->ino = ROOTINO;
  477. if (*offset == 1) {
  478. if (dp->I_ino != ROOTINO) {
  479. struct inode* pdp = unixfs_internal_iget(dp->I_ino);
  480. if (pdp) {
  481. dent->ino = pdp->I_ino;
  482. unixfs_internal_iput(pdp);
  483. }
  484. }
  485. dent->name[idx++] = '.';
  486. }
  487. dent->name[idx++] = '\0';
  488. goto out;
  489. }
  490. struct bcpio_node_info* child =
  491. ((struct bcpio_node_info*)dp->I_private)->ci_children;;
  492. off_t i;
  493. for (i = 0; i < (*offset - 2); i++)
  494. child = child->ci_next_sibling;
  495. dent->ino = (ino_t)child->ci_self->I_ino;
  496. size_t dirnamelen = strlen(child->ci_name);
  497. dirnamelen = min(dirnamelen, UNIXFS_MAXNAMLEN);
  498. memcpy(dent->name, child->ci_name, dirnamelen);
  499. dent->name[dirnamelen] = '\0';
  500. out:
  501. *offset += 1;
  502. return 0;
  503. }
  504. static ssize_t
  505. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  506. int* error)
  507. {
  508. off_t start = (off_t)ip->I_daddr[0];
  509. /* caller already checked for bounds */
  510. return pread(unixfs->s_bdev, buf, nbyte, start + offset);
  511. }
  512. static int
  513. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  514. {
  515. struct inode* ip = unixfs_internal_iget(ino);
  516. if (!ip)
  517. return ENOENT;
  518. int error;
  519. struct bcpio_node_info* ci = (struct bcpio_node_info*)ip->I_private;
  520. if (!ci->ci_linktargetname) {
  521. error = ENOENT;
  522. goto out;
  523. }
  524. size_t linklen = min(ip->I_size, BCBLOCK);
  525. memcpy(path, ci->ci_linktargetname, linklen);
  526. path[linklen] = '\0';
  527. error = 0;
  528. out:
  529. unixfs_internal_iput(ip);
  530. return error;
  531. }
  532. static int
  533. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  534. {
  535. return 0;
  536. }
  537. static int
  538. unixfs_internal_statvfs(struct statvfs* svb)
  539. {
  540. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  541. return 0;
  542. }