~ubuntu-branches/debian/jessie/ufsutils/jessie

« back to all changes in this revision

Viewing changes to include/ufs/ufs/ufs_lookup.c

  • Committer: Bazaar Package Importer
  • Author(s): Aurelien Jarno, Petr Salinger, Aurelien Jarno
  • Date: 2010-04-13 22:20:32 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20100413222032-je6xhqdvomf3yrj2
Tags: 7.3-1
[ Petr Salinger ]
* New upstream version (RELENG_7_3_0_RELEASE)
* Use intmax_t cast in fsbtodb() to fix aborts when 
  making a filesystem larger than one terabyte. Closes: #559647.

[ Aurelien Jarno ]
* Bump Standard-Versions to 3.8.4 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 */
36
36
 
37
37
#include <sys/cdefs.h>
38
 
__FBSDID("$FreeBSD: src/sys/ufs/ufs/ufs_lookup.c,v 1.83.2.5.2.1 2009/04/15 03:14:26 kensmith Exp $");
 
38
__FBSDID("$FreeBSD: src/sys/ufs/ufs/ufs_lookup.c,v 1.83.2.8.2.1 2010/02/10 00:26:20 kensmith Exp $");
39
39
 
40
40
#include "opt_ffs_broken_fixme.h"
41
41
#include "opt_ufs.h"
77
77
/* true if old FS format...*/
78
78
#define OFSFMT(vp)      ((vp)->v_mount->mnt_maxsymlinklen <= 0)
79
79
 
 
80
static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *,
 
81
    ino_t *);
 
82
 
80
83
/*
81
84
 * Convert a component of a pathname into a pointer to a locked inode.
82
85
 * This is a very central and rather complicated routine.
130
133
                struct componentname *a_cnp;
131
134
        } */ *ap;
132
135
{
133
 
        struct vnode *vdp;              /* vnode for directory being searched */
 
136
 
 
137
        return (ufs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
 
138
}
 
139
 
 
140
static int
 
141
ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
 
142
    ino_t *dd_ino)
 
143
{
134
144
        struct inode *dp;               /* inode for directory being searched */
135
145
        struct buf *bp;                 /* a buffer of directory entries */
136
146
        struct direct *ep;              /* the current directory entry */
150
160
        doff_t enduseful;               /* pointer past last used dir slot */
151
161
        u_long bmask;                   /* block offset mask */
152
162
        int namlen, error;
153
 
        struct vnode **vpp = ap->a_vpp;
154
 
        struct componentname *cnp = ap->a_cnp;
155
163
        struct ucred *cred = cnp->cn_cred;
156
164
        int flags = cnp->cn_flags;
157
165
        int nameiop = cnp->cn_nameiop;
158
166
        struct thread *td = cnp->cn_thread;
159
 
        ino_t ino;
 
167
        ino_t ino, ino1;
160
168
        int ltype;
161
169
 
162
 
        bp = NULL;
163
 
        slotoffset = -1;
164
 
/*
165
 
 *  XXX there was a soft-update diff about this I couldn't merge.
166
 
 * I think this was the equiv.
167
 
 */
168
 
        *vpp = NULL;
 
170
        if (vpp != NULL)
 
171
                *vpp = NULL;
169
172
 
170
 
        vdp = ap->a_dvp;
171
173
        dp = VTOI(vdp);
172
174
 
173
175
        /*
178
180
         */
179
181
        vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread);
180
182
 
 
183
        bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 
184
 
 
185
restart:
 
186
        bp = NULL;
 
187
        slotoffset = -1;
 
188
 
181
189
        /*
182
190
         * We now have a segment name to search for, and a directory to search.
183
191
         *
195
203
                slotstatus = NONE;
196
204
                slotneeded = DIRECTSIZ(cnp->cn_namelen);
197
205
        }
198
 
        bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
199
206
 
200
207
#ifdef UFS_DIRHASH
201
208
        /*
364
371
                                        slotoffset = i_offset;
365
372
                                        slotsize = ep->d_reclen;
366
373
                                        enduseful = dp->i_size;
367
 
                                        ap->a_cnp->cn_flags |= ISWHITEOUT;
 
374
                                        cnp->cn_flags |= ISWHITEOUT;
368
375
                                        numdirpasses--;
369
376
                                        goto notfound;
370
377
                                }
398
405
         */
399
406
        if ((nameiop == CREATE || nameiop == RENAME ||
400
407
             (nameiop == DELETE &&
401
 
              (ap->a_cnp->cn_flags & DOWHITEOUT) &&
402
 
              (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
 
408
              (cnp->cn_flags & DOWHITEOUT) &&
 
409
              (cnp->cn_flags & ISWHITEOUT))) &&
403
410
            (flags & ISLASTCN) && dp->i_effnlink != 0) {
404
411
                /*
405
412
                 * Access for write is interpreted as allowing
454
461
         * Insert name into cache (as non-existent) if appropriate.
455
462
         */
456
463
        if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
457
 
                cache_enter(vdp, *vpp, cnp);
 
464
                cache_enter(vdp, NULL, cnp);
458
465
        return (ENOENT);
459
466
 
460
467
found:
480
487
        if ((flags & ISLASTCN) && nameiop == LOOKUP)
481
488
                dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
482
489
 
 
490
        if (dd_ino != NULL) {
 
491
                *dd_ino = ino;
 
492
                return (0);
 
493
        }
 
494
 
483
495
        /*
484
496
         * If deleting, and at end of pathname, return
485
497
         * parameters which can be used to remove file.
581
593
                error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp);
582
594
                if (error)
583
595
                        return (error);
 
596
 
 
597
                /*
 
598
                 * Recheck that ".." entry in the vdp directory points
 
599
                 * to the inode we looked up before vdp lock was
 
600
                 * dropped.
 
601
                 */
 
602
                error = ufs_lookup_(pdp, NULL, cnp, &ino1);
 
603
                if (error) {
 
604
                        vput(tdp);
 
605
                        return (error);
 
606
                }
 
607
                if (ino1 != ino) {
 
608
                        vput(tdp);
 
609
                        goto restart;
 
610
                }
 
611
 
584
612
                *vpp = tdp;
585
613
        } else if (dp->i_number == ino) {
586
614
                VREF(vdp);      /* we want ourself, ie "." */
1210
1238
        return (1);
1211
1239
}
1212
1240
 
 
1241
static int
 
1242
ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino)
 
1243
{
 
1244
        struct dirtemplate dirbuf;
 
1245
        int error, namlen;
 
1246
 
 
1247
        if (vp->v_type != VDIR)
 
1248
                return (ENOTDIR);
 
1249
        error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
 
1250
            sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
 
1251
            IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL);
 
1252
        if (error != 0)
 
1253
                return (error);
 
1254
#if (BYTE_ORDER == LITTLE_ENDIAN)
 
1255
        if (OFSFMT(vp))
 
1256
                namlen = dirbuf.dotdot_type;
 
1257
        else
 
1258
                namlen = dirbuf.dotdot_namlen;
 
1259
#else
 
1260
        namlen = dirbuf.dotdot_namlen;
 
1261
#endif
 
1262
        if (namlen != 2 || dirbuf.dotdot_name[0] != '.' ||
 
1263
            dirbuf.dotdot_name[1] != '.')
 
1264
                return (ENOTDIR);
 
1265
        *dd_ino = dirbuf.dotdot_ino;
 
1266
        return (0);
 
1267
}
 
1268
 
1213
1269
/*
1214
1270
 * Check if source directory is in the path of the target directory.
1215
1271
 * Target is supplied locked, source is unlocked.
1216
1272
 * The target is always vput before returning.
1217
1273
 */
1218
1274
int
1219
 
ufs_checkpath(source, target, cred)
1220
 
        struct inode *source, *target;
1221
 
        struct ucred *cred;
 
1275
ufs_checkpath(ino_t source_ino, struct inode *target, struct ucred *cred)
1222
1276
{
1223
 
        struct vnode *vp;
1224
 
        int error, namlen;
1225
 
        ino_t rootino;
1226
 
        struct dirtemplate dirbuf;
 
1277
        struct vnode *vp, *vp1;
 
1278
        int error;
 
1279
        ino_t dd_ino;
1227
1280
 
1228
1281
        vp = ITOV(target);
1229
 
        if (target->i_number == source->i_number) {
 
1282
        if (target->i_number == source_ino) {
1230
1283
                error = EEXIST;
1231
1284
                goto out;
1232
1285
        }
1233
 
        rootino = ROOTINO;
1234
1286
        error = 0;
1235
 
        if (target->i_number == rootino)
 
1287
        if (target->i_number == ROOTINO)
1236
1288
                goto out;
1237
1289
 
1238
1290
        for (;;) {
1239
 
                if (vp->v_type != VDIR) {
1240
 
                        error = ENOTDIR;
1241
 
                        break;
1242
 
                }
1243
 
                error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1244
 
                        sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
1245
 
                        IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, (int *)0,
1246
 
                        (struct thread *)0);
 
1291
                error = ufs_dir_dd_ino(vp, cred, &dd_ino);
1247
1292
                if (error != 0)
1248
1293
                        break;
1249
 
#               if (BYTE_ORDER == LITTLE_ENDIAN)
1250
 
                        if (OFSFMT(vp))
1251
 
                                namlen = dirbuf.dotdot_type;
1252
 
                        else
1253
 
                                namlen = dirbuf.dotdot_namlen;
1254
 
#               else
1255
 
                        namlen = dirbuf.dotdot_namlen;
1256
 
#               endif
1257
 
                if (namlen != 2 ||
1258
 
                    dirbuf.dotdot_name[0] != '.' ||
1259
 
                    dirbuf.dotdot_name[1] != '.') {
1260
 
                        error = ENOTDIR;
1261
 
                        break;
1262
 
                }
1263
 
                if (dirbuf.dotdot_ino == source->i_number) {
 
1294
                if (dd_ino == source_ino) {
1264
1295
                        error = EINVAL;
1265
1296
                        break;
1266
1297
                }
1267
 
                if (dirbuf.dotdot_ino == rootino)
1268
 
                        break;
 
1298
                if (dd_ino == ROOTINO)
 
1299
                        break;
 
1300
                error = vn_vget_ino(vp, dd_ino, LK_EXCLUSIVE, &vp1);
 
1301
                if (error != 0)
 
1302
                        break;
 
1303
                /* Recheck that ".." still points to vp1 after relock of vp */
 
1304
                error = ufs_dir_dd_ino(vp, cred, &dd_ino);
 
1305
                if (error != 0) {
 
1306
                        vput(vp1);
 
1307
                        break;
 
1308
                }
 
1309
                /* Redo the check of ".." if directory was reparented */
 
1310
                if (dd_ino != VTOI(vp1)->i_number) {
 
1311
                        vput(vp1);
 
1312
                        continue;
 
1313
                }
1269
1314
                vput(vp);
1270
 
                error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino,
1271
 
                    LK_EXCLUSIVE, &vp);
1272
 
                if (error) {
1273
 
                        vp = NULL;
1274
 
                        break;
1275
 
                }
 
1315
                vp = vp1;
1276
1316
        }
1277
1317
 
1278
1318
out: