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.

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