shim_fs.c 21 KB

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