/filesystems/unixfs/minixfs/unixfs_minixfs.c

http://macfuse.googlecode.com/ · C · 356 lines · 277 code · 73 blank · 6 comment · 57 complexity · d5aa8212550e43fae27e841d061318e3 MD5 · raw file

  1. /*
  2. * Minix File System Famiy for MacFUSE
  3. * Copyright (c) 2008 Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "minixfs.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("Minix", minix);
  17. static void*
  18. unixfs_internal_init(const char* dmg, uint32_t flags, __unused 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;
  27. struct stat stbuf;
  28. struct super_block* sb = (struct super_block*)0;
  29. if ((err = fstat(fd, &stbuf)) != 0) {
  30. perror("fstat");
  31. goto out;
  32. }
  33. if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
  34. err = EINVAL;
  35. fprintf(stderr, "%s is not a disk image file\n", dmg);
  36. goto out;
  37. }
  38. if ((err = unixfs_inodelayer_init(sizeof(struct minix_inode_info))) != 0)
  39. goto out;
  40. sb = minixfs_fill_super(fd, (void*)0, 1 /* silent */);
  41. if (!sb) {
  42. err = EINVAL;
  43. goto out;
  44. }
  45. struct minix_sb_info* sbi = minix_sb(sb);
  46. unixfs = sb;
  47. unixfs->s_flags = flags;
  48. (void)minixfs_statvfs(sb, &(unixfs->s_statvfs));
  49. unixfs->s_dentsize = 0;
  50. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s %s",
  51. unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" :
  52. (sbi->s_version == MINIX_V2) ? "V2" :
  53. (sbi->s_version == MINIX_V1) ? "V1" : "??");
  54. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (%s)",
  55. unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" :
  56. (sbi->s_version == MINIX_V2) ? "V2" :
  57. (sbi->s_version == MINIX_V1) ? "V1" : "??");
  58. *fsname = unixfs->s_fsname;
  59. *volname = unixfs->s_volname;
  60. out:
  61. if (err) {
  62. if (fd > 0)
  63. close(fd);
  64. if (sb) {
  65. free(sb);
  66. sb = NULL;
  67. }
  68. }
  69. return sb;
  70. }
  71. static void
  72. unixfs_internal_fini(void* filsys)
  73. {
  74. unixfs_inodelayer_fini();
  75. struct super_block* sb = (struct super_block*)filsys;
  76. if (sb) {
  77. struct minix_sb_info* sbi = minix_sb(sb);
  78. if (sbi)
  79. free(sbi);
  80. free(sb);
  81. }
  82. }
  83. static off_t
  84. unixfs_internal_alloc(void)
  85. {
  86. return (off_t)0;
  87. }
  88. static off_t
  89. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  90. {
  91. off_t result;
  92. *error = minixfs_get_block(ip, lblkno, &result);
  93. return result;
  94. }
  95. static int
  96. unixfs_internal_bread(off_t blkno, char* blkbuf)
  97. {
  98. struct super_block* sb = unixfs;
  99. if (pread(sb->s_bdev, blkbuf, sb->s_blocksize,
  100. blkno * (off_t)(sb->s_blocksize)) != sb->s_blocksize)
  101. return EIO;
  102. return 0;
  103. }
  104. struct inode*
  105. unixfs_internal_iget(ino_t ino)
  106. {
  107. if (ino == MACFUSE_ROOTINO)
  108. ino = MINIX_ROOT_INO;
  109. struct super_block* sb = unixfs;
  110. struct inode* inode = unixfs_inodelayer_iget(ino);
  111. if (!inode) {
  112. fprintf(stderr, "*** fatal error: no inode for %llu\n", ino);
  113. abort();
  114. }
  115. if (inode->I_initialized)
  116. return inode;
  117. inode->I_sb = unixfs;
  118. inode->I_blkbits = sb->s_blocksize_bits;
  119. if (minixfs_iget(sb, inode) != 0) {
  120. fprintf(stderr, "major problem: failed to read inode %llu\n", ino);
  121. unixfs_inodelayer_ifailed(inode);
  122. goto bad_inode;
  123. }
  124. unixfs_inodelayer_isucceeded(inode);
  125. return inode;
  126. bad_inode:
  127. return NULL;
  128. }
  129. static void
  130. unixfs_internal_iput(struct inode* ip)
  131. {
  132. unixfs_inodelayer_iput(ip);
  133. }
  134. static int
  135. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  136. {
  137. if (ino == MACFUSE_ROOTINO)
  138. ino = MINIX_ROOT_INO;
  139. struct inode* ip = unixfs_internal_iget(ino);
  140. if (!ip)
  141. return ENOENT;
  142. unixfs_internal_istat(ip, stbuf);
  143. unixfs_internal_iput(ip);
  144. return 0;
  145. }
  146. static void
  147. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  148. {
  149. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  150. }
  151. static int
  152. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  153. {
  154. if (parentino == MACFUSE_ROOTINO)
  155. parentino = MINIX_ROOT_INO;
  156. stbuf->st_ino = ENOENT;
  157. struct inode* dir = unixfs_internal_iget(parentino);
  158. if (!dir)
  159. return ENOENT;
  160. if (!S_ISDIR(dir->I_mode)) {
  161. unixfs_internal_iput(dir);
  162. return ENOTDIR;
  163. }
  164. int ret = ENOENT;
  165. unsigned long namelen = strlen(name);
  166. unsigned long start, n;
  167. unsigned long npages = minix_dir_pages(dir);
  168. minix3_dirent* de3;
  169. minix_dirent* de;
  170. char page[PAGE_SIZE];
  171. char* kaddr = NULL;
  172. struct super_block* sb = dir->I_sb;
  173. struct minix_sb_info* sbi = minix_sb(sb);
  174. unsigned chunk_size = sbi->s_dirsize;
  175. struct minix_inode_info* minix_inode = minix_i(dir);
  176. start = minix_inode->i_dir_start_lookup;
  177. if (start >= npages)
  178. start = 0;
  179. n = start;
  180. ino_t found_ino = 0;
  181. do {
  182. int error = minixfs_get_page(dir, n, page);
  183. if (!error) {
  184. kaddr = (char*)page;
  185. if (INODE_VERSION(dir) == MINIX_V3) {
  186. de3 = (minix3_dirent*)kaddr;
  187. kaddr += PAGE_CACHE_SIZE - chunk_size;
  188. for (; (char*)de3 <= kaddr; de3++) {
  189. if (!de3->inode)
  190. continue;
  191. if (minix_namecompare(namelen, chunk_size,
  192. name, de3->name)) {
  193. found_ino = de3->inode;
  194. goto found;
  195. }
  196. }
  197. } else {
  198. de = (minix_dirent*)kaddr;
  199. kaddr += PAGE_CACHE_SIZE - chunk_size;
  200. for (; (char*)de <= kaddr; de++) {
  201. if (!de->inode)
  202. continue;
  203. if (minix_namecompare(namelen, chunk_size,
  204. name, de->name)) {
  205. found_ino = de->inode;
  206. goto found;
  207. }
  208. }
  209. }
  210. }
  211. if (++n >= npages)
  212. n = 0;
  213. } while (n != start);
  214. found:
  215. if (found_ino)
  216. minix_inode->i_dir_start_lookup = n;
  217. unixfs_internal_iput(dir);
  218. if (found_ino)
  219. ret = unixfs_internal_igetattr(found_ino, stbuf);
  220. return ret;
  221. }
  222. int
  223. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  224. off_t* offset, struct unixfs_direntry* dent)
  225. {
  226. return minixfs_next_direntry(dp, dirbuf, offset, dent);
  227. }
  228. static ssize_t
  229. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  230. int* error)
  231. {
  232. char* p = buf;
  233. ssize_t done = 0;
  234. ssize_t tomove = 0;
  235. ssize_t remaining = nbyte;
  236. char page[PAGE_SIZE];
  237. sector_t beginpgno = offset >> PAGE_CACHE_SHIFT;
  238. while (remaining > 0) { /* page sized reads */
  239. *error = minixfs_get_page(ip, beginpgno, page);
  240. if (*error)
  241. break;
  242. tomove = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
  243. memcpy(p, page, tomove);
  244. remaining -= tomove;
  245. done += tomove;
  246. p += tomove;
  247. beginpgno++;
  248. }
  249. if ((done == 0) && *error)
  250. return -1;
  251. return done;
  252. }
  253. static int
  254. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  255. {
  256. struct inode* ip = unixfs_internal_iget(ino);
  257. if (!ip)
  258. return ENOENT;
  259. int error = 0;
  260. size_t linklen =
  261. (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;
  262. char page[PAGE_SIZE];
  263. error = minixfs_get_page(ip, (off_t)0, page);
  264. if (error)
  265. goto out;
  266. memcpy(path, page, linklen);
  267. path[linklen] = '\0';
  268. out:
  269. unixfs_internal_iput(ip);
  270. return error;
  271. }
  272. int
  273. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  274. {
  275. /* handled elsewhere */
  276. return 0;
  277. }
  278. static int
  279. unixfs_internal_statvfs(struct statvfs* svb)
  280. {
  281. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  282. return 0;
  283. }