1 /*
2 libparted - a library for manipulating disk partitions
3 Copyright (C) 1999, 2000, 2007 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <parted/parted.h>
22 #include <parted/debug.h>
23 #include <parted/endian.h>
24
25 #if ENABLE_NLS
26 # include <libintl.h>
27 # define _(String) dgettext (PACKAGE, String)
28 #else
29 # define _(String) (String)
30 #endif /* ENABLE_NLS */
31
32 #define LOOP_SIGNATURE "GNU Parted Loopback 0"
33
34 static PedDiskType loop_disk_type;
35
36 static PedDisk* loop_alloc (const PedDevice* dev);
37 static void loop_free (PedDisk* disk);
38
39 static int
40 loop_probe (const PedDevice* dev)
41 {
42 PedDisk* disk;
43 char buf [512];
44 int result;
45
46 if (dev->sector_size != 512)
47 return 0;
48
49 disk = loop_alloc (dev);
50 if (!disk)
51 goto error;
52
53 if (!ped_device_read (dev, buf, 0, 1))
54 goto error_destroy_disk;
55 if (strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)) == 0) {
56 result = 1;
57 } else {
58 PedGeometry* geom;
59
60 geom = ped_geometry_new (dev, 0, disk->dev->length);
61 if (!geom)
62 goto error_destroy_disk;
63 result = ped_file_system_probe (geom) != NULL;
64 ped_geometry_destroy (geom);
65 }
66 loop_free (disk);
67 return result;
68
69 error_destroy_disk:
70 loop_free (disk);
71 error:
72 return 0;
73 }
74
75 #ifndef DISCOVER_ONLY
76 static int
77 loop_clobber (PedDevice* dev)
78 {
79 char buf [512];
80 PedSector i = 0;
81
82 PED_ASSERT (dev != NULL, return 0);
83
84 memset (buf, 0, 512);
85
86 while (loop_probe (dev)) {
87 if (!ped_device_write (dev, buf, i++, 1))
88 return 0;
89 }
90 return 1;
91 }
92 #endif /* !DISCOVER_ONLY */
93
94 static PedDisk*
95 loop_alloc (const PedDevice* dev)
96 {
97 PED_ASSERT (dev != NULL, return 0);
98
99 if (dev->length < 256)
100 return NULL;
101 return _ped_disk_alloc ((PedDevice*)dev, &loop_disk_type);
102 }
103
104 static PedDisk*
105 loop_duplicate (const PedDisk* disk)
106 {
107 return ped_disk_new_fresh (disk->dev, &loop_disk_type);
108 }
109
110 static void
111 loop_free (PedDisk* disk)
112 {
113 PED_ASSERT (disk != NULL, return);
114
115 _ped_disk_free (disk);
116 }
117
118 static int
119 loop_read (PedDisk* disk)
120 {
121 PedDevice* dev = NULL;
122 char buf [512];
123 PedGeometry* geom;
124 PedFileSystemType* fs_type;
125 PedPartition* part;
126 PedConstraint* constraint_any;
127
128 PED_ASSERT (disk != NULL, return 0);
129 dev = disk->dev;
130 constraint_any = ped_constraint_any (dev);
131
132 ped_disk_delete_all (disk);
133
134 if (!ped_device_read (dev, buf, 0, 1))
135 goto error;
136 if (!strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)))
137 return 1;
138
139 geom = ped_geometry_new (dev, 0, dev->length);
140 if (!geom)
141 goto error;
142
143 fs_type = ped_file_system_probe (geom);
144 if (!fs_type)
145 goto error_free_geom;
146
147 part = ped_partition_new (disk, 0, fs_type, geom->start, geom->end);
148 ped_geometry_destroy (geom);
149 if (!part)
150 goto error;
151 part->fs_type = fs_type;
152
153 if (!ped_disk_add_partition (disk, part, constraint_any))
154 goto error;
155 ped_constraint_destroy (constraint_any);
156 return 1;
157
158 error_free_geom:
159 ped_geometry_destroy (geom);
160 error:
161 ped_constraint_destroy (constraint_any);
162 return 0;
163 }
164
165 #ifndef DISCOVER_ONLY
166 static int
167 loop_write (const PedDisk* disk)
168 {
169 char buf [512];
170
171 if (ped_disk_get_partition (disk, 1)) {
172 if (!ped_device_read (disk->dev, buf, 0, 1))
173 return 0;
174 if (strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)) != 0)
175 return 1;
176 memset (buf, 0, strlen (LOOP_SIGNATURE));
177 return ped_device_write (disk->dev, buf, 0, 1);
178 }
179
180 memset (buf, 0, 512);
181 strcpy (buf, LOOP_SIGNATURE);
182
183 return ped_device_write (disk->dev, buf, 0, 1);
184 }
185 #endif /* !DISCOVER_ONLY */
186
187 static PedPartition*
188 loop_partition_new (const PedDisk* disk, PedPartitionType part_type,
189 const PedFileSystemType* fs_type,
190 PedSector start, PedSector end)
191 {
192 PedPartition* part;
193
194 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
195 if (!part)
196 return NULL;
197 part->disk_specific = NULL;
198 return part;
199 }
200
201 static PedPartition*
202 loop_partition_duplicate (const PedPartition* part)
203 {
204 PedPartition* result;
205
206 result = ped_partition_new (part->disk, part->type, part->fs_type,
207 part->geom.start, part->geom.end);
208 result->num = part->num;
209 return result;
210 }
211
212 static void
213 loop_partition_destroy (PedPartition* part)
214 {
215 ped_free (part);
216 }
217
218 static int
219 loop_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
220 {
221 part->fs_type = fs_type;
222 return 1;
223 }
224
225 static int
226 loop_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
227 {
228 return 0;
229 }
230
231 static int
232 loop_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
233 {
234 return 0;
235 }
236
237 static int
238 loop_partition_align (PedPartition* part, const PedConstraint* constraint)
239 {
240 PedGeometry* new_geom;
241
242 new_geom = ped_constraint_solve_nearest (constraint, &part->geom);
243 if (!new_geom) {
244 ped_exception_throw (
245 PED_EXCEPTION_ERROR,
246 PED_EXCEPTION_CANCEL,
247 _("Unable to satisfy all constraints on the "
248 "partition."));
249 return 0;
250 }
251 ped_geometry_set (&part->geom, new_geom->start, new_geom->length);
252 ped_geometry_destroy (new_geom);
253 return 1;
254 }
255
256 static int
257 loop_partition_is_flag_available (const PedPartition* part,
258 PedPartitionFlag flag)
259 {
260 return 0;
261 }
262
263 static int
264 loop_partition_enumerate (PedPartition* part)
265 {
266 part->num = 1;
267 return 1;
268 }
269
270 static int
271 loop_alloc_metadata (PedDisk* disk)
272 {
273 return 1;
274 }
275
276 static int
277 loop_get_max_primary_partition_count (const PedDisk* disk)
278 {
279 return 1;
280 }
281
282 static PedDiskOps loop_disk_ops = {
283 .probe = loop_probe,
284 #ifndef DISCOVER_ONLY
285 .clobber = loop_clobber,
286 #else
287 .clobber = NULL,
288 #endif
289 .alloc = loop_alloc,
290 .duplicate = loop_duplicate,
291 .free = loop_free,
292 .read = loop_read,
293 #ifndef DISCOVER_ONLY
294 .write = loop_write,
295 #else
296 .write = NULL,
297 #endif
298
299 .partition_new = loop_partition_new,
300 .partition_duplicate = loop_partition_duplicate,
301 .partition_destroy = loop_partition_destroy,
302 .partition_set_system = loop_partition_set_system,
303 .partition_set_flag = loop_partition_set_flag,
304 .partition_get_flag = loop_partition_get_flag,
305 .partition_is_flag_available = loop_partition_is_flag_available,
306 .partition_set_name = NULL,
307 .partition_get_name = NULL,
308 .partition_align = loop_partition_align,
309 .partition_enumerate = loop_partition_enumerate,
310
311 .alloc_metadata = loop_alloc_metadata,
312 .get_max_primary_partition_count =
313 loop_get_max_primary_partition_count
314 };
315
316 static PedDiskType loop_disk_type = {
317 .next = NULL,
318 .name = "loop",
319 .ops = &loop_disk_ops,
320 .features = 0
321 };
322
323 void
324 ped_disk_loop_init ()
325 {
326 ped_disk_type_register (&loop_disk_type);
327 }
328
329 void
330 ped_disk_loop_done ()
331 {
332 ped_disk_type_unregister (&loop_disk_type);
333 }