]>
git.saurik.com Git - apple/libutil.git/blob - wipefs.cpp
d5efc0558507ea1e7a359fa07b29c4805d4bc9dd
   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@ 
  29 #include <sys/ioctl.h> 
  33 #include "ExtentManager.h" 
  36 #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y)) 
  40         class ExtentManager extMan
; 
  44 AddExtentsForFutureFS(class ExtentManager 
*extMan
) 
  46         // we don't know what blocks future FS will use to recognize itself.  But we'd better be safe than sorry and write 
  47         // the first and last 2MB of the volume 
  48         off_t size 
= 2 * 1024 * 1024; 
  49         extMan
->AddByteRangeExtent(0, size
); 
  50         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- size
, size
); 
  54 AddExtentsForHFS(class ExtentManager 
*extMan
) 
  56         // first 1KB is boot block, last 512B is reserved 
  57         // the Volume Header (512B) is after 1KB and before the last 512B 
  58         extMan
->AddByteRangeExtent(0, 1024 + 512); 
  59         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 1024, 1024); 
  63 AddExtentsForMSDOS(class ExtentManager 
*extMan
) 
  65         // MSDOS needs the first block (in theory, up to 32KB) 
  66         extMan
->AddByteRangeExtent(0, 32 * 1024); 
  70 AddExtentsForNTFS(class ExtentManager 
*extMan
) 
  72         // NTFS supports block size from 256B to 32768B.  The first, middle and last block are needed 
  73         extMan
->AddByteRangeExtent(0, 32 * 1024); 
  74         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 32 * 1024, 32 * 1024); 
  75         // to be safe, add the rage from (mid_point - 32KB) to (mid_point + 32KB) 
  76         extMan
->AddByteRangeExtent(extMan
->totalBytes 
/ 2 - 32 * 1024, 64 * 1024); 
  80 AddExtentsForUDF(class ExtentManager 
*extMan
) 
  82         off_t lastBlockAddr 
= extMan
->totalBlocks 
- 1; 
  84         // Volume Recognization Sequence (VRS) starts at 32KB, usually less than 7 Volume Structure Descriptors (2KB each) 
  85         extMan
->AddByteRangeExtent(32 * 1024, 14 * 1024); 
  87         // AVDP is on 256, 512, last block, last block - 256 
  88         extMan
->AddBlockRangeExtent(256, 1); 
  89         extMan
->AddBlockRangeExtent(512, 1); 
  90         extMan
->AddBlockRangeExtent(lastBlockAddr
, 1); 
  91         extMan
->AddBlockRangeExtent(lastBlockAddr 
- 256, 1); 
  93         // to be safe, assume the device has 2KB block size and do it again 
  94         if (extMan
->blockSize 
!= 2048) { 
  95                 off_t blockSize 
= 2048; 
  96                 // AVDP is on 256, 512, last block, last block - 256 
  97                 extMan
->AddByteRangeExtent(256 * blockSize
, blockSize
); 
  98                 extMan
->AddByteRangeExtent(512 * blockSize
, blockSize
); 
  99                 extMan
->AddByteRangeExtent(extMan
->totalBytes 
- blockSize
, blockSize
); 
 100                 extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 256 * blockSize
, blockSize
); 
 105 AddExtentsForUFS(class ExtentManager 
*extMan
) 
 107         // UFS super block is 8KB at offset 8KB 
 108         extMan
->AddByteRangeExtent(8192, 8192); 
 112 AddExtentsForZFS(class ExtentManager 
*extMan
) 
 114         // ZFS needs the first 512KB and last 512KB for all the 4 disk labels 
 115         extMan
->AddByteRangeExtent(0, 512 * 1024); 
 116         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 512 * 1024, 512 * 1024); 
 120 AddExtentsForPartitions(class ExtentManager 
*extMan
) 
 122         // MBR (Master Boot Record) needs the first sector 
 123         // APM (Apple Partition Map) needs the second sector 
 124         // GPT (GUID Partition Table) needs the first 34 and last 33 sectors 
 125         extMan
->AddByteRangeExtent(0, 512 * 34); 
 126         extMan
->AddByteRangeExtent(extMan
->totalBytes 
- 512 * 33, 512 * 33); 
 130 wipefs_alloc(int fd
, size_t block_size
, wipefs_ctx 
*handle
) 
 133         uint64_t numBlocks 
= 0; 
 134         uint32_t nativeBlockSize 
= 0; 
 135         off_t totalSizeInBytes 
= 0; 
 136         class ExtentManager 
*extMan 
= NULL
; 
 137         struct stat sbuf 
= { 0 }; 
 140         (void)fstat(fd
, &sbuf
); 
 141         switch (sbuf
.st_mode 
& S_IFMT
) { 
 144                 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (char *)&nativeBlockSize
) < 0) { 
 148                 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (char *)&numBlocks
) < 0) { 
 152                 totalSizeInBytes 
= numBlocks 
* nativeBlockSize
; 
 155                 nativeBlockSize 
= sbuf
.st_blksize
; 
 156                 numBlocks 
= sbuf
.st_size 
/ sbuf
.st_blksize
; 
 157                 totalSizeInBytes 
= sbuf
.st_size
; 
 163         if (block_size 
== 0) { 
 164                 block_size 
= nativeBlockSize
; 
 166         if (block_size 
== 0 || totalSizeInBytes 
== 0) { 
 172                 *handle 
= new __wipefs_ctx
; 
 173                 if (*handle 
== NULL
) { 
 179                 extMan 
= &(*handle
)->extMan
; 
 181                 extMan
->Init(block_size
, nativeBlockSize
, totalSizeInBytes
); 
 182                 AddExtentsForFutureFS(extMan
); 
 183                 AddExtentsForHFS(extMan
); 
 184                 AddExtentsForMSDOS(extMan
); 
 185                 AddExtentsForNTFS(extMan
); 
 186                 AddExtentsForUDF(extMan
); 
 187                 AddExtentsForUFS(extMan
); 
 188                 AddExtentsForZFS(extMan
); 
 189                 AddExtentsForPartitions(extMan
); 
 191         catch (bad_alloc 
&e
) { 
 194         catch (...) { // currently only ENOMEM is possible 
 206 wipefs_except_blocks(wipefs_ctx handle
, off_t block_offset
, off_t nblocks
) 
 210                 handle
->extMan
.RemoveBlockRangeExtent(block_offset
, nblocks
); 
 212         catch (bad_alloc 
&e
) { 
 215         catch (...) { // currently only ENOMEM is possible 
 222 wipefs_wipe(wipefs_ctx handle
) 
 225         uint8_t *bufZero 
= NULL
; 
 228         dk_discard_t discard
; 
 230         memset(&discard
, 0, sizeof(dk_discard_t
)); 
 231         discard
.length 
= handle
->extMan
.totalBytes
; 
 234         // Don't bother to check the return value since this is mostly 
 235         // informational for the lower-level drivers. 
 237         ioctl(handle
->fd
, DKIOCDISCARD
, (caddr_t
)&discard
); 
 240         bufSize 
= 256 * 1024; // issue large I/O to get better performance 
 241         bufZero 
= new uint8_t[bufSize
]; 
 242         bzero(bufZero
, bufSize
); 
 244         off_t byteOffset
, totalBytes
; 
 245         size_t numBytes
, numBytesToWrite
, blockSize
; 
 247         blockSize 
= handle
->extMan
.blockSize
; 
 248         totalBytes 
= handle
->extMan
.totalBytes
; 
 249         // write zero to all extents 
 250         for (curExt 
= handle
->extMan
.extentList
.begin(); curExt 
!= handle
->extMan
.extentList
.end(); curExt
++) { 
 251                 byteOffset 
= curExt
->blockAddr 
* blockSize
; 
 252                 numBytes 
= curExt
->numBlocks 
* blockSize
; 
 253                 // make both offset and numBytes on native block boundary 
 254                 if (byteOffset 
% handle
->extMan
.nativeBlockSize 
!= 0 || 
 255                         numBytes 
% handle
->extMan
.nativeBlockSize 
!= 0) { 
 256                         size_t nativeBlockSize 
= handle
->extMan
.nativeBlockSize
; 
 257                         off_t newOffset
, newEndOffset
; 
 258                         newOffset 
= byteOffset 
/ nativeBlockSize 
* nativeBlockSize
; 
 259                         newEndOffset 
= roundup(byteOffset 
+ numBytes
, nativeBlockSize
); 
 260                         byteOffset 
= newOffset
; 
 261                         numBytes 
= newEndOffset 
- newOffset
; 
 263                 if (byteOffset 
+ (off_t
)numBytes 
> totalBytes
) { 
 264                         numBytes 
= totalBytes 
- byteOffset
; 
 266                 while (numBytes 
> 0) { 
 267                         numBytesToWrite 
= min(numBytes
, bufSize
); 
 268                         if (pwrite(handle
->fd
, bufZero
, numBytesToWrite
, byteOffset
) != (ssize_t
)numBytesToWrite
) { 
 272                         numBytes 
-= numBytesToWrite
; 
 273                         byteOffset 
+= numBytesToWrite
; 
 284 wipefs_free(wipefs_ctx 
*handle
) 
 286         if (*handle 
!= NULL
) {