Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/fs/ext2/fsys_ext2fs.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 /* $Id: fsys_ext2fs.c,v 1.8 2005/09/16 18:16:27 gtw Exp $ */
0019 
0020 /*
0021  * Based on...
0022  *
0023  *  GRUB  --  GRand Unified Bootloader
0024  *  Copyright (C) 1999, 2001, 2003  Free Software Foundation, Inc.
0025  *
0026  *  This program is free software; you can redistribute it and/or modify
0027  *  it under the terms of the GNU General Public License as published by
0028  *  the Free Software Foundation; either version 2 of the License, or
0029  *  (at your option) any later version.
0030  *
0031  *  This program is distributed in the hope that it will be useful,
0032  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0033  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0034  *  GNU General Public License for more details.
0035  *
0036  *  You should have received a copy of the GNU General Public License
0037  *  along with this program; if not, write to the Free Software
0038  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0039  */
0040 
0041 #include "kernel.h"
0042 #include "fs/filesys.h"
0043 #include "arch/i386.h"
0044 #include "util/printf.h"
0045 
0046 extern void ReadSector (void *offset, int cylinder, int head, int sector);
0047 extern void WriteSector (void *offset, int cylinder, int head, int sector);
0048 extern void ReadSectorLBA (void *offset, uint32 lba);
0049 extern void WriteSectorLBA (void *offset, uint32 lba);
0050 
0051 static int mapblock1, mapblock2;
0052 static int errnum;
0053 static char fsys_buf[0x8000];
0054 static int filepos;
0055 static int filemax;
0056 
0057 /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
0058 #define DEV_BSIZE 512
0059 
0060 /* include/linux/fs.h */
0061 #define BLOCK_SIZE 1024         /* initial block size for superblock read */
0062 /* made up, defaults to 1 but can be passed via mount_opts */
0063 #define WHICH_SUPER 1
0064 /* kind of from fs/ext2/super.c */
0065 #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)   /* = 2 */
0066 
0067 /* include/asm-i386/types.h */
0068 typedef __signed__ char __s8;
0069 typedef uint8 __u8;
0070 typedef __signed__ short __s16;
0071 typedef uint16 __u16;
0072 typedef __signed__ int __s32;
0073 typedef unsigned int __u32;
0074 
0075 /*
0076  * Constants relative to the data blocks, from ext2_fs.h
0077  */
0078 #define EXT2_NDIR_BLOCKS                12
0079 #define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
0080 #define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
0081 #define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
0082 #define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
0083 
0084 #define SECTOR_BITS 9
0085 
0086 /* include/linux/ext2_fs.h */
0087 struct ext2_super_block
0088 {
0089   __u32 s_inodes_count;         /* Inodes count */
0090   __u32 s_blocks_count;         /* Blocks count */
0091   __u32 s_r_blocks_count;       /* Reserved blocks count */
0092   __u32 s_free_blocks_count;    /* Free blocks count */
0093   __u32 s_free_inodes_count;    /* Free inodes count */
0094   __u32 s_first_data_block;     /* First Data Block */
0095   __u32 s_log_block_size;       /* Block size */
0096   __s32 s_log_frag_size;        /* Fragment size */
0097   __u32 s_blocks_per_group;     /* # Blocks per group */
0098   __u32 s_frags_per_group;      /* # Fragments per group */
0099   __u32 s_inodes_per_group;     /* # Inodes per group */
0100   __u32 s_mtime;                /* Mount time */
0101   __u32 s_wtime;                /* Write time */
0102   __u16 s_mnt_count;            /* Mount count */
0103   __s16 s_max_mnt_count;        /* Maximal mount count */
0104   __u16 s_magic;                /* Magic signature */
0105   __u16 s_state;                /* File system state */
0106   __u16 s_errors;               /* Behaviour when detecting errors */
0107   __u16 s_pad;
0108   __u32 s_lastcheck;            /* time of last check */
0109   __u32 s_checkinterval;        /* max. time between checks */
0110   __u32 s_creator_os;           /* OS */
0111   __u32 s_rev_level;            /* Revision level */
0112   __u16 s_def_resuid;           /* Default uid for reserved blocks */
0113   __u16 s_def_resgid;           /* Default gid for reserved blocks */
0114   __u32 s_reserved[235];        /* Padding to the end of the block */
0115 };
0116 
0117 struct ext2_group_desc
0118 {
0119   __u32 bg_block_bitmap;        /* Blocks bitmap block */
0120   __u32 bg_inode_bitmap;        /* Inodes bitmap block */
0121   __u32 bg_inode_table;         /* Inodes table block */
0122   __u16 bg_free_blocks_count;   /* Free blocks count */
0123   __u16 bg_free_inodes_count;   /* Free inodes count */
0124   __u16 bg_used_dirs_count;     /* Directories count */
0125   __u16 bg_pad;
0126   __u32 bg_reserved[3];
0127 };
0128 
0129 struct ext2_inode
0130 {
0131   __u16 i_mode;                 /* File mode */
0132   __u16 i_uid;                  /* Owner Uid */
0133   __u32 i_size;                 /* 4: Size in bytes */
0134   __u32 i_atime;                /* Access time */
0135   __u32 i_ctime;                /* 12: Creation time */
0136   __u32 i_mtime;                /* Modification time */
0137   __u32 i_dtime;                /* 20: Deletion Time */
0138   __u16 i_gid;                  /* Group Id */
0139   __u16 i_links_count;          /* 24: Links count */
0140   __u32 i_blocks;               /* Blocks count */
0141   __u32 i_flags;                /* 32: File flags */
0142   union
0143   {
0144     struct
0145     {
0146       __u32 l_i_reserved1;
0147     }
0148     linux1;
0149     struct
0150     {
0151       __u32 h_i_translator;
0152     }
0153     hurd1;
0154     struct
0155     {
0156       __u32 m_i_reserved1;
0157     }
0158     masix1;
0159   }
0160   osd1;                         /* OS dependent 1 */
0161   __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
0162   __u32 i_version;              /* File version (for NFS) */
0163   __u32 i_file_acl;             /* File ACL */
0164   __u32 i_dir_acl;              /* Directory ACL */
0165   __u32 i_faddr;                /* Fragment address */
0166   union
0167   {
0168     struct
0169     {
0170       __u8 l_i_frag;            /* Fragment number */
0171       __u8 l_i_fsize;           /* Fragment size */
0172       __u16 i_pad1;
0173       __u32 l_i_reserved2[2];
0174     }
0175     linux2;
0176     struct
0177     {
0178       __u8 h_i_frag;            /* Fragment number */
0179       __u8 h_i_fsize;           /* Fragment size */
0180       __u16 h_i_mode_high;
0181       __u16 h_i_uid_high;
0182       __u16 h_i_gid_high;
0183       __u32 h_i_author;
0184     }
0185     hurd2;
0186     struct
0187     {
0188       __u8 m_i_frag;            /* Fragment number */
0189       __u8 m_i_fsize;           /* Fragment size */
0190       __u16 m_pad1;
0191       __u32 m_i_reserved2[2];
0192     }
0193     masix2;
0194   }
0195   osd2;                         /* OS dependent 2 */
0196 };
0197 
0198 /* linux/limits.h */
0199 #define NAME_MAX         255    /* # chars in a file name */
0200 
0201 /* linux/posix_type.h */
0202 typedef long linux_off_t;
0203 
0204 /* linux/ext2fs.h */
0205 #define EXT2_NAME_LEN 255
0206 struct ext2_dir_entry
0207 {
0208   __u32 inode;                  /* Inode number */
0209   __u16 rec_len;                /* Directory entry length */
0210   __u8 name_len;                /* Name length */
0211   __u8 file_type;
0212   char name[EXT2_NAME_LEN];     /* File name */
0213 };
0214 
0215 /* linux/ext2fs.h */
0216 /*
0217  * EXT2_DIR_PAD defines the directory entries boundaries
0218  *
0219  * NOTE: It must be a multiple of 4
0220  */
0221 #define EXT2_DIR_PAD                    4
0222 #define EXT2_DIR_ROUND                  (EXT2_DIR_PAD - 1)
0223 #define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
0224                                          ~EXT2_DIR_ROUND)
0225 
0226 
0227 /* ext2/super.c */
0228 #define log2(n) ffz(~(n))
0229 
0230 #define EXT2_SUPER_MAGIC      0xEF53    /* include/linux/ext2_fs.h */
0231 #define EXT2_ROOT_INO              2    /* include/linux/ext2_fs.h */
0232 #define PATH_MAX                1024    /* include/linux/limits.h */
0233 #define MAX_LINK_COUNT             5    /* number of symbolic links to follow */
0234 
0235 /* made up, these are pointers into fsysbuf */
0236 /* read once, always stays there: */
0237 #define SUPERBLOCK \
0238     ((struct ext2_super_block *)(fsys_buf))
0239 #define GROUP_DESC \
0240     ((struct ext2_group_desc *) \
0241      ((int)SUPERBLOCK + sizeof(struct ext2_super_block)))
0242 #define INODE \
0243     ((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
0244 #define DATABLOCK1 \
0245     ((int)((int)INODE + sizeof(struct ext2_inode)))
0246 #define DATABLOCK2 \
0247     ((int)((int)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
0248 
0249 /* linux/ext2_fs.h */
0250 #define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
0251 #define EXT2_ADDR_PER_BLOCK_BITS(s)             (log2(EXT2_ADDR_PER_BLOCK(s)))
0252 
0253 /* linux/ext2_fs.h */
0254 #define EXT2_BLOCK_SIZE_BITS(s)        ((s)->s_log_block_size + 10)
0255 /* kind of from ext2/super.c */
0256 #define EXT2_BLOCK_SIZE(s)      (1 << EXT2_BLOCK_SIZE_BITS(s))
0257 /* linux/ext2fs.h */
0258 #define EXT2_DESC_PER_BLOCK(s) \
0259      (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
0260 /* linux/stat.h */
0261 #define S_IFMT  00170000
0262 #define S_IFLNK  0120000
0263 #define S_IFREG  0100000
0264 #define S_IFDIR  0040000
0265 #define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)
0266 #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
0267 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
0268 
0269 /* Convert the integer D to a string and save the string in BUF. If
0270    BASE is equal to 'd', interpret that D is decimal, and if BASE is
0271    equal to 'x', interpret that D is hexadecimal. */
0272 void
0273 itoa (char *buf, int base, int d)
0274 {
0275   char *p = buf;
0276   char *p1, *p2;
0277   uint32 ud = d;
0278   int divisor = 10;
0279 
0280   /* If %d is specified and D is minus, put `-' in the head. */
0281   if (base == 'd' && d < 0) {
0282     *p++ = '-';
0283     buf++;
0284     ud = -d;
0285   } else if (base == 'x')
0286     divisor = 16;
0287 
0288   /* Divide UD by DIVISOR until UD == 0. */
0289   do {
0290     int remainder = ud % divisor;
0291 
0292     *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
0293   }
0294   while (ud /= divisor);
0295 
0296   /* Terminate BUF. */
0297   *p = 0;
0298 
0299   /* Reverse BUF. */
0300   p1 = buf;
0301   p2 = p - 1;
0302   while (p1 < p2) {
0303     char tmp = *p1;
0304     *p1 = *p2;
0305     *p2 = tmp;
0306     p1++;
0307     p2--;
0308   }
0309 }
0310 
0311 
0312 
0313 /* Format a string and print it on the screen, just like the libc
0314    function printf. */
0315 #if 0
0316 void
0317 printf (const char *format, ...)
0318 {
0319   char **arg = (char **) &format;
0320   int c;
0321   char buf[20];
0322 
0323   arg++;
0324 
0325   while ((c = *format++) != 0) {
0326     if (c != '%')
0327       putchar (c);
0328     else {
0329       char *p;
0330 
0331       c = *format++;
0332       switch (c) {
0333       case 'd':
0334       case 'u':
0335       case 'x':
0336         itoa (buf, c, *((int *) arg++));
0337         p = buf;
0338         goto string;
0339         break;
0340 
0341       case 's':
0342         p = *arg++;
0343         if (!p)
0344           p = "(null)";
0345 
0346       string:
0347         while (*p)
0348           putchar (*p++);
0349         break;
0350 
0351       default:
0352         putchar (*((int *) arg++));
0353         break;
0354       }
0355     }
0356   }
0357 }
0358 #endif
0359 
0360 
0361 int
0362 substring (const char *s1, const char *s2)
0363 {
0364   while (*s1 == *s2) {
0365     /* The strings match exactly. */
0366     if (!*(s1++))
0367       return 0;
0368     s2++;
0369   }
0370 
0371   /* S1 is a substring of S2. */
0372   if (*s1 == 0)
0373     return -1;
0374 
0375   /* S1 isn't a substring. */
0376   return 1;
0377 }
0378 
0379 int
0380 isspace (int c)
0381 {
0382   switch (c) {
0383   case ' ':
0384   case '\t':
0385   case '\r':
0386   case '\n':
0387     return 1;
0388   default:
0389     break;
0390   }
0391 
0392   return 0;
0393 }
0394 
0395 void *
0396 memmove (void *to, const void *from, int len)
0397 {
0398 
0399   /* This assembly code is stolen from
0400      linux-2.2.2/include/asm-i386/string.h. This is not very fast
0401      but compact.  */
0402   int d0, d1, d2;
0403 
0404   if (to < from) {
0405     asm volatile ("cld\n\t"
0406                   "rep\n\t" "movsb":"=&c" (d0), "=&S" (d1), "=&D" (d2)
0407                   :"0" (len), "1" (from), "2" (to)
0408                   :"memory");
0409   } else {
0410     asm volatile ("std\n\t"
0411                   "rep\n\t"
0412                   "movsb\n\t" "cld":"=&c" (d0), "=&S" (d1), "=&D" (d2)
0413                   :"0" (len),
0414                   "1" (len - 1 + (const char *) from),
0415                   "2" (len - 1 + (char *) to)
0416                   :"memory");
0417   }
0418   return to;
0419 }
0420 
0421 
0422 
0423 /* Convert logical block address to cylinders, heads, sectors format */
0424 void
0425 LBAtoCHS (int LBA, int *cylinder, int *head, int *sector)
0426 {
0427 
0428   int temp;
0429 
0430   /* --??-- Hard-coded CHS disk geometry to be:
0431    * 16 heads per cylinder, 63 sectors per track 
0432    * See: http://www.nondot.org/sabre/os/files/Disk/CHSTranslation.txt
0433    */
0434   *cylinder = LBA / (16 * 63);
0435   temp = LBA % (16 * 63);
0436   *head = temp / 63;
0437   *sector = temp % 63 + 1;
0438 }
0439 
0440 
0441 int
0442 devread (int sector, int byte_offset, int byte_len, char *buf)
0443 {
0444 
0445   char sector_buf[SECTOR_SIZE]; /* Temporary sector buffer */
0446   int partial_bytes;
0447   int cyl, hd, sect;
0448 
0449   int CHS = 0;                  /* --??-- Set to non-zero for CHS mode */
0450 
0451   /* Hard-code the size of the disk in sectors */
0452   /* int part_length = ( ( 60 * 63 + 16 ) * 63 ) + 63 - 1; */
0453 
0454   sector += 63;                 /* --??-- Start of partition: see fdisk -u partition */
0455 
0456 #if 0
0457   /*
0458    * --??-- In future, check partition boundaries
0459    */
0460   if (sector < 0 || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
0461                      >= part_length)) {
0462     errnum = ERR_OUTSIDE_PART;
0463     return 0;
0464   }
0465 #endif
0466 
0467 
0468   /*
0469    *  Get the read to the beginning of a partition.
0470    */
0471   sector += byte_offset >> SECTOR_BITS;
0472   byte_offset &= SECTOR_SIZE - 1;
0473 
0474   /*
0475    *  Perform RAWREAD, which is very similar, but:
0476    *
0477    *    --  It requires that "sector" is relative to the beginning
0478    *            of the disk.
0479    *    --  It doesn't handle offsets of more than 511 bytes into the
0480    *            sector.
0481    */
0482 
0483   /* In what follows, we read the end of first sector, zero or more sectors
0484    * followed by (possibly) a partial final sector.
0485    *
0486    * Round up to a sector boundary -- Will need to read 'partial_bytes' 
0487    */
0488   if (byte_offset) {
0489     partial_bytes = SECTOR_SIZE - byte_offset;
0490 
0491     if (CHS) {
0492       LBAtoCHS (sector, &cyl, &hd, &sect);
0493       ReadSector (sector_buf, cyl, hd, sect);
0494     } else
0495       ReadSectorLBA (sector_buf, sector);
0496 
0497     memcpy (buf, sector_buf + byte_offset, partial_bytes);
0498     buf += partial_bytes;
0499     byte_len -= partial_bytes;
0500     sector++;
0501   }
0502 
0503   for (; byte_len >= SECTOR_SIZE; byte_len -= SECTOR_SIZE) {
0504     if (CHS) {
0505       LBAtoCHS (sector, &cyl, &hd, &sect);
0506       ReadSector (buf, cyl, hd, sect);
0507     } else
0508       ReadSectorLBA (buf, sector);
0509 
0510     buf += SECTOR_SIZE;
0511     sector++;
0512   }
0513 
0514   if (byte_len) {
0515     if (CHS) {
0516       LBAtoCHS (sector, &cyl, &hd, &sect);
0517       ReadSector (sector_buf, cyl, hd, sect);
0518     } else
0519       ReadSectorLBA (sector_buf, sector);
0520 
0521     memcpy (buf, sector_buf, byte_len);
0522   }
0523 
0524   return 1;
0525 }
0526 
0527 
0528 /* include/asm-i386/bitops.h */
0529 /*
0530  * ffz = Find First Zero in word. Undefined if no zero exists,
0531  * so code should check against ~0UL first..
0532  */
0533 static __inline__ uint32
0534 ffz (uint32 word)
0535 {
0536   asm volatile ("bsfl %1,%0":"=r" (word):"r" (~word));
0537   return word;
0538 }
0539 
0540 /* check filesystem types and read superblock into memory buffer */
0541 int
0542 ext2fs_mount (void)
0543 {
0544   int retval = 1;
0545 
0546   if (!devread (SBLOCK, 0, sizeof (struct ext2_super_block),
0547                 (char *) SUPERBLOCK)
0548       || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
0549     retval = 0;
0550 
0551   return retval;
0552 }
0553 
0554 /* Takes a file system block number and reads it into BUFFER. */
0555 static int
0556 ext2_rdfsb (int fsblock, int buffer)
0557 {
0558 #ifdef E2DEBUG
0559   printf ("fsblock %d buffer %d\n", fsblock, buffer);
0560 #endif /* E2DEBUG */
0561   return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
0562                   EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
0563 }
0564 
0565 /* from
0566   ext2/inode.c:ext2_bmap()
0567 */
0568 /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
0569    a physical block (the location in the file system) via an inode. */
0570 static int
0571 ext2fs_block_map (int logical_block)
0572 {
0573 
0574 #ifdef E2DEBUG
0575   uint8 *i;
0576   for (i = (uint8 *) INODE;
0577        i < ((uint8 *) INODE + sizeof (struct ext2_inode)); i++) {
0578     printf ("%c", "0123456789abcdef"[*i >> 4]);
0579     printf ("%c", "0123456789abcdef"[*i % 16]);
0580     if (!((i + 1 - (uint8 *) INODE) % 16)) {
0581       printf ("\n");
0582     } else {
0583       printf (" ");
0584     }
0585   }
0586   printf ("logical block %d\n", logical_block);
0587 #endif /* E2DEBUG */
0588 
0589   /* if it is directly pointed to by the inode, return that physical addr */
0590   if (logical_block < EXT2_NDIR_BLOCKS) {
0591 #ifdef E2DEBUG
0592     printf ("returning %d\n", (uint8 *) (INODE->i_block[logical_block]));
0593     printf ("returning %d\n", INODE->i_block[logical_block]);
0594 #endif /* E2DEBUG */
0595     return INODE->i_block[logical_block];
0596   }
0597   /* else */
0598   logical_block -= EXT2_NDIR_BLOCKS;
0599   /* try the indirect block */
0600   if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK)) {
0601     if (mapblock1 != 1
0602         && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1)) {
0603       errnum = ERR_FSYS_CORRUPT;
0604       return -1;
0605     }
0606     mapblock1 = 1;
0607     return ((__u32 *) DATABLOCK1)[logical_block];
0608   }
0609   /* else */
0610   logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
0611   /* now try the double indirect block */
0612   if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2))) {
0613     int bnum;
0614     if (mapblock1 != 2
0615         && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1)) {
0616       errnum = ERR_FSYS_CORRUPT;
0617       return -1;
0618     }
0619     mapblock1 = 2;
0620     if ((bnum = (((__u32 *) DATABLOCK1)
0621                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
0622         != mapblock2 && !ext2_rdfsb (bnum, DATABLOCK2)) {
0623       errnum = ERR_FSYS_CORRUPT;
0624       return -1;
0625     }
0626     mapblock2 = bnum;
0627     return ((__u32 *) DATABLOCK2)
0628       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
0629   }
0630   /* else */
0631   mapblock2 = -1;
0632   logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
0633   if (mapblock1 != 3
0634       && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1)) {
0635     errnum = ERR_FSYS_CORRUPT;
0636     return -1;
0637   }
0638   mapblock1 = 3;
0639   if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
0640                    [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
0641                                       * 2)], DATABLOCK2)) {
0642     errnum = ERR_FSYS_CORRUPT;
0643     return -1;
0644   }
0645   if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
0646                    [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
0647                     & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)], DATABLOCK2)) {
0648     errnum = ERR_FSYS_CORRUPT;
0649     return -1;
0650   }
0651   return ((__u32 *) DATABLOCK2)
0652     [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
0653 }
0654 
0655 /* preconditions: all preconds of ext2fs_block_map */
0656 int
0657 ext2fs_read (char *buf, int len)
0658 {
0659   int logical_block;
0660   int offset;
0661   int map;
0662   int ret = 0;
0663   int size = 0;
0664 
0665 #ifdef E2DEBUG
0666   static char hexdigit[] = "0123456789abcdef";
0667   uint8 *i;
0668   for (i = (uint8 *) INODE;
0669        i < ((uint8 *) INODE + sizeof (struct ext2_inode)); i++) {
0670     printf ("%c", hexdigit[*i >> 4]);
0671     printf ("%c", hexdigit[*i % 16]);
0672     if (!((i + 1 - (uint8 *) INODE) % 16)) {
0673       printf ("\n");
0674     } else {
0675       printf (" ");
0676     }
0677   }
0678 #endif /* E2DEBUG */
0679   while (len > 0) {
0680     /* find the (logical) block component of our location */
0681     logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
0682     offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
0683     map = ext2fs_block_map (logical_block);
0684 #ifdef E2DEBUG
0685     printf ("map=%d\n", map);
0686 #endif /* E2DEBUG */
0687     if (map < 0)
0688       break;
0689 
0690     size = EXT2_BLOCK_SIZE (SUPERBLOCK);
0691     size -= offset;
0692     if (size > len)
0693       size = len;
0694 
0695     if (map == 0) {
0696       memset ((char *) buf, 0, size);
0697     } else {
0698       devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
0699                offset, size, buf);
0700     }
0701 
0702     buf += size;
0703     len -= size;
0704     filepos += size;
0705     ret += size;
0706   }
0707 
0708   if (errnum)
0709     ret = 0;
0710 
0711   return ret;
0712 }
0713 
0714 
0715 /* Based on:
0716    def_blk_fops points to
0717    blkdev_open, which calls (I think):
0718    sys_open()
0719    do_open()
0720    open_namei()
0721    dir_namei() which accesses current->fs->root
0722      fs->root was set during original mount:
0723      (something)... which calls (I think):
0724      ext2_read_super()
0725      iget()
0726      __iget()
0727      read_inode()
0728      ext2_read_inode()
0729        uses desc_per_block_bits, which is set in ext2_read_super()
0730        also uses group descriptors loaded during ext2_read_super()
0731    lookup()
0732    ext2_lookup()
0733    ext2_find_entry()
0734    ext2_getblk()
0735 
0736 */
0737 
0738 static inline int
0739 ext2_is_fast_symlink (void)
0740 {
0741   int ea_blocks;
0742   ea_blocks =
0743     INODE->i_file_acl ? EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE : 0;
0744   return INODE->i_blocks == ea_blocks;
0745 }
0746 
0747 /* preconditions: ext2fs_mount already executed, therefore supblk in buffer
0748  *   known as SUPERBLOCK
0749  * returns: 0 if error, nonzero iff we were able to find the file successfully
0750  * postconditions: on a nonzero return, buffer known as INODE contains the
0751  *   inode of the file we were trying to look up
0752  * side effects: messes up GROUP_DESC buffer area
0753  */
0754 int
0755 ext2fs_dir (char *dirname)
0756 {
0757   int current_ino = EXT2_ROOT_INO;      /* start at the root */
0758   int updir_ino = current_ino;  /* the parent of the current directory */
0759   int group_id;                 /* which group the inode is in */
0760   int group_desc;               /* fs pointer to that group */
0761   int desc;                     /* index within that group */
0762   int ino_blk;                  /* fs pointer of the inode's information */
0763   int str_chk = 0;              /* used to hold the results of a string compare */
0764   struct ext2_group_desc *gdp;
0765   struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */
0766 
0767   char linkbuf[PATH_MAX];       /* buffer for following symbolic links */
0768   int link_count = 0;
0769 
0770   char *rest;
0771   char ch;                      /* temp char holder */
0772 
0773   int off;                      /* offset within block of directory entry (off mod blocksize) */
0774   int loc;                      /* location within a directory */
0775   int blk;                      /* which data blk within dir entry (off div blocksize) */
0776   long map;                     /* fs pointer of a particular block from dir entry */
0777   struct ext2_dir_entry *dp;    /* pointer to directory entry */
0778 #ifdef E2DEBUG
0779   uint8 *i;
0780 #endif /* E2DEBUG */
0781 
0782   /* loop invariants:
0783      current_ino = inode to lookup
0784      dirname = pointer to filename component we are cur looking up within
0785      the directory known pointed to by current_ino (if any)
0786    */
0787 
0788   filepos = 0;
0789   filemax = 0;
0790   errnum = 0;
0791 
0792   while (1) {
0793 #ifdef E2DEBUG
0794     printf ("inode %d\n", current_ino);
0795     printf ("dirname=%s\n", dirname);
0796 #endif /* E2DEBUG */
0797 
0798     /* look up an inode */
0799     group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
0800     group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
0801     desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
0802 #ifdef E2DEBUG
0803     printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
0804             EXT2_DESC_PER_BLOCK (SUPERBLOCK));
0805     printf ("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc,
0806             desc);
0807 #endif /* E2DEBUG */
0808     if (!ext2_rdfsb ((WHICH_SUPER + group_desc +
0809                       SUPERBLOCK->s_first_data_block), (int) GROUP_DESC)) {
0810       return -1;
0811     }
0812     gdp = GROUP_DESC;
0813     ino_blk = gdp[desc].bg_inode_table +
0814       (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
0815        >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
0816 #ifdef E2DEBUG
0817     printf ("inode table fsblock=%d\n", ino_blk);
0818 #endif /* E2DEBUG */
0819     if (!ext2_rdfsb (ino_blk, (int) INODE)) {
0820       return -1;
0821     }
0822 
0823     /* reset indirect blocks! */
0824     mapblock2 = mapblock1 = -1;
0825 
0826     raw_inode = INODE + ((current_ino - 1)
0827                          & (EXT2_BLOCK_SIZE (SUPERBLOCK) /
0828                             sizeof (struct ext2_inode) - 1));
0829 #ifdef E2DEBUG
0830     printf ("ipb=%d, sizeof(inode)=%d\n",
0831             (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
0832             sizeof (struct ext2_inode));
0833     printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
0834     printf ("offset into inode table block=%d\n",
0835             (int) raw_inode - (int) INODE);
0836     for (i = (uint8 *) INODE; i <= (uint8 *) raw_inode; i++) {
0837       printf ("%c", "0123456789abcdef"[*i >> 4]);
0838       printf ("%c", "0123456789abcdef"[*i % 16]);
0839       if (!((i + 1 - (uint8 *) INODE) % 16)) {
0840         printf ("\n");
0841       } else {
0842         printf (" ");
0843       }
0844     }
0845     printf ("first word=%x\n", *((int *) raw_inode));
0846 #endif /* E2DEBUG */
0847 
0848     /* copy inode to fixed location */
0849     memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
0850 
0851 #ifdef E2DEBUG
0852     printf ("first word=%x\n", *((int *) INODE));
0853 #endif /* E2DEBUG */
0854 
0855     /* If we've got a symbolic link, then chase it. */
0856     if (S_ISLNK (INODE->i_mode)) {
0857       int len;
0858       if (++link_count > MAX_LINK_COUNT) {
0859         errnum = ERR_SYMLINK_LOOP;
0860         return -1;
0861       }
0862 
0863       /* Find out how long our remaining name is. */
0864       len = 0;
0865       while (dirname[len] && !isspace (dirname[len]))
0866         len++;
0867 
0868       /* Get the symlink size. */
0869       filemax = (INODE->i_size);
0870       if (filemax + len > sizeof (linkbuf) - 2) {
0871         errnum = ERR_FILELENGTH;
0872         return -1;
0873       }
0874 
0875       if (len) {
0876         /* Copy the remaining name to the end of the symlink data.
0877            Note that DIRNAME and LINKBUF may overlap! */
0878         memmove (linkbuf + filemax, dirname, len);
0879       }
0880       linkbuf[filemax + len] = '\0';
0881 
0882       /* Read the symlink data. */
0883       if (!ext2_is_fast_symlink ()) {
0884 #if 0
0885         /* --??-- Disabled symlinks  */
0886         /* Read the necessary blocks, and reset the file pointer. */
0887         len = grub_read (linkbuf, filemax);
0888         filepos = 0;
0889         if (!len)
0890           return -1;
0891 #endif
0892       } else {
0893         /* Copy the data directly from the inode. */
0894         len = filemax;
0895         memmove (linkbuf, (char *) INODE->i_block, len);
0896       }
0897 
0898 #ifdef E2DEBUG
0899       printf ("symlink=%s\n", linkbuf);
0900 #endif
0901 
0902       dirname = linkbuf;
0903       if (*dirname == '/') {
0904         /* It's an absolute link, so look it up in root. */
0905         current_ino = EXT2_ROOT_INO;
0906         updir_ino = current_ino;
0907       } else {
0908         /* Relative, so look it up in our parent directory. */
0909         current_ino = updir_ino;
0910       }
0911 
0912       /* Try again using the new name. */
0913       continue;
0914     }
0915 
0916     /* if end of filename, INODE points to the file's inode */
0917     if (!*dirname || isspace (*dirname)) {
0918       if (!S_ISREG (INODE->i_mode)) {
0919         errnum = ERR_BAD_FILETYPE;
0920         return -1;
0921       }
0922 
0923       filemax = (INODE->i_size);
0924       return filemax;
0925     }
0926 
0927     /* else we have to traverse a directory */
0928     updir_ino = current_ino;
0929 
0930     /* skip over slashes */
0931     while (*dirname == '/')
0932       dirname++;
0933 
0934     /* if this isn't a directory of sufficient size to hold our file, abort */
0935     if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode)) {
0936       errnum = ERR_BAD_FILETYPE;
0937       return -1;
0938     }
0939 
0940     /* skip to next slash or end of filename (space) */
0941     for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
0942 
0943     /* look through this directory and find the next filename component */
0944     /* invariant: rest points to slash after the next filename component */
0945     *rest = 0;
0946     loc = 0;
0947 
0948     do {
0949 
0950 #ifdef E2DEBUG
0951       printf ("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
0952 #endif /* E2DEBUG */
0953 
0954       /* if our location/byte offset into the directory exceeds the size,
0955          give up */
0956       if (loc >= INODE->i_size) {
0957         errnum = ERR_FILE_NOT_FOUND;
0958         *rest = ch;
0959         return -1;
0960       }
0961 
0962       /* else, find the (logical) block component of our location */
0963       blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
0964 
0965       /* we know which logical block of the directory entry we are looking
0966          for, now we have to translate that to the physical (fs) block on
0967          the disk */
0968       map = ext2fs_block_map (blk);
0969 #ifdef E2DEBUG
0970       printf ("fs block=%d\n", map);
0971 #endif /* E2DEBUG */
0972       mapblock2 = -1;
0973       if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) {
0974         errnum = ERR_FSYS_CORRUPT;
0975         *rest = ch;
0976         return -1;
0977       }
0978       off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
0979       dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
0980       /* advance loc prematurely to next on-disk directory entry  */
0981       loc += dp->rec_len;
0982 
0983       /* NOTE: ext2fs filenames are NOT null-terminated */
0984 
0985 #ifdef E2DEBUG
0986       printf ("directory entry ino=%d\n", dp->inode);
0987       if (dp->inode)
0988         printf ("entry=%s\n", dp->name);
0989 #endif /* E2DEBUG */
0990 
0991       if (dp->inode) {
0992         int saved_c = dp->name[dp->name_len];
0993 
0994         dp->name[dp->name_len] = 0;
0995         str_chk = substring (dirname, dp->name);
0996         dp->name[dp->name_len] = saved_c;
0997       }
0998 
0999     }
1000     while (!dp->inode || (str_chk));
1001 
1002     current_ino = dp->inode;
1003     *(dirname = rest) = ch;
1004   }
1005   /* never get here */
1006 }
1007 
1008 /* 
1009  * Local Variables:
1010  * indent-tabs-mode: nil
1011  * mode: C
1012  * c-file-style: "gnu"
1013  * c-basic-offset: 2
1014  * End: 
1015  */
1016 
1017 /* vi: set et sw=2 sts=2: */