/filesystems/unixfs/ancientfs/ancientfs_cpio_odc.c

http://macfuse.googlecode.com/ · C · 659 lines · 512 code · 128 blank · 19 comment · 110 complexity · 67e35c8439bc367ecf1d7fbae29b2097 MD5 · raw file

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