]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/MacOSStubs.c
2b8809c6b6cc8f79d80a0c3a84dadbdaa0835744
[apple/xnu.git] / bsd / hfs / MacOSStubs.c
1 /*
2 * Copyright (c) 2000-2001 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
68 extern 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 */
75 struct 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 */
89 static 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
160 static 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
175 OSErr 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
253 Error_Exit: ;
254 return status;
255 }
256
257
258 OSErr RelBlock_glue (Ptr address, UInt16 options )
259 {
260 int err;
261 struct buf *bp;
262 int mappingEntry;
263
264 if (options & ~(rbTrashMask | rbDirtyMask | rbWriteMask) == 0) {
265 DEBUG_BREAK_MSG(("RelBlock_glue: options = 0x%04X.\n", options));
266 };
267
268 if ((err = LookupBufferMapping(address, &bp, &mappingEntry))) {
269 DEBUG_BREAK_MSG(("Failed to find buffer pointer for buffer in RelBlock_glue.\n"));
270 } else {
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;
275 };
276 ReleaseMappingEntry(mappingEntry);
277 if (options & rbTrashMask) {
278 bp->b_flags |= B_INVAL;
279 brelse(bp);
280 } else {
281 if (options & (rbDirtyMask | rbWriteMask)) {
282 bp->b_flags |= B_DIRTY;
283 if (options & rbWriteMask) {
284 bwrite(bp);
285 } else {
286 bdwrite(bp);
287 }
288 } else {
289 brelse(bp);
290 };
291 };
292 err = E_NONE;
293 };
294 return err;
295 }
296
297 /* */
298 /* Creates a new vnode to hold a psuedo file like an extents tree file */
299 /* */
300
301 OSStatus GetInitializedVNode(struct hfsmount *hfsmp, struct vnode **tmpvnode)
302 {
303
304 struct hfsnode *hp;
305 struct vnode *vp = NULL;
306 int rtn;
307
308 DBG_ASSERT(hfsmp != NULL);
309 DBG_ASSERT(tmpvnode != NULL);
310
311 /* Allocate a new hfsnode. */
312 /*
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
316 */
317 MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
318 if(hp == NULL) {
319 rtn = ENOMEM;
320 goto Err_Exit;
321 }
322 bzero((caddr_t)hp, sizeof(struct hfsnode));
323 lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
324
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);
331 goto Err_Exit;
332 }
333
334 /* Init the structure */
335 bzero(hp->h_meta, sizeof(struct hfsfilemeta));
336
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);
343 #if HFS_DIAGNOSTIC
344 hp->h_valid = HFS_VNODE_MAGIC;
345 #endif
346 vp->v_data = hp; /* Make VTOH work */
347 vp->v_type = VREG;
348 /*
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
352 */
353 vp->v_ubcinfo = UBC_NOINFO;
354
355 *tmpvnode = vp;
356
357 VREF(hp->h_meta->h_devvp);
358
359 return noErr;
360
361 Err_Exit:
362
363 *tmpvnode = NULL;
364
365 return rtn;
366 }
367
368 OSErr C_FlushMDB( ExtendedVCB *volume)
369 {
370 short err;
371
372 if (volume->vcbSigWord == kHFSPlusSigWord)
373 err = hfs_flushvolumeheader(VCBTOHFS(volume), 0);
374 else
375 err = hfs_flushMDB(VCBTOHFS(volume), 0);
376
377 return err;
378 }
379
380
381 /*
382 * GetTimeUTC - get the GMT Mac OS time (in seconds since 1/1/1904)
383 *
384 * called by the Catalog Manager when creating/updating HFS Plus records
385 */
386 UInt32 GetTimeUTC(void)
387 {
388 return (time.tv_sec + MAC_GMT_FACTOR);
389 }
390
391 /*
392 * GetTimeLocal - get the local Mac OS time (in seconds since 1/1/1904)
393 *
394 * called by the Catalog Manager when creating/updating HFS records
395 */
396 UInt32 GetTimeLocal(Boolean forHFS)
397 {
398 UInt32 localTime;
399
400 localTime = UTCToLocal(GetTimeUTC());
401
402 if (forHFS && gTimeZone.tz_dsttime)
403 localTime += 3600;
404
405 return localTime;
406 }
407
408 /*
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).
411 */
412 UInt32 LocalToUTC(UInt32 localTime)
413 {
414 UInt32 gtime = localTime;
415
416 if (gtime != 0) {
417 gtime += (gTimeZone.tz_minuteswest * 60);
418 /*
419 * We no longer do DST adjustments here since we don't
420 * know if time supplied needs adjustment!
421 *
422 * if (gTimeZone.tz_dsttime)
423 * gtime -= 3600;
424 */
425 }
426 return (gtime);
427 }
428
429 /*
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).
432 */
433 UInt32 UTCToLocal(UInt32 utcTime)
434 {
435 UInt32 ltime = utcTime;
436
437 if (ltime != 0) {
438 ltime -= (gTimeZone.tz_minuteswest * 60);
439 /*
440 * We no longer do DST adjustments here since we don't
441 * know if time supplied needs adjustment!
442 *
443 * if (gTimeZone.tz_dsttime)
444 * ltime += 3600;
445 */
446 }
447 return (ltime);
448 }
449
450 /*
451 * to_bsd_time - convert from Mac OS time (seconds since 1/1/1904)
452 * to BSD time (seconds since 1/1/1970)
453 */
454 u_int32_t to_bsd_time(u_int32_t hfs_time)
455 {
456 u_int32_t gmt = hfs_time;
457
458 if (gmt > MAC_GMT_FACTOR)
459 gmt -= MAC_GMT_FACTOR;
460 else
461 gmt = 0; /* don't let date go negative! */
462
463 return gmt;
464 }
465
466 /*
467 * to_hfs_time - convert from BSD time (seconds since 1/1/1970)
468 * to Mac OS time (seconds since 1/1/1904)
469 */
470 u_int32_t to_hfs_time(u_int32_t bsd_time)
471 {
472 u_int32_t hfs_time = bsd_time;
473
474 /* don't adjust zero - treat as uninitialzed */
475 if (hfs_time != 0)
476 hfs_time += MAC_GMT_FACTOR;
477
478 return (hfs_time);
479 }
480
481
482 void BlockMoveData (const void *srcPtr, void *destPtr, Size byteCount)
483 {
484 bcopy(srcPtr, destPtr, byteCount);
485 }
486
487
488 Ptr NewPtrSysClear (Size byteCount)
489 {
490 Ptr tmptr;
491 MALLOC (tmptr, Ptr, byteCount, M_TEMP, M_WAITOK);
492 if (tmptr)
493 bzero(tmptr, byteCount);
494 return tmptr;
495 }
496
497
498
499 Ptr NewPtr (Size byteCount)
500 {
501 Ptr tmptr;
502 MALLOC (tmptr, Ptr, byteCount, M_TEMP, M_WAITOK);
503 return tmptr;
504 }
505
506
507 void DisposePtr (Ptr p)
508 {
509 FREE (p, M_TEMP);
510 }
511
512
513 void DebugStr (ConstStr255Param debuggerMsg)
514 {
515 kprintf ("*** Mac OS Debugging Message: %s\n", &debuggerMsg[1]);
516 DEBUG_BREAK;
517 }
518
519 OSErr MemError (void)
520 {
521 return 0;
522 }
523
524
525 void ClearMemory( void* start, UInt32 length )
526 {
527 bzero(start, (size_t)length);
528 }
529
530
531 /*
532 * RequireFileLock
533 *
534 * Check to see if a vnode is locked in the current context
535 * This is to be used for debugging purposes only!!
536 */
537 #if HFS_DIAGNOSTIC
538 void RequireFileLock(FileReference vp, int shareable)
539 {
540 struct lock__bsd__ *lkp;
541 int locked = false;
542 pid_t pid;
543 void * self;
544
545 pid = current_proc()->p_pid;
546 self = (void *) current_thread();
547 lkp = &VTOH(vp)->h_lock;
548
549 return;
550
551 simple_lock(&lkp->lk_interlock);
552
553 if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC))
554 locked = true;
555 else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self))
556 locked = true;
557
558 simple_unlock(&lkp->lk_interlock);
559
560 if (!locked) {
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));
563
564 switch (H_FILEID(VTOH(vp))) {
565 case 3:
566 DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
567 break;
568
569 case 4:
570 DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
571 break;
572
573 default:
574 DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", H_FILEID(VTOH(vp)), (u_int)vp));
575 break;
576 }
577 }
578 }
579 #endif
580