Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 515