2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * This file is part of the ELILO, the EFI Linux boot loader.
7 * ELILO is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * ELILO is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with ELILO; see the file COPYING. If not, write to the Free
19 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 * Please check out the elilo.txt for complete documentation on how
23 * to use this program.
25 * The ext2 code in this file is derived from aboot-0.7 (the Linux/Alpha
26 * bootloader) and credits are attributed to:
28 * This file has been ported from the DEC 32-bit Linux version
29 * by David Mosberger (davidm@cs.arizona.edu).
37 #define FS_NAME L"ext2fs"
40 #error You must have included some Linux header file by error
44 #define EXT2FS_PATH_MAXLEN PATH_MAX
46 #include "fs/ext2fs.h"
47 #include "fs/ext2_private.h"
50 * should we decide to spin off ext2, let's say to a boottime driver
51 * we would have to change this
53 #define EXT2FS_MEMTYPE EfiLoaderData
55 /* ext2 file size is __u32 */
56 #define EXT2_FILESIZE_MAX (0x100000000UL)
59 * Number of simultaneous open files. This needs to be high because
60 * directories are kept open while traversing long path names.
62 #define MAX_OPEN_FILES 32
64 typedef struct inode_table_entry {
65 struct ext2_inode inode;
68 unsigned short old_mode;
70 UINT32 pos; /* current position in file ext2 uses __u32 !*/
75 struct ext2_super_block sb;
76 struct ext2_group_desc *gds;
77 struct ext2_inode *root_inode;
79 int directlim; /* Maximum direct blkno */
80 int ind1lim; /* Maximum single-indir blkno */
81 int ind2lim; /* Maximum double-indir blkno */
82 int ptrs_per_blk; /* ptrs/indirect block */
83 CHAR8 blkbuf[EXT2_MAX_BLOCK_SIZE];
85 CHAR8 iblkbuf[EXT2_MAX_BLOCK_SIZE];
87 CHAR8 diblkbuf[EXT2_MAX_BLOCK_SIZE];
91 inode_entry_t inode_table[MAX_OPEN_FILES];
93 /* fields added to fit the protocol construct */
97 } ext2fs_priv_state_t;
101 ext2fs_interface_t pub_intf;
103 ext2fs_interface_t pub_intf;
104 ext2fs_priv_state_t priv_data;
108 #define FS_PRIVATE(n) (&(((ext2fs_t *)n)->ext2fs_priv.priv_data))
115 static dev_tab_t *dev_tab; /* holds all devices we found */
116 static UINTN ndev; /* how many entries in dev_tab */
119 static EFI_GUID Ext2FsProtocol = EXT2FS_PROTOCOL;
122 read_bytes(EFI_BLOCK_IO *blkio, UINT32 mediaid, UINTN offset, VOID *addr, UINTN size)
126 UINTN count, buffer_size;
128 INTN ret = EFI_INVALID_PARAMETER;
130 base = offset / blkio->Media->BlockSize;
131 count = (size + blkio->Media->BlockSize -1) / blkio->Media->BlockSize;
132 buffer_size = count * blkio->Media->BlockSize;
134 DBG_PRT((L"readblock(%x, %d,%d) base=%d count=%d", blkio, offset, size, base, count));
137 * slow but avoid large buffer on the stack
139 buffer = (UINT8 *)alloc(buffer_size, EfiLoaderData);
140 if (buffer == NULL) {
141 ERR_PRT((L"cannot allocate ext2fs buffer size=%d", buffer_size));
145 DBG_PRT((L"readblock(%x, %d, %d, %d, %x)", blkio, mediaid, base, buffer_size, buffer));
147 status = uefi_call_wrapper(blkio->ReadBlocks, 5, blkio, mediaid, base, buffer_size, buffer);
148 if (EFI_ERROR(status)) {
149 ERR_PRT((L"readblock(%d,%d)=%r", base, buffer_size, status));
153 DBG_PRT((L"readblock(%d,%d)->%r", offset, buffer_size, status));
155 Memcpy(addr, buffer+(offset-(base*blkio->Media->BlockSize)), size);
166 * Read the specified inode from the disk and return it to the user.
167 * Returns NULL if the inode can't be read...
169 static struct ext2_inode *
170 ext2_iget(ext2fs_priv_state_t *e2fs, int ino)
173 struct ext2_inode *ip;
174 struct inode_table_entry *itp = 0;
179 for (i = 0; i < MAX_OPEN_FILES; i++) {
180 DBG_PRT((L"ext2_iget: looping, entry %d inode %d free %d",
181 i, e2fs->inode_table[i].inumber, e2fs->inode_table[i].free));
182 if (e2fs->inode_table[i].free) {
183 itp = &e2fs->inode_table[i];
189 ERR_PRT((L"ext2_iget: no free inodes"));
194 group = (ino-1) / e2fs->sb.s_inodes_per_group;
196 DBG_PRT((L" itp-inode_table=%d bg_inode_table=%d group=%d ino=%d\n", (UINTN)(itp-e2fs->inode_table),
197 (UINTN)(e2fs->gds[group].bg_inode_table), (UINTN)group, (UINTN)ino));
199 offset = ((long) e2fs->gds[group].bg_inode_table * e2fs->blocksize)
200 + (((ino - 1) % EXT2_INODES_PER_GROUP(&e2fs->sb)) * EXT2_INODE_SIZE(&e2fs->sb));
202 DBG_PRT((L"ext2_iget: reading %d bytes at offset %d"
203 " ((%d * %d) + ((%d) %% %d) * %d) "
204 "(inode %d -> table %d)",
205 sizeof(struct ext2_inode),
207 (UINTN)e2fs->gds[group].bg_inode_table, (UINTN)e2fs->blocksize,
208 (UINTN)(ino - 1), (UINTN)EXT2_INODES_PER_GROUP(&e2fs->sb), EXT2_INODE_SIZE(&e2fs->sb),
209 (UINTN)ino, (UINTN) (itp - e2fs->inode_table)));
211 if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, ip, sizeof(struct ext2_inode))) {
212 ERR_PRT((L"ext2_iget: read error"));
216 DBG_PRT((L"mode=%x uid=%d size=%d gid=%d links=%d flags=%d",
221 (UINTN)ip->i_flags));
225 itp->old_mode = ip->i_mode;
232 * Release our hold on an inode. Since this is a read-only application,
233 * don't worry about putting back any changes...
236 ext2_iput(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip)
238 struct inode_table_entry *itp;
240 /* Find and free the inode table slot we used... */
241 itp = (struct inode_table_entry *)ip;
243 DBG_PRT((L"ext2_iput: inode %d table %d", itp->inumber, (int) (itp - e2fs->inode_table)));
251 * Map a block offset into a file into an absolute block number.
252 * (traverse the indirect blocks if necessary). Note: Double-indirect
253 * blocks allow us to map over 64Mb on a 1k file system. Therefore, for
254 * our purposes, we will NOT bother with triple indirect blocks.
256 * The "allocate" argument is set if we want to *allocate* a block
257 * and we don't already have one allocated.
260 ext2_blkno(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, int blkoff)
270 ilp = (unsigned int *)e2fs->iblkbuf;
271 dlp = (unsigned int *)e2fs->diblkbuf;
272 lp = (unsigned int *)e2fs->blkbuf;
274 /* If it's a direct block, it's easy! */
275 if (blkoff <= e2fs->directlim) {
276 return ip->i_block[blkoff];
279 /* Is it a single-indirect? */
280 if (blkoff <= e2fs->ind1lim) {
281 iblkno = ip->i_block[EXT2_IND_BLOCK];
287 /* Read the indirect block */
288 if (e2fs->cached_iblkno != iblkno) {
289 offset = iblkno * e2fs->blocksize;
290 if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) {
291 ERR_PRT((L"ext2_blkno: error on iblk read"));
294 e2fs->cached_iblkno = iblkno;
297 blkno = ilp[blkoff-(e2fs->directlim+1)];
301 /* Is it a double-indirect? */
302 if (blkoff <= e2fs->ind2lim) {
303 /* Find the double-indirect block */
304 diblkno = ip->i_block[EXT2_DIND_BLOCK];
310 /* Read in the double-indirect block */
311 if (e2fs->cached_diblkno != diblkno) {
312 offset = diblkno * e2fs->blocksize;
313 if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->diblkbuf, e2fs->blocksize)) {
314 ERR_PRT((L"ext2_blkno: err reading dindr blk"));
317 e2fs->cached_diblkno = diblkno;
320 /* Find the single-indirect block pointer ... */
321 iblkno = dlp[(blkoff - (e2fs->ind1lim+1)) / e2fs->ptrs_per_blk];
327 /* Read the indirect block */
329 if (e2fs->cached_iblkno != iblkno) {
330 offset = iblkno * e2fs->blocksize;
331 if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) {
332 ERR_PRT((L"ext2_blkno: err on iblk read"));
335 e2fs->cached_iblkno = iblkno;
338 /* Find the block itself. */
339 blkno = ilp[(blkoff-(e2fs->ind1lim+1)) % e2fs->ptrs_per_blk];
343 if (blkoff > e2fs->ind2lim) {
344 ERR_PRT((L"ext2_blkno: block number too large: %d", blkoff));
352 ext2_breadi(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, long blkno, long nblks, CHAR8 *buffer)
354 long dev_blkno, ncontig, offset, nbytes, tot_bytes;
357 if ((blkno+nblks)*e2fs->blocksize > ip->i_size)
358 nblks = (ip->i_size + e2fs->blocksize) / e2fs->blocksize - blkno;
362 * Contiguous reads are a lot faster, so we try to group
363 * as many blocks as possible:
365 ncontig = 0; nbytes = 0;
366 dev_blkno = ext2_blkno(e2fs,ip, blkno);
368 ++blkno; ++ncontig; --nblks;
369 nbytes += e2fs->blocksize;
371 ext2_blkno(e2fs, ip, blkno) == dev_blkno + ncontig);
373 if (dev_blkno == 0) {
374 /* This is a "hole" */
375 Memset(buffer, 0, nbytes);
377 /* Read it for real */
378 offset = dev_blkno*e2fs->blocksize;
379 DBG_PRT((L"ext2_bread: reading %d bytes at offset %d", nbytes, offset));
381 if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, buffer, nbytes)) {
382 ERR_PRT((L"ext2_bread: read error"));
392 static struct ext2_dir_entry_2 *
393 ext2_readdiri(ext2fs_priv_state_t *e2fs, struct ext2_inode *dir_inode, int rewind)
395 struct ext2_dir_entry_2 *dp;
396 static int diroffset = 0, blockoffset = 0;
398 /* Reading a different directory, invalidate previous state */
402 /* read first block */
403 if (ext2_breadi(e2fs, dir_inode, 0, 1, e2fs->blkbuf) < 0)
407 DBG_PRT((L"ext2_readdiri: blkoffset %d diroffset %d len %d", blockoffset, diroffset, dir_inode->i_size));
409 if (blockoffset >= e2fs->blocksize) {
410 diroffset += e2fs->blocksize;
411 if (diroffset >= dir_inode->i_size)
413 ERR_PRT((L"ext2_readdiri: reading block at %d", diroffset));
414 /* assume that this will read the whole block */
415 if (ext2_breadi(e2fs, dir_inode, diroffset / e2fs->blocksize, 1, e2fs->blkbuf) < 0) return NULL;
419 dp = (struct ext2_dir_entry_2 *) (e2fs->blkbuf + blockoffset);
420 blockoffset += dp->rec_len;
423 Print(L"ext2_readdiri: returning %x = ");
424 { INTN i; for(i=0; i < dp->name_len; i++) Print(L"%c", (CHAR16)dp->name[i]); Print(L"\n");}
430 * the string 'name' is modified by this call as per the parsing that
431 * is done in strtok_simple()
433 static struct ext2_inode *
434 ext2_namei(ext2fs_priv_state_t *e2fs, CHAR8 *name)
437 struct ext2_inode *dir_inode;
438 struct ext2_dir_entry_2 *dp;
441 /* start at the root: */
442 if (!e2fs->root_inode)
443 e2fs->root_inode = ext2_iget(e2fs, EXT2_ROOT_INO);
444 dir_inode = e2fs->root_inode;
448 component = strtok_simple(name, '/');
450 int component_length;
453 * Search for the specified component in the current
457 component_length = strlena(component);
459 DBG_PRT((L"ext2_namei: component = %a", component));
461 /* rewind the first time through */
462 while ((dp = ext2_readdiri(e2fs, dir_inode, !rewind++))) {
463 if ((dp->name_len == component_length) &&
464 (strncmpa(component, dp->name,
465 component_length) == 0))
468 DBG_PRT((L"ext2_namei: found entry %a", component));
469 next_ino = dp->inode;
472 DBG_PRT((L"ext2_namei: looping"));
475 DBG_PRT((L"ext2_namei: next_ino = %d", next_ino));
478 * At this point, we're done with this directory whether
479 * we've succeeded or failed...
481 if (dir_inode != e2fs->root_inode) ext2_iput(e2fs, dir_inode);
484 * If next_ino is negative, then we've failed (gone
485 * all the way through without finding anything)
492 * Otherwise, we can get this inode and find the next
493 * component string...
495 dir_inode = ext2_iget(e2fs, next_ino);
499 component = strtok_simple(NULL, '/');
503 * If we get here, then we got through all the components.
504 * Whatever we got must match up with the last one.
511 * Read block number "blkno" from the specified file.
514 ext2_bread(ext2fs_priv_state_t *e2fs, int fd, long blkno, long nblks, char *buffer)
516 struct ext2_inode * ip;
517 ip = &e2fs->inode_table[fd].inode;
518 return ext2_breadi(e2fs, ip, blkno, nblks, buffer);
523 * Note: don't mix any kind of file lookup or other I/O with this or
524 * you will lose horribly (as it reuses blkbuf)
527 ext2_readdir(ext2fs_priv_state_t *e2fs, int fd, int rewind)
529 struct ext2_inode * ip = &e2fs->inode_table[fd].inode;
530 struct ext2_dir_entry_2 * ent;
531 if (!S_ISDIR(ip->i_mode)) {
532 ERR_PRT((L"fd %d (inode %d) is not a directory (mode %x)",
533 fd, e2fs->inode_table[fd].inumber, ip->i_mode));
536 ent = ext2_readdiri(e2fs, ip, rewind);
538 ent->name[ent->name_len] = '\0';
547 ext2_fstat(ext2fs_priv_state_t *e2fs, int fd, ext2fs_stat_t *buf)
549 struct ext2_inode * ip = &e2fs->inode_table[fd].inode;
551 Memset(buf, 0, sizeof(*buf));
553 /* fill in relevant fields */
554 buf->st_ino = e2fs->inode_table[fd].inumber;
555 buf->st_mode = ip->i_mode;
556 buf->st_nlink = ip->i_links_count;
557 buf->st_uid = ip->i_uid;
558 buf->st_gid = ip->i_gid;
559 buf->st_size = ip->i_size;
560 buf->st_atime = ip->i_atime;
561 buf->st_mtime = ip->i_mtime;
562 buf->st_ctime = ip->i_ctime;
564 return 0; /* NOTHING CAN GO WROGN! */
568 ext2fs_fstat(ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st)
570 ext2fs_priv_state_t *e2fs;
572 if (this == NULL || fd > MAX_OPEN_FILES || st == NULL) return EFI_INVALID_PARAMETER;
574 e2fs = FS_PRIVATE(this);
576 ext2_fstat(e2fs, fd, st);
582 ext2fs_seek(ext2fs_interface_t *this, UINTN fd, UINT64 newpos)
584 ext2fs_priv_state_t *e2fs;
586 if (this == NULL || fd > MAX_OPEN_FILES || newpos >= EXT2_FILESIZE_MAX) return EFI_INVALID_PARAMETER;
588 e2fs = FS_PRIVATE(this);
589 if (newpos > (UINT64)e2fs->inode_table[fd].inode.i_size) return EFI_INVALID_PARAMETER;
591 e2fs->inode_table[fd].pos = newpos;
597 ext2fs_read(ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
599 ext2fs_priv_state_t *e2fs;
600 UINTN count, nc, bofs, bnum, pos;
601 EFI_STATUS ret = EFI_INVALID_PARAMETER;
604 if (this == NULL || size == NULL || buf == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
606 e2fs = FS_PRIVATE(this);
608 count = MIN(*size, e2fs->inode_table[fd].inode.i_size - e2fs->inode_table[fd].pos);
614 block = e2fs->blkbuf;
618 pos = e2fs->inode_table[fd].pos;
619 DBG_PRT((L"size=%d i_size=%d count=%d pos=%ld", *size,e2fs->inode_table[fd].inode.i_size, count, pos));
621 bnum = pos / e2fs->blocksize;
622 bofs = pos % e2fs->blocksize;
623 nc = MIN(count, e2fs->blocksize - bofs);
625 DBG_PRT((L"bnum =%d bofs=%d nc=%d *size=%d", bnum, bofs, nc, *size));
627 if (ext2_bread(e2fs, fd, bnum, 1, block) == -1) goto error;
629 { int i; char *p = block+bofs;
630 for(i=MIN(nc, 64); i>=0 ; i--, p++) {
631 if (i % 16 == 0) Print(L"\n");
632 Print(L"%02x ", (UINTN)*p & 0xff);
637 Memcpy(buf, block+bofs, nc);
644 e2fs->inode_table[fd].pos += *size;
647 DBG_PRT((L"*size=%d ret=%r", *size, ret));
651 static struct ext2_inode *
652 ext2_follow_link(ext2fs_priv_state_t *e2fs, struct ext2_inode * from, const char * base)
656 if (from->i_blocks) {
657 linkto = e2fs->blkbuf;
658 if (ext2_breadi(e2fs, from, 0, 1, e2fs->blkbuf) == -1)
660 DBG_PRT((L"long link!"));
662 linkto = (char*)from->i_block;
664 DBG_PRT((L"symlink to %s", linkto));
666 /* Resolve relative links */
667 if (linkto[0] != '/') {
668 char *end = strrchra(base, '/');
670 //char fullname[(end - base + 1) + strlena(linkto) + 1];
671 char fullname[EXT2FS_PATH_MAXLEN];
673 if (((end - base + 1) + strlena(linkto) + 1) >= EXT2FS_PATH_MAXLEN) {
674 Print(L"%s: filename too long, can't resolve\n", __FUNCTION__);
678 strncpya(fullname, base, end - base + 1);
679 fullname[end - base + 1] = '\0';
680 strcata(fullname, linkto);
681 DBG_PRT((L"resolved to %s", fullname));
682 return ext2_namei(e2fs, fullname);
684 /* Assume it's in the root */
685 return ext2_namei(e2fs, linkto);
688 return ext2_namei(e2fs, linkto);
693 ext2_open(ext2fs_priv_state_t *e2fs, char *filename)
696 * Unix-like open routine. Returns a small integer (actually
697 * an index into the inode table...
699 struct ext2_inode * ip;
701 ip = ext2_namei(e2fs, filename);
703 struct inode_table_entry *itp;
705 while (S_ISLNK(ip->i_mode)) {
706 ip = ext2_follow_link(e2fs, ip, filename);
709 itp = (struct inode_table_entry *)ip;
710 return itp - e2fs->inode_table;
715 static void ext2_close(ext2fs_priv_state_t *e2fs, int fd)
717 /* blah, hack, don't close the root inode ever */
718 if (&e2fs->inode_table[fd].inode != e2fs->root_inode)
719 ext2_iput(e2fs, &e2fs->inode_table[fd].inode);
723 ext2fs_close(ext2fs_interface_t *this, UINTN fd)
725 ext2fs_priv_state_t *e2fs;
727 if (this == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
729 e2fs = FS_PRIVATE(this);
731 ext2_close(e2fs, fd);
737 ext2fs_open(ext2fs_interface_t *this, CHAR16 *name, UINTN *fd)
739 ext2fs_priv_state_t *e2fs;
740 CHAR8 filename[EXT2FS_PATH_MAXLEN]; /* XXX: kind of big for a stack object */
743 DBG_PRT((L"name:%s fd=%x", name, fd));
745 if (this == NULL || name == NULL || fd == NULL || StrLen(name) >=EXT2FS_PATH_MAXLEN) return EFI_INVALID_PARAMETER;
747 e2fs = FS_PRIVATE(this);
750 * XXX: for security reasons, we may have to force a prefix like /boot to all filenames
752 StrnXCpy(filename, name, EXT2FS_PATH_MAXLEN);
754 DBG_PRT((L"ASCII name:%a UTF-name:%s", filename, name));
756 tmp = ext2_open(e2fs, filename);
759 e2fs->inode_table[tmp].pos = 0; /* reset file position */
762 DBG_PRT((L"name: %s fd=%d tmp=%d", name, *fd, tmp));
764 return tmp == -1 ? EFI_NOT_FOUND : EFI_SUCCESS;
768 ext2fs_name(ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen)
770 if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
772 StrnCpy(name, FS_NAME, maxlen-1);
774 name[maxlen-1] = CHAR_NULL;
780 ext2fs_init_state(ext2fs_t *ext2fs, EFI_HANDLE dev, EFI_BLOCK_IO *blkio, struct ext2_super_block *sb)
782 ext2fs_priv_state_t *e2fs = FS_PRIVATE(ext2fs);
786 Memset(ext2fs, 0, sizeof(*ext2fs));
790 e2fs->mediaid = blkio->Media->MediaId;
792 /* fools gcc builtin memcpy */
793 Memcpy(&e2fs->sb, sb, sizeof(*sb));
795 e2fs->ngroups = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb);
797 e2fs->gds = (struct ext2_group_desc *)alloc(e2fs->ngroups * sizeof(struct ext2_group_desc), EXT2FS_MEMTYPE);
798 if (e2fs->gds == NULL) {
799 ERR_PRT((L"failed to allocate gds"));
800 return EFI_OUT_OF_RESOURCES;
803 e2fs->blocksize = EXT2_BLOCK_SIZE(sb);
805 DBG_PRT((L"gds_size=%d gds_offset=%d ngroups=%d blocksize=%d",
806 e2fs->ngroups * sizeof(struct ext2_group_desc),
807 e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),
808 e2fs->ngroups, (UINTN)e2fs->blocksize));
810 /* read in the group descriptors (immediately follows superblock) */
811 status = read_bytes(blkio, e2fs->mediaid, e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),
812 e2fs->gds, e2fs->ngroups * sizeof(struct ext2_group_desc));
813 if (EFI_ERROR(status)) {
814 ERR_PRT((L"cannot read gds: %r", status));
816 return EFI_INVALID_PARAMETER;
819 { int i; char *p = (char *)e2fs->gds;
820 for(i=e2fs->ngroups*sizeof(*e2fs->gds); i ; i--, p++) {
821 if (i % 16 == 0) Print(L"\n");
822 Print(L"%02x ", (UINTN)*p & 0xff);
828 e2fs->cached_diblkno = -1;
829 e2fs->cached_iblkno = -1;
831 /* initialize the inode table */
832 for (i = 0; i < MAX_OPEN_FILES; i++) {
833 e2fs->inode_table[i].free = 1;
834 e2fs->inode_table[i].inumber = 0;
836 /* clear the root inode pointer (very important!) */
837 e2fs->root_inode = NULL;
840 * Calculate direct/indirect block limits for this file system
841 * (blocksize dependent):
842 ext2_blocksize = EXT2_BLOCK_SIZE(&sb);
844 e2fs->directlim = EXT2_NDIR_BLOCKS - 1;
845 e2fs->ptrs_per_blk = e2fs->blocksize/sizeof(unsigned int);
846 e2fs->ind1lim = e2fs->ptrs_per_blk + e2fs->directlim;
847 e2fs->ind2lim = (e2fs->ptrs_per_blk * e2fs->ptrs_per_blk) + e2fs->directlim;
849 ext2fs->pub_intf.ext2fs_name = ext2fs_name;
850 ext2fs->pub_intf.ext2fs_open = ext2fs_open;
851 ext2fs->pub_intf.ext2fs_read = ext2fs_read;
852 ext2fs->pub_intf.ext2fs_close = ext2fs_close;
853 ext2fs->pub_intf.ext2fs_seek = ext2fs_seek;
854 ext2fs->pub_intf.ext2fs_fstat = ext2fs_fstat;
861 ext2fs_install_one(EFI_HANDLE dev, VOID **intf)
863 struct ext2_super_block sb;
869 status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &Ext2FsProtocol, (VOID **)&ext2fs);
870 if (status == EFI_SUCCESS) {
871 ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
875 status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &BlockIoProtocol, (VOID **)&blkio);
876 if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
879 { EFI_DEVICE_PATH *dp; CHAR16 *str;
880 dp = DevicePathFromHandle(dev);
881 str = DevicePathToStr(dp);
882 Print(L"dev:%s\nLogical partition: %s BlockSize: %d WriteCaching: %s \n", str,
883 blkio->Media->LogicalPartition ? L"Yes": L"No",
884 blkio->Media->BlockSize,
885 blkio->Media->WriteCaching ? L"Yes":L"No");
888 if (blkio->Media->LogicalPartition == FALSE) return EFI_INVALID_PARAMETER;
892 * Used to be necessary on some older versions of EFI to avoid getting
893 * stuck. Now can cause problems with some SCSI controllers when enabled.
894 * Does not seem necessary with EFI 12.38
896 blkio->Reset(blkio, FALSE);
899 status = read_bytes(blkio, blkio->Media->MediaId, sb_block * EXT2_MIN_BLOCK_SIZE, &sb, sizeof(sb));
900 if (EFI_ERROR(status)) {
901 DBG_PRT((L"cannot read superblock: %r", status));
902 return EFI_INVALID_PARAMETER;
905 if (sb.s_magic != EXT2_SUPER_MAGIC) {
906 DBG_PRT((L"bad magic 0x%x\n", sb.s_magic));
907 return EFI_INVALID_PARAMETER;
910 ext2fs = (ext2fs_t *)alloc(sizeof(*ext2fs), EXT2FS_MEMTYPE);
911 if (ext2fs == NULL) return EFI_OUT_OF_RESOURCES;
913 status = ext2fs_init_state(ext2fs, dev, blkio, &sb);
914 if (status != EFI_SUCCESS) {
919 status = LibInstallProtocolInterfaces(&dev, &Ext2FsProtocol, ext2fs, NULL);
920 if (EFI_ERROR(status)) {
921 ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
926 if (intf) *intf = (VOID *)ext2fs;
929 { EFI_DEVICE_PATH *dp; CHAR16 *str;
930 dp = DevicePathFromHandle(dev);
931 str = DevicePathToStr(dp);
932 Print(L"dev:%s %s detected\n", str, FS_NAME);
947 uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL, &size, NULL);
948 if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
950 DBG_PRT((L"size=%d", size));
952 dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
953 if (dev_tab == NULL) {
954 ERR_PRT((L"failed to allocate handle table"));
955 return EFI_OUT_OF_RESOURCES;
958 status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL,
959 &size, (VOID **)dev_tab);
960 if (status != EFI_SUCCESS) {
961 ERR_PRT((L"failed to get handles: %r", status));
965 ndev = size / sizeof(EFI_HANDLE);
967 for(i=0; i < ndev; i++) {
969 ext2fs_install_one(dev_tab[i].dev, &intf);
970 /* override device handle with interface pointer */
971 dev_tab[i].intf = intf;
978 ext2fs_uninstall(VOID)
981 ext2fs_priv_state_t *e2fs;
985 for(i=0; i < ndev; i++) {
986 if (dev_tab[i].intf == NULL) continue;
987 e2fs = FS_PRIVATE(dev_tab[i].intf);
988 status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf);
989 if (EFI_ERROR(status)) {
990 ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
994 { EFI_DEVICE_PATH *dp; CHAR16 *str;
995 dp = DevicePathFromHandle(e2fs->dev);
996 str = DevicePathToStr(dp);
997 Print(L"uninstalled %s on %s\n", FS_NAME, str);
1000 free(dev_tab[i].intf);
1002 if (dev_tab) free(dev_tab);