hammer2 - Enhance pfs-list and pfs-delete
[dragonfly.git] / sbin / hammer2 / subs.c
blobfed76b10901f01f0fd6cf6bf1dacb670406ce071
1 /*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <sys/ioctl.h>
39 #include <sys/mount.h>
40 #include <sys/statvfs.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <uuid.h>
49 #include <vfs/hammer2/hammer2_disk.h>
50 #include <vfs/hammer2/hammer2_ioctl.h>
52 #include "hammer2_subs.h"
55 * Obtain a file descriptor that the caller can execute ioctl()'s on.
57 int
58 hammer2_ioctl_handle(const char *sel_path)
60 struct hammer2_ioc_version info;
61 int fd;
63 if (sel_path == NULL)
64 sel_path = ".";
66 fd = open(sel_path, O_RDONLY, 0);
67 if (fd < 0) {
68 fprintf(stderr, "hammer2: Unable to open %s: %s\n",
69 sel_path, strerror(errno));
70 return(-1);
72 if (ioctl(fd, HAMMER2IOC_VERSION_GET, &info) < 0) {
73 fprintf(stderr, "hammer2: '%s' is not a hammer2 filesystem\n",
74 sel_path);
75 close(fd);
76 return(-1);
78 return (fd);
81 const char *
82 hammer2_time64_to_str(uint64_t htime64, char **strp)
84 struct tm *tp;
85 time_t t;
87 if (*strp) {
88 free(*strp);
89 *strp = NULL;
91 *strp = malloc(64);
92 t = htime64 / 1000000;
93 tp = localtime(&t);
94 strftime(*strp, 64, "%d-%b-%Y %H:%M:%S", tp);
95 return (*strp);
98 const char *
99 hammer2_uuid_to_str(uuid_t *uuid, char **strp)
101 uint32_t status;
102 if (*strp) {
103 free(*strp);
104 *strp = NULL;
106 uuid_to_string(uuid, strp, &status);
107 return (*strp);
110 const char *
111 hammer2_iptype_to_str(uint8_t type)
113 switch(type) {
114 case HAMMER2_OBJTYPE_UNKNOWN:
115 return("UNKNOWN");
116 case HAMMER2_OBJTYPE_DIRECTORY:
117 return("DIR");
118 case HAMMER2_OBJTYPE_REGFILE:
119 return("FILE");
120 case HAMMER2_OBJTYPE_FIFO:
121 return("FIFO");
122 case HAMMER2_OBJTYPE_CDEV:
123 return("CDEV");
124 case HAMMER2_OBJTYPE_BDEV:
125 return("BDEV");
126 case HAMMER2_OBJTYPE_SOFTLINK:
127 return("SOFTLINK");
128 case HAMMER2_OBJTYPE_SOCKET:
129 return("SOCKET");
130 case HAMMER2_OBJTYPE_WHITEOUT:
131 return("WHITEOUT");
132 default:
133 return("ILLEGAL");
137 const char *
138 hammer2_pfstype_to_str(uint8_t type)
140 switch(type) {
141 case HAMMER2_PFSTYPE_NONE:
142 return("NONE");
143 case HAMMER2_PFSTYPE_SUPROOT:
144 return("SUPROOT");
145 case HAMMER2_PFSTYPE_DUMMY:
146 return("DUMMY");
147 case HAMMER2_PFSTYPE_CACHE:
148 return("CACHE");
149 case HAMMER2_PFSTYPE_SLAVE:
150 return("SLAVE");
151 case HAMMER2_PFSTYPE_SOFT_SLAVE:
152 return("SOFT_SLAVE");
153 case HAMMER2_PFSTYPE_SOFT_MASTER:
154 return("SOFT_MASTER");
155 case HAMMER2_PFSTYPE_MASTER:
156 return("MASTER");
157 default:
158 return("ILLEGAL");
162 const char *
163 hammer2_breftype_to_str(uint8_t type)
165 switch (type) {
166 case HAMMER2_BREF_TYPE_EMPTY:
167 return("empty");
168 case HAMMER2_BREF_TYPE_INODE:
169 return("inode");
170 case HAMMER2_BREF_TYPE_INDIRECT:
171 return("indirect");
172 case HAMMER2_BREF_TYPE_DATA:
173 return("data");
174 case HAMMER2_BREF_TYPE_DIRENT:
175 return("dirent");
176 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
177 return("freemap_node");
178 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
179 return("freemap_leaf");
180 case HAMMER2_BREF_TYPE_FREEMAP:
181 return("freemap");
182 case HAMMER2_BREF_TYPE_VOLUME:
183 return("volume");
184 default:
185 return("unknown");
189 const char *
190 sizetostr(hammer2_off_t size)
192 static char buf[32];
194 if (size < 1024 / 2) {
195 snprintf(buf, sizeof(buf), "%6.2fB", (double)size);
196 } else if (size < 1024 * 1024 / 2) {
197 snprintf(buf, sizeof(buf), "%6.2fKB",
198 (double)size / 1024);
199 } else if (size < 1024 * 1024 * 1024LL / 2) {
200 snprintf(buf, sizeof(buf), "%6.2fMB",
201 (double)size / (1024 * 1024));
202 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
203 snprintf(buf, sizeof(buf), "%6.2fGB",
204 (double)size / (1024 * 1024 * 1024LL));
205 } else {
206 snprintf(buf, sizeof(buf), "%6.2fTB",
207 (double)size / (1024 * 1024 * 1024LL * 1024LL));
209 return(buf);
212 const char *
213 counttostr(hammer2_off_t size)
215 static char buf[32];
217 if (size < 1024 / 2) {
218 snprintf(buf, sizeof(buf), "%jd",
219 (intmax_t)size);
220 } else if (size < 1024 * 1024 / 2) {
221 snprintf(buf, sizeof(buf), "%jd",
222 (intmax_t)size);
223 } else if (size < 1024 * 1024 * 1024LL / 2) {
224 snprintf(buf, sizeof(buf), "%6.2fM",
225 (double)size / (1024 * 1024));
226 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
227 snprintf(buf, sizeof(buf), "%6.2fG",
228 (double)(size / (1024 * 1024 * 1024LL)));
229 } else {
230 snprintf(buf, sizeof(buf), "%6.2fT",
231 (double)(size / (1024 * 1024 * 1024LL * 1024LL)));
233 return(buf);
237 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
238 * The filename is split into fields which are hashed separately and then
239 * added together.
241 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
242 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
243 * (This means we do not need to do a 0-check/or-with-0x100000000 either).
245 * Also, the iscsi crc code is used instead of the old crc32 code.
247 hammer2_key_t
248 dirhash(const unsigned char *name, size_t len)
250 const unsigned char *aname = name;
251 uint32_t crcx;
252 uint64_t key;
253 size_t i;
254 size_t j;
257 * Filesystem version 6 or better will create directories
258 * using the ALG1 dirhash. This hash breaks the filename
259 * up into domains separated by special characters and
260 * hashes each domain independently.
262 * We also do a simple sub-sort using the first character
263 * of the filename in the top 5-bits.
265 key = 0;
268 * m32
270 crcx = 0;
271 for (i = j = 0; i < len; ++i) {
272 if (aname[i] == '.' ||
273 aname[i] == '-' ||
274 aname[i] == '_' ||
275 aname[i] == '~') {
276 if (i != j)
277 crcx += hammer2_icrc32(aname + j, i - j);
278 j = i + 1;
281 if (i != j)
282 crcx += hammer2_icrc32(aname + j, i - j);
285 * The directory hash utilizes the top 32 bits of the 64-bit key.
286 * Bit 63 must be set to 1.
288 crcx |= 0x80000000U;
289 key |= (uint64_t)crcx << 32;
292 * l16 - crc of entire filename
294 * This crc reduces degenerate hash collision conditions
296 crcx = hammer2_icrc32(aname, len);
297 crcx = crcx ^ (crcx << 16);
298 key |= crcx & 0xFFFF0000U;
301 * Set bit 15. This allows readdir to strip bit 63 so a positive
302 * 64-bit cookie/offset can always be returned, and still guarantee
303 * that the values 0x0000-0x7FFF are available for artificial entries.
304 * ('.' and '..').
306 key |= 0x8000U;
308 return (key);
311 char **
312 get_hammer2_mounts(int *acp)
314 struct statfs *fs;
315 char **av;
316 int n;
317 int w;
318 int i;
321 * Get a stable list of mount points
323 again:
324 n = getfsstat(NULL, 0, MNT_NOWAIT);
325 av = malloc(sizeof(char *) * n);
326 fs = malloc(sizeof(struct statfs *) * n);
327 if (getfsstat(fs, sizeof(*fs) * n, MNT_NOWAIT) != n) {
328 free(av);
329 free(fs);
330 goto again;
334 * Pull out hammer2 filesystems only
336 for (i = w = 0; i < n; ++i) {
337 if (strcmp(fs[i].f_fstypename, "hammer2") != 0)
338 continue;
339 av[w++] = strdup(fs[i].f_mntonname);
341 *acp = w;
343 return av;
346 void
347 put_hammer2_mounts(int ac, char **av)
349 while (--ac >= 0)
350 free(av[ac]);
351 free(av);