dep ensure

This commit is contained in:
Barak Michener 2018-03-30 11:41:24 -07:00
parent 1158ac4760
commit c8c18403e4
371 changed files with 168673 additions and 1 deletions

25
vendor/github.com/gorilla/websocket/.gitignore generated vendored Normal file
View file

@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
.idea/
*.iml

19
vendor/github.com/gorilla/websocket/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,19 @@
language: go
sudo: false
matrix:
include:
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: 1.8
- go: tip
allow_failures:
- go: tip
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

8
vendor/github.com/gorilla/websocket/AUTHORS generated vendored Normal file
View file

@ -0,0 +1,8 @@
# This is the official list of Gorilla WebSocket authors for copyright
# purposes.
#
# Please keep the list sorted.
Gary Burd <gary@beagledreams.com>
Joachim Bauch <mail@joachim-bauch.de>

22
vendor/github.com/gorilla/websocket/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

64
vendor/github.com/gorilla/websocket/README.md generated vendored Normal file
View file

@ -0,0 +1,64 @@
# Gorilla WebSocket
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket)
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
### Documentation
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
### Status
The Gorilla WebSocket package provides a complete and tested implementation of
the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The
package API is stable.
### Installation
go get github.com/gorilla/websocket
### Protocol Compliance
The Gorilla WebSocket package passes the server tests in the [Autobahn Test
Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
### Gorilla WebSocket compared with other packages
<table>
<tr>
<th></th>
<th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th>
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
</tr>
<tr>
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
<tr><td>Passes <a href="http://autobahn.ws/testsuite/">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
<tr><td colspan="3">Other Features</tr></td>
<tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr>
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
</table>
Notes:
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
2. The application can get the type of a received data message by implementing
a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
function.
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
Read returns when the input buffer is full or a frame boundary is
encountered. Each call to Write sends a single frame message. The Gorilla
io.Reader and io.WriteCloser operate on a single WebSocket message.

392
vendor/github.com/gorilla/websocket/client.go generated vendored Normal file
View file

@ -0,0 +1,392 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"bytes"
"crypto/tls"
"encoding/base64"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
"time"
)
// ErrBadHandshake is returned when the server response to opening handshake is
// invalid.
var ErrBadHandshake = errors.New("websocket: bad handshake")
var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
// NewClient creates a new client connection using the given net connection.
// The URL u specifies the host and request URI. Use requestHeader to specify
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
// (Cookie). Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
// etc.
//
// Deprecated: Use Dialer instead.
func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
d := Dialer{
ReadBufferSize: readBufSize,
WriteBufferSize: writeBufSize,
NetDial: func(net, addr string) (net.Conn, error) {
return netConn, nil
},
}
return d.Dial(u.String(), requestHeader)
}
// A Dialer contains options for connecting to WebSocket server.
type Dialer struct {
// NetDial specifies the dial function for creating TCP connections. If
// NetDial is nil, net.Dial is used.
NetDial func(network, addr string) (net.Conn, error)
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
// request is aborted with the provided error.
// If Proxy is nil or returns a nil *URL, no proxy is used.
Proxy func(*http.Request) (*url.URL, error)
// TLSClientConfig specifies the TLS configuration to use with tls.Client.
// If nil, the default configuration is used.
TLSClientConfig *tls.Config
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
// size is zero, then a useful default size is used. The I/O buffer sizes
// do not limit the size of the messages that can be sent or received.
ReadBufferSize, WriteBufferSize int
// Subprotocols specifies the client's requested subprotocols.
Subprotocols []string
// EnableCompression specifies if the client should attempt to negotiate
// per message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
// Jar specifies the cookie jar.
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar http.CookieJar
}
var errMalformedURL = errors.New("malformed ws or wss URL")
// parseURL parses the URL.
//
// This function is a replacement for the standard library url.Parse function.
// In Go 1.4 and earlier, url.Parse loses information from the path.
func parseURL(s string) (*url.URL, error) {
// From the RFC:
//
// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
var u url.URL
switch {
case strings.HasPrefix(s, "ws://"):
u.Scheme = "ws"
s = s[len("ws://"):]
case strings.HasPrefix(s, "wss://"):
u.Scheme = "wss"
s = s[len("wss://"):]
default:
return nil, errMalformedURL
}
if i := strings.Index(s, "?"); i >= 0 {
u.RawQuery = s[i+1:]
s = s[:i]
}
if i := strings.Index(s, "/"); i >= 0 {
u.Opaque = s[i:]
s = s[:i]
} else {
u.Opaque = "/"
}
u.Host = s
if strings.Contains(u.Host, "@") {
// Don't bother parsing user information because user information is
// not allowed in websocket URIs.
return nil, errMalformedURL
}
return &u, nil
}
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
hostPort = u.Host
hostNoPort = u.Host
if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
hostNoPort = hostNoPort[:i]
} else {
switch u.Scheme {
case "wss":
hostPort += ":443"
case "https":
hostPort += ":443"
default:
hostPort += ":80"
}
}
return hostPort, hostNoPort
}
// DefaultDialer is a dialer with all fields set to the default zero values.
var DefaultDialer = &Dialer{
Proxy: http.ProxyFromEnvironment,
}
// Dial creates a new client connection. Use requestHeader to specify the
// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
// Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
// etcetera. The response body may not contain the entire response and does not
// need to be closed by the application.
func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
if d == nil {
d = &Dialer{
Proxy: http.ProxyFromEnvironment,
}
}
challengeKey, err := generateChallengeKey()
if err != nil {
return nil, nil, err
}
u, err := parseURL(urlStr)
if err != nil {
return nil, nil, err
}
switch u.Scheme {
case "ws":
u.Scheme = "http"
case "wss":
u.Scheme = "https"
default:
return nil, nil, errMalformedURL
}
if u.User != nil {
// User name and password are not allowed in websocket URIs.
return nil, nil, errMalformedURL
}
req := &http.Request{
Method: "GET",
URL: u,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(http.Header),
Host: u.Host,
}
// Set the cookies present in the cookie jar of the dialer
if d.Jar != nil {
for _, cookie := range d.Jar.Cookies(u) {
req.AddCookie(cookie)
}
}
// Set the request headers using the capitalization for names and values in
// RFC examples. Although the capitalization shouldn't matter, there are
// servers that depend on it. The Header.Set method is not used because the
// method canonicalizes the header names.
req.Header["Upgrade"] = []string{"websocket"}
req.Header["Connection"] = []string{"Upgrade"}
req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
req.Header["Sec-WebSocket-Version"] = []string{"13"}
if len(d.Subprotocols) > 0 {
req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
}
for k, vs := range requestHeader {
switch {
case k == "Host":
if len(vs) > 0 {
req.Host = vs[0]
}
case k == "Upgrade" ||
k == "Connection" ||
k == "Sec-Websocket-Key" ||
k == "Sec-Websocket-Version" ||
k == "Sec-Websocket-Extensions" ||
(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
default:
req.Header[k] = vs
}
}
if d.EnableCompression {
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
}
hostPort, hostNoPort := hostPortNoPort(u)
var proxyURL *url.URL
// Check wether the proxy method has been configured
if d.Proxy != nil {
proxyURL, err = d.Proxy(req)
}
if err != nil {
return nil, nil, err
}
var targetHostPort string
if proxyURL != nil {
targetHostPort, _ = hostPortNoPort(proxyURL)
} else {
targetHostPort = hostPort
}
var deadline time.Time
if d.HandshakeTimeout != 0 {
deadline = time.Now().Add(d.HandshakeTimeout)
}
netDial := d.NetDial
if netDial == nil {
netDialer := &net.Dialer{Deadline: deadline}
netDial = netDialer.Dial
}
netConn, err := netDial("tcp", targetHostPort)
if err != nil {
return nil, nil, err
}
defer func() {
if netConn != nil {
netConn.Close()
}
}()
if err := netConn.SetDeadline(deadline); err != nil {
return nil, nil, err
}
if proxyURL != nil {
connectHeader := make(http.Header)
if user := proxyURL.User; user != nil {
proxyUser := user.Username()
if proxyPassword, passwordSet := user.Password(); passwordSet {
credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
connectHeader.Set("Proxy-Authorization", "Basic "+credential)
}
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: hostPort},
Host: hostPort,
Header: connectHeader,
}
connectReq.Write(netConn)
// Read response.
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(netConn)
resp, err := http.ReadResponse(br, connectReq)
if err != nil {
return nil, nil, err
}
if resp.StatusCode != 200 {
f := strings.SplitN(resp.Status, " ", 2)
return nil, nil, errors.New(f[1])
}
}
if u.Scheme == "https" {
cfg := cloneTLSConfig(d.TLSClientConfig)
if cfg.ServerName == "" {
cfg.ServerName = hostNoPort
}
tlsConn := tls.Client(netConn, cfg)
netConn = tlsConn
if err := tlsConn.Handshake(); err != nil {
return nil, nil, err
}
if !cfg.InsecureSkipVerify {
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
return nil, nil, err
}
}
}
conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize)
if err := req.Write(netConn); err != nil {
return nil, nil, err
}
resp, err := http.ReadResponse(conn.br, req)
if err != nil {
return nil, nil, err
}
if d.Jar != nil {
if rc := resp.Cookies(); len(rc) > 0 {
d.Jar.SetCookies(u, rc)
}
}
if resp.StatusCode != 101 ||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
// Before closing the network connection on return from this
// function, slurp up some of the response to aid application
// debugging.
buf := make([]byte, 1024)
n, _ := io.ReadFull(resp.Body, buf)
resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
return nil, resp, ErrBadHandshake
}
for _, ext := range parseExtensions(resp.Header) {
if ext[""] != "permessage-deflate" {
continue
}
_, snct := ext["server_no_context_takeover"]
_, cnct := ext["client_no_context_takeover"]
if !snct || !cnct {
return nil, resp, errInvalidCompression
}
conn.newCompressionWriter = compressNoContextTakeover
conn.newDecompressionReader = decompressNoContextTakeover
break
}
resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
netConn.SetDeadline(time.Time{})
netConn = nil // to avoid close in defer.
return conn, resp, nil
}

16
vendor/github.com/gorilla/websocket/client_clone.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.8
package websocket
import "crypto/tls"
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
return cfg.Clone()
}

View file

@ -0,0 +1,38 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8
package websocket
import "crypto/tls"
// cloneTLSConfig clones all public fields except the fields
// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
// config in active use.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
return &tls.Config{
Rand: cfg.Rand,
Time: cfg.Time,
Certificates: cfg.Certificates,
NameToCertificate: cfg.NameToCertificate,
GetCertificate: cfg.GetCertificate,
RootCAs: cfg.RootCAs,
NextProtos: cfg.NextProtos,
ServerName: cfg.ServerName,
ClientAuth: cfg.ClientAuth,
ClientCAs: cfg.ClientCAs,
InsecureSkipVerify: cfg.InsecureSkipVerify,
CipherSuites: cfg.CipherSuites,
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
ClientSessionCache: cfg.ClientSessionCache,
MinVersion: cfg.MinVersion,
MaxVersion: cfg.MaxVersion,
CurvePreferences: cfg.CurvePreferences,
}
}

148
vendor/github.com/gorilla/websocket/compression.go generated vendored Normal file
View file

@ -0,0 +1,148 @@
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"compress/flate"
"errors"
"io"
"strings"
"sync"
)
const (
minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
maxCompressionLevel = flate.BestCompression
defaultCompressionLevel = 1
)
var (
flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
flateReaderPool = sync.Pool{New: func() interface{} {
return flate.NewReader(nil)
}}
)
func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
const tail =
// Add four bytes as specified in RFC
"\x00\x00\xff\xff" +
// Add final block to squelch unexpected EOF error from flate reader.
"\x01\x00\x00\xff\xff"
fr, _ := flateReaderPool.Get().(io.ReadCloser)
fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
return &flateReadWrapper{fr}
}
func isValidCompressionLevel(level int) bool {
return minCompressionLevel <= level && level <= maxCompressionLevel
}
func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
p := &flateWriterPools[level-minCompressionLevel]
tw := &truncWriter{w: w}
fw, _ := p.Get().(*flate.Writer)
if fw == nil {
fw, _ = flate.NewWriter(tw, level)
} else {
fw.Reset(tw)
}
return &flateWriteWrapper{fw: fw, tw: tw, p: p}
}
// truncWriter is an io.Writer that writes all but the last four bytes of the
// stream to another io.Writer.
type truncWriter struct {
w io.WriteCloser
n int
p [4]byte
}
func (w *truncWriter) Write(p []byte) (int, error) {
n := 0
// fill buffer first for simplicity.
if w.n < len(w.p) {
n = copy(w.p[w.n:], p)
p = p[n:]
w.n += n
if len(p) == 0 {
return n, nil
}
}
m := len(p)
if m > len(w.p) {
m = len(w.p)
}
if nn, err := w.w.Write(w.p[:m]); err != nil {
return n + nn, err
}
copy(w.p[:], w.p[m:])
copy(w.p[len(w.p)-m:], p[len(p)-m:])
nn, err := w.w.Write(p[:len(p)-m])
return n + nn, err
}
type flateWriteWrapper struct {
fw *flate.Writer
tw *truncWriter
p *sync.Pool
}
func (w *flateWriteWrapper) Write(p []byte) (int, error) {
if w.fw == nil {
return 0, errWriteClosed
}
return w.fw.Write(p)
}
func (w *flateWriteWrapper) Close() error {
if w.fw == nil {
return errWriteClosed
}
err1 := w.fw.Flush()
w.p.Put(w.fw)
w.fw = nil
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
}
err2 := w.tw.w.Close()
if err1 != nil {
return err1
}
return err2
}
type flateReadWrapper struct {
fr io.ReadCloser
}
func (r *flateReadWrapper) Read(p []byte) (int, error) {
if r.fr == nil {
return 0, io.ErrClosedPipe
}
n, err := r.fr.Read(p)
if err == io.EOF {
// Preemptively place the reader back in the pool. This helps with
// scenarios where the application does not call NextReader() soon after
// this final read.
r.Close()
}
return n, err
}
func (r *flateReadWrapper) Close() error {
if r.fr == nil {
return io.ErrClosedPipe
}
err := r.fr.Close()
flateReaderPool.Put(r.fr)
r.fr = nil
return err
}

1149
vendor/github.com/gorilla/websocket/conn.go generated vendored Normal file

File diff suppressed because it is too large Load diff

18
vendor/github.com/gorilla/websocket/conn_read.go generated vendored Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.5
package websocket
import "io"
func (c *Conn) read(n int) ([]byte, error) {
p, err := c.br.Peek(n)
if err == io.EOF {
err = errUnexpectedEOF
}
c.br.Discard(len(p))
return p, err
}

View file

@ -0,0 +1,21 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.5
package websocket
import "io"
func (c *Conn) read(n int) ([]byte, error) {
p, err := c.br.Peek(n)
if err == io.EOF {
err = errUnexpectedEOF
}
if len(p) > 0 {
// advance over the bytes just read
io.ReadFull(c.br, p)
}
return p, err
}

180
vendor/github.com/gorilla/websocket/doc.go generated vendored Normal file
View file

@ -0,0 +1,180 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package websocket implements the WebSocket protocol defined in RFC 6455.
//
// Overview
//
// The Conn type represents a WebSocket connection. A server application uses
// the Upgrade function from an Upgrader object with a HTTP request handler
// to get a pointer to a Conn:
//
// var upgrader = websocket.Upgrader{
// ReadBufferSize: 1024,
// WriteBufferSize: 1024,
// }
//
// func handler(w http.ResponseWriter, r *http.Request) {
// conn, err := upgrader.Upgrade(w, r, nil)
// if err != nil {
// log.Println(err)
// return
// }
// ... Use conn to send and receive messages.
// }
//
// Call the connection's WriteMessage and ReadMessage methods to send and
// receive messages as a slice of bytes. This snippet of code shows how to echo
// messages using these methods:
//
// for {
// messageType, p, err := conn.ReadMessage()
// if err != nil {
// return
// }
// if err = conn.WriteMessage(messageType, p); err != nil {
// return err
// }
// }
//
// In above snippet of code, p is a []byte and messageType is an int with value
// websocket.BinaryMessage or websocket.TextMessage.
//
// An application can also send and receive messages using the io.WriteCloser
// and io.Reader interfaces. To send a message, call the connection NextWriter
// method to get an io.WriteCloser, write the message to the writer and close
// the writer when done. To receive a message, call the connection NextReader
// method to get an io.Reader and read until io.EOF is returned. This snippet
// shows how to echo messages using the NextWriter and NextReader methods:
//
// for {
// messageType, r, err := conn.NextReader()
// if err != nil {
// return
// }
// w, err := conn.NextWriter(messageType)
// if err != nil {
// return err
// }
// if _, err := io.Copy(w, r); err != nil {
// return err
// }
// if err := w.Close(); err != nil {
// return err
// }
// }
//
// Data Messages
//
// The WebSocket protocol distinguishes between text and binary data messages.
// Text messages are interpreted as UTF-8 encoded text. The interpretation of
// binary messages is left to the application.
//
// This package uses the TextMessage and BinaryMessage integer constants to
// identify the two data message types. The ReadMessage and NextReader methods
// return the type of the received message. The messageType argument to the
// WriteMessage and NextWriter methods specifies the type of a sent message.
//
// It is the application's responsibility to ensure that text messages are
// valid UTF-8 encoded text.
//
// Control Messages
//
// The WebSocket protocol defines three types of control messages: close, ping
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
// methods to send a control message to the peer.
//
// Connections handle received close messages by sending a close message to the
// peer and returning a *CloseError from the the NextReader, ReadMessage or the
// message Read method.
//
// Connections handle received ping and pong messages by invoking callback
// functions set with SetPingHandler and SetPongHandler methods. The callback
// functions are called from the NextReader, ReadMessage and the message Read
// methods.
//
// The default ping handler sends a pong to the peer. The application's reading
// goroutine can block for a short time while the handler writes the pong data
// to the connection.
//
// The application must read the connection to process ping, pong and close
// messages sent from the peer. If the application is not otherwise interested
// in messages from the peer, then the application should start a goroutine to
// read and discard messages from the peer. A simple example is:
//
// func readLoop(c *websocket.Conn) {
// for {
// if _, _, err := c.NextReader(); err != nil {
// c.Close()
// break
// }
// }
// }
//
// Concurrency
//
// Connections support one concurrent reader and one concurrent writer.
//
// Applications are responsible for ensuring that no more than one goroutine
// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
// that no more than one goroutine calls the read methods (NextReader,
// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
// concurrently.
//
// The Close and WriteControl methods can be called concurrently with all other
// methods.
//
// Origin Considerations
//
// Web browsers allow Javascript applications to open a WebSocket connection to
// any host. It's up to the server to enforce an origin policy using the Origin
// request header sent by the browser.
//
// The Upgrader calls the function specified in the CheckOrigin field to check
// the origin. If the CheckOrigin function returns false, then the Upgrade
// method fails the WebSocket handshake with HTTP status 403.
//
// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
// the handshake if the Origin request header is present and not equal to the
// Host request header.
//
// An application can allow connections from any origin by specifying a
// function that always returns true:
//
// var upgrader = websocket.Upgrader{
// CheckOrigin: func(r *http.Request) bool { return true },
// }
//
// The deprecated Upgrade function does not enforce an origin policy. It's the
// application's responsibility to check the Origin header before calling
// Upgrade.
//
// Compression EXPERIMENTAL
//
// Per message compression extensions (RFC 7692) are experimentally supported
// by this package in a limited capacity. Setting the EnableCompression option
// to true in Dialer or Upgrader will attempt to negotiate per message deflate
// support.
//
// var upgrader = websocket.Upgrader{
// EnableCompression: true,
// }
//
// If compression was successfully negotiated with the connection's peer, any
// message received in compressed form will be automatically decompressed.
// All Read methods will return uncompressed bytes.
//
// Per message compression of messages written to a connection can be enabled
// or disabled by calling the corresponding Conn method:
//
// conn.EnableWriteCompression(false)
//
// Currently this package does not support compression with "context takeover".
// This means that messages must be compressed and decompressed in isolation,
// without retaining sliding window or dictionary state across messages. For
// more details refer to RFC 7692.
//
// Use of compression is experimental and may result in decreased performance.
package websocket

55
vendor/github.com/gorilla/websocket/json.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"encoding/json"
"io"
)
// WriteJSON is deprecated, use c.WriteJSON instead.
func WriteJSON(c *Conn, v interface{}) error {
return c.WriteJSON(v)
}
// WriteJSON writes the JSON encoding of v to the connection.
//
// See the documentation for encoding/json Marshal for details about the
// conversion of Go values to JSON.
func (c *Conn) WriteJSON(v interface{}) error {
w, err := c.NextWriter(TextMessage)
if err != nil {
return err
}
err1 := json.NewEncoder(w).Encode(v)
err2 := w.Close()
if err1 != nil {
return err1
}
return err2
}
// ReadJSON is deprecated, use c.ReadJSON instead.
func ReadJSON(c *Conn, v interface{}) error {
return c.ReadJSON(v)
}
// ReadJSON reads the next JSON-encoded message from the connection and stores
// it in the value pointed to by v.
//
// See the documentation for the encoding/json Unmarshal function for details
// about the conversion of JSON to a Go value.
func (c *Conn) ReadJSON(v interface{}) error {
_, r, err := c.NextReader()
if err != nil {
return err
}
err = json.NewDecoder(r).Decode(v)
if err == io.EOF {
// One value is expected in the message.
err = io.ErrUnexpectedEOF
}
return err
}

55
vendor/github.com/gorilla/websocket/mask.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
// +build !appengine
package websocket
import "unsafe"
const wordSize = int(unsafe.Sizeof(uintptr(0)))
func maskBytes(key [4]byte, pos int, b []byte) int {
// Mask one byte at a time for small buffers.
if len(b) < 2*wordSize {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
// Mask one byte at a time to word boundary.
if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
n = wordSize - n
for i := range b[:n] {
b[i] ^= key[pos&3]
pos++
}
b = b[n:]
}
// Create aligned word size key.
var k [wordSize]byte
for i := range k {
k[i] = key[(pos+i)&3]
}
kw := *(*uintptr)(unsafe.Pointer(&k))
// Mask one word at a time.
n := (len(b) / wordSize) * wordSize
for i := 0; i < n; i += wordSize {
*(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
}
// Mask one byte at a time for remaining bytes.
b = b[n:]
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}

15
vendor/github.com/gorilla/websocket/mask_safe.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
// +build appengine
package websocket
func maskBytes(key [4]byte, pos int, b []byte) int {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}

103
vendor/github.com/gorilla/websocket/prepared.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bytes"
"net"
"sync"
"time"
)
// PreparedMessage caches on the wire representations of a message payload.
// Use PreparedMessage to efficiently send a message payload to multiple
// connections. PreparedMessage is especially useful when compression is used
// because the CPU and memory expensive compression operation can be executed
// once for a given set of compression options.
type PreparedMessage struct {
messageType int
data []byte
err error
mu sync.Mutex
frames map[prepareKey]*preparedFrame
}
// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
type prepareKey struct {
isServer bool
compress bool
compressionLevel int
}
// preparedFrame contains data in wire representation.
type preparedFrame struct {
once sync.Once
data []byte
}
// NewPreparedMessage returns an initialized PreparedMessage. You can then send
// it to connection using WritePreparedMessage method. Valid wire
// representation will be calculated lazily only once for a set of current
// connection options.
func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
pm := &PreparedMessage{
messageType: messageType,
frames: make(map[prepareKey]*preparedFrame),
data: data,
}
// Prepare a plain server frame.
_, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
if err != nil {
return nil, err
}
// To protect against caller modifying the data argument, remember the data
// copied to the plain server frame.
pm.data = frameData[len(frameData)-len(data):]
return pm, nil
}
func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
pm.mu.Lock()
frame, ok := pm.frames[key]
if !ok {
frame = &preparedFrame{}
pm.frames[key] = frame
}
pm.mu.Unlock()
var err error
frame.once.Do(func() {
// Prepare a frame using a 'fake' connection.
// TODO: Refactor code in conn.go to allow more direct construction of
// the frame.
mu := make(chan bool, 1)
mu <- true
var nc prepareConn
c := &Conn{
conn: &nc,
mu: mu,
isServer: key.isServer,
compressionLevel: key.compressionLevel,
enableWriteCompression: true,
writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
}
if key.compress {
c.newCompressionWriter = compressNoContextTakeover
}
err = c.WriteMessage(pm.messageType, pm.data)
frame.data = nc.buf.Bytes()
})
return pm.messageType, frame.data, err
}
type prepareConn struct {
buf bytes.Buffer
net.Conn
}
func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }

291
vendor/github.com/gorilla/websocket/server.go generated vendored Normal file
View file

@ -0,0 +1,291 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"errors"
"net"
"net/http"
"net/url"
"strings"
"time"
)
// HandshakeError describes an error with the handshake from the peer.
type HandshakeError struct {
message string
}
func (e HandshakeError) Error() string { return e.message }
// Upgrader specifies parameters for upgrading an HTTP connection to a
// WebSocket connection.
type Upgrader struct {
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
// size is zero, then buffers allocated by the HTTP server are used. The
// I/O buffer sizes do not limit the size of the messages that can be sent
// or received.
ReadBufferSize, WriteBufferSize int
// Subprotocols specifies the server's supported protocols in order of
// preference. If this field is set, then the Upgrade method negotiates a
// subprotocol by selecting the first match in this list with a protocol
// requested by the client.
Subprotocols []string
// Error specifies the function for generating HTTP error responses. If Error
// is nil, then http.Error is used to generate the HTTP response.
Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
// CheckOrigin returns true if the request Origin header is acceptable. If
// CheckOrigin is nil, the host in the Origin header must not be set or
// must match the host of the request.
CheckOrigin func(r *http.Request) bool
// EnableCompression specify if the server should attempt to negotiate per
// message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
}
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
err := HandshakeError{reason}
if u.Error != nil {
u.Error(w, r, status, err)
} else {
w.Header().Set("Sec-Websocket-Version", "13")
http.Error(w, http.StatusText(status), status)
}
return nil, err
}
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
func checkSameOrigin(r *http.Request) bool {
origin := r.Header["Origin"]
if len(origin) == 0 {
return true
}
u, err := url.Parse(origin[0])
if err != nil {
return false
}
return u.Host == r.Host
}
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
if u.Subprotocols != nil {
clientProtocols := Subprotocols(r)
for _, serverProtocol := range u.Subprotocols {
for _, clientProtocol := range clientProtocols {
if clientProtocol == serverProtocol {
return clientProtocol
}
}
}
} else if responseHeader != nil {
return responseHeader.Get("Sec-Websocket-Protocol")
}
return ""
}
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// application negotiated subprotocol (Sec-Websocket-Protocol).
//
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
// response.
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
if r.Method != "GET" {
return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET")
}
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
}
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header")
}
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header")
}
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
}
checkOrigin := u.CheckOrigin
if checkOrigin == nil {
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
}
challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank")
}
subprotocol := u.selectSubprotocol(r, responseHeader)
// Negotiate PMCE
var compress bool
if u.EnableCompression {
for _, ext := range parseExtensions(r.Header) {
if ext[""] != "permessage-deflate" {
continue
}
compress = true
break
}
}
var (
netConn net.Conn
err error
)
h, ok := w.(http.Hijacker)
if !ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
}
var brw *bufio.ReadWriter
netConn, brw, err = h.Hijack()
if err != nil {
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
}
if brw.Reader.Buffered() > 0 {
netConn.Close()
return nil, errors.New("websocket: client sent data before handshake is complete")
}
c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw)
c.subprotocol = subprotocol
if compress {
c.newCompressionWriter = compressNoContextTakeover
c.newDecompressionReader = decompressNoContextTakeover
}
p := c.writeBuf[:0]
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
p = append(p, computeAcceptKey(challengeKey)...)
p = append(p, "\r\n"...)
if c.subprotocol != "" {
p = append(p, "Sec-Websocket-Protocol: "...)
p = append(p, c.subprotocol...)
p = append(p, "\r\n"...)
}
if compress {
p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
}
for k, vs := range responseHeader {
if k == "Sec-Websocket-Protocol" {
continue
}
for _, v := range vs {
p = append(p, k...)
p = append(p, ": "...)
for i := 0; i < len(v); i++ {
b := v[i]
if b <= 31 {
// prevent response splitting.
b = ' '
}
p = append(p, b)
}
p = append(p, "\r\n"...)
}
}
p = append(p, "\r\n"...)
// Clear deadlines set by HTTP server.
netConn.SetDeadline(time.Time{})
if u.HandshakeTimeout > 0 {
netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
}
if _, err = netConn.Write(p); err != nil {
netConn.Close()
return nil, err
}
if u.HandshakeTimeout > 0 {
netConn.SetWriteDeadline(time.Time{})
}
return c, nil
}
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// This function is deprecated, use websocket.Upgrader instead.
//
// The application is responsible for checking the request origin before
// calling Upgrade. An example implementation of the same origin policy is:
//
// if req.Header.Get("Origin") != "http://"+req.Host {
// http.Error(w, "Origin not allowed", 403)
// return
// }
//
// If the endpoint supports subprotocols, then the application is responsible
// for negotiating the protocol used on the connection. Use the Subprotocols()
// function to get the subprotocols requested by the client. Use the
// Sec-Websocket-Protocol response header to specify the subprotocol selected
// by the application.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// negotiated subprotocol (Sec-Websocket-Protocol).
//
// The connection buffers IO to the underlying network connection. The
// readBufSize and writeBufSize parameters specify the size of the buffers to
// use. Messages can be larger than the buffers.
//
// If the request is not a valid WebSocket handshake, then Upgrade returns an
// error of type HandshakeError. Applications should handle this error by
// replying to the client with an HTTP error response.
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
// don't return errors to maintain backwards compatibility
}
u.CheckOrigin = func(r *http.Request) bool {
// allow all connections by default
return true
}
return u.Upgrade(w, r, responseHeader)
}
// Subprotocols returns the subprotocols requested by the client in the
// Sec-Websocket-Protocol header.
func Subprotocols(r *http.Request) []string {
h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
if h == "" {
return nil
}
protocols := strings.Split(h, ",")
for i := range protocols {
protocols[i] = strings.TrimSpace(protocols[i])
}
return protocols
}
// IsWebSocketUpgrade returns true if the client requested upgrade to the
// WebSocket protocol.
func IsWebSocketUpgrade(r *http.Request) bool {
return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
tokenListContainsValue(r.Header, "Upgrade", "websocket")
}

214
vendor/github.com/gorilla/websocket/util.go generated vendored Normal file
View file

@ -0,0 +1,214 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"io"
"net/http"
"strings"
)
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string {
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func generateChallengeKey() (string, error) {
p := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, p); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(p), nil
}
// Octet types from RFC 2616.
var octetTypes [256]byte
const (
isTokenOctet = 1 << iota
isSpaceOctet
)
func init() {
// From RFC 2616
//
// OCTET = <any 8-bit sequence of data>
// CHAR = <any US-ASCII character (octets 0 - 127)>
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
// CR = <US-ASCII CR, carriage return (13)>
// LF = <US-ASCII LF, linefeed (10)>
// SP = <US-ASCII SP, space (32)>
// HT = <US-ASCII HT, horizontal-tab (9)>
// <"> = <US-ASCII double-quote mark (34)>
// CRLF = CR LF
// LWS = [CRLF] 1*( SP | HT )
// TEXT = <any OCTET except CTLs, but including LWS>
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
// token = 1*<any CHAR except CTLs or separators>
// qdtext = <any TEXT except <">>
for c := 0; c < 256; c++ {
var t byte
isCtl := c <= 31 || c == 127
isChar := 0 <= c && c <= 127
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
t |= isSpaceOctet
}
if isChar && !isCtl && !isSeparator {
t |= isTokenOctet
}
octetTypes[c] = t
}
}
func skipSpace(s string) (rest string) {
i := 0
for ; i < len(s); i++ {
if octetTypes[s[i]]&isSpaceOctet == 0 {
break
}
}
return s[i:]
}
func nextToken(s string) (token, rest string) {
i := 0
for ; i < len(s); i++ {
if octetTypes[s[i]]&isTokenOctet == 0 {
break
}
}
return s[:i], s[i:]
}
func nextTokenOrQuoted(s string) (value string, rest string) {
if !strings.HasPrefix(s, "\"") {
return nextToken(s)
}
s = s[1:]
for i := 0; i < len(s); i++ {
switch s[i] {
case '"':
return s[:i], s[i+1:]
case '\\':
p := make([]byte, len(s)-1)
j := copy(p, s[:i])
escape := true
for i = i + 1; i < len(s); i++ {
b := s[i]
switch {
case escape:
escape = false
p[j] = b
j += 1
case b == '\\':
escape = true
case b == '"':
return string(p[:j]), s[i+1:]
default:
p[j] = b
j += 1
}
}
return "", ""
}
}
return "", ""
}
// tokenListContainsValue returns true if the 1#token header with the given
// name contains token.
func tokenListContainsValue(header http.Header, name string, value string) bool {
headers:
for _, s := range header[name] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
s = skipSpace(s)
if s != "" && s[0] != ',' {
continue headers
}
if strings.EqualFold(t, value) {
return true
}
if s == "" {
continue headers
}
s = s[1:]
}
}
return false
}
// parseExtensiosn parses WebSocket extensions from a header.
func parseExtensions(header http.Header) []map[string]string {
// From RFC 6455:
//
// Sec-WebSocket-Extensions = extension-list
// extension-list = 1#extension
// extension = extension-token *( ";" extension-param )
// extension-token = registered-token
// registered-token = token
// extension-param = token [ "=" (token | quoted-string) ]
// ;When using the quoted-string syntax variant, the value
// ;after quoted-string unescaping MUST conform to the
// ;'token' ABNF.
var result []map[string]string
headers:
for _, s := range header["Sec-Websocket-Extensions"] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
ext := map[string]string{"": t}
for {
s = skipSpace(s)
if !strings.HasPrefix(s, ";") {
break
}
var k string
k, s = nextToken(skipSpace(s[1:]))
if k == "" {
continue headers
}
s = skipSpace(s)
var v string
if strings.HasPrefix(s, "=") {
v, s = nextTokenOrQuoted(skipSpace(s[1:]))
s = skipSpace(s)
}
if s != "" && s[0] != ',' && s[0] != ';' {
continue headers
}
ext[k] = v
}
if s != "" && s[0] != ',' {
continue headers
}
result = append(result, ext)
if s == "" {
continue headers
}
s = s[1:]
}
}
return result
}

15
vendor/github.com/hanwen/go-fuse/AUTHORS generated vendored Normal file
View file

@ -0,0 +1,15 @@
Adam H. Leventhal <adam.leventhal@gmail.com>
Daniel Martí <mvdan@mvdan.cc>
Fazlul Shahriar <fshahriar@gmail.com>
Frederick Akalin <akalin@gmail.com>
Google Inc.
Haitao Li <lihaitao@gmail.com>
Jakob Unterwurzacher <jakobunt@gmail.com>
James D. Nurmi <james@abneptis.com>
Jeff <leterip@me.com>
Logan Hanks <logan@bitcasa.com>
Nick Cooper <gh@smoogle.org>
Patrick Crosby <pcrosby@gmail.com>
Paul Jolly <paul@myitcv.org.uk>
Valient Gough <vgough@pobox.com>
Yongwoo Park <nnnlife@gmail.com>

30
vendor/github.com/hanwen/go-fuse/LICENSE generated vendored Normal file
View file

@ -0,0 +1,30 @@
// New BSD License
//
// Copyright (c) 2010 the Go-FUSE Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Ivan Krasin nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

1
vendor/github.com/hanwen/go-fuse/fuse/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
version.gen.go

148
vendor/github.com/hanwen/go-fuse/fuse/api.go generated vendored Normal file
View file

@ -0,0 +1,148 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The fuse package provides APIs to implement filesystems in
// userspace. Typically, each call of the API happens in its own
// goroutine, so take care to make the file system thread-safe.
package fuse
// Types for users to implement.
// The result of Read is an array of bytes, but for performance
// reasons, we can also return data as a file-descriptor/offset/size
// tuple. If the backing store for a file is another filesystem, this
// reduces the amount of copying between the kernel and the FUSE
// server. The ReadResult interface captures both cases.
type ReadResult interface {
// Returns the raw bytes for the read, possibly using the
// passed buffer. The buffer should be larger than the return
// value from Size.
Bytes(buf []byte) ([]byte, Status)
// Size returns how many bytes this return value takes at most.
Size() int
// Done() is called after sending the data to the kernel.
Done()
}
type MountOptions struct {
AllowOther bool
// Options are passed as -o string to fusermount.
Options []string
// Default is _DEFAULT_BACKGROUND_TASKS, 12. This numbers
// controls the allowed number of requests that relate to
// async I/O. Concurrency for synchronous I/O is not limited.
MaxBackground int
// Write size to use. If 0, use default. This number is
// capped at the kernel maximum.
MaxWrite int
// Max read ahead to use. If 0, use default. This number is
// capped at the kernel maximum.
MaxReadAhead int
// If IgnoreSecurityLabels is set, all security related xattr
// requests will return NO_DATA without passing through the
// user defined filesystem. You should only set this if you
// file system implements extended attributes, and you are not
// interested in security labels.
IgnoreSecurityLabels bool // ignoring labels should be provided as a fusermount mount option.
// If given, use this buffer pool instead of the global one.
Buffers BufferPool
// If RememberInodes is set, we will never forget inodes.
// This may be useful for NFS.
RememberInodes bool
// Values shown in "df -T" and friends
// First column, "Filesystem"
FsName string
// Second column, "Type", will be shown as "fuse." + Name
Name string
// If set, wrap the file system in a single-threaded locking wrapper.
SingleThreaded bool
// If set, return ENOSYS for Getxattr calls, so the kernel does not issue any
// Xattr operations at all.
DisableXAttrs bool
// If set, print debugging information.
Debug bool
}
// RawFileSystem is an interface close to the FUSE wire protocol.
//
// Unless you really know what you are doing, you should not implement
// this, but rather the FileSystem interface; the details of getting
// interactions with open files, renames, and threading right etc. are
// somewhat tricky and not very interesting.
//
// A null implementation is provided by NewDefaultRawFileSystem.
type RawFileSystem interface {
String() string
// If called, provide debug output through the log package.
SetDebug(debug bool)
Lookup(header *InHeader, name string, out *EntryOut) (status Status)
Forget(nodeid, nlookup uint64)
// Attributes.
GetAttr(input *GetAttrIn, out *AttrOut) (code Status)
SetAttr(input *SetAttrIn, out *AttrOut) (code Status)
// Modifying structure.
Mknod(input *MknodIn, name string, out *EntryOut) (code Status)
Mkdir(input *MkdirIn, name string, out *EntryOut) (code Status)
Unlink(header *InHeader, name string) (code Status)
Rmdir(header *InHeader, name string) (code Status)
Rename(input *RenameIn, oldName string, newName string) (code Status)
Link(input *LinkIn, filename string, out *EntryOut) (code Status)
Symlink(header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status)
Readlink(header *InHeader) (out []byte, code Status)
Access(input *AccessIn) (code Status)
// Extended attributes.
GetXAttrSize(header *InHeader, attr string) (sz int, code Status)
GetXAttrData(header *InHeader, attr string) (data []byte, code Status)
ListXAttr(header *InHeader) (attributes []byte, code Status)
SetXAttr(input *SetXAttrIn, attr string, data []byte) Status
RemoveXAttr(header *InHeader, attr string) (code Status)
// File handling.
Create(input *CreateIn, name string, out *CreateOut) (code Status)
Open(input *OpenIn, out *OpenOut) (status Status)
Read(input *ReadIn, buf []byte) (ReadResult, Status)
Flock(input *FlockIn, flags int) (code Status)
Release(input *ReleaseIn)
Write(input *WriteIn, data []byte) (written uint32, code Status)
Flush(input *FlushIn) Status
Fsync(input *FsyncIn) (code Status)
Fallocate(input *FallocateIn) (code Status)
// Directory handling
OpenDir(input *OpenIn, out *OpenOut) (status Status)
ReadDir(input *ReadIn, out *DirEntryList) Status
ReadDirPlus(input *ReadIn, out *DirEntryList) Status
ReleaseDir(input *ReleaseIn)
FsyncDir(input *FsyncIn) (code Status)
//
StatFs(input *InHeader, out *StatfsOut) (code Status)
// This is called on processing the first request. The
// filesystem implementation can use the server argument to
// talk back to the kernel (through notify methods).
Init(*Server)
}

79
vendor/github.com/hanwen/go-fuse/fuse/attr.go generated vendored Normal file
View file

@ -0,0 +1,79 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"os"
"syscall"
"time"
)
func (a *Attr) IsFifo() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFIFO }
// IsChar reports whether the FileInfo describes a character special file.
func (a *Attr) IsChar() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFCHR }
// IsDir reports whether the FileInfo describes a directory.
func (a *Attr) IsDir() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFDIR }
// IsBlock reports whether the FileInfo describes a block special file.
func (a *Attr) IsBlock() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFBLK }
// IsRegular reports whether the FileInfo describes a regular file.
func (a *Attr) IsRegular() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFREG }
// IsSymlink reports whether the FileInfo describes a symbolic link.
func (a *Attr) IsSymlink() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFLNK }
// IsSocket reports whether the FileInfo describes a socket.
func (a *Attr) IsSocket() bool { return (uint32(a.Mode) & syscall.S_IFMT) == syscall.S_IFSOCK }
func (a *Attr) SetTimes(access *time.Time, mod *time.Time, chstatus *time.Time) {
if access != nil {
a.Atime = uint64(access.Unix())
a.Atimensec = uint32(access.Nanosecond())
}
if mod != nil {
a.Mtime = uint64(mod.Unix())
a.Mtimensec = uint32(mod.Nanosecond())
}
if chstatus != nil {
a.Ctime = uint64(chstatus.Unix())
a.Ctimensec = uint32(chstatus.Nanosecond())
}
}
func (a *Attr) ChangeTime() time.Time {
return time.Unix(int64(a.Ctime), int64(a.Ctimensec))
}
func (a *Attr) AccessTime() time.Time {
return time.Unix(int64(a.Atime), int64(a.Atimensec))
}
func (a *Attr) ModTime() time.Time {
return time.Unix(int64(a.Mtime), int64(a.Mtimensec))
}
func ToStatT(f os.FileInfo) *syscall.Stat_t {
s, _ := f.Sys().(*syscall.Stat_t)
if s != nil {
return s
}
return nil
}
func ToAttr(f os.FileInfo) *Attr {
if f == nil {
return nil
}
s := ToStatT(f)
if s != nil {
a := &Attr{}
a.FromStat(s)
return a
}
return nil
}

26
vendor/github.com/hanwen/go-fuse/fuse/attr_darwin.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
func (a *Attr) FromStat(s *syscall.Stat_t) {
a.Ino = uint64(s.Ino)
a.Size = uint64(s.Size)
a.Blocks = uint64(s.Blocks)
a.Atime = uint64(s.Atimespec.Sec)
a.Atimensec = uint32(s.Atimespec.Nsec)
a.Mtime = uint64(s.Mtimespec.Sec)
a.Mtimensec = uint32(s.Mtimespec.Nsec)
a.Ctime = uint64(s.Ctimespec.Sec)
a.Ctimensec = uint32(s.Ctimespec.Nsec)
a.Mode = uint32(s.Mode)
a.Nlink = uint32(s.Nlink)
a.Uid = uint32(s.Uid)
a.Gid = uint32(s.Gid)
a.Rdev = uint32(s.Rdev)
}

27
vendor/github.com/hanwen/go-fuse/fuse/attr_linux.go generated vendored Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
func (a *Attr) FromStat(s *syscall.Stat_t) {
a.Ino = uint64(s.Ino)
a.Size = uint64(s.Size)
a.Blocks = uint64(s.Blocks)
a.Atime = uint64(s.Atim.Sec)
a.Atimensec = uint32(s.Atim.Nsec)
a.Mtime = uint64(s.Mtim.Sec)
a.Mtimensec = uint32(s.Mtim.Nsec)
a.Ctime = uint64(s.Ctim.Sec)
a.Ctimensec = uint32(s.Ctim.Nsec)
a.Mode = s.Mode
a.Nlink = uint32(s.Nlink)
a.Uid = uint32(s.Uid)
a.Gid = uint32(s.Gid)
a.Rdev = uint32(s.Rdev)
a.Blksize = uint32(s.Blksize)
}

102
vendor/github.com/hanwen/go-fuse/fuse/bufferpool.go generated vendored Normal file
View file

@ -0,0 +1,102 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"os"
"sync"
)
var paranoia bool
// BufferPool implements explicit memory management. It is used for
// minimizing the GC overhead of communicating with the kernel.
type BufferPool interface {
// AllocBuffer creates a buffer of at least the given size. After use,
// it should be deallocated with FreeBuffer().
AllocBuffer(size uint32) []byte
// FreeBuffer takes back a buffer if it was allocated through
// AllocBuffer. It is not an error to call FreeBuffer() on a slice
// obtained elsewhere.
FreeBuffer(slice []byte)
}
type gcBufferPool struct {
}
// NewGcBufferPool is a fallback to the standard allocation routines.
func NewGcBufferPool() BufferPool {
return &gcBufferPool{}
}
func (p *gcBufferPool) AllocBuffer(size uint32) []byte {
return make([]byte, size)
}
func (p *gcBufferPool) FreeBuffer(slice []byte) {
}
type bufferPoolImpl struct {
lock sync.Mutex
// For each page size multiple a list of slice pointers.
buffersBySize []*sync.Pool
}
// NewBufferPool returns a BufferPool implementation that that returns
// slices with capacity of a multiple of page size, which have possibly
// been used, and may contain random contents. When using
// NewBufferPool, file system handlers may not hang on to passed-in
// buffers beyond the handler's return.
func NewBufferPool() BufferPool {
bp := new(bufferPoolImpl)
return bp
}
var pageSize = os.Getpagesize()
func (p *bufferPoolImpl) getPool(pageCount int) *sync.Pool {
p.lock.Lock()
for len(p.buffersBySize) < pageCount+1 {
p.buffersBySize = append(p.buffersBySize, nil)
}
if p.buffersBySize[pageCount] == nil {
p.buffersBySize[pageCount] = &sync.Pool{
New: func() interface{} { return make([]byte, pageSize*pageCount) },
}
}
pool := p.buffersBySize[pageCount]
p.lock.Unlock()
return pool
}
func (p *bufferPoolImpl) AllocBuffer(size uint32) []byte {
sz := int(size)
if sz < pageSize {
sz = pageSize
}
if sz%pageSize != 0 {
sz += pageSize
}
pages := sz / pageSize
b := p.getPool(pages).Get().([]byte)
return b[:size]
}
func (p *bufferPoolImpl) FreeBuffer(slice []byte) {
if slice == nil {
return
}
if cap(slice)%pageSize != 0 || cap(slice) == 0 {
return
}
pages := cap(slice) / pageSize
slice = slice[:cap(slice)]
p.getPool(pages).Put(slice)
}

35
vendor/github.com/hanwen/go-fuse/fuse/constants.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"os"
"syscall"
)
const (
FUSE_ROOT_ID = 1
FUSE_UNKNOWN_INO = 0xffffffff
CUSE_UNRESTRICTED_IOCTL = (1 << 0)
FUSE_LK_FLOCK = (1 << 0)
FUSE_IOCTL_MAX_IOV = 256
FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0)
CUSE_INIT_INFO_MAX = 4096
S_IFDIR = syscall.S_IFDIR
S_IFREG = syscall.S_IFREG
S_IFLNK = syscall.S_IFLNK
S_IFIFO = syscall.S_IFIFO
CUSE_INIT = 4096
O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC)
)

View file

@ -0,0 +1,9 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
// arbitrary values
const syscall_O_LARGEFILE = 1 << 29
const syscall_O_NOATIME = 1 << 30

View file

@ -0,0 +1,12 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
const syscall_O_LARGEFILE = syscall.O_LARGEFILE
const syscall_O_NOATIME = syscall.O_NOATIME

156
vendor/github.com/hanwen/go-fuse/fuse/defaultraw.go generated vendored Normal file
View file

@ -0,0 +1,156 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"os"
)
// NewDefaultRawFileSystem returns ENOSYS (not implemented) for all
// operations.
func NewDefaultRawFileSystem() RawFileSystem {
return (*defaultRawFileSystem)(nil)
}
type defaultRawFileSystem struct{}
func (fs *defaultRawFileSystem) Init(*Server) {
}
func (fs *defaultRawFileSystem) String() string {
return os.Args[0]
}
func (fs *defaultRawFileSystem) SetDebug(dbg bool) {
}
func (fs *defaultRawFileSystem) StatFs(header *InHeader, out *StatfsOut) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) Lookup(header *InHeader, name string, out *EntryOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Forget(nodeID, nlookup uint64) {
}
func (fs *defaultRawFileSystem) GetAttr(input *GetAttrIn, out *AttrOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Open(input *OpenIn, out *OpenOut) (status Status) {
return OK
}
func (fs *defaultRawFileSystem) SetAttr(input *SetAttrIn, out *AttrOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Readlink(header *InHeader) (out []byte, code Status) {
return nil, ENOSYS
}
func (fs *defaultRawFileSystem) Mknod(input *MknodIn, name string, out *EntryOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Mkdir(input *MkdirIn, name string, out *EntryOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Unlink(header *InHeader, name string) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Rmdir(header *InHeader, name string) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Symlink(header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Rename(input *RenameIn, oldName string, newName string) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Link(input *LinkIn, name string, out *EntryOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) GetXAttrSize(header *InHeader, attr string) (size int, code Status) {
return 0, ENOSYS
}
func (fs *defaultRawFileSystem) GetXAttrData(header *InHeader, attr string) (data []byte, code Status) {
return nil, ENOATTR
}
func (fs *defaultRawFileSystem) SetXAttr(input *SetXAttrIn, attr string, data []byte) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) ListXAttr(header *InHeader) (data []byte, code Status) {
return nil, ENOSYS
}
func (fs *defaultRawFileSystem) RemoveXAttr(header *InHeader, attr string) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) Access(input *AccessIn) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Create(input *CreateIn, name string, out *CreateOut) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) OpenDir(input *OpenIn, out *OpenOut) (status Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Status) {
return nil, ENOSYS
}
func (fs *defaultRawFileSystem) Flock(input *FlockIn, flags int) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) Release(input *ReleaseIn) {
}
func (fs *defaultRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
return 0, ENOSYS
}
func (fs *defaultRawFileSystem) Flush(input *FlushIn) Status {
return OK
}
func (fs *defaultRawFileSystem) Fsync(input *FsyncIn) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) ReadDir(input *ReadIn, l *DirEntryList) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) ReadDirPlus(input *ReadIn, l *DirEntryList) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) ReleaseDir(input *ReleaseIn) {
}
func (fs *defaultRawFileSystem) FsyncDir(input *FsyncIn) (code Status) {
return ENOSYS
}
func (fs *defaultRawFileSystem) Fallocate(in *FallocateIn) (code Status) {
return ENOSYS
}

102
vendor/github.com/hanwen/go-fuse/fuse/direntry.go generated vendored Normal file
View file

@ -0,0 +1,102 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
// all of the code for DirEntryList.
import (
"fmt"
"unsafe"
)
var eightPadding [8]byte
const direntSize = int(unsafe.Sizeof(_Dirent{}))
// DirEntry is a type for PathFileSystem and NodeFileSystem to return
// directory contents in.
type DirEntry struct {
// Mode is the file's mode. Only the high bits (eg. S_IFDIR)
// are considered.
Mode uint32
// Name is the basename of the file in the directory.
Name string
}
func (d DirEntry) String() string {
return fmt.Sprintf("%o: %q", d.Mode, d.Name)
}
// DirEntryList holds the return value for READDIR and READDIRPLUS
// opcodes.
type DirEntryList struct {
buf []byte
size int
offset uint64
}
// NewDirEntryList creates a DirEntryList with the given data buffer
// and offset.
func NewDirEntryList(data []byte, off uint64) *DirEntryList {
return &DirEntryList{
buf: data[:0],
size: len(data),
offset: off,
}
}
// AddDirEntry tries to add an entry, and reports whether it
// succeeded.
func (l *DirEntryList) AddDirEntry(e DirEntry) (bool, uint64) {
return l.Add(0, e.Name, uint64(FUSE_UNKNOWN_INO), e.Mode)
}
// Add adds a direntry to the DirEntryList, returning whether it
// succeeded.
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (bool, uint64) {
padding := (8 - len(name)&7) & 7
delta := padding + direntSize + len(name) + prefix
oldLen := len(l.buf)
newLen := delta + oldLen
if newLen > l.size {
return false, l.offset
}
l.buf = l.buf[:newLen]
oldLen += prefix
dirent := (*_Dirent)(unsafe.Pointer(&l.buf[oldLen]))
dirent.Off = l.offset + 1
dirent.Ino = inode
dirent.NameLen = uint32(len(name))
dirent.Typ = (mode & 0170000) >> 12
oldLen += direntSize
copy(l.buf[oldLen:], name)
oldLen += len(name)
if padding > 0 {
copy(l.buf[oldLen:], eightPadding[:padding])
}
l.offset = dirent.Off
return true, l.offset
}
// AddDirLookupEntry is used for ReadDirPlus. It serializes a DirEntry
// and returns the space for entry. If no space is left, returns a nil
// pointer.
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) (*EntryOut, uint64) {
lastStart := len(l.buf)
ok, off := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
uint64(FUSE_UNKNOWN_INO), e.Mode)
if !ok {
return nil, off
}
return (*EntryOut)(unsafe.Pointer(&l.buf[lastStart])), off
}
func (l *DirEntryList) bytes() []byte {
return l.buf
}

215
vendor/github.com/hanwen/go-fuse/fuse/lockingfs.go generated vendored Normal file
View file

@ -0,0 +1,215 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
"sync"
)
////////////////////////////////////////////////////////////////
// Locking raw FS.
type lockingRawFileSystem struct {
RawFS RawFileSystem
lock sync.Mutex
}
// Returns a Wrap
func NewLockingRawFileSystem(fs RawFileSystem) RawFileSystem {
return &lockingRawFileSystem{
RawFS: fs,
}
}
func (fs *lockingRawFileSystem) FS() RawFileSystem {
return fs.RawFS
}
func (fs *lockingRawFileSystem) locked() func() {
fs.lock.Lock()
return func() { fs.lock.Unlock() }
}
func (fs *lockingRawFileSystem) Lookup(header *InHeader, name string, out *EntryOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Lookup(header, name, out)
}
func (fs *lockingRawFileSystem) SetDebug(dbg bool) {
defer fs.locked()()
fs.RawFS.SetDebug(dbg)
}
func (fs *lockingRawFileSystem) Forget(nodeID uint64, nlookup uint64) {
defer fs.locked()()
fs.RawFS.Forget(nodeID, nlookup)
}
func (fs *lockingRawFileSystem) GetAttr(input *GetAttrIn, out *AttrOut) (code Status) {
defer fs.locked()()
return fs.RawFS.GetAttr(input, out)
}
func (fs *lockingRawFileSystem) Open(input *OpenIn, out *OpenOut) (status Status) {
defer fs.locked()()
return fs.RawFS.Open(input, out)
}
func (fs *lockingRawFileSystem) SetAttr(input *SetAttrIn, out *AttrOut) (code Status) {
defer fs.locked()()
return fs.RawFS.SetAttr(input, out)
}
func (fs *lockingRawFileSystem) Readlink(header *InHeader) (out []byte, code Status) {
defer fs.locked()()
return fs.RawFS.Readlink(header)
}
func (fs *lockingRawFileSystem) Mknod(input *MknodIn, name string, out *EntryOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Mknod(input, name, out)
}
func (fs *lockingRawFileSystem) Mkdir(input *MkdirIn, name string, out *EntryOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Mkdir(input, name, out)
}
func (fs *lockingRawFileSystem) Unlink(header *InHeader, name string) (code Status) {
defer fs.locked()()
return fs.RawFS.Unlink(header, name)
}
func (fs *lockingRawFileSystem) Rmdir(header *InHeader, name string) (code Status) {
defer fs.locked()()
return fs.RawFS.Rmdir(header, name)
}
func (fs *lockingRawFileSystem) Symlink(header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Symlink(header, pointedTo, linkName, out)
}
func (fs *lockingRawFileSystem) Rename(input *RenameIn, oldName string, newName string) (code Status) {
defer fs.locked()()
return fs.RawFS.Rename(input, oldName, newName)
}
func (fs *lockingRawFileSystem) Link(input *LinkIn, name string, out *EntryOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Link(input, name, out)
}
func (fs *lockingRawFileSystem) SetXAttr(input *SetXAttrIn, attr string, data []byte) Status {
defer fs.locked()()
return fs.RawFS.SetXAttr(input, attr, data)
}
func (fs *lockingRawFileSystem) GetXAttrData(header *InHeader, attr string) (data []byte, code Status) {
defer fs.locked()()
return fs.RawFS.GetXAttrData(header, attr)
}
func (fs *lockingRawFileSystem) GetXAttrSize(header *InHeader, attr string) (sz int, code Status) {
defer fs.locked()()
return fs.RawFS.GetXAttrSize(header, attr)
}
func (fs *lockingRawFileSystem) ListXAttr(header *InHeader) (data []byte, code Status) {
defer fs.locked()()
return fs.RawFS.ListXAttr(header)
}
func (fs *lockingRawFileSystem) RemoveXAttr(header *InHeader, attr string) Status {
defer fs.locked()()
return fs.RawFS.RemoveXAttr(header, attr)
}
func (fs *lockingRawFileSystem) Access(input *AccessIn) (code Status) {
defer fs.locked()()
return fs.RawFS.Access(input)
}
func (fs *lockingRawFileSystem) Create(input *CreateIn, name string, out *CreateOut) (code Status) {
defer fs.locked()()
return fs.RawFS.Create(input, name, out)
}
func (fs *lockingRawFileSystem) OpenDir(input *OpenIn, out *OpenOut) (status Status) {
defer fs.locked()()
return fs.RawFS.OpenDir(input, out)
}
func (fs *lockingRawFileSystem) Release(input *ReleaseIn) {
defer fs.locked()()
fs.RawFS.Release(input)
}
func (fs *lockingRawFileSystem) ReleaseDir(input *ReleaseIn) {
defer fs.locked()()
fs.RawFS.ReleaseDir(input)
}
func (fs *lockingRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Status) {
defer fs.locked()()
return fs.RawFS.Read(input, buf)
}
func (fs *lockingRawFileSystem) Flock(input *FlockIn, flags int) Status {
defer fs.locked()()
return fs.RawFS.Flock(input, flags)
}
func (fs *lockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
defer fs.locked()()
return fs.RawFS.Write(input, data)
}
func (fs *lockingRawFileSystem) Flush(input *FlushIn) Status {
defer fs.locked()()
return fs.RawFS.Flush(input)
}
func (fs *lockingRawFileSystem) Fsync(input *FsyncIn) (code Status) {
defer fs.locked()()
return fs.RawFS.Fsync(input)
}
func (fs *lockingRawFileSystem) ReadDir(input *ReadIn, out *DirEntryList) Status {
defer fs.locked()()
return fs.RawFS.ReadDir(input, out)
}
func (fs *lockingRawFileSystem) ReadDirPlus(input *ReadIn, out *DirEntryList) Status {
defer fs.locked()()
return fs.RawFS.ReadDirPlus(input, out)
}
func (fs *lockingRawFileSystem) FsyncDir(input *FsyncIn) (code Status) {
defer fs.locked()()
return fs.RawFS.FsyncDir(input)
}
func (fs *lockingRawFileSystem) Init(s *Server) {
defer fs.locked()()
fs.RawFS.Init(s)
}
func (fs *lockingRawFileSystem) StatFs(header *InHeader, out *StatfsOut) (code Status) {
defer fs.locked()()
return fs.RawFS.StatFs(header, out)
}
func (fs *lockingRawFileSystem) Fallocate(in *FallocateIn) (code Status) {
defer fs.locked()()
return fs.RawFS.Fallocate(in)
}
func (fs *lockingRawFileSystem) String() string {
defer fs.locked()()
return fmt.Sprintf("Locked(%s)", fs.RawFS.String())
}

100
vendor/github.com/hanwen/go-fuse/fuse/misc.go generated vendored Normal file
View file

@ -0,0 +1,100 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Random odds and ends.
package fuse
import (
"fmt"
"log"
"os"
"reflect"
"syscall"
"time"
"unsafe"
)
func (code Status) String() string {
if code <= 0 {
return []string{
"OK",
"NOTIFY_POLL",
"NOTIFY_INVAL_INODE",
"NOTIFY_INVAL_ENTRY",
"NOTIFY_INVAL_STORE",
"NOTIFY_INVAL_RETRIEVE",
"NOTIFY_INVAL_DELETE",
}[-code]
}
return fmt.Sprintf("%d=%v", int(code), syscall.Errno(code))
}
func (code Status) Ok() bool {
return code == OK
}
// ToStatus extracts an errno number from Go error objects. If it
// fails, it logs an error and returns ENOSYS.
func ToStatus(err error) Status {
switch err {
case nil:
return OK
case os.ErrPermission:
return EPERM
case os.ErrExist:
return Status(syscall.EEXIST)
case os.ErrNotExist:
return ENOENT
case os.ErrInvalid:
return EINVAL
}
switch t := err.(type) {
case syscall.Errno:
return Status(t)
case *os.SyscallError:
return Status(t.Err.(syscall.Errno))
case *os.PathError:
return ToStatus(t.Err)
case *os.LinkError:
return ToStatus(t.Err)
}
log.Println("can't convert error type:", err)
return ENOSYS
}
func toSlice(dest *[]byte, ptr unsafe.Pointer, byteCount uintptr) {
h := (*reflect.SliceHeader)(unsafe.Pointer(dest))
*h = reflect.SliceHeader{
Data: uintptr(ptr),
Len: int(byteCount),
Cap: int(byteCount),
}
}
func CurrentOwner() *Owner {
return &Owner{
Uid: uint32(os.Getuid()),
Gid: uint32(os.Getgid()),
}
}
const _UTIME_OMIT = ((1 << 30) - 2)
// UtimeToTimespec converts a "Time" pointer as passed to Utimens to a
// "Timespec" that can be passed to the utimensat syscall.
// A nil pointer is converted to the special UTIME_OMIT value.
func UtimeToTimespec(t *time.Time) (ts syscall.Timespec) {
if t == nil {
ts.Nsec = _UTIME_OMIT
} else {
ts = syscall.NsecToTimespec(t.UnixNano())
// Go bug https://github.com/golang/go/issues/12777
if ts.Nsec < 0 {
ts.Nsec = 0
}
}
return ts
}

82
vendor/github.com/hanwen/go-fuse/fuse/mount_darwin.go generated vendored Normal file
View file

@ -0,0 +1,82 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
)
func openFUSEDevice() (*os.File, error) {
fs, err := filepath.Glob("/dev/osxfuse*")
if err != nil {
return nil, err
}
if len(fs) == 0 {
// TODO(hanwen): run the load_osxfuse command.
return nil, fmt.Errorf("no FUSE devices found")
}
for _, fn := range fs {
f, err := os.OpenFile(fn, os.O_RDWR, 0)
if err != nil {
continue
}
return f, nil
}
return nil, fmt.Errorf("all FUSE devices busy")
}
const oldMountBin = "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
const newMountBin = "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"
func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, err error) {
f, err := openFUSEDevice()
if err != nil {
return 0, err
}
bin := oldMountBin
if _, err := os.Stat(newMountBin); err == nil {
bin = newMountBin
}
cmd := exec.Command(bin, "-o", strings.Join(opts.optionsStrings(), ","), "-o", fmt.Sprintf("iosize=%d", opts.MaxWrite), "3", mountPoint)
cmd.ExtraFiles = []*os.File{f}
cmd.Env = append(os.Environ(), "MOUNT_FUSEFS_CALL_BY_LIB=", "MOUNT_OSXFUSE_CALL_BY_LIB=",
"MOUNT_OSXFUSE_DAEMON_PATH="+os.Args[0],
"MOUNT_FUSEFS_DAEMON_PATH="+os.Args[0])
var out, errOut bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errOut
if err := cmd.Start(); err != nil {
f.Close()
return 0, err
}
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("mount_osxfusefs failed: %v. Stderr: %s, Stdout: %s", err, errOut.String(), out.String())
}
ready <- err
close(ready)
}()
// The finalizer for f will close its fd so we return a dup.
defer f.Close()
return syscall.Dup(int(f.Fd()))
}
func unmount(dir string) error {
return syscall.Unmount(dir, 0)
}

162
vendor/github.com/hanwen/go-fuse/fuse/mount_linux.go generated vendored Normal file
View file

@ -0,0 +1,162 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"bytes"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"syscall"
"unsafe"
)
func unixgramSocketpair() (l, r *os.File, err error) {
fd, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
if err != nil {
return nil, nil, os.NewSyscallError("socketpair",
err.(syscall.Errno))
}
l = os.NewFile(uintptr(fd[0]), "socketpair-half1")
r = os.NewFile(uintptr(fd[1]), "socketpair-half2")
return
}
// Create a FUSE FS on the specified mount point. The returned
// mount point is always absolute.
func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, err error) {
local, remote, err := unixgramSocketpair()
if err != nil {
return
}
defer local.Close()
defer remote.Close()
bin, err := fusermountBinary()
if err != nil {
return 0, err
}
cmd := []string{bin, mountPoint}
if s := opts.optionsStrings(); len(s) > 0 {
cmd = append(cmd, "-o", strings.Join(s, ","))
}
proc, err := os.StartProcess(bin,
cmd,
&os.ProcAttr{
Env: []string{"_FUSE_COMMFD=3"},
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr, remote}})
if err != nil {
return
}
w, err := proc.Wait()
if err != nil {
return
}
if !w.Success() {
err = fmt.Errorf("fusermount exited with code %v\n", w.Sys())
return
}
fd, err = getConnection(local)
if err != nil {
return -1, err
}
close(ready)
return fd, err
}
func privilegedUnmount(mountPoint string) error {
dir, _ := filepath.Split(mountPoint)
bin, err := umountBinary()
if err != nil {
return err
}
proc, err := os.StartProcess(bin,
[]string{bin, mountPoint},
&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
if err != nil {
return err
}
w, err := proc.Wait()
if !w.Success() {
return fmt.Errorf("umount exited with code %v\n", w.Sys())
}
return err
}
func unmount(mountPoint string) (err error) {
if os.Geteuid() == 0 {
return privilegedUnmount(mountPoint)
}
bin, err := fusermountBinary()
if err != nil {
return err
}
errBuf := bytes.Buffer{}
cmd := exec.Command(bin, "-u", mountPoint)
cmd.Stderr = &errBuf
err = cmd.Run()
if errBuf.Len() > 0 {
return fmt.Errorf("%s (code %v)\n",
errBuf.String(), err)
}
return err
}
func getConnection(local *os.File) (int, error) {
var data [4]byte
control := make([]byte, 4*256)
// n, oobn, recvflags, from, errno - todo: error checking.
_, oobn, _, _,
err := syscall.Recvmsg(
int(local.Fd()), data[:], control[:], 0)
if err != nil {
return 0, err
}
message := *(*syscall.Cmsghdr)(unsafe.Pointer(&control[0]))
fd := *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&control[0])) + syscall.SizeofCmsghdr))
if message.Type != 1 {
return 0, fmt.Errorf("getConnection: recvmsg returned wrong control type: %d", message.Type)
}
if oobn <= syscall.SizeofCmsghdr {
return 0, fmt.Errorf("getConnection: too short control message. Length: %d", oobn)
}
if fd < 0 {
return 0, fmt.Errorf("getConnection: fd < 0: %d", fd)
}
return int(fd), nil
}
// lookPathFallback - search binary in PATH and, if that fails,
// in fallbackDir. This is useful if PATH is possible empty.
func lookPathFallback(file string, fallbackDir string) (string, error) {
binPath, err := exec.LookPath(file)
if err == nil {
return binPath, nil
}
abs := path.Join(fallbackDir, file)
return exec.LookPath(abs)
}
func fusermountBinary() (string, error) {
return lookPathFallback("fusermount", "/bin")
}
func umountBinary() (string, error) {
return lookPathFallback("umount", "/bin")
}

190
vendor/github.com/hanwen/go-fuse/fuse/nodefs/api.go generated vendored Normal file
View file

@ -0,0 +1,190 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The nodefs package offers a high level API that resembles the
// kernel's idea of what an FS looks like. File systems can have
// multiple hard-links to one file, for example. It is also suited if
// the data to represent fits in memory: you can construct the
// complete file system tree at mount time
package nodefs
import (
"time"
"github.com/hanwen/go-fuse/fuse"
)
// The Node interface implements the user-defined file system
// functionality
type Node interface {
// Inode and SetInode are basic getter/setters. They are
// called by the FileSystemConnector. You get them for free by
// embedding the result of NewDefaultNode() in your node
// struct.
Inode() *Inode
SetInode(node *Inode)
// OnMount is called on the root node just after a mount is
// executed, either when the actual root is mounted, or when a
// filesystem is mounted in-process. The passed-in
// FileSystemConnector gives access to Notify methods and
// Debug settings.
OnMount(conn *FileSystemConnector)
// OnUnmount is executed just before a submount is removed,
// and when the process receives a forget for the FUSE root
// node.
OnUnmount()
// Lookup finds a child node to this node; it is only called
// for directory Nodes.
Lookup(out *fuse.Attr, name string, context *fuse.Context) (*Inode, fuse.Status)
// Deletable() should return true if this node may be discarded once
// the kernel forgets its reference.
// If it returns false, OnForget will never get called for this node. This
// is appropriate if the filesystem has no persistent backing store
// (in-memory filesystems) where discarding the node loses the stored data.
// Deletable will be called from within the treeLock critical section, so you
// cannot look at other nodes.
Deletable() bool
// OnForget is called when the kernel forgets its reference to this node and
// sends a FORGET request. It should perform cleanup and free memory as
// appropriate for the filesystem.
// OnForget is not called if the node is a directory and has children.
// This is called from within a treeLock critical section.
OnForget()
// Misc.
Access(mode uint32, context *fuse.Context) (code fuse.Status)
Readlink(c *fuse.Context) ([]byte, fuse.Status)
// Namespace operations; these are only called on directory Nodes.
// Mknod should create the node, add it to the receiver's
// inode, and return it
Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
// Mkdir should create the directory Inode, add it to the
// receiver's Inode, and return it
Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
Unlink(name string, context *fuse.Context) (code fuse.Status)
Rmdir(name string, context *fuse.Context) (code fuse.Status)
// Symlink should create a child inode to the receiver, and
// return it.
Symlink(name string, content string, context *fuse.Context) (*Inode, fuse.Status)
Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status)
// Link should return the Inode of the resulting link. In
// a POSIX conformant file system, this should add 'existing'
// to the receiver, and return the Inode corresponding to
// 'existing'.
Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status)
// Create should return an open file, and the Inode for that file.
Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status)
// Open opens a file, and returns a File which is associated
// with a file handle. It is OK to return (nil, OK) here. In
// that case, the Node should implement Read or Write
// directly.
Open(flags uint32, context *fuse.Context) (file File, code fuse.Status)
OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status)
Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status)
Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status)
// XAttrs
GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status)
RemoveXAttr(attr string, context *fuse.Context) fuse.Status
SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status
ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)
// Attributes
GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status)
Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status)
Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status)
StatFs() *fuse.StatfsOut
}
// A File object is returned from FileSystem.Open and
// FileSystem.Create. Include the NewDefaultFile return value into
// the struct to inherit a null implementation.
type File interface {
// Called upon registering the filehandle in the inode.
SetInode(*Inode)
// The String method is for debug printing.
String() string
// Wrappers around other File implementations, should return
// the inner file here.
InnerFile() File
Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
Write(data []byte, off int64) (written uint32, code fuse.Status)
Flock(flags int) fuse.Status
// Flush is called for close() call on a file descriptor. In
// case of duplicated descriptor, it may be called more than
// once for a file.
Flush() fuse.Status
// This is called to before the file handle is forgotten. This
// method has no return value, so nothing can synchronizes on
// the call. Any cleanup that requires specific synchronization or
// could fail with I/O errors should happen in Flush instead.
Release()
Fsync(flags int) (code fuse.Status)
// The methods below may be called on closed files, due to
// concurrency. In that case, you should return EBADF.
Truncate(size uint64) fuse.Status
GetAttr(out *fuse.Attr) fuse.Status
Chown(uid uint32, gid uint32) fuse.Status
Chmod(perms uint32) fuse.Status
Utimens(atime *time.Time, mtime *time.Time) fuse.Status
Allocate(off uint64, size uint64, mode uint32) (code fuse.Status)
}
// Wrap a File return in this to set FUSE flags. Also used internally
// to store open file data.
type WithFlags struct {
File
// For debugging.
Description string
// Put FOPEN_* flags here.
FuseFlags uint32
// O_RDWR, O_TRUNCATE, etc.
OpenFlags uint32
}
// Options contains time out options for a node FileSystem. The
// default copied from libfuse and set in NewMountOptions() is
// (1s,1s,0s).
type Options struct {
EntryTimeout time.Duration
AttrTimeout time.Duration
NegativeTimeout time.Duration
// If set, replace all uids with given UID.
// NewOptions() will set this to the daemon's
// uid/gid.
*fuse.Owner
// This option exists for compatibility and is ignored.
PortableInodes bool
// If set, print debug information.
Debug bool
}

View file

@ -0,0 +1,75 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"time"
"github.com/hanwen/go-fuse/fuse"
)
type defaultFile struct{}
// NewDefaultFile returns a File instance that returns ENOSYS for
// every operation.
func NewDefaultFile() File {
return (*defaultFile)(nil)
}
func (f *defaultFile) SetInode(*Inode) {
}
func (f *defaultFile) InnerFile() File {
return nil
}
func (f *defaultFile) String() string {
return "defaultFile"
}
func (f *defaultFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
return nil, fuse.ENOSYS
}
func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) {
return 0, fuse.ENOSYS
}
func (f *defaultFile) Flock(flags int) fuse.Status { return fuse.ENOSYS }
func (f *defaultFile) Flush() fuse.Status {
return fuse.OK
}
func (f *defaultFile) Release() {
}
func (f *defaultFile) GetAttr(*fuse.Attr) fuse.Status {
return fuse.ENOSYS
}
func (f *defaultFile) Fsync(flags int) (code fuse.Status) {
return fuse.ENOSYS
}
func (f *defaultFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status {
return fuse.ENOSYS
}
func (f *defaultFile) Truncate(size uint64) fuse.Status {
return fuse.ENOSYS
}
func (f *defaultFile) Chown(uid uint32, gid uint32) fuse.Status {
return fuse.ENOSYS
}
func (f *defaultFile) Chmod(perms uint32) fuse.Status {
return fuse.ENOSYS
}
func (f *defaultFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
return fuse.ENOSYS
}

View file

@ -0,0 +1,172 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"time"
"github.com/hanwen/go-fuse/fuse"
)
// NewDefaultNode returns an implementation of Node that returns
// ENOSYS for all operations.
func NewDefaultNode() Node {
return &defaultNode{}
}
type defaultNode struct {
inode *Inode
}
func (fs *defaultNode) OnUnmount() {
}
func (fs *defaultNode) OnMount(conn *FileSystemConnector) {
}
func (n *defaultNode) StatFs() *fuse.StatfsOut {
return nil
}
func (n *defaultNode) SetInode(node *Inode) {
n.inode = node
}
func (n *defaultNode) Deletable() bool {
return true
}
func (n *defaultNode) Inode() *Inode {
return n.inode
}
func (n *defaultNode) OnForget() {
}
func (n *defaultNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node *Inode, code fuse.Status) {
return nil, fuse.ENOENT
}
func (n *defaultNode) Access(mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Unlink(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Symlink(name string, content string, context *fuse.Context) (newNode *Inode, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, newNode *Inode, code fuse.Status) {
return nil, nil, fuse.ENOSYS
}
func (n *defaultNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) Flush(file File, openFlags uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
ch := n.Inode().Children()
s := make([]fuse.DirEntry, 0, len(ch))
for name, child := range ch {
if child.mountPoint != nil {
continue
}
var a fuse.Attr
code := child.Node().GetAttr(&a, nil, context)
if code.Ok() {
s = append(s, fuse.DirEntry{Name: name, Mode: a.Mode})
}
}
return s, fuse.OK
}
func (n *defaultNode) GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status) {
return nil, fuse.ENOATTR
}
func (n *defaultNode) RemoveXAttr(attr string, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (n *defaultNode) SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (n *defaultNode) ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (n *defaultNode) GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) {
if file != nil {
return file.GetAttr(out)
}
if n.Inode().IsDir() {
out.Mode = fuse.S_IFDIR | 0755
} else {
out.Mode = fuse.S_IFREG | 0644
}
return fuse.OK
}
func (n *defaultNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (n *defaultNode) Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
if file != nil {
return file.Read(dest, off)
}
return nil, fuse.ENOSYS
}
func (n *defaultNode) Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status) {
if file != nil {
return file.Write(data, off)
}
return 0, fuse.ENOSYS
}

118
vendor/github.com/hanwen/go-fuse/fuse/nodefs/dir.go generated vendored Normal file
View file

@ -0,0 +1,118 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"log"
"sync"
"github.com/hanwen/go-fuse/fuse"
)
type connectorDir struct {
node Node
rawFS fuse.RawFileSystem
// Protect stream and lastOffset. These are written in case
// there is a seek on the directory.
mu sync.Mutex
stream []fuse.DirEntry
// lastOffset stores the last offset for a readdir. This lets
// readdir pick up changes to the directory made after opening
// it.
lastOffset uint64
}
func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
// TODO - test this.
if d.lastOffset > 0 && input.Offset == 0 {
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
if !code.Ok() {
return code
}
}
if input.Offset > uint64(len(d.stream)) {
// This shouldn't happen, but let's not crash.
return fuse.EINVAL
}
todo := d.stream[input.Offset:]
for _, e := range todo {
if e.Name == "" {
log.Printf("got empty directory entry, mode %o.", e.Mode)
continue
}
ok, off := out.AddDirEntry(e)
d.lastOffset = off
if !ok {
break
}
}
return fuse.OK
}
func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
if d.lastOffset > 0 && input.Offset == 0 {
d.stream, code = d.node.OpenDir((*fuse.Context)(&input.Context))
if !code.Ok() {
return code
}
}
if input.Offset > uint64(len(d.stream)) {
// This shouldn't happen, but let's not crash.
return fuse.EINVAL
}
todo := d.stream[input.Offset:]
for _, e := range todo {
if e.Name == "" {
log.Printf("got empty directory entry, mode %o.", e.Mode)
continue
}
// we have to be sure entry will fit if we try to add
// it, or we'll mess up the lookup counts.
entryDest, off := out.AddDirLookupEntry(e)
if entryDest == nil {
break
}
entryDest.Ino = uint64(fuse.FUSE_UNKNOWN_INO)
// No need to fill attributes for . and ..
if e.Name == "." || e.Name == ".." {
continue
}
// Clear entryDest before use it, some fields can be corrupted if does not set all fields in rawFS.Lookup
*entryDest = fuse.EntryOut{}
d.rawFS.Lookup(&input.InHeader, e.Name, entryDest)
d.lastOffset = off
}
return fuse.OK
}
type rawDir interface {
ReadDir(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
ReadDirPlus(out *fuse.DirEntryList, input *fuse.ReadIn, c *fuse.Context) fuse.Status
}

261
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files.go generated vendored Normal file
View file

@ -0,0 +1,261 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"fmt"
"os"
"sync"
"syscall"
"github.com/hanwen/go-fuse/fuse"
)
// DataFile is for implementing read-only filesystems. This
// assumes we already have the data in memory.
type dataFile struct {
data []byte
File
}
func (f *dataFile) String() string {
l := len(f.data)
if l > 10 {
l = 10
}
return fmt.Sprintf("dataFile(%x)", f.data[:l])
}
func (f *dataFile) GetAttr(out *fuse.Attr) fuse.Status {
out.Mode = fuse.S_IFREG | 0644
out.Size = uint64(len(f.data))
return fuse.OK
}
func NewDataFile(data []byte) File {
f := new(dataFile)
f.data = data
f.File = NewDefaultFile()
return f
}
func (f *dataFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
end := int(off) + int(len(buf))
if end > len(f.data) {
end = len(f.data)
}
return fuse.ReadResultData(f.data[off:end]), fuse.OK
}
type devNullFile struct {
File
}
// NewDevNullFile returns a file that accepts any write, and always
// returns EOF for reads.
func NewDevNullFile() File {
return &devNullFile{
File: NewDefaultFile(),
}
}
func (f *devNullFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
return fuse.OK
}
func (f *devNullFile) String() string {
return "devNullFile"
}
func (f *devNullFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
return fuse.ReadResultData(nil), fuse.OK
}
func (f *devNullFile) Write(content []byte, off int64) (uint32, fuse.Status) {
return uint32(len(content)), fuse.OK
}
func (f *devNullFile) Flush() fuse.Status {
return fuse.OK
}
func (f *devNullFile) Fsync(flags int) (code fuse.Status) {
return fuse.OK
}
func (f *devNullFile) Truncate(size uint64) (code fuse.Status) {
return fuse.OK
}
////////////////
// LoopbackFile delegates all operations back to an underlying os.File.
func NewLoopbackFile(f *os.File) File {
return &loopbackFile{File: f}
}
type loopbackFile struct {
File *os.File
// os.File is not threadsafe. Although fd themselves are
// constant during the lifetime of an open file, the OS may
// reuse the fd number after it is closed. When open races
// with another close, they may lead to confusion as which
// file gets written in the end.
lock sync.Mutex
}
func (f *loopbackFile) InnerFile() File {
return nil
}
func (f *loopbackFile) SetInode(n *Inode) {
}
func (f *loopbackFile) String() string {
return fmt.Sprintf("loopbackFile(%s)", f.File.Name())
}
func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
f.lock.Lock()
// This is not racy by virtue of the kernel properly
// synchronizing the open/write/close.
r := fuse.ReadResultFd(f.File.Fd(), off, len(buf))
f.lock.Unlock()
return r, fuse.OK
}
func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) {
f.lock.Lock()
n, err := f.File.WriteAt(data, off)
f.lock.Unlock()
return uint32(n), fuse.ToStatus(err)
}
func (f *loopbackFile) Release() {
f.lock.Lock()
f.File.Close()
f.lock.Unlock()
}
func (f *loopbackFile) Flush() fuse.Status {
f.lock.Lock()
// Since Flush() may be called for each dup'd fd, we don't
// want to really close the file, we just want to flush. This
// is achieved by closing a dup'd fd.
newFd, err := syscall.Dup(int(f.File.Fd()))
f.lock.Unlock()
if err != nil {
return fuse.ToStatus(err)
}
err = syscall.Close(newFd)
return fuse.ToStatus(err)
}
func (f *loopbackFile) Fsync(flags int) (code fuse.Status) {
f.lock.Lock()
r := fuse.ToStatus(syscall.Fsync(int(f.File.Fd())))
f.lock.Unlock()
return r
}
func (f *loopbackFile) Flock(flags int) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(syscall.Flock(int(f.File.Fd()), flags))
f.lock.Unlock()
return r
}
func (f *loopbackFile) Truncate(size uint64) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size)))
f.lock.Unlock()
return r
}
func (f *loopbackFile) Chmod(mode uint32) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(f.File.Chmod(os.FileMode(mode)))
f.lock.Unlock()
return r
}
func (f *loopbackFile) Chown(uid uint32, gid uint32) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(f.File.Chown(int(uid), int(gid)))
f.lock.Unlock()
return r
}
func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status {
st := syscall.Stat_t{}
f.lock.Lock()
err := syscall.Fstat(int(f.File.Fd()), &st)
f.lock.Unlock()
if err != nil {
return fuse.ToStatus(err)
}
a.FromStat(&st)
return fuse.OK
}
// Utimens implemented in files_linux.go
// Allocate implemented in files_linux.go
////////////////////////////////////////////////////////////////
// NewReadOnlyFile wraps a File so all read/write operations are
// denied.
func NewReadOnlyFile(f File) File {
return &readOnlyFile{File: f}
}
type readOnlyFile struct {
File
}
func (f *readOnlyFile) InnerFile() File {
return f.File
}
func (f *readOnlyFile) String() string {
return fmt.Sprintf("readOnlyFile(%s)", f.File.String())
}
func (f *readOnlyFile) Write(data []byte, off int64) (uint32, fuse.Status) {
return 0, fuse.EPERM
}
func (f *readOnlyFile) Fsync(flag int) (code fuse.Status) {
return fuse.OK
}
func (f *readOnlyFile) Truncate(size uint64) fuse.Status {
return fuse.EPERM
}
func (f *readOnlyFile) Chmod(mode uint32) fuse.Status {
return fuse.EPERM
}
func (f *readOnlyFile) Chown(uid uint32, gid uint32) fuse.Status {
return fuse.EPERM
}
func (f *readOnlyFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
return fuse.EPERM
}

View file

@ -0,0 +1,102 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"syscall"
"time"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
// TODO: Handle `mode` parameter.
// From `man fcntl` on OSX:
// The F_PREALLOCATE command operates on the following structure:
//
// typedef struct fstore {
// u_int32_t fst_flags; /* IN: flags word */
// int fst_posmode; /* IN: indicates offset field */
// off_t fst_offset; /* IN: start of the region */
// off_t fst_length; /* IN: size of the region */
// off_t fst_bytesalloc; /* OUT: number of bytes allocated */
// } fstore_t;
//
// The flags (fst_flags) for the F_PREALLOCATE command are as follows:
//
// F_ALLOCATECONTIG Allocate contiguous space.
//
// F_ALLOCATEALL Allocate all requested space or no space at all.
//
// The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use the offset field. The modes are as fol-
// lows:
//
// F_PEOFPOSMODE Allocate from the physical end of file.
//
// F_VOLPOSMODE Allocate from the volume offset.
k := struct {
Flags uint32 // u_int32_t
Posmode int64 // int
Offset int64 // off_t
Length int64 // off_t
Bytesalloc int64 // off_t
}{
0,
0,
int64(off),
int64(sz),
0,
}
// Linux version for reference:
// err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
f.lock.Lock()
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.File.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(&k)))
f.lock.Unlock()
if errno != 0 {
return fuse.ToStatus(errno)
}
return fuse.OK
}
const _UTIME_OMIT = ((1 << 30) - 2)
// timeToTimeval - Convert time.Time to syscall.Timeval
//
// Note: This does not use syscall.NsecToTimespec because
// that does not work properly for times before 1970,
// see https://github.com/golang/go/issues/12777
func timeToTimeval(t *time.Time) syscall.Timeval {
var tv syscall.Timeval
tv.Usec = int32(t.Nanosecond() / 1000)
tv.Sec = t.Unix()
return tv
}
// OSX does not have the utimensat syscall neded to implement this properly.
// We do our best to emulate it using futimes.
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
tv := make([]syscall.Timeval, 2)
if a == nil {
tv[0].Usec = _UTIME_OMIT
} else {
tv[0] = timeToTimeval(a)
}
if m == nil {
tv[1].Usec = _UTIME_OMIT
} else {
tv[1] = timeToTimeval(m)
}
f.lock.Lock()
err := syscall.Futimes(int(f.File.Fd()), tv)
f.lock.Unlock()
return fuse.ToStatus(err)
}

View file

@ -0,0 +1,33 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
f.lock.Lock()
err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
f.lock.Unlock()
if err != nil {
return fuse.ToStatus(err)
}
return fuse.OK
}
// Utimens - file handle based version of loopbackFileSystem.Utimens()
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
var ts [2]syscall.Timespec
ts[0] = fuse.UtimeToTimespec(a)
ts[1] = fuse.UtimeToTimespec(m)
f.lock.Lock()
err := futimens(int(f.File.Fd()), &ts)
f.lock.Unlock()
return fuse.ToStatus(err)
}

View file

@ -0,0 +1,424 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
// This file contains the internal logic of the
// FileSystemConnector. The functions for satisfying the raw interface
// are in fsops.go
import (
"log"
"path/filepath"
"strings"
"time"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
// Tests should set to true.
var paranoia = false
// FilesystemConnector translates the raw FUSE protocol (serialized
// structs of uint32/uint64) to operations on Go objects representing
// files and directories.
type FileSystemConnector struct {
debug bool
// Callbacks for talking back to the kernel.
server *fuse.Server
// Translate between uint64 handles and *Inode.
inodeMap handleMap
// The root of the FUSE file system.
rootNode *Inode
}
// NewOptions generates FUSE options that correspond to libfuse's
// defaults.
func NewOptions() *Options {
return &Options{
NegativeTimeout: 0,
AttrTimeout: time.Second,
EntryTimeout: time.Second,
Owner: fuse.CurrentOwner(),
}
}
// NewFileSystemConnector creates a FileSystemConnector with the given
// options.
func NewFileSystemConnector(root Node, opts *Options) (c *FileSystemConnector) {
c = new(FileSystemConnector)
if opts == nil {
opts = NewOptions()
}
c.inodeMap = newPortableHandleMap()
c.rootNode = newInode(true, root)
c.verify()
c.mountRoot(opts)
// FUSE does not issue a LOOKUP for 1 (obviously), but it does
// issue a forget. This lookupUpdate is to make the counts match.
c.lookupUpdate(c.rootNode)
c.debug = opts.Debug
return c
}
// Server returns the fuse.Server that talking to the kernel.
func (c *FileSystemConnector) Server() *fuse.Server {
return c.server
}
// SetDebug toggles printing of debug information. This function is
// deprecated. Set the Debug option in the Options struct instead.
func (c *FileSystemConnector) SetDebug(debug bool) {
c.debug = debug
}
// This verifies invariants of the data structure. This routine
// acquires tree locks as it walks the inode tree.
func (c *FileSystemConnector) verify() {
if !paranoia {
return
}
root := c.rootNode
root.verify(c.rootNode.mountPoint)
}
// childLookup fills entry information for a newly created child inode
func (c *rawBridge) childLookup(out *fuse.EntryOut, n *Inode, context *fuse.Context) {
n.Node().GetAttr((*fuse.Attr)(&out.Attr), nil, context)
n.mount.fillEntry(out)
out.NodeId, out.Generation = c.fsConn().lookupUpdate(n)
if out.Ino == 0 {
out.Ino = out.NodeId
}
if out.Nlink == 0 {
// With Nlink == 0, newer kernels will refuse link
// operations.
out.Nlink = 1
}
}
func (c *rawBridge) toInode(nodeid uint64) *Inode {
if nodeid == fuse.FUSE_ROOT_ID {
return c.rootNode
}
i := (*Inode)(unsafe.Pointer(c.inodeMap.Decode(nodeid)))
return i
}
// Must run outside treeLock. Returns the nodeId and generation.
func (c *FileSystemConnector) lookupUpdate(node *Inode) (id, generation uint64) {
id, generation = c.inodeMap.Register(&node.handled)
c.verify()
return
}
// forgetUpdate decrements the reference counter for "nodeID" by "forgetCount".
// Must run outside treeLock.
func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) {
if nodeID == fuse.FUSE_ROOT_ID {
c.rootNode.Node().OnUnmount()
// We never got a lookup for root, so don't try to
// forget root.
return
}
// Prevent concurrent modification of the tree while we are processing
// the FORGET
node := (*Inode)(unsafe.Pointer(c.inodeMap.Decode(nodeID)))
node.mount.treeLock.Lock()
defer node.mount.treeLock.Unlock()
if forgotten, _ := c.inodeMap.Forget(nodeID, forgetCount); forgotten {
if len(node.children) > 0 || !node.Node().Deletable() ||
node == c.rootNode || node.mountPoint != nil {
// We cannot forget a directory that still has children as these
// would become unreachable.
return
}
// We have to remove ourself from all parents.
// Create a copy of node.parents so we can safely iterate over it
// while modifying the original.
parents := make(map[parentData]struct{}, len(node.parents))
for k, v := range node.parents {
parents[k] = v
}
for p := range parents {
// This also modifies node.parents
p.parent.rmChild(p.name)
}
node.fsInode.OnForget()
}
// TODO - try to drop children even forget was not successful.
c.verify()
}
// InodeCount returns the number of inodes registered with the kernel.
func (c *FileSystemConnector) InodeHandleCount() int {
return c.inodeMap.Count()
}
// Finds a node within the currently known inodes, returns the last
// known node and the remaining unknown path components. If parent is
// nil, start from FUSE mountpoint.
func (c *FileSystemConnector) Node(parent *Inode, fullPath string) (*Inode, []string) {
if parent == nil {
parent = c.rootNode
}
if fullPath == "" {
return parent, nil
}
sep := string(filepath.Separator)
fullPath = strings.TrimLeft(filepath.Clean(fullPath), sep)
comps := strings.Split(fullPath, sep)
node := parent
if node.mountPoint == nil {
node.mount.treeLock.RLock()
defer node.mount.treeLock.RUnlock()
}
for i, component := range comps {
if len(component) == 0 {
continue
}
if node.mountPoint != nil {
node.mount.treeLock.RLock()
defer node.mount.treeLock.RUnlock()
}
next := node.children[component]
if next == nil {
return node, comps[i:]
}
node = next
}
return node, nil
}
// Follows the path from the given parent, doing lookups as
// necessary. The path should be '/' separated without leading slash.
func (c *FileSystemConnector) LookupNode(parent *Inode, path string) *Inode {
if path == "" {
return parent
}
components := strings.Split(path, "/")
for _, r := range components {
var a fuse.Attr
// This will not affect inode ID lookup counts, which
// are only update in response to kernel requests.
var dummy fuse.InHeader
child, _ := c.internalLookup(&a, parent, r, &dummy)
if child == nil {
return nil
}
parent = child
}
return parent
}
func (c *FileSystemConnector) mountRoot(opts *Options) {
c.rootNode.mountFs(opts)
c.rootNode.mount.connector = c
c.verify()
}
// Mount() generates a synthetic directory node, and mounts the file
// system there. If opts is nil, the mount options of the root file
// system are inherited. The encompassing filesystem should pretend
// the mount point does not exist.
//
// It returns ENOENT if the directory containing the mount point does
// not exist, and EBUSY if the intended mount point already exists.
func (c *FileSystemConnector) Mount(parent *Inode, name string, root Node, opts *Options) fuse.Status {
node, code := c.lockMount(parent, name, root, opts)
if !code.Ok() {
return code
}
node.Node().OnMount(c)
return code
}
func (c *FileSystemConnector) lockMount(parent *Inode, name string, root Node, opts *Options) (*Inode, fuse.Status) {
defer c.verify()
parent.mount.treeLock.Lock()
defer parent.mount.treeLock.Unlock()
node := parent.children[name]
if node != nil {
return nil, fuse.EBUSY
}
node = newInode(true, root)
if opts == nil {
opts = c.rootNode.mountPoint.options
}
node.mountFs(opts)
node.mount.connector = c
parent.addChild(name, node)
node.mountPoint.parentInode = parent
if c.debug {
log.Printf("Mount %T on subdir %s, parent %d", node,
name, c.inodeMap.Handle(&parent.handled))
}
return node, fuse.OK
}
// Unmount() tries to unmount the given inode. It returns EINVAL if the
// path does not exist, or is not a mount point, and EBUSY if there
// are open files or submounts below this node.
func (c *FileSystemConnector) Unmount(node *Inode) fuse.Status {
// TODO - racy.
if node.mountPoint == nil {
log.Println("not a mountpoint:", c.inodeMap.Handle(&node.handled))
return fuse.EINVAL
}
nodeID := c.inodeMap.Handle(&node.handled)
// Must lock parent to update tree structure.
parentNode := node.mountPoint.parentInode
parentNode.mount.treeLock.Lock()
defer parentNode.mount.treeLock.Unlock()
mount := node.mountPoint
name := node.mountPoint.mountName()
if mount.openFiles.Count() > 0 {
return fuse.EBUSY
}
node.mount.treeLock.Lock()
defer node.mount.treeLock.Unlock()
if mount.mountInode != node {
log.Panicf("got two different mount inodes %v vs %v",
c.inodeMap.Handle(&mount.mountInode.handled),
c.inodeMap.Handle(&node.handled))
}
if !node.canUnmount() {
return fuse.EBUSY
}
delete(parentNode.children, name)
node.Node().OnUnmount()
parentId := c.inodeMap.Handle(&parentNode.handled)
if parentNode == c.rootNode {
// TODO - test coverage. Currently covered by zipfs/multizip_test.go
parentId = fuse.FUSE_ROOT_ID
}
// We have to wait until the kernel has forgotten the
// mountpoint, so the write to node.mountPoint is no longer
// racy.
mount.treeLock.Unlock()
parentNode.mount.treeLock.Unlock()
code := c.server.DeleteNotify(parentId, nodeID, name)
if code.Ok() {
delay := 100 * time.Microsecond
for {
// This operation is rare, so we kludge it to avoid
// contention.
time.Sleep(delay)
delay = delay * 2
if !c.inodeMap.Has(nodeID) {
break
}
if delay >= time.Second {
// We limit the wait at one second. If
// it takes longer, something else is
// amiss, and we would be waiting forever.
log.Println("kernel did not issue FORGET for node on Unmount.")
break
}
}
}
parentNode.mount.treeLock.Lock()
mount.treeLock.Lock()
mount.mountInode = nil
node.mountPoint = nil
return fuse.OK
}
// FileNotify notifies the kernel that data and metadata of this inode
// has changed. After this call completes, the kernel will issue a
// new GetAttr requests for metadata and new Read calls for content.
// Use negative offset for metadata-only invalidation, and zero-length
// for invalidating all content.
func (c *FileSystemConnector) FileNotify(node *Inode, off int64, length int64) fuse.Status {
var nId uint64
if node == c.rootNode {
nId = fuse.FUSE_ROOT_ID
} else {
nId = c.inodeMap.Handle(&node.handled)
}
if nId == 0 {
return fuse.OK
}
return c.server.InodeNotify(nId, off, length)
}
// EntryNotify makes the kernel forget the entry data from the given
// name from a directory. After this call, the kernel will issue a
// new lookup request for the given name when necessary. No filesystem
// related locks should be held when calling this.
func (c *FileSystemConnector) EntryNotify(node *Inode, name string) fuse.Status {
var nId uint64
if node == c.rootNode {
nId = fuse.FUSE_ROOT_ID
} else {
nId = c.inodeMap.Handle(&node.handled)
}
if nId == 0 {
return fuse.OK
}
return c.server.EntryNotify(nId, name)
}
// DeleteNotify signals to the kernel that the named entry in dir for
// the child disappeared. No filesystem related locks should be held
// when calling this.
func (c *FileSystemConnector) DeleteNotify(dir *Inode, child *Inode, name string) fuse.Status {
var nId uint64
if dir == c.rootNode {
nId = fuse.FUSE_ROOT_ID
} else {
nId = c.inodeMap.Handle(&dir.handled)
}
if nId == 0 {
return fuse.OK
}
chId := c.inodeMap.Handle(&child.handled)
return c.server.DeleteNotify(nId, chId, name)
}

158
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsmount.go generated vendored Normal file
View file

@ -0,0 +1,158 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"log"
"sync"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
// openedFile stores either an open dir or an open file.
type openedFile struct {
handled
WithFlags
dir *connectorDir
}
type fileSystemMount struct {
// Node that we were mounted on.
mountInode *Inode
// Parent to the mountInode.
parentInode *Inode
// Options for the mount.
options *Options
// Protects the "children" and "parents" hashmaps of the inodes
// within the mount.
// treeLock should be acquired before openFilesLock.
//
// If multiple treeLocks must be acquired, the treeLocks
// closer to the root must be acquired first.
treeLock sync.RWMutex
// Manage filehandles of open files.
openFiles handleMap
Debug bool
connector *FileSystemConnector
}
// Must called with lock for parent held.
func (m *fileSystemMount) mountName() string {
for k, v := range m.parentInode.children {
if m.mountInode == v {
return k
}
}
panic("not found")
}
func (m *fileSystemMount) setOwner(attr *fuse.Attr) {
if m.options.Owner != nil {
attr.Owner = *(*fuse.Owner)(m.options.Owner)
}
}
func (m *fileSystemMount) fillEntry(out *fuse.EntryOut) {
splitDuration(m.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
m.setOwner(&out.Attr)
if out.Mode&fuse.S_IFDIR == 0 && out.Nlink == 0 {
out.Nlink = 1
}
}
func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
m.setOwner(&out.Attr)
if out.Ino == 0 {
out.Ino = nodeId
}
}
func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
var b *openedFile
if h != 0 {
b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
}
if b != nil && m.connector.debug && b.WithFlags.Description != "" {
log.Printf("File %d = %q", h, b.WithFlags.Description)
}
return b
}
func (m *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
_, obj := m.openFiles.Forget(handle, 1)
opened := (*openedFile)(unsafe.Pointer(obj))
node.openFilesMutex.Lock()
idx := -1
for i, v := range node.openFiles {
if v == opened {
idx = i
break
}
}
l := len(node.openFiles)
if idx == l-1 {
node.openFiles[idx] = nil
} else {
node.openFiles[idx] = node.openFiles[l-1]
}
node.openFiles = node.openFiles[:l-1]
node.openFilesMutex.Unlock()
return opened
}
func (m *fileSystemMount) registerFileHandle(node *Inode, dir *connectorDir, f File, flags uint32) (uint64, *openedFile) {
node.openFilesMutex.Lock()
b := &openedFile{
dir: dir,
WithFlags: WithFlags{
File: f,
OpenFlags: flags,
},
}
for {
withFlags, ok := f.(*WithFlags)
if !ok {
break
}
b.WithFlags.File = withFlags.File
b.WithFlags.FuseFlags |= withFlags.FuseFlags
b.WithFlags.Description += withFlags.Description
f = withFlags.File
}
if b.WithFlags.File != nil {
b.WithFlags.File.SetInode(node)
}
node.openFiles = append(node.openFiles, b)
handle, _ := m.openFiles.Register(&b.handled)
node.openFilesMutex.Unlock()
return handle, b
}
// Creates a return entry for a non-existent path.
func (m *fileSystemMount) negativeEntry(out *fuse.EntryOut) bool {
if m.options.NegativeTimeout > 0.0 {
out.NodeId = 0
splitDuration(m.options.NegativeTimeout, &out.EntryValid, &out.EntryValidNsec)
return true
}
return false
}

487
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go generated vendored Normal file
View file

@ -0,0 +1,487 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
// This file contains FileSystemConnector's implementation of
// RawFileSystem
import (
"bytes"
"fmt"
"log"
"strings"
"time"
"github.com/hanwen/go-fuse/fuse"
)
// Returns the RawFileSystem so it can be mounted.
func (c *FileSystemConnector) RawFS() fuse.RawFileSystem {
return (*rawBridge)(c)
}
type rawBridge FileSystemConnector
func (c *rawBridge) Fsync(input *fuse.FsyncIn) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
if opened != nil {
return opened.WithFlags.File.Fsync(int(input.FsyncFlags))
}
return fuse.ENOSYS
}
func (c *rawBridge) SetDebug(debug bool) {
c.fsConn().SetDebug(debug)
}
func (c *rawBridge) FsyncDir(input *fuse.FsyncIn) fuse.Status {
return fuse.ENOSYS
}
func (c *rawBridge) fsConn() *FileSystemConnector {
return (*FileSystemConnector)(c)
}
func (c *rawBridge) String() string {
if c.rootNode == nil || c.rootNode.mount == nil {
return "go-fuse:unmounted"
}
name := fmt.Sprintf("%T", c.rootNode.Node())
name = strings.TrimLeft(name, "*")
return name
}
func (c *rawBridge) Init(s *fuse.Server) {
c.server = s
c.rootNode.Node().OnMount((*FileSystemConnector)(c))
}
func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) {
code = mount.mountInode.Node().GetAttr(out, nil, nil)
if !code.Ok() {
log.Println("Root getattr should not return error", code)
out.Mode = fuse.S_IFDIR | 0755
return mount.mountInode, fuse.OK
}
return mount.mountInode, fuse.OK
}
// internalLookup executes a lookup without affecting NodeId reference counts.
func (c *FileSystemConnector) internalLookup(out *fuse.Attr, parent *Inode, name string, header *fuse.InHeader) (node *Inode, code fuse.Status) {
// We may already know the child because it was created using Create or Mkdir,
// from an earlier lookup, or because the nodes were created in advance
// (in-memory filesystems).
child := parent.GetChild(name)
if child != nil && child.mountPoint != nil {
return c.lookupMountUpdate(out, child.mountPoint)
}
if child != nil {
parent = nil
}
if child != nil {
code = child.fsInode.GetAttr(out, nil, &header.Context)
} else {
child, code = parent.fsInode.Lookup(out, name, &header.Context)
}
return child, code
}
func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) {
parent := c.toInode(header.NodeId)
if !parent.IsDir() {
log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId)
return fuse.ENOTDIR
}
outAttr := (*fuse.Attr)(&out.Attr)
child, code := c.fsConn().internalLookup(outAttr, parent, name, header)
if code == fuse.ENOENT && parent.mount.negativeEntry(out) {
return fuse.OK
}
if !code.Ok() {
return code
}
if child == nil {
log.Println("Lookup returned fuse.OK with nil child", name)
}
child.mount.fillEntry(out)
out.NodeId, out.Generation = c.fsConn().lookupUpdate(child)
if out.Ino == 0 {
out.Ino = out.NodeId
}
return fuse.OK
}
func (c *rawBridge) Forget(nodeID, nlookup uint64) {
c.fsConn().forgetUpdate(nodeID, int(nlookup))
}
func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
node := c.toInode(input.NodeId)
var f File
if input.Flags()&fuse.FUSE_GETATTR_FH != 0 {
if opened := node.mount.getOpenedFile(input.Fh()); opened != nil {
f = opened.WithFlags.File
}
}
dest := (*fuse.Attr)(&out.Attr)
code = node.fsInode.GetAttr(dest, f, &input.Context)
if !code.Ok() {
return code
}
if out.Nlink == 0 {
// With Nlink == 0, newer kernels will refuse link
// operations.
out.Nlink = 1
}
node.mount.fillAttr(out, input.NodeId)
return fuse.OK
}
func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
node := c.toInode(input.NodeId)
stream, err := node.fsInode.OpenDir(&input.Context)
if err != fuse.OK {
return err
}
stream = append(stream, node.getMountDirEntries()...)
de := &connectorDir{
node: node.Node(),
stream: append(stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}),
rawFS: c,
}
h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
out.OpenFlags = opened.FuseFlags
out.Fh = h
return fuse.OK
}
func (c *rawBridge) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
return opened.dir.ReadDir(input, out)
}
func (c *rawBridge) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
return opened.dir.ReadDirPlus(input, out)
}
func (c *rawBridge) Open(input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
node := c.toInode(input.NodeId)
f, code := node.fsInode.Open(input.Flags, &input.Context)
if !code.Ok() || f == nil {
return code
}
h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
out.OpenFlags = opened.FuseFlags
out.Fh = h
return fuse.OK
}
func (c *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
node := c.toInode(input.NodeId)
var f File
if input.Valid&fuse.FATTR_FH != 0 {
opened := node.mount.getOpenedFile(input.Fh)
f = opened.WithFlags.File
}
if code.Ok() && input.Valid&fuse.FATTR_MODE != 0 {
permissions := uint32(07777) & input.Mode
code = node.fsInode.Chmod(f, permissions, &input.Context)
}
if code.Ok() && (input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0) {
var uid uint32 = ^uint32(0) // means "do not change" in chown(2)
var gid uint32 = ^uint32(0)
if input.Valid&fuse.FATTR_UID != 0 {
uid = input.Uid
}
if input.Valid&fuse.FATTR_GID != 0 {
gid = input.Gid
}
code = node.fsInode.Chown(f, uid, gid, &input.Context)
}
if code.Ok() && input.Valid&fuse.FATTR_SIZE != 0 {
code = node.fsInode.Truncate(f, input.Size, &input.Context)
}
if code.Ok() && (input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0) {
now := time.Now()
var atime *time.Time
var mtime *time.Time
if input.Valid&fuse.FATTR_ATIME != 0 {
if input.Valid&fuse.FATTR_ATIME_NOW != 0 {
atime = &now
} else {
t := time.Unix(int64(input.Atime), int64(input.Atimensec))
atime = &t
}
}
if input.Valid&fuse.FATTR_MTIME != 0 {
if input.Valid&fuse.FATTR_MTIME_NOW != 0 {
mtime = &now
} else {
t := time.Unix(int64(input.Mtime), int64(input.Mtimensec))
mtime = &t
}
}
code = node.fsInode.Utimens(f, atime, mtime, &input.Context)
}
if !code.Ok() {
return code
}
// Must call GetAttr(); the filesystem may override some of
// the changes we effect here.
attr := (*fuse.Attr)(&out.Attr)
code = node.fsInode.GetAttr(attr, nil, &input.Context)
if code.Ok() {
node.mount.fillAttr(out, input.NodeId)
}
return code
}
func (c *rawBridge) Fallocate(input *fuse.FallocateIn) (code fuse.Status) {
n := c.toInode(input.NodeId)
opened := n.mount.getOpenedFile(input.Fh)
return n.fsInode.Fallocate(opened, input.Offset, input.Length, input.Mode, &input.Context)
}
func (c *rawBridge) Readlink(header *fuse.InHeader) (out []byte, code fuse.Status) {
n := c.toInode(header.NodeId)
return n.fsInode.Readlink(&header.Context)
}
func (c *rawBridge) Mknod(input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
parent := c.toInode(input.NodeId)
child, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &input.Context)
if code.Ok() {
c.childLookup(out, child, &input.Context)
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
}
return code
}
func (c *rawBridge) Mkdir(input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
parent := c.toInode(input.NodeId)
child, code := parent.fsInode.Mkdir(name, input.Mode, &input.Context)
if code.Ok() {
c.childLookup(out, child, &input.Context)
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
}
return code
}
func (c *rawBridge) Unlink(header *fuse.InHeader, name string) (code fuse.Status) {
parent := c.toInode(header.NodeId)
return parent.fsInode.Unlink(name, &header.Context)
}
func (c *rawBridge) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) {
parent := c.toInode(header.NodeId)
return parent.fsInode.Rmdir(name, &header.Context)
}
func (c *rawBridge) Symlink(header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) {
parent := c.toInode(header.NodeId)
child, code := parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
if code.Ok() {
c.childLookup(out, child, &header.Context)
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &header.Context)
}
return code
}
func (c *rawBridge) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
oldParent := c.toInode(input.NodeId)
child := oldParent.GetChild(oldName)
if child == nil {
return fuse.ENOENT
}
if child.mountPoint != nil {
return fuse.EBUSY
}
newParent := c.toInode(input.Newdir)
if oldParent.mount != newParent.mount {
return fuse.EXDEV
}
return oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &input.Context)
}
func (c *rawBridge) Link(input *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) {
existing := c.toInode(input.Oldnodeid)
parent := c.toInode(input.NodeId)
if existing.mount != parent.mount {
return fuse.EXDEV
}
child, code := parent.fsInode.Link(name, existing.fsInode, &input.Context)
if code.Ok() {
c.childLookup(out, child, &input.Context)
code = child.fsInode.GetAttr((*fuse.Attr)(&out.Attr), nil, &input.Context)
}
return code
}
func (c *rawBridge) Access(input *fuse.AccessIn) (code fuse.Status) {
n := c.toInode(input.NodeId)
return n.fsInode.Access(input.Mask, &input.Context)
}
func (c *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) {
parent := c.toInode(input.NodeId)
f, child, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &input.Context)
if !code.Ok() {
return code
}
c.childLookup(&out.EntryOut, child, &input.Context)
handle, opened := parent.mount.registerFileHandle(child, nil, f, input.Flags)
out.OpenOut.OpenFlags = opened.FuseFlags
out.OpenOut.Fh = handle
return code
}
func (c *rawBridge) Release(input *fuse.ReleaseIn) {
if input.Fh != 0 {
node := c.toInode(input.NodeId)
opened := node.mount.unregisterFileHandle(input.Fh, node)
opened.WithFlags.File.Release()
}
}
func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) {
if input.Fh != 0 {
node := c.toInode(input.NodeId)
node.mount.unregisterFileHandle(input.Fh, node)
}
}
func (c *rawBridge) GetXAttrSize(header *fuse.InHeader, attribute string) (sz int, code fuse.Status) {
node := c.toInode(header.NodeId)
data, errno := node.fsInode.GetXAttr(attribute, &header.Context)
return len(data), errno
}
func (c *rawBridge) GetXAttrData(header *fuse.InHeader, attribute string) (data []byte, code fuse.Status) {
node := c.toInode(header.NodeId)
return node.fsInode.GetXAttr(attribute, &header.Context)
}
func (c *rawBridge) RemoveXAttr(header *fuse.InHeader, attr string) fuse.Status {
node := c.toInode(header.NodeId)
return node.fsInode.RemoveXAttr(attr, &header.Context)
}
func (c *rawBridge) SetXAttr(input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
node := c.toInode(input.NodeId)
return node.fsInode.SetXAttr(attr, data, int(input.Flags), &input.Context)
}
func (c *rawBridge) ListXAttr(header *fuse.InHeader) (data []byte, code fuse.Status) {
node := c.toInode(header.NodeId)
attrs, code := node.fsInode.ListXAttr(&header.Context)
if code != fuse.OK {
return nil, code
}
b := bytes.NewBuffer([]byte{})
for _, v := range attrs {
b.Write([]byte(v))
b.WriteByte(0)
}
return b.Bytes(), code
}
////////////////
// files.
func (c *rawBridge) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
var f File
if opened != nil {
f = opened.WithFlags.File
}
return node.Node().Write(f, data, int64(input.Offset), &input.Context)
}
func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
var f File
if opened != nil {
f = opened.WithFlags.File
}
return node.Node().Read(f, buf, int64(input.Offset), &input.Context)
}
func (c *rawBridge) Flock(input *fuse.FlockIn, flags int) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
if opened != nil {
return opened.WithFlags.File.Flock(flags)
}
return fuse.EBADF
}
func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
node := c.toInode(header.NodeId)
s := node.Node().StatFs()
if s == nil {
return fuse.ENOSYS
}
*out = *s
return fuse.OK
}
func (c *rawBridge) Flush(input *fuse.FlushIn) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
if opened != nil {
return opened.WithFlags.File.Flush()
}
return fuse.OK
}

24
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fuse.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"github.com/hanwen/go-fuse/fuse"
)
// Mounts a filesystem with the given root node on the given directory
func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) {
conn := NewFileSystemConnector(root, opts)
mountOpts := fuse.MountOptions{}
if opts != nil && opts.Debug {
mountOpts.Debug = opts.Debug
}
s, err := fuse.NewServer(conn.RawFS(), mountpoint, &mountOpts)
if err != nil {
return nil, nil, err
}
return s, conn, nil
}

151
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go generated vendored Normal file
View file

@ -0,0 +1,151 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"log"
"sync"
)
// HandleMap translates objects in Go space to 64-bit handles that can
// be given out to -say- the linux kernel as NodeIds.
//
// The 32 bits version of this is a threadsafe wrapper around a map.
//
// To use it, include "handled" as first member of the structure
// you wish to export.
//
// This structure is thread-safe.
type handleMap interface {
// Register stores "obj" and returns a unique (NodeId, generation) tuple.
Register(obj *handled) (handle, generation uint64)
Count() int
// Decode retrieves a stored object from its 64-bit handle.
Decode(uint64) *handled
// Forget decrements the reference counter for "handle" by "count" and drops
// the object if the refcount reaches zero.
// Returns a boolean whether the object was dropped and the object itself.
Forget(handle uint64, count int) (bool, *handled)
// Handle gets the object's NodeId.
Handle(obj *handled) uint64
// Has checks if NodeId is stored.
Has(uint64) bool
}
type handled struct {
check uint32
handle uint64
count int
}
func (h *handled) verify() {
if h.count < 0 {
log.Panicf("negative lookup count %d", h.count)
}
if (h.count == 0) != (h.handle == 0) {
log.Panicf("registration mismatch: lookup %d id %d", h.count, h.handle)
}
}
const _ALREADY_MSG = "Object already has a handle"
////////////////////////////////////////////////////////////////
// portable version using 32 bit integers.
type portableHandleMap struct {
sync.RWMutex
// The generation counter is incremented each time a NodeId is reused,
// hence the (NodeId, Generation) tuple is always unique.
generation uint64
// Number of currently used handles
used int
// Array of Go objects indexed by NodeId
handles []*handled
// Free slots in the "handles" array
freeIds []uint64
}
func newPortableHandleMap() *portableHandleMap {
return &portableHandleMap{
// Avoid handing out ID 0 and 1.
handles: []*handled{nil, nil},
}
}
func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
m.Lock()
if obj.count == 0 {
if obj.check != 0 {
panic(_ALREADY_MSG)
}
if len(m.freeIds) == 0 {
handle = uint64(len(m.handles))
m.handles = append(m.handles, obj)
} else {
handle = m.freeIds[len(m.freeIds)-1]
m.freeIds = m.freeIds[:len(m.freeIds)-1]
m.generation++
m.handles[handle] = obj
}
m.used++
obj.handle = handle
} else {
handle = obj.handle
}
obj.count++
generation = m.generation
m.Unlock()
return
}
func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
m.RLock()
if obj.count == 0 {
h = 0
} else {
h = obj.handle
}
m.RUnlock()
return h
}
func (m *portableHandleMap) Count() int {
m.RLock()
c := m.used
m.RUnlock()
return c
}
func (m *portableHandleMap) Decode(h uint64) *handled {
m.RLock()
v := m.handles[h]
m.RUnlock()
return v
}
func (m *portableHandleMap) Forget(h uint64, count int) (forgotten bool, obj *handled) {
m.Lock()
obj = m.handles[h]
obj.count -= count
if obj.count < 0 {
log.Panicf("underflow: handle %d, count %d, object %d", h, count, obj.count)
} else if obj.count == 0 {
m.handles[h] = nil
m.freeIds = append(m.freeIds, h)
m.used--
forgotten = true
obj.handle = 0
}
m.Unlock()
return forgotten, obj
}
func (m *portableHandleMap) Has(h uint64) bool {
m.RLock()
ok := m.handles[h] != nil
m.RUnlock()
return ok
}

289
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go generated vendored Normal file
View file

@ -0,0 +1,289 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"log"
"sync"
"github.com/hanwen/go-fuse/fuse"
)
type parentData struct {
parent *Inode
name string
}
// An Inode reflects the kernel's idea of the inode. Inodes have IDs
// that are communicated to the kernel, and they have a tree
// structure: a directory Inode may contain named children. Each
// Inode object is paired with a Node object, which file system
// implementers should supply.
type Inode struct {
handled handled
// Generation number of the inode. Each (re)use of an inode
// should have a unique generation number.
generation uint64
// Number of open files and its protection.
openFilesMutex sync.Mutex
openFiles []*openedFile
fsInode Node
// Each inode belongs to exactly one fileSystemMount. This
// pointer is constant during the lifetime, except upon
// Unmount() when it is set to nil.
mount *fileSystemMount
// All data below is protected by treeLock.
children map[string]*Inode
// Due to hard links, an Inode can have many parents.
parents map[parentData]struct{}
// Non-nil if this inode is a mountpoint, ie. the Root of a
// NodeFileSystem.
mountPoint *fileSystemMount
}
func newInode(isDir bool, fsNode Node) *Inode {
me := new(Inode)
me.parents = map[parentData]struct{}{}
if isDir {
me.children = make(map[string]*Inode, initDirSize)
}
me.fsInode = fsNode
me.fsInode.SetInode(me)
return me
}
// public methods.
// Returns any open file, preferably a r/w one.
func (n *Inode) AnyFile() (file File) {
n.openFilesMutex.Lock()
for _, f := range n.openFiles {
if file == nil || f.WithFlags.OpenFlags&fuse.O_ANYWRITE != 0 {
file = f.WithFlags.File
}
}
n.openFilesMutex.Unlock()
return file
}
// Children returns all children of this inode.
func (n *Inode) Children() (out map[string]*Inode) {
n.mount.treeLock.RLock()
out = make(map[string]*Inode, len(n.children))
for k, v := range n.children {
out[k] = v
}
n.mount.treeLock.RUnlock()
return out
}
// Parent returns a random parent and the name this inode has under this parent.
// This function can be used to walk up the directory tree. It will not cross
// sub-mounts.
func (n *Inode) Parent() (parent *Inode, name string) {
if n.mountPoint != nil {
return nil, ""
}
for k := range n.parents {
return k.parent, k.name
}
return nil, ""
}
// FsChildren returns all the children from the same filesystem. It
// will skip mountpoints.
func (n *Inode) FsChildren() (out map[string]*Inode) {
n.mount.treeLock.RLock()
out = map[string]*Inode{}
for k, v := range n.children {
if v.mount == n.mount {
out[k] = v
}
}
n.mount.treeLock.RUnlock()
return out
}
// Node returns the file-system specific node.
func (n *Inode) Node() Node {
return n.fsInode
}
// Files() returns an opens file that have bits in common with the
// give mask. Use mask==0 to return all files.
func (n *Inode) Files(mask uint32) (files []WithFlags) {
n.openFilesMutex.Lock()
for _, f := range n.openFiles {
if mask == 0 || f.WithFlags.OpenFlags&mask != 0 {
files = append(files, f.WithFlags)
}
}
n.openFilesMutex.Unlock()
return files
}
// IsDir returns true if this is a directory.
func (n *Inode) IsDir() bool {
return n.children != nil
}
// NewChild adds a new child inode to this inode.
func (n *Inode) NewChild(name string, isDir bool, fsi Node) *Inode {
ch := newInode(isDir, fsi)
ch.mount = n.mount
n.AddChild(name, ch)
return ch
}
// GetChild returns a child inode with the given name, or nil if it
// does not exist.
func (n *Inode) GetChild(name string) (child *Inode) {
n.mount.treeLock.RLock()
child = n.children[name]
n.mount.treeLock.RUnlock()
return child
}
// AddChild adds a child inode. The parent inode must be a directory
// node.
func (n *Inode) AddChild(name string, child *Inode) {
if child == nil {
log.Panicf("adding nil child as %q", name)
}
n.mount.treeLock.Lock()
n.addChild(name, child)
n.mount.treeLock.Unlock()
}
// TreeWatcher is an additional interface that Nodes can implement.
// If they do, the OnAdd and OnRemove are called for operations on the
// file system tree. These functions run under a lock, so they should
// not do blocking operations.
type TreeWatcher interface {
OnAdd(parent *Inode, name string)
OnRemove(parent *Inode, name string)
}
// RmChild removes an inode by name, and returns it. It returns nil if
// child does not exist.
func (n *Inode) RmChild(name string) (ch *Inode) {
n.mount.treeLock.Lock()
ch = n.rmChild(name)
n.mount.treeLock.Unlock()
return
}
//////////////////////////////////////////////////////////////
// private
// addChild adds "child" to our children under name "name".
// Must be called with treeLock for the mount held.
func (n *Inode) addChild(name string, child *Inode) {
if paranoia {
ch := n.children[name]
if ch != nil {
log.Panicf("Already have an Inode with same name: %v: %v", name, ch)
}
}
n.children[name] = child
child.parents[parentData{n, name}] = struct{}{}
if w, ok := child.Node().(TreeWatcher); ok && child.mountPoint == nil {
w.OnAdd(n, name)
}
}
// rmChild throws out child "name". This means (1) deleting "name" from our
// "children" map and (2) deleting ourself from the child's "parents" map.
// Must be called with treeLock for the mount held.
func (n *Inode) rmChild(name string) *Inode {
ch := n.children[name]
if ch != nil {
delete(n.children, name)
delete(ch.parents, parentData{n, name})
if w, ok := ch.Node().(TreeWatcher); ok && ch.mountPoint == nil {
w.OnRemove(n, name)
}
}
return ch
}
// Can only be called on untouched root inodes.
func (n *Inode) mountFs(opts *Options) {
n.mountPoint = &fileSystemMount{
openFiles: newPortableHandleMap(),
mountInode: n,
options: opts,
}
n.mount = n.mountPoint
}
// Must be called with treeLock held.
func (n *Inode) canUnmount() bool {
for _, v := range n.children {
if v.mountPoint != nil {
// This access may be out of date, but it is no
// problem to err on the safe side.
return false
}
if !v.canUnmount() {
return false
}
}
n.openFilesMutex.Lock()
ok := len(n.openFiles) == 0
n.openFilesMutex.Unlock()
return ok
}
func (n *Inode) getMountDirEntries() (out []fuse.DirEntry) {
n.mount.treeLock.RLock()
for k, v := range n.children {
if v.mountPoint != nil {
out = append(out, fuse.DirEntry{
Name: k,
Mode: fuse.S_IFDIR,
})
}
}
n.mount.treeLock.RUnlock()
return out
}
const initDirSize = 20
func (n *Inode) verify(cur *fileSystemMount) {
n.handled.verify()
if n.mountPoint != nil {
if n != n.mountPoint.mountInode {
log.Panicf("mountpoint mismatch %v %v", n, n.mountPoint.mountInode)
}
cur = n.mountPoint
cur.treeLock.Lock()
defer cur.treeLock.Unlock()
}
if n.mount != cur {
log.Panicf("n.mount not set correctly %v %v", n.mount, cur)
}
for nm, ch := range n.children {
if ch == nil {
log.Panicf("Found nil child: %q", nm)
}
ch.verify(cur)
}
}

View file

@ -0,0 +1,109 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"fmt"
"sync"
"time"
"github.com/hanwen/go-fuse/fuse"
)
type lockingFile struct {
mu *sync.Mutex
file File
}
// NewLockingFile serializes operations an existing File.
func NewLockingFile(mu *sync.Mutex, f File) File {
return &lockingFile{
mu: mu,
file: f,
}
}
func (f *lockingFile) SetInode(*Inode) {
}
func (f *lockingFile) InnerFile() File {
return f.file
}
func (f *lockingFile) String() string {
return fmt.Sprintf("lockingFile(%s)", f.file.String())
}
func (f *lockingFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Read(buf, off)
}
func (f *lockingFile) Write(data []byte, off int64) (uint32, fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Write(data, off)
}
func (f *lockingFile) Flush() fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Flush()
}
func (f *lockingFile) Flock(flags int) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Flock(flags)
}
func (f *lockingFile) Release() {
f.mu.Lock()
defer f.mu.Unlock()
f.file.Release()
}
func (f *lockingFile) GetAttr(a *fuse.Attr) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.GetAttr(a)
}
func (f *lockingFile) Fsync(flags int) (code fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Fsync(flags)
}
func (f *lockingFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Utimens(atime, mtime)
}
func (f *lockingFile) Truncate(size uint64) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Truncate(size)
}
func (f *lockingFile) Chown(uid uint32, gid uint32) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Chown(uid, gid)
}
func (f *lockingFile) Chmod(perms uint32) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Chmod(perms)
}
func (f *lockingFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Allocate(off, size, mode)
}

232
vendor/github.com/hanwen/go-fuse/fuse/nodefs/memnode.go generated vendored Normal file
View file

@ -0,0 +1,232 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"fmt"
"os"
"sync"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
// NewMemNodeFSRoot creates an in-memory node-based filesystem. Files
// are written into a backing store under the given prefix.
func NewMemNodeFSRoot(prefix string) Node {
fs := &memNodeFs{
backingStorePrefix: prefix,
}
fs.root = fs.newNode()
return fs.root
}
type memNodeFs struct {
backingStorePrefix string
root *memNode
mutex sync.Mutex
nextFree int
}
func (fs *memNodeFs) String() string {
return fmt.Sprintf("MemNodeFs(%s)", fs.backingStorePrefix)
}
func (fs *memNodeFs) Root() Node {
return fs.root
}
func (fs *memNodeFs) SetDebug(bool) {
}
func (fs *memNodeFs) OnMount(*FileSystemConnector) {
}
func (fs *memNodeFs) OnUnmount() {
}
func (fs *memNodeFs) newNode() *memNode {
fs.mutex.Lock()
id := fs.nextFree
fs.nextFree++
fs.mutex.Unlock()
n := &memNode{
Node: NewDefaultNode(),
fs: fs,
id: id,
}
now := time.Now()
n.info.SetTimes(&now, &now, &now)
n.info.Mode = fuse.S_IFDIR | 0777
return n
}
func (fs *memNodeFs) Filename(n *Inode) string {
mn := n.Node().(*memNode)
return mn.filename()
}
type memNode struct {
Node
fs *memNodeFs
id int
link string
info fuse.Attr
}
func (n *memNode) filename() string {
return fmt.Sprintf("%s%d", n.fs.backingStorePrefix, n.id)
}
func (n *memNode) Deletable() bool {
return false
}
func (n *memNode) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
return []byte(n.link), fuse.OK
}
func (n *memNode) StatFs() *fuse.StatfsOut {
return &fuse.StatfsOut{}
}
func (n *memNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) {
ch := n.fs.newNode()
ch.info.Mode = mode | fuse.S_IFDIR
n.Inode().NewChild(name, true, ch)
return ch.Inode(), fuse.OK
}
func (n *memNode) Unlink(name string, context *fuse.Context) (code fuse.Status) {
ch := n.Inode().RmChild(name)
if ch == nil {
return fuse.ENOENT
}
return fuse.OK
}
func (n *memNode) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return n.Unlink(name, context)
}
func (n *memNode) Symlink(name string, content string, context *fuse.Context) (newNode *Inode, code fuse.Status) {
ch := n.fs.newNode()
ch.info.Mode = fuse.S_IFLNK | 0777
ch.link = content
n.Inode().NewChild(name, false, ch)
return ch.Inode(), fuse.OK
}
func (n *memNode) Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status) {
ch := n.Inode().RmChild(oldName)
newParent.Inode().RmChild(newName)
newParent.Inode().AddChild(newName, ch)
return fuse.OK
}
func (n *memNode) Link(name string, existing Node, context *fuse.Context) (*Inode, fuse.Status) {
n.Inode().AddChild(name, existing.Inode())
return existing.Inode(), fuse.OK
}
func (n *memNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, node *Inode, code fuse.Status) {
ch := n.fs.newNode()
ch.info.Mode = mode | fuse.S_IFREG
f, err := os.Create(ch.filename())
if err != nil {
return nil, nil, fuse.ToStatus(err)
}
n.Inode().NewChild(name, false, ch)
return ch.newFile(f), ch.Inode(), fuse.OK
}
type memNodeFile struct {
File
node *memNode
}
func (n *memNodeFile) String() string {
return fmt.Sprintf("memNodeFile(%s)", n.File.String())
}
func (n *memNodeFile) InnerFile() File {
return n.File
}
func (n *memNodeFile) Flush() fuse.Status {
code := n.File.Flush()
if !code.Ok() {
return code
}
st := syscall.Stat_t{}
err := syscall.Stat(n.node.filename(), &st)
n.node.info.Size = uint64(st.Size)
n.node.info.Blocks = uint64(st.Blocks)
return fuse.ToStatus(err)
}
func (n *memNode) newFile(f *os.File) File {
return &memNodeFile{
File: NewLoopbackFile(f),
node: n,
}
}
func (n *memNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) {
f, err := os.OpenFile(n.filename(), int(flags), 0666)
if err != nil {
return nil, fuse.ToStatus(err)
}
return n.newFile(f), fuse.OK
}
func (n *memNode) GetAttr(fi *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) {
*fi = n.info
return fuse.OK
}
func (n *memNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) {
if file != nil {
code = file.Truncate(size)
} else {
err := os.Truncate(n.filename(), int64(size))
code = fuse.ToStatus(err)
}
if code.Ok() {
now := time.Now()
n.info.SetTimes(nil, nil, &now)
// TODO - should update mtime too?
n.info.Size = size
}
return code
}
func (n *memNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status) {
c := time.Now()
n.info.SetTimes(atime, mtime, &c)
return fuse.OK
}
func (n *memNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) {
n.info.Mode = (n.info.Mode &^ 07777) | perms
now := time.Now()
n.info.SetTimes(nil, nil, &now)
return fuse.OK
}
func (n *memNode) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
n.info.Uid = uid
n.info.Gid = gid
now := time.Now()
n.info.SetTimes(nil, nil, &now)
return fuse.OK
}

13
vendor/github.com/hanwen/go-fuse/fuse/nodefs/nodefs.go generated vendored Normal file
View file

@ -0,0 +1,13 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import "time"
func splitDuration(dt time.Duration, secs *uint64, nsecs *uint32) {
ns := int64(dt)
*nsecs = uint32(ns % 1e9)
*secs = uint64(ns / 1e9)
}

18
vendor/github.com/hanwen/go-fuse/fuse/nodefs/print.go generated vendored Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"fmt"
"github.com/hanwen/go-fuse/fuse"
)
// String provides a debug string for the given file.
func (f *WithFlags) String() string {
return fmt.Sprintf("File %s (%s) %s %s",
f.File, f.Description, fuse.FlagString(fuse.OpenFlagNames, int64(f.OpenFlags), "O_RDONLY"),
fuse.FlagString(fuse.FuseOpenFlagNames, int64(f.FuseFlags), ""))
}

View file

@ -0,0 +1,20 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"syscall"
"unsafe"
)
// futimens - futimens(3) calls utimensat(2) with "pathname" set to null and
// "flags" set to zero
func futimens(fd int, times *[2]syscall.Timespec) (err error) {
_, _, e1 := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(fd), 0, uintptr(unsafe.Pointer(times)), uintptr(0), 0, 0)
if e1 != 0 {
err = syscall.Errno(e1)
}
return
}

658
vendor/github.com/hanwen/go-fuse/fuse/opcode.go generated vendored Normal file

File diff suppressed because it is too large Load diff

85
vendor/github.com/hanwen/go-fuse/fuse/pathfs/api.go generated vendored Normal file
View file

@ -0,0 +1,85 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
// A filesystem API that uses paths rather than inodes. A minimal
// file system should have at least a functional GetAttr method.
// Typically, each call happens in its own goroutine, so take care to
// make the file system thread-safe.
//
// NewDefaultFileSystem provides a null implementation of required
// methods.
type FileSystem interface {
// Used for pretty printing.
String() string
// If called, provide debug output through the log package.
SetDebug(debug bool)
// Attributes. This function is the main entry point, through
// which FUSE discovers which files and directories exist.
//
// If the filesystem wants to implement hard-links, it should
// return consistent non-zero FileInfo.Ino data. Using
// hardlinks incurs a performance hit.
GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status)
// These should update the file's ctime too.
Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status)
Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status)
Truncate(name string, size uint64, context *fuse.Context) (code fuse.Status)
Access(name string, mode uint32, context *fuse.Context) (code fuse.Status)
// Tree structure
Link(oldName string, newName string, context *fuse.Context) (code fuse.Status)
Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status
Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status
Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status)
Rmdir(name string, context *fuse.Context) (code fuse.Status)
Unlink(name string, context *fuse.Context) (code fuse.Status)
// Extended attributes.
GetXAttr(name string, attribute string, context *fuse.Context) (data []byte, code fuse.Status)
ListXAttr(name string, context *fuse.Context) (attributes []string, code fuse.Status)
RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status
SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status
// Called after mount.
OnMount(nodeFs *PathNodeFs)
OnUnmount()
// File handling. If opening for writing, the file's mtime
// should be updated too.
Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status)
Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status)
// Directory handling
OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, code fuse.Status)
// Symlinks.
Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status)
Readlink(name string, context *fuse.Context) (string, fuse.Status)
StatFs(name string) *fuse.StatfsOut
}
type PathNodeFsOptions struct {
// If ClientInodes is set, use Inode returned from GetAttr to
// find hard-linked files.
ClientInodes bool
// Debug controls printing of debug information.
Debug bool
}

61
vendor/github.com/hanwen/go-fuse/fuse/pathfs/copy.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"os"
"github.com/hanwen/go-fuse/fuse"
)
func CopyFile(srcFs, destFs FileSystem, srcFile, destFile string, context *fuse.Context) fuse.Status {
src, code := srcFs.Open(srcFile, uint32(os.O_RDONLY), context)
if !code.Ok() {
return code
}
defer src.Release()
defer src.Flush()
attr, code := srcFs.GetAttr(srcFile, context)
if !code.Ok() {
return code
}
dst, code := destFs.Create(destFile, uint32(os.O_WRONLY|os.O_CREATE|os.O_TRUNC), attr.Mode, context)
if !code.Ok() {
return code
}
defer dst.Release()
defer dst.Flush()
buf := make([]byte, 128*(1<<10))
off := int64(0)
for {
res, code := src.Read(buf, off)
if !code.Ok() {
return code
}
data, code := res.Bytes(buf)
if !code.Ok() {
return code
}
if len(data) == 0 {
break
}
n, code := dst.Write(data, off)
if !code.Ok() {
return code
}
if int(n) < len(data) {
return fuse.EIO
}
if len(data) < len(buf) {
break
}
off += int64(len(data))
}
return fuse.OK
}

122
vendor/github.com/hanwen/go-fuse/fuse/pathfs/default.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
// NewDefaultFileSystem creates a filesystem that responds ENOSYS for
// all methods
func NewDefaultFileSystem() FileSystem {
return (*defaultFileSystem)(nil)
}
// defaultFileSystem implements a FileSystem that returns ENOSYS for every operation.
type defaultFileSystem struct{}
func (fs *defaultFileSystem) SetDebug(debug bool) {}
// defaultFileSystem
func (fs *defaultFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
return nil, fuse.ENOSYS
}
func (fs *defaultFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
return nil, fuse.ENOATTR
}
func (fs *defaultFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
return nil, fuse.ENOSYS
}
func (fs *defaultFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
return "", fuse.ENOSYS
}
func (fs *defaultFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (fs *defaultFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
return nil, fuse.ENOSYS
}
func (fs *defaultFileSystem) OnMount(nodeFs *PathNodeFs) {
}
func (fs *defaultFileSystem) OnUnmount() {
}
func (fs *defaultFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return nil, fuse.ENOSYS
}
func (fs *defaultFileSystem) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS
}
func (fs *defaultFileSystem) String() string {
return "defaultFileSystem"
}
func (fs *defaultFileSystem) StatFs(name string) *fuse.StatfsOut {
return nil
}

167
vendor/github.com/hanwen/go-fuse/fuse/pathfs/locking.go generated vendored Normal file
View file

@ -0,0 +1,167 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"sync"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
type lockingFileSystem struct {
// Should be public so people reusing can access the wrapped
// FS.
FS FileSystem
lock sync.Mutex
}
// NewLockingFileSystem is a wrapper that makes a FileSystem
// threadsafe by serializing each operation.
func NewLockingFileSystem(pfs FileSystem) FileSystem {
l := new(lockingFileSystem)
l.FS = pfs
return l
}
func (fs *lockingFileSystem) String() string {
defer fs.locked()()
return fs.FS.String()
}
func (fs *lockingFileSystem) SetDebug(debug bool) {
defer fs.locked()()
fs.FS.SetDebug(debug)
}
func (fs *lockingFileSystem) StatFs(name string) *fuse.StatfsOut {
defer fs.locked()()
return fs.FS.StatFs(name)
}
func (fs *lockingFileSystem) locked() func() {
fs.lock.Lock()
return func() { fs.lock.Unlock() }
}
func (fs *lockingFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
defer fs.locked()()
return fs.FS.GetAttr(name, context)
}
func (fs *lockingFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
defer fs.locked()()
return fs.FS.Readlink(name, context)
}
func (fs *lockingFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
defer fs.locked()()
return fs.FS.Mknod(name, mode, dev, context)
}
func (fs *lockingFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
defer fs.locked()()
return fs.FS.Mkdir(name, mode, context)
}
func (fs *lockingFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Unlink(name, context)
}
func (fs *lockingFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Rmdir(name, context)
}
func (fs *lockingFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Symlink(value, linkName, context)
}
func (fs *lockingFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Rename(oldName, newName, context)
}
func (fs *lockingFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Link(oldName, newName, context)
}
func (fs *lockingFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Chmod(name, mode, context)
}
func (fs *lockingFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Chown(name, uid, gid, context)
}
func (fs *lockingFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Truncate(name, offset, context)
}
func (fs *lockingFileSystem) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
file, code = fs.FS.Open(name, flags, context)
file = nodefs.NewLockingFile(&fs.lock, file)
return
}
func (fs *lockingFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
defer fs.locked()()
return fs.FS.OpenDir(name, context)
}
func (fs *lockingFileSystem) OnMount(nodeFs *PathNodeFs) {
defer fs.locked()()
fs.FS.OnMount(nodeFs)
}
func (fs *lockingFileSystem) OnUnmount() {
defer fs.locked()()
fs.FS.OnUnmount()
}
func (fs *lockingFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Access(name, mode, context)
}
func (fs *lockingFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
defer fs.locked()()
file, code = fs.FS.Create(name, flags, mode, context)
file = nodefs.NewLockingFile(&fs.lock, file)
return file, code
}
func (fs *lockingFileSystem) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
defer fs.locked()()
return fs.FS.Utimens(name, Atime, Mtime, context)
}
func (fs *lockingFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
defer fs.locked()()
return fs.FS.GetXAttr(name, attr, context)
}
func (fs *lockingFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
defer fs.locked()()
return fs.FS.SetXAttr(name, attr, data, flags, context)
}
func (fs *lockingFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
defer fs.locked()()
return fs.FS.ListXAttr(name, context)
}
func (fs *lockingFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
defer fs.locked()()
return fs.FS.RemoveXAttr(name, attr, context)
}

View file

@ -0,0 +1,183 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"io"
"log"
"os"
"path/filepath"
"syscall"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
type loopbackFileSystem struct {
// TODO - this should need default fill in.
FileSystem
Root string
}
// A FUSE filesystem that shunts all request to an underlying file
// system. Its main purpose is to provide test coverage without
// having to build a synthetic filesystem.
func NewLoopbackFileSystem(root string) FileSystem {
// Make sure the Root path is absolute to avoid problems when the
// application changes working directory.
root, err := filepath.Abs(root)
if err != nil {
panic(err)
}
return &loopbackFileSystem{
FileSystem: NewDefaultFileSystem(),
Root: root,
}
}
func (fs *loopbackFileSystem) StatFs(name string) *fuse.StatfsOut {
s := syscall.Statfs_t{}
err := syscall.Statfs(fs.GetPath(name), &s)
if err == nil {
out := &fuse.StatfsOut{}
out.FromStatfsT(&s)
return out
}
return nil
}
func (fs *loopbackFileSystem) OnMount(nodeFs *PathNodeFs) {
}
func (fs *loopbackFileSystem) OnUnmount() {}
func (fs *loopbackFileSystem) GetPath(relPath string) string {
return filepath.Join(fs.Root, relPath)
}
func (fs *loopbackFileSystem) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, code fuse.Status) {
fullPath := fs.GetPath(name)
var err error = nil
st := syscall.Stat_t{}
if name == "" {
// When GetAttr is called for the toplevel directory, we always want
// to look through symlinks.
err = syscall.Stat(fullPath, &st)
} else {
err = syscall.Lstat(fullPath, &st)
}
if err != nil {
return nil, fuse.ToStatus(err)
}
a = &fuse.Attr{}
a.FromStat(&st)
return a, fuse.OK
}
func (fs *loopbackFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
// What other ways beyond O_RDONLY are there to open
// directories?
f, err := os.Open(fs.GetPath(name))
if err != nil {
return nil, fuse.ToStatus(err)
}
want := 500
output := make([]fuse.DirEntry, 0, want)
for {
infos, err := f.Readdir(want)
for i := range infos {
// workaround forhttps://code.google.com/p/go/issues/detail?id=5960
if infos[i] == nil {
continue
}
n := infos[i].Name()
d := fuse.DirEntry{
Name: n,
}
if s := fuse.ToStatT(infos[i]); s != nil {
d.Mode = uint32(s.Mode)
} else {
log.Printf("ReadDir entry %q for %q has no stat info", n, name)
}
output = append(output, d)
}
if len(infos) < want || err == io.EOF {
break
}
if err != nil {
log.Println("Readdir() returned err:", err)
break
}
}
f.Close()
return output, fuse.OK
}
func (fs *loopbackFileSystem) Open(name string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
f, err := os.OpenFile(fs.GetPath(name), int(flags), 0)
if err != nil {
return nil, fuse.ToStatus(err)
}
return nodefs.NewLoopbackFile(f), fuse.OK
}
func (fs *loopbackFileSystem) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
err := os.Chmod(fs.GetPath(path), os.FileMode(mode))
return fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) Chown(path string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(os.Chown(fs.GetPath(path), int(uid), int(gid)))
}
func (fs *loopbackFileSystem) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(os.Truncate(fs.GetPath(path), int64(offset)))
}
func (fs *loopbackFileSystem) Readlink(name string, context *fuse.Context) (out string, code fuse.Status) {
f, err := os.Readlink(fs.GetPath(name))
return f, fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(syscall.Mknod(fs.GetPath(name), mode, int(dev)))
}
func (fs *loopbackFileSystem) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(os.Mkdir(fs.GetPath(path), os.FileMode(mode)))
}
// Don't use os.Remove, it removes twice (unlink followed by rmdir).
func (fs *loopbackFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(syscall.Unlink(fs.GetPath(name)))
}
func (fs *loopbackFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(syscall.Rmdir(fs.GetPath(name)))
}
func (fs *loopbackFileSystem) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(os.Symlink(pointedTo, fs.GetPath(linkName)))
}
func (fs *loopbackFileSystem) Rename(oldPath string, newPath string, context *fuse.Context) (codee fuse.Status) {
err := os.Rename(fs.GetPath(oldPath), fs.GetPath(newPath))
return fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(os.Link(fs.GetPath(orig), fs.GetPath(newName)))
}
func (fs *loopbackFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(syscall.Access(fs.GetPath(name), mode))
}
func (fs *loopbackFileSystem) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) {
f, err := os.OpenFile(fs.GetPath(path), int(flags)|os.O_CREATE, os.FileMode(mode))
return nodefs.NewLoopbackFile(f), fuse.ToStatus(err)
}

View file

@ -0,0 +1,47 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// timeToTimeval - Convert time.Time to syscall.Timeval
//
// Note: This does not use syscall.NsecToTimespec because
// that does not work properly for times before 1970,
// see https://github.com/golang/go/issues/12777
func timeToTimeval(t *time.Time) syscall.Timeval {
var tv syscall.Timeval
tv.Usec = int32(t.Nanosecond() / 1000)
tv.Sec = t.Unix()
return tv
}
// OSX does not have the utimensat syscall neded to implement this properly.
// We do our best to emulate it using futimes.
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) fuse.Status {
tv := make([]syscall.Timeval, 2)
if a == nil {
tv[0].Usec = _UTIME_OMIT
} else {
tv[0] = timeToTimeval(a)
}
if m == nil {
tv[1].Usec = _UTIME_OMIT
} else {
tv[1] = timeToTimeval(m)
}
err := syscall.Utimes(fs.GetPath(path), tv)
return fuse.ToStatus(err)
}

View file

@ -0,0 +1,49 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"fmt"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
func (fs *loopbackFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
data, err := listXAttr(fs.GetPath(name))
return data, fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
err := sysRemovexattr(fs.GetPath(name), attr)
return fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) String() string {
return fmt.Sprintf("LoopbackFs(%s)", fs.Root)
}
func (fs *loopbackFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
data := make([]byte, 1024)
data, err := getXAttr(fs.GetPath(name), attr, data)
return data, fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
err := syscall.Setxattr(fs.GetPath(name), attr, data, flags)
return fuse.ToStatus(err)
}
// Utimens - path based version of loopbackFile.Utimens()
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) {
var ts [2]syscall.Timespec
ts[0] = fuse.UtimeToTimespec(a)
ts[1] = fuse.UtimeToTimespec(m)
err := sysUtimensat(0, fs.GetPath(path), &ts, _AT_SYMLINK_NOFOLLOW)
return fuse.ToStatus(err)
}

741
vendor/github.com/hanwen/go-fuse/fuse/pathfs/pathfs.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"fmt"
"path/filepath"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
// PrefixFileSystem adds a path prefix to incoming calls.
type prefixFileSystem struct {
FileSystem FileSystem
Prefix string
}
func NewPrefixFileSystem(fs FileSystem, prefix string) FileSystem {
return &prefixFileSystem{fs, prefix}
}
func (fs *prefixFileSystem) SetDebug(debug bool) {
fs.FileSystem.SetDebug(debug)
}
func (fs *prefixFileSystem) prefixed(n string) string {
return filepath.Join(fs.Prefix, n)
}
func (fs *prefixFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
return fs.FileSystem.GetAttr(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
return fs.FileSystem.Readlink(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
return fs.FileSystem.Mknod(fs.prefixed(name), mode, dev, context)
}
func (fs *prefixFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
return fs.FileSystem.Mkdir(fs.prefixed(name), mode, context)
}
func (fs *prefixFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Unlink(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Rmdir(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Symlink(value, fs.prefixed(linkName), context)
}
func (fs *prefixFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Rename(fs.prefixed(oldName), fs.prefixed(newName), context)
}
func (fs *prefixFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Link(fs.prefixed(oldName), fs.prefixed(newName), context)
}
func (fs *prefixFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Chmod(fs.prefixed(name), mode, context)
}
func (fs *prefixFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Chown(fs.prefixed(name), uid, gid, context)
}
func (fs *prefixFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Truncate(fs.prefixed(name), offset, context)
}
func (fs *prefixFileSystem) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return fs.FileSystem.Open(fs.prefixed(name), flags, context)
}
func (fs *prefixFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
return fs.FileSystem.OpenDir(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) OnMount(nodeFs *PathNodeFs) {
fs.FileSystem.OnMount(nodeFs)
}
func (fs *prefixFileSystem) OnUnmount() {
fs.FileSystem.OnUnmount()
}
func (fs *prefixFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Access(fs.prefixed(name), mode, context)
}
func (fs *prefixFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return fs.FileSystem.Create(fs.prefixed(name), flags, mode, context)
}
func (fs *prefixFileSystem) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Utimens(fs.prefixed(name), Atime, Mtime, context)
}
func (fs *prefixFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
return fs.FileSystem.GetXAttr(fs.prefixed(name), attr, context)
}
func (fs *prefixFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
return fs.FileSystem.SetXAttr(fs.prefixed(name), attr, data, flags, context)
}
func (fs *prefixFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
return fs.FileSystem.ListXAttr(fs.prefixed(name), context)
}
func (fs *prefixFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
return fs.FileSystem.RemoveXAttr(fs.prefixed(name), attr, context)
}
func (fs *prefixFileSystem) String() string {
return fmt.Sprintf("prefixFileSystem(%s,%s)", fs.FileSystem.String(), fs.Prefix)
}
func (fs *prefixFileSystem) StatFs(name string) *fuse.StatfsOut {
return fs.FileSystem.StatFs(fs.prefixed(name))
}

View file

@ -0,0 +1,123 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"fmt"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
// NewReadonlyFileSystem returns a wrapper that only exposes read-only
// operations.
func NewReadonlyFileSystem(fs FileSystem) FileSystem {
return &readonlyFileSystem{fs}
}
type readonlyFileSystem struct {
FileSystem
}
func (fs *readonlyFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
return fs.FileSystem.GetAttr(name, context)
}
func (fs *readonlyFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
return fs.FileSystem.Readlink(name, context)
}
func (fs *readonlyFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
if flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM
}
file, code = fs.FileSystem.Open(name, flags, context)
return nodefs.NewReadOnlyFile(file), code
}
func (fs *readonlyFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
return fs.FileSystem.OpenDir(name, context)
}
func (fs *readonlyFileSystem) OnMount(nodeFs *PathNodeFs) {
fs.FileSystem.OnMount(nodeFs)
}
func (fs *readonlyFileSystem) OnUnmount() {
fs.FileSystem.OnUnmount()
}
func (fs *readonlyFileSystem) String() string {
return fmt.Sprintf("readonlyFileSystem(%v)", fs.FileSystem)
}
func (fs *readonlyFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
return fs.FileSystem.Access(name, mode, context)
}
func (fs *readonlyFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
return nil, fuse.EPERM
}
func (fs *readonlyFileSystem) Utimens(name string, atime *time.Time, ctime *time.Time, context *fuse.Context) (code fuse.Status) {
return fuse.EPERM
}
func (fs *readonlyFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
return fs.FileSystem.GetXAttr(name, attr, context)
}
func (fs *readonlyFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
return fuse.EPERM
}
func (fs *readonlyFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
return fs.FileSystem.ListXAttr(name, context)
}
func (fs *readonlyFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
return fuse.EPERM
}

View file

@ -0,0 +1,144 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pathfs
import (
"bytes"
"syscall"
"unsafe"
)
var _zero uintptr
func getXAttr(path string, attr string, dest []byte) (value []byte, err error) {
sz, err := sysGetxattr(path, attr, dest)
for sz > cap(dest) && err == nil {
dest = make([]byte, sz)
sz, err = sysGetxattr(path, attr, dest)
}
if err != nil {
return nil, err
}
return dest[:sz], err
}
func listXAttr(path string) (attributes []string, err error) {
dest := make([]byte, 0)
sz, err := sysListxattr(path, dest)
if err != nil {
return nil, err
}
for sz > cap(dest) && err == nil {
dest = make([]byte, sz)
sz, err = sysListxattr(path, dest)
}
if sz == 0 {
return nil, err
}
// -1 to drop the final empty slice.
dest = dest[:sz-1]
attributesBytes := bytes.Split(dest, []byte{0})
attributes = make([]string, len(attributesBytes))
for i, v := range attributesBytes {
attributes[i] = string(v)
}
return attributes, err
}
// Below is cut & paste from std lib syscall, so gccgo 4.8.1 can
// compile this too.
func sysGetxattr(path string, attr string, dest []byte) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
var _p2 unsafe.Pointer
if len(dest) > 0 {
_p2 = unsafe.Pointer(&dest[0])
} else {
_p2 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
sz = int(r0)
if e1 != 0 {
err = e1
}
return
}
func sysRemovexattr(path string, attr string) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 *byte
_p1, err = syscall.BytePtrFromString(attr)
if err != nil {
return
}
_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
if e1 != 0 {
err = e1
}
return
}
func sysListxattr(path string, dest []byte) (sz int, err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(dest) > 0 {
_p1 = unsafe.Pointer(&dest[0])
} else {
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall.Syscall(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
sz = int(r0)
if e1 != 0 {
err = e1
}
return
}
func sysSetxattr(path string, attr string, val []byte, flag int) error {
return syscall.Setxattr(path, attr, val, flag)
}
const _AT_SYMLINK_NOFOLLOW = 0x100
// Linux kernel syscall utimensat(2)
//
// Needed to implement SetAttr on symlinks correctly as only utimensat provides
// AT_SYMLINK_NOFOLLOW.
func sysUtimensat(dirfd int, pathname string, times *[2]syscall.Timespec, flags int) (err error) {
// Null-terminated version of pathname
p0, err := syscall.BytePtrFromString(pathname)
if err != nil {
return err
}
_, _, e1 := syscall.Syscall6(syscall.SYS_UTIMENSAT,
uintptr(dirfd), uintptr(unsafe.Pointer(p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
if e1 != 0 {
err = syscall.Errno(e1)
}
return
}

250
vendor/github.com/hanwen/go-fuse/fuse/print.go generated vendored Normal file
View file

@ -0,0 +1,250 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
"os"
"strings"
"syscall"
)
var initFlagNames map[int64]string
var releaseFlagNames map[int64]string
var OpenFlagNames map[int64]string
var FuseOpenFlagNames map[int64]string
var accessFlagName map[int64]string
var writeFlagNames map[int64]string
var readFlagNames map[int64]string
func init() {
writeFlagNames = map[int64]string{
WRITE_CACHE: "CACHE",
WRITE_LOCKOWNER: "LOCKOWNER",
}
readFlagNames = map[int64]string{
READ_LOCKOWNER: "LOCKOWNER",
}
initFlagNames = map[int64]string{
CAP_ASYNC_READ: "ASYNC_READ",
CAP_POSIX_LOCKS: "POSIX_LOCKS",
CAP_FILE_OPS: "FILE_OPS",
CAP_ATOMIC_O_TRUNC: "ATOMIC_O_TRUNC",
CAP_EXPORT_SUPPORT: "EXPORT_SUPPORT",
CAP_BIG_WRITES: "BIG_WRITES",
CAP_DONT_MASK: "DONT_MASK",
CAP_SPLICE_WRITE: "SPLICE_WRITE",
CAP_SPLICE_MOVE: "SPLICE_MOVE",
CAP_SPLICE_READ: "SPLICE_READ",
CAP_FLOCK_LOCKS: "FLOCK_LOCKS",
CAP_IOCTL_DIR: "IOCTL_DIR",
CAP_AUTO_INVAL_DATA: "AUTO_INVAL_DATA",
CAP_READDIRPLUS: "READDIRPLUS",
CAP_READDIRPLUS_AUTO: "READDIRPLUS_AUTO",
CAP_ASYNC_DIO: "ASYNC_DIO",
CAP_WRITEBACK_CACHE: "WRITEBACK_CACHE",
CAP_NO_OPEN_SUPPORT: "NO_OPEN_SUPPORT",
}
releaseFlagNames = map[int64]string{
RELEASE_FLUSH: "FLUSH",
}
OpenFlagNames = map[int64]string{
int64(os.O_WRONLY): "WRONLY",
int64(os.O_RDWR): "RDWR",
int64(os.O_APPEND): "APPEND",
int64(syscall.O_ASYNC): "ASYNC",
int64(os.O_CREATE): "CREAT",
int64(os.O_EXCL): "EXCL",
int64(syscall.O_NOCTTY): "NOCTTY",
int64(syscall.O_NONBLOCK): "NONBLOCK",
int64(os.O_SYNC): "SYNC",
int64(os.O_TRUNC): "TRUNC",
int64(syscall.O_CLOEXEC): "CLOEXEC",
int64(syscall.O_DIRECTORY): "DIRECTORY",
}
FuseOpenFlagNames = map[int64]string{
FOPEN_DIRECT_IO: "DIRECT",
FOPEN_KEEP_CACHE: "CACHE",
FOPEN_NONSEEKABLE: "NONSEEK",
}
accessFlagName = map[int64]string{
X_OK: "x",
W_OK: "w",
R_OK: "r",
}
}
func FlagString(names map[int64]string, fl int64, def string) string {
s := []string{}
for k, v := range names {
if fl&k != 0 {
s = append(s, v)
fl ^= k
}
}
if len(s) == 0 && def != "" {
s = []string{def}
}
if fl != 0 {
s = append(s, fmt.Sprintf("0x%x", fl))
}
return strings.Join(s, ",")
}
func (me *ForgetIn) string() string {
return fmt.Sprintf("{Nlookup=%d}", me.Nlookup)
}
func (me *_BatchForgetIn) string() string {
return fmt.Sprintf("{Count=%d}", me.Count)
}
func (me *MkdirIn) string() string {
return fmt.Sprintf("{0%o (0%o)}", me.Mode, me.Umask)
}
func (me *RenameIn) string() string {
return fmt.Sprintf("{%d}", me.Newdir)
}
func (me *SetAttrIn) string() string {
s := []string{}
if me.Valid&FATTR_MODE != 0 {
s = append(s, fmt.Sprintf("mode 0%o", me.Mode))
}
if me.Valid&FATTR_UID != 0 {
s = append(s, fmt.Sprintf("uid %d", me.Uid))
}
if me.Valid&FATTR_GID != 0 {
s = append(s, fmt.Sprintf("uid %d", me.Gid))
}
if me.Valid&FATTR_SIZE != 0 {
s = append(s, fmt.Sprintf("size %d", me.Size))
}
if me.Valid&FATTR_ATIME != 0 {
s = append(s, fmt.Sprintf("atime %d.%09d", me.Atime, me.Atimensec))
}
if me.Valid&FATTR_MTIME != 0 {
s = append(s, fmt.Sprintf("mtime %d.%09d", me.Mtime, me.Mtimensec))
}
if me.Valid&FATTR_FH != 0 {
s = append(s, fmt.Sprintf("fh %d", me.Fh))
}
// TODO - FATTR_ATIME_NOW = (1 << 7), FATTR_MTIME_NOW = (1 << 8), FATTR_LOCKOWNER = (1 << 9)
return fmt.Sprintf("{%s}", strings.Join(s, ", "))
}
func (me *ReleaseIn) string() string {
return fmt.Sprintf("{Fh %d %s %s L%d}",
me.Fh, FlagString(OpenFlagNames, int64(me.Flags), ""),
FlagString(releaseFlagNames, int64(me.ReleaseFlags), ""),
me.LockOwner)
}
func (me *OpenIn) string() string {
return fmt.Sprintf("{%s}", FlagString(OpenFlagNames, int64(me.Flags), "O_RDONLY"))
}
func (me *OpenOut) string() string {
return fmt.Sprintf("{Fh %d %s}", me.Fh,
FlagString(FuseOpenFlagNames, int64(me.OpenFlags), ""))
}
func (me *InitIn) string() string {
return fmt.Sprintf("{%d.%d Ra 0x%x %s}",
me.Major, me.Minor, me.MaxReadAhead,
FlagString(initFlagNames, int64(me.Flags), ""))
}
func (me *InitOut) string() string {
return fmt.Sprintf("{%d.%d Ra 0x%x %s %d/%d Wr 0x%x Tg 0x%x}",
me.Major, me.Minor, me.MaxReadAhead,
FlagString(initFlagNames, int64(me.Flags), ""),
me.CongestionThreshold, me.MaxBackground, me.MaxWrite,
me.TimeGran)
}
func (s *FsyncIn) string() string {
return fmt.Sprintf("{Fh %d Flags %x}", s.Fh, s.FsyncFlags)
}
func (me *SetXAttrIn) string() string {
return fmt.Sprintf("{sz %d f%o}", me.Size, me.Flags)
}
func (me *GetXAttrIn) string() string {
return fmt.Sprintf("{sz %d}", me.Size)
}
func (me *GetXAttrOut) string() string {
return fmt.Sprintf("{sz %d}", me.Size)
}
func (me *AccessIn) string() string {
return fmt.Sprintf("{%s}", FlagString(accessFlagName, int64(me.Mask), ""))
}
func (me *FlushIn) string() string {
return fmt.Sprintf("{Fh %d}", me.Fh)
}
func (me *AttrOut) string() string {
return fmt.Sprintf(
"{A%d.%09d %v}",
me.AttrValid, me.AttrValidNsec, &me.Attr)
}
// Returned by LOOKUP
func (me *EntryOut) string() string {
return fmt.Sprintf("{NodeId: %d Generation=%d EntryValid=%d.%03d AttrValid=%d.%03d Attr=%v}",
me.NodeId, me.Generation, me.EntryValid, me.EntryValidNsec/1000000,
me.AttrValid, me.AttrValidNsec/1000000, &me.Attr)
}
func (me *CreateOut) string() string {
return fmt.Sprintf("{NodeId: %d Generation=%d %v %v}", me.NodeId, me.Generation, &me.EntryOut, &me.OpenOut)
}
func (me *StatfsOut) string() string {
return fmt.Sprintf(
"{blocks (%d,%d)/%d files %d/%d bs%d nl%d frs%d}",
me.Bfree, me.Bavail, me.Blocks, me.Ffree, me.Files,
me.Bsize, me.NameLen, me.Frsize)
}
func (o *NotifyInvalEntryOut) string() string {
return fmt.Sprintf("{parent %d sz %d}", o.Parent, o.NameLen)
}
func (o *NotifyInvalInodeOut) string() string {
return fmt.Sprintf("{ino %d off %d sz %d}", o.Ino, o.Off, o.Length)
}
func (o *NotifyInvalDeleteOut) string() string {
return fmt.Sprintf("{parent %d ch %d sz %d}", o.Parent, o.Child, o.NameLen)
}
func (f *FallocateIn) string() string {
return fmt.Sprintf("{Fh %d off %d sz %d mod 0%o}",
f.Fh, f.Offset, f.Length, f.Mode)
}
func (f *LinkIn) string() string {
return fmt.Sprintf("{Oldnodeid: %d}", f.Oldnodeid)
}
// Print pretty prints FUSE data types for kernel communication
func Print(obj interface{}) string {
t, ok := obj.(interface {
string() string
})
if ok {
return t.string()
}
return fmt.Sprintf("%T: %v", obj, obj)
}

54
vendor/github.com/hanwen/go-fuse/fuse/print_darwin.go generated vendored Normal file
View file

@ -0,0 +1,54 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
)
func init() {
initFlagNames[CAP_XTIMES] = "XTIMES"
initFlagNames[CAP_VOL_RENAME] = "VOL_RENAME"
initFlagNames[CAP_CASE_INSENSITIVE] = "CASE_INSENSITIVE"
}
func (a *Attr) string() string {
return fmt.Sprintf(
"{M0%o SZ=%d L=%d "+
"%d:%d "+
"%d %d:%d "+
"A %d.%09d "+
"M %d.%09d "+
"C %d.%09d}",
a.Mode, a.Size, a.Nlink,
a.Uid, a.Gid,
a.Blocks,
a.Rdev, a.Ino, a.Atime, a.Atimensec, a.Mtime, a.Mtimensec,
a.Ctime, a.Ctimensec)
}
func (me *CreateIn) string() string {
return fmt.Sprintf(
"{0%o [%s]}", me.Mode,
FlagString(OpenFlagNames, int64(me.Flags), "O_RDONLY"))
}
func (me *GetAttrIn) string() string { return "" }
func (me *MknodIn) string() string {
return fmt.Sprintf("{0%o, %d}", me.Mode, me.Rdev)
}
func (me *ReadIn) string() string {
return fmt.Sprintf("{Fh %d off %d sz %d %s}",
me.Fh, me.Offset, me.Size,
FlagString(readFlagNames, int64(me.ReadFlags), ""))
}
func (me *WriteIn) string() string {
return fmt.Sprintf("{Fh %d off %d sz %d %s}",
me.Fh, me.Offset, me.Size,
FlagString(writeFlagNames, int64(me.WriteFlags), ""))
}

62
vendor/github.com/hanwen/go-fuse/fuse/print_linux.go generated vendored Normal file
View file

@ -0,0 +1,62 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
"syscall"
)
func init() {
OpenFlagNames[syscall.O_DIRECT] = "DIRECT"
OpenFlagNames[syscall.O_LARGEFILE] = "LARGEFILE"
OpenFlagNames[syscall_O_NOATIME] = "NOATIME"
}
func (a *Attr) string() string {
return fmt.Sprintf(
"{M0%o SZ=%d L=%d "+
"%d:%d "+
"B%d*%d i%d:%d "+
"A %d.%09d "+
"M %d.%09d "+
"C %d.%09d}",
a.Mode, a.Size, a.Nlink,
a.Uid, a.Gid,
a.Blocks, a.Blksize,
a.Rdev, a.Ino, a.Atime, a.Atimensec, a.Mtime, a.Mtimensec,
a.Ctime, a.Ctimensec)
}
func (me *CreateIn) string() string {
return fmt.Sprintf(
"{0%o [%s] (0%o)}", me.Mode,
FlagString(OpenFlagNames, int64(me.Flags), "O_RDONLY"), me.Umask)
}
func (me *GetAttrIn) string() string {
return fmt.Sprintf("{Fh %d}", me.Fh_)
}
func (me *MknodIn) string() string {
return fmt.Sprintf("{0%o (0%o), %d}", me.Mode, me.Umask, me.Rdev)
}
func (me *ReadIn) string() string {
return fmt.Sprintf("{Fh %d off %d sz %d %s L %d %s}",
me.Fh, me.Offset, me.Size,
FlagString(readFlagNames, int64(me.ReadFlags), ""),
me.LockOwner,
FlagString(OpenFlagNames, int64(me.Flags), "RDONLY"))
}
func (me *WriteIn) string() string {
return fmt.Sprintf("{Fh %d off %d sz %d %s L %d %s}",
me.Fh, me.Offset, me.Size,
FlagString(writeFlagNames, int64(me.WriteFlags), ""),
me.LockOwner,
FlagString(OpenFlagNames, int64(me.Flags), "RDONLY"))
}

75
vendor/github.com/hanwen/go-fuse/fuse/read.go generated vendored Normal file
View file

@ -0,0 +1,75 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"io"
"syscall"
)
// ReadResultData is the read return for returning bytes directly.
type readResultData struct {
// Raw bytes for the read.
Data []byte
}
func (r *readResultData) Size() int {
return len(r.Data)
}
func (r *readResultData) Done() {
}
func (r *readResultData) Bytes(buf []byte) ([]byte, Status) {
return r.Data, OK
}
func ReadResultData(b []byte) ReadResult {
return &readResultData{b}
}
func ReadResultFd(fd uintptr, off int64, sz int) ReadResult {
return &readResultFd{fd, off, sz}
}
// ReadResultFd is the read return for zero-copy file data.
type readResultFd struct {
// Splice from the following file.
Fd uintptr
// Offset within Fd, or -1 to use current offset.
Off int64
// Size of data to be loaded. Actual data available may be
// less at the EOF.
Sz int
}
// Reads raw bytes from file descriptor if necessary, using the passed
// buffer as storage.
func (r *readResultFd) Bytes(buf []byte) ([]byte, Status) {
sz := r.Sz
if len(buf) < sz {
sz = len(buf)
}
n, err := syscall.Pread(int(r.Fd), buf[:sz], r.Off)
if err == io.EOF {
err = nil
}
if n < 0 {
n = 0
}
return buf[:n], ToStatus(err)
}
func (r *readResultFd) Size() int {
return r.Sz
}
func (r *readResultFd) Done() {
}

217
vendor/github.com/hanwen/go-fuse/fuse/request.go generated vendored Normal file
View file

@ -0,0 +1,217 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"bytes"
"fmt"
"log"
"strings"
"time"
"unsafe"
)
var sizeOfOutHeader = unsafe.Sizeof(OutHeader{})
var zeroOutBuf [outputHeaderSize]byte
type request struct {
inputBuf []byte
// These split up inputBuf.
inHeader *InHeader // generic header
inData unsafe.Pointer // per op data
arg []byte // flat data.
filenames []string // filename arguments
// Unstructured data, a pointer to the relevant XxxxOut struct.
outData unsafe.Pointer
status Status
flatData []byte
fdData *readResultFd
// In case of read, keep read result here so we can call
// Done() on it.
readResult ReadResult
// Start timestamp for timing info.
startTime time.Time
// All information pertaining to opcode of this request.
handler *operationHandler
// Request storage. For large inputs and outputs, use data
// obtained through bufferpool.
bufferPoolInputBuf []byte
bufferPoolOutputBuf []byte
// For small pieces of data, we use the following inlines
// arrays:
//
// Output header and structured data.
outBuf [outputHeaderSize]byte
// Input, if small enough to fit here.
smallInputBuf [128]byte
context Context
}
func (r *request) clear() {
r.inputBuf = nil
r.inHeader = nil
r.inData = nil
r.arg = nil
r.filenames = nil
r.outData = nil
r.status = OK
r.flatData = nil
r.fdData = nil
r.startTime = time.Time{}
r.handler = nil
r.readResult = nil
}
func (r *request) InputDebug() string {
val := " "
if r.handler.DecodeIn != nil {
val = fmt.Sprintf(" data: %v ", Print(r.handler.DecodeIn(r.inData)))
}
names := ""
if r.filenames != nil {
names = fmt.Sprintf("names: %v", r.filenames)
}
if len(r.arg) > 0 {
names += fmt.Sprintf(" %d bytes", len(r.arg))
}
return fmt.Sprintf("Dispatch %d: %s, NodeId: %v.%v%v",
r.inHeader.Unique, operationName(r.inHeader.Opcode),
r.inHeader.NodeId, val, names)
}
func (r *request) OutputDebug() string {
var dataStr string
if r.handler.DecodeOut != nil && r.outData != nil {
dataStr = Print(r.handler.DecodeOut(r.outData))
}
max := 1024
if len(dataStr) > max {
dataStr = dataStr[:max] + fmt.Sprintf(" ...trimmed")
}
flatStr := ""
if r.flatDataSize() > 0 {
if r.handler.FileNameOut {
s := strings.TrimRight(string(r.flatData), "\x00")
flatStr = fmt.Sprintf(" %q", s)
} else {
spl := ""
if r.fdData != nil {
spl = " (fd data)"
}
flatStr = fmt.Sprintf(" %d bytes data%s\n", r.flatDataSize(), spl)
}
}
return fmt.Sprintf("Serialize %d: %s code: %v value: %v%v",
r.inHeader.Unique, operationName(r.inHeader.Opcode), r.status,
dataStr, flatStr)
}
// setInput returns true if it takes ownership of the argument, false if not.
func (r *request) setInput(input []byte) bool {
if len(input) < len(r.smallInputBuf) {
copy(r.smallInputBuf[:], input)
r.inputBuf = r.smallInputBuf[:len(input)]
return false
}
r.inputBuf = input
r.bufferPoolInputBuf = input[:cap(input)]
return true
}
func (r *request) parse() {
inHSize := int(unsafe.Sizeof(InHeader{}))
if len(r.inputBuf) < inHSize {
log.Printf("Short read for input header: %v", r.inputBuf)
return
}
r.inHeader = (*InHeader)(unsafe.Pointer(&r.inputBuf[0]))
r.arg = r.inputBuf[:]
r.handler = getHandler(r.inHeader.Opcode)
if r.handler == nil {
log.Printf("Unknown opcode %d", r.inHeader.Opcode)
r.status = ENOSYS
return
}
if len(r.arg) < int(r.handler.InputSize) {
log.Printf("Short read for %v: %v", operationName(r.inHeader.Opcode), r.arg)
r.status = EIO
return
}
if r.handler.InputSize > 0 {
r.inData = unsafe.Pointer(&r.arg[0])
r.arg = r.arg[r.handler.InputSize:]
} else {
r.arg = r.arg[inHSize:]
}
count := r.handler.FileNames
if count > 0 {
if count == 1 {
r.filenames = []string{string(r.arg[:len(r.arg)-1])}
} else {
names := bytes.SplitN(r.arg[:len(r.arg)-1], []byte{0}, count)
r.filenames = make([]string, len(names))
for i, n := range names {
r.filenames[i] = string(n)
}
if len(names) != count {
log.Println("filename argument mismatch", names, count)
r.status = EIO
}
}
}
copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader],
zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader])
r.outData = unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
}
func (r *request) serializeHeader(dataSize int) (header []byte) {
dataLength := r.handler.OutputSize
if r.outData == nil || r.status > OK {
dataLength = 0
}
sizeOfOutHeader := unsafe.Sizeof(OutHeader{})
header = r.outBuf[:sizeOfOutHeader+dataLength]
o := (*OutHeader)(unsafe.Pointer(&header[0]))
o.Unique = r.inHeader.Unique
o.Status = int32(-r.status)
o.Length = uint32(
int(sizeOfOutHeader) + int(dataLength) + dataSize)
var asSlice []byte
toSlice(&asSlice, r.outData, dataLength)
copy(header[sizeOfOutHeader:], asSlice)
return header
}
func (r *request) flatDataSize() int {
if r.fdData != nil {
return r.fdData.Size()
}
return len(r.flatData)
}

View file

@ -0,0 +1,13 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
const outputHeaderSize = 200
const (
_FUSE_KERNEL_VERSION = 7
_MINIMUM_MINOR_VERSION = 8
_OUR_MINOR_VERSION = 8
)

13
vendor/github.com/hanwen/go-fuse/fuse/request_linux.go generated vendored Normal file
View file

@ -0,0 +1,13 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
const outputHeaderSize = 160
const (
_FUSE_KERNEL_VERSION = 7
_MINIMUM_MINOR_VERSION = 12
_OUR_MINOR_VERSION = 23
)

586
vendor/github.com/hanwen/go-fuse/fuse/server.go generated vendored Normal file

File diff suppressed because it is too large Load diff

32
vendor/github.com/hanwen/go-fuse/fuse/server_darwin.go generated vendored Normal file
View file

@ -0,0 +1,32 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 {
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err)
}
if req.fdData != nil {
sz := req.flatDataSize()
buf := ms.allocOut(req, uint32(sz))
req.flatData, req.status = req.fdData.Bytes(buf)
header = req.serializeHeader(len(req.flatData))
}
_, err := writev(int(ms.mountFd), [][]byte{header, req.flatData})
if req.readResult != nil {
req.readResult.Done()
}
return ToStatus(err)
}

42
vendor/github.com/hanwen/go-fuse/fuse/server_linux.go generated vendored Normal file
View file

@ -0,0 +1,42 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"log"
"syscall"
)
func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 {
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err)
}
if req.fdData != nil {
if ms.canSplice {
err := ms.trySplice(header, req, req.fdData)
if err == nil {
req.readResult.Done()
return OK
}
log.Println("trySplice:", err)
}
sz := req.flatDataSize()
buf := ms.allocOut(req, uint32(sz))
req.flatData, req.status = req.fdData.Bytes(buf)
header = req.serializeHeader(len(req.flatData))
}
_, err := writev(ms.mountFd, [][]byte{header, req.flatData})
if req.readResult != nil {
req.readResult.Done()
}
return ToStatus(err)
}

17
vendor/github.com/hanwen/go-fuse/fuse/splice_darwin.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
)
func (s *Server) setSplice() {
s.canSplice = false
}
func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) error {
return fmt.Errorf("unimplemented")
}

97
vendor/github.com/hanwen/go-fuse/fuse/splice_linux.go generated vendored Normal file
View file

@ -0,0 +1,97 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
"os"
"github.com/hanwen/go-fuse/splice"
)
func (s *Server) setSplice() {
s.canSplice = splice.Resizable()
}
// trySplice: Zero-copy read from fdData.Fd into /dev/fuse
//
// This is a four-step process:
//
// 1) Splice data form fdData.Fd into the "pair1" pipe buffer --> pair1: [payload]
// Now we know the actual payload length and can
// construct the reply header
// 2) Write header into the "pair2" pipe buffer --> pair2: [header]
// 4) Splice data from "pair1" into "pair2" --> pair2: [header][payload]
// 3) Splice the data from "pair2" into /dev/fuse
//
// This dance is neccessary because header and payload cannot be split across
// two splices and we cannot seek in a pipe buffer.
func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) error {
var err error
// Get a pair of connected pipes
pair1, err := splice.Get()
if err != nil {
return err
}
defer splice.Done(pair1)
// Grow buffer pipe to requested size + one extra page
// Without the extra page the kernel will block once the pipe is almost full
pair1Sz := fdData.Size() + os.Getpagesize()
if err := pair1.Grow(pair1Sz); err != nil {
return err
}
// Read data from file
payloadLen, err := pair1.LoadFromAt(fdData.Fd, fdData.Size(), fdData.Off)
if err != nil {
// TODO - extract the data from splice.
return err
}
// Get another pair of connected pipes
pair2, err := splice.Get()
if err != nil {
return err
}
defer splice.Done(pair2)
// Grow pipe to header + actually read size + one extra page
// Without the extra page the kernel will block once the pipe is almost full
header = req.serializeHeader(payloadLen)
total := len(header) + payloadLen
pair2Sz := total + os.Getpagesize()
if err := pair2.Grow(pair2Sz); err != nil {
return err
}
// Write header into pair2
n, err := pair2.Write(header)
if err != nil {
return err
}
if n != len(header) {
return fmt.Errorf("Short write into splice: wrote %d, want %d", n, len(header))
}
// Write data into pair2
n, err = pair2.LoadFrom(pair1.ReadFd(), payloadLen)
if err != nil {
return err
}
if n != payloadLen {
return fmt.Errorf("Short splice: wrote %d, want %d", n, payloadLen)
}
// Write header + data to /dev/fuse
_, err = pair2.WriteTo(uintptr(ms.mountFd), total)
if err != nil {
return err
}
return nil
}

139
vendor/github.com/hanwen/go-fuse/fuse/syscall_darwin.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"bytes"
"os"
"syscall"
"unsafe"
)
// TODO - move these into Go's syscall package.
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return
}
func writev(fd int, packet [][]byte) (n int, err error) {
iovecs := make([]syscall.Iovec, 0, len(packet))
for _, v := range packet {
if len(v) == 0 {
continue
}
vec := syscall.Iovec{
Base: &v[0],
}
vec.SetLen(len(v))
iovecs = append(iovecs, vec)
}
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}
func getxattr(path string, attr string, dest []byte) (sz int, errno int) {
pathBs := syscall.StringBytePtr(path)
attrBs := syscall.StringBytePtr(attr)
size, _, errNo := syscall.Syscall6(
syscall.SYS_GETXATTR,
uintptr(unsafe.Pointer(pathBs)),
uintptr(unsafe.Pointer(attrBs)),
uintptr(unsafe.Pointer(&dest[0])),
uintptr(len(dest)),
0, 0)
return int(size), int(errNo)
}
func GetXAttr(path string, attr string, dest []byte) (value []byte, errno int) {
sz, errno := getxattr(path, attr, dest)
for sz > cap(dest) && errno == 0 {
dest = make([]byte, sz)
sz, errno = getxattr(path, attr, dest)
}
if errno != 0 {
return nil, errno
}
return dest[:sz], errno
}
func listxattr(path string, dest []byte) (sz int, errno int) {
pathbs := syscall.StringBytePtr(path)
var destPointer unsafe.Pointer
if len(dest) > 0 {
destPointer = unsafe.Pointer(&dest[0])
}
size, _, errNo := syscall.Syscall(
syscall.SYS_LISTXATTR,
uintptr(unsafe.Pointer(pathbs)),
uintptr(destPointer),
uintptr(len(dest)))
return int(size), int(errNo)
}
func ListXAttr(path string) (attributes []string, errno int) {
dest := make([]byte, 0)
sz, errno := listxattr(path, dest)
if errno != 0 {
return nil, errno
}
for sz > cap(dest) && errno == 0 {
dest = make([]byte, sz)
sz, errno = listxattr(path, dest)
}
// -1 to drop the final empty slice.
dest = dest[:sz-1]
attributesBytes := bytes.Split(dest, []byte{0})
attributes = make([]string, len(attributesBytes))
for i, v := range attributesBytes {
attributes[i] = string(v)
}
return attributes, errno
}
func Setxattr(path string, attr string, data []byte, flags int) (errno int) {
pathbs := syscall.StringBytePtr(path)
attrbs := syscall.StringBytePtr(attr)
_, _, errNo := syscall.Syscall6(
syscall.SYS_SETXATTR,
uintptr(unsafe.Pointer(pathbs)),
uintptr(unsafe.Pointer(attrbs)),
uintptr(unsafe.Pointer(&data[0])),
uintptr(len(data)),
uintptr(flags), 0)
return int(errNo)
}
func Removexattr(path string, attr string) (errno int) {
pathbs := syscall.StringBytePtr(path)
attrbs := syscall.StringBytePtr(attr)
_, _, errNo := syscall.Syscall(
syscall.SYS_REMOVEXATTR,
uintptr(unsafe.Pointer(pathbs)),
uintptr(unsafe.Pointer(attrbs)), 0)
return int(errNo)
}

49
vendor/github.com/hanwen/go-fuse/fuse/syscall_linux.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"os"
"syscall"
"unsafe"
)
// TODO - move these into Go's syscall package.
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return n, err
}
func writev(fd int, packet [][]byte) (n int, err error) {
iovecs := make([]syscall.Iovec, 0, len(packet))
for _, v := range packet {
if len(v) == 0 {
continue
}
vec := syscall.Iovec{
Base: &v[0],
}
vec.SetLen(len(v))
iovecs = append(iovecs, vec)
}
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}

9
vendor/github.com/hanwen/go-fuse/fuse/typeprint.go generated vendored Normal file
View file

@ -0,0 +1,9 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
func (a *Attr) String() string {
return Print((*Attr)(a))
}

470
vendor/github.com/hanwen/go-fuse/fuse/types.go generated vendored Normal file
View file

@ -0,0 +1,470 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
const (
_DEFAULT_BACKGROUND_TASKS = 12
)
// Status is the errno number that a FUSE call returns to the kernel.
type Status int32
const (
OK = Status(0)
// EACCESS Permission denied
EACCES = Status(syscall.EACCES)
// EBUSY Device or resource busy
EBUSY = Status(syscall.EBUSY)
// EAGAIN Resource temporarily unavailable
EAGAIN = Status(syscall.EAGAIN)
// EINVAL Invalid argument
EINVAL = Status(syscall.EINVAL)
// EIO I/O error
EIO = Status(syscall.EIO)
// ENOENT No such file or directory
ENOENT = Status(syscall.ENOENT)
// ENOSYS Function not implemented
ENOSYS = Status(syscall.ENOSYS)
// ENODATA No data available
ENODATA = Status(syscall.ENODATA)
// ENOTDIR Not a directory
ENOTDIR = Status(syscall.ENOTDIR)
// EPERM Operation not permitted
EPERM = Status(syscall.EPERM)
// ERANGE Math result not representable
ERANGE = Status(syscall.ERANGE)
// EXDEV Cross-device link
EXDEV = Status(syscall.EXDEV)
// EBADF Bad file number
EBADF = Status(syscall.EBADF)
// ENODEV No such device
ENODEV = Status(syscall.ENODEV)
// EROFS Read-only file system
EROFS = Status(syscall.EROFS)
)
type ForgetIn struct {
InHeader
Nlookup uint64
}
// batch forget is handled internally.
type _ForgetOne struct {
NodeId uint64
Nlookup uint64
}
// batch forget is handled internally.
type _BatchForgetIn struct {
InHeader
Count uint32
Dummy uint32
}
type MkdirIn struct {
InHeader
Mode uint32
Umask uint32
}
type RenameIn struct {
InHeader
Newdir uint64
}
type Rename2In struct {
InHeader
Newdir uint64
Flags uint32
Padding uint32
}
type LinkIn struct {
InHeader
Oldnodeid uint64
}
type Owner struct {
Uid uint32
Gid uint32
}
const ( // SetAttrIn.Valid
FATTR_MODE = (1 << 0)
FATTR_UID = (1 << 1)
FATTR_GID = (1 << 2)
FATTR_SIZE = (1 << 3)
FATTR_ATIME = (1 << 4)
FATTR_MTIME = (1 << 5)
FATTR_FH = (1 << 6)
FATTR_ATIME_NOW = (1 << 7)
FATTR_MTIME_NOW = (1 << 8)
FATTR_LOCKOWNER = (1 << 9)
FATTR_CTIME = (1 << 10)
)
type SetAttrInCommon struct {
InHeader
Valid uint32
Padding uint32
Fh uint64
Size uint64
LockOwner uint64
Atime uint64
Mtime uint64
Ctime uint64
Atimensec uint32
Mtimensec uint32
Ctimensec uint32
Mode uint32
Unused4 uint32
Owner
Unused5 uint32
}
const RELEASE_FLUSH = (1 << 0)
type ReleaseIn struct {
InHeader
Fh uint64
Flags uint32
ReleaseFlags uint32
LockOwner uint64
}
type OpenIn struct {
InHeader
Flags uint32
Mode uint32
}
const (
// OpenOut.Flags
FOPEN_DIRECT_IO = (1 << 0)
FOPEN_KEEP_CACHE = (1 << 1)
FOPEN_NONSEEKABLE = (1 << 2)
)
type OpenOut struct {
Fh uint64
OpenFlags uint32
Padding uint32
}
// To be set in InitIn/InitOut.Flags.
const (
CAP_ASYNC_READ = (1 << 0)
CAP_POSIX_LOCKS = (1 << 1)
CAP_FILE_OPS = (1 << 2)
CAP_ATOMIC_O_TRUNC = (1 << 3)
CAP_EXPORT_SUPPORT = (1 << 4)
CAP_BIG_WRITES = (1 << 5)
CAP_DONT_MASK = (1 << 6)
CAP_SPLICE_WRITE = (1 << 7)
CAP_SPLICE_MOVE = (1 << 8)
CAP_SPLICE_READ = (1 << 9)
CAP_FLOCK_LOCKS = (1 << 10)
CAP_IOCTL_DIR = (1 << 11)
CAP_AUTO_INVAL_DATA = (1 << 12)
CAP_READDIRPLUS = (1 << 13)
CAP_READDIRPLUS_AUTO = (1 << 14)
CAP_ASYNC_DIO = (1 << 15)
CAP_WRITEBACK_CACHE = (1 << 16)
CAP_NO_OPEN_SUPPORT = (1 << 17)
)
type InitIn struct {
InHeader
Major uint32
Minor uint32
MaxReadAhead uint32
Flags uint32
}
type InitOut struct {
Major uint32
Minor uint32
MaxReadAhead uint32
Flags uint32
MaxBackground uint16
CongestionThreshold uint16
MaxWrite uint32
TimeGran uint32
Unused [9]uint32
}
type _CuseInitIn struct {
InHeader
Major uint32
Minor uint32
Unused uint32
Flags uint32
}
type _CuseInitOut struct {
Major uint32
Minor uint32
Unused uint32
Flags uint32
MaxRead uint32
MaxWrite uint32
DevMajor uint32
DevMinor uint32
Spare [10]uint32
}
type InterruptIn struct {
InHeader
Unique uint64
}
type _BmapIn struct {
InHeader
Block uint64
Blocksize uint32
Padding uint32
}
type _BmapOut struct {
Block uint64
}
const (
FUSE_IOCTL_COMPAT = (1 << 0)
FUSE_IOCTL_UNRESTRICTED = (1 << 1)
FUSE_IOCTL_RETRY = (1 << 2)
)
type _IoctlIn struct {
InHeader
Fh uint64
Flags uint32
Cmd uint32
Arg uint64
InSize uint32
OutSize uint32
}
type _IoctlOut struct {
Result int32
Flags uint32
InIovs uint32
OutIovs uint32
}
type _PollIn struct {
InHeader
Fh uint64
Kh uint64
Flags uint32
Padding uint32
}
type _PollOut struct {
Revents uint32
Padding uint32
}
type _NotifyPollWakeupOut struct {
Kh uint64
}
type WriteOut struct {
Size uint32
Padding uint32
}
type GetXAttrOut struct {
Size uint32
Padding uint32
}
type _FileLock struct {
Start uint64
End uint64
Typ uint32
Pid uint32
}
type _LkIn struct {
InHeader
Fh uint64
Owner uint64
Lk _FileLock
LkFlags uint32
Padding uint32
}
type _LkOut struct {
Lk _FileLock
}
// For AccessIn.Mask.
const (
X_OK = 1
W_OK = 2
R_OK = 4
F_OK = 0
)
type AccessIn struct {
InHeader
Mask uint32
Padding uint32
}
type FsyncIn struct {
InHeader
Fh uint64
FsyncFlags uint32
Padding uint32
}
type OutHeader struct {
Length uint32
Status int32
Unique uint64
}
type NotifyInvalInodeOut struct {
Ino uint64
Off int64
Length int64
}
type NotifyInvalEntryOut struct {
Parent uint64
NameLen uint32
Padding uint32
}
type NotifyInvalDeleteOut struct {
Parent uint64
Child uint64
NameLen uint32
Padding uint32
}
const (
// NOTIFY_POLL = -1
NOTIFY_INVAL_INODE = -2
NOTIFY_INVAL_ENTRY = -3
// NOTIFY_STORE = -4
// NOTIFY_RETRIEVE = -5
NOTIFY_INVAL_DELETE = -6
// NOTIFY_CODE_MAX = -6
)
type FlushIn struct {
InHeader
Fh uint64
Unused uint32
Padding uint32
LockOwner uint64
}
type EntryOut struct {
NodeId uint64
Generation uint64
EntryValid uint64
AttrValid uint64
EntryValidNsec uint32
AttrValidNsec uint32
Attr
}
type AttrOut struct {
AttrValid uint64
AttrValidNsec uint32
Dummy uint32
Attr
}
type CreateOut struct {
EntryOut
OpenOut
}
type Context struct {
Owner
Pid uint32
}
type InHeader struct {
Length uint32
Opcode int32
Unique uint64
NodeId uint64
Context
Padding uint32
}
type StatfsOut struct {
Blocks uint64
Bfree uint64
Bavail uint64
Files uint64
Ffree uint64
Bsize uint32
NameLen uint32
Frsize uint32
Padding uint32
Spare [6]uint32
}
// _Dirent is what we send to the kernel, but we offer DirEntry and
// DirEntryList to the user.
type _Dirent struct {
Ino uint64
Off uint64
NameLen uint32
Typ uint32
}
const (
READ_LOCKOWNER = (1 << 1)
)
const (
WRITE_CACHE = (1 << 0)
WRITE_LOCKOWNER = (1 << 1)
)
type FallocateIn struct {
InHeader
Fh uint64
Offset uint64
Length uint64
Mode uint32
Padding uint32
}
type FlockIn struct {
InHeader
Fh uint64
}

153
vendor/github.com/hanwen/go-fuse/fuse/types_darwin.go generated vendored Normal file
View file

@ -0,0 +1,153 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
const (
ENOATTR = Status(syscall.ENOATTR) // ENOATTR is not defined for all GOOS.
)
type Attr struct {
Ino uint64
Size uint64
Blocks uint64
Atime uint64
Mtime uint64
Ctime uint64
Crtime_ uint64 // OS X
Atimensec uint32
Mtimensec uint32
Ctimensec uint32
Crtimensec_ uint32 // OS X
Mode uint32
Nlink uint32
Owner
Rdev uint32
Flags_ uint32 // OS X
}
const (
FATTR_CRTIME = (1 << 28)
FATTR_CHGTIME = (1 << 29)
FATTR_BKUPTIME = (1 << 30)
FATTR_FLAGS = (1 << 31)
)
type SetAttrIn struct {
SetAttrInCommon
// OS X only
Bkuptime_ uint64
Chgtime_ uint64
Crtime uint64
BkuptimeNsec uint32
ChgtimeNsec uint32
CrtimeNsec uint32
Flags_ uint32 // see chflags(2)
}
const (
FOPEN_PURGE_ATTR = (1 << 30)
FOPEN_PURGE_UBC = (1 << 31)
)
// compat with linux.
const (
// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
FUSE_GETATTR_FH = (1 << 0)
)
type GetAttrIn struct {
InHeader
}
func (g *GetAttrIn) Flags() uint32 {
return 0
}
func (g *GetAttrIn) Fh() uint64 {
return 0
}
// Uses OpenIn struct for create.
type CreateIn struct {
InHeader
Flags uint32
Mode uint32
}
type MknodIn struct {
InHeader
Mode uint32
Rdev uint32
}
type ReadIn struct {
InHeader
Fh uint64
Offset uint64
Size uint32
ReadFlags uint32
}
type WriteIn struct {
InHeader
Fh uint64
Offset uint64
Size uint32
WriteFlags uint32
}
type SetXAttrIn struct {
InHeader
Size uint32
Flags uint32
Position uint32
Padding uint32
}
type GetXAttrIn struct {
InHeader
Size uint32
Padding uint32
Position uint32
Padding2 uint32
}
const (
CAP_CASE_INSENSITIVE = (1 << 29)
CAP_VOL_RENAME = (1 << 30)
CAP_XTIMES = (1 << 31)
)
type GetxtimesOut struct {
Bkuptime uint64
Crtime uint64
Bkuptimensec uint32
Crtimensec uint32
}
type ExchangeIn struct {
InHeader
Olddir uint64
Newdir uint64
Options uint64
}
func (s *StatfsOut) FromStatfsT(statfs *syscall.Statfs_t) {
s.Blocks = statfs.Blocks
s.Bfree = statfs.Bfree
s.Bavail = statfs.Bavail
s.Files = statfs.Files
s.Ffree = statfs.Ffree
s.Bsize = uint32(statfs.Iosize) // Iosize translates to Bsize: the optimal transfer size.
s.Frsize = s.Bsize // Bsize translates to Frsize: the minimum transfer size.
}

121
vendor/github.com/hanwen/go-fuse/fuse/types_linux.go generated vendored Normal file
View file

@ -0,0 +1,121 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"syscall"
)
const (
ENOATTR = Status(syscall.ENODATA) // On Linux, ENOATTR is an alias for ENODATA.
)
type Attr struct {
Ino uint64
Size uint64
Blocks uint64
Atime uint64
Mtime uint64
Ctime uint64
Atimensec uint32
Mtimensec uint32
Ctimensec uint32
Mode uint32
Nlink uint32
Owner
Rdev uint32
Blksize uint32
Padding uint32
}
type SetAttrIn struct {
SetAttrInCommon
}
const (
// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
FUSE_GETATTR_FH = (1 << 0)
)
type GetAttrIn struct {
InHeader
Flags_ uint32
Dummy uint32
Fh_ uint64
}
// Flags accesses the flags. This is a method, because OSXFuse does not
// have GetAttrIn flags.
func (g *GetAttrIn) Flags() uint32 {
return g.Flags_
}
// Fh accesses the file handle. This is a method, because OSXFuse does not
// have GetAttrIn flags.
func (g *GetAttrIn) Fh() uint64 {
return g.Fh_
}
type CreateIn struct {
InHeader
Flags uint32
Mode uint32
Umask uint32
Pading uint32
}
type MknodIn struct {
InHeader
Mode uint32
Rdev uint32
Umask uint32
Padding uint32
}
type ReadIn struct {
InHeader
Fh uint64
Offset uint64
Size uint32
ReadFlags uint32
LockOwner uint64
Flags uint32
Padding uint32
}
type WriteIn struct {
InHeader
Fh uint64
Offset uint64
Size uint32
WriteFlags uint32
LockOwner uint64
Flags uint32
Padding uint32
}
type SetXAttrIn struct {
InHeader
Size uint32
Flags uint32
}
type GetXAttrIn struct {
InHeader
Size uint32
Padding uint32
}
func (s *StatfsOut) FromStatfsT(statfs *syscall.Statfs_t) {
s.Blocks = statfs.Blocks
s.Bsize = uint32(statfs.Bsize)
s.Bfree = statfs.Bfree
s.Bavail = statfs.Bavail
s.Files = statfs.Files
s.Ffree = statfs.Ffree
s.Frsize = uint32(statfs.Frsize)
s.NameLen = uint32(statfs.Namelen)
}

333
vendor/github.com/hanwen/go-fuse/fuse/upgrade.go generated vendored Normal file
View file

@ -0,0 +1,333 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"fmt"
)
// NewRawFileSystem adds the methods missing for implementing a
// RawFileSystem to any object.
func NewRawFileSystem(fs interface{}) RawFileSystem {
return &wrappingFS{fs}
}
type wrappingFS struct {
fs interface{}
}
func (fs *wrappingFS) Init(srv *Server) {
if s, ok := fs.fs.(interface {
Init(*Server)
}); ok {
s.Init(srv)
}
}
func (fs *wrappingFS) String() string {
return fmt.Sprintf("%v", fs.fs)
}
func (fs *wrappingFS) SetDebug(dbg bool) {
if s, ok := fs.fs.(interface {
SetDebug(bool)
}); ok {
s.SetDebug(dbg)
}
}
func (fs *wrappingFS) StatFs(header *InHeader, out *StatfsOut) Status {
if s, ok := fs.fs.(interface {
StatFs(header *InHeader, out *StatfsOut) Status
}); ok {
return s.StatFs(header, out)
}
return ENOSYS
}
func (fs *wrappingFS) Lookup(header *InHeader, name string, out *EntryOut) (code Status) {
if s, ok := fs.fs.(interface {
Lookup(header *InHeader, name string, out *EntryOut) (code Status)
}); ok {
return s.Lookup(header, name, out)
}
return ENOSYS
}
func (fs *wrappingFS) Forget(nodeID, nlookup uint64) {
if s, ok := fs.fs.(interface {
Forget(nodeID, nlookup uint64)
}); ok {
s.Forget(nodeID, nlookup)
}
}
func (fs *wrappingFS) GetAttr(input *GetAttrIn, out *AttrOut) (code Status) {
if s, ok := fs.fs.(interface {
GetAttr(input *GetAttrIn, out *AttrOut) (code Status)
}); ok {
return s.GetAttr(input, out)
}
return ENOSYS
}
func (fs *wrappingFS) Open(input *OpenIn, out *OpenOut) (status Status) {
if s, ok := fs.fs.(interface {
Open(input *OpenIn, out *OpenOut) (status Status)
}); ok {
return s.Open(input, out)
}
return ENOSYS
}
func (fs *wrappingFS) SetAttr(input *SetAttrIn, out *AttrOut) (code Status) {
if s, ok := fs.fs.(interface {
SetAttr(input *SetAttrIn, out *AttrOut) (code Status)
}); ok {
return s.SetAttr(input, out)
}
return ENOSYS
}
func (fs *wrappingFS) Readlink(header *InHeader) (out []byte, code Status) {
if s, ok := fs.fs.(interface {
Readlink(header *InHeader) (out []byte, code Status)
}); ok {
return s.Readlink(header)
}
return nil, ENOSYS
}
func (fs *wrappingFS) Mknod(input *MknodIn, name string, out *EntryOut) (code Status) {
if s, ok := fs.fs.(interface {
Mknod(input *MknodIn, name string, out *EntryOut) (code Status)
}); ok {
return s.Mknod(input, name, out)
}
return ENOSYS
}
func (fs *wrappingFS) Mkdir(input *MkdirIn, name string, out *EntryOut) (code Status) {
if s, ok := fs.fs.(interface {
Mkdir(input *MkdirIn, name string, out *EntryOut) (code Status)
}); ok {
return s.Mkdir(input, name, out)
}
return ENOSYS
}
func (fs *wrappingFS) Unlink(header *InHeader, name string) (code Status) {
if s, ok := fs.fs.(interface {
Unlink(header *InHeader, name string) (code Status)
}); ok {
return s.Unlink(header, name)
}
return ENOSYS
}
func (fs *wrappingFS) Rmdir(header *InHeader, name string) (code Status) {
if s, ok := fs.fs.(interface {
Rmdir(header *InHeader, name string) (code Status)
}); ok {
return s.Rmdir(header, name)
}
return ENOSYS
}
func (fs *wrappingFS) Symlink(header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status) {
if s, ok := fs.fs.(interface {
Symlink(header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status)
}); ok {
return s.Symlink(header, pointedTo, linkName, out)
}
return ENOSYS
}
func (fs *wrappingFS) Rename(input *RenameIn, oldName string, newName string) (code Status) {
if s, ok := fs.fs.(interface {
Rename(input *RenameIn, oldName string, newName string) (code Status)
}); ok {
return s.Rename(input, oldName, newName)
}
return ENOSYS
}
func (fs *wrappingFS) Link(input *LinkIn, name string, out *EntryOut) (code Status) {
if s, ok := fs.fs.(interface {
Link(input *LinkIn, name string, out *EntryOut) (code Status)
}); ok {
return s.Link(input, name, out)
}
return ENOSYS
}
func (fs *wrappingFS) GetXAttrSize(header *InHeader, attr string) (size int, code Status) {
if s, ok := fs.fs.(interface {
GetXAttrSize(header *InHeader, attr string) (size int, code Status)
}); ok {
return s.GetXAttrSize(header, attr)
}
return 0, ENOSYS
}
func (fs *wrappingFS) GetXAttrData(header *InHeader, attr string) (data []byte, code Status) {
if s, ok := fs.fs.(interface {
GetXAttrData(header *InHeader, attr string) (data []byte, code Status)
}); ok {
return s.GetXAttrData(header, attr)
}
return nil, ENOSYS
}
func (fs *wrappingFS) SetXAttr(input *SetXAttrIn, attr string, data []byte) Status {
if s, ok := fs.fs.(interface {
SetXAttr(input *SetXAttrIn, attr string, data []byte) Status
}); ok {
return s.SetXAttr(input, attr, data)
}
return ENOSYS
}
func (fs *wrappingFS) ListXAttr(header *InHeader) (data []byte, code Status) {
if s, ok := fs.fs.(interface {
ListXAttr(header *InHeader) (data []byte, code Status)
}); ok {
return s.ListXAttr(header)
}
return nil, ENOSYS
}
func (fs *wrappingFS) RemoveXAttr(header *InHeader, attr string) Status {
if s, ok := fs.fs.(interface {
RemoveXAttr(header *InHeader, attr string) Status
}); ok {
return s.RemoveXAttr(header, attr)
}
return ENOSYS
}
func (fs *wrappingFS) Access(input *AccessIn) (code Status) {
if s, ok := fs.fs.(interface {
Access(input *AccessIn) (code Status)
}); ok {
return s.Access(input)
}
return ENOSYS
}
func (fs *wrappingFS) Create(input *CreateIn, name string, out *CreateOut) (code Status) {
if s, ok := fs.fs.(interface {
Create(input *CreateIn, name string, out *CreateOut) (code Status)
}); ok {
return s.Create(input, name, out)
}
return ENOSYS
}
func (fs *wrappingFS) OpenDir(input *OpenIn, out *OpenOut) (status Status) {
if s, ok := fs.fs.(interface {
OpenDir(input *OpenIn, out *OpenOut) (status Status)
}); ok {
return s.OpenDir(input, out)
}
return ENOSYS
}
func (fs *wrappingFS) Read(input *ReadIn, buf []byte) (ReadResult, Status) {
if s, ok := fs.fs.(interface {
Read(input *ReadIn, buf []byte) (ReadResult, Status)
}); ok {
return s.Read(input, buf)
}
return nil, ENOSYS
}
func (fs *wrappingFS) Flock(input *FlockIn, flags int) Status {
if s, ok := fs.fs.(interface {
Flock(input *FlockIn, flags int) Status
}); ok {
return s.Flock(input, flags)
}
return ENOSYS
}
func (fs *wrappingFS) Release(input *ReleaseIn) {
if s, ok := fs.fs.(interface {
Release(input *ReleaseIn)
}); ok {
s.Release(input)
}
}
func (fs *wrappingFS) Write(input *WriteIn, data []byte) (written uint32, code Status) {
if s, ok := fs.fs.(interface {
Write(input *WriteIn, data []byte) (written uint32, code Status)
}); ok {
return s.Write(input, data)
}
return 0, ENOSYS
}
func (fs *wrappingFS) Flush(input *FlushIn) Status {
if s, ok := fs.fs.(interface {
Flush(input *FlushIn) Status
}); ok {
return s.Flush(input)
}
return OK
}
func (fs *wrappingFS) Fsync(input *FsyncIn) (code Status) {
if s, ok := fs.fs.(interface {
Fsync(input *FsyncIn) (code Status)
}); ok {
return s.Fsync(input)
}
return ENOSYS
}
func (fs *wrappingFS) ReadDir(input *ReadIn, l *DirEntryList) Status {
if s, ok := fs.fs.(interface {
ReadDir(input *ReadIn, l *DirEntryList) Status
}); ok {
return s.ReadDir(input, l)
}
return ENOSYS
}
func (fs *wrappingFS) ReadDirPlus(input *ReadIn, l *DirEntryList) Status {
if s, ok := fs.fs.(interface {
ReadDirPlus(input *ReadIn, l *DirEntryList) Status
}); ok {
return s.ReadDirPlus(input, l)
}
return ENOSYS
}
func (fs *wrappingFS) ReleaseDir(input *ReleaseIn) {
if s, ok := fs.fs.(interface {
ReleaseDir(input *ReleaseIn)
}); ok {
s.ReleaseDir(input)
}
}
func (fs *wrappingFS) FsyncDir(input *FsyncIn) (code Status) {
if s, ok := fs.fs.(interface {
FsyncDir(input *FsyncIn) (code Status)
}); ok {
return s.FsyncDir(input)
}
return ENOSYS
}
func (fs *wrappingFS) Fallocate(in *FallocateIn) (code Status) {
if s, ok := fs.fs.(interface {
Fallocate(in *FallocateIn) (code Status)
}); ok {
return s.Fallocate(in)
}
return ENOSYS
}

70
vendor/github.com/hanwen/go-fuse/splice/copy.go generated vendored Normal file
View file

@ -0,0 +1,70 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
import (
"io"
"os"
)
func SpliceCopy(dst *os.File, src *os.File, p *Pair) (int64, error) {
total := int64(0)
for {
n, err := p.LoadFrom(src.Fd(), p.size)
if err != nil {
return total, err
}
if n == 0 {
break
}
m, err := p.WriteTo(dst.Fd(), n)
total += int64(m)
if err != nil {
return total, err
}
if m < n {
return total, err
}
if int(n) < p.size {
break
}
}
return total, nil
}
// Argument ordering follows io.Copy.
func CopyFile(dstName string, srcName string, mode int) error {
src, err := os.Open(srcName)
if err != nil {
return err
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode))
if err != nil {
return err
}
defer dst.Close()
return CopyFds(dst, src)
}
func CopyFds(dst *os.File, src *os.File) (err error) {
p, err := splicePool.get()
if p != nil {
p.Grow(256 * 1024)
_, err := SpliceCopy(dst, src, p)
splicePool.done(p)
return err
} else {
_, err = io.Copy(dst, src)
}
if err == io.EOF {
err = nil
}
return err
}

68
vendor/github.com/hanwen/go-fuse/splice/pair.go generated vendored Normal file
View file

@ -0,0 +1,68 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
import (
"fmt"
"os"
)
type Pair struct {
r, w *os.File
size int
}
func (p *Pair) MaxGrow() {
for p.Grow(2*p.size) == nil {
}
}
func (p *Pair) Grow(n int) error {
if n <= p.size {
return nil
}
if !resizable {
return fmt.Errorf("splice: want %d bytes, but not resizable", n)
}
if n > maxPipeSize {
return fmt.Errorf("splice: want %d bytes, max pipe size %d", n, maxPipeSize)
}
newsize, errNo := fcntl(p.r.Fd(), F_SETPIPE_SZ, n)
if errNo != 0 {
return fmt.Errorf("splice: fcntl returned %v", errNo)
}
p.size = newsize
return nil
}
func (p *Pair) Cap() int {
return p.size
}
func (p *Pair) Close() error {
err1 := p.r.Close()
err2 := p.w.Close()
if err1 != nil {
return err1
}
return err2
}
func (p *Pair) Read(d []byte) (n int, err error) {
return p.r.Read(d)
}
func (p *Pair) ReadFd() uintptr {
return p.r.Fd()
}
func (p *Pair) WriteFd() uintptr {
return p.w.Fd()
}
func (p *Pair) Write(d []byte) (n int, err error) {
return p.w.Write(d)
}

22
vendor/github.com/hanwen/go-fuse/splice/pair_darwin.go generated vendored Normal file
View file

@ -0,0 +1,22 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
import ()
func (p *Pair) LoadFromAt(fd uintptr, sz int, off int64) (int, error) {
panic("not implemented")
return 0, nil
}
func (p *Pair) LoadFrom(fd uintptr, sz int) (int, error) {
panic("not implemented")
return 0, nil
}
func (p *Pair) WriteTo(fd uintptr, n int) (int, error) {
panic("not implemented")
return 0, nil
}

37
vendor/github.com/hanwen/go-fuse/splice/pair_linux.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
import (
"fmt"
"os"
"syscall"
)
func (p *Pair) LoadFromAt(fd uintptr, sz int, off int64) (int, error) {
n, err := syscall.Splice(int(fd), &off, int(p.w.Fd()), nil, sz, 0)
return int(n), err
}
func (p *Pair) LoadFrom(fd uintptr, sz int) (int, error) {
if sz > p.size {
return 0, fmt.Errorf("LoadFrom: not enough space %d, %d",
sz, p.size)
}
n, err := syscall.Splice(int(fd), nil, int(p.w.Fd()), nil, sz, 0)
if err != nil {
err = os.NewSyscallError("Splice load from", err)
}
return int(n), err
}
func (p *Pair) WriteTo(fd uintptr, n int) (int, error) {
m, err := syscall.Splice(int(p.r.Fd()), nil, int(fd), nil, int(n), 0)
if err != nil {
err = os.NewSyscallError("Splice write", err)
}
return int(m), err
}

119
vendor/github.com/hanwen/go-fuse/splice/pool.go generated vendored Normal file
View file

@ -0,0 +1,119 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
import (
"io"
"sync"
)
var splicePool *pairPool
type pairPool struct {
sync.Mutex
unused []*Pair
usedCount int
}
func ClearSplicePool() {
splicePool.clear()
}
func Get() (*Pair, error) {
return splicePool.get()
}
func Total() int {
return splicePool.total()
}
func Used() int {
return splicePool.used()
}
// Return pipe pair to pool
func Done(p *Pair) {
splicePool.done(p)
}
// Closes and discards pipe pair.
func Drop(p *Pair) {
splicePool.drop(p)
}
func newSplicePairPool() *pairPool {
return &pairPool{}
}
func (me *pairPool) clear() {
me.Lock()
for _, p := range me.unused {
p.Close()
}
me.unused = me.unused[:0]
me.Unlock()
}
func (me *pairPool) used() (n int) {
me.Lock()
n = me.usedCount
me.Unlock()
return n
}
func (me *pairPool) total() int {
me.Lock()
n := me.usedCount + len(me.unused)
me.Unlock()
return n
}
func (me *pairPool) drop(p *Pair) {
p.Close()
me.Lock()
me.usedCount--
me.Unlock()
}
func (me *pairPool) get() (p *Pair, err error) {
me.Lock()
defer me.Unlock()
me.usedCount++
l := len(me.unused)
if l > 0 {
p := me.unused[l-1]
me.unused = me.unused[:l-1]
return p, nil
}
return newSplicePair()
}
var discardBuffer [32 * 1024]byte
func DiscardAll(r io.Reader) {
buf := discardBuffer[:]
for {
n, _ := r.Read(buf)
if n < len(buf) {
break
}
}
}
func (me *pairPool) done(p *Pair) {
DiscardAll(p.r)
me.Lock()
me.usedCount--
me.unused = append(me.unused, p)
me.Unlock()
}
func init() {
splicePool = newSplicePairPool()
}

90
vendor/github.com/hanwen/go-fuse/splice/splice.go generated vendored Normal file
View file

@ -0,0 +1,90 @@
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package splice
// Routines for efficient file to file copying.
import (
"fmt"
"io/ioutil"
"log"
"os"
"syscall"
)
var maxPipeSize int
var resizable bool
func Resizable() bool {
return resizable
}
func MaxPipeSize() int {
return maxPipeSize
}
// From manpage on ubuntu Lucid:
//
// Since Linux 2.6.11, the pipe capacity is 65536 bytes.
const DefaultPipeSize = 16 * 4096
func init() {
content, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size")
if err != nil {
maxPipeSize = DefaultPipeSize
} else {
fmt.Sscan(string(content), &maxPipeSize)
}
r, w, err := os.Pipe()
if err != nil {
log.Panicf("cannot create pipe: %v", err)
}
sz, errNo := fcntl(r.Fd(), F_GETPIPE_SZ, 0)
resizable = (errNo == 0)
_, errNo = fcntl(r.Fd(), F_SETPIPE_SZ, 2*sz)
resizable = resizable && (errNo == 0)
r.Close()
w.Close()
}
// copy & paste from syscall.
func fcntl(fd uintptr, cmd int, arg int) (val int, errno syscall.Errno) {
r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, fd, uintptr(cmd), uintptr(arg))
val = int(r0)
errno = syscall.Errno(e1)
return
}
const F_SETPIPE_SZ = 1031
const F_GETPIPE_SZ = 1032
func newSplicePair() (p *Pair, err error) {
p = &Pair{}
p.r, p.w, err = os.Pipe()
if err != nil {
return nil, err
}
errNo := syscall.Errno(0)
for _, f := range []*os.File{p.r, p.w} {
_, errNo = fcntl(f.Fd(), syscall.F_SETFL, syscall.O_NONBLOCK)
if errNo != 0 {
p.Close()
return nil, os.NewSyscallError("fcntl setfl", errNo)
}
}
p.size, errNo = fcntl(p.r.Fd(), F_GETPIPE_SZ, 0)
if errNo == syscall.EINVAL {
p.size = DefaultPipeSize
return p, nil
}
if errNo != 0 {
p.Close()
return nil, os.NewSyscallError("fcntl getsize", errNo)
}
return p, nil
}

1
vendor/github.com/sirupsen/logrus/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
logrus

15
vendor/github.com/sirupsen/logrus/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,15 @@
language: go
go:
- 1.6.x
- 1.7.x
- 1.8.x
- tip
env:
- GOMAXPROCS=4 GORACE=halt_on_error=1
install:
- go get github.com/stretchr/testify/assert
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v ./...

123
vendor/github.com/sirupsen/logrus/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,123 @@
# 1.0.5
* Fix hooks race (#707)
* Fix panic deadlock (#695)
# 1.0.4
* Fix race when adding hooks (#612)
* Fix terminal check in AppEngine (#635)
# 1.0.3
* Replace example files with testable examples
# 1.0.2
* bug: quote non-string values in text formatter (#583)
* Make (*Logger) SetLevel a public method
# 1.0.1
* bug: fix escaping in text formatter (#575)
# 1.0.0
* Officially changed name to lower-case
* bug: colors on Windows 10 (#541)
* bug: fix race in accessing level (#512)
# 0.11.5
* feature: add writer and writerlevel to entry (#372)
# 0.11.4
* bug: fix undefined variable on solaris (#493)
# 0.11.3
* formatter: configure quoting of empty values (#484)
* formatter: configure quoting character (default is `"`) (#484)
* bug: fix not importing io correctly in non-linux environments (#481)
# 0.11.2
* bug: fix windows terminal detection (#476)
# 0.11.1
* bug: fix tty detection with custom out (#471)
# 0.11.0
* performance: Use bufferpool to allocate (#370)
* terminal: terminal detection for app-engine (#343)
* feature: exit handler (#375)
# 0.10.0
* feature: Add a test hook (#180)
* feature: `ParseLevel` is now case-insensitive (#326)
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
* performance: avoid re-allocations on `WithFields` (#335)
# 0.9.0
* logrus/text_formatter: don't emit empty msg
* logrus/hooks/airbrake: move out of main repository
* logrus/hooks/sentry: move out of main repository
* logrus/hooks/papertrail: move out of main repository
* logrus/hooks/bugsnag: move out of main repository
* logrus/core: run tests with `-race`
* logrus/core: detect TTY based on `stderr`
* logrus/core: support `WithError` on logger
* logrus/core: Solaris support
# 0.8.7
* logrus/core: fix possible race (#216)
* logrus/doc: small typo fixes and doc improvements
# 0.8.6
* hooks/raven: allow passing an initialized client
# 0.8.5
* logrus/core: revert #208
# 0.8.4
* formatter/text: fix data race (#218)
# 0.8.3
* logrus/core: fix entry log level (#208)
* logrus/core: improve performance of text formatter by 40%
* logrus/core: expose `LevelHooks` type
* logrus/core: add support for DragonflyBSD and NetBSD
* formatter/text: print structs more verbosely
# 0.8.2
* logrus: fix more Fatal family functions
# 0.8.1
* logrus: fix not exiting on `Fatalf` and `Fatalln`
# 0.8.0
* logrus: defaults to stderr instead of stdout
* hooks/sentry: add special field for `*http.Request`
* formatter/text: ignore Windows for colors
# 0.7.3
* formatter/\*: allow configuration of timestamp layout
# 0.7.2
* formatter/text: Add configuration option for time format (#158)

21
vendor/github.com/sirupsen/logrus/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Simon Eskildsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

511
vendor/github.com/sirupsen/logrus/README.md generated vendored Normal file

File diff suppressed because it is too large Load diff

64
vendor/github.com/sirupsen/logrus/alt_exit.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
package logrus
// The following code was sourced and modified from the
// https://github.com/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}

14
vendor/github.com/sirupsen/logrus/appveyor.yml generated vendored Normal file
View file

@ -0,0 +1,14 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
environment:
GOPATH: c:\gopath
branches:
only:
- master
install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
build_script:
- go get -t
- go test

26
vendor/github.com/sirupsen/logrus/doc.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
/*
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
The simplest way to use Logrus is simply the package-level exported logger:
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"number": 1,
"size": 10,
}).Info("A walrus appears")
}
Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
For a full guide visit https://github.com/sirupsen/logrus
*/
package logrus

288
vendor/github.com/sirupsen/logrus/entry.go generated vendored Normal file
View file

@ -0,0 +1,288 @@
package logrus
import (
"bytes"
"fmt"
"os"
"sync"
"time"
)
var bufferPool *sync.Pool
func init() {
bufferPool = &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
}
// Defines the key when adding errors using WithError.
var ErrorKey = "error"
// An entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
// passed around as much as you wish to avoid field duplication.
type Entry struct {
Logger *Logger
// Contains all the fields set by the user.
Data Fields
// Time at which the log entry was created
Time time.Time
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
Buffer *bytes.Buffer
}
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, give a little extra room
Data: make(Fields, 5),
}
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
return "", err
}
str := string(serialized)
return str, nil
}
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
func (entry *Entry) WithError(err error) *Entry {
return entry.WithField(ErrorKey, err)
}
// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
return entry.WithFields(Fields{key: value})
}
// Add a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
data := make(Fields, len(entry.Data)+len(fields))
for k, v := range entry.Data {
data[k] = v
}
for k, v := range fields {
data[k] = v
}
return &Entry{Logger: entry.Logger, Data: data}
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now()
entry.Level = level
entry.Message = msg
entry.fireHooks()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
entry.write()
entry.Buffer = nil
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
// directly here.
if level <= PanicLevel {
panic(&entry)
}
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, &entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
serialized, err := entry.Logger.Formatter.Format(entry)
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
} else {
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
}
func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.log(DebugLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Print(args ...interface{}) {
entry.Info(args...)
}
func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.log(InfoLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.log(WarnLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Warning(args ...interface{}) {
entry.Warn(args...)
}
func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.log(ErrorLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...))
}
Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.log(PanicLevel, fmt.Sprint(args...))
}
panic(fmt.Sprint(args...))
}
// Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.Debug(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.Info(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Printf(format string, args ...interface{}) {
entry.Infof(format, args...)
}
func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.Warn(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Warningf(format string, args ...interface{}) {
entry.Warnf(format, args...)
}
func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.Error(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...))
}
Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.Panic(fmt.Sprintf(format, args...))
}
}
// Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.Debug(entry.sprintlnn(args...))
}
}
func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.Info(entry.sprintlnn(args...))
}
}
func (entry *Entry) Println(args ...interface{}) {
entry.Infoln(args...)
}
func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.Warn(entry.sprintlnn(args...))
}
}
func (entry *Entry) Warningln(args ...interface{}) {
entry.Warnln(args...)
}
func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.Error(entry.sprintlnn(args...))
}
}
func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...))
}
Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.Panic(entry.sprintlnn(args...))
}
}
// Sprintlnn => Sprint no newline. This is to get the behavior of how
// fmt.Sprintln where spaces are always added between operands, regardless of
// their type. Instead of vendoring the Sprintln implementation to spare a
// string allocation, we do the simplest thing.
func (entry *Entry) sprintlnn(args ...interface{}) string {
msg := fmt.Sprintln(args...)
return msg[:len(msg)-1]
}

Some files were not shown because too many files have changed in this diff Show more