Chameleon

Chameleon Svn Source Tree

Root/branches/meklortOld/i386/libsaio/ufs.c

Source at commit 1146 created 12 years 10 months ago.
By azimutz, Sync with trunk (r1145). Add nVidia dev id's, 0DF4 for "GeForce GT 450M" (issue 99) and 1251 for "GeForce GTX 560M" (thanks to oSxFr33k for testing).
1/*
2 * Copyright (c) 2000-2003 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 2.0 (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/*
23 * ufs.c - File System Module for UFS.
24 *
25 * Copyright (c) 1998-2002 Apple Computer, Inc.
26 *
27 * DRI: Josh de Cesare
28 */
29#include <sl.h>
30
31#include "ufs.h"
32#include "ufs_byteorder.h"
33
34#if !defined(MAXNAMLEN) && defined(UFSMAXNAMLEN)
35#define MAXNAMLEN UFSMAXNAMLEN
36#endif
37
38typedef struct dinode Inode, *InodePtr;
39
40// Private function prototypes
41
42static char *ReadBlock(long fragNum, long fragOffset, long length,
43 char *buffer, long cache);
44static long ReadInode(long inodeNum, InodePtr inode, long *flags, long *time);
45static long ResolvePathToInode(char *filePath, long *flags,
46 InodePtr fileInode, InodePtr dirInode);
47static long ReadDirEntry(InodePtr dirInode, long *fileInodeNum,
48 long long *dirIndex, char **name);
49static long FindFileInDir(char *fileName, long *flags,
50 InodePtr fileInode, InodePtr dirInode);
51static char *ReadFileBlock(InodePtr fileInode, long fragNum, long blockOffset,
52 long length, char *buffer, long cache);
53static long ReadFile(InodePtr fileInode, uint64_t *length, void *base, uint64_t offset);
54
55#define kDevBlockSize (0x200) // Size of each disk block.
56#define kDiskLabelBlock (15) // Block the DL is in.
57
58#ifdef __i386__
59
60static CICell gCurrentIH;
61static long long gPartitionBase;
62static char *gULBuf;
63static char *gFSBuf;
64static struct fs *gFS;
65#if !BOOT1
66static struct ufslabel gUFSLabel; // for UUID
67#endif
68static long gBlockSize;
69static long gFragSize;
70static long gFragsPerBlock;
71static char *gTempBlock;
72static char *gTempName;
73static char *gTempName2;
74static InodePtr gRootInodePtr;
75static InodePtr gFileInodePtr;
76
77#else /* !__i386__ */
78
79static CICell gCurrentIH;
80static long long gPartitionBase;
81static char gDLBuf[8192];
82static char gFSBuf[SBSIZE];
83static struct fs *gFS;
84#if !BOOT1
85static struct ufslabel gUFSLabel; // for UUID
86#endif
87static long gBlockSize;
88static long gFragSize;
89static long gFragsPerBlock;
90static char *gTempBlock;
91static char gTempName[MAXNAMLEN + 1];
92static char gTempName2[MAXNAMLEN + 1];
93static Inode _gRootInode;
94static Inode _gFileInode;
95static InodePtr gRootInodePtr = &_gRootInode;
96static InodePtr gFileInodePtr = &_gFileInode;
97
98#endif /* !__i386__ */
99
100// Public functions
101
102void UFSFree(CICell ih)
103{
104 if(gCurrentIH == ih)
105 gCurrentIH = 0;
106 free(ih);
107}
108
109long UFSInitPartition( CICell ih )
110{
111#if !BOOT1
112 long ret;
113#endif
114
115 if (ih == gCurrentIH) {
116#ifdef __i386__
117 CacheInit(ih, gBlockSize);
118#endif
119 return 0;
120 }
121
122#if !BOOT1
123 verbose("UFSInitPartition: %x\n", ih);
124#endif
125
126 gCurrentIH = 0;
127
128#ifdef __i386__
129 if (!gULBuf) gULBuf = (char *) malloc(UFS_LABEL_SIZE);
130 if (!gFSBuf) gFSBuf = (char *) malloc(SBSIZE);
131 if (!gTempName) gTempName = (char *) malloc(MAXNAMLEN + 1);
132 if (!gTempName2) gTempName2 = (char *) malloc(MAXNAMLEN + 1);
133 if (!gRootInodePtr) gRootInodePtr = (InodePtr) malloc(sizeof(Inode));
134 if (!gFileInodePtr) gFileInodePtr = (InodePtr) malloc(sizeof(Inode));
135 if (!gULBuf || !gFSBuf || !gTempName || !gTempName2 ||
136 !gRootInodePtr || !gFileInodePtr) return -1;
137#endif
138
139 // Assume there is no Disk Label
140 gPartitionBase = 0;
141
142#if !BOOT1
143 // read the disk label to get the UUID
144 // (rumor has it that UFS headers can be either-endian on disk; hopefully
145 // that isn't true for this UUID field).
146 Seek(ih, gPartitionBase + UFS_LABEL_OFFSET);
147 ret = Read(ih, (long)&gUFSLabel, UFS_LABEL_SIZE);
148 if(ret != 0)
149 bzero(&gUFSLabel, UFS_LABEL_SIZE);
150#endif /* !BOOT1 */
151
152 // Look for the Super Block
153 Seek(ih, gPartitionBase + SBOFF);
154 Read(ih, (long)gFSBuf, SBSIZE);
155
156 gFS = (struct fs *)gFSBuf;
157 byte_swap_superblock(gFS);
158
159 if (gFS->fs_magic != FS_MAGIC) {
160 return -1;
161 }
162
163ih->modTime = gFS->fs_time;
164
165 // Calculate the block size and set up the block cache.
166 gBlockSize = gFS->fs_bsize;
167 gFragSize = gFS->fs_fsize;
168 gFragsPerBlock = gBlockSize / gFragSize;
169 if (gTempBlock != 0) free(gTempBlock);
170 gTempBlock = malloc(gBlockSize);
171 CacheInit(ih, gBlockSize);
172
173 gCurrentIH = ih;
174
175 // Read the Root Inode
176 ReadInode(ROOTINO, gRootInodePtr, 0, 0);
177
178 return 0;
179}
180
181#if !BOOT1
182
183long UFSGetUUID(CICell ih, char *uuidStr)
184{
185 long long uuid = gUFSLabel.ul_uuid;
186
187 if (UFSInitPartition(ih) == -1) return -1;
188 if (uuid == 0LL) return -1;
189
190 return CreateUUIDString((uint8_t*)(&uuid), sizeof(uuid), uuidStr);
191}
192
193#endif /* !BOOT1 */
194
195long UFSLoadFile( CICell ih, char * filePath )
196{
197 return UFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
198}
199
200long UFSReadFile( CICell ih, char * filePath, void * base, uint64_t offset, uint64_t length )
201{
202 long ret, flags;
203
204#if !BOOT1
205 verbose("Loading UFS file: [%s] from %x.\n", filePath, (unsigned)ih);
206#endif
207
208 if (UFSInitPartition(ih) == -1) return -1;
209
210 // Skip one or two leading '/'.
211 if (*filePath == '/') filePath++;
212 if (*filePath == '/') filePath++;
213
214 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
215 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
216
217 ret = ReadFile(gFileInodePtr, &length, base, offset);
218 if (ret == -1) return -1;
219
220 return length;
221}
222
223#ifndef BOOT1
224
225long UFSGetDirEntry( CICell ih, char * dirPath, long long * dirIndex,
226 char ** name, long * flags, long * time,
227 FinderInfo * finderInfo, long * infoValid)
228{
229 long ret, fileInodeNum, dirFlags;
230 Inode tmpInode;
231
232 if (UFSInitPartition(ih) == -1) return -1;
233
234 if (infoValid) *infoValid = 0;
235
236 // Skip a leading '/' if present
237 if (*dirPath == '/') dirPath++;
238 if (*dirPath == '/') dirPath++;
239
240 ret = ResolvePathToInode(dirPath, &dirFlags, gFileInodePtr, gRootInodePtr);
241 if ((ret == -1) || ((dirFlags & kFileTypeMask) != kFileTypeDirectory))
242 return -1;
243
244 ret = ReadDirEntry(gFileInodePtr, &fileInodeNum, dirIndex, name);
245 if (ret != 0) return ret;
246
247 ReadInode(fileInodeNum, &tmpInode, flags, time);
248
249 return 0;
250}
251
252void
253UFSGetDescription(CICell ih, char *str, long strMaxLen)
254{
255 if (UFSInitPartition(ih) == -1) { return; }
256
257 struct ufslabel *ul;
258
259 // Look for the Disk Label
260 Seek(ih, 1ULL * UFS_LABEL_OFFSET);
261 Read(ih, (long)gULBuf, UFS_LABEL_SIZE);
262
263 ul = (struct ufslabel *)gULBuf;
264
265 unsigned char magic_bytes[] = UFS_LABEL_MAGIC;
266 int i;
267 unsigned char *p = (unsigned char *)&ul->ul_magic;
268
269 for (i=0; i<sizeof(magic_bytes); i++, p++) {
270 if (*p != magic_bytes[i])
271 return;
272 }
273 strncpy(str, (const char *)ul->ul_name, strMaxLen);
274}
275
276long
277UFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
278{
279 long ret, flags;
280
281 if (UFSInitPartition(ih) == -1) return -1;
282
283 // Skip one or two leading '/'.
284 if (*filePath == '/') filePath++;
285 if (*filePath == '/') filePath++;
286
287 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
288 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
289
290 *firstBlock = (gPartitionBase + 1ULL * gFileInodePtr->di_db[0] * gBlockSize) / 512ULL;
291
292 return 0;
293}
294
295
296#endif /* !BOOT1 */
297
298// Private functions
299
300static char * ReadBlock( long fragNum, long blockOffset, long length,
301 char * buffer, long cache )
302{
303 long long offset;
304 long blockNum;
305
306 blockNum = fragNum / gFragsPerBlock;
307 fragNum -= blockNum * gFragsPerBlock;
308
309 blockOffset += fragNum * gFragSize;
310
311 offset = gPartitionBase + 1ULL * blockNum * gBlockSize;
312
313 if (cache && ((blockOffset + length) <= gBlockSize)) {
314 CacheRead(gCurrentIH, gTempBlock, offset, gBlockSize, 1);
315 if (buffer != 0) bcopy(gTempBlock + blockOffset, buffer, length);
316 else buffer = gTempBlock + blockOffset;
317 } else {
318 offset += blockOffset;
319 CacheRead(gCurrentIH, buffer, offset, length, 0);
320 }
321
322 return buffer;
323}
324
325static long ReadInode( long inodeNum, InodePtr inode, long * flags, long * time )
326{
327 long fragNum = ino_to_fsba(gFS, inodeNum);
328 long blockOffset = ino_to_fsbo(gFS, inodeNum) * sizeof(Inode);
329
330 ReadBlock(fragNum, blockOffset, sizeof(Inode), (char *)inode, 1);
331 byte_swap_dinode_in(inode);
332
333 if (time != 0) *time = inode->di_mtime;
334
335 if (flags != 0) {
336 switch (inode->di_mode & IFMT) {
337 case IFREG: *flags = kFileTypeFlat; break;
338 case IFDIR: *flags = kFileTypeDirectory; break;
339 case IFLNK: *flags = kFileTypeLink; break;
340 default : *flags = kFileTypeUnknown; break;
341 }
342
343 *flags |= inode->di_mode & kPermMask;
344
345 if (inode->di_uid != 0) *flags |= kOwnerNotRoot;
346 }
347
348 return 0;
349}
350
351static long ResolvePathToInode( char * filePath, long * flags,
352 InodePtr fileInode, InodePtr dirInode )
353{
354 char * restPath;
355 long ret, cnt;
356
357 // if filePath is empty the we want this directory.
358 if (*filePath == '\0') {
359 bcopy((char *)dirInode, (char *)fileInode, sizeof(Inode));
360 return 0;
361 }
362
363 // Copy the file name to gTempName
364 cnt = 0;
365 while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
366 strlcpy(gTempName, filePath, cnt+1);
367
368 // Move restPath to the right place.
369 if (filePath[cnt] != '\0') cnt++;
370 restPath = filePath + cnt;
371
372 // gTempName is a name in the current Dir.
373 // restPath is the rest of the path if any.
374
375 ret = FindFileInDir(gTempName, flags, fileInode, dirInode);
376 if (ret == -1) return -1;
377
378 if ((*restPath != '\0') && ((*flags & kFileTypeMask) == kFileTypeDirectory))
379 ret = ResolvePathToInode(restPath, flags, fileInode, fileInode);
380
381 return ret;
382}
383
384static long ReadDirEntry( InodePtr dirInode, long * fileInodeNum,
385 long long * dirIndex, char ** name )
386{
387 struct direct *dir;
388 char *buffer;
389 long long index;
390 long dirBlockNum, dirBlockOffset;
391
392 while (1) {
393 index = *dirIndex;
394
395 dirBlockOffset = (long) (index % DIRBLKSIZ);
396 dirBlockNum = (long) (index / DIRBLKSIZ);
397
398 buffer = ReadFileBlock(dirInode, dirBlockNum, 0, DIRBLKSIZ, 0, 1);
399 if (buffer == 0) return -1;
400
401 dir = (struct direct *)(buffer + dirBlockOffset);
402 byte_swap_dir_block_in((char *)dir, 1);
403
404 *dirIndex += dir->d_reclen;
405
406 if (dir->d_ino != 0) break;
407
408 if (dirBlockOffset != 0) return -1;
409 }
410
411 *fileInodeNum = dir->d_ino;
412 *name = strlcpy(gTempName2, dir->d_name, dir->d_namlen+1);
413
414 return 0;
415}
416
417static long FindFileInDir( char * fileName, long * flags,
418 InodePtr fileInode, InodePtr dirInode )
419{
420 long ret, inodeNum;
421 long long index = 0;
422 char *name;
423
424 while (1) {
425 ret = ReadDirEntry(dirInode, &inodeNum, &index, &name);
426 if (ret == -1) return -1;
427
428 if (strcmp(fileName, name) == 0) break;
429 }
430
431 ReadInode(inodeNum, fileInode, flags, 0);
432
433 return 0;
434}
435
436static char * ReadFileBlock( InodePtr fileInode, long fragNum, long blockOffset,
437 long length, char * buffer, long cache )
438{
439 long fragCount, blockNum;
440 long diskFragNum, indFragNum, indBlockOff, refsPerBlock;
441 char *indBlock;
442
443 fragCount = (fileInode->di_size + gFragSize - 1) / gFragSize;
444 if (fragNum >= fragCount) return 0;
445
446 refsPerBlock = gBlockSize / sizeof(ufs_daddr_t);
447
448 blockNum = fragNum / gFragsPerBlock;
449 fragNum -= blockNum * gFragsPerBlock;
450
451 // Get Direct Block Number.
452 if (blockNum < NDADDR) {
453 diskFragNum = fileInode->di_db[blockNum];
454 } else {
455 blockNum -= NDADDR;
456
457 // Get Single Indirect Fragment Number.
458 if (blockNum < refsPerBlock) {
459 indFragNum = fileInode->di_ib[0];
460 } else {
461 blockNum -= refsPerBlock;
462
463 // Get Double Indirect Fragment Number.
464 if (blockNum < (refsPerBlock * refsPerBlock)) {
465 indFragNum = fileInode->di_ib[1];
466 } else {
467 blockNum -= refsPerBlock * refsPerBlock;
468
469 // Get Triple Indirect Fragment Number.
470 indFragNum = fileInode->di_ib[2];
471
472 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
473 indBlockOff = blockNum / (refsPerBlock * refsPerBlock);
474 blockNum %= (refsPerBlock * refsPerBlock);
475 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
476 }
477
478 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
479 indBlockOff = blockNum / refsPerBlock;
480 blockNum %= refsPerBlock;
481 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
482 }
483
484 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
485 diskFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[blockNum]);
486 }
487
488 buffer = ReadBlock(diskFragNum+fragNum, blockOffset, length, buffer, cache);
489
490 return buffer;
491}
492
493static long ReadFile( InodePtr fileInode, uint64_t * length, void * base, uint64_t offset )
494{
495 long bytesLeft, curSize, curFrag;
496 char *buffer, *curAddr = (char *)base;
497
498 bytesLeft = fileInode->di_size;
499
500 if (offset > bytesLeft) {
501 printf("Offset is too large.\n");
502 return -1;
503 }
504
505 if ((*length == 0) || ((offset + *length) > bytesLeft)) {
506 *length = bytesLeft - offset;
507 }
508/*
509 if (bytesLeft > kLoadSize) {
510 printf("File is too large.\n");
511 return -1;
512 }
513*/
514 bytesLeft = *length;
515 curFrag = (offset / gBlockSize) * gFragsPerBlock;
516 offset %= gBlockSize;
517
518 while (bytesLeft) {
519 curSize = gBlockSize;
520 if (curSize > bytesLeft) curSize = bytesLeft;
521 if ((offset + curSize) > gBlockSize) curSize = (gBlockSize - offset);
522
523 buffer = ReadFileBlock(fileInode, curFrag, offset, curSize, curAddr, 0);
524 if (buffer == 0) break;
525
526 if (offset != 0) offset = 0;
527
528 curFrag += gFragsPerBlock;
529 curAddr += curSize;
530 bytesLeft -= curSize;
531 }
532
533 return bytesLeft;
534}

Archive Download this file

Revision: 1146