github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/swarm/fuse/fuse_file.go (about)

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