~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to fs/fshelp.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* fshelp.c -- Filesystem helper functions */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2004,2005,2006,2007,2008  Free Software Foundation, Inc.
5
 
 *
6
 
 *  GRUB is free software: you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation, either version 3 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  GRUB is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include <grub/err.h>
21
 
#include <grub/mm.h>
22
 
#include <grub/misc.h>
23
 
#include <grub/disk.h>
24
 
#include <grub/fshelp.h>
25
 
 
26
 
 
27
 
/* Lookup the node PATH.  The node ROOTNODE describes the root of the
28
 
   directory tree.  The node found is returned in FOUNDNODE, which is
29
 
   either a ROOTNODE or a new malloc'ed node.  ITERATE_DIR is used to
30
 
   iterate over all directory entries in the current node.
31
 
   READ_SYMLINK is used to read the symlink if a node is a symlink.
32
 
   EXPECTTYPE is the type node that is expected by the called, an
33
 
   error is generated if the node is not of the expected type.  Make
34
 
   sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
35
 
   because GCC has a nasty bug when using regparm=3.  */
36
 
grub_err_t
37
 
grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
38
 
                       grub_fshelp_node_t *foundnode,
39
 
                       int (*iterate_dir) (grub_fshelp_node_t dir,
40
 
                                           int NESTED_FUNC_ATTR (*hook)
41
 
                                           (const char *filename,
42
 
                                            enum grub_fshelp_filetype filetype,
43
 
                                            grub_fshelp_node_t node)),
44
 
                       char *(*read_symlink) (grub_fshelp_node_t node),
45
 
                       enum grub_fshelp_filetype expecttype)
46
 
{
47
 
  grub_err_t err;
48
 
  enum grub_fshelp_filetype foundtype = GRUB_FSHELP_DIR;
49
 
  int symlinknest = 0;
50
 
 
51
 
  auto grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
52
 
                                              grub_fshelp_node_t currroot,
53
 
                                              grub_fshelp_node_t *currfound);
54
 
 
55
 
  grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
56
 
                                         grub_fshelp_node_t currroot,
57
 
                                         grub_fshelp_node_t *currfound)
58
 
    {
59
 
      char fpath[grub_strlen (currpath) + 1];
60
 
      char *name = fpath;
61
 
      char *next;
62
 
      //  unsigned int pos = 0;
63
 
      enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
64
 
      grub_fshelp_node_t currnode = currroot;
65
 
      grub_fshelp_node_t oldnode = currroot;
66
 
 
67
 
      auto int NESTED_FUNC_ATTR iterate (const char *filename,
68
 
                                         enum grub_fshelp_filetype filetype,
69
 
                                         grub_fshelp_node_t node);
70
 
 
71
 
      auto void free_node (grub_fshelp_node_t node);
72
 
 
73
 
      void free_node (grub_fshelp_node_t node)
74
 
        {
75
 
          if (node != rootnode && node != currroot)
76
 
            grub_free (node);
77
 
        }
78
 
 
79
 
      int NESTED_FUNC_ATTR iterate (const char *filename,
80
 
                                    enum grub_fshelp_filetype filetype,
81
 
                                    grub_fshelp_node_t node)
82
 
        {
83
 
          if (filetype == GRUB_FSHELP_UNKNOWN ||
84
 
              (grub_strcmp (name, filename) &&
85
 
               (! (filetype & GRUB_FSHELP_CASE_INSENSITIVE) ||
86
 
                grub_strncasecmp (name, filename, GRUB_LONG_MAX))))
87
 
            {
88
 
              grub_free (node);
89
 
              return 0;
90
 
            }
91
 
 
92
 
          /* The node is found, stop iterating over the nodes.  */
93
 
          type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
94
 
          oldnode = currnode;
95
 
          currnode = node;
96
 
 
97
 
          return 1;
98
 
        }
99
 
 
100
 
      grub_strncpy (fpath, currpath, grub_strlen (currpath) + 1);
101
 
 
102
 
      /* Remove all leading slashes.  */
103
 
      while (*name == '/')
104
 
        name++;
105
 
 
106
 
      if (! *name)
107
 
        {
108
 
          *currfound = currnode;
109
 
          return 0;
110
 
        }
111
 
 
112
 
      for (;;)
113
 
        {
114
 
          int found;
115
 
 
116
 
          /* Extract the actual part from the pathname.  */
117
 
          next = grub_strchr (name, '/');
118
 
          if (next)
119
 
            {
120
 
              /* Remove all leading slashes.  */
121
 
              while (*next == '/')
122
 
                *(next++) = '\0';
123
 
            }
124
 
 
125
 
          /* At this point it is expected that the current node is a
126
 
             directory, check if this is true.  */
127
 
          if (type != GRUB_FSHELP_DIR)
128
 
            {
129
 
              free_node (currnode);
130
 
              return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
131
 
            }
132
 
 
133
 
          /* Iterate over the directory.  */
134
 
          found = iterate_dir (currnode, iterate);
135
 
          if (! found)
136
 
            {
137
 
              if (grub_errno)
138
 
                return grub_errno;
139
 
 
140
 
              break;
141
 
            }
142
 
 
143
 
          /* Read in the symlink and follow it.  */
144
 
          if (type == GRUB_FSHELP_SYMLINK)
145
 
            {
146
 
              char *symlink;
147
 
 
148
 
              /* Test if the symlink does not loop.  */
149
 
              if (++symlinknest == 8)
150
 
                {
151
 
                  free_node (currnode);
152
 
                  free_node (oldnode);
153
 
                  return grub_error (GRUB_ERR_SYMLINK_LOOP,
154
 
                                     "too deep nesting of symlinks");
155
 
                }
156
 
 
157
 
              symlink = read_symlink (currnode);
158
 
              free_node (currnode);
159
 
 
160
 
              if (!symlink)
161
 
                {
162
 
                  free_node (oldnode);
163
 
                  return grub_errno;
164
 
                }
165
 
 
166
 
              /* The symlink is an absolute path, go back to the root inode.  */
167
 
              if (symlink[0] == '/')
168
 
                {
169
 
                  free_node (oldnode);
170
 
                  oldnode = rootnode;
171
 
                }
172
 
 
173
 
              /* Lookup the node the symlink points to.  */
174
 
              find_file (symlink, oldnode, &currnode);
175
 
              type = foundtype;
176
 
              grub_free (symlink);
177
 
 
178
 
              if (grub_errno)
179
 
                {
180
 
                  free_node (oldnode);
181
 
                  return grub_errno;
182
 
                }
183
 
            }
184
 
 
185
 
          free_node (oldnode);
186
 
 
187
 
          /* Found the node!  */
188
 
          if (! next || *next == '\0')
189
 
            {
190
 
              *currfound = currnode;
191
 
              foundtype = type;
192
 
              return 0;
193
 
            }
194
 
 
195
 
          name = next;
196
 
        }
197
 
 
198
 
      return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
199
 
    }
200
 
 
201
 
  if (!path || path[0] != '/')
202
 
    {
203
 
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
204
 
      return grub_errno;
205
 
    }
206
 
 
207
 
  err = find_file (path, rootnode, foundnode);
208
 
  if (err)
209
 
    return err;
210
 
 
211
 
  /* Check if the node that was found was of the expected type.  */
212
 
  if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype)
213
 
    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");
214
 
  else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype)
215
 
    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
216
 
 
217
 
  return 0;
218
 
}
219
 
 
220
 
/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF,
221
 
   beginning with the block POS.  READ_HOOK should be set before
222
 
   reading a block from the file.  GET_BLOCK is used to translate file
223
 
   blocks to disk blocks.  The file is FILESIZE bytes big and the
224
 
   blocks have a size of LOG2BLOCKSIZE (in log2).  */
225
 
grub_ssize_t
226
 
grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
227
 
                       void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
228
 
                                                           unsigned offset,
229
 
                                                           unsigned length),
230
 
                       grub_off_t pos, grub_size_t len, char *buf,
231
 
                       grub_disk_addr_t (*get_block) (grub_fshelp_node_t node,
232
 
                                                      grub_disk_addr_t block),
233
 
                       grub_off_t filesize, int log2blocksize)
234
 
{
235
 
  grub_disk_addr_t i, blockcnt;
236
 
  int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
237
 
 
238
 
  /* Adjust LEN so it we can't read past the end of the file.  */
239
 
  if (pos + len > filesize)
240
 
    len = filesize - pos;
241
 
 
242
 
  blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
243
 
 
244
 
  for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
245
 
    {
246
 
      grub_disk_addr_t blknr;
247
 
      int blockoff = pos & (blocksize - 1);
248
 
      int blockend = blocksize;
249
 
 
250
 
      int skipfirst = 0;
251
 
 
252
 
      blknr = get_block (node, i);
253
 
      if (grub_errno)
254
 
        return -1;
255
 
 
256
 
      blknr = blknr << log2blocksize;
257
 
 
258
 
      /* Last block.  */
259
 
      if (i == blockcnt - 1)
260
 
        {
261
 
          blockend = (len + pos) & (blocksize - 1);
262
 
 
263
 
          /* The last portion is exactly blocksize.  */
264
 
          if (! blockend)
265
 
            blockend = blocksize;
266
 
        }
267
 
 
268
 
      /* First block.  */
269
 
      if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS)))
270
 
        {
271
 
          skipfirst = blockoff;
272
 
          blockend -= skipfirst;
273
 
        }
274
 
 
275
 
      /* If the block number is 0 this block is not stored on disk but
276
 
         is zero filled instead.  */
277
 
      if (blknr)
278
 
        {
279
 
          disk->read_hook = read_hook;
280
 
 
281
 
          grub_disk_read (disk, blknr, skipfirst,
282
 
                          blockend, buf);
283
 
          disk->read_hook = 0;
284
 
          if (grub_errno)
285
 
            return -1;
286
 
        }
287
 
      else
288
 
        grub_memset (buf, 0, blockend);
289
 
 
290
 
      buf += blocksize - skipfirst;
291
 
    }
292
 
 
293
 
  return len;
294
 
}
295
 
 
296
 
unsigned int
297
 
grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow)
298
 
{
299
 
  int mod;
300
 
 
301
 
  *pow = 0;
302
 
  while (blksize > 1)
303
 
    {
304
 
      mod = blksize - ((blksize >> 1) << 1);
305
 
      blksize >>= 1;
306
 
 
307
 
      /* Check if it really is a power of two.  */
308
 
      if (mod)
309
 
        return grub_error (GRUB_ERR_BAD_NUMBER,
310
 
                           "the blocksize is not a power of two");
311
 
      (*pow)++;
312
 
    }
313
 
 
314
 
  return GRUB_ERR_NONE;
315
 
}