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.flags |= HAMMER2IOC_INODE_FLAG_COMP; 153 inode.ip_data.meta.comp_algo = comp_algo; 154 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 155 if (res < 0) { 156 fprintf(stderr, 157 "%s: HAMMER2IOC_INODE_SET: error %s\n", 158 path_str, strerror(errno)); 159 res = 3; 160 goto failed; 161 } 162 res = 0; 163 164 if (RecurseOpt && S_ISDIR(st->st_mode)) { 165 DIR *dir; 166 char *path; 167 struct dirent *den; 168 169 if ((dir = fdopendir(fd)) != NULL) { 170 while ((den = readdir(dir)) != NULL) { 171 if (strcmp(den->d_name, ".") == 0 || 172 strcmp(den->d_name, "..") == 0) { 173 continue; 174 } 175 asprintf(&path, "%s/%s", path_str, den->d_name); 176 if (lstat(path, st) == 0) 177 cmd_setcomp_core(comp_algo, path, st); 178 free(path); 179 } 180 closedir(dir); 181 } 182 } 183 failed: 184 close(fd); 185 return res; 186 } 187 188 #if 0 189 190 int 191 cmd_setcomp_recursive(char* option_string, char* comp_string, char* file_string) 192 { 193 int ecode = 0; 194 int set_files; 195 int comp_method; 196 197 if (strcmp(option_string, "-r") == 0) { 198 set_files = 0; 199 } else if (strcmp(option_string, "-rf") == 0) { 200 set_files = 1; 201 } else { 202 printf("setcomp: Unrecognized option.\n"); 203 exit(1); 204 } 205 if (strcmp(comp_string, "0") == 0) { 206 printf("Will turn off compression on directory/file %s\n", file_string); 207 comp_method = HAMMER2_COMP_NONE; 208 } else if (strcmp(comp_string, "1") == 0) { 209 printf("Will set zero-checking compression on directory/file %s.\n", file_string); 210 comp_method = HAMMER2_COMP_AUTOZERO; 211 } else if (strcmp(comp_string, "2") == 0) { 212 printf("Will set LZ4 compression on directory/file %s.\n", file_string); 213 comp_method = HAMMER2_COMP_LZ4; 214 } else if (strcmp(comp_string, "3") == 0) { 215 printf("Will set ZLIB (slowest) compression on directory/file %s.\n", file_string); 216 comp_method = HAMMER2_COMP_ZLIB; 217 } 218 else { 219 printf("Unknown compression method.\n"); 220 return 1; 221 } 222 int fd = hammer2_ioctl_handle(file_string); 223 hammer2_ioc_inode_t inode; 224 int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode); 225 if (res < 0) { 226 fprintf(stderr, "ERROR before setting the mode: %s\n", strerror(errno)); 227 return 3; 228 } 229 if (inode.ip_data.type != HAMMER2_OBJTYPE_DIRECTORY) { 230 printf("setcomp: the specified object is not a directory, nothing changed.\n"); 231 return 1; 232 } 233 printf("Attention: recursive compression mode setting demanded, this may take a while...\n"); 234 ecode = setcomp_recursive_call(file_string, comp_method, set_files); 235 inode.ip_data.comp_algo = comp_method; 236 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 237 if (res < 0) { 238 if (errno != EINVAL) { 239 fprintf(stderr, "ERROR after trying to set the mode: %s\n", strerror(errno)); 240 return 3; 241 } 242 } 243 close(fd); 244 return ecode; 245 } 246 247 int 248 setcomp_recursive_call(char *directory, int comp_method, int set_files) 249 { 250 int ecode = 0; 251 DIR *dir; 252 if ((dir = opendir (directory)) == NULL) { 253 fprintf(stderr, "ERROR while trying to set the mode recursively: %s\n", 254 strerror(errno)); 255 return 3; 256 } 257 struct dirent *dent; 258 int length; 259 length = strlen(directory); 260 char name[HAMMER2_INODE_MAXNAME]; 261 strcpy(name, directory); 262 name[length] = '/'; 263 ++length; 264 errno = 0; 265 dent = readdir(dir); 266 while (dent != NULL && ecode == 0) { 267 if ((strcmp(dent->d_name, ".") != 0) && 268 (strcmp(dent->d_name, "..") != 0)) { 269 strncpy(name + length, dent->d_name, HAMMER2_INODE_MAXNAME - 270 length); 271 int fd = hammer2_ioctl_handle(name); 272 hammer2_ioc_inode_t inode; 273 int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode); 274 if (res < 0) { 275 fprintf(stderr, "ERROR during recursion: %s\n", 276 strerror(errno)); 277 return 3; 278 } 279 if (inode.ip_data.type == HAMMER2_OBJTYPE_DIRECTORY) { 280 ecode = setcomp_recursive_call(name, comp_method, set_files); 281 inode.ip_data.comp_algo = comp_method; 282 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 283 } 284 else { 285 if (set_files == 1 && inode.ip_data.type == 286 HAMMER2_OBJTYPE_REGFILE) { 287 inode.ip_data.comp_algo = comp_method; 288 res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode); 289 } 290 } 291 if (res < 0) { 292 if (errno != EINVAL) { 293 fprintf(stderr, "ERROR during recursion after trying" 294 "to set the mode: %s\n", 295 strerror(errno)); 296 return 3; 297 } 298 } 299 close(fd); 300 } 301 errno = 0; //we must set errno to 0 before readdir() 302 dent = readdir(dir); 303 } 304 closedir(dir); 305 if (errno != 0) { 306 fprintf(stderr, "ERROR during iteration: %s\n", strerror(errno)); 307 return 3; 308 } 309 return ecode; 310 } 311 312 #endif 313