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