3 Copyright (C) 1999 Benjamin Herrenschmidt
7 Copyright (C) 1996 Maurizio Plaza
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 Note: This version is way too slow due to the way we use bmap. This
25 should be replaced by an iterator.
34 #include "partition.h"
39 #define MAX_READ_RANGE 256
43 #include "linux/ext2_fs.h"
44 #include "ext2fs/ext2fs.h"
46 static int ext2_open( struct boot_file_t* file,
48 struct partition_t* part,
49 const char* file_name);
50 static int ext2_read( struct boot_file_t* file,
53 static int ext2_seek( struct boot_file_t* file,
55 static int ext2_close( struct boot_file_t* file);
57 struct fs_t ext2_filesystem =
66 /* IO manager structure for the ext2 library */
68 static errcode_t linux_open (const char *name, int flags, io_channel * channel);
69 static errcode_t linux_close (io_channel channel);
70 static errcode_t linux_set_blksize (io_channel channel, int blksize);
71 static errcode_t linux_read_blk (io_channel channel, unsigned long block, int count, void *data);
72 static errcode_t linux_write_blk (io_channel channel, unsigned long block, int count, const void *data);
73 static errcode_t linux_flush (io_channel channel);
75 static struct struct_io_manager struct_linux_manager =
77 EXT2_ET_MAGIC_IO_MANAGER,
87 static io_manager linux_io_manager = &struct_linux_manager;
89 /* Currently, we have a mess between what is in the file structure
90 * and what is stored globally here. I'll clean this up later
92 static int opened = 0; /* We can't open twice ! */
93 static unsigned int bs; /* Blocksize */
94 static unsigned long long doff; /* Byte offset where partition starts */
95 static ino_t root,cwd;
96 static ext2_filsys fs = 0;
97 static struct boot_file_t* cur_file;
98 static char *block_buffer = NULL;
101 static unsigned long read_range_start;
102 static unsigned long read_range_count;
103 static unsigned long read_last_logical;
104 static unsigned long read_total;
105 static unsigned long read_max;
106 static struct boot_file_t* read_cur_file;
107 static errcode_t read_result;
108 static char* read_buffer;
110 static int read_dump_range(void);
111 static int read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private);
112 #else /* FAST_VERSION */
113 static struct ext2_inode cur_inode;
114 #endif /* FAST_VERSION */
116 void com_err (const char *a, long i, const char *fmt,...)
118 prom_printf ((char *) fmt);
122 ext2_open( struct boot_file_t* file,
123 const char* dev_name,
124 struct partition_t* part,
125 const char* file_name)
128 int error = FILE_ERR_NOTFOUND;
129 static char buffer[1024];
136 prom_printf("ext2_open() : fs busy\n");
137 DEBUG_LEAVE(FILE_ERR_FSBUSY);
138 return FILE_ERR_FSBUSY;
140 if (file->device_kind != FILE_DEVICE_BLOCK) {
141 prom_printf("Can't open ext2 filesystem on non-block device\n");
142 DEBUG_LEAVE(FILE_ERR_BADDEV);
143 return FILE_ERR_BADDEV;
148 /* We don't care too much about the device block size since we run
149 * thru the deblocker. We may have to change that is we plan to be
150 * compatible with older versions of OF
155 doff = (unsigned long long)(part->part_start) * part->blocksize;
159 DEBUG_F("partition offset: %Lu\n", doff);
161 /* Open the OF device for the entire disk */
162 strncpy(buffer, dev_name, 1020);
163 strcat(buffer, ":0");
165 DEBUG_F("<%s>\n", buffer);
167 file->of_device = prom_open(buffer);
169 DEBUG_F("file->of_device = %p\n", file->of_device);
171 if (file->of_device == PROM_INVALID_HANDLE) {
173 DEBUG_F("Can't open device %p\n", file->of_device);
174 DEBUG_LEAVE(FILE_IOERR);
179 /* Open the ext2 filesystem */
180 result = ext2fs_open (buffer, EXT2_FLAG_RW, 0, 0, linux_io_manager, &fs);
183 if(result == EXT2_ET_BAD_MAGIC)
185 DEBUG_F( "ext2fs_open returned bad magic loading file %p\n",
190 DEBUG_F( "ext2fs_open error #%d while loading file %s\n",
193 error = FILE_ERR_BAD_FSYS;
197 /* Allocate the block buffer */
198 block_buffer = malloc(fs->blocksize * 2);
201 DEBUG_F("ext2fs: can't alloc block buffer (%d bytes)\n", fs->blocksize * 2);
206 /* Lookup file by pathname */
207 root = cwd = EXT2_ROOT_INO;
208 result = ext2fs_namei_follow(fs, root, cwd, file_name, &file->inode);
211 DEBUG_F("ext2fs_namei error #%d while loading file %s\n", result, file_name);
212 if (result == EXT2_ET_SYMLINK_LOOP)
213 error = FILE_ERR_SYMLINK_LOOP;
214 else if (result == EXT2_ET_FILE_NOT_FOUND)
215 error = FILE_ERR_NOTFOUND;
222 result = ext2fs_follow_link(fs, root, cwd, file->inode, &file->inode);
225 DEBUG_F("ext2fs_follow_link error #%d while loading file %s\n", result, file_name);
226 error = FILE_ERR_NOTFOUND;
232 result = ext2fs_read_inode(fs, file->inode, &cur_inode);
235 DEBUG_F("ext2fs_read_inode error #%d while loading file %s\n", result, file_name);
236 if (result == EXT2_ET_FILE_TOO_BIG)
237 error = FILE_ERR_LENGTH;
238 else if (result == EXT2_ET_LLSEEK_FAILED)
239 error = FILE_CANT_SEEK;
240 else if (result == EXT2_ET_FILE_NOT_FOUND)
241 error = FILE_ERR_NOTFOUND;
246 #endif /* FAST_VERSION */
256 prom_close(file->of_device);
262 DEBUG_LEAVE_F(error);
266 DEBUG_LEAVE(FILE_ERR_OK);
273 read_dump_range(void)
275 int count = read_range_count;
279 DEBUG_F(" dumping range: start: 0x%x count: 0x%x\n",
280 read_range_count, read_range_start);
282 /* Check if we need to handle a special case for the last block */
283 if ((count * bs) > read_max)
287 read_result = io_channel_read_blk(fs->io, read_range_start, count, read_buffer);
293 read_cur_file->pos += size;
294 read_range_count -= count;
295 read_range_start += count;
296 read_last_logical += count;
298 /* Handle remaining block */
299 if (read_max && read_range_count) {
300 read_result = io_channel_read_blk(fs->io, read_range_start, 1, block_buffer);
303 memcpy(read_buffer, block_buffer, read_max);
304 read_cur_file->pos += read_max;
305 read_total += read_max;
308 read_range_count = read_range_start = 0;
310 return (read_max == 0) ? BLOCK_ABORT : 0;
314 read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private)
317 DEBUG_F("read_it: p_bloc: 0x%x, l_bloc: 0x%x, f_pos: 0x%x, rng_pos: 0x%x ",
318 *blocknr, lg_block, read_cur_file->pos, read_last_logical);
322 DEBUG_F(" <skip lg>\n");
327 /* If we have not reached the start block yet, we skip */
328 if (lg_block < read_cur_file->pos / bs) {
330 DEBUG_F(" <skip pos>\n");
335 /* If block is contiguous to current range, just extend range,
336 * exit if we pass the remaining bytes count to read
338 if (read_range_start && read_range_count < MAX_READ_RANGE
339 && (*blocknr == read_range_start + read_range_count)
340 && (lg_block == read_last_logical + read_range_count)) {
342 DEBUG_F(" block in range\n");
345 return ((read_range_count * bs) >= read_max) ? BLOCK_ABORT : 0;
348 /* Range doesn't match. Dump existing range */
349 if (read_range_start) {
351 DEBUG_F(" calling dump range \n");
353 if (read_dump_range())
357 /* Here we handle holes in the file */
358 if (lg_block && lg_block != read_last_logical) {
361 DEBUG_F(" hole from lg_bloc 0x%x\n", read_last_logical);
363 if (read_cur_file->pos % bs) {
364 int offset = read_cur_file->pos % bs;
365 int size = bs - offset;
368 memset(read_buffer, 0, size);
372 read_cur_file->pos += size;
377 nzero = (lg_block - read_last_logical) * bs;
379 if (nzero > read_max)
381 memset(read_buffer, 0, nzero);
384 read_buffer += nzero;
385 read_cur_file->pos += nzero;
389 read_last_logical = lg_block;
392 /* If we are not aligned, handle that case */
393 if (read_cur_file->pos % bs) {
394 int offset = read_cur_file->pos % bs;
395 int size = bs - offset;
397 DEBUG_F(" handle unaligned start\n");
399 read_result = io_channel_read_blk(fs->io, *blocknr, 1, block_buffer);
404 memcpy(read_buffer, block_buffer + offset, size);
405 read_cur_file->pos += size;
409 read_last_logical = lg_block + 1;
410 return (read_max == 0) ? BLOCK_ABORT : 0;
413 /* If there is still a physical block to add, then create a new range */
416 DEBUG_F(" new range\n");
418 read_range_start = *blocknr;
419 read_range_count = 1;
420 return (bs >= read_max) ? BLOCK_ABORT : 0;
429 #endif /* FAST_VERSION */
432 ext2_read( struct boot_file_t* file,
443 DEBUG_F("ext_read() from pos 0x%Lx, size: 0x%ux\n", file->pos, size);
446 read_cur_file = file;
447 read_range_start = 0;
448 read_range_count = 0;
449 read_last_logical = file->pos / bs;
452 read_buffer = (unsigned char*)buffer;
455 retval = ext2fs_block_iterate(fs, file->inode, 0, 0, read_iterator, 0);
456 if (retval == BLOCK_ABORT)
457 retval = read_result;
458 if (!retval && read_range_start) {
460 DEBUG_F("on exit: range_start is 0x%x, calling dump...\n",
464 retval = read_result;
467 prom_printf ("ext2: i/o error %ld in read\n", (long) retval);
471 #else /* FAST_VERSION */
473 unsigned int read = 0;
479 DEBUG_F("ext_read() from pos 0x%x, size: 0x%x\n", file->pos, size);
483 blk_t fblock = file->pos / bs;
485 unsigned int blkorig, s, b;
488 status = ext2fs_bmap(fs, file->inode, &cur_inode,
489 block_buffer, 0, fblock, &pblock);
492 DEBUG_F("ext2fs_bmap(fblock:%d) return: %d\n", fblock, status);
495 blkorig = fblock * bs;
496 b = file->pos - blkorig;
497 s = ((bs - b) > size) ? size : (bs - b);
499 unsigned long long pos =
500 ((unsigned long long)pblock) * (unsigned long long)bs;
502 prom_lseek(file->of_device, pos);
503 status = prom_read(file->of_device, block_buffer, bs);
505 prom_printf("ext2: io error in read, ex: %d, got: %d\n",
510 memset(block_buffer, 0, bs);
512 memcpy(buffer, block_buffer + b, s);
519 #endif /* FAST_VERSION */
523 ext2_seek( struct boot_file_t* file,
527 return FILE_CANT_SEEK;
534 ext2_close( struct boot_file_t* file)
547 prom_close(file->of_device);
548 DEBUG_F("ext2_close called\n");
555 static errcode_t linux_open (const char *name, int flags, io_channel * channel)
561 return EXT2_ET_BAD_DEVICE_NAME;
562 io = (io_channel) malloc (sizeof (struct struct_io_channel));
564 return EXT2_ET_BAD_DEVICE_NAME;
565 memset (io, 0, sizeof (struct struct_io_channel));
566 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
567 io->manager = linux_io_manager;
568 io->name = (char *) malloc (strlen (name) + 1);
569 strcpy (io->name, name);
578 static errcode_t linux_close (io_channel channel)
584 static errcode_t linux_set_blksize (io_channel channel, int blksize)
586 channel->block_size = bs = blksize;
589 block_buffer = malloc(bs * 2);
594 static errcode_t linux_read_blk (io_channel channel, unsigned long block, int count, void *data)
597 unsigned long long tempb;
602 tempb = (((unsigned long long) block) *
603 ((unsigned long long)bs)) + (unsigned long long)doff;
604 size = (count < 0) ? -count : count * bs;
605 prom_lseek(cur_file->of_device, tempb);
606 if (prom_read(cur_file->of_device, data, size) != size) {
607 DEBUG_F("\nRead error on block %ld\n", block);
608 return EXT2_ET_SHORT_READ;
613 static errcode_t linux_write_blk (io_channel channel, unsigned long block, int count, const void *data)
618 static errcode_t linux_flush (io_channel channel)