[97] | 1 | // Fat32 formatter version 1.05
|
---|
| 2 | // (c) Tom Thornhill 2007,2008,2009
|
---|
| 3 | // This software is covered by the GPL.
|
---|
| 4 | // By using this tool, you agree to absolve Ridgecrop of an liabilities for lost data.
|
---|
| 5 | // Please backup any data you value before using this tool.
|
---|
| 6 |
|
---|
| 7 | #include <stdio.h>
|
---|
| 8 | #include <stdlib.h>
|
---|
| 9 | #include <string.h>
|
---|
| 10 | #include <signal.h>
|
---|
[101] | 11 | #include <math.h>
|
---|
[97] | 12 |
|
---|
| 13 | #include "fat32c.h"
|
---|
| 14 |
|
---|
| 15 | /*
|
---|
| 16 | 28.2 CALCULATING THE VOLUME SERIAL NUMBER
|
---|
| 17 |
|
---|
| 18 | For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
|
---|
| 19 | seconds. DOS takes the date and time just before it writes it to the
|
---|
| 20 | disk.
|
---|
| 21 |
|
---|
| 22 | Low order word is calculated: Volume Serial Number is:
|
---|
| 23 | Month & Day 12/26 0c1ah
|
---|
| 24 | Sec & Hundrenths 41:94 295eh 3578:1d02
|
---|
| 25 | -----
|
---|
| 26 | 3578h
|
---|
| 27 |
|
---|
| 28 | High order word is calculated:
|
---|
| 29 | Hours & Minutes 21:55 1537h
|
---|
| 30 | Year 1995 07cbh
|
---|
| 31 | -----
|
---|
| 32 | 1d02h
|
---|
| 33 | */
|
---|
| 34 |
|
---|
| 35 |
|
---|
| 36 | /*
|
---|
| 37 | This is the Microsoft calculation from FATGEN
|
---|
| 38 |
|
---|
| 39 | DWORD RootDirSectors = 0;
|
---|
| 40 | DWORD TmpVal1, TmpVal2, FATSz;
|
---|
| 41 |
|
---|
| 42 | TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
|
---|
| 43 | TmpVal2 = (256 * SecPerClus) + NumFATs;
|
---|
| 44 | TmpVal2 = TmpVal2 / 2;
|
---|
| 45 | FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
|
---|
| 46 |
|
---|
| 47 | return( FatSz );
|
---|
| 48 | */
|
---|
| 49 |
|
---|
| 50 | // disk file open handle
|
---|
| 51 | HANDLE hDev = 0;
|
---|
[186] | 52 | extern char msg;
|
---|
[97] | 53 |
|
---|
| 54 | DWORD get_fat_size_sectors ( DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect )
|
---|
| 55 | {
|
---|
| 56 | ULONGLONG Numerator, Denominator;
|
---|
| 57 | ULONGLONG FatElementSize = 4;
|
---|
| 58 | ULONGLONG FatSz;
|
---|
| 59 |
|
---|
| 60 | // This is based on
|
---|
| 61 | // http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
|
---|
| 62 | // I've made the obvious changes for FAT32
|
---|
| 63 | Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
|
---|
| 64 | Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
|
---|
| 65 | FatSz = Numerator / Denominator;
|
---|
| 66 | // round up
|
---|
| 67 | FatSz += 1;
|
---|
| 68 |
|
---|
| 69 | return( (DWORD) FatSz );
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 |
|
---|
| 73 | BYTE get_spc ( DWORD ClusterSizeKB, DWORD BytesPerSect )
|
---|
| 74 | {
|
---|
| 75 | DWORD spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
|
---|
| 76 | return( (BYTE) spc );
|
---|
| 77 | }
|
---|
| 78 |
|
---|
| 79 | BYTE get_sectors_per_cluster ( LONGLONG DiskSizeBytes, DWORD BytesPerSect )
|
---|
| 80 | {
|
---|
| 81 | BYTE ret = 0x01; // 1 sector per cluster
|
---|
| 82 | LONGLONG DiskSizeMB = DiskSizeBytes / ( 1024*1024 );
|
---|
| 83 |
|
---|
| 84 | // 512 MB to 8,191 MB 4 KB
|
---|
| 85 | if ( DiskSizeMB > 512 )
|
---|
| 86 | ret = get_spc( 4, BytesPerSect ); // ret = 0x8;
|
---|
| 87 |
|
---|
| 88 | // 8,192 MB to 16,383 MB 8 KB
|
---|
| 89 | if ( DiskSizeMB > 8192 )
|
---|
| 90 | ret = get_spc( 8, BytesPerSect ); // ret = 0x10;
|
---|
| 91 |
|
---|
| 92 | // 16,384 MB to 32,767 MB 16 KB
|
---|
| 93 | if ( DiskSizeMB > 16384 )
|
---|
| 94 | ret = get_spc( 16, BytesPerSect ); // ret = 0x20;
|
---|
| 95 |
|
---|
| 96 | // Larger than 32,768 MB 32 KB
|
---|
| 97 | if ( DiskSizeMB > 32768 )
|
---|
| 98 | ret = get_spc( 32, BytesPerSect ); // ret = 0x40;
|
---|
| 99 |
|
---|
| 100 | return( ret );
|
---|
| 101 |
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | void zero_sectors ( HANDLE hDevice, DWORD Sector, DWORD BytesPerSect, DWORD NumSects) //, DISK_GEOMETRY* pdgDrive )
|
---|
| 105 | {
|
---|
| 106 | BYTE *pZeroSect;
|
---|
| 107 | DWORD BurstSize;
|
---|
| 108 | DWORD WriteSize;
|
---|
| 109 | BOOL ret;
|
---|
| 110 | DWORD dwWritten;
|
---|
| 111 | //LARGE_INTEGER Start, End, Ticks, Frequency;
|
---|
| 112 | ULONGLONG Start, End, Ticks, Frequency;
|
---|
| 113 | double fTime;
|
---|
| 114 | double fBytesTotal;
|
---|
[101] | 115 | ULONGLONG qBytesTotal, qBytesWritten;
|
---|
[98] | 116 | float fPercentWritten, fPrevPercentWritten = 0;
|
---|
| 117 | //char Str[12];
|
---|
[97] | 118 |
|
---|
| 119 | //BurstSize = pdgDrive->SectorsPerTrack * pdgDrive->TracksPerCylinder;
|
---|
[100] | 120 | BurstSize = 64; // 32K
|
---|
| 121 | //BurstSize = 128; // 64K
|
---|
[97] | 122 | //BurstSize = 8; // 4k
|
---|
| 123 | //BurstSize = 1; // one sector
|
---|
| 124 |
|
---|
[100] | 125 | //printf("zero_sectors: \nhDevice=0x%lx, Sector=%lu, \nBytesPerSect=%lu, NumSects=%lu\n",
|
---|
| 126 | // hDevice, Sector, BytesPerSect, NumSects);
|
---|
| 127 |
|
---|
[97] | 128 | mem_alloc((void **)&pZeroSect, BytesPerSect * BurstSize);
|
---|
| 129 |
|
---|
| 130 | seek_to_sect( hDevice, Sector, BytesPerSect );
|
---|
| 131 |
|
---|
| 132 | query_freq( &Frequency );
|
---|
| 133 | query_time( &Start );
|
---|
| 134 |
|
---|
| 135 | qBytesTotal = NumSects * BytesPerSect;
|
---|
| 136 | qBytesWritten = 0;
|
---|
| 137 | fPercentWritten = 0;
|
---|
| 138 |
|
---|
| 139 | //printf("Percent written: ");
|
---|
| 140 |
|
---|
| 141 | while ( NumSects )
|
---|
| 142 | {
|
---|
| 143 | if ( NumSects > BurstSize )
|
---|
| 144 | WriteSize = BurstSize;
|
---|
| 145 | else
|
---|
| 146 | WriteSize = NumSects;
|
---|
| 147 |
|
---|
| 148 | //ret = WriteFile ( hDevice, pZeroSect, WriteSize*BytesPerSect, &dwWritten, NULL );
|
---|
| 149 | ret = write_file ( hDevice, pZeroSect, WriteSize * BytesPerSect, &dwWritten );
|
---|
| 150 |
|
---|
[133] | 151 | if ( !ret )
|
---|
| 152 | die ( "Failed to write", ret );
|
---|
[97] | 153 |
|
---|
| 154 | qBytesWritten += dwWritten;
|
---|
[98] | 155 |
|
---|
[101] | 156 | fPercentWritten = ( 100 * qBytesWritten ) / qBytesTotal;
|
---|
[98] | 157 | //sprintf(Str, "%.2f%%...", fPercentWritten);
|
---|
[97] | 158 |
|
---|
[137] | 159 | if ( fPercentWritten - fPrevPercentWritten >= 1 )
|
---|
[98] | 160 | {
|
---|
| 161 | // update progress indicator if it has grown by >= 5%
|
---|
| 162 | fPrevPercentWritten = fPercentWritten;
|
---|
| 163 | // percent written indication
|
---|
| 164 | show_progress(fPercentWritten);
|
---|
| 165 | }
|
---|
[97] | 166 |
|
---|
| 167 | NumSects -= WriteSize;
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | query_time( &End );
|
---|
| 171 |
|
---|
| 172 | //Ticks.QuadPart = End.QuadPart - Start.QuadPart;
|
---|
| 173 | //fTime = (double) ( Ticks.QuadPart ) / Frequency.QuadPart;
|
---|
| 174 |
|
---|
| 175 | Ticks = End - Start;
|
---|
| 176 | fTime = (double) ( Ticks ) / Frequency;
|
---|
| 177 |
|
---|
| 178 | mem_free(pZeroSect, BytesPerSect * BurstSize);
|
---|
| 179 |
|
---|
| 180 | fBytesTotal = (double) qBytesTotal;
|
---|
[186] | 181 | show_message ( "\nWrote %I64d bytes in %.2f seconds, %.2f Megabytes/sec\n", 0, 3,
|
---|
[97] | 182 | qBytesTotal, fTime, fBytesTotal/(fTime*1024.0*1024.0) );
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | int format_volume (char *path, format_params *params)
|
---|
| 186 | {
|
---|
| 187 | // First open the device
|
---|
[129] | 188 | char *p;
|
---|
[97] | 189 | DWORD i;
|
---|
| 190 | HANDLE hDevice;
|
---|
| 191 | UCHAR PartitionType = 0x0c;
|
---|
| 192 |
|
---|
| 193 | int cbRet;
|
---|
| 194 | BOOL bRet;
|
---|
[186] | 195 | BYTE szString[12];
|
---|
[97] | 196 |
|
---|
[100] | 197 | // extended BPB
|
---|
| 198 | struct extbpb dp = {0, 0, 32, 2, 0, 0, 0xf8, 0, 0, 0, 0, 0, {0}};
|
---|
[97] | 199 |
|
---|
| 200 | // Recommended values
|
---|
[100] | 201 | //DWORD ReservedSectCount = 32; !!! create cmd line parameter !!!
|
---|
[97] | 202 | //DWORD NumFATs = 2;
|
---|
| 203 | DWORD BackupBootSect = 6;
|
---|
| 204 | DWORD VolumeId=0; // calculated before format
|
---|
| 205 |
|
---|
| 206 | // // Calculated later
|
---|
| 207 | //DWORD FatSize=0;
|
---|
| 208 | //DWORD BytesPerSect=0;
|
---|
| 209 | //DWORD SectorsPerCluster=0;
|
---|
| 210 | //DWORD TotalSectors=0;
|
---|
| 211 | DWORD SystemAreaSize=0;
|
---|
| 212 | DWORD UserAreaSize=0;
|
---|
| 213 | ULONGLONG qTotalSectors=0;
|
---|
| 214 |
|
---|
| 215 | // structures to be written to the disk
|
---|
| 216 | FAT_BOOTSECTOR32 *pFAT32BootSect;
|
---|
| 217 | FAT_FSINFO *pFAT32FsInfo;
|
---|
| 218 |
|
---|
| 219 | DWORD *pFirstSectOfFat;
|
---|
| 220 |
|
---|
| 221 | // Debug temp vars
|
---|
| 222 | ULONGLONG FatNeeded, ClusterCount;
|
---|
| 223 | char c;
|
---|
| 224 |
|
---|
| 225 | static char volId[12] = {0};
|
---|
| 226 | char *vol = volId;
|
---|
| 227 |
|
---|
[137] | 228 | if (params->reserved_sectors)
|
---|
| 229 | dp.ReservedSectCount = params->reserved_sectors;
|
---|
| 230 |
|
---|
[97] | 231 | VolumeId = get_vol_id( );
|
---|
| 232 |
|
---|
| 233 | strncpy(vol, params->volume_label, 11);
|
---|
| 234 | check_vol_label(path, (char **)&vol);
|
---|
| 235 |
|
---|
| 236 | // Open drive
|
---|
| 237 | open_drive (path, &hDevice);
|
---|
[129] | 238 | get_drive_params(hDevice, &dp);
|
---|
[97] | 239 | lock_drive(hDevice);
|
---|
| 240 | begin_format(hDevice);
|
---|
[130] | 241 | sectorio(hDevice);
|
---|
[97] | 242 |
|
---|
| 243 | // Checks on Disk Size
|
---|
[100] | 244 | // qTotalSectors = dp.PartitionLength / dp.BytesPerSect;
|
---|
| 245 | qTotalSectors = dp.TotalSectors;
|
---|
[97] | 246 | // low end limit - 65536 sectors
|
---|
| 247 | if ( qTotalSectors < 65536 )
|
---|
| 248 | {
|
---|
| 249 | // I suspect that most FAT32 implementations would mount this volume just fine, but the
|
---|
| 250 | // spec says that we shouldn't do this, so we won't
|
---|
| 251 | die ( "This drive is too small for FAT32 - there must be at least 64K clusters\n", -1);
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | if ( qTotalSectors >= 0xffffffff )
|
---|
| 255 | {
|
---|
| 256 | // This is a more fundamental limitation on FAT32 - the total sector count in the root dir
|
---|
| 257 | // ís 32bit. With a bit of creativity, FAT32 could be extended to handle at least 2^28 clusters
|
---|
| 258 | // There would need to be an extra field in the FSInfo sector, and the old sector count could
|
---|
| 259 | // be set to 0xffffffff. This is non standard though, the Windows FAT driver FASTFAT.SYS won't
|
---|
| 260 | // understand this. Perhaps a future version of FAT32 and FASTFAT will handle this.
|
---|
| 261 | die ( "This drive is too big for FAT32 - max 2TB supported\n", -1);
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | mem_alloc ( (void **)&pFAT32BootSect, dp.BytesPerSect );
|
---|
| 265 | mem_alloc ( (void **)&pFAT32FsInfo, dp.BytesPerSect );
|
---|
| 266 | mem_alloc ( (void **)&pFirstSectOfFat, dp.BytesPerSect );
|
---|
| 267 |
|
---|
| 268 | if ( !pFAT32BootSect || !pFAT32FsInfo || !pFirstSectOfFat )
|
---|
| 269 | die ( "Failed to allocate memory", -2 );
|
---|
| 270 |
|
---|
| 271 | // fill out the boot sector and fs info
|
---|
| 272 | pFAT32BootSect->sJmpBoot[0]=0xEB;
|
---|
| 273 | pFAT32BootSect->sJmpBoot[1]=0x5A;
|
---|
| 274 | pFAT32BootSect->sJmpBoot[2]=0x90;
|
---|
| 275 | strcpy( pFAT32BootSect->sOEMName, "MSWIN4.1" );
|
---|
| 276 | pFAT32BootSect->wBytsPerSec = (WORD) dp.BytesPerSect;
|
---|
[156] | 277 |
|
---|
[97] | 278 | if ( params->sectors_per_cluster )
|
---|
| 279 | dp.SectorsPerCluster = params->sectors_per_cluster;
|
---|
| 280 | else
|
---|
[100] | 281 | dp.SectorsPerCluster = get_sectors_per_cluster( ((LONGLONG)dp.TotalSectors) * dp.BytesPerSect, dp.BytesPerSect );
|
---|
[97] | 282 |
|
---|
| 283 | pFAT32BootSect->bSecPerClus = (BYTE) dp.SectorsPerCluster ;
|
---|
| 284 | pFAT32BootSect->wRsvdSecCnt = (WORD) dp.ReservedSectCount;
|
---|
| 285 | pFAT32BootSect->bNumFATs = (BYTE) dp.NumFATs;
|
---|
| 286 | pFAT32BootSect->wRootEntCnt = 0;
|
---|
| 287 | pFAT32BootSect->wTotSec16 = 0;
|
---|
| 288 | pFAT32BootSect->bMedia = 0xF8;
|
---|
| 289 | pFAT32BootSect->wFATSz16 = 0;
|
---|
| 290 | pFAT32BootSect->wSecPerTrk = (WORD) dp.SectorsPerTrack;
|
---|
| 291 | pFAT32BootSect->wNumHeads = (WORD) dp.TracksPerCylinder;
|
---|
| 292 | pFAT32BootSect->dHiddSec = (DWORD) dp.HiddenSectors;
|
---|
[100] | 293 | //dp.TotalSectors = (DWORD) (dp.PartitionLength / dp.BytesPerSect);
|
---|
[97] | 294 | pFAT32BootSect->dTotSec32 = dp.TotalSectors;
|
---|
| 295 |
|
---|
| 296 | dp.FatSize = get_fat_size_sectors ( pFAT32BootSect->dTotSec32, pFAT32BootSect->wRsvdSecCnt, pFAT32BootSect->bSecPerClus, pFAT32BootSect->bNumFATs, dp.BytesPerSect );
|
---|
| 297 |
|
---|
| 298 | pFAT32BootSect->dFATSz32 = dp.FatSize;
|
---|
| 299 | pFAT32BootSect->wExtFlags = 0;
|
---|
| 300 | pFAT32BootSect->wFSVer = 0;
|
---|
| 301 | pFAT32BootSect->dRootClus = 2;
|
---|
| 302 | pFAT32BootSect->wFSInfo = 1;
|
---|
| 303 | pFAT32BootSect->wBkBootSec = (WORD) BackupBootSect;
|
---|
| 304 | pFAT32BootSect->bDrvNum = 0x80;
|
---|
| 305 | pFAT32BootSect->Reserved1 = 0;
|
---|
| 306 | pFAT32BootSect->bBootSig = 0x29;
|
---|
| 307 |
|
---|
| 308 | // Specify volume label
|
---|
| 309 | if (!*vol)
|
---|
[129] | 310 | vol = get_vol_label(path, vol);
|
---|
[97] | 311 |
|
---|
[129] | 312 | vol = strupr(vol);
|
---|
| 313 |
|
---|
[97] | 314 | pFAT32BootSect->dBS_VolID = VolumeId;
|
---|
[129] | 315 | strncpy ( pFAT32BootSect->sVolLab, vol, 11 );
|
---|
| 316 | strncpy ( pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
|
---|
[97] | 317 | ((BYTE*)pFAT32BootSect)[510] = 0x55;
|
---|
| 318 | ((BYTE*)pFAT32BootSect)[511] = 0xaa;
|
---|
| 319 |
|
---|
| 320 | /* FATGEN103.DOC says "NOTE: Many FAT documents mistakenly say that this 0xAA55 signature occupies the "last 2 bytes of
|
---|
| 321 | the boot sector". This statement is correct if - and only if - BPB_BytsPerSec is 512. If BPB_BytsPerSec is greater than
|
---|
| 322 | 512, the offsets of these signature bytes do not change (although it is perfectly OK for the last two bytes at the end
|
---|
| 323 | of the boot sector to also contain this signature)."
|
---|
| 324 |
|
---|
| 325 | Windows seems to only check the bytes at offsets 510 and 511. Other OSs might check the ones at the end of the sector,
|
---|
| 326 | so we'll put them there too.
|
---|
| 327 | */
|
---|
| 328 | if ( dp.BytesPerSect != 512 )
|
---|
| 329 | {
|
---|
| 330 | ((BYTE*)pFAT32BootSect)[dp.BytesPerSect-2] = 0x55;
|
---|
| 331 | ((BYTE*)pFAT32BootSect)[dp.BytesPerSect-1] = 0xaa;
|
---|
| 332 | }
|
---|
| 333 |
|
---|
| 334 | // FSInfo sect
|
---|
| 335 | pFAT32FsInfo->dLeadSig = 0x41615252;
|
---|
| 336 | pFAT32FsInfo->dStrucSig = 0x61417272;
|
---|
| 337 | pFAT32FsInfo->dFree_Count = (DWORD) -1;
|
---|
| 338 | pFAT32FsInfo->dNxt_Free = (DWORD) -1;
|
---|
| 339 | pFAT32FsInfo->dTrailSig = 0xaa550000;
|
---|
| 340 |
|
---|
| 341 | // First FAT Sector
|
---|
| 342 | pFirstSectOfFat[0] = 0x0ffffff8; // Reserved cluster 1 media id in low byte
|
---|
| 343 | pFirstSectOfFat[1] = 0x0fffffff; // Reserved cluster 2 EOC
|
---|
| 344 | pFirstSectOfFat[2] = 0x0fffffff; // end of cluster chain for root dir
|
---|
| 345 |
|
---|
| 346 | // Write boot sector, fats
|
---|
| 347 | // Sector 0 Boot Sector
|
---|
| 348 | // Sector 1 FSInfo
|
---|
| 349 | // Sector 2 More boot code - we write zeros here
|
---|
| 350 | // Sector 3 unused
|
---|
| 351 | // Sector 4 unused
|
---|
| 352 | // Sector 5 unused
|
---|
| 353 | // Sector 6 Backup boot sector
|
---|
| 354 | // Sector 7 Backup FSInfo sector
|
---|
| 355 | // Sector 8 Backup 'more boot code'
|
---|
| 356 | // zero'd sectors upto ReservedSectCount
|
---|
| 357 | // FAT1 ReservedSectCount to ReservedSectCount + FatSize
|
---|
| 358 | // ...
|
---|
| 359 | // FATn ReservedSectCount to ReservedSectCount + FatSize
|
---|
| 360 | // RootDir - allocated to cluster2
|
---|
| 361 |
|
---|
| 362 | UserAreaSize = dp.TotalSectors - dp.ReservedSectCount - (dp.NumFATs*dp.FatSize);
|
---|
| 363 | ClusterCount = UserAreaSize / dp.SectorsPerCluster;
|
---|
| 364 |
|
---|
| 365 | // Sanity check for a cluster count of >2^28, since the upper 4 bits of the cluster values in
|
---|
| 366 | // the FAT are reserved.
|
---|
| 367 | if ( ClusterCount > 0x0FFFFFFF )
|
---|
| 368 | {
|
---|
[98] | 369 | die ( "This drive has more than 2^28 clusters, \n"
|
---|
| 370 | "try to specify a larger cluster size or use \n"
|
---|
| 371 | "the default (i.e. don't use -cXX)\n", -3 );
|
---|
[97] | 372 | }
|
---|
| 373 |
|
---|
| 374 | // Sanity check - < 64K clusters means that the volume will be misdetected as FAT16
|
---|
| 375 | if ( ClusterCount < 65536 )
|
---|
| 376 | {
|
---|
[98] | 377 | die ( "FAT32 must have at least 65536 clusters, \n"
|
---|
| 378 | "try to specify a smaller cluster size or \n"
|
---|
| 379 | "use the default (i.e. don't use -cXX)\n", -4 );
|
---|
[97] | 380 | }
|
---|
| 381 |
|
---|
| 382 | // Sanity check, make sure the fat is big enough
|
---|
| 383 | // Convert the cluster count into a Fat sector count, and check the fat size value we calculated
|
---|
| 384 | // earlier is OK.
|
---|
| 385 | FatNeeded = ClusterCount * 4;
|
---|
| 386 | FatNeeded += (dp.BytesPerSect-1);
|
---|
| 387 | FatNeeded /= dp.BytesPerSect;
|
---|
[100] | 388 |
|
---|
| 389 | //printf("dp.BytesPerSect=%lu\n", dp.BytesPerSect);
|
---|
| 390 | //printf("ClusterCount=%llu, FatNeeded=%llu, FatSize=%lu\n", ClusterCount, FatNeeded, dp.FatSize);
|
---|
[97] | 391 | if ( FatNeeded > dp.FatSize )
|
---|
| 392 | {
|
---|
[98] | 393 | die ( "This drive is too big for this version \n"
|
---|
| 394 | "of fat32format, check for an upgrade\n", -5 );
|
---|
[97] | 395 | }
|
---|
| 396 |
|
---|
| 397 | // Now we're commited - print some info first
|
---|
[186] | 398 | show_message ( "Size: %g MB %u sectors\n", 0, 0, (double) ((dp.TotalSectors / (1024*1024)) * dp.BytesPerSect), dp.TotalSectors );
|
---|
| 399 | show_message ( "%d Bytes Per Sector, Cluster size %d bytes\n", 0, 0, dp.BytesPerSect, dp.SectorsPerCluster * dp.BytesPerSect );
|
---|
[97] | 400 |
|
---|
[186] | 401 | //show_message ( "Volume Serial No. is %x:%x", 1243, 1, TYPE_LONG, VolumeId );
|
---|
| 402 | sprintf(szString, "%4.4X-%4.4X", HIUSHORT(VolumeId), LOUSHORT(VolumeId));
|
---|
| 403 | show_message ( "The Volume Serial Number is %s.", 1243, 1, TYPE_STRING, szString);
|
---|
| 404 | show_message ( "Volume label is %s", 1375, 1, TYPE_STRING, vol );
|
---|
| 405 |
|
---|
| 406 | show_message ( "%d Reserved Sectors, %d Sectors per FAT, %d fats\n", 0, 0, dp.ReservedSectCount, dp.FatSize, dp.NumFATs );
|
---|
| 407 |
|
---|
| 408 | show_message ( "%d Total clusters\n", 0, 0, ClusterCount );
|
---|
[97] | 409 |
|
---|
| 410 | // fix up the FSInfo sector
|
---|
| 411 | pFAT32FsInfo->dFree_Count = (UserAreaSize/dp.SectorsPerCluster)-1;
|
---|
| 412 | pFAT32FsInfo->dNxt_Free = 3; // clusters 0-1 resered, we used cluster 2 for the root dir
|
---|
| 413 |
|
---|
[186] | 414 | show_message ( "%d Free Clusters\n", 0, 0, pFAT32FsInfo->dFree_Count );
|
---|
[97] | 415 | // Work out the Cluster count
|
---|
| 416 |
|
---|
[186] | 417 | show_message( "Formatting drive %s\n", 534, 0, path );
|
---|
[97] | 418 |
|
---|
| 419 | // Once zero_sectors has run, any data on the drive is basically lost....
|
---|
| 420 |
|
---|
| 421 | // First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster
|
---|
| 422 | SystemAreaSize = (dp.ReservedSectCount+(dp.NumFATs*dp.FatSize) + dp.SectorsPerCluster);
|
---|
| 423 | zero_sectors( hDevice, 0, dp.BytesPerSect, SystemAreaSize); // &dgDrive);
|
---|
| 424 |
|
---|
[186] | 425 | show_message ( "Clearing out %d sectors for \nReserved sectors, fats and root cluster...\n", 0, 0, SystemAreaSize );
|
---|
| 426 | show_message ( "Initialising reserved sectors and FATs...\n", 0, 0 );
|
---|
[97] | 427 | // Now we should write the boot sector and fsinfo twice, once at 0 and once at the backup boot sect position
|
---|
| 428 | for ( i=0; i<2; i++ )
|
---|
| 429 | {
|
---|
| 430 | int SectorStart = (i==0) ? 0 : BackupBootSect;
|
---|
| 431 | write_sect ( hDevice, SectorStart, dp.BytesPerSect, pFAT32BootSect, 1 );
|
---|
| 432 | write_sect ( hDevice, SectorStart+1, dp.BytesPerSect, pFAT32FsInfo, 1 );
|
---|
| 433 | }
|
---|
| 434 | // Write the first fat sector in the right places
|
---|
| 435 | for ( i=0; i<dp.NumFATs; i++ )
|
---|
| 436 | {
|
---|
| 437 | int SectorStart = dp.ReservedSectCount + (i * dp.FatSize );
|
---|
| 438 | write_sect ( hDevice, SectorStart, dp.BytesPerSect, pFirstSectOfFat, 1 );
|
---|
| 439 | }
|
---|
| 440 |
|
---|
| 441 | // The filesystem recogniser in Windows XP doesn't use the partition type - in can be
|
---|
| 442 | // set to pretty much anything other Os's like Dos (still useful for Norton Ghost!) and Windows ME might,
|
---|
| 443 | // so we could fix it here
|
---|
| 444 | // On the other hand, I'm not sure that exposing big partitions to Windows ME/98 is a very good idea
|
---|
| 445 | // There are a couple of issues here -
|
---|
| 446 | // 1) WinME/98 doesn't know about 48bit LBA, so IDE drives bigger than 137GB will cause it
|
---|
| 447 | // problems. Rather than refuse to mount them, it uses 28bit LBA which wraps
|
---|
| 448 | // around, so writing to files above the 137GB boundary will erase the FAT and root dirs.
|
---|
| 449 | // 2) Win98 and WinME have 16 bit scandisk tools, which you need to disable, assuming you
|
---|
| 450 | // can get third party support for 48bit LBA, or use a USB external case, most of which
|
---|
| 451 | // will let you use a 48bit LBA drive.
|
---|
| 452 | // see http://www.48bitlba.com/win98.htm for instructions
|
---|
| 453 |
|
---|
[129] | 454 | set_part_type (hDevice, &dp, 0xc);
|
---|
[97] | 455 | remount_media ( hDevice );
|
---|
| 456 | unlock_drive ( hDevice );
|
---|
| 457 | close_drive ( hDevice );
|
---|
| 458 | fflush(stdout);
|
---|
| 459 |
|
---|
[129] | 460 | set_vol_label (path, vol);
|
---|
| 461 |
|
---|
[115] | 462 | // free memory
|
---|
| 463 | mem_free ( (void *)pFirstSectOfFat, dp.BytesPerSect );
|
---|
| 464 | mem_free ( (void *)pFAT32FsInfo, dp.BytesPerSect );
|
---|
| 465 | mem_free ( (void *)pFAT32BootSect, dp.BytesPerSect );
|
---|
| 466 |
|
---|
[97] | 467 | return( TRUE );
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 | void usage( char *s )
|
---|
| 471 | {
|
---|
[98] | 472 | printf ( "\nFat32format, ver. 1.07, \n"
|
---|
| 473 | "see http://www.ridgecrop.demon.co.uk/fat32format.htm\n"
|
---|
| 474 | "Modified and ported to OS/2 by osFree project \n"
|
---|
| 475 | "(http://osfree.org) for ufat32.dll.\n"
|
---|
| 476 | "This software is covered by the GPL.\n"
|
---|
| 477 | "Use with care - Ridgecrop are not liable\n"
|
---|
[100] | 478 | "for data lost using this tool.\n\n"
|
---|
[98] | 479 | "Usage:[c:\\] %s <d>: [options]\n\n"
|
---|
[97] | 480 | "/C:<N> with different cluster sizes:\n"
|
---|
| 481 | " N: sectors per cluster:\n"
|
---|
| 482 | " 1 ( max size 137GB ) \n"
|
---|
| 483 | " 2 ( max size 274GB )\n"
|
---|
| 484 | " 4 ( max size 549GB )\n"
|
---|
[100] | 485 | " 8 ( max size 1TB. )\n"
|
---|
[98] | 486 | " ... \n"
|
---|
| 487 | " 128 - use 128 sectors per cluster (64K clusters)\n"
|
---|
[97] | 488 | "/V:<volume label>\n"
|
---|
[137] | 489 | "/R:<reserved sectors>\n"
|
---|
[97] | 490 | "/? this help message\n\n", s );
|
---|
| 491 |
|
---|
| 492 | exit(1);
|
---|
| 493 | }
|
---|
| 494 |
|
---|
| 495 | void sig_handler (int sig);
|
---|
| 496 |
|
---|
| 497 | int setup_signals (void)
|
---|
| 498 | {
|
---|
| 499 | if (SIG_ERR == signal(SIGABRT, sig_handler)) {
|
---|
| 500 | perror("Could not set SIGABRT");
|
---|
| 501 | return EXIT_FAILURE;
|
---|
| 502 | }
|
---|
| 503 |
|
---|
| 504 | if (SIG_ERR == signal(SIGBREAK, sig_handler)) {
|
---|
| 505 | perror("Could not set SIGBREAK");
|
---|
| 506 | return EXIT_FAILURE;
|
---|
| 507 | }
|
---|
| 508 |
|
---|
| 509 | if (SIG_ERR == signal(SIGINT, sig_handler)) {
|
---|
| 510 | perror("Could not set SIGINT");
|
---|
| 511 | return EXIT_FAILURE;
|
---|
| 512 | }
|
---|
| 513 |
|
---|
| 514 | if (SIG_ERR == signal(SIGFPE, sig_handler)) {
|
---|
| 515 | perror("Could not set SIGFPE");
|
---|
| 516 | return EXIT_FAILURE;
|
---|
| 517 | }
|
---|
| 518 | if (SIG_ERR == signal(SIGSEGV, sig_handler)) {
|
---|
| 519 | perror("Could not set SIGSEGV");
|
---|
| 520 | return EXIT_FAILURE;
|
---|
| 521 | }
|
---|
| 522 | if (SIG_ERR == signal(SIGILL, sig_handler)) {
|
---|
| 523 | perror("Could not set SIGILL");
|
---|
| 524 | return EXIT_FAILURE;
|
---|
| 525 | }
|
---|
| 526 |
|
---|
| 527 | return 0;
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | int format(int argc, char *argv[], char *envp[])
|
---|
| 531 | {
|
---|
| 532 | format_params p;
|
---|
| 533 | char cVolume;
|
---|
[98] | 534 | int i=1;
|
---|
[97] | 535 | char path[] = "Z:";
|
---|
| 536 | char *s, *t;
|
---|
[98] | 537 | char key[12], val[12];
|
---|
[97] | 538 |
|
---|
| 539 | // set up signal handlers
|
---|
| 540 | if (setup_signals())
|
---|
| 541 | {
|
---|
| 542 | printf("Error setting the signal handler!\n");
|
---|
| 543 | quit (1);
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 | memset( &p, 0, sizeof(p) );
|
---|
| 547 |
|
---|
| 548 | if ( argc < 2 )
|
---|
| 549 | {
|
---|
| 550 | usage( argv[0] );
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 | cVolume = argv[1][0];
|
---|
| 554 |
|
---|
| 555 | if (!isalpha(cVolume) || argv[1][1] != ':')
|
---|
| 556 | usage( argv[0] );
|
---|
| 557 |
|
---|
| 558 | #if 0
|
---|
| 559 | if ( cVolume != 'f' )
|
---|
| 560 | die( "Debug - only F: can be formatted\n", -9 );
|
---|
| 561 | #endif
|
---|
| 562 |
|
---|
| 563 | path[0] = cVolume;
|
---|
| 564 | path[1] = ':';
|
---|
| 565 | path[2] = '\0';
|
---|
| 566 |
|
---|
| 567 | for ( i = 2; i < argc; i++ )
|
---|
| 568 | {
|
---|
| 569 | if ( !((strlen(argv[i])>=2) && ((argv[i][0] == '-')||(argv[i][0] == '/'))) )
|
---|
| 570 | usage( argv[0] );
|
---|
| 571 |
|
---|
| 572 | memset(key, 0, 12);
|
---|
| 573 | memset(val, 0, 12);
|
---|
| 574 |
|
---|
| 575 | if ( strlen(argv[i]) > 3 )
|
---|
| 576 | {
|
---|
| 577 | // move to ':'
|
---|
| 578 | s = argv[i] + 1;
|
---|
| 579 | t = strchr(s, ':');
|
---|
| 580 |
|
---|
| 581 | if (t >= s)
|
---|
| 582 | {
|
---|
| 583 | strncpy(key, s, t - s); key[t - s] = '\0';
|
---|
| 584 | strncpy(val, t + 1, strlen(t + 1)); val[strlen(t + 1)] = '\0';
|
---|
| 585 | }
|
---|
| 586 | else
|
---|
| 587 | {
|
---|
| 588 | strncpy(key, s, 12);
|
---|
| 589 | val[0] = '\0';
|
---|
| 590 | }
|
---|
| 591 | }
|
---|
| 592 |
|
---|
| 593 | // skip /fs:... parameter
|
---|
| 594 | if (!stricmp(key, "FS"))
|
---|
| 595 | continue;
|
---|
| 596 |
|
---|
| 597 | switch ( toupper(argv[i][1]) )
|
---|
| 598 | {
|
---|
| 599 | case 'C':
|
---|
| 600 | p.sectors_per_cluster = atol(val);
|
---|
| 601 | if ( (p.sectors_per_cluster != 1) && // 512 bytes, 0.5k
|
---|
| 602 | (p.sectors_per_cluster != 2) && // 1K
|
---|
| 603 | (p.sectors_per_cluster != 4) && // 2K
|
---|
| 604 | (p.sectors_per_cluster != 8) && // 4K
|
---|
| 605 | (p.sectors_per_cluster != 16) && // 8K
|
---|
| 606 | (p.sectors_per_cluster != 32) && // 16K
|
---|
| 607 | (p.sectors_per_cluster != 64) && // 32K
|
---|
| 608 | (p.sectors_per_cluster != 128) // 64K ( Microsoft say don't use 64K or bigger);
|
---|
| 609 | )
|
---|
| 610 | {
|
---|
| 611 | printf ( "Ignoring bad cluster size %d\n", p.sectors_per_cluster );
|
---|
| 612 | p.sectors_per_cluster = 0;
|
---|
| 613 | usage( argv[0] );
|
---|
| 614 | }
|
---|
| 615 | continue;
|
---|
[137] | 616 | case 'R':
|
---|
| 617 | p.reserved_sectors = atol(val);
|
---|
| 618 | if (! p.reserved_sectors)
|
---|
| 619 | {
|
---|
| 620 | printf( "Ignoring bad reserved sectors %d\n", p.reserved_sectors );
|
---|
| 621 | p.reserved_sectors = 32;
|
---|
| 622 | usage( argv[0] );
|
---|
| 623 | }
|
---|
| 624 | continue;
|
---|
[97] | 625 | case 'H':
|
---|
| 626 | case '?':
|
---|
| 627 | usage( argv[0] );
|
---|
| 628 | case 'V':
|
---|
| 629 | memcpy(p.volume_label, val, 12);
|
---|
| 630 | continue;
|
---|
[186] | 631 | case 'P':
|
---|
| 632 | msg = TRUE;
|
---|
| 633 | continue;
|
---|
[97] | 634 | default:
|
---|
[100] | 635 | // printf ( "Ignoring bad flag '-%c'\n", argv[i][1] );
|
---|
[97] | 636 | usage( argv[0] );
|
---|
| 637 | }
|
---|
| 638 | //i++;
|
---|
| 639 | }
|
---|
| 640 |
|
---|
[98] | 641 | if ( format_volume( path, &p ) )
|
---|
| 642 | show_message( "Done.", 1294, 0 );
|
---|
[97] | 643 |
|
---|
| 644 | return 0;
|
---|
| 645 | }
|
---|
| 646 |
|
---|
| 647 | #ifndef __DLL__
|
---|
| 648 | int main(int argc, char *argv[])
|
---|
| 649 | {
|
---|
| 650 | return format(argc, argv, NULL);
|
---|
| 651 | }
|
---|
| 652 | #endif
|
---|
| 653 |
|
---|
| 654 | void cleanup ( void )
|
---|
| 655 | {
|
---|
| 656 | if (hDev == 0)
|
---|
| 657 | return;
|
---|
| 658 |
|
---|
| 659 | remount_media ( hDev );
|
---|
| 660 | unlock_drive ( hDev );
|
---|
| 661 | close_drive ( hDev);
|
---|
[99] | 662 | hDev = 0;
|
---|
[97] | 663 | }
|
---|
| 664 |
|
---|
| 665 | void quit (int rc)
|
---|
| 666 | {
|
---|
| 667 | cleanup ();
|
---|
| 668 | exit (rc);
|
---|
| 669 | }
|
---|
| 670 |
|
---|
| 671 | void show_sig_string(int s)
|
---|
| 672 | {
|
---|
| 673 | char *str = "";
|
---|
| 674 | switch (s)
|
---|
| 675 | {
|
---|
| 676 | case SIGABRT:
|
---|
| 677 | str="SIGABRT";
|
---|
| 678 | break;
|
---|
| 679 | case SIGBREAK:
|
---|
| 680 | str="SIGBREAK";
|
---|
| 681 | break;
|
---|
| 682 | case SIGINT:
|
---|
| 683 | str="SIGINT";
|
---|
| 684 | break;
|
---|
| 685 | case SIGFPE:
|
---|
| 686 | str="SIGFPE";
|
---|
| 687 | break;
|
---|
| 688 | case SIGSEGV:
|
---|
| 689 | str="SIGSEGV";
|
---|
| 690 | break;
|
---|
| 691 | case SIGILL:
|
---|
| 692 | str="SIGILL";
|
---|
| 693 | break;
|
---|
| 694 | default:
|
---|
| 695 | ;
|
---|
| 696 | }
|
---|
| 697 | printf("Signal: %d = %s\n", s, str);
|
---|
| 698 | }
|
---|
| 699 |
|
---|
| 700 | void sig_handler (int sig)
|
---|
| 701 | {
|
---|
| 702 | show_sig_string(sig);
|
---|
| 703 | cleanup();
|
---|
| 704 | }
|
---|