You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

412 lines
6.9 KiB

  1. /*
  2. FUSE: Filesystem in Userspace
  3. Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
  4. Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
  5. This program can be distributed under the terms of the GNU GPL.
  6. See the file COPYING.
  7. gcc -Wall fusexmp.c `pkg-config fuse --cflags --libs` -o fusexmp
  8. */
  9. #define FUSE_USE_VERSION 26
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #ifdef linux
  14. /* For pread()/pwrite()/utimensat() */
  15. #define _XOPEN_SOURCE 700
  16. #endif
  17. #include <fuse.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #include <sys/stat.h>
  23. #include <dirent.h>
  24. #include <errno.h>
  25. #include <sys/time.h>
  26. #ifdef HAVE_SETXATTR
  27. #include <sys/xattr.h>
  28. #endif
  29. static int xmp_getattr(const char *path, struct stat *stbuf)
  30. {
  31. int res;
  32. res = lstat(path, stbuf);
  33. if (res == -1)
  34. return -errno;
  35. return 0;
  36. }
  37. static int xmp_access(const char *path, int mask)
  38. {
  39. int res;
  40. res = access(path, mask);
  41. if (res == -1)
  42. return -errno;
  43. return 0;
  44. }
  45. static int xmp_readlink(const char *path, char *buf, size_t size)
  46. {
  47. int res;
  48. res = readlink(path, buf, size - 1);
  49. if (res == -1)
  50. return -errno;
  51. buf[res] = '\0';
  52. return 0;
  53. }
  54. static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  55. off_t offset, struct fuse_file_info *fi)
  56. {
  57. DIR *dp;
  58. struct dirent *de;
  59. (void) offset;
  60. (void) fi;
  61. dp = opendir(path);
  62. if (dp == NULL)
  63. return -errno;
  64. while ((de = readdir(dp)) != NULL) {
  65. struct stat st;
  66. memset(&st, 0, sizeof(st));
  67. st.st_ino = de->d_ino;
  68. st.st_mode = de->d_type << 12;
  69. if (filler(buf, de->d_name, &st, 0))
  70. break;
  71. }
  72. closedir(dp);
  73. return 0;
  74. }
  75. static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
  76. {
  77. int res;
  78. /* On Linux this could just be 'mknod(path, mode, rdev)' but this
  79. is more portable */
  80. if (S_ISREG(mode)) {
  81. res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
  82. if (res >= 0)
  83. res = close(res);
  84. } else if (S_ISFIFO(mode))
  85. res = mkfifo(path, mode);
  86. else
  87. res = mknod(path, mode, rdev);
  88. if (res == -1)
  89. return -errno;
  90. return 0;
  91. }
  92. static int xmp_mkdir(const char *path, mode_t mode)
  93. {
  94. int res;
  95. res = mkdir(path, mode);
  96. if (res == -1)
  97. return -errno;
  98. return 0;
  99. }
  100. static int xmp_unlink(const char *path)
  101. {
  102. int res;
  103. res = unlink(path);
  104. if (res == -1)
  105. return -errno;
  106. return 0;
  107. }
  108. static int xmp_rmdir(const char *path)
  109. {
  110. int res;
  111. res = rmdir(path);
  112. if (res == -1)
  113. return -errno;
  114. return 0;
  115. }
  116. static int xmp_symlink(const char *from, const char *to)
  117. {
  118. int res;
  119. res = symlink(from, to);
  120. if (res == -1)
  121. return -errno;
  122. return 0;
  123. }
  124. static int xmp_rename(const char *from, const char *to)
  125. {
  126. int res;
  127. res = rename(from, to);
  128. if (res == -1)
  129. return -errno;
  130. return 0;
  131. }
  132. static int xmp_link(const char *from, const char *to)
  133. {
  134. int res;
  135. res = link(from, to);
  136. if (res == -1)
  137. return -errno;
  138. return 0;
  139. }
  140. static int xmp_chmod(const char *path, mode_t mode)
  141. {
  142. int res;
  143. res = chmod(path, mode);
  144. if (res == -1)
  145. return -errno;
  146. return 0;
  147. }
  148. static int xmp_chown(const char *path, uid_t uid, gid_t gid)
  149. {
  150. int res;
  151. res = lchown(path, uid, gid);
  152. if (res == -1)
  153. return -errno;
  154. return 0;
  155. }
  156. static int xmp_truncate(const char *path, off_t size)
  157. {
  158. int res;
  159. res = truncate(path, size);
  160. if (res == -1)
  161. return -errno;
  162. return 0;
  163. }
  164. #ifdef HAVE_UTIMENSAT
  165. static int xmp_utimens(const char *path, const struct timespec ts[2])
  166. {
  167. int res;
  168. /* don't use utime/utimes since they follow symlinks */
  169. res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
  170. if (res == -1)
  171. return -errno;
  172. return 0;
  173. }
  174. #endif
  175. static int xmp_open(const char *path, struct fuse_file_info *fi)
  176. {
  177. int res;
  178. res = open(path, fi->flags);
  179. if (res == -1)
  180. return -errno;
  181. close(res);
  182. return 0;
  183. }
  184. static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
  185. struct fuse_file_info *fi)
  186. {
  187. int fd;
  188. int res;
  189. (void) fi;
  190. fd = open(path, O_RDONLY);
  191. if (fd == -1)
  192. return -errno;
  193. res = pread(fd, buf, size, offset);
  194. if (res == -1)
  195. res = -errno;
  196. close(fd);
  197. return res;
  198. }
  199. static int xmp_write(const char *path, const char *buf, size_t size,
  200. off_t offset, struct fuse_file_info *fi)
  201. {
  202. int fd;
  203. int res;
  204. (void) fi;
  205. fd = open(path, O_WRONLY);
  206. if (fd == -1)
  207. return -errno;
  208. res = pwrite(fd, buf, size, offset);
  209. if (res == -1)
  210. res = -errno;
  211. close(fd);
  212. return res;
  213. }
  214. static int xmp_statfs(const char *path, struct statvfs *stbuf)
  215. {
  216. int res;
  217. res = statvfs(path, stbuf);
  218. if (res == -1)
  219. return -errno;
  220. return 0;
  221. }
  222. static int xmp_release(const char *path, struct fuse_file_info *fi)
  223. {
  224. /* Just a stub. This method is optional and can safely be left
  225. unimplemented */
  226. (void) path;
  227. (void) fi;
  228. return 0;
  229. }
  230. static int xmp_fsync(const char *path, int isdatasync,
  231. struct fuse_file_info *fi)
  232. {
  233. /* Just a stub. This method is optional and can safely be left
  234. unimplemented */
  235. (void) path;
  236. (void) isdatasync;
  237. (void) fi;
  238. return 0;
  239. }
  240. #ifdef HAVE_POSIX_FALLOCATE
  241. static int xmp_fallocate(const char *path, int mode,
  242. off_t offset, off_t length, struct fuse_file_info *fi)
  243. {
  244. int fd;
  245. int res;
  246. (void) fi;
  247. if (mode)
  248. return -EOPNOTSUPP;
  249. fd = open(path, O_WRONLY);
  250. if (fd == -1)
  251. return -errno;
  252. res = -posix_fallocate(fd, offset, length);
  253. close(fd);
  254. return res;
  255. }
  256. #endif
  257. #ifdef HAVE_SETXATTR
  258. /* xattr operations are optional and can safely be left unimplemented */
  259. static int xmp_setxattr(const char *path, const char *name, const char *value,
  260. size_t size, int flags)
  261. {
  262. int res = lsetxattr(path, name, value, size, flags);
  263. if (res == -1)
  264. return -errno;
  265. return 0;
  266. }
  267. static int xmp_getxattr(const char *path, const char *name, char *value,
  268. size_t size)
  269. {
  270. int res = lgetxattr(path, name, value, size);
  271. if (res == -1)
  272. return -errno;
  273. return res;
  274. }
  275. static int xmp_listxattr(const char *path, char *list, size_t size)
  276. {
  277. int res = llistxattr(path, list, size);
  278. if (res == -1)
  279. return -errno;
  280. return res;
  281. }
  282. static int xmp_removexattr(const char *path, const char *name)
  283. {
  284. int res = lremovexattr(path, name);
  285. if (res == -1)
  286. return -errno;
  287. return 0;
  288. }
  289. #endif /* HAVE_SETXATTR */
  290. static struct fuse_operations xmp_oper = {
  291. .getattr = xmp_getattr,
  292. .access = xmp_access,
  293. .readlink = xmp_readlink,
  294. .readdir = xmp_readdir,
  295. .mknod = xmp_mknod,
  296. .mkdir = xmp_mkdir,
  297. .symlink = xmp_symlink,
  298. .unlink = xmp_unlink,
  299. .rmdir = xmp_rmdir,
  300. .rename = xmp_rename,
  301. .link = xmp_link,
  302. .chmod = xmp_chmod,
  303. .chown = xmp_chown,
  304. .truncate = xmp_truncate,
  305. #ifdef HAVE_UTIMENSAT
  306. .utimens = xmp_utimens,
  307. #endif
  308. .open = xmp_open,
  309. .read = xmp_read,
  310. .write = xmp_write,
  311. .statfs = xmp_statfs,
  312. .release = xmp_release,
  313. .fsync = xmp_fsync,
  314. #ifdef HAVE_POSIX_FALLOCATE
  315. .fallocate = xmp_fallocate,
  316. #endif
  317. #ifdef HAVE_SETXATTR
  318. .setxattr = xmp_setxattr,
  319. .getxattr = xmp_getxattr,
  320. .listxattr = xmp_listxattr,
  321. .removexattr = xmp_removexattr,
  322. #endif
  323. };
  324. int main(int argc, char *argv[])
  325. {
  326. umask(0);
  327. return fuse_main(argc, argv, &xmp_oper, NULL);
  328. }