File: writepart.c

package info (click to toggle)
atari-fdisk 0.7.1-1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 236 kB
  • ctags: 225
  • sloc: ansic: 2,946; makefile: 136; sh: 23
file content (246 lines) | stat: -rw-r--r-- 7,574 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/* writepart.c: write the partition table
 *
 * Copyright (C) 1995-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
 *               1996-97 Michael Schlueter <schlue00@marvin.informatik.uni-dortmund.de>
 *
 * This program is free software.  You can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation: either version 2 or
 * (at your option) any later version.
 *
 */

/* $Id: writepart.c,v 1.8 1998/02/07 21:27:17 rnhodek Exp $
 *
 * $Log: writepart.c,v $
 * Revision 1.8  1998/02/07 21:27:17  rnhodek
 * Print newline before error message in reread_ioctl() -- it's called
 * after an \n-less printf.
 * Make warning text after failed BLKRRPART more descriptive.
 * Better strategy to set checksum field in rootsector: avoid
 * accidentally making it bootable, and avoid PC-format magic number.
 *
 * Revision 1.7  1997/10/01 08:00:23  rnhodek
 * Don't close disk file in reread_disk_partition
 *
 * Revision 1.6  1997/08/22 15:36:53  rnhodek
 * Implemented basic support for ICD format. Should work, but conversion
 * AHDI<->ICD isn't very clever yet.
 *
 * Revision 1.5  1997/06/22 10:31:01  rnhodek
 * Add __attribute__((unused)) to cvid
 *
 * Revision 1.4  1997/06/21 20:47:53  rnhodek
 * Added RCS keywords
 *
 * Revision 1.3  1997/06/13 12:50:44  rnhodek
 * Forgot byte swaps on writing
 * 
 * Revision 1.2  1997/06/11 19:49:17  rnhodek
 * Implemented bad sector list handling
 * 
 * Revision 1.1  1997/06/11 14:36:36  rnhodek
 * Initial revision
 * 
 * Revision 1.1.1.1  1997/06/11 14:36:36  rnhodek
 * Started using CVS for atafdisk
 *
 */

#ifndef lint
static char vcid[] __attribute__ ((unused)) =
"$Id: writepart.c,v 1.8 1998/02/07 21:27:17 rnhodek Exp $";
#endif /* lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

#include "fdisk.h"
#include "disk.h"
#include "util.h"
#include "readpart.h"


/* tell the kernel to reread the partition tables */
int reread_ioctl( int fd )
{
    if (ioctl( fd, BLKRRPART )) {
	perror( "\nBLKRRPART" );
	return -1;
    }
    return 0;
}

/* reread after writing */
void reread_disk_partition( int fd )
{
    printf( "Re-reading the partition table ...\n" );
    fflush(stdout);
    sync();
    sleep(3);			/* superfluous since 1.3.20 */

    if (reread_ioctl(fd))
      printf( "The command to re-read the partition table failed!\n"
	      "Reboot your system now to make sure that the partition table "
	      "is reread!\n" );
}

static void PART2diskpart( PARTITION *cp, struct apartition *dp,
			   unsigned long relto )
{
    dp->start = cp->start - relto;
    dp->size  = cp->size;
    dp->flag  = cp->flag | PART_FLAG_VALID;
    memcpy( dp->id, cp->id, 3 );
}

static void set_checksum( char *buffer, int was_bootable )
{
    /* Set the checksum to make it bootable for now... */
    recalc_rootsec_checksum( buffer );
    if (!was_bootable) {
	/* ...and modify the checksum field if the sector wasn't bootable
	 * before. The avoids the (admitted :-) rare case that the checksum is
	 * accidentally correct -- if we would't touch the field at all. */
	short *cks = (short *)&buffer[SECTOR_SIZE-2];
	++(*cks);
	/* Avoid that we accidentlly put in the magic of PC partition format */
	if (*cks == 0x55aa)
	    ++(*cks);
    }
}

/* write out the partition table */
void put_boot( int first_ext, int last_ext, PARTITION *master_XGM )
{
    char buffer[SECTOR_SIZE];
    struct rootsector *rs = (struct rootsector *)buffer;
    struct apartition *pi;
    int i, bootable;
    PARTITION cont_XGM;
    
    /* read the root sector for modifying it */
    sread( buffer, 0 );
    swab_rs( rs );
    bootable = check_rootsec_checksum( buffer );
    
    /* first write out the primary partitions */
    pi = &rs->part[0];
    for( i = 0; i < partitions; ++i ) {
	if (i == first_ext) {
	    /* write XGM for first extended partition */
	    PART2diskpart( master_XGM, pi, 0 );
	}
	else if (i > first_ext && i <= last_ext)
	    /* is extended and not the first, skip here */
	    continue;
	else {
	    /* primary partition */
	    PART2diskpart( &part_table[i], pi, 0 );
	}
	++pi;
    }
    /* clear valid bit for remaining slots */
    for( ; pi <= &rs->part[3]; ++pi )
	pi->flag &= ~PART_FLAG_VALID;

    /* for ICD format, write remaining primary partitions to the special ICD
     * slots */
    if (xpart_fmt == xfmt_ICD && partitions > MAX_PRIMARY_AHDI) {
	for( pi = &rs->icdpart[0], i = MAX_PRIMARY_AHDI;
	     i < partitions && i < MAX_PRIMARY_ICD;
	     ++i, ++pi )
	    PART2diskpart( &part_table[i], pi, 0 );
	/* clear valid bit for remaining slots */
	for( ; pi <= &rs->icdpart[7]; ++pi )
	    pi->flag &= ~PART_FLAG_VALID;
    }
    
    /* set other fields of root sector */
    rs->hd_size = rs_hd_size;
    rs->bsl_st  = bsl_start;
    rs->bsl_cnt = bsl_size;
    
    /* recalculate checksum if needed, and write root sector back */
    set_checksum( buffer, bootable );
    swab_rs( rs );
    swrite( buffer, 0 );

    /* now write aux. root sectors for each extended partition */
    if (xpart_fmt == xfmt_AHDI && first_ext >= 0) {
	for( i = first_ext; i <= last_ext; ++i ) {
	    sread( buffer, part_table[i].rootsec );
	    swab_rs( rs );
	    bootable = check_rootsec_checksum( buffer );

	    /* We always use slots #0 and #1 in the aux. root sector, though
	     * the valid entries could have been in some other consecutive
	     * entries originally. This shouldn't make any difference, I
	     * hope...
	     */
	    
	    /* the start field is relative to the aux. root sector for this
	     * partition */
	    PART2diskpart( &part_table[i], &rs->part[0],
			   part_table[i].rootsec );

	    if (i == last_ext) {
		/* last extended partition: make second slot invalid */
		rs->part[1].flag &= ~PART_FLAG_VALID;
	    }
	    else {
		/* otherwise: make it an XGM entry
		 * the start field of this entry is the pointer to the next
		 * aux. root sector, and the size isn't really relevant. We
		 * adopt the usual convention to make that fake partition
		 * extend util the end of its data.
		 */
		cont_XGM.start = part_table[i+1].rootsec;
		cont_XGM.size  = part_table[i+1].start +
				 part_table[i+1].size - cont_XGM.start;
		cont_XGM.flag  = 0;
		strcpy( cont_XGM.id, "XGM" );
		/* the start field is relative to the first sector of the
		 * overall XGM area */
		PART2diskpart( &cont_XGM, &rs->part[1], master_XGM->start );
	    }

	    /* make remaining entries invalid */
	    rs->part[2].flag &= ~PART_FLAG_VALID;
	    rs->part[3].flag &= ~PART_FLAG_VALID;

	    /* recalculate checksum if needed, and write aux. root sector back
	     * The is checksum needed only for the very first aux. root sector
	     * (that one the master XGM entry in the root sector points to),
	     * because from there a boot sector can be loaded.
	     */
	    if (i == first_ext)
		set_checksum( buffer, bootable );
	    swab_rs( rs );
	    swrite( buffer, part_table[i].rootsec );
	}
    }

    /* write empty bad sector list if its location on disk changed */
    if (bsl_size > 0 &&
	(bsl_start != saved_bsl_start || bsl_size != saved_bsl_size)) {
	unsigned long sec;
	for( sec = bsl_start; sec < bsl_start+bsl_size; ++sec ) {
	    memset( buffer, 0, SECTOR_SIZE );
	    if (sec == bsl_start && bsl_HDX_compat)
		/* HDX doesn't like an empty bad sector list... */
		buffer[3] = 0xa5;
	    swrite( buffer, sec );
	}
    }
    
    reread_disk_partition( fd );
}

/* Local Variables: */
/* tab-width: 8     */
/* End:             */