github.com/hanwen/go-fuse@v1.0.0/fuse/request.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fuse 6 7 import ( 8 "bytes" 9 "fmt" 10 "log" 11 "strings" 12 "time" 13 "unsafe" 14 ) 15 16 var sizeOfOutHeader = unsafe.Sizeof(OutHeader{}) 17 var zeroOutBuf [outputHeaderSize]byte 18 19 type request struct { 20 inputBuf []byte 21 22 // These split up inputBuf. 23 inHeader *InHeader // generic header 24 inData unsafe.Pointer // per op data 25 arg []byte // flat data. 26 27 filenames []string // filename arguments 28 29 // Output data. 30 status Status 31 flatData []byte 32 fdData *readResultFd 33 34 // In case of read, keep read result here so we can call 35 // Done() on it. 36 readResult ReadResult 37 38 // Start timestamp for timing info. 39 startTime time.Time 40 41 // All information pertaining to opcode of this request. 42 handler *operationHandler 43 44 // Request storage. For large inputs and outputs, use data 45 // obtained through bufferpool. 46 bufferPoolInputBuf []byte 47 bufferPoolOutputBuf []byte 48 49 // For small pieces of data, we use the following inlines 50 // arrays: 51 // 52 // Output header and structured data. 53 outBuf [outputHeaderSize]byte 54 55 // Input, if small enough to fit here. 56 smallInputBuf [128]byte 57 58 context Context 59 } 60 61 func (r *request) clear() { 62 r.inputBuf = nil 63 r.inHeader = nil 64 r.inData = nil 65 r.arg = nil 66 r.filenames = nil 67 r.status = OK 68 r.flatData = nil 69 r.fdData = nil 70 r.startTime = time.Time{} 71 r.handler = nil 72 r.readResult = nil 73 } 74 75 func (r *request) InputDebug() string { 76 val := "" 77 if r.handler.DecodeIn != nil { 78 val = fmt.Sprintf("%v ", Print(r.handler.DecodeIn(r.inData))) 79 } 80 81 names := "" 82 if r.filenames != nil { 83 names = fmt.Sprintf("%q", r.filenames) 84 } 85 86 if len(r.arg) > 0 { 87 names += fmt.Sprintf(" %db", len(r.arg)) 88 } 89 90 return fmt.Sprintf("rx %d: %s i%d %s%s", 91 r.inHeader.Unique, operationName(r.inHeader.Opcode), r.inHeader.NodeId, 92 val, names) 93 } 94 95 func (r *request) OutputDebug() string { 96 var dataStr string 97 if r.handler.DecodeOut != nil && r.handler.OutputSize > 0 { 98 dataStr = Print(r.handler.DecodeOut(r.outData())) 99 } 100 101 max := 1024 102 if len(dataStr) > max { 103 dataStr = dataStr[:max] + fmt.Sprintf(" ...trimmed") 104 } 105 106 flatStr := "" 107 if r.flatDataSize() > 0 { 108 if r.handler.FileNameOut { 109 s := strings.TrimRight(string(r.flatData), "\x00") 110 flatStr = fmt.Sprintf(" %q", s) 111 } else { 112 spl := "" 113 if r.fdData != nil { 114 spl = " (fd data)" 115 } else { 116 l := len(r.flatData) 117 s := "" 118 if l > 8 { 119 l = 8 120 s = "..." 121 } 122 spl = fmt.Sprintf(" %q%s", r.flatData[:l], s) 123 } 124 flatStr = fmt.Sprintf(" %db data%s", r.flatDataSize(), spl) 125 } 126 } 127 128 extraStr := dataStr + flatStr 129 if extraStr != "" { 130 extraStr = ", " + extraStr 131 } 132 return fmt.Sprintf("tx %d: %v%s", 133 r.inHeader.Unique, r.status, extraStr) 134 } 135 136 // setInput returns true if it takes ownership of the argument, false if not. 137 func (r *request) setInput(input []byte) bool { 138 if len(input) < len(r.smallInputBuf) { 139 copy(r.smallInputBuf[:], input) 140 r.inputBuf = r.smallInputBuf[:len(input)] 141 return false 142 } 143 r.inputBuf = input 144 r.bufferPoolInputBuf = input[:cap(input)] 145 146 return true 147 } 148 149 func (r *request) parse() { 150 inHSize := int(unsafe.Sizeof(InHeader{})) 151 if len(r.inputBuf) < inHSize { 152 log.Printf("Short read for input header: %v", r.inputBuf) 153 return 154 } 155 156 r.inHeader = (*InHeader)(unsafe.Pointer(&r.inputBuf[0])) 157 r.arg = r.inputBuf[:] 158 159 r.handler = getHandler(r.inHeader.Opcode) 160 if r.handler == nil { 161 log.Printf("Unknown opcode %d", r.inHeader.Opcode) 162 r.status = ENOSYS 163 return 164 } 165 166 if len(r.arg) < int(r.handler.InputSize) { 167 log.Printf("Short read for %v: %v", operationName(r.inHeader.Opcode), r.arg) 168 r.status = EIO 169 return 170 } 171 172 if r.handler.InputSize > 0 { 173 r.inData = unsafe.Pointer(&r.arg[0]) 174 r.arg = r.arg[r.handler.InputSize:] 175 } else { 176 r.arg = r.arg[inHSize:] 177 } 178 179 count := r.handler.FileNames 180 if count > 0 { 181 if count == 1 && r.inHeader.Opcode == _OP_SETXATTR { 182 // SETXATTR is special: the only opcode with a file name AND a 183 // binary argument. 184 splits := bytes.SplitN(r.arg, []byte{0}, 2) 185 r.filenames = []string{string(splits[0])} 186 } else if count == 1 { 187 r.filenames = []string{string(r.arg[:len(r.arg)-1])} 188 } else { 189 names := bytes.SplitN(r.arg[:len(r.arg)-1], []byte{0}, count) 190 r.filenames = make([]string, len(names)) 191 for i, n := range names { 192 r.filenames[i] = string(n) 193 } 194 if len(names) != count { 195 log.Println("filename argument mismatch", names, count) 196 r.status = EIO 197 } 198 } 199 } 200 201 copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader], 202 zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader]) 203 } 204 205 func (r *request) outData() unsafe.Pointer { 206 return unsafe.Pointer(&r.outBuf[sizeOfOutHeader]) 207 } 208 209 // serializeHeader serializes the response header. The header points 210 // to an internal buffer of the receiver. 211 func (r *request) serializeHeader(flatDataSize int) (header []byte) { 212 dataLength := r.handler.OutputSize 213 if r.status > OK { 214 dataLength = 0 215 } 216 217 // [GET|LIST]XATTR is two opcodes in one: get/list xattr size (return 218 // structured GetXAttrOut, no flat data) and get/list xattr data 219 // (return no structured data, but only flat data) 220 if r.inHeader.Opcode == _OP_GETXATTR || r.inHeader.Opcode == _OP_LISTXATTR { 221 if (*GetXAttrIn)(r.inData).Size != 0 { 222 dataLength = 0 223 } 224 } 225 226 header = r.outBuf[:sizeOfOutHeader+dataLength] 227 o := (*OutHeader)(unsafe.Pointer(&header[0])) 228 o.Unique = r.inHeader.Unique 229 o.Status = int32(-r.status) 230 o.Length = uint32( 231 int(sizeOfOutHeader) + int(dataLength) + flatDataSize) 232 return header 233 } 234 235 func (r *request) flatDataSize() int { 236 if r.fdData != nil { 237 return r.fdData.Size() 238 } 239 return len(r.flatData) 240 }