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.

406 lines
7.7 KiB

  1. #define _FILE_OFFSET_BITS 64
  2. #include "fuse_attr.h"
  3. #include "fuse_dirent.h"
  4. #include "fuse_direntplus.h"
  5. #include "fuse_dirents.h"
  6. #include "fuse_entry.h"
  7. #include "linux_dirent64.h"
  8. #include "stat_utils.h"
  9. #include <dirent.h>
  10. #include <errno.h>
  11. #include <stddef.h>
  12. #include <stdint.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. /* 32KB - same as glibc getdents buffer size */
  17. #define DEFAULT_SIZE (1024 * 32)
  18. static
  19. uint64_t
  20. round_up(const uint64_t number_,
  21. const uint64_t multiple_)
  22. {
  23. return (((number_ + multiple_ - 1) / multiple_) * multiple_);
  24. }
  25. static
  26. uint64_t
  27. align_uint64_t(uint64_t v_)
  28. {
  29. return ((v_ + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1));
  30. }
  31. static
  32. uint64_t
  33. fuse_dirent_size(const uint64_t namelen_)
  34. {
  35. uint64_t rv;
  36. rv = offsetof(fuse_dirent_t,name);
  37. rv += namelen_;
  38. rv = align_uint64_t(rv);
  39. return rv;
  40. }
  41. static
  42. uint64_t
  43. fuse_direntplus_size(const uint64_t namelen_)
  44. {
  45. uint64_t rv;
  46. rv = offsetof(fuse_direntplus_t,dirent.name);
  47. rv += namelen_;
  48. rv = align_uint64_t(rv);
  49. return rv;
  50. }
  51. static
  52. int
  53. fuse_dirents_buf_resize(fuse_dirents_t *d_,
  54. uint64_t size_)
  55. {
  56. if((kv_size(d_->data) + size_) >= kv_max(d_->data))
  57. {
  58. uint64_t new_size;
  59. new_size = round_up((kv_size(d_->data) + size_),DEFAULT_SIZE);
  60. kv_resize(char,d_->data,new_size);
  61. if(d_->data.a == NULL)
  62. return -ENOMEM;
  63. }
  64. return 0;
  65. }
  66. static
  67. void*
  68. fuse_dirents_dirent_alloc(fuse_dirents_t *d_,
  69. uint64_t namelen_)
  70. {
  71. int rv;
  72. uint64_t size;
  73. fuse_dirent_t *d;
  74. size = fuse_dirent_size(namelen_);
  75. rv = fuse_dirents_buf_resize(d_,size);
  76. if(rv)
  77. return NULL;
  78. d = (fuse_dirent_t*)&kv_end(d_->data);
  79. kv_size(d_->data) += size;
  80. return d;
  81. }
  82. static
  83. void*
  84. fuse_dirents_direntplus_alloc(fuse_dirents_t *d_,
  85. uint64_t namelen_)
  86. {
  87. int rv;
  88. uint64_t size;
  89. fuse_dirent_t *d;
  90. size = fuse_direntplus_size(namelen_);
  91. rv = fuse_dirents_buf_resize(d_,size);
  92. if(rv)
  93. return NULL;
  94. d = (fuse_dirent_t*)&kv_end(d_->data);
  95. kv_size(d_->data) += size;
  96. return d;
  97. }
  98. static
  99. void
  100. fuse_dirents_fill_attr(fuse_attr_t *attr_,
  101. const struct stat *st_)
  102. {
  103. attr_->ino = st_->st_ino;
  104. attr_->size = st_->st_size;
  105. attr_->blocks = st_->st_blocks;
  106. attr_->atime = st_->st_atime;
  107. attr_->mtime = st_->st_mtime;
  108. attr_->ctime = st_->st_ctime;
  109. attr_->atimensec = ST_ATIM_NSEC(st_);
  110. attr_->mtimensec = ST_MTIM_NSEC(st_);
  111. attr_->ctimensec = ST_CTIM_NSEC(st_);
  112. attr_->mode = st_->st_mode;
  113. attr_->nlink = st_->st_nlink;
  114. attr_->uid = st_->st_uid;
  115. attr_->gid = st_->st_gid;
  116. attr_->rdev = st_->st_rdev;
  117. attr_->blksize = st_->st_blksize;
  118. }
  119. fuse_dirent_t*
  120. fuse_dirent_next(fuse_dirent_t *cur_)
  121. {
  122. char *buf;
  123. buf = (char*)cur_;
  124. buf += fuse_dirent_size(cur_->namelen);
  125. return (fuse_dirent_t*)buf;
  126. }
  127. fuse_direntplus_t*
  128. fuse_direntplus_next(fuse_direntplus_t *cur_)
  129. {
  130. char *buf;
  131. buf = (char*)cur_;
  132. buf += fuse_direntplus_size(cur_->dirent.namelen);
  133. return (fuse_direntplus_t*)buf;
  134. }
  135. fuse_dirent_t*
  136. fuse_dirent_find(fuse_dirents_t *d_,
  137. const uint64_t ino_)
  138. {
  139. fuse_dirent_t *cur;
  140. fuse_dirent_t *end;
  141. if(d_->type != NORMAL)
  142. return NULL;
  143. cur = (fuse_dirent_t*)&kv_first(d_->data);
  144. end = (fuse_dirent_t*)&kv_end(d_->data);
  145. while(cur < end)
  146. {
  147. if(cur->ino == ino_)
  148. return cur;
  149. cur = fuse_dirent_next(cur);
  150. }
  151. return NULL;
  152. }
  153. fuse_direntplus_t*
  154. fuse_direntplus_find(fuse_dirents_t *d_,
  155. const uint64_t ino_)
  156. {
  157. fuse_direntplus_t *cur;
  158. fuse_direntplus_t *end;
  159. if(d_->type != PLUS)
  160. return NULL;
  161. cur = (fuse_direntplus_t*)&kv_first(d_->data);
  162. end = (fuse_direntplus_t*)&kv_end(d_->data);
  163. while(cur < end)
  164. {
  165. if(cur->dirent.ino == ino_)
  166. return cur;
  167. cur = fuse_direntplus_next(cur);
  168. }
  169. return NULL;
  170. }
  171. void*
  172. fuse_dirents_find(fuse_dirents_t *d_,
  173. const uint64_t ino_)
  174. {
  175. switch(d_->type)
  176. {
  177. default:
  178. case UNSET:
  179. return NULL;
  180. case NORMAL:
  181. return fuse_dirent_find(d_,ino_);
  182. case PLUS:
  183. return fuse_direntplus_find(d_,ino_);
  184. }
  185. }
  186. int
  187. fuse_dirents_convert_plus2normal(fuse_dirents_t *d_)
  188. {
  189. return -ENOSYS;
  190. }
  191. int
  192. fuse_dirents_add(fuse_dirents_t *d_,
  193. const struct dirent *dirent_,
  194. const uint64_t namelen_)
  195. {
  196. fuse_dirent_t *d;
  197. switch(d_->type)
  198. {
  199. case UNSET:
  200. d_->type = NORMAL;
  201. break;
  202. case NORMAL:
  203. break;
  204. case PLUS:
  205. return -EINVAL;
  206. }
  207. d = fuse_dirents_dirent_alloc(d_,namelen_);
  208. if(d == NULL)
  209. return -ENOMEM;
  210. d->off = kv_size(d_->offs);
  211. kv_push(uint32_t,d_->offs,kv_size(d_->data));
  212. d->ino = dirent_->d_ino;
  213. d->namelen = namelen_;
  214. d->type = dirent_->d_type;
  215. memcpy(d->name,dirent_->d_name,namelen_);
  216. return 0;
  217. }
  218. int
  219. fuse_dirents_add_plus(fuse_dirents_t *d_,
  220. const struct dirent *dirent_,
  221. const uint64_t namelen_,
  222. const fuse_entry_t *entry_,
  223. const struct stat *st_)
  224. {
  225. fuse_direntplus_t *d;
  226. switch(d_->type)
  227. {
  228. case UNSET:
  229. d_->type = PLUS;
  230. break;
  231. case NORMAL:
  232. return -EINVAL;
  233. case PLUS:
  234. break;
  235. }
  236. d = fuse_dirents_direntplus_alloc(d_,namelen_);
  237. if(d == NULL)
  238. return -ENOMEM;
  239. d->dirent.off = kv_size(d_->offs);
  240. kv_push(uint32_t,d_->offs,kv_size(d_->data));
  241. d->dirent.ino = dirent_->d_ino;
  242. d->dirent.namelen = namelen_;
  243. d->dirent.type = dirent_->d_type;
  244. memcpy(d->dirent.name,dirent_->d_name,namelen_);
  245. d->entry = *entry_;
  246. fuse_dirents_fill_attr(&d->attr,st_);
  247. return 0;
  248. }
  249. int
  250. fuse_dirents_add_linux(fuse_dirents_t *d_,
  251. const linux_dirent64_t *dirent_,
  252. const uint64_t namelen_)
  253. {
  254. fuse_dirent_t *d;
  255. switch(d_->type)
  256. {
  257. case UNSET:
  258. d_->type = NORMAL;
  259. break;
  260. case NORMAL:
  261. break;
  262. case PLUS:
  263. return -EINVAL;
  264. }
  265. d = fuse_dirents_dirent_alloc(d_,namelen_);
  266. if(d == NULL)
  267. return -ENOMEM;
  268. d->off = kv_size(d_->offs);
  269. kv_push(uint32_t,d_->offs,kv_size(d_->data));
  270. d->ino = dirent_->ino;
  271. d->namelen = namelen_;
  272. d->type = dirent_->type;
  273. memcpy(d->name,dirent_->name,namelen_);
  274. return 0;
  275. }
  276. int
  277. fuse_dirents_add_linux_plus(fuse_dirents_t *d_,
  278. const linux_dirent64_t *dirent_,
  279. const uint64_t namelen_,
  280. const fuse_entry_t *entry_,
  281. const struct stat *st_)
  282. {
  283. fuse_direntplus_t *d;
  284. switch(d_->type)
  285. {
  286. case UNSET:
  287. d_->type = PLUS;
  288. break;
  289. case NORMAL:
  290. return -EINVAL;
  291. case PLUS:
  292. break;
  293. }
  294. d = fuse_dirents_direntplus_alloc(d_,namelen_);
  295. if(d == NULL)
  296. return -ENOMEM;
  297. d->dirent.off = kv_size(d_->offs);
  298. kv_push(uint32_t,d_->offs,kv_size(d_->data));
  299. d->dirent.ino = dirent_->ino;
  300. d->dirent.namelen = namelen_;
  301. d->dirent.type = dirent_->type;
  302. memcpy(d->dirent.name,dirent_->name,namelen_);
  303. d->entry = *entry_;
  304. fuse_dirents_fill_attr(&d->attr,st_);
  305. return 0;
  306. }
  307. void
  308. fuse_dirents_reset(fuse_dirents_t *d_)
  309. {
  310. d_->type = UNSET;
  311. kv_size(d_->data) = 0;
  312. kv_size(d_->offs) = 1;
  313. }
  314. int
  315. fuse_dirents_init(fuse_dirents_t *d_)
  316. {
  317. d_->type = UNSET;
  318. kv_init(d_->data);
  319. kv_resize(char,d_->data,DEFAULT_SIZE);
  320. if(d_->data.a == NULL)
  321. return -ENOMEM;
  322. kv_init(d_->offs);
  323. kv_resize(uint32_t,d_->offs,64);
  324. kv_push(uint32_t,d_->offs,0);
  325. return 0;
  326. }
  327. void
  328. fuse_dirents_free(fuse_dirents_t *d_)
  329. {
  330. kv_destroy(d_->data);
  331. kv_destroy(d_->offs);
  332. }