xref: /dragonfly/sbin/hammer2/cmd_setcomp.c (revision f2c43266)
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