ac9823db7cecbf38b1ca6a5fc51953823804adb8
[strongswan.git] / src / dumm / cowfs.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2001-2007 Miklos Szeredi
5 *
6 * Based on example shipped with FUSE.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19
20 #define FUSE_USE_VERSION 26
21
22 #include <fuse.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <sys/time.h>
31 #include <pthread.h>
32
33 #include "cowfs.h"
34
35 #include <library.h>
36 #include <debug.h>
37
38 typedef struct private_cowfs_t private_cowfs_t;
39
40 struct private_cowfs_t {
41 /** public cowfs interface */
42 cowfs_t public;
43 /** fuse channel to mountpoint */
44 struct fuse_chan *chan;
45 /** fuse handle */
46 struct fuse *fuse;
47 /** mountpoint of cowfs FUSE */
48 char *mount;
49 /** read only master filesystem */
50 char *master;
51 /** copy on write overlay to master */
52 char *host;
53 /** optional scenario COW overlay */
54 char *scenario;
55 /** thread processing FUSE */
56 pthread_t thread;
57 };
58
59
60 static int cowfs_getattr(const char *path, struct stat *stbuf)
61 {
62 int res;
63
64 res = lstat(path, stbuf);
65 if (res == -1)
66 return -errno;
67
68 return 0;
69 }
70
71 static int cowfs_access(const char *path, int mask)
72 {
73 int res;
74
75 res = access(path, mask);
76 if (res == -1)
77 return -errno;
78
79 return 0;
80 }
81
82 static int cowfs_readlink(const char *path, char *buf, size_t size)
83 {
84 int res;
85
86 res = readlink(path, buf, size - 1);
87 if (res == -1)
88 return -errno;
89
90 buf[res] = '\0';
91 return 0;
92 }
93
94
95 static int cowfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
96 off_t offset, struct fuse_file_info *fi)
97 {
98 DIR *dp;
99 struct dirent *de;
100
101 (void) offset;
102 (void) fi;
103
104 dp = opendir(path);
105 if (dp == NULL)
106 return -errno;
107
108 while ((de = readdir(dp)) != NULL) {
109 struct stat st;
110 memset(&st, 0, sizeof(st));
111 st.st_ino = de->d_ino;
112 st.st_mode = de->d_type << 12;
113 if (filler(buf, de->d_name, &st, 0))
114 break;
115 }
116
117 closedir(dp);
118 return 0;
119 }
120
121 static int cowfs_mknod(const char *path, mode_t mode, dev_t rdev)
122 {
123 int res;
124
125 res = mknod(path, mode, rdev);
126 if (res == -1)
127 return -errno;
128
129 return 0;
130 }
131
132 static int cowfs_mkdir(const char *path, mode_t mode)
133 {
134 int res;
135
136 res = mkdir(path, mode);
137 if (res == -1)
138 return -errno;
139
140 return 0;
141 }
142
143 static int cowfs_unlink(const char *path)
144 {
145 int res;
146
147 res = unlink(path);
148 if (res == -1)
149 return -errno;
150
151 return 0;
152 }
153
154 static int cowfs_rmdir(const char *path)
155 {
156 int res;
157
158 res = rmdir(path);
159 if (res == -1)
160 return -errno;
161
162 return 0;
163 }
164
165 static int cowfs_symlink(const char *from, const char *to)
166 {
167 int res;
168
169 res = symlink(from, to);
170 if (res == -1)
171 return -errno;
172
173 return 0;
174 }
175
176 static int cowfs_rename(const char *from, const char *to)
177 {
178 int res;
179
180 res = rename(from, to);
181 if (res == -1)
182 return -errno;
183
184 return 0;
185 }
186
187 static int cowfs_link(const char *from, const char *to)
188 {
189 int res;
190
191 res = link(from, to);
192 if (res == -1)
193 return -errno;
194
195 return 0;
196 }
197
198 static int cowfs_chmod(const char *path, mode_t mode)
199 {
200 int res;
201
202 res = chmod(path, mode);
203 if (res == -1)
204 return -errno;
205
206 return 0;
207 }
208
209 static int cowfs_chown(const char *path, uid_t uid, gid_t gid)
210 {
211 int res;
212
213 res = lchown(path, uid, gid);
214 if (res == -1)
215 return -errno;
216
217 return 0;
218 }
219
220 static int cowfs_truncate(const char *path, off_t size)
221 {
222 int res;
223
224 res = truncate(path, size);
225 if (res == -1)
226 return -errno;
227
228 return 0;
229 }
230
231 static int cowfs_utimens(const char *path, const struct timespec ts[2])
232 {
233 int res;
234 struct timeval tv[2];
235
236 tv[0].tv_sec = ts[0].tv_sec;
237 tv[0].tv_usec = ts[0].tv_nsec / 1000;
238 tv[1].tv_sec = ts[1].tv_sec;
239 tv[1].tv_usec = ts[1].tv_nsec / 1000;
240
241 res = utimes(path, tv);
242 if (res == -1)
243 return -errno;
244
245 return 0;
246 }
247
248 static int cowfs_open(const char *path, struct fuse_file_info *fi)
249 {
250 int res;
251
252 res = open(path, fi->flags);
253 if (res == -1)
254 return -errno;
255
256 close(res);
257 return 0;
258 }
259
260 static int cowfs_read(const char *path, char *buf, size_t size, off_t offset,
261 struct fuse_file_info *fi)
262 {
263 int fd;
264 int res;
265
266 (void) fi;
267 fd = open(path, O_RDONLY);
268 if (fd == -1)
269 return -errno;
270
271 res = pread(fd, buf, size, offset);
272 if (res == -1)
273 res = -errno;
274
275 close(fd);
276 return res;
277 }
278
279 static int cowfs_write(const char *path, const char *buf, size_t size,
280 off_t offset, struct fuse_file_info *fi)
281 {
282 int fd;
283 int res;
284
285 (void) fi;
286 fd = open(path, O_WRONLY);
287 if (fd == -1)
288 return -errno;
289
290 res = pwrite(fd, buf, size, offset);
291 if (res == -1)
292 res = -errno;
293
294 close(fd);
295 return res;
296 }
297
298 static int cowfs_statfs(const char *path, struct statvfs *stbuf)
299 {
300 int res;
301
302 res = statvfs(path, stbuf);
303 if (res == -1)
304 return -errno;
305
306 return 0;
307 }
308
309 static void *cowfs_init(struct fuse_conn_info *conn)
310 {
311 struct fuse_context *ctx;
312
313 ctx = fuse_get_context();
314
315 return ctx->private_data;
316 }
317
318 static struct fuse_operations cowfs_operations = {
319 .getattr = cowfs_getattr,
320 .access = cowfs_access,
321 .readlink = cowfs_readlink,
322 .readdir = cowfs_readdir,
323 .mknod = cowfs_mknod,
324 .mkdir = cowfs_mkdir,
325 .symlink = cowfs_symlink,
326 .unlink = cowfs_unlink,
327 .rmdir = cowfs_rmdir,
328 .rename = cowfs_rename,
329 .link = cowfs_link,
330 .chmod = cowfs_chmod,
331 .chown = cowfs_chown,
332 .truncate = cowfs_truncate,
333 .utimens = cowfs_utimens,
334 .open = cowfs_open,
335 .read = cowfs_read,
336 .write = cowfs_write,
337 .statfs = cowfs_statfs,
338 .init = cowfs_init,
339 };
340
341 /**
342 * Implementation of cowfs_t.set_scenario.
343 */
344 static void set_scenario(private_cowfs_t *this, char *path)
345 {
346 free(this->scenario);
347 this->scenario = path ? strdup(path) : NULL;
348 }
349
350 /**
351 * stop, umount and destroy a cowfs FUSE filesystem
352 */
353 static void destroy(private_cowfs_t *this)
354 {
355 fuse_exit(this->fuse);
356 pthread_join(this->thread, NULL);
357 fuse_unmount(this->mount, this->chan);
358 fuse_destroy(this->fuse);
359 free(this->mount);
360 free(this->master);
361 free(this->host);
362 free(this->scenario);
363 free(this);
364 }
365
366 /**
367 * creates a new cowfs fuse instance
368 */
369 cowfs_t *cowfs_create(char *master, char *host, char *mount)
370 {
371 struct fuse_args args = {0, NULL, 0};
372 private_cowfs_t *this = malloc_thing(private_cowfs_t);
373
374 this->public.set_scenario = (void(*)(cowfs_t*, char *path))set_scenario;
375 this->public.destroy = (void(*)(cowfs_t*))destroy;
376
377 this->chan = fuse_mount(mount, &args);
378 if (this->chan == NULL)
379 {
380 DBG1("mounting cowfs FUSE on '%s' failed", mount);
381 free(this);
382 return NULL;
383 }
384
385 this->fuse = fuse_new(this->chan, &args, &cowfs_operations,
386 sizeof(cowfs_operations), this);
387 if (this->fuse == NULL)
388 {
389 DBG1("creating cowfs FUSE handle failed");
390 fuse_unmount(mount, this->chan);
391 free(this);
392 return NULL;
393 }
394
395 this->mount = strdup(mount);
396 this->master = strdup(master);
397 this->host = strdup(host);
398 this->scenario = NULL;
399
400 if (pthread_create(&this->thread, NULL, (void*)fuse_loop_mt, this->fuse) != 0)
401 {
402 DBG1("creating thread to handle FUSE failed");
403 fuse_unmount(mount, this->chan);
404 free(this->mount);
405 free(this->master);
406 free(this->host);
407 free(this);
408 return NULL;
409 }
410
411 return &this->public;
412 }
413