xref: /dragonfly/sbin/hammer2/subs.c (revision 47492050)
1 /*
2  * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
3  *
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>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
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.
21  *
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.
34  */
35 
36 #include "hammer2.h"
37 
38 /*
39  * Obtain a file descriptor that the caller can execute ioctl()'s on.
40  */
41 int
42 hammer2_ioctl_handle(const char *sel_path)
43 {
44 	struct hammer2_ioc_version info;
45 	int fd;
46 
47 	if (sel_path == NULL)
48 		sel_path = ".";
49 
50 	fd = open(sel_path, O_RDONLY, 0);
51 	if (fd < 0) {
52 		fprintf(stderr, "hammer2: Unable to open %s: %s\n",
53 			sel_path, strerror(errno));
54 		return(-1);
55 	}
56 	if (ioctl(fd, HAMMER2IOC_VERSION_GET, &info) < 0) {
57 		fprintf(stderr, "hammer2: '%s' is not a hammer2 filesystem\n",
58 			sel_path);
59 		close(fd);
60 		return(-1);
61 	}
62 	return (fd);
63 }
64 
65 const char *
66 hammer2_time64_to_str(uint64_t htime64, char **strp)
67 {
68 	struct tm *tp;
69 	time_t t;
70 
71 	if (*strp) {
72 		free(*strp);
73 		*strp = NULL;
74 	}
75 	*strp = malloc(64);
76 	t = htime64 / 1000000;
77 	tp = localtime(&t);
78 	strftime(*strp, 64, "%d-%b-%Y %H:%M:%S", tp);
79 	return (*strp);
80 }
81 
82 const char *
83 hammer2_uuid_to_str(uuid_t *uuid, char **strp)
84 {
85 	uint32_t status;
86 	if (*strp) {
87 		free(*strp);
88 		*strp = NULL;
89 	}
90 	uuid_to_string(uuid, strp, &status);
91 	return (*strp);
92 }
93 
94 const char *
95 hammer2_iptype_to_str(uint8_t type)
96 {
97 	switch(type) {
98 	case HAMMER2_OBJTYPE_UNKNOWN:
99 		return("UNKNOWN");
100 	case HAMMER2_OBJTYPE_DIRECTORY:
101 		return("DIR");
102 	case HAMMER2_OBJTYPE_REGFILE:
103 		return("FILE");
104 	case HAMMER2_OBJTYPE_FIFO:
105 		return("FIFO");
106 	case HAMMER2_OBJTYPE_CDEV:
107 		return("CDEV");
108 	case HAMMER2_OBJTYPE_BDEV:
109 		return("BDEV");
110 	case HAMMER2_OBJTYPE_SOFTLINK:
111 		return("SOFTLINK");
112 	case HAMMER2_OBJTYPE_SOCKET:
113 		return("SOCKET");
114 	case HAMMER2_OBJTYPE_WHITEOUT:
115 		return("WHITEOUT");
116 	default:
117 		return("ILLEGAL");
118 	}
119 }
120 
121 const char *
122 hammer2_pfstype_to_str(uint8_t type)
123 {
124 	switch(type) {
125 	case HAMMER2_PFSTYPE_NONE:
126 		return("NONE");
127 	case HAMMER2_PFSTYPE_SUPROOT:
128 		return("SUPROOT");
129 	case HAMMER2_PFSTYPE_DUMMY:
130 		return("DUMMY");
131 	case HAMMER2_PFSTYPE_CACHE:
132 		return("CACHE");
133 	case HAMMER2_PFSTYPE_SLAVE:
134 		return("SLAVE");
135 	case HAMMER2_PFSTYPE_SOFT_SLAVE:
136 		return("SOFT_SLAVE");
137 	case HAMMER2_PFSTYPE_SOFT_MASTER:
138 		return("SOFT_MASTER");
139 	case HAMMER2_PFSTYPE_MASTER:
140 		return("MASTER");
141 	default:
142 		return("ILLEGAL");
143 	}
144 }
145 
146 const char *
147 sizetostr(hammer2_off_t size)
148 {
149 	static char buf[32];
150 
151 	if (size < 1024 / 2) {
152 		snprintf(buf, sizeof(buf), "%6.2f", (double)size);
153 	} else if (size < 1024 * 1024 / 2) {
154 		snprintf(buf, sizeof(buf), "%6.2fKB",
155 			(double)size / 1024);
156 	} else if (size < 1024 * 1024 * 1024LL / 2) {
157 		snprintf(buf, sizeof(buf), "%6.2fMB",
158 			(double)size / (1024 * 1024));
159 	} else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
160 		snprintf(buf, sizeof(buf), "%6.2fGB",
161 			(double)size / (1024 * 1024 * 1024LL));
162 	} else {
163 		snprintf(buf, sizeof(buf), "%6.2fTB",
164 			(double)size / (1024 * 1024 * 1024LL * 1024LL));
165 	}
166 	return(buf);
167 }
168 
169 const char *
170 counttostr(hammer2_off_t size)
171 {
172 	static char buf[32];
173 
174 	if (size < 1024 / 2) {
175 		snprintf(buf, sizeof(buf), "%jd",
176 			 (intmax_t)size);
177 	} else if (size < 1024 * 1024 / 2) {
178 		snprintf(buf, sizeof(buf), "%jd",
179 			 (intmax_t)size);
180 	} else if (size < 1024 * 1024 * 1024LL / 2) {
181 		snprintf(buf, sizeof(buf), "%6.2fM",
182 			 (double)size / (1024 * 1024));
183 	} else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
184 		snprintf(buf, sizeof(buf), "%6.2fG",
185 			 (double)(size / (1024 * 1024 * 1024LL)));
186 	} else {
187 		snprintf(buf, sizeof(buf), "%6.2fT",
188 			 (double)(size / (1024 * 1024 * 1024LL * 1024LL)));
189 	}
190 	return(buf);
191 }
192 
193 /*
194  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
195  * The filename is split into fields which are hashed separately and then
196  * added together.
197  *
198  * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
199  * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
200  * (This means we do not need to do a 0-check/or-with-0x100000000 either).
201  *
202  * Also, the iscsi crc code is used instead of the old crc32 code.
203  */
204 hammer2_key_t
205 dirhash(const unsigned char *name, size_t len)
206 {
207 	const unsigned char *aname = name;
208 	uint32_t crcx;
209 	uint64_t key;
210 	size_t i;
211 	size_t j;
212 
213 	/*
214 	 * Filesystem version 6 or better will create directories
215 	 * using the ALG1 dirhash.  This hash breaks the filename
216 	 * up into domains separated by special characters and
217 	 * hashes each domain independently.
218 	 *
219 	 * We also do a simple sub-sort using the first character
220 	 * of the filename in the top 5-bits.
221 	 */
222 	key = 0;
223 
224 	/*
225 	 * m32
226 	 */
227 	crcx = 0;
228 	for (i = j = 0; i < len; ++i) {
229 		if (aname[i] == '.' ||
230 		    aname[i] == '-' ||
231 		    aname[i] == '_' ||
232 		    aname[i] == '~') {
233 			if (i != j)
234 				crcx += hammer2_icrc32(aname + j, i - j);
235 			j = i + 1;
236 		}
237 	}
238 	if (i != j)
239 		crcx += hammer2_icrc32(aname + j, i - j);
240 
241 	/*
242 	 * The directory hash utilizes the top 32 bits of the 64-bit key.
243 	 * Bit 63 must be set to 1.
244 	 */
245 	crcx |= 0x80000000U;
246 	key |= (uint64_t)crcx << 32;
247 
248 	/*
249 	 * l16 - crc of entire filename
250 	 *
251 	 * This crc reduces degenerate hash collision conditions
252 	 */
253 	crcx = hammer2_icrc32(aname, len);
254 	crcx = crcx ^ (crcx << 16);
255 	key |= crcx & 0xFFFF0000U;
256 
257 	/*
258 	 * Set bit 15.  This allows readdir to strip bit 63 so a positive
259 	 * 64-bit cookie/offset can always be returned, and still guarantee
260 	 * that the values 0x0000-0x7FFF are available for artificial entries.
261 	 * ('.' and '..').
262 	 */
263 	key |= 0x8000U;
264 
265 	return (key);
266 }
267