2 * Copyright (c) 2000-2001 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
);
258 OSErr
RelBlock_glue (Ptr address
, UInt16 options
)
264 if (options
& ~(rbTrashMask
| rbDirtyMask
| rbWriteMask
) == 0) {
265 DEBUG_BREAK_MSG(("RelBlock_glue: options = 0x%04X.\n", options
));
268 if ((err
= LookupBufferMapping(address
, &bp
, &mappingEntry
))) {
269 DEBUG_BREAK_MSG(("Failed to find buffer pointer for buffer in RelBlock_glue.\n"));
271 if (bp
->b_flags
& B_DIRTY
) {
272 /* The buffer was previously marked dirty (using MarkBlock_glue):
273 now's the time to write it. */
274 options
|= rbDirtyMask
;
276 ReleaseMappingEntry(mappingEntry
);
277 if (options
& rbTrashMask
) {
278 bp
->b_flags
|= B_INVAL
;
281 if (options
& (rbDirtyMask
| rbWriteMask
)) {
282 bp
->b_flags
|= B_DIRTY
;
283 if (options
& rbWriteMask
) {
298 /* Creates a new vnode to hold a psuedo file like an extents tree file */
301 OSStatus
GetInitializedVNode(struct hfsmount
*hfsmp
, struct vnode
**tmpvnode
)
305 struct vnode
*vp
= NULL
;
308 DBG_ASSERT(hfsmp
!= NULL
);
309 DBG_ASSERT(tmpvnode
!= NULL
);
311 /* Allocate a new hfsnode. */
313 * Must do malloc() before getnewvnode(), since malloc() can block
314 * and could cause other part of the system to access v_data
315 * which has not been initialized yet
317 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
322 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
323 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
325 MALLOC_ZONE(hp
->h_meta
, struct hfsfilemeta
*,
326 sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
327 /* Allocate a new vnode. */
328 if ((rtn
= getnewvnode(VT_HFS
, HFSTOVFS(hfsmp
), hfs_vnodeop_p
, &vp
))) {
329 FREE_ZONE(hp
->h_meta
, sizeof(struct hfsfilemeta
), M_HFSFMETA
);
330 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
334 /* Init the structure */
335 bzero(hp
->h_meta
, sizeof(struct hfsfilemeta
));
337 hp
->h_vp
= vp
; /* Make HFSTOV work */
338 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
339 hp
->h_meta
->h_dev
= hfsmp
->hfs_raw_dev
;
340 hp
->h_meta
->h_usecount
++;
341 hp
->h_nodeflags
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
342 rl_init(&hp
->h_invalidranges
);
344 hp
->h_valid
= HFS_VNODE_MAGIC
;
346 vp
->v_data
= hp
; /* Make VTOH work */
349 * Metadata files are VREG but not available for IO
350 * through mapped IO as will as POSIX IO APIs.
351 * Hence we do not initialize UBC for those files
353 vp
->v_ubcinfo
= UBC_NOINFO
;
357 VREF(hp
->h_meta
->h_devvp
);
368 OSErr
C_FlushMDB( ExtendedVCB
*volume
)
372 if (volume
->vcbSigWord
== kHFSPlusSigWord
)
373 err
= hfs_flushvolumeheader(VCBTOHFS(volume
), 0);
375 err
= hfs_flushMDB(VCBTOHFS(volume
), 0);
382 * GetTimeUTC - get the GMT Mac OS time (in seconds since 1/1/1904)
384 * called by the Catalog Manager when creating/updating HFS Plus records
386 UInt32
GetTimeUTC(void)
388 return (time
.tv_sec
+ MAC_GMT_FACTOR
);
392 * GetTimeLocal - get the local Mac OS time (in seconds since 1/1/1904)
394 * called by the Catalog Manager when creating/updating HFS records
396 UInt32
GetTimeLocal(Boolean forHFS
)
400 localTime
= UTCToLocal(GetTimeUTC());
402 if (forHFS
&& gTimeZone
.tz_dsttime
)
409 * LocalToUTC - convert from Mac OS local time to Mac OS GMT time.
410 * This should only be called for HFS volumes (not for HFS Plus).
412 UInt32
LocalToUTC(UInt32 localTime
)
414 UInt32 gtime
= localTime
;
417 gtime
+= (gTimeZone
.tz_minuteswest
* 60);
419 * We no longer do DST adjustments here since we don't
420 * know if time supplied needs adjustment!
422 * if (gTimeZone.tz_dsttime)
430 * UTCToLocal - convert from Mac OS GMT time to Mac OS local time.
431 * This should only be called for HFS volumes (not for HFS Plus).
433 UInt32
UTCToLocal(UInt32 utcTime
)
435 UInt32 ltime
= utcTime
;
438 ltime
-= (gTimeZone
.tz_minuteswest
* 60);
440 * We no longer do DST adjustments here since we don't
441 * know if time supplied needs adjustment!
443 * if (gTimeZone.tz_dsttime)
451 * to_bsd_time - convert from Mac OS time (seconds since 1/1/1904)
452 * to BSD time (seconds since 1/1/1970)
454 u_int32_t
to_bsd_time(u_int32_t hfs_time
)
456 u_int32_t gmt
= hfs_time
;
458 if (gmt
> MAC_GMT_FACTOR
)
459 gmt
-= MAC_GMT_FACTOR
;
461 gmt
= 0; /* don't let date go negative! */
467 * to_hfs_time - convert from BSD time (seconds since 1/1/1970)
468 * to Mac OS time (seconds since 1/1/1904)
470 u_int32_t
to_hfs_time(u_int32_t bsd_time
)
472 u_int32_t hfs_time
= bsd_time
;
474 /* don't adjust zero - treat as uninitialzed */
476 hfs_time
+= MAC_GMT_FACTOR
;
482 void BlockMoveData (const void *srcPtr
, void *destPtr
, Size byteCount
)
484 bcopy(srcPtr
, destPtr
, byteCount
);
488 Ptr
NewPtrSysClear (Size byteCount
)
491 MALLOC (tmptr
, Ptr
, byteCount
, M_TEMP
, M_WAITOK
);
493 bzero(tmptr
, byteCount
);
499 Ptr
NewPtr (Size byteCount
)
502 MALLOC (tmptr
, Ptr
, byteCount
, M_TEMP
, M_WAITOK
);
507 void DisposePtr (Ptr p
)
513 void DebugStr (ConstStr255Param debuggerMsg
)
515 kprintf ("*** Mac OS Debugging Message: %s\n", &debuggerMsg
[1]);
519 OSErr
MemError (void)
525 void ClearMemory( void* start
, UInt32 length
)
527 bzero(start
, (size_t)length
);
534 * Check to see if a vnode is locked in the current context
535 * This is to be used for debugging purposes only!!
538 void RequireFileLock(FileReference vp
, int shareable
)
540 struct lock__bsd__
*lkp
;
545 pid
= current_proc()->p_pid
;
546 self
= (void *) current_thread();
547 lkp
= &VTOH(vp
)->h_lock
;
551 simple_lock(&lkp
->lk_interlock
);
553 if (shareable
&& (lkp
->lk_sharecount
> 0) && (lkp
->lk_lockholder
== LK_NOPROC
))
555 else if ((lkp
->lk_exclusivecount
> 0) && (lkp
->lk_lockholder
== pid
) && (lkp
->lk_lockthread
== self
))
558 simple_unlock(&lkp
->lk_interlock
);
561 DBG_VFS((" # context... self=0x%0X, pid=0x%0X, proc=0x%0X\n", (int)self
, pid
, (int)current_proc()));
562 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
));
564 switch (H_FILEID(VTOH(vp
))) {
566 DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int
)vp
));
570 DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int
)vp
));
574 DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", H_FILEID(VTOH(vp
)), (u_int
)vp
));