om@2: /* om@2: * main.cpp om@2: * om@2: * This is the shadowfuse main startup file. om@2: * om@2: * Autor: Oliver Maurhart, om@2: * om@2: * Copyright (C) 2013 AIT Austrian Institute of Technology om@2: * AIT Austrian Institute of Technology GmbH om@2: * Donau-City-Strasse 1 | 1220 Vienna | Austria om@2: * http://www.ait.ac.at om@2: * om@2: * This program is free software; you can redistribute it and/or om@2: * modify it under the terms of the GNU General Public License om@2: * as published by the Free Software Foundation version 2. om@2: * om@2: * This program is distributed in the hope that it will be useful, om@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of om@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the om@2: * GNU General Public License for more details. om@2: * om@2: * You should have received a copy of the GNU General Public License om@2: * along with this program; if not, write to the Free Software om@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, om@2: * Boston, MA 02110-1301, USA. om@2: */ om@2: om@2: om@2: // ------------------------------------------------------------ om@2: // incs om@2: om@2: #include "baseinc.h" om@2: om@2: om@2: // ------------------------------------------------------------ om@2: // defs om@2: om@2: om@2: /** om@2: * shadowfuse version om@2: */ om@2: #define SHADOWFUSE_VERSION "0.1" om@2: om@2: om@2: // ------------------------------------------------------------ om@2: // vars om@2: om@2: om@2: /** om@2: * keys for FUSE_OPT_ options om@2: */ om@2: enum { om@2: KEY_VERSION, om@2: KEY_HELP, om@2: }; om@2: om@2: om@2: /** om@2: * array of options we know om@2: */ om@2: static struct fuse_opt shadowfuse_opts[] = { om@2: FUSE_OPT_KEY("-V", KEY_VERSION), om@2: FUSE_OPT_KEY("--version", KEY_VERSION), om@2: FUSE_OPT_KEY("-h", KEY_HELP), om@2: FUSE_OPT_KEY("--help", KEY_HELP), om@2: FUSE_OPT_END om@2: }; om@2: om@2: om@2: /** om@2: * configuration of shadowfuse om@2: */ om@2: static struct shadowfuse_config { om@2: om@2: std::string sShadowedPath; om@2: std::string sMountPoint; om@2: om@2: /** om@2: * check for paths been set om@2: */ om@2: inline bool is_paths_set() const { return !(sShadowedPath.empty() || sMountPoint.empty()); }; om@2: om@2: } g_cShadowFuseConfig; om@2: om@2: om@2: // ------------------------------------------------------------ om@2: // fwd om@2: om@2: static int option_processor(void * cData, const char * sArg, int nKey, struct fuse_args * cOutArgs); om@2: static void usage(const char * sProgName); om@2: om@2: om@2: // ------------------------------------------------------------ om@2: // code om@2: om@2: om@2: om@2: /** om@2: * get file attributes. om@2: */ om@2: static int shadow_getattr(const char * sPath, struct stat * cFileStat) { om@2: om@2: // open the shadow file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Getting file attributes of " << sShadow << std::endl; om@2: om@2: memset(cFileStat, 0, sizeof(struct stat)); om@2: if (stat(sShadow.c_str(), cFileStat) == -1) return -errno; om@2: om@2: return 0; om@2: } om@2: om@2: om@2: om@2: /** om@2: * create a directory om@2: */ om@2: static int shadow_mkdir(const char * sPath, mode_t cMode) { om@2: om@2: // create directory om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Create directory " << sShadow << std::endl; om@2: om@2: if (mkdir(sShadow.c_str(), cMode) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * create a file om@2: */ om@2: static int shadow_mknod(const char * sPath, mode_t cMode, dev_t cDev) { om@2: om@2: // create file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Create file " << sShadow << std::endl; om@2: om@2: if (mknod(sShadow.c_str(), cMode, cDev) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * open file om@2: */ om@2: static int shadow_open(const char * sPath, struct fuse_file_info * cFileInfo) { om@2: om@2: // open the shadow file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Opening file " << sShadow << std::endl; om@2: om@2: if (open(sShadow.c_str(), cFileInfo->flags) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * read from file om@2: */ om@2: static int shadow_read(const char * sPath, char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) { om@2: om@2: // read from shadow file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Reading file " << sShadow << " [offset=" << nOffset << ", fetch max bytes=" << nSize << "]" << std::endl; om@2: om@2: // open, pick bytes, close & out om@2: int fd = open(sShadow.c_str(), O_RDONLY); om@2: if (fd == -1) return -errno; om@2: int res = pread(fd, cBuffer, nSize, nOffset); om@2: if (res == -1) res = -errno; om@2: close(fd); om@2: om@2: return res; om@2: } om@2: om@2: om@2: /** om@2: * read directory om@2: */ om@2: static int shadow_readdir(const char * sPath, void * cBuffer, fuse_fill_dir_t fFiller, UNUSED off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) { om@2: om@2: DIR * cDIR; om@2: struct dirent * cDirEntry; om@2: int res = 0; om@2: om@2: // open the shadow folder om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Reading content of " << sShadow << std::endl; om@2: om@2: cDIR = opendir(sShadow.c_str()); om@2: if (!cDIR) return -errno; om@2: om@2: // walk over the entries om@2: while ((cDirEntry = readdir(cDIR)) != NULL) { om@2: om@2: // pick file stat as well om@2: struct stat cFileStat; om@2: stat(sShadow.c_str(), &cFileStat); om@2: res = fFiller(cBuffer, cDirEntry->d_name, &cFileStat, 0); om@2: if (res != 0) break; om@2: } om@2: om@2: // free directory om@2: closedir(cDIR); om@2: return res; om@2: } om@2: om@2: om@2: /** om@2: * move file om@2: */ om@2: static int shadow_rename(const char * sFromPath, const char * sToPath) { om@2: om@2: // move file om@2: std::string sShadowFrom = g_cShadowFuseConfig.sShadowedPath + sFromPath; om@2: std::string sShadowTo = g_cShadowFuseConfig.sShadowedPath + sToPath; om@2: std::cerr << "=== INSERT HOOK HERE. Moving file from " << sShadowFrom << " to " << sShadowTo << std::endl; om@2: om@2: if (rename(sShadowFrom.c_str(), sShadowTo.c_str()) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * delete a folder om@2: */ om@2: static int shadow_rmdir(const char * sPath) { om@2: om@2: // delete the shadow folder om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Delete folder " << sShadow << std::endl; om@2: om@2: if (rmdir(sShadow.c_str()) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * delete a file om@2: */ om@2: static int shadow_unlink(const char * sPath) { om@2: om@2: // delete the shadow file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Delete file " << sShadow << std::endl; om@2: om@2: if (unlink(sShadow.c_str()) == -1) return -errno; om@2: return 0; om@2: } om@2: om@2: om@2: /** om@2: * write int file om@2: */ om@2: static int shadow_write(const char * sPath, const char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) { om@2: om@2: // write into file om@2: std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath; om@2: std::cerr << "=== INSERT HOOK HERE. Write into file " << sShadow << std::endl; om@2: om@2: // open, push bytes, close & out om@2: int fd = open(sShadow.c_str(), O_WRONLY); om@2: if (fd == -1) return -errno; om@2: int res = pwrite(fd, cBuffer, nSize, nOffset); om@2: if (res == -1) res = -errno; om@2: close(fd); om@2: om@2: return res; om@2: } om@2: om@2: om@2: /** om@2: * the shadowfuse function table om@2: */ om@2: static struct fuse_operations shadowfuse_operations { om@2: om@2: shadow_getattr, // getattr om@2: nullptr, // readlink om@2: nullptr, // getdir om@2: shadow_mknod, // mknod om@2: shadow_mkdir, // mkdir om@2: shadow_unlink, // unlink om@2: shadow_rmdir, // rmdir om@2: nullptr, // symlink om@2: shadow_rename, // rename om@2: nullptr, // link om@2: nullptr, // chmod om@2: nullptr, // chown om@2: nullptr, // truncate om@2: nullptr, // utime om@2: shadow_open, // open om@2: shadow_read, // read om@2: shadow_write, // write om@2: nullptr, // statfs om@2: nullptr, // flush om@2: nullptr, // release om@2: nullptr, // fsync om@2: nullptr, // setxattr om@2: nullptr, // getxattr om@2: nullptr, // listxattr om@2: nullptr, // removexattr om@2: nullptr, // opendir om@2: shadow_readdir, // readdir om@2: nullptr, // releasedir om@2: nullptr, // fsyncdir om@2: nullptr, // init om@2: nullptr, // destroy om@2: nullptr, // access om@2: nullptr, // create om@2: nullptr, // ftruncate om@2: nullptr, // fgetattr om@2: nullptr, // lock om@2: nullptr, // utimens om@2: nullptr, // bmap om@2: 0, // flag_nullpath_ok om@2: 0, // flag_nopath om@2: 0, // flag_utime_omit_ok om@2: 0, // flag_reserved om@2: nullptr, // ioctl om@2: nullptr, // poll om@2: nullptr, // write_buf om@2: nullptr, // read_buf om@2: nullptr, // flock om@2: nullptr // fallocate om@2: }; om@2: om@2: om@2: /** om@2: * start om@2: * om@2: * @param argc as usual om@2: * @param argv as usual om@2: * @return as usual om@2: */ om@2: int main(int argc, char ** argv) { om@2: om@2: // option parsing om@2: struct fuse_args cFUSEArgs = FUSE_ARGS_INIT(argc, argv); om@2: if (fuse_opt_parse(&cFUSEArgs, NULL, shadowfuse_opts, option_processor) == -1) { om@2: return -1; om@2: } om@2: om@2: // test if our config is setup ok om@2: if (!g_cShadowFuseConfig.is_paths_set()) { om@2: std::cerr << "sourcefolder and/or mount point not given" << std::endl; om@2: exit(1); om@2: } om@2: om@2: // do FUSE om@2: int ret = fuse_main(cFUSEArgs.argc, cFUSEArgs.argv, &shadowfuse_operations, NULL); om@2: if (ret) printf("\n"); om@2: fuse_opt_free_args(&cFUSEArgs); om@2: om@2: return ret; om@2: } om@2: om@2: om@2: /** om@2: * option parser processor om@2: * om@2: * @param cData is the user data passed to the fuse_opt_parse() function om@2: * @param sArg is the whole argument or option om@2: * @param nKey determines why the processing function was called om@2: * @param cOutArgs the current output argument list om@2: * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept om@2: */ om@2: static int option_processor(UNUSED void * cData, UNUSED const char * sArg, int nKey, struct fuse_args * cOutArgs) { om@2: om@2: // select by key om@2: switch (nKey) { om@2: om@2: case FUSE_OPT_KEY_OPT: om@2: return 1; om@2: om@2: case FUSE_OPT_KEY_NONOPT: om@2: // the non-options om@2: if (g_cShadowFuseConfig.sShadowedPath.empty()) { om@2: // first non-option is the path to be shadowed om@2: g_cShadowFuseConfig.sShadowedPath = sArg; om@2: return 0; om@2: } om@2: else om@2: if (g_cShadowFuseConfig.sMountPoint.empty()) { om@2: // the mount point om@2: g_cShadowFuseConfig.sMountPoint = sArg; om@2: return 1; om@2: } om@2: return 1; om@2: om@2: case KEY_HELP: om@2: usage(cOutArgs->argv[0]); om@2: exit(1); om@2: om@2: case KEY_VERSION: om@2: printf("shadowfuse version %s\n", SHADOWFUSE_VERSION); om@2: exit(0); om@2: om@2: default: om@2: fprintf(stderr, "internal error\n"); om@2: abort(); om@2: } om@2: } om@2: om@2: om@2: /** om@2: * print usage om@2: * om@2: * @param sProgName name of the current program om@2: */ om@2: static void usage(const char * sProgName) { om@2: printf( om@2: "usage: %s sourcefolder mountpoint\n" om@2: "\n" om@2: "general options:\n" om@2: " -f foreground\n" om@2: " -d -odebug foreground, but keep the debug option\n" om@2: " -h --help print help\n" om@2: " -V --version print version\n" om@2: "\n", sProgName); om@2: } om@2: