/filesystems/unixfs/sysvfs/unixfs_sysvfs.c

http://macfuse.googlecode.com/ · C · 397 lines · 310 code · 80 blank · 7 comment · 58 complexity · 56a082cdd2a2a73ca6009dcbb631b50b MD5 · raw file

  1. /*
  2. * SYSV File System Famiy for MacFUSE
  3. * Copyright (c) 2008 Amit Singh
  4. * http://osxbook.com
  5. */
  6. #include "sysvfs.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 System V", sysv);
  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 sysv_inode_info))) != 0)
  39. goto out;
  40. sb = sysv_fill_super(fd, (void*)0, 1 /* silent */);
  41. if (!sb) {
  42. err = EINVAL;
  43. goto out;
  44. }
  45. struct sysv_sb_info* sbi = SYSV_SB(sb);
  46. unixfs = sb;
  47. unixfs->s_flags = flags;
  48. unixfs->s_statvfs.f_bsize = max(PAGE_SIZE, sb->s_blocksize);
  49. unixfs->s_statvfs.f_frsize = sb->s_blocksize;
  50. unixfs->s_statvfs.f_blocks = sbi->s_ndatazones;
  51. unixfs->s_statvfs.f_bavail = sysv_count_free_blocks(sb);
  52. unixfs->s_statvfs.f_bfree = unixfs->s_statvfs.f_bavail;
  53. unixfs->s_statvfs.f_files = sbi->s_ninodes;
  54. unixfs->s_statvfs.f_ffree = sysv_count_free_inodes(sb);
  55. unixfs->s_statvfs.f_namemax = SYSV_NAMELEN;
  56. unixfs->s_dentsize = 0;
  57. snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s", sysv_flavor(sbi->s_type));
  58. snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (%s)",
  59. unixfs_fstype, sysv_flavor(sbi->s_type));
  60. *fsname = unixfs->s_fsname;
  61. *volname = unixfs->s_volname;
  62. out:
  63. if (err) {
  64. if (fd > 0)
  65. close(fd);
  66. if (sb) {
  67. struct sysv_sb_info* sbi = SYSV_SB(sb);
  68. if (sbi) {
  69. void* bh1 = sbi->s_bh1;
  70. void* bh2 = sbi->s_bh2;
  71. if (bh1) {
  72. if (bh1 == bh2)
  73. bh2 = NULL;
  74. brelse(bh1);
  75. }
  76. if (bh2)
  77. brelse(bh2);
  78. free(sbi);
  79. }
  80. free(sb);
  81. }
  82. }
  83. return sb;
  84. }
  85. static void
  86. unixfs_internal_fini(void* filsys)
  87. {
  88. unixfs_inodelayer_fini();
  89. struct super_block* sb = (struct super_block*)filsys;
  90. if (sb) {
  91. struct sysv_sb_info* sbi = SYSV_SB(sb);
  92. if (sbi) {
  93. void* bh1 = sbi->s_bh1;
  94. void* bh2 = sbi->s_bh2;
  95. if (bh1) {
  96. if (bh1 == bh2)
  97. bh2 = NULL;
  98. brelse(bh1);
  99. }
  100. if (bh2)
  101. brelse(bh2);
  102. free(sbi);
  103. }
  104. free(sb);
  105. }
  106. }
  107. static off_t
  108. unixfs_internal_alloc(void)
  109. {
  110. return (off_t)0;
  111. }
  112. static off_t
  113. unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
  114. {
  115. off_t result;
  116. *error = sysv_get_block(ip, lblkno, &result);
  117. return result;
  118. }
  119. static int
  120. unixfs_internal_bread(off_t blkno, char* blkbuf)
  121. {
  122. struct super_block* sb = unixfs;
  123. if (pread(sb->s_bdev, blkbuf, sb->s_blocksize,
  124. blkno * (off_t)(sb->s_blocksize)) != sb->s_blocksize)
  125. return EIO;
  126. return 0;
  127. }
  128. struct inode*
  129. unixfs_internal_iget(ino_t ino)
  130. {
  131. if (ino == MACFUSE_ROOTINO)
  132. ino = SYSV_ROOT_INO;
  133. struct super_block* sb = unixfs;
  134. struct sysv_sb_info* sbi = SYSV_SB(sb);
  135. if (!ino || ino > sbi->s_ninodes) {
  136. fprintf(stderr, "bad inode number: %llu\n", ino);
  137. return NULL;
  138. }
  139. struct inode* inode = unixfs_inodelayer_iget(ino);
  140. if (!inode) {
  141. fprintf(stderr, "*** fatal error: no inode for %llu\n", ino);
  142. abort();
  143. }
  144. if (inode->I_initialized)
  145. return inode;
  146. struct buffer_head bh;
  147. struct sysv_dinode* raw_inode = sysv_raw_inode(sb, ino, &bh);
  148. if (!raw_inode) {
  149. fprintf(stderr, "major problem: failed to read inode %llu\n", ino);
  150. unixfs_inodelayer_ifailed(inode);
  151. goto bad_inode;
  152. }
  153. struct sysv_inode_info *si = SYSV_I(inode);
  154. inode->I_ino = ino;
  155. /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
  156. inode->I_mode = fs16_to_host(unixfs->s_endian, raw_inode->di_mode);
  157. inode->I_uid = (uid_t)fs16_to_host(unixfs->s_endian, raw_inode->di_uid);
  158. inode->I_gid = (gid_t)fs16_to_host(unixfs->s_endian, raw_inode->di_gid);
  159. inode->I_nlink = fs16_to_host(unixfs->s_endian, raw_inode->di_nlink);
  160. inode->I_size = fs32_to_host(unixfs->s_endian, raw_inode->di_size);
  161. inode->I_atime.tv_sec = fs32_to_host(unixfs->s_endian, raw_inode->di_atime);
  162. inode->I_mtime.tv_sec = fs32_to_host(unixfs->s_endian, raw_inode->di_mtime);
  163. inode->I_ctime.tv_sec = fs32_to_host(unixfs->s_endian, raw_inode->di_ctime);
  164. inode->I_ctime.tv_nsec = 0;
  165. inode->I_atime.tv_nsec = 0;
  166. inode->I_mtime.tv_nsec = 0;
  167. inode->I_sb = unixfs;
  168. inode->I_blkbits = sb->s_blocksize_bits;
  169. unsigned int block;
  170. for (block = 0; block < (10 + 1 + 1 + 1); block++)
  171. sysv_read3byte(sbi, &raw_inode->di_data[3 * block],
  172. (u8*)&si->i_data[block]);
  173. if (S_ISCHR(inode->I_mode) || S_ISBLK(inode->I_mode)) {
  174. uint32_t rdev = fs32_to_host(unixfs->s_endian, si->i_data[0]);
  175. inode->I_rdev = makedev((rdev >> 8) & 255, rdev & 255);
  176. }
  177. si->i_dir_start_lookup = 0;
  178. unixfs_inodelayer_isucceeded(inode);
  179. return inode;
  180. bad_inode:
  181. return NULL;
  182. }
  183. static void
  184. unixfs_internal_iput(struct inode* ip)
  185. {
  186. unixfs_inodelayer_iput(ip);
  187. }
  188. static int
  189. unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
  190. {
  191. if (ino == MACFUSE_ROOTINO)
  192. ino = SYSV_ROOT_INO;
  193. struct inode* ip = unixfs_internal_iget(ino);
  194. if (!ip)
  195. return ENOENT;
  196. unixfs_internal_istat(ip, stbuf);
  197. unixfs_internal_iput(ip);
  198. return 0;
  199. }
  200. static void
  201. unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
  202. {
  203. memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
  204. }
  205. static int
  206. unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
  207. {
  208. if (parentino == MACFUSE_ROOTINO)
  209. parentino = SYSV_ROOT_INO;
  210. stbuf->st_ino = ENOENT;
  211. struct inode* dir = unixfs_internal_iget(parentino);
  212. if (!dir)
  213. return ENOENT;
  214. if (!S_ISDIR(dir->I_mode)) {
  215. unixfs_internal_iput(dir);
  216. return ENOTDIR;
  217. }
  218. int ret = ENOENT, found = 0;
  219. unsigned long namelen = strlen(name);
  220. unsigned long start, n;
  221. unsigned long npages = sysv_dir_pages(dir);
  222. struct sysv_dir_entry* de;
  223. char page[PAGE_SIZE];
  224. char* kaddr = NULL;
  225. start = SYSV_I(dir)->i_dir_start_lookup;
  226. if (start >= npages)
  227. start = 0;
  228. n = start;
  229. do {
  230. int error = sysv_get_page(dir, n, page);
  231. if (!error) {
  232. kaddr = (char*)page;
  233. de = (struct sysv_dir_entry*) kaddr;
  234. kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
  235. for ( ; (char*) de <= kaddr ; de++) {
  236. if (!de->inode)
  237. continue;
  238. if (sysv_namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
  239. found = 1;
  240. goto found;
  241. }
  242. }
  243. }
  244. if (++n >= npages)
  245. n = 0;
  246. } while (n != start);
  247. found:
  248. if (found)
  249. SYSV_I(dir)->i_dir_start_lookup = n;
  250. unixfs_internal_iput(dir);
  251. if (found)
  252. ret = unixfs_internal_igetattr((ino_t)fs16_to_host(unixfs->s_endian,
  253. de->inode), stbuf);
  254. return ret;
  255. }
  256. int
  257. unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
  258. off_t* offset, struct unixfs_direntry* dent)
  259. {
  260. return sysv_next_direntry(dp, dirbuf, offset, dent);
  261. }
  262. static ssize_t
  263. unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
  264. int* error)
  265. {
  266. char* p = buf;
  267. ssize_t done = 0;
  268. ssize_t tomove = 0;
  269. ssize_t remaining = nbyte;
  270. char page[PAGE_SIZE];
  271. sector_t beginpgno = offset >> PAGE_CACHE_SHIFT;
  272. while (remaining > 0) { /* page sized reads */
  273. *error = sysv_get_page(ip, beginpgno, page);
  274. if (*error)
  275. break;
  276. tomove = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
  277. memcpy(p, page, tomove);
  278. remaining -= tomove;
  279. done += tomove;
  280. p += tomove;
  281. beginpgno++;
  282. }
  283. if ((done == 0) && *error)
  284. return -1;
  285. return done;
  286. }
  287. static int
  288. unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
  289. {
  290. struct inode* ip = unixfs_internal_iget(ino);
  291. if (!ip)
  292. return ENOENT;
  293. int error = 0;
  294. size_t linklen =
  295. (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;
  296. char page[PAGE_SIZE];
  297. error = sysv_get_page(ip, (off_t)0, page);
  298. if (error)
  299. goto out;
  300. memcpy(path, page, linklen);
  301. path[linklen] = '\0';
  302. out:
  303. unixfs_internal_iput(ip);
  304. return error;
  305. }
  306. int
  307. unixfs_internal_sanitycheck(void* filsys, off_t disksize)
  308. {
  309. /* handled elsewhere */
  310. return 0;
  311. }
  312. static int
  313. unixfs_internal_statvfs(struct statvfs* svb)
  314. {
  315. memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
  316. return 0;
  317. }