xref: /netbsd-src/external/bsd/pdisk/dist/partition_map.c (revision 45b261d12f0e594311dd24457a980324e85b4b3a)
1 //
2 // partition_map.c - partition map routines
3 //
4 // Written by Eryk Vershen
5 //
6 
7 /*
8  * Copyright 1996,1997,1998 by Apple Computer, Inc.
9  *              All Rights Reserved
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appears in all copies and
14  * that both the copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE.
20  *
21  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26  */
27 
28 // for *printf()
29 #include <stdio.h>
30 
31 // for malloc(), calloc() & free()
32 #ifndef __linux__
33 #include <stdlib.h>
34 #else
35 #include <malloc.h>
36 #endif
37 
38 // for strncpy() & strcmp()
39 #include <string.h>
40 // for O_RDONLY & O_RDWR
41 #include <fcntl.h>
42 // for errno
43 #include <errno.h>
44 
45 #include <inttypes.h>
46 
47 #include "partition_map.h"
48 #include "pathname.h"
49 #include "hfs_misc.h"
50 #include "deblock_media.h"
51 #include "io.h"
52 #include "convert.h"
53 #include "util.h"
54 #include "errors.h"
55 
56 
57 //
58 // Defines
59 //
60 #define APPLE_HFS_FLAGS_VALUE	0x4000037f
61 #define get_align_long(x)	(*(x))
62 #define put_align_long(y, x)	((*(x)) = (y))
63 // #define TEST_COMPUTE
64 
65 
66 //
67 // Types
68 //
69 
70 
71 //
72 // Global Constants
73 //
74 const char * kFreeType	= "Apple_Free";
75 const char * kMapType	= "Apple_partition_map";
76 const char * kUnixType	= "Apple_UNIX_SVR2";
77 const char * kHFSType	= "Apple_HFS";
78 const char * kPatchType	= "Apple_Patches";
79 
80 const char * kFreeName	= "Extra";
81 
82 enum add_action {
83     kReplace = 0,
84     kAdd = 1,
85     kSplit = 2
86 };
87 
88 //
89 // Global Variables
90 //
91 extern int cflag;
92 
93 
94 //
95 // Forward declarations
96 //
97 int add_data_to_map(struct dpme *, long, partition_map_header *);
98 int coerce_block0(partition_map_header *map);
99 int contains_driver(partition_map *entry);
100 void combine_entry(partition_map *entry);
101 long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
102 DPME* create_data(const char *name, const char *dptype, uint32_t base, uint32_t length);
103 void delete_entry(partition_map *entry);
104 char *get_HFS_name(partition_map *entry, int *kind);
105 void insert_in_base_order(partition_map *entry);
106 void insert_in_disk_order(partition_map *entry);
107 int read_block(partition_map_header *map, uint32_t num, char *buf);
108 int read_partition_map(partition_map_header *map);
109 void remove_driver(partition_map *entry);
110 void remove_from_disk_order(partition_map *entry);
111 void renumber_disk_addresses(partition_map_header *map);
112 void sync_device_size(partition_map_header *map);
113 int write_block(partition_map_header *map, uint32_t num, char *buf);
114 
115 
116 //
117 // Routines
118 //
119 partition_map_header *
open_partition_map(char * name,int * valid_file,int ask_logical_size)120 open_partition_map(char *name, int *valid_file, int ask_logical_size)
121 {
122     MEDIA m;
123     partition_map_header * map;
124     int writable;
125     long size;
126 
127     m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
128     if (m == 0) {
129 	m = open_pathname_as_media(name, O_RDONLY);
130 	if (m == 0) {
131 	    error(errno, "can't open file '%s'", name);
132 	    *valid_file = 0;
133 	    return NULL;
134 	} else {
135 	    writable = 0;
136 	}
137     } else {
138 	writable = 1;
139     }
140     *valid_file = 1;
141 
142     map = (partition_map_header *) malloc(sizeof(partition_map_header));
143     if (map == NULL) {
144 	error(errno, "can't allocate memory for open partition map");
145 	close_media(m);
146 	return NULL;
147     }
148     map->name = name;
149     map->writable = (rflag)?0:writable;
150     map->changed = 0;
151     map->written = 0;
152     map->disk_order = NULL;
153     map->base_order = NULL;
154 
155     map->physical_block = media_granularity(m);	/* preflight */
156     m = open_deblock_media(PBLOCK_SIZE, m);
157     map->m = m;
158     map->misc = (Block0 *) malloc(PBLOCK_SIZE);
159     if (map->misc == NULL) {
160 	error(errno, "can't allocate memory for block zero buffer");
161 	close_media(map->m);
162 	free(map);
163 	return NULL;
164     } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
165 	    || convert_block0(map->misc, 1)
166 	    || coerce_block0(map)) {
167 	// if I can't read block 0 I might as well give up
168 	error(-1, "Can't read block 0 from '%s'", name);
169 	close_partition_map(map);
170 	return NULL;
171     }
172     map->physical_block = map->misc->sbBlkSize;
173     //printf("physical block size is %d\n", map->physical_block);
174 
175     if (ask_logical_size && interactive) {
176 	size = PBLOCK_SIZE;
177 	printf("A logical block is %ld bytes: ", size);
178 	flush_to_newline(0);
179 	get_number_argument("what should be the logical block size? ",
180 		&size, size);
181 	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
182 	if (size < PBLOCK_SIZE) {
183 	    size = PBLOCK_SIZE;
184 	}
185 	map->logical_block = size;
186     } else {
187 	map->logical_block = PBLOCK_SIZE;
188     }
189     if (map->logical_block > MAXIOSIZE) {
190 	map->logical_block = MAXIOSIZE;
191     }
192     if (map->logical_block > map->physical_block) {
193 	map->physical_block = map->logical_block;
194     }
195     map->blocks_in_map = 0;
196     map->maximum_in_map = -1;
197     map->media_size = compute_device_size(map, map);
198     sync_device_size(map);
199 
200     if (read_partition_map(map) < 0) {
201 	// some sort of failure reading the map
202     } else {
203 	// got it!
204 	;
205 	return map;
206     }
207     close_partition_map(map);
208     return NULL;
209 }
210 
211 
212 void
close_partition_map(partition_map_header * map)213 close_partition_map(partition_map_header *map)
214 {
215     partition_map * entry;
216     partition_map * next;
217 
218     if (map == NULL) {
219 	return;
220     }
221 
222     free(map->misc);
223 
224     for (entry = map->disk_order; entry != NULL; entry = next) {
225 	next = entry->next_on_disk;
226 	free(entry->data);
227 	free(entry->HFS_name);
228 	free(entry);
229     }
230     close_media(map->m);
231     free(map);
232 }
233 
234 
235 int
read_partition_map(partition_map_header * map)236 read_partition_map(partition_map_header *map)
237 {
238     DPME *data;
239     uint32_t limit;
240     uint32_t ix;
241     int old_logical;
242     double d;
243 
244 //printf("called read_partition_map\n");
245 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
246     data = (DPME *) malloc(PBLOCK_SIZE);
247     if (data == NULL) {
248 	error(errno, "can't allocate memory for disk buffers");
249 	return -1;
250     }
251 
252     if (read_block(map, 1, (char *)data) == 0) {
253 	error(-1, "Can't read block 1 from '%s'", map->name);
254 	free(data);
255 	return -1;
256     } else if (convert_dpme(data, 1)
257 	    || data->dpme_signature != DPME_SIGNATURE) {
258 	old_logical = map->logical_block;
259 	map->logical_block = 512;
260 	while (map->logical_block <= map->physical_block) {
261 	    if (read_block(map, 1, (char *)data) == 0) {
262 		error(-1, "Can't read block 1 from '%s'", map->name);
263 		free(data);
264 		return -1;
265 	    } else if (convert_dpme(data, 1) == 0
266 		    && data->dpme_signature == DPME_SIGNATURE) {
267 		d = map->media_size;
268 		map->media_size =  (d * old_logical) / map->logical_block;
269 		break;
270 	    }
271 	    map->logical_block *= 2;
272 	}
273 	if (map->logical_block > map->physical_block) {
274 	    error(-1, "No valid block 1 on '%s'", map->name);
275 	    free(data);
276 	    return -1;
277 	}
278     }
279 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
280 
281     limit = data->dpme_map_entries;
282     ix = 1;
283     while (1) {
284 	if (add_data_to_map(data, ix, map) == 0) {
285 	    free(data);
286 	    return -1;
287 	}
288 
289 	if (ix >= limit) {
290 	    break;
291 	} else {
292 	    ix++;
293 	}
294 
295 	data = (DPME *) malloc(PBLOCK_SIZE);
296 	if (data == NULL) {
297 	    error(errno, "can't allocate memory for disk buffers");
298 	    return -1;
299 	}
300 
301 	if (read_block(map, ix, (char *)data) == 0) {
302 	    error(-1, "Can't read block %u from '%s'", ix, map->name);
303 	    free(data);
304 	    return -1;
305 	} else if (convert_dpme(data, 1)
306 		|| (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
307 		|| (data->dpme_map_entries != limit && dflag == 0)) {
308 	    error(-1, "Bad data in block %u from '%s'", ix, map->name);
309 	    free(data);
310 	    return -1;
311 	}
312     }
313     return 0;
314 }
315 
316 
317 void
write_partition_map(partition_map_header * map)318 write_partition_map(partition_map_header *map)
319 {
320     char *block;
321     partition_map * entry;
322     int i = 0;
323     int result = 0;
324 
325     if (map->misc != NULL) {
326 	convert_block0(map->misc, 0);
327 	result = write_block(map, 0, (char *)map->misc);
328 	convert_block0(map->misc, 1);
329     } else {
330 	block = (char *) calloc(1, PBLOCK_SIZE);
331 	if (block != NULL) {
332 	    result = write_block(map, 0, block);
333 	    free(block);
334 	}
335     }
336     if (result == 0) {
337 	error(errno, "Unable to write block zero");
338     }
339     for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
340 	convert_dpme(entry->data, 0);
341 	result = write_block(map, entry->disk_address, (char *)entry->data);
342 	convert_dpme(entry->data, 1);
343 	i = entry->disk_address;
344 	if (result == 0) {
345 	    error(errno, "Unable to write block %d", i);
346 	}
347     }
348 
349 #ifdef __linux__
350 	// zap the block after the map (if possible) to get around a bug.
351     if (map->maximum_in_map > 0 &&  i < map->maximum_in_map) {
352 	i += 1;
353 	block = (char *) malloc(PBLOCK_SIZE);
354 	if (block != NULL) {
355 	    if (read_block(map, i, block)) {
356 		block[0] = 0;
357 		write_block(map, i, block);
358 	    }
359 	    free(block);
360 	}
361     }
362 #endif
363 
364     if (interactive)
365 	printf("The partition table has been altered!\n\n");
366 
367     os_reload_media(map->m);
368 }
369 
370 
371 int
add_data_to_map(struct dpme * data,long ix,partition_map_header * map)372 add_data_to_map(struct dpme *data, long ix, partition_map_header *map)
373 {
374     partition_map *entry;
375 
376 //printf("add data %d to map\n", ix);
377     entry = (partition_map *) malloc(sizeof(partition_map));
378     if (entry == NULL) {
379 	error(errno, "can't allocate memory for map entries");
380 	return 0;
381     }
382     entry->next_on_disk = NULL;
383     entry->prev_on_disk = NULL;
384     entry->next_by_base = NULL;
385     entry->prev_by_base = NULL;
386     entry->disk_address = ix;
387     entry->the_map = map;
388     entry->data = data;
389     entry->contains_driver = contains_driver(entry);
390     entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind);
391 
392     insert_in_disk_order(entry);
393     insert_in_base_order(entry);
394 
395     map->blocks_in_map++;
396     if (map->maximum_in_map < 0) {
397 	if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) {
398 	    map->maximum_in_map = data->dpme_pblocks;
399 	}
400     }
401 
402     return 1;
403 }
404 
405 
406 partition_map_header *
init_partition_map(char * name,partition_map_header * oldmap)407 init_partition_map(char *name, partition_map_header* oldmap)
408 {
409     partition_map_header *map;
410 
411     if (oldmap != NULL) {
412 	printf("map already exists\n");
413 	if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) {
414 	    return oldmap;
415 	}
416     }
417 
418     map = create_partition_map(name, oldmap);
419     if (map == NULL) {
420 	return oldmap;
421     }
422     close_partition_map(oldmap);
423 
424     add_partition_to_map("Apple", kMapType,
425 	    1, (map->media_size <= 128? 2: 63), map);
426     return map;
427 }
428 
429 
430 partition_map_header *
create_partition_map(char * name,partition_map_header * oldmap)431 create_partition_map(char *name, partition_map_header *oldmap)
432 {
433     MEDIA m;
434     partition_map_header * map;
435     DPME *data;
436     uint32_t default_number;
437     uint32_t number;
438     long size;
439     uint32_t multiple;
440 
441     m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
442     if (m == 0) {
443 	error(errno, "can't open file '%s' for %sing", name,
444 		(rflag)?"read":"writ");
445 	return NULL;
446     }
447 
448     map = (partition_map_header *) malloc(sizeof(partition_map_header));
449     if (map == NULL) {
450 	error(errno, "can't allocate memory for open partition map");
451 	close_media(m);
452 	return NULL;
453     }
454     map->name = name;
455     map->writable = (rflag)?0:1;
456     map->changed = 1;
457     map->disk_order = NULL;
458     map->base_order = NULL;
459 
460     if (oldmap != NULL) {
461 	size = oldmap->physical_block;
462     } else {
463 	size = media_granularity(m);
464     }
465     m = open_deblock_media(PBLOCK_SIZE, m);
466     map->m = m;
467     if (interactive) {
468 	printf("A physical block is %ld bytes: ", size);
469 	flush_to_newline(0);
470 	get_number_argument("what should be the physical block size? ",
471 		&size, size);
472 	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
473 	if (size < PBLOCK_SIZE) {
474 	    size = PBLOCK_SIZE;
475 	}
476     }
477     if (map->physical_block > MAXIOSIZE) {
478 	map->physical_block = MAXIOSIZE;
479     }
480     map->physical_block = size;
481     // printf("block size is %d\n", map->physical_block);
482 
483     if (oldmap != NULL) {
484 	size = oldmap->logical_block;
485     } else {
486 	size = PBLOCK_SIZE;
487     }
488     if (interactive) {
489 	printf("A logical block is %ld bytes: ", size);
490 	flush_to_newline(0);
491 	get_number_argument("what should be the logical block size? ",
492 		&size, size);
493 	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
494 	if (size < PBLOCK_SIZE) {
495 	    size = PBLOCK_SIZE;
496 	}
497     }
498 #if 0
499     if (size > map->physical_block) {
500 	size = map->physical_block;
501     }
502 #endif
503     map->logical_block = size;
504 
505     map->blocks_in_map = 0;
506     map->maximum_in_map = -1;
507 
508     number = compute_device_size(map, oldmap);
509     if (interactive) {
510 	printf("size of 'device' is %"PRIu32" blocks (%d byte blocks): ",
511 		number, map->logical_block);
512 	default_number = number;
513 	flush_to_newline(0);
514 	do {
515 	    long long_number = number;
516 	    if (get_number_argument("what should be the size? ",
517 		    &long_number, default_number) == 0) {
518 		printf("Not a number\n");
519 		flush_to_newline(1);
520 		number = 0;
521 	    } else {
522 		number = long_number;
523 		multiple = get_multiplier(map->logical_block);
524 		if (multiple == 0) {
525 		    printf("Bad multiplier\n");
526 		    number = 0;
527 		} else if (multiple != 1) {
528 		    if (0xFFFFFFFF/multiple < number) {
529 			printf("Number too large\n");
530 			number = 0;
531 		    } else {
532 			number *= multiple;
533 		    }
534 		}
535 	    }
536 	    default_number = kDefault;
537 	} while (number == 0);
538 
539 	if (number < 4) {
540 	    number = 4;
541 	}
542 	printf("new size of 'device' is %"PRIu32" blocks (%d byte blocks)\n",
543 		number, map->logical_block);
544     }
545     map->media_size = number;
546 
547     map->misc = (Block0 *) calloc(1, PBLOCK_SIZE);
548     if (map->misc == NULL) {
549 	error(errno, "can't allocate memory for block zero buffer");
550     } else {
551 	// got it!
552 	coerce_block0(map);
553 	sync_device_size(map);
554 
555 	data = (DPME *) calloc(1, PBLOCK_SIZE);
556 	if (data == NULL) {
557 	    error(errno, "can't allocate memory for disk buffers");
558 	} else {
559 	    // set data into entry
560 	    data->dpme_signature = DPME_SIGNATURE;
561 	    data->dpme_map_entries = 1;
562 	    data->dpme_pblock_start = 1;
563 	    data->dpme_pblocks = map->media_size - 1;
564 	    strncpy(data->dpme_name, kFreeName, DPISTRLEN);
565 	    strncpy(data->dpme_type, kFreeType, DPISTRLEN);
566 	    data->dpme_lblock_start = 0;
567 	    data->dpme_lblocks = data->dpme_pblocks;
568 	    dpme_writable_set(data, 1);
569 	    dpme_readable_set(data, 1);
570 	    dpme_bootable_set(data, 0);
571 	    dpme_in_use_set(data, 0);
572 	    dpme_allocated_set(data, 0);
573 	    dpme_valid_set(data, 1);
574 
575 	    if (add_data_to_map(data, 1, map) == 0) {
576 		free(data);
577 	    } else {
578 		return map;
579 	    }
580 	}
581     }
582     close_partition_map(map);
583     return NULL;
584 }
585 
586 
587 int
coerce_block0(partition_map_header * map)588 coerce_block0(partition_map_header *map)
589 {
590     Block0 *p;
591 
592     p = map->misc;
593     if (p == NULL) {
594 	return 1;
595     }
596     if (p->sbSig != BLOCK0_SIGNATURE) {
597 	p->sbSig = BLOCK0_SIGNATURE;
598 	if (map->physical_block == 1) {
599 	    p->sbBlkSize = PBLOCK_SIZE;
600 	} else {
601 	    p->sbBlkSize = map->physical_block;
602 	}
603 	p->sbBlkCount = 0;
604 	p->sbDevType = 0;
605 	p->sbDevId = 0;
606 	p->sbData = 0;
607 	p->sbDrvrCount = 0;
608     }
609     return 0;	// we do this simply to make it easier to call this function
610 }
611 
612 
613 int
add_partition_to_map(const char * name,const char * dptype,uint32_t base,uint32_t length,partition_map_header * map)614 add_partition_to_map(const char *name, const char *dptype, uint32_t base, uint32_t length,
615 	partition_map_header *map)
616 {
617     partition_map * cur;
618     DPME *data;
619     enum add_action act;
620     int limit;
621     uint32_t adjusted_base = 0;
622     uint32_t adjusted_length = 0;
623     uint32_t new_base = 0;
624     uint32_t new_length = 0;
625 
626 	// find a block that starts includes base and length
627     cur = map->base_order;
628     while (cur != NULL) {
629 	if (cur->data->dpme_pblock_start <= base
630 		&& (base + length) <=
631 		    (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) {
632 	    break;
633 	} else {
634 	  // check if request is past end of existing partitions, but on disk
635 	  if ((cur->next_by_base == NULL) &&
636 	      (base + length <= map->media_size)) {
637 	    // Expand final free partition
638 	    if ((istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) &&
639 		base >= cur->data->dpme_pblock_start) {
640 	      cur->data->dpme_pblocks =
641 		map->media_size - cur->data->dpme_pblock_start;
642 	      break;
643 	    }
644 	    // create an extra free partition
645 	    if (base >= cur->data->dpme_pblock_start + cur->data->dpme_pblocks) {
646 	      if (map->maximum_in_map < 0) {
647 		limit = map->media_size;
648 	      } else {
649 		limit = map->maximum_in_map;
650 	      }
651 	      if (map->blocks_in_map + 1 > limit) {
652 		printf("the map is not big enough\n");
653 		return 0;
654 	      }
655 	      data = create_data(kFreeName, kFreeType,
656 		  cur->data->dpme_pblock_start + cur->data->dpme_pblocks,
657 		  map->media_size - (cur->data->dpme_pblock_start + cur->data->dpme_pblocks));
658 	      if (data != NULL) {
659 		if (add_data_to_map(data, cur->disk_address, map) == 0) {
660 		  free(data);
661 		}
662 	      }
663 	    }
664 	  }
665 	  cur = cur->next_by_base;
666 	}
667     }
668 	// if it is not Extra then punt
669     if (cur == NULL
670 	    || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
671 	printf("requested base and length is not "
672 		"within an existing free partition\n");
673 	return 0;
674     }
675 	// figure out what to do and sizes
676     data = cur->data;
677     if (data->dpme_pblock_start == base) {
678 	// replace or add
679 	if (data->dpme_pblocks == length) {
680 	    act = kReplace;
681 	} else {
682 	    act = kAdd;
683 	    adjusted_base = base + length;
684 	    adjusted_length = data->dpme_pblocks - length;
685 	}
686     } else {
687 	// split or add
688 	if (data->dpme_pblock_start + data->dpme_pblocks == base + length) {
689 	    act = kAdd;
690 	    adjusted_base = data->dpme_pblock_start;
691 	    adjusted_length = base - adjusted_base;
692 	} else {
693 	    act = kSplit;
694 	    new_base = data->dpme_pblock_start;
695 	    new_length = base - new_base;
696 	    adjusted_base = base + length;
697 	    adjusted_length = data->dpme_pblocks - (length + new_length);
698 	}
699     }
700 	// if the map will overflow then punt
701     if (map->maximum_in_map < 0) {
702 	limit = map->media_size;
703     } else {
704 	limit = map->maximum_in_map;
705     }
706     if (map->blocks_in_map + (int)act > limit) {
707 	printf("the map is not big enough\n");
708 	return 0;
709     }
710 
711     data = create_data(name, dptype, base, length);
712     if (data == NULL) {
713 	return 0;
714     }
715     if (act == kReplace) {
716 	free(cur->data);
717 	cur->data = data;
718     } else {
719 	    // adjust this block's size
720 	cur->data->dpme_pblock_start = adjusted_base;
721 	cur->data->dpme_pblocks = adjusted_length;
722 	cur->data->dpme_lblocks = adjusted_length;
723 	    // insert new with block address equal to this one
724 	if (add_data_to_map(data, cur->disk_address, map) == 0) {
725 	    free(data);
726 	} else if (act == kSplit) {
727 	    data = create_data(kFreeName, kFreeType, new_base, new_length);
728 	    if (data != NULL) {
729 		    // insert new with block address equal to this one
730 		if (add_data_to_map(data, cur->disk_address, map) == 0) {
731 		    free(data);
732 		}
733 	    }
734 	}
735     }
736 	// renumber disk addresses
737     renumber_disk_addresses(map);
738 	// mark changed
739     map->changed = 1;
740     return 1;
741 }
742 
743 
744 DPME *
create_data(const char * name,const char * dptype,uint32_t base,uint32_t length)745 create_data(const char *name, const char *dptype, uint32_t base, uint32_t length)
746 {
747     DPME *data;
748 
749     data = (DPME *) calloc(1, PBLOCK_SIZE);
750     if (data == NULL) {
751 	error(errno, "can't allocate memory for disk buffers");
752     } else {
753 	// set data into entry
754 	data->dpme_signature = DPME_SIGNATURE;
755 	data->dpme_map_entries = 1;
756 	data->dpme_pblock_start = base;
757 	data->dpme_pblocks = length;
758 	strncpy(data->dpme_name, name, DPISTRLEN);
759 	strncpy(data->dpme_type, dptype, DPISTRLEN);
760 	data->dpme_lblock_start = 0;
761 	data->dpme_lblocks = data->dpme_pblocks;
762 	dpme_init_flags(data);
763     }
764     return data;
765 }
766 
767 void
dpme_init_flags(DPME * data)768 dpme_init_flags(DPME *data)
769 {
770     if (istrncmp(data->dpme_type, kHFSType, DPISTRLEN) == 0) { /* XXX this is gross, fix it! */
771 	data->dpme_flags = APPLE_HFS_FLAGS_VALUE;
772     }
773     else {
774 	dpme_writable_set(data, 1);
775 	dpme_readable_set(data, 1);
776 	dpme_bootable_set(data, 0);
777 	dpme_in_use_set(data, 0);
778 	dpme_allocated_set(data, 1);
779 	dpme_valid_set(data, 1);
780     }
781 }
782 
783 /* These bits are appropriate for Apple_UNIX_SVR2 partitions
784  * used by NetBSD.  They may be ok for A/UX, but have not been
785  * tested.
786  */
787 void
bzb_init_slice(BZB * bp,int slice)788 bzb_init_slice(BZB *bp, int slice)
789 {
790     memset(bp,0,sizeof(BZB));
791     if ((slice >= 'A') && (slice <= 'Z')) {
792 	slice += 'a' - 'A';
793     }
794     if ((slice != 0) && ((slice < 'a') || (slice > 'z'))) {
795 	error(-1,"Bad bzb slice");
796 	slice = 0;
797     }
798     switch (slice) {
799     case 0:
800     case 'c':
801 	return;
802     case 'a':
803 	bp->bzb_type = FST;
804 	strlcpy((char *)bp->bzb_mount_point, "/", sizeof(bp->bzb_mount_point));
805 	bp->bzb_inode = 1;
806 	bzb_root_set(bp,1);
807 	bzb_usr_set(bp,1);
808 	break;
809     case 'b':
810 	bp->bzb_type = FSTSFS;
811 	strlcpy((char *)bp->bzb_mount_point, "(swap)", sizeof(bp->bzb_mount_point));
812 	break;
813     case 'g':
814 	strlcpy((char *)bp->bzb_mount_point, "/usr", sizeof(bp->bzb_mount_point));
815 	/* Fall through */
816     default:
817 	bp->bzb_type = FST;
818 	bp->bzb_inode = 1;
819 	bzb_usr_set(bp,1);
820 	break;
821     }
822     bzb_slice_set(bp,0);  // XXX NetBSD disksubr.c ignores slice
823     //	bzb_slice_set(bp,slice-'a'+1);
824     bp->bzb_magic = BZBMAGIC;
825 }
826 
827 void
renumber_disk_addresses(partition_map_header * map)828 renumber_disk_addresses(partition_map_header *map)
829 {
830     partition_map * cur;
831     long ix;
832 
833 	// reset disk addresses
834     cur = map->disk_order;
835     ix = 1;
836     while (cur != NULL) {
837 	cur->disk_address = ix++;
838 	cur->data->dpme_map_entries = map->blocks_in_map;
839 	cur = cur->next_on_disk;
840     }
841 }
842 
843 
844 long
compute_device_size(partition_map_header * map,partition_map_header * oldmap)845 compute_device_size(partition_map_header *map, partition_map_header *oldmap)
846 {
847 #ifdef TEST_COMPUTE
848     uint32_t length;
849     struct hd_geometry geometry;
850     struct stat info;
851     loff_t pos;
852 #endif
853     char* data;
854     uint32_t l, r, x = 0;
855     long long size;
856     int valid = 0;
857 #ifdef TEST_COMPUTE
858     int fd;
859 
860     fd = map->fd->fd;
861     printf("\n");
862     if (fstat(fd, &info) < 0) {
863 	printf("stat of device failed\n");
864     } else {
865 	printf("stat: mode = 0%o, type=%s\n", info.st_mode,
866 		(S_ISREG(info.st_mode)? "Regular":
867 		(S_ISBLK(info.st_mode)?"Block":"Other")));
868 	printf("size = %d, blocks = %d\n",
869 		info.st_size, info.st_size/map->logical_block);
870     }
871 
872     if (ioctl(fd, BLKGETSIZE, &length) < 0) {
873 	printf("get device size failed\n");
874     } else {
875 	printf("BLKGETSIZE:size in blocks = %u\n", length);
876     }
877 
878     if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) {
879 	printf("get device geometry failed\n");
880     } else {
881 	printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d,  total=%d\n",
882 		geometry.heads, geometry.sectors,
883 		geometry.cylinders, geometry.start,
884 		geometry.heads*geometry.sectors*geometry.cylinders);
885     }
886 
887     if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) {
888 	printf("llseek to end of device failed\n");
889     } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) {
890 	printf("llseek to end of device failed on second try\n");
891     } else {
892 	printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block);
893     }
894 #endif
895 
896     if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) {
897 	return (oldmap->misc->sbBlkCount
898 		* (oldmap->physical_block / map->logical_block));
899     }
900 
901     size = media_total_size(map->m);
902     if (size != 0) {
903     	return (long)(size / map->logical_block);
904     }
905 
906     // else case
907 
908     data = (char *) malloc(PBLOCK_SIZE);
909     if (data == NULL) {
910 	error(errno, "can't allocate memory for try buffer");
911 	x = 0;
912     } else {
913 	// double till off end
914 	l = 0;
915 	r = 1024;
916 	while (read_block(map, r, data) != 0) {
917 	    l = r;
918 	    if (r <= 1024) {
919 		r = r * 1024;
920 	    } else {
921 		r = r * 2;
922 	    }
923 	    if (r >= 0x80000000) {
924 		r = 0xFFFFFFFE;
925 		break;
926 	    }
927 	}
928 	// binary search for end
929 	while (l <= r) {
930 	    x = (r - l) / 2 + l;
931 	    if ((valid = read_block(map, x, data)) != 0) {
932 		l = x + 1;
933 	    } else {
934 		if (x > 0) {
935 		    r = x - 1;
936 		} else {
937 		    break;
938 		}
939 	    }
940 	}
941 	if (valid != 0) {
942 	    x = x + 1;
943 	}
944 	// printf("size in blocks = %d\n", x);
945 	free(data);
946     }
947 
948     return x;
949 }
950 
951 
952 void
sync_device_size(partition_map_header * map)953 sync_device_size(partition_map_header *map)
954 {
955     Block0 *p;
956     uint32_t size;
957     double d;
958 
959     p = map->misc;
960     if (p == NULL) {
961 	return;
962     }
963     d = map->media_size;
964     size = (d * map->logical_block) / p->sbBlkSize;
965     if (p->sbBlkCount != size) {
966 	p->sbBlkCount = size;
967     }
968 }
969 
970 
971 void
delete_partition_from_map(partition_map * entry)972 delete_partition_from_map(partition_map *entry)
973 {
974     partition_map_header *map;
975     DPME *data;
976 
977     if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) {
978 	printf("Can't delete entry for the map itself\n");
979 	return;
980     }
981     if (entry->contains_driver) {
982 	printf("This program can't install drivers\n");
983 	if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) {
984 	    return;
985 	}
986     }
987     // if past end of disk, delete it completely
988     if (entry->next_by_base == NULL &&
989 	entry->data->dpme_pblock_start >= entry->the_map->media_size) {
990       if (entry->contains_driver) {
991 	remove_driver(entry);	// update block0 if necessary
992       }
993       delete_entry(entry);
994       return;
995     }
996     // If at end of disk, incorporate extra disk space to partition
997     if (entry->next_by_base == NULL) {
998       entry->data->dpme_pblocks =
999 	 entry->the_map->media_size - entry->data->dpme_pblock_start;
1000     }
1001     data = create_data(kFreeName, kFreeType,
1002 	    entry->data->dpme_pblock_start, entry->data->dpme_pblocks);
1003     if (data == NULL) {
1004 	return;
1005     }
1006     if (entry->contains_driver) {
1007     	remove_driver(entry);	// update block0 if necessary
1008     }
1009     free(entry->data);
1010     free(entry->HFS_name);
1011     entry->HFS_kind = kHFS_not;
1012     entry->HFS_name = 0;
1013     entry->data = data;
1014     combine_entry(entry);
1015     map = entry->the_map;
1016     renumber_disk_addresses(map);
1017     map->changed = 1;
1018 }
1019 
1020 
1021 int
contains_driver(partition_map * entry)1022 contains_driver(partition_map *entry)
1023 {
1024     partition_map_header *map;
1025     Block0 *p;
1026     DDMap *m;
1027     int i;
1028     int f;
1029     uint32_t start;
1030 
1031     map = entry->the_map;
1032     p = map->misc;
1033     if (p == NULL) {
1034 	return 0;
1035     }
1036     if (p->sbSig != BLOCK0_SIGNATURE) {
1037 	return 0;
1038     }
1039     if (map->logical_block > p->sbBlkSize) {
1040 	return 0;
1041     } else {
1042 	f = p->sbBlkSize / map->logical_block;
1043     }
1044     if (p->sbDrvrCount > 0) {
1045 	m = (DDMap *) p->sbMap;
1046 	for (i = 0; i < p->sbDrvrCount; i++) {
1047 	    start = get_align_long(&m[i].ddBlock);
1048 	    if (entry->data->dpme_pblock_start <= f*start
1049 		    && f*(start + m[i].ddSize)
1050 			<= (entry->data->dpme_pblock_start
1051 			+ entry->data->dpme_pblocks)) {
1052 		return 1;
1053 	    }
1054 	}
1055     }
1056     return 0;
1057 }
1058 
1059 
1060 void
combine_entry(partition_map * entry)1061 combine_entry(partition_map *entry)
1062 {
1063     partition_map *p;
1064     uint32_t end;
1065 
1066     if (entry == NULL
1067 	    || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1068 	return;
1069     }
1070     if (entry->next_by_base != NULL) {
1071 	p = entry->next_by_base;
1072 	if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1073 	    // next is not free
1074 	} else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1075 		!= p->data->dpme_pblock_start) {
1076 	    // next is not contiguous (XXX this is bad)
1077 	    printf("next entry is not contiguous\n");
1078 	    // start is already minimum
1079 	    // new end is maximum of two ends
1080 	    end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1081 	    if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1082 	    	entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start;
1083 	    }
1084 	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1085 	    delete_entry(p);
1086 	} else {
1087 	    entry->data->dpme_pblocks += p->data->dpme_pblocks;
1088 	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1089 	    delete_entry(p);
1090 	}
1091     }
1092     if (entry->prev_by_base != NULL) {
1093 	p = entry->prev_by_base;
1094 	if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1095 	    // previous is not free
1096 	} else if (p->data->dpme_pblock_start + p->data->dpme_pblocks
1097 		!= entry->data->dpme_pblock_start) {
1098 	    // previous is not contiguous (XXX this is bad)
1099 	    printf("previous entry is not contiguous\n");
1100 	    // new end is maximum of two ends
1101 	    end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1102 	    if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1103 		end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks;
1104 	    }
1105 	    entry->data->dpme_pblocks = end - p->data->dpme_pblock_start;
1106 	    // new start is previous entry's start
1107 	    entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1108 	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1109 	    delete_entry(p);
1110 	} else {
1111 	    entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1112 	    entry->data->dpme_pblocks += p->data->dpme_pblocks;
1113 	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1114 	    delete_entry(p);
1115 	}
1116     }
1117     entry->contains_driver = contains_driver(entry);
1118 }
1119 
1120 
1121 void
delete_entry(partition_map * entry)1122 delete_entry(partition_map *entry)
1123 {
1124     partition_map_header *map;
1125     partition_map *p;
1126 
1127     map = entry->the_map;
1128     map->blocks_in_map--;
1129 
1130     remove_from_disk_order(entry);
1131 
1132     p = entry->next_by_base;
1133     if (map->base_order == entry) {
1134 	map->base_order = p;
1135     }
1136     if (p != NULL) {
1137 	p->prev_by_base = entry->prev_by_base;
1138     }
1139     if (entry->prev_by_base != NULL) {
1140 	entry->prev_by_base->next_by_base = p;
1141     }
1142 
1143     free(entry->data);
1144     free(entry->HFS_name);
1145     free(entry);
1146 }
1147 
1148 
1149 partition_map *
find_entry_by_disk_address(int32_t ix,partition_map_header * map)1150 find_entry_by_disk_address(int32_t ix, partition_map_header *map)
1151 {
1152     partition_map * cur;
1153 
1154     cur = map->disk_order;
1155     while (cur != NULL) {
1156 	if (cur->disk_address == ix) {
1157 	    break;
1158 	}
1159 	cur = cur->next_on_disk;
1160     }
1161     return cur;
1162 }
1163 
1164 
1165 partition_map *
find_entry_by_type(const char * type_name,partition_map_header * map)1166 find_entry_by_type(const char *type_name, partition_map_header *map)
1167 {
1168     partition_map * cur;
1169 
1170     cur = map->base_order;
1171     while (cur != NULL) {
1172 	if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) {
1173 	    break;
1174 	}
1175 	cur = cur->next_by_base;
1176     }
1177     return cur;
1178 }
1179 
1180 partition_map *
find_entry_by_base(uint32_t base,partition_map_header * map)1181 find_entry_by_base(uint32_t base, partition_map_header *map)
1182 {
1183     partition_map * cur;
1184 
1185     cur = map->base_order;
1186     while (cur != NULL) {
1187 	if (cur->data->dpme_pblock_start == base) {
1188 	    break;
1189 	}
1190 	cur = cur->next_by_base;
1191     }
1192     return cur;
1193 }
1194 
1195 
1196 void
move_entry_in_map(int32_t old_index,int32_t ix,partition_map_header * map)1197 move_entry_in_map(int32_t old_index, int32_t ix, partition_map_header *map)
1198 {
1199     partition_map * cur;
1200 
1201     cur = find_entry_by_disk_address(old_index, map);
1202     if (cur == NULL) {
1203 	printf("No such partition\n");
1204     } else {
1205 	remove_from_disk_order(cur);
1206 	cur->disk_address = ix;
1207 	insert_in_disk_order(cur);
1208 	renumber_disk_addresses(map);
1209 	map->changed = 1;
1210     }
1211 }
1212 
1213 
1214 void
remove_from_disk_order(partition_map * entry)1215 remove_from_disk_order(partition_map *entry)
1216 {
1217     partition_map_header *map;
1218     partition_map *p;
1219 
1220     map = entry->the_map;
1221     p = entry->next_on_disk;
1222     if (map->disk_order == entry) {
1223 	map->disk_order = p;
1224     }
1225     if (p != NULL) {
1226 	p->prev_on_disk = entry->prev_on_disk;
1227     }
1228     if (entry->prev_on_disk != NULL) {
1229 	entry->prev_on_disk->next_on_disk = p;
1230     }
1231     entry->next_on_disk = NULL;
1232     entry->prev_on_disk = NULL;
1233 }
1234 
1235 
1236 void
insert_in_disk_order(partition_map * entry)1237 insert_in_disk_order(partition_map *entry)
1238 {
1239     partition_map_header *map;
1240     partition_map * cur;
1241 
1242     // find position in disk list & insert
1243     map = entry->the_map;
1244     cur = map->disk_order;
1245     if (cur == NULL || entry->disk_address <= cur->disk_address) {
1246 	map->disk_order = entry;
1247 	entry->next_on_disk = cur;
1248 	if (cur != NULL) {
1249 	    cur->prev_on_disk = entry;
1250 	}
1251 	entry->prev_on_disk = NULL;
1252     } else {
1253 	for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) {
1254 	    if (cur->disk_address <= entry->disk_address
1255 		    && (cur->next_on_disk == NULL
1256 		    || entry->disk_address <= cur->next_on_disk->disk_address)) {
1257 		entry->next_on_disk = cur->next_on_disk;
1258 		cur->next_on_disk = entry;
1259 		entry->prev_on_disk = cur;
1260 		if (entry->next_on_disk != NULL) {
1261 		    entry->next_on_disk->prev_on_disk = entry;
1262 		}
1263 		break;
1264 	    }
1265 	}
1266     }
1267 }
1268 
1269 
1270 void
insert_in_base_order(partition_map * entry)1271 insert_in_base_order(partition_map *entry)
1272 {
1273     partition_map_header *map;
1274     partition_map * cur;
1275 
1276     // find position in base list & insert
1277     map = entry->the_map;
1278     cur = map->base_order;
1279     if (cur == NULL
1280 	    || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) {
1281 	map->base_order = entry;
1282 	entry->next_by_base = cur;
1283 	if (cur != NULL) {
1284 	    cur->prev_by_base = entry;
1285 	}
1286 	entry->prev_by_base = NULL;
1287     } else {
1288 	for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) {
1289 	    if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start
1290 		    && (cur->next_by_base == NULL
1291 		    || entry->data->dpme_pblock_start
1292 			<= cur->next_by_base->data->dpme_pblock_start)) {
1293 		entry->next_by_base = cur->next_by_base;
1294 		cur->next_by_base = entry;
1295 		entry->prev_by_base = cur;
1296 		if (entry->next_by_base != NULL) {
1297 		    entry->next_by_base->prev_by_base = entry;
1298 		}
1299 		break;
1300 	    }
1301 	}
1302     }
1303 }
1304 
1305 
1306 void
resize_map(uint32_t new_size,partition_map_header * map)1307 resize_map(uint32_t new_size, partition_map_header *map)
1308 {
1309     partition_map * entry;
1310     partition_map * next;
1311     uint32_t incr;
1312 
1313     // find map entry
1314     entry = find_entry_by_type(kMapType, map);
1315 
1316     if (entry == NULL) {
1317 	printf("Couldn't find entry for map!\n");
1318 	return;
1319     }
1320     next = entry->next_by_base;
1321 
1322 	// same size
1323     if (new_size == entry->data->dpme_pblocks) {
1324 	// do nothing
1325 	return;
1326     }
1327 
1328 	// make it smaller
1329     if (new_size < entry->data->dpme_pblocks) {
1330 	if (next == NULL
1331 		|| istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1332 	    incr = 1;
1333 	} else {
1334 	    incr = 0;
1335 	}
1336 	if (new_size < map->blocks_in_map + incr) {
1337 	    printf("New size would be too small\n");
1338 	    return;
1339 	}
1340 	goto doit;
1341     }
1342 
1343 	// make it larger
1344     if (next == NULL
1345 	    || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1346 	printf("No free space to expand into\n");
1347 	return;
1348     }
1349     if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1350 	    != next->data->dpme_pblock_start) {
1351 	printf("No contiguous free space to expand into\n");
1352 	return;
1353     }
1354     if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) {
1355 	printf("No enough free space\n");
1356 	return;
1357     }
1358 doit:
1359     entry->data->dpme_type[0] = 0;
1360     delete_partition_from_map(entry);
1361     add_partition_to_map("Apple", kMapType, 1, new_size, map);
1362     map->maximum_in_map = new_size;
1363 }
1364 
1365 
1366 void
remove_driver(partition_map * entry)1367 remove_driver(partition_map *entry)
1368 {
1369     partition_map_header *map;
1370     Block0 *p;
1371     DDMap *m;
1372     int i;
1373     int j;
1374     int f;
1375     uint32_t start;
1376 
1377     map = entry->the_map;
1378     p = map->misc;
1379     if (p == NULL) {
1380 	return;
1381     }
1382     if (p->sbSig != BLOCK0_SIGNATURE) {
1383 	return;
1384     }
1385     if (map->logical_block > p->sbBlkSize) {
1386 	/* this is not supposed to happen, but let's just ignore it. */
1387 	return;
1388     } else {
1389 	/*
1390 	 * compute the factor to convert the block numbers in block0
1391 	 * into partition map block numbers.
1392 	 */
1393 	f = p->sbBlkSize / map->logical_block;
1394     }
1395     if (p->sbDrvrCount > 0) {
1396 	m = (DDMap *) p->sbMap;
1397 	for (i = 0; i < p->sbDrvrCount; i++) {
1398 	    start = get_align_long(&m[i].ddBlock);
1399 
1400 	    /* zap the driver if it is wholly contained in the partition */
1401 	    if (entry->data->dpme_pblock_start <= f*start
1402 		    && f*(start + m[i].ddSize)
1403 			<= (entry->data->dpme_pblock_start
1404 			+ entry->data->dpme_pblocks)) {
1405 		// delete this driver
1406 		// by copying down later ones and zapping the last
1407 		for (j = i+1; j < p->sbDrvrCount; j++, i++) {
1408 		   put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock);
1409 		   m[i].ddSize = m[j].ddSize;
1410 		   m[i].ddType = m[j].ddType;
1411 		}
1412 	        put_align_long(0, &m[i].ddBlock);
1413 		m[i].ddSize = 0;
1414 		m[i].ddType = 0;
1415 		p->sbDrvrCount -= 1;
1416 		return; /* XXX if we continue we will delete other drivers? */
1417 	    }
1418 	}
1419     }
1420 }
1421 
1422 int
read_block(partition_map_header * map,uint32_t num,char * buf)1423 read_block(partition_map_header *map, uint32_t num, char *buf)
1424 {
1425 //printf("read block %d\n", num);
1426     return read_media(map->m, ((long long) num) * map->logical_block,
1427     		PBLOCK_SIZE, (void *)buf);
1428 }
1429 
1430 
1431 int
write_block(partition_map_header * map,uint32_t num,char * buf)1432 write_block(partition_map_header *map, uint32_t num, char *buf)
1433 {
1434     return write_media(map->m, ((long long) num) * map->logical_block,
1435     		PBLOCK_SIZE, (void *)buf);
1436 }
1437