4 * This is the shadowfuse main startup file.
6 * Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
8 * Copyright (C) 2013 AIT Austrian Institute of Technology
9 * AIT Austrian Institute of Technology GmbH
10 * Donau-City-Strasse 1 | 1220 Vienna | Austria
11 * http://www.ait.ac.at
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation version 2.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
29 // ------------------------------------------------------------
35 // ------------------------------------------------------------
42 #define SHADOWFUSE_VERSION "0.1"
45 // ------------------------------------------------------------
50 * keys for FUSE_OPT_ options
59 * array of options we know
61 static struct fuse_opt shadowfuse_opts[] = {
62 FUSE_OPT_KEY("-V", KEY_VERSION),
63 FUSE_OPT_KEY("--version", KEY_VERSION),
64 FUSE_OPT_KEY("-h", KEY_HELP),
65 FUSE_OPT_KEY("--help", KEY_HELP),
71 * configuration of shadowfuse
73 static struct shadowfuse_config {
75 std::string sShadowedPath;
76 std::string sMountPoint;
79 * check for paths been set
81 inline bool is_paths_set() const { return !(sShadowedPath.empty() || sMountPoint.empty()); };
83 } g_cShadowFuseConfig;
86 // ------------------------------------------------------------
89 static int option_processor(void * cData, const char * sArg, int nKey, struct fuse_args * cOutArgs);
90 static void usage(const char * sProgName);
93 // ------------------------------------------------------------
99 * get file attributes.
101 static int shadow_getattr(const char * sPath, struct stat * cFileStat) {
103 // open the shadow file
104 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
105 std::cerr << "=== INSERT HOOK HERE. Getting file attributes of " << sShadow << std::endl;
107 memset(cFileStat, 0, sizeof(struct stat));
108 if (stat(sShadow.c_str(), cFileStat) == -1) return -errno;
118 static int shadow_mkdir(const char * sPath, mode_t cMode) {
121 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
122 std::cerr << "=== INSERT HOOK HERE. Create directory " << sShadow << std::endl;
124 if (mkdir(sShadow.c_str(), cMode) == -1) return -errno;
132 static int shadow_mknod(const char * sPath, mode_t cMode, dev_t cDev) {
135 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
136 std::cerr << "=== INSERT HOOK HERE. Create file " << sShadow << std::endl;
138 if (mknod(sShadow.c_str(), cMode, cDev) == -1) return -errno;
146 static int shadow_open(const char * sPath, struct fuse_file_info * cFileInfo) {
148 // open the shadow file
149 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
150 std::cerr << "=== INSERT HOOK HERE. Opening file " << sShadow << std::endl;
152 if (open(sShadow.c_str(), cFileInfo->flags) == -1) return -errno;
160 static int shadow_read(const char * sPath, char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) {
162 // read from shadow file
163 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
164 std::cerr << "=== INSERT HOOK HERE. Reading file " << sShadow << " [offset=" << nOffset << ", fetch max bytes=" << nSize << "]" << std::endl;
166 // open, pick bytes, close & out
167 int fd = open(sShadow.c_str(), O_RDONLY);
168 if (fd == -1) return -errno;
169 int res = pread(fd, cBuffer, nSize, nOffset);
170 if (res == -1) res = -errno;
180 static int shadow_readdir(const char * sPath, void * cBuffer, fuse_fill_dir_t fFiller, UNUSED off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) {
183 struct dirent * cDirEntry;
186 // open the shadow folder
187 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
188 std::cerr << "=== INSERT HOOK HERE. Reading content of " << sShadow << std::endl;
190 cDIR = opendir(sShadow.c_str());
191 if (!cDIR) return -errno;
193 // walk over the entries
194 while ((cDirEntry = readdir(cDIR)) != NULL) {
196 // pick file stat as well
197 struct stat cFileStat;
198 stat(sShadow.c_str(), &cFileStat);
199 res = fFiller(cBuffer, cDirEntry->d_name, &cFileStat, 0);
212 static int shadow_rename(const char * sFromPath, const char * sToPath) {
215 std::string sShadowFrom = g_cShadowFuseConfig.sShadowedPath + sFromPath;
216 std::string sShadowTo = g_cShadowFuseConfig.sShadowedPath + sToPath;
217 std::cerr << "=== INSERT HOOK HERE. Moving file from " << sShadowFrom << " to " << sShadowTo << std::endl;
219 if (rename(sShadowFrom.c_str(), sShadowTo.c_str()) == -1) return -errno;
227 static int shadow_rmdir(const char * sPath) {
229 // delete the shadow folder
230 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
231 std::cerr << "=== INSERT HOOK HERE. Delete folder " << sShadow << std::endl;
233 if (rmdir(sShadow.c_str()) == -1) return -errno;
241 static int shadow_unlink(const char * sPath) {
243 // delete the shadow file
244 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
245 std::cerr << "=== INSERT HOOK HERE. Delete file " << sShadow << std::endl;
247 if (unlink(sShadow.c_str()) == -1) return -errno;
255 static int shadow_write(const char * sPath, const char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) {
258 std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
259 std::cerr << "=== INSERT HOOK HERE. Write into file " << sShadow << std::endl;
261 // open, push bytes, close & out
262 int fd = open(sShadow.c_str(), O_WRONLY);
263 if (fd == -1) return -errno;
264 int res = pwrite(fd, cBuffer, nSize, nOffset);
265 if (res == -1) res = -errno;
273 * the shadowfuse function table
275 static struct fuse_operations shadowfuse_operations {
277 shadow_getattr, // getattr
280 shadow_mknod, // mknod
281 shadow_mkdir, // mkdir
282 shadow_unlink, // unlink
283 shadow_rmdir, // rmdir
285 shadow_rename, // rename
293 shadow_write, // write
300 nullptr, // listxattr
301 nullptr, // removexattr
303 shadow_readdir, // readdir
304 nullptr, // releasedir
310 nullptr, // ftruncate
315 0, // flag_nullpath_ok
317 0, // flag_utime_omit_ok
321 nullptr, // write_buf
331 * @param argc as usual
332 * @param argv as usual
335 int main(int argc, char ** argv) {
338 struct fuse_args cFUSEArgs = FUSE_ARGS_INIT(argc, argv);
339 if (fuse_opt_parse(&cFUSEArgs, NULL, shadowfuse_opts, option_processor) == -1) {
343 // test if our config is setup ok
344 if (!g_cShadowFuseConfig.is_paths_set()) {
345 std::cerr << "sourcefolder and/or mount point not given" << std::endl;
350 int ret = fuse_main(cFUSEArgs.argc, cFUSEArgs.argv, &shadowfuse_operations, NULL);
351 if (ret) printf("\n");
352 fuse_opt_free_args(&cFUSEArgs);
359 * option parser processor
361 * @param cData is the user data passed to the fuse_opt_parse() function
362 * @param sArg is the whole argument or option
363 * @param nKey determines why the processing function was called
364 * @param cOutArgs the current output argument list
365 * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
367 static int option_processor(UNUSED void * cData, UNUSED const char * sArg, int nKey, struct fuse_args * cOutArgs) {
372 case FUSE_OPT_KEY_OPT:
375 case FUSE_OPT_KEY_NONOPT:
377 if (g_cShadowFuseConfig.sShadowedPath.empty()) {
378 // first non-option is the path to be shadowed
379 g_cShadowFuseConfig.sShadowedPath = sArg;
383 if (g_cShadowFuseConfig.sMountPoint.empty()) {
385 g_cShadowFuseConfig.sMountPoint = sArg;
391 usage(cOutArgs->argv[0]);
395 printf("shadowfuse version %s\n", SHADOWFUSE_VERSION);
399 fprintf(stderr, "internal error\n");
408 * @param sProgName name of the current program
410 static void usage(const char * sProgName) {
412 "usage: %s sourcefolder mountpoint\n"
416 " -d -odebug foreground, but keep the debug option\n"
417 " -h --help print help\n"
418 " -V --version print version\n"