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