om@2
|
1 |
/*
|
om@2
|
2 |
* main.cpp
|
om@2
|
3 |
*
|
om@2
|
4 |
* This is the shadowfuse main startup file.
|
om@2
|
5 |
*
|
om@2
|
6 |
* Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
|
om@2
|
7 |
*
|
om@2
|
8 |
* Copyright (C) 2013 AIT Austrian Institute of Technology
|
om@2
|
9 |
* AIT Austrian Institute of Technology GmbH
|
om@2
|
10 |
* Donau-City-Strasse 1 | 1220 Vienna | Austria
|
om@2
|
11 |
* http://www.ait.ac.at
|
om@2
|
12 |
*
|
om@2
|
13 |
* This program is free software; you can redistribute it and/or
|
om@2
|
14 |
* modify it under the terms of the GNU General Public License
|
om@2
|
15 |
* as published by the Free Software Foundation version 2.
|
om@2
|
16 |
*
|
om@2
|
17 |
* This program is distributed in the hope that it will be useful,
|
om@2
|
18 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
om@2
|
19 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
om@2
|
20 |
* GNU General Public License for more details.
|
om@2
|
21 |
*
|
om@2
|
22 |
* You should have received a copy of the GNU General Public License
|
om@2
|
23 |
* along with this program; if not, write to the Free Software
|
om@2
|
24 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
om@2
|
25 |
* Boston, MA 02110-1301, USA.
|
om@2
|
26 |
*/
|
om@2
|
27 |
|
om@2
|
28 |
|
om@2
|
29 |
// ------------------------------------------------------------
|
om@2
|
30 |
// incs
|
om@2
|
31 |
|
om@2
|
32 |
#include "baseinc.h"
|
om@2
|
33 |
|
om@2
|
34 |
|
om@2
|
35 |
// ------------------------------------------------------------
|
om@2
|
36 |
// defs
|
om@2
|
37 |
|
om@2
|
38 |
|
om@2
|
39 |
/**
|
om@2
|
40 |
* shadowfuse version
|
om@2
|
41 |
*/
|
om@2
|
42 |
#define SHADOWFUSE_VERSION "0.1"
|
om@2
|
43 |
|
om@2
|
44 |
|
om@2
|
45 |
// ------------------------------------------------------------
|
om@2
|
46 |
// vars
|
om@2
|
47 |
|
om@2
|
48 |
|
om@2
|
49 |
/**
|
om@2
|
50 |
* keys for FUSE_OPT_ options
|
om@2
|
51 |
*/
|
om@2
|
52 |
enum {
|
om@2
|
53 |
KEY_VERSION,
|
om@2
|
54 |
KEY_HELP,
|
om@2
|
55 |
};
|
om@2
|
56 |
|
om@2
|
57 |
|
om@2
|
58 |
/**
|
om@2
|
59 |
* array of options we know
|
om@2
|
60 |
*/
|
om@2
|
61 |
static struct fuse_opt shadowfuse_opts[] = {
|
om@2
|
62 |
FUSE_OPT_KEY("-V", KEY_VERSION),
|
om@2
|
63 |
FUSE_OPT_KEY("--version", KEY_VERSION),
|
om@2
|
64 |
FUSE_OPT_KEY("-h", KEY_HELP),
|
om@2
|
65 |
FUSE_OPT_KEY("--help", KEY_HELP),
|
om@2
|
66 |
FUSE_OPT_END
|
om@2
|
67 |
};
|
om@2
|
68 |
|
om@2
|
69 |
|
om@2
|
70 |
/**
|
om@2
|
71 |
* configuration of shadowfuse
|
om@2
|
72 |
*/
|
om@2
|
73 |
static struct shadowfuse_config {
|
om@2
|
74 |
|
om@2
|
75 |
std::string sShadowedPath;
|
om@2
|
76 |
std::string sMountPoint;
|
om@2
|
77 |
|
om@2
|
78 |
/**
|
om@2
|
79 |
* check for paths been set
|
om@2
|
80 |
*/
|
om@2
|
81 |
inline bool is_paths_set() const { return !(sShadowedPath.empty() || sMountPoint.empty()); };
|
om@2
|
82 |
|
om@2
|
83 |
} g_cShadowFuseConfig;
|
om@2
|
84 |
|
om@2
|
85 |
|
om@2
|
86 |
// ------------------------------------------------------------
|
om@2
|
87 |
// fwd
|
om@2
|
88 |
|
om@2
|
89 |
static int option_processor(void * cData, const char * sArg, int nKey, struct fuse_args * cOutArgs);
|
om@2
|
90 |
static void usage(const char * sProgName);
|
om@2
|
91 |
|
om@2
|
92 |
|
om@2
|
93 |
// ------------------------------------------------------------
|
om@2
|
94 |
// code
|
om@2
|
95 |
|
om@2
|
96 |
|
om@2
|
97 |
|
om@2
|
98 |
/**
|
om@2
|
99 |
* get file attributes.
|
om@2
|
100 |
*/
|
om@2
|
101 |
static int shadow_getattr(const char * sPath, struct stat * cFileStat) {
|
om@2
|
102 |
|
om@2
|
103 |
// open the shadow file
|
om@2
|
104 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
105 |
std::cerr << "=== INSERT HOOK HERE. Getting file attributes of " << sShadow << std::endl;
|
om@2
|
106 |
|
om@2
|
107 |
memset(cFileStat, 0, sizeof(struct stat));
|
om@2
|
108 |
if (stat(sShadow.c_str(), cFileStat) == -1) return -errno;
|
om@2
|
109 |
|
om@2
|
110 |
return 0;
|
om@2
|
111 |
}
|
om@2
|
112 |
|
om@2
|
113 |
|
om@2
|
114 |
|
om@2
|
115 |
/**
|
om@2
|
116 |
* create a directory
|
om@2
|
117 |
*/
|
om@2
|
118 |
static int shadow_mkdir(const char * sPath, mode_t cMode) {
|
om@2
|
119 |
|
om@2
|
120 |
// create directory
|
om@2
|
121 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
122 |
std::cerr << "=== INSERT HOOK HERE. Create directory " << sShadow << std::endl;
|
om@2
|
123 |
|
om@2
|
124 |
if (mkdir(sShadow.c_str(), cMode) == -1) return -errno;
|
om@2
|
125 |
return 0;
|
om@2
|
126 |
}
|
om@2
|
127 |
|
om@2
|
128 |
|
om@2
|
129 |
/**
|
om@2
|
130 |
* create a file
|
om@2
|
131 |
*/
|
om@2
|
132 |
static int shadow_mknod(const char * sPath, mode_t cMode, dev_t cDev) {
|
om@2
|
133 |
|
om@2
|
134 |
// create file
|
om@2
|
135 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
136 |
std::cerr << "=== INSERT HOOK HERE. Create file " << sShadow << std::endl;
|
om@2
|
137 |
|
om@2
|
138 |
if (mknod(sShadow.c_str(), cMode, cDev) == -1) return -errno;
|
om@2
|
139 |
return 0;
|
om@2
|
140 |
}
|
om@2
|
141 |
|
om@2
|
142 |
|
om@2
|
143 |
/**
|
om@2
|
144 |
* open file
|
om@2
|
145 |
*/
|
om@2
|
146 |
static int shadow_open(const char * sPath, struct fuse_file_info * cFileInfo) {
|
om@2
|
147 |
|
om@2
|
148 |
// open the shadow file
|
om@2
|
149 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
150 |
std::cerr << "=== INSERT HOOK HERE. Opening file " << sShadow << std::endl;
|
om@2
|
151 |
|
om@2
|
152 |
if (open(sShadow.c_str(), cFileInfo->flags) == -1) return -errno;
|
om@2
|
153 |
return 0;
|
om@2
|
154 |
}
|
om@2
|
155 |
|
om@2
|
156 |
|
om@2
|
157 |
/**
|
om@2
|
158 |
* read from file
|
om@2
|
159 |
*/
|
om@2
|
160 |
static int shadow_read(const char * sPath, char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) {
|
om@2
|
161 |
|
om@2
|
162 |
// read from shadow file
|
om@2
|
163 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
164 |
std::cerr << "=== INSERT HOOK HERE. Reading file " << sShadow << " [offset=" << nOffset << ", fetch max bytes=" << nSize << "]" << std::endl;
|
om@2
|
165 |
|
om@2
|
166 |
// open, pick bytes, close & out
|
om@2
|
167 |
int fd = open(sShadow.c_str(), O_RDONLY);
|
om@2
|
168 |
if (fd == -1) return -errno;
|
om@2
|
169 |
int res = pread(fd, cBuffer, nSize, nOffset);
|
om@2
|
170 |
if (res == -1) res = -errno;
|
om@2
|
171 |
close(fd);
|
om@2
|
172 |
|
om@2
|
173 |
return res;
|
om@2
|
174 |
}
|
om@2
|
175 |
|
om@2
|
176 |
|
om@2
|
177 |
/**
|
om@2
|
178 |
* read directory
|
om@2
|
179 |
*/
|
om@2
|
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) {
|
om@2
|
181 |
|
om@2
|
182 |
DIR * cDIR;
|
om@2
|
183 |
struct dirent * cDirEntry;
|
om@2
|
184 |
int res = 0;
|
om@2
|
185 |
|
om@2
|
186 |
// open the shadow folder
|
om@2
|
187 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
188 |
std::cerr << "=== INSERT HOOK HERE. Reading content of " << sShadow << std::endl;
|
om@2
|
189 |
|
om@2
|
190 |
cDIR = opendir(sShadow.c_str());
|
om@2
|
191 |
if (!cDIR) return -errno;
|
om@2
|
192 |
|
om@2
|
193 |
// walk over the entries
|
om@2
|
194 |
while ((cDirEntry = readdir(cDIR)) != NULL) {
|
om@2
|
195 |
|
om@2
|
196 |
// pick file stat as well
|
om@2
|
197 |
struct stat cFileStat;
|
om@2
|
198 |
stat(sShadow.c_str(), &cFileStat);
|
om@2
|
199 |
res = fFiller(cBuffer, cDirEntry->d_name, &cFileStat, 0);
|
om@2
|
200 |
if (res != 0) break;
|
om@2
|
201 |
}
|
om@2
|
202 |
|
om@2
|
203 |
// free directory
|
om@2
|
204 |
closedir(cDIR);
|
om@2
|
205 |
return res;
|
om@2
|
206 |
}
|
om@2
|
207 |
|
om@2
|
208 |
|
om@2
|
209 |
/**
|
om@2
|
210 |
* move file
|
om@2
|
211 |
*/
|
om@2
|
212 |
static int shadow_rename(const char * sFromPath, const char * sToPath) {
|
om@2
|
213 |
|
om@2
|
214 |
// move file
|
om@2
|
215 |
std::string sShadowFrom = g_cShadowFuseConfig.sShadowedPath + sFromPath;
|
om@2
|
216 |
std::string sShadowTo = g_cShadowFuseConfig.sShadowedPath + sToPath;
|
om@2
|
217 |
std::cerr << "=== INSERT HOOK HERE. Moving file from " << sShadowFrom << " to " << sShadowTo << std::endl;
|
om@2
|
218 |
|
om@2
|
219 |
if (rename(sShadowFrom.c_str(), sShadowTo.c_str()) == -1) return -errno;
|
om@2
|
220 |
return 0;
|
om@2
|
221 |
}
|
om@2
|
222 |
|
om@2
|
223 |
|
om@2
|
224 |
/**
|
om@2
|
225 |
* delete a folder
|
om@2
|
226 |
*/
|
om@2
|
227 |
static int shadow_rmdir(const char * sPath) {
|
om@2
|
228 |
|
om@2
|
229 |
// delete the shadow folder
|
om@2
|
230 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
231 |
std::cerr << "=== INSERT HOOK HERE. Delete folder " << sShadow << std::endl;
|
om@2
|
232 |
|
om@2
|
233 |
if (rmdir(sShadow.c_str()) == -1) return -errno;
|
om@2
|
234 |
return 0;
|
om@2
|
235 |
}
|
om@2
|
236 |
|
om@2
|
237 |
|
om@2
|
238 |
/**
|
om@2
|
239 |
* delete a file
|
om@2
|
240 |
*/
|
om@2
|
241 |
static int shadow_unlink(const char * sPath) {
|
om@2
|
242 |
|
om@2
|
243 |
// delete the shadow file
|
om@2
|
244 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
245 |
std::cerr << "=== INSERT HOOK HERE. Delete file " << sShadow << std::endl;
|
om@2
|
246 |
|
om@2
|
247 |
if (unlink(sShadow.c_str()) == -1) return -errno;
|
om@2
|
248 |
return 0;
|
om@2
|
249 |
}
|
om@2
|
250 |
|
om@2
|
251 |
|
om@2
|
252 |
/**
|
om@2
|
253 |
* write int file
|
om@2
|
254 |
*/
|
om@2
|
255 |
static int shadow_write(const char * sPath, const char * cBuffer, size_t nSize, off_t nOffset, UNUSED struct fuse_file_info * cFileInfo) {
|
om@2
|
256 |
|
om@2
|
257 |
// write into file
|
om@2
|
258 |
std::string sShadow = g_cShadowFuseConfig.sShadowedPath + sPath;
|
om@2
|
259 |
std::cerr << "=== INSERT HOOK HERE. Write into file " << sShadow << std::endl;
|
om@2
|
260 |
|
om@2
|
261 |
// open, push bytes, close & out
|
om@2
|
262 |
int fd = open(sShadow.c_str(), O_WRONLY);
|
om@2
|
263 |
if (fd == -1) return -errno;
|
om@2
|
264 |
int res = pwrite(fd, cBuffer, nSize, nOffset);
|
om@2
|
265 |
if (res == -1) res = -errno;
|
om@2
|
266 |
close(fd);
|
om@2
|
267 |
|
om@2
|
268 |
return res;
|
om@2
|
269 |
}
|
om@2
|
270 |
|
om@2
|
271 |
|
om@2
|
272 |
/**
|
om@2
|
273 |
* the shadowfuse function table
|
om@2
|
274 |
*/
|
om@2
|
275 |
static struct fuse_operations shadowfuse_operations {
|
om@2
|
276 |
|
om@2
|
277 |
shadow_getattr, // getattr
|
om@2
|
278 |
nullptr, // readlink
|
om@2
|
279 |
nullptr, // getdir
|
om@2
|
280 |
shadow_mknod, // mknod
|
om@2
|
281 |
shadow_mkdir, // mkdir
|
om@2
|
282 |
shadow_unlink, // unlink
|
om@2
|
283 |
shadow_rmdir, // rmdir
|
om@2
|
284 |
nullptr, // symlink
|
om@2
|
285 |
shadow_rename, // rename
|
om@2
|
286 |
nullptr, // link
|
om@2
|
287 |
nullptr, // chmod
|
om@2
|
288 |
nullptr, // chown
|
om@2
|
289 |
nullptr, // truncate
|
om@2
|
290 |
nullptr, // utime
|
om@2
|
291 |
shadow_open, // open
|
om@2
|
292 |
shadow_read, // read
|
om@2
|
293 |
shadow_write, // write
|
om@2
|
294 |
nullptr, // statfs
|
om@2
|
295 |
nullptr, // flush
|
om@2
|
296 |
nullptr, // release
|
om@2
|
297 |
nullptr, // fsync
|
om@2
|
298 |
nullptr, // setxattr
|
om@2
|
299 |
nullptr, // getxattr
|
om@2
|
300 |
nullptr, // listxattr
|
om@2
|
301 |
nullptr, // removexattr
|
om@2
|
302 |
nullptr, // opendir
|
om@2
|
303 |
shadow_readdir, // readdir
|
om@2
|
304 |
nullptr, // releasedir
|
om@2
|
305 |
nullptr, // fsyncdir
|
om@2
|
306 |
nullptr, // init
|
om@2
|
307 |
nullptr, // destroy
|
om@2
|
308 |
nullptr, // access
|
om@2
|
309 |
nullptr, // create
|
om@2
|
310 |
nullptr, // ftruncate
|
om@2
|
311 |
nullptr, // fgetattr
|
om@2
|
312 |
nullptr, // lock
|
om@2
|
313 |
nullptr, // utimens
|
om@2
|
314 |
nullptr, // bmap
|
om@2
|
315 |
0, // flag_nullpath_ok
|
om@2
|
316 |
0, // flag_nopath
|
om@2
|
317 |
0, // flag_utime_omit_ok
|
om@2
|
318 |
0, // flag_reserved
|
om@2
|
319 |
nullptr, // ioctl
|
om@2
|
320 |
nullptr, // poll
|
om@2
|
321 |
nullptr, // write_buf
|
om@2
|
322 |
nullptr, // read_buf
|
om@2
|
323 |
nullptr, // flock
|
om@2
|
324 |
nullptr // fallocate
|
om@2
|
325 |
};
|
om@2
|
326 |
|
om@2
|
327 |
|
om@2
|
328 |
/**
|
om@2
|
329 |
* start
|
om@2
|
330 |
*
|
om@2
|
331 |
* @param argc as usual
|
om@2
|
332 |
* @param argv as usual
|
om@2
|
333 |
* @return as usual
|
om@2
|
334 |
*/
|
om@2
|
335 |
int main(int argc, char ** argv) {
|
om@2
|
336 |
|
om@2
|
337 |
// option parsing
|
om@2
|
338 |
struct fuse_args cFUSEArgs = FUSE_ARGS_INIT(argc, argv);
|
om@2
|
339 |
if (fuse_opt_parse(&cFUSEArgs, NULL, shadowfuse_opts, option_processor) == -1) {
|
om@2
|
340 |
return -1;
|
om@2
|
341 |
}
|
om@2
|
342 |
|
om@2
|
343 |
// test if our config is setup ok
|
om@2
|
344 |
if (!g_cShadowFuseConfig.is_paths_set()) {
|
om@2
|
345 |
std::cerr << "sourcefolder and/or mount point not given" << std::endl;
|
om@2
|
346 |
exit(1);
|
om@2
|
347 |
}
|
om@2
|
348 |
|
om@2
|
349 |
// do FUSE
|
om@2
|
350 |
int ret = fuse_main(cFUSEArgs.argc, cFUSEArgs.argv, &shadowfuse_operations, NULL);
|
om@2
|
351 |
if (ret) printf("\n");
|
om@2
|
352 |
fuse_opt_free_args(&cFUSEArgs);
|
om@2
|
353 |
|
om@2
|
354 |
return ret;
|
om@2
|
355 |
}
|
om@2
|
356 |
|
om@2
|
357 |
|
om@2
|
358 |
/**
|
om@2
|
359 |
* option parser processor
|
om@2
|
360 |
*
|
om@2
|
361 |
* @param cData is the user data passed to the fuse_opt_parse() function
|
om@2
|
362 |
* @param sArg is the whole argument or option
|
om@2
|
363 |
* @param nKey determines why the processing function was called
|
om@2
|
364 |
* @param cOutArgs the current output argument list
|
om@2
|
365 |
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
|
om@2
|
366 |
*/
|
om@2
|
367 |
static int option_processor(UNUSED void * cData, UNUSED const char * sArg, int nKey, struct fuse_args * cOutArgs) {
|
om@2
|
368 |
|
om@2
|
369 |
// select by key
|
om@2
|
370 |
switch (nKey) {
|
om@2
|
371 |
|
om@2
|
372 |
case FUSE_OPT_KEY_OPT:
|
om@2
|
373 |
return 1;
|
om@2
|
374 |
|
om@2
|
375 |
case FUSE_OPT_KEY_NONOPT:
|
om@2
|
376 |
// the non-options
|
om@2
|
377 |
if (g_cShadowFuseConfig.sShadowedPath.empty()) {
|
om@2
|
378 |
// first non-option is the path to be shadowed
|
om@2
|
379 |
g_cShadowFuseConfig.sShadowedPath = sArg;
|
om@2
|
380 |
return 0;
|
om@2
|
381 |
}
|
om@2
|
382 |
else
|
om@2
|
383 |
if (g_cShadowFuseConfig.sMountPoint.empty()) {
|
om@2
|
384 |
// the mount point
|
om@2
|
385 |
g_cShadowFuseConfig.sMountPoint = sArg;
|
om@2
|
386 |
return 1;
|
om@2
|
387 |
}
|
om@2
|
388 |
return 1;
|
om@2
|
389 |
|
om@2
|
390 |
case KEY_HELP:
|
om@2
|
391 |
usage(cOutArgs->argv[0]);
|
om@2
|
392 |
exit(1);
|
om@2
|
393 |
|
om@2
|
394 |
case KEY_VERSION:
|
om@2
|
395 |
printf("shadowfuse version %s\n", SHADOWFUSE_VERSION);
|
om@2
|
396 |
exit(0);
|
om@2
|
397 |
|
om@2
|
398 |
default:
|
om@2
|
399 |
fprintf(stderr, "internal error\n");
|
om@2
|
400 |
abort();
|
om@2
|
401 |
}
|
om@2
|
402 |
}
|
om@2
|
403 |
|
om@2
|
404 |
|
om@2
|
405 |
/**
|
om@2
|
406 |
* print usage
|
om@2
|
407 |
*
|
om@2
|
408 |
* @param sProgName name of the current program
|
om@2
|
409 |
*/
|
om@2
|
410 |
static void usage(const char * sProgName) {
|
om@2
|
411 |
printf(
|
om@2
|
412 |
"usage: %s sourcefolder mountpoint\n"
|
om@2
|
413 |
"\n"
|
om@2
|
414 |
"general options:\n"
|
om@2
|
415 |
" -f foreground\n"
|
om@2
|
416 |
" -d -odebug foreground, but keep the debug option\n"
|
om@2
|
417 |
" -h --help print help\n"
|
om@2
|
418 |
" -V --version print version\n"
|
om@2
|
419 |
"\n", sProgName);
|
om@2
|
420 |
}
|
om@2
|
421 |
|