Annotation of XNU/bsd/hfs/hfs_link.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: 
                     23: #if HFS_HARDLINKS
                     24: 
                     25: #include <sys/systm.h>
                     26: #include <sys/kernel.h>
                     27: #include <sys/malloc.h>
                     28: #include <sys/namei.h>
                     29: #include <sys/stat.h>
                     30: #include <sys/vnode.h>
                     31: #include <vfs/vfs_support.h>
                     32: 
                     33: #include "hfs.h"
                     34: #include "hfscommon/headers/FileMgrInternal.h"
                     35: 
                     36: 
                     37: #define OFFSETOF(structure,field) ((size_t)&((structure *) 0)->field)
                     38: 
                     39: #define MAKE_DATANODE_NAME(NAME,FID) \
                     40:            (void) sprintf((NAME), "%s%d", HFS_LINK_PREFIX, (FID))
                     41: 
                     42: 
                     43: #define ALIAS_VERS     2
                     44: #define ALIAS_TYPE     'alis'
                     45: #define ALIAS_ENDMARK  (-1)
                     46: #define ALIAS_RSRC_ID  0
                     47: 
                     48: /* alias kind is a file or directory */
                     49: enum {
                     50:        kFileAlias,             /* 0  file alias */
                     51:        kDirAlias               /* 1  directory/folder alias */
                     52: };
                     53: typedef int16_t AliasKind;
                     54: 
                     55: 
                     56: #if PRAGMA_STRUCT_ALIGN
                     57:        #pragma options align=mac68k
                     58: #elif PRAGMA_STRUCT_PACKPUSH
                     59:        #pragma pack(push, 2)
                     60: #elif PRAGMA_STRUCT_PACK
                     61:        #pragma pack(2)
                     62: #endif
                     63: 
                     64: /* Alias record as it is manipulated by Alias manager */
                     65: struct aliasrec {
                     66:        /* first two fields are for application use */
                     67:        OSType          userType;       /* appl stored type */
                     68:        u_int16_t       aliasSize;      /* alias record size in bytes */
                     69: 
                     70:        /*
                     71:         * What follows is a variable length amount of data that is
                     72:         * private.  These private fields should not be accessed by
                     73:         * apps directly.
                     74:         */
                     75:        int16_t         aliasVersion;   /* alias version, used internally */
                     76:        AliasKind       thisAliasKind;  /* file or directory */
                     77:        Str27           volumeName;     /* volume name */
                     78:        u_int32_t       volumeCrDate;   /* volume creation date used as volID */
                     79:        u_int16_t       volumeSig;      /* volume signature (flat or hierarchical) */
                     80:        int16_t         volumeType;     /* 0 = HD */
                     81:        u_int32_t       parDirID;       /* parent directory ID */
                     82:        Str63           fileName;       /* file or directory(if dir Alias) name */
                     83:        u_int32_t       fileNum;        /* unique file number(also known as file ID) or directory ID */
                     84:        u_int32_t       fileCrDate;     /* file or directory creation date */
                     85:        OSType          fileType;       /* file type */
                     86:        OSType          fdCreator;      /* file's creator */
                     87:        int16_t         nlvlFrom;       /* # of levels from fromFile/toFile until a common */
                     88:        int16_t         nlvlTo;         /* ancestor directory is found */
                     89:        u_int32_t       volumeAttr;     /* bitfield for VolMntInfo exists or not, vol ejectable or not etc. */
                     90:        int16_t         volumeFSID;     /* file system ID for the volume */
                     91:        int8_t          unused[10];     /* 10 bytes for future expansion */
                     92:        int16_t         vdwhat;         /* what kind of information */
                     93:        int16_t         vdlen;          /* length of variable data */
                     94: };
                     95: 
                     96: 
                     97: 
                     98: struct rsrcforkhdr {
                     99:        u_int32_t       rsrcDataOffset; /* Offset to the resource data from beginning of the file */
                    100:        u_int32_t       rsrcMapOffset;  /* Offset to the resource map from the beginning of the file */
                    101:        u_int32_t       rsrcDataLength; /* Total length of resource data */
                    102:        u_int32_t       rsrcMapLength;  /* Total length of resource map */
                    103: };
                    104: 
                    105: /*
                    106:    For each resource type in a resource file, the resource map contains a type entry
                    107:    which specifies the resource type, how many resources there are of this type, and
                    108:    the offset from the beginning of the type list to the reference list for this type
                    109: */
                    110: struct TypeEntry {
                    111:        ResType         tType;          /* The resource type*/
                    112:        u_int16_t       tCount;         /* Number of resources of this type, minus 1*/
                    113:        u_int16_t       tOffset;        /* Offset to resource reference list for this resource type.*/
                    114: };
                    115: typedef struct TypeEntry TypeEntry;
                    116: typedef TypeEntry *TypeEntryPtr;
                    117: /*
                    118:    For each resource in a resource file, the resource map contains a reference entry
                    119:    which specifies the resource ID, the offset to the resource�s name (if any), the
                    120:    offset to the actual resource data from the beginning of the resource data, and
                    121:    the handle to the resource data in memory, if it�s loaded.
                    122: */
                    123: 
                    124: 
                    125: union ResAttrData {
                    126:        u_int8_t        rAttr;          /* Attributes for this resource*/
                    127:        u_int32_t       rDataLocation;  /* Offset from beginning of resource data to length of data for this resource.*/
                    128: };
                    129: typedef union ResAttrData ResAttrData;
                    130: 
                    131: struct ReferenceEntry {
                    132:        int16_t         rID;            /* Resource ID*/
                    133:        int16_t         rNameOffset;    /* Offset to resource name.  (-1 if no name)*/
                    134:        ResAttrData     rAttrData;      /* Attributes or offset to length of data for this resource*/
                    135:        Handle          rHandle;        /* Resource handle.  (0 if resource is not loaded)*/
                    136: };
                    137: typedef struct ReferenceEntry ReferenceEntry;
                    138: 
                    139: /*
                    140:    The resource map describes all of the resources in a file, with a list of type entries,
                    141:    reference entries, and a list of resource names.  It also contains the file reference
                    142:    number of the resource file, and some attributes.
                    143:    I�ve split the resource map into two structs, the rsrcmaphdr, which contains
                    144:    information that is in an empty resource map (a resource map that contains no resources)
                    145:    and the rsrcmap proper, which contains fields which describe type entries, reference
                    146:    entries, and the name list.
                    147: */
                    148: 
                    149: 
                    150: struct rsrcmaphdr {
                    151:        struct rsrcforkhdr      mHeader;        /* Copy of the resource header*/
                    152:        Handle                  mNext;          /* Handle to next resource map*/
                    153:        u_int16_t               mRefNum;        /* File reference number of this resource file*/
                    154:        u_int8_t                mAttr;          /* Map attributes (read only, compact, changed)*/
                    155:        u_int8_t                mInMemoryAttr;  /* Override attributes & decompression bit*/
                    156:        u_int16_t               mTypes;         /* Offset from start of resource map to type list (typically 0x1C)*/
                    157:        u_int16_t               mNames;         /* Offset from start of resource map to name list*/
                    158: };
                    159: 
                    160: struct rsrcmap {
                    161:        struct rsrcmaphdr       mapHeader;      /* Header information for the resource map*/
                    162:        u_int16_t               typeCount;      /* Number of resource types in this map, minus 1*/
                    163:        TypeEntry               typeList[1];    /* Type entries for all the types in this resource file*/
                    164:        ReferenceEntry          refList[1];     /* Reference entries for all resources in this file*/
                    165: };
                    166: 
                    167: 
                    168: struct ResourceFork {
                    169:        struct rsrcforkhdr      rsrcHead;
                    170:        u_int8_t                reserved[240];
                    171:        u_int32_t               rsrcLen;
                    172:        struct aliasrec         rsrcData;
                    173:        struct rsrcmap          rsrcMap;
                    174: };
                    175: 
                    176: 
                    177: #if PRAGMA_STRUCT_ALIGN
                    178:        #pragma options align=reset
                    179: #elif PRAGMA_STRUCT_PACKPUSH
                    180:        #pragma pack(pop)
                    181: #elif PRAGMA_STRUCT_PACK
                    182:        #pragma pack()
                    183: #endif
                    184: 
                    185: 
                    186: /*
                    187:  *
                    188:  */
                    189: int
                    190: readlinknode(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt32 *nodeID)
                    191: {
                    192:        int result;
                    193:        struct ResourceFork *rfp = NULL;
                    194:        struct buf *bp = NULL;
                    195:        int blksize;
                    196:        daddr_t diskblk;
                    197:        off_t diskoff;
                    198: 
                    199:        *nodeID = 0;
                    200:        blksize = VCBTOHFS(vcb)->hfs_phys_block_size;
                    201:        if (catInfo->nodeData.cnd_rsrcfork.logicalSize < sizeof(struct ResourceFork))
                    202:                return (ENOENT);
                    203:        
                    204:        diskoff = vcb->hfsPlusIOPosOffset;
                    205:        diskoff += (off_t)catInfo->nodeData.cnd_rsrcfork.extents[0].startBlock * (off_t)vcb->blockSize;
                    206:        diskblk = diskoff / blksize;
                    207: 
                    208:        result = bread( VCBTOHFS(vcb)->hfs_devvp,
                    209:                        IOBLKNOFORBLK(diskblk, blksize),
                    210:                        IOBYTECCNTFORBLK(diskblk, blksize, blksize),
                    211:                        NOCRED,
                    212:                        &bp);
                    213:        if (result) {
                    214:                if (bp != NULL)
                    215:                        brelse(bp);
                    216:                return (result);
                    217:         }
                    218: 
                    219:        rfp = (struct ResourceFork *) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(diskblk, blksize));
                    220: 
                    221:        /* Make sure we have an alias record */
                    222:        if ((rfp->rsrcData.aliasSize >= sizeof(struct aliasrec))        &&
                    223:            (rfp->rsrcData.aliasVersion == ALIAS_VERS)                  &&
                    224:            (rfp->rsrcData.thisAliasKind == kFileAlias)
                    225:           ) {
                    226:                *nodeID = rfp->rsrcData.fileNum;
                    227:        } else {
                    228:                brelse(bp);
                    229:                return (ENOENT);
                    230:        }
                    231: 
                    232:        brelse(bp);
                    233: 
                    234:        return (0);
                    235: }
                    236: 
                    237: /*
                    238:  * Create a new link node
                    239:  *
                    240:  * A link node is a reference to a data node.  The only useable fields in the
                    241:  * link are the parentID, name and text encoding.  All other catalog fields
                    242:  * are ignored.  The target data node reference is stored as an alias.
                    243:  */
                    244: static int
                    245: newlinknode(struct hfsnode *dnhp, UInt32 linkPID, char *linkName, struct ucred *cred)
                    246: {
                    247:        struct hfsCatalogInfo catInfo;
                    248:        struct buf *bp = NULL;
                    249:        struct ResourceFork *rfp = NULL;
                    250:        struct FInfo *fip;
                    251:        ExtendedVCB *vcb;
                    252:        int forksize;
                    253:        u_int32_t blk, diskblk;
                    254:        u_int32_t numblk;
                    255:        u_int32_t phyblksize;
                    256:        int result;
                    257:        
                    258:        blk = numblk = 0;
                    259:        vcb = HTOVCB(dnhp);
                    260:        phyblksize = VCBTOHFS(vcb)->hfs_phys_block_size;
                    261:        forksize = sizeof(struct ResourceFork);
                    262:        if (forksize > phyblksize)
                    263:                return (EINVAL);
                    264: 
                    265:        /* Create the link node directly in the catalog */
                    266:        result = hfsCreate(vcb, linkPID, linkName, IFREG);
                    267:        if (result) return (result);
                    268: 
                    269:        /* 
                    270:         * XXX SER Here is a good example where hfsCreate should pass in a catinfo and return
                    271:         * things like the hint and file ID there should be no reason to call lookup here 
                    272:         */
                    273:        catInfo.hint = 0;
                    274:        result = hfsLookup(vcb, linkPID, linkName, -1, &catInfo);
                    275:        if (result) goto errExit;
                    276: 
                    277:        fip = (struct FInfo *)&catInfo.nodeData.cnd_finderInfo;
                    278:        fip->fdType = kHardLinkFileType;
                    279:        fip->fdCreator = kHardLinkCreator;
                    280:        fip->fdFlags |= kIsAlias + kHasBeenInited;
                    281: 
                    282:        /* Allocate space for link node's resource fork */
                    283:        result = MacToVFSError(BlockAllocate(vcb, 0, forksize, forksize, TRUE, &blk, &numblk));
                    284:        if (result) goto errExit;
                    285: 
                    286:        catInfo.nodeData.cnd_rsrcfork.extents[0].startBlock = blk;
                    287:        catInfo.nodeData.cnd_rsrcfork.extents[0].blockCount = numblk;
                    288:        catInfo.nodeData.cnd_rsrcfork.logicalSize = forksize;
                    289:        catInfo.nodeData.cnd_rsrcfork.totalBlocks = numblk;
                    290: 
                    291:        result = UpdateCatalogNode(vcb, linkPID, linkName, catInfo.hint, &catInfo.nodeData);
                    292:        if (result) goto errExit;
                    293: 
                    294:        /* map logical block to physical disk block */
                    295:        diskblk = blk * (vcb->blockSize / phyblksize) +
                    296:                        vcb->hfsPlusIOPosOffset / phyblksize;
                    297: 
                    298:        bp = getblk (VCBTOHFS(vcb)->hfs_devvp,
                    299:                     IOBLKNOFORBLK(diskblk, phyblksize),
                    300:                     IOBYTECCNTFORBLK(diskblk, phyblksize, phyblksize),
                    301:                     0, 0);
                    302:        rfp = (struct ResourceFork *) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(diskblk, phyblksize));
                    303:        bzero(rfp, phyblksize);
                    304: 
                    305:        /* fill in resource fork header... */
                    306:        rfp->rsrcHead.rsrcDataOffset = OFFSETOF(struct ResourceFork,rsrcLen);
                    307:        rfp->rsrcHead.rsrcMapOffset = OFFSETOF(struct ResourceFork,rsrcMap);
                    308:        rfp->rsrcHead.rsrcDataLength = sizeof(struct aliasrec) + 4;
                    309:        rfp->rsrcHead.rsrcMapLength = sizeof(struct rsrcmap);
                    310: 
                    311:        /* fill in resource map... */
                    312:        rfp->rsrcMap.mapHeader.mHeader = rfp->rsrcHead;
                    313:        rfp->rsrcMap.mapHeader.mTypes = sizeof(struct rsrcmaphdr);
                    314:        rfp->rsrcMap.mapHeader.mNames = sizeof(struct rsrcmap);
                    315:        rfp->rsrcMap.typeList[0].tType = ALIAS_TYPE;
                    316:        rfp->rsrcMap.typeList[0].tOffset = sizeof(TypeEntry) + 2;
                    317:        rfp->rsrcMap.refList[0].rID = ALIAS_RSRC_ID;
                    318:        rfp->rsrcMap.refList[0].rNameOffset = -1;
                    319: 
                    320:        /* fill in alias resource... */
                    321:        rfp->rsrcData.aliasSize = rfp->rsrcLen = sizeof(struct aliasrec);
                    322:        rfp->rsrcData.aliasVersion = ALIAS_VERS;
                    323:        rfp->rsrcData.thisAliasKind = kFileAlias;
                    324: //     rfp->rsrcData.fileType  = '????';
                    325: //     rfp->rsrcData.fdCreator = '????';
                    326:        rfp->rsrcData.fileNum = H_FILEID(dnhp);
                    327:        rfp->rsrcData.fileCrDate = to_hfs_time(dnhp->h_meta->h_crtime);
                    328:        rfp->rsrcData.volumeCrDate = UTCToLocal(vcb->vcbCrDate);
                    329:        rfp->rsrcData.volumeSig = kHFSSigWord;  /* always 'BD' */
                    330:        rfp->rsrcData.nlvlFrom = -1;
                    331:        rfp->rsrcData.nlvlTo = -1;
                    332:        rfp->rsrcData.vdwhat = ALIAS_ENDMARK; /* no extra data */
                    333:        
                    334:        /* XXX can this overflow volumeName field? */
                    335:        result = utf8_to_hfs(vcb, strlen(vcb->vcbVN), vcb->vcbVN, rfp->rsrcData.volumeName);
                    336:        if (result) goto errExit;
                    337: 
                    338:        rfp->rsrcData.parDirID = HTOHFS(dnhp)->hfs_private_metadata_dir;
                    339:        MAKE_DATANODE_NAME(&rfp->rsrcData.fileName[1], H_FILEID(dnhp));
                    340:        rfp->rsrcData.fileName[0] = strlen(&rfp->rsrcData.fileName[1]);
                    341: 
                    342: 
                    343:        /* Finally, write resource fork to disk */
                    344:        result = bwrite(bp);
                    345:        if (result) goto errExit;
                    346: 
                    347:        return (0);
                    348: 
                    349: errExit:
                    350:        /* get rid of link node */
                    351:        (void) hfsDelete(vcb, linkPID, linkName, TRUE, 0);
                    352:        if (numblk > 0)
                    353:                (void) BlockDeallocate(vcb, blk, numblk);
                    354: 
                    355:        return (result);
                    356: }
                    357: 
                    358: 
                    359: /*
                    360:  * 2 locks are needed (dvp and hp)
                    361:  * also need catalog lock and extents lock (for exchange)
                    362:  *
                    363:  * caller's responsibility:
                    364:  *             componentname cleanup
                    365:  *             unlocking dvp and hp
                    366:  */
                    367: static int
                    368: hfs_makelink(hp, dvp, cnp)
                    369:        struct hfsnode *hp;
                    370:        struct vnode *dvp;
                    371:        register struct componentname *cnp;
                    372: {
                    373:        struct proc *p = cnp->cn_proc;
                    374:        struct hfsnode *dhp = VTOH(dvp);
                    375:        u_int32_t ldirID;       /* directory ID of linked nodes directory */
                    376:        ExtendedVCB *vcb = VTOVCB(dvp);
                    377:        u_int32_t hint;
                    378:        char nodeName[32];
                    379:        int retval;
                    380: 
                    381:        ldirID = VTOHFS(dvp)->hfs_private_metadata_dir;
                    382: 
                    383:        /* We don't allow link nodes in our Private Meta Data folder! */
                    384:        if ( H_FILEID(dhp) == ldirID)
                    385:                return EPERM;
                    386: 
                    387:        if (vcb->freeBlocks == 0)
                    388:                return ENOSPC;
                    389: 
                    390:        /* lock catalog b-tree */
                    391:        retval = hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
                    392:        if (retval != E_NONE) goto out2;
                    393: 
                    394:        /*
                    395:         * Create a catalog entry for the new link (parentID + name).
                    396:         */
                    397:        retval = newlinknode(hp, H_FILEID(dhp), cnp->cn_nameptr, cnp->cn_cred);
                    398:        if (retval) goto out;
                    399:        
                    400:        /*
                    401:         * If this is a new hardlink then we need to create the data
                    402:         * node (inode) and replace the original file with a link node.
                    403:         */
                    404:        if (hp->h_meta->h_nlink == 1) {
                    405:                MAKE_DATANODE_NAME(nodeName, H_FILEID(hp));
                    406:                
                    407:                /* move source file to data node directory */
                    408:                hint = 0;
                    409:                retval = hfsMoveRename(vcb, H_DIRID(hp), H_NAME(hp), ldirID, nodeName, &hint);
                    410:                if (retval) goto err1Link;
                    411:                
                    412:                /* replace source file with link node */
                    413:                retval = newlinknode(hp, H_DIRID(hp), H_NAME(hp), cnp->cn_cred);
                    414:                if (retval) goto errMoved;
                    415: 
                    416:                hp->h_meta->h_nlink++;
                    417:                hp->h_nodeflags |= IN_CHANGE;
                    418:                hp->h_meta->h_metaflags |= IN_DATANODE;
                    419:        }
                    420: 
                    421: out:;
                    422:        /* unlock catalog b-tree */
                    423:        (void) hfs_metafilelocking(VTOHFS(dvp), kHFSCatalogFileID, LK_RELEASE, p);
                    424: 
                    425: out2:;
                    426:        return retval;
                    427: 
                    428: 
                    429: errMoved:;
                    430:        /* put it source file back */
                    431:        hint = 0;
                    432:        (void) hfsMoveRename(vcb, ldirID, nodeName, H_DIRID(hp), H_NAME(hp), &hint);
                    433:        /* fall through */
                    434: err1Link:;
                    435:        /* get rid of target link node */
                    436:        (void) hfsDelete(vcb, H_FILEID(dhp), cnp->cn_nameptr, TRUE, 0);
                    437:        goto out;
                    438: }
                    439: 
                    440: 
                    441: /*
                    442:  * link vnode call
                    443: #% link                vp      U U U
                    444: #% link                tdvp    L U U
                    445: #
                    446:  vop_link {
                    447:      IN WILLRELE struct vnode *vp;
                    448:      IN struct vnode *targetPar_vp;
                    449:      IN struct componentname *cnp;
                    450: 
                    451:      */
                    452: int
                    453: hfs_link(ap)
                    454: struct vop_link_args /* {
                    455:        struct vnode *a_vp;
                    456:        struct vnode *a_tdvp;
                    457:        struct componentname *a_cnp;
                    458: } */ *ap;
                    459: {
                    460:        struct vnode *vp = ap->a_vp;
                    461:        struct vnode *tdvp = ap->a_tdvp;
                    462:        struct componentname *cnp = ap->a_cnp;
                    463:        struct proc *p = cnp->cn_proc;
                    464:        struct hfsnode *hp;
                    465:        struct timeval tv;
                    466:        int error;
                    467: 
                    468: #if HFS_DIAGNOSTIC
                    469:        if ((cnp->cn_flags & HASBUF) == 0)
                    470:                panic("hfs_link: no name");
                    471: #endif
                    472:        if (tdvp->v_mount != vp->v_mount) {
                    473:                VOP_ABORTOP(tdvp, cnp);
                    474:                error = EXDEV;
                    475:                goto out2;
                    476:        }
                    477:        if (VTOVCB(tdvp)->vcbSigWord != kHFSPlusSigWord)
                    478:                return err_link(ap);    /* hfs disks don't support hard links */
                    479:        
                    480:        if (VTOHFS(vp)->hfs_private_metadata_dir == 0)
                    481:                return err_link(ap);    /* no private metadata dir, no links possible */
                    482: 
                    483:        if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
                    484:                VOP_ABORTOP(tdvp, cnp);
                    485:                goto out2;
                    486:        }
                    487:        hp = VTOH(vp);
                    488:        if (hp->h_meta->h_nlink >= HFS_LINK_MAX) {
                    489:                VOP_ABORTOP(tdvp, cnp);
                    490:                error = EMLINK;
                    491:                goto out1;
                    492:        }
                    493:        if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) {
                    494:                VOP_ABORTOP(tdvp, cnp);
                    495:                error = EPERM;
                    496:                goto out1;
                    497:        }
                    498:        hp->h_meta->h_nlink++;
                    499:        hp->h_nodeflags |= IN_CHANGE;
                    500:        tv = time;
                    501:        error = VOP_UPDATE(vp, &tv, &tv, 1);
                    502:        if (!error)
                    503:                error = hfs_makelink(hp, tdvp, cnp);
                    504:        if (error) {
                    505:                hp->h_meta->h_nlink--;
                    506:                hp->h_nodeflags |= IN_CHANGE;
                    507:        }
                    508:        FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
                    509: out1:
                    510:        if (tdvp != vp)
                    511:                VOP_UNLOCK(vp, 0, p);
                    512: out2:
                    513:        vput(tdvp);
                    514:        return (error);
                    515: }
                    516: 
                    517: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.