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.

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