]>
git.saurik.com Git - apple/libutil.git/blob - wipefs.cpp
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 wipefs_alloc(int fd
, size_t block_size
, wipefs_ctx
*handle
)
134 uint64_t numBlocks
= 0;
135 uint32_t nativeBlockSize
= 0;
136 off_t totalSizeInBytes
= 0;
137 class ExtentManager
*extMan
= NULL
;
138 struct stat sbuf
= { 0 };
141 (void)fstat(fd
, &sbuf
);
142 switch (sbuf
.st_mode
& S_IFMT
) {
145 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (char *)&nativeBlockSize
) < 0) {
149 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (char *)&numBlocks
) < 0) {
153 totalSizeInBytes
= numBlocks
* nativeBlockSize
;
156 nativeBlockSize
= sbuf
.st_blksize
;
157 numBlocks
= sbuf
.st_size
/ sbuf
.st_blksize
;
158 totalSizeInBytes
= sbuf
.st_size
;
164 if (block_size
== 0) {
165 block_size
= nativeBlockSize
;
167 if (block_size
== 0 || totalSizeInBytes
== 0) {
173 *handle
= new __wipefs_ctx
;
174 if (*handle
== NULL
) {
180 extMan
= &(*handle
)->extMan
;
182 extMan
->Init(block_size
, nativeBlockSize
, totalSizeInBytes
);
183 AddExtentsForFutureFS(extMan
);
184 AddExtentsForHFS(extMan
);
185 AddExtentsForMSDOS(extMan
);
186 AddExtentsForNTFS(extMan
);
187 AddExtentsForUDF(extMan
);
188 AddExtentsForUFS(extMan
);
189 AddExtentsForZFS(extMan
);
190 AddExtentsForPartitions(extMan
);
192 catch (bad_alloc
&e
) {
195 catch (...) { // currently only ENOMEM is possible
207 wipefs_include_blocks(wipefs_ctx handle
, off_t block_offset
, off_t nblocks
)
211 handle
->extMan
.AddBlockRangeExtent(block_offset
, nblocks
);
213 catch (bad_alloc
&e
) {
216 catch (...) { // currently only ENOMEM is possible
223 wipefs_except_blocks(wipefs_ctx handle
, off_t block_offset
, off_t nblocks
)
227 handle
->extMan
.RemoveBlockRangeExtent(block_offset
, nblocks
);
229 catch (bad_alloc
&e
) {
232 catch (...) { // currently only ENOMEM is possible
239 wipefs_wipe(wipefs_ctx handle
)
242 uint8_t *bufZero
= NULL
;
248 memset(&extent
, 0, sizeof(dk_extent_t
));
249 extent
.length
= handle
->extMan
.totalBytes
;
251 memset(&unmap
, 0, sizeof(dk_unmap_t
));
252 unmap
.extents
= &extent
;
253 unmap
.extentsCount
= 1;
256 // Don't bother to check the return value since this is mostly
257 // informational for the lower-level drivers.
259 ioctl(handle
->fd
, DKIOCUNMAP
, (caddr_t
)&unmap
);
262 bufSize
= 128 * 1024; // issue large I/O to get better performance
263 if (handle
->extMan
.nativeBlockSize
> bufSize
) {
264 bufSize
= handle
->extMan
.nativeBlockSize
;
266 bufZero
= new uint8_t[bufSize
];
267 bzero(bufZero
, bufSize
);
269 off_t byteOffset
, totalBytes
;
270 size_t numBytes
, numBytesToWrite
, blockSize
;
272 blockSize
= handle
->extMan
.blockSize
;
273 totalBytes
= handle
->extMan
.totalBytes
;
274 // write zero to all extents
275 for (curExt
= handle
->extMan
.extentList
.begin(); curExt
!= handle
->extMan
.extentList
.end(); curExt
++) {
276 byteOffset
= curExt
->blockAddr
* blockSize
;
277 numBytes
= curExt
->numBlocks
* blockSize
;
278 // make both offset and numBytes on native block boundary
279 if (byteOffset
% handle
->extMan
.nativeBlockSize
!= 0 ||
280 numBytes
% handle
->extMan
.nativeBlockSize
!= 0) {
281 size_t nativeBlockSize
= handle
->extMan
.nativeBlockSize
;
282 off_t newOffset
, newEndOffset
;
283 newOffset
= byteOffset
/ nativeBlockSize
* nativeBlockSize
;
284 newEndOffset
= roundup(byteOffset
+ numBytes
, nativeBlockSize
);
285 byteOffset
= newOffset
;
286 numBytes
= newEndOffset
- newOffset
;
288 if (byteOffset
+ (off_t
)numBytes
> totalBytes
) {
289 numBytes
= totalBytes
- byteOffset
;
291 while (numBytes
> 0) {
292 numBytesToWrite
= min(numBytes
, bufSize
);
293 if (pwrite(handle
->fd
, bufZero
, numBytesToWrite
, byteOffset
) != (ssize_t
)numBytesToWrite
) {
297 numBytes
-= numBytesToWrite
;
298 byteOffset
+= numBytesToWrite
;
309 wipefs_free(wipefs_ctx
*handle
)
311 if (*handle
!= NULL
) {