Chameleon

Chameleon Svn Source Tree

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

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);
171if (!gTempBlock) return -1;
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, long strMaxLen)
185{
186 (void)strMaxLen;
187
188 long long uuid = gUFSLabel.ul_uuid;
189
190 if (UFSInitPartition(ih) == -1) return -1;
191 if (uuid == 0LL) return -1;
192
193 return CreateUUIDString((uint8_t*)(&uuid), sizeof(uuid), uuidStr, strMaxLen);
194}
195
196#endif /* !BOOT1 */
197
198long UFSLoadFile( CICell ih, char * filePath )
199{
200return UFSReadFile(ih, filePath, (void *)(uint32_t)get_env(envgFSLoadAddress), 0, 0);
201
202}
203
204long UFSReadFile( CICell ih, char * filePath, void * base, uint64_t offset, uint64_t length )
205{
206 long ret, flags;
207
208#if !BOOT1
209 verbose("Loading UFS file: [%s] from %x.\n", filePath, (unsigned)ih);
210#endif
211
212 if (UFSInitPartition(ih) == -1) return -1;
213
214 // Skip one or two leading '/'.
215 if (*filePath == '/') filePath++;
216 if (*filePath == '/') filePath++;
217
218 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
219 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
220
221 ret = ReadFile(gFileInodePtr, &length, base, offset);
222 if (ret == -1) return -1;
223
224 return length;
225}
226
227#ifndef BOOT1
228
229long UFSGetDirEntry( CICell ih, char * dirPath, long long * dirIndex,
230 char ** name, long * flags, long * time,
231 FinderInfo * finderInfo, long * infoValid)
232{
233 long ret, fileInodeNum, dirFlags;
234 Inode tmpInode;
235
236 if (UFSInitPartition(ih) == -1) return -1;
237
238 if (infoValid) *infoValid = 0;
239
240 // Skip a leading '/' if present
241 if (*dirPath == '/') dirPath++;
242 if (*dirPath == '/') dirPath++;
243
244 ret = ResolvePathToInode(dirPath, &dirFlags, gFileInodePtr, gRootInodePtr);
245 if ((ret == -1) || ((dirFlags & kFileTypeMask) != kFileTypeDirectory))
246 return -1;
247
248 ret = ReadDirEntry(gFileInodePtr, &fileInodeNum, dirIndex, name);
249 if (ret != 0) return ret;
250
251 ReadInode(fileInodeNum, &tmpInode, flags, time);
252
253 return 0;
254}
255
256void
257UFSGetDescription(CICell ih, char *str, long strMaxLen)
258{
259 if (UFSInitPartition(ih) == -1) { return; }
260
261 struct ufslabel *ul;
262
263 // Look for the Disk Label
264 Seek(ih, 1ULL * UFS_LABEL_OFFSET);
265 Read(ih, (long)gULBuf, UFS_LABEL_SIZE);
266
267 ul = (struct ufslabel *)gULBuf;
268
269 unsigned char magic_bytes[] = UFS_LABEL_MAGIC;
270 int i;
271 unsigned char *p = (unsigned char *)&ul->ul_magic;
272
273 for (i=0; i<sizeof(magic_bytes); i++, p++) {
274 if (*p != magic_bytes[i])
275 return;
276 }
277 strncpy(str, (const char *)ul->ul_name, strMaxLen);
278}
279
280long
281UFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
282{
283 long ret, flags;
284
285 if (UFSInitPartition(ih) == -1) return -1;
286
287 // Skip one or two leading '/'.
288 if (*filePath == '/') filePath++;
289 if (*filePath == '/') filePath++;
290
291 ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
292 if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
293
294 *firstBlock = (gPartitionBase + 1ULL * gFileInodePtr->di_db[0] * gBlockSize) / 512ULL;
295
296 return 0;
297}
298
299
300#endif /* !BOOT1 */
301
302// Private functions
303
304static char * ReadBlock( long fragNum, long blockOffset, long length,
305 char * buffer, long cache )
306{
307 long long offset;
308 long blockNum;
309
310 blockNum = fragNum / gFragsPerBlock;
311 fragNum -= blockNum * gFragsPerBlock;
312
313 blockOffset += fragNum * gFragSize;
314
315 offset = gPartitionBase + 1ULL * blockNum * gBlockSize;
316
317 if (cache && ((blockOffset + length) <= gBlockSize)) {
318 CacheRead(gCurrentIH, gTempBlock, offset, gBlockSize, 1);
319 if (buffer != 0) bcopy(gTempBlock + blockOffset, buffer, length);
320 else buffer = gTempBlock + blockOffset;
321 } else {
322 offset += blockOffset;
323 CacheRead(gCurrentIH, buffer, offset, length, 0);
324 }
325
326 return buffer;
327}
328
329static long ReadInode( long inodeNum, InodePtr inode, long * flags, long * time )
330{
331 long fragNum = ino_to_fsba(gFS, inodeNum);
332 long blockOffset = ino_to_fsbo(gFS, inodeNum) * sizeof(Inode);
333
334 ReadBlock(fragNum, blockOffset, sizeof(Inode), (char *)inode, 1);
335 byte_swap_dinode_in(inode);
336
337 if (time != 0) *time = inode->di_mtime;
338
339 if (flags != 0) {
340 switch (inode->di_mode & IFMT) {
341 case IFREG: *flags = kFileTypeFlat; break;
342 case IFDIR: *flags = kFileTypeDirectory; break;
343 case IFLNK: *flags = kFileTypeLink; break;
344 default : *flags = kFileTypeUnknown; break;
345 }
346
347 *flags |= inode->di_mode & kPermMask;
348
349 if (inode->di_uid != 0) *flags |= kOwnerNotRoot;
350 }
351
352 return 0;
353}
354
355static long ResolvePathToInode( char * filePath, long * flags,
356 InodePtr fileInode, InodePtr dirInode )
357{
358 char * restPath;
359 long ret, cnt;
360
361 // if filePath is empty the we want this directory.
362 if (*filePath == '\0') {
363 bcopy((char *)dirInode, (char *)fileInode, sizeof(Inode));
364 return 0;
365 }
366
367 // Copy the file name to gTempName
368 cnt = 0;
369 while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
370 strlcpy(gTempName, filePath, cnt+1);
371
372 // Move restPath to the right place.
373 if (filePath[cnt] != '\0') cnt++;
374 restPath = filePath + cnt;
375
376 // gTempName is a name in the current Dir.
377 // restPath is the rest of the path if any.
378
379 ret = FindFileInDir(gTempName, flags, fileInode, dirInode);
380 if (ret == -1) return -1;
381
382 if ((*restPath != '\0') && ((*flags & kFileTypeMask) == kFileTypeDirectory))
383 ret = ResolvePathToInode(restPath, flags, fileInode, fileInode);
384
385 return ret;
386}
387
388static long ReadDirEntry( InodePtr dirInode, long * fileInodeNum,
389 long long * dirIndex, char ** name )
390{
391 struct direct *dir;
392 char *buffer;
393 long long index;
394 long dirBlockNum, dirBlockOffset;
395
396 while (1) {
397 index = *dirIndex;
398
399 dirBlockOffset = (long) (index % DIRBLKSIZ);
400 dirBlockNum = (long) (index / DIRBLKSIZ);
401
402 buffer = ReadFileBlock(dirInode, dirBlockNum, 0, DIRBLKSIZ, 0, 1);
403 if (buffer == 0) return -1;
404
405 dir = (struct direct *)(buffer + dirBlockOffset);
406 byte_swap_dir_block_in((char *)dir, 1);
407
408 *dirIndex += dir->d_reclen;
409
410 if (dir->d_ino != 0) break;
411
412 if (dirBlockOffset != 0) return -1;
413 }
414
415 *fileInodeNum = dir->d_ino;
416 *name = strlcpy(gTempName2, dir->d_name, dir->d_namlen+1);
417
418 return 0;
419}
420
421static long FindFileInDir( char * fileName, long * flags,
422 InodePtr fileInode, InodePtr dirInode )
423{
424 long ret, inodeNum;
425 long long index = 0;
426 char *name;
427
428 while (1) {
429 ret = ReadDirEntry(dirInode, &inodeNum, &index, &name);
430 if (ret == -1) return -1;
431
432 if (strcmp(fileName, name) == 0) break;
433 }
434
435 ReadInode(inodeNum, fileInode, flags, 0);
436
437 return 0;
438}
439
440static char * ReadFileBlock( InodePtr fileInode, long fragNum, long blockOffset,
441 long length, char * buffer, long cache )
442{
443 long fragCount, blockNum;
444 long diskFragNum, indFragNum, indBlockOff, refsPerBlock;
445 char *indBlock;
446
447 fragCount = (fileInode->di_size + gFragSize - 1) / gFragSize;
448 if (fragNum >= fragCount) return 0;
449
450 refsPerBlock = gBlockSize / sizeof(ufs_daddr_t);
451
452 blockNum = fragNum / gFragsPerBlock;
453 fragNum -= blockNum * gFragsPerBlock;
454
455 // Get Direct Block Number.
456 if (blockNum < NDADDR) {
457 diskFragNum = fileInode->di_db[blockNum];
458 } else {
459 blockNum -= NDADDR;
460
461 // Get Single Indirect Fragment Number.
462 if (blockNum < refsPerBlock) {
463 indFragNum = fileInode->di_ib[0];
464 } else {
465 blockNum -= refsPerBlock;
466
467 // Get Double Indirect Fragment Number.
468 if (blockNum < (refsPerBlock * refsPerBlock)) {
469 indFragNum = fileInode->di_ib[1];
470 } else {
471 blockNum -= refsPerBlock * refsPerBlock;
472
473 // Get Triple Indirect Fragment Number.
474 indFragNum = fileInode->di_ib[2];
475
476 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
477 indBlockOff = blockNum / (refsPerBlock * refsPerBlock);
478 blockNum %= (refsPerBlock * refsPerBlock);
479 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
480 }
481
482 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
483 indBlockOff = blockNum / refsPerBlock;
484 blockNum %= refsPerBlock;
485 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
486 }
487
488 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
489 diskFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[blockNum]);
490 }
491
492 buffer = ReadBlock(diskFragNum+fragNum, blockOffset, length, buffer, cache);
493
494 return buffer;
495}
496
497static long ReadFile( InodePtr fileInode, uint64_t * length, void * base, uint64_t offset )
498{
499 long bytesLeft, curSize, curFrag;
500 char *buffer, *curAddr = (char *)base;
501
502 bytesLeft = fileInode->di_size;
503
504 if (offset > bytesLeft) {
505 printf("Offset is too large.\n");
506 return -1;
507 }
508
509 if ((*length == 0) || ((offset + *length) > bytesLeft)) {
510 *length = bytesLeft - offset;
511 }
512/*
513 if (bytesLeft > kLoadSize) {
514 printf("File is too large.\n");
515 return -1;
516 }
517*/
518 bytesLeft = *length;
519 curFrag = (offset / gBlockSize) * gFragsPerBlock;
520 offset %= gBlockSize;
521
522 while (bytesLeft) {
523 curSize = gBlockSize;
524 if (curSize > bytesLeft) curSize = bytesLeft;
525 if ((offset + curSize) > gBlockSize) curSize = (gBlockSize - offset);
526
527 buffer = ReadFileBlock(fileInode, curFrag, offset, curSize, curAddr, 0);
528 if (buffer == 0) break;
529
530 if (offset != 0) offset = 0;
531
532 curFrag += gFragsPerBlock;
533 curAddr += curSize;
534 bytesLeft -= curSize;
535 }
536
537 return bytesLeft;
538}

Archive Download this file

Revision: HEAD