source: MondoRescue/branches/3.3/mindi-busybox/util-linux/mkfs_vfat.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 21.8 KB
RevLine 
[2725]1/* vi: set sw=4 ts=4: */
2/*
3 * mkfs_vfat: utility to create FAT32 filesystem
4 * inspired by dosfstools
5 *
6 * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
[3232]10
11//usage:#define mkfs_vfat_trivial_usage
12//usage: "[-v] [-n LABEL] BLOCKDEV [KBYTES]"
13/* Accepted but ignored:
14 "[-c] [-C] [-I] [-l bad-block-file] [-b backup-boot-sector] "
15 "[-m boot-msg-file] [-i volume-id] "
16 "[-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs] "
17 "[-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors] "
18*/
19//usage:#define mkfs_vfat_full_usage "\n\n"
20//usage: "Make a FAT32 filesystem\n"
21/* //usage: "\n -c Check device for bad blocks" */
22//usage: "\n -v Verbose"
23/* //usage: "\n -I Allow to use entire disk device (e.g. /dev/hda)" */
24//usage: "\n -n LBL Volume label"
25
[2725]26#include "libbb.h"
27
28#include <linux/hdreg.h> /* HDIO_GETGEO */
29#include <linux/fd.h> /* FDGETPRM */
30#include <sys/mount.h> /* BLKSSZGET */
31#if !defined(BLKSSZGET)
32# define BLKSSZGET _IO(0x12, 104)
33#endif
34//#include <linux/msdos_fs.h>
35
36#define SECTOR_SIZE 512
37
38#define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE)
39
40// M$ says the high 4 bits of a FAT32 FAT entry are reserved
41#define EOF_FAT32 0x0FFFFFF8
42#define BAD_FAT32 0x0FFFFFF7
43#define MAX_CLUST_32 0x0FFFFFF0
44
45#define ATTR_VOLUME 8
46
47#define NUM_FATS 2
48
49/* FAT32 filesystem looks like this:
50 * sector -nn...-1: "hidden" sectors, all sectors before this partition
51 * (-h hidden-sectors sets it. Useful only for boot loaders,
52 * they need to know _disk_ offset in order to be able to correctly
53 * address sectors relative to start of disk)
54 * sector 0: boot sector
55 * sector 1: info sector
56 * sector 2: set aside for boot code which didn't fit into sector 0
57 * ...(zero-filled sectors)...
58 * sector B: backup copy of sector 0 [B set by -b backup-boot-sector]
59 * sector B+1: backup copy of sector 1
60 * sector B+2: backup copy of sector 2
61 * ...(zero-filled sectors)...
62 * sector R: FAT#1 [R set by -R reserved-sectors]
63 * ...(FAT#1)...
64 * sector R+fat_size: FAT#2
65 * ...(FAT#2)...
66 * sector R+fat_size*2: cluster #2
67 * ...(cluster #2)...
68 * sector R+fat_size*2+clust_size: cluster #3
69 * ...(the rest is filled by clusters till the end)...
70 */
71
72enum {
73// Perhaps this should remain constant
74 info_sector_number = 1,
75// TODO: make these cmdline options
76// dont forget sanity check: backup_boot_sector + 3 <= reserved_sect
77 backup_boot_sector = 3,
78 reserved_sect = 6,
79};
80
81// how many blocks we try to read while testing
82#define TEST_BUFFER_BLOCKS 16
83
84struct msdos_dir_entry {
85 char name[11]; /* 000 name and extension */
86 uint8_t attr; /* 00b attribute bits */
87 uint8_t lcase; /* 00c case for base and extension */
88 uint8_t ctime_cs; /* 00d creation time, centiseconds (0-199) */
89 uint16_t ctime; /* 00e creation time */
90 uint16_t cdate; /* 010 creation date */
91 uint16_t adate; /* 012 last access date */
92 uint16_t starthi; /* 014 high 16 bits of cluster in FAT32 */
93 uint16_t time; /* 016 time */
94 uint16_t date; /* 018 date */
95 uint16_t start; /* 01a first cluster */
96 uint32_t size; /* 01c file size in bytes */
97} PACKED;
98
99/* Example of boot sector's beginning:
1000000 eb 58 90 4d 53 57 49 4e 34 2e 31 00 02 08 26 00 |...MSWIN4.1...&.|
1010010 02 00 00 00 00 f8 00 00 3f 00 ff 00 3f 00 00 00 |........?...?...|
1020020 54 9b d0 00 0d 34 00 00 00 00 00 00 02 00 00 00 |T....4..........|
1030030 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
1040040 80 00 29 71 df 51 e0 4e 4f 20 4e 41 4d 45 20 20 |..)q.Q.NO NAME |
1050050 20 20 46 41 54 33 32 20 20 20 33 c9 8e d1 bc f4 | FAT32 3.....|
106*/
107struct msdos_volume_info { /* (offsets are relative to start of boot sector) */
108 uint8_t drive_number; /* 040 BIOS drive number */
109 uint8_t reserved; /* 041 unused */
110 uint8_t ext_boot_sign; /* 042 0x29 if fields below exist (DOS 3.3+) */
111 uint32_t volume_id32; /* 043 volume ID number */
112 char volume_label[11];/* 047 volume label */
113 char fs_type[8]; /* 052 typically "FATnn" */
114} PACKED; /* 05a end. Total size 26 (0x1a) bytes */
115
116struct msdos_boot_sector {
117 /* We use strcpy to fill both, and gcc-4.4.x complains if they are separate */
118 char boot_jump_and_sys_id[3+8]; /* 000 short or near jump instruction */
119 /*char system_id[8];*/ /* 003 name - can be used to special case partition manager volumes */
120 uint16_t bytes_per_sect; /* 00b bytes per logical sector */
121 uint8_t sect_per_clust; /* 00d sectors/cluster */
122 uint16_t reserved_sect; /* 00e reserved sectors (sector offset of 1st FAT relative to volume start) */
123 uint8_t fats; /* 010 number of FATs */
124 uint16_t dir_entries; /* 011 root directory entries */
125 uint16_t volume_size_sect; /* 013 volume size in sectors */
126 uint8_t media_byte; /* 015 media code */
127 uint16_t sect_per_fat; /* 016 sectors/FAT */
128 uint16_t sect_per_track; /* 018 sectors per track */
129 uint16_t heads; /* 01a number of heads */
130 uint32_t hidden; /* 01c hidden sectors (sector offset of volume within physical disk) */
131 uint32_t fat32_volume_size_sect; /* 020 volume size in sectors (if volume_size_sect == 0) */
132 uint32_t fat32_sect_per_fat; /* 024 sectors/FAT */
133 uint16_t fat32_flags; /* 028 bit 8: fat mirroring, low 4: active fat */
134 uint8_t fat32_version[2]; /* 02a major, minor filesystem version (I see 0,0) */
135 uint32_t fat32_root_cluster; /* 02c first cluster in root directory */
136 uint16_t fat32_info_sector; /* 030 filesystem info sector (usually 1) */
137 uint16_t fat32_backup_boot; /* 032 backup boot sector (usually 6) */
138 uint32_t reserved2[3]; /* 034 unused */
139 struct msdos_volume_info vi; /* 040 */
140 char boot_code[0x200 - 0x5a - 2]; /* 05a */
141#define BOOT_SIGN 0xAA55
142 uint16_t boot_sign; /* 1fe */
143} PACKED;
144
145#define FAT_FSINFO_SIG1 0x41615252
146#define FAT_FSINFO_SIG2 0x61417272
147struct fat32_fsinfo {
148 uint32_t signature1; /* 0x52,0x52,0x41,0x61, "RRaA" */
149 uint32_t reserved1[128 - 8];
150 uint32_t signature2; /* 0x72,0x72,0x61,0x41, "rrAa" */
151 uint32_t free_clusters; /* free cluster count. -1 if unknown */
152 uint32_t next_cluster; /* most recently allocated cluster */
153 uint32_t reserved2[3];
154 uint16_t reserved3; /* 1fc */
155 uint16_t boot_sign; /* 1fe */
156} PACKED;
157
158struct bug_check {
159 char BUG1[sizeof(struct msdos_dir_entry ) == 0x20 ? 1 : -1];
160 char BUG2[sizeof(struct msdos_volume_info) == 0x1a ? 1 : -1];
161 char BUG3[sizeof(struct msdos_boot_sector) == 0x200 ? 1 : -1];
162 char BUG4[sizeof(struct fat32_fsinfo ) == 0x200 ? 1 : -1];
163};
164
165static const char boot_code[] ALIGN1 =
166 "\x0e" /* 05a: push cs */
167 "\x1f" /* 05b: pop ds */
168 "\xbe\x77\x7c" /* write_msg: mov si, offset message_txt */
169 "\xac" /* 05f: lodsb */
170 "\x22\xc0" /* 060: and al, al */
171 "\x74\x0b" /* 062: jz key_press */
172 "\x56" /* 064: push si */
173 "\xb4\x0e" /* 065: mov ah, 0eh */
174 "\xbb\x07\x00" /* 067: mov bx, 0007h */
175 "\xcd\x10" /* 06a: int 10h */
176 "\x5e" /* 06c: pop si */
177 "\xeb\xf0" /* 06d: jmp write_msg */
178 "\x32\xe4" /* key_press: xor ah, ah */
179 "\xcd\x16" /* 071: int 16h */
180 "\xcd\x19" /* 073: int 19h */
181 "\xeb\xfe" /* foo: jmp foo */
182 /* 077: message_txt: */
183 "This is not a bootable disk\r\n";
184
185
186#define MARK_CLUSTER(cluster, value) \
187 ((uint32_t *)fat)[cluster] = SWAP_LE32(value)
188
189void BUG_unsupported_field_size(void);
190#define STORE_LE(field, value) \
191do { \
192 if (sizeof(field) == 4) \
193 field = SWAP_LE32(value); \
194 else if (sizeof(field) == 2) \
195 field = SWAP_LE16(value); \
196 else if (sizeof(field) == 1) \
197 field = (value); \
198 else \
199 BUG_unsupported_field_size(); \
200} while (0)
201
202/* compat:
203 * mkdosfs 2.11 (12 Mar 2005)
204 * Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file]
205 * [-b backup-boot-sector]
206 * [-m boot-msg-file] [-n volume-name] [-i volume-id]
207 * [-s sectors-per-cluster] [-S logical-sector-size]
208 * [-f number-of-FATs]
209 * [-h hidden-sectors] [-F fat-size] [-r root-dir-entries]
210 * [-R reserved-sectors]
211 * /dev/name [blocks]
212 */
213int mkfs_vfat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
214int mkfs_vfat_main(int argc UNUSED_PARAM, char **argv)
215{
216 struct stat st;
217 const char *volume_label = "";
218 char *buf;
219 char *device_name;
220 uoff_t volume_size_bytes;
221 uoff_t volume_size_sect;
222 uint32_t total_clust;
223 uint32_t volume_id;
224 int dev;
225 unsigned bytes_per_sect;
226 unsigned sect_per_fat;
227 unsigned opts;
228 uint16_t sect_per_track;
229 uint8_t media_byte;
230 uint8_t sect_per_clust;
231 uint8_t heads;
232 enum {
233 OPT_A = 1 << 0, // [IGNORED] atari format
234 OPT_b = 1 << 1, // [IGNORED] location of backup boot sector
235 OPT_c = 1 << 2, // [IGNORED] check filesystem
236 OPT_C = 1 << 3, // [IGNORED] create a new file
237 OPT_f = 1 << 4, // [IGNORED] number of FATs
238 OPT_F = 1 << 5, // [IGNORED, implied 32] choose FAT size
239 OPT_h = 1 << 6, // [IGNORED] number of hidden sectors
240 OPT_I = 1 << 7, // [IGNORED] don't bark at entire disk devices
241 OPT_i = 1 << 8, // [IGNORED] volume ID
242 OPT_l = 1 << 9, // [IGNORED] bad block filename
243 OPT_m = 1 << 10, // [IGNORED] message file
244 OPT_n = 1 << 11, // volume label
245 OPT_r = 1 << 12, // [IGNORED] root directory entries
246 OPT_R = 1 << 13, // [IGNORED] number of reserved sectors
247 OPT_s = 1 << 14, // [IGNORED] sectors per cluster
248 OPT_S = 1 << 15, // [IGNORED] sector size
249 OPT_v = 1 << 16, // verbose
250 };
251
252 opt_complementary = "-1";//:b+:f+:F+:h+:r+:R+:s+:S+:vv:c--l:l--c";
253 opts = getopt32(argv, "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v",
254 NULL, NULL, NULL, NULL, NULL,
255 NULL, NULL, &volume_label, NULL, NULL, NULL, NULL);
256 argv += optind;
257
258 // cache device name
259 device_name = argv[0];
260 // default volume ID = creation time
261 volume_id = time(NULL);
262
263 dev = xopen(device_name, O_RDWR);
264 xfstat(dev, &st, device_name);
265
266 //
267 // Get image size and sector size
268 //
269 bytes_per_sect = SECTOR_SIZE;
270 if (!S_ISBLK(st.st_mode)) {
271 if (!S_ISREG(st.st_mode)) {
272 if (!argv[1])
273 bb_error_msg_and_die("image size must be specified");
274 }
275 // not a block device, skip bad sectors check
276 opts &= ~OPT_c;
277 } else {
278 int min_bytes_per_sect;
279#if 0
280 unsigned device_num;
281 // for true block devices we do check sanity
282 device_num = st.st_rdev & 0xff3f;
283 // do we allow to format the whole disk device?
284 if (!(opts & OPT_I) && (
285 device_num == 0x0300 || // hda, hdb
286 (device_num & 0xff0f) == 0x0800 || // sd
287 device_num == 0x0d00 || // xd
288 device_num == 0x1600 ) // hdc, hdd
289 )
290 bb_error_msg_and_die("will not try to make filesystem on full-disk device (use -I if wanted)");
291 // can't work on mounted filesystems
292 if (find_mount_point(device_name, 0))
293 bb_error_msg_and_die("can't format mounted filesystem");
294#endif
295 // get true sector size
296 // (parameter must be int*, not long* or size_t*)
297 xioctl(dev, BLKSSZGET, &min_bytes_per_sect);
298 if (min_bytes_per_sect > SECTOR_SIZE) {
299 bytes_per_sect = min_bytes_per_sect;
300 bb_error_msg("for this device sector size is %u", min_bytes_per_sect);
301 }
302 }
303 volume_size_bytes = get_volume_size_in_bytes(dev, argv[1], 1024, /*extend:*/ 1);
304 volume_size_sect = volume_size_bytes / bytes_per_sect;
305
306 //
307 // Find out or guess media parameters
308 //
309 media_byte = 0xf8;
310 heads = 255;
311 sect_per_track = 63;
312 sect_per_clust = 1;
313 {
314 struct hd_geometry geometry;
315 // size (in sectors), sect (per track), head
316 struct floppy_struct param;
317
318 // N.B. whether to use HDIO_GETGEO or HDIO_REQ?
319 if (ioctl(dev, HDIO_GETGEO, &geometry) == 0
320 && geometry.sectors
321 && geometry.heads
322 ) {
323 // hard drive
324 sect_per_track = geometry.sectors;
325 heads = geometry.heads;
326
327 set_cluster_size:
328 /* For FAT32, try to do the same as M$'s format command
329 * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
330 * fs size <= 260M: 0.5k clusters
331 * fs size <= 8G: 4k clusters
332 * fs size <= 16G: 8k clusters
333 * fs size > 16G: 16k clusters
334 */
335 sect_per_clust = 1;
336 if (volume_size_bytes >= 260*1024*1024) {
337 sect_per_clust = 8;
338 /* fight gcc: */
339 /* "error: integer overflow in expression" */
340 /* "error: right shift count >= width of type" */
341 if (sizeof(off_t) > 4) {
342 unsigned t = (volume_size_bytes >> 31 >> 1);
343 if (t >= 8/4)
344 sect_per_clust = 16;
345 if (t >= 16/4)
346 sect_per_clust = 32;
347 }
348 }
349 } else {
350 // floppy, loop, or regular file
351 int not_floppy = ioctl(dev, FDGETPRM, &param);
352 if (not_floppy == 0) {
353 // floppy disk
354 sect_per_track = param.sect;
355 heads = param.head;
356 volume_size_sect = param.size;
357 volume_size_bytes = param.size * SECTOR_SIZE;
358 }
359 // setup the media descriptor byte
360 switch (volume_size_sect) {
361 case 2*360: // 5.25", 2, 9, 40 - 360K
362 media_byte = 0xfd;
363 break;
364 case 2*720: // 3.5", 2, 9, 80 - 720K
365 case 2*1200: // 5.25", 2, 15, 80 - 1200K
366 media_byte = 0xf9;
367 break;
368 default: // anything else
369 if (not_floppy)
370 goto set_cluster_size;
371 case 2*1440: // 3.5", 2, 18, 80 - 1440K
372 case 2*2880: // 3.5", 2, 36, 80 - 2880K
373 media_byte = 0xf0;
374 break;
375 }
376 // not floppy, but size matches floppy exactly.
377 // perhaps it is a floppy image.
378 // we already set media_byte as if it is a floppy,
379 // now set sect_per_track and heads.
380 heads = 2;
381 sect_per_track = (unsigned)volume_size_sect / 160;
382 if (sect_per_track < 9)
383 sect_per_track = 9;
384 }
385 }
386
387 //
388 // Calculate number of clusters, sectors/cluster, sectors/FAT
389 // (an initial guess for sect_per_clust should already be set)
390 //
391 // "mkdosfs -v -F 32 image5k 5" is the minimum:
392 // 2 sectors for FATs and 2 data sectors
393 if ((off_t)(volume_size_sect - reserved_sect) < 4)
394 bb_error_msg_and_die("the image is too small for FAT32");
395 sect_per_fat = 1;
396 while (1) {
397 while (1) {
398 int spf_adj;
399 uoff_t tcl = (volume_size_sect - reserved_sect - NUM_FATS * sect_per_fat) / sect_per_clust;
400 // tcl may be > MAX_CLUST_32 here, but it may be
401 // because sect_per_fat is underestimated,
402 // and with increased sect_per_fat it still may become
403 // <= MAX_CLUST_32. Therefore, we do not check
404 // against MAX_CLUST_32, but against a bigger const:
405 if (tcl > 0x80ffffff)
406 goto next;
407 total_clust = tcl; // fits in uint32_t
408 // Every cluster needs 4 bytes in FAT. +2 entries since
409 // FAT has space for non-existent clusters 0 and 1.
410 // Let's see how many sectors that needs.
411 //May overflow at "*4":
412 //spf_adj = ((total_clust+2) * 4 + bytes_per_sect-1) / bytes_per_sect - sect_per_fat;
413 //Same in the more obscure, non-overflowing form:
414 spf_adj = ((total_clust+2) + (bytes_per_sect/4)-1) / (bytes_per_sect/4) - sect_per_fat;
415#if 0
416 bb_error_msg("sect_per_clust:%u sect_per_fat:%u total_clust:%u",
417 sect_per_clust, sect_per_fat, (int)tcl);
418 bb_error_msg("adjust to sect_per_fat:%d", spf_adj);
419#endif
420 if (spf_adj <= 0) {
421 // do not need to adjust sect_per_fat.
422 // so, was total_clust too big after all?
423 if (total_clust <= MAX_CLUST_32)
424 goto found_total_clust; // no
425 // yes, total_clust is _a bit_ too big
426 goto next;
427 }
428 // adjust sect_per_fat, go back and recalc total_clust
429 // (note: just "sect_per_fat += spf_adj" isn't ok)
430 sect_per_fat += ((unsigned)spf_adj / 2) | 1;
431 }
432 next:
433 if (sect_per_clust == 128)
434 bb_error_msg_and_die("can't make FAT32 with >128 sectors/cluster");
435 sect_per_clust *= 2;
436 sect_per_fat = (sect_per_fat / 2) | 1;
437 }
438 found_total_clust:
439
440 //
441 // Print info
442 //
443 if (opts & OPT_v) {
444 fprintf(stderr,
445 "Device '%s':\n"
446 "heads:%u, sectors/track:%u, bytes/sector:%u\n"
447 "media descriptor:%02x\n"
448 "total sectors:%"OFF_FMT"u, clusters:%u, sectors/cluster:%u\n"
449 "FATs:2, sectors/FAT:%u\n"
450 "volumeID:%08x, label:'%s'\n",
451 device_name,
452 heads, sect_per_track, bytes_per_sect,
453 (int)media_byte,
454 volume_size_sect, (int)total_clust, (int)sect_per_clust,
455 sect_per_fat,
456 (int)volume_id, volume_label
457 );
458 }
459
460 //
461 // Write filesystem image sequentially (no seeking)
462 //
463 {
464 // (a | b) is poor man's max(a, b)
465 unsigned bufsize = reserved_sect;
466 //bufsize |= sect_per_fat; // can be quite large
467 bufsize |= 2; // use this instead
468 bufsize |= sect_per_clust;
469 buf = xzalloc(bufsize * bytes_per_sect);
470 }
471
472 { // boot and fsinfo sectors, and their copies
473 struct msdos_boot_sector *boot_blk = (void*)buf;
474 struct fat32_fsinfo *info = (void*)(buf + bytes_per_sect);
475
476 strcpy(boot_blk->boot_jump_and_sys_id, "\xeb\x58\x90" "mkdosfs");
477 STORE_LE(boot_blk->bytes_per_sect, bytes_per_sect);
478 STORE_LE(boot_blk->sect_per_clust, sect_per_clust);
479 // cast in needed on big endian to suppress a warning
480 STORE_LE(boot_blk->reserved_sect, (uint16_t)reserved_sect);
481 STORE_LE(boot_blk->fats, 2);
482 //STORE_LE(boot_blk->dir_entries, 0); // for FAT32, stays 0
483 if (volume_size_sect <= 0xffff)
484 STORE_LE(boot_blk->volume_size_sect, volume_size_sect);
485 STORE_LE(boot_blk->media_byte, media_byte);
486 // wrong: this would make Linux think that it's fat12/16:
487 //if (sect_per_fat <= 0xffff)
488 // STORE_LE(boot_blk->sect_per_fat, sect_per_fat);
489 // works:
490 //STORE_LE(boot_blk->sect_per_fat, 0);
491 STORE_LE(boot_blk->sect_per_track, sect_per_track);
492 STORE_LE(boot_blk->heads, heads);
493 //STORE_LE(boot_blk->hidden, 0);
494 STORE_LE(boot_blk->fat32_volume_size_sect, volume_size_sect);
495 STORE_LE(boot_blk->fat32_sect_per_fat, sect_per_fat);
496 //STORE_LE(boot_blk->fat32_flags, 0);
497 //STORE_LE(boot_blk->fat32_version[2], 0,0);
498 STORE_LE(boot_blk->fat32_root_cluster, 2);
499 STORE_LE(boot_blk->fat32_info_sector, info_sector_number);
500 STORE_LE(boot_blk->fat32_backup_boot, backup_boot_sector);
501 //STORE_LE(boot_blk->reserved2[3], 0,0,0);
502 STORE_LE(boot_blk->vi.ext_boot_sign, 0x29);
503 STORE_LE(boot_blk->vi.volume_id32, volume_id);
504 strncpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type));
505 strncpy(boot_blk->vi.volume_label, volume_label, sizeof(boot_blk->vi.volume_label));
506 memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code));
507 STORE_LE(boot_blk->boot_sign, BOOT_SIGN);
508
509 STORE_LE(info->signature1, FAT_FSINFO_SIG1);
510 STORE_LE(info->signature2, FAT_FSINFO_SIG2);
511 // we've allocated cluster 2 for the root dir
512 STORE_LE(info->free_clusters, (total_clust - 1));
513 STORE_LE(info->next_cluster, 2);
514 STORE_LE(info->boot_sign, BOOT_SIGN);
515
516 // 1st copy
517 xwrite(dev, buf, bytes_per_sect * backup_boot_sector);
518 // 2nd copy and possibly zero sectors
519 xwrite(dev, buf, bytes_per_sect * (reserved_sect - backup_boot_sector));
520 }
521
522 { // file allocation tables
523 unsigned i,j;
524 unsigned char *fat = (void*)buf;
525
526 memset(buf, 0, bytes_per_sect * 2);
527 // initial FAT entries
528 MARK_CLUSTER(0, 0x0fffff00 | media_byte);
529 MARK_CLUSTER(1, 0xffffffff);
530 // mark cluster 2 as EOF (used for root dir)
531 MARK_CLUSTER(2, EOF_FAT32);
532 for (i = 0; i < NUM_FATS; i++) {
533 xwrite(dev, buf, bytes_per_sect);
534 for (j = 1; j < sect_per_fat; j++)
535 xwrite(dev, buf + bytes_per_sect, bytes_per_sect);
536 }
537 }
538
539 // root directory
540 // empty directory is just a set of zero bytes
541 memset(buf, 0, sect_per_clust * bytes_per_sect);
542 if (volume_label[0]) {
543 // create dir entry for volume_label
544 struct msdos_dir_entry *de;
545#if 0
546 struct tm tm_time;
547 uint16_t t, d;
548#endif
549 de = (void*)buf;
550 strncpy(de->name, volume_label, sizeof(de->name));
551 STORE_LE(de->attr, ATTR_VOLUME);
552#if 0
553 localtime_r(&create_time, &tm_time);
554 t = (tm_time.tm_sec >> 1) + (tm_time.tm_min << 5) + (tm_time.tm_hour << 11);
555 d = tm_time.tm_mday + ((tm_time.tm_mon+1) << 5) + ((tm_time.tm_year-80) << 9);
556 STORE_LE(de->time, t);
557 STORE_LE(de->date, d);
558 //STORE_LE(de->ctime_cs, 0);
559 de->ctime = de->time;
560 de->cdate = de->date;
561 de->adate = de->date;
562#endif
563 }
564 xwrite(dev, buf, sect_per_clust * bytes_per_sect);
565
566#if 0
567 if (opts & OPT_c) {
568 uoff_t volume_size_blocks;
569 unsigned start_data_sector;
570 unsigned start_data_block;
571 unsigned badblocks = 0;
572 int try, got;
573 off_t currently_testing;
574 char *blkbuf = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
575
576 volume_size_blocks = (volume_size_bytes >> BLOCK_SIZE_BITS);
577 // N.B. the two following vars are in hard sectors, i.e. SECTOR_SIZE byte sectors!
578 start_data_sector = (reserved_sect + NUM_FATS * sect_per_fat) * (bytes_per_sect / SECTOR_SIZE);
579 start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
580
[3621]581 bb_error_msg("searching for bad blocks");
[2725]582 currently_testing = 0;
583 try = TEST_BUFFER_BLOCKS;
584 while (currently_testing < volume_size_blocks) {
585 if (currently_testing + try > volume_size_blocks)
586 try = volume_size_blocks - currently_testing;
587 // perform a test on a block. return the number of blocks
588 // that could be read successfully.
589 // seek to the correct location
590 xlseek(dev, currently_testing * BLOCK_SIZE, SEEK_SET);
591 // try reading
592 got = read(dev, blkbuf, try * BLOCK_SIZE);
593 if (got < 0)
594 got = 0;
595 if (got & (BLOCK_SIZE - 1))
596 bb_error_msg("unexpected values in do_check: probably bugs");
597 got /= BLOCK_SIZE;
598 currently_testing += got;
599 if (got == try) {
600 try = TEST_BUFFER_BLOCKS;
601 continue;
602 }
603 try = 1;
604 if (currently_testing < start_data_block)
605 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
606
607 // mark all of the sectors in the block as bad
608 for (i = 0; i < SECTORS_PER_BLOCK; i++) {
609 int cluster = (currently_testing * SECTORS_PER_BLOCK + i - start_data_sector) / (int) (sect_per_clust) / (bytes_per_sect / SECTOR_SIZE);
610 if (cluster < 0)
611 bb_error_msg_and_die("invalid cluster number in mark_sector: probably bug!");
612 MARK_CLUSTER(cluster, BAD_FAT32);
613 }
614 badblocks++;
615 currently_testing++;
616 }
617 free(blkbuf);
618 if (badblocks)
[3621]619 bb_error_msg("%d bad block(s)", badblocks);
[2725]620 }
621#endif
622
623 // cleanup
624 if (ENABLE_FEATURE_CLEAN_UP) {
625 free(buf);
626 close(dev);
627 }
628
629 return 0;
630}
Note: See TracBrowser for help on using the repository browser.