"Fossies" - the Fresh Open Source Software Archive

Member "rufus-3.13/src/format_ext.c" (20 Nov 2020, 17417 Bytes) of package /linux/misc/rufus-3.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "format_ext.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.12_vs_3.13.

    1 /*
    2  * Rufus: The Reliable USB Formatting Utility
    3  * extfs formatting
    4  * Copyright © 2019-2020 Pete Batard <pete@akeo.ie>
    5  *
    6  * This program is free software: you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation, either version 3 of the License, or
    9  * (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18  */
   19 
   20 #ifdef _CRTDBG_MAP_ALLOC
   21 #include <stdlib.h>
   22 #include <crtdbg.h>
   23 #endif
   24 
   25 #include <windows.h>
   26 #include <stdio.h>
   27 #include <string.h>
   28 #include <stdlib.h>
   29 #include <assert.h>
   30 
   31 #include "rufus.h"
   32 #include "file.h"
   33 #include "drive.h"
   34 #include "format.h"
   35 #include "missing.h"
   36 #include "resource.h"
   37 #include "msapi_utf8.h"
   38 #include "localization.h"
   39 #include "ext2fs/ext2fs.h"
   40 
   41 extern const char* FileSystemLabel[FS_MAX];
   42 extern io_manager nt_io_manager(void);
   43 extern DWORD ext2_last_winerror(DWORD default_error);
   44 static float ext2_percent_start = 0.0f, ext2_percent_share = 0.5f;
   45 const float ext2_max_marker = 80.0f;
   46 
   47 typedef struct {
   48     uint64_t max_size;
   49     uint32_t block_size;
   50     uint32_t inode_size;
   51     uint32_t inode_ratio;
   52 } ext2fs_default_t;
   53 
   54 const char* error_message(errcode_t error_code)
   55 {
   56     static char error_string[256];
   57 
   58     switch (error_code) {
   59     case EXT2_ET_MAGIC_EXT2FS_FILSYS:
   60     case EXT2_ET_MAGIC_BADBLOCKS_LIST:
   61     case EXT2_ET_MAGIC_BADBLOCKS_ITERATE:
   62     case EXT2_ET_MAGIC_INODE_SCAN:
   63     case EXT2_ET_MAGIC_IO_CHANNEL:
   64     case EXT2_ET_MAGIC_IO_MANAGER:
   65     case EXT2_ET_MAGIC_BLOCK_BITMAP:
   66     case EXT2_ET_MAGIC_INODE_BITMAP:
   67     case EXT2_ET_MAGIC_GENERIC_BITMAP:
   68     case EXT2_ET_MAGIC_ICOUNT:
   69     case EXT2_ET_MAGIC_EXTENT_HANDLE:
   70     case EXT2_ET_BAD_MAGIC:
   71         return "Bad magic";
   72     case EXT2_ET_RO_FILSYS:
   73         return "Read-only file system";
   74     case EXT2_ET_GDESC_BAD_BLOCK_MAP:
   75     case EXT2_ET_GDESC_BAD_INODE_MAP:
   76     case EXT2_ET_GDESC_BAD_INODE_TABLE:
   77         return "Bad map or table";
   78     case EXT2_ET_UNEXPECTED_BLOCK_SIZE:
   79         return "Unexpected block size";
   80     case EXT2_ET_DIR_CORRUPTED:
   81         return "Corrupted entry";
   82     case EXT2_ET_GDESC_READ:
   83     case EXT2_ET_GDESC_WRITE:
   84     case EXT2_ET_INODE_BITMAP_WRITE:
   85     case EXT2_ET_INODE_BITMAP_READ:
   86     case EXT2_ET_BLOCK_BITMAP_WRITE:
   87     case EXT2_ET_BLOCK_BITMAP_READ:
   88     case EXT2_ET_INODE_TABLE_WRITE:
   89     case EXT2_ET_INODE_TABLE_READ:
   90     case EXT2_ET_NEXT_INODE_READ:
   91     case EXT2_ET_SHORT_READ:
   92     case EXT2_ET_SHORT_WRITE:
   93         return "read/write error";
   94     case EXT2_ET_DIR_NO_SPACE:
   95         return "no space left";
   96     case EXT2_ET_TOOSMALL:
   97         return "Too small";
   98     case EXT2_ET_BAD_DEVICE_NAME:
   99         return "Bad device name";
  100     case EXT2_ET_MISSING_INODE_TABLE:
  101         return "Missing inode table";
  102     case EXT2_ET_CORRUPT_SUPERBLOCK:
  103         return "Superblock is corrupted";
  104     case EXT2_ET_CALLBACK_NOTHANDLED:
  105         return "Unhandled callback";
  106     case EXT2_ET_BAD_BLOCK_IN_INODE_TABLE:
  107         return "Bad block in inode table";
  108     case EXT2_ET_UNSUPP_FEATURE:
  109     case EXT2_ET_RO_UNSUPP_FEATURE:
  110     case EXT2_ET_UNIMPLEMENTED:
  111         return "Unsupported feature";
  112     case EXT2_ET_LLSEEK_FAILED:
  113         return "Seek failed";
  114     case EXT2_ET_NO_MEMORY:
  115     case EXT2_ET_BLOCK_ALLOC_FAIL:
  116     case EXT2_ET_INODE_ALLOC_FAIL:
  117         return "Out of memory";
  118     case EXT2_ET_INVALID_ARGUMENT:
  119         return "Invalid argument";
  120     case EXT2_ET_NO_DIRECTORY:
  121         return "No directory";
  122     case EXT2_ET_FILE_NOT_FOUND:
  123         return "File not found";
  124     case EXT2_ET_FILE_RO:
  125         return "File is read-only";
  126     case EXT2_ET_DIR_EXISTS:
  127         return "Directory already exists";
  128     case EXT2_ET_CANCEL_REQUESTED:
  129         return "Cancel requested";
  130     case EXT2_ET_FILE_TOO_BIG:
  131         return "File too big";
  132     case EXT2_ET_JOURNAL_NOT_BLOCK:
  133     case EXT2_ET_NO_JOURNAL_SB:
  134         return "No journal superblock";
  135     case EXT2_ET_JOURNAL_TOO_SMALL:
  136         return "Journal too small";
  137     case EXT2_ET_NO_JOURNAL:
  138         return "No journal";
  139     case EXT2_ET_TOO_MANY_INODES:
  140         return "Too many inodes";
  141     case EXT2_ET_NO_CURRENT_NODE:
  142         return "No current node";
  143     case EXT2_ET_OP_NOT_SUPPORTED:
  144         return "Operation not supported";
  145     case EXT2_ET_IO_CHANNEL_NO_SUPPORT_64:
  146         return "I/O Channel does not support 64-bit operation";
  147     case EXT2_ET_BAD_DESC_SIZE:
  148         return "Bad descriptor size";
  149     case EXT2_ET_INODE_CSUM_INVALID:
  150     case EXT2_ET_INODE_BITMAP_CSUM_INVALID:
  151     case EXT2_ET_EXTENT_CSUM_INVALID:
  152     case EXT2_ET_DIR_CSUM_INVALID:
  153     case EXT2_ET_EXT_ATTR_CSUM_INVALID:
  154     case EXT2_ET_SB_CSUM_INVALID:
  155     case EXT2_ET_BLOCK_BITMAP_CSUM_INVALID:
  156     case EXT2_ET_MMP_CSUM_INVALID:
  157         return "Invalid checksum";
  158     case EXT2_ET_UNKNOWN_CSUM:
  159         return "Unknown checksum";
  160     case EXT2_ET_FILE_EXISTS:
  161         return "File exists";
  162     case EXT2_ET_INODE_IS_GARBAGE:
  163         return "Inode is garbage";
  164     case EXT2_ET_JOURNAL_FLAGS_WRONG:
  165         return "Wrong journal flags";
  166     case EXT2_ET_FILESYSTEM_CORRUPTED:
  167         return "File system is corrupted";
  168     case EXT2_ET_BAD_CRC:
  169         return "Bad CRC";
  170     case EXT2_ET_CORRUPT_JOURNAL_SB:
  171         return "Journal Superblock is corrupted";
  172     case EXT2_ET_INODE_CORRUPTED:
  173     case EXT2_ET_EA_INODE_CORRUPTED:
  174         return "Inode is corrupted";
  175     default:
  176         if ((error_code > EXT2_ET_BASE) && error_code < (EXT2_ET_BASE + 1000)) {
  177             static_sprintf(error_string, "Unknown ext2fs error %ld (EXT2_ET_BASE + %ld)", error_code, error_code - EXT2_ET_BASE);
  178         } else {
  179             SetLastError((FormatStatus == 0) ? (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | (error_code & 0xFFFF)) : FormatStatus);
  180             static_sprintf(error_string, "%s", WindowsErrorString());
  181         }
  182         return error_string;
  183     }
  184 }
  185 
  186 errcode_t ext2fs_print_progress(int64_t cur_value, int64_t max_value)
  187 {
  188     static int64_t last_value = -1;
  189     if (max_value == 0)
  190         return 0;
  191     UpdateProgressWithInfo(OP_FORMAT, MSG_217, (uint64_t)((ext2_percent_start * max_value) + (ext2_percent_share * cur_value)), max_value);
  192     cur_value = (int64_t)(((float)cur_value / (float)max_value) * min(ext2_max_marker, (float)max_value));
  193     if (cur_value != last_value) {
  194         last_value = cur_value;
  195         uprintfs("+");
  196     }
  197     return IS_ERROR(FormatStatus) ? EXT2_ET_CANCEL_REQUESTED : 0;
  198 }
  199 
  200 const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset)
  201 {
  202     static char label[EXT2_LABEL_LEN + 1];
  203     errcode_t r;
  204     ext2_filsys ext2fs = NULL;
  205     io_manager manager = nt_io_manager();
  206     char* volume_name = GetExtPartitionName(DriveIndex, PartitionOffset);
  207 
  208     if (volume_name == NULL)
  209         return NULL;
  210     r = ext2fs_open(volume_name, EXT2_FLAG_SKIP_MMP, 0, 0, manager, &ext2fs);
  211     free(volume_name);
  212     if (r == 0) {
  213         strncpy(label, ext2fs->super->s_volume_name, EXT2_LABEL_LEN);
  214         label[EXT2_LABEL_LEN] = 0;
  215     }
  216     if (ext2fs != NULL)
  217         ext2fs_close(ext2fs);
  218     return (r == 0) ? label : NULL;
  219 }
  220 
  221 #define TEST_IMG_PATH               "\\??\\C:\\tmp\\disk.img"
  222 #define TEST_IMG_SIZE               4000        // Size in MB
  223 #define SET_EXT2_FORMAT_ERROR(x)    if (!IS_ERROR(FormatStatus)) FormatStatus = ext2_last_winerror(x)
  224 
  225 BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags)
  226 {
  227     // Mostly taken from mke2fs.conf
  228     const float reserve_ratio = 0.05f;
  229     const ext2fs_default_t ext2fs_default[5] = {
  230         { 3 * MB, 1024, 128, 3},    // "floppy"
  231         { 512 * MB, 1024, 128, 2},  // "small"
  232         { 4 * GB, 4096, 256, 2},    // "default"
  233         { 16 * GB, 4096, 256, 3},   // "big"
  234         { 1024 * TB, 4096, 256, 4}  // "huge"
  235     };
  236 
  237     BOOL ret = FALSE;
  238     char* volume_name = NULL;
  239     int i, count;
  240     struct ext2_super_block features = { 0 };
  241     io_manager manager = nt_io_manager();
  242     blk_t journal_size;
  243     blk64_t size = 0, cur;
  244     ext2_filsys ext2fs = NULL;
  245     errcode_t r;
  246     uint8_t* buf = NULL;
  247 
  248 #if defined(RUFUS_TEST)
  249     // Create a disk image file to test
  250     uint8_t zb[1024];
  251     HANDLE h;
  252     DWORD dwSize;
  253     HCRYPTPROV hCryptProv = 0;
  254     volume_name = strdup(TEST_IMG_PATH);
  255     uprintf("Creating '%s'...", volume_name);
  256     if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || !CryptGenRandom(hCryptProv, sizeof(zb), zb)) {
  257         uprintf("Failed to randomize buffer - filling with constant value");
  258         memset(zb, rand(), sizeof(zb));
  259     }
  260     CryptReleaseContext(hCryptProv, 0);
  261     h = CreateFileU(volume_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  262     for (i = 0; i < TEST_IMG_SIZE * sizeof(zb); i++) {
  263         if (!WriteFile(h, zb, sizeof(zb), &dwSize, NULL) || (dwSize != sizeof(zb))) {
  264             uprintf("Write error: %s", WindowsErrorString());
  265             break;
  266         }
  267     }
  268     CloseHandle(h);
  269 #else
  270     volume_name = GetExtPartitionName(DriveIndex, PartitionOffset);
  271 #endif
  272     if ((volume_name == NULL) | (strlen(FSName) != 4) || (strncmp(FSName, "ext", 3) != 0)) {
  273         FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER;
  274         goto out;
  275     }
  276     if (strchr(volume_name, ' ') != NULL)
  277         uprintf("Notice: Using physical device to access partition data");
  278 
  279     if ((strcmp(FSName, FileSystemLabel[FS_EXT2]) != 0) && (strcmp(FSName, FileSystemLabel[FS_EXT3]) != 0)) {
  280         if (strcmp(FSName, FileSystemLabel[FS_EXT4]) == 0)
  281             uprintf("ext4 file system is not supported, defaulting to ext3");
  282         else
  283             uprintf("Invalid ext file system version requested, defaulting to ext3");
  284         FSName = FileSystemLabel[FS_EXT3];
  285     }
  286 
  287     PrintInfoDebug(0, MSG_222, FSName);
  288     UpdateProgressWithInfoInit(NULL, TRUE);
  289 
  290     // Figure out the volume size and block size
  291     r = ext2fs_get_device_size2(volume_name, KB, &size);
  292     if ((r != 0) || (size == 0)) {
  293         SET_EXT2_FORMAT_ERROR(ERROR_READ_FAULT);
  294         uprintf("Could not read device size: %s", error_message(r));
  295         goto out;
  296     }
  297     size *= KB;
  298     for (i = 0; i < ARRAYSIZE(ext2fs_default); i++) {
  299         if (size < ext2fs_default[i].max_size)
  300             break;
  301     }
  302     assert(i < ARRAYSIZE(ext2fs_default));
  303     if ((BlockSize == 0) || (BlockSize < EXT2_MIN_BLOCK_SIZE))
  304         BlockSize = ext2fs_default[i].block_size;
  305     assert(IS_POWER_OF_2(BlockSize));
  306     for (features.s_log_block_size = 0; EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE; features.s_log_block_size++) {
  307         if (EXT2_BLOCK_SIZE(&features) == BlockSize)
  308             break;
  309     }
  310     assert(EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE);
  311     features.s_log_cluster_size = features.s_log_block_size;
  312     size /= BlockSize;
  313 
  314     // ext2 and ext3 have a can only accomodate up to Blocksize * 2^32 sized volumes
  315     if (((strcmp(FSName, FileSystemLabel[FS_EXT2]) == 0) || (strcmp(FSName, FileSystemLabel[FS_EXT3]) == 0)) &&
  316         (size >= 0x100000000ULL)) {
  317         SET_EXT2_FORMAT_ERROR(ERROR_INVALID_VOLUME_SIZE);
  318         uprintf("Volume size is too large for ext2 or ext3");
  319         goto out;
  320     }
  321 
  322     // Set the blocks, reserved blocks and inodes
  323     ext2fs_blocks_count_set(&features, size);
  324     ext2fs_r_blocks_count_set(&features, (blk64_t)(reserve_ratio * size));
  325     features.s_rev_level = 1;
  326     features.s_inode_size = ext2fs_default[i].inode_size;
  327     features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ?
  328         UINT32_MAX : (uint32_t)(ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio);
  329     uprintf("%d possible inodes out of %lld blocks (block size = %d)", features.s_inodes_count, size, EXT2_BLOCK_SIZE(&features));
  330     uprintf("%lld blocks (%0.1f%%) reserved for the super user", ext2fs_r_blocks_count(&features), reserve_ratio * 100.0f);
  331 
  332     // Set features
  333     ext2fs_set_feature_dir_index(&features);
  334     ext2fs_set_feature_filetype(&features);
  335     ext2fs_set_feature_large_file(&features);
  336     ext2fs_set_feature_sparse_super(&features);
  337     ext2fs_set_feature_xattr(&features);
  338     if (FSName[3] != '2')
  339         ext2fs_set_feature_journal(&features);
  340     features.s_default_mount_opts = EXT2_DEFM_XATTR_USER | EXT2_DEFM_ACL;
  341 
  342     // Now that we have set our base features, initialize a virtual superblock
  343     r = ext2fs_initialize(volume_name, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs);
  344     if (r != 0) {
  345         SET_EXT2_FORMAT_ERROR(ERROR_INVALID_DATA);
  346         uprintf("Could not initialize %s features: %s", FSName, error_message(r));
  347         goto out;
  348     }
  349 
  350     // Zero 16 blocks of data from the start of our volume
  351     buf = calloc(16, ext2fs->io->block_size);
  352     assert(buf != NULL);
  353     r = io_channel_write_blk64(ext2fs->io, 0, 16, buf);
  354     safe_free(buf);
  355     if (r != 0) {
  356         SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  357         uprintf("Could not zero %s superblock area: %s", FSName, error_message(r));
  358         goto out;
  359     }
  360 
  361     // Finish setting up the file system
  362     IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_uuid));
  363     ext2fs_init_csum_seed(ext2fs);
  364     ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4;
  365     IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_hash_seed));
  366     ext2fs->super->s_max_mnt_count = -1;
  367     ext2fs->super->s_creator_os = EXT2_OS_WINDOWS;
  368     ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE;
  369     if (Label != NULL)
  370         static_strcpy(ext2fs->super->s_volume_name, Label);
  371 
  372     r = ext2fs_allocate_tables(ext2fs);
  373     if (r != 0) {
  374         SET_EXT2_FORMAT_ERROR(ERROR_INVALID_DATA);
  375         uprintf("Could not allocate %s tables: %s", FSName, error_message(r));
  376         goto out;
  377     }
  378     r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map);
  379     if (r != 0) {
  380         uprintf("Could not set %s cluster bitmap: %s", FSName, error_message(r));
  381         goto out;
  382     }
  383 
  384     ext2_percent_start = 0.0f;
  385     ext2_percent_share = (FSName[3] == '2') ? 1.0f : 0.5f;
  386     uprintf("Creating %d inode sets: [1 marker = %0.1f set(s)]", ext2fs->group_desc_count,
  387         max((float)ext2fs->group_desc_count / ext2_max_marker, 1.0f));
  388     for (i = 0; i < (int)ext2fs->group_desc_count; i++) {
  389         if (ext2fs_print_progress((int64_t)i, (int64_t)ext2fs->group_desc_count))
  390             goto out;
  391         cur = ext2fs_inode_table_loc(ext2fs, i);
  392         count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i))
  393             * EXT2_INODE_SIZE(ext2fs->super), EXT2_BLOCK_SIZE(ext2fs->super));
  394         r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count);
  395         if (r != 0) {
  396             SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  397             uprintf("\r\nCould not zero inode set at position %llu (%d blocks): %s", cur, count, error_message(r));
  398             goto out;
  399         }
  400     }
  401     uprintfs("\r\n");
  402 
  403     // Create root and lost+found dirs
  404     r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
  405     if (r != 0) {
  406         SET_EXT2_FORMAT_ERROR(ERROR_DIR_NOT_ROOT);
  407         uprintf("Failed to create %s root dir: %s", FSName, error_message(r));
  408         goto out;
  409     }
  410     ext2fs->umask = 077;
  411     r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found");
  412     if (r != 0) {
  413         SET_EXT2_FORMAT_ERROR(ERROR_DIR_NOT_ROOT);
  414         uprintf("Failed to create %s 'lost+found' dir: %s", FSName, error_message(r));
  415         goto out;
  416     }
  417 
  418     // Create bitmaps
  419     for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++)
  420         ext2fs_inode_alloc_stats(ext2fs, i, 1);
  421     ext2fs_mark_ib_dirty(ext2fs);
  422 
  423     r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO);
  424     if (r != 0) {
  425         SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  426         uprintf("Could not set inode bitmaps: %s", error_message(r));
  427         goto out;
  428     }
  429     ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1);
  430     r = ext2fs_update_bb_inode(ext2fs, NULL);
  431     if (r != 0) {
  432         SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  433         uprintf("Could not set inode stats: %s", error_message(r));
  434         goto out;
  435     }
  436 
  437     if (FSName[3] != '2') {
  438         // Create the journal
  439         ext2_percent_start = 0.5f;
  440         journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super));
  441         journal_size /= 2;  // That journal init is really killing us!
  442         uprintf("Creating %d journal blocks: [1 marker = %0.1f block(s)]", journal_size,
  443             max((float)journal_size / ext2_max_marker, 1.0f));
  444         // Even with EXT2_MKJOURNAL_LAZYINIT, this call is absolutely dreadful in terms of speed...
  445         r = ext2fs_add_journal_inode(ext2fs, journal_size, EXT2_MKJOURNAL_NO_MNT_CHECK | ((Flags & FP_QUICK) ? EXT2_MKJOURNAL_LAZYINIT : 0));
  446         uprintfs("\r\n");
  447         if (r != 0) {
  448             SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  449             uprintf("Could not create %s journal: %s", FSName, error_message(r));
  450             goto out;
  451         }
  452     }
  453 
  454     // Create a 'persistence.conf' file if required
  455     if (Flags & FP_CREATE_PERSISTENCE_CONF) {
  456         // You *do* want the LF at the end of the "/ union" line, else Debian Live bails out...
  457         const char* name = "persistence.conf", data[] = "/ union\n";
  458         int written = 0, fsize = sizeof(data) - 1;
  459         ext2_file_t ext2fd;
  460         ext2_ino_t inode_id;
  461         uint32_t ctime = (uint32_t)time(0);
  462         struct ext2_inode inode = { 0 };
  463         inode.i_mode = 0100644;
  464         inode.i_links_count = 1;
  465         inode.i_atime = ctime;
  466         inode.i_ctime = ctime;
  467         inode.i_mtime = ctime;
  468         inode.i_size = fsize;
  469 
  470         ext2fs_namei(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &inode_id);
  471         ext2fs_new_inode(ext2fs, EXT2_ROOT_INO, 010755, 0, &inode_id);
  472         ext2fs_link(ext2fs, EXT2_ROOT_INO, name, inode_id, EXT2_FT_REG_FILE);
  473         ext2fs_inode_alloc_stats(ext2fs, inode_id, 1);
  474         ext2fs_write_new_inode(ext2fs, inode_id, &inode);
  475         ext2fs_file_open(ext2fs, inode_id, EXT2_FILE_WRITE, &ext2fd);
  476         if ((ext2fs_file_write(ext2fd, data, fsize, &written) != 0) || (written != fsize))
  477             uprintf("Error: Could not create '%s' file", name);
  478         else
  479             uprintf("Created '%s' file", name);
  480         ext2fs_file_close(ext2fd);
  481     }
  482 
  483     // Finally we can call close() to get the file system gets created
  484     r = ext2fs_close(ext2fs);
  485     if (r != 0) {
  486         SET_EXT2_FORMAT_ERROR(ERROR_WRITE_FAULT);
  487         uprintf("Could not create %s volume: %s", FSName, error_message(r));
  488         goto out;
  489     }
  490     UpdateProgressWithInfo(OP_FORMAT, MSG_217, 100, 100);
  491     uprintf("Done");
  492     ret = TRUE;
  493 
  494 out:
  495     free(volume_name);
  496     ext2fs_free(ext2fs);
  497     free(buf);
  498     return ret;
  499 }