shim_fs.c 19 KB

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