]>
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
) {