2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2001-2007 Miklos Szeredi
6 * Based on example shipped with FUSE.
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>.
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
20 #define FUSE_USE_VERSION 26
38 typedef struct private_cowfs_t private_cowfs_t
;
40 struct private_cowfs_t
{
41 /** public cowfs interface */
43 /** fuse channel to mountpoint */
44 struct fuse_chan
*chan
;
47 /** mountpoint of cowfs FUSE */
49 /** read only master filesystem */
51 /** copy on write overlay to master */
53 /** optional scenario COW overlay */
55 /** thread processing FUSE */
60 static int cowfs_getattr(const char *path
, struct stat
*stbuf
)
64 res
= lstat(path
, stbuf
);
71 static int cowfs_access(const char *path
, int mask
)
75 res
= access(path
, mask
);
82 static int cowfs_readlink(const char *path
, char *buf
, size_t size
)
86 res
= readlink(path
, buf
, size
- 1);
95 static int cowfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
96 off_t offset
, struct fuse_file_info
*fi
)
108 while ((de
= readdir(dp
)) != NULL
) {
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))
121 static int cowfs_mknod(const char *path
, mode_t mode
, dev_t rdev
)
125 res
= mknod(path
, mode
, rdev
);
132 static int cowfs_mkdir(const char *path
, mode_t mode
)
136 res
= mkdir(path
, mode
);
143 static int cowfs_unlink(const char *path
)
154 static int cowfs_rmdir(const char *path
)
165 static int cowfs_symlink(const char *from
, const char *to
)
169 res
= symlink(from
, to
);
176 static int cowfs_rename(const char *from
, const char *to
)
180 res
= rename(from
, to
);
187 static int cowfs_link(const char *from
, const char *to
)
191 res
= link(from
, to
);
198 static int cowfs_chmod(const char *path
, mode_t mode
)
202 res
= chmod(path
, mode
);
209 static int cowfs_chown(const char *path
, uid_t uid
, gid_t gid
)
213 res
= lchown(path
, uid
, gid
);
220 static int cowfs_truncate(const char *path
, off_t size
)
224 res
= truncate(path
, size
);
231 static int cowfs_utimens(const char *path
, const struct timespec ts
[2])
234 struct timeval tv
[2];
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;
241 res
= utimes(path
, tv
);
248 static int cowfs_open(const char *path
, struct fuse_file_info
*fi
)
252 res
= open(path
, fi
->flags
);
260 static int cowfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
261 struct fuse_file_info
*fi
)
267 fd
= open(path
, O_RDONLY
);
271 res
= pread(fd
, buf
, size
, offset
);
279 static int cowfs_write(const char *path
, const char *buf
, size_t size
,
280 off_t offset
, struct fuse_file_info
*fi
)
286 fd
= open(path
, O_WRONLY
);
290 res
= pwrite(fd
, buf
, size
, offset
);
298 static int cowfs_statfs(const char *path
, struct statvfs
*stbuf
)
302 res
= statvfs(path
, stbuf
);
309 static void *cowfs_init(struct fuse_conn_info
*conn
)
311 struct fuse_context
*ctx
;
313 ctx
= fuse_get_context();
315 return ctx
->private_data
;
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
,
330 .chmod
= cowfs_chmod
,
331 .chown
= cowfs_chown
,
332 .truncate
= cowfs_truncate
,
333 .utimens
= cowfs_utimens
,
336 .write
= cowfs_write
,
337 .statfs
= cowfs_statfs
,
342 * Implementation of cowfs_t.set_scenario.
344 static void set_scenario(private_cowfs_t
*this, char *path
)
346 free(this->scenario
);
347 this->scenario
= path ?
strdup(path
) : NULL
;
351 * stop, umount and destroy a cowfs FUSE filesystem
353 static void destroy(private_cowfs_t
*this)
355 fuse_exit(this->fuse
);
356 pthread_join(this->thread
, NULL
);
357 fuse_unmount(this->mount
, this->chan
);
358 fuse_destroy(this->fuse
);
362 free(this->scenario
);
367 * creates a new cowfs fuse instance
369 cowfs_t
*cowfs_create(char *master
, char *host
, char *mount
)
371 struct fuse_args args
= {0, NULL
, 0};
372 private_cowfs_t
*this = malloc_thing(private_cowfs_t
);
374 this->public.set_scenario
= (void(*)(cowfs_t
*, char *path
))set_scenario
;
375 this->public.destroy
= (void(*)(cowfs_t
*))destroy
;
377 this->chan
= fuse_mount(mount
, &args
);
378 if (this->chan
== NULL
)
380 DBG1("mounting cowfs FUSE on '%s' failed", mount
);
385 this->fuse
= fuse_new(this->chan
, &args
, &cowfs_operations
,
386 sizeof(cowfs_operations
), this);
387 if (this->fuse
== NULL
)
389 DBG1("creating cowfs FUSE handle failed");
390 fuse_unmount(mount
, this->chan
);
395 this->mount
= strdup(mount
);
396 this->master
= strdup(master
);
397 this->host
= strdup(host
);
398 this->scenario
= NULL
;
400 if (pthread_create(&this->thread
, NULL
, (void*)fuse_loop_mt
, this->fuse
) != 0)
402 DBG1("creating thread to handle FUSE failed");
403 fuse_unmount(mount
, this->chan
);
411 return &this->public;