/* * Rufus: The Reliable USB Formatting Utility * Formatting function calls * Copyright (c) 2011-2012 Pete Batard * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef _CRTDBG_MAP_ALLOC #include #include #endif #include #include #include #include #include #include #include #include #include "msapi_utf8.h" #include "rufus.h" #include "resource.h" #include "br.h" #include "fat16.h" #include "fat32.h" #include "ntfs.h" #include "partition_info.h" #include "file.h" #include "format.h" #include "badblocks.h" /* * Globals */ DWORD FormatStatus; badblocks_report report; static float format_percent = 0.0f; static int task_number = 0; /* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */ const int nb_steps[FS_MAX] = { 5, 5, 12, 10 }; static int fs_index = 0; /* * FormatEx callback. Return FALSE to halt operations */ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DWORD Action, PVOID pData) { DWORD* percent; if (IS_ERROR(FormatStatus)) return FALSE; switch(Command) { case FCC_PROGRESS: percent = (DWORD*)pData; PrintStatus(0, FALSE, "Formatting: %d%% completed.", *percent); UpdateProgress(OP_FORMAT, 1.0f * (*percent)); break; case FCC_STRUCTURE_PROGRESS: // No progress on quick format PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", ++task_number, nb_steps[fs_index]); format_percent += 100.0f / (1.0f * nb_steps[fs_index]); UpdateProgress(OP_CREATE_FS, format_percent); break; case FCC_DONE: PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", nb_steps[fs_index], nb_steps[fs_index]); UpdateProgress(OP_CREATE_FS, 100.0f); if(*(BOOLEAN*)pData == FALSE) { uprintf("Error while formatting.\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; } break; case FCC_DONE_WITH_STRUCTURE: // We get this message when formatting Small FAT16 // pData Seems to be a struct with at least one (32 BIT!!!) string pointer to the size in MB uprintf("Done with that sort of thing: Action=%d pData=%0p\n", Action, pData); // /!\ THE FOLLOWING ONLY WORKS ON VISTA OR LATER - DO NOT ENABLE ON XP! // DumpBufferHex(pData, 8); // uprintf("Volume size: %s MB\n", (char*)(LONG_PTR)(*(ULONG32*)pData)); break; case FCC_INCOMPATIBLE_FILE_SYSTEM: uprintf("Incompatible File System\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS); break; case FCC_ACCESS_DENIED: uprintf("Access denied\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED; break; case FCC_MEDIA_WRITE_PROTECTED: uprintf("Media is write protected\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT; break; case FCC_VOLUME_IN_USE: uprintf("Volume is in use\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE; break; case FCC_CANT_QUICK_FORMAT: uprintf("Cannot quick format this volume\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_QUICK_FORMAT); break; case FCC_BAD_LABEL: uprintf("Bad label\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_LABEL_TOO_LONG; break; case FCC_OUTPUT: uprintf("%s\n", ((PTEXTOUTPUT)pData)->Output); break; case FCC_CLUSTER_SIZE_TOO_BIG: case FCC_CLUSTER_SIZE_TOO_SMALL: uprintf("Unsupported cluster size\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_CLUSTER_SIZE); break; case FCC_VOLUME_TOO_BIG: case FCC_VOLUME_TOO_SMALL: uprintf("Volume is too %s\n", FCC_VOLUME_TOO_BIG?"big":"small"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_VOLUME_SIZE); case FCC_NO_MEDIA_IN_DRIVE: uprintf("No media in drive\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE; break; default: uprintf("FormatExCallback: received unhandled command %X\n", Command); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED; break; } return (!IS_ERROR(FormatStatus)); } /* * Converts an UTF-16 label to a valid FAT/NTFS one */ static void ToValidLabel(WCHAR* name, BOOL bFAT) { size_t i, j, k; BOOL found; WCHAR unauthorized[] = L"*?.,;:/\\|+=<>[]"; WCHAR to_underscore[] = L"\t"; if (name == NULL) return; for (i=0, k=0; i= 0x80) { name[k++] = '_'; found = TRUE; } if (found) continue; } found = FALSE; for (j=0; j delete the log file // NB: the log doesn't get deleted on abort fclose(log_fd); _unlink(logfile); } } while (r == IDRETRY); if (r == IDABORT) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; goto out; } } // Close the (unmounted) volume before formatting, but keep the lock safe_closehandle(hLogicalVolume); // Especially after destructive badblocks test, you must zero the MBR completely // before repartitioning. Else, all kind of bad things happen if (!ClearMBR(hPhysicalDrive)) { uprintf("unable to zero MBR\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; goto out; } UpdateProgress(OP_ZERO_MBR, -1.0f); if (!CreatePartition(hPhysicalDrive)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; goto out; } UpdateProgress(OP_PARTITION, -1.0f); // Add a small delay after partitioning to be safe Sleep(200); if (!FormatDrive(drive_name[0])) { // Error will be set by FormatDrive() in FormatStatus uprintf("Format error: %s\n", StrError(FormatStatus)); goto out; } PrintStatus(0, TRUE, "Writing master boot record..."); if (!WriteMBR(hPhysicalDrive)) { // Errorcode has already been set goto out; } UpdateProgress(OP_FIX_MBR, -1.0f); if (IsChecked(IDC_DOS)) { switch(ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType))) { case DT_WINME: case DT_FREEDOS: case DT_ISO_NTFS: // We still have a lock, which we need to modify the volume boot record // => no need to reacquire the lock... hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, FALSE); if (hLogicalVolume == INVALID_HANDLE_VALUE) { uprintf("Could not re-mount volume for partition boot record access\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } // NB: if you unmount the logical volume here, XP will report error: // [0x00000456] The media in the drive may have changed PrintStatus(0, TRUE, "Writing partition boot record..."); if (!WritePBR(hLogicalVolume)) { if (!FormatStatus) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; goto out; } // We must close and unlock the volume to write files to it safe_unlockclose(hLogicalVolume); break; case DT_ISO_FAT: PrintStatus(0, TRUE, "Installing Syslinux..."); if (!InstallSyslinux(num, drive_name)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE; } break; } } else { if (IsChecked(IDC_SET_ICON)) SetAutorun(drive_name); } // We issue a complete remount of the filesystem at on account of: // - Ensuring the file explorer properly detects that the volume was updated // - Ensuring that an NTFS system will be reparsed so that it becomes bootable if (!RemountVolume(drive_name[0])) goto out; if (IsChecked(IDC_DOS)) { UpdateProgress(OP_DOS, -1.0f); switch(ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType))) { case DT_WINME: case DT_FREEDOS: PrintStatus(0, TRUE, "Copying DOS files..."); if (!ExtractDOS(drive_name)) { if (!FormatStatus) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; goto out; } break; case DT_ISO_NTFS: case DT_ISO_FAT: if (iso_path != NULL) { PrintStatus(0, TRUE, "Copying ISO files..."); drive_name[2] = 0; if ( (!ExtractISO(iso_path, drive_name, FALSE)) && (!FormatStatus)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; goto out; } } break; } if (IsChecked(IDC_SET_ICON)) SetAutorun(drive_name); UpdateProgress(OP_DOS, -1.0f); // Issue another complete remount before we exit, to ensure we're clean RemountVolume(drive_name[0]); } out: safe_unlockclose(hLogicalVolume); safe_unlockclose(hPhysicalDrive); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); ExitThread(0); }