Merge from vendor branch GROFF:
[dragonfly.git] / sys / vfs / gnu / ext2fs / ext2_lookup.c
1 /*
2  *  modified for Lites 1.1
3  *
4  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
5  *  University of Utah, Department of Computer Science
6  *
7  * $FreeBSD: src/sys/gnu/ext2fs/ext2_lookup.c,v 1.21.2.3 2002/11/17 02:02:42 bde Exp $
8  * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_lookup.c,v 1.17 2005/08/10 16:58:54 joerg Exp $
9  */
10 /*
11  * Copyright (c) 1989, 1993
12  *      The Regents of the University of California.  All rights reserved.
13  * (c) UNIX System Laboratories, Inc.
14  * All or some portions of this file are derived from material licensed
15  * to the University of California by American Telephone and Telegraph
16  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
17  * the permission of UNIX System Laboratories, Inc.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. All advertising materials mentioning features or use of this software
28  *    must display the following acknowledgement:
29  *      This product includes software developed by the University of
30  *      California, Berkeley and its contributors.
31  * 4. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  *
47  *      @(#)ufs_lookup.c        8.6 (Berkeley) 4/1/94
48  */
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/namei.h>
53 #include <sys/buf.h>
54 #include <sys/mount.h>
55 #include <sys/vnode.h>
56 #include <sys/malloc.h>
57 #include <sys/dirent.h>
58
59 #include <vfs/ufs/quota.h>
60 #include <vfs/ufs/inode.h>
61 #include <vfs/ufs/dir.h>
62 #include <vfs/ufs/ufsmount.h>
63 #include <vfs/ufs/ufs_extern.h>
64
65 #include "ext2_extern.h"
66 #include "ext2_fs.h"
67 #include "ext2_fs_sb.h"
68
69 /* 
70    DIRBLKSIZE in ffs is DEV_BSIZE (in most cases 512)
71    while it is the native blocksize in ext2fs - thus, a #define
72    is no longer appropriate
73 */
74 #undef  DIRBLKSIZ
75
76 extern  int dirchk;
77
78 static u_char ext2_ft_to_dt[] = {
79         DT_UNKNOWN,             /* EXT2_FT_UNKNOWN */
80         DT_REG,                 /* EXT2_FT_REG_FILE */
81         DT_DIR,                 /* EXT2_FT_DIR */
82         DT_CHR,                 /* EXT2_FT_CHRDEV */
83         DT_BLK,                 /* EXT2_FT_BLKDEV */
84         DT_FIFO,                /* EXT2_FT_FIFO */
85         DT_SOCK,                /* EXT2_FT_SOCK */
86         DT_LNK,                 /* EXT2_FT_SYMLINK */
87 };
88 #define FTTODT(ft)                                              \
89     ((ft) > sizeof(ext2_ft_to_dt) / sizeof(ext2_ft_to_dt[0]) ?  \
90     DT_UNKNOWN : ext2_ft_to_dt[(ft)])
91
92 static u_char dt_to_ext2_ft[] = {
93         EXT2_FT_UNKNOWN,        /* DT_UNKNOWN */
94         EXT2_FT_FIFO,           /* DT_FIFO */
95         EXT2_FT_CHRDEV,         /* DT_CHR */
96         EXT2_FT_UNKNOWN,        /* unused */
97         EXT2_FT_DIR,            /* DT_DIR */
98         EXT2_FT_UNKNOWN,        /* unused */
99         EXT2_FT_BLKDEV,         /* DT_BLK */
100         EXT2_FT_UNKNOWN,        /* unused */
101         EXT2_FT_REG_FILE,       /* DT_REG */
102         EXT2_FT_UNKNOWN,        /* unused */
103         EXT2_FT_SYMLINK,        /* DT_LNK */
104         EXT2_FT_UNKNOWN,        /* unused */
105         EXT2_FT_SOCK,           /* DT_SOCK */
106         EXT2_FT_UNKNOWN,        /* unused */
107         EXT2_FT_UNKNOWN,        /* DT_WHT */
108 };
109 #define DTTOFT(dt)                                              \
110     ((dt) > sizeof(dt_to_ext2_ft) / sizeof(dt_to_ext2_ft[0]) ?  \
111     EXT2_FT_UNKNOWN : dt_to_ext2_ft[(dt)])
112
113 static int      ext2_dirbadentry (struct vnode *dp,
114                                       struct ext2_dir_entry_2 *de,
115                                       int entryoffsetinblock);
116
117 /*
118  * Vnode op for reading directories.
119  *
120  * The routine below assumes that the on-disk format of a directory
121  * is the same as that defined by <sys/dirent.h>. If the on-disk
122  * format changes, then it will be necessary to do a conversion
123  * from the on-disk format that read returns to the format defined
124  * by <sys/dirent.h>.
125  */
126 /*
127  * this is exactly what we do here - the problem is that the conversion
128  * will blow up some entries by four bytes, so it can't be done in place.
129  * This is too bad. Right now the conversion is done entry by entry, the
130  * converted entry is sent via uiomove. 
131  *
132  * XXX allocate a buffer, convert as many entries as possible, then send
133  * the whole buffer to uiomove
134  *
135  * ext2_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred)
136  */
137 int
138 ext2_readdir(struct vop_readdir_args *ap)
139 {
140         struct uio *uio = ap->a_uio;
141         int count, error;
142
143         struct ext2_dir_entry_2 *edp, *dp;
144         int ncookies;
145         struct uio auio;
146         struct iovec aiov;
147         caddr_t dirbuf;
148         int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->s_blocksize;
149         int readcnt, retval;
150         off_t startoffset = uio->uio_offset;
151
152         count = uio->uio_resid;
153         /*
154          * Avoid complications for partial directory entries by adjusting
155          * the i/o to end at a block boundary.  Don't give up (like ufs
156          * does) if the initial adjustment gives a negative count, since
157          * many callers don't supply a large enough buffer.  The correct
158          * size is a little larger than DIRBLKSIZ to allow for expansion
159          * of directory entries, but some callers just use 512.
160          */
161         count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
162         if (count <= 0)
163                 count += DIRBLKSIZ;
164
165 #ifdef EXT2FS_DEBUG
166         printf("ext2_readdir: uio_offset = %lld, uio_resid = %d, count = %d\n", 
167             uio->uio_offset, uio->uio_resid, count);
168 #endif
169
170         auio = *uio;
171         auio.uio_iov = &aiov;
172         auio.uio_iovcnt = 1;
173         auio.uio_resid = count;
174         auio.uio_segflg = UIO_SYSSPACE;
175         aiov.iov_len = count;
176         MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
177         aiov.iov_base = dirbuf;
178         error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
179         if (error == 0) {
180                 readcnt = count - auio.uio_resid;
181                 edp = (struct ext2_dir_entry_2 *)&dirbuf[readcnt];
182                 ncookies = 0;
183                 for (dp = (struct ext2_dir_entry_2 *)dirbuf; 
184                     !error && uio->uio_resid > 0 && dp < edp; ) {
185                         /*-
186                          * "New" ext2fs directory entries differ in 3 ways
187                          * from ufs on-disk ones:
188                          * - the name is not necessarily NUL-terminated.
189                          * - the file type field always exists and always
190                          * follows the name length field.
191                          * - the file type is encoded in a different way.
192                          *
193                          * "Old" ext2fs directory entries need no special
194                          * conversions, since they binary compatible with
195                          * "new" entries having a file type of 0 (i.e.,
196                          * EXT2_FT_UNKNOWN).  Splitting the old name length
197                          * field didn't make a mess like it did in ufs,
198                          * because ext2fs uses a machine-dependent disk
199                          * layout.
200                          */
201                         if (dp->rec_len <= 0) {
202                                 error = EIO;
203                                 break;
204                         }
205                         retval = vop_write_dirent(&error, uio, dp->inode,
206                             FTTODT(dp->file_type), dp->name_len, dp->name);
207
208                         if (retval)
209                                 break;
210                         /* advance dp */
211                         dp = (struct ext2_dir_entry_2 *)((char *)dp + dp->rec_len); 
212                         if (!error)
213                                 ncookies++;
214                 }
215                 /* we need to correct uio_offset */
216                 uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
217
218                 if (!error && ap->a_ncookies != NULL) {
219                         u_long *cookiep, *cookies, *ecookies;
220                         off_t off;
221
222                         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
223                                 panic("ext2fs_readdir: unexpected uio from NFS server");
224                         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
225                                M_WAITOK);
226                         off = startoffset;
227                         for (dp = (struct ext2_dir_entry_2 *)dirbuf,
228                              cookiep = cookies, ecookies = cookies + ncookies;
229                              cookiep < ecookies;
230                              dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
231                                 off += dp->rec_len;
232                                 *cookiep++ = (u_long) off;
233                         }
234                         *ap->a_ncookies = ncookies;
235                         *ap->a_cookies = cookies;
236                 }
237         }
238         FREE(dirbuf, M_TEMP);
239         if (ap->a_eofflag)
240                 *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
241         return (error);
242 }
243
244 /*
245  * Convert a component of a pathname into a pointer to a locked inode.
246  * This is a very central and rather complicated routine.
247  * If the file system is not maintained in a strict tree hierarchy,
248  * this can result in a deadlock situation (see comments in code below).
249  *
250  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
251  * on whether the name is to be looked up, created, renamed, or deleted.
252  * When CREATE, RENAME, or DELETE is specified, information usable in
253  * creating, renaming, or deleting a directory entry may be calculated.
254  * If flag has LOCKPARENT or'ed into it and the target of the pathname
255  * exists, lookup returns both the target and its parent directory locked.
256  * When creating or renaming and LOCKPARENT is specified, the target may
257  * not be ".".  When deleting and LOCKPARENT is specified, the target may
258  * be "."., but the caller must check to ensure it does an vrele and vput
259  * instead of two vputs.
260  *
261  * Overall outline of ufs_lookup:
262  *
263  *      search for name in directory, to found or notfound
264  * notfound:
265  *      if creating, return locked directory, leaving info on available slots
266  *      else return error
267  * found:
268  *      if at end of path and deleting, return information to allow delete
269  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target
270  *        inode and return info to allow rewrite
271  *      if not at end, add name to cache; if at end and neither creating
272  *        nor deleting, add name to cache
273  *
274  * ext2_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
275  *             struct componentname *a_cnp)
276  */
277 int
278 ext2_lookup(struct vop_lookup_args *ap)
279 {
280         struct vnode *vdp;      /* vnode for directory being searched */
281         struct inode *dp;       /* inode for directory being searched */
282         struct buf *bp;                 /* a buffer of directory entries */
283         struct ext2_dir_entry_2 *ep; /* the current directory entry */
284         int entryoffsetinblock;         /* offset of ep in bp's buffer */
285         enum {NONE, COMPACT, FOUND} slotstatus;
286         doff_t slotoffset;              /* offset of area with free space */
287         int slotsize;                   /* size of area at slotoffset */
288         int slotfreespace;              /* amount of space free in slot */
289         int slotneeded;                 /* size of the entry we're seeking */
290         int numdirpasses;               /* strategy for directory search */
291         doff_t endsearch;               /* offset to end directory search */
292         doff_t prevoff;                 /* prev entry dp->i_offset */
293         struct vnode *pdp;              /* saved dp during symlink work */
294         struct vnode *tdp;              /* returned by VFS_VGET */
295         doff_t enduseful;               /* pointer past last used dir slot */
296         u_long bmask;                   /* block offset mask */
297         int lockparent;                 /* 1 => lockparent flag is set */
298         int wantparent;                 /* 1 => wantparent or lockparent flag */
299         int namlen, error;
300         struct vnode **vpp = ap->a_vpp;
301         struct componentname *cnp = ap->a_cnp;
302         struct ucred *cred = cnp->cn_cred;
303         int flags = cnp->cn_flags;
304         int nameiop = cnp->cn_nameiop;
305         struct thread *td = cnp->cn_td;
306         globaldata_t gd = mycpu;
307
308         int     DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize;
309
310         bp = NULL;
311         slotoffset = -1;
312         *vpp = NULL;
313         vdp = ap->a_dvp;
314         dp = VTOI(vdp);
315         lockparent = flags & CNP_LOCKPARENT;
316         wantparent = flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
317
318         /*
319          * We now have a segment name to search for, and a directory to search.
320          */
321
322         /*
323          * Suppress search for slots unless creating
324          * file and at end of pathname, in which case
325          * we watch for a place to put the new file in
326          * case it doesn't already exist.
327          */
328         slotstatus = FOUND;
329         slotfreespace = slotsize = slotneeded = 0;
330         if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) {
331                 slotstatus = NONE;
332                 slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen); 
333                 /* was
334                 slotneeded = (sizeof(struct direct) - MAXNAMLEN +
335                         cnp->cn_namelen + 3) &~ 3; */
336         }
337
338         /*
339          * If there is cached information on a previous search of
340          * this directory, pick up where we last left off.
341          * We cache only lookups as these are the most common
342          * and have the greatest payoff. Caching CREATE has little
343          * benefit as it usually must search the entire directory
344          * to determine that the entry does not exist. Caching the
345          * location of the last DELETE or RENAME has not reduced
346          * profiling time and hence has been removed in the interest
347          * of simplicity.
348          */
349         bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
350         if (nameiop != NAMEI_LOOKUP || dp->i_diroff == 0 ||
351             dp->i_diroff > dp->i_size) {
352                 entryoffsetinblock = 0;
353                 dp->i_offset = 0;
354                 numdirpasses = 1;
355         } else {
356                 dp->i_offset = dp->i_diroff;
357                 if ((entryoffsetinblock = dp->i_offset & bmask) &&
358                     (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
359                         return (error);
360                 numdirpasses = 2;
361                 gd->gd_nchstats->ncs_2passes++;
362         }
363         prevoff = dp->i_offset;
364         endsearch = roundup(dp->i_size, DIRBLKSIZ);
365         enduseful = 0;
366
367 searchloop:
368         while (dp->i_offset < endsearch) {
369                 /*
370                  * If necessary, get the next directory block.
371                  */
372                 if ((dp->i_offset & bmask) == 0) {
373                         if (bp != NULL)
374                                 brelse(bp);
375                         if ((error =
376                             UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0)
377                                 return (error);
378                         entryoffsetinblock = 0;
379                 }
380                 /*
381                  * If still looking for a slot, and at a DIRBLKSIZE
382                  * boundary, have to start looking for free space again.
383                  */
384                 if (slotstatus == NONE &&
385                     (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
386                         slotoffset = -1;
387                         slotfreespace = 0;
388                 }
389                 /*
390                  * Get pointer to next entry.
391                  * Full validation checks are slow, so we only check
392                  * enough to insure forward progress through the
393                  * directory. Complete checks can be run by patching
394                  * "dirchk" to be true.
395                  */
396                 ep = (struct ext2_dir_entry_2 *)
397                         ((char *)bp->b_data + entryoffsetinblock);
398                 if (ep->rec_len == 0 ||
399                     (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
400                         int i;
401                         ufs_dirbad(dp, dp->i_offset, "mangled entry");
402                         i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
403                         dp->i_offset += i;
404                         entryoffsetinblock += i;
405                         continue;
406                 }
407
408                 /*
409                  * If an appropriate sized slot has not yet been found,
410                  * check to see if one is available. Also accumulate space
411                  * in the current block so that we can determine if
412                  * compaction is viable.
413                  */
414                 if (slotstatus != FOUND) {
415                         int size = ep->rec_len;
416
417                         if (ep->inode != 0)
418                                 size -= EXT2_DIR_REC_LEN(ep->name_len);
419                         if (size > 0) {
420                                 if (size >= slotneeded) {
421                                         slotstatus = FOUND;
422                                         slotoffset = dp->i_offset;
423                                         slotsize = ep->rec_len;
424                                 } else if (slotstatus == NONE) {
425                                         slotfreespace += size;
426                                         if (slotoffset == -1)
427                                                 slotoffset = dp->i_offset;
428                                         if (slotfreespace >= slotneeded) {
429                                                 slotstatus = COMPACT;
430                                                 slotsize = dp->i_offset +
431                                                       ep->rec_len - slotoffset;
432                                         }
433                                 }
434                         }
435                 }
436
437                 /*
438                  * Check for a name match.
439                  */
440                 if (ep->inode) {
441                         namlen = ep->name_len;
442                         if (namlen == cnp->cn_namelen &&
443                             !bcmp(cnp->cn_nameptr, ep->name,
444                                 (unsigned)namlen)) {
445                                 /*
446                                  * Save directory entry's inode number and
447                                  * reclen in ndp->ni_ufs area, and release
448                                  * directory buffer.
449                                  */
450                                 dp->i_ino = ep->inode;
451                                 dp->i_reclen = ep->rec_len;
452                                 goto found;
453                         }
454                 }
455                 prevoff = dp->i_offset;
456                 dp->i_offset += ep->rec_len;
457                 entryoffsetinblock += ep->rec_len;
458                 if (ep->inode)
459                         enduseful = dp->i_offset;
460         }
461 /* notfound: */
462         /*
463          * If we started in the middle of the directory and failed
464          * to find our target, we must check the beginning as well.
465          */
466         if (numdirpasses == 2) {
467                 numdirpasses--;
468                 dp->i_offset = 0;
469                 endsearch = dp->i_diroff;
470                 goto searchloop;
471         }
472         if (bp != NULL)
473                 brelse(bp);
474         /*
475          * If creating, and at end of pathname and current
476          * directory has not been removed, then can consider
477          * allowing file to be created.
478          */
479         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
480             dp->i_nlink != 0) {
481                 /*
482                  * Access for write is interpreted as allowing
483                  * creation of files in the directory.
484                  */
485                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
486                         return (error);
487                 /*
488                  * Return an indication of where the new directory
489                  * entry should be put.  If we didn't find a slot,
490                  * then set dp->i_count to 0 indicating
491                  * that the new slot belongs at the end of the
492                  * directory. If we found a slot, then the new entry
493                  * can be put in the range from dp->i_offset to
494                  * dp->i_offset + dp->i_count.
495                  */
496                 if (slotstatus == NONE) {
497                         dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
498                         dp->i_count = 0;
499                         enduseful = dp->i_offset;
500                 } else {
501                         dp->i_offset = slotoffset;
502                         dp->i_count = slotsize;
503                         if (enduseful < slotoffset + slotsize)
504                                 enduseful = slotoffset + slotsize;
505                 }
506                 dp->i_endoff = roundup(enduseful, DIRBLKSIZ);
507                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
508                 /*
509                  * We return with the directory locked, so that
510                  * the parameters we set up above will still be
511                  * valid if we actually decide to do a direnter().
512                  * We return ni_vp == NULL to indicate that the entry
513                  * does not currently exist; we leave a pointer to
514                  * the (locked) directory inode in ndp->ni_dvp.
515                  * The pathname buffer is saved so that the name
516                  * can be obtained later.
517                  *
518                  * NB - if the directory is unlocked, then this
519                  * information cannot be used.
520                  */
521                 if (!lockparent)
522                         VOP_UNLOCK(vdp, 0, td);
523                 return (EJUSTRETURN);
524         }
525         return (ENOENT);
526
527 found:
528         if (numdirpasses == 2)
529                 gd->gd_nchstats->ncs_pass2++;
530         /*
531          * Check that directory length properly reflects presence
532          * of this entry.
533          */
534         if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
535                 > dp->i_size) {
536                 ufs_dirbad(dp, dp->i_offset, "i_size too small");
537                 dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
538                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
539         }
540         brelse(bp);
541
542         /*
543          * Found component in pathname.
544          * If the final component of path name, save information
545          * in the cache as to where the entry was found.
546          */
547         if (nameiop == NAMEI_LOOKUP)
548                 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
549
550         /*
551          * If deleting, and at end of pathname, return
552          * parameters which can be used to remove file.
553          * If the wantparent flag isn't set, we return only
554          * the directory (in ndp->ni_dvp), otherwise we go
555          * on and lock the inode, being careful with ".".
556          */
557         if (nameiop == NAMEI_DELETE) {
558                 /*
559                  * Write access to directory required to delete files.
560                  */
561                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
562                         return (error);
563                 /*
564                  * Return pointer to current entry in dp->i_offset,
565                  * and distance past previous entry (if there
566                  * is a previous entry in this block) in dp->i_count.
567                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
568                  */
569                 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
570                         dp->i_count = 0;
571                 else
572                         dp->i_count = dp->i_offset - prevoff;
573                 if (dp->i_number == dp->i_ino) {
574                         vref(vdp);
575                         *vpp = vdp;
576                         return (0);
577                 }
578                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
579                         return (error);
580                 /*
581                  * If directory is "sticky", then user must own
582                  * the directory, or the file in it, else she
583                  * may not delete it (unless she's root). This
584                  * implements append-only directories.
585                  */
586                 if ((dp->i_mode & ISVTX) &&
587                     cred->cr_uid != 0 &&
588                     cred->cr_uid != dp->i_uid &&
589                     VTOI(tdp)->i_uid != cred->cr_uid) {
590                         vput(tdp);
591                         return (EPERM);
592                 }
593                 *vpp = tdp;
594                 if (!lockparent)
595                         VOP_UNLOCK(vdp, 0, td);
596                 return (0);
597         }
598
599         /*
600          * If rewriting (RENAME), return the inode and the
601          * information required to rewrite the present directory
602          * Must get inode of directory entry to verify it's a
603          * regular file, or empty directory.
604          */
605         if (nameiop == NAMEI_RENAME && wantparent) {
606                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
607                         return (error);
608                 /*
609                  * Careful about locking second inode.
610                  * This can only occur if the target is ".".
611                  */
612                 if (dp->i_number == dp->i_ino)
613                         return (EISDIR);
614                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
615                         return (error);
616                 *vpp = tdp;
617                 if (!lockparent)
618                         VOP_UNLOCK(vdp, 0, td);
619                 return (0);
620         }
621
622         /*
623          * Step through the translation in the name.  We do not `vput' the
624          * directory because we may need it again if a symbolic link
625          * is relative to the current directory.  Instead we save it
626          * unlocked as "pdp".  We must get the target inode before unlocking
627          * the directory to insure that the inode will not be removed
628          * before we get it.  We prevent deadlock by always fetching
629          * inodes from the root, moving down the directory tree. Thus
630          * when following backward pointers ".." we must unlock the
631          * parent directory before getting the requested directory.
632          * There is a potential race condition here if both the current
633          * and parent directories are removed before the VFS_VGET for the
634          * inode associated with ".." returns.  We hope that this occurs
635          * infrequently since we cannot avoid this race condition without
636          * implementing a sophisticated deadlock detection algorithm.
637          * Note also that this simple deadlock detection scheme will not
638          * work if the file system has any hard links other than ".."
639          * that point backwards in the directory structure.
640          */
641         pdp = vdp;
642         if (flags & CNP_ISDOTDOT) {
643                 VOP_UNLOCK(pdp, 0, td); /* race to get the inode */
644                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
645                         vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td);
646                         return (error);
647                 }
648                 if (lockparent && (error = vn_lock(pdp, LK_EXCLUSIVE, td))) {
649                         vput(tdp);
650                         return (error);
651                 }
652                 *vpp = tdp;
653         } else if (dp->i_number == dp->i_ino) {
654                 vref(vdp);      /* we want ourself, ie "." */
655                 *vpp = vdp;
656         } else {
657                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
658                         return (error);
659                 if (!lockparent)
660                         VOP_UNLOCK(pdp, 0, td);
661                 *vpp = tdp;
662         }
663         return (0);
664 }
665
666 /*
667  * Do consistency checking on a directory entry:
668  *      record length must be multiple of 4
669  *      entry must fit in rest of its DIRBLKSIZ block
670  *      record must be large enough to contain entry
671  *      name is not longer than MAXNAMLEN
672  *      name must be as long as advertised, and null terminated
673  */
674 /*
675  *      changed so that it confirms to ext2_check_dir_entry
676  */
677 static int
678 ext2_dirbadentry(struct vnode *dp, struct ext2_dir_entry_2 *de,
679                  int entryoffsetinblock)
680 {
681         int     DIRBLKSIZ = VTOI(dp)->i_e2fs->s_blocksize;
682
683         char * error_msg = NULL;
684
685         if (de->rec_len < EXT2_DIR_REC_LEN(1))
686                 error_msg = "rec_len is smaller than minimal";
687         else if (de->rec_len % 4 != 0)
688                 error_msg = "rec_len % 4 != 0";
689         else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
690                 error_msg = "reclen is too small for name_len";
691         else if (entryoffsetinblock + de->rec_len > DIRBLKSIZ)
692                 error_msg = "directory entry across blocks";
693         /* else LATER
694              if (de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
695                 error_msg = "inode out of bounds";
696         */
697
698         if (error_msg != NULL) {
699                 printf("bad directory entry: %s\n", error_msg);
700                 printf("offset=%d, inode=%lu, rec_len=%u, name_len=%u\n",
701                         entryoffsetinblock, (unsigned long)de->inode,
702                         de->rec_len, de->name_len);
703         }
704         return error_msg == NULL ? 0 : 1;
705 }
706
707 /*
708  * Write a directory entry after a call to namei, using the parameters
709  * that it left in the directory inode.  The argument ip is the inode which
710  * the new directory entry will refer to.  Dvp is a pointer to the directory 
711  * to be written, which was left locked by namei. Remaining parameters
712  * (dp->i_offset, dp->i_count) indicate how the space for the new
713  * entry is to be obtained.
714  */
715 int
716 ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
717 {
718         struct ext2_dir_entry_2 *ep, *nep;
719         struct inode *dp;
720         struct buf *bp;
721         struct ext2_dir_entry_2 newdir;
722         struct iovec aiov;
723         struct uio auio;
724         u_int dsize;
725         int error, loc, newentrysize, spacefree;
726         char *dirbuf;
727         int     DIRBLKSIZ = ip->i_e2fs->s_blocksize;
728
729
730         dp = VTOI(dvp);
731         newdir.inode = ip->i_number;
732         newdir.name_len = cnp->cn_namelen;
733         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
734             EXT2_FEATURE_INCOMPAT_FILETYPE))
735                 newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
736         else
737                 newdir.file_type = EXT2_FT_UNKNOWN;
738         bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
739         newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
740         if (dp->i_count == 0) {
741                 /*
742                  * If dp->i_count is 0, then namei could find no
743                  * space in the directory. Here, dp->i_offset will
744                  * be on a directory block boundary and we will write the
745                  * new entry into a fresh block.
746                  */
747                 if (dp->i_offset & (DIRBLKSIZ - 1))
748                         panic("ext2_direnter: newblk");
749                 auio.uio_offset = dp->i_offset;
750                 newdir.rec_len = DIRBLKSIZ;
751                 auio.uio_resid = newentrysize;
752                 aiov.iov_len = newentrysize;
753                 aiov.iov_base = (caddr_t)&newdir;
754                 auio.uio_iov = &aiov;
755                 auio.uio_iovcnt = 1;
756                 auio.uio_rw = UIO_WRITE;
757                 auio.uio_segflg = UIO_SYSSPACE;
758                 auio.uio_td = NULL;
759                 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
760                 if (DIRBLKSIZ >
761                     VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
762                         /* XXX should grow with balloc() */
763                         panic("ext2_direnter: frag size");
764                 else if (!error) {
765                         dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
766                         dp->i_flag |= IN_CHANGE;
767                 }
768                 return (error);
769         }
770
771         /*
772          * If dp->i_count is non-zero, then namei found space
773          * for the new entry in the range dp->i_offset to
774          * dp->i_offset + dp->i_count in the directory.
775          * To use this space, we may have to compact the entries located
776          * there, by copying them together towards the beginning of the
777          * block, leaving the free space in one usable chunk at the end.
778          */
779
780         /*
781          * Increase size of directory if entry eats into new space.
782          * This should never push the size past a new multiple of
783          * DIRBLKSIZE.
784          *
785          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
786          */
787         if (dp->i_offset + dp->i_count > dp->i_size)
788                 dp->i_size = dp->i_offset + dp->i_count;
789         /*
790          * Get the block containing the space for the new directory entry.
791          */
792         if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
793                 return (error);
794         /*
795          * Find space for the new entry. In the simple case, the entry at
796          * offset base will have the space. If it does not, then namei
797          * arranged that compacting the region dp->i_offset to
798          * dp->i_offset + dp->i_count would yield the
799          * space.
800          */
801         ep = (struct ext2_dir_entry_2 *)dirbuf;
802         dsize = EXT2_DIR_REC_LEN(ep->name_len);
803         spacefree = ep->rec_len - dsize;
804         for (loc = ep->rec_len; loc < dp->i_count; ) {
805                 nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
806                 if (ep->inode) {
807                         /* trim the existing slot */
808                         ep->rec_len = dsize;
809                         ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
810                 } else {
811                         /* overwrite; nothing there; header is ours */
812                         spacefree += dsize;
813                 }
814                 dsize = EXT2_DIR_REC_LEN(nep->name_len);
815                 spacefree += nep->rec_len - dsize;
816                 loc += nep->rec_len;
817                 bcopy((caddr_t)nep, (caddr_t)ep, dsize);
818         }
819         /*
820          * Update the pointer fields in the previous entry (if any),
821          * copy in the new entry, and write out the block.
822          */
823         if (ep->inode == 0) {
824                 if (spacefree + dsize < newentrysize)
825                         panic("ext2_direnter: compact1");
826                 newdir.rec_len = spacefree + dsize;
827         } else {
828                 if (spacefree < newentrysize)
829                         panic("ext2_direnter: compact2");
830                 newdir.rec_len = spacefree;
831                 ep->rec_len = dsize;
832                 ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
833         }
834         bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
835         error = VOP_BWRITE(bp->b_vp, bp);
836         dp->i_flag |= IN_CHANGE | IN_UPDATE;
837         if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
838                 error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
839                     cnp->cn_cred, cnp->cn_td);
840         return (error);
841 }
842
843 /*
844  * Remove a directory entry after a call to namei, using
845  * the parameters which it left in the directory inode. The entry
846  * dp->i_offset contains the offset into the directory of the
847  * entry to be eliminated.  The dp->i_count field contains the
848  * size of the previous record in the directory.  If this
849  * is 0, the first entry is being deleted, so we need only
850  * zero the inode number to mark the entry as free.  If the
851  * entry is not the first in the directory, we must reclaim
852  * the space of the now empty record by adding the record size
853  * to the size of the previous entry.
854  */
855 int
856 ext2_dirremove(struct vnode *dvp, struct componentname *cnp)
857 {
858         struct inode *dp;
859         struct ext2_dir_entry_2 *ep;
860         struct buf *bp;
861         int error;
862          
863         dp = VTOI(dvp);
864         if (dp->i_count == 0) {
865                 /*
866                  * First entry in block: set d_ino to zero.
867                  */
868                 if ((error =
869                     UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
870                         return (error);
871                 ep->inode = 0;
872                 error = VOP_BWRITE(bp->b_vp, bp);
873                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
874                 return (error);
875         }
876         /*
877          * Collapse new free space into previous entry.
878          */
879         if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count),
880             (char **)&ep, &bp)) != 0)
881                 return (error);
882         ep->rec_len += dp->i_reclen;
883         error = VOP_BWRITE(bp->b_vp, bp);
884         dp->i_flag |= IN_CHANGE | IN_UPDATE;
885         return (error);
886 }
887
888 /*
889  * Rewrite an existing directory entry to point at the inode
890  * supplied.  The parameters describing the directory entry are
891  * set up by a call to namei.
892  */
893 int
894 ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp)
895 {
896         struct buf *bp;
897         struct ext2_dir_entry_2 *ep;
898         struct vnode *vdp = ITOV(dp);
899         int error;
900
901         if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
902                 return (error);
903         ep->inode = ip->i_number;
904         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
905             EXT2_FEATURE_INCOMPAT_FILETYPE))
906                 ep->file_type = DTTOFT(IFTODT(ip->i_mode));
907         else
908                 ep->file_type = EXT2_FT_UNKNOWN;
909         error = VOP_BWRITE(bp->b_vp, bp);
910         dp->i_flag |= IN_CHANGE | IN_UPDATE;
911         return (error);
912 }
913
914 /*
915  * Check if a directory is empty or not.
916  * Inode supplied must be locked.
917  *
918  * Using a struct dirtemplate here is not precisely
919  * what we want, but better than using a struct direct.
920  *
921  * NB: does not handle corrupted directories.
922  */
923 int
924 ext2_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
925 {
926         off_t off;
927         struct dirtemplate dbuf;
928         struct ext2_dir_entry_2 *dp = (struct ext2_dir_entry_2 *)&dbuf;
929         int error, count, namlen;
930                  
931 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
932
933         for (off = 0; off < ip->i_size; off += dp->rec_len) {
934                 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
935                    UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
936                 /*
937                  * Since we read MINDIRSIZ, residual must
938                  * be 0 unless we're at end of file.
939                  */
940                 if (error || count != 0)
941                         return (0);
942                 /* avoid infinite loops */
943                 if (dp->rec_len == 0)
944                         return (0);
945                 /* skip empty entries */
946                 if (dp->inode == 0)
947                         continue;
948                 /* accept only "." and ".." */
949                 namlen = dp->name_len;
950                 if (namlen > 2)
951                         return (0);
952                 if (dp->name[0] != '.')
953                         return (0);
954                 /*
955                  * At this point namlen must be 1 or 2.
956                  * 1 implies ".", 2 implies ".." if second
957                  * char is also "."
958                  */
959                 if (namlen == 1)
960                         continue;
961                 if (dp->name[1] == '.' && dp->inode == parentino)
962                         continue;
963                 return (0);
964         }
965         return (1);
966 }
967
968 /*
969  * Check if source directory is in the path of the target directory.
970  * Target is supplied locked, source is unlocked.
971  * The target is always vput before returning.
972  */
973 int
974 ext2_checkpath(struct inode *source, struct inode *target, struct ucred *cred)
975 {
976         struct vnode *vp;
977         int error, rootino, namlen;
978         struct dirtemplate dirbuf;
979
980         vp = ITOV(target);
981         if (target->i_number == source->i_number) {
982                 error = EEXIST;
983                 goto out;
984         }
985         rootino = ROOTINO;
986         error = 0;
987         if (target->i_number == rootino)
988                 goto out;
989
990         for (;;) {
991                 if (vp->v_type != VDIR) {
992                         error = ENOTDIR;
993                         break;
994                 }
995                 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
996                         sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
997                         IO_NODELOCKED, cred, (int *)0, NULL);
998                 if (error != 0)
999                         break;
1000                 namlen = dirbuf.dotdot_type;    /* like ufs little-endian */
1001                 if (namlen != 2 ||
1002                     dirbuf.dotdot_name[0] != '.' ||
1003                     dirbuf.dotdot_name[1] != '.') {
1004                         error = ENOTDIR;
1005                         break;
1006                 }
1007                 if (dirbuf.dotdot_ino == source->i_number) {
1008                         error = EINVAL;
1009                         break;
1010                 }
1011                 if (dirbuf.dotdot_ino == rootino)
1012                         break;
1013                 vput(vp);
1014                 if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) != 0) {
1015                         vp = NULL;
1016                         break;
1017                 }
1018         }
1019
1020 out:
1021         if (error == ENOTDIR)
1022                 printf("checkpath: .. not a directory\n");
1023         if (vp != NULL)
1024                 vput(vp);
1025         return (error);
1026 }