Imported Upstream version 3.10
[debian/elilo] / fs / ext2fs.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *
5  * This file is part of the ELILO, the EFI Linux boot loader.
6  *
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)
10  *  any later version.
11  *
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.
16  *
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
20  *  02111-1307, USA.
21  *
22  * Please check out the elilo.txt for complete documentation on how
23  * to use this program.
24  *
25  * The ext2 code in this file is derived from aboot-0.7 (the Linux/Alpha
26  * bootloader) and credits are attributed to:
27  *
28  * This file has been ported from the DEC 32-bit Linux version
29  * by David Mosberger (davidm@cs.arizona.edu).
30  */
31
32 #include <efi.h>
33 #include <efilib.h>
34
35 #include "elilo.h"
36
37 #define FS_NAME L"ext2fs"
38
39 #ifdef PATH_MAX
40 #error You must have included some Linux header file by error
41 #endif
42
43 #define PATH_MAX                4095
44 #define EXT2FS_PATH_MAXLEN      PATH_MAX
45
46 #include "fs/ext2fs.h"
47 #include "fs/ext2_private.h"
48
49 /*
50  * should we decide to spin off ext2, let's say to a boottime driver
51  * we would have to change this
52  */
53 #define EXT2FS_MEMTYPE  EfiLoaderData
54
55 /* ext2 file size is __u32 */
56 #define EXT2_FILESIZE_MAX       (0x100000000UL)
57
58 /* 
59  * Number of simultaneous open files. This needs to be high because
60  * directories are kept open while traversing long path names.
61  */
62 #define MAX_OPEN_FILES          32 
63
64 typedef struct inode_table_entry {
65         struct  ext2_inode      inode;
66         int                     inumber;
67         int                     free;
68         unsigned short          old_mode;
69
70         UINT32                  pos;    /* current position in file ext2 uses __u32 !*/
71 } inode_entry_t;
72
73
74 typedef struct {
75         struct ext2_super_block sb;
76         struct ext2_group_desc *gds;
77         struct ext2_inode *root_inode;
78         int ngroups;
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];
84         int cached_iblkno;
85         CHAR8 iblkbuf[EXT2_MAX_BLOCK_SIZE];
86         int cached_diblkno;
87         CHAR8 diblkbuf[EXT2_MAX_BLOCK_SIZE];
88         long blocksize;
89
90
91         inode_entry_t inode_table[MAX_OPEN_FILES];
92
93         /* fields added to fit the protocol construct */
94         EFI_BLOCK_IO *blkio;
95         UINT32       mediaid;
96         EFI_HANDLE   dev;
97 } ext2fs_priv_state_t;
98
99
100 typedef union {
101         ext2fs_interface_t pub_intf;
102         struct {
103                 ext2fs_interface_t  pub_intf;
104                 ext2fs_priv_state_t priv_data;
105         } ext2fs_priv;
106 } ext2fs_t;
107
108 #define FS_PRIVATE(n)   (&(((ext2fs_t *)n)->ext2fs_priv.priv_data))
109
110 typedef union {
111         EFI_HANDLE *dev;
112         ext2fs_t  *intf;
113 } dev_tab_t;
114
115 static dev_tab_t *dev_tab;      /* holds all devices we found */
116 static UINTN ndev;              /* how many entries in dev_tab */
117
118
119 static EFI_GUID Ext2FsProtocol = EXT2FS_PROTOCOL;
120
121 static INTN
122 read_bytes(EFI_BLOCK_IO *blkio, UINT32 mediaid, UINTN offset, VOID *addr, UINTN size)
123 {
124         EFI_STATUS status;
125         UINT8 *buffer;
126         UINTN count, buffer_size;
127         EFI_LBA base;
128         INTN ret  = EFI_INVALID_PARAMETER;
129
130         base        = offset / blkio->Media->BlockSize;
131         count       = (size + blkio->Media->BlockSize -1) / blkio->Media->BlockSize;
132         buffer_size = count * blkio->Media->BlockSize;
133
134         DBG_PRT((L"readblock(%x, %d,%d) base=%d count=%d", blkio, offset, size, base, count));
135
136         /*
137          * slow but avoid large buffer on the stack
138          */
139         buffer = (UINT8 *)alloc(buffer_size, EfiLoaderData);
140         if (buffer == NULL) {
141                 ERR_PRT((L"cannot allocate ext2fs buffer size=%d", buffer_size));
142                 return ret;
143         }
144
145         DBG_PRT((L"readblock(PTR_FMT ", %d, %ld, %d, " PTR_FMT ")", blkio, mediaid, base, buffer_size, buffer));
146
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));
150                 goto error;
151         }
152
153         DBG_PRT((L"readblock(%d,%d)->%r", offset, buffer_size, status));
154
155         Memcpy(addr, buffer+(offset-(base*blkio->Media->BlockSize)), size);
156
157         ret = 0;
158
159 error:
160         free(buffer);
161
162         return ret;
163 }
164
165 /*
166  * Read the specified inode from the disk and return it to the user.
167  * Returns NULL if the inode can't be read...
168  */
169 static struct ext2_inode *
170 ext2_iget(ext2fs_priv_state_t *e2fs, int ino)
171 {
172         int i;
173         struct ext2_inode *ip;
174         struct inode_table_entry *itp = 0;
175         int group;
176         long offset;
177
178         ip = 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];
184                         ip = &itp->inode;
185                         break;
186                 }
187         }
188         if (!ip) {
189                 ERR_PRT((L"ext2_iget: no free inodes"));
190                 return NULL;
191         }
192
193
194         group = (ino-1) / e2fs->sb.s_inodes_per_group;
195
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));
198
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));
201         
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), 
206                (UINTN)offset,
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)));
210
211         if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, ip, sizeof(struct ext2_inode))) {
212                 ERR_PRT((L"ext2_iget: read error"));
213                 return NULL;
214         }
215         
216         DBG_PRT((L"mode=%x uid=%d size=%d gid=%d links=%d flags=%d",
217                                         (UINTN)ip->i_mode,
218                                         (UINTN)ip->i_uid,
219                                         (UINTN)ip->i_size,
220                                         (UINTN)ip->i_gid,
221                                         (UINTN)ip->i_flags));
222
223         itp->free = 0;
224         itp->inumber = ino;
225         itp->old_mode = ip->i_mode;
226
227         return ip;
228 }
229
230
231 /*
232  * Release our hold on an inode.  Since this is a read-only application,
233  * don't worry about putting back any changes...
234  */
235 static void 
236 ext2_iput(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip)
237 {
238         struct inode_table_entry *itp;
239
240         /* Find and free the inode table slot we used... */
241         itp = (struct inode_table_entry *)ip;
242
243         DBG_PRT((L"ext2_iput: inode %d table %d", itp->inumber, (int) (itp - e2fs->inode_table)));
244
245         itp->inumber = 0;
246         itp->free = 1;
247 }
248
249
250 /*
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.
255  *
256  * The "allocate" argument is set if we want to *allocate* a block
257  * and we don't already have one allocated.
258  */
259 static int 
260 ext2_blkno(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, int blkoff)
261 {
262         unsigned int *lp;
263         unsigned int *ilp;
264         unsigned int *dlp;
265         int blkno;
266         int iblkno;
267         int diblkno;
268         long offset;
269
270         ilp = (unsigned int *)e2fs->iblkbuf;
271         dlp = (unsigned int *)e2fs->diblkbuf;
272         lp = (unsigned int *)e2fs->blkbuf;
273
274         /* If it's a direct block, it's easy! */
275         if (blkoff <= e2fs->directlim) {
276                 return ip->i_block[blkoff];
277         }
278
279         /* Is it a single-indirect? */
280         if (blkoff <= e2fs->ind1lim) {
281                 iblkno = ip->i_block[EXT2_IND_BLOCK];
282
283                 if (iblkno == 0) {
284                         return 0;
285                 }
286
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"));
292                                 return 0;
293                         }
294                         e2fs->cached_iblkno = iblkno;
295                 }
296
297                 blkno = ilp[blkoff-(e2fs->directlim+1)];
298                 return blkno;
299         }
300
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];
305
306                 if (diblkno == 0) {
307                         return 0;
308                 }
309
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"));
315                                 return 0;
316                         }
317                         e2fs->cached_diblkno = diblkno;
318                 }
319
320                 /* Find the single-indirect block pointer ... */
321                 iblkno = dlp[(blkoff - (e2fs->ind1lim+1)) / e2fs->ptrs_per_blk];
322
323                 if (iblkno == 0) {
324                         return 0;
325                 }
326
327                 /* Read the indirect block */
328     
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"));
333                                 return 0;
334                         }
335                         e2fs->cached_iblkno = iblkno;
336                 }
337
338                 /* Find the block itself. */
339                 blkno = ilp[(blkoff-(e2fs->ind1lim+1)) % e2fs->ptrs_per_blk];
340                 return blkno;
341         }
342
343         if (blkoff > e2fs->ind2lim) {
344                 ERR_PRT((L"ext2_blkno: block number too large: %d", blkoff));
345                 return 0;
346         }
347         return -1;
348 }
349
350
351 static int
352 ext2_breadi(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, long blkno, long nblks, CHAR8 *buffer)
353
354         long dev_blkno, ncontig, offset, nbytes, tot_bytes;
355
356         tot_bytes = 0;
357         if ((blkno+nblks)*e2fs->blocksize > ip->i_size)
358                 nblks = (ip->i_size + e2fs->blocksize) / e2fs->blocksize - blkno;
359
360         while (nblks) {
361                 /*
362                  * Contiguous reads are a lot faster, so we try to group
363                  * as many blocks as possible:
364                  */
365                 ncontig = 0; nbytes = 0;
366                 dev_blkno = ext2_blkno(e2fs,ip, blkno);
367                 do {
368                         ++blkno; ++ncontig; --nblks;
369                         nbytes += e2fs->blocksize;
370                 } while (nblks &&
371                          ext2_blkno(e2fs, ip, blkno) == dev_blkno + ncontig);
372
373                 if (dev_blkno == 0) {
374                         /* This is a "hole" */
375                         Memset(buffer, 0, nbytes);
376                 } else {
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));
380
381                         if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, buffer, nbytes)) {
382                                 ERR_PRT((L"ext2_bread: read error"));
383                                 return -1;
384                         }
385                 }
386                 buffer    += nbytes;
387                 tot_bytes += nbytes;
388         }
389         return tot_bytes;
390 }
391
392 static struct ext2_dir_entry_2 *
393 ext2_readdiri(ext2fs_priv_state_t *e2fs, struct ext2_inode *dir_inode, int rewind)
394 {
395         struct ext2_dir_entry_2 *dp;
396         static int diroffset = 0, blockoffset = 0;
397
398         /* Reading a different directory, invalidate previous state */
399         if (rewind) {
400                 diroffset = 0;
401                 blockoffset = 0;
402                 /* read first block */
403                 if (ext2_breadi(e2fs, dir_inode, 0, 1, e2fs->blkbuf) < 0)
404                         return NULL;
405         }
406
407         DBG_PRT((L"ext2_readdiri: blkoffset %d diroffset %d len %d", blockoffset, diroffset, dir_inode->i_size));
408
409         if (blockoffset >= e2fs->blocksize) {
410                 diroffset += e2fs->blocksize;
411                 if (diroffset >= dir_inode->i_size)
412                         return NULL;
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;
416                 blockoffset = 0;
417         }
418
419         dp = (struct ext2_dir_entry_2 *) (e2fs->blkbuf + blockoffset);
420         blockoffset += dp->rec_len;
421
422 #if 0
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");}
425 #endif
426         return dp;
427 }
428
429 /*
430  * the string 'name' is modified by this call as per the parsing that
431  * is done in strtok_simple()
432  */
433 static struct ext2_inode *
434 ext2_namei(ext2fs_priv_state_t *e2fs, CHAR8 *name)
435 {
436         CHAR8 *component;
437         struct ext2_inode *dir_inode;
438         struct ext2_dir_entry_2 *dp;
439         int next_ino;
440
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;
445         if (!dir_inode)
446           return NULL;
447
448         component = strtok_simple(name, '/');
449         while (component) {
450                 int component_length;
451                 int rewind = 0;
452                 /*
453                  * Search for the specified component in the current
454                  * directory inode.
455                  */
456                 next_ino = -1;
457                 component_length = strlena(component);
458
459                 DBG_PRT((L"ext2_namei: component = %a", component));
460
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))
466                         {
467                                 /* Found it! */
468                                 DBG_PRT((L"ext2_namei: found entry %a", component));
469                                 next_ino = dp->inode;
470                                 break;
471                         }
472                         DBG_PRT((L"ext2_namei: looping"));
473                 }
474         
475                 DBG_PRT((L"ext2_namei: next_ino = %d", next_ino));
476
477                 /*
478                  * At this point, we're done with this directory whether
479                  * we've succeeded or failed...
480                  */
481                 if (dir_inode != e2fs->root_inode) ext2_iput(e2fs, dir_inode);
482
483                 /*
484                  * If next_ino is negative, then we've failed (gone
485                  * all the way through without finding anything)
486                  */
487                 if (next_ino < 0) {
488                         return NULL;
489                 }
490
491                 /*
492                  * Otherwise, we can get this inode and find the next
493                  * component string...
494                  */
495                 dir_inode = ext2_iget(e2fs, next_ino);
496                 if (!dir_inode)
497                   return NULL;
498
499                 component = strtok_simple(NULL, '/');
500         }
501
502         /*
503          * If we get here, then we got through all the components.
504          * Whatever we got must match up with the last one.
505          */
506         return dir_inode;
507 }
508
509
510 /*
511  * Read block number "blkno" from the specified file.
512  */
513 static int 
514 ext2_bread(ext2fs_priv_state_t *e2fs, int fd, long blkno, long nblks, char *buffer)
515 {
516         struct ext2_inode * ip;
517         ip = &e2fs->inode_table[fd].inode;
518         return ext2_breadi(e2fs, ip, blkno, nblks, buffer);
519 }
520
521 #if 0
522 /*
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)
525  */
526 static const char *
527 ext2_readdir(ext2fs_priv_state_t *e2fs, int fd, int rewind)
528 {
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));
534                 return NULL;
535         }
536         ent = ext2_readdiri(e2fs, ip, rewind);
537         if (ent) {
538                 ent->name[ent->name_len] = '\0';
539                 return ent->name;
540         } else { 
541                 return NULL;
542         }
543 }
544 #endif
545
546 static int 
547 ext2_fstat(ext2fs_priv_state_t *e2fs, int fd, ext2fs_stat_t *buf)
548 {
549         struct ext2_inode * ip = &e2fs->inode_table[fd].inode;
550
551         Memset(buf, 0, sizeof(*buf));
552
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;
563
564         return 0; /* NOTHING CAN GO WROGN! */
565 }
566
567 static EFI_STATUS
568 ext2fs_fstat(ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st)
569 {
570         ext2fs_priv_state_t *e2fs;
571
572         if (this == NULL || fd > MAX_OPEN_FILES || st == NULL) return EFI_INVALID_PARAMETER;
573
574         e2fs = FS_PRIVATE(this);
575
576         ext2_fstat(e2fs, fd, st);
577
578         return EFI_SUCCESS;
579 }
580
581 static EFI_STATUS
582 ext2fs_seek(ext2fs_interface_t *this, UINTN fd, UINT64 newpos)
583 {
584         ext2fs_priv_state_t *e2fs;
585
586         if (this == NULL || fd > MAX_OPEN_FILES || newpos >= EXT2_FILESIZE_MAX) return EFI_INVALID_PARAMETER;
587
588         e2fs = FS_PRIVATE(this);
589         if (newpos > (UINT64)e2fs->inode_table[fd].inode.i_size) return EFI_INVALID_PARAMETER;
590
591         e2fs->inode_table[fd].pos = newpos;
592
593         return EFI_SUCCESS;
594 }
595
596 static EFI_STATUS
597 ext2fs_read(ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
598 {
599         ext2fs_priv_state_t *e2fs;
600         UINTN count, nc, bofs, bnum, pos;
601         EFI_STATUS ret = EFI_INVALID_PARAMETER;
602         CHAR8 *block;
603
604         if (this == NULL || size == NULL || buf == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
605
606         e2fs = FS_PRIVATE(this);
607
608         count = MIN(*size, e2fs->inode_table[fd].inode.i_size - e2fs->inode_table[fd].pos);
609
610         if (count == 0)  {
611                 *size = 0;
612                 return EFI_SUCCESS;
613         }
614         block = e2fs->blkbuf;
615
616         *size = 0;
617
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));
620         while (count) {
621                 bnum = pos / e2fs->blocksize;
622                 bofs = pos % e2fs->blocksize;
623                 nc   = MIN(count, e2fs->blocksize - bofs);
624
625                 DBG_PRT((L"bnum =%d bofs=%d nc=%d *size=%d", bnum, bofs, nc, *size));
626
627                 if (ext2_bread(e2fs, fd, bnum, 1, block) == -1) goto error;
628 #if 0           
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);
633                         }
634                 }
635 #endif
636
637                 Memcpy(buf, block+bofs, nc);
638                 count -= nc;
639                 pos   += nc;
640                 buf   += nc;
641                 *size += nc;
642         }
643
644         e2fs->inode_table[fd].pos += *size;
645         ret = EFI_SUCCESS;
646 error:
647         DBG_PRT((L"*size=%d ret=%r", *size, ret));
648         return ret;
649 }
650
651 static struct ext2_inode *
652 ext2_follow_link(ext2fs_priv_state_t *e2fs, struct ext2_inode * from, const char * base)
653 {
654         char *linkto;
655
656         if (from->i_blocks) {
657                 linkto = e2fs->blkbuf;
658                 if (ext2_breadi(e2fs, from, 0, 1, e2fs->blkbuf) == -1)
659                         return NULL;
660                 DBG_PRT((L"long link!"));
661         } else {
662                 linkto = (char*)from->i_block;
663         }
664         DBG_PRT((L"symlink to %s", linkto));
665
666         /* Resolve relative links */
667         if (linkto[0] != '/') {
668                 char *end = strrchra(base, '/');
669                 if (end) {
670                         //char fullname[(end - base + 1) + strlena(linkto) + 1];
671                         char fullname[EXT2FS_PATH_MAXLEN];
672
673                         if (((end - base + 1) + strlena(linkto) + 1) >= EXT2FS_PATH_MAXLEN) {
674                                 Print(L"%s: filename too long, can't resolve\n", __FUNCTION__);
675                                 return NULL;
676                         }
677
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);
683                 } else {
684                         /* Assume it's in the root */
685                         return ext2_namei(e2fs, linkto);
686                 }
687         } else {
688                 return ext2_namei(e2fs, linkto);
689         }
690 }
691
692 static int
693 ext2_open(ext2fs_priv_state_t *e2fs, char *filename)
694 {
695         /*
696          * Unix-like open routine.  Returns a small integer (actually
697          * an index into the inode table...
698          */
699         struct ext2_inode * ip;
700
701         ip = ext2_namei(e2fs, filename);
702         if (ip) {
703                 struct inode_table_entry *itp;
704
705                 while (S_ISLNK(ip->i_mode)) {
706                         ip = ext2_follow_link(e2fs, ip, filename);
707                         if (!ip) return -1;
708                 }
709                 itp = (struct inode_table_entry *)ip;
710                 return itp - e2fs->inode_table;
711         } else
712                 return -1;
713 }
714
715 static void ext2_close(ext2fs_priv_state_t *e2fs, int fd)
716 {
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);
720 }
721
722 static EFI_STATUS
723 ext2fs_close(ext2fs_interface_t *this, UINTN fd)
724 {
725         ext2fs_priv_state_t *e2fs;
726
727         if (this == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
728
729         e2fs = FS_PRIVATE(this);
730
731         ext2_close(e2fs, fd);
732
733         return EFI_SUCCESS;
734 }
735
736 static EFI_STATUS
737 ext2fs_open(ext2fs_interface_t *this, CHAR16 *name, UINTN *fd)
738 {
739         ext2fs_priv_state_t *e2fs;
740         CHAR8 filename[EXT2FS_PATH_MAXLEN]; /* XXX: kind of big for a stack object */
741         INTN tmp;
742
743         DBG_PRT((L"name:%s fd=%x", name, fd));
744
745         if (this == NULL || name == NULL || fd == NULL || StrLen(name) >=EXT2FS_PATH_MAXLEN) return EFI_INVALID_PARAMETER;
746
747         e2fs = FS_PRIVATE(this);
748
749         /*
750          * XXX: for security reasons, we may have to force a prefix like /boot to all filenames
751          */
752         StrnXCpy(filename, name, EXT2FS_PATH_MAXLEN);
753         
754         DBG_PRT((L"ASCII name:%a UTF-name:%s", filename, name));
755
756         tmp = ext2_open(e2fs, filename);
757         if (tmp != -1) {
758                 *fd = (UINTN)tmp;
759                 e2fs->inode_table[tmp].pos = 0; /* reset file position */
760         }
761
762         DBG_PRT((L"name: %s fd=%d tmp=%d", name, *fd, tmp));
763
764         return tmp == -1 ? EFI_NOT_FOUND : EFI_SUCCESS;
765 }
766
767 static EFI_STATUS
768 ext2fs_name(ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen)
769 {
770         if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
771
772         StrnCpy(name, FS_NAME, maxlen-1);
773
774         name[maxlen-1] = CHAR_NULL;
775
776         return EFI_SUCCESS;
777 }
778
779 static INTN
780 ext2fs_init_state(ext2fs_t *ext2fs, EFI_HANDLE dev, EFI_BLOCK_IO *blkio, struct ext2_super_block *sb)
781 {
782         ext2fs_priv_state_t *e2fs = FS_PRIVATE(ext2fs);
783         UINTN i;
784         EFI_STATUS status;
785
786         Memset(ext2fs, 0, sizeof(*ext2fs));
787
788         e2fs->dev     = dev;
789         e2fs->blkio   = blkio;
790         e2fs->mediaid = blkio->Media->MediaId;
791
792         /* fools gcc builtin memcpy */
793         Memcpy(&e2fs->sb, sb, sizeof(*sb));
794
795         e2fs->ngroups = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb);
796
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;
801         }
802         
803         e2fs->blocksize = EXT2_BLOCK_SIZE(sb);
804
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));
809
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));
815                 free(e2fs->gds);
816                 return EFI_INVALID_PARAMETER;
817         }
818 #if 0
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);
823
824                 }
825         }
826 #endif
827
828         e2fs->cached_diblkno = -1;
829         e2fs->cached_iblkno  = -1;
830
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;
835         }
836         /* clear the root inode pointer (very important!) */
837         e2fs->root_inode = NULL;
838
839         /*
840          * Calculate direct/indirect block limits for this file system
841          * (blocksize dependent):
842         ext2_blocksize = EXT2_BLOCK_SIZE(&sb);
843          */
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;
848
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;
855
856         return EFI_SUCCESS;
857 }
858
859
860 static EFI_STATUS
861 ext2fs_install_one(EFI_HANDLE dev, VOID **intf)
862 {
863         struct ext2_super_block sb;
864         long sb_block = 1;
865         EFI_STATUS status;
866         EFI_BLOCK_IO *blkio;
867         ext2fs_t *ext2fs;
868
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));
872                 goto found;
873         }
874         
875         status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &BlockIoProtocol, (VOID **)&blkio);
876         if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
877         
878         VERB_PRT(5,
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");
886                   FreePool(str);
887                 });
888         if (blkio->Media->LogicalPartition == FALSE) return EFI_INVALID_PARAMETER;
889
890 #if 0
891         /*
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
895          */
896         blkio->Reset(blkio, FALSE);
897 #endif
898
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;
903         }
904         
905         if (sb.s_magic != EXT2_SUPER_MAGIC) {
906                 DBG_PRT((L"bad magic "PTR_FMT"\n", sb.s_magic));
907                 return EFI_INVALID_PARAMETER;
908         }
909         
910         ext2fs = (ext2fs_t *)alloc(sizeof(*ext2fs), EXT2FS_MEMTYPE);
911         if (ext2fs == NULL) return EFI_OUT_OF_RESOURCES;
912
913         status = ext2fs_init_state(ext2fs, dev, blkio, &sb);
914         if (status != EFI_SUCCESS) {
915                 free(ext2fs);
916                 return status;
917         }
918
919         status = LibInstallProtocolInterfaces(&dev, &Ext2FsProtocol, ext2fs, NULL);
920         if (EFI_ERROR(status)) {
921                 ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
922                 free(ext2fs);
923                 return status;
924         }
925 found:
926         if (intf) *intf = (VOID *)ext2fs;
927
928         VERB_PRT(3,
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);
933                   FreePool(str);
934                 });
935
936         return EFI_SUCCESS;
937 }
938
939 EFI_STATUS
940 ext2fs_install(VOID)
941 {
942         UINTN size = 0;
943         UINTN i;
944         EFI_STATUS status;
945         VOID *intf;
946
947         uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL, &size, NULL);
948         if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
949
950         DBG_PRT((L"size=%d", size));
951
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;
956         }
957         
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));
962                 free(dev_tab);
963                 return status;
964         }
965         ndev = size / sizeof(EFI_HANDLE);
966
967         for(i=0; i < ndev; i++) {
968                 intf = NULL;
969                 ext2fs_install_one(dev_tab[i].dev, &intf);
970                 /* override device handle with interface pointer */
971                 dev_tab[i].intf = intf;
972         }
973
974         return EFI_SUCCESS;
975 }
976         
977 EFI_STATUS
978 ext2fs_uninstall(VOID)
979 {
980         
981         ext2fs_priv_state_t *e2fs;
982         EFI_STATUS status;
983         UINTN i;
984
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));
991                         continue;
992                 }
993                 VERB_PRT(3,
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);
998                         FreePool(str);
999                         });
1000                 free(dev_tab[i].intf);
1001         }
1002         if (dev_tab) free(dev_tab);
1003
1004         return EFI_SUCCESS;
1005 }