Merge from vendor branch OPENSSH:
[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.13 2004/04/24 04:32:03 drhodus 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 dirent dstdp;
146         struct uio auio;
147         struct iovec aiov;
148         caddr_t dirbuf;
149         int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->s_blocksize;
150         int readcnt;
151         off_t startoffset = uio->uio_offset;
152
153         count = uio->uio_resid;
154         /*
155          * Avoid complications for partial directory entries by adjusting
156          * the i/o to end at a block boundary.  Don't give up (like ufs
157          * does) if the initial adjustment gives a negative count, since
158          * many callers don't supply a large enough buffer.  The correct
159          * size is a little larger than DIRBLKSIZ to allow for expansion
160          * of directory entries, but some callers just use 512.
161          */
162         count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
163         if (count <= 0)
164                 count += DIRBLKSIZ;
165
166 #ifdef EXT2FS_DEBUG
167         printf("ext2_readdir: uio_offset = %lld, uio_resid = %d, count = %d\n", 
168             uio->uio_offset, uio->uio_resid, count);
169 #endif
170
171         auio = *uio;
172         auio.uio_iov = &aiov;
173         auio.uio_iovcnt = 1;
174         auio.uio_resid = count;
175         auio.uio_segflg = UIO_SYSSPACE;
176         aiov.iov_len = count;
177         MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
178         aiov.iov_base = dirbuf;
179         error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
180         if (error == 0) {
181                 readcnt = count - auio.uio_resid;
182                 edp = (struct ext2_dir_entry_2 *)&dirbuf[readcnt];
183                 ncookies = 0;
184                 bzero(&dstdp, offsetof(struct dirent, d_name));
185                 for (dp = (struct ext2_dir_entry_2 *)dirbuf; 
186                     !error && uio->uio_resid > 0 && dp < edp; ) {
187                         /*-
188                          * "New" ext2fs directory entries differ in 3 ways
189                          * from ufs on-disk ones:
190                          * - the name is not necessarily NUL-terminated.
191                          * - the file type field always exists and always
192                          * follows the name length field.
193                          * - the file type is encoded in a different way.
194                          *
195                          * "Old" ext2fs directory entries need no special
196                          * conversions, since they binary compatible with
197                          * "new" entries having a file type of 0 (i.e.,
198                          * EXT2_FT_UNKNOWN).  Splitting the old name length
199                          * field didn't make a mess like it did in ufs,
200                          * because ext2fs uses a machine-dependent disk
201                          * layout.
202                          */
203                         dstdp.d_fileno = dp->inode;
204                         dstdp.d_type = FTTODT(dp->file_type);
205                         dstdp.d_namlen = dp->name_len;
206                         dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
207                         bcopy(dp->name, dstdp.d_name, dstdp.d_namlen);
208                         bzero(dstdp.d_name + dstdp.d_namlen,
209                             dstdp.d_reclen - offsetof(struct dirent, d_name) -
210                             dstdp.d_namlen);
211
212                         if (dp->rec_len > 0) {
213                                 if(dstdp.d_reclen <= uio->uio_resid) {
214                                         /* advance dp */
215                                         dp = (struct ext2_dir_entry_2 *)
216                                             ((char *)dp + dp->rec_len); 
217                                         error = 
218                                           uiomove((caddr_t)&dstdp,
219                                                   dstdp.d_reclen, uio);
220                                         if (!error)
221                                                 ncookies++;
222                                 } else
223                                         break;
224                         } else {
225                                 error = EIO;
226                                 break;
227                         }
228                 }
229                 /* we need to correct uio_offset */
230                 uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
231
232                 if (!error && ap->a_ncookies != NULL) {
233                         u_long *cookiep, *cookies, *ecookies;
234                         off_t off;
235
236                         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
237                                 panic("ext2fs_readdir: unexpected uio from NFS server");
238                         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
239                                M_WAITOK);
240                         off = startoffset;
241                         for (dp = (struct ext2_dir_entry_2 *)dirbuf,
242                              cookiep = cookies, ecookies = cookies + ncookies;
243                              cookiep < ecookies;
244                              dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
245                                 off += dp->rec_len;
246                                 *cookiep++ = (u_long) off;
247                         }
248                         *ap->a_ncookies = ncookies;
249                         *ap->a_cookies = cookies;
250                 }
251         }
252         FREE(dirbuf, M_TEMP);
253         if (ap->a_eofflag)
254                 *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
255         return (error);
256 }
257
258 /*
259  * Convert a component of a pathname into a pointer to a locked inode.
260  * This is a very central and rather complicated routine.
261  * If the file system is not maintained in a strict tree hierarchy,
262  * this can result in a deadlock situation (see comments in code below).
263  *
264  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
265  * on whether the name is to be looked up, created, renamed, or deleted.
266  * When CREATE, RENAME, or DELETE is specified, information usable in
267  * creating, renaming, or deleting a directory entry may be calculated.
268  * If flag has LOCKPARENT or'ed into it and the target of the pathname
269  * exists, lookup returns both the target and its parent directory locked.
270  * When creating or renaming and LOCKPARENT is specified, the target may
271  * not be ".".  When deleting and LOCKPARENT is specified, the target may
272  * be "."., but the caller must check to ensure it does an vrele and vput
273  * instead of two vputs.
274  *
275  * Overall outline of ufs_lookup:
276  *
277  *      search for name in directory, to found or notfound
278  * notfound:
279  *      if creating, return locked directory, leaving info on available slots
280  *      else return error
281  * found:
282  *      if at end of path and deleting, return information to allow delete
283  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target
284  *        inode and return info to allow rewrite
285  *      if not at end, add name to cache; if at end and neither creating
286  *        nor deleting, add name to cache
287  *
288  * ext2_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
289  *             struct componentname *a_cnp)
290  */
291 int
292 ext2_lookup(struct vop_cachedlookup_args *ap)
293 {
294         struct vnode *vdp;      /* vnode for directory being searched */
295         struct inode *dp;       /* inode for directory being searched */
296         struct buf *bp;                 /* a buffer of directory entries */
297         struct ext2_dir_entry_2 *ep; /* the current directory entry */
298         int entryoffsetinblock;         /* offset of ep in bp's buffer */
299         enum {NONE, COMPACT, FOUND} slotstatus;
300         doff_t slotoffset;              /* offset of area with free space */
301         int slotsize;                   /* size of area at slotoffset */
302         int slotfreespace;              /* amount of space free in slot */
303         int slotneeded;                 /* size of the entry we're seeking */
304         int numdirpasses;               /* strategy for directory search */
305         doff_t endsearch;               /* offset to end directory search */
306         doff_t prevoff;                 /* prev entry dp->i_offset */
307         struct vnode *pdp;              /* saved dp during symlink work */
308         struct vnode *tdp;              /* returned by VFS_VGET */
309         doff_t enduseful;               /* pointer past last used dir slot */
310         u_long bmask;                   /* block offset mask */
311         int lockparent;                 /* 1 => lockparent flag is set */
312         int wantparent;                 /* 1 => wantparent or lockparent flag */
313         int namlen, error;
314         struct vnode **vpp = ap->a_vpp;
315         struct componentname *cnp = ap->a_cnp;
316         struct ucred *cred = cnp->cn_cred;
317         int flags = cnp->cn_flags;
318         int nameiop = cnp->cn_nameiop;
319         struct thread *td = cnp->cn_td;
320         globaldata_t gd = mycpu;
321
322         int     DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize;
323
324         bp = NULL;
325         slotoffset = -1;
326         *vpp = NULL;
327         vdp = ap->a_dvp;
328         dp = VTOI(vdp);
329         lockparent = flags & CNP_LOCKPARENT;
330         wantparent = flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
331
332         /*
333          * We now have a segment name to search for, and a directory to search.
334          */
335
336         /*
337          * Suppress search for slots unless creating
338          * file and at end of pathname, in which case
339          * we watch for a place to put the new file in
340          * case it doesn't already exist.
341          */
342         slotstatus = FOUND;
343         slotfreespace = slotsize = slotneeded = 0;
344         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
345             (flags & CNP_ISLASTCN)) {
346                 slotstatus = NONE;
347                 slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen); 
348                 /* was
349                 slotneeded = (sizeof(struct direct) - MAXNAMLEN +
350                         cnp->cn_namelen + 3) &~ 3; */
351         }
352
353         /*
354          * If there is cached information on a previous search of
355          * this directory, pick up where we last left off.
356          * We cache only lookups as these are the most common
357          * and have the greatest payoff. Caching CREATE has little
358          * benefit as it usually must search the entire directory
359          * to determine that the entry does not exist. Caching the
360          * location of the last DELETE or RENAME has not reduced
361          * profiling time and hence has been removed in the interest
362          * of simplicity.
363          */
364         bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
365         if (nameiop != NAMEI_LOOKUP || dp->i_diroff == 0 ||
366             dp->i_diroff > dp->i_size) {
367                 entryoffsetinblock = 0;
368                 dp->i_offset = 0;
369                 numdirpasses = 1;
370         } else {
371                 dp->i_offset = dp->i_diroff;
372                 if ((entryoffsetinblock = dp->i_offset & bmask) &&
373                     (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
374                         return (error);
375                 numdirpasses = 2;
376                 gd->gd_nchstats->ncs_2passes++;
377         }
378         prevoff = dp->i_offset;
379         endsearch = roundup(dp->i_size, DIRBLKSIZ);
380         enduseful = 0;
381
382 searchloop:
383         while (dp->i_offset < endsearch) {
384                 /*
385                  * If necessary, get the next directory block.
386                  */
387                 if ((dp->i_offset & bmask) == 0) {
388                         if (bp != NULL)
389                                 brelse(bp);
390                         if ((error =
391                             UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0)
392                                 return (error);
393                         entryoffsetinblock = 0;
394                 }
395                 /*
396                  * If still looking for a slot, and at a DIRBLKSIZE
397                  * boundary, have to start looking for free space again.
398                  */
399                 if (slotstatus == NONE &&
400                     (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
401                         slotoffset = -1;
402                         slotfreespace = 0;
403                 }
404                 /*
405                  * Get pointer to next entry.
406                  * Full validation checks are slow, so we only check
407                  * enough to insure forward progress through the
408                  * directory. Complete checks can be run by patching
409                  * "dirchk" to be true.
410                  */
411                 ep = (struct ext2_dir_entry_2 *)
412                         ((char *)bp->b_data + entryoffsetinblock);
413                 if (ep->rec_len == 0 ||
414                     (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
415                         int i;
416                         ufs_dirbad(dp, dp->i_offset, "mangled entry");
417                         i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
418                         dp->i_offset += i;
419                         entryoffsetinblock += i;
420                         continue;
421                 }
422
423                 /*
424                  * If an appropriate sized slot has not yet been found,
425                  * check to see if one is available. Also accumulate space
426                  * in the current block so that we can determine if
427                  * compaction is viable.
428                  */
429                 if (slotstatus != FOUND) {
430                         int size = ep->rec_len;
431
432                         if (ep->inode != 0)
433                                 size -= EXT2_DIR_REC_LEN(ep->name_len);
434                         if (size > 0) {
435                                 if (size >= slotneeded) {
436                                         slotstatus = FOUND;
437                                         slotoffset = dp->i_offset;
438                                         slotsize = ep->rec_len;
439                                 } else if (slotstatus == NONE) {
440                                         slotfreespace += size;
441                                         if (slotoffset == -1)
442                                                 slotoffset = dp->i_offset;
443                                         if (slotfreespace >= slotneeded) {
444                                                 slotstatus = COMPACT;
445                                                 slotsize = dp->i_offset +
446                                                       ep->rec_len - slotoffset;
447                                         }
448                                 }
449                         }
450                 }
451
452                 /*
453                  * Check for a name match.
454                  */
455                 if (ep->inode) {
456                         namlen = ep->name_len;
457                         if (namlen == cnp->cn_namelen &&
458                             !bcmp(cnp->cn_nameptr, ep->name,
459                                 (unsigned)namlen)) {
460                                 /*
461                                  * Save directory entry's inode number and
462                                  * reclen in ndp->ni_ufs area, and release
463                                  * directory buffer.
464                                  */
465                                 dp->i_ino = ep->inode;
466                                 dp->i_reclen = ep->rec_len;
467                                 goto found;
468                         }
469                 }
470                 prevoff = dp->i_offset;
471                 dp->i_offset += ep->rec_len;
472                 entryoffsetinblock += ep->rec_len;
473                 if (ep->inode)
474                         enduseful = dp->i_offset;
475         }
476 /* notfound: */
477         /*
478          * If we started in the middle of the directory and failed
479          * to find our target, we must check the beginning as well.
480          */
481         if (numdirpasses == 2) {
482                 numdirpasses--;
483                 dp->i_offset = 0;
484                 endsearch = dp->i_diroff;
485                 goto searchloop;
486         }
487         if (bp != NULL)
488                 brelse(bp);
489         /*
490          * If creating, and at end of pathname and current
491          * directory has not been removed, then can consider
492          * allowing file to be created.
493          */
494         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
495             (flags & CNP_ISLASTCN) && dp->i_nlink != 0) {
496                 /*
497                  * Access for write is interpreted as allowing
498                  * creation of files in the directory.
499                  */
500                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
501                         return (error);
502                 /*
503                  * Return an indication of where the new directory
504                  * entry should be put.  If we didn't find a slot,
505                  * then set dp->i_count to 0 indicating
506                  * that the new slot belongs at the end of the
507                  * directory. If we found a slot, then the new entry
508                  * can be put in the range from dp->i_offset to
509                  * dp->i_offset + dp->i_count.
510                  */
511                 if (slotstatus == NONE) {
512                         dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
513                         dp->i_count = 0;
514                         enduseful = dp->i_offset;
515                 } else {
516                         dp->i_offset = slotoffset;
517                         dp->i_count = slotsize;
518                         if (enduseful < slotoffset + slotsize)
519                                 enduseful = slotoffset + slotsize;
520                 }
521                 dp->i_endoff = roundup(enduseful, DIRBLKSIZ);
522                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
523                 /*
524                  * We return with the directory locked, so that
525                  * the parameters we set up above will still be
526                  * valid if we actually decide to do a direnter().
527                  * We return ni_vp == NULL to indicate that the entry
528                  * does not currently exist; we leave a pointer to
529                  * the (locked) directory inode in ndp->ni_dvp.
530                  * The pathname buffer is saved so that the name
531                  * can be obtained later.
532                  *
533                  * NB - if the directory is unlocked, then this
534                  * information cannot be used.
535                  */
536                 cnp->cn_flags |= CNP_SAVENAME;
537                 if (!lockparent)
538                         VOP_UNLOCK(vdp, NULL, 0, td);
539                 return (EJUSTRETURN);
540         }
541         /*
542          * Insert name into cache (as non-existent) if appropriate.
543          */
544         if ((cnp->cn_flags & CNP_MAKEENTRY) && nameiop != NAMEI_CREATE)
545                 cache_enter(vdp, NCPNULL, *vpp, cnp);
546         return (ENOENT);
547
548 found:
549         if (numdirpasses == 2)
550                 gd->gd_nchstats->ncs_pass2++;
551         /*
552          * Check that directory length properly reflects presence
553          * of this entry.
554          */
555         if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
556                 > dp->i_size) {
557                 ufs_dirbad(dp, dp->i_offset, "i_size too small");
558                 dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
559                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
560         }
561         brelse(bp);
562
563         /*
564          * Found component in pathname.
565          * If the final component of path name, save information
566          * in the cache as to where the entry was found.
567          */
568         if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP)
569                 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
570
571         /*
572          * If deleting, and at end of pathname, return
573          * parameters which can be used to remove file.
574          * If the wantparent flag isn't set, we return only
575          * the directory (in ndp->ni_dvp), otherwise we go
576          * on and lock the inode, being careful with ".".
577          */
578         if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) {
579                 /*
580                  * Write access to directory required to delete files.
581                  */
582                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
583                         return (error);
584                 /*
585                  * Return pointer to current entry in dp->i_offset,
586                  * and distance past previous entry (if there
587                  * is a previous entry in this block) in dp->i_count.
588                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
589                  */
590                 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
591                         dp->i_count = 0;
592                 else
593                         dp->i_count = dp->i_offset - prevoff;
594                 if (dp->i_number == dp->i_ino) {
595                         vref(vdp);
596                         *vpp = vdp;
597                         return (0);
598                 }
599                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
600                         return (error);
601                 /*
602                  * If directory is "sticky", then user must own
603                  * the directory, or the file in it, else she
604                  * may not delete it (unless she's root). This
605                  * implements append-only directories.
606                  */
607                 if ((dp->i_mode & ISVTX) &&
608                     cred->cr_uid != 0 &&
609                     cred->cr_uid != dp->i_uid &&
610                     VTOI(tdp)->i_uid != cred->cr_uid) {
611                         vput(tdp);
612                         return (EPERM);
613                 }
614                 *vpp = tdp;
615                 if (!lockparent)
616                         VOP_UNLOCK(vdp, NULL, 0, td);
617                 return (0);
618         }
619
620         /*
621          * If rewriting (RENAME), return the inode and the
622          * information required to rewrite the present directory
623          * Must get inode of directory entry to verify it's a
624          * regular file, or empty directory.
625          */
626         if (nameiop == NAMEI_RENAME && wantparent &&
627             (flags & CNP_ISLASTCN)) {
628                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
629                         return (error);
630                 /*
631                  * Careful about locking second inode.
632                  * This can only occur if the target is ".".
633                  */
634                 if (dp->i_number == dp->i_ino)
635                         return (EISDIR);
636                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
637                         return (error);
638                 *vpp = tdp;
639                 cnp->cn_flags |= CNP_SAVENAME;
640                 if (!lockparent)
641                         VOP_UNLOCK(vdp, NULL, 0, td);
642                 return (0);
643         }
644
645         /*
646          * Step through the translation in the name.  We do not `vput' the
647          * directory because we may need it again if a symbolic link
648          * is relative to the current directory.  Instead we save it
649          * unlocked as "pdp".  We must get the target inode before unlocking
650          * the directory to insure that the inode will not be removed
651          * before we get it.  We prevent deadlock by always fetching
652          * inodes from the root, moving down the directory tree. Thus
653          * when following backward pointers ".." we must unlock the
654          * parent directory before getting the requested directory.
655          * There is a potential race condition here if both the current
656          * and parent directories are removed before the VFS_VGET for the
657          * inode associated with ".." returns.  We hope that this occurs
658          * infrequently since we cannot avoid this race condition without
659          * implementing a sophisticated deadlock detection algorithm.
660          * Note also that this simple deadlock detection scheme will not
661          * work if the file system has any hard links other than ".."
662          * that point backwards in the directory structure.
663          */
664         pdp = vdp;
665         if (flags & CNP_ISDOTDOT) {
666                 VOP_UNLOCK(pdp, NULL, 0, td);   /* race to get the inode */
667                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
668                         vn_lock(pdp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
669                         return (error);
670                 }
671                 if (lockparent && (flags & CNP_ISLASTCN) &&
672                     (error = vn_lock(pdp, NULL, LK_EXCLUSIVE, td))) {
673                         vput(tdp);
674                         return (error);
675                 }
676                 *vpp = tdp;
677         } else if (dp->i_number == dp->i_ino) {
678                 vref(vdp);      /* we want ourself, ie "." */
679                 *vpp = vdp;
680         } else {
681                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
682                         return (error);
683                 if (!lockparent || !(flags & CNP_ISLASTCN))
684                         VOP_UNLOCK(pdp, NULL, 0, td);
685                 *vpp = tdp;
686         }
687
688         /*
689          * Insert name into cache if appropriate.
690          */
691         if (cnp->cn_flags & CNP_MAKEENTRY)
692                 cache_enter(vdp, NCPNULL, *vpp, cnp);
693         return (0);
694 }
695
696 /*
697  * Do consistency checking on a directory entry:
698  *      record length must be multiple of 4
699  *      entry must fit in rest of its DIRBLKSIZ block
700  *      record must be large enough to contain entry
701  *      name is not longer than MAXNAMLEN
702  *      name must be as long as advertised, and null terminated
703  */
704 /*
705  *      changed so that it confirms to ext2_check_dir_entry
706  */
707 static int
708 ext2_dirbadentry(struct vnode *dp, struct ext2_dir_entry_2 *de,
709                  int entryoffsetinblock)
710 {
711         int     DIRBLKSIZ = VTOI(dp)->i_e2fs->s_blocksize;
712
713         char * error_msg = NULL;
714
715         if (de->rec_len < EXT2_DIR_REC_LEN(1))
716                 error_msg = "rec_len is smaller than minimal";
717         else if (de->rec_len % 4 != 0)
718                 error_msg = "rec_len % 4 != 0";
719         else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
720                 error_msg = "reclen is too small for name_len";
721         else if (entryoffsetinblock + de->rec_len > DIRBLKSIZ)
722                 error_msg = "directory entry across blocks";
723         /* else LATER
724              if (de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
725                 error_msg = "inode out of bounds";
726         */
727
728         if (error_msg != NULL) {
729                 printf("bad directory entry: %s\n", error_msg);
730                 printf("offset=%d, inode=%lu, rec_len=%u, name_len=%u\n",
731                         entryoffsetinblock, (unsigned long)de->inode,
732                         de->rec_len, de->name_len);
733         }
734         return error_msg == NULL ? 0 : 1;
735 }
736
737 /*
738  * Write a directory entry after a call to namei, using the parameters
739  * that it left in nameidata.  The argument ip is the inode which the new
740  * directory entry will refer to.  Dvp is a pointer to the directory to
741  * be written, which was left locked by namei. Remaining parameters
742  * (dp->i_offset, dp->i_count) indicate how the space for the new
743  * entry is to be obtained.
744  */
745 int
746 ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
747 {
748         struct ext2_dir_entry_2 *ep, *nep;
749         struct inode *dp;
750         struct buf *bp;
751         struct ext2_dir_entry_2 newdir;
752         struct iovec aiov;
753         struct uio auio;
754         u_int dsize;
755         int error, loc, newentrysize, spacefree;
756         char *dirbuf;
757         int     DIRBLKSIZ = ip->i_e2fs->s_blocksize;
758
759
760 #if DIAGNOSTIC
761         if ((cnp->cn_flags & CNP_SAVENAME) == 0)
762                 panic("direnter: missing name");
763 #endif
764         dp = VTOI(dvp);
765         newdir.inode = ip->i_number;
766         newdir.name_len = cnp->cn_namelen;
767         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
768             EXT2_FEATURE_INCOMPAT_FILETYPE))
769                 newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
770         else
771                 newdir.file_type = EXT2_FT_UNKNOWN;
772         bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
773         newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
774         if (dp->i_count == 0) {
775                 /*
776                  * If dp->i_count is 0, then namei could find no
777                  * space in the directory. Here, dp->i_offset will
778                  * be on a directory block boundary and we will write the
779                  * new entry into a fresh block.
780                  */
781                 if (dp->i_offset & (DIRBLKSIZ - 1))
782                         panic("ext2_direnter: newblk");
783                 auio.uio_offset = dp->i_offset;
784                 newdir.rec_len = DIRBLKSIZ;
785                 auio.uio_resid = newentrysize;
786                 aiov.iov_len = newentrysize;
787                 aiov.iov_base = (caddr_t)&newdir;
788                 auio.uio_iov = &aiov;
789                 auio.uio_iovcnt = 1;
790                 auio.uio_rw = UIO_WRITE;
791                 auio.uio_segflg = UIO_SYSSPACE;
792                 auio.uio_td = NULL;
793                 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
794                 if (DIRBLKSIZ >
795                     VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
796                         /* XXX should grow with balloc() */
797                         panic("ext2_direnter: frag size");
798                 else if (!error) {
799                         dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
800                         dp->i_flag |= IN_CHANGE;
801                 }
802                 return (error);
803         }
804
805         /*
806          * If dp->i_count is non-zero, then namei found space
807          * for the new entry in the range dp->i_offset to
808          * dp->i_offset + dp->i_count in the directory.
809          * To use this space, we may have to compact the entries located
810          * there, by copying them together towards the beginning of the
811          * block, leaving the free space in one usable chunk at the end.
812          */
813
814         /*
815          * Increase size of directory if entry eats into new space.
816          * This should never push the size past a new multiple of
817          * DIRBLKSIZE.
818          *
819          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
820          */
821         if (dp->i_offset + dp->i_count > dp->i_size)
822                 dp->i_size = dp->i_offset + dp->i_count;
823         /*
824          * Get the block containing the space for the new directory entry.
825          */
826         if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
827                 return (error);
828         /*
829          * Find space for the new entry. In the simple case, the entry at
830          * offset base will have the space. If it does not, then namei
831          * arranged that compacting the region dp->i_offset to
832          * dp->i_offset + dp->i_count would yield the
833          * space.
834          */
835         ep = (struct ext2_dir_entry_2 *)dirbuf;
836         dsize = EXT2_DIR_REC_LEN(ep->name_len);
837         spacefree = ep->rec_len - dsize;
838         for (loc = ep->rec_len; loc < dp->i_count; ) {
839                 nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
840                 if (ep->inode) {
841                         /* trim the existing slot */
842                         ep->rec_len = dsize;
843                         ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
844                 } else {
845                         /* overwrite; nothing there; header is ours */
846                         spacefree += dsize;
847                 }
848                 dsize = EXT2_DIR_REC_LEN(nep->name_len);
849                 spacefree += nep->rec_len - dsize;
850                 loc += nep->rec_len;
851                 bcopy((caddr_t)nep, (caddr_t)ep, dsize);
852         }
853         /*
854          * Update the pointer fields in the previous entry (if any),
855          * copy in the new entry, and write out the block.
856          */
857         if (ep->inode == 0) {
858                 if (spacefree + dsize < newentrysize)
859                         panic("ext2_direnter: compact1");
860                 newdir.rec_len = spacefree + dsize;
861         } else {
862                 if (spacefree < newentrysize)
863                         panic("ext2_direnter: compact2");
864                 newdir.rec_len = spacefree;
865                 ep->rec_len = dsize;
866                 ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
867         }
868         bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
869         error = VOP_BWRITE(bp->b_vp, bp);
870         dp->i_flag |= IN_CHANGE | IN_UPDATE;
871         if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
872                 error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
873                     cnp->cn_cred, cnp->cn_td);
874         return (error);
875 }
876
877 /*
878  * Remove a directory entry after a call to namei, using
879  * the parameters which it left in nameidata. The entry
880  * dp->i_offset contains the offset into the directory of the
881  * entry to be eliminated.  The dp->i_count field contains the
882  * size of the previous record in the directory.  If this
883  * is 0, the first entry is being deleted, so we need only
884  * zero the inode number to mark the entry as free.  If the
885  * entry is not the first in the directory, we must reclaim
886  * the space of the now empty record by adding the record size
887  * to the size of the previous entry.
888  */
889 int
890 ext2_dirremove(struct vnode *dvp, struct componentname *cnp)
891 {
892         struct inode *dp;
893         struct ext2_dir_entry_2 *ep;
894         struct buf *bp;
895         int error;
896          
897         dp = VTOI(dvp);
898         if (dp->i_count == 0) {
899                 /*
900                  * First entry in block: set d_ino to zero.
901                  */
902                 if ((error =
903                     UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
904                         return (error);
905                 ep->inode = 0;
906                 error = VOP_BWRITE(bp->b_vp, bp);
907                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
908                 return (error);
909         }
910         /*
911          * Collapse new free space into previous entry.
912          */
913         if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count),
914             (char **)&ep, &bp)) != 0)
915                 return (error);
916         ep->rec_len += dp->i_reclen;
917         error = VOP_BWRITE(bp->b_vp, bp);
918         dp->i_flag |= IN_CHANGE | IN_UPDATE;
919         return (error);
920 }
921
922 /*
923  * Rewrite an existing directory entry to point at the inode
924  * supplied.  The parameters describing the directory entry are
925  * set up by a call to namei.
926  */
927 int
928 ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp)
929 {
930         struct buf *bp;
931         struct ext2_dir_entry_2 *ep;
932         struct vnode *vdp = ITOV(dp);
933         int error;
934
935         if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
936                 return (error);
937         ep->inode = ip->i_number;
938         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
939             EXT2_FEATURE_INCOMPAT_FILETYPE))
940                 ep->file_type = DTTOFT(IFTODT(ip->i_mode));
941         else
942                 ep->file_type = EXT2_FT_UNKNOWN;
943         error = VOP_BWRITE(bp->b_vp, bp);
944         dp->i_flag |= IN_CHANGE | IN_UPDATE;
945         return (error);
946 }
947
948 /*
949  * Check if a directory is empty or not.
950  * Inode supplied must be locked.
951  *
952  * Using a struct dirtemplate here is not precisely
953  * what we want, but better than using a struct direct.
954  *
955  * NB: does not handle corrupted directories.
956  */
957 int
958 ext2_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
959 {
960         off_t off;
961         struct dirtemplate dbuf;
962         struct ext2_dir_entry_2 *dp = (struct ext2_dir_entry_2 *)&dbuf;
963         int error, count, namlen;
964                  
965 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
966
967         for (off = 0; off < ip->i_size; off += dp->rec_len) {
968                 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
969                    UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
970                 /*
971                  * Since we read MINDIRSIZ, residual must
972                  * be 0 unless we're at end of file.
973                  */
974                 if (error || count != 0)
975                         return (0);
976                 /* avoid infinite loops */
977                 if (dp->rec_len == 0)
978                         return (0);
979                 /* skip empty entries */
980                 if (dp->inode == 0)
981                         continue;
982                 /* accept only "." and ".." */
983                 namlen = dp->name_len;
984                 if (namlen > 2)
985                         return (0);
986                 if (dp->name[0] != '.')
987                         return (0);
988                 /*
989                  * At this point namlen must be 1 or 2.
990                  * 1 implies ".", 2 implies ".." if second
991                  * char is also "."
992                  */
993                 if (namlen == 1)
994                         continue;
995                 if (dp->name[1] == '.' && dp->inode == parentino)
996                         continue;
997                 return (0);
998         }
999         return (1);
1000 }
1001
1002 /*
1003  * Check if source directory is in the path of the target directory.
1004  * Target is supplied locked, source is unlocked.
1005  * The target is always vput before returning.
1006  */
1007 int
1008 ext2_checkpath(struct inode *source, struct inode *target, struct ucred *cred)
1009 {
1010         struct vnode *vp;
1011         int error, rootino, namlen;
1012         struct dirtemplate dirbuf;
1013
1014         vp = ITOV(target);
1015         if (target->i_number == source->i_number) {
1016                 error = EEXIST;
1017                 goto out;
1018         }
1019         rootino = ROOTINO;
1020         error = 0;
1021         if (target->i_number == rootino)
1022                 goto out;
1023
1024         for (;;) {
1025                 if (vp->v_type != VDIR) {
1026                         error = ENOTDIR;
1027                         break;
1028                 }
1029                 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1030                         sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
1031                         IO_NODELOCKED, cred, (int *)0, NULL);
1032                 if (error != 0)
1033                         break;
1034                 namlen = dirbuf.dotdot_type;    /* like ufs little-endian */
1035                 if (namlen != 2 ||
1036                     dirbuf.dotdot_name[0] != '.' ||
1037                     dirbuf.dotdot_name[1] != '.') {
1038                         error = ENOTDIR;
1039                         break;
1040                 }
1041                 if (dirbuf.dotdot_ino == source->i_number) {
1042                         error = EINVAL;
1043                         break;
1044                 }
1045                 if (dirbuf.dotdot_ino == rootino)
1046                         break;
1047                 vput(vp);
1048                 if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) != 0) {
1049                         vp = NULL;
1050                         break;
1051                 }
1052         }
1053
1054 out:
1055         if (error == ENOTDIR)
1056                 printf("checkpath: .. not a directory\n");
1057         if (vp != NULL)
1058                 vput(vp);
1059         return (error);
1060 }