~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to disk/loopback.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* loopback.c - command to add loopback devices.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2005  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 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program 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, write to the Free Software
 
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include <grub/normal.h>
 
22
#include <grub/dl.h>
 
23
#include <grub/arg.h>
 
24
#include <grub/misc.h>
 
25
#include <grub/file.h>
 
26
#include <grub/disk.h>
 
27
#include <grub/mm.h>
 
28
 
 
29
struct grub_loopback
 
30
{
 
31
  char *devname;
 
32
  char *filename;
 
33
  int has_partitions;
 
34
  struct grub_loopback *next;
 
35
};
 
36
 
 
37
static struct grub_loopback *loopback_list; 
 
38
 
 
39
static const struct grub_arg_option options[] =
 
40
  {
 
41
    {"delete", 'd', 0, "delete the loopback device entry", 0, 0},
 
42
    {"partitions", 'p', 0, "set that the drive has partitions to"
 
43
     " simulate a harddrive", 0, 0},
 
44
    {0, 0, 0, 0, 0, 0}
 
45
  };
 
46
 
 
47
/* Delete the loopback device NAME.  */
 
48
static grub_err_t
 
49
delete_loopback (const char *name)
 
50
{
 
51
  struct grub_loopback *dev;
 
52
  struct grub_loopback **prev;
 
53
 
 
54
  /* Search for the device.  */
 
55
  for (dev = loopback_list, prev = &loopback_list;
 
56
       dev; prev = &dev->next, dev = dev->next)
 
57
    if (!grub_strcmp (dev->devname, name))
 
58
      break;
 
59
  if (!dev)
 
60
    return grub_error (GRUB_ERR_BAD_DEVICE, "Device not found");
 
61
  
 
62
  /* Remove the device from the list.  */
 
63
  *prev = dev->next;
 
64
 
 
65
  grub_free (dev->devname);
 
66
  grub_free (dev->filename);
 
67
  grub_free (dev);
 
68
  
 
69
  return 0;
 
70
}
 
71
 
 
72
/* The command to add and remove loopback devices.  */
 
73
static grub_err_t
 
74
grub_cmd_loopback (struct grub_arg_list *state,
 
75
                   int argc, char **args)
 
76
{
 
77
  grub_file_t file;
 
78
  struct grub_loopback *newdev;
 
79
  
 
80
  if (argc < 1)
 
81
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
 
82
  
 
83
  /* Check if `-d' was used.  */
 
84
  if (state[0].set)
 
85
      return delete_loopback (args[0]);
 
86
  
 
87
  if (argc < 2)
 
88
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 
89
 
 
90
  file = grub_file_open (args[1]);
 
91
  if (! file)
 
92
    return grub_errno;
 
93
  
 
94
  /* Close the file, the only reason for opening it is validation.  */
 
95
  grub_file_close (file);
 
96
  
 
97
  /* First try to replace the old device.  */
 
98
  for (newdev = loopback_list; newdev; newdev = newdev->next)
 
99
    if (!grub_strcmp (newdev->devname, args[0]))
 
100
      break;
 
101
  if (newdev)
 
102
    {
 
103
      char *newname = grub_strdup (args[1]);
 
104
      if (!newname)
 
105
        return grub_errno;
 
106
      
 
107
      grub_free (newdev->filename);
 
108
      newdev->filename = newname;
 
109
      
 
110
      /* Set has_partitions when `--partitions' was used.  */
 
111
      newdev->has_partitions = state[1].set;
 
112
      
 
113
      return 0;
 
114
    }
 
115
  
 
116
  /* Unable to replace it, make a new entry.  */
 
117
  newdev = grub_malloc (sizeof (struct grub_loopback));
 
118
  if (!newdev)
 
119
    return grub_errno;
 
120
  
 
121
  newdev->devname = grub_strdup (args[0]);
 
122
  if (!newdev->devname)
 
123
    {
 
124
      grub_free (newdev);
 
125
      return grub_errno;
 
126
    }
 
127
  
 
128
  newdev->filename = grub_strdup (args[1]);
 
129
  if (!newdev->devname)
 
130
    {
 
131
      grub_free (newdev->devname);
 
132
      grub_free (newdev);
 
133
      return grub_errno;
 
134
    }
 
135
  
 
136
  /* Set has_partitions when `--partitions' was used.  */
 
137
  newdev->has_partitions = state[1].set;
 
138
  
 
139
  /* Add the new entry to the list.  */
 
140
  newdev->next = loopback_list;
 
141
  loopback_list = newdev;
 
142
  
 
143
  return 0;
 
144
}
 
145
 
 
146
 
 
147
static int
 
148
grub_loopback_iterate (int (*hook) (const char *name))
 
149
{
 
150
  struct grub_loopback *d;
 
151
  for (d = loopback_list; d; d = d->next)
 
152
    {
 
153
      if (hook (d->devname))
 
154
        return 1;
 
155
    }
 
156
  return 0;
 
157
}
 
158
 
 
159
static grub_err_t
 
160
grub_loopback_open (const char *name, grub_disk_t disk)
 
161
{
 
162
  grub_file_t file;
 
163
  struct grub_loopback *dev;
 
164
    
 
165
  for (dev = loopback_list; dev; dev = dev->next)
 
166
    if (!grub_strcmp (dev->devname, name))
 
167
      break;
 
168
  
 
169
  if (! dev)
 
170
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
 
171
 
 
172
  file = grub_file_open (dev->filename);
 
173
  if (! file)
 
174
    return grub_errno;
 
175
  
 
176
  /* Use the filesize for the disk size, round up to a complete sector.  */
 
177
  disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1)
 
178
                         / GRUB_DISK_SECTOR_SIZE);
 
179
  disk->id = (int) dev;
 
180
  
 
181
  disk->has_partitions = dev->has_partitions;
 
182
  disk->data = file;
 
183
  
 
184
  return 0;
 
185
}
 
186
 
 
187
static void
 
188
grub_loopback_close (grub_disk_t disk)
 
189
{
 
190
  grub_file_t file = (grub_file_t) disk->data;
 
191
  
 
192
  grub_file_close (file);
 
193
}
 
194
 
 
195
static grub_err_t
 
196
grub_loopback_read (grub_disk_t disk, unsigned long sector,
 
197
                    unsigned long size, char *buf)
 
198
{
 
199
  grub_file_t file = (grub_file_t) disk->data;
 
200
  long pos;
 
201
  
 
202
  grub_file_seek (file, sector * GRUB_DISK_SECTOR_SIZE);
 
203
  
 
204
  grub_file_read (file, buf, size * GRUB_DISK_SECTOR_SIZE);
 
205
  if (grub_errno)
 
206
    return grub_errno;
 
207
  
 
208
  /* In case there is more data read than there is available, in case
 
209
     of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill
 
210
     the rest with zeros.  */
 
211
  pos = sector * GRUB_DISK_SECTOR_SIZE + size * GRUB_DISK_SECTOR_SIZE;
 
212
  if (pos > file->size)
 
213
    {
 
214
      unsigned long amount = pos - file->size;
 
215
      grub_memset (buf + pos - amount, amount, 0);
 
216
    }
 
217
  
 
218
  return 0;
 
219
}
 
220
 
 
221
static grub_err_t
 
222
grub_loopback_write (grub_disk_t disk __attribute ((unused)),
 
223
                   unsigned long sector __attribute ((unused)),
 
224
                   unsigned long size __attribute ((unused)),
 
225
                   const char *buf __attribute ((unused)))
 
226
{
 
227
  return GRUB_ERR_NOT_IMPLEMENTED_YET;
 
228
}
 
229
 
 
230
static struct grub_disk_dev grub_loopback_dev =
 
231
  {
 
232
    .name = "loopback",
 
233
    .id = GRUB_DISK_DEVICE_LOOPBACK_ID,
 
234
    .iterate = grub_loopback_iterate,
 
235
    .open = grub_loopback_open,
 
236
    .close = grub_loopback_close,
 
237
    .read = grub_loopback_read,
 
238
    .write = grub_loopback_write,
 
239
    .next = 0
 
240
  };
 
241
 
 
242
 
 
243
 
 
244
GRUB_MOD_INIT(loop)
 
245
{
 
246
  (void)mod;                    /* To stop warning. */
 
247
  grub_register_command ("loopback", grub_cmd_loopback, GRUB_COMMAND_FLAG_BOTH,
 
248
                         "loopback [-d|-p] DEVICENAME FILE",
 
249
                         "Make a device of a file.", options);
 
250
  grub_disk_dev_register (&grub_loopback_dev);
 
251
}
 
252
 
 
253
GRUB_MOD_FINI(loop)
 
254
{
 
255
  grub_unregister_command ("loopback");
 
256
  grub_disk_dev_unregister (&grub_loopback_dev);
 
257
}
 
258