PageRenderTime 82ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 1ms

/filesystems/unixfs/ancientfs/ancientfs_ar.c

http://macfuse.googlecode.com/
C | 540 lines | 394 code | 91 blank | 55 comment | 69 complexity | d95bec4866ff86a7e85435ee2a86a918 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. /*
  2. * Ancient UNIX File Systems for MacFUSE
  3. * Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ancientfs_ar.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 ar", ar);
  17. /*
  18. * The header reading function is adapted from the BSD version.
  19. */
  20. /*-
  21. * Copyright (c) 1990, 1993, 1994
  22. * The Regents of the University of California. All rights reserved.
  23. *
  24. * This code is derived from software contributed to Berkeley by
  25. * Hugh Smith at The University of Guelph.
  26. *
  27. * Redistribution and use in source and binary forms, with or without
  28. * modification, are permitted provided that the following conditions
  29. * are met:
  30. * 1. Redistributions of source code must retain the above copyright
  31. * notice, this list of conditions and the following disclaimer.
  32. * 2. Redistributions in binary form must reproduce the above copyright
  33. * notice, this list of conditions and the following disclaimer in the
  34. * documentation and/or other materials provided with the distribution.
  35. * 3. All advertising materials mentioning features or use of this software
  36. * must display the following acknowledgement:
  37. * This product includes software developed by the University of
  38. * California, Berkeley and its contributors.
  39. * 4. Neither the name of the University nor the names of its contributors
  40. * may be used to endorse or promote products derived from this software
  41. * without specific prior written permission.
  42. *
  43. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  44. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  45. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  46. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  47. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  48. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  49. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  50. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  51. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  52. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  53. * SUCH DAMAGE.
  54. */
  55. /* Convert ar header field to an integer. */
  56. #define AR_ATOI(from, to, len, base) { \
  57. memmove(buf, from, len); \
  58. buf[len] = '\0'; \
  59. to = strtol(buf, (char **)NULL, base); \
  60. }
  61. struct chdr {
  62. off_t size; /* size of the object in bytes */
  63. off_t addr; /* where the file begins */
  64. time_t date; /* date */
  65. int lname; /* size of the long name in bytes */
  66. gid_t gid; /* group */
  67. uid_t uid; /* owner */
  68. u_short mode; /* permissions */
  69. char name[UNIXFS_MAXNAMLEN + 1]; /* name */
  70. };
  71. static int ancientfs_ar_readheader(int fd, struct chdr* chdr);
  72. static int
  73. ancientfs_ar_readheader(int fd, struct chdr* chdr)
  74. {
  75. int len, nr;
  76. char *p, buf[20];
  77. char hb[sizeof(struct ar_hdr) + 1];
  78. struct ar_hdr* hdr;
  79. nr = read(fd, hb, sizeof(struct ar_hdr));
  80. if (nr != sizeof(struct ar_hdr)) {
  81. if (!nr)
  82. return 1;
  83. if (nr < 0)
  84. return -1;
  85. }
  86. hdr = (struct ar_hdr*)hb;
  87. if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
  88. return -2;
  89. /* Convert the header into the internal format. */
  90. #define DECIMAL 10
  91. #define OCTAL 8
  92. AR_ATOI(hdr->ar_date, chdr->date, sizeof(hdr->ar_date), DECIMAL);
  93. AR_ATOI(hdr->ar_uid, chdr->uid, sizeof(hdr->ar_uid), DECIMAL);
  94. AR_ATOI(hdr->ar_gid, chdr->gid, sizeof(hdr->ar_gid), DECIMAL);
  95. AR_ATOI(hdr->ar_mode, chdr->mode, sizeof(hdr->ar_mode), OCTAL);
  96. AR_ATOI(hdr->ar_size, chdr->size, sizeof(hdr->ar_size), DECIMAL);
  97. /* Leading spaces should never happen. */
  98. if (hdr->ar_name[0] == ' ')
  99. return -2;
  100. /*
  101. * Long name support. Set the "real" size of the file, and the
  102. * long name flag/size.
  103. */
  104. if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
  105. chdr->lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
  106. if (len <= 0 || len > UNIXFS_MAXNAMLEN)
  107. return -1;
  108. nr = read(fd, chdr->name, len);
  109. if (nr != len) {
  110. if (nr < 0)
  111. return -1;
  112. }
  113. chdr->name[len] = 0;
  114. chdr->size -= len;
  115. } else {
  116. memmove(chdr->name, hdr->ar_name, sizeof(hdr->ar_name));
  117. /* Strip trailing spaces, null terminate. */
  118. for (p = chdr->name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
  119. *++p = '\0';
  120. chdr->lname = strlen(chdr->name);
  121. }
  122. /* limiting to 32-bit offsets */
  123. chdr->addr = (uint32_t)lseek(fd, (off_t)0, SEEK_CUR);
  124. return 0;
  125. }
  126. static void*
  127. unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse,
  128. char** fsname, char** volname)
  129. {
  130. int fd = -1;
  131. if ((fd = open(dmg, O_RDONLY)) < 0) {
  132. perror("open");
  133. return NULL;
  134. }
  135. int err;
  136. struct stat stbuf;
  137. struct super_block* sb = (struct super_block*)0;
  138. struct filsys* fs = (struct filsys*)0;
  139. if ((err = fstat(fd, &stbuf)) != 0) {
  140. perror("fstat");
  141. goto out;
  142. }
  143. if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
  144. err = EINVAL;
  145. fprintf(stderr, "%s is not an ar image file\n", dmg);
  146. goto out;
  147. }
  148. char magic[SARMAG];
  149. if (read(fd, magic, SARMAG) != SARMAG) {
  150. err = EIO;
  151. fprintf(stderr, "failed to read magic from file\n");
  152. goto out;
  153. }
  154. if (memcmp(magic, ARMAG, SARMAG) != 0) {
  155. err = EINVAL;
  156. fprintf(stderr, "%s is not an ar image file\n", dmg);
  157. goto out;
  158. }
  159. sb = malloc(sizeof(struct super_block));
  160. if (!sb) {
  161. err = ENOMEM;
  162. goto out;
  163. }
  164. assert(sizeof(struct filsys) <= BSIZE);
  165. fs = calloc(1, BSIZE);
  166. if (!fs) {
  167. free(sb);
  168. err = ENOMEM;
  169. goto out;
  170. }
  171. unixfs = sb;
  172. unixfs->s_flags = flags;
  173. unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_LITTLE : fse;
  174. unixfs->s_fs_info = (void*)fs;
  175. unixfs->s_bdev = fd;
  176. /* must initialize the inode layer before sanity checking */
  177. if ((err = unixfs_inodelayer_init(sizeof(struct ar_node_info))) != 0)
  178. goto out;
  179. struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO);
  180. if (!rootip) {
  181. fprintf(stderr, "*** fatal error: no root inode\n");
  182. abort();
  183. }
  184. rootip->I_mode = S_IFDIR | 0755;
  185. rootip->I_uid = getuid();
  186. rootip->I_gid = getgid();
  187. rootip->I_size = 2;
  188. rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0);
  189. struct ar_node_info* rootai = (struct ar_node_info*)rootip->I_private;
  190. rootai->ar_self = rootip;
  191. rootai->ar_parent = NULL;
  192. rootai->ar_children = NULL;
  193. rootai->ar_next_sibling = NULL;
  194. unixfs_inodelayer_isucceeded(rootip);
  195. fs->s_fsize = (stbuf.st_size / BSIZE) + 1;
  196. fs->s_files = 0;
  197. fs->s_directories = 1 + 1 + 1;
  198. fs->s_rootip = rootip;
  199. fs->s_lastino = ROOTINO;
  200. struct chdr ar;
  201. ino_t parent_ino = ROOTINO;
  202. for (;;) {
  203. if (ancientfs_ar_readheader(fd, &ar) != 0)
  204. break;
  205. int missing = unixfs_internal_namei(parent_ino, ar.name, &stbuf);
  206. if (!missing) /* duplicate */
  207. goto next;
  208. struct inode* ip = unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1));
  209. if (!ip) {
  210. fprintf(stderr, "*** fatal error: no inode for %llu\n",
  211. (ino64_t)(fs->s_lastino + 1));
  212. abort();
  213. }
  214. ip->I_mode = ar.mode;
  215. ip->I_uid = ar.uid;
  216. ip->I_gid = ar.gid;
  217. ip->I_nlink = 1;
  218. ip->I_size = ar.size;
  219. ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec = ar.date;
  220. ip->I_daddr[0] = ar.addr;
  221. struct ar_node_info* ai = (struct ar_node_info*)ip->I_private;
  222. ai->ar_name = malloc(ar.lname + 1);
  223. if (!ai->ar_name) {
  224. fprintf(stderr, "*** fatal error: cannot allocate memory\n");
  225. abort();
  226. }
  227. memcpy(ai->ar_name, ar.name, ar.lname);
  228. ai->ar_name[ar.lname] = '\0';
  229. ai->ar_namelen = ar.lname;
  230. ai->ar_self = ip;
  231. ai->ar_children = NULL;
  232. struct inode* parent_ip = unixfs_internal_iget(parent_ino);
  233. parent_ip->I_size += 1;
  234. ai->ar_parent = (struct ar_node_info*)(parent_ip->I_private);
  235. ai->ar_next_sibling = ai->ar_parent->ar_children;
  236. ai->ar_parent->ar_children = ai;
  237. if (S_ISDIR(ip->I_mode)) {
  238. fs->s_directories++;
  239. parent_ino = fs->s_lastino + 1;
  240. ip->I_size = 2;
  241. ip->I_daddr[0] = 0;
  242. } else {
  243. fs->s_files++;
  244. fs->s_lastino++;
  245. unixfs_internal_iput(parent_ip);
  246. unixfs_inodelayer_isucceeded(ip);
  247. /* no put */
  248. }
  249. fs->s_lastino++;
  250. next:
  251. (void)lseek(fd, (off_t)(ar.size + (ar.size & 1)), SEEK_CUR);
  252. }
  253. unixfs->s_statvfs.f_bsize = BSIZE;
  254. unixfs->s_statvfs.f_frsize = BSIZE;
  255. unixfs->s_statvfs.f_ffree = 0;
  256. unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories;
  257. unixfs->s_statvfs.f_blocks = fs->s_fsize;
  258. unixfs->s_statvfs.f_bfree = 0;
  259. unixfs->s_statvfs.f_bavail = 0;
  260. unixfs->s_dentsize = 1;
  261. unixfs->s_statvfs.f_namemax = UNIXFS_MAXNAMLEN;
  262. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "UNIX ar");
  263. char* dmg_basename = basename((char*)dmg);
  264. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (tape=%s)",
  265. unixfs_fstype, (dmg_basename) ? dmg_basename : "Archive Image");
  266. *fsname = unixfs->s_fsname;
  267. *volname = unixfs->s_volname;
  268. out:
  269. if (err) {
  270. if (fd >= 0)
  271. close(fd);
  272. if (fs)
  273. free(fs);
  274. if (sb)
  275. free(sb);
  276. return NULL;
  277. }
  278. return sb;
  279. }
  280. static void
  281. unixfs_internal_fini(void* filsys)
  282. {
  283. struct super_block* sb = (struct super_block*)filsys;
  284. struct filsys* fs = (struct filsys*)sb->s_fs_info;
  285. ino_t i = fs->s_lastino;
  286. for (; i >= ROOTINO; i--) {
  287. struct inode* tmp = unixfs_internal_iget(i);
  288. if (tmp) {
  289. struct ar_node_info* ai = (struct ar_node_info*)tmp->I_private;
  290. if (ai->ar_name)
  291. free(ai->ar_name);
  292. unixfs_internal_iput(tmp);
  293. unixfs_internal_iput(tmp);
  294. }
  295. }
  296. unixfs_inodelayer_fini();
  297. if (sb) {
  298. if (sb->s_bdev >= 0)
  299. close(sb->s_bdev);
  300. sb->s_bdev = -1;
  301. if (sb->s_fs_info)
  302. free(sb->s_fs_info);
  303. }
  304. }
  305. static off_t
  306. unixfs_internal_alloc(void)
  307. {
  308. return (off_t)0;
  309. }
  310. static off_t
  311. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  312. {
  313. return (off_t)0;
  314. }
  315. static int
  316. unixfs_internal_bread(off_t blkno, char* blkbuf)
  317. {
  318. return EIO;
  319. }
  320. static struct inode*
  321. unixfs_internal_iget(ino_t ino)
  322. {
  323. struct inode* ip = unixfs_inodelayer_iget(ino);
  324. if (!ip) {
  325. fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)ino);
  326. abort();
  327. }
  328. if (ip->I_initialized)
  329. return ip;
  330. unixfs_inodelayer_ifailed(ip);
  331. return NULL;
  332. }
  333. static void
  334. unixfs_internal_iput(struct inode* ip)
  335. {
  336. unixfs_inodelayer_iput(ip);
  337. }
  338. static int
  339. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  340. {
  341. struct inode* ip = unixfs_internal_iget(ino);
  342. if (!ip)
  343. return ENOENT;
  344. unixfs_internal_istat(ip, stbuf);
  345. unixfs_internal_iput(ip);
  346. return 0;
  347. }
  348. static void
  349. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  350. {
  351. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  352. }
  353. static int
  354. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  355. {
  356. int ret = ENOENT;
  357. stbuf->st_ino = 0;
  358. size_t namelen = strlen(name);
  359. if (namelen > UNIXFS_MAXNAMLEN)
  360. return ENAMETOOLONG;
  361. struct inode* dp = unixfs_internal_iget(parentino);
  362. if (!dp)
  363. return ENOENT;
  364. if (!S_ISDIR(dp->I_mode)) {
  365. ret = ENOTDIR;
  366. goto out;
  367. }
  368. struct ar_node_info* child =
  369. ((struct ar_node_info*)dp->I_private)->ar_children;;
  370. if (!child) {
  371. ret = ENOENT;
  372. goto out;
  373. }
  374. int found = 0;
  375. do {
  376. size_t target_namelen = strlen((const char*)child->ar_name);
  377. if ((namelen == target_namelen) &&
  378. (memcmp(name, child->ar_name, target_namelen) == 0)) {
  379. found = 1;
  380. break;
  381. }
  382. child = child->ar_next_sibling;
  383. } while (child);
  384. if (found)
  385. ret = unixfs_internal_igetattr((ino_t)child->ar_self->I_ino, stbuf);
  386. out:
  387. unixfs_internal_iput(dp);
  388. return ret;
  389. }
  390. static int
  391. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  392. off_t* offset, struct unixfs_direntry* dent)
  393. {
  394. if (*offset >= dp->I_size)
  395. return -1;
  396. if (*offset < 2) {
  397. int idx = 0;
  398. dent->name[idx++] = '.';
  399. dent->ino = ROOTINO;
  400. if (*offset == 1) {
  401. if (dp->I_ino != ROOTINO) {
  402. struct inode* pdp = unixfs_internal_iget(dp->I_ino);
  403. if (pdp) {
  404. dent->ino = pdp->I_ino;
  405. unixfs_internal_iput(pdp);
  406. }
  407. }
  408. dent->name[idx++] = '.';
  409. }
  410. dent->name[idx++] = '\0';
  411. goto out;
  412. }
  413. struct ar_node_info* child =
  414. ((struct ar_node_info*)dp->I_private)->ar_children;;
  415. off_t i;
  416. for (i = 0; i < (*offset - 2); i++)
  417. child = child->ar_next_sibling;
  418. dent->ino = (ino_t)child->ar_self->I_ino;
  419. size_t dirnamelen = min(child->ar_namelen, UNIXFS_MAXNAMLEN);
  420. memcpy(dent->name, child->ar_name, dirnamelen);
  421. dent->name[dirnamelen] = '\0';
  422. out:
  423. *offset += 1;
  424. return 0;
  425. }
  426. static ssize_t
  427. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  428. int* error)
  429. {
  430. off_t start = (off_t)ip->I_daddr[0];
  431. /* caller already checked for bounds */
  432. return pread(unixfs->s_bdev, buf, nbyte, start + offset);
  433. }
  434. static int
  435. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  436. {
  437. return ENOSYS;
  438. }
  439. static int
  440. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  441. {
  442. return 0;
  443. }
  444. static int
  445. unixfs_internal_statvfs(struct statvfs* svb)
  446. {
  447. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  448. return 0;
  449. }