github.com/anthdm/go-ethereum@v1.8.4-0.20180412101906-60516c83b011/swarm/fuse/fuse_file.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // +build linux darwin freebsd
    18  
    19  package fuse
    20  
    21  import (
    22  	"errors"
    23  	"io"
    24  	"os"
    25  	"sync"
    26  
    27  	"bazil.org/fuse"
    28  	"bazil.org/fuse/fs"
    29  	"github.com/ethereum/go-ethereum/log"
    30  	"github.com/ethereum/go-ethereum/swarm/storage"
    31  	"golang.org/x/net/context"
    32  )
    33  
    34  const (
    35  	MaxAppendFileSize = 10485760 // 10Mb
    36  )
    37  
    38  var (
    39  	errInvalidOffset           = errors.New("Invalid offset during write")
    40  	errFileSizeMaxLimixReached = errors.New("File size exceeded max limit")
    41  )
    42  
    43  var (
    44  	_ fs.Node         = (*SwarmFile)(nil)
    45  	_ fs.HandleReader = (*SwarmFile)(nil)
    46  	_ fs.HandleWriter = (*SwarmFile)(nil)
    47  )
    48  
    49  type SwarmFile struct {
    50  	inode    uint64
    51  	name     string
    52  	path     string
    53  	key      storage.Key
    54  	fileSize int64
    55  	reader   storage.LazySectionReader
    56  
    57  	mountInfo *MountInfo
    58  	lock      *sync.RWMutex
    59  }
    60  
    61  func NewSwarmFile(path, fname string, minfo *MountInfo) *SwarmFile {
    62  	newFile := &SwarmFile{
    63  		inode:    NewInode(),
    64  		name:     fname,
    65  		path:     path,
    66  		key:      nil,
    67  		fileSize: -1, // -1 means , file already exists in swarm and you need to just get the size from swarm
    68  		reader:   nil,
    69  
    70  		mountInfo: minfo,
    71  		lock:      &sync.RWMutex{},
    72  	}
    73  	return newFile
    74  }
    75  
    76  func (file *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error {
    77  
    78  	a.Inode = file.inode
    79  	//TODO: need to get permission as argument
    80  	a.Mode = 0700
    81  	a.Uid = uint32(os.Getuid())
    82  	a.Gid = uint32(os.Getegid())
    83  
    84  	if file.fileSize == -1 {
    85  		reader := file.mountInfo.swarmApi.Retrieve(file.key)
    86  		quitC := make(chan bool)
    87  		size, err := reader.Size(quitC)
    88  		if err != nil {
    89  			log.Warn("Couldnt get size of file %s : %v", file.path, err)
    90  		}
    91  		file.fileSize = size
    92  	}
    93  	a.Size = uint64(file.fileSize)
    94  	return nil
    95  }
    96  
    97  func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
    98  
    99  	sf.lock.RLock()
   100  	defer sf.lock.RUnlock()
   101  	if sf.reader == nil {
   102  		sf.reader = sf.mountInfo.swarmApi.Retrieve(sf.key)
   103  	}
   104  	buf := make([]byte, req.Size)
   105  	n, err := sf.reader.ReadAt(buf, req.Offset)
   106  	if err == io.ErrUnexpectedEOF || err == io.EOF {
   107  		err = nil
   108  	}
   109  	resp.Data = buf[:n]
   110  	sf.reader = nil
   111  	return err
   112  
   113  }
   114  
   115  func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
   116  
   117  	if sf.fileSize == 0 && req.Offset == 0 {
   118  
   119  		// A new file is created
   120  		err := addFileToSwarm(sf, req.Data, len(req.Data))
   121  		if err != nil {
   122  			return err
   123  		}
   124  		resp.Size = len(req.Data)
   125  
   126  	} else if req.Offset <= sf.fileSize {
   127  
   128  		totalSize := sf.fileSize + int64(len(req.Data))
   129  		if totalSize > MaxAppendFileSize {
   130  			log.Warn("Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data))
   131  			return errFileSizeMaxLimixReached
   132  		}
   133  
   134  		err := appendToExistingFileInSwarm(sf, req.Data, req.Offset, int64(len(req.Data)))
   135  		if err != nil {
   136  			return err
   137  		}
   138  		resp.Size = len(req.Data)
   139  	} else {
   140  		log.Warn("Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset)
   141  		return errInvalidOffset
   142  	}
   143  
   144  	return nil
   145  }