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);