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