PageRenderTime 216ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/sys/ufs/ufs/ufs_vnops.c

https://bitbucket.org/gthummalapalle/minix
C | 2989 lines | 1957 code | 220 blank | 812 comment | 477 complexity | 243686a49f381a6797c8d3dea722aed3 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, WTFPL, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /* $NetBSD: ufs_vnops.c,v 1.206 2011/11/18 21:18:52 christos Exp $ */
  2. /*-
  3. * Copyright (c) 2008 The NetBSD Foundation, Inc.
  4. * All rights reserved.
  5. *
  6. * This code is derived from software contributed to The NetBSD Foundation
  7. * by Wasabi Systems, Inc.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  20. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  22. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /*
  31. * Copyright (c) 1982, 1986, 1989, 1993, 1995
  32. * The Regents of the University of California. All rights reserved.
  33. * (c) UNIX System Laboratories, Inc.
  34. * All or some portions of this file are derived from material licensed
  35. * to the University of California by American Telephone and Telegraph
  36. * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  37. * the permission of UNIX System Laboratories, Inc.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. Neither the name of the University nor the names of its contributors
  48. * may be used to endorse or promote products derived from this software
  49. * without specific prior written permission.
  50. *
  51. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  52. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  53. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  54. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  55. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  56. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  57. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  60. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  61. * SUCH DAMAGE.
  62. *
  63. * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
  64. */
  65. #include <sys/cdefs.h>
  66. __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.206 2011/11/18 21:18:52 christos Exp $");
  67. #if defined(_KERNEL_OPT)
  68. #include "opt_ffs.h"
  69. #include "opt_quota.h"
  70. #endif
  71. #include <sys/param.h>
  72. #include <sys/systm.h>
  73. #include <sys/namei.h>
  74. #include <sys/resourcevar.h>
  75. #include <sys/kernel.h>
  76. #include <sys/file.h>
  77. #include <sys/stat.h>
  78. #include <sys/buf.h>
  79. #include <sys/proc.h>
  80. #include <sys/mount.h>
  81. #include <sys/vnode.h>
  82. #include <sys/malloc.h>
  83. #include <sys/dirent.h>
  84. #include <sys/lockf.h>
  85. #include <sys/kauth.h>
  86. #include <sys/wapbl.h>
  87. #include <sys/fstrans.h>
  88. #include <miscfs/specfs/specdev.h>
  89. #include <miscfs/fifofs/fifo.h>
  90. #include <miscfs/genfs/genfs.h>
  91. #include <ufs/ufs/inode.h>
  92. #include <ufs/ufs/dir.h>
  93. #include <ufs/ufs/ufsmount.h>
  94. #include <ufs/ufs/ufs_bswap.h>
  95. #include <ufs/ufs/ufs_extern.h>
  96. #include <ufs/ufs/ufs_wapbl.h>
  97. #ifdef UFS_DIRHASH
  98. #include <ufs/ufs/dirhash.h>
  99. #endif
  100. #include <ufs/ext2fs/ext2fs_extern.h>
  101. #include <ufs/ext2fs/ext2fs_dir.h>
  102. #include <ufs/ffs/ffs_extern.h>
  103. #include <ufs/lfs/lfs_extern.h>
  104. #include <ufs/lfs/lfs.h>
  105. #include <uvm/uvm.h>
  106. __CTASSERT(EXT2FS_MAXNAMLEN == FFS_MAXNAMLEN);
  107. __CTASSERT(LFS_MAXNAMLEN == FFS_MAXNAMLEN);
  108. static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
  109. static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
  110. struct lwp *);
  111. /*
  112. * A virgin directory (no blushing please).
  113. */
  114. static const struct dirtemplate mastertemplate = {
  115. 0, 12, DT_DIR, 1, ".",
  116. 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
  117. };
  118. /*
  119. * Create a regular file
  120. */
  121. int
  122. ufs_create(void *v)
  123. {
  124. struct vop_create_args /* {
  125. struct vnode *a_dvp;
  126. struct vnode **a_vpp;
  127. struct componentname *a_cnp;
  128. struct vattr *a_vap;
  129. } */ *ap = v;
  130. int error;
  131. struct vnode *dvp = ap->a_dvp;
  132. struct ufs_lookup_results *ulr;
  133. /* XXX should handle this material another way */
  134. ulr = &VTOI(dvp)->i_crap;
  135. UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
  136. /*
  137. * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
  138. * ufs_makeinode
  139. */
  140. fstrans_start(dvp->v_mount, FSTRANS_SHARED);
  141. error =
  142. ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
  143. dvp, ulr, ap->a_vpp, ap->a_cnp);
  144. if (error) {
  145. fstrans_done(dvp->v_mount);
  146. return (error);
  147. }
  148. UFS_WAPBL_END1(dvp->v_mount, dvp);
  149. fstrans_done(dvp->v_mount);
  150. VN_KNOTE(dvp, NOTE_WRITE);
  151. return (0);
  152. }
  153. /*
  154. * Mknod vnode call
  155. */
  156. /* ARGSUSED */
  157. int
  158. ufs_mknod(void *v)
  159. {
  160. struct vop_mknod_args /* {
  161. struct vnode *a_dvp;
  162. struct vnode **a_vpp;
  163. struct componentname *a_cnp;
  164. struct vattr *a_vap;
  165. } */ *ap = v;
  166. struct vattr *vap;
  167. struct vnode **vpp;
  168. struct inode *ip;
  169. int error;
  170. struct mount *mp;
  171. ino_t ino;
  172. struct ufs_lookup_results *ulr;
  173. vap = ap->a_vap;
  174. vpp = ap->a_vpp;
  175. /* XXX should handle this material another way */
  176. ulr = &VTOI(ap->a_dvp)->i_crap;
  177. UFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp));
  178. /*
  179. * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
  180. * ufs_makeinode
  181. */
  182. fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
  183. if ((error =
  184. ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
  185. ap->a_dvp, ulr, vpp, ap->a_cnp)) != 0)
  186. goto out;
  187. VN_KNOTE(ap->a_dvp, NOTE_WRITE);
  188. ip = VTOI(*vpp);
  189. mp = (*vpp)->v_mount;
  190. ino = ip->i_number;
  191. ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  192. if (vap->va_rdev != VNOVAL) {
  193. struct ufsmount *ump = ip->i_ump;
  194. /*
  195. * Want to be able to use this to make badblock
  196. * inodes, so don't truncate the dev number.
  197. */
  198. if (ump->um_fstype == UFS1)
  199. ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev,
  200. UFS_MPNEEDSWAP(ump));
  201. else
  202. ip->i_ffs2_rdev = ufs_rw64(vap->va_rdev,
  203. UFS_MPNEEDSWAP(ump));
  204. }
  205. UFS_WAPBL_UPDATE(*vpp, NULL, NULL, 0);
  206. UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
  207. /*
  208. * Remove inode so that it will be reloaded by VFS_VGET and
  209. * checked to see if it is an alias of an existing entry in
  210. * the inode cache.
  211. */
  212. (*vpp)->v_type = VNON;
  213. VOP_UNLOCK(*vpp);
  214. vgone(*vpp);
  215. error = VFS_VGET(mp, ino, vpp);
  216. out:
  217. fstrans_done(ap->a_dvp->v_mount);
  218. if (error != 0) {
  219. *vpp = NULL;
  220. return (error);
  221. }
  222. return (0);
  223. }
  224. /*
  225. * Open called.
  226. *
  227. * Nothing to do.
  228. */
  229. /* ARGSUSED */
  230. int
  231. ufs_open(void *v)
  232. {
  233. struct vop_open_args /* {
  234. struct vnode *a_vp;
  235. int a_mode;
  236. kauth_cred_t a_cred;
  237. } */ *ap = v;
  238. /*
  239. * Files marked append-only must be opened for appending.
  240. */
  241. if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
  242. (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
  243. return (EPERM);
  244. return (0);
  245. }
  246. /*
  247. * Close called.
  248. *
  249. * Update the times on the inode.
  250. */
  251. /* ARGSUSED */
  252. int
  253. ufs_close(void *v)
  254. {
  255. struct vop_close_args /* {
  256. struct vnode *a_vp;
  257. int a_fflag;
  258. kauth_cred_t a_cred;
  259. } */ *ap = v;
  260. struct vnode *vp;
  261. struct inode *ip;
  262. vp = ap->a_vp;
  263. ip = VTOI(vp);
  264. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  265. if (vp->v_usecount > 1)
  266. UFS_ITIMES(vp, NULL, NULL, NULL);
  267. fstrans_done(vp->v_mount);
  268. return (0);
  269. }
  270. static int
  271. ufs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
  272. kauth_cred_t cred)
  273. {
  274. #if defined(QUOTA) || defined(QUOTA2)
  275. int error;
  276. #endif
  277. /*
  278. * Disallow write attempts on read-only file systems;
  279. * unless the file is a socket, fifo, or a block or
  280. * character device resident on the file system.
  281. */
  282. if (mode & VWRITE) {
  283. switch (vp->v_type) {
  284. case VDIR:
  285. case VLNK:
  286. case VREG:
  287. if (vp->v_mount->mnt_flag & MNT_RDONLY)
  288. return (EROFS);
  289. #if defined(QUOTA) || defined(QUOTA2)
  290. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  291. error = chkdq(ip, 0, cred, 0);
  292. fstrans_done(vp->v_mount);
  293. if (error != 0)
  294. return error;
  295. #endif
  296. break;
  297. case VBAD:
  298. case VBLK:
  299. case VCHR:
  300. case VSOCK:
  301. case VFIFO:
  302. case VNON:
  303. default:
  304. break;
  305. }
  306. }
  307. /* If it is a snapshot, nobody gets access to it. */
  308. if ((ip->i_flags & SF_SNAPSHOT))
  309. return (EPERM);
  310. /* If immutable bit set, nobody gets to write it. */
  311. if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
  312. return (EPERM);
  313. return 0;
  314. }
  315. static int
  316. ufs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
  317. kauth_cred_t cred)
  318. {
  319. return genfs_can_access(vp->v_type, ip->i_mode & ALLPERMS, ip->i_uid,
  320. ip->i_gid, mode, cred);
  321. }
  322. int
  323. ufs_access(void *v)
  324. {
  325. struct vop_access_args /* {
  326. struct vnode *a_vp;
  327. int a_mode;
  328. kauth_cred_t a_cred;
  329. } */ *ap = v;
  330. struct vnode *vp;
  331. struct inode *ip;
  332. mode_t mode;
  333. int error;
  334. vp = ap->a_vp;
  335. ip = VTOI(vp);
  336. mode = ap->a_mode;
  337. error = ufs_check_possible(vp, ip, mode, ap->a_cred);
  338. if (error)
  339. return error;
  340. error = ufs_check_permitted(vp, ip, mode, ap->a_cred);
  341. return error;
  342. }
  343. /* ARGSUSED */
  344. int
  345. ufs_getattr(void *v)
  346. {
  347. struct vop_getattr_args /* {
  348. struct vnode *a_vp;
  349. struct vattr *a_vap;
  350. kauth_cred_t a_cred;
  351. } */ *ap = v;
  352. struct vnode *vp;
  353. struct inode *ip;
  354. struct vattr *vap;
  355. vp = ap->a_vp;
  356. ip = VTOI(vp);
  357. vap = ap->a_vap;
  358. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  359. UFS_ITIMES(vp, NULL, NULL, NULL);
  360. /*
  361. * Copy from inode table
  362. */
  363. vap->va_fsid = ip->i_dev;
  364. vap->va_fileid = ip->i_number;
  365. vap->va_mode = ip->i_mode & ALLPERMS;
  366. vap->va_nlink = ip->i_nlink;
  367. vap->va_uid = ip->i_uid;
  368. vap->va_gid = ip->i_gid;
  369. vap->va_size = vp->v_size;
  370. if (ip->i_ump->um_fstype == UFS1) {
  371. vap->va_rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
  372. UFS_MPNEEDSWAP(ip->i_ump));
  373. vap->va_atime.tv_sec = ip->i_ffs1_atime;
  374. vap->va_atime.tv_nsec = ip->i_ffs1_atimensec;
  375. vap->va_mtime.tv_sec = ip->i_ffs1_mtime;
  376. vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec;
  377. vap->va_ctime.tv_sec = ip->i_ffs1_ctime;
  378. vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec;
  379. vap->va_birthtime.tv_sec = 0;
  380. vap->va_birthtime.tv_nsec = 0;
  381. vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks);
  382. } else {
  383. vap->va_rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
  384. UFS_MPNEEDSWAP(ip->i_ump));
  385. vap->va_atime.tv_sec = ip->i_ffs2_atime;
  386. vap->va_atime.tv_nsec = ip->i_ffs2_atimensec;
  387. vap->va_mtime.tv_sec = ip->i_ffs2_mtime;
  388. vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec;
  389. vap->va_ctime.tv_sec = ip->i_ffs2_ctime;
  390. vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec;
  391. vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime;
  392. vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec;
  393. vap->va_bytes = dbtob(ip->i_ffs2_blocks);
  394. }
  395. vap->va_gen = ip->i_gen;
  396. vap->va_flags = ip->i_flags;
  397. /* this doesn't belong here */
  398. if (vp->v_type == VBLK)
  399. vap->va_blocksize = BLKDEV_IOSIZE;
  400. else if (vp->v_type == VCHR)
  401. vap->va_blocksize = MAXBSIZE;
  402. else
  403. vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
  404. vap->va_type = vp->v_type;
  405. vap->va_filerev = ip->i_modrev;
  406. fstrans_done(vp->v_mount);
  407. return (0);
  408. }
  409. /*
  410. * Set attribute vnode op. called from several syscalls
  411. */
  412. int
  413. ufs_setattr(void *v)
  414. {
  415. struct vop_setattr_args /* {
  416. struct vnode *a_vp;
  417. struct vattr *a_vap;
  418. kauth_cred_t a_cred;
  419. } */ *ap = v;
  420. struct vattr *vap;
  421. struct vnode *vp;
  422. struct inode *ip;
  423. kauth_cred_t cred;
  424. struct lwp *l;
  425. int error;
  426. vap = ap->a_vap;
  427. vp = ap->a_vp;
  428. ip = VTOI(vp);
  429. cred = ap->a_cred;
  430. l = curlwp;
  431. /*
  432. * Check for unsettable attributes.
  433. */
  434. if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
  435. (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
  436. (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
  437. ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
  438. return (EINVAL);
  439. }
  440. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  441. if (vap->va_flags != VNOVAL) {
  442. if (vp->v_mount->mnt_flag & MNT_RDONLY) {
  443. error = EROFS;
  444. goto out;
  445. }
  446. if (kauth_cred_geteuid(cred) != ip->i_uid &&
  447. (error = kauth_authorize_generic(cred,
  448. KAUTH_GENERIC_ISSUSER, NULL)))
  449. goto out;
  450. if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  451. NULL) == 0) {
  452. if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
  453. kauth_authorize_system(l->l_cred,
  454. KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL)) {
  455. error = EPERM;
  456. goto out;
  457. }
  458. /* Snapshot flag cannot be set or cleared */
  459. if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
  460. (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
  461. error = EPERM;
  462. goto out;
  463. }
  464. error = UFS_WAPBL_BEGIN(vp->v_mount);
  465. if (error)
  466. goto out;
  467. ip->i_flags = vap->va_flags;
  468. DIP_ASSIGN(ip, flags, ip->i_flags);
  469. } else {
  470. if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) ||
  471. (vap->va_flags & UF_SETTABLE) != vap->va_flags) {
  472. error = EPERM;
  473. goto out;
  474. }
  475. if ((ip->i_flags & SF_SETTABLE) !=
  476. (vap->va_flags & SF_SETTABLE)) {
  477. error = EPERM;
  478. goto out;
  479. }
  480. error = UFS_WAPBL_BEGIN(vp->v_mount);
  481. if (error)
  482. goto out;
  483. ip->i_flags &= SF_SETTABLE;
  484. ip->i_flags |= (vap->va_flags & UF_SETTABLE);
  485. DIP_ASSIGN(ip, flags, ip->i_flags);
  486. }
  487. ip->i_flag |= IN_CHANGE;
  488. UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
  489. UFS_WAPBL_END(vp->v_mount);
  490. if (vap->va_flags & (IMMUTABLE | APPEND)) {
  491. error = 0;
  492. goto out;
  493. }
  494. }
  495. if (ip->i_flags & (IMMUTABLE | APPEND)) {
  496. error = EPERM;
  497. goto out;
  498. }
  499. /*
  500. * Go through the fields and update iff not VNOVAL.
  501. */
  502. if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  503. if (vp->v_mount->mnt_flag & MNT_RDONLY) {
  504. error = EROFS;
  505. goto out;
  506. }
  507. error = UFS_WAPBL_BEGIN(vp->v_mount);
  508. if (error)
  509. goto out;
  510. error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
  511. UFS_WAPBL_END(vp->v_mount);
  512. if (error)
  513. goto out;
  514. }
  515. if (vap->va_size != VNOVAL) {
  516. /*
  517. * Disallow write attempts on read-only file systems;
  518. * unless the file is a socket, fifo, or a block or
  519. * character device resident on the file system.
  520. */
  521. switch (vp->v_type) {
  522. case VDIR:
  523. error = EISDIR;
  524. goto out;
  525. case VCHR:
  526. case VBLK:
  527. case VFIFO:
  528. break;
  529. case VREG:
  530. if (vp->v_mount->mnt_flag & MNT_RDONLY) {
  531. error = EROFS;
  532. goto out;
  533. }
  534. if ((ip->i_flags & SF_SNAPSHOT) != 0) {
  535. error = EPERM;
  536. goto out;
  537. }
  538. error = UFS_WAPBL_BEGIN(vp->v_mount);
  539. if (error)
  540. goto out;
  541. /*
  542. * When journaling, only truncate one indirect block
  543. * at a time.
  544. */
  545. if (vp->v_mount->mnt_wapbl) {
  546. uint64_t incr = MNINDIR(ip->i_ump) <<
  547. vp->v_mount->mnt_fs_bshift; /* Power of 2 */
  548. uint64_t base = NDADDR <<
  549. vp->v_mount->mnt_fs_bshift;
  550. while (!error && ip->i_size > base + incr &&
  551. ip->i_size > vap->va_size + incr) {
  552. /*
  553. * round down to next full indirect
  554. * block boundary.
  555. */
  556. uint64_t nsize = base +
  557. ((ip->i_size - base - 1) &
  558. ~(incr - 1));
  559. error = UFS_TRUNCATE(vp, nsize, 0,
  560. cred);
  561. if (error == 0) {
  562. UFS_WAPBL_END(vp->v_mount);
  563. error =
  564. UFS_WAPBL_BEGIN(vp->v_mount);
  565. }
  566. }
  567. }
  568. if (!error)
  569. error = UFS_TRUNCATE(vp, vap->va_size, 0, cred);
  570. UFS_WAPBL_END(vp->v_mount);
  571. if (error)
  572. goto out;
  573. break;
  574. default:
  575. error = EOPNOTSUPP;
  576. goto out;
  577. }
  578. }
  579. ip = VTOI(vp);
  580. if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
  581. vap->va_birthtime.tv_sec != VNOVAL) {
  582. if (vp->v_mount->mnt_flag & MNT_RDONLY) {
  583. error = EROFS;
  584. goto out;
  585. }
  586. if ((ip->i_flags & SF_SNAPSHOT) != 0) {
  587. error = EPERM;
  588. goto out;
  589. }
  590. error = genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred);
  591. if (error)
  592. goto out;
  593. error = UFS_WAPBL_BEGIN(vp->v_mount);
  594. if (error)
  595. goto out;
  596. if (vap->va_atime.tv_sec != VNOVAL)
  597. if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
  598. ip->i_flag |= IN_ACCESS;
  599. if (vap->va_mtime.tv_sec != VNOVAL) {
  600. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  601. if (vp->v_mount->mnt_flag & MNT_RELATIME)
  602. ip->i_flag |= IN_ACCESS;
  603. }
  604. if (vap->va_birthtime.tv_sec != VNOVAL &&
  605. ip->i_ump->um_fstype == UFS2) {
  606. ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
  607. ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
  608. }
  609. error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
  610. UFS_WAPBL_END(vp->v_mount);
  611. if (error)
  612. goto out;
  613. }
  614. error = 0;
  615. if (vap->va_mode != (mode_t)VNOVAL) {
  616. if (vp->v_mount->mnt_flag & MNT_RDONLY) {
  617. error = EROFS;
  618. goto out;
  619. }
  620. if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
  621. (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
  622. S_IXOTH | S_IWOTH))) {
  623. error = EPERM;
  624. goto out;
  625. }
  626. error = UFS_WAPBL_BEGIN(vp->v_mount);
  627. if (error)
  628. goto out;
  629. error = ufs_chmod(vp, (int)vap->va_mode, cred, l);
  630. UFS_WAPBL_END(vp->v_mount);
  631. }
  632. VN_KNOTE(vp, NOTE_ATTRIB);
  633. out:
  634. fstrans_done(vp->v_mount);
  635. return (error);
  636. }
  637. /*
  638. * Change the mode on a file.
  639. * Inode must be locked before calling.
  640. */
  641. static int
  642. ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
  643. {
  644. struct inode *ip;
  645. int error;
  646. UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
  647. ip = VTOI(vp);
  648. error = genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode);
  649. if (error)
  650. return (error);
  651. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  652. ip->i_mode &= ~ALLPERMS;
  653. ip->i_mode |= (mode & ALLPERMS);
  654. ip->i_flag |= IN_CHANGE;
  655. DIP_ASSIGN(ip, mode, ip->i_mode);
  656. UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
  657. fstrans_done(vp->v_mount);
  658. return (0);
  659. }
  660. /*
  661. * Perform chown operation on inode ip;
  662. * inode must be locked prior to call.
  663. */
  664. static int
  665. ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
  666. struct lwp *l)
  667. {
  668. struct inode *ip;
  669. int error = 0;
  670. #if defined(QUOTA) || defined(QUOTA2)
  671. uid_t ouid;
  672. gid_t ogid;
  673. int64_t change;
  674. #endif
  675. ip = VTOI(vp);
  676. error = 0;
  677. if (uid == (uid_t)VNOVAL)
  678. uid = ip->i_uid;
  679. if (gid == (gid_t)VNOVAL)
  680. gid = ip->i_gid;
  681. error = genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid);
  682. if (error)
  683. return (error);
  684. fstrans_start(vp->v_mount, FSTRANS_SHARED);
  685. #if defined(QUOTA) || defined(QUOTA2)
  686. ogid = ip->i_gid;
  687. ouid = ip->i_uid;
  688. change = DIP(ip, blocks);
  689. (void) chkdq(ip, -change, cred, 0);
  690. (void) chkiq(ip, -1, cred, 0);
  691. #endif
  692. ip->i_gid = gid;
  693. DIP_ASSIGN(ip, gid, gid);
  694. ip->i_uid = uid;
  695. DIP_ASSIGN(ip, uid, uid);
  696. #if defined(QUOTA) || defined(QUOTA2)
  697. if ((error = chkdq(ip, change, cred, 0)) == 0) {
  698. if ((error = chkiq(ip, 1, cred, 0)) == 0)
  699. goto good;
  700. else
  701. (void) chkdq(ip, -change, cred, FORCE);
  702. }
  703. ip->i_gid = ogid;
  704. DIP_ASSIGN(ip, gid, ogid);
  705. ip->i_uid = ouid;
  706. DIP_ASSIGN(ip, uid, ouid);
  707. (void) chkdq(ip, change, cred, FORCE);
  708. (void) chkiq(ip, 1, cred, FORCE);
  709. fstrans_done(vp->v_mount);
  710. return (error);
  711. good:
  712. #endif /* QUOTA || QUOTA2 */
  713. ip->i_flag |= IN_CHANGE;
  714. UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
  715. fstrans_done(vp->v_mount);
  716. return (0);
  717. }
  718. int
  719. ufs_remove(void *v)
  720. {
  721. struct vop_remove_args /* {
  722. struct vnode *a_dvp;
  723. struct vnode *a_vp;
  724. struct componentname *a_cnp;
  725. } */ *ap = v;
  726. struct vnode *vp, *dvp;
  727. struct inode *ip;
  728. int error;
  729. struct ufs_lookup_results *ulr;
  730. vp = ap->a_vp;
  731. dvp = ap->a_dvp;
  732. ip = VTOI(vp);
  733. /* XXX should handle this material another way */
  734. ulr = &VTOI(dvp)->i_crap;
  735. UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
  736. fstrans_start(dvp->v_mount, FSTRANS_SHARED);
  737. if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
  738. (VTOI(dvp)->i_flags & APPEND))
  739. error = EPERM;
  740. else {
  741. error = UFS_WAPBL_BEGIN(dvp->v_mount);
  742. if (error == 0) {
  743. error = ufs_dirremove(dvp, ulr,
  744. ip, ap->a_cnp->cn_flags, 0);
  745. UFS_WAPBL_END(dvp->v_mount);
  746. }
  747. }
  748. VN_KNOTE(vp, NOTE_DELETE);
  749. VN_KNOTE(dvp, NOTE_WRITE);
  750. if (dvp == vp)
  751. vrele(vp);
  752. else
  753. vput(vp);
  754. vput(dvp);
  755. fstrans_done(dvp->v_mount);
  756. return (error);
  757. }
  758. /*
  759. * ufs_link: create hard link.
  760. */
  761. int
  762. ufs_link(void *v)
  763. {
  764. struct vop_link_args /* {
  765. struct vnode *a_dvp;
  766. struct vnode *a_vp;
  767. struct componentname *a_cnp;
  768. } */ *ap = v;
  769. struct vnode *dvp = ap->a_dvp;
  770. struct vnode *vp = ap->a_vp;
  771. struct componentname *cnp = ap->a_cnp;
  772. struct inode *ip;
  773. struct direct *newdir;
  774. int error;
  775. struct ufs_lookup_results *ulr;
  776. KASSERT(dvp != vp);
  777. KASSERT(vp->v_type != VDIR);
  778. KASSERT(dvp->v_mount == vp->v_mount);
  779. /* XXX should handle this material another way */
  780. ulr = &VTOI(dvp)->i_crap;
  781. UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
  782. fstrans_start(dvp->v_mount, FSTRANS_SHARED);
  783. error = vn_lock(vp, LK_EXCLUSIVE);
  784. if (error) {
  785. VOP_ABORTOP(dvp, cnp);
  786. goto out2;
  787. }
  788. ip = VTOI(vp);
  789. if ((nlink_t)ip->i_nlink >= LINK_MAX) {
  790. VOP_ABORTOP(dvp, cnp);
  791. error = EMLINK;
  792. goto out1;
  793. }
  794. if (ip->i_flags & (IMMUTABLE | APPEND)) {
  795. VOP_ABORTOP(dvp, cnp);
  796. error = EPERM;
  797. goto out1;
  798. }
  799. error = UFS_WAPBL_BEGIN(vp->v_mount);
  800. if (error) {
  801. VOP_ABORTOP(dvp, cnp);
  802. goto out1;
  803. }
  804. ip->i_nlink++;
  805. DIP_ASSIGN(ip, nlink, ip->i_nlink);
  806. ip->i_flag |= IN_CHANGE;
  807. error = UFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
  808. if (!error) {
  809. newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
  810. ufs_makedirentry(ip, cnp, newdir);
  811. error = ufs_direnter(dvp, ulr, vp, newdir, cnp, NULL);
  812. pool_cache_put(ufs_direct_cache, newdir);
  813. }
  814. if (error) {
  815. ip->i_nlink--;
  816. DIP_ASSIGN(ip, nlink, ip->i_nlink);
  817. ip->i_flag |= IN_CHANGE;
  818. UFS_WAPBL_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
  819. }
  820. UFS_WAPBL_END(vp->v_mount);
  821. out1:
  822. VOP_UNLOCK(vp);
  823. out2:
  824. VN_KNOTE(vp, NOTE_LINK);
  825. VN_KNOTE(dvp, NOTE_WRITE);
  826. vput(dvp);
  827. fstrans_done(dvp->v_mount);
  828. return (error);
  829. }
  830. /*
  831. * whiteout vnode call
  832. */
  833. int
  834. ufs_whiteout(void *v)
  835. {
  836. struct vop_whiteout_args /* {
  837. struct vnode *a_dvp;
  838. struct componentname *a_cnp;
  839. int a_flags;
  840. } */ *ap = v;
  841. struct vnode *dvp = ap->a_dvp;
  842. struct componentname *cnp = ap->a_cnp;
  843. struct direct *newdir;
  844. int error;
  845. struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
  846. struct ufs_lookup_results *ulr;
  847. /* XXX should handle this material another way */
  848. ulr = &VTOI(dvp)->i_crap;
  849. UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
  850. error = 0;
  851. switch (ap->a_flags) {
  852. case LOOKUP:
  853. /* 4.4 format directories support whiteout operations */
  854. if (ump->um_maxsymlinklen > 0)
  855. return (0);
  856. return (EOPNOTSUPP);
  857. case CREATE:
  858. /* create a new directory whiteout */
  859. fstrans_start(dvp->v_mount, FSTRANS_SHARED);
  860. error = UFS_WAPBL_BEGIN(dvp->v_mount);
  861. if (error)
  862. break;
  863. #ifdef DIAGNOSTIC
  864. if (ump->um_maxsymlinklen <= 0)
  865. panic("ufs_whiteout: old format filesystem");
  866. #endif
  867. newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
  868. newdir->d_ino = WINO;
  869. newdir->d_namlen = cnp->cn_namelen;
  870. memcpy(newdir->d_name, cnp->cn_nameptr,
  871. (size_t)cnp->cn_namelen);
  872. newdir->d_name[cnp->cn_namelen] = '\0';
  873. newdir->d_type = DT_WHT;
  874. error = ufs_direnter(dvp, ulr, NULL, newdir, cnp, NULL);
  875. pool_cache_put(ufs_direct_cache, newdir);
  876. break;
  877. case DELETE:
  878. /* remove an existing directory whiteout */
  879. fstrans_start(dvp->v_mount, FSTRANS_SHARED);
  880. error = UFS_WAPBL_BEGIN(dvp->v_mount);
  881. if (error)
  882. break;
  883. #ifdef DIAGNOSTIC
  884. if (ump->um_maxsymlinklen <= 0)
  885. panic("ufs_whiteout: old format filesystem");
  886. #endif
  887. cnp->cn_flags &= ~DOWHITEOUT;
  888. error = ufs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
  889. break;
  890. default:
  891. panic("ufs_whiteout: unknown op");
  892. /* NOTREACHED */
  893. }
  894. UFS_WAPBL_END(dvp->v_mount);
  895. fstrans_done(dvp->v_mount);
  896. return (error);
  897. }
  898. /*
  899. * Rename vnode operation
  900. * rename("foo", "bar");
  901. * is essentially
  902. * unlink("bar");
  903. * link("foo", "bar");
  904. * unlink("foo");
  905. * but ``atomically''. Can't do full commit without saving state in the
  906. * inode on disk which isn't feasible at this time. Best we can do is
  907. * always guarantee the target exists.
  908. *
  909. * Basic algorithm is:
  910. *
  911. * 1) Bump link count on source while we're linking it to the
  912. * target. This also ensure the inode won't be deleted out
  913. * from underneath us while we work (it may be truncated by
  914. * a concurrent `trunc' or `open' for creation).
  915. * 2) Link source to destination. If destination already exists,
  916. * delete it first.
  917. * 3) Unlink source reference to inode if still around. If a
  918. * directory was moved and the parent of the destination
  919. * is different from the source, patch the ".." entry in the
  920. * directory.
  921. */
  922. /*
  923. * Notes on rename locking:
  924. *
  925. * We lock parent vnodes before child vnodes. This means in particular
  926. * that if A is above B in the directory tree then A must be locked
  927. * before B. (This is true regardless of how many steps appear in
  928. * between, because an arbitrary number of other processes could lock
  929. * parent/child in between and establish a lock cycle and deadlock.)
  930. *
  931. * Therefore, if tdvp is above fdvp we must lock tdvp first; if fdvp
  932. * is above tdvp we must lock fdvp first; and if they're
  933. * incommensurate it doesn't matter. (But, we rely on the fact that
  934. * there's a whole-volume rename lock to prevent deadlock among groups
  935. * of renames upon overlapping sets of incommensurate vnodes.)
  936. *
  937. * In addition to establishing lock ordering the parent check also
  938. * serves to rule out cases where someone tries to move a directory
  939. * underneath itself, e.g. rename("a/b", "a/b/c"). If allowed to
  940. * proceed such renames would detach portions of the directory tree
  941. * and make fsck very unhappy.
  942. *
  943. * Note that it is an error for *fvp* to be above tdvp; however,
  944. * *fdvp* can be above tdvp, as in rename("a/b", "a/c/d").
  945. *
  946. * The parent check searches up the tree from tdvp until it either
  947. * finds fdvp or the root of the volume. It also returns the vnode it
  948. * saw immediately before fdvp, if any. Later on (after looking up
  949. * fvp) we will check to see if this *is* fvp and if so fail.
  950. *
  951. * If the parent check finds fdvp, it means fdvp is above tdvp, so we
  952. * lock fdvp first and then tdvp. Otherwise, either tdvp is above fdvp
  953. * or they're incommensurate and we lock tdvp first.
  954. *
  955. * In either case each of the child vnodes has to be looked up and
  956. * locked immediately after its parent. The cases
  957. *
  958. * fdvp/fvp/[.../]tdvp/tvp
  959. * tdvp/tvp/[.../]fdvp/fvp
  960. *
  961. * can cause deadlock otherwise. Note that both of these are error
  962. * cases; the first fails the parent check and the second fails
  963. * because tvp isn't empty. The parent check case is handled before
  964. * we start locking; however, the nonempty case requires locking tvp
  965. * to find out safely that it's nonempty.
  966. *
  967. * Therefore the procedure is either
  968. *
  969. * lock fdvp
  970. * lookup fvp
  971. * lock fvp
  972. * lock tdvp
  973. * lookup tvp
  974. * lock tvp
  975. *
  976. * or
  977. *
  978. * lock tdvp
  979. * lookup tvp
  980. * lock tvp
  981. * lock fdvp
  982. * lookup fvp
  983. * lock fvp
  984. *
  985. * This could in principle be simplified by always looking up fvp
  986. * last; because of the parent check we know by the time we start
  987. * locking that fvp cannot be directly above tdvp, so (given the
  988. * whole-volume rename lock and other assumptions) it's safe to lock
  989. * tdvp before fvp. This would allow the following scheme:
  990. *
  991. * lock fdvp
  992. * lock tdvp
  993. * or
  994. * lock tdvp
  995. * lock fdvp
  996. *
  997. * then
  998. * lookup tvp
  999. * lock tvp
  1000. * lookup fvp
  1001. * check if fvp is above of tdvp, fail if so
  1002. * lock fvp
  1003. *
  1004. * which is much, much simpler.
  1005. *
  1006. * However, current levels of vfs namei/lookup sanity do not permit
  1007. * this. It is impossible currently to look up fvp without locking it.
  1008. * (It gets locked regardless of whether LOCKLEAF is set; without
  1009. * LOCKLEAF it just gets unlocked again, which doesn't help.)
  1010. *
  1011. * Therefore, because we must look up fvp to know if it's above tdvp,
  1012. * which locks fvp, we must, at least in the case where fdvp is above
  1013. * tdvp, do that before locking tdvp. The longer scheme does that; the
  1014. * simpler scheme is not safe.
  1015. *
  1016. * Note that for now we aren't doing lookup() but relookup(); however,
  1017. * the differences are minor.
  1018. *
  1019. * On top of all the above, just to make everything more
  1020. * exciting, any two of the vnodes might end up being the same.
  1021. *
  1022. * FROMPARENT == FROMCHILD mv a/. foo is an error.
  1023. * FROMPARENT == TOPARENT mv a/b a/c is ok.
  1024. * FROMPARENT == TOCHILD mv a/b/c a/b will give ENOTEMPTY.
  1025. * FROMCHILD == TOPARENT mv a/b a/b/c fails the parent check.
  1026. * FROMCHILD == TOCHILD mv a/b a/b is ok.
  1027. * TOPARENT == TOCHILD mv foo a/. is an error.
  1028. *
  1029. * This introduces more cases in the locking, because each distinct
  1030. * vnode must be locked exactly once.
  1031. *
  1032. * When FROMPARENT == TOPARENT and FROMCHILD != TOCHILD we assume it
  1033. * doesn't matter what order the children are locked in, because the
  1034. * per-volume rename lock excludes other renames and no other
  1035. * operation locks two files in the same directory at once. (Note: if
  1036. * it turns out that link() does, link() is wrong.)
  1037. *
  1038. * Until such time as we can do lookups without the namei and lookup
  1039. * machinery "helpfully" locking the result vnode for us, we can't
  1040. * avoid tripping on cases where FROMCHILD == TOCHILD. Currently for
  1041. * non-directories we unlock the first one we lock while looking up
  1042. * the second, then relock it if necessary. This is more or less
  1043. * harmless since not much of interest can happen to the objects in
  1044. * that window while we have the containing directory locked; but it's
  1045. * not desirable and should be cleaned up when that becomes possible.
  1046. * The right way to do it is to check after looking the second one up
  1047. * and only lock it if it's different. (Note: for directories we don't
  1048. * do this dance because the same directory can't appear more than
  1049. * once.)
  1050. */
  1051. /* XXX following lifted from ufs_lookup.c */
  1052. #define FSFMT(vp) (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0)
  1053. /*
  1054. * Check if either entry referred to by FROM_ULR is within the range
  1055. * of entries named by TO_ULR.
  1056. */
  1057. static int
  1058. ulr_overlap(const struct ufs_lookup_results *from_ulr,
  1059. const struct ufs_lookup_results *to_ulr)
  1060. {
  1061. doff_t from_start, from_prevstart;
  1062. doff_t to_start, to_end;
  1063. /*
  1064. * FROM is a DELETE result; offset points to the entry to
  1065. * remove and subtracting count gives the previous entry.
  1066. */
  1067. from_start = from_ulr->ulr_offset - from_ulr->ulr_count;
  1068. from_prevstart = from_ulr->ulr_offset;
  1069. /*
  1070. * TO is a RENAME (thus non-DELETE) result; offset points
  1071. * to the beginning of a region to write in, and adding
  1072. * count gives the end of the region.
  1073. */
  1074. to_start = to_ulr->ulr_offset;
  1075. to_end = to_ulr->ulr_offset + to_ulr->ulr_count;
  1076. if (from_prevstart >= to_start && from_prevstart < to_end) {
  1077. return 1;
  1078. }
  1079. if (from_start >= to_start && from_start < to_end) {
  1080. return 1;
  1081. }
  1082. return 0;
  1083. }
  1084. /*
  1085. * Wrapper for relookup that also updates the supplemental results.
  1086. */
  1087. static int
  1088. do_relookup(struct vnode *dvp, struct ufs_lookup_results *ulr,
  1089. struct vnode **vp, struct componentname *cnp)
  1090. {
  1091. int error;
  1092. error = relookup(dvp, vp, cnp, 0);
  1093. if (error) {
  1094. return error;
  1095. }
  1096. /* update the supplemental reasults */
  1097. *ulr = VTOI(dvp)->i_crap;
  1098. UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
  1099. return 0;
  1100. }
  1101. /*
  1102. * Lock and relookup a sequence of two directories and two children.
  1103. *
  1104. */
  1105. static int
  1106. lock_vnode_sequence(struct vnode *d1, struct ufs_lookup_results *ulr1,
  1107. struct vnode **v1_ret, struct componentname *cn1,
  1108. int v1_missing_ok,
  1109. int overlap_error,
  1110. struct vnode *d2, struct ufs_lookup_results *ulr2,
  1111. struct vnode **v2_ret, struct componentname *cn2,
  1112. int v2_missing_ok)
  1113. {
  1114. struct vnode *v1, *v2;
  1115. int error;
  1116. KASSERT(d1 != d2);
  1117. vn_lock(d1, LK_EXCLUSIVE | LK_RETRY);
  1118. if (VTOI(d1)->i_size == 0) {
  1119. /* d1 has been rmdir'd */
  1120. VOP_UNLOCK(d1);
  1121. return ENOENT;
  1122. }
  1123. error = do_relookup(d1, ulr1, &v1, cn1);
  1124. if (v1_missing_ok) {
  1125. if (error == ENOENT) {
  1126. /*
  1127. * Note: currently if the name doesn't exist,
  1128. * relookup succeeds (it intercepts the
  1129. * EJUSTRETURN from VOP_LOOKUP) and sets tvp
  1130. * to NULL. Therefore, we will never get
  1131. * ENOENT and this branch is not needed.
  1132. * However, in a saner future the EJUSTRETURN
  1133. * garbage will go away, so let's DTRT.
  1134. */
  1135. v1 = NULL;
  1136. error = 0;
  1137. }
  1138. } else {
  1139. if (error == 0 && v1 == NULL) {
  1140. /* This is what relookup sets if v1 disappeared. */
  1141. error = ENOENT;
  1142. }
  1143. }
  1144. if (error) {
  1145. VOP_UNLOCK(d1);
  1146. return error;
  1147. }
  1148. if (v1 && v1 == d2) {
  1149. VOP_UNLOCK(d1);
  1150. VOP_UNLOCK(v1);
  1151. vrele(v1);
  1152. return overlap_error;
  1153. }
  1154. /*
  1155. * The right way to do this is to do lookups without locking
  1156. * the results, and lock the results afterwards; then at the
  1157. * end we can avoid trying to lock v2 if v2 == v1.
  1158. *
  1159. * However, for the reasons described in the fdvp == tdvp case
  1160. * in rename below, we can't do that safely. So, in the case
  1161. * where v1 is not a directory, unlock it and lock it again
  1162. * afterwards. This is safe in locking order because a
  1163. * non-directory can't be above anything else in the tree. If
  1164. * v1 *is* a directory, that's not true, but then because d1
  1165. * != d2, v1 != v2.
  1166. */
  1167. if (v1 && v1->v_type != VDIR) {
  1168. VOP_UNLOCK(v1);
  1169. }
  1170. vn_lock(d2, LK_EXCLUSIVE | LK_RETRY);
  1171. if (VTOI(d2)->i_size == 0) {
  1172. /* d2 has been rmdir'd */
  1173. VOP_UNLOCK(d2);
  1174. if (v1 && v1->v_type == VDIR) {
  1175. VOP_UNLOCK(v1);
  1176. }
  1177. VOP_UNLOCK(d1);
  1178. if (v1) {
  1179. vrele(v1);
  1180. }
  1181. return ENOENT;
  1182. }
  1183. error = do_relookup(d2, ulr2, &v2, cn2);
  1184. if (v2_missing_ok) {
  1185. if (error == ENOENT) {
  1186. /* as above */
  1187. v2 = NULL;
  1188. error = 0;
  1189. }
  1190. } else {
  1191. if (error == 0 && v2 == NULL) {
  1192. /* This is what relookup sets if v2 disappeared. */
  1193. error = ENOENT;
  1194. }
  1195. }
  1196. if (error) {
  1197. VOP_UNLOCK(d2);
  1198. if (v1 && v1->v_type == VDIR) {
  1199. VOP_UNLOCK(v1);
  1200. }
  1201. VOP_UNLOCK(d1);
  1202. if (v1) {
  1203. vrele(v1);
  1204. }
  1205. return error;
  1206. }
  1207. if (v1 && v1->v_type != VDIR && v1 != v2) {
  1208. vn_lock(v1, LK_EXCLUSIVE | LK_RETRY);
  1209. }
  1210. *v1_ret = v1;
  1211. *v2_ret = v2;
  1212. return 0;
  1213. }
  1214. /*
  1215. * Rename vnode operation
  1216. * rename("foo", "bar");
  1217. * is essentially
  1218. * unlink("bar");
  1219. * link("foo", "bar");
  1220. * unlink("foo");
  1221. * but ``atomically''. Can't do full commit without saving state in the
  1222. * inode on disk which isn't feasible at this time. Best we can do is
  1223. * always guarantee the target exists.
  1224. *
  1225. * Basic algorithm is:
  1226. *
  1227. * 1) Bump link count on source while we're linking it to the
  1228. * target. This also ensure the inode won't be deleted out
  1229. * from underneath us while we work (it may be truncated by
  1230. * a concurrent `trunc' or `open' for creation).
  1231. * 2) Link source to destination. If destination already exists,
  1232. * delete it first.
  1233. * 3) Unlink source reference to inode if still around. If a
  1234. * directory was moved and the parent of the destination
  1235. * is different from the source, patch the ".." entry in the
  1236. * directory.
  1237. */
  1238. int
  1239. ufs_rename(void *v)
  1240. {
  1241. struct vop_rename_args /* {
  1242. struct vnode *a_fdvp;
  1243. struct vnode *a_fvp;
  1244. struct componentname *a_fcnp;
  1245. struct vnode *a_tdvp;
  1246. struct vnode *a_tvp;
  1247. struct componentname *a_tcnp;
  1248. } */ *ap = v;
  1249. struct vnode *tvp, *tdvp, *fvp, *fdvp;
  1250. struct componentname *tcnp, *fcnp;
  1251. struct inode *ip, *txp, *fxp, *tdp, *fdp;
  1252. struct mount *mp;
  1253. struct direct *newdir;
  1254. int doingdirectory, error;
  1255. ino_t oldparent, newparent;
  1256. struct ufs_lookup_results from_ulr, to_ulr;
  1257. tvp = ap->a_tvp;
  1258. tdvp = ap->a_tdvp;
  1259. fvp = ap->a_fvp;
  1260. fdvp = ap->a_fdvp;
  1261. tcnp = ap->a_tcnp;
  1262. fcnp = ap->a_fcnp;
  1263. doingdirectory = error = 0;
  1264. oldparent = newparent = 0;
  1265. /* save the supplemental lookup results as they currently exist */
  1266. from_ulr = VTOI(fdvp)->i_crap;
  1267. to_ulr = VTOI(tdvp)->i_crap;
  1268. UFS_CHECK_CRAPCOUNTER(VTOI(fdvp));
  1269. UFS_CHECK_CRAPCOUNTER(VTOI(tdvp));
  1270. /*
  1271. * Owing to VFS oddities we are currently called with tdvp/tvp
  1272. * locked and not fdvp/fvp. In a sane world we'd be passed
  1273. * tdvp and fdvp only, unlocked, and two name strings. Pretend
  1274. * we have a sane world and unlock tdvp and tvp.
  1275. */
  1276. VOP_UNLOCK(tdvp);
  1277. if (tvp && tvp != tdvp) {
  1278. VOP_UNLOCK(tvp);
  1279. }
  1280. /* Also pretend we have a sane world and vrele fvp/tvp. */
  1281. vrele(fvp);
  1282. fvp = NULL;
  1283. if (tvp) {
  1284. vrele(tvp);
  1285. tvp = NULL;
  1286. }
  1287. /*
  1288. * Check for cross-device rename.
  1289. */
  1290. if (fdvp->v_mount != tdvp->v_mount) {
  1291. error = EXDEV;
  1292. goto abort;
  1293. }
  1294. /*
  1295. * Reject "." and ".."
  1296. */
  1297. if ((fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT) ||
  1298. (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
  1299. (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')) {
  1300. error = EINVAL;
  1301. goto abort;
  1302. }
  1303. /*
  1304. * Get locks.
  1305. */
  1306. /* paranoia */
  1307. fcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
  1308. tcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
  1309. if (fdvp == tdvp) {
  1310. /* One directory. Lock it and relookup both children. */
  1311. vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
  1312. if (VTOI(fdvp)->i_size == 0) {
  1313. /* directory has been rmdir'd */
  1314. VOP_UNLOCK(fdvp);
  1315. error = ENOENT;
  1316. goto abort;
  1317. }
  1318. error = do_relookup(fdvp, &from_ulr, &fvp, fcnp);
  1319. if (error == 0 && fvp == NULL) {
  1320. /* relookup may produce this if fvp disappears */
  1321. error = ENOENT;
  1322. }
  1323. if (error) {
  1324. VOP_UNLOCK(fdvp);
  1325. goto abort;
  1326. }
  1327. /*
  1328. * The right way to do this is to look up both children
  1329. * without locking either, and then lock both unless they
  1330. * turn out to be the same. However, due to deep-seated
  1331. * VFS-level issues all lookups lock the child regardless
  1332. * of whether LOCKLEAF is set (if LOCKLEAF is not set,
  1333. * the child is locked during lookup and then unlocked)
  1334. * so it is not safe to look up tvp while fvp is locked.
  1335. *
  1336. * Unlocking fvp here temporarily is more or less safe,
  1337. * because with the directory locked there's not much
  1338. * that can happen to it. However, ideally it wouldn't
  1339. * be necessary. XXX.
  1340. */
  1341. VOP_UNLOCK(fvp);
  1342. /* remember fdvp == tdvp so tdvp is locked */
  1343. error = do_relookup(tdvp, &to_ulr, &tvp, tcnp);
  1344. if (error && error != ENOENT) {
  1345. VOP_UNLOCK(fdvp);
  1346. goto abort;
  1347. }
  1348. if (error == ENOENT) {
  1349. /*
  1350. * Note: currently if the name doesn't exist,
  1351. * relookup succeeds (it intercepts the
  1352. * EJUSTRETURN from VOP_LOOKUP) and sets tvp
  1353. * to NULL. Therefore, we will never get
  1354. * ENOENT and this branch is not needed.
  1355. * However, in a saner future the EJUSTRETURN
  1356. * garbage will go away, so let's DTRT.
  1357. */
  1358. tvp = NULL;
  1359. }
  1360. /* tvp is locked; lock fvp if necessary */
  1361. if (!tvp || tvp != fvp) {
  1362. vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
  1363. }
  1364. } else {
  1365. int found_fdvp;
  1366. struct vnode *illegal_fvp;
  1367. /*
  1368. * The source must not be above the destination. (If
  1369. * it were, the rename would detach a section of the
  1370. * tree.)
  1371. *
  1372. * Look up the tree from tdvp to see if we find fdvp,
  1373. * and if so, return the immediate child of fdvp we're
  1374. * under; that must not turn out to be the same as
  1375. * fvp.
  1376. *
  1377. * The per-volume rename lock guarantees that the
  1378. * result of this check remains true until we finish
  1379. * looking up and locking.
  1380. */
  1381. error = ufs_parentcheck(fdvp, tdvp, fcnp->cn_cred,
  1382. &found_fdvp, &illegal_fvp);
  1383. if (error) {
  1384. goto abort;
  1385. }
  1386. /* Must lock in tree order. */
  1387. if (found_fdvp) {
  1388. /* fdvp -> fvp -> tdvp -> tvp */
  1389. error = lock_vnode_sequence(fdvp, &from_ulr,
  1390. &fvp, fcnp, 0,
  1391. EINVAL,
  1392. tdvp, &to_ulr,
  1393. &tvp, tcnp, 1);
  1394. } else {
  1395. /* tdvp -> tvp -> fdvp -> fvp */
  1396. error = lock_vnode_sequence(tdvp, &to_ulr,
  1397. &tvp, tcnp, 1,
  1398. ENOTEMPTY,
  1399. fdvp, &from_ulr,
  1400. &fvp, fcnp, 0);
  1401. }
  1402. if (error) {
  1403. if (illegal_fvp) {
  1404. vrele(illegal_fvp);
  1405. }
  1406. goto abort;
  1407. }
  1408. KASSERT(fvp != NULL);
  1409. if (illegal_fvp && fvp == illegal_fvp) {
  1410. vrele(illegal_fvp);
  1411. error = EINVAL;
  1412. goto abort_withlocks;
  1413. }
  1414. if (illegal_fvp) {
  1415. vrele(illegal_fvp);
  1416. }
  1417. }
  1418. KASSERT(fdvp && VOP_ISLOCKED(fdvp));
  1419. KASSERT(fvp && VOP_ISLOCKED(fvp));
  1420. KASSERT(tdvp && VOP_ISLOCKED(tdvp));
  1421. KASSERT(tvp == NULL || VOP_ISLOCKED(tvp));
  1422. /* --- everything is now locked --- */
  1423. if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
  1424. (VTOI(tdvp)->i_flags & APPEND))) {
  1425. error = EPERM;
  1426. goto abort_withlocks;
  1427. }
  1428. /*
  1429. * Check if just deleting a link name.
  1430. */
  1431. if (fvp == tvp) {
  1432. if (fvp->v_type == VDIR) {
  1433. error = EINVAL;
  1434. goto abort_withlocks;
  1435. }
  1436. /* Release destination completely. Leave fdvp locked. */
  1437. VOP_ABORTOP(tdvp, tcnp);
  1438. if (fdvp != tdvp) {
  1439. VOP_UNLOCK(tdvp);
  1440. }
  1441. VOP_UNLOCK(tvp);
  1442. vrele(tdvp);
  1443. vrele(tvp);
  1444. /* Delete source. */
  1445. /* XXX: do we really need to relookup again? */
  1446. /*
  1447. * fdvp is still locked, but we just unlocked fvp
  1448. * (because fvp == tvp) so just decref fvp
  1449. */
  1450. vrele(fvp);
  1451. fcnp->cn_flags &= ~(MODMASK);
  1452. fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
  1453. fcnp->cn_nameiop = DELETE;
  1454. if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
  1455. vput(fdvp);
  1456. return (error);
  1457. }
  1458. return (VOP_REMOVE(fdvp, fvp, fcnp));
  1459. }
  1460. fdp = VTOI(fdvp);
  1461. ip = VTOI(fvp);
  1462. if ((nlink_t) ip->i_nlink >= LINK_MAX) {
  1463. error = EMLINK;
  1464. goto abort_withlocks;
  1465. }
  1466. if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
  1467. (fdp->i_flags & APPEND)) {
  1468. error = EPERM;
  1469. goto abort_withlocks;
  1470. }
  1471. if ((ip->i_mode & IFMT) == IFDIR) {
  1472. /*
  1473. * Avoid ".", "..", and aliases of "." for obvious reasons.
  1474. */
  1475. if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
  1476. fdp == ip ||
  1477. (fcnp->cn_flags & ISDOTDOT) ||
  1478. (tcnp->cn_flags & ISDOTDOT) ||
  1479. (ip->i_flag & IN_RENAME)) {
  1480. error = EINVAL;
  1481. goto abort_withlocks;
  1482. }
  1483. ip->i_flag |= IN_RENAME;
  1484. doingdirectory = 1;
  1485. }
  1486. oldparent = fdp->i_number;
  1487. VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
  1488. /*
  1489. * Both the directory
  1490. * and target vnodes are locked.
  1491. */
  1492. tdp = VTOI(tdvp);
  1493. txp = NULL;
  1494. if (tvp)
  1495. txp = VTOI(tvp);
  1496. mp = fdvp->v_mount;
  1497. fstrans_start(mp, FSTRANS_SHARED);
  1498. if (oldparent != tdp->i_number)
  1499. newparent = tdp->i_number;
  1500. /*
  1501. * If ".." must be changed (ie the directory gets a new
  1502. * parent) the user must have write permission in the source
  1503. * so as to be able to change "..".
  1504. */
  1505. if (doingdirectory && newparent) {
  1506. error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
  1507. if (error)
  1508. goto out;
  1509. }
  1510. KASSERT(fdvp != tvp);
  1511. if (newparent) {
  1512. /* Check for the rename("foo/foo", "foo") case. */
  1513. if (fdvp == tvp) {
  1514. error = doingdirectory ? ENOTEMPTY : EISDIR;
  1515. goto out;
  1516. }
  1517. }
  1518. fxp = VTOI(fvp);
  1519. fdp = VTOI(fdvp);
  1520. error = UFS_WAPBL_BEGIN(fdvp->v_mount);
  1521. if (error)
  1522. goto out2;
  1523. /*
  1524. * 1) Bump link count while we're moving stuff
  1525. * around. If we crash somewhere before
  1526. * completing our work, the link count
  1527. * may be wrong, but correctable.
  1528. */
  1529. ip->i_nlink++;
  1530. DIP_ASSIGN(ip, nlink, ip->i_nlink);
  1531. ip->i_flag |= IN_CHANGE;
  1532. if ((error = UFS_UPDATE(fvp, NULL, NULL, UPDATE_DIROP)) != 0) {
  1533. goto bad;
  1534. }
  1535. /*
  1536. * 2) If target doesn't exist, link the target
  1537. * to the source and unlink the source.
  1538. * Otherwise, rewrite the target directory
  1539. * entry to reference the source inode and
  1540. * expunge the original entry's existence.
  1541. */
  1542. if (txp == NULL) {
  1543. if (tdp->i_dev != ip->i_dev)
  1544. panic("rename: EXDEV");
  1545. /*
  1546. * Account for ".." in new directory.
  1547. * When source and destination have the same
  1548. * parent we don't fool with the link count.
  1549. */
  1550. if (doingdirectory && newparent) {
  1551. if ((nlink_t)tdp->i_nlink >= LINK_MAX) {
  1552. error = EMLINK;
  1553. goto bad;
  1554. }
  1555. tdp->i_nlink++;
  1556. DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
  1557. tdp->i_flag |= IN_CHANGE;
  1558. if ((error = UFS_UPDATE(tdvp, NULL, NULL,
  1559. UPDATE_DIROP)) != 0) {
  1560. tdp->i_nlink--;
  1561. DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
  1562. tdp->i_flag |= IN_CHANGE;
  1563. goto bad;
  1564. }
  1565. }
  1566. newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
  1567. ufs_makedirentry(ip, tcnp, newdir);
  1568. error = ufs_direnter(tdvp, &to_ulr,
  1569. NULL, newdir, tcnp, NULL);
  1570. pool_cache_put(ufs_direct_cache, newdir);
  1571. if (error != 0) {
  1572. if (doingdirectory && newparent) {
  1573. tdp->i_nlink--;
  1574. DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
  1575. tdp->i_flag |= IN_CHANGE;
  1576. (void)UFS_UPDATE(tdvp, NULL, NULL,
  1577. UPDATE_WAIT | UPDATE_DIROP);
  1578. }
  1579. goto bad;
  1580. }
  1581. VN_KNOTE(tdvp, NOTE_WRITE);
  1582. } else {
  1583. if (txp->i_dev != tdp->i_dev || txp->i_dev != ip->i_dev)
  1584. panic("rename: EXDEV");
  1585. /*
  1586. * Short circuit rename(foo, foo).
  1587. */
  1588. if (txp->i_number == ip->i_number)
  1589. panic("rename: same file");
  1590. /*
  1591. * If the parent directory is "sticky", then the user must
  1592. * own the parent directory, or the destination of the rename,
  1593. * otherwise the destination may not be changed (except by
  1594. * root). This implements append-only directories.
  1595. */
  1596. if ((tdp->i_mode & S_ISTXT) &&
  1597. kauth_authorize_generic(tcnp->cn_cred,
  1598. KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
  1599. kauth_cred_geteuid(tcnp->cn_cred) != tdp->i_uid &&
  1600. txp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
  1601. error = EPERM;
  1602. goto bad;
  1603. }
  1604. /*
  1605. * Target must be empty if a directory and have no links
  1606. * to it. Also, ensure source and target are compatible
  1607. * (both directories, or both not directories).
  1608. */
  1609. if ((txp->i_mode & IFMT) == IFDIR) {
  1610. if (txp->i_nlink > 2 ||
  1611. !ufs_dirempty(txp, tdp->i_number, tcnp->cn_cred)) {
  1612. error = ENOTEMPTY;
  1613. goto bad;
  1614. }
  1615. if (!doingdirectory) {
  1616. error = ENOTDIR;
  1617. goto bad;
  1618. }
  1619. cache_purge(tdvp);
  1620. } else if (doingdirectory) {
  1621. error = EISDIR;
  1622. goto bad;
  1623. }
  1624. if ((error = ufs_dirrewrite(tdp, to_ulr.ulr_offset,
  1625. txp, ip->i_number,
  1626. IFTODT(ip->i_mode), doingdirectory && newparent ?
  1627. newparent : doingdirectory, IN_CHANGE | IN_UPDATE)) != 0)
  1628. goto bad;
  1629. if (doingdirectory) {
  1630. /*
  1631. * Truncate inode. The only stuff left in the directory
  1632. * is "." and "..". The "." reference is inconsequential
  1633. * since we are quashing it. We have removed the "."
  1634. * reference and the reference in the parent directory,
  1635. * but there may be other hard links.
  1636. */
  1637. if (!newparent) {
  1638. tdp->i_nlink--;
  1639. DIP_ASSIGN(tdp, nlink, tdp->i_nlink);
  1640. tdp->i_flag |= IN_CHANGE;
  1641. UFS_WAPBL_UPDATE(tdvp, NULL, NULL, 0);
  1642. }
  1643. txp->i_nlink--;
  1644. DIP_ASSIGN(txp, nlink, txp->i_nlink);
  1645. txp->i_flag |= IN_CHANGE;
  1646. if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
  1647. tcnp->cn_cred)))
  1648. goto bad;
  1649. }
  1650. VN_KNOTE(tdvp, NOTE_WRITE);
  1651. VN_KNOTE(tvp, NOTE_DELETE);
  1652. }
  1653. /*
  1654. * Handle case where the directory entry we need to remove,
  1655. * which is/was at from_ulr.ulr_offset, or the one before it,
  1656. * which is/was at from_ulr.ulr_offset - from_ulr.ulr_count,
  1657. * may have been moved when the directory insertion above
  1658. * performed compaction.
  1659. */
  1660. if (tdp->i_number == fdp->i_number &&
  1661. ulr_overlap(&from_ulr, &to_ulr)) {
  1662. struct buf *bp;
  1663. struct direct *ep;
  1664. struct ufsmount *ump = fdp->i_ump;
  1665. doff_t curpos;
  1666. doff_t endsearch; /* offset to end directory search */
  1667. uint32_t prev_reclen;
  1668. int dirblksiz = ump->um_dirblksiz;
  1669. const int needswap = UFS_MPNEEDSWAP(ump);
  1670. u_long bmask;
  1671. int namlen, entryoffsetinblock;
  1672. char *dirbuf;
  1673. bmask = fdvp->v_mount->mnt_stat.f_iosize - 1;
  1674. /*
  1675. * The fcnp entry will be somewhere between the start of
  1676. * compaction (to_ulr.ulr_offset) and the original location
  1677. * (from_ulr.ulr_offset).
  1678. */
  1679. curpos = to_ulr.ulr_offset;
  1680. endsearch = from_ulr.ulr_offset + from_ulr.ulr_reclen;
  1681. entryoffsetinblock = 0;
  1682. /*
  1683. * Get the directory block containing the start of
  1684. * compaction.
  1685. */
  1686. error = ufs_blkatoff(fdvp, (off_t)to_ulr.ulr_offset, &dirbuf,
  1687. &bp, false);
  1688. if (error)
  1689. goto bad;
  1690. /*
  1691. * Keep existing ulr_count (length of previous record)
  1692. * for the case where compaction did not include the
  1693. * previous entry but started at the from-entry.
  1694. */
  1695. prev_reclen = from_ulr.ulr_count;
  1696. while (curpos < endsearch) {
  1697. uint32_t reclen;
  1698. /*
  1699. * If necessary, get the next directory block.
  1700. *
  1701. * dholland 7/13/11 to the best of my understanding
  1702. * this should never happen; compaction occurs only
  1703. * within single blocks. I think.
  1704. */
  1705. if ((curpos & bmask) == 0) {
  1706. if (bp != NULL)
  1707. brelse(bp, 0);
  1708. error = ufs_blkatoff(fdvp, (off_t)curpos,
  1709. &dirbuf, &bp, false);
  1710. if (error)
  1711. goto bad;
  1712. entryoffsetinblock = 0;
  1713. }
  1714. KASSERT(bp != NULL);
  1715. ep = (struct direct *)(dirbuf + entryoffsetinblock);
  1716. reclen = ufs_rw16(ep->d_reclen, needswap);
  1717. #if (BYTE_ORDER == LITTLE_ENDIAN)
  1718. if (FSFMT(fdvp) && needswap == 0)
  1719. namlen = ep->d_type;
  1720. else
  1721. namlen = ep->d_namlen;
  1722. #else
  1723. if (FSFMT(fdvp) && needswap != 0)
  1724. namlen = ep->d_type;
  1725. else
  1726. namlen = ep->d_namlen;
  1727. #endif
  1728. if ((ep->d_ino != 0) &&
  1729. (ufs_rw32(ep->d_ino, needswap) != WINO) &&
  1730. (namlen == fcnp->cn_namelen) &&
  1731. memcmp(ep->d_name, fcnp->cn_nameptr, namlen) == 0) {
  1732. from_ulr.ulr_reclen = reclen;
  1733. break;
  1734. }
  1735. curpos += reclen;
  1736. entryoffsetinblock += reclen;
  1737. prev_reclen = reclen;
  1738. }
  1739. from_ulr.ulr_offset = curpos;
  1740. from_ulr.ulr_count = prev_reclen;
  1741. KASSERT(curpos <= endsearch);
  1742. /*
  1743. * If ulr_offset points to start of a directory block,
  1744. * clear ulr_count so ufs_dirremove() doesn't try to
  1745. * merge free space over a directory block boundary.
  1746. */
  1747. if ((from_ulr.ulr_offset & (dirblksiz - 1)) == 0)
  1748. from_ulr.ulr_count = 0;
  1749. brelse(bp, 0);
  1750. }
  1751. /*
  1752. * 3) Unlink the source.
  1753. */
  1754. #if 0
  1755. /*
  1756. * Ensure that the directory entry still exists and has not
  1757. * changed while the new name has been entered. If the source is
  1758. * a file then…

Large files files are truncated, but you can click here to view the full file