]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/MacOSStubs.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / hfs / MacOSStubs.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 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/* @(#)MacOSStubs.c 4.0
23*
24* (c) 1997-1999 Apple Computer, Inc. All Rights Reserved
25*
26* MacOSStubs.c -- Contains routines called by MacOS code, that is not defined.
27*
28* HISTORY
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.
49*
50*/
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/kernel.h>
54#include <sys/vnode.h>
55#include <sys/buf.h>
56#include <sys/malloc.h>
57#include <sys/mount.h>
58#include <sys/types.h>
59#include <sys/ubc.h>
60#include <sys/vm.h>
61#include <dev/disk.h>
62#include "hfs.h"
63#include "hfs_dbg.h"
64
65
66#include "hfscommon/headers/FileMgrInternal.h"
67
68extern int (**hfs_vnodeop_p)(void *);
69
70
71/*
72 * gTimeZone should only be used for HFS volumes!
73 * It is initialized when an HFS volume is mounted.
74 */
75struct timezone gTimeZone = {8*60,1};
76
77
78/*************************************************************************************/
79
80/*************************************************************************************/
81/*
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).
87 *
88 */
89static void StoreBufferMapping(caddr_t bufferAddress, struct buf *bp)
90{
91 int i;
92
93 DBG_ASSERT(gBufferListIndex >= 0);
94 DBG_ASSERT(gBufferListIndex < BUFFERPTRLISTSIZE);
95
96 simple_lock(&gBufferPtrListLock);
97
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;
103 break;
104 }
105 gBufferListIndex = (gBufferListIndex + 1) % BUFFERPTRLISTSIZE;
106 };
107
108 if (i == 0) {
109 panic("StoreBufferMapping: couldn't find an empty slot in buffer list.");
110 };
111
112 DBG_ASSERT(gBufferListIndex >= 0);
113 DBG_ASSERT(gBufferListIndex < BUFFERPTRLISTSIZE);
114
115 simple_unlock(&gBufferPtrListLock);
116}
117
118
119/*static*/ OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr)
120{
121 OSErr err = E_NONE;
122 int i;
123 int listIndex = gBufferListIndex;
124 struct buf *bp = NULL;
125
126 DBG_ASSERT(gBufferListIndex >= 0);
127 DBG_ASSERT(gBufferListIndex < BUFFERPTRLISTSIZE);
128
129 simple_lock(&gBufferPtrListLock);
130
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];
136 break;
137 };
138
139 listIndex = (listIndex - 1);
140 if (listIndex < 0) {
141 listIndex = BUFFERPTRLISTSIZE - 1;
142 };
143 };
144
145 if (bp == NULL) {
146 DEBUG_BREAK_MSG(("LookupBufferMapping: couldn't find buffer header for buffer in list.\n"));
147 err = -1;
148 };
149
150 DBG_ASSERT(gBufferListIndex >= 0);
151 DBG_ASSERT(gBufferListIndex < BUFFERPTRLISTSIZE);
152
153 simple_unlock(&gBufferPtrListLock);
154
155 *bpp = bp;
156 return err;
157}
158
159
160static void ReleaseMappingEntry(int entryIndex) {
161
162 DBG_ASSERT(gBufferListIndex >= 0);
163 DBG_ASSERT(gBufferListIndex < BUFFERPTRLISTSIZE);
164
165 simple_lock(&gBufferPtrListLock);
166 gBufferAddress[entryIndex] = NULL;
167 simple_unlock(&gBufferPtrListLock);
168};
169#if HFS_DIAGNOSTIC
170#define DBG_GETBLOCK 0
171#else
172#define DBG_GETBLOCK 0
173#endif
174
175OSErr GetBlock_glue (UInt16 options, UInt32 blockNum, Ptr *baddress, FileReference fileRefNum, ExtendedVCB * vcb)
176{
177 int status;
178 struct buf *bp = NULL;
179 int readcount = 0;
180
181#if DBG_GETBLOCK
182 DBG_IO(("Getting block %ld with options %d and a refnum of %x\n", blockNum, options, fileRefNum ));
183#endif
184
185 if ((options & ~(gbReadMask | gbNoReadMask)) != 0) {
186 DEBUG_BREAK_MSG(("GetBlock_glue: options = 0x%04X.\n", options));
187 };
188
189 *baddress = NULL;
190
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),
196 0,
197 0,
198 BLK_META);
199 } else {
200 bp = getblk (fileRefNum,
201 IOBLKNOFORBLK(blockNum, VCBTOHFS(vcb)->hfs_phys_block_size),
202 IOBYTECCNTFORBLK(blockNum, kHFSBlockSize, VCBTOHFS(vcb)->hfs_phys_block_size),
203 0,
204 0,
205 BLK_META);
206 };
207 status = E_NONE;
208 } else {
209 do {
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),
214 NOCRED,
215 &bp);
216 } else {
217 status = meta_bread (fileRefNum,
218 IOBLKNOFORBLK(blockNum, VCBTOHFS(vcb)->hfs_phys_block_size),
219 IOBYTECCNTFORBLK(blockNum, kHFSBlockSize, VCBTOHFS(vcb)->hfs_phys_block_size),
220 NOCRED,
221 &bp);
222 };
223 if (status != E_NONE) {
224 if (bp) brelse(bp);
225 goto Error_Exit;
226 };
227
228 if (bp == NULL) {
229 status = -1;
230 goto Error_Exit;
231 };
232
233 ++readcount;
234
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...
238 */
239 if (bp->b_flags & B_DIRTY) {
240 DEBUG_BREAK_MSG(("GetBlock_glue: forced read for dirty block!\n"))
241 };
242 bp->b_flags |= B_INVAL;
243 brelse(bp);
244
245 /* Fall through and try again until we get a fresh copy from the disk... */
246 };
247 } while (((options & gbReadMask) != 0) && (readcount <= 1));
248 };
249
250 *baddress = bp->b_data + IOBYTEOFFSETFORBLK(bp->b_blkno, VCBTOHFS(vcb)->hfs_phys_block_size);
251 StoreBufferMapping(*baddress, bp);
252
253Error_Exit: ;
254 return status;
255}
256
257void MarkBlock_glue (Ptr address)
258{
259 int err;
260 struct buf *bp = NULL;
261 int mappingEntry;
262
263 if ((err = LookupBufferMapping(address, &bp, &mappingEntry))) {
264 panic("Failed to find buffer pointer for buffer in MarkBlock_glue.");
265 } else {
266 bp->b_flags |= B_DIRTY;
267 };
268}
269
270OSErr RelBlock_glue (Ptr address, UInt16 options )
271{
272 int err;
273 struct buf *bp;
274 int mappingEntry;
275
276 if (options & ~(rbTrashMask | rbDirtyMask | rbWriteMask) == 0) {
277 DEBUG_BREAK_MSG(("RelBlock_glue: options = 0x%04X.\n", options));
278 };
279
280 if ((err = LookupBufferMapping(address, &bp, &mappingEntry))) {
281 DEBUG_BREAK_MSG(("Failed to find buffer pointer for buffer in RelBlock_glue.\n"));
282 } else {
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;
287 };
288 ReleaseMappingEntry(mappingEntry);
289 if (options & rbTrashMask) {
290 bp->b_flags |= B_INVAL;
291 brelse(bp);
292 } else {
293 if (options & (rbDirtyMask | rbWriteMask)) {
294 bp->b_flags |= B_DIRTY;
295 if (options & rbWriteMask) {
296 bwrite(bp);
297 } else {
298 bdwrite(bp);
299 }
300 } else {
301 brelse(bp);
302 };
303 };
304 err = E_NONE;
305 };
306 return err;
307}
308
309/* */
310/* Creates a new vnode to hold a psuedo file like an extents tree file */
311/* */
312
313OSStatus GetInitializedVNode(struct hfsmount *hfsmp, struct vnode **tmpvnode, int init_ubc)
314{
315
316 struct hfsnode *hp;
317 struct vnode *vp = NULL;
318 int rtn;
319
320 DBG_ASSERT(hfsmp != NULL);
321 DBG_ASSERT(tmpvnode != NULL);
322
323 /* Allocate a new hfsnode. */
324 /*
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
328 */
329 MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
330 if(hp == NULL) {
331 rtn = ENOMEM;
332 goto Err_Exit;
333 }
334 bzero((caddr_t)hp, sizeof(struct hfsnode));
335 lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
336
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);
343 goto Err_Exit;
344 }
345
346 /* Init the structure */
347 bzero(hp->h_meta, sizeof(struct hfsfilemeta));
348
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;
354#if HFS_DIAGNOSTIC
355 hp->h_valid = HFS_VNODE_MAGIC;
356#endif
357 vp->v_data = hp; /* Make VTOH work */
358 vp->v_type = VREG;
359 /*
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
363 */
364 if (init_ubc)
365 ubc_info_init(vp);
366 else
367 vp->v_ubcinfo = UBC_NOINFO;
368
369 *tmpvnode = vp;
370
371 VREF(hp->h_meta->h_devvp);
372
373 return noErr;
374
375Err_Exit:
376
377 *tmpvnode = NULL;
378
379 return rtn;
380}
381
382OSErr GetNewFCB(ExtendedVCB *vcb, FileReference* fRefPtr)
383{
384 OSErr err;
385
386 err = GetInitializedVNode( VCBTOHFS(vcb), fRefPtr, 0 );
387 panic("This node is not completely initialized in GetNewFCB!"); /* XXX SER */
388
389 return( err );
390}
391
392
393OSErr CheckVolumeOffLine( ExtendedVCB *vcb )
394{
395
396 return( 0 );
397}
398
399
400OSErr C_FlushMDB( ExtendedVCB *volume)
401{
402 short err;
403
404 if (volume->vcbSigWord == kHFSPlusSigWord)
405 err = hfs_flushvolumeheader(VCBTOHFS(volume), 0);
406 else
407 err = hfs_flushMDB(VCBTOHFS(volume), 0);
408
409 return err;
410}
411
412
413/*
414 * GetTimeUTC - get the GMT Mac OS time (in seconds since 1/1/1904)
415 *
416 * called by the Catalog Manager when creating/updating HFS Plus records
417 */
418UInt32 GetTimeUTC(void)
419{
420 return (time.tv_sec + MAC_GMT_FACTOR);
421}
422
423/*
424 * GetTimeLocal - get the local Mac OS time (in seconds since 1/1/1904)
425 *
426 * called by the Catalog Manager when creating/updating HFS records
427 */
428UInt32 GetTimeLocal(Boolean forHFS)
429{
430 UInt32 localTime;
431
432 localTime = UTCToLocal(GetTimeUTC());
433
434 if (forHFS && gTimeZone.tz_dsttime)
435 localTime += 3600;
436
437 return localTime;
438}
439
440/*
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).
443 */
444UInt32 LocalToUTC(UInt32 localTime)
445{
446 UInt32 gtime = localTime;
447
448 if (gtime != 0) {
449 gtime += (gTimeZone.tz_minuteswest * 60);
450 /*
451 * We no longer do DST adjustments here since we don't
452 * know if time supplied needs adjustment!
453 *
454 * if (gTimeZone.tz_dsttime)
455 * gtime -= 3600;
456 */
457 }
458 return (gtime);
459}
460
461/*
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).
464 */
465UInt32 UTCToLocal(UInt32 utcTime)
466{
467 UInt32 ltime = utcTime;
468
469 if (ltime != 0) {
470 ltime -= (gTimeZone.tz_minuteswest * 60);
471 /*
472 * We no longer do DST adjustments here since we don't
473 * know if time supplied needs adjustment!
474 *
475 * if (gTimeZone.tz_dsttime)
476 * ltime += 3600;
477 */
478 }
479 return (ltime);
480}
481
482/*
483 * to_bsd_time - convert from Mac OS time (seconds since 1/1/1904)
484 * to BSD time (seconds since 1/1/1970)
485 */
486u_int32_t to_bsd_time(u_int32_t hfs_time)
487{
488 u_int32_t gmt = hfs_time;
489
490 if (gmt > MAC_GMT_FACTOR)
491 gmt -= MAC_GMT_FACTOR;
492 else
493 gmt = 0; /* don't let date go negative! */
494
495 return gmt;
496}
497
498/*
499 * to_hfs_time - convert from BSD time (seconds since 1/1/1970)
500 * to Mac OS time (seconds since 1/1/1904)
501 */
502u_int32_t to_hfs_time(u_int32_t bsd_time)
503{
504 u_int32_t hfs_time = bsd_time;
505
506 /* don't adjust zero - treat as uninitialzed */
507 if (hfs_time != 0)
508 hfs_time += MAC_GMT_FACTOR;
509
510 return (hfs_time);
511}
512
513
514void BlockMoveData (const void *srcPtr, void *destPtr, Size byteCount)
515{
516 bcopy(srcPtr, destPtr, byteCount);
517}
518
519
520Ptr NewPtrSysClear (Size byteCount)
521{
522 Ptr tmptr;
523 MALLOC (tmptr, Ptr, byteCount, M_TEMP, M_WAITOK);
524 if (tmptr)
525 bzero(tmptr, byteCount);
526 return tmptr;
527}
528
529
530
531Ptr NewPtr (Size byteCount)
532{
533 Ptr tmptr;
534 MALLOC (tmptr, Ptr, byteCount, M_TEMP, M_WAITOK);
535 return tmptr;
536}
537
538
539void DisposePtr (Ptr p)
540{
541 FREE (p, M_TEMP);
542}
543
544
545void DebugStr (ConstStr255Param debuggerMsg)
546{
547 kprintf ("*** Mac OS Debugging Message: %s\n", &debuggerMsg[1]);
548 DEBUG_BREAK;
549}
550
551OSErr MemError (void)
552{
553 return 0;
554}
555
556
557void ClearMemory( void* start, UInt32 length )
558{
559 bzero(start, (size_t)length);
560}
561
562
563/*
564 * RequireFileLock
565 *
566 * Check to see if a vnode is locked in the current context
567 * This is to be used for debugging purposes only!!
568 */
569#if HFS_DIAGNOSTIC
570void RequireFileLock(FileReference vp, int shareable)
571{
572 struct lock__bsd__ *lkp;
573 int locked = false;
574 pid_t pid;
575 void * self;
576
577 pid = current_proc()->p_pid;
578 self = (void *) current_thread();
579 lkp = &VTOH(vp)->h_lock;
580
581return;
582
583 simple_lock(&lkp->lk_interlock);
584
585 if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC))
586 locked = true;
587 else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self))
588 locked = true;
589
590 simple_unlock(&lkp->lk_interlock);
591
592 if (!locked) {
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));
595
596 switch (H_FILEID(VTOH(vp))) {
597 case 3:
598 DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
599 break;
600
601 case 4:
602 DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
603 break;
604
605 default:
606 DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", H_FILEID(VTOH(vp)), (u_int)vp));
607 break;
608 }
609 }
610}
611#endif
612