1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <sys/types.h>
26#include <sys/t_lock.h>
27#include <sys/param.h>
28#include <sys/time.h>
29#include <sys/systm.h>
30#include <sys/sysmacros.h>
31#include <sys/resource.h>
32#include <sys/signal.h>
33#include <sys/cred.h>
34#include <sys/user.h>
35#include <sys/buf.h>
36#include <sys/vfs.h>
37#include <sys/stat.h>
38#include <sys/vnode.h>
39#include <sys/mode.h>
40#include <sys/proc.h>
41#include <sys/disp.h>
42#include <sys/file.h>
43#include <sys/fcntl.h>
44#include <sys/flock.h>
45#include <sys/kmem.h>
46#include <sys/uio.h>
47#include <sys/dnlc.h>
48#include <sys/conf.h>
49#include <sys/errno.h>
50#include <sys/mman.h>
51#include <sys/fbuf.h>
52#include <sys/pathname.h>
53#include <sys/debug.h>
54#include <sys/vmsystm.h>
55#include <sys/cmn_err.h>
56#include <sys/dirent.h>
57#include <sys/errno.h>
58#include <sys/modctl.h>
59#include <sys/statvfs.h>
60#include <sys/mount.h>
61#include <sys/sunddi.h>
62#include <sys/bootconf.h>
63#include <sys/policy.h>
64
65#include <vm/hat.h>
66#include <vm/page.h>
67#include <vm/pvn.h>
68#include <vm/as.h>
69#include <vm/seg.h>
70#include <vm/seg_map.h>
71#include <vm/seg_kmem.h>
72#include <vm/seg_vn.h>
73#include <vm/rm.h>
74#include <vm/page.h>
75#include <sys/swap.h>
76
77
78#include <fs/fs_subr.h>
79
80
81#include <sys/fs/udf_volume.h>
82#include <sys/fs/udf_inode.h>
83
84
85struct slot {
86	enum	{NONE, COMPACT, FOUND, EXIST} status;
87	off_t	offset;		/* offset of area with free space */
88	int	size;		/* size of area at slotoffset */
89	struct	fbuf *fbp;	/* dir buf where slot is */
90	struct file_id *ep;	/* pointer to slot */
91	off_t	endoff;		/* last useful location found in search */
92};
93
94
95int32_t ud_dircheckforname(struct ud_inode *, char *, int,
96		struct slot *, struct ud_inode **, uint8_t *, struct cred *);
97int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
98int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
99int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
100int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
101	struct vattr *, enum de_op, struct cred *);
102int32_t ud_diraddentry(struct ud_inode *, char *,
103	enum de_op, int, struct slot *, struct ud_inode *,
104	struct ud_inode *, struct cred *);
105int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
106int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
107	struct ud_inode *, struct ud_inode *, char *, uint8_t *,
108	struct slot *, struct cred *);
109int32_t ud_dirprepareentry(struct ud_inode *,
110	struct slot *, uint8_t *, struct cred *);
111int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
112		struct ud_inode *);
113int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
114
115int
116ud_dirlook(struct ud_inode *dip,
117	char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
118{
119	struct udf_vfs *udf_vfsp;
120	int32_t error = 0, namelen, adhoc_search;
121	u_offset_t offset, adhoc_offset, dirsize, end;
122	struct vnode *dvp, *vp;
123	struct fbuf *fbp;
124	struct file_id *fid;
125	uint8_t *fname, dummy[3];
126	int32_t id_len, doingchk;
127	uint32_t old_loc;
128	uint16_t old_prn;
129
130	uint8_t *dname;
131	uint8_t *buf = NULL;
132
133	ud_printf("ud_dirlook\n");
134
135	udf_vfsp = dip->i_udf;
136
137restart:
138	doingchk = 0;
139	old_prn = 0xFFFF;
140	old_loc = 0;
141	dvp = ITOV(dip);
142	/*
143	 * Check accessibility of directory.
144	 */
145	if (dip->i_type != VDIR) {
146		return (ENOTDIR);
147	}
148	if (error = ud_iaccess(dip, IEXEC, cr, 1)) {
149		return (error);
150	}
151
152	/*
153	 * Null component name is synonym for directory being searched.
154	 */
155	if (*namep == '\0') {
156		VN_HOLD(dvp);
157		*ipp = dip;
158		return (0);
159	}
160	namelen = strlen(namep);
161	if ((namelen == 1) &&
162	    (namep[0] == '.') && (namep[1] == '\0')) {
163		/* Current directory */
164		VN_HOLD(dvp);
165		*ipp = dip;
166		dnlc_enter(dvp, namep, ITOV(*ipp));
167		return (0);
168	}
169
170	if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
171		/* vp is already held from dnlc_lookup */
172
173		*ipp = VTOI(vp);
174		return (0);
175	}
176
177	dname = kmem_zalloc(1024, KM_SLEEP);
178	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
179
180	/*
181	 * Read lock the inode we are searching.  You will notice that we
182	 * didn't hold the read lock while searching the dnlc.  This means
183	 * that the entry could now be in the dnlc.  This doesn't cause any
184	 * problems because dnlc_enter won't add an entry if it is already
185	 * there.
186	 */
187	rw_enter(&dip->i_rwlock, RW_READER);
188
189	/*
190	 * Take care to look at dip->i_diroff only once, as it
191	 * may be changing due to other threads/cpus.
192	 */
193
194recheck:
195	offset = dip->i_diroff;
196	end = dirsize = dip->i_size;
197
198	if (offset > dirsize) {
199		offset = 0;
200	}
201	adhoc_offset = offset;
202	adhoc_search = (offset == 0) ? 1 : 2;
203
204	fbp = NULL;
205
206	while (adhoc_search--) {
207		while (offset < end) {
208			error = ud_get_next_fid(dip, &fbp,
209			    offset, &fid, &fname, buf);
210			if (error != 0) {
211				break;
212			}
213			if ((fid->fid_flags & FID_DELETED) == 0) {
214				if (fid->fid_flags & FID_PARENT) {
215					id_len = 2;
216					fname = dummy;
217					dummy[0] = '.';
218					dummy[1] = '.';
219					dummy[2] = '\0';
220				} else {
221					if ((error = ud_uncompress(
222					    fid->fid_idlen, &id_len,
223					    fname, dname)) != 0) {
224						break;
225					}
226					fname = (uint8_t *)dname;
227					fname[id_len] = '\0';
228				}
229				if ((namelen == id_len) &&
230				    (strncmp(namep, (caddr_t)fname,
231				    namelen) == 0)) {
232					uint32_t loc;
233					uint16_t prn;
234
235
236					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
237					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
238					dip->i_diroff = offset + FID_LEN(fid);
239
240					if (doingchk) {
241						if ((loc == old_loc) &&
242						    (prn == old_prn)) {
243							goto checkok;
244						} else {
245							if (fbp != NULL) {
246								fbrelse(fbp,
247								    S_READ);
248								fbp = NULL;
249							}
250							VN_RELE(ITOV(*ipp));
251							rw_exit(&dip->i_rwlock);
252							goto restart;
253						}
254						/* NOTREACHED */
255					}
256
257					if (namelen == 2 &&
258					    fname[0] == '.' &&
259					    fname[1] == '.') {
260
261						struct timespec32 omtime;
262
263						omtime = dip->i_mtime;
264						rw_exit(&dip->i_rwlock);
265
266						error = ud_iget(dip->i_vfs, prn,
267						    loc, ipp, NULL, cr);
268
269						rw_enter(&dip->i_rwlock,
270						    RW_READER);
271
272						if (error) {
273							goto done;
274						}
275
276						if ((omtime.tv_sec !=
277						    dip->i_mtime.tv_sec) ||
278						    (omtime.tv_nsec !=
279						    dip->i_mtime.tv_nsec)) {
280
281							doingchk = 1;
282							old_prn = prn;
283							old_loc = loc;
284							dip->i_diroff = 0;
285							if (fbp != NULL) {
286								fbrelse(fbp,
287								    S_READ);
288								fbp = NULL;
289							}
290							goto recheck;
291						}
292					} else {
293
294						error = ud_iget(dip->i_vfs, prn,
295						    loc, ipp, NULL, cr);
296					}
297checkok:
298					if (error == 0) {
299						dnlc_enter(dvp, namep,
300						    ITOV(*ipp));
301					}
302					goto done;
303				}
304			}
305			offset += FID_LEN(fid);
306		}
307		if (fbp != NULL) {
308			fbrelse(fbp, S_READ);
309			fbp = NULL;
310		}
311		end = adhoc_offset;
312		offset = 0;
313	}
314	error = ENOENT;
315done:
316	kmem_free(buf, udf_vfsp->udf_lbsize);
317	kmem_free(dname, 1024);
318	if (fbp != NULL) {
319		fbrelse(fbp, S_READ);
320	}
321	rw_exit(&dip->i_rwlock);
322	return (error);
323}
324
325int
326ud_direnter(
327	struct ud_inode *tdp,
328	char *namep,
329	enum de_op op,
330	struct ud_inode *sdp,
331	struct ud_inode *sip,
332	struct vattr *vap,
333	struct ud_inode **ipp,
334	struct cred *cr,
335	caller_context_t *ctp)
336{
337	struct udf_vfs *udf_vfsp;
338	struct ud_inode *tip;
339	struct slot slot;
340	int32_t namlen, err;
341	char *s;
342
343	uint8_t *buf = NULL;
344
345	ud_printf("ud_direnter\n");
346
347	udf_vfsp = tdp->i_udf;
348	/* don't allow '/' characters in pathname component */
349	for (s = namep, namlen = 0; *s; s++, namlen++) {
350		if (*s == '/') {
351			return (EACCES);
352		}
353	}
354
355	if (namlen == 0) {
356		cmn_err(CE_WARN, "name length == 0 in ud_direnter");
357		return (EINVAL);
358	}
359
360	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
361	/*
362	 * If name is "." or ".." then if this is a create look it up
363	 * and return EEXIST.  Rename or link TO "." or ".." is forbidden.
364	 */
365	if (namep[0] == '.' &&
366	    (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
367		if (op == DE_RENAME) {
368			return (EINVAL);	/* *SIGH* should be ENOTEMPTY */
369		}
370		if (ipp) {
371			/*
372			 * ud_dirlook will acquire the i_rwlock
373			 */
374			rw_exit(&tdp->i_rwlock);
375			if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
376				rw_enter(&tdp->i_rwlock, RW_WRITER);
377				return (err);
378			}
379			rw_enter(&tdp->i_rwlock, RW_WRITER);
380		}
381		return (EEXIST);
382	}
383
384	tip = NULL;
385	slot.status = NONE;
386	slot.offset = 0;
387	slot.size = 0;
388	slot.fbp = NULL;
389	slot.ep = NULL;
390	slot.endoff = 0;
391
392	/*
393	 * For link and rename lock the source entry and check the link count
394	 * to see if it has been removed while it was unlocked.  If not, we
395	 * increment the link count and force the inode to disk to make sure
396	 * that it is there before any directory entry that points to it.
397	 */
398	if (op == DE_LINK || op == DE_RENAME) {
399		rw_enter(&sip->i_contents, RW_WRITER);
400		if (sip->i_nlink == 0) {
401			rw_exit(&sip->i_contents);
402			return (ENOENT);
403		}
404		if (sip->i_nlink == MAXLINK) {
405			rw_exit(&sip->i_contents);
406			return (EMLINK);
407		}
408
409		sip->i_nlink++;
410		mutex_enter(&sip->i_tlock);
411		sip->i_flag |= ICHG;
412		mutex_exit(&sip->i_tlock);
413		ud_iupdat(sip, 1);
414		rw_exit(&sip->i_contents);
415	}
416	/*
417	 * If target directory has not been removed, then we can consider
418	 * allowing file to be created.
419	 */
420	if (tdp->i_nlink == 0) {
421		err = ENOENT;
422		goto out2;
423	}
424	/*
425	 * Check accessibility of directory.
426	 */
427	if (tdp->i_type != VDIR) {
428		err = ENOTDIR;
429		goto out2;
430	}
431	/*
432	 * Execute access is required to search the directory.
433	 */
434	if (err = ud_iaccess(tdp, IEXEC, cr, 1)) {
435		goto out2;
436	}
437	/*
438	 * If this is a rename of a directory and the parent is
439	 * different (".." must be changed), then the source
440	 * directory must not be in the directory hierarchy
441	 * above the target, as this would orphan everything
442	 * below the source directory.  Also the user must have
443	 * write permission in the source so as to be able to
444	 * change "..".
445	 */
446	if (op == DE_RENAME) {
447		if (sip == tdp) {
448			err = EINVAL;
449			goto out2;
450		}
451		rw_enter(&sip->i_contents, RW_READER);
452		if ((sip->i_type == VDIR) && (sdp != tdp)) {
453			uint32_t blkno;
454
455			if ((err = ud_iaccess(sip, IWRITE, cr, 0))) {
456				rw_exit(&sip->i_contents);
457				goto out2;
458			}
459			blkno = sip->i_icb_lbano;
460			rw_exit(&sip->i_contents);
461			if ((err = ud_dircheckpath(blkno, tdp, cr))) {
462				goto out2;
463			}
464		} else {
465			rw_exit(&sip->i_contents);
466		}
467	}
468
469	/*
470	 * Search for the entry. Return VN_HELD tip if found.
471	 */
472	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
473	rw_enter(&tdp->i_contents, RW_WRITER);
474	if (err = ud_dircheckforname(tdp,
475	    namep, namlen, &slot, &tip, buf, cr)) {
476		goto out;
477	}
478	if (tip) {
479		switch (op) {
480			case DE_CREATE :
481			case DE_MKDIR :
482				if (ipp) {
483					*ipp = tip;
484					err = EEXIST;
485				} else {
486					VN_RELE(ITOV(tip));
487				}
488				break;
489			case DE_RENAME :
490				err = ud_dirrename(sdp, sip, tdp, tip,
491				    namep, buf, &slot, cr);
492				/*
493				 * We used to VN_RELE() here, but this
494				 * was moved down so that we could send
495				 * a vnevent after the locks were dropped.
496				 */
497				break;
498			case DE_LINK :
499				/*
500				 * Can't link to an existing file.
501				 */
502				VN_RELE(ITOV(tip));
503				err = EEXIST;
504				break;
505		}
506	} else {
507		/*
508		 * The entry does not exist. Check write permission in
509		 * directory to see if entry can be created.
510		 */
511		if (err = ud_iaccess(tdp, IWRITE, cr, 0)) {
512			goto out;
513		}
514		if ((op == DE_CREATE) || (op == DE_MKDIR)) {
515			/*
516			 * Make new inode and directory entry as required.
517			 */
518			if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
519				goto out;
520		}
521		if (err = ud_diraddentry(tdp, namep, op,
522		    namlen, &slot, sip, sdp, cr)) {
523			if ((op == DE_CREATE) || (op == DE_MKDIR)) {
524				/*
525				 * Unmake the inode we just made.
526				 */
527				rw_enter(&sip->i_contents, RW_WRITER);
528				if (sip->i_type == VDIR) {
529					tdp->i_nlink--;
530				}
531				sip->i_nlink = 0;
532				mutex_enter(&sip->i_tlock);
533				sip->i_flag |= ICHG;
534				mutex_exit(&sip->i_tlock);
535				rw_exit(&sip->i_contents);
536				VN_RELE(ITOV(sip));
537				sip = NULL;
538			}
539		} else if (ipp) {
540			*ipp = sip;
541		} else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
542			VN_RELE(ITOV(sip));
543		}
544	}
545out:
546	if (buf != NULL) {
547		kmem_free(buf, udf_vfsp->udf_lbsize);
548	}
549	if (slot.fbp) {
550		fbrelse(slot.fbp, S_OTHER);
551	}
552	rw_exit(&tdp->i_contents);
553
554	if (op == DE_RENAME) {
555		/*
556		 * If it's all good, send events after locks are dropped
557		 * but before vnodes are released.
558		 */
559		if (err == 0) {
560			if (tip) {
561				vnevent_rename_dest(ITOV(tip), ITOV(tdp),
562				    namep, ctp);
563			}
564
565			if (sdp != tdp) {
566				vnevent_rename_dest_dir(ITOV(tdp), ctp);
567			}
568		}
569
570		/*
571		 * The following VN_RELE() was moved from the
572		 * DE_RENAME case above
573		 */
574		if (tip) {
575			VN_RELE(ITOV(tip));
576		}
577	}
578
579out2:
580	if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
581		/*
582		 * Undo bumped link count.
583		 */
584		rw_enter(&sip->i_contents, RW_WRITER);
585		sip->i_nlink--;
586		rw_exit(&sip->i_contents);
587
588		mutex_enter(&sip->i_tlock);
589		sip->i_flag |= ICHG;
590		mutex_exit(&sip->i_tlock);
591	}
592	return (err);
593}
594
595/*
596 * Locking i_contents in this
597 * function seems to be really weird
598 */
599int
600ud_dirremove(
601	struct ud_inode *dp,
602	char *namep,
603	struct ud_inode *oip,
604	struct vnode *cdir,
605	enum dr_op op,
606	struct cred *cr,
607	caller_context_t *ctp)
608{
609	struct udf_vfs *udf_vfsp;
610	int32_t namelen, err = 0;
611	struct slot slot;
612	struct ud_inode *ip;
613	mode_t mode;
614	struct file_id *fid;
615	uint8_t *buf = NULL;
616	uint32_t tbno;
617
618	ud_printf("ud_dirremove\n");
619
620	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
621
622	udf_vfsp = dp->i_udf;
623	namelen = (int)strlen(namep);
624	if (namelen == 0) {
625		cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
626		return (EINVAL);
627	}
628
629	/*
630	 * return err when removing . and ..
631	 */
632	if (namep[0] == '.') {
633		if (namelen == 1) {
634			return (EINVAL);
635		} else if (namelen == 2 && namep[1] == '.') {
636			return (EEXIST);	/* SIGH should be ENOTEMPTY */
637		}
638	}
639
640	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
641
642	/*
643	 * Check accessibility of directory.
644	 */
645	if (dp->i_type != VDIR) {
646		return (ENOTDIR);
647	}
648
649	ip = NULL;
650	slot.status = FOUND;	/* don't need to look for empty slot */
651	slot.offset = 0;
652	slot.size = 0;
653	slot.fbp = NULL;
654	slot.ep = NULL;
655	slot.endoff = 0;
656	/*
657	 * Execute access is required to search the directory.
658	 * Access for write is interpreted as allowing
659	 * deletion of files in the directory.
660	 */
661	if (err = ud_iaccess(dp, IEXEC|IWRITE, cr, 1)) {
662		return (err);
663	}
664
665	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
666
667	rw_enter(&dp->i_contents, RW_WRITER);
668
669	if (err = ud_dircheckforname(dp, namep, namelen, &slot, &ip,
670	    buf, cr)) {
671		goto out_novfs;
672	}
673	if (ip == NULL) {
674		err = ENOENT;
675		goto out_novfs;
676	}
677	if (oip && oip != ip) {
678		err = ENOENT;
679		goto out_novfs;
680	}
681
682	if ((mode = ip->i_type) == VDIR) {
683		/*
684		 * vn_vfswlock() prevents races between mount and rmdir.
685		 */
686		if (vn_vfswlock(ITOV(ip))) {
687			err = EBUSY;
688			goto out_novfs;
689		}
690		if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
691			err = EBUSY;
692			goto out;
693		}
694		/*
695		 * If we are removing a directory, get a lock on it.
696		 * If the directory is empty, it will stay empty until
697		 * we can remove it.
698		 */
699		rw_enter(&ip->i_rwlock, RW_READER);
700	}
701	/* We must be holding i_contents */
702	rw_enter(&ip->i_contents, RW_READER);
703
704	if (err = ud_sticky_remove_access(dp, ip, cr)) {
705		rw_exit(&ip->i_contents);
706		if (mode == VDIR) {
707			rw_exit(&ip->i_rwlock);
708		}
709		goto out;
710	}
711	if (op == DR_RMDIR) {
712		/*
713		 * For rmdir(2), some special checks are required.
714		 * (a) Don't remove any alias of the parent (e.g. ".").
715		 * (b) Don't remove the current directory.
716		 * (c) Make sure the entry is (still) a directory.
717		 * (d) Make sure the directory is empty.
718		 */
719
720		if (dp == ip || ITOV(ip) == cdir) {
721			err = EINVAL;
722		} else if (ip->i_type != VDIR) {
723			err = ENOTDIR;
724		} else if ((ip->i_nlink != 1) ||
725		    (!ud_dirempty(ip, dp->i_uniqid, cr))) {
726			/*
727			 * Directories do not have an
728			 * entry for "." so only one link
729			 * will be there
730			 */
731			err = EEXIST;	/* SIGH should be ENOTEMPTY */
732		}
733		if (err) {
734			rw_exit(&ip->i_contents);
735			if (mode == VDIR) {
736				rw_exit(&ip->i_rwlock);
737			}
738			goto out;
739		}
740	} else if (op == DR_REMOVE)  {
741		/*
742		 * unlink(2) requires a different check: allow only
743		 * privileged processes to unlink a directory.
744		 */
745		struct vnode *vp = ITOV(ip);
746
747		if (vp->v_type == VDIR &&
748		    secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
749			err = EPERM;
750			rw_exit(&ip->i_contents);
751			rw_exit(&ip->i_rwlock);
752			goto out;
753		}
754	}
755	rw_exit(&ip->i_contents);
756
757	/*
758	 * Remove the cache'd entry, if any.
759	 */
760	dnlc_remove(ITOV(dp), namep);
761
762	/*
763	 * We can collapse all the directory
764	 * entries that are deleted into one big entry
765	 * but the better way is to
766	 * defer it till next directory entry
767	 * creation. where we can do this
768	 * in a more efficient way
769	 */
770	fid = slot.ep;
771
772	/*
773	 * If this is the last entry
774	 * just truncate the file instead
775	 * of marking it deleted
776	 */
777	if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
778		fbrelse(slot.fbp, S_OTHER);
779		if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
780			goto out;
781		}
782	} else {
783		fid->fid_flags |= FID_DELETED;
784
785		if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
786			goto out;
787		}
788
789		ud_make_tag(dp->i_udf, &fid->fid_tag,
790		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
791
792		err = ud_write_fid(dp, &slot, buf);
793	}
794
795	slot.fbp = NULL;
796
797	/*
798	 * If we were removing a directory, it is 'gone' now so we can
799	 * unlock it.
800	 */
801	if (mode == VDIR) {
802		rw_exit(&ip->i_rwlock);
803	}
804
805	mutex_enter(&dp->i_tlock);
806	dp->i_flag |= IUPD|ICHG;
807	mutex_exit(&dp->i_tlock);
808	mutex_enter(&ip->i_tlock);
809	ip->i_flag |= ICHG;
810	mutex_exit(&ip->i_tlock);
811
812	if (err != 0) {
813		goto out;
814	}
815
816	rw_enter(&ip->i_contents, RW_WRITER);
817
818	/*
819	 * Now dispose of the inode.
820	 */
821	if (ip->i_nlink > 0) {
822		if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
823			/*
824			 * Decrement by 1 because there is no "."
825			 * Clear the inode, but there may be other hard
826			 * links so don't free the inode.
827			 * Decrement the dp linkcount because we're
828			 * trashing the ".." entry.
829			 */
830			ip->i_nlink --;
831			dp->i_nlink--;
832			dnlc_remove(ITOV(ip), ".");
833			dnlc_remove(ITOV(ip), "..");
834/*
835 *			(void) ud_itrunc(ip, 0, 0, cr);
836 */
837		} else {
838			ip->i_nlink--;
839		}
840	}
841	ITIMES_NOLOCK(dp);
842	ITIMES_NOLOCK(ip);
843	rw_exit(&ip->i_contents);
844out:
845	if (mode == VDIR) {
846		vn_vfsunlock(ITOV(ip));
847	}
848out_novfs:
849	ASSERT(RW_WRITE_HELD(&dp->i_contents));
850
851	if (slot.fbp != NULL) {
852		fbrelse(slot.fbp, S_OTHER);
853	}
854	rw_exit(&dp->i_contents);
855
856	if (ip) {
857		/*
858		 * If no errors, send any events after locks are dropped,
859		 * but before the VN_RELE().
860		 */
861		if (err == 0) {
862			if (op == DR_REMOVE) {
863				vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
864			} else if (op == DR_RMDIR) {
865				vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
866			}
867		}
868		VN_RELE(ITOV(ip));
869	}
870
871	kmem_free(buf, udf_vfsp->udf_lbsize);
872	return (err);
873}
874
875int
876ud_dircheckforname(struct ud_inode *tdp,
877	char *namep, int32_t namelen, struct slot *slotp,
878	struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
879{
880	struct udf_vfs *udf_vfsp;
881	uint32_t dirsize, offset;
882	struct fbuf *fbp;
883	struct file_id *fid;
884	int32_t sz, error = 0, sz_req, matched = 0;
885	uint8_t *nm;
886
887	uint8_t *dname;
888	int32_t id_len;
889
890	ud_printf("ud_dircheckforname\n");
891
892	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
893	fbp = NULL;
894
895	dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
896
897	udf_vfsp = tdp->i_udf;
898
899	offset = 0;
900	dirsize = tdp->i_size;
901
902	if (slotp->status != FOUND) {
903		int32_t temp;
904
905		temp = 1024; /* set to size of dname allocated above */
906		if ((error = ud_compress(namelen, &temp,
907		    (uint8_t *)namep, dname)) != 0) {
908			goto end;
909		}
910		sz_req = F_LEN + temp;
911		sz_req  = (sz_req + 3) & ~3;
912	}
913
914	while (offset < dirsize) {
915		if ((error = ud_get_next_fid(tdp, &fbp,
916		    offset, &fid, &nm, buf)) != 0) {
917			break;
918		}
919		if ((error = ud_uncompress(fid->fid_idlen,
920		    &id_len, nm, dname)) != 0) {
921			break;
922		}
923		if ((fid->fid_flags & FID_DELETED) == 0) {
924			/* Check for name match */
925			if (((namelen == id_len) &&
926			    (strncmp(namep, (caddr_t)dname, namelen) == 0)) ||
927			    ((fid->fid_flags & FID_PARENT) &&
928			    (namep[0] == '.' &&
929			    (namelen == 1 ||
930			    (namelen == 2 && namep[1] == '.'))))) {
931
932				tdp->i_diroff = offset;
933				if ((fid->fid_flags & FID_PARENT) &&
934				    (namelen == 1) && (namep[0] == '.')) {
935					struct vnode *vp = ITOV(tdp);
936
937					*ipp = tdp;
938					VN_HOLD(vp);
939				} else {
940					uint16_t prn;
941					uint32_t loc;
942
943					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
944					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
945					if ((error = ud_iget(tdp->i_vfs, prn,
946					    loc, ipp, NULL, cr)) != 0) {
947
948						fbrelse(fbp, S_OTHER);
949						goto end;
950					}
951				}
952				slotp->status = EXIST;
953				slotp->offset = offset;
954				slotp->size = FID_LEN(fid);
955				slotp->fbp = fbp;
956				slotp->ep = fid;
957				slotp->endoff = 0;
958				goto end;
959			}
960		} else {
961			/*
962			 * see if we need to find an
963			 * empty slot and the current slot
964			 * matches
965			 */
966			if ((slotp->status != FOUND) || (matched == 0)) {
967				sz = FID_LEN(fid);
968				if (sz == sz_req) {
969					slotp->status = FOUND;
970					slotp->offset = offset;
971					slotp->size = sz;
972				}
973				if (matched == 0) {
974					if ((namelen == id_len) &&
975					    (strncmp(namep, (caddr_t)dname,
976					    namelen) == 0)) {
977						matched = 1;
978						slotp->status = FOUND;
979						slotp->offset = offset;
980						slotp->size = sz;
981					}
982				}
983			}
984		}
985		offset += FID_LEN(fid);
986	}
987	if (fbp) {
988		fbrelse(fbp, S_OTHER);
989	}
990	if (slotp->status == NONE) {
991		/*
992		 * We didn't find a slot; the new directory entry should be put
993		 * at the end of the directory.  Return an indication of where
994		 * this is, and set "endoff" to zero; since we're going to have
995		 * to extend the directory, we're certainly not going to
996		 * trucate it.
997		 */
998		slotp->offset = dirsize;
999		if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
1000			slotp->size = tdp->i_max_emb - tdp->i_size;
1001		} else {
1002			slotp->size = udf_vfsp->udf_lbsize -
1003			    slotp->offset & udf_vfsp->udf_lbmask;
1004		}
1005		slotp->endoff = 0;
1006	}
1007
1008	*ipp = NULL;
1009end:
1010	kmem_free((caddr_t)dname, 1024);
1011	return (error);
1012}
1013
1014/*
1015 * Return 1 if the dir has all files
1016 * deleted except the parent
1017 * else return 0
1018 */
1019/* ARGSUSED */
1020int
1021ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
1022{
1023	offset_t off;
1024	int32_t empty = 1, error, count, entry_len, rcount;
1025	struct file_id *fid;
1026	caddr_t addr;
1027	uint32_t tbno;
1028	int32_t	desc_len;
1029
1030	ud_printf("ud_dirempty\n");
1031
1032	ASSERT(RW_LOCK_HELD(&ip->i_contents));
1033
1034	if (ip->i_size == 0) {
1035		return (empty);
1036	}
1037
1038	desc_len = 1024;
1039	addr = kmem_zalloc(desc_len, KM_SLEEP);
1040	fid = (struct file_id *)addr;
1041
1042	for (off = 0; off < ip->i_size; off += entry_len) {
1043
1044		/*
1045		 * First read fid
1046		 * and verify checksum
1047		 */
1048
1049		rcount = sizeof (struct file_id);
1050		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1051		    UIO_SYSSPACE, &count, cr);
1052		if ((error != 0) || (count != 0)) {
1053			empty = 0;
1054			break;
1055		}
1056
1057		if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
1058			empty = 0;
1059			break;
1060		}
1061
1062		/*
1063		 * We verify the tag id and also the FID_LEN.
1064		 * FID_LEN should be <= desc_len.
1065		 */
1066		if (ud_verify_tag_and_desc(&fid->fid_tag,
1067		    UD_FILE_ID_DESC,
1068		    tbno, 0, desc_len) != 0) {
1069		/* Corrupted directory */
1070			empty = 0;
1071			break;
1072		}
1073
1074		/*
1075		 * Read the fid + iulen + len
1076		 * Now verify both checksum andCRC
1077		 */
1078
1079		rcount = FID_LEN(fid);
1080		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1081		    UIO_SYSSPACE, &count, cr);
1082		if ((error != 0) || (count != 0)) {
1083			empty = 0;
1084			break;
1085		}
1086		/*
1087		 * Now that the entire decsriptor is read we verify the
1088		 * crc.
1089		 */
1090		if (ud_verify_tag_and_desc(&fid->fid_tag,
1091		    UD_FILE_ID_DESC,
1092		    tbno,
1093		    1, rcount) != 0) {
1094			/* Corrupted directory */
1095			empty = 0;
1096			break;
1097		}
1098
1099		/*
1100		 * Is the file deleted
1101		 */
1102
1103		if ((fid->fid_flags & FID_DELETED) == 0) {
1104			if ((fid->fid_flags & FID_PARENT) == 0) {
1105				empty = 0;
1106				break;
1107			}
1108		}
1109		entry_len = FID_LEN(fid);
1110	}
1111
1112	kmem_free(addr, 1024);
1113
1114	return (empty);
1115}
1116
1117
1118int
1119ud_dircheckpath(int32_t blkno,
1120	struct ud_inode *target, struct cred *cr)
1121{
1122	int32_t err = 0;
1123	struct vfs *vfsp;
1124	struct udf_vfs *udf_vfsp;
1125	struct fbuf *fbp;
1126	struct file_id *fid;
1127	struct ud_inode *ip, *tip;
1128	uint16_t prn;
1129	uint32_t lbno, dummy, tbno;
1130	daddr_t parent_icb_loc;
1131
1132	ud_printf("ud_dircheckpath\n");
1133
1134	udf_vfsp = target->i_udf;
1135	ip = target;
1136
1137	ASSERT(udf_vfsp != NULL);
1138	ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
1139	ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
1140
1141	if (ip->i_icb_lbano == blkno) {
1142		err = EINVAL;
1143		goto out;
1144	}
1145	if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
1146		goto out;
1147	}
1148
1149	/*
1150	 * Search back through the directory tree, using the PARENT entries
1151	 * Fail any attempt to move a directory into an ancestor directory.
1152	 */
1153	for (;;) {
1154		if ((err = fbread(ITOV(ip), 0,
1155		    udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
1156			break;
1157		}
1158
1159		if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
1160			break;
1161		}
1162		fid = (struct file_id *)fbp->fb_addr;
1163		/* IS this a valid file_identifier */
1164		if (ud_verify_tag_and_desc(&fid->fid_tag,
1165		    UD_FILE_ID_DESC,
1166		    tbno,
1167		    1, udf_vfsp->udf_lbsize) != 0) {
1168			break;
1169		}
1170		if ((fid->fid_flags & FID_DELETED) != 0) {
1171			break;
1172		}
1173		if ((fid->fid_flags & FID_PARENT) == 0) {
1174			/*
1175			 * This cannot happen unless
1176			 * something is grossly wrong
1177			 * First entry has to be parent
1178			 */
1179			break;
1180		}
1181		prn = SWAP_16(fid->fid_icb.lad_ext_prn);
1182		lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
1183		parent_icb_loc =
1184		    ud_xlate_to_daddr(udf_vfsp, prn, lbno, 1, &dummy);
1185		ASSERT(dummy == 1);
1186		if (parent_icb_loc == blkno) {
1187			err = EINVAL;
1188			break;
1189		}
1190		vfsp = ip->i_vfs;
1191		udf_vfsp = ip->i_udf;
1192		if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
1193			break;
1194		}
1195		if (fbp != NULL) {
1196			fbrelse(fbp, S_OTHER);
1197			fbp = NULL;
1198		}
1199		if (ip != target) {
1200			rw_exit(&ip->i_rwlock);
1201			VN_RELE(ITOV(ip));
1202		}
1203
1204		/*
1205		 * Race to get the inode.
1206		 */
1207		if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
1208			ip = NULL;
1209			break;
1210		}
1211		ip = tip;
1212		rw_enter(&ip->i_rwlock, RW_READER);
1213	}
1214	if (fbp) {
1215		fbrelse(fbp, S_OTHER);
1216	}
1217out:
1218	if (ip) {
1219		if (ip != target) {
1220			rw_exit(&ip->i_rwlock);
1221			VN_RELE(ITOV(ip));
1222		}
1223	}
1224	return (err);
1225}
1226
1227int
1228ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
1229	struct vattr *vap, enum de_op op, struct cred *cr)
1230{
1231	struct ud_inode *ip;
1232	int32_t error;
1233
1234	ASSERT(vap != NULL);
1235	ASSERT(op == DE_CREATE || op == DE_MKDIR);
1236	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
1237	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1238
1239	/*
1240	 * Allocate a new inode.
1241	 */
1242	if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
1243		return (error);
1244	}
1245
1246	ASSERT(ip != NULL);
1247
1248	rw_enter(&ip->i_contents, RW_WRITER);
1249
1250	if (op == DE_MKDIR) {
1251		error = ud_dirmakedirect(ip, tdp, cr);
1252	}
1253
1254	ip->i_flag |= IACC|IUPD|ICHG;
1255	/*
1256	 * Clear IACC and/or IUPD if the caller specified the atime and/or
1257	 * mtime fields.  They were set from the passed in attributes in
1258	 * ud_ialloc().
1259	 */
1260	if (vap->va_mask & AT_ATIME)
1261		ip->i_flag &= ~IACC;
1262	if (vap->va_mask & AT_MTIME)
1263		ip->i_flag &= ~IUPD;
1264	/*
1265	 * push inode before it's name appears in a directory
1266	 */
1267	ud_iupdat(ip, 1);
1268	*ipp = ip;
1269	rw_exit(&ip->i_contents);
1270	return (error);
1271}
1272
1273/*
1274 * Enter the file sip in the directory tdp with name namep.
1275 */
1276int
1277ud_diraddentry(struct ud_inode *tdp, char *namep,
1278	enum de_op op, int32_t namelen, struct slot *slotp,
1279	struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
1280{
1281	struct udf_vfs *udf_vfsp;
1282	int32_t error, temp;
1283	struct file_id *fid;
1284	uint8_t *buf = NULL;
1285
1286	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1287
1288	ud_printf("ud_diraddentry\n");
1289
1290	udf_vfsp = sip->i_udf;
1291
1292	/*
1293	 * Check inode to be linked to see if it is in the
1294	 * same filesystem.
1295	 */
1296	if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
1297		error = EXDEV;
1298		goto bad;
1299	}
1300
1301	if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
1302		if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
1303			goto bad;
1304		}
1305	}
1306
1307	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1308
1309	/*
1310	 * Fill in entry data.
1311	 */
1312	fid = (struct file_id *)buf;
1313	fid->fid_ver = SWAP_16(1);
1314	if (sip->i_type == VDIR) {
1315		fid->fid_flags = FID_DIR;
1316	} else {
1317		fid->fid_flags = 0;
1318	}
1319	fid->fid_iulen = 0;
1320
1321	fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
1322	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1323	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1324	fid->fid_iulen = 0;
1325
1326	temp = MIN(udf_vfsp->udf_lbsize - F_LEN, MAXNAMELEN);
1327	if ((error = ud_compress(namelen, &temp,
1328	    (uint8_t *)namep, fid->fid_spec)) == 0) {
1329		fid->fid_idlen = (uint8_t)temp;
1330		error = ud_dirprepareentry(tdp, slotp, buf, cr);
1331	}
1332
1333	kmem_free(buf, udf_vfsp->udf_lbsize);
1334
1335bad:
1336	return (error);
1337}
1338
1339/*
1340 * Write a prototype directory into the empty inode ip, whose parent is dp.
1341 */
1342/* ARGSUSED2 */
1343int
1344ud_dirmakedirect(struct ud_inode *ip,
1345	struct ud_inode *dp, struct cred *cr)
1346{
1347	int32_t err;
1348	uint32_t blkno, size, parent_len, tbno;
1349	struct fbuf *fbp;
1350	struct file_id *fid;
1351	struct icb_ext *iext;
1352
1353	ud_printf("ud_dirmakedirect\n");
1354
1355	ASSERT(RW_WRITE_HELD(&ip->i_contents));
1356	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1357
1358	parent_len = sizeof (struct file_id);
1359
1360	if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
1361	    (parent_len > ip->i_max_emb)) {
1362		ASSERT(ip->i_ext);
1363		/*
1364		 * Allocate space for the directory we're creating.
1365		 */
1366		if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1367		    0, 1, &blkno, &size, 0, 0)) != 0) {
1368			return (err);
1369		}
1370		/*
1371		 * init with the size of
1372		 * directory with just the
1373		 * parent
1374		 */
1375		ip->i_size = sizeof (struct file_id);
1376		ip->i_flag |= IUPD|ICHG|IATTCHG;
1377		iext = ip->i_ext;
1378		iext->ib_prn = ip->i_icb_prn;
1379		iext->ib_block = blkno;
1380		iext->ib_count = ip->i_size;
1381		iext->ib_offset = 0;
1382		ip->i_ext_used = 1;
1383	} else {
1384		ip->i_size = sizeof (struct file_id);
1385		ip->i_flag |= IUPD|ICHG|IATTCHG;
1386	}
1387
1388	ITIMES_NOLOCK(ip);
1389
1390	/*
1391	 * Update the dp link count and write out the change.
1392	 * This reflects the ".." entry we'll soon write.
1393	 */
1394	if (dp->i_nlink == MAXLINK) {
1395		return (EMLINK);
1396	}
1397	dp->i_nlink++;
1398	dp->i_flag |= ICHG;
1399	ud_iupdat(dp, 1);
1400
1401	/*
1402	 * Initialize directory with ".."
1403	 * Since the parent directory is locked, we don't have to
1404	 * worry about anything changing when we drop the write
1405	 * lock on (ip).
1406	 */
1407	rw_exit(&ip->i_contents);
1408	if ((err = fbread(ITOV(ip), (offset_t)0,
1409	    ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
1410		rw_enter(&ip->i_contents, RW_WRITER);
1411		return (err);
1412	}
1413
1414	bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
1415
1416	fid = (struct file_id *)fbp->fb_addr;
1417	fid->fid_ver = SWAP_16(1);
1418	fid->fid_flags = FID_DIR | FID_PARENT;
1419	fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
1420	fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
1421	fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
1422
1423	/*
1424	 * fid_idlen, fid_iulen and fid_spec are zero
1425	 * due to bzero above
1426	 */
1427
1428	if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
1429		ud_make_tag(ip->i_udf, &fid->fid_tag,
1430		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1431	}
1432
1433	err = ud_fbwrite(fbp, ip);
1434	rw_enter(&ip->i_contents, RW_WRITER);
1435
1436	return (err);
1437}
1438
1439int
1440ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
1441	struct ud_inode *tdp, struct ud_inode *tip, char *namep,
1442	uint8_t *buf, struct slot *slotp, struct cred *cr)
1443{
1444	int32_t error = 0, doingdirectory;
1445	struct file_id *fid;
1446
1447	ud_printf("ud_dirrename\n");
1448	ASSERT(sdp->i_udf != NULL);
1449	ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
1450	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1451	ASSERT(RW_WRITE_HELD(&tdp->i_contents));
1452	ASSERT(buf);
1453	ASSERT(slotp->ep);
1454
1455	fid = slotp->ep;
1456
1457	/*
1458	 * Short circuit rename of something to itself.
1459	 */
1460	if (sip->i_icb_lbano == tip->i_icb_lbano) {
1461		return (ESAME);		/* special KLUDGE error code */
1462	}
1463	/*
1464	 * Everything is protected under the vfs_rename_lock so the ordering
1465	 * of i_contents locks doesn't matter here.
1466	 */
1467	rw_enter(&sip->i_contents, RW_READER);
1468	rw_enter(&tip->i_contents, RW_READER);
1469
1470	/*
1471	 * Check that everything is on the same filesystem.
1472	 */
1473	if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
1474	    (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
1475		error = EXDEV;		/* XXX archaic */
1476		goto out;
1477	}
1478
1479	/*
1480	 * Must have write permission to rewrite target entry.
1481	 */
1482	if ((error = ud_iaccess(tdp, IWRITE, cr, 0)) != 0 ||
1483	    (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
1484		goto out;
1485
1486	/*
1487	 * Ensure source and target are compatible (both directories
1488	 * or both not directories).  If target is a directory it must
1489	 * be empty and have no links to it; in addition it must not
1490	 * be a mount point, and both the source and target must be
1491	 * writable.
1492	 */
1493	doingdirectory = (sip->i_type == VDIR);
1494	if (tip->i_type == VDIR) {
1495		if (!doingdirectory) {
1496			error = EISDIR;
1497			goto out;
1498		}
1499		/*
1500		 * vn_vfswlock will prevent mounts from using the directory
1501		 * until we are done.
1502		 */
1503		if (vn_vfswlock(ITOV(tip))) {
1504			error = EBUSY;
1505			goto out;
1506		}
1507		if (vn_mountedvfs(ITOV(tip)) != NULL) {
1508			vn_vfsunlock(ITOV(tip));
1509			error = EBUSY;
1510			goto out;
1511		}
1512		if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
1513			vn_vfsunlock(ITOV(tip));
1514			error = EEXIST;	/* SIGH should be ENOTEMPTY */
1515			goto out;
1516		}
1517	} else if (doingdirectory) {
1518		error = ENOTDIR;
1519		goto out;
1520	}
1521
1522	/*
1523	 * Rewrite the inode pointer for target name entry
1524	 * from the target inode (ip) to the source inode (sip).
1525	 * This prevents the target entry from disappearing
1526	 * during a crash. Mark the directory inode to reflect the changes.
1527	 */
1528	dnlc_remove(ITOV(tdp), namep);
1529	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1530	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1531	dnlc_enter(ITOV(tdp), namep, ITOV(sip));
1532
1533	ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1534	    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1535
1536	error = ud_write_fid(tdp, slotp, buf);
1537
1538	if (error) {
1539		if (doingdirectory) {
1540			vn_vfsunlock(ITOV(tip));
1541		}
1542		goto out;
1543	}
1544
1545	/*
1546	 * Upgrade to write lock on tip
1547	 */
1548	rw_exit(&tip->i_contents);
1549	rw_enter(&tip->i_contents, RW_WRITER);
1550
1551	mutex_enter(&tdp->i_tlock);
1552	tdp->i_flag |= IUPD|ICHG;
1553	mutex_exit(&tdp->i_tlock);
1554	/*
1555	 * Decrement the link count of the target inode.
1556	 * Fix the ".." entry in sip to point to dp.
1557	 * This is done after the new entry is on the disk.
1558	 */
1559	tip->i_nlink--;
1560	mutex_enter(&tip->i_tlock);
1561	tip->i_flag |= ICHG;
1562	mutex_exit(&tip->i_tlock);
1563
1564	if (doingdirectory) {
1565		/*
1566		 * The entry for tip no longer exists so I can unlock the
1567		 * vfslock.
1568		 */
1569		vn_vfsunlock(ITOV(tip));
1570		/*
1571		 * Decrement target link count once more if it was a directory.
1572		 */
1573		if (tip->i_nlink != 0) {
1574			cmn_err(CE_WARN,
1575			"ud_direnter: target directory link count != 0");
1576			rw_exit(&tip->i_contents);
1577			rw_exit(&sip->i_contents);
1578			return (EINVAL);
1579		}
1580		/*
1581		 * Renaming a directory with the parent different
1582		 * requires that ".." be rewritten.  The window is
1583		 * still there for ".." to be inconsistent, but this
1584		 * is unavoidable, and a lot shorter than when it was
1585		 * done in a user process.  We decrement the link
1586		 * count in the new parent as appropriate to reflect
1587		 * the just-removed target.  If the parent is the
1588		 * same, this is appropriate since the original
1589		 * directory is going away.  If the new parent is
1590		 * different, dirfixdotdot() will bump the link count
1591		 * back.
1592		 */
1593		tdp->i_nlink--;
1594		mutex_enter(&tdp->i_tlock);
1595		tdp->i_flag |= ICHG;
1596		mutex_exit(&tdp->i_tlock);
1597		ITIMES_NOLOCK(tdp);
1598		if (sdp != tdp) {
1599			rw_exit(&tip->i_contents);
1600			rw_exit(&sip->i_contents);
1601			error = ud_dirfixdotdot(sip, sdp, tdp);
1602			return (error);
1603		}
1604	}
1605
1606out:
1607	rw_exit(&tip->i_contents);
1608	rw_exit(&sip->i_contents);
1609	return (error);
1610}
1611
1612
1613/*
1614 * 1. When we find a slot that belonged to a file which was deleted
1615 *      and is in the middle of the directory
1616 * 2. There is not empty slot available. The new entry
1617 *      will be at the end of the directory and fits in the same block.
1618 * 3. There is no empty slot available. The new
1619 *      entry will not fit the left over directory
1620 *      so we need to allocate a new block. If
1621 *      we cannot allocate a proximity block we need
1622 *      to allocate a new icb, and data block.
1623 */
1624int
1625ud_dirprepareentry(struct ud_inode *dp,
1626	struct slot *slotp, uint8_t *buf, struct cred *cr)
1627{
1628	struct fbuf *fbp;
1629	uint16_t old_dtype;
1630	int32_t error = 0;
1631	uint32_t entrysize, count, offset, tbno, old_size, off;
1632	struct file_id *fid;
1633	int32_t lbsize, lbmask, mask;
1634
1635	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1636
1637	ASSERT((slotp->status == NONE) || (slotp->status == FOUND));
1638
1639	ud_printf("ud_dirprepareentry\n");
1640	lbsize = dp->i_udf->udf_lbsize;
1641	lbmask = dp->i_udf->udf_lbmask;
1642	mask = ~lbmask;
1643
1644	fid = (struct file_id *)buf;
1645	entrysize = FID_LEN(fid);
1646
1647	/*
1648	 * If we didn't find a slot, then indicate that the
1649	 * new slot belongs at the end of the directory.
1650	 * If we found a slot, then the new entry can be
1651	 * put at slotp->offset.
1652	 */
1653	if (slotp->status == NONE) {
1654		/*
1655		 * We did not find a slot, the next
1656		 * entry will be in the end of the directory
1657		 * see if we can fit the new entry inside
1658		 * the old block. If not allocate a new block.
1659		 */
1660		if (entrysize > slotp->size) {
1661			/*
1662			 * extend the directory
1663			 * size by one new block
1664			 */
1665			old_dtype = dp->i_desc_type;
1666			old_size = (uint32_t)dp->i_size;
1667			error = ud_bmap_write(dp, slotp->offset,
1668			    blkoff(dp->i_udf, slotp->offset) + entrysize,
1669			    0, cr);
1670			if (error != 0) {
1671				return (error);
1672			}
1673			if (old_dtype != dp->i_desc_type) {
1674				/*
1675				 * oops we changed the astrat
1676				 * of the file, we have to
1677				 * recaliculate tags
1678				 * fortunately we donot have more
1679				 * than one lbsize to handle here
1680				 */
1681				if ((error = ud_ip_off2bno(dp,
1682				    0, &tbno)) != 0) {
1683					return (error);
1684				}
1685				if ((error = fbread(ITOV(dp), 0,
1686				    dp->i_udf->udf_lbsize,
1687				    S_WRITE, &fbp)) != 0) {
1688					return (error);
1689				}
1690				off = 0;
1691				while (off < old_size) {
1692					struct file_id *tfid;
1693
1694					tfid = (struct file_id *)
1695					    (fbp->fb_addr + off);
1696
1697					ud_make_tag(dp->i_udf, &tfid->fid_tag,
1698					    UD_FILE_ID_DESC, tbno,
1699					    FID_LEN(tfid));
1700
1701					off += FID_LEN(tfid);
1702				}
1703				if (error = ud_fbwrite(fbp, dp)) {
1704					return (error);
1705				}
1706			}
1707		} else {
1708			/* Extend the directory size */
1709			if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
1710				ASSERT(dp->i_ext);
1711				dp->i_ext[dp->i_ext_used - 1].ib_count +=
1712				    entrysize;
1713			}
1714		}
1715		dp->i_size += entrysize;
1716		dp->i_flag |= IUPD|ICHG|IATTCHG;
1717		ITIMES_NOLOCK(dp);
1718	} else if (slotp->status != FOUND) {
1719		cmn_err(CE_WARN, "status is not NONE/FOUND");
1720		return (EINVAL);
1721	}
1722
1723	if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
1724		return (error);
1725	}
1726	ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1727	    tbno, FID_LEN(fid));
1728
1729	/*
1730	 * fbread cannot cross a
1731	 * MAXBSIZE boundary so handle it here
1732	 */
1733	offset = slotp->offset;
1734	if ((error = fbread(ITOV(dp), offset & mask, lbsize,
1735	    S_WRITE, &fbp)) != 0) {
1736		return (error);
1737	}
1738	if ((offset & mask) != ((offset + entrysize) & mask)) {
1739		count = entrysize - ((offset + entrysize) & lbmask);
1740	} else {
1741		count = entrysize;
1742	}
1743	bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
1744
1745	if (error = ud_fbwrite(fbp, dp)) {
1746		return (error);
1747	}
1748
1749	if (entrysize > count) {
1750		if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
1751		    lbsize, S_WRITE, &fbp)) != 0) {
1752			return (error);
1753		}
1754		bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
1755		if (error = ud_fbwrite(fbp, dp)) {
1756			return (error);
1757		}
1758	}
1759
1760	dp->i_flag |= IUPD|ICHG|IATTCHG;
1761	ITIMES_NOLOCK(dp);
1762	return (error);
1763}
1764
1765
1766/*
1767 * Fix the FID_PARENT entry of the child directory so that it points
1768 * to the new parent directory instead of the old one.  Routine
1769 * assumes that dp is a directory and that all the inodes are on
1770 * the same file system.
1771 */
1772int
1773ud_dirfixdotdot(struct ud_inode *dp,
1774	struct ud_inode *opdp, struct ud_inode *npdp)
1775{
1776	int32_t err = 0;
1777	struct fbuf *fbp;
1778	struct file_id *fid;
1779	uint32_t loc, dummy, tbno;
1780
1781	ud_printf("ud_dirfixdotdot\n");
1782
1783	ASSERT(opdp->i_type == VDIR);
1784	ASSERT(npdp->i_type == VDIR);
1785
1786	ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
1787
1788	err = fbread(ITOV(dp), (offset_t)0,
1789	    dp->i_udf->udf_lbsize, S_WRITE, &fbp);
1790
1791	if (err || dp->i_nlink == 0 ||
1792	    dp->i_size < sizeof (struct file_id)) {
1793		goto bad;
1794	}
1795
1796	if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
1797		goto bad;
1798	}
1799
1800	fid = (struct file_id *)fbp->fb_addr;
1801	if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
1802	    tbno,
1803	    1, dp->i_udf->udf_lbsize) != 0) ||
1804	    ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
1805	    (FID_DIR | FID_PARENT))) {
1806		err = ENOTDIR;
1807		goto bad;
1808	}
1809
1810	loc = ud_xlate_to_daddr(dp->i_udf,
1811	    SWAP_16(fid->fid_icb.lad_ext_prn),
1812	    SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
1813	ASSERT(dummy == 1);
1814	if (loc == npdp->i_icb_lbano) {
1815		goto bad;
1816	}
1817
1818	/*
1819	 * Increment the link count in the new parent inode and force it out.
1820	 */
1821	if (npdp->i_nlink == MAXLINK) {
1822		err = EMLINK;
1823		goto bad;
1824	}
1825
1826	npdp->i_nlink++;
1827	mutex_enter(&npdp->i_tlock);
1828	npdp->i_flag |= ICHG;
1829	mutex_exit(&npdp->i_tlock);
1830	ud_iupdat(npdp, 1);
1831
1832	/*
1833	 * Rewrite the child FID_PARENT entry and force it out.
1834	 */
1835	dnlc_remove(ITOV(dp), "..");
1836	fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
1837	fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
1838	ud_make_tag(npdp->i_udf, &fid->fid_tag,
1839	    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1840	dnlc_enter(ITOV(dp), "..", ITOV(npdp));
1841
1842	err = ud_fbwrite(fbp, dp);
1843	fbp = NULL;
1844	if (err != 0) {
1845		goto bad;
1846	}
1847
1848	/*
1849	 * Decrement the link count of the old parent inode and force
1850	 * it out.  If opdp is NULL, then this is a new directory link;
1851	 * it has no parent, so we need not do anything.
1852	 */
1853	if (opdp != NULL) {
1854		rw_enter(&opdp->i_contents, RW_WRITER);
1855		if (opdp->i_nlink != 0) {
1856			opdp->i_nlink--;
1857			mutex_enter(&opdp->i_tlock);
1858			opdp->i_flag |= ICHG;
1859			mutex_exit(&opdp->i_tlock);
1860			ud_iupdat(opdp, 1);
1861		}
1862		rw_exit(&opdp->i_contents);
1863	}
1864	return (0);
1865
1866bad:
1867	if (fbp) {
1868		fbrelse(fbp, S_OTHER);
1869	}
1870	return (err);
1871}
1872
1873int32_t
1874ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
1875{
1876	struct udf_vfs *udf_vfsp;
1877	struct fbuf *lfbp;
1878	struct file_id *fid;
1879	int32_t error = 0;
1880	uint32_t lbsize, lbmask, count, old_count;
1881
1882
1883	ASSERT(slot->fbp);
1884	ASSERT(slot->ep);
1885
1886	udf_vfsp = dp->i_udf;
1887	fid = slot->ep;
1888	lbsize = dp->i_udf->udf_lbsize;
1889	lbmask = dp->i_udf->udf_lbmask;
1890
1891	if (((uint8_t *)fid >= buf) &&
1892	    ((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
1893
1894		if ((error = fbread(ITOV(dp),
1895		    (offset_t)(slot->offset & ~lbmask),
1896		    lbsize, S_WRITE, &lfbp)) != 0) {
1897			goto out;
1898		}
1899
1900
1901		/*
1902		 * We do not need to write the
1903		 * file name. So check if the entry
1904		 * does not cross a block boundary
1905		 * and write only required portions
1906		 */
1907		if (((slot->offset & lbmask) +
1908			sizeof (struct file_id)) > lbsize) {
1909
1910			if ((slot->offset & lbmask) != 0) {
1911				old_count = lbsize -
1912					(slot->offset & lbmask);
1913				count = (slot->offset +
1914					sizeof (struct file_id)) &
1915					lbmask;
1916			} else {
1917				old_count = 0;
1918				count = sizeof (struct file_id);
1919			}
1920
1921			bcopy(buf, lfbp->fb_addr +
1922				(slot->offset & lbmask), old_count);
1923			bcopy(buf + old_count,
1924				slot->fbp->fb_addr, count);
1925
1926			error = ud_fbwrite(lfbp, dp);
1927
1928			error = ud_fbwrite(slot->fbp, dp);
1929		} else {
1930			bcopy(buf, lfbp->fb_addr +
1931				(slot->offset & lbmask),
1932				sizeof (struct file_id));
1933
1934			error = ud_fbwrite(lfbp, dp);
1935
1936			fbrelse(slot->fbp, S_OTHER);
1937		}
1938	} else {
1939		if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
1940			fid->fid_flags &= ~FID_DELETED;
1941			ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1942			    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1943		}
1944	}
1945	slot->fbp = NULL;
1946
1947out:
1948	return (error);
1949}
1950