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 }