Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 9 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
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
30#include <sl.h>
31
32#include "ufs.h"
33#include "ufs_byteorder.h"
34
35#if !defined(MAXNAMLEN) && defined(UFSMAXNAMLEN)
36#define MAXNAMLEN UFSMAXNAMLEN
37#endif
38
39typedef struct dinode Inode, *InodePtr;
40
41// Private function prototypes
42
43static char *ReadBlock(long fragNum, long fragOffset, long length,
44 char *buffer, long cache);
45static long ReadInode(long inodeNum, InodePtr inode, long *flags, long *time);
46static long ResolvePathToInode(char *filePath, long *flags,
47 InodePtr fileInode, InodePtr dirInode);
48static long ReadDirEntry(InodePtr dirInode, long *fileInodeNum,
49 long *dirIndex, char **name);
50static long FindFileInDir(char *fileName, long *flags,
51 InodePtr fileInode, InodePtr dirInode);
52static char *ReadFileBlock(InodePtr fileInode, long fragNum, long blockOffset,
53 long length, char *buffer, long cache);
54static long ReadFile(InodePtr fileInode, uint64_t *length, void *base, uint64_t offset);
55
56#define kDevBlockSize (0x200) // Size of each disk block.
57#define kDiskLabelBlock (15) // Block the DL is in.
58
59#ifdef __i386__
60
61static CICell gCurrentIH;
62static long long gPartitionBase;
63static char *gULBuf;
64static char *gFSBuf;
65static struct fs *gFS;
66#if !BOOT1
67static struct ufslabel gUFSLabel; // for UUID
68#endif
69static long gBlockSize;
70static long gFragSize;
71static long gFragsPerBlock;
72static char *gTempBlock;
73static char *gTempName;
74static char *gTempName2;
75static InodePtr gRootInodePtr;
76static InodePtr gFileInodePtr;
77
78#else /* !__i386__ */
79
80static CICell gCurrentIH;
81static long long gPartitionBase;
82static char gDLBuf[8192];
83static char gFSBuf[SBSIZE];
84static struct fs *gFS;
85#if !BOOT1
86static struct ufslabel gUFSLabel; // for UUID
87#endif
88static long gBlockSize;
89static long gFragSize;
90static long gFragsPerBlock;
91static char *gTempBlock;
92static char gTempName[MAXNAMLEN + 1];
93static char gTempName2[MAXNAMLEN + 1];
94static Inode _gRootInode;
95static Inode _gFileInode;
96static InodePtr gRootInodePtr = &_gRootInode;
97static InodePtr gFileInodePtr = &_gFileInode;
98
99#endif /* !__i386__ */
100
101// Public functions
102
103void UFSFree(CICell ih)
104{
105 if(gCurrentIH == ih)
106 gCurrentIH = 0;
107 free(ih);
108}
109
110long UFSInitPartition( CICell ih )
111{
112#if !BOOT1
113 long ret;
114#endif
115
116 if (ih == gCurrentIH) {
117#ifdef __i386__
118 CacheInit(ih, gBlockSize);
119#endif
120 return 0;
121 }
122
123#if !BOOT1
124 verbose("UFSInitPartition: %x\n", ih);
125#endif
126
127 gCurrentIH = 0;
128
129#ifdef __i386__
130 if (!gULBuf) gULBuf = (char *) malloc(UFS_LABEL_SIZE);
131 if (!gFSBuf) gFSBuf = (char *) malloc(SBSIZE);
132 if (!gTempName) gTempName = (char *) malloc(MAXNAMLEN + 1);
133 if (!gTempName2) gTempName2 = (char *) malloc(MAXNAMLEN + 1);
134 if (!gRootInodePtr) gRootInodePtr = (InodePtr) malloc(sizeof(Inode));
135 if (!gFileInodePtr) gFileInodePtr = (InodePtr) malloc(sizeof(Inode));
136 if (!gULBuf || !gFSBuf || !gTempName || !gTempName2 ||
137 !gRootInodePtr || !gFileInodePtr) return -1;
138#endif
139
140 // Assume there is no Disk Label
141 gPartitionBase = 0;
142
143#if !BOOT1
144 // read the disk label to get the UUID
145 // (rumor has it that UFS headers can be either-endian on disk; hopefully
146 // that isn't true for this UUID field).
147 Seek(ih, gPartitionBase + UFS_LABEL_OFFSET);
148 ret = Read(ih, (long)&gUFSLabel, UFS_LABEL_SIZE);
149 if(ret != 0)
150 bzero(&gUFSLabel, UFS_LABEL_SIZE);
151#endif /* !BOOT1 */
152
153 // Look for the Super Block
154 Seek(ih, gPartitionBase + SBOFF);
155 Read(ih, (long)gFSBuf, SBSIZE);
156
157 gFS = (struct fs *)gFSBuf;
158 byte_swap_superblock(gFS);
159
160 if (gFS->fs_magic != FS_MAGIC) {
161 return -1;
162 }
163
164ih->modTime = gFS->fs_time;
165
166 // Calculate the block size and set up the block cache.
167 gBlockSize = gFS->fs_bsize;
168 gFragSize = gFS->fs_fsize;
169 gFragsPerBlock = gBlockSize / gFragSize;
170 if (gTempBlock != 0) free(gTempBlock);
171 gTempBlock = malloc(gBlockSize);
172 CacheInit(ih, gBlockSize);
173
174 gCurrentIH = ih;
175
176 // Read the Root Inode
177 ReadInode(ROOTINO, gRootInodePtr, 0, 0);
178
179 return 0;
180}
181
182#if !BOOT1
183
184long UFSGetUUID(CICell ih, char *uuidStr)
185{
186 long long uuid = gUFSLabel.ul_uuid;
187
188 if (UFSInitPartition(ih) == -1) return -1;
189 if (uuid == 0LL) return -1;
190
191 return CreateUUIDString((uint8_t*)(&uuid), sizeof(uuid), uuidStr);
192}
193
194#endif /* !BOOT1 */
195
196long UFSLoadFile( CICell ih, char * filePath )
197{
198 return UFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
199}
200
201long UFSReadFile( CICell ih, char * filePath, void * base, uint64_t offset, uint64_t length )
202{
203 long ret, flags;
204
205#if !BOOT1
206 verbose("Loading UFS file: [%s] from %x.\n", filePath, (unsigned)ih);
207#endif
208
209 if (UFSInitPartition(ih) == -1) return -1;
210
211 // Skip one or two leading '/'.
212 if (*filePath == '/') filePath++;
213 if (*filePath == '/') filePath++;
214
215 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
216 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
217
218 ret = ReadFile(gFileInodePtr, &length, base, offset);
219 if (ret == -1) return -1;
220
221 return length;
222}
223
224#ifndef BOOT1
225
226long UFSGetDirEntry( CICell ih, char * dirPath, long * dirIndex,
227 char ** name, long * flags, long * time,
228 FinderInfo * finderInfo, long * infoValid)
229{
230 long ret, fileInodeNum, dirFlags;
231 Inode tmpInode;
232
233 if (UFSInitPartition(ih) == -1) return -1;
234
235 if (infoValid) *infoValid = 0;
236
237 // Skip a leading '/' if present
238 if (*dirPath == '/') dirPath++;
239 if (*dirPath == '/') dirPath++;
240
241 ret = ResolvePathToInode(dirPath, &dirFlags, gFileInodePtr, gRootInodePtr);
242 if ((ret == -1) || ((dirFlags & kFileTypeMask) != kFileTypeDirectory))
243 return -1;
244
245 ret = ReadDirEntry(gFileInodePtr, &fileInodeNum, dirIndex, name);
246 if (ret != 0) return ret;
247
248 ReadInode(fileInodeNum, &tmpInode, flags, time);
249
250 return 0;
251}
252
253void
254UFSGetDescription(CICell ih, char *str, long strMaxLen)
255{
256 if (UFSInitPartition(ih) == -1) { return; }
257
258 struct ufslabel *ul;
259
260 // Look for the Disk Label
261 Seek(ih, 1ULL * UFS_LABEL_OFFSET);
262 Read(ih, (long)gULBuf, UFS_LABEL_SIZE);
263
264 ul = (struct ufslabel *)gULBuf;
265
266 unsigned char magic_bytes[] = UFS_LABEL_MAGIC;
267 int i;
268 unsigned char *p = (unsigned char *)&ul->ul_magic;
269
270 for (i=0; i<sizeof(magic_bytes); i++, p++) {
271 if (*p != magic_bytes[i])
272 return;
273 }
274 strncpy(str, (const char *)ul->ul_name, strMaxLen);
275}
276
277long
278UFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
279{
280 long ret, flags;
281
282 if (UFSInitPartition(ih) == -1) return -1;
283
284 // Skip one or two leading '/'.
285 if (*filePath == '/') filePath++;
286 if (*filePath == '/') filePath++;
287
288 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
289 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
290
291 *firstBlock = (gPartitionBase + 1ULL * gFileInodePtr->di_db[0] * gBlockSize) / 512ULL;
292
293 return 0;
294}
295
296
297#endif /* !BOOT1 */
298
299// Private functions
300
301static char * ReadBlock( long fragNum, long blockOffset, long length,
302 char * buffer, long cache )
303{
304 long long offset;
305 long blockNum;
306
307 blockNum = fragNum / gFragsPerBlock;
308 fragNum -= blockNum * gFragsPerBlock;
309
310 blockOffset += fragNum * gFragSize;
311
312 offset = gPartitionBase + 1ULL * blockNum * gBlockSize;
313
314 if (cache && ((blockOffset + length) <= gBlockSize)) {
315 CacheRead(gCurrentIH, gTempBlock, offset, gBlockSize, 1);
316 if (buffer != 0) bcopy(gTempBlock + blockOffset, buffer, length);
317 else buffer = gTempBlock + blockOffset;
318 } else {
319 offset += blockOffset;
320 CacheRead(gCurrentIH, buffer, offset, length, 0);
321 }
322
323 return buffer;
324}
325
326static long ReadInode( long inodeNum, InodePtr inode, long * flags, long * time )
327{
328 long fragNum = ino_to_fsba(gFS, inodeNum);
329 long blockOffset = ino_to_fsbo(gFS, inodeNum) * sizeof(Inode);
330
331 ReadBlock(fragNum, blockOffset, sizeof(Inode), (char *)inode, 1);
332 byte_swap_dinode_in(inode);
333
334 if (time != 0) *time = inode->di_mtime;
335
336 if (flags != 0) {
337 switch (inode->di_mode & IFMT) {
338 case IFREG: *flags = kFileTypeFlat; break;
339 case IFDIR: *flags = kFileTypeDirectory; break;
340 case IFLNK: *flags = kFileTypeLink; break;
341 default : *flags = kFileTypeUnknown; break;
342 }
343
344 *flags |= inode->di_mode & kPermMask;
345
346 if (inode->di_uid != 0) *flags |= kOwnerNotRoot;
347 }
348
349 return 0;
350}
351
352static long ResolvePathToInode( char * filePath, long * flags,
353 InodePtr fileInode, InodePtr dirInode )
354{
355 char * restPath;
356 long ret, cnt;
357
358 // if filePath is empty the we want this directory.
359 if (*filePath == '\0') {
360 bcopy((char *)dirInode, (char *)fileInode, sizeof(Inode));
361 return 0;
362 }
363
364 // Copy the file name to gTempName
365 cnt = 0;
366 while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
367 strlcpy(gTempName, filePath, cnt+1);
368
369 // Move restPath to the right place.
370 if (filePath[cnt] != '\0') cnt++;
371 restPath = filePath + cnt;
372
373 // gTempName is a name in the current Dir.
374 // restPath is the rest of the path if any.
375
376 ret = FindFileInDir(gTempName, flags, fileInode, dirInode);
377 if (ret == -1) return -1;
378
379 if ((*restPath != '\0') && ((*flags & kFileTypeMask) == kFileTypeDirectory))
380 ret = ResolvePathToInode(restPath, flags, fileInode, fileInode);
381
382 return ret;
383}
384
385static long ReadDirEntry( InodePtr dirInode, long * fileInodeNum,
386 long * dirIndex, char ** name )
387{
388 struct direct *dir;
389 char *buffer;
390 long index;
391 long dirBlockNum, dirBlockOffset;
392
393 while (1) {
394 index = *dirIndex;
395
396 dirBlockOffset = index % DIRBLKSIZ;
397 dirBlockNum = index / DIRBLKSIZ;
398
399 buffer = ReadFileBlock(dirInode, dirBlockNum, 0, DIRBLKSIZ, 0, 1);
400 if (buffer == 0) return -1;
401
402 dir = (struct direct *)(buffer + dirBlockOffset);
403 byte_swap_dir_block_in((char *)dir, 1);
404
405 *dirIndex += dir->d_reclen;
406
407 if (dir->d_ino != 0) break;
408
409 if (dirBlockOffset != 0) return -1;
410 }
411
412 *fileInodeNum = dir->d_ino;
413 *name = strlcpy(gTempName2, dir->d_name, dir->d_namlen+1);
414
415 return 0;
416}
417
418static long FindFileInDir( char * fileName, long * flags,
419 InodePtr fileInode, InodePtr dirInode )
420{
421 long ret, inodeNum, 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}
535

Archive Download this file

Revision: 429