Root/
Source at commit 284 created 13 years 10 months ago. By blackosx, Amended my mistake by updating the Default theme images in the trunk. Now put them back as they were.. (Sorry) | |
---|---|
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 | ␊ |
39 | typedef struct dinode Inode, *InodePtr;␊ |
40 | ␊ |
41 | // Private function prototypes␊ |
42 | ␊ |
43 | static char *ReadBlock(long fragNum, long fragOffset, long length,␊ |
44 | char *buffer, long cache);␊ |
45 | static long ReadInode(long inodeNum, InodePtr inode, long *flags, long *time);␊ |
46 | static long ResolvePathToInode(char *filePath, long *flags,␊ |
47 | InodePtr fileInode, InodePtr dirInode);␊ |
48 | static long ReadDirEntry(InodePtr dirInode, long *fileInodeNum,␊ |
49 | long *dirIndex, char **name);␊ |
50 | static long FindFileInDir(char *fileName, long *flags,␊ |
51 | InodePtr fileInode, InodePtr dirInode);␊ |
52 | static char *ReadFileBlock(InodePtr fileInode, long fragNum, long blockOffset,␊ |
53 | long length, char *buffer, long cache);␊ |
54 | static 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 | ␊ |
61 | static CICell gCurrentIH;␊ |
62 | static long long gPartitionBase;␊ |
63 | static char *gULBuf;␊ |
64 | static char *gFSBuf;␊ |
65 | static struct fs *gFS;␊ |
66 | #if !BOOT1␊ |
67 | static struct ufslabel gUFSLabel; // for UUID␊ |
68 | #endif␊ |
69 | static long gBlockSize;␊ |
70 | static long gFragSize;␊ |
71 | static long gFragsPerBlock;␊ |
72 | static char *gTempBlock;␊ |
73 | static char *gTempName;␊ |
74 | static char *gTempName2;␊ |
75 | static InodePtr gRootInodePtr;␊ |
76 | static InodePtr gFileInodePtr;␊ |
77 | ␊ |
78 | #else /* !__i386__ */␊ |
79 | ␊ |
80 | static CICell gCurrentIH;␊ |
81 | static long long gPartitionBase;␊ |
82 | static char gDLBuf[8192];␊ |
83 | static char gFSBuf[SBSIZE];␊ |
84 | static struct fs *gFS;␊ |
85 | #if !BOOT1␊ |
86 | static struct ufslabel gUFSLabel; // for UUID␊ |
87 | #endif␊ |
88 | static long gBlockSize;␊ |
89 | static long gFragSize;␊ |
90 | static long gFragsPerBlock;␊ |
91 | static char *gTempBlock;␊ |
92 | static char gTempName[MAXNAMLEN + 1];␊ |
93 | static char gTempName2[MAXNAMLEN + 1];␊ |
94 | static Inode _gRootInode;␊ |
95 | static Inode _gFileInode;␊ |
96 | static InodePtr gRootInodePtr = &_gRootInode;␊ |
97 | static InodePtr gFileInodePtr = &_gFileInode;␊ |
98 | ␊ |
99 | #endif /* !__i386__ */␊ |
100 | ␊ |
101 | // Public functions␊ |
102 | ␊ |
103 | void UFSFree(CICell ih)␊ |
104 | {␊ |
105 | if(gCurrentIH == ih)␊ |
106 | gCurrentIH = 0;␊ |
107 | free(ih);␊ |
108 | }␊ |
109 | ␊ |
110 | long 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 | ␊ |
164 | ␉ih->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 | ␊ |
184 | long 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 | ␊ |
196 | long UFSLoadFile( CICell ih, char * filePath )␊ |
197 | {␊ |
198 | return UFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);␊ |
199 | }␊ |
200 | ␊ |
201 | long 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 | ␊ |
226 | long 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 | ␊ |
253 | void␊ |
254 | UFSGetDescription(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 | ␊ |
277 | long␊ |
278 | UFSGetFileBlock(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 | ␊ |
301 | static 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 | ␊ |
326 | static 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 | ␊ |
352 | static 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 | ␊ |
385 | static 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 | ␊ |
418 | static 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 | ␊ |
436 | static 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 | ␊ |
493 | static 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 |