/filesystems/unixfs/ufs/unixfs_ufs.c

http://macfuse.googlecode.com/ · C · 297 lines · 227 code · 64 blank · 6 comment · 39 complexity · ed57a22eb9ccac464aae8a9389e0a16e MD5 · raw file

  1. /*
  2. * UFS for MacFUSE
  3. * Copyright (c) 2008 Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "ufs.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("UFS", ufs);
  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 ufs_inode_info))) != 0)
  39. goto out;
  40. char args[UNIXFS_MNAMELEN];
  41. snprintf(args, UNIXFS_MNAMELEN, "%s", *fsname);
  42. char* c = args;
  43. for (; *c; c++)
  44. *c = tolower(*c);
  45. sb = U_ufs_fill_super(fd, (void*)args, 0 /* silent */);
  46. if (!sb) {
  47. err = EINVAL;
  48. goto out;
  49. }
  50. unixfs = sb;
  51. err = U_ufs_statvfs(sb, &(unixfs->s_statvfs));
  52. if (err)
  53. goto out;
  54. unixfs->s_flags = flags;
  55. unixfs->s_dentsize = 0; /* variable */
  56. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s", unixfs_fstype);
  57. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s", *fsname);
  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. }
  67. return sb;
  68. }
  69. static void
  70. unixfs_internal_fini(void* filsys)
  71. {
  72. unixfs_inodelayer_fini();
  73. struct super_block* sb = (struct super_block*)filsys;
  74. if (sb)
  75. free(sb);
  76. }
  77. static off_t
  78. unixfs_internal_alloc(void)
  79. {
  80. return (off_t)0;
  81. }
  82. static off_t
  83. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  84. {
  85. off_t result;
  86. *error = U_ufs_get_block(ip, lblkno, &result);
  87. return result;
  88. }
  89. static int
  90. unixfs_internal_bread(off_t blkno, char* blkbuf)
  91. {
  92. struct super_block* sb = unixfs;
  93. if (pread(sb->s_bdev, blkbuf, sb->s_blocksize,
  94. blkno * (off_t)(sb->s_blocksize)) != sb->s_blocksize)
  95. return EIO;
  96. return 0;
  97. }
  98. struct inode*
  99. unixfs_internal_iget(ino_t ino)
  100. {
  101. if (ino == MACFUSE_ROOTINO)
  102. ino = UFS_ROOTINO;
  103. struct inode* inode = unixfs_inodelayer_iget(ino);
  104. if (!inode) {
  105. fprintf(stderr, "*** fatal error: no inode for %llu\n", ino);
  106. abort();
  107. }
  108. if (inode->I_initialized)
  109. return inode;
  110. struct super_block* sb = unixfs;
  111. inode->I_ino = ino;
  112. int error = U_ufs_iget(sb, inode);
  113. if (error) {
  114. fprintf(stderr, "major problem: failed to read inode %llu\n", ino);
  115. unixfs_inodelayer_ifailed(inode);
  116. goto bad_inode;
  117. }
  118. unixfs_inodelayer_isucceeded(inode);
  119. return inode;
  120. bad_inode:
  121. return NULL;
  122. }
  123. static void
  124. unixfs_internal_iput(struct inode* ip)
  125. {
  126. unixfs_inodelayer_iput(ip);
  127. }
  128. static int
  129. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  130. {
  131. if (ino == MACFUSE_ROOTINO)
  132. ino = UFS_ROOTINO;
  133. struct inode* ip = unixfs_internal_iget(ino);
  134. if (!ip)
  135. return ENOENT;
  136. unixfs_internal_istat(ip, stbuf);
  137. unixfs_internal_iput(ip);
  138. return 0;
  139. }
  140. static void
  141. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  142. {
  143. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  144. }
  145. static int
  146. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  147. {
  148. if (parentino == MACFUSE_ROOTINO)
  149. parentino = UFS_ROOTINO;
  150. int ret = ENOENT;
  151. stbuf->st_ino = 0;
  152. size_t namelen = strlen(name);
  153. if (namelen > UFS_MAXNAMLEN)
  154. return ENAMETOOLONG;
  155. struct inode* dir = unixfs_internal_iget(parentino);
  156. if (!dir)
  157. return ENOENT;
  158. if (!S_ISDIR(dir->I_mode)) {
  159. unixfs_internal_iput(dir);
  160. return ENOTDIR;
  161. }
  162. ino_t target = U_ufs_inode_by_name(dir, name);
  163. if (target)
  164. ret = unixfs_internal_igetattr(target, stbuf);
  165. unixfs_internal_iput(dir);
  166. return ret;
  167. }
  168. int
  169. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  170. off_t* offset, struct unixfs_direntry* dent)
  171. {
  172. return U_ufs_next_direntry(dp, dirbuf, offset, dent);
  173. }
  174. static ssize_t
  175. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  176. int* error)
  177. {
  178. char* p = buf;
  179. ssize_t done = 0;
  180. ssize_t tomove = 0;
  181. ssize_t remaining = nbyte;
  182. char page[PAGE_SIZE];
  183. sector_t beginpgno = offset >> PAGE_CACHE_SHIFT;
  184. while (remaining > 0) { /* page sized reads */
  185. *error = U_ufs_get_page(ip, beginpgno, page);
  186. if (*error)
  187. break;
  188. tomove = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
  189. memcpy(p, page, tomove);
  190. remaining -= tomove;
  191. done += tomove;
  192. p += tomove;
  193. beginpgno++;
  194. }
  195. if ((done == 0) && *error)
  196. return -1;
  197. return done;
  198. }
  199. static int
  200. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  201. {
  202. struct inode* ip = unixfs_internal_iget(ino);
  203. if (!ip)
  204. return ENOENT;
  205. int error = 0;
  206. size_t linklen =
  207. (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;
  208. if (!ip->I_blocks) { /* fast */
  209. struct ufs_inode_info* p = (struct ufs_inode_info*)ip->I_private;
  210. memcpy(path, (char*)p->i_u1.i_symlink, sizeof(p->i_u1.i_symlink));
  211. } else {
  212. char page[PAGE_SIZE];
  213. error = U_ufs_get_page(ip, (off_t)0, page);
  214. if (error)
  215. goto out;
  216. memcpy(path, page, linklen);
  217. }
  218. path[linklen] = '\0';
  219. out:
  220. unixfs_internal_iput(ip);
  221. return error;
  222. }
  223. int
  224. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  225. {
  226. /* handled elsewhere */
  227. return 0;
  228. }
  229. static int
  230. unixfs_internal_statvfs(struct statvfs* svb)
  231. {
  232. return U_ufs_statvfs(unixfs, svb);
  233. }