github.com/MaynardMiner/ethereumprogpow@v1.8.23/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/ethereumprogpow/ethereumprogpow/swarm/log"
    30  	"github.com/ethereumprogpow/ethereumprogpow/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  	addr     storage.Address
    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  		addr:     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 (sf *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error {
    77  	log.Debug("swarmfs Attr", "path", sf.path)
    78  	sf.lock.Lock()
    79  	defer sf.lock.Unlock()
    80  	a.Inode = sf.inode
    81  	//TODO: need to get permission as argument
    82  	a.Mode = 0700
    83  	a.Uid = uint32(os.Getuid())
    84  	a.Gid = uint32(os.Getegid())
    85  
    86  	if sf.fileSize == -1 {
    87  		reader, _ := sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr)
    88  		quitC := make(chan bool)
    89  		size, err := reader.Size(ctx, quitC)
    90  		if err != nil {
    91  			log.Error("Couldnt get size of file %s : %v", sf.path, err)
    92  			return err
    93  		}
    94  		sf.fileSize = size
    95  		log.Trace("swarmfs Attr", "size", size)
    96  		close(quitC)
    97  	}
    98  	a.Size = uint64(sf.fileSize)
    99  	return nil
   100  }
   101  
   102  func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
   103  	log.Debug("swarmfs Read", "path", sf.path, "req.String", req.String())
   104  	sf.lock.RLock()
   105  	defer sf.lock.RUnlock()
   106  	if sf.reader == nil {
   107  		sf.reader, _ = sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr)
   108  	}
   109  	buf := make([]byte, req.Size)
   110  	n, err := sf.reader.ReadAt(buf, req.Offset)
   111  	if err == io.ErrUnexpectedEOF || err == io.EOF {
   112  		err = nil
   113  	}
   114  	resp.Data = buf[:n]
   115  	sf.reader = nil
   116  
   117  	return err
   118  }
   119  
   120  func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
   121  	log.Debug("swarmfs Write", "path", sf.path, "req.String", req.String())
   122  	if sf.fileSize == 0 && req.Offset == 0 {
   123  		// A new file is created
   124  		err := addFileToSwarm(sf, req.Data, len(req.Data))
   125  		if err != nil {
   126  			return err
   127  		}
   128  		resp.Size = len(req.Data)
   129  	} else if req.Offset <= sf.fileSize {
   130  		totalSize := sf.fileSize + int64(len(req.Data))
   131  		if totalSize > MaxAppendFileSize {
   132  			log.Warn("swarmfs Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data))
   133  			return errFileSizeMaxLimixReached
   134  		}
   135  
   136  		err := appendToExistingFileInSwarm(sf, req.Data, req.Offset, int64(len(req.Data)))
   137  		if err != nil {
   138  			return err
   139  		}
   140  		resp.Size = len(req.Data)
   141  	} else {
   142  		log.Warn("swarmfs Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset)
   143  		return errInvalidOffset
   144  	}
   145  	return nil
   146  }