shim_fs.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * shim_fs.c
  15. *
  16. * Implementation of system call "unlink", "unlinkat", "mkdir", "mkdirat",
  17. * "rmdir", "umask", "chmod", "fchmod", "fchmodat", "rename", "renameat" and
  18. * "sendfile".
  19. */
  20. #define __KERNEL__
  21. #include <asm/mman.h>
  22. #include <errno.h>
  23. #include <linux/fcntl.h>
  24. #include <linux/stat.h>
  25. #include <pal.h>
  26. #include <pal_error.h>
  27. #include <shim_fs.h>
  28. #include <shim_handle.h>
  29. #include <shim_internal.h>
  30. #include <shim_table.h>
  31. #include <shim_thread.h>
  32. #include <shim_utils.h>
  33. /* The kernel would look up the parent directory, and remove the child from the inode. But we are
  34. * working with the PAL, so we open the file, truncate and close it. */
  35. int shim_do_unlink(const char* file) {
  36. if (!file)
  37. return -EINVAL;
  38. if (test_user_string(file))
  39. return -EFAULT;
  40. struct shim_dentry* dent = NULL;
  41. int ret = 0;
  42. if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent, NULL)) < 0)
  43. return ret;
  44. if (!dent->parent)
  45. return -EACCES;
  46. if (dent->state & DENTRY_ISDIRECTORY)
  47. return -EISDIR;
  48. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->unlink) {
  49. if ((ret = dent->fs->d_ops->unlink(dent->parent, dent)) < 0)
  50. return ret;
  51. } else {
  52. dent->state |= DENTRY_PERSIST;
  53. }
  54. dent->state |= DENTRY_NEGATIVE;
  55. put_dentry(dent);
  56. return 0;
  57. }
  58. int shim_do_unlinkat(int dfd, const char* pathname, int flag) {
  59. if (!pathname)
  60. return -EINVAL;
  61. if (test_user_string(pathname))
  62. return -EFAULT;
  63. if (flag & ~AT_REMOVEDIR)
  64. return -EINVAL;
  65. struct shim_dentry* dir = NULL;
  66. struct shim_dentry* dent = NULL;
  67. int ret = 0;
  68. if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
  69. return ret;
  70. if ((ret = path_lookupat(dir, pathname, LOOKUP_OPEN, &dent, NULL)) < 0)
  71. goto out;
  72. if (!dent->parent) {
  73. ret = -EACCES;
  74. goto out_dent;
  75. }
  76. if (flag & AT_REMOVEDIR) {
  77. if (!(dent->state & DENTRY_ISDIRECTORY))
  78. return -ENOTDIR;
  79. } else {
  80. if (dent->state & DENTRY_ISDIRECTORY)
  81. return -EISDIR;
  82. }
  83. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->unlink) {
  84. if ((ret = dent->fs->d_ops->unlink(dent->parent, dent)) < 0)
  85. return ret;
  86. } else {
  87. dent->state |= DENTRY_PERSIST;
  88. }
  89. if (flag & AT_REMOVEDIR)
  90. dent->state &= ~DENTRY_ISDIRECTORY;
  91. dent->state |= DENTRY_NEGATIVE;
  92. out_dent:
  93. put_dentry(dent);
  94. out:
  95. put_dentry(dir);
  96. return ret;
  97. }
  98. int shim_do_mkdir(const char* pathname, int mode) {
  99. return open_namei(NULL, NULL, pathname, O_CREAT | O_EXCL | O_DIRECTORY, mode, NULL);
  100. }
  101. int shim_do_mkdirat(int dfd, const char* pathname, int mode) {
  102. if (!pathname)
  103. return -EINVAL;
  104. if (test_user_string(pathname))
  105. return -EFAULT;
  106. struct shim_dentry* dir = NULL;
  107. int ret = 0;
  108. if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
  109. return ret;
  110. ret = open_namei(NULL, dir, pathname, O_CREAT | O_EXCL | O_DIRECTORY, mode, NULL);
  111. put_dentry(dir);
  112. return ret;
  113. }
  114. int shim_do_rmdir(const char* pathname) {
  115. int ret = 0;
  116. struct shim_dentry* dent = NULL;
  117. if (!pathname)
  118. return -EINVAL;
  119. if (test_user_string(pathname))
  120. return -EFAULT;
  121. if ((ret = path_lookupat(NULL, pathname, LOOKUP_OPEN | LOOKUP_DIRECTORY, &dent, NULL)) < 0)
  122. return ret;
  123. if (!dent->parent) {
  124. ret = -EACCES;
  125. goto out;
  126. }
  127. if (!(dent->state & DENTRY_ISDIRECTORY)) {
  128. ret = -ENOTDIR;
  129. goto out;
  130. }
  131. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->unlink) {
  132. if ((ret = dent->fs->d_ops->unlink(dent->parent, dent)) < 0)
  133. goto out;
  134. } else {
  135. dent->state |= DENTRY_PERSIST;
  136. }
  137. dent->state &= ~DENTRY_ISDIRECTORY;
  138. dent->state |= DENTRY_NEGATIVE;
  139. out:
  140. put_dentry(dent);
  141. return ret;
  142. }
  143. mode_t shim_do_umask(mode_t mask) {
  144. struct shim_thread* cur = get_cur_thread();
  145. lock(&cur->lock);
  146. mode_t old = cur->umask;
  147. cur->umask = mask & 0777;
  148. unlock(&cur->lock);
  149. return old;
  150. }
  151. int shim_do_chmod(const char* path, mode_t mode) {
  152. struct shim_dentry* dent = NULL;
  153. int ret = 0;
  154. if (test_user_string(path))
  155. return -EFAULT;
  156. if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
  157. return ret;
  158. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->chmod) {
  159. if ((ret = dent->fs->d_ops->chmod(dent, mode)) < 0)
  160. goto out;
  161. } else {
  162. dent->state |= DENTRY_PERSIST;
  163. }
  164. dent->mode = mode;
  165. out:
  166. put_dentry(dent);
  167. return ret;
  168. }
  169. int shim_do_fchmodat(int dfd, const char* filename, mode_t mode) {
  170. if (!filename)
  171. return -EINVAL;
  172. if (test_user_string(filename))
  173. return -EFAULT;
  174. struct shim_dentry* dir = NULL;
  175. struct shim_dentry* dent = NULL;
  176. int ret = 0;
  177. if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
  178. return ret;
  179. if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
  180. goto out;
  181. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->chmod) {
  182. if ((ret = dent->fs->d_ops->chmod(dent, mode)) < 0)
  183. goto out_dent;
  184. } else {
  185. dent->state |= DENTRY_PERSIST;
  186. }
  187. dent->mode = mode;
  188. out_dent:
  189. put_dentry(dent);
  190. out:
  191. put_dentry(dir);
  192. return ret;
  193. }
  194. int shim_do_fchmod(int fd, mode_t mode) {
  195. struct shim_handle* hdl = get_fd_handle(fd, NULL, NULL);
  196. if (!hdl)
  197. return -EBADF;
  198. struct shim_dentry* dent = hdl->dentry;
  199. int ret = 0;
  200. if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->chmod) {
  201. if ((ret = dent->fs->d_ops->chmod(dent, mode)) < 0)
  202. goto out;
  203. } else {
  204. dent->state |= DENTRY_PERSIST;
  205. }
  206. dent->mode = mode;
  207. out:
  208. put_handle(hdl);
  209. return ret;
  210. }
  211. int shim_do_chown(const char* path, uid_t uid, gid_t gid) {
  212. struct shim_dentry* dent = NULL;
  213. int ret = 0;
  214. __UNUSED(uid);
  215. __UNUSED(gid);
  216. if (!path)
  217. return -EINVAL;
  218. if (test_user_string(path))
  219. return -EFAULT;
  220. if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
  221. return ret;
  222. /* XXX: do nothing now */
  223. put_dentry(dent);
  224. return ret;
  225. }
  226. int shim_do_fchownat(int dfd, const char* filename, uid_t uid, gid_t gid, int flags) {
  227. __UNUSED(flags);
  228. __UNUSED(uid);
  229. __UNUSED(gid);
  230. if (!filename)
  231. return -EINVAL;
  232. if (test_user_string(filename))
  233. return -EFAULT;
  234. struct shim_dentry* dir = NULL;
  235. struct shim_dentry* dent = NULL;
  236. int ret = 0;
  237. if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
  238. return ret;
  239. if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
  240. goto out;
  241. /* XXX: do nothing now */
  242. put_dentry(dent);
  243. out:
  244. put_dentry(dir);
  245. return ret;
  246. }
  247. int shim_do_fchown(int fd, uid_t uid, gid_t gid) {
  248. __UNUSED(uid);
  249. __UNUSED(gid);
  250. struct shim_handle* hdl = get_fd_handle(fd, NULL, NULL);
  251. if (!hdl)
  252. return -EBADF;
  253. /* XXX: do nothing now */
  254. return 0;
  255. }
  256. #define MAP_SIZE (g_pal_alloc_align * 4)
  257. #define BUF_SIZE 2048
  258. static ssize_t handle_copy(struct shim_handle* hdli, off_t* offseti, struct shim_handle* hdlo,
  259. off_t* offseto, ssize_t count) {
  260. struct shim_mount* fsi = hdli->fs;
  261. struct shim_mount* fso = hdlo->fs;
  262. if (!count)
  263. return 0;
  264. if (!fsi || !fsi->fs_ops || !fso || !fso->fs_ops)
  265. return -EACCES;
  266. bool do_mapi = fsi->fs_ops->mmap != NULL;
  267. bool do_mapo = fso->fs_ops->mmap != NULL;
  268. bool do_marki = false;
  269. bool do_marko = false;
  270. int offi = 0, offo = 0;
  271. if (offseti) {
  272. if (!fsi->fs_ops->seek)
  273. return -EACCES;
  274. offi = *offseti;
  275. fsi->fs_ops->seek(hdli, offi, SEEK_SET);
  276. } else {
  277. if (!fsi->fs_ops->seek || (offi = fsi->fs_ops->seek(hdli, 0, SEEK_CUR)) < 0)
  278. do_mapi = false;
  279. }
  280. if (offseto) {
  281. if (!fso->fs_ops->seek)
  282. return -EACCES;
  283. offo = *offseto;
  284. fso->fs_ops->seek(hdlo, offo, SEEK_SET);
  285. } else {
  286. if (!fso->fs_ops->seek || (offo = fso->fs_ops->seek(hdlo, 0, SEEK_CUR)) < 0)
  287. do_mapo = false;
  288. }
  289. if (do_mapi) {
  290. int size;
  291. if (fsi->fs_ops->poll && (size = fsi->fs_ops->poll(hdli, FS_POLL_SZ)) >= 0) {
  292. if (count == -1 || count > size - offi)
  293. count = size - offi;
  294. if (!count)
  295. return 0;
  296. } else {
  297. do_mapi = false;
  298. }
  299. }
  300. if (do_mapo && count > 0)
  301. do {
  302. int size;
  303. if (!fso->fs_ops->poll || (size = fso->fs_ops->poll(hdlo, FS_POLL_SZ)) < 0) {
  304. do_mapo = false;
  305. break;
  306. }
  307. if (offo + count < size)
  308. break;
  309. if (!fso->fs_ops->truncate || fso->fs_ops->truncate(hdlo, offo + count) < 0) {
  310. do_mapo = false;
  311. break;
  312. }
  313. } while (0);
  314. void* bufi = NULL;
  315. void* bufo = NULL;
  316. int bytes = 0;
  317. int bufsize = MAP_SIZE;
  318. int copysize = 0;
  319. if (!do_mapi && (hdli->flags & O_NONBLOCK) && fsi->fs_ops->setflags) {
  320. int ret = fsi->fs_ops->setflags(hdli, 0);
  321. if (!ret) {
  322. debug("mark handle %s as blocking\n", qstrgetstr(&hdli->uri));
  323. do_marki = true;
  324. }
  325. }
  326. if (!do_mapo && (hdlo->flags & O_NONBLOCK) && fso->fs_ops->setflags) {
  327. int ret = fso->fs_ops->setflags(hdlo, 0);
  328. if (!ret) {
  329. debug("mark handle %s as blocking\n", qstrgetstr(&hdlo->uri));
  330. do_marko = true;
  331. }
  332. }
  333. assert(count);
  334. do {
  335. int boffi = 0, boffo = 0;
  336. int expectsize = bufsize;
  337. if (count > 0 && bufsize > count - bytes)
  338. expectsize = bufsize = count - bytes;
  339. if (do_mapi && !bufi) {
  340. boffi = offi - ALLOC_ALIGN_DOWN(offi);
  341. if (fsi->fs_ops->mmap(hdli, &bufi, ALLOC_ALIGN_UP(bufsize + boffi), PROT_READ, MAP_FILE,
  342. offi - boffi) < 0) {
  343. do_mapi = false;
  344. boffi = 0;
  345. if ((hdli->flags & O_NONBLOCK) && fsi->fs_ops->setflags) {
  346. int ret = fsi->fs_ops->setflags(hdli, 0);
  347. if (!ret) {
  348. debug("mark handle %s as blocking\n", qstrgetstr(&hdli->uri));
  349. do_marki = true;
  350. }
  351. }
  352. if (fsi->fs_ops->seek)
  353. offi = fsi->fs_ops->seek(hdli, offi, SEEK_SET);
  354. }
  355. }
  356. if (do_mapo && !bufo) {
  357. boffo = offo - ALLOC_ALIGN_DOWN(offo);
  358. if (fso->fs_ops->mmap(hdlo, &bufo, ALLOC_ALIGN_UP(bufsize + boffo), PROT_WRITE,
  359. MAP_FILE, offo - boffo) < 0) {
  360. do_mapo = false;
  361. boffo = 0;
  362. if ((hdlo->flags & O_NONBLOCK) && fso->fs_ops->setflags) {
  363. int ret = fso->fs_ops->setflags(hdlo, 0);
  364. if (!ret) {
  365. debug("mark handle %s as blocking\n", qstrgetstr(&hdlo->uri));
  366. do_marko = true;
  367. }
  368. }
  369. if (fso->fs_ops->seek)
  370. offo = fso->fs_ops->seek(hdlo, offo, SEEK_SET);
  371. }
  372. }
  373. if (do_mapi && do_mapo) {
  374. copysize = count - bytes > bufsize ? bufsize : count - bytes;
  375. memcpy(bufo + boffo, bufi + boffi, copysize);
  376. DkVirtualMemoryFree(bufi, ALLOC_ALIGN_UP(bufsize + boffi));
  377. bufi = NULL;
  378. DkVirtualMemoryFree(bufo, ALLOC_ALIGN_UP(bufsize + boffo));
  379. bufo = NULL;
  380. } else if (do_mapo) {
  381. copysize = fsi->fs_ops->read(hdli, bufo + boffo, bufsize);
  382. DkVirtualMemoryFree(bufo, ALLOC_ALIGN_UP(bufsize + boffo));
  383. bufo = NULL;
  384. if (copysize < 0)
  385. break;
  386. } else if (do_mapi) {
  387. copysize = fso->fs_ops->write(hdlo, bufi + boffi, bufsize);
  388. DkVirtualMemoryFree(bufi, ALLOC_ALIGN_UP(bufsize + boffi));
  389. bufi = NULL;
  390. if (copysize < 0)
  391. break;
  392. } else {
  393. if (!bufi)
  394. bufi = __alloca((bufsize = (bufsize > BUF_SIZE) ? BUF_SIZE : bufsize));
  395. copysize = fsi->fs_ops->read(hdli, bufi, bufsize);
  396. if (copysize <= 0)
  397. break;
  398. expectsize = copysize;
  399. copysize = fso->fs_ops->write(hdlo, bufi, expectsize);
  400. if (copysize < 0)
  401. break;
  402. }
  403. debug("copy %d bytes\n", copysize);
  404. bytes += copysize;
  405. offi += copysize;
  406. offo += copysize;
  407. if (copysize < expectsize)
  408. break;
  409. } while (bytes < count);
  410. if (copysize < 0 || (count > 0 && bytes < count)) {
  411. int ret = copysize < 0 ? copysize : -EAGAIN;
  412. if (bytes) {
  413. if (fsi->fs_ops->seek)
  414. fsi->fs_ops->seek(hdli, offi - bytes, SEEK_SET);
  415. if (fso->fs_ops->seek)
  416. fso->fs_ops->seek(hdlo, offo - bytes, SEEK_SET);
  417. }
  418. return ret;
  419. }
  420. if (do_marki && (hdli->flags & O_NONBLOCK)) {
  421. debug("mark handle %s as nonblocking\n", qstrgetstr(&hdli->uri));
  422. fsi->fs_ops->setflags(hdli, O_NONBLOCK);
  423. }
  424. if (do_marko && (hdlo->flags & O_NONBLOCK)) {
  425. debug("mark handle %s as nonblocking\n", qstrgetstr(&hdlo->uri));
  426. fso->fs_ops->setflags(hdlo, O_NONBLOCK);
  427. }
  428. if (do_mapi) {
  429. if (fsi->fs_ops->seek)
  430. fsi->fs_ops->seek(hdli, offi, SEEK_SET);
  431. }
  432. if (offseti)
  433. *offseti = offi;
  434. if (do_mapo) {
  435. if (fso->fs_ops->seek)
  436. fso->fs_ops->seek(hdlo, offo, SEEK_SET);
  437. }
  438. if (offseto)
  439. *offseto = offo;
  440. return bytes;
  441. }
  442. static int do_rename(struct shim_dentry* old_dent, struct shim_dentry* new_dent) {
  443. if ((old_dent->type != S_IFREG) ||
  444. (!(new_dent->state & DENTRY_NEGATIVE) && (new_dent->type != S_IFREG))) {
  445. /* Current implementation of fs does not allow for renaming anything but regular files */
  446. return -ENOSYS;
  447. }
  448. if (old_dent->fs != new_dent->fs) {
  449. /* Disallow cross mount renames */
  450. return -EXDEV;
  451. }
  452. if (!old_dent->fs || !old_dent->fs->d_ops || !old_dent->fs->d_ops->rename) {
  453. return -EPERM;
  454. }
  455. if (old_dent->state & DENTRY_ISDIRECTORY) {
  456. if (!(new_dent->state & DENTRY_NEGATIVE)) {
  457. if (!(new_dent->state & DENTRY_ISDIRECTORY)) {
  458. return -ENOTDIR;
  459. }
  460. if (new_dent->nchildren > 0) {
  461. return -ENOTEMPTY;
  462. }
  463. } else {
  464. /* destination is a negative dentry and needs to be marked as a directory, since source
  465. * is a directory */
  466. new_dent->state |= DENTRY_ISDIRECTORY;
  467. }
  468. } else if (new_dent->state & DENTRY_ISDIRECTORY) {
  469. return -EISDIR;
  470. }
  471. if (dentry_is_ancestor(old_dent, new_dent) || dentry_is_ancestor(new_dent, old_dent)) {
  472. return -EINVAL;
  473. }
  474. /* TODO: Add appropriate checks for hardlinks once they get implemented. */
  475. int ret = old_dent->fs->d_ops->rename(old_dent, new_dent);
  476. if (!ret) {
  477. old_dent->state |= DENTRY_NEGATIVE;
  478. new_dent->state &= ~DENTRY_NEGATIVE;
  479. }
  480. return ret;
  481. }
  482. int shim_do_rename(const char* oldpath, const char* newpath) {
  483. return shim_do_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
  484. }
  485. int shim_do_renameat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) {
  486. struct shim_dentry* old_dir_dent = NULL;
  487. struct shim_dentry* old_dent = NULL;
  488. struct shim_dentry* new_dir_dent = NULL;
  489. struct shim_dentry* new_dent = NULL;
  490. int ret = 0;
  491. if (!oldpath || test_user_string(oldpath) || !newpath || test_user_string(newpath)) {
  492. return -EFAULT;
  493. }
  494. if ((ret = get_dirfd_dentry(olddirfd, &old_dir_dent)) < 0) {
  495. goto out;
  496. }
  497. if ((ret = path_lookupat(old_dir_dent, oldpath, LOOKUP_OPEN, &old_dent, NULL)) < 0) {
  498. goto out;
  499. }
  500. if (old_dent->state & DENTRY_NEGATIVE) {
  501. ret = -ENOENT;
  502. goto out;
  503. }
  504. if ((ret = get_dirfd_dentry(newdirfd, &new_dir_dent)) < 0) {
  505. goto out;
  506. }
  507. ret = path_lookupat(new_dir_dent, newpath, LOOKUP_OPEN | LOOKUP_CREATE, &new_dent, NULL);
  508. if (ret < 0) {
  509. if (ret != -ENOENT || !new_dent ||
  510. (new_dent->state & (DENTRY_NEGATIVE | DENTRY_VALID)) !=
  511. (DENTRY_NEGATIVE | DENTRY_VALID)) {
  512. goto out;
  513. }
  514. }
  515. // Both dentries should have a ref count of at least 2 at this point
  516. assert(REF_GET(old_dent->ref_count) >= 2);
  517. assert(REF_GET(new_dent->ref_count) >= 2);
  518. ret = do_rename(old_dent, new_dent);
  519. out:
  520. if (old_dir_dent)
  521. put_dentry(old_dir_dent);
  522. if (old_dent)
  523. put_dentry(old_dent);
  524. if (new_dir_dent)
  525. put_dentry(new_dir_dent);
  526. if (new_dent)
  527. put_dentry(new_dent);
  528. return ret;
  529. }
  530. ssize_t shim_do_sendfile(int ofd, int ifd, off_t* offset, size_t count) {
  531. struct shim_handle* hdli = get_fd_handle(ifd, NULL, NULL);
  532. struct shim_handle* hdlo = get_fd_handle(ofd, NULL, NULL);
  533. if (!hdli || !hdlo)
  534. return -EBADF;
  535. off_t old_offset = 0;
  536. int ret = -EACCES;
  537. if (offset) {
  538. if (!hdli->fs || !hdli->fs->fs_ops || !hdli->fs->fs_ops->seek)
  539. goto out;
  540. old_offset = hdli->fs->fs_ops->seek(hdli, 0, SEEK_CUR);
  541. if (old_offset < 0) {
  542. ret = old_offset;
  543. goto out;
  544. }
  545. }
  546. ret = handle_copy(hdli, offset, hdlo, NULL, count);
  547. if (ret >= 0 && offset)
  548. hdli->fs->fs_ops->seek(hdli, old_offset, SEEK_SET);
  549. out:
  550. put_handle(hdli);
  551. put_handle(hdlo);
  552. return ret;
  553. }
  554. int shim_do_chroot(const char* filename) {
  555. int ret = 0;
  556. struct shim_dentry* dent = NULL;
  557. if ((ret = path_lookupat(NULL, filename, 0, &dent, NULL)) < 0)
  558. goto out;
  559. if (!dent) {
  560. ret = -ENOENT;
  561. goto out;
  562. }
  563. struct shim_thread* thread = get_cur_thread();
  564. lock(&thread->lock);
  565. put_dentry(thread->root);
  566. thread->root = dent;
  567. unlock(&thread->lock);
  568. out:
  569. return ret;
  570. }