Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Cleancut/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#if 0
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 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 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 long * dirIndex, char ** name )
387{
388 struct direct *dir;
389 char *buffer;
390 long long index;
391 long dirBlockNum, dirBlockOffset;
392
393 while (1) {
394 index = *dirIndex;
395
396 dirBlockOffset = (long) (index % DIRBLKSIZ);
397 dirBlockNum = (long) (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;
422 long long index = 0;
423 char *name;
424
425 while (1) {
426 ret = ReadDirEntry(dirInode, &inodeNum, &index, &name);
427 if (ret == -1) return -1;
428
429 if (strcmp(fileName, name) == 0) break;
430 }
431
432 ReadInode(inodeNum, fileInode, flags, 0);
433
434 return 0;
435}
436
437static char * ReadFileBlock( InodePtr fileInode, long fragNum, long blockOffset,
438 long length, char * buffer, long cache )
439{
440 long fragCount, blockNum;
441 long diskFragNum, indFragNum, indBlockOff, refsPerBlock;
442 char *indBlock;
443
444 fragCount = (fileInode->di_size + gFragSize - 1) / gFragSize;
445 if (fragNum >= fragCount) return 0;
446
447 refsPerBlock = gBlockSize / sizeof(ufs_daddr_t);
448
449 blockNum = fragNum / gFragsPerBlock;
450 fragNum -= blockNum * gFragsPerBlock;
451
452 // Get Direct Block Number.
453 if (blockNum < NDADDR) {
454 diskFragNum = fileInode->di_db[blockNum];
455 } else {
456 blockNum -= NDADDR;
457
458 // Get Single Indirect Fragment Number.
459 if (blockNum < refsPerBlock) {
460 indFragNum = fileInode->di_ib[0];
461 } else {
462 blockNum -= refsPerBlock;
463
464 // Get Double Indirect Fragment Number.
465 if (blockNum < (refsPerBlock * refsPerBlock)) {
466 indFragNum = fileInode->di_ib[1];
467 } else {
468 blockNum -= refsPerBlock * refsPerBlock;
469
470 // Get Triple Indirect Fragment Number.
471 indFragNum = fileInode->di_ib[2];
472
473 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
474 indBlockOff = blockNum / (refsPerBlock * refsPerBlock);
475 blockNum %= (refsPerBlock * refsPerBlock);
476 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
477 }
478
479 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
480 indBlockOff = blockNum / refsPerBlock;
481 blockNum %= refsPerBlock;
482 indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]);
483 }
484
485 indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1);
486 diskFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[blockNum]);
487 }
488
489 buffer = ReadBlock(diskFragNum+fragNum, blockOffset, length, buffer, cache);
490
491 return buffer;
492}
493
494static long ReadFile( InodePtr fileInode, uint64_t * length, void * base, uint64_t offset )
495{
496 long bytesLeft, curSize, curFrag;
497 char *buffer, *curAddr = (char *)base;
498
499 bytesLeft = fileInode->di_size;
500
501 if (offset > bytesLeft) {
502 printf("Offset is too large.\n");
503 return -1;
504 }
505
506 if ((*length == 0) || ((offset + *length) > bytesLeft)) {
507 *length = bytesLeft - offset;
508 }
509/*
510 if (bytesLeft > kLoadSize) {
511 printf("File is too large.\n");
512 return -1;
513 }
514*/
515 bytesLeft = *length;
516 curFrag = (offset / gBlockSize) * gFragsPerBlock;
517 offset %= gBlockSize;
518
519 while (bytesLeft) {
520 curSize = gBlockSize;
521 if (curSize > bytesLeft) curSize = bytesLeft;
522 if ((offset + curSize) > gBlockSize) curSize = (gBlockSize - offset);
523
524 buffer = ReadFileBlock(fileInode, curFrag, offset, curSize, curAddr, 0);
525 if (buffer == 0) break;
526
527 if (offset != 0) offset = 0;
528
529 curFrag += gFragsPerBlock;
530 curAddr += curSize;
531 bytesLeft -= curSize;
532 }
533
534 return bytesLeft;
535}
536#endif

Archive Download this file

Revision: 899