Annotation of kernel/bsd/hfs/hfscommon/Misc/Attributes.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:        File:           Attributes.c
        !            27: 
        !            28:        Contains:       Extended Attributes Manager
        !            29:                                Routines for managing attributes (additional catalog-like data) associated
        !            30:                                with files or folders on HFS Plus volumes.
        !            31: 
        !            32:        Version:        HFS Plus 1.0
        !            33: 
        !            34:        Copyright:      � 1997-1998 by Apple Computer, Inc., all rights reserved.
        !            35: 
        !            36:        File Ownership:
        !            37: 
        !            38:                DRI:                            Mark Day
        !            39: 
        !            40:                Other Contact:          Greg Parks
        !            41: 
        !            42:                Technology:                     HFS Plus
        !            43: 
        !            44:        Writers:
        !            45: 
        !            46:                (djb)   Don Brady
        !            47:                (DSH)   Deric Horn
        !            48:                (msd)   Mark Day
        !            49: 
        !            50:        Change History (most recent first):
        !            51:          <Rhap>         4/17/98        djb             Add VCB locking.
        !            52:          <Rhap>         3/31/98        djb             Sync up with final HFSVolumes.h header file.
        !            53: 
        !            54:          <CS13>         11/7/97        msd             Change calls to the wrapper routine CompareUnicodeNames() to use
        !            55:                                                                        the underlying routine FastUnicodeCompare() instead.
        !            56:          <CS12>        10/17/97        msd             Remove DebugStrs.
        !            57:          <CS11>        10/13/97        DSH             Added InitBTreeHeader() fileSize parameter.
        !            58:          <CS10>          9/4/97        msd             Remove unneeded/unused routines.
        !            59:           <CS9>         8/22/97        djb             Add readFromDisk flag to GetCacheBlock.
        !            60:           <CS8>         7/25/97        DSH             Pass kInvalidMRUCacheKey to BTSearchRecord as the heuristicHint.
        !            61:           <CS7>         7/24/97        djb             SetEndOfForkProc takes a refNum instead of an FCB.
        !            62:           <CS6>         7/18/97        msd             Include LowMemPriv.h.
        !            63:           <CS5>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
        !            64:                                                                        collision
        !            65:           <CS4>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
        !            66:           <CS3>          6/2/97        DSH             On creation make sure we call through the SetEndOfFileProc so
        !            67:                                                                        the AlternateVolumeHeader is updated.
        !            68:           <CS2>         5/28/97        msd             Change keys to {cnid, flags, creator, selector}. Prototype an
        !            69:                                                                        SPI for testing.
        !            70:           <CS1>         4/24/97        djb             first checked in
        !            71:          <HFS5>         4/10/97        msd             In PropertyDeleteObject, use the global buffer instead of an
        !            72:                                                                        automatic variable.
        !            73:          <HFS4>          4/8/97        msd             Add AttributesOpenVolume to allocate appropriate buffer space.
        !            74:          <HFS3>          4/7/97        msd             Start adding real code. Removed PropertyOpenVolume; that code
        !            75:                                                                        now resides in Volumes.c.
        !            76:          <HFS2>         3/17/97        DSH             SC needs parameters to the stub functions.
        !            77:          <HFS1>          3/5/97        msd             first checked in
        !            78: */
        !            79: 
        !            80: /*
        !            81: Public routines:
        !            82:        AttributesCloseVolume
        !            83:                                Clean up and finalize for a given volume.  Close a property database
        !            84:                                file if needed.  In general, clean up after PropertyOpenVolume.
        !            85:                                This routine should be called before closing the Catalog and Extents
        !            86:                                files on the volume.
        !            87: */
        !            88: 
        !            89: #if ( PRAGMA_LOAD_SUPPORTED )
        !            90:         #pragma        load    PrecompiledHeaders
        !            91: #else
        !            92:        #if TARGET_OS_MAC
        !            93:                #include <Types.h>
        !            94:                #include <LowMemPriv.h>
        !            95:        #else
        !            96:                #include "../headers/system/MacOSStubs.h"
        !            97:        #endif  /* TARGET_OS_MAC */
        !            98: #endif /* PRAGMA_LOAD_SUPPORTED */
        !            99: 
        !           100: #include "../headers/HFSVolumes.h"
        !           101: #include "../headers/FileMgrInternal.h"
        !           102: #include "../headers/BTreesInternal.h"
        !           103: #include "../headers/HFSBtreesPriv.h"
        !           104: #include "../headers/system/HFSUnicodeWrappers.h"
        !           105: 
        !           106: #if HFSInstrumentation
        !           107:         #include "Instrumentation.h"
        !           108: #endif
        !           109: 
        !           110: #define min(x,y)       ((x < y) ? x : y)
        !           111: 
        !           112: //
        !           113: //     Values for flags in AttributesKey.flags
        !           114: //
        !           115: enum {
        !           116:        kAttributeNodeSize              = 4096                  // Size of our Btree node
        !           117: };
        !           118: 
        !           119: 
        !           120: #if TARGET_OS_MAC
        !           121: OSErr AttributesCloseVolume(ExtendedVCB *              vcb)
        !           122: {
        !           123:        OSErr   err;
        !           124:        
        !           125:        err = noErr;
        !           126:        
        !           127:        if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->attributesRefNum != 0) {
        !           128:                err = CloseFile( vcb, vcb->attributesRefNum, LMGetFCBSPtr() );
        !           129:                vcb->attributesRefNum = 0;
        !           130:        }
        !           131:        
        !           132:        return err;
        !           133: }
        !           134: #endif /* TARGET_OS_MAC */
        !           135: 
        !           136: SInt32 CompareAttributeKeys( const void *inSearchKey, const void *inTrialKey )
        !           137: {
        !           138:        const AttributeKey *searchKey   = inSearchKey;
        !           139:        const AttributeKey *trialKey    = inTrialKey;
        !           140:        SInt32                          temp;
        !           141:                
        !           142:        //
        !           143:        //      First, compare the CNID's
        !           144:        //
        !           145:        if (searchKey->cnid != trialKey->cnid) {
        !           146:                return searchKey->cnid < trialKey->cnid ? -1 : 1;
        !           147:        }
        !           148: 
        !           149:        //
        !           150:        //      CNID's are equal; compare names
        !           151:        //
        !           152:        if (searchKey->attributeName.length == 0 || trialKey->attributeName.length == 0)
        !           153:                return searchKey->attributeName.length < trialKey->attributeName.length ? -1 : 1;
        !           154:        temp = FastUnicodeCompare(&searchKey->attributeName.unicode[0], searchKey->attributeName.length,
        !           155:                                                          &trialKey->attributeName.unicode[0], trialKey->attributeName.length);
        !           156:        if (temp != 0)
        !           157:                return temp;
        !           158: 
        !           159:        //
        !           160:        //      Names are equal; compare startBlock
        !           161:        //
        !           162:        if (searchKey->startBlock == trialKey->startBlock)
        !           163:                return 0;
        !           164:        else
        !           165:                return searchKey->startBlock < trialKey->startBlock ? -1 : 1;
        !           166: }
        !           167: 
        !           168: 
        !           169: #if TARGET_OS_MAC
        !           170: static OSErr CreateAndOpenBtree(ExtendedVCB *vcb)
        !           171: {
        !           172:        OSStatus                err;
        !           173:        UInt16                  refnum;                         //      attribute file's refnum
        !           174:        Ptr                             fcbHeader;                      //      points to start of FCBs (unused)
        !           175:        FCB                             *fcb;                           //      attribute file's FCB
        !           176:        ExtendedFCB             *extendedFCB;           //      attribute file's extended FCB
        !           177:        UInt32                  clumpSize;
        !           178:        UInt32                  mapNodes;
        !           179:        LogicalAddress  header;
        !           180:        Boolean                 readFromDisk;
        !           181:        
        !           182:        clumpSize = 32 * vcb->blockSize;                        //�� Need a better value.
        !           183: 
        !           184:     // Find a free FCB for the attributes file
        !           185: #if TARGET_OS_MAC
        !           186:        err = FindFileControlBlock(&refnum, &fcbHeader);
        !           187: #else  /* TARGET_OS_MAC */
        !           188:     err = GetNewFCB(vcb, &refnum );
        !           189: #endif /* TARGET_OS_MAC */
        !           190: 
        !           191:        ReturnIfError(err);
        !           192: //     fcb = GetFileControlBlock(refnum);
        !           193:        fcb = SetupFCB(vcb, refnum, kHFSAttributesFileID, clumpSize);
        !           194: 
        !           195:        //      Mark file as empty.
        !           196:        fcb->fcbEOF = 0;
        !           197:        fcb->fcbPLen = 0;
        !           198:        vcb->attributesRefNum = refnum;
        !           199:        ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
        !           200: /* XXX PPD: Is there any reason this isn't the same for EVERY platform? */
        !           201: #if TARGET_OS_MAC
        !           202:        extendedFCB = ParallelFCBFromRefnum( refnum );
        !           203: #else
        !           204:        extendedFCB = GetParallelFCB( refnum );
        !           205: #endif
        !           206:        ClearMemory( (Ptr)extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
        !           207: 
        !           208:        //      Allocate some space to the file
        !           209:        err = SetEndOfForkProc(refnum, clumpSize, clumpSize);
        !           210:        if (err) {
        !           211:                ClearMemory(fcb, sizeof(FCB));
        !           212:                goto ErrorExit;
        !           213:        }
        !           214:        fcb->fcbEOF = fcb->fcbPLen;             // grow the file to include the allocated space
        !           215:        
        !           216:        //      Initialize the b-tree.  Write out the header.
        !           217:        err = GetCacheBlock(refnum, 0, kAttributeNodeSize, gbDefault, &header, &readFromDisk);
        !           218:        ClearMemory(header, kAttributeNodeSize);
        !           219:        InitBTreeHeader(fcb->fcbEOF, clumpSize, kAttributeNodeSize, 0, kAttributeKeyMaximumLength, kBTBigKeysMask, &mapNodes, header);
        !           220:        err = ReleaseCacheBlock(header, rbWriteMask);
        !           221:        
        !           222:        //      Finally, prepare for using the B-tree           
        !           223:        err = OpenBTree( refnum, (KeyCompareProcPtr) CompareAttributeKeys );
        !           224:        if (err) {
        !           225:                ClearMemory(fcb, sizeof(FCB));
        !           226:                goto ErrorExit;
        !           227:        }
        !           228:        
        !           229:        //�� Should we update the volume header and alternate volume header?
        !           230: 
        !           231: ErrorExit:     
        !           232:        return err;
        !           233: }
        !           234: #endif /* #if TARGET_OS_MAC */
        !           235: 
        !           236: #if TARGET_OS_MAC
        !           237: static OSErr PreflightAttributeCall(AttributeParam *pb, FindFileNameGlueRec *fileInfo, Boolean needsWrite)
        !           238: {
        !           239:        OSErr                           err;
        !           240:        ExtendedVCB                     *vcb;
        !           241: 
        !           242:        //
        !           243:        //      See if the file exists.  Get its FileID.
        !           244:        //
        !           245:        err = FindFileName((ParamBlockRec *) pb, fileInfo);
        !           246:        ReturnIfError( err );
        !           247:        
        !           248:        //
        !           249:        //      Make sure the volume is on-line and writable.
        !           250:        //
        !           251:        vcb = fileInfo->vcb;
        !           252:        
        !           253:        if (needsWrite) {
        !           254:                err = VolumeWritable( vcb );
        !           255:                ReturnIfError( err );
        !           256:        }
        !           257:        
        !           258:        err = CheckVolumeOffLine( vcb );
        !           259:        ReturnIfError( err );
        !           260:        
        !           261:        //
        !           262:        //      And make sure it is HFS Plus.
        !           263:        //
        !           264:        if (vcb->vcbSigWord != kHFSPlusSigWord)
        !           265:                return wrgVolTypErr;
        !           266:        
        !           267:        //
        !           268:        //��    Make sure there is an attribute file.  Create and open it if needed.
        !           269:        //
        !           270:        if (vcb->attributesRefNum == 0) {
        !           271:                
        !           272:                if (needsWrite == false)                //      If we only wanted to read,
        !           273:                        return notBTree;                        //      tell caller there is no b-tree
        !           274:                //
        !           275:                //      Create and open b-tree
        !           276:                //
        !           277:                err = CreateAndOpenBtree(vcb);
        !           278:        }
        !           279:        
        !           280:        return err;
        !           281: }
        !           282: #endif /* TARGET_OS_MAC */
        !           283: 
        !           284: 
        !           285: #if TARGET_OS_MAC
        !           286: OSErr CreateAttribute(AttributeParam *pb)
        !           287: {
        !           288:        OSErr                           err;
        !           289:        ExtendedVCB                     *vcb;
        !           290:        UInt32                          length;
        !           291:        UInt32                          numberOfExtents;
        !           292:        UInt32                          i,extentsThisRecord;
        !           293:        UInt32                          blocksAllocated = 0;
        !           294:        UInt32                          hint;
        !           295:        AttributeKey            key;
        !           296:        FindFileNameGlueRec     fileInfo;
        !           297: 
        !           298:        err = PreflightAttributeCall(pb, &fileInfo, true);
        !           299:        ReturnIfError( err );
        !           300:        
        !           301:        vcb = fileInfo.vcb;
        !           302:        
        !           303:        //
        !           304:        //      Set up the first key
        !           305:        //
        !           306:        length = sizeof(UniChar) * (pb->ioAttributeName->length+1);             // length in bytes of Unicode name
        !           307: 
        !           308:        key.keyLength   = length + offsetof(AttributeKey, attributeName);
        !           309:        key.pad                 = 0;
        !           310:        key.cnid                = fileInfo.data->nodeID;
        !           311:        key.startBlock  = 0;
        !           312:        BlockMoveData(pb->ioAttributeName, &key.attributeName, length); // copy attributeName
        !           313:        
        !           314:        //
        !           315:        //      Determine the first record type based on the number of extents
        !           316:        //
        !           317:        numberOfExtents = pb->filler1;
        !           318:        if (numberOfExtents == 0) {
        !           319:                AttributeInlineData             record;
        !           320:                
        !           321:                record.recordType = kAttributeInlineData;
        !           322:                record.logicalSize = 0;
        !           323:                length = offsetof(AttributeInlineData, userData);
        !           324:                err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, length, &hint);
        !           325:        }
        !           326:        else {
        !           327:                {
        !           328:                        AttributeForkData               record;
        !           329:                        
        !           330:                        //      Set up first record, with ForkData
        !           331:                        ClearMemory(&record, sizeof(record));
        !           332:                        record.recordType                               = kAttributeForkData;
        !           333:                        record.theFork.logicalSize.lo   = numberOfExtents * vcb->blockSize;             // each extent is one block
        !           334:                        record.theFork.logicalSize.hi   = 0;
        !           335:                        record.theFork.clumpSize                = vcb->attributesClumpSize;
        !           336:                        record.theFork.totalBlocks              = numberOfExtents;                                              // one block per extent
        !           337:                        extentsThisRecord = min(numberOfExtents, kHFSPlusExtentDensity);
        !           338:                        for (i=0; i<extentsThisRecord; i++) {
        !           339:                                err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, 1, &record.theFork.extents[i].startBlock,
        !           340:                                                                                                                                        &record.theFork.extents[i].blockCount);
        !           341:                                ReturnIfError(err);
        !           342:                                ++blocksAllocated;
        !           343:                        }
        !           344:                        err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, sizeof(record), &hint);
        !           345:                        ReturnIfError(err);
        !           346:                }
        !           347:                
        !           348:                {
        !           349:                        AttributeExtents                record;
        !           350:                        
        !           351:                        //      Handle overflow extent records
        !           352:                        ClearMemory(&record, sizeof(record));
        !           353:                        numberOfExtents -= extentsThisRecord;
        !           354:                        record.recordType       = kAttributeExtents;
        !           355:                        while (numberOfExtents) {
        !           356:                                extentsThisRecord = min(numberOfExtents, kHFSPlusExtentDensity);
        !           357:                                key.startBlock += kHFSPlusExtentDensity;
        !           358:                                for (i=0; i<extentsThisRecord; i++) {
        !           359:                                        err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, 1, &record.extents[i].startBlock,
        !           360:                                                                                                                                                &record.extents[i].blockCount);
        !           361:                                        ReturnIfError(err);
        !           362:                                        ++blocksAllocated;
        !           363:                                }
        !           364:                                for (; i<kHFSPlusExtentDensity; i++) {
        !           365:                                        record.extents[i].startBlock = 0;
        !           366:                                        record.extents[i].blockCount = 0;
        !           367:                                }
        !           368:                                err = InsertBTreeRecord(vcb->attributesRefNum, &key, &record, sizeof(record), &hint);
        !           369:                                ReturnIfError(err);
        !           370:                                numberOfExtents -= extentsThisRecord;
        !           371:                        }
        !           372:                }
        !           373:        }
        !           374:        
        !           375:        if (blocksAllocated) {
        !           376:                VCB_LOCK(vcb);
        !           377:                vcb->freeBlocks -= blocksAllocated;
        !           378:                VCB_UNLOCK(vcb);
        !           379:                UpdateVCBFreeBlks( vcb );
        !           380:                MarkVCBDirty(vcb);
        !           381:        }
        !           382:        
        !           383:        if (err == fsBTDuplicateRecordErr)
        !           384:                err = btDupRecErr;
        !           385:                        
        !           386:        return err;
        !           387: }
        !           388: #endif /* TARGET_OS_MAC */

unix.superglobalmegacorp.com

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