2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@dragonflybsd.org>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 // # gcc -Wall -g -I../../sys -I../hammer2 ../../sys/libkern/icrc32.c ../hammer2/subs.c ../hammer2/ondisk.c ./destroy.c -o destroy
39 #include <sys/types.h>
51 #include <vfs/hammer2/hammer2_disk.h>
53 #include "hammer2_subs.h"
55 static int modify_blockref(const hammer2_volume_data_t
*, int,
56 hammer2_blockref_t
*, hammer2_blockref_t
*);
57 static int modify_inode(const hammer2_blockref_t
*,
58 hammer2_media_data_t
*, size_t);
59 static int modify_dirent_embedded(int, hammer2_blockref_t
*);
60 static int modify_dirent(int, hammer2_blockref_t
*, const hammer2_blockref_t
*,
61 hammer2_media_data_t
*, size_t);
63 static hammer2_tid_t src_inode
= 0;
64 static hammer2_tid_t dst_inode
= 0;
65 static const char *src_dirent
= NULL
;
66 static const char *dst_dirent
= NULL
;
67 static bool ForceOpt
= false;
70 destroy_blockref(uint8_t type
)
75 for (i
= 0; i
< HAMMER2_NUM_VOLHDRS
; ++i
) {
76 hammer2_volume_data_t voldata
;
77 hammer2_blockref_t broot
;
81 memset(&broot
, 0, sizeof(broot
));
83 broot
.data_off
= (i
* HAMMER2_ZONE_BYTES64
) | HAMMER2_PBUFRADIX
;
84 off
= broot
.data_off
& ~HAMMER2_OFF_MASK_RADIX
;
85 if (lseek(hammer2_get_root_volume_fd(),
86 off
- hammer2_get_root_volume_offset(), SEEK_SET
) == -1) {
91 ret
= read(hammer2_get_root_volume_fd(), &voldata
,
92 HAMMER2_VOLUME_BYTES
);
93 if (ret
== HAMMER2_VOLUME_BYTES
) {
94 fprintf(stdout
, "zone.%d %016jx\n",
95 i
, (uintmax_t)broot
.data_off
);
96 if (modify_blockref(&voldata
, -1, &broot
, NULL
) == -1)
98 } else if (ret
== -1) {
102 fprintf(stderr
, "Failed to read volume header\n");
107 return failed
? -1 : 0;
111 read_media(const hammer2_blockref_t
*bref
, hammer2_media_data_t
*media
,
114 hammer2_off_t io_off
, io_base
;
115 size_t bytes
, io_bytes
, boff
;
119 bytes
= (bref
->data_off
& HAMMER2_OFF_MASK_RADIX
);
121 bytes
= (size_t)1 << bytes
;
123 *media_bytes
= bytes
;
128 io_off
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
129 io_base
= io_off
& ~(hammer2_off_t
)(HAMMER2_LBUFSIZE
- 1);
130 boff
= io_off
- io_base
;
132 io_bytes
= HAMMER2_LBUFSIZE
;
133 while (io_bytes
+ boff
< bytes
)
136 if (io_bytes
> sizeof(*media
)) {
137 fprintf(stderr
, "Bad I/O bytes\n");
140 fd
= hammer2_get_volume_fd(io_off
);
141 if (lseek(fd
, io_base
- hammer2_get_volume_offset(io_base
), SEEK_SET
)
146 ret
= read(fd
, media
, io_bytes
);
150 } else if (ret
!= (ssize_t
)io_bytes
) {
151 fprintf(stderr
, "Failed to read media\n");
155 memmove(media
, (char *)media
+ boff
, bytes
);
161 write_media(const hammer2_blockref_t
*bref
, const hammer2_media_data_t
*media
,
164 hammer2_off_t io_off
, io_base
;
165 char buf
[HAMMER2_PBUFSIZE
];
166 size_t bytes
, io_bytes
, boff
;
170 bytes
= (bref
->data_off
& HAMMER2_OFF_MASK_RADIX
);
172 bytes
= (size_t)1 << bytes
;
174 assert(bytes
== media_bytes
);
176 io_off
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
177 io_base
= io_off
& ~(hammer2_off_t
)(HAMMER2_LBUFSIZE
- 1);
178 boff
= io_off
- io_base
;
180 io_bytes
= HAMMER2_LBUFSIZE
;
181 while (io_bytes
+ boff
< bytes
)
184 if (io_bytes
> sizeof(buf
)) {
185 fprintf(stderr
, "Bad I/O bytes\n");
188 fd
= hammer2_get_volume_fd(io_off
);
189 if (lseek(fd
, io_base
- hammer2_get_volume_offset(io_base
), SEEK_SET
)
194 if (read(fd
, buf
, io_bytes
) != (ssize_t
)io_bytes
) {
199 memcpy(buf
+ boff
, media
, media_bytes
);
200 if (lseek(fd
, io_base
- hammer2_get_volume_offset(io_base
), SEEK_SET
)
205 ret
= write(fd
, buf
, io_bytes
);
209 } else if (ret
!= (ssize_t
)io_bytes
) {
210 fprintf(stderr
, "Failed to write media\n");
213 if (fsync(fd
) == -1) {
222 modify_blockref(const hammer2_volume_data_t
*voldata
, int bi
,
223 hammer2_blockref_t
*bref
, hammer2_blockref_t
*prev_bref
)
225 hammer2_media_data_t media
;
226 hammer2_blockref_t
*bscan
;
227 int i
, bcount
, namlen
;
230 if (read_media(bref
, &media
, &bytes
) == -1)
233 switch (bref
->type
) {
234 case HAMMER2_BREF_TYPE_INODE
:
235 if (!(media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_DIRECTDATA
)) {
236 bscan
= &media
.ipdata
.u
.blockset
.blockref
[0];
237 bcount
= HAMMER2_SET_COUNT
;
242 if (src_inode
&& media
.ipdata
.meta
.inum
== src_inode
)
243 if (modify_inode(bref
, &media
, bytes
) == -1)
246 case HAMMER2_BREF_TYPE_INDIRECT
:
247 bscan
= &media
.npdata
[0];
248 bcount
= bytes
/ sizeof(hammer2_blockref_t
);
250 case HAMMER2_BREF_TYPE_DIRENT
:
253 namlen
= bref
->embed
.dirent
.namlen
;
254 if (src_dirent
&& namlen
== strlen(src_dirent
)) {
255 if (namlen
<= sizeof(bref
->check
.buf
) &&
256 !memcmp(bref
->check
.buf
, src_dirent
, namlen
)) {
257 if (modify_dirent_embedded(bi
, prev_bref
) == -1)
259 } else if (!memcmp(media
.buf
, src_dirent
, namlen
)) {
260 if (modify_dirent(bi
, prev_bref
, bref
, &media
,
266 case HAMMER2_BREF_TYPE_VOLUME
:
267 bscan
= &media
.voldata
.sroot_blockset
.blockref
[0];
268 bcount
= HAMMER2_SET_COUNT
;
276 for (i
= 0; i
< bcount
; ++i
)
277 if (bscan
[i
].type
!= HAMMER2_BREF_TYPE_EMPTY
)
278 if (modify_blockref(voldata
, i
, &bscan
[i
], bref
) == -1)
284 modify_inode(const hammer2_blockref_t
*bref
,
285 hammer2_media_data_t
*media
, size_t media_bytes
)
287 assert(src_inode
== media
->ipdata
.meta
.inum
);
290 media
->ipdata
.meta
.inum
= dst_inode
;
291 if (write_media(bref
, media
, media_bytes
) == -1)
295 printf("%sinode# 0x%016jx -> 0x%016jx\n", ForceOpt
? "Modified " : "",
296 src_inode
, dst_inode
);
302 modify_dirent_embedded(int bi
, hammer2_blockref_t
*prev_bref
)
304 hammer2_media_data_t bscan_media
;
305 hammer2_blockref_t
*bscan
;
308 if (read_media(prev_bref
, &bscan_media
, &bytes
) == -1)
312 switch (prev_bref
->type
) {
313 case HAMMER2_BREF_TYPE_INODE
:
314 bscan
= &bscan_media
.ipdata
.u
.blockset
.blockref
[bi
];
316 case HAMMER2_BREF_TYPE_INDIRECT
:
317 bscan
= &bscan_media
.npdata
[bi
];
323 assert(!memcmp(src_dirent
, bscan
->check
.buf
, strlen(src_dirent
)));
325 if (strlen(dst_dirent
) > sizeof(bscan
->check
.buf
)) {
326 fprintf(stderr
, "embedded dirent %s (%d bytes) can't exceed "
327 "%lu bytes\n", dst_dirent
, (int)strlen(dst_dirent
),
328 sizeof(bscan
->check
.buf
));
333 memset(bscan
->check
.buf
, 0, sizeof(bscan
->check
.buf
));
334 memcpy(bscan
->check
.buf
, dst_dirent
, strlen(dst_dirent
));
335 bscan
->embed
.dirent
.namlen
= strlen(dst_dirent
);
336 bscan
->key
= dirhash(dst_dirent
, strlen(dst_dirent
));
337 if (write_media(prev_bref
, &bscan_media
, bytes
) == -1)
341 printf("%sembedded dirent %s (%d bytes) -> %s (%d bytes)\n",
342 ForceOpt
? "Modified " : "",
343 src_dirent
, (int)strlen(src_dirent
),
344 dst_dirent
, (int)strlen(dst_dirent
));
350 modify_dirent(int bi
, hammer2_blockref_t
*prev_bref
,
351 const hammer2_blockref_t
*bref
, hammer2_media_data_t
*media
,
354 hammer2_media_data_t bscan_media
;
355 hammer2_blockref_t
*bscan
;
358 assert(!memcmp(src_dirent
, media
->buf
, strlen(src_dirent
)));
359 if (read_media(prev_bref
, &bscan_media
, &bytes
) == -1)
363 switch (prev_bref
->type
) {
364 case HAMMER2_BREF_TYPE_INODE
:
365 bscan
= &bscan_media
.ipdata
.u
.blockset
.blockref
[bi
];
367 case HAMMER2_BREF_TYPE_INDIRECT
:
368 bscan
= &bscan_media
.npdata
[bi
];
375 if (memcmp(bref
, bscan
, sizeof(*bref
))) {
376 fprintf(stderr
, "Blockref contents mismatch\n");
379 if (strlen(dst_dirent
) > sizeof(media
->buf
)) {
380 fprintf(stderr
, "dirent %s (%d bytes) can't exceed %lu bytes\n",
381 dst_dirent
, (int)strlen(dst_dirent
), sizeof(media
->buf
));
384 if (strlen(dst_dirent
) <= sizeof(bscan
->check
.buf
)) {
385 fprintf(stderr
, "dirent %s (%d bytes) must exceed %lu bytes\n",
386 dst_dirent
, (int)strlen(dst_dirent
),
387 sizeof(bscan
->check
.buf
));
392 memset(media
->buf
, 0, sizeof(media
->buf
));
393 memcpy(media
->buf
, dst_dirent
, strlen(dst_dirent
));
394 bscan
->embed
.dirent
.namlen
= strlen(dst_dirent
);
395 bscan
->key
= dirhash(dst_dirent
, strlen(dst_dirent
));
396 if (write_media(bref
, media
, media_bytes
) == -1)
398 if (write_media(prev_bref
, &bscan_media
, bytes
) == -1) {
399 memset(media
->buf
, 0, sizeof(media
->buf
));
400 memcpy(media
->buf
, src_dirent
, strlen(src_dirent
));
401 if (write_media(bref
, media
, media_bytes
) == -1)
407 printf("%sdirent %s (%d bytes) -> %s (%d bytes)\n",
408 ForceOpt
? "Modified " : "",
409 src_dirent
, (int)strlen(src_dirent
),
410 dst_dirent
, (int)strlen(dst_dirent
));
416 init_args(int argc
, char **argv
, const char **devpathp
)
418 const char *devpath
, *type
;
420 *devpathp
= devpath
= argv
[0];
423 if (!strcmp(type
, "inode")) {
425 src_inode
= strtoull(argv
[2], NULL
, 16);
426 if (errno
== ERANGE
&& src_inode
== ULLONG_MAX
) {
430 if (src_inode
== 0) {
431 fprintf(stderr
, "Invalid src inode# %ju\n",
432 (uintmax_t)src_inode
);
436 dst_inode
= strtoull(argv
[3], NULL
, 16);
437 if (errno
== ERANGE
&& dst_inode
== ULLONG_MAX
) {
441 if (dst_inode
== 0) {
442 fprintf(stderr
, "Invalid dst inode# %ju\n",
443 (uintmax_t)dst_inode
);
446 if (src_inode
== dst_inode
) {
447 fprintf(stderr
, "src equals dst\n");
450 printf("%s 0x%016jx 0x%016jx\n", devpath
, (uintmax_t)src_inode
,
451 (uintmax_t)dst_inode
);
452 } else if (!strcmp(type
, "dirent")) {
453 src_dirent
= argv
[2];
454 if (strlen(src_dirent
) > HAMMER2_PBUFSIZE
) {
455 fprintf(stderr
, "src dirent too long\n");
458 dst_dirent
= argv
[3];
459 if (strlen(dst_dirent
) > HAMMER2_PBUFSIZE
) {
460 fprintf(stderr
, "dst dirent too long\n");
463 if (!strcmp(src_dirent
, dst_dirent
)) {
464 fprintf(stderr
, "src equals dst\n");
467 printf("%s %s %s\n", devpath
, src_dirent
, dst_dirent
);
469 fprintf(stderr
, "Invalid blockref type %s\n", type
);
477 main(int argc
, char **argv
)
480 const char *binpath
= argv
[0];
483 while ((ch
= getopt(argc
, argv
, "f")) != -1) {
496 fprintf(stderr
, "%s [-f] special type src dst\n", binpath
);
500 if (init_args(argc
, argv
, &devpath
) == -1)
503 hammer2_init_volumes(devpath
, 0);
505 if (destroy_blockref(HAMMER2_BREF_TYPE_VOLUME
) == -1)
508 hammer2_cleanup_volumes();