/[grub]/grub2/fs/ext2.c
ViewVC logotype

Diff of /grub2/fs/ext2.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by marco_g, Fri Aug 13 22:33:35 2004 UTC revision 1.9 by marco_g, Sat Sep 11 11:42:43 2004 UTC
# Line 29  Line 29 
29    
30  /* Filetype used in directory entry.  */  /* Filetype used in directory entry.  */
31  #define FILETYPE_UNKNOWN        0  #define FILETYPE_UNKNOWN        0
32    #define FILETYPE_REG            1
33  #define FILETYPE_DIRECTORY      2  #define FILETYPE_DIRECTORY      2
34  #define FILETYPE_SYMLINK        7  #define FILETYPE_SYMLINK        7
35    
36  /* Filetype information as used in inodes.  */  /* Filetype information as used in inodes.  */
37  #define FILETYPE_INO_MASK       0170000  #define FILETYPE_INO_MASK       0170000
38    #define FILETYPE_INO_REG        0100000
39  #define FILETYPE_INO_DIRECTORY  0040000  #define FILETYPE_INO_DIRECTORY  0040000
40  #define FILETYPE_INO_SYMLINK    0120000  #define FILETYPE_INO_SYMLINK    0120000
41    
# Line 44  Line 46 
46  #include <grub/disk.h>  #include <grub/disk.h>
47  #include <grub/dl.h>  #include <grub/dl.h>
48  #include <grub/types.h>  #include <grub/types.h>
49    #include <grub/fshelp.h>
50    
51  /* Log2 size of ext2 block in 512 blocks.  */  /* Log2 size of ext2 block in 512 blocks.  */
52  #define LOG2_EXT2_BLOCK_SIZE(data)                      \  #define LOG2_EXT2_BLOCK_SIZE(data)                      \
# Line 57  Line 60 
60  #define EXT2_BLOCK_SIZE(data)           (1 << LOG2_BLOCK_SIZE(data))  #define EXT2_BLOCK_SIZE(data)           (1 << LOG2_BLOCK_SIZE(data))
61    
62  /* The ext2 superblock.  */  /* The ext2 superblock.  */
63  struct grub_ext_sblock  struct grub_ext2_sblock
64  {  {
65    grub_uint32_t total_inodes;    grub_uint32_t total_inodes;
66    grub_uint32_t total_blocks;    grub_uint32_t total_blocks;
# Line 97  struct grub_ext_sblock Line 100  struct grub_ext_sblock
100  };  };
101    
102  /* The ext2 blockgroup.  */  /* The ext2 blockgroup.  */
103  struct ext2_block_group  struct grub_ext2_block_group
104  {  {
105    grub_uint32_t block_id;    grub_uint32_t block_id;
106    grub_uint32_t inode_id;    grub_uint32_t inode_id;
# Line 150  struct ext2_dirent Line 153  struct ext2_dirent
153    grub_uint8_t filetype;    grub_uint8_t filetype;
154  };  };
155    
156    struct grub_fshelp_node
157    {
158      struct grub_ext2_data *data;
159      struct grub_ext2_inode inode;
160      int ino;
161      int inode_read;
162    };
163    
164  /* Information about a "mounted" ext2 filesystem.  */  /* Information about a "mounted" ext2 filesystem.  */
165  struct grub_ext2_data  struct grub_ext2_data
166  {  {
167    struct grub_ext_sblock sblock;    struct grub_ext2_sblock sblock;
168    grub_disk_t disk;    grub_disk_t disk;
169    struct grub_ext2_inode inode;    struct grub_ext2_inode *inode;
170      struct grub_fshelp_node diropen;
171  };  };
172    
173  #ifndef GRUB_UTIL  #ifndef GRUB_UTIL
# Line 166  static grub_dl_t my_mod; Line 178  static grub_dl_t my_mod;
178     the mounted filesystem DATA.  */     the mounted filesystem DATA.  */
179  inline static grub_err_t  inline static grub_err_t
180  grub_ext2_blockgroup (struct grub_ext2_data *data, int group,  grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
181                        struct ext2_block_group *blkgrp)                        struct grub_ext2_block_group *blkgrp)
182  {  {
183    return grub_disk_read (data->disk,    return grub_disk_read (data->disk,
184                           ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)                           ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
185                            << LOG2_EXT2_BLOCK_SIZE (data)),                            << LOG2_EXT2_BLOCK_SIZE (data)),
186                           group * sizeof (struct ext2_block_group),                           group * sizeof (struct grub_ext2_block_group),
187                           sizeof (struct ext2_block_group), (char *) blkgrp);                           sizeof (struct grub_ext2_block_group), (char *) blkgrp);
188  }  }
189    
190  /* Return in BLOCK the on disk block number of block FILEBLOCK in the  
191     opened file descibed by DATA.  If this block is not stored on disk  static int
192     in case of a sparse file return 0.  */  grub_ext2_read_block (grub_fshelp_node_t node, int fileblock)
 static grub_err_t  
 grub_ext2_get_file_block (struct grub_ext2_data *data,  
                           int fileblock, int *block)  
193  {  {
194      struct grub_ext2_data *data = node->data;
195      struct grub_ext2_inode *inode = &node->inode;
196    int blknr;    int blknr;
197    struct grub_ext2_inode *inode = &data->inode;    int blksz = EXT2_BLOCK_SIZE (data);
198      int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
199      
200    /* Direct blocks.  */    /* Direct blocks.  */
201    if (fileblock < INDIRECT_BLOCKS)    if (fileblock < INDIRECT_BLOCKS)
202      blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);      blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
203    /* Indirect.  */    /* Indirect.  */
204    else if (fileblock < INDIRECT_BLOCKS + EXT2_BLOCK_SIZE (data) / 4)    else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
205      {      {
206        grub_uint32_t indir[EXT2_BLOCK_SIZE (data) / 4];        grub_uint32_t indir[blksz / 4];
207    
208        if (grub_disk_read (data->disk,        if (grub_disk_read (data->disk,
209                            grub_le_to_cpu32 (inode->blocks.indir_block)                            grub_le_to_cpu32 (inode->blocks.indir_block)
210                            << LOG2_EXT2_BLOCK_SIZE (data),                            << log2_blksz,
211                            0, EXT2_BLOCK_SIZE (data), (char *) indir))                            0, blksz, (char *) indir))
212          return grub_errno;          return grub_errno;
213                        
214        blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);        blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
215      }      }
216    /* Double indirect.  */    /* Double indirect.  */
217    else if (fileblock < INDIRECT_BLOCKS + EXT2_BLOCK_SIZE (data) / 4    else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz  / 4 + 1))
            * (EXT2_BLOCK_SIZE (data)  / 4 + 1))  
218      {      {
219        unsigned int perblock = EXT2_BLOCK_SIZE (data) / 4;        unsigned int perblock = blksz / 4;
220        unsigned int rblock = fileblock - (INDIRECT_BLOCKS        unsigned int rblock = fileblock - (INDIRECT_BLOCKS
221                                           + EXT2_BLOCK_SIZE (data) / 4);                                           + blksz / 4);
222        grub_uint32_t indir[EXT2_BLOCK_SIZE (data) / 4];        grub_uint32_t indir[blksz / 4];
223    
224        if (grub_disk_read (data->disk,        if (grub_disk_read (data->disk,
225                            grub_le_to_cpu32 (inode->blocks.double_indir_block)                            grub_le_to_cpu32 (inode->blocks.double_indir_block)
226                            << LOG2_EXT2_BLOCK_SIZE (data),                            << log2_blksz,
227                            0, EXT2_BLOCK_SIZE (data), (char *) indir))                            0, blksz, (char *) indir))
228          return grub_errno;          return grub_errno;
229    
230        if (grub_disk_read (data->disk,        if (grub_disk_read (data->disk,
231                            grub_le_to_cpu32 (indir[rblock / perblock])                            grub_le_to_cpu32 (indir[rblock / perblock])
232                            << LOG2_EXT2_BLOCK_SIZE (data),                            << log2_blksz,
233                            0, EXT2_BLOCK_SIZE (data), (char *) indir))                            0, blksz, (char *) indir))
234          return grub_errno;          return grub_errno;
235    
236                
# Line 233  grub_ext2_get_file_block (struct grub_ex Line 244  grub_ext2_get_file_block (struct grub_ex
244        return grub_errno;        return grub_errno;
245      }      }
246    
247    *block = blknr;    return blknr;
   
   return 0;  
248  }  }
249    
250    
251  /* Read LEN bytes from the file described by DATA starting with byte  /* Read LEN bytes from the file described by DATA starting with byte
252     POS.  Return the amount of read bytes in READ.  */     POS.  Return the amount of read bytes in READ.  */
253  static grub_ssize_t  static grub_ssize_t
254  grub_ext2_read_file (struct grub_ext2_data *data,  grub_ext2_read_file (grub_fshelp_node_t node,
255                       void (*read_hook) (unsigned long sector,                       void (*read_hook) (unsigned long sector,
256                                          unsigned offset, unsigned length),                                          unsigned offset, unsigned length),
257                       int pos, unsigned int len, char *buf)                       int pos, unsigned int len, char *buf)
258  {  {
259    int i;    return grub_fshelp_read_file (node->data->disk, node, read_hook,
260    int blockcnt;                                  pos, len, buf, grub_ext2_read_block,
261                                    node->inode.size,
262    /* Adjust len so it we can't read past the end of the file.  */                                  LOG2_EXT2_BLOCK_SIZE (node->data));
263    if (len > grub_le_to_cpu32 (data->inode.size))      
     len = grub_le_to_cpu32 (data->inode.size);  
   
   blockcnt = ((len + pos)  
               + EXT2_BLOCK_SIZE (data) - 1) / EXT2_BLOCK_SIZE (data);  
   
   for (i = pos / EXT2_BLOCK_SIZE (data); i < blockcnt; i++)  
     {  
       int blknr;  
       int blockoff = pos % EXT2_BLOCK_SIZE (data);  
       int blockend = EXT2_BLOCK_SIZE (data);  
   
       int skipfirst = 0;  
   
       grub_ext2_get_file_block (data, i, &blknr);  
       if (grub_errno)  
         return -1;  
         
       blknr = blknr << LOG2_EXT2_BLOCK_SIZE (data);  
   
       /* Last block.  */  
       if (i == blockcnt - 1)  
         {  
           blockend = (len + pos) % EXT2_BLOCK_SIZE (data);  
             
           /* The last portion is exactly EXT2_BLOCK_SIZE (data).  */  
           if (!blockend)  
             blockend = EXT2_BLOCK_SIZE (data);  
         }  
   
       /* First block.  */  
       if (i == pos / EXT2_BLOCK_SIZE (data))  
         {  
           skipfirst = blockoff;  
           blockend -= skipfirst;  
         }  
   
       /* If the block number is 0 this block is not stored on disk but  
          is zero filled instead.  */  
       if (blknr)  
         {  
           data->disk->read_hook = read_hook;        
           grub_disk_read (data->disk, blknr, skipfirst,  
                           blockend, buf);  
           data->disk->read_hook = 0;  
           if (grub_errno)  
             return -1;  
         }  
       else  
         grub_memset (buf, EXT2_BLOCK_SIZE (data) - skipfirst, 0);  
   
       buf += EXT2_BLOCK_SIZE (data) - skipfirst;  
     }  
   
   return len;  
264  }  }
265    
266    
# Line 313  static grub_err_t Line 269  static grub_err_t
269  grub_ext2_read_inode (struct grub_ext2_data *data,  grub_ext2_read_inode (struct grub_ext2_data *data,
270                        int ino, struct grub_ext2_inode *inode)                        int ino, struct grub_ext2_inode *inode)
271  {  {
272    struct ext2_block_group blkgrp;    struct grub_ext2_block_group blkgrp;
273    struct grub_ext_sblock *sblock = &data->sblock;    struct grub_ext2_sblock *sblock = &data->sblock;
274    int inodes_per_block;    int inodes_per_block;
275        
276    unsigned int blkno;    unsigned int blkno;
# Line 355  grub_ext2_mount (grub_disk_t disk) Line 311  grub_ext2_mount (grub_disk_t disk)
311      return 0;      return 0;
312    
313    /* Read the superblock.  */    /* Read the superblock.  */
314    grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext_sblock),    grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock),
315                          (char *) &data->sblock);                          (char *) &data->sblock);
316    if (grub_errno)    if (grub_errno)
317      goto fail;      goto fail;
# Line 364  grub_ext2_mount (grub_disk_t disk) Line 320  grub_ext2_mount (grub_disk_t disk)
320    if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)    if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)
321      goto fail;      goto fail;
322        
323      data->diropen.data = data;
324      data->diropen.ino = 2;
325      data->diropen.inode_read = 1;
326    
327      data->inode = &data->diropen.inode;
328    data->disk = disk;    data->disk = disk;
329    
330      grub_ext2_read_inode (data, 2, data->inode);
331      if (grub_errno)
332        goto fail;
333      
334    return data;    return data;
335    
336   fail:   fail:
# Line 373  grub_ext2_mount (grub_disk_t disk) Line 339  grub_ext2_mount (grub_disk_t disk)
339    return 0;    return 0;
340  }  }
341    
342  /* Find the file with the pathname PATH on the filesystem described by  static char *
343     DATA.  Return its inode number in INO.  */  grub_ext2_read_symlink (grub_fshelp_node_t node)
 static grub_err_t  
 grub_ext2_find_file (struct grub_ext2_data *data, const char *path, int *ino)  
344  {  {
345    int blocksize = EXT2_BLOCK_SIZE (data)    char *symlink;
346      << grub_le_to_cpu32 (data->sblock.log2_block_size);    struct grub_fshelp_node *diro = node;
347    struct grub_ext2_inode *inode = &data->inode;    
348    int currinode = 2;    if (!diro->inode_read)
   int symlinkcnt = 0;  
   
   char fpath[EXT2_PATH_MAX];  
   char *name = fpath;  
   
   grub_strncpy (fpath, path, EXT2_PATH_MAX);  
   
   if (!name || name[0] != '/')  
     {  
       grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");  
       return grub_errno;  
     }  
   
   /* Skip the first slash.  */  
   name++;  
   if (!*name)  
349      {      {
350        *ino = 2;        grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
351        return 0;        if (grub_errno)
352            return 0;
353      }      }
354      
355    /* Remove trailing "/".  */    symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
356    if (name[grub_strlen (name) - 1] =='/')    if (!symlink)
357      name[grub_strlen (name) - 1] = '\0';      return 0;
358      
359    while (*name)    /* If the filesize of the symlink is bigger than
360         60 the symlink is stored in a separate block,
361         otherwise it is stored in the inode.  */
362      if (grub_le_to_cpu32 (diro->inode.size) <= 60)
363        grub_strncpy (symlink,
364                      diro->inode.symlink,
365                      grub_le_to_cpu32 (diro->inode.size));
366      else
367      {      {
368        unsigned int fpos = 0;        grub_ext2_read_file (diro, 0, 0,
369        char *next;                             grub_le_to_cpu32 (diro->inode.size),
370        int namesize;                             symlink);
371          if (grub_errno)
       /* Extract the actual part from the pathname.  */  
       next = grub_strchr (name, '/');  
       if (next)  
372          {          {
373            next[0] = '\0';            grub_free (symlink);
374            next++;            return 0;
375          }          }
376        }
377      
378      symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0';
379      return symlink;
380    }
381    
382        namesize = grub_strlen (name);  static int
383    grub_ext2_iterate_dir (grub_fshelp_node_t dir,
384                           int NESTED_FUNC_ATTR
385                           (*hook) (const char *filename,
386                                    enum grub_fshelp_filetype filetype,
387                                    grub_fshelp_node_t node))
388    {
389      unsigned int fpos = 0;
390      struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
391      
392      if (!diro->inode_read)
393        {
394          grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
395          if (grub_errno)
396            return 0;
397        }
398      
399      /* Search the file.  */
400      while (fpos < grub_le_to_cpu32 (diro->inode.size))
401        {
402          struct ext2_dirent dirent;
403    
404        /* Open the file.  */        grub_ext2_read_file (diro, 0, fpos, sizeof (struct ext2_dirent),
405        grub_ext2_read_inode (data, currinode, inode);                             (char *) &dirent);
406        if (grub_errno)        if (grub_errno)
407          goto fail;          return 0;
408                
409        /* Search the file.  */        if (dirent.namelen != 0)
       while (fpos < grub_le_to_cpu32 (inode->size))  
410          {          {
411            struct ext2_dirent dirent;            char filename[dirent.namelen + 1];
412              struct grub_fshelp_node *fdiro;
413            /* Read the directory entry.  */            enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
414            grub_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent),            
415                                 (char *) &dirent);            grub_ext2_read_file (diro, 0, fpos + sizeof (struct ext2_dirent),
416                                   dirent.namelen, filename);
417            if (grub_errno)            if (grub_errno)
418              goto fail;              return 0;
419              
420              fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
421              if (!fdiro)
422                return 0;
423              
424              fdiro->data = diro->data;
425              fdiro->ino = grub_le_to_cpu32 (dirent.inode);
426              
427              filename[dirent.namelen] = '\0';
428    
429            if (dirent.namelen != 0)            if (dirent.filetype != FILETYPE_UNKNOWN)
430              {              {
431                char filename[dirent.namelen + 1];                fdiro->inode_read = 0;
432    
433                /* Read the filename part of this directory entry.  */                if (dirent.filetype == FILETYPE_DIRECTORY)
434                grub_ext2_read_file (data, 0, fpos                  type = GRUB_FSHELP_DIR;
435                                     + sizeof (struct ext2_dirent),                else if (dirent.filetype == FILETYPE_SYMLINK)
436                                     dirent.namelen, filename);                  type = GRUB_FSHELP_SYMLINK;
437                  else if (dirent.filetype == FILETYPE_REG)
438                    type = GRUB_FSHELP_REG;
439                }
440              else
441                {
442                  /* The filetype can not be read from the dirent, read
443                     the inode to get more information.  */
444                  grub_ext2_read_inode (diro->data, grub_le_to_cpu32 (dirent.inode),
445                                        &fdiro->inode);
446                if (grub_errno)                if (grub_errno)
                 goto fail;  
             
               filename[dirent.namelen] = '\0';  
   
               /* Check if the current directory entry described the  
                  file we are looking for.  */  
               if (dirent.namelen == namesize  
                   && !grub_strncmp (name, filename, namesize))  
447                  {                  {
448                    /* Stat the inode.  */                    grub_free (fdiro);
449                    grub_ext2_read_inode (data,                    return 0;
                                         grub_le_to_cpu32 (dirent.inode),  
                                         inode);  
   
                   /* If this is a symlink, follow it.  */  
                   if ((grub_le_to_cpu16 (data->inode.mode)  
                        & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)  
                     {  
                       /* XXX: Use malloc instead?  */  
                       char symlink[blocksize];  
   
                       if (++symlinkcnt == EXT2_MAX_SYMLINKCNT)  
                         {  
                           grub_error (GRUB_ERR_SYMLINK_LOOP,  
                                       "too deep nesting of symlinks");  
                           goto fail;  
                         }  
   
                       /* If the filesize of the symlink is bigger than  
                          60 the symlink is stored in a separate block,  
                          otherwise it is stored in the inode.  */  
                       if (grub_le_to_cpu32 (inode->size) <= 60)  
                         grub_strncpy (symlink,  
                                       inode->symlink,  
                                       grub_le_to_cpu32 (inode->size));  
                       else  
                         {  
                           grub_ext2_read_file (data, 0, 0,  
                                                grub_le_to_cpu32 (inode->size),  
                                                symlink);  
                           if (grub_errno)  
                             goto fail;  
                         }  
   
                       symlink[grub_le_to_cpu32 (inode->size)] = '\0';  
             
                       /* Check if the symlink is absolute or relative.  */  
                       if (symlink[0] == '/')  
                         {  
                           grub_strncpy (fpath, symlink + 1, EXT2_PATH_MAX);  
                           name = fpath;  
                           currinode = 2;  
                         }  
                       else  
                         {  
                           char *bak = 0;  
   
                           if (next)  
                             {  
                               bak = grub_strdup (next);  
                               if (!bak)  
                                 goto fail;  
                             }  
                         
                           /* Relative symlink, construct the new path.  */  
                           grub_strcpy (fpath, symlink);  
                           name = fpath;  
                         
                           if (next)  
                             {  
                               grub_strcat (name, "/");  
                               grub_strcat (name, bak);  
                               grub_free (bak);  
                             }  
                         }  
   
                       fpos = 0;  
                       break;  
                     }  
   
                   if (next)  
                     {  
                       currinode = grub_le_to_cpu32 (dirent.inode);  
                       name = next;  
   
                       if ((grub_le_to_cpu16 (data->inode.mode)  
                            & FILETYPE_INO_MASK) != FILETYPE_INO_DIRECTORY)  
                         {  
                           grub_error (GRUB_ERR_BAD_FILE_TYPE,  
                                       "not a directory");  
                           goto fail;  
                         }  
                       break;  
                     }  
                   else /* Found it!  */  
                     {  
                       *ino = grub_le_to_cpu32 (dirent.inode);  
                       return 0;  
                     }  
450                  }                  }
451                  
452                  fdiro->inode_read = 1;
453                  
454                  if ((grub_le_to_cpu16 (diro->inode.mode)
455                       & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
456                    type = GRUB_FSHELP_DIR;
457                  else if ((grub_le_to_cpu16 (diro->inode.mode)
458                            & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
459                    type = GRUB_FSHELP_SYMLINK;
460                  else if ((grub_le_to_cpu16 (diro->inode.mode)
461                            & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
462                    type = GRUB_FSHELP_REG;
463              }              }
464              
465            /* Move to next directory entry.  */            if (hook (filename, type, fdiro))
466            fpos += grub_le_to_cpu16 (dirent.direntlen);              return 1;
         }  
   
       /* The complete directory was read and no matching file was  
          found.  */  
       if (fpos >= grub_le_to_cpu32 (inode->size))  
         {  
           grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");  
           goto fail;  
467          }          }
468          
469          fpos += grub_le_to_cpu16 (dirent.direntlen);
470      }      }
471      
472   fail:    return 0;
   return grub_errno;  
473  }  }
474    
475  /* Open a file named NAME and initialize FILE.  */  /* Open a file named NAME and initialize FILE.  */
# Line 572  static grub_err_t Line 477  static grub_err_t
477  grub_ext2_open (struct grub_file *file, const char *name)  grub_ext2_open (struct grub_file *file, const char *name)
478  {  {
479    struct grub_ext2_data *data;    struct grub_ext2_data *data;
480    int ino;    struct grub_fshelp_node *fdiro = 0;
481      
482  #ifndef GRUB_UTIL  #ifndef GRUB_UTIL
483    grub_dl_ref (my_mod);    grub_dl_ref (my_mod);
484  #endif  #endif
485      
486    data = grub_ext2_mount (file->device->disk);    data = grub_ext2_mount (file->device->disk);
487    if (!data)    if (!data)
488      goto fail;      goto fail;
489        
490    grub_ext2_find_file (data, name, &ino);    grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_ext2_iterate_dir,
491    if (grub_errno)                           grub_ext2_read_symlink, GRUB_FSHELP_REG);
     goto fail;  
   
   grub_ext2_read_inode (data, ino, &data->inode);  
492    if (grub_errno)    if (grub_errno)
493      goto fail;      goto fail;
494      
495    if (!(grub_le_to_cpu16 (data->inode.mode) & 0100000))    if (!fdiro->inode_read)
496      {      {
497        grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");        grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode);
498        goto fail;        if (grub_errno)
499            goto fail;
500      }      }
501        
502    file->size = grub_le_to_cpu32 (data->inode.size);    grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
503      grub_free (fdiro);
504    
505      file->size = grub_le_to_cpu32 (data->inode->size);
506    file->data = data;    file->data = data;
507    file->offset = 0;    file->offset = 0;
508    
509    return 0;    return 0;
510    
511   fail:   fail:
   
512    grub_free (data);    grub_free (data);
513      if (fdiro != &data->diropen)
514        grub_free (fdiro);
515      
516  #ifndef GRUB_UTIL  #ifndef GRUB_UTIL
517    grub_dl_unref (my_mod);    grub_dl_unref (my_mod);
518  #endif  #endif
# Line 632  grub_ext2_read (grub_file_t file, char * Line 539  grub_ext2_read (grub_file_t file, char *
539    struct grub_ext2_data *data =    struct grub_ext2_data *data =
540      (struct grub_ext2_data *) file->data;      (struct grub_ext2_data *) file->data;
541        
542    return grub_ext2_read_file (data, file->read_hook, file->offset, len, buf);    return grub_ext2_read_file (&data->diropen, file->read_hook,
543                                  file->offset, len, buf);
544  }  }
545    
546    
# Line 641  grub_ext2_dir (grub_device_t device, con Line 549  grub_ext2_dir (grub_device_t device, con
549                 int (*hook) (const char *filename, int dir))                 int (*hook) (const char *filename, int dir))
550  {  {
551    struct grub_ext2_data *data = 0;;    struct grub_ext2_data *data = 0;;
552      struct grub_fshelp_node *fdiro = 0;
   int ino;  
   unsigned int fpos = 0;  
553        
554      auto int NESTED_FUNC_ATTR iterate (const char *filename,
555                                         enum grub_fshelp_filetype filetype,
556                                         grub_fshelp_node_t node);
557    
558      int NESTED_FUNC_ATTR iterate (const char *filename,
559                                    enum grub_fshelp_filetype filetype,
560                                    grub_fshelp_node_t node)
561        {
562          grub_free (node);
563          
564          if (filetype == GRUB_FSHELP_DIR)
565            return hook (filename, 1);
566          else
567            return hook (filename, 0);
568          
569          return 0;
570        }
571    
572  #ifndef GRUB_UTIL  #ifndef GRUB_UTIL
573    grub_dl_ref (my_mod);    grub_dl_ref (my_mod);
574  #endif  #endif
# Line 652  grub_ext2_dir (grub_device_t device, con Line 576  grub_ext2_dir (grub_device_t device, con
576    data = grub_ext2_mount (device->disk);    data = grub_ext2_mount (device->disk);
577    if (!data)    if (!data)
578      goto fail;      goto fail;
579      
580    grub_ext2_find_file (data, (char *) path, &ino);    grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir,
581    if (grub_errno)                           grub_ext2_read_symlink, GRUB_FSHELP_DIR);
     goto fail;  
   
   grub_ext2_read_inode (data, ino, &data->inode);  
582    if (grub_errno)    if (grub_errno)
583      goto fail;      return grub_errno;
584      
585    if ((grub_le_to_cpu16 (data->inode.mode)    grub_ext2_iterate_dir (fdiro, iterate);
586         & FILETYPE_INO_MASK) != FILETYPE_INO_DIRECTORY)    
     {  
       grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");  
       goto fail;  
     }  
   
   /* Search the file.  */  
   while (fpos < grub_le_to_cpu32 (data->inode.size))  
     {  
       struct ext2_dirent dirent;  
           
       grub_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent),  
                            (char *) &dirent);  
       if (grub_errno)  
         goto fail;  
   
       if (dirent.namelen != 0)  
         {  
           char filename[dirent.namelen + 1];  
   
           grub_ext2_read_file (data, 0, fpos + sizeof (struct ext2_dirent),  
                                dirent.namelen, filename);  
           if (grub_errno)  
             goto fail;  
             
           filename[dirent.namelen] = '\0';  
             
           if (dirent.filetype != FILETYPE_UNKNOWN)  
             hook (filename, dirent.filetype == FILETYPE_DIRECTORY);  
           else  
             {  
               struct grub_ext2_inode inode;  
               grub_ext2_read_inode (data, grub_le_to_cpu32 (dirent.inode), &inode);  
                 
               hook (filename, (grub_le_to_cpu16 (inode.mode)  
                                & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY);  
             }  
         }  
   
       fpos += grub_le_to_cpu16 (dirent.direntlen);  
     }  
   
587   fail:   fail:
   
588    grub_free (data);    grub_free (data);
589      if (fdiro != &data->diropen)
590        grub_free (fdiro);
591    
592  #ifndef GRUB_UTIL  #ifndef GRUB_UTIL
593    grub_dl_unref (my_mod);    grub_dl_unref (my_mod);

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26