Annotation of XNU/bsd/hfs/hfs_link.c, revision 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.