VirtualBox

Changeset 40240 in vbox


Ignore:
Timestamp:
Feb 23, 2012 8:51:34 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
76450
Message:

Storage: Implement repair callback for VDI, fixes for the VHD repair callback and add repair command to vbox-img

Location:
trunk/src/VBox/Storage
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VDI.cpp

    r40033 r40240  
    31023102    if (pcbActuallyDiscarded)
    31033103        *pcbActuallyDiscarded = cbDiscard;
     3104
     3105    LogFlowFunc(("returns %Rrc\n", rc));
     3106    return rc;
     3107}
     3108
     3109/** @copydoc VBOXHDDBACKEND::pfnRepair */
     3110static DECLCALLBACK(int) vdiRepair(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
     3111                                   PVDINTERFACE pVDIfsImage, uint32_t fFlags)
     3112{
     3113    LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
     3114    int rc;
     3115    PVDINTERFACEERROR pIfError;
     3116    PVDINTERFACEIOINT pIfIo;
     3117    PVDIOSTORAGE pStorage;
     3118    uint64_t cbFile;
     3119    PVDIIMAGEBLOCKPOINTER paBlocks = NULL;
     3120    uint32_t *pu32BlockBitmap = NULL;
     3121    VDIPREHEADER PreHdr;
     3122    VDIHEADER    Hdr;
     3123
     3124    pIfIo = VDIfIoIntGet(pVDIfsImage);
     3125    AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
     3126
     3127    pIfError = VDIfErrorGet(pVDIfsDisk);
     3128
     3129    do
     3130    {
     3131        bool fRepairHdr = false;
     3132        bool fRepairBlockArray = false;
     3133
     3134        rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
     3135                               VDOpenFlagsToFileOpenFlags(  fFlags & VD_REPAIR_DRY_RUN
     3136                                                          ? VD_OPEN_FLAGS_READONLY
     3137                                                          : 0,
     3138                                                          false /* fCreate */),
     3139                               &pStorage);
     3140        if (RT_FAILURE(rc))
     3141        {
     3142            rc = vdIfError(pIfError, rc, RT_SRC_POS, "VDI: Failed to open image \"%s\"", pszFilename);
     3143            break;
     3144        }
     3145
     3146        rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
     3147        if (RT_FAILURE(rc))
     3148        {
     3149            rc = vdIfError(pIfError, rc, RT_SRC_POS, "VDI: Failed to query image size");
     3150            break;
     3151        }
     3152
     3153        /* Read pre-header. */
     3154        rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &PreHdr, sizeof(PreHdr), NULL);
     3155        if (RT_FAILURE(rc))
     3156        {
     3157            rc = vdIfError(pIfError, rc, RT_SRC_POS, N_("VDI: Error reading pre-header in '%s'"), pszFilename);
     3158            break;
     3159        }
     3160        rc = vdiValidatePreHeader(&PreHdr);
     3161        if (RT_FAILURE(rc))
     3162        {
     3163            rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
     3164                           N_("VDI: invalid pre-header in '%s'"), pszFilename);
     3165            break;
     3166        }
     3167
     3168        /* Read header. */
     3169        Hdr.uVersion = RT_H2LE_U32(PreHdr.u32Version);
     3170        switch (GET_MAJOR_HEADER_VERSION(&Hdr))
     3171        {
     3172            case 0:
     3173                rc = vdIfIoIntFileReadSync(pIfIo, pStorage, sizeof(PreHdr),
     3174                                           &Hdr.u.v0, sizeof(Hdr.u.v0),
     3175                                           NULL);
     3176                if (RT_FAILURE(rc))
     3177                    rc = vdIfError(pIfError, rc, RT_SRC_POS, N_("VDI: error reading v0 header in '%s'"),
     3178                                   pszFilename);
     3179                break;
     3180            case 1:
     3181                rc = vdIfIoIntFileReadSync(pIfIo, pStorage, sizeof(PreHdr),
     3182                                           &Hdr.u.v1, sizeof(Hdr.u.v1), NULL);
     3183                if (RT_FAILURE(rc))
     3184                {
     3185                    rc = vdIfError(pIfError, rc, RT_SRC_POS, N_("VDI: error reading v1 header in '%s'"),
     3186                                   pszFilename);
     3187                }
     3188                if (Hdr.u.v1.cbHeader >= sizeof(Hdr.u.v1plus))
     3189                {
     3190                    /* Read the VDI 1.1+ header completely. */
     3191                    rc = vdIfIoIntFileReadSync(pIfIo, pStorage, sizeof(PreHdr),
     3192                                               &Hdr.u.v1plus, sizeof(Hdr.u.v1plus),
     3193                                               NULL);
     3194                    if (RT_FAILURE(rc))
     3195                        rc = vdIfError(pIfError, rc, RT_SRC_POS, N_("VDI: error reading v1.1+ header in '%s'"),
     3196                                       pszFilename);
     3197                }
     3198                break;
     3199            default:
     3200                rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
     3201                               N_("VDI: unsupported major version %u in '%s'"),
     3202                               GET_MAJOR_HEADER_VERSION(&Hdr), pszFilename);
     3203                break;
     3204        }
     3205
     3206        if (RT_SUCCESS(rc))
     3207        {
     3208            rc = vdiValidateHeader(&Hdr);
     3209            if (RT_FAILURE(rc))
     3210            {
     3211                rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
     3212                               N_("VDI: invalid header in '%s'"), pszFilename);
     3213                break;
     3214            }
     3215        }
     3216
     3217        /* Setup image parameters by header. */
     3218        uint64_t offStartBlocks, offStartData;
     3219        size_t cbTotalBlockData;
     3220
     3221        offStartBlocks     = getImageBlocksOffset(&Hdr);
     3222        offStartData       = getImageDataOffset(&Hdr);
     3223        cbTotalBlockData   = getImageExtraBlockSize(&Hdr) + getImageBlockSize(&Hdr);
     3224
     3225        /* Allocate memory for blocks array. */
     3226        paBlocks = (PVDIIMAGEBLOCKPOINTER)RTMemAlloc(sizeof(VDIIMAGEBLOCKPOINTER) * getImageBlocks(&Hdr));
     3227        if (!paBlocks)
     3228        {
     3229            rc = vdIfError(pIfError, VERR_NO_MEMORY, RT_SRC_POS,
     3230                           "Failed to allocate memory for block array");
     3231            break;
     3232        }
     3233
     3234        /* Read blocks array. */
     3235        rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offStartBlocks, paBlocks,
     3236                                   getImageBlocks(&Hdr) * sizeof(VDIIMAGEBLOCKPOINTER),
     3237                                   NULL);
     3238        if (RT_FAILURE(rc))
     3239        {
     3240            rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
     3241                           "Failed to read block array (at %llu), %Rrc",
     3242                           offStartBlocks, rc);
     3243            break;
     3244        }
     3245
     3246        pu32BlockBitmap = (uint32_t *)RTMemAllocZ(RT_ALIGN_Z(getImageBlocks(&Hdr) / 8, 4));
     3247        if (!pu32BlockBitmap)
     3248        {
     3249            rc = vdIfError(pIfError, VERR_NO_MEMORY, RT_SRC_POS,
     3250                           "Failed to allocate memory for block bitmap");
     3251            break;
     3252        }
     3253
     3254        for (uint32_t i = 0; i < getImageBlocks(&Hdr); i++)
     3255        {
     3256            if (IS_VDI_IMAGE_BLOCK_ALLOCATED(paBlocks[i]))
     3257            {
     3258                uint64_t offBlock =   (uint64_t)paBlocks[i] * cbTotalBlockData
     3259                                    + offStartData;
     3260
     3261                /*
     3262                 * Check that the offsets are valid (inside of the image) and
     3263                 * that there are no double references.
     3264                 */
     3265                if (offBlock + cbTotalBlockData > cbFile)
     3266                {
     3267                    vdIfErrorMessage(pIfError, "Entry %u points to invalid offset %llu, clearing\n",
     3268                                     i, offBlock);
     3269                    paBlocks[i] = VDI_IMAGE_BLOCK_FREE;
     3270                    fRepairBlockArray = true;
     3271                }
     3272                else if (ASMBitTestAndSet(pu32BlockBitmap, paBlocks[i]))
     3273                {
     3274                    vdIfErrorMessage(pIfError, "Entry %u points to an already referenced data block, clearing\n",
     3275                                     i);
     3276                    paBlocks[i] = VDI_IMAGE_BLOCK_FREE;
     3277                    fRepairBlockArray = true;
     3278                }
     3279            }
     3280        }
     3281
     3282        /* Write repaired structures now. */
     3283        if (!fRepairBlockArray)
     3284            vdIfErrorMessage(pIfError, "VDI image is in a consistent state, no repair required\n");
     3285        else if (!(fFlags & VD_REPAIR_DRY_RUN))
     3286        {
     3287            for (uint32_t i = 0; i < getImageBlocks(&Hdr); i++)
     3288                paBlocks[i] = RT_H2BE_U32(paBlocks[i]);
     3289
     3290            vdIfErrorMessage(pIfError, "Writing repaired block allocation table...\n");
     3291
     3292            rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offStartBlocks, paBlocks,
     3293                                        getImageBlocks(&Hdr) * sizeof(VDIIMAGEBLOCKPOINTER),
     3294                                        NULL);
     3295            if (RT_FAILURE(rc))
     3296            {
     3297                rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
     3298                               "Could not write repaired block allocation table (at %llu), %Rrc",
     3299                               offStartBlocks, rc);
     3300                break;
     3301            }
     3302        }
     3303
     3304        vdIfErrorMessage(pIfError, "Corrupted VDI image repaired successfully\n");
     3305    } while(0);
     3306
     3307    if (paBlocks)
     3308        RTMemFree(paBlocks);
     3309
     3310    if (pu32BlockBitmap)
     3311        RTMemFree(pu32BlockBitmap);
     3312
     3313    if (pStorage)
     3314        vdIfIoIntFileClose(pIfIo, pStorage);
    31043315
    31053316    LogFlowFunc(("returns %Rrc\n", rc));
     
    32093420    vdiAsyncDiscard,
    32103421    /* pfnRepair */
    3211     NULL
     3422    vdiRepair
    32123423};
  • trunk/src/VBox/Storage/VHD.cpp

    r40107 r40240  
    32743274                        vdIfErrorMessage(pIfError, "Entry %u points to invalid offset %llu, clearing\n",
    32753275                                         i, offBlock);
    3276                         paBat[i] = 0;
     3276                        paBat[i] = UINT32_C(0xffffffff);
    32773277                        fRepairBat = true;
    32783278                    }
     
    32853285                    }
    32863286
    3287                     if (ASMBitTestAndSet(pu32BlockBitmap, (paBat[i] - idxMinBlock) / (cbBlock / VHD_SECTOR_SIZE)))
     3287                    if (   paBat[i] != UINT32_C(0xffffffff)
     3288                        && ASMBitTestAndSet(pu32BlockBitmap, (paBat[i] - idxMinBlock) / (cbBlock / VHD_SECTOR_SIZE)))
    32883289                    {
    32893290                        vdIfErrorMessage(pIfError, "Entry %u points to an already referenced data block, clearing\n",
    32903291                                         i);
    3291                         paBat[i] = 0;
     3292                        paBat[i] = UINT32_C(0xffffffff);
    32923293                        fRepairBat = true;
    32933294                    }
  • trunk/src/VBox/Storage/testcase/vbox-img.cpp

    r38945 r40240  
    6060                 "                --size <size in bytes>\n"
    6161                 "                [--format VDI|VMDK|VHD] (default: VDI)\n"
    62                  "                [--variant Standard,Fixed,Split2G,Stream,ESX]\n",
     62                 "                [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
     63                 "\n"
     64                 "   repair       --filename <filename>\n"
     65                 "                [--dry-run]\n"
     66                 "                [--format VDI|VMDK|VHD] (default: autodetect)\n",
    6367                 g_pszProgName);
    6468}
     
    11581162
    11591163
     1164int handleRepair(HandlerArg *a)
     1165{
     1166    int rc = VINF_SUCCESS;
     1167    PVBOXHDD pDisk = NULL;
     1168    const char *pszFilename = NULL;
     1169    char *pszBackend = NULL;
     1170    const char *pszFormat  = NULL;
     1171    bool fDryRun = false;
     1172    VDTYPE enmType = VDTYPE_HDD;
     1173
     1174    /* Parse the command line. */
     1175    static const RTGETOPTDEF s_aOptions[] =
     1176    {
     1177        { "--filename", 'f', RTGETOPT_REQ_STRING  },
     1178        { "--dry-run",  'd', RTGETOPT_REQ_NOTHING },
     1179        { "--format",   'b', RTGETOPT_REQ_STRING  }
     1180    };
     1181    int ch;
     1182    RTGETOPTUNION ValueUnion;
     1183    RTGETOPTSTATE GetState;
     1184    RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
     1185    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     1186    {
     1187        switch (ch)
     1188        {
     1189            case 'f':   // --filename
     1190                pszFilename = ValueUnion.psz;
     1191                break;
     1192
     1193            case 'd':   // --dry-run
     1194                fDryRun = true;
     1195                break;
     1196
     1197            case 'b':   // --format
     1198                pszFormat = ValueUnion.psz;
     1199                break;
     1200
     1201            default:
     1202                ch = RTGetOptPrintError(ch, &ValueUnion);
     1203                printUsage(g_pStdErr);
     1204                return ch;
     1205        }
     1206    }
     1207
     1208    /* Check for mandatory parameters. */
     1209    if (!pszFilename)
     1210        return errorSyntax("Mandatory --filename option missing\n");
     1211
     1212    /* just try it */
     1213    if (!pszFormat)
     1214    {
     1215        rc = VDGetFormat(NULL, NULL, pszFilename, &pszBackend, &enmType);
     1216        if (RT_FAILURE(rc))
     1217            return errorSyntax("Format autodetect failed: %Rrc\n", rc);
     1218        pszFormat = pszBackend;
     1219    }
     1220
     1221    rc = VDRepair(pVDIfs, NULL, pszFilename, pszFormat, fDryRun ? VD_REPAIR_DRY_RUN : 0);
     1222    if (RT_FAILURE(rc))
     1223        rc = errorRuntime("Error while repairing the virtual disk: %Rrc\n", rc);
     1224
     1225    if (pszBackend)
     1226        RTStrFree(pszBackend);
     1227    return rc;
     1228}
     1229
     1230
    11601231int main(int argc, char *argv[])
    11611232{
     
    12461317        { "createcache", handleCreateCache },
    12471318        { "createbase",  handleCreateBase  },
     1319        { "repair",      handleRepair      },
    12481320        { NULL,                       NULL }
    12491321    };
Note: See TracChangeset for help on using the changeset viewer.

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