~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/fs/amiga/amiga.c

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted/fs_amiga - amiga file system support.
 
3
    Copyright (C) 2000-2001, 2007, 2009-2012 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
    Contributor:  Sven Luther <luther@debian.org>
 
19
*/
 
20
 
 
21
#include <config.h>
 
22
#include <parted/parted.h>
 
23
#include <parted/debug.h>
 
24
#include <parted/endian.h>
 
25
 
 
26
#include "amiga.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
#define IDNAME_RIGIDDISK        (uint32_t)0x5244534B    /* 'RDSK' */
 
36
#define IDNAME_BADBLOCK         (uint32_t)0x42414442    /* 'BADB' */
 
37
#define IDNAME_PARTITION        (uint32_t)0x50415254    /* 'PART' */
 
38
#define IDNAME_FILESYSHEADER    (uint32_t)0x46534844    /* 'FSHD' */
 
39
#define IDNAME_LOADSEG          (uint32_t)0x4C534547    /* 'LSEG' */
 
40
#define IDNAME_BOOT             (uint32_t)0x424f4f54    /* 'BOOT' */
 
41
#define IDNAME_FREE             (uint32_t)0xffffffff
 
42
 
 
43
static const char *
 
44
_amiga_block_id (uint32_t id) {
 
45
        switch (id) {
 
46
                case IDNAME_RIGIDDISK :
 
47
                        return "RDSK";
 
48
                case IDNAME_BADBLOCK :
 
49
                        return "BADB";
 
50
                case IDNAME_PARTITION :
 
51
                        return "PART";
 
52
                case IDNAME_FILESYSHEADER :
 
53
                        return "FSHD";
 
54
                case IDNAME_LOADSEG :
 
55
                        return "LSEG";
 
56
                case IDNAME_BOOT :
 
57
                        return "BOOT";
 
58
                case IDNAME_FREE :
 
59
                        return "<free>";
 
60
                default :
 
61
                        return "<unknown>";
 
62
        }
 
63
}
 
64
 
 
65
struct AmigaIds *
 
66
_amiga_add_id (uint32_t id, struct AmigaIds *ids) {
 
67
        struct AmigaIds *newid;
 
68
 
 
69
        if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL) {
 
70
                ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 
71
                        _("%s : Failed to allocate id list element\n"), __func__);
 
72
                return 0;
 
73
        }
 
74
        newid->ID = id;
 
75
        newid->next = ids;
 
76
        return newid;
 
77
}
 
78
 
 
79
void
 
80
_amiga_free_ids (struct AmigaIds *ids) {
 
81
        struct AmigaIds *current, *next;
 
82
 
 
83
        for (current = ids; current != NULL; current = next) {
 
84
                next = current->next;
 
85
                free (current);
 
86
        }
 
87
}
 
88
int
 
89
_amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
 
90
        struct AmigaIds *current;
 
91
 
 
92
        for (current = ids; current != NULL; current = current->next) {
 
93
                if (id == current->ID)
 
94
                        return 1;
 
95
        }
 
96
        return 0;
 
97
}
 
98
 
 
99
#define AMIGA_RDB_NOT_FOUND     ((uint32_t)0xffffffff)
 
100
 
 
101
struct AmigaBlock {
 
102
    uint32_t    amiga_ID;               /* Identifier 32 bit word */
 
103
    uint32_t    amiga_SummedLongss;     /* Size of the structure for checksums */
 
104
    int32_t     amiga_ChkSum;           /* Checksum of the structure */
 
105
};
 
106
#define AMIGA(pos) ((struct AmigaBlock *)(pos))
 
107
 
 
108
struct RigidDiskBlock {
 
109
    uint32_t    rdb_ID;                 /* Identifier 32 bit word : 'RDSK' */
 
110
    uint32_t    rdb_SummedLongs;        /* Size of the structure for checksums */
 
111
    int32_t     rdb_ChkSum;             /* Checksum of the structure */
 
112
    uint32_t    rdb_HostID;             /* SCSI Target ID of host, not really used */
 
113
    uint32_t    rdb_BlockBytes;         /* Size of disk blocks */
 
114
    uint32_t    rdb_Flags;              /* RDB Flags */
 
115
    /* block list heads */
 
116
    uint32_t    rdb_BadBlockList;       /* Bad block list */
 
117
    uint32_t    rdb_PartitionList;      /* Partition list */
 
118
    uint32_t    rdb_FileSysHeaderList;  /* File system header list */
 
119
    uint32_t    rdb_DriveInit;          /* Drive specific init code */
 
120
    uint32_t    rdb_BootBlockList;      /* Amiga OS 4 Boot Blocks */
 
121
    uint32_t    rdb_Reserved1[5];       /* Unused word, need to be set to $ffffffff */
 
122
    /* physical drive characteristics */
 
123
    uint32_t    rdb_Cylinders;          /* Number of the cylinders of the drive */
 
124
    uint32_t    rdb_Sectors;            /* Number of sectors of the drive */
 
125
    uint32_t    rdb_Heads;              /* Number of heads of the drive */
 
126
    uint32_t    rdb_Interleave;         /* Interleave */
 
127
    uint32_t    rdb_Park;               /* Head parking cylinder */
 
128
    uint32_t    rdb_Reserved2[3];       /* Unused word, need to be set to $ffffffff */
 
129
    uint32_t    rdb_WritePreComp;       /* Starting cylinder of write precompensation */
 
130
    uint32_t    rdb_ReducedWrite;       /* Starting cylinder of reduced write current */
 
131
    uint32_t    rdb_StepRate;           /* Step rate of the drive */
 
132
    uint32_t    rdb_Reserved3[5];       /* Unused word, need to be set to $ffffffff */
 
133
    /* logical drive characteristics */
 
134
    uint32_t    rdb_RDBBlocksLo;        /* low block of range reserved for hardblocks */
 
135
    uint32_t    rdb_RDBBlocksHi;        /* high block of range for these hardblocks */
 
136
    uint32_t    rdb_LoCylinder;         /* low cylinder of partitionable disk area */
 
137
    uint32_t    rdb_HiCylinder;         /* high cylinder of partitionable data area */
 
138
    uint32_t    rdb_CylBlocks;          /* number of blocks available per cylinder */
 
139
    uint32_t    rdb_AutoParkSeconds;    /* zero for no auto park */
 
140
    uint32_t    rdb_HighRDSKBlock;      /* highest block used by RDSK */
 
141
                                        /* (not including replacement bad blocks) */
 
142
    uint32_t    rdb_Reserved4;
 
143
    /* drive identification */
 
144
    char        rdb_DiskVendor[8];
 
145
    char        rdb_DiskProduct[16];
 
146
    char        rdb_DiskRevision[4];
 
147
    char        rdb_ControllerVendor[8];
 
148
    char        rdb_ControllerProduct[16];
 
149
    char        rdb_ControllerRevision[4];
 
150
    uint32_t    rdb_Reserved5[10];
 
151
};
 
152
 
 
153
#define AMIGA_MAX_PARTITIONS    128
 
154
#define RDB_LOCATION_LIMIT      16
 
155
#define RDSK(pos) ((struct RigidDiskBlock *)(pos))
 
156
 
 
157
static int
 
158
_amiga_checksum (struct AmigaBlock *blk) {
 
159
        uint32_t *rdb = (uint32_t *) blk;
 
160
        uint32_t sum;
 
161
        int i, end;
 
162
 
 
163
        sum = PED_BE32_TO_CPU (rdb[0]);
 
164
        end = PED_BE32_TO_CPU (rdb[1]);
 
165
 
 
166
        if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
 
167
 
 
168
        for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
 
169
 
 
170
        return sum;
 
171
}
 
172
 
 
173
static void
 
174
_amiga_calculate_checksum (struct AmigaBlock *blk) {
 
175
 
 
176
        blk->amiga_ChkSum = PED_CPU_TO_BE32(
 
177
                PED_BE32_TO_CPU(blk->amiga_ChkSum) -
 
178
                _amiga_checksum((struct AmigaBlock *) blk));
 
179
        return;
 
180
}
 
181
 
 
182
 
 
183
static struct AmigaBlock *
 
184
_amiga_read_block (PedDevice *dev, struct AmigaBlock *blk, PedSector block, struct AmigaIds *ids) {
 
185
        if (!ped_device_read (dev, blk, block, 1)) {
 
186
                switch (ped_exception_throw(PED_EXCEPTION_ERROR,
 
187
                        PED_EXCEPTION_CANCEL,
 
188
                        _("%s : Couldn't read block %llu\n"), __func__, block))
 
189
                {
 
190
                        case PED_EXCEPTION_CANCEL :
 
191
                        case PED_EXCEPTION_UNHANDLED :
 
192
                        default :
 
193
                                return NULL;
 
194
                }
 
195
        }
 
196
        if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
 
197
                return NULL;
 
198
        if (_amiga_checksum (blk) != 0) {
 
199
                switch (ped_exception_throw(PED_EXCEPTION_ERROR,
 
200
                        PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
 
201
                        _("%s : Bad checksum on block %llu of type %s\n"),
 
202
                        __func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID))))
 
203
                {
 
204
                        case PED_EXCEPTION_CANCEL :
 
205
                                return NULL;
 
206
                        case PED_EXCEPTION_FIX :
 
207
                                _amiga_calculate_checksum(AMIGA(blk));
 
208
                                if (!ped_device_write (dev, blk, block, 1)) {
 
209
                                        switch (ped_exception_throw(PED_EXCEPTION_FATAL,
 
210
                                                PED_EXCEPTION_CANCEL,
 
211
                                                _("%s : Couldn't write block %d\n"), __func__, block))
 
212
                                        {
 
213
                                                case PED_EXCEPTION_CANCEL :
 
214
                                                case PED_EXCEPTION_UNHANDLED :
 
215
                                                default :
 
216
                                                        return NULL;
 
217
                                        }
 
218
                                }
 
219
                        case PED_EXCEPTION_IGNORE :
 
220
                        case PED_EXCEPTION_UNHANDLED :
 
221
                        default :
 
222
                                return blk;
 
223
                }
 
224
        }
 
225
        return blk;
 
226
}
 
227
 
 
228
static uint32_t
 
229
_amiga_find_rdb (PedDevice *dev, struct RigidDiskBlock *rdb) {
 
230
        int i;
 
231
        struct AmigaIds *ids;
 
232
 
 
233
        ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
 
234
 
 
235
        for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
 
236
                if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
 
237
                        continue;
 
238
                }
 
239
                if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
 
240
                        _amiga_free_ids (ids);
 
241
                        return i;
 
242
                }
 
243
        }
 
244
        _amiga_free_ids (ids);
 
245
        return AMIGA_RDB_NOT_FOUND;
 
246
}
 
247
 
 
248
static int
 
249
_amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
 
250
{
 
251
        uint32_t i;
 
252
 
 
253
        for (i = 0; i < max; i++)
 
254
                if (block == blocklist[i]) {
 
255
                        /* We are looping, let's stop.  */
 
256
                        return 1;
 
257
                }
 
258
        blocklist[max] = block;
 
259
        return 0;
 
260
}
 
261
 
 
262
/* We have already allocated a rdb, we are now reading it from the disk */
 
263
struct PartitionBlock *
 
264
amiga_find_part (PedGeometry *geom, struct PartitionBlock *part)
 
265
{
 
266
        struct RigidDiskBlock *rdb;
 
267
        uint32_t partblock;
 
268
        uint32_t partlist[AMIGA_MAX_PARTITIONS];
 
269
        int i;
 
270
 
 
271
        PED_ASSERT(geom!= NULL);
 
272
        PED_ASSERT(geom->dev!= NULL);
 
273
 
 
274
        if (!(rdb = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
 
275
                switch (ped_exception_throw(PED_EXCEPTION_ERROR,
 
276
                        PED_EXCEPTION_CANCEL,
 
277
                        _("%s : Failed to allocate disk_specific rdb block\n"), __func__))
 
278
                {
 
279
                        case PED_EXCEPTION_CANCEL :
 
280
                        case PED_EXCEPTION_UNHANDLED :
 
281
                        default :
 
282
                                return NULL;
 
283
                }
 
284
        }
 
285
        if (_amiga_find_rdb (geom->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
 
286
                switch (ped_exception_throw(PED_EXCEPTION_ERROR,
 
287
                        PED_EXCEPTION_CANCEL,
 
288
                        _("%s : Didn't find rdb block, should never happen\n"), __func__))
 
289
                {
 
290
                        case PED_EXCEPTION_CANCEL :
 
291
                        case PED_EXCEPTION_UNHANDLED :
 
292
                        default :
 
293
                                free(rdb);
 
294
                                return NULL;
 
295
                }
 
296
        }
 
297
 
 
298
        /* We initialize the hardblock free list to detect loops */
 
299
        for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = IDNAME_FREE;
 
300
 
 
301
        for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
 
302
                i < AMIGA_MAX_PARTITIONS && partblock != IDNAME_FREE;
 
303
                i++, partblock = PED_BE32_TO_CPU(part->pb_Next))
 
304
        {
 
305
                PedSector start, end;
 
306
                PedSector cylblocks;
 
307
 
 
308
                /* Let's look for loops in the partition table */
 
309
                if (_amiga_loop_check(partblock, partlist, i)) {
 
310
                        free (rdb);
 
311
                        return NULL;
 
312
                }
 
313
                /* Let's read a partition block to get its geometry*/
 
314
                if (!ped_device_read (geom->dev, part, (PedSector)partblock, 1)) {
 
315
                        switch (ped_exception_throw(PED_EXCEPTION_ERROR,
 
316
                                PED_EXCEPTION_CANCEL,
 
317
                                _("%s : Failed to read partition block %llu\n"),
 
318
                                __func__, (PedSector)partblock))
 
319
                        {
 
320
                                case PED_EXCEPTION_CANCEL :
 
321
                                case PED_EXCEPTION_UNHANDLED :
 
322
                                default :
 
323
                                        free(rdb);
 
324
                                        return NULL;
 
325
                        }
 
326
                }
 
327
 
 
328
                /* Current block is not a Partition Block */
 
329
                if (part->pb_ID != IDNAME_PARTITION) {
 
330
                        free (rdb);
 
331
                        return NULL;
 
332
                }
 
333
 
 
334
                /* Calculate the geometry of the partition */
 
335
                cylblocks = ((PedSector) PED_BE32_TO_CPU (part->de_Surfaces)) *
 
336
                        ((PedSector) PED_BE32_TO_CPU (part->de_BlocksPerTrack));
 
337
                start = ((PedSector) PED_BE32_TO_CPU (part->de_LowCyl)) * cylblocks;
 
338
                end = ((((PedSector) PED_BE32_TO_CPU (part->de_HighCyl))+1) * (cylblocks))-1;
 
339
 
 
340
                /* And check if it is the one we are searching for */
 
341
                if (start == geom->start && end == geom->end) {
 
342
                        free (rdb);
 
343
                        return part;
 
344
                }
 
345
        }
 
346
 
 
347
        free (rdb);
 
348
        return NULL;
 
349
}