root/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEVolume.h
/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef USERLAND_FS_FUSE_VOLUME_H
#define USERLAND_FS_FUSE_VOLUME_H

#include <AutoLocker.h>
#include <RWLockManager.h>

#include "Locker.h"

#include "fuse_fs.h"
#include "FUSEEntry.h"
#include "FUSEFileSystem.h"

#include "../Volume.h"


namespace UserlandFS {

class FUSEFileSystem;


class FUSEVolume : public Volume {
public:
                                                                FUSEVolume(FUSEFileSystem* fileSystem,
                                                                        dev_t id);
        virtual                                         ~FUSEVolume();

                        status_t                        Init();

                        void                            SetFS(fuse_fs* fs)      { fFS = fs; }

        // FS
        virtual status_t                        Mount(const char* device, uint32 flags,
                                                                        const char* parameters, ino_t* rootID);
        virtual status_t                        Unmount();
        virtual status_t                        Sync();
        virtual status_t                        ReadFSInfo(fs_info* info);

        // vnodes
        virtual status_t                        Lookup(void* dir, const char* entryName,
                                                                        ino_t* vnid);
        virtual status_t                        GetVNodeName(void* node, char* buffer,
                                                                        size_t bufferSize);
        virtual status_t                        ReadVNode(ino_t vnid, bool reenter,
                                                                        void** node, int* type, uint32* flags,
                                                                        FSVNodeCapabilities* _capabilities);
        virtual status_t                        WriteVNode(void* node, bool reenter);
        virtual status_t                        RemoveVNode(void* node, bool reenter);

        // asynchronous I/O
        virtual status_t                        DoIO(void* node, void* cookie,
                                                                        const IORequestInfo& requestInfo);

        // nodes
        virtual status_t                        SetFlags(void* node, void* cookie,
                                                                        int flags);

        virtual status_t                        FSync(void* node);

        virtual status_t                        ReadSymlink(void* node, char* buffer,
                                                                        size_t bufferSize, size_t* bytesRead);
        virtual status_t                        CreateSymlink(void* dir, const char* name,
                                                                        const char* target, int mode);

        virtual status_t                        Link(void* dir, const char* name,
                                                                        void* node);
        virtual status_t                        Unlink(void* dir, const char* name);
        virtual status_t                        Rename(void* oldDir, const char* oldName,
                                                                        void* newDir, const char* newName);

        virtual status_t                        Access(void* node, int mode);
        virtual status_t                        ReadStat(void* node, struct stat* st);
        virtual status_t                        WriteStat(void* node, const struct stat* st,
                                                                        uint32 mask);

        // files
        virtual status_t                        Create(void* dir, const char* name,
                                                                        int openMode, int mode, void** cookie,
                                                                        ino_t* vnid);
        virtual status_t                        Open(void* node, int openMode,
                                                                        void** cookie);
        virtual status_t                        Close(void* node, void* cookie);
        virtual status_t                        FreeCookie(void* node, void* cookie);
        virtual status_t                        Read(void* node, void* cookie, off_t pos,
                                                                        void* buffer, size_t bufferSize,
                                                                        size_t* bytesRead);
        virtual status_t                        Write(void* node, void* cookie,
                                                                        off_t pos, const void* buffer,
                                                                        size_t bufferSize, size_t* bytesWritten);

        // directories
        virtual status_t                        CreateDir(void* dir, const char* name,
                                                                        int mode);
        virtual status_t                        RemoveDir(void* dir, const char* name);
        virtual status_t                        OpenDir(void* node, void** cookie);
        virtual status_t                        CloseDir(void* node, void* cookie);
        virtual status_t                        FreeDirCookie(void* node, void* cookie);
        virtual status_t                        ReadDir(void* node, void* cookie,
                                                                        void* buffer, size_t bufferSize,
                                                                        uint32 count, uint32* countRead);
        virtual status_t                        RewindDir(void* node, void* cookie);

        // attribute directories
        virtual status_t                        OpenAttrDir(void* node, void** cookie);
        virtual status_t                        CloseAttrDir(void* node, void* cookie);
        virtual status_t                        FreeAttrDirCookie(void* node,
                                                                        void* cookie);
        virtual status_t                        ReadAttrDir(void* node, void* cookie,
                                                                        void* buffer, size_t bufferSize,
                                                                        uint32 count, uint32* countRead);
        virtual status_t                        RewindAttrDir(void* node, void* cookie);

        // attributes
        virtual status_t                        OpenAttr(void* node, const char* name,
                                                                        int openMode, void** cookie);
        virtual status_t                        CloseAttr(void* node, void* cookie);
        virtual status_t                        FreeAttrCookie(void* node, void* cookie);
        virtual status_t                        ReadAttr(void* node, void* cookie,
                                                                        off_t pos, void* buffer, size_t bufferSize,
                                                                        size_t* bytesRead);
        virtual status_t                        ReadAttrStat(void* node, void* cookie,
                                                                        struct stat* st);

private:
        struct DirEntryCache;
        struct DirCookie;
        struct FileCookie;
        struct AttrDirCookie;
        struct AttrCookie;
        struct ReadDirBuffer;
        struct LockIterator;
        struct RWLockableReadLocking;
        struct RWLockableWriteLocking;
        struct RWLockableReadLocker;
        struct RWLockableWriteLocker;
        struct NodeLocker;
        struct NodeReadLocker;
        struct NodeWriteLocker;
        struct MultiNodeLocker;

        friend struct LockIterator;
        friend struct RWLockableReadLocking;
        friend struct RWLockableWriteLocking;
        friend struct NodeLocker;
        friend struct MultiNodeLocker;

private:
        inline  FUSEFileSystem*         _FileSystem() const
                                                                        { return static_cast<FUSEFileSystem*>(fFileSystem); }

                        ino_t                           _GenerateNodeID();

                        bool                            _GetNodeID(FUSENode* dir, const char* entryName,
                                                                        ino_t* _nodeID);
                        status_t                        _GetNode(FUSENode* dir, const char* entryName,
                                                                        FUSENode** _node);
                        status_t                        _InternalGetNode(FUSENode* dir,
                                                                        const char* entryName, FUSENode** _node,
                                                                        AutoLocker<Locker>& locker);
                        void                            _PutNode(FUSENode* node);
                        void                            _PutNodes(FUSENode* const* nodes, int32 count);

                        void                            _RemoveEntry(FUSEEntry* entry);
                        status_t                        _RemoveEntry(FUSENode* dir, const char* name);
                        status_t                        _RenameEntry(FUSENode* oldDir,
                                                                        const char* oldName, FUSENode* newDir,
                                                                        const char* newName);

                        status_t                        _LockNodeChain(FUSENode* node, bool lockParent,
                                                                        bool writeLock);
                        void                            _UnlockNodeChain(FUSENode* node, bool parent,
                                                                        bool writeLock);
                        void                            _UnlockNodeChainInternal(FUSENode* node,
                                                                        bool writeLock, FUSENode* stopNode,
                                                                        FUSENode* stopBeforeNode);

                        status_t                        _LockNodeChains(FUSENode* node1,
                                                                        bool lockParent1, bool writeLock1,
                                                                        FUSENode* node2, bool lockParent2,
                                                                        bool writeLock2);
                        status_t                        _LockNodeChainsInternal(FUSENode* node1,
                                                                        bool lockParent1, bool writeLock1,
                                                                        FUSENode* node2, bool lockParent2,
                                                                        bool writeLock2, bool* _retry);
                        void                            _UnlockNodeChains(FUSENode* node1, bool parent1,
                                                                        bool writeLock1, FUSENode* node2,
                                                                        bool parent2, bool writeLock2);

                        bool                            _FindCommonAncestor(FUSENode* node1,
                                                                        FUSENode* node2, FUSENode** _commonAncestor,
                                                                        bool* _inverseLockingOrder);
                        bool                            _GetNodeAncestors(FUSENode* node,
                                                                        FUSENode** ancestors, uint32* _count);

                        status_t                        _BuildPath(FUSENode* dir, const char* entryName,
                                                                        char* path, size_t& pathLen);
                        status_t                        _BuildPath(FUSENode* node, char* path,
                                                                        size_t& pathLen);

        static  int                                     _AddReadDirEntryLowLevel(void* buffer, char* buf, size_t bufsize,
                                                                        const char* name, const struct stat* st, off_t offset);
        static  int                                     _AddReadDirEntry(void* buffer, const char* name,
                                                                        const struct stat* st, off_t offset);
        static  int                                     _AddReadDirEntryGetDir(fuse_dirh_t handle,
                                                                        const char* name, int type, ino_t nodeID);
                        int                                     _AddReadDirEntryLowLevel(ReadDirBuffer* buffer,
                                                                        char* buf, size_t bufSize, const char* name, int type,
                                                                        ino_t nodeID, off_t offset);
                        int                                     _AddReadDirEntry(ReadDirBuffer* buffer,
                                                                        const char* name, int type, ino_t nodeID,
                                                                        off_t offset);                  
                        status_t                        _InternalIO(FUSENode* node, FileCookie* cookie, const char* path,
                                                                        off_t pos, char* buffer, size_t& bytes, bool isWrite);

private:
                        RWLockManager           fLockManager;
                        Locker                          fLock;
        const   fuse_lowlevel_ops*      fOps;
                        fuse_fs*                        fFS;
                        FUSEEntryTable          fEntries;
                        FUSENodeTable           fNodes;
                        FUSENode*                       fRootNode;
                        ino_t                           fNextNodeID;
                        bool                            fUseNodeIDs;
                        char                            fName[B_OS_NAME_LENGTH];
};

}       // namespace UserlandFS

using UserlandFS::FUSEVolume;

#endif  // USERLAND_FS_FUSE_VOLUME_H