VirtualBox

Changeset 66689 in vbox for trunk


Ignore:
Timestamp:
Apr 27, 2017 2:39:50 PM (7 years ago)
Author:
vboxsync
Message:

fatvfs: Added code for formatting a FAT volume.

Location:
trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/formats/fat.h

    r66676 r66689  
    5353#define FAT_ID_IS_VALID(a_bFatId) (   (uint8_t)(a_bFatId) >= 0xf8 \
    5454                                   || (uint8_t)(a_bFatId) == 0xf0 \
    55                                    || (uint8_t)(a_bMedia) == 0xf4 /* obscure - msdos 2.11 */ \
    56                                    || (uint8_t)(a_bMedia) == 0xf5 /* obscure - msdos 2.11 */ \
     55                                   || (uint8_t)(a_bFatId) == 0xf4 /* obscure - msdos 2.11 */ \
     56                                   || (uint8_t)(a_bFatId) == 0xf5 /* obscure - msdos 2.11 */ \
    5757                                   || (uint8_t)(a_bFatId) == 0xed /* obscure, tandy 2000 */ \
    5858                                   || (uint8_t)(a_bFatId) == 0xe5 /* obscure, tandy 2000 */ )
     
    503503 * @{ */
    504504#define FAT_FIRST_DATA_CLUSTER          2                       /**< The first data cluster. */
     505
     506#define FAT_MAX_FAT12_TOTAL_CLUSTERS    UINT32_C(0x00000ff6)    /**< Maximum number of clusters in a 12-bit FAT . */
     507#define FAT_MAX_FAT16_TOTAL_CLUSTERS    UINT32_C(0x0000fff6)    /**< Maximum number of clusters in a 16-bit FAT . */
     508#define FAT_MAX_FAT32_TOTAL_CLUSTERS    UINT32_C(0x0ffffff6)    /**< Maximum number of clusters in a 32-bit FAT . */
     509
    505510#define FAT_LAST_FAT12_DATA_CLUSTER     UINT32_C(0x00000ff5)    /**< The last possible data cluster for FAT12. */
    506511#define FAT_LAST_FAT16_DATA_CLUSTER     UINT32_C(0x0000fff5)    /**< The last possible data cluster for FAT16. */
    507512#define FAT_LAST_FAT32_DATA_CLUSTER     UINT32_C(0x0ffffff5)    /**< The last possible data cluster for FAT32. */
     513
     514#define FAT_MAX_FAT12_DATA_CLUSTERS     UINT32_C(0x00000ff4)    /**< Maximum number of data clusters for FAT12. */
     515#define FAT_MAX_FAT16_DATA_CLUSTERS     UINT32_C(0x0000fff4)    /**< Maximum number of data clusters for FAT16. */
     516#define FAT_MAX_FAT32_DATA_CLUSTERS     UINT32_C(0x0ffffff4)    /**< Maximum number of data clusters for FAT32. */
     517
     518#define FAT_MIN_FAT12_DATA_CLUSTERS     UINT32_C(0x00000001)    /**< Maximum number of data clusters for FAT12. */
     519#define FAT_MIN_FAT16_DATA_CLUSTERS     UINT32_C(0x00000ff5)    /**< Maximum number of data clusters for FAT16. */
     520#define FAT_MIN_FAT32_DATA_CLUSTERS     UINT32_C(0x0000fff5)    /**< Maximum number of data clusters for FAT32. */
    508521
    509522#define FAT_FIRST_FAT12_EOC             UINT32_C(0x00000ff8)    /**< The first end-of-file-cluster number for FAT12. */
  • trunk/include/iprt/mangling.h

    r66615 r66689  
    916916# define RTFsTypeName                                   RT_MANGLER(RTFsTypeName)
    917917# define RTFsFatVolOpen                                 RT_MANGLER(RTFsFatVolOpen)
     918# define RTFsFatVolFormat                               RT_MANGLER(RTFsFatVolFormat)
     919# define RTFsFatVolFormat144                            RT_MANGLER(RTFsFatVolFormat144)
    918920# define RTGetOpt                                       RT_MANGLER(RTGetOpt)
    919921# define RTGetOptArgvFree                               RT_MANGLER(RTGetOptArgvFree)
  • trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp

    r66676 r66689  
    3030*********************************************************************************************************************************/
    3131#include "internal/iprt.h"
    32 #include <iprt/fs.h>
     32#include <iprt/fsvfs.h>
    3333
    3434#include <iprt/asm.h>
     
    3939#include <iprt/mem.h>
    4040#include <iprt/poll.h>
     41#include <iprt/rand.h>
    4142#include <iprt/string.h>
    4243#include <iprt/sg.h>
     
    4546#include <iprt/vfs.h>
    4647#include <iprt/vfslowlevel.h>
     48#include <iprt/zero.h>
    4749#include <iprt/formats/fat.h>
    4850
     
    263265/** Pointer to a FAT linear metadata cache. */
    264266typedef RTFSFATCLUSTERMAPCACHE *PRTFSFATCLUSTERMAPCACHE;
    265 
    266 
    267 /**
    268  * FAT type (format).
    269  */
    270 typedef enum RTFSFATTYPE
    271 {
    272     RTFSFATTYPE_INVALID = 0,
    273     RTFSFATTYPE_FAT12,
    274     RTFSFATTYPE_FAT16,
    275     RTFSFATTYPE_FAT32,
    276     RTFSFATTYPE_END
    277 } RTFSFATTYPE;
    278267
    279268
     
    36053594    pThis->cClusters = (pThis->cbTotalSize - cbSystemStuff) / pThis->cbCluster;
    36063595
    3607     if (pThis->cClusters >= FAT_LAST_FAT16_DATA_CLUSTER)
    3608     {
    3609         pThis->cClusters  = FAT_LAST_FAT16_DATA_CLUSTER + 1;
     3596    if (pThis->cClusters >= FAT_MAX_FAT16_DATA_CLUSTERS)
     3597    {
     3598        pThis->cClusters  = FAT_MAX_FAT16_DATA_CLUSTERS;
    36103599        pThis->enmFatType = RTFSFATTYPE_FAT16;
    36113600    }
    3612     else if (pThis->cClusters > FAT_LAST_FAT12_DATA_CLUSTER)
     3601    else if (pThis->cClusters >= FAT_MIN_FAT16_DATA_CLUSTERS)
    36133602        pThis->enmFatType = RTFSFATTYPE_FAT16;
    36143603    else
     
    37203709        uint64_t cbFat = pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32 * (uint64_t)pThis->cbSector;
    37213710        if (   cbFat == 0
    3722             || cbFat >= (FAT_LAST_FAT32_DATA_CLUSTER + 1) * 4 + pThis->cbSector * 16)
     3711            || cbFat >= FAT_MAX_FAT32_TOTAL_CLUSTERS * 4 + pThis->cbSector * 16)
    37233712            return RTErrInfoSetF(pErrInfo, VERR_VFS_BOGUS_FORMAT,
    37243713                                 "Bogus 32-bit FAT size: %#RX32", pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32);
     
    37413730
    37423731    uint64_t cClusters = (pThis->cbTotalSize - (pThis->offFirstCluster - pThis->offBootSector)) / pThis->cbCluster;
    3743     if (cClusters <= FAT_LAST_FAT32_DATA_CLUSTER)
     3732    if (cClusters <= FAT_MAX_FAT32_DATA_CLUSTERS)
    37443733        pThis->cClusters = (uint32_t)cClusters;
    37453734    else
    3746         pThis->cClusters = FAT_LAST_FAT32_DATA_CLUSTER + 1;
    3747     if (pThis->cClusters > pThis->cbFat / 4)
    3748         pThis->cClusters = pThis->cbFat / 4;
     3735        pThis->cClusters = FAT_MAX_FAT32_DATA_CLUSTERS;
     3736    if (pThis->cClusters > (pThis->cbFat / 4 - FAT_FIRST_DATA_CLUSTER))
     3737        pThis->cClusters = (pThis->cbFat / 4 - FAT_FIRST_DATA_CLUSTER);
    37493738
    37503739    /*
     
    41394128
    41404129
     4130/**
     4131 * Opens a FAT file system volume.
     4132 *
     4133 * @returns IPRT status code.
     4134 * @param   hVfsFileIn      The file or device backing the volume.
     4135 * @param   fReadOnly       Whether to mount it read-only.
     4136 * @param   offBootSector   The offset of the boot sector relative to the start
     4137 *                          of @a hVfsFileIn.  Pass 0 for floppies.
     4138 * @param   phVfs           Where to return the virtual file system handle.
     4139 * @param   pErrInfo        Where to return additional error information.
     4140 */
    41414141RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, uint64_t offBootSector, PRTVFS phVfs, PRTERRINFO pErrInfo)
    41424142{
     
    41674167        RTVfsFileRelease(hVfsFileIn);
    41684168    return rc;
     4169}
     4170
     4171
     4172
     4173
     4174/**
     4175 * Fills a range in the file with zeros in the most efficient manner.
     4176 *
     4177 * @returns IPRT status code.
     4178 * @param   hVfsFile            The file to write to.
     4179 * @param   off                 Where to start filling with zeros.
     4180 * @param   cbZeros             How many zero blocks to write.
     4181 */
     4182static int rtFsFatVolWriteZeros(RTVFSFILE hVfsFile, uint64_t off, uint32_t cbZeros)
     4183{
     4184    while (cbZeros > 0)
     4185    {
     4186        uint32_t cbToWrite = sizeof(g_abRTZero64K);
     4187        if (cbToWrite > cbZeros)
     4188            cbToWrite = cbZeros;
     4189        int rc = RTVfsFileWriteAt(hVfsFile, off, g_abRTZero64K, cbToWrite, NULL);
     4190        if (RT_FAILURE(rc))
     4191            return rc;
     4192        off     += cbToWrite;
     4193        cbZeros -= cbToWrite;
     4194    }
     4195    return VINF_SUCCESS;
     4196}
     4197
     4198
     4199/**
     4200 * Formats a FAT volume.
     4201 *
     4202 * @returns IRPT status code.
     4203 * @param   hVfsFile            The volume file.
     4204 * @param   offVol              The offset into @a hVfsFile of the file.
     4205 *                              Typically 0.
     4206 * @param   cbVol               The size of the volume.  Pass 0 if the rest of
     4207 *                              hVfsFile should be used.
     4208 * @param   fFlags              See RTFSFATVOL_FMT_F_XXX.
     4209 * @param   cbSector            The logical sector size.  Must be power of two.
     4210 *                              Optional, pass zero to use 512.
     4211 * @param   cSectorsPerCluster  Number of sectors per cluster.  Power of two.
     4212 *                              Optional, pass zero to auto detect.
     4213 * @param   enmFatType          The FAT type (12, 16, 32) to use.
     4214 *                              Optional, pass RTFSFATTYPE_INVALID for default.
     4215 * @param   cHeads              The number of heads to report in the BPB.
     4216 *                              Optional, pass zero to auto detect.
     4217 * @param   cSectorsPerTrack    The number of sectors per track to put in the
     4218 *                              BPB. Optional, pass zero to auto detect.
     4219 * @param   bMedia              The media byte value and FAT ID to use.
     4220 *                              Optional, pass zero to auto detect.
     4221 * @param   cRootDirEntries     Number of root directory entries.
     4222 *                              Optional, pass zero to auto detect.
     4223 * @param   cHiddenSectors      Number of hidden sectors.  Pass 0 for
     4224 *                              unpartitioned media.
     4225 * @param   pErrInfo            Additional error information, maybe.  Optional.
     4226 */
     4227RTDECL(int) RTFsFatVolFormat(RTVFSFILE hVfsFile, uint64_t offVol, uint64_t cbVol, uint32_t fFlags, uint16_t cbSector,
     4228                             uint16_t cSectorsPerCluster, RTFSFATTYPE enmFatType, uint32_t cHeads, uint32_t cSectorsPerTrack,
     4229                             uint8_t bMedia, uint16_t cRootDirEntries, uint32_t cHiddenSectors, PRTERRINFO pErrInfo)
     4230{
     4231    int         rc;
     4232    uint32_t    cFats = 2;
     4233
     4234    /*
     4235     * Validate input.
     4236     */
     4237    if (!cbSector)
     4238        cbSector = 512;
     4239    else
     4240        AssertMsgReturn(   cbSector == 128
     4241                        || cbSector == 512
     4242                        || cbSector == 1024
     4243                        || cbSector == 4096,
     4244                        ("cbSector=%#x\n", cbSector),
     4245                        VERR_INVALID_PARAMETER);
     4246    AssertMsgReturn(cSectorsPerCluster == 0 || (cSectorsPerCluster <= 128 && RT_IS_POWER_OF_TWO(cSectorsPerCluster)),
     4247                    ("cSectorsPerCluster=%#x\n", cSectorsPerCluster), VERR_INVALID_PARAMETER);
     4248    AssertMsgReturn(bMedia == 0 || (FAT_ID_IS_VALID(bMedia) && FATBPB_MEDIA_IS_VALID(bMedia)),
     4249                    ("bMedia=%#x\n"), VERR_INVALID_PARAMETER);
     4250    AssertReturn(!(fFlags & ~RTFSFATVOL_FMT_F_VALID_MASK), VERR_INVALID_FLAGS);
     4251    AssertReturn(enmFatType >= RTFSFATTYPE_INVALID && enmFatType < RTFSFATTYPE_END, VERR_INVALID_PARAMETER);
     4252
     4253    if (!cbVol)
     4254    {
     4255        uint64_t cbFile;
     4256        rc = RTVfsFileGetSize(hVfsFile, &cbFile);
     4257        AssertRCReturn(rc, rc);
     4258        AssertMsgReturn(cbFile > offVol, ("cbFile=%#RX64 offVol=%#RX64\n", cbFile, offVol), VERR_INVALID_PARAMETER);
     4259        cbVol = cbFile - offVol;
     4260    }
     4261    uint64_t const cSectorsInVol = cbVol / cbSector;
     4262
     4263    /*
     4264     * Guess defaults if necessary.
     4265     */
     4266    if (!cSectorsPerCluster || !cHeads || !cSectorsPerTrack || !bMedia || !cRootDirEntries)
     4267    {
     4268        static struct
     4269        {
     4270            uint64_t    cbVol;
     4271            uint8_t     bMedia;
     4272            uint8_t     cHeads;
     4273            uint8_t     cSectorsPerTrack;
     4274            uint8_t     cSectorsPerCluster;
     4275            uint16_t    cRootDirEntries;
     4276        } s_aDefaults[] =
     4277        {
     4278            /*                  cbVol, bMedia,              cHeads, cSectorsPTrk, cSectorsPClstr, cRootDirEntries */
     4279            {                 163840,    0xfe, /* cyl:   40,*/   1,          8,                1,           64 },
     4280            {                 184320,    0xfc, /* cyl:   40,*/   1,          9,                2,           64 },
     4281            {                 327680,    0xff, /* cyl:   40,*/   2,          8,                2,          112 },
     4282            {                 368640,    0xfd, /* cyl:   40,*/   2,          9,                2,          112 },
     4283            {                 737280,    0xf9, /* cyl:   80,*/   2,          9,                2,          112 },
     4284            {                1228800,    0xf9, /* cyl:   80,*/   2,         15,                2,          112 },
     4285            {                1474560,    0xf0, /* cyl:   80,*/   2,         18,                1,          224 },
     4286            {                2949120,    0xf0, /* cyl:   80,*/   2,         36,                2,          224 },
     4287            {              528482304,    0xf8, /* cyl: 1024,*/  16,         63,                0,          512 }, // 504MB limit
     4288            {   UINT64_C(7927234560),    0xf8, /* cyl: 1024,*/ 240,         63,                0,          512 }, // 7.3GB limit
     4289            {   UINT64_C(8422686720),    0xf8, /* cyl: 1024,*/ 255,         63,                0,          512 }, // 7.84GB limit
     4290
     4291        };
     4292        uint32_t iDefault = 0;
     4293        while (   iDefault < RT_ELEMENTS(s_aDefaults) - 1U
     4294               && cbVol > s_aDefaults[iDefault].cbVol)
     4295            iDefault++;
     4296        if (!cHeads)
     4297            cHeads              = s_aDefaults[iDefault].cHeads;
     4298        if (!cSectorsPerTrack)
     4299            cSectorsPerTrack    = s_aDefaults[iDefault].cSectorsPerTrack;
     4300        if (!bMedia)
     4301            bMedia              = s_aDefaults[iDefault].bMedia;
     4302        if (!cRootDirEntries)
     4303            cRootDirEntries     = s_aDefaults[iDefault].cRootDirEntries;
     4304        if (!cSectorsPerCluster)
     4305        {
     4306            cSectorsPerCluster  = s_aDefaults[iDefault].cSectorsPerCluster;
     4307            if (!cSectorsPerCluster)
     4308            {
     4309                uint32_t cbFat12Overhead = cbSector  /* boot sector */
     4310                                         + RT_ALIGN_32(FAT_MAX_FAT12_TOTAL_CLUSTERS * 3 / 2, cbSector) * cFats /* FATs */
     4311                                         + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */;
     4312                uint32_t cbFat16Overhead = cbSector  /* boot sector */
     4313                                         + RT_ALIGN_32(FAT_MAX_FAT16_TOTAL_CLUSTERS * 2, cbSector) * cFats /* FATs */
     4314                                         + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */;
     4315
     4316                if (   enmFatType == RTFSFATTYPE_FAT12
     4317                    || cbVol <= cbFat12Overhead + FAT_MAX_FAT12_DATA_CLUSTERS * 4 * cbSector)
     4318                {
     4319                    enmFatType = RTFSFATTYPE_FAT12;
     4320                    cSectorsPerCluster = 1;
     4321                    while (   cSectorsPerCluster < 128
     4322                           &&   cSectorsInVol
     4323                              >   cbFat12Overhead / cbSector
     4324                                + (uint32_t)cSectorsPerCluster * FAT_MAX_FAT12_DATA_CLUSTERS
     4325                                + cSectorsPerCluster - 1)
     4326                        cSectorsPerCluster <<= 1;
     4327                }
     4328                else if (   enmFatType == RTFSFATTYPE_FAT16
     4329                         || cbVol <= cbFat16Overhead + FAT_MAX_FAT16_DATA_CLUSTERS * 128 * cbSector)
     4330                {
     4331                    enmFatType = RTFSFATTYPE_FAT16;
     4332                    cSectorsPerCluster = 1;
     4333                    while (   cSectorsPerCluster < 128
     4334                           &&   cSectorsInVol
     4335                              >   cbFat12Overhead / cbSector
     4336                                + (uint32_t)cSectorsPerCluster * FAT_MAX_FAT16_DATA_CLUSTERS
     4337                                + cSectorsPerCluster - 1)
     4338                        cSectorsPerCluster <<= 1;
     4339                }
     4340                else
     4341                {
     4342                    /* The target here is keeping the FAT size below 8MB.  Seems windows
     4343                       likes a minimum 4KB cluster size as wells as a max of 32KB (googling). */
     4344                    enmFatType = RTFSFATTYPE_FAT32;
     4345                    uint32_t cbFat32Overhead = cbSector * 32 /* boot sector, info sector, boot sector copies, reserved sectors */
     4346                                             + _8M * cFats;
     4347                    if (cbSector >= _4K)
     4348                        cSectorsPerCluster = 1;
     4349                    else
     4350                        cSectorsPerCluster = _4K / cbSector;
     4351                    while (   cSectorsPerCluster < 128
     4352                           && cSectorsPerCluster * cbSector < _32K
     4353                           && cSectorsInVol > cbFat32Overhead / cbSector + (uint64_t)cSectorsPerCluster * _2M)
     4354                        cSectorsPerCluster <<= 1;
     4355                }
     4356            }
     4357        }
     4358    }
     4359    Assert(cSectorsPerCluster);
     4360    Assert(cRootDirEntries);
     4361    uint32_t       cbRootDir    = RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector);
     4362    uint32_t const cbCluster    = cSectorsPerCluster * cbSector;
     4363
     4364    /*
     4365     * If we haven't figured out the FAT type yet, do so.
     4366     * The file system code determins the FAT based on cluster counts,
     4367     * so we must do so here too.
     4368     */
     4369    if (enmFatType == RTFSFATTYPE_INVALID)
     4370    {
     4371        uint32_t cbFat12Overhead = cbSector  /* boot sector */
     4372                                 + RT_ALIGN_32(FAT_MAX_FAT12_TOTAL_CLUSTERS * 3 / 2, cbSector) * cFats /* FATs */
     4373                                 + RT_ALIGN_32(cRootDirEntries * sizeof(FATDIRENTRY), cbSector) /* root dir */;
     4374        if (   cbVol <= cbFat12Overhead + cbCluster
     4375            || (cbVol - cbFat12Overhead) / cbCluster <= FAT_MAX_FAT12_DATA_CLUSTERS)
     4376            enmFatType = RTFSFATTYPE_FAT12;
     4377        else
     4378        {
     4379            uint32_t cbFat16Overhead = cbSector  /* boot sector */
     4380                                     + RT_ALIGN_32(FAT_MAX_FAT16_TOTAL_CLUSTERS * 2, cbSector) * cFats /* FATs */
     4381                                     + cbRootDir;
     4382            if (   cbVol <= cbFat16Overhead + cbCluster
     4383                || (cbVol - cbFat16Overhead) / cbCluster <= FAT_MAX_FAT16_DATA_CLUSTERS)
     4384                enmFatType = RTFSFATTYPE_FAT16;
     4385            else
     4386                enmFatType = RTFSFATTYPE_FAT32;
     4387        }
     4388    }
     4389    if (enmFatType == RTFSFATTYPE_FAT32)
     4390        cbRootDir = cbCluster;
     4391
     4392    /*
     4393     * Calculate the FAT size and number of data cluster.
     4394     *
     4395     * Since the FAT size depends on how many data clusters there are, we start
     4396     * with a minimum FAT size and maximum clust count, then recalucate it. The
     4397     * result isn't necessarily stable, so we will only retry stabalizing the
     4398     * result a few times.
     4399     */
     4400    uint32_t cbReservedFixed = enmFatType == RTFSFATTYPE_FAT32 ? 32 * cbSector : cbSector + cbRootDir;
     4401    uint32_t cbFat           = cbSector;
     4402    if (cbReservedFixed + cbFat * cFats >= cbVol)
     4403        return RTErrInfoSetF(pErrInfo, VERR_DISK_FULL, "volume is too small (cbVol=%#RX64 rsvd=%#x cbFat=%#x cFat=%#x)",
     4404                             cbVol, cbReservedFixed, cbFat, cFats);
     4405    uint32_t cMaxClusters    = enmFatType == RTFSFATTYPE_FAT12 ? FAT_MAX_FAT12_DATA_CLUSTERS
     4406                             : enmFatType == RTFSFATTYPE_FAT16 ? FAT_MAX_FAT16_DATA_CLUSTERS
     4407                             :                                   FAT_MAX_FAT12_DATA_CLUSTERS;
     4408    uint32_t cClusters       = (uint32_t)RT_MIN((cbVol - cbReservedFixed - cbFat * cFats) / cbCluster, cMaxClusters);
     4409    uint32_t cPrevClusters;
     4410    uint32_t cTries          = 4;
     4411    do
     4412    {
     4413        cPrevClusters = cClusters;
     4414        switch (enmFatType)
     4415        {
     4416            case RTFSFATTYPE_FAT12:
     4417                cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT12_TOTAL_CLUSTERS, cClusters) * 3 / 2;
     4418                break;
     4419            case RTFSFATTYPE_FAT16:
     4420                cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT16_TOTAL_CLUSTERS, cClusters) * 2;
     4421                break;
     4422            case RTFSFATTYPE_FAT32:
     4423                cbFat = (uint32_t)RT_MIN(FAT_MAX_FAT32_TOTAL_CLUSTERS, cClusters) * 4;
     4424                cbFat = RT_ALIGN_32(cbFat, _4K);
     4425                break;
     4426            default:
     4427                AssertFailedReturn(VERR_INTERNAL_ERROR_2);
     4428        }
     4429        cbFat = RT_ALIGN_32(cbFat, cbSector);
     4430        if (cbReservedFixed + cbFat * cFats >= cbVol)
     4431            return RTErrInfoSetF(pErrInfo, VERR_DISK_FULL, "volume is too small (cbVol=%#RX64 rsvd=%#x cbFat=%#x cFat=%#x)",
     4432                                 cbVol, cbReservedFixed, cbFat, cFats);
     4433        cClusters = (uint32_t)RT_MIN((cbVol - cbReservedFixed - cbFat * cFats) / cbCluster, cMaxClusters);
     4434    } while (   cClusters != cPrevClusters
     4435             && cTries-- > 0);
     4436    uint64_t const cTotalSectors = cClusters * (uint64_t)cSectorsPerCluster + (cbReservedFixed + cbFat * cFats) / cbSector;
     4437
     4438    /*
     4439     * Check that the file system type and cluster count matches up.  If they
     4440     * don't the type will be misdetected.
     4441     *
     4442     * Note! These assertions could trigger if the above calculations are wrong.
     4443     */
     4444    switch (enmFatType)
     4445    {
     4446        case RTFSFATTYPE_FAT12:
     4447            AssertMsgReturn(cClusters >= FAT_MIN_FAT12_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT12_DATA_CLUSTERS,
     4448                            ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE);
     4449            break;
     4450        case RTFSFATTYPE_FAT16:
     4451            AssertMsgReturn(cClusters >= FAT_MIN_FAT16_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT16_DATA_CLUSTERS,
     4452                            ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE);
     4453            break;
     4454        case RTFSFATTYPE_FAT32:
     4455            AssertMsgReturn(cClusters >= FAT_MIN_FAT32_DATA_CLUSTERS && cClusters <= FAT_MAX_FAT32_DATA_CLUSTERS,
     4456                            ("cClusters=%#x\n", cClusters), VERR_OUT_OF_RANGE);
     4457        default:
     4458            AssertFailedReturn(VERR_INTERNAL_ERROR_2);
     4459    }
     4460
     4461    /*
     4462     * Okay, create the boot sector.
     4463     */
     4464    size_t   cbBuf = RT_MAX(RT_MAX(_64K, cbCluster), cbSector * 2U);
     4465    uint8_t *pbBuf = (uint8_t *)RTMemTmpAllocZ(cbBuf);
     4466    AssertReturn(pbBuf, VERR_NO_TMP_MEMORY);
     4467
     4468    const char *pszLastOp = "boot sector";
     4469    PFATBOOTSECTOR pBootSector = (PFATBOOTSECTOR)pbBuf;
     4470    pBootSector->abJmp[0] = 0xeb;
     4471    pBootSector->abJmp[1] = RT_UOFFSETOF(FATBOOTSECTOR, Bpb)
     4472                          + (enmFatType == RTFSFATTYPE_FAT32 ? sizeof(FAT32EBPB) : sizeof(FATEBPB)) - 2;
     4473    pBootSector->abJmp[2] = 0x90;
     4474    memcpy(pBootSector->achOemName, enmFatType == RTFSFATTYPE_FAT32 ? "FAT32   " : "IPRT 6.2", sizeof(pBootSector->achOemName));
     4475    pBootSector->Bpb.Bpb331.cbSector            = (uint16_t)cbSector;
     4476    pBootSector->Bpb.Bpb331.cSectorsPerCluster  = (uint8_t)cSectorsPerCluster;
     4477    pBootSector->Bpb.Bpb331.cReservedSectors    = enmFatType == RTFSFATTYPE_FAT32 ? cbReservedFixed / cbSector : 1;
     4478    pBootSector->Bpb.Bpb331.cFats               = (uint8_t)cFats;
     4479    pBootSector->Bpb.Bpb331.cMaxRootDirEntries  = enmFatType == RTFSFATTYPE_FAT32 ?  0 : cRootDirEntries;
     4480    pBootSector->Bpb.Bpb331.cTotalSectors16     = cTotalSectors <= UINT16_MAX     ? (uint16_t)cTotalSectors : 0;
     4481    pBootSector->Bpb.Bpb331.bMedia              = bMedia;
     4482    pBootSector->Bpb.Bpb331.cSectorsPerFat      = enmFatType == RTFSFATTYPE_FAT32 ?  0 : cbFat / cbSector;
     4483    pBootSector->Bpb.Bpb331.cSectorsPerTrack    = cSectorsPerTrack;
     4484    pBootSector->Bpb.Bpb331.cTracksPerCylinder  = cHeads;
     4485    pBootSector->Bpb.Bpb331.cHiddenSectors      = cHiddenSectors;
     4486    pBootSector->Bpb.Bpb331.cTotalSectors32     = cTotalSectors <= UINT32_MAX     ? (uint32_t)cTotalSectors : 0;
     4487    if (enmFatType != RTFSFATTYPE_FAT32)
     4488    {
     4489        pBootSector->Bpb.Ebpb.bInt13Drive       = 0;
     4490        pBootSector->Bpb.Ebpb.bReserved         = 0;
     4491        pBootSector->Bpb.Ebpb.bExtSignature     = FATEBPB_SIGNATURE;
     4492        pBootSector->Bpb.Ebpb.uSerialNumber     = RTRandU32();
     4493        memset(pBootSector->Bpb.Ebpb.achLabel, ' ',  sizeof(pBootSector->Bpb.Ebpb.achLabel));
     4494        memcpy(pBootSector->Bpb.Ebpb.achType, enmFatType == RTFSFATTYPE_FAT12 ? "FAT12   " : "FAT16   ",
     4495               sizeof(pBootSector->Bpb.Ebpb.achType));
     4496    }
     4497    else
     4498    {
     4499        pBootSector->Bpb.Fat32Ebpb.cSectorsPerFat32         = cbFat / cbSector;
     4500        pBootSector->Bpb.Fat32Ebpb.fFlags                   = 0;
     4501        pBootSector->Bpb.Fat32Ebpb.uVersion                 = FAT32EBPB_VERSION_0_0;
     4502        pBootSector->Bpb.Fat32Ebpb.uRootDirCluster          = FAT_FIRST_DATA_CLUSTER;
     4503        pBootSector->Bpb.Fat32Ebpb.uInfoSectorNo            = 1;
     4504        pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo  = 6;
     4505        RT_ZERO(pBootSector->Bpb.Fat32Ebpb.abReserved);
     4506
     4507        pBootSector->Bpb.Fat32Ebpb.bInt13Drive   = 0;
     4508        pBootSector->Bpb.Fat32Ebpb.bReserved     = 0;
     4509        pBootSector->Bpb.Fat32Ebpb.bExtSignature = FATEBPB_SIGNATURE;
     4510        pBootSector->Bpb.Fat32Ebpb.uSerialNumber = RTRandU32();
     4511        memset(pBootSector->Bpb.Fat32Ebpb.achLabel, ' ',  sizeof(pBootSector->Bpb.Fat32Ebpb.achLabel));
     4512        if (cTotalSectors > UINT32_MAX)
     4513            pBootSector->Bpb.Fat32Ebpb.u.cTotalSectors64 = cTotalSectors;
     4514        else
     4515            memcpy(pBootSector->Bpb.Fat32Ebpb.u.achType, "FAT32   ", sizeof(pBootSector->Bpb.Fat32Ebpb.u.achType));
     4516    }
     4517    pbBuf[pBootSector->abJmp[1] + 2 + 0] = 0xcd; /* int 19h */
     4518    pbBuf[pBootSector->abJmp[1] + 2 + 1] = 0x19;
     4519    pbBuf[pBootSector->abJmp[1] + 2 + 2] = 0xcc; /* int3 */
     4520    pbBuf[pBootSector->abJmp[1] + 2 + 3] = 0xcc;
     4521
     4522    pBootSector->uSignature = FATBOOTSECTOR_SIGNATURE;
     4523    if (cbSector != sizeof(*pBootSector))
     4524        *(uint16_t *)&pbBuf[cbSector - 2] = FATBOOTSECTOR_SIGNATURE; /** @todo figure out how disks with non-512 byte sectors work! */
     4525
     4526    rc = RTVfsFileWriteAt(hVfsFile, offVol, pBootSector, cbSector, NULL);
     4527    uint32_t const offFirstFat = pBootSector->Bpb.Bpb331.cReservedSectors * cbSector;
     4528
     4529    /*
     4530     * Write the FAT32 info sector, 3 boot sector copies, and zero fill
     4531     * the other reserved sectors.
     4532     */
     4533    if (RT_SUCCESS(rc) && enmFatType == RTFSFATTYPE_FAT32)
     4534    {
     4535        pszLastOp = "fat32 info sector";
     4536        PFAT32INFOSECTOR pInfoSector = (PFAT32INFOSECTOR)&pbBuf[cbSector]; /* preserve the boot sector. */
     4537        RT_ZERO(*pInfoSector);
     4538        pInfoSector->uSignature1           = FAT32INFOSECTOR_SIGNATURE_1;
     4539        pInfoSector->uSignature2           = FAT32INFOSECTOR_SIGNATURE_2;
     4540        pInfoSector->uSignature3           = FAT32INFOSECTOR_SIGNATURE_3;
     4541        pInfoSector->cFreeClusters         = cClusters - 1; /* ASSUMES 1 cluster for the root dir. */
     4542        pInfoSector->cLastAllocatedCluster = FAT_FIRST_DATA_CLUSTER;
     4543        rc = RTVfsFileWriteAt(hVfsFile, offVol + cbSector, pInfoSector, cbSector, NULL);
     4544
     4545        uint32_t iSector = 2;
     4546        if (RT_SUCCESS(rc))
     4547        {
     4548            pszLastOp = "fat32 unused reserved sectors";
     4549            rc = rtFsFatVolWriteZeros(hVfsFile, offVol + iSector * cbSector,
     4550                                      (pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo - iSector) * cbSector);
     4551            iSector = pBootSector->Bpb.Fat32Ebpb.uBootSectorCopySectorNo;
     4552        }
     4553
     4554        if (RT_SUCCESS(rc))
     4555        {
     4556            pszLastOp = "boot sector copy";
     4557            for (uint32_t i = 0; i < 3 && RT_SUCCESS(rc); i++, iSector++)
     4558                rc = RTVfsFileWriteAt(hVfsFile, offVol + iSector * cbSector, pBootSector, cbSector, NULL);
     4559        }
     4560
     4561        if (RT_SUCCESS(rc))
     4562        {
     4563            pszLastOp = "fat32 unused reserved sectors";
     4564            rc = rtFsFatVolWriteZeros(hVfsFile, offVol + iSector * cbSector,
     4565                                      (pBootSector->Bpb.Bpb331.cReservedSectors - iSector) * cbSector);
     4566        }
     4567    }
     4568
     4569    /*
     4570     * The FATs.
     4571     */
     4572    if (RT_SUCCESS(rc))
     4573    {
     4574        pszLastOp = "fat";
     4575        pBootSector = NULL; /* invalid  */
     4576        RT_BZERO(pbBuf, cbSector);
     4577        switch (enmFatType)
     4578        {
     4579            case RTFSFATTYPE_FAT32:
     4580                pbBuf[11] = 0x0f;       /* EOC for root dir*/
     4581                pbBuf[10] = 0xff;
     4582                pbBuf[9]  = 0xff;
     4583                pbBuf[8]  = 0xff;
     4584                pbBuf[7]  = 0x0f;       /* Formatter's EOC, followed by signed extend FAT ID. */
     4585                pbBuf[6]  = 0xff;
     4586                pbBuf[5]  = 0xff;
     4587                pbBuf[4]  = 0xff;
     4588                /* fall thru */
     4589            case RTFSFATTYPE_FAT16:
     4590                pbBuf[3]  = 0xff;
     4591                /* fall thru */
     4592            case RTFSFATTYPE_FAT12:
     4593                pbBuf[2]  = 0xff;
     4594                pbBuf[1]  = 0xff;
     4595                pbBuf[0]  = bMedia;     /* FAT ID */
     4596                break;
     4597            default: AssertFailed();
     4598        }
     4599        for (uint32_t iFatCopy = 0; iFatCopy < cFats && RT_SUCCESS(rc); iFatCopy++)
     4600        {
     4601            rc = RTVfsFileWriteAt(hVfsFile, offVol + offFirstFat + cbFat * iFatCopy, pbBuf, cbSector, NULL);
     4602            if (RT_SUCCESS(rc) && cbFat > cbSector)
     4603                rc = rtFsFatVolWriteZeros(hVfsFile, offVol + offFirstFat + cbFat * iFatCopy + cbSector, cbFat - cbSector);
     4604        }
     4605    }
     4606
     4607    /*
     4608     * The root directory.
     4609     */
     4610    if (RT_SUCCESS(rc))
     4611    {
     4612        /** @todo any mandatory directory entries we need to fill in here? */
     4613        pszLastOp = "root dir";
     4614        rc = rtFsFatVolWriteZeros(hVfsFile, offVol + offFirstFat + cbFat * cFats, cbRootDir);
     4615    }
     4616
     4617    /*
     4618     * If long format, fill the rest of the disk with 0xf6.
     4619     */
     4620    AssertCompile(RTFSFATVOL_FMT_F_QUICK != 0);
     4621    if (RT_SUCCESS(rc) && !(fFlags & RTFSFATVOL_FMT_F_QUICK))
     4622    {
     4623        pszLastOp = "formatting data clusters";
     4624        uint64_t offCur = offFirstFat + cbFat * cFats + cbRootDir;
     4625        uint64_t cbLeft = cTotalSectors * cbSector;
     4626        if (cbLeft > offCur)
     4627        {
     4628            cbLeft -= offCur;
     4629            offCur += offVol;
     4630
     4631            memset(pbBuf, 0xf6, cbBuf);
     4632            while (cbLeft > 0)
     4633            {
     4634                size_t cbToWrite = cbLeft >= cbBuf ? cbBuf : (size_t)cbLeft;
     4635                rc = RTVfsFileWriteAt(hVfsFile, offCur, pbBuf, cbToWrite, NULL);
     4636                if (RT_SUCCESS(rc))
     4637                {
     4638                    offCur += cbToWrite;
     4639                    cbLeft -= cbToWrite;
     4640                }
     4641                else
     4642                    break;
     4643            }
     4644        }
     4645    }
     4646
     4647    /*
     4648     * Done.
     4649     */
     4650    RTMemTmpFree(pbBuf);
     4651    if (RT_SUCCESS(rc))
     4652        return rc;
     4653    return RTErrInfoSet(pErrInfo, rc, pszLastOp);
     4654}
     4655
     4656
     4657/**
     4658 * Formats a 1.44MB floppy image.
     4659 *
     4660 * @returns IPRT status code.
     4661 * @param   hVfsFile            The image.
     4662 */
     4663RTDECL(int) RTFsFatVolFormat144(RTVFSFILE hVfsFile, bool fQuick)
     4664{
     4665    return RTFsFatVolFormat(hVfsFile, 0 /*offVol*/, 1474560, fQuick ? RTFSFATVOL_FMT_F_QUICK : RTFSFATVOL_FMT_F_FULL,
     4666                            512 /*cbSector*/, 2 /*cSectorsPerCluster*/, RTFSFATTYPE_FAT12, 2 /*cHeads*/,  18 /*cSectors*/,
     4667                            0xf0 /*bMedia*/, 0 /*cHiddenSectors*/, 224 /*cRootDirEntries*/, NULL /*pErrInfo*/);
    41694668}
    41704669
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette