github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/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  	"bazil.org/fuse"
    23  	"bazil.org/fuse/fs"
    24  	"errors"
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/swarm/storage"
    27  	"golang.org/x/net/context"
    28  	"io"
    29  	"os"
    30  	"sync"
    31  )
    32  
    33  const (
    34  	MaxAppendFileSize = 10485760 // 10Mb
    35  )
    36  
    37  var (
    38  	errInvalidOffset           = errors.New("Invalid offset during write")
    39  	errFileSizeMaxLimixReached = errors.New("File size exceeded max limit")
    40  )
    41  
    42  var (
    43  	_ fs.Node         = (*SwarmFile)(nil)
    44  	_ fs.HandleReader = (*SwarmFile)(nil)
    45  	_ fs.HandleWriter = (*SwarmFile)(nil)
    46  )
    47  
    48  type SwarmFile struct {
    49  	inode    uint64
    50  	name     string
    51  	path     string
    52  	key      storage.Key
    53  	fileSize int64
    54  	reader   storage.LazySectionReader
    55  
    56  	mountInfo *MountInfo
    57  	lock      *sync.RWMutex
    58  }
    59  
    60  func NewSwarmFile(path, fname string, minfo *MountInfo) *SwarmFile {
    61  	newFile := &SwarmFile{
    62  		inode:    NewInode(),
    63  		name:     fname,
    64  		path:     path,
    65  		key:      nil,
    66  		fileSize: -1, // -1 means , file already exists in swarm and you need to just get the size from swarm
    67  		reader:   nil,
    68  
    69  		mountInfo: minfo,
    70  		lock:      &sync.RWMutex{},
    71  	}
    72  	return newFile
    73  }
    74  
    75  func (file *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error {
    76  
    77  	a.Inode = file.inode
    78  	//TODO: need to get permission as argument
    79  	a.Mode = 0700
    80  	a.Uid = uint32(os.Getuid())
    81  	a.Gid = uint32(os.Getegid())
    82  
    83  	if file.fileSize == -1 {
    84  		reader := file.mountInfo.swarmApi.Retrieve(file.key)
    85  		quitC := make(chan bool)
    86  		size, err := reader.Size(quitC)
    87  		if err != nil {
    88  			log.Warn("Couldnt get size of file %s : %v", file.path, err)
    89  		}
    90  		file.fileSize = int64(size)
    91  	}
    92  	a.Size = uint64(file.fileSize)
    93  	return nil
    94  }
    95  
    96  func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
    97  
    98  	sf.lock.RLock()
    99  	defer sf.lock.RUnlock()
   100  	if sf.reader == nil {
   101  		sf.reader = sf.mountInfo.swarmApi.Retrieve(sf.key)
   102  	}
   103  	buf := make([]byte, req.Size)
   104  	n, err := sf.reader.ReadAt(buf, req.Offset)
   105  	if err == io.ErrUnexpectedEOF || err == io.EOF {
   106  		err = nil
   107  	}
   108  	resp.Data = buf[:n]
   109  	sf.reader = nil
   110  	return err
   111  
   112  }
   113  
   114  func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
   115  
   116  	if sf.fileSize == 0 && req.Offset == 0 {
   117  
   118  		// A new file is created
   119  		err := addFileToSwarm(sf, req.Data, len(req.Data))
   120  		if err != nil {
   121  			return err
   122  		}
   123  		resp.Size = len(req.Data)
   124  
   125  	} else if req.Offset <= sf.fileSize {
   126  
   127  		totalSize := sf.fileSize + int64(len(req.Data))
   128  		if totalSize > MaxAppendFileSize {
   129  			log.Warn("Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data))
   130  			return errFileSizeMaxLimixReached
   131  		}
   132  
   133  		err := appendToExistingFileInSwarm(sf, req.Data, req.Offset, int64(len(req.Data)))
   134  		if err != nil {
   135  			return err
   136  		}
   137  		resp.Size = int(sf.fileSize)
   138  	} else {
   139  		log.Warn("Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset)
   140  		return errInvalidOffset
   141  	}
   142  
   143  	return nil
   144  }