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 }