1 /*
   2     apfs.c -- parted support for apfs file systems
   3     Copyright (C) 1998-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 #include "amiga.h"
  26 #include "apfs.h"
  27 
  28 #if ENABLE_NLS
  29 #  include <libintl.h>
  30 #  define _(String) dgettext (PACKAGE, String)
  31 #else
  32 #  define _(String) (String)
  33 #endif /* ENABLE_NLS */
  34 
  35 static int
  36 _apfs_probe_root (uint32_t *block, uint32_t blocksize, uint32_t kind) {
  37         if (PED_BE32_TO_CPU (block[0]) != kind) return 0;
  38         return 1;
  39 }
  40 
  41 static PedGeometry*
  42 _generic_apfs_probe (PedGeometry* geom, uint32_t kind)
  43 {
  44         uint32_t *block;
  45         PedSector root;
  46         struct PartitionBlock * part;
  47         uint32_t blocksize = 1, reserved = 2, prealloc = 0;
  48 
  49         PED_ASSERT (geom != NULL, return NULL);
  50         PED_ASSERT (geom->dev != NULL, return NULL);
  51 
  52         /* Finds the blocksize, prealloc and reserved values of the partition block */
  53         if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
  54                 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
  55                         _("%s : Failed to allocate partition block\n"), __func__);
  56                 goto error_part;
  57         }
  58         if (amiga_find_part(geom, part) != NULL) {
  59                 prealloc = PED_BE32_TO_CPU (part->de_PreAlloc);
  60                 reserved = PED_BE32_TO_CPU (part->de_Reserved);
  61                 blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
  62                         * PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
  63         }
  64         ped_free (part);
  65 
  66         /* Test boot block */
  67         if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
  68                 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
  69                         _("%s : Failed to allocate block\n"), __func__);
  70                 goto error_block;
  71         }
  72         if (!ped_device_read (geom->dev, block, geom->start, blocksize)) {
  73                 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
  74                         _("%s : Couldn't read boot block %llu\n"), __func__, geom->start);
  75                 goto error;
  76         }
  77         if (PED_BE32_TO_CPU (block[0]) != kind) {
  78                 goto error;
  79         }
  80 
  81         /* Find and test the root block */
  82         root = geom->start+reserved*blocksize;
  83         if (!ped_device_read (geom->dev, block, root, blocksize)) {
  84                 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
  85                         _("%s : Couldn't read root block %llu\n"), __func__, root);
  86                 goto error;
  87         }
  88         if (_apfs_probe_root(block, blocksize, kind) == 1) {
  89                 ped_free(block);
  90                 return ped_geometry_duplicate (geom);
  91         }
  92 
  93 error:
  94         ped_free (block);
  95 error_block:
  96 error_part:
  97         return NULL;
  98 }
  99 
 100 static PedGeometry*
 101 _apfs1_probe (PedGeometry* geom) {
 102         return _generic_apfs_probe (geom, 0x50463101);
 103 }
 104 
 105 static PedGeometry*
 106 _apfs2_probe (PedGeometry* geom) {
 107         return _generic_apfs_probe (geom, 0x50463102);
 108 }
 109 
 110 static PedFileSystemOps _apfs1_ops = {
 111         .probe =                _apfs1_probe,
 112         .clobber =      NULL,
 113         .open =         NULL,
 114         .create =         NULL,
 115         .close =                NULL,
 116         .check =          NULL,
 117         .resize =               NULL,
 118         .copy =           NULL,
 119         .get_create_constraint =        NULL,
 120         .get_copy_constraint =  NULL,
 121         .get_resize_constraint =        NULL
 122 };
 123 static PedFileSystemOps _apfs2_ops = {
 124         .probe =                _apfs2_probe,
 125         .clobber =      NULL,
 126         .open =         NULL,
 127         .create =         NULL,
 128         .close =                NULL,
 129         .check =          NULL,
 130         .resize =               NULL,
 131         .copy =           NULL,
 132         .get_create_constraint =        NULL,
 133         .get_copy_constraint =  NULL,
 134         .get_resize_constraint =        NULL
 135 };
 136 
 137 #define APFS_BLOCK_SIZES ((int[2]){512, 0})
 138 
 139 PedFileSystemType _apfs1_type = {
 140        .next =           NULL,
 141        .ops =            &_apfs1_ops,
 142        .name =           "apfs1",
 143        .block_sizes =      APFS_BLOCK_SIZES
 144 };
 145 PedFileSystemType _apfs2_type = {
 146        .next =           NULL,
 147        .ops =            &_apfs2_ops,
 148        .name =           "apfs2",
 149        .block_sizes =      APFS_BLOCK_SIZES
 150 };