Merge from vendor branch OPENSSL:
[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.16 2004/11/12 00:09:30 dillon 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_lookup_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                 slotstatus = NONE;
346                 slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen); 
347                 /* was
348                 slotneeded = (sizeof(struct direct) - MAXNAMLEN +
349                         cnp->cn_namelen + 3) &~ 3; */
350         }
351
352         /*
353          * If there is cached information on a previous search of
354          * this directory, pick up where we last left off.
355          * We cache only lookups as these are the most common
356          * and have the greatest payoff. Caching CREATE has little
357          * benefit as it usually must search the entire directory
358          * to determine that the entry does not exist. Caching the
359          * location of the last DELETE or RENAME has not reduced
360          * profiling time and hence has been removed in the interest
361          * of simplicity.
362          */
363         bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
364         if (nameiop != NAMEI_LOOKUP || dp->i_diroff == 0 ||
365             dp->i_diroff > dp->i_size) {
366                 entryoffsetinblock = 0;
367                 dp->i_offset = 0;
368                 numdirpasses = 1;
369         } else {
370                 dp->i_offset = dp->i_diroff;
371                 if ((entryoffsetinblock = dp->i_offset & bmask) &&
372                     (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
373                         return (error);
374                 numdirpasses = 2;
375                 gd->gd_nchstats->ncs_2passes++;
376         }
377         prevoff = dp->i_offset;
378         endsearch = roundup(dp->i_size, DIRBLKSIZ);
379         enduseful = 0;
380
381 searchloop:
382         while (dp->i_offset < endsearch) {
383                 /*
384                  * If necessary, get the next directory block.
385                  */
386                 if ((dp->i_offset & bmask) == 0) {
387                         if (bp != NULL)
388                                 brelse(bp);
389                         if ((error =
390                             UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0)
391                                 return (error);
392                         entryoffsetinblock = 0;
393                 }
394                 /*
395                  * If still looking for a slot, and at a DIRBLKSIZE
396                  * boundary, have to start looking for free space again.
397                  */
398                 if (slotstatus == NONE &&
399                     (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
400                         slotoffset = -1;
401                         slotfreespace = 0;
402                 }
403                 /*
404                  * Get pointer to next entry.
405                  * Full validation checks are slow, so we only check
406                  * enough to insure forward progress through the
407                  * directory. Complete checks can be run by patching
408                  * "dirchk" to be true.
409                  */
410                 ep = (struct ext2_dir_entry_2 *)
411                         ((char *)bp->b_data + entryoffsetinblock);
412                 if (ep->rec_len == 0 ||
413                     (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
414                         int i;
415                         ufs_dirbad(dp, dp->i_offset, "mangled entry");
416                         i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
417                         dp->i_offset += i;
418                         entryoffsetinblock += i;
419                         continue;
420                 }
421
422                 /*
423                  * If an appropriate sized slot has not yet been found,
424                  * check to see if one is available. Also accumulate space
425                  * in the current block so that we can determine if
426                  * compaction is viable.
427                  */
428                 if (slotstatus != FOUND) {
429                         int size = ep->rec_len;
430
431                         if (ep->inode != 0)
432                                 size -= EXT2_DIR_REC_LEN(ep->name_len);
433                         if (size > 0) {
434                                 if (size >= slotneeded) {
435                                         slotstatus = FOUND;
436                                         slotoffset = dp->i_offset;
437                                         slotsize = ep->rec_len;
438                                 } else if (slotstatus == NONE) {
439                                         slotfreespace += size;
440                                         if (slotoffset == -1)
441                                                 slotoffset = dp->i_offset;
442                                         if (slotfreespace >= slotneeded) {
443                                                 slotstatus = COMPACT;
444                                                 slotsize = dp->i_offset +
445                                                       ep->rec_len - slotoffset;
446                                         }
447                                 }
448                         }
449                 }
450
451                 /*
452                  * Check for a name match.
453                  */
454                 if (ep->inode) {
455                         namlen = ep->name_len;
456                         if (namlen == cnp->cn_namelen &&
457                             !bcmp(cnp->cn_nameptr, ep->name,
458                                 (unsigned)namlen)) {
459                                 /*
460                                  * Save directory entry's inode number and
461                                  * reclen in ndp->ni_ufs area, and release
462                                  * directory buffer.
463                                  */
464                                 dp->i_ino = ep->inode;
465                                 dp->i_reclen = ep->rec_len;
466                                 goto found;
467                         }
468                 }
469                 prevoff = dp->i_offset;
470                 dp->i_offset += ep->rec_len;
471                 entryoffsetinblock += ep->rec_len;
472                 if (ep->inode)
473                         enduseful = dp->i_offset;
474         }
475 /* notfound: */
476         /*
477          * If we started in the middle of the directory and failed
478          * to find our target, we must check the beginning as well.
479          */
480         if (numdirpasses == 2) {
481                 numdirpasses--;
482                 dp->i_offset = 0;
483                 endsearch = dp->i_diroff;
484                 goto searchloop;
485         }
486         if (bp != NULL)
487                 brelse(bp);
488         /*
489          * If creating, and at end of pathname and current
490          * directory has not been removed, then can consider
491          * allowing file to be created.
492          */
493         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
494             dp->i_nlink != 0) {
495                 /*
496                  * Access for write is interpreted as allowing
497                  * creation of files in the directory.
498                  */
499                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
500                         return (error);
501                 /*
502                  * Return an indication of where the new directory
503                  * entry should be put.  If we didn't find a slot,
504                  * then set dp->i_count to 0 indicating
505                  * that the new slot belongs at the end of the
506                  * directory. If we found a slot, then the new entry
507                  * can be put in the range from dp->i_offset to
508                  * dp->i_offset + dp->i_count.
509                  */
510                 if (slotstatus == NONE) {
511                         dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
512                         dp->i_count = 0;
513                         enduseful = dp->i_offset;
514                 } else {
515                         dp->i_offset = slotoffset;
516                         dp->i_count = slotsize;
517                         if (enduseful < slotoffset + slotsize)
518                                 enduseful = slotoffset + slotsize;
519                 }
520                 dp->i_endoff = roundup(enduseful, DIRBLKSIZ);
521                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
522                 /*
523                  * We return with the directory locked, so that
524                  * the parameters we set up above will still be
525                  * valid if we actually decide to do a direnter().
526                  * We return ni_vp == NULL to indicate that the entry
527                  * does not currently exist; we leave a pointer to
528                  * the (locked) directory inode in ndp->ni_dvp.
529                  * The pathname buffer is saved so that the name
530                  * can be obtained later.
531                  *
532                  * NB - if the directory is unlocked, then this
533                  * information cannot be used.
534                  */
535                 if (!lockparent)
536                         VOP_UNLOCK(vdp, 0, td);
537                 return (EJUSTRETURN);
538         }
539         return (ENOENT);
540
541 found:
542         if (numdirpasses == 2)
543                 gd->gd_nchstats->ncs_pass2++;
544         /*
545          * Check that directory length properly reflects presence
546          * of this entry.
547          */
548         if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
549                 > dp->i_size) {
550                 ufs_dirbad(dp, dp->i_offset, "i_size too small");
551                 dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
552                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
553         }
554         brelse(bp);
555
556         /*
557          * Found component in pathname.
558          * If the final component of path name, save information
559          * in the cache as to where the entry was found.
560          */
561         if (nameiop == NAMEI_LOOKUP)
562                 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
563
564         /*
565          * If deleting, and at end of pathname, return
566          * parameters which can be used to remove file.
567          * If the wantparent flag isn't set, we return only
568          * the directory (in ndp->ni_dvp), otherwise we go
569          * on and lock the inode, being careful with ".".
570          */
571         if (nameiop == NAMEI_DELETE) {
572                 /*
573                  * Write access to directory required to delete files.
574                  */
575                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
576                         return (error);
577                 /*
578                  * Return pointer to current entry in dp->i_offset,
579                  * and distance past previous entry (if there
580                  * is a previous entry in this block) in dp->i_count.
581                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
582                  */
583                 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
584                         dp->i_count = 0;
585                 else
586                         dp->i_count = dp->i_offset - prevoff;
587                 if (dp->i_number == dp->i_ino) {
588                         vref(vdp);
589                         *vpp = vdp;
590                         return (0);
591                 }
592                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
593                         return (error);
594                 /*
595                  * If directory is "sticky", then user must own
596                  * the directory, or the file in it, else she
597                  * may not delete it (unless she's root). This
598                  * implements append-only directories.
599                  */
600                 if ((dp->i_mode & ISVTX) &&
601                     cred->cr_uid != 0 &&
602                     cred->cr_uid != dp->i_uid &&
603                     VTOI(tdp)->i_uid != cred->cr_uid) {
604                         vput(tdp);
605                         return (EPERM);
606                 }
607                 *vpp = tdp;
608                 if (!lockparent)
609                         VOP_UNLOCK(vdp, 0, td);
610                 return (0);
611         }
612
613         /*
614          * If rewriting (RENAME), return the inode and the
615          * information required to rewrite the present directory
616          * Must get inode of directory entry to verify it's a
617          * regular file, or empty directory.
618          */
619         if (nameiop == NAMEI_RENAME && wantparent) {
620                 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0)
621                         return (error);
622                 /*
623                  * Careful about locking second inode.
624                  * This can only occur if the target is ".".
625                  */
626                 if (dp->i_number == dp->i_ino)
627                         return (EISDIR);
628                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
629                         return (error);
630                 *vpp = tdp;
631                 if (!lockparent)
632                         VOP_UNLOCK(vdp, 0, td);
633                 return (0);
634         }
635
636         /*
637          * Step through the translation in the name.  We do not `vput' the
638          * directory because we may need it again if a symbolic link
639          * is relative to the current directory.  Instead we save it
640          * unlocked as "pdp".  We must get the target inode before unlocking
641          * the directory to insure that the inode will not be removed
642          * before we get it.  We prevent deadlock by always fetching
643          * inodes from the root, moving down the directory tree. Thus
644          * when following backward pointers ".." we must unlock the
645          * parent directory before getting the requested directory.
646          * There is a potential race condition here if both the current
647          * and parent directories are removed before the VFS_VGET for the
648          * inode associated with ".." returns.  We hope that this occurs
649          * infrequently since we cannot avoid this race condition without
650          * implementing a sophisticated deadlock detection algorithm.
651          * Note also that this simple deadlock detection scheme will not
652          * work if the file system has any hard links other than ".."
653          * that point backwards in the directory structure.
654          */
655         pdp = vdp;
656         if (flags & CNP_ISDOTDOT) {
657                 VOP_UNLOCK(pdp, 0, td); /* race to get the inode */
658                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
659                         vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td);
660                         return (error);
661                 }
662                 if (lockparent && (error = vn_lock(pdp, LK_EXCLUSIVE, td))) {
663                         vput(tdp);
664                         return (error);
665                 }
666                 *vpp = tdp;
667         } else if (dp->i_number == dp->i_ino) {
668                 vref(vdp);      /* we want ourself, ie "." */
669                 *vpp = vdp;
670         } else {
671                 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
672                         return (error);
673                 if (!lockparent)
674                         VOP_UNLOCK(pdp, 0, td);
675                 *vpp = tdp;
676         }
677         return (0);
678 }
679
680 /*
681  * Do consistency checking on a directory entry:
682  *      record length must be multiple of 4
683  *      entry must fit in rest of its DIRBLKSIZ block
684  *      record must be large enough to contain entry
685  *      name is not longer than MAXNAMLEN
686  *      name must be as long as advertised, and null terminated
687  */
688 /*
689  *      changed so that it confirms to ext2_check_dir_entry
690  */
691 static int
692 ext2_dirbadentry(struct vnode *dp, struct ext2_dir_entry_2 *de,
693                  int entryoffsetinblock)
694 {
695         int     DIRBLKSIZ = VTOI(dp)->i_e2fs->s_blocksize;
696
697         char * error_msg = NULL;
698
699         if (de->rec_len < EXT2_DIR_REC_LEN(1))
700                 error_msg = "rec_len is smaller than minimal";
701         else if (de->rec_len % 4 != 0)
702                 error_msg = "rec_len % 4 != 0";
703         else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
704                 error_msg = "reclen is too small for name_len";
705         else if (entryoffsetinblock + de->rec_len > DIRBLKSIZ)
706                 error_msg = "directory entry across blocks";
707         /* else LATER
708              if (de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
709                 error_msg = "inode out of bounds";
710         */
711
712         if (error_msg != NULL) {
713                 printf("bad directory entry: %s\n", error_msg);
714                 printf("offset=%d, inode=%lu, rec_len=%u, name_len=%u\n",
715                         entryoffsetinblock, (unsigned long)de->inode,
716                         de->rec_len, de->name_len);
717         }
718         return error_msg == NULL ? 0 : 1;
719 }
720
721 /*
722  * Write a directory entry after a call to namei, using the parameters
723  * that it left in the directory inode.  The argument ip is the inode which
724  * the new directory entry will refer to.  Dvp is a pointer to the directory 
725  * to be written, which was left locked by namei. Remaining parameters
726  * (dp->i_offset, dp->i_count) indicate how the space for the new
727  * entry is to be obtained.
728  */
729 int
730 ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
731 {
732         struct ext2_dir_entry_2 *ep, *nep;
733         struct inode *dp;
734         struct buf *bp;
735         struct ext2_dir_entry_2 newdir;
736         struct iovec aiov;
737         struct uio auio;
738         u_int dsize;
739         int error, loc, newentrysize, spacefree;
740         char *dirbuf;
741         int     DIRBLKSIZ = ip->i_e2fs->s_blocksize;
742
743
744         dp = VTOI(dvp);
745         newdir.inode = ip->i_number;
746         newdir.name_len = cnp->cn_namelen;
747         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
748             EXT2_FEATURE_INCOMPAT_FILETYPE))
749                 newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
750         else
751                 newdir.file_type = EXT2_FT_UNKNOWN;
752         bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
753         newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
754         if (dp->i_count == 0) {
755                 /*
756                  * If dp->i_count is 0, then namei could find no
757                  * space in the directory. Here, dp->i_offset will
758                  * be on a directory block boundary and we will write the
759                  * new entry into a fresh block.
760                  */
761                 if (dp->i_offset & (DIRBLKSIZ - 1))
762                         panic("ext2_direnter: newblk");
763                 auio.uio_offset = dp->i_offset;
764                 newdir.rec_len = DIRBLKSIZ;
765                 auio.uio_resid = newentrysize;
766                 aiov.iov_len = newentrysize;
767                 aiov.iov_base = (caddr_t)&newdir;
768                 auio.uio_iov = &aiov;
769                 auio.uio_iovcnt = 1;
770                 auio.uio_rw = UIO_WRITE;
771                 auio.uio_segflg = UIO_SYSSPACE;
772                 auio.uio_td = NULL;
773                 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
774                 if (DIRBLKSIZ >
775                     VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
776                         /* XXX should grow with balloc() */
777                         panic("ext2_direnter: frag size");
778                 else if (!error) {
779                         dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
780                         dp->i_flag |= IN_CHANGE;
781                 }
782                 return (error);
783         }
784
785         /*
786          * If dp->i_count is non-zero, then namei found space
787          * for the new entry in the range dp->i_offset to
788          * dp->i_offset + dp->i_count in the directory.
789          * To use this space, we may have to compact the entries located
790          * there, by copying them together towards the beginning of the
791          * block, leaving the free space in one usable chunk at the end.
792          */
793
794         /*
795          * Increase size of directory if entry eats into new space.
796          * This should never push the size past a new multiple of
797          * DIRBLKSIZE.
798          *
799          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
800          */
801         if (dp->i_offset + dp->i_count > dp->i_size)
802                 dp->i_size = dp->i_offset + dp->i_count;
803         /*
804          * Get the block containing the space for the new directory entry.
805          */
806         if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
807                 return (error);
808         /*
809          * Find space for the new entry. In the simple case, the entry at
810          * offset base will have the space. If it does not, then namei
811          * arranged that compacting the region dp->i_offset to
812          * dp->i_offset + dp->i_count would yield the
813          * space.
814          */
815         ep = (struct ext2_dir_entry_2 *)dirbuf;
816         dsize = EXT2_DIR_REC_LEN(ep->name_len);
817         spacefree = ep->rec_len - dsize;
818         for (loc = ep->rec_len; loc < dp->i_count; ) {
819                 nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
820                 if (ep->inode) {
821                         /* trim the existing slot */
822                         ep->rec_len = dsize;
823                         ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
824                 } else {
825                         /* overwrite; nothing there; header is ours */
826                         spacefree += dsize;
827                 }
828                 dsize = EXT2_DIR_REC_LEN(nep->name_len);
829                 spacefree += nep->rec_len - dsize;
830                 loc += nep->rec_len;
831                 bcopy((caddr_t)nep, (caddr_t)ep, dsize);
832         }
833         /*
834          * Update the pointer fields in the previous entry (if any),
835          * copy in the new entry, and write out the block.
836          */
837         if (ep->inode == 0) {
838                 if (spacefree + dsize < newentrysize)
839                         panic("ext2_direnter: compact1");
840                 newdir.rec_len = spacefree + dsize;
841         } else {
842                 if (spacefree < newentrysize)
843                         panic("ext2_direnter: compact2");
844                 newdir.rec_len = spacefree;
845                 ep->rec_len = dsize;
846                 ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
847         }
848         bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
849         error = VOP_BWRITE(bp->b_vp, bp);
850         dp->i_flag |= IN_CHANGE | IN_UPDATE;
851         if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
852                 error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
853                     cnp->cn_cred, cnp->cn_td);
854         return (error);
855 }
856
857 /*
858  * Remove a directory entry after a call to namei, using
859  * the parameters which it left in the directory inode. The entry
860  * dp->i_offset contains the offset into the directory of the
861  * entry to be eliminated.  The dp->i_count field contains the
862  * size of the previous record in the directory.  If this
863  * is 0, the first entry is being deleted, so we need only
864  * zero the inode number to mark the entry as free.  If the
865  * entry is not the first in the directory, we must reclaim
866  * the space of the now empty record by adding the record size
867  * to the size of the previous entry.
868  */
869 int
870 ext2_dirremove(struct vnode *dvp, struct componentname *cnp)
871 {
872         struct inode *dp;
873         struct ext2_dir_entry_2 *ep;
874         struct buf *bp;
875         int error;
876          
877         dp = VTOI(dvp);
878         if (dp->i_count == 0) {
879                 /*
880                  * First entry in block: set d_ino to zero.
881                  */
882                 if ((error =
883                     UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
884                         return (error);
885                 ep->inode = 0;
886                 error = VOP_BWRITE(bp->b_vp, bp);
887                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
888                 return (error);
889         }
890         /*
891          * Collapse new free space into previous entry.
892          */
893         if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count),
894             (char **)&ep, &bp)) != 0)
895                 return (error);
896         ep->rec_len += dp->i_reclen;
897         error = VOP_BWRITE(bp->b_vp, bp);
898         dp->i_flag |= IN_CHANGE | IN_UPDATE;
899         return (error);
900 }
901
902 /*
903  * Rewrite an existing directory entry to point at the inode
904  * supplied.  The parameters describing the directory entry are
905  * set up by a call to namei.
906  */
907 int
908 ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp)
909 {
910         struct buf *bp;
911         struct ext2_dir_entry_2 *ep;
912         struct vnode *vdp = ITOV(dp);
913         int error;
914
915         if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
916                 return (error);
917         ep->inode = ip->i_number;
918         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
919             EXT2_FEATURE_INCOMPAT_FILETYPE))
920                 ep->file_type = DTTOFT(IFTODT(ip->i_mode));
921         else
922                 ep->file_type = EXT2_FT_UNKNOWN;
923         error = VOP_BWRITE(bp->b_vp, bp);
924         dp->i_flag |= IN_CHANGE | IN_UPDATE;
925         return (error);
926 }
927
928 /*
929  * Check if a directory is empty or not.
930  * Inode supplied must be locked.
931  *
932  * Using a struct dirtemplate here is not precisely
933  * what we want, but better than using a struct direct.
934  *
935  * NB: does not handle corrupted directories.
936  */
937 int
938 ext2_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
939 {
940         off_t off;
941         struct dirtemplate dbuf;
942         struct ext2_dir_entry_2 *dp = (struct ext2_dir_entry_2 *)&dbuf;
943         int error, count, namlen;
944                  
945 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
946
947         for (off = 0; off < ip->i_size; off += dp->rec_len) {
948                 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
949                    UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
950                 /*
951                  * Since we read MINDIRSIZ, residual must
952                  * be 0 unless we're at end of file.
953                  */
954                 if (error || count != 0)
955                         return (0);
956                 /* avoid infinite loops */
957                 if (dp->rec_len == 0)
958                         return (0);
959                 /* skip empty entries */
960                 if (dp->inode == 0)
961                         continue;
962                 /* accept only "." and ".." */
963                 namlen = dp->name_len;
964                 if (namlen > 2)
965                         return (0);
966                 if (dp->name[0] != '.')
967                         return (0);
968                 /*
969                  * At this point namlen must be 1 or 2.
970                  * 1 implies ".", 2 implies ".." if second
971                  * char is also "."
972                  */
973                 if (namlen == 1)
974                         continue;
975                 if (dp->name[1] == '.' && dp->inode == parentino)
976                         continue;
977                 return (0);
978         }
979         return (1);
980 }
981
982 /*
983  * Check if source directory is in the path of the target directory.
984  * Target is supplied locked, source is unlocked.
985  * The target is always vput before returning.
986  */
987 int
988 ext2_checkpath(struct inode *source, struct inode *target, struct ucred *cred)
989 {
990         struct vnode *vp;
991         int error, rootino, namlen;
992         struct dirtemplate dirbuf;
993
994         vp = ITOV(target);
995         if (target->i_number == source->i_number) {
996                 error = EEXIST;
997                 goto out;
998         }
999         rootino = ROOTINO;
1000         error = 0;
1001         if (target->i_number == rootino)
1002                 goto out;
1003
1004         for (;;) {
1005                 if (vp->v_type != VDIR) {
1006                         error = ENOTDIR;
1007                         break;
1008                 }
1009                 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1010                         sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
1011                         IO_NODELOCKED, cred, (int *)0, NULL);
1012                 if (error != 0)
1013                         break;
1014                 namlen = dirbuf.dotdot_type;    /* like ufs little-endian */
1015                 if (namlen != 2 ||
1016                     dirbuf.dotdot_name[0] != '.' ||
1017                     dirbuf.dotdot_name[1] != '.') {
1018                         error = ENOTDIR;
1019                         break;
1020                 }
1021                 if (dirbuf.dotdot_ino == source->i_number) {
1022                         error = EINVAL;
1023                         break;
1024                 }
1025                 if (dirbuf.dotdot_ino == rootino)
1026                         break;
1027                 vput(vp);
1028                 if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) != 0) {
1029                         vp = NULL;
1030                         break;
1031                 }
1032         }
1033
1034 out:
1035         if (error == ENOTDIR)
1036                 printf("checkpath: .. not a directory\n");
1037         if (vp != NULL)
1038                 vput(vp);
1039         return (error);
1040 }