123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // +build linux
- /*
- * Rufs - Remote Union File System
- *
- * Copyright 2017 Matthias Ladkau. All rights reserved.
- *
- * This Source Code Form is subject to the terms of the MIT
- * License, If a copy of the MIT License was not distributed with this
- * file, You can obtain one at https://opensource.org/licenses/MIT.
- */
- /*
- Package export contains export bindings for Rufs.
- */
- package export
- /*
- This file contains Rufs bindings for FUSE (Filesystem in Userspace) enabling
- a user to operate on Rufs as if it was a local file system.
- This uses GO-FUSE: https://github.com/hanwen/go-fuse
- Distributed under the New BSD License
- Copyright (c) 2010 the Go-FUSE Authors. All rights reserved.
- */
- import (
- "log"
- "os"
- "path"
- "path/filepath"
- "devt.de/krotik/rufs"
- "github.com/hanwen/go-fuse/v2/fuse"
- "github.com/hanwen/go-fuse/v2/fuse/nodefs"
- "github.com/hanwen/go-fuse/v2/fuse/pathfs"
- )
- /*
- RufsFuse is the Rufs specific FUSE filesystem API that uses paths rather
- than inodes.
- */
- type RufsFuse struct {
- pathfs.FileSystem
- Tree *rufs.Tree
- }
- /*
- GetAttr is the main entry point, through which FUSE discovers which
- files and directories exist.
- */
- func (rf *RufsFuse) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
- if name == "" {
- // Mount point is always a directory
- return &fuse.Attr{
- Mode: fuse.S_IFDIR | 0755,
- }, fuse.OK
- }
- var a *fuse.Attr
- status := fuse.ENOENT
- // Construct path and filename
- name = path.Join("/", name)
- dir, file := filepath.Split(name)
- // Query the tree
- _, fis, err := rf.Tree.Dir(dir, "", false, false)
- if err != nil {
- log.Print(err)
- status = fuse.EIO
- }
- if len(fis) > 0 {
- // Create attribute entries
- for _, fi := range fis[0] {
- if fi.Name() == file {
- a = &fuse.Attr{
- Mode: OSModeToFuseMode(fi.Mode()),
- Size: uint64(fi.Size()),
- }
- status = fuse.OK
- }
- }
- }
- return a, status
- }
- /*
- OpenDir handles directories.
- */
- func (rf *RufsFuse) OpenDir(name string,
- context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
- var c []fuse.DirEntry
- // Construct path and filename
- name = path.Join("/", name)
- status := fuse.ENOENT
- // Query the tree
- _, fis, err := rf.Tree.Dir(name, "", false, false)
- if err != nil {
- LogError(err)
- return nil, fuse.EIO
- }
- if len(fis) > 0 {
- // Create entries
- for _, fi := range fis[0] {
- c = append(c, fuse.DirEntry{
- Name: fi.Name(),
- Mode: OSModeToFuseMode(fi.Mode()),
- })
- }
- status = fuse.OK
- }
- return c, status
- }
- /*
- Open file handling.
- */
- func (rf *RufsFuse) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
- return &RufsFile{nodefs.NewDefaultFile(), path.Join("/", name), rf.Tree}, fuse.OK
- }
- // File related objects
- // ====================
- /*
- RufsFile models a file of Rufs.
- */
- type RufsFile struct {
- nodefs.File
- name string
- tree *rufs.Tree
- }
- /*
- Read reads a portion of the file.
- */
- func (f *RufsFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
- var res fuse.ReadResult
- status := fuse.OK
- n, err := f.tree.ReadFile(f.name, buf, off)
- if err != nil {
- LogError(err)
- status = fuse.EIO
- } else {
- res = &RufsReadResult{buf, n}
- }
- return res, status
- }
- /*
- RufsReadResult is an implementation of fuse.ReadResult.
- */
- type RufsReadResult struct {
- buf []byte
- n int
- }
- /*
- Bytes returns the raw bytes for the read.
- */
- func (r *RufsReadResult) Bytes(buf []byte) ([]byte, fuse.Status) {
- return r.buf, fuse.OK
- }
- /*
- Size returns how many bytes this return value takes at most.
- */
- func (r *RufsReadResult) Size() int {
- return r.n
- }
- /*
- Done is called after sending the data to the kernel.
- */
- func (r *RufsReadResult) Done() {}
- // Helper functions
- // ================
- /*
- OSModeToFuseMode converts a given os.FileMode to a Fuse Mode
- */
- func OSModeToFuseMode(fm os.FileMode) uint32 {
- m := uint32(fm)
- m = m & 0x0FFF // Remove special bits
- if fm.IsDir() {
- m = fuse.S_IFDIR | m
- } else {
- m = fuse.S_IFREG | m
- }
- return m
- }
|