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 }