Chameleon Applications

Chameleon Applications Svn Source Tree

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

Source at commit 214 created 13 years 5 months ago.
By ifabio, update to chameleon trunk 630, and now the pakage folder is the same as blackosx branch, also add Icon "building" into buildpkg script, and add mint theme info into the English localizable.strings.
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 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

Archive Download this file

Revision: 214