]>
git.saurik.com Git - apple/libutil.git/blob - wipefs.cpp
3be8ae1e2419d9d8cca103f27b2c5916a8ab2217
   2  * Copyright (c) 2008 Apple Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  30 #include <sys/ioctl.h> 
  34 #include "ExtentManager.h" 
  37 #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y)) 
  41         class ExtentManager extMan
; 
  45 AddExtentsForFutureFS(class ExtentManager 
*extMan
) 
  47         // we don't know what blocks future FS will use to recognize itself.  But we'd better be safe than sorry and write 
  48         // the first and last 2MB of the volume 
  49         off_t size 
= 2 * 1024 * 1024; 
  50         extMan
->AddByteRangeExtent(0, size
); 
  51         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- size
, size
); 
  55 AddExtentsForHFS(class ExtentManager 
*extMan
) 
  57         // first 1KB is boot block, last 512B is reserved 
  58         // the Volume Header (512B) is after 1KB and before the last 512B 
  59         extMan
->AddByteRangeExtent(0, 1024 + 512); 
  60         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 1024, 1024); 
  64 AddExtentsForMSDOS(class ExtentManager 
*extMan
) 
  66         // MSDOS needs the first block (in theory, up to 32KB) 
  67         extMan
->AddByteRangeExtent(0, 32 * 1024); 
  71 AddExtentsForNTFS(class ExtentManager 
*extMan
) 
  73         // NTFS supports block size from 256B to 32768B.  The first, middle and last block are needed 
  74         extMan
->AddByteRangeExtent(0, 32 * 1024); 
  75         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 32 * 1024, 32 * 1024); 
  76         // to be safe, add the rage from (mid_point - 32KB) to (mid_point + 32KB) 
  77         extMan
->AddByteRangeExtent(extMan
->totalBytes 
/ 2 - 32 * 1024, 64 * 1024); 
  81 AddExtentsForUDF(class ExtentManager 
*extMan
) 
  83         off_t lastBlockAddr 
= extMan
->totalBlocks 
- 1; 
  85         // Volume Recognization Sequence (VRS) starts at 32KB, usually less than 7 Volume Structure Descriptors (2KB each) 
  86         extMan
->AddByteRangeExtent(32 * 1024, 14 * 1024); 
  88         // AVDP is on 256, 512, last block, last block - 256 
  89         extMan
->AddBlockRangeExtent(256, 1); 
  90         extMan
->AddBlockRangeExtent(512, 1); 
  91         extMan
->AddBlockRangeExtent(lastBlockAddr
, 1); 
  92         extMan
->AddBlockRangeExtent(lastBlockAddr 
- 256, 1); 
  94         // to be safe, assume the device has 2KB block size and do it again 
  95         if (extMan
->blockSize 
!= 2048) { 
  96                 off_t blockSize 
= 2048; 
  97                 // AVDP is on 256, 512, last block, last block - 256 
  98                 extMan
->AddByteRangeExtent(256 * blockSize
, blockSize
); 
  99                 extMan
->AddByteRangeExtent(512 * blockSize
, blockSize
); 
 100                 extMan
->AddByteRangeExtent(extMan
->totalBytes 
- blockSize
, blockSize
); 
 101                 extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 256 * blockSize
, blockSize
); 
 106 AddExtentsForUFS(class ExtentManager 
*extMan
) 
 108         // UFS super block is 8KB at offset 8KB 
 109         extMan
->AddByteRangeExtent(8192, 8192); 
 113 AddExtentsForZFS(class ExtentManager 
*extMan
) 
 115         // ZFS needs the first 512KB and last 512KB for all the 4 disk labels 
 116         extMan
->AddByteRangeExtent(0, 512 * 1024); 
 117         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 512 * 1024, 512 * 1024); 
 121 AddExtentsForPartitions(class ExtentManager 
*extMan
) 
 123         // MBR (Master Boot Record) needs the first sector 
 124         // APM (Apple Partition Map) needs the second sector 
 125         // GPT (GUID Partition Table) needs the first 34 and last 33 sectors 
 126         extMan
->AddByteRangeExtent(0, 512 * 34); 
 127         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 512 * 33, 512 * 33); 
 131 AddExtentsForCoreStorage(class ExtentManager 
*extMan
) 
 133         // the CoreStorage VolumeHeader structures reside in the first/last 512 bytes of each PV 
 134         extMan
->AddByteRangeExtent(0, 512); 
 135         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 512, 512); 
 139 wipefs_alloc(int fd
, size_t block_size
, wipefs_ctx 
*handle
) 
 142         uint64_t numBlocks 
= 0; 
 143         uint32_t nativeBlockSize 
= 0; 
 144         off_t totalSizeInBytes 
= 0; 
 145         class ExtentManager 
*extMan 
= NULL
; 
 146         struct stat sbuf 
= { 0 }; 
 149         (void)fstat(fd
, &sbuf
); 
 150         switch (sbuf
.st_mode 
& S_IFMT
) { 
 153                 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (char *)&nativeBlockSize
) < 0) { 
 157                 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (char *)&numBlocks
) < 0) { 
 161                 totalSizeInBytes 
= numBlocks 
* nativeBlockSize
; 
 164                 nativeBlockSize 
= sbuf
.st_blksize
; 
 165                 numBlocks 
= sbuf
.st_size 
/ sbuf
.st_blksize
; 
 166                 totalSizeInBytes 
= sbuf
.st_size
; 
 172         if (block_size 
== 0) { 
 173                 block_size 
= nativeBlockSize
; 
 175         if (block_size 
== 0 || totalSizeInBytes 
== 0) { 
 181                 *handle 
= new __wipefs_ctx
; 
 182                 if (*handle 
== NULL
) { 
 188                 extMan 
= &(*handle
)->extMan
; 
 190                 extMan
->Init(block_size
, nativeBlockSize
, totalSizeInBytes
); 
 191                 AddExtentsForFutureFS(extMan
); 
 192                 AddExtentsForHFS(extMan
); 
 193                 AddExtentsForMSDOS(extMan
); 
 194                 AddExtentsForNTFS(extMan
); 
 195                 AddExtentsForUDF(extMan
); 
 196                 AddExtentsForUFS(extMan
); 
 197                 AddExtentsForZFS(extMan
); 
 198                 AddExtentsForPartitions(extMan
); 
 199                 AddExtentsForCoreStorage(extMan
); 
 201         catch (bad_alloc 
&e
) { 
 204         catch (...) { // currently only ENOMEM is possible 
 216 wipefs_include_blocks(wipefs_ctx handle
, off_t block_offset
, off_t nblocks
) 
 220                 handle
->extMan
.AddBlockRangeExtent(block_offset
, nblocks
); 
 222         catch (bad_alloc 
&e
) { 
 225         catch (...) { // currently only ENOMEM is possible 
 232 wipefs_except_blocks(wipefs_ctx handle
, off_t block_offset
, off_t nblocks
) 
 236                 handle
->extMan
.RemoveBlockRangeExtent(block_offset
, nblocks
); 
 238         catch (bad_alloc 
&e
) { 
 241         catch (...) { // currently only ENOMEM is possible 
 248 wipefs_wipe(wipefs_ctx handle
) 
 251         uint8_t *bufZero 
= NULL
; 
 257         memset(&extent
, 0, sizeof(dk_extent_t
)); 
 258         extent
.length 
= handle
->extMan
.totalBytes
; 
 260         memset(&unmap
, 0, sizeof(dk_unmap_t
)); 
 261         unmap
.extents 
= &extent
; 
 262         unmap
.extentsCount 
= 1; 
 265         // Don't bother to check the return value since this is mostly 
 266         // informational for the lower-level drivers. 
 268         ioctl(handle
->fd
, DKIOCUNMAP
, (caddr_t
)&unmap
); 
 271         bufSize 
= 128 * 1024; // issue large I/O to get better performance 
 272         if (handle
->extMan
.nativeBlockSize 
> bufSize
) { 
 273             bufSize 
= handle
->extMan
.nativeBlockSize
; 
 275         bufZero 
= new uint8_t[bufSize
]; 
 276         bzero(bufZero
, bufSize
); 
 278         off_t byteOffset
, totalBytes
; 
 279         size_t numBytes
, numBytesToWrite
, blockSize
; 
 281         blockSize 
= handle
->extMan
.blockSize
; 
 282         totalBytes 
= handle
->extMan
.totalBytes
; 
 283         // write zero to all extents 
 284         for (curExt 
= handle
->extMan
.extentList
.begin(); curExt 
!= handle
->extMan
.extentList
.end(); curExt
++) { 
 285                 byteOffset 
= curExt
->blockAddr 
* blockSize
; 
 286                 numBytes 
= curExt
->numBlocks 
* blockSize
; 
 287                 // make both offset and numBytes on native block boundary 
 288                 if (byteOffset 
% handle
->extMan
.nativeBlockSize 
!= 0 || 
 289                         numBytes 
% handle
->extMan
.nativeBlockSize 
!= 0) { 
 290                         size_t nativeBlockSize 
= handle
->extMan
.nativeBlockSize
; 
 291                         off_t newOffset
, newEndOffset
; 
 292                         newOffset 
= byteOffset 
/ nativeBlockSize 
* nativeBlockSize
; 
 293                         newEndOffset 
= roundup(byteOffset 
+ numBytes
, nativeBlockSize
); 
 294                         byteOffset 
= newOffset
; 
 295                         numBytes 
= newEndOffset 
- newOffset
; 
 297                 if (byteOffset 
+ (off_t
)numBytes 
> totalBytes
) { 
 298                         numBytes 
= totalBytes 
- byteOffset
; 
 300                 while (numBytes 
> 0) { 
 301                         numBytesToWrite 
= min(numBytes
, bufSize
); 
 302                         if (pwrite(handle
->fd
, bufZero
, numBytesToWrite
, byteOffset
) != (ssize_t
)numBytesToWrite
) { 
 306                         numBytes 
-= numBytesToWrite
; 
 307                         byteOffset 
+= numBytesToWrite
; 
 313         (void)ioctl(handle
->fd
, DKIOCSYNCHRONIZECACHE
); 
 320 wipefs_free(wipefs_ctx 
*handle
) 
 322         if (*handle 
!= NULL
) {