2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* @(#)MacOSStubs.c 4.0
24 * (c) 1997-1999 Apple Computer, Inc. All Rights Reserved
26 * MacOSStubs.c -- Contains routines called by MacOS code, that is not defined.
29 * 9-9-99 Don Brady Don't use MNT_WAIT in C_FlushMDB.
30 * 9-Mar-1999 Don Brady Remove more obsolete routines, add ClearMemory(bzero).
31 * 20-Nov-1998 Don Brady Remove UFSToHFSStr and HFSToUFSStr routines (obsolete).
32 * 31-Aug-1998 Don Brady Move DST adjustments to GetTimeLocal (radar #2265075).
33 * 28-Jul-1998 Don Brady Add GetDiskBlocks routine (radar #2258148).
34 * 23-Jul-1998 Don Brady Use bdwrite instead of bwrite for default in RelBlock_glue (radar #2257225).
35 * 7-Jul-1998 Don Brady Remove character mappings from/to hfs (ufs_hfs and hfs_ufs tables).
36 * 22-Jun-1998 Pat Dirks Added the vice versa mappings in ufs_hfs and hfs_ufs to more
37 * thoroughly interchange ":" and "/" in name strings.
38 * 4-Jun-1998 Pat Dirks Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1)
39 * 4-jun-1998 Don Brady Use VPUT macro instead of vput.
40 * 6-may-1998 Don Brady Bump h_devvp refcount in GetInitializedVNode (radar #2232480).
41 * 27-apr-1998 Don Brady Change printf to kprintf.
42 * 23-Apr-1998 Pat Dirks Cleaned up GetBlock_glue to add brelse on I/O errors from bread.
43 * 23-apr-1998 Don Brady Add '/' to ':' mapping and vice versa to mapping tables.
44 * 21-apr-1998 Don Brady Clean up time/date conversion routines.
45 * 11-apr-1998 Don Brady Add RequireFileLock routine.
46 * 8-apr-1998 Don Brady C_FlushMDB now calls hfs_flushvolumeheader and hfs_flushMDB.
47 * 12-nov-1997 Scott Roberts
48 * Initially created file.
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/vnode.h>
56 #include <sys/malloc.h>
57 #include <sys/mount.h>
58 #include <sys/types.h>
66 #include "hfscommon/headers/FileMgrInternal.h"
68 extern int (**hfs_vnodeop_p
)(void *);
72 * gTimeZone should only be used for HFS volumes!
73 * It is initialized when an HFS volume is mounted.
75 struct timezone gTimeZone
= {8*60,1};
78 /*************************************************************************************/
80 /*************************************************************************************/
82 * The following two routines work in tandem: StoreBufferMapping stores
83 * successive buffer address -> buffer pointer mappings in a circular
84 * match list, advancing the list index forward each time, while LookupBufferMapping
85 * looks backwards through the list to look up a particular mapping (which is
86 * typically the entry currently pointed to by gBufferAddress).
89 static void StoreBufferMapping(caddr_t bufferAddress
, struct buf
*bp
)
93 DBG_ASSERT(gBufferListIndex
>= 0);
94 DBG_ASSERT(gBufferListIndex
< BUFFERPTRLISTSIZE
);
96 simple_lock(&gBufferPtrListLock
);
98 /* We've got at most BUFFERPTRLISTSIZE tries at this... */
99 for (i
= BUFFERPTRLISTSIZE
; i
> 0; --i
) {
100 if (gBufferAddress
[gBufferListIndex
] == NULL
) {
101 gBufferAddress
[gBufferListIndex
] = bufferAddress
;
102 gBufferHeaderPtr
[gBufferListIndex
] = bp
;
105 gBufferListIndex
= (gBufferListIndex
+ 1) % BUFFERPTRLISTSIZE
;
109 panic("StoreBufferMapping: couldn't find an empty slot in buffer list.");
112 DBG_ASSERT(gBufferListIndex
>= 0);
113 DBG_ASSERT(gBufferListIndex
< BUFFERPTRLISTSIZE
);
115 simple_unlock(&gBufferPtrListLock
);
119 /*static*/ OSErr
LookupBufferMapping(caddr_t bufferAddress
, struct buf
**bpp
, int *mappingIndexPtr
)
123 int listIndex
= gBufferListIndex
;
124 struct buf
*bp
= NULL
;
126 DBG_ASSERT(gBufferListIndex
>= 0);
127 DBG_ASSERT(gBufferListIndex
< BUFFERPTRLISTSIZE
);
129 simple_lock(&gBufferPtrListLock
);
131 /* We've got at most BUFFERPTRLISTSIZE tries at this... */
132 for (i
= BUFFERPTRLISTSIZE
; i
> 0; --i
) {
133 if (gBufferAddress
[listIndex
] == bufferAddress
) {
134 *mappingIndexPtr
= listIndex
;
135 bp
= gBufferHeaderPtr
[listIndex
];
139 listIndex
= (listIndex
- 1);
141 listIndex
= BUFFERPTRLISTSIZE
- 1;
146 DEBUG_BREAK_MSG(("LookupBufferMapping: couldn't find buffer header for buffer in list.\n"));
150 DBG_ASSERT(gBufferListIndex
>= 0);
151 DBG_ASSERT(gBufferListIndex
< BUFFERPTRLISTSIZE
);
153 simple_unlock(&gBufferPtrListLock
);
160 static void ReleaseMappingEntry(int entryIndex
) {
162 DBG_ASSERT(gBufferListIndex
>= 0);
163 DBG_ASSERT(gBufferListIndex
< BUFFERPTRLISTSIZE
);
165 simple_lock(&gBufferPtrListLock
);
166 gBufferAddress
[entryIndex
] = NULL
;
167 simple_unlock(&gBufferPtrListLock
);
170 #define DBG_GETBLOCK 0
172 #define DBG_GETBLOCK 0
175 OSErr
GetBlock_glue (UInt16 options
, UInt32 blockNum
, Ptr
*baddress
, FileReference fileRefNum
, ExtendedVCB
* vcb
)
178 struct buf
*bp
= NULL
;
182 DBG_IO(("Getting block %ld with options %d and a refnum of %x\n", blockNum
, options
, fileRefNum
));
185 if ((options
& ~(gbReadMask
| gbNoReadMask
)) != 0) {
186 DEBUG_BREAK_MSG(("GetBlock_glue: options = 0x%04X.\n", options
));
191 if (options
& gbNoReadMask
) {
192 if (fileRefNum
== NULL
) {
193 bp
= getblk (VCBTOHFS(vcb
)->hfs_devvp
,
194 IOBLKNOFORBLK(blockNum
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
195 IOBYTECCNTFORBLK(blockNum
, kHFSBlockSize
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
200 bp
= getblk (fileRefNum
,
201 IOBLKNOFORBLK(blockNum
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
202 IOBYTECCNTFORBLK(blockNum
, kHFSBlockSize
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
210 if (fileRefNum
== NULL
) {
211 status
= meta_bread (VCBTOHFS(vcb
)->hfs_devvp
,
212 IOBLKNOFORBLK(blockNum
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
213 IOBYTECCNTFORBLK(blockNum
, kHFSBlockSize
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
217 status
= meta_bread (fileRefNum
,
218 IOBLKNOFORBLK(blockNum
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
219 IOBYTECCNTFORBLK(blockNum
, kHFSBlockSize
, VCBTOHFS(vcb
)->hfs_phys_block_size
),
223 if (status
!= E_NONE
) {
235 if ((options
& gbReadMask
) && (bp
->b_flags
& B_CACHE
)) {
236 /* Rats! The block was found in the cache just when we really wanted a
237 fresh copy off disk...
239 if (bp
->b_flags
& B_DIRTY
) {
240 DEBUG_BREAK_MSG(("GetBlock_glue: forced read for dirty block!\n"))
242 bp
->b_flags
|= B_INVAL
;
245 /* Fall through and try again until we get a fresh copy from the disk... */
247 } while (((options
& gbReadMask
) != 0) && (readcount
<= 1));
250 *baddress
= bp
->b_data
+ IOBYTEOFFSETFORBLK(bp
->b_blkno
, VCBTOHFS(vcb
)->hfs_phys_block_size
);
251 StoreBufferMapping(*baddress
, bp
);
257 void MarkBlock_glue (Ptr address
)
260 struct buf
*bp
= NULL
;
263 if ((err
= LookupBufferMapping(address
, &bp
, &mappingEntry
))) {
264 panic("Failed to find buffer pointer for buffer in MarkBlock_glue.");
266 bp
->b_flags
|= B_DIRTY
;
270 OSErr
RelBlock_glue (Ptr address
, UInt16 options
)
276 if (options
& ~(rbTrashMask
| rbDirtyMask
| rbWriteMask
) == 0) {
277 DEBUG_BREAK_MSG(("RelBlock_glue: options = 0x%04X.\n", options
));
280 if ((err
= LookupBufferMapping(address
, &bp
, &mappingEntry
))) {
281 DEBUG_BREAK_MSG(("Failed to find buffer pointer for buffer in RelBlock_glue.\n"));
283 if (bp
->b_flags
& B_DIRTY
) {
284 /* The buffer was previously marked dirty (using MarkBlock_glue):
285 now's the time to write it. */
286 options
|= rbDirtyMask
;
288 ReleaseMappingEntry(mappingEntry
);
289 if (options
& rbTrashMask
) {
290 bp
->b_flags
|= B_INVAL
;
293 if (options
& (rbDirtyMask
| rbWriteMask
)) {
294 bp
->b_flags
|= B_DIRTY
;
295 if (options
& rbWriteMask
) {
310 /* Creates a new vnode to hold a psuedo file like an extents tree file */
313 OSStatus
GetInitializedVNode(struct hfsmount
*hfsmp
, struct vnode
**tmpvnode
, int init_ubc
)
317 struct vnode
*vp
= NULL
;
320 DBG_ASSERT(hfsmp
!= NULL
);
321 DBG_ASSERT(tmpvnode
!= NULL
);
323 /* Allocate a new hfsnode. */
325 * Must do malloc() before getnewvnode(), since malloc() can block
326 * and could cause other part of the system to access v_data
327 * which has not been initialized yet
329 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
334 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
335 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
337 MALLOC_ZONE(hp
->h_meta
, struct hfsfilemeta
*,
338 sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
339 /* Allocate a new vnode. */
340 if ((rtn
= getnewvnode(VT_HFS
, HFSTOVFS(hfsmp
), hfs_vnodeop_p
, &vp
))) {
341 FREE_ZONE(hp
->h_meta
, sizeof(struct hfsfilemeta
), M_HFSFMETA
);
342 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
346 /* Init the structure */
347 bzero(hp
->h_meta
, sizeof(struct hfsfilemeta
));
349 hp
->h_vp
= vp
; /* Make HFSTOV work */
350 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
351 hp
->h_meta
->h_dev
= hfsmp
->hfs_raw_dev
;
352 hp
->h_meta
->h_usecount
++;
353 hp
->h_nodeflags
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
355 hp
->h_valid
= HFS_VNODE_MAGIC
;
357 vp
->v_data
= hp
; /* Make VTOH work */
360 * Metadata files are VREG but not available for IO
361 * through mapped IO as will as POSIX IO APIs.
362 * Hence we do not initialize UBC for those files
367 vp
->v_ubcinfo
= UBC_NOINFO
;
371 VREF(hp
->h_meta
->h_devvp
);
382 OSErr
GetNewFCB(ExtendedVCB
*vcb
, FileReference
* fRefPtr
)
386 err
= GetInitializedVNode( VCBTOHFS(vcb
), fRefPtr
, 0 );
387 panic("This node is not completely initialized in GetNewFCB!"); /* XXX SER */
393 OSErr
CheckVolumeOffLine( ExtendedVCB
*vcb
)
400 OSErr
C_FlushMDB( ExtendedVCB
*volume
)
404 if (volume
->vcbSigWord
== kHFSPlusSigWord
)
405 err
= hfs_flushvolumeheader(VCBTOHFS(volume
), 0);
407 err
= hfs_flushMDB(VCBTOHFS(volume
), 0);
414 * GetTimeUTC - get the GMT Mac OS time (in seconds since 1/1/1904)
416 * called by the Catalog Manager when creating/updating HFS Plus records
418 UInt32
GetTimeUTC(void)
420 return (time
.tv_sec
+ MAC_GMT_FACTOR
);
424 * GetTimeLocal - get the local Mac OS time (in seconds since 1/1/1904)
426 * called by the Catalog Manager when creating/updating HFS records
428 UInt32
GetTimeLocal(Boolean forHFS
)
432 localTime
= UTCToLocal(GetTimeUTC());
434 if (forHFS
&& gTimeZone
.tz_dsttime
)
441 * LocalToUTC - convert from Mac OS local time to Mac OS GMT time.
442 * This should only be called for HFS volumes (not for HFS Plus).
444 UInt32
LocalToUTC(UInt32 localTime
)
446 UInt32 gtime
= localTime
;
449 gtime
+= (gTimeZone
.tz_minuteswest
* 60);
451 * We no longer do DST adjustments here since we don't
452 * know if time supplied needs adjustment!
454 * if (gTimeZone.tz_dsttime)
462 * UTCToLocal - convert from Mac OS GMT time to Mac OS local time.
463 * This should only be called for HFS volumes (not for HFS Plus).
465 UInt32
UTCToLocal(UInt32 utcTime
)
467 UInt32 ltime
= utcTime
;
470 ltime
-= (gTimeZone
.tz_minuteswest
* 60);
472 * We no longer do DST adjustments here since we don't
473 * know if time supplied needs adjustment!
475 * if (gTimeZone.tz_dsttime)
483 * to_bsd_time - convert from Mac OS time (seconds since 1/1/1904)
484 * to BSD time (seconds since 1/1/1970)
486 u_int32_t
to_bsd_time(u_int32_t hfs_time
)
488 u_int32_t gmt
= hfs_time
;
490 if (gmt
> MAC_GMT_FACTOR
)
491 gmt
-= MAC_GMT_FACTOR
;
493 gmt
= 0; /* don't let date go negative! */
499 * to_hfs_time - convert from BSD time (seconds since 1/1/1970)
500 * to Mac OS time (seconds since 1/1/1904)
502 u_int32_t
to_hfs_time(u_int32_t bsd_time
)
504 u_int32_t hfs_time
= bsd_time
;
506 /* don't adjust zero - treat as uninitialzed */
508 hfs_time
+= MAC_GMT_FACTOR
;
514 void BlockMoveData (const void *srcPtr
, void *destPtr
, Size byteCount
)
516 bcopy(srcPtr
, destPtr
, byteCount
);
520 Ptr
NewPtrSysClear (Size byteCount
)
523 MALLOC (tmptr
, Ptr
, byteCount
, M_TEMP
, M_WAITOK
);
525 bzero(tmptr
, byteCount
);
531 Ptr
NewPtr (Size byteCount
)
534 MALLOC (tmptr
, Ptr
, byteCount
, M_TEMP
, M_WAITOK
);
539 void DisposePtr (Ptr p
)
545 void DebugStr (ConstStr255Param debuggerMsg
)
547 kprintf ("*** Mac OS Debugging Message: %s\n", &debuggerMsg
[1]);
551 OSErr
MemError (void)
557 void ClearMemory( void* start
, UInt32 length
)
559 bzero(start
, (size_t)length
);
566 * Check to see if a vnode is locked in the current context
567 * This is to be used for debugging purposes only!!
570 void RequireFileLock(FileReference vp
, int shareable
)
572 struct lock__bsd__
*lkp
;
577 pid
= current_proc()->p_pid
;
578 self
= (void *) current_thread();
579 lkp
= &VTOH(vp
)->h_lock
;
583 simple_lock(&lkp
->lk_interlock
);
585 if (shareable
&& (lkp
->lk_sharecount
> 0) && (lkp
->lk_lockholder
== LK_NOPROC
))
587 else if ((lkp
->lk_exclusivecount
> 0) && (lkp
->lk_lockholder
== pid
) && (lkp
->lk_lockthread
== self
))
590 simple_unlock(&lkp
->lk_interlock
);
593 DBG_VFS((" # context... self=0x%0X, pid=0x%0X, proc=0x%0X\n", (int)self
, pid
, (int)current_proc()));
594 DBG_VFS((" # lock state... thread=0x%0X, holder=0x%0X, ex=%d, sh=%d\n", (int)lkp
->lk_lockthread
, lkp
->lk_lockholder
, lkp
->lk_exclusivecount
, lkp
->lk_sharecount
));
596 switch (H_FILEID(VTOH(vp
))) {
598 DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int
)vp
));
602 DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int
)vp
));
606 DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", H_FILEID(VTOH(vp
)), (u_int
)vp
));