Merge branch 'vendor/FILE'
[dragonfly.git] / sbin / hammer2 / cmd_setcomp.c
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