1 /* 2 * Copyright (c) 2013 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 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "hammer2.h" 36 37 static int cmd_setcomp_core(uint8_t comp_algo, const char *path_str, 38 struct stat *st); 39 40 int 41 cmd_setcomp(const char *comp_str, char **paths) 42 { 43 static const char *comps[] = HAMMER2_COMP_STRINGS; 44 struct stat st; 45 int comp_algo; 46 int comp_level; 47 int ecode; 48 int res; 49 char *str; 50 const char *s1; 51 const char *s2; 52 53 str = strdup(comp_str); 54 s1 = strtok(str, ":"); 55 s2 = s1 ? strtok(NULL, ":") : NULL; 56 ecode = 0; 57 58 if (isdigit(s1[0])) { 59 comp_algo = strtol(s1, NULL, 0); 60 } else { 61 comp_algo = HAMMER2_COMP_STRINGS_COUNT; 62 while (--comp_algo >= 0) { 63 if (strcasecmp(s1, comps[comp_algo]) == 0) 64 break; 65 } 66 if (comp_algo < 0 && strcasecmp(s1, "default") == 0) { 67 comp_algo = HAMMER2_COMP_LZ4; 68 s1 = "lz4"; 69 } 70 if (comp_algo < 0 && strcasecmp(s1, "disabled") == 0) { 71 comp_algo = HAMMER2_COMP_AUTOZERO; 72 s1 = "autozero"; 73 } 74 if (comp_algo < 0) { 75 fprintf(stderr, "Unknown compression type: %s\n", s1); 76 ecode = 3; 77 } 78 } 79 if (s2 == NULL) { 80 comp_level = 0; 81 } else if (isdigit(s2[0])) { 82 comp_level = strtol(s2, NULL, 0); 83 } else if (strcasecmp(s2, "default") == 0) { 84 comp_level = 0; 85 } else { 86 comp_level = 0; 87 fprintf(stderr, "Unknown compression level: %s\n", s2); 88 ecode = 3; 89 } 90 91 if (comp_level) { 92 switch(comp_algo) { 93 case HAMMER2_COMP_ZLIB: 94 if (comp_level < 6 || comp_level > 9) { 95 fprintf(stderr, 96 "Unsupported comp_level %d for %s\n", 97 comp_level, s1); 98 ecode = 3; 99 } 100 break; 101 default: 102 fprintf(stderr, 103 "Unsupported comp_level %d for %s\n", 104 comp_level, s1); 105 ecode = 3; 106 } 107 } 108 109 if (ecode == 0) { 110 while (*paths) { 111 if (lstat(*paths, &st) == 0) { 112 res = cmd_setcomp_core( 113 HAMMER2_ENC_ALGO(comp_algo) | 114 HAMMER2_ENC_LEVEL(comp_level), 115 *paths, 116 &st); 117 if (res) 118 ecode = res; 119 } else { 120 printf("%s: %s\n", *paths, strerror(errno)); 121 ecode = 3; 122 } 123 ++paths; 124 } 125 } 126 free (str); 127 128 return ecode; 129 } 130 131 static int 132 cmd_setcomp_core(uint8_t comp_algo, const char *path_str, struct stat *st) 133 { 134 hammer2_ioc_inode_t inode; 135 int fd; 136 int res; 137 138 fd = hammer2_ioctl_handle(path_str); 139 if (fd < 0) { 140 res = 3; 141 goto failed; 142 } 143 res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode); 144 if (res < 0) { 145 fprintf(stderr, 146 "%s: HAMMER2IOC_INODE_GET: error %s\n", 147 path_str, strerror(errno)); 148 res = 3; 149 goto failed; 150 } 151 printf("%s\tcomp_algo=0x%02x\n", path_str, comp_algo); 152 inode.ip_data.comp_algo = comp_algo; 153 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 154 if (res < 0) { 155 fprintf(stderr, 156 "%s: HAMMER2IOC_INODE_SET: error %s\n", 157 path_str, strerror(errno)); 158 res = 3; 159 goto failed; 160 } 161 res = 0; 162 163 if (RecurseOpt && S_ISDIR(st->st_mode)) { 164 DIR *dir; 165 char *path; 166 struct dirent *den; 167 168 if ((dir = fdopendir(fd)) != NULL) { 169 while ((den = readdir(dir)) != NULL) { 170 if (strcmp(den->d_name, ".") == 0 || 171 strcmp(den->d_name, "..") == 0) { 172 continue; 173 } 174 asprintf(&path, "%s/%s", path_str, den->d_name); 175 if (lstat(path, st) == 0) 176 cmd_setcomp_core(comp_algo, path, st); 177 free(path); 178 } 179 closedir(dir); 180 } 181 } 182 failed: 183 close(fd); 184 return res; 185 } 186 187 #if 0 188 189 int 190 cmd_setcomp_recursive(char* option_string, char* comp_string, char* file_string) 191 { 192 int ecode = 0; 193 int set_files; 194 int comp_method; 195 196 if (strcmp(option_string, "-r") == 0) { 197 set_files = 0; 198 } else if (strcmp(option_string, "-rf") == 0) { 199 set_files = 1; 200 } else { 201 printf("setcomp: Unrecognized option.\n"); 202 exit(1); 203 } 204 if (strcmp(comp_string, "0") == 0) { 205 printf("Will turn off compression on directory/file %s\n", file_string); 206 comp_method = HAMMER2_COMP_NONE; 207 } else if (strcmp(comp_string, "1") == 0) { 208 printf("Will set zero-checking compression on directory/file %s.\n", file_string); 209 comp_method = HAMMER2_COMP_AUTOZERO; 210 } else if (strcmp(comp_string, "2") == 0) { 211 printf("Will set LZ4 compression on directory/file %s.\n", file_string); 212 comp_method = HAMMER2_COMP_LZ4; 213 } else if (strcmp(comp_string, "3") == 0) { 214 printf("Will set ZLIB (slowest) compression on directory/file %s.\n", file_string); 215 comp_method = HAMMER2_COMP_ZLIB; 216 } 217 else { 218 printf("Unknown compression method.\n"); 219 return 1; 220 } 221 int fd = hammer2_ioctl_handle(file_string); 222 hammer2_ioc_inode_t inode; 223 int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode); 224 if (res < 0) { 225 fprintf(stderr, "ERROR before setting the mode: %s\n", strerror(errno)); 226 return 3; 227 } 228 if (inode.ip_data.type != HAMMER2_OBJTYPE_DIRECTORY) { 229 printf("setcomp: the specified object is not a directory, nothing changed.\n"); 230 return 1; 231 } 232 printf("Attention: recursive compression mode setting demanded, this may take a while...\n"); 233 ecode = setcomp_recursive_call(file_string, comp_method, set_files); 234 inode.ip_data.comp_algo = comp_method; 235 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 236 if (res < 0) { 237 if (errno != EINVAL) { 238 fprintf(stderr, "ERROR after trying to set the mode: %s\n", strerror(errno)); 239 return 3; 240 } 241 } 242 close(fd); 243 return ecode; 244 } 245 246 int 247 setcomp_recursive_call(char *directory, int comp_method, int set_files) 248 { 249 int ecode = 0; 250 DIR *dir; 251 if ((dir = opendir (directory)) == NULL) { 252 fprintf(stderr, "ERROR while trying to set the mode recursively: %s\n", 253 strerror(errno)); 254 return 3; 255 } 256 struct dirent *dent; 257 int lenght; 258 lenght = strlen(directory); 259 char name[HAMMER2_INODE_MAXNAME]; 260 strcpy(name, directory); 261 name[lenght] = '/'; 262 ++lenght; 263 errno = 0; 264 dent = readdir(dir); 265 while (dent != NULL && ecode == 0) { 266 if ((strcmp(dent->d_name, ".") != 0) && 267 (strcmp(dent->d_name, "..") != 0)) { 268 strncpy(name + lenght, dent->d_name, HAMMER2_INODE_MAXNAME - 269 lenght); 270 int fd = hammer2_ioctl_handle(name); 271 hammer2_ioc_inode_t inode; 272 int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode); 273 if (res < 0) { 274 fprintf(stderr, "ERROR during recursion: %s\n", 275 strerror(errno)); 276 return 3; 277 } 278 if (inode.ip_data.type == HAMMER2_OBJTYPE_DIRECTORY) { 279 ecode = setcomp_recursive_call(name, comp_method, set_files); 280 inode.ip_data.comp_algo = comp_method; 281 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 282 } 283 else { 284 if (set_files == 1 && inode.ip_data.type == 285 HAMMER2_OBJTYPE_REGFILE) { 286 inode.ip_data.comp_algo = comp_method; 287 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 288 } 289 } 290 if (res < 0) { 291 if (errno != EINVAL) { 292 fprintf(stderr, "ERROR during recursion after trying" 293 "to set the mode: %s\n", 294 strerror(errno)); 295 return 3; 296 } 297 } 298 close(fd); 299 } 300 errno = 0; //we must set errno to 0 before readdir() 301 dent = readdir(dir); 302 } 303 closedir(dir); 304 if (errno != 0) { 305 fprintf(stderr, "ERROR during iteration: %s\n", strerror(errno)); 306 return 3; 307 } 308 return ecode; 309 } 310 311 #endif 312