1 // -*- mode:C++; tab-width:8; c-basic-offset:4; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=4 smarttab
5 FUSE: Filesystem in Userspace
6 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
8 This program can be distributed under the terms of the GNU GPL.
11 gcc -Wall `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -o fusexmp_fh
14 #define FUSE_USE_VERSION 30
21 #include <fuse/fuse_lowlevel.h>
31 #include <sys/xattr.h>
36 #include "include/unordered_map.h"
37 #include "include/hash_namespace.h"
40 CEPH_HASH_NAMESPACE_START
41 template<> struct hash
<uint64_t> {
42 size_t operator()(uint64_t __x
) const {
43 static hash
<uint32_t> H
;
44 return H((__x
>> 32) ^ (__x
& 0xffffffff));
47 CEPH_HASH_NAMESPACE_END
57 #include "common/Mutex.h"
62 #define traceout (tracefile.is_open() ? tracefile : cout)
66 bool do_timestamps
= true;
68 #define dout if (debug) cout
77 map
<pair
<string
,ino_t
>,Inode
*> parents
;
80 map
<string
,Inode
*> dentries
;
84 Inode
*lookup(const string
& dname
) {
85 if (dentries
.count(dname
))
86 return dentries
[dname
];
92 ceph::unordered_map
<ino_t
, Inode
*> inode_map
;
94 bool make_inode_path(string
&buf
, Inode
*in
)
96 if (!in
->parents
.empty()) {
97 if (!make_inode_path(buf
, in
->parents
.begin()->second
))
100 buf
+= in
->parents
.begin()->first
.first
;
102 if (in
!= root
) return false;
103 assert(in
->stbuf
.st_ino
== 1);
108 //dout << "path: " << in->stbuf.st_ino << " -> " << buf << endl;
111 bool make_inode_path(string
&buf
, Inode
*in
, const char *name
)
113 if (!make_inode_path(buf
, in
)) return false;
119 bool make_ino_path(string
&buf
, ino_t ino
)
121 Inode
*in
= inode_map
[ino
];
123 return make_inode_path(buf
, in
);
126 bool make_ino_path(string
&buf
, ino_t ino
, const char *name
)
128 Inode
*in
= inode_map
[ino
];
130 if (!make_inode_path(buf
, in
))
137 void remove_dentry(Inode
*pin
, const string
& dname
)
139 dout
<< "remove_dentry " << pin
->stbuf
.st_ino
<< " " << dname
<< endl
;
141 Inode
*in
= pin
->lookup(dname
);
143 pin
->dentries
.erase(dname
);
144 in
->parents
.erase(pair
<string
,ino_t
>(dname
,pin
->stbuf
.st_ino
));
146 dout
<< "remove_dentry " << pin
->stbuf
.st_ino
<< " " << dname
147 << " ... inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
151 void add_dentry(Inode
*parent
, const string
& dname
, Inode
*in
)
153 dout
<< "add_dentry " << parent
->stbuf
.st_ino
<< " " << dname
<< " to " << in
->stbuf
.st_ino
<< endl
;
155 if (parent
->dentries
.count(dname
))
156 remove_dentry(parent
, dname
); // e.g., when renaming over another file..
158 parent
->dentries
[dname
] = in
;
159 in
->parents
[pair
<string
,ino_t
>(dname
,parent
->stbuf
.st_ino
)] = parent
;
162 void unlink_inode(Inode
*in
)
164 dout
<< "unlink_inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
<< endl
;
166 // remove parent links
167 while (!in
->parents
.empty()) {
168 Inode
*parent
= in
->parents
.begin()->second
;
169 string dname
= in
->parents
.begin()->first
.first
;
170 remove_dentry(parent
, dname
);
174 while (!in
->dentries
.empty())
175 remove_dentry(in
, in
->dentries
.begin()->first
);
177 while (!in
->fds
.empty()) {
178 int fd
= *in
->fds
.begin();
180 in
->fds
.erase(in
->fds
.begin());
181 dout
<< "remove_inode closeing stray fd " << fd
<< endl
;
185 void remove_inode(Inode
*in
)
187 dout
<< "remove_inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
<< endl
;
191 inode_map
.erase(in
->stbuf
.st_ino
);
192 dout
<< "remove_inode " << in
->stbuf
.st_ino
<< " done" << endl
;
196 Inode
*add_inode(Inode
*parent
, const char *name
, struct stat
*attr
)
198 dout
<< "add_inode " << parent
->stbuf
.st_ino
<< " " << name
<< " " << attr
->st_ino
<< endl
;
201 if (inode_map
.count(attr
->st_ino
)) {
203 in
= inode_map
[attr
->st_ino
];
204 unlink_inode(in
); // hrm.. should this close open fds? probably.
205 dout
<< "** REUSING INODE **" << endl
;
207 inode_map
[attr
->st_ino
] = in
= new Inode
;
209 memcpy(&in
->stbuf
, attr
, sizeof(*attr
));
212 add_dentry(parent
, dname
, in
);
222 gettimeofday(&tv
, 0);
223 traceout
<< "@" << endl
225 << tv
.tv_usec
<< endl
;
230 bool has_perm(int mask
, Inode
*in
, int uid
, int gid
)
232 dout
<< "hash_perm " << uid
<< "." << gid
<< " " << oct
<< mask
<< " in " << in
->stbuf
.st_mode
233 << " " << in
->stbuf
.st_uid
<< "." << in
->stbuf
.st_gid
<< endl
;
234 if (in
->stbuf
.st_mode
& mask
) return true;
235 if (in
->stbuf
.st_gid
== gid
&& in
->stbuf
.st_mode
& (mask
<< 3)) return true;
236 if (in
->stbuf
.st_uid
== uid
&& in
->stbuf
.st_mode
& (mask
<< 6)) return true;
241 static void ft_ll_lookup(fuse_req_t req
, fuse_ino_t pino
, const char *name
)
245 //dout << "lookup " << pino << " " << name << endl;
247 struct fuse_entry_param fe
;
248 memset(&fe
, 0, sizeof(fe
));
251 Inode
*parent
= inode_map
[pino
];
259 if (!has_perm(0001, parent
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)) {
262 else if (!make_inode_path(path
, parent
, name
)) {
265 in
= parent
->lookup(dname
);
266 if (in
&& res
== 0) {
267 // re-stat, for good measure
268 res
= ::lstat(path
.c_str(), &in
->stbuf
);
272 dout
<< "** WEIRD ** lookup on " << pino
<< " " << name
<< " inode went away!" << endl
;
277 //dout << "have " << in->stbuf.st_ino << endl;
280 res
= ::lstat(path
.c_str(), &in
->stbuf
);
281 //dout << "stat " << path << " res = " << res << endl;
283 inode_map
[in
->stbuf
.st_ino
] = in
;
284 add_dentry(parent
, dname
, in
);
293 fe
.ino
= in
->stbuf
.st_ino
;
294 memcpy(&fe
.attr
, &in
->stbuf
, sizeof(in
->stbuf
));
301 traceout
<< "ll_lookup" << endl
<< pino
<< endl
<< name
<< endl
<< fe
.attr
.st_ino
<< endl
;
305 fuse_reply_entry(req
, &fe
);
307 fuse_reply_err(req
, res
);
310 static void ft_ll_forget(fuse_req_t req
, fuse_ino_t ino
, long unsigned nlookup
)
314 Inode
*in
= inode_map
[ino
];
316 dout
<< "forget on " << ino
<< " ref " << in
->ref
<< ", forget " << nlookup
<< endl
;
317 if (in
->ref
< nlookup
)
318 dout
<< "**** BAD **** forget on " << ino
<< " ref " << in
->ref
<< ", forget " << nlookup
<< endl
;
324 dout
<< "**** BAD **** forget " << nlookup
<< " on nonexistent inode " << ino
<< endl
;
331 traceout
<< "ll_forget" << endl
<< ino
<< endl
<< nlookup
<< endl
;
334 fuse_reply_none(req
);
337 static void ft_ll_getattr(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
348 if (in
->fds
.empty()) {
349 if (!make_inode_path(path
, in
))
352 fd
= *in
->fds
.begin();
356 res
= ::fstat(fd
, &attr
);
357 dout
<< "getattr fstat on fd " << fd
<< " res " << res
<< endl
;
358 } else if (res
== 0) {
359 res
= ::lstat(path
.c_str(), &attr
);
360 dout
<< "getattr lstat on " << path
<< " res " << res
<< endl
;
362 if (res
< 0) res
= errno
;
363 if (ino
== 1) attr
.st_ino
= 1;
367 traceout
<< "ll_getattr" << endl
<< ino
<< endl
;
372 memcpy(&in
->stbuf
, &attr
, sizeof(attr
));
374 fuse_reply_attr(req
, &attr
, 0);
376 fuse_reply_err(req
, res
);
379 static void ft_ll_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
380 int to_set
, struct fuse_file_info
*fi
)
389 if (in
->fds
.empty() || (to_set
& FUSE_SET_ATTR_MTIME
)) {
390 if (!make_inode_path(path
, in
))
393 fd
= *in
->fds
.begin();
398 traceout
<< "ll_setattr" << endl
<< ino
<< endl
;
399 traceout
<< attr
->st_mode
<< endl
;
400 traceout
<< attr
->st_uid
<< endl
<< attr
->st_gid
<< endl
;
401 traceout
<< attr
->st_size
<< endl
;
402 traceout
<< attr
->st_mtime
<< endl
;
403 traceout
<< attr
->st_atime
<< endl
;
404 traceout
<< to_set
<< endl
;
407 if (res
== 0 && !has_perm(0010, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)) {
409 } else if (res
== 0) {
410 if (to_set
& FUSE_SET_ATTR_MODE
) {
412 res
= ::fchmod(fd
, attr
->st_mode
);
414 res
= ::chmod(path
.c_str(), attr
->st_mode
);
416 if (!res
&& to_set
& FUSE_SET_ATTR_UID
) {
418 res
= ::fchown(fd
, attr
->st_uid
, attr
->st_gid
);
420 res
= ::chown(path
.c_str(), attr
->st_uid
, attr
->st_gid
);
422 if (!res
&& to_set
& FUSE_SET_ATTR_SIZE
) {
424 res
= ::ftruncate(fd
, attr
->st_size
);
426 res
= ::truncate(path
.c_str(), attr
->st_size
);
428 if (!res
&& to_set
& FUSE_SET_ATTR_MTIME
) {
430 ut
.actime
= attr
->st_atime
;
431 ut
.modtime
= attr
->st_mtime
;
432 res
= ::utime(path
.c_str(), &ut
);
434 if (res
< 0) res
= errno
;
439 ::lstat(path
.c_str(), &in
->stbuf
);
440 if (ino
== 1) in
->stbuf
.st_ino
= 1;
441 memcpy(attr
, &in
->stbuf
, sizeof(*attr
));
443 fuse_reply_attr(req
, attr
, 0);
445 fuse_reply_err(req
, res
);
449 static void ft_ll_readlink(fuse_req_t req
, fuse_ino_t ino
)
455 if (!make_ino_path(path
, ino
))
461 traceout
<< "ll_readlink" << endl
<< ino
<< endl
;
465 if (res
== 0) res
= readlink(path
.c_str(), buf
, 255);
466 if (res
< 0) res
= errno
;
470 fuse_reply_readlink(req
, buf
);
472 fuse_reply_err(req
, res
);
477 static void ft_ll_opendir(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
482 Inode
*in
= inode_map
[ino
];
483 if (!make_inode_path(path
, in
))
488 if (res
== 0 && !has_perm(0100, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
490 else if (res
== 0) dir
= opendir(path
.c_str());
491 if (res
< 0) res
= errno
;
495 traceout
<< "ll_opendir" << endl
<< ino
<< endl
<< (unsigned long)dir
<< endl
;
500 fuse_reply_open(req
, fi
);
502 fuse_reply_err(req
, res
);
505 static void ft_ll_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
506 off_t off
, struct fuse_file_info
*fi
)
509 DIR *dp
= (DIR*)fi
->fh
;
515 buf
= new char[size
];
517 fuse_reply_err(req
, ENOMEM
);
522 while ((de
= readdir(dp
)) != NULL
) {
524 memset(&st
, 0, sizeof(st
));
525 st
.st_ino
= de
->d_ino
;
526 st
.st_mode
= de
->d_type
<< 12;
528 size_t entrysize
= fuse_add_direntry(req
, buf
+ pos
, size
- pos
,
529 de
->d_name
, &st
, telldir(dp
));
530 if (entrysize
> size
- pos
)
531 break; // didn't fit, done for now.
535 fuse_reply_buf(req
, buf
, pos
);
539 static void ft_ll_releasedir(fuse_req_t req
, fuse_ino_t ino
,
540 struct fuse_file_info
*fi
)
542 DIR *dir
= (DIR*)fi
->fh
;
546 traceout
<< "ll_releasedir" << endl
<< (unsigned long)dir
<< endl
;
550 fuse_reply_err(req
, 0);
555 static void ft_ll_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
556 mode_t mode
, dev_t rdev
)
562 pin
= inode_map
[parent
];
563 if (!make_inode_path(path
, pin
, name
))
567 dout
<< "mknod " << path
<< endl
;
568 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
570 else if (res
== 0) res
= ::mknod(path
.c_str(), mode
, rdev
);
574 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
576 struct fuse_entry_param fe
;
578 memset(&fe
, 0, sizeof(fe
));
579 ::lstat(path
.c_str(), &fe
.attr
);
580 fe
.ino
= fe
.attr
.st_ino
;
582 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
589 traceout
<< "ll_mknod" << endl
<< parent
<< endl
<< name
<< endl
<< mode
<< endl
<< rdev
<< endl
;
590 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
594 fuse_reply_entry(req
, &fe
);
596 fuse_reply_err(req
, res
);
599 static void ft_ll_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
606 pin
= inode_map
[parent
];
607 if (!make_inode_path(path
, pin
, name
))
611 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
613 else if (res
== 0) res
= ::mkdir(path
.c_str(), mode
);
617 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
619 struct fuse_entry_param fe
;
621 memset(&fe
, 0, sizeof(fe
));
622 ::lstat(path
.c_str(), &fe
.attr
);
623 fe
.ino
= fe
.attr
.st_ino
;
625 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
632 traceout
<< "ll_mkdir" << endl
<< parent
<< endl
<< name
<< endl
<< mode
<< endl
;
633 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
637 fuse_reply_entry(req
, &fe
);
639 fuse_reply_err(req
, res
);
642 static void ft_ll_symlink(fuse_req_t req
, const char *value
, fuse_ino_t parent
, const char *name
)
649 pin
= inode_map
[parent
];
650 if (!make_inode_path(path
, pin
, name
))
654 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
656 else if (res
== 0) res
= ::symlink(value
, path
.c_str());
660 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
662 struct fuse_entry_param fe
;
664 memset(&fe
, 0, sizeof(fe
));
665 ::lstat(path
.c_str(), &fe
.attr
);
666 fe
.ino
= fe
.attr
.st_ino
;
668 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
675 traceout
<< "ll_symlink" << endl
<< parent
<< endl
<< name
<< endl
<< value
<< endl
;
676 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
680 fuse_reply_entry(req
, &fe
);
682 fuse_reply_err(req
, res
);
685 static void ft_ll_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
686 mode_t mode
, struct fuse_file_info
*fi
)
693 pin
= inode_map
[parent
];
694 if (!make_inode_path(path
, pin
, name
))
698 dout
<< "create " << path
<< endl
;
700 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
703 fd
= ::open(path
.c_str(), fi
->flags
|O_CREAT
, mode
);
707 ::fchown(fd
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
711 struct fuse_entry_param fe
;
712 memset(&fe
, 0, sizeof(fe
));
714 ::lstat(path
.c_str(), &fe
.attr
);
715 fe
.ino
= fe
.attr
.st_ino
;
717 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
726 traceout
<< "ll_create" << endl
731 << (res
== 0 ? fd
:0) << endl
736 fuse_reply_create(req
, &fe
, fi
);
738 fuse_reply_err(req
, res
);
743 static void ft_ll_statfs(fuse_req_t req
, fuse_ino_t ino
)
749 if (!make_ino_path(path
, ino
))
758 traceout
<< "ll_statfs" << endl
<< ino
<< endl
;
761 struct statvfs stbuf
;
762 if (res
== 0) res
= statvfs(path
.c_str(), &stbuf
);
763 if (res
< 0) res
= errno
;
766 fuse_reply_statfs(req
, &stbuf
);
768 fuse_reply_err(req
, res
);
771 static void ft_ll_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
779 pin
= inode_map
[parent
];
780 in
= pin
->lookup(dname
);
781 if (!make_inode_path(path
, pin
, name
))
787 traceout
<< "ll_unlink" << endl
<< parent
<< endl
<< name
<< endl
;
790 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
793 if (in
&& in
->fds
.empty()) {
794 int fd
= ::open(path
.c_str(), O_RDWR
);
796 in
->fds
.insert(fd
); // for slow getattrs.. wtf
797 dout
<< "unlink opening paranoia fd " << fd
<< endl
;
799 res
= ::unlink(path
.c_str());
800 if (res
< 0) res
= errno
;
804 // remove from out cache
807 if (pin
->lookup(dname
))
808 remove_dentry(pin
, dname
);
810 fuse_reply_err(req
, 0);
812 fuse_reply_err(req
, res
);
815 static void ft_ll_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
822 pin
= inode_map
[parent
];
823 if (!make_inode_path(path
, pin
, name
))
829 traceout
<< "ll_rmdir" << endl
<< parent
<< endl
<< name
<< endl
;
832 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
834 else if (res
== 0) res
= ::rmdir(path
.c_str());
835 if (res
< 0) res
= errno
;
838 // remove from out cache
841 if (pin
->lookup(dname
))
842 remove_dentry(pin
, dname
);
844 fuse_reply_err(req
, 0);
846 fuse_reply_err(req
, res
);
850 static void ft_ll_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
851 fuse_ino_t newparent
, const char *newname
)
859 pin
= inode_map
[parent
];
860 if (!make_inode_path(path
, pin
, name
))
862 newpin
= inode_map
[newparent
];
863 if (!make_inode_path(newpath
, newpin
, newname
))
869 traceout
<< "ll_rename" << endl
876 if (res
== 0 && (!has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
) ||
877 !has_perm(0010, newpin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)))
879 else if (res
== 0) res
= ::rename(path
.c_str(), newpath
.c_str());
880 if (res
< 0) res
= errno
;
884 string
newdname(newname
);
886 Inode
*in
= pin
->lookup(dname
);
888 add_dentry(newpin
, newdname
, in
);
889 remove_dentry(pin
, dname
);
891 dout
<< "hrm, rename didn't have renamed inode.. " << path
<< " to " << newpath
<< endl
;
894 fuse_reply_err(req
, 0);
896 fuse_reply_err(req
, res
);
899 static void ft_ll_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t newparent
,
909 if (!make_inode_path(path
, in
))
912 newpin
= inode_map
[newparent
];
913 if (!make_inode_path(newpath
, newpin
, newname
))
919 traceout
<< "ll_link" << endl
925 //cout << "link " << path << " newpath " << newpath << endl;
926 if (res
== 0 && (!has_perm(0010, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
) ||
927 !has_perm(0010, newpin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)))
929 else if (res
== 0) res
= ::link(path
.c_str(), newpath
.c_str());
930 if (res
< 0) res
= errno
;
933 struct fuse_entry_param fe
;
934 memset(&fe
, 0, sizeof(fe
));
935 ::lstat(newpath
.c_str(), &fe
.attr
);
938 string
newdname(newname
);
939 add_dentry(newpin
, newdname
, in
);
941 memcpy(&in
->stbuf
, &fe
.attr
, sizeof(fe
.attr
)); // re-read, bc we changed the link count
944 fe
.ino
= fe
.attr
.st_ino
;
945 fuse_reply_entry(req
, &fe
);
947 fuse_reply_err(req
, res
);
950 static void ft_ll_open(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
958 if (!make_inode_path(path
, in
))
963 if (fi
->flags
& O_RDWR
) want
|= 0010;
964 if (fi
->flags
== O_WRONLY
) want
= 0010;
967 if (res
== 0 && !has_perm(want
, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
970 fd
= ::open(path
.c_str(), fi
->flags
);
971 if (fd
<= 0) res
= errno
;
976 traceout
<< "ll_open" << endl
979 << (fd
> 0 ? fd
:0) << endl
;
987 fuse_reply_open(req
, fi
);
989 fuse_reply_err(req
, res
);
992 static void ft_ll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t off
,
993 struct fuse_file_info
*fi
)
996 char *buf
= new char[size
];
997 int res
= ::pread(fi
->fh
, buf
, size
, off
);
999 //cout << "read " << path << " " << off << "~" << size << endl;
1002 traceout
<< "ll_read" << endl
1006 trace_lock
.Unlock();
1009 fuse_reply_buf(req
, buf
, res
);
1011 fuse_reply_err(req
, errno
);
1015 static void ft_ll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
1016 size_t size
, off_t off
, struct fuse_file_info
*fi
)
1018 int res
= ::pwrite(fi
->fh
, buf
, size
, off
);
1022 traceout
<< "ll_write" << endl
1026 trace_lock
.Unlock();
1029 fuse_reply_write(req
, res
);
1031 fuse_reply_err(req
, errno
);
1034 static void ft_ll_flush(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
1038 traceout
<< "ll_flush" << endl
<< fi
->fh
<< endl
;
1039 trace_lock
.Unlock();
1041 int res
= ::fdatasync(fi
->fh
);
1042 //int res = ::close(dup(fi->fh));
1044 fuse_reply_err(req
, 0);
1046 fuse_reply_err(req
, errno
);
1049 static void ft_ll_release(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
1053 traceout
<< "ll_release" << endl
<< fi
->fh
<< endl
;
1054 trace_lock
.Unlock();
1057 Inode
*in
= inode_map
[ino
];
1058 in
->fds
.erase(fi
->fh
);
1061 int res
= ::close(fi
->fh
);
1063 fuse_reply_err(req
, 0);
1065 fuse_reply_err(req
, errno
);
1068 static void ft_ll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
1069 struct fuse_file_info
*fi
)
1073 traceout
<< "ll_fsync" << endl
<< fi
->fh
<< endl
;
1074 trace_lock
.Unlock();
1076 int res
= ::fsync(fi
->fh
);
1078 fuse_reply_err(req
, 0);
1080 fuse_reply_err(req
, errno
);
1083 static struct fuse_lowlevel_ops ft_ll_oper
= {
1086 lookup
: ft_ll_lookup
,
1087 forget
: ft_ll_forget
,
1088 getattr
: ft_ll_getattr
,
1089 setattr
: ft_ll_setattr
,
1090 readlink
: ft_ll_readlink
,
1093 unlink
: ft_ll_unlink
,
1095 symlink
: ft_ll_symlink
,
1096 rename
: ft_ll_rename
,
1102 release
: ft_ll_release
,
1104 opendir
: ft_ll_opendir
,
1105 readdir
: ft_ll_readdir
,
1106 releasedir
: ft_ll_releasedir
,
1108 statfs
: ft_ll_statfs
,
1114 create
: ft_ll_create
,
1120 int main(int argc
, char *argv
[])
1127 for (int i
=0; i
<argc
; i
++) {
1128 if (strcmp(argv
[i
], "--basedir") == 0) {
1129 basedir
= argv
[++i
];
1130 } else if (strcmp(argv
[i
], "--timestamps") == 0) {
1131 do_timestamps
= atoi(argv
[++i
]);
1132 } else if (strcmp(argv
[i
], "--trace") == 0) {
1133 tracefile
.open(argv
[++i
], ios::out
|ios::trunc
);
1134 if (!tracefile
.is_open())
1135 cerr
<< "** couldn't open trace file " << argv
[i
] << endl
;
1136 } else if (strcmp(argv
[i
], "--debug") == 0) {
1139 cout
<< "arg: " << newargc
<< " " << argv
[i
] << endl
;
1140 newargv
[newargc
++] = argv
[i
];
1143 newargv
[newargc
++] = "-o";
1144 newargv
[newargc
++] = "allow_other";
1145 // newargv[newargc++] = "-o";
1146 // newargv[newargc++] = "default_permissions";
1147 if (!basedir
) return 1;
1148 cout
<< "basedir is " << basedir
<< endl
;
1152 ::lstat(basedir
, &root
->stbuf
);
1153 root
->stbuf
.st_ino
= 1;
1154 inode_map
[1] = root
;
1159 // go go gadget fuse
1160 struct fuse_args args
= FUSE_ARGS_INIT(newargc
, newargv
);
1161 struct fuse_chan
*ch
;
1164 if (fuse_parse_cmdline(&args
, &mountpoint
, NULL
, NULL
) != -1 &&
1165 (ch
= fuse_mount(mountpoint
, &args
)) != NULL
) {
1166 struct fuse_session
*se
;
1169 se
= fuse_lowlevel_new(&args
, &ft_ll_oper
, sizeof(ft_ll_oper
),
1172 if (fuse_set_signal_handlers(se
) != -1) {
1173 fuse_session_add_chan(se
, ch
);
1174 if (fuse_session_loop(se
) <= -1) {
1175 cout
<< "Failed fuse_session_loop() call." << endl
;
1178 fuse_remove_signal_handlers(se
);
1179 fuse_session_remove_chan(ch
);
1181 fuse_session_destroy(se
);
1183 fuse_unmount(mountpoint
, ch
);
1185 fuse_opt_free_args(&args
);