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
19 #include <fuse/fuse_lowlevel.h>
29 #include <sys/xattr.h>
34 #include "include/unordered_map.h"
35 #include "include/hash_namespace.h"
38 CEPH_HASH_NAMESPACE_START
39 template<> struct hash
<uint64_t> {
40 size_t operator()(uint64_t __x
) const {
41 static hash
<uint32_t> H
;
42 return H((__x
>> 32) ^ (__x
& 0xffffffff));
45 CEPH_HASH_NAMESPACE_END
55 #include "common/ceph_mutex.h"
57 ceph::mutex trace_lock
;
60 #define traceout (tracefile.is_open() ? tracefile : cout)
64 bool do_timestamps
= true;
66 #define dout if (debug) cout
75 map
<pair
<string
,ino_t
>,Inode
*> parents
;
78 map
<string
,Inode
*> dentries
;
82 Inode
*lookup(const string
& dname
) {
83 if (dentries
.count(dname
))
84 return dentries
[dname
];
90 ceph::unordered_map
<ino_t
, Inode
*> inode_map
;
92 bool make_inode_path(string
&buf
, Inode
*in
)
94 if (!in
->parents
.empty()) {
95 if (!make_inode_path(buf
, in
->parents
.begin()->second
))
98 buf
+= in
->parents
.begin()->first
.first
;
100 if (in
!= root
) return false;
101 assert(in
->stbuf
.st_ino
== 1);
106 //dout << "path: " << in->stbuf.st_ino << " -> " << buf << endl;
109 bool make_inode_path(string
&buf
, Inode
*in
, const char *name
)
111 if (!make_inode_path(buf
, in
)) return false;
117 bool make_ino_path(string
&buf
, ino_t ino
)
119 Inode
*in
= inode_map
[ino
];
121 return make_inode_path(buf
, in
);
124 bool make_ino_path(string
&buf
, ino_t ino
, const char *name
)
126 Inode
*in
= inode_map
[ino
];
128 if (!make_inode_path(buf
, in
))
135 void remove_dentry(Inode
*pin
, const string
& dname
)
137 dout
<< "remove_dentry " << pin
->stbuf
.st_ino
<< " " << dname
<< endl
;
139 Inode
*in
= pin
->lookup(dname
);
141 pin
->dentries
.erase(dname
);
142 in
->parents
.erase(pair
<string
,ino_t
>(dname
,pin
->stbuf
.st_ino
));
144 dout
<< "remove_dentry " << pin
->stbuf
.st_ino
<< " " << dname
145 << " ... inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
149 void add_dentry(Inode
*parent
, const string
& dname
, Inode
*in
)
151 dout
<< "add_dentry " << parent
->stbuf
.st_ino
<< " " << dname
<< " to " << in
->stbuf
.st_ino
<< endl
;
153 if (parent
->dentries
.count(dname
))
154 remove_dentry(parent
, dname
); // e.g., when renaming over another file..
156 parent
->dentries
[dname
] = in
;
157 in
->parents
[pair
<string
,ino_t
>(dname
,parent
->stbuf
.st_ino
)] = parent
;
160 void unlink_inode(Inode
*in
)
162 dout
<< "unlink_inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
<< endl
;
164 // remove parent links
165 while (!in
->parents
.empty()) {
166 Inode
*parent
= in
->parents
.begin()->second
;
167 string dname
= in
->parents
.begin()->first
.first
;
168 remove_dentry(parent
, dname
);
172 while (!in
->dentries
.empty())
173 remove_dentry(in
, in
->dentries
.begin()->first
);
175 while (!in
->fds
.empty()) {
176 int fd
= *in
->fds
.begin();
178 in
->fds
.erase(in
->fds
.begin());
179 dout
<< "remove_inode closeing stray fd " << fd
<< endl
;
183 void remove_inode(Inode
*in
)
185 dout
<< "remove_inode " << in
->stbuf
.st_ino
<< " ref " << in
->ref
<< endl
;
189 inode_map
.erase(in
->stbuf
.st_ino
);
190 dout
<< "remove_inode " << in
->stbuf
.st_ino
<< " done" << endl
;
194 Inode
*add_inode(Inode
*parent
, const char *name
, struct stat
*attr
)
196 dout
<< "add_inode " << parent
->stbuf
.st_ino
<< " " << name
<< " " << attr
->st_ino
<< endl
;
199 if (inode_map
.count(attr
->st_ino
)) {
201 in
= inode_map
[attr
->st_ino
];
202 unlink_inode(in
); // hrm.. should this close open fds? probably.
203 dout
<< "** REUSING INODE **" << endl
;
205 inode_map
[attr
->st_ino
] = in
= new Inode
;
207 memcpy(&in
->stbuf
, attr
, sizeof(*attr
));
210 add_dentry(parent
, dname
, in
);
220 gettimeofday(&tv
, 0);
221 traceout
<< "@" << endl
223 << tv
.tv_usec
<< endl
;
228 bool has_perm(int mask
, Inode
*in
, int uid
, int gid
)
230 dout
<< "hash_perm " << uid
<< "." << gid
<< " " << oct
<< mask
<< " in " << in
->stbuf
.st_mode
231 << " " << in
->stbuf
.st_uid
<< "." << in
->stbuf
.st_gid
<< endl
;
232 if (in
->stbuf
.st_mode
& mask
) return true;
233 if (in
->stbuf
.st_gid
== gid
&& in
->stbuf
.st_mode
& (mask
<< 3)) return true;
234 if (in
->stbuf
.st_uid
== uid
&& in
->stbuf
.st_mode
& (mask
<< 6)) return true;
239 static void ft_ll_lookup(fuse_req_t req
, fuse_ino_t pino
, const char *name
)
243 //dout << "lookup " << pino << " " << name << endl;
245 struct fuse_entry_param fe
;
246 memset(&fe
, 0, sizeof(fe
));
249 Inode
*parent
= inode_map
[pino
];
257 if (!has_perm(0001, parent
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)) {
260 else if (!make_inode_path(path
, parent
, name
)) {
263 in
= parent
->lookup(dname
);
264 if (in
&& res
== 0) {
265 // re-stat, for good measure
266 res
= ::lstat(path
.c_str(), &in
->stbuf
);
270 dout
<< "** WEIRD ** lookup on " << pino
<< " " << name
<< " inode went away!" << endl
;
275 //dout << "have " << in->stbuf.st_ino << endl;
278 res
= ::lstat(path
.c_str(), &in
->stbuf
);
279 //dout << "stat " << path << " res = " << res << endl;
281 inode_map
[in
->stbuf
.st_ino
] = in
;
282 add_dentry(parent
, dname
, in
);
291 fe
.ino
= in
->stbuf
.st_ino
;
292 memcpy(&fe
.attr
, &in
->stbuf
, sizeof(in
->stbuf
));
299 traceout
<< "ll_lookup" << endl
<< pino
<< endl
<< name
<< endl
<< fe
.attr
.st_ino
<< endl
;
303 fuse_reply_entry(req
, &fe
);
305 fuse_reply_err(req
, res
);
308 static void ft_ll_forget(fuse_req_t req
, fuse_ino_t ino
, long unsigned nlookup
)
311 std::scoped_lock l
{lock
};
312 Inode
*in
= inode_map
[ino
];
314 dout
<< "forget on " << ino
<< " ref " << in
->ref
<< ", forget " << nlookup
<< endl
;
315 if (in
->ref
< nlookup
)
316 dout
<< "**** BAD **** forget on " << ino
<< " ref " << in
->ref
<< ", forget " << nlookup
<< endl
;
322 dout
<< "**** BAD **** forget " << nlookup
<< " on nonexistent inode " << ino
<< endl
;
327 std::scoped_lock l
{trace_lock
};
329 traceout
<< "ll_forget" << endl
<< ino
<< endl
<< nlookup
<< endl
;
332 fuse_reply_none(req
);
335 static void ft_ll_getattr(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
346 if (in
->fds
.empty()) {
347 if (!make_inode_path(path
, in
))
350 fd
= *in
->fds
.begin();
354 res
= ::fstat(fd
, &attr
);
355 dout
<< "getattr fstat on fd " << fd
<< " res " << res
<< endl
;
356 } else if (res
== 0) {
357 res
= ::lstat(path
.c_str(), &attr
);
358 dout
<< "getattr lstat on " << path
<< " res " << res
<< endl
;
360 if (res
< 0) res
= errno
;
361 if (ino
== 1) attr
.st_ino
= 1;
365 traceout
<< "ll_getattr" << endl
<< ino
<< endl
;
370 memcpy(&in
->stbuf
, &attr
, sizeof(attr
));
372 fuse_reply_attr(req
, &attr
, 0);
374 fuse_reply_err(req
, res
);
377 static void ft_ll_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
378 int to_set
, struct fuse_file_info
*fi
)
387 if (in
->fds
.empty() || (to_set
& FUSE_SET_ATTR_MTIME
)) {
388 if (!make_inode_path(path
, in
))
391 fd
= *in
->fds
.begin();
396 traceout
<< "ll_setattr" << endl
<< ino
<< endl
;
397 traceout
<< attr
->st_mode
<< endl
;
398 traceout
<< attr
->st_uid
<< endl
<< attr
->st_gid
<< endl
;
399 traceout
<< attr
->st_size
<< endl
;
400 traceout
<< attr
->st_mtime
<< endl
;
401 traceout
<< attr
->st_atime
<< endl
;
402 traceout
<< to_set
<< endl
;
405 if (res
== 0 && !has_perm(0010, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)) {
407 } else if (res
== 0) {
408 if (to_set
& FUSE_SET_ATTR_MODE
) {
410 res
= ::fchmod(fd
, attr
->st_mode
);
412 res
= ::chmod(path
.c_str(), attr
->st_mode
);
414 if (!res
&& to_set
& FUSE_SET_ATTR_UID
) {
416 res
= ::fchown(fd
, attr
->st_uid
, attr
->st_gid
);
418 res
= ::chown(path
.c_str(), attr
->st_uid
, attr
->st_gid
);
420 if (!res
&& to_set
& FUSE_SET_ATTR_SIZE
) {
422 res
= ::ftruncate(fd
, attr
->st_size
);
424 res
= ::truncate(path
.c_str(), attr
->st_size
);
426 if (!res
&& to_set
& FUSE_SET_ATTR_MTIME
) {
428 ut
.actime
= attr
->st_atime
;
429 ut
.modtime
= attr
->st_mtime
;
430 res
= ::utime(path
.c_str(), &ut
);
432 if (res
< 0) res
= errno
;
437 ::lstat(path
.c_str(), &in
->stbuf
);
438 if (ino
== 1) in
->stbuf
.st_ino
= 1;
439 memcpy(attr
, &in
->stbuf
, sizeof(*attr
));
441 fuse_reply_attr(req
, attr
, 0);
443 fuse_reply_err(req
, res
);
447 static void ft_ll_readlink(fuse_req_t req
, fuse_ino_t ino
)
453 if (!make_ino_path(path
, ino
))
459 traceout
<< "ll_readlink" << endl
<< ino
<< endl
;
463 if (res
== 0) res
= readlink(path
.c_str(), buf
, 255);
464 if (res
< 0) res
= errno
;
468 fuse_reply_readlink(req
, buf
);
470 fuse_reply_err(req
, res
);
475 static void ft_ll_opendir(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
480 Inode
*in
= inode_map
[ino
];
481 if (!make_inode_path(path
, in
))
486 if (res
== 0 && !has_perm(0100, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
488 else if (res
== 0) dir
= opendir(path
.c_str());
489 if (res
< 0) res
= errno
;
493 traceout
<< "ll_opendir" << endl
<< ino
<< endl
<< (unsigned long)dir
<< endl
;
498 fuse_reply_open(req
, fi
);
500 fuse_reply_err(req
, res
);
503 static void ft_ll_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
504 off_t off
, struct fuse_file_info
*fi
)
507 DIR *dp
= (DIR*)fi
->fh
;
513 buf
= new char[size
];
515 fuse_reply_err(req
, ENOMEM
);
520 while ((de
= readdir(dp
)) != NULL
) {
522 memset(&st
, 0, sizeof(st
));
523 st
.st_ino
= de
->d_ino
;
524 st
.st_mode
= de
->d_type
<< 12;
526 size_t entrysize
= fuse_add_direntry(req
, buf
+ pos
, size
- pos
,
527 de
->d_name
, &st
, telldir(dp
));
528 if (entrysize
> size
- pos
)
529 break; // didn't fit, done for now.
533 fuse_reply_buf(req
, buf
, pos
);
537 static void ft_ll_releasedir(fuse_req_t req
, fuse_ino_t ino
,
538 struct fuse_file_info
*fi
)
540 DIR *dir
= (DIR*)fi
->fh
;
544 traceout
<< "ll_releasedir" << endl
<< (unsigned long)dir
<< endl
;
548 fuse_reply_err(req
, 0);
553 static void ft_ll_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
554 mode_t mode
, dev_t rdev
)
560 pin
= inode_map
[parent
];
561 if (!make_inode_path(path
, pin
, name
))
565 dout
<< "mknod " << path
<< endl
;
566 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
568 else if (res
== 0) res
= ::mknod(path
.c_str(), mode
, rdev
);
572 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
574 struct fuse_entry_param fe
;
576 memset(&fe
, 0, sizeof(fe
));
577 ::lstat(path
.c_str(), &fe
.attr
);
578 fe
.ino
= fe
.attr
.st_ino
;
580 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
587 traceout
<< "ll_mknod" << endl
<< parent
<< endl
<< name
<< endl
<< mode
<< endl
<< rdev
<< endl
;
588 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
592 fuse_reply_entry(req
, &fe
);
594 fuse_reply_err(req
, res
);
597 static void ft_ll_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
604 pin
= inode_map
[parent
];
605 if (!make_inode_path(path
, pin
, name
))
609 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
611 else if (res
== 0) res
= ::mkdir(path
.c_str(), mode
);
615 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
617 struct fuse_entry_param fe
;
619 memset(&fe
, 0, sizeof(fe
));
620 ::lstat(path
.c_str(), &fe
.attr
);
621 fe
.ino
= fe
.attr
.st_ino
;
623 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
630 traceout
<< "ll_mkdir" << endl
<< parent
<< endl
<< name
<< endl
<< mode
<< endl
;
631 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
635 fuse_reply_entry(req
, &fe
);
637 fuse_reply_err(req
, res
);
640 static void ft_ll_symlink(fuse_req_t req
, const char *value
, fuse_ino_t parent
, const char *name
)
647 pin
= inode_map
[parent
];
648 if (!make_inode_path(path
, pin
, name
))
652 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
654 else if (res
== 0) res
= ::symlink(value
, path
.c_str());
658 ::chown(path
.c_str(), fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
660 struct fuse_entry_param fe
;
662 memset(&fe
, 0, sizeof(fe
));
663 ::lstat(path
.c_str(), &fe
.attr
);
664 fe
.ino
= fe
.attr
.st_ino
;
666 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
673 traceout
<< "ll_symlink" << endl
<< parent
<< endl
<< name
<< endl
<< value
<< endl
;
674 traceout
<< (res
== 0 ? fe
.ino
:0) << endl
;
678 fuse_reply_entry(req
, &fe
);
680 fuse_reply_err(req
, res
);
683 static void ft_ll_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
684 mode_t mode
, struct fuse_file_info
*fi
)
691 pin
= inode_map
[parent
];
692 if (!make_inode_path(path
, pin
, name
))
696 dout
<< "create " << path
<< endl
;
698 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
701 fd
= ::open(path
.c_str(), fi
->flags
|O_CREAT
, mode
);
705 ::fchown(fd
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
);
709 struct fuse_entry_param fe
;
710 memset(&fe
, 0, sizeof(fe
));
712 ::lstat(path
.c_str(), &fe
.attr
);
713 fe
.ino
= fe
.attr
.st_ino
;
715 Inode
*in
= add_inode(pin
, name
, &fe
.attr
);
724 traceout
<< "ll_create" << endl
729 << (res
== 0 ? fd
:0) << endl
734 fuse_reply_create(req
, &fe
, fi
);
736 fuse_reply_err(req
, res
);
741 static void ft_ll_statfs(fuse_req_t req
, fuse_ino_t ino
)
747 if (!make_ino_path(path
, ino
))
756 traceout
<< "ll_statfs" << endl
<< ino
<< endl
;
759 struct statvfs stbuf
;
760 if (res
== 0) res
= statvfs(path
.c_str(), &stbuf
);
761 if (res
< 0) res
= errno
;
764 fuse_reply_statfs(req
, &stbuf
);
766 fuse_reply_err(req
, res
);
769 static void ft_ll_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
777 pin
= inode_map
[parent
];
778 in
= pin
->lookup(dname
);
779 if (!make_inode_path(path
, pin
, name
))
785 traceout
<< "ll_unlink" << endl
<< parent
<< endl
<< name
<< endl
;
788 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
791 if (in
&& in
->fds
.empty()) {
792 int fd
= ::open(path
.c_str(), O_RDWR
);
794 in
->fds
.insert(fd
); // for slow getattrs.. wtf
795 dout
<< "unlink opening paranoia fd " << fd
<< endl
;
797 res
= ::unlink(path
.c_str());
798 if (res
< 0) res
= errno
;
802 // remove from out cache
805 if (pin
->lookup(dname
))
806 remove_dentry(pin
, dname
);
808 fuse_reply_err(req
, 0);
810 fuse_reply_err(req
, res
);
813 static void ft_ll_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
820 pin
= inode_map
[parent
];
821 if (!make_inode_path(path
, pin
, name
))
827 traceout
<< "ll_rmdir" << endl
<< parent
<< endl
<< name
<< endl
;
830 if (res
== 0 && !has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
832 else if (res
== 0) res
= ::rmdir(path
.c_str());
833 if (res
< 0) res
= errno
;
836 // remove from out cache
839 if (pin
->lookup(dname
))
840 remove_dentry(pin
, dname
);
842 fuse_reply_err(req
, 0);
844 fuse_reply_err(req
, res
);
848 static void ft_ll_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
849 fuse_ino_t newparent
, const char *newname
)
857 pin
= inode_map
[parent
];
858 if (!make_inode_path(path
, pin
, name
))
860 newpin
= inode_map
[newparent
];
861 if (!make_inode_path(newpath
, newpin
, newname
))
867 traceout
<< "ll_rename" << endl
874 if (res
== 0 && (!has_perm(0010, pin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
) ||
875 !has_perm(0010, newpin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)))
877 else if (res
== 0) res
= ::rename(path
.c_str(), newpath
.c_str());
878 if (res
< 0) res
= errno
;
882 string
newdname(newname
);
884 Inode
*in
= pin
->lookup(dname
);
886 add_dentry(newpin
, newdname
, in
);
887 remove_dentry(pin
, dname
);
889 dout
<< "hrm, rename didn't have renamed inode.. " << path
<< " to " << newpath
<< endl
;
892 fuse_reply_err(req
, 0);
894 fuse_reply_err(req
, res
);
897 static void ft_ll_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t newparent
,
907 if (!make_inode_path(path
, in
))
910 newpin
= inode_map
[newparent
];
911 if (!make_inode_path(newpath
, newpin
, newname
))
917 traceout
<< "ll_link" << endl
923 //cout << "link " << path << " newpath " << newpath << endl;
924 if (res
== 0 && (!has_perm(0010, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
) ||
925 !has_perm(0010, newpin
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
)))
927 else if (res
== 0) res
= ::link(path
.c_str(), newpath
.c_str());
928 if (res
< 0) res
= errno
;
931 struct fuse_entry_param fe
;
932 memset(&fe
, 0, sizeof(fe
));
933 ::lstat(newpath
.c_str(), &fe
.attr
);
936 string
newdname(newname
);
937 add_dentry(newpin
, newdname
, in
);
939 memcpy(&in
->stbuf
, &fe
.attr
, sizeof(fe
.attr
)); // re-read, bc we changed the link count
942 fe
.ino
= fe
.attr
.st_ino
;
943 fuse_reply_entry(req
, &fe
);
945 fuse_reply_err(req
, res
);
948 static void ft_ll_open(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
956 if (!make_inode_path(path
, in
))
961 if (fi
->flags
& O_RDWR
) want
|= 0010;
962 if (fi
->flags
== O_WRONLY
) want
= 0010;
965 if (res
== 0 && !has_perm(want
, in
, fuse_req_ctx(req
)->uid
, fuse_req_ctx(req
)->gid
))
968 fd
= ::open(path
.c_str(), fi
->flags
);
969 if (fd
<= 0) res
= errno
;
974 traceout
<< "ll_open" << endl
977 << (fd
> 0 ? fd
:0) << endl
;
985 fuse_reply_open(req
, fi
);
987 fuse_reply_err(req
, res
);
990 static void ft_ll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t off
,
991 struct fuse_file_info
*fi
)
994 char *buf
= new char[size
];
995 int res
= ::pread(fi
->fh
, buf
, size
, off
);
997 //cout << "read " << path << " " << off << "~" << size << endl;
1000 traceout
<< "ll_read" << endl
1004 trace_lock
.unlock();
1007 fuse_reply_buf(req
, buf
, res
);
1009 fuse_reply_err(req
, errno
);
1013 static void ft_ll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
1014 size_t size
, off_t off
, struct fuse_file_info
*fi
)
1016 int res
= ::pwrite(fi
->fh
, buf
, size
, off
);
1020 traceout
<< "ll_write" << endl
1024 trace_lock
.unlock();
1027 fuse_reply_write(req
, res
);
1029 fuse_reply_err(req
, errno
);
1032 static void ft_ll_flush(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
1036 traceout
<< "ll_flush" << endl
<< fi
->fh
<< endl
;
1037 trace_lock
.unlock();
1039 int res
= ::fdatasync(fi
->fh
);
1040 //int res = ::close(dup(fi->fh));
1042 fuse_reply_err(req
, 0);
1044 fuse_reply_err(req
, errno
);
1047 static void ft_ll_release(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
1051 traceout
<< "ll_release" << endl
<< fi
->fh
<< endl
;
1052 trace_lock
.unlock();
1055 Inode
*in
= inode_map
[ino
];
1056 in
->fds
.erase(fi
->fh
);
1059 int res
= ::close(fi
->fh
);
1061 fuse_reply_err(req
, 0);
1063 fuse_reply_err(req
, errno
);
1066 static void ft_ll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
1067 struct fuse_file_info
*fi
)
1071 traceout
<< "ll_fsync" << endl
<< fi
->fh
<< endl
;
1072 trace_lock
.unlock();
1074 int res
= ::fsync(fi
->fh
);
1076 fuse_reply_err(req
, 0);
1078 fuse_reply_err(req
, errno
);
1081 static struct fuse_lowlevel_ops ft_ll_oper
= {
1084 lookup
: ft_ll_lookup
,
1085 forget
: ft_ll_forget
,
1086 getattr
: ft_ll_getattr
,
1087 setattr
: ft_ll_setattr
,
1088 readlink
: ft_ll_readlink
,
1091 unlink
: ft_ll_unlink
,
1093 symlink
: ft_ll_symlink
,
1094 rename
: ft_ll_rename
,
1100 release
: ft_ll_release
,
1102 opendir
: ft_ll_opendir
,
1103 readdir
: ft_ll_readdir
,
1104 releasedir
: ft_ll_releasedir
,
1106 statfs
: ft_ll_statfs
,
1112 create
: ft_ll_create
,
1118 int main(int argc
, char *argv
[])
1125 for (int i
=0; i
<argc
; i
++) {
1126 if (strcmp(argv
[i
], "--basedir") == 0) {
1127 basedir
= argv
[++i
];
1128 } else if (strcmp(argv
[i
], "--timestamps") == 0) {
1129 do_timestamps
= atoi(argv
[++i
]);
1130 } else if (strcmp(argv
[i
], "--trace") == 0) {
1131 tracefile
.open(argv
[++i
], ios::out
|ios::trunc
);
1132 if (!tracefile
.is_open())
1133 cerr
<< "** couldn't open trace file " << argv
[i
] << endl
;
1134 } else if (strcmp(argv
[i
], "--debug") == 0) {
1137 cout
<< "arg: " << newargc
<< " " << argv
[i
] << endl
;
1138 newargv
[newargc
++] = argv
[i
];
1141 newargv
[newargc
++] = "-o";
1142 newargv
[newargc
++] = "allow_other";
1143 // newargv[newargc++] = "-o";
1144 // newargv[newargc++] = "default_permissions";
1145 if (!basedir
) return 1;
1146 cout
<< "basedir is " << basedir
<< endl
;
1150 ::lstat(basedir
, &root
->stbuf
);
1151 root
->stbuf
.st_ino
= 1;
1152 inode_map
[1] = root
;
1157 // go go gadget fuse
1158 struct fuse_args args
= FUSE_ARGS_INIT(newargc
, newargv
);
1159 struct fuse_chan
*ch
;
1162 if (fuse_parse_cmdline(&args
, &mountpoint
, NULL
, NULL
) != -1 &&
1163 (ch
= fuse_mount(mountpoint
, &args
)) != NULL
) {
1164 struct fuse_session
*se
;
1167 se
= fuse_lowlevel_new(&args
, &ft_ll_oper
, sizeof(ft_ll_oper
),
1170 if (fuse_set_signal_handlers(se
) != -1) {
1171 fuse_session_add_chan(se
, ch
);
1172 if (fuse_session_loop(se
) <= -1) {
1173 cout
<< "Failed fuse_session_loop() call." << endl
;
1176 fuse_remove_signal_handlers(se
);
1177 fuse_session_remove_chan(ch
);
1179 fuse_session_destroy(se
);
1181 fuse_unmount(mountpoint
, ch
);
1183 fuse_opt_free_args(&args
);