dep ensure
This commit is contained in:
parent
1158ac4760
commit
c8c18403e4
371 changed files with 168673 additions and 1 deletions
25
vendor/github.com/gorilla/websocket/.gitignore
generated
vendored
Normal file
25
vendor/github.com/gorilla/websocket/.gitignore
generated
vendored
Normal 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
19
vendor/github.com/gorilla/websocket/.travis.yml
generated
vendored
Normal 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
8
vendor/github.com/gorilla/websocket/AUTHORS
generated
vendored
Normal 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
22
vendor/github.com/gorilla/websocket/LICENSE
generated
vendored
Normal 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
64
vendor/github.com/gorilla/websocket/README.md
generated
vendored
Normal 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.
|
||||
|
||||
[](https://travis-ci.org/gorilla/websocket)
|
||||
[](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
392
vendor/github.com/gorilla/websocket/client.go
generated
vendored
Normal 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
16
vendor/github.com/gorilla/websocket/client_clone.go
generated
vendored
Normal 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()
|
||||
}
|
||||
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
Normal file
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
Normal 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
148
vendor/github.com/gorilla/websocket/compression.go
generated
vendored
Normal 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
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
18
vendor/github.com/gorilla/websocket/conn_read.go
generated
vendored
Normal 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
|
||||
}
|
||||
21
vendor/github.com/gorilla/websocket/conn_read_legacy.go
generated
vendored
Normal file
21
vendor/github.com/gorilla/websocket/conn_read_legacy.go
generated
vendored
Normal 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
180
vendor/github.com/gorilla/websocket/doc.go
generated
vendored
Normal 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
55
vendor/github.com/gorilla/websocket/json.go
generated
vendored
Normal 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
55
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
Normal 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
15
vendor/github.com/gorilla/websocket/mask_safe.go
generated
vendored
Normal 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
103
vendor/github.com/gorilla/websocket/prepared.go
generated
vendored
Normal 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
291
vendor/github.com/gorilla/websocket/server.go
generated
vendored
Normal 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
214
vendor/github.com/gorilla/websocket/util.go
generated
vendored
Normal 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
15
vendor/github.com/hanwen/go-fuse/AUTHORS
generated
vendored
Normal 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
30
vendor/github.com/hanwen/go-fuse/LICENSE
generated
vendored
Normal 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
1
vendor/github.com/hanwen/go-fuse/fuse/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
version.gen.go
|
||||
148
vendor/github.com/hanwen/go-fuse/fuse/api.go
generated
vendored
Normal file
148
vendor/github.com/hanwen/go-fuse/fuse/api.go
generated
vendored
Normal 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
79
vendor/github.com/hanwen/go-fuse/fuse/attr.go
generated
vendored
Normal 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
26
vendor/github.com/hanwen/go-fuse/fuse/attr_darwin.go
generated
vendored
Normal 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
27
vendor/github.com/hanwen/go-fuse/fuse/attr_linux.go
generated
vendored
Normal 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
102
vendor/github.com/hanwen/go-fuse/fuse/bufferpool.go
generated
vendored
Normal 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
35
vendor/github.com/hanwen/go-fuse/fuse/constants.go
generated
vendored
Normal 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)
|
||||
)
|
||||
9
vendor/github.com/hanwen/go-fuse/fuse/constants_freebsd.go
generated
vendored
Normal file
9
vendor/github.com/hanwen/go-fuse/fuse/constants_freebsd.go
generated
vendored
Normal 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
|
||||
12
vendor/github.com/hanwen/go-fuse/fuse/constants_linux.go
generated
vendored
Normal file
12
vendor/github.com/hanwen/go-fuse/fuse/constants_linux.go
generated
vendored
Normal 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
156
vendor/github.com/hanwen/go-fuse/fuse/defaultraw.go
generated
vendored
Normal 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
102
vendor/github.com/hanwen/go-fuse/fuse/direntry.go
generated
vendored
Normal 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
215
vendor/github.com/hanwen/go-fuse/fuse/lockingfs.go
generated
vendored
Normal 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
100
vendor/github.com/hanwen/go-fuse/fuse/misc.go
generated
vendored
Normal 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
82
vendor/github.com/hanwen/go-fuse/fuse/mount_darwin.go
generated
vendored
Normal 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
162
vendor/github.com/hanwen/go-fuse/fuse/mount_linux.go
generated
vendored
Normal 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
190
vendor/github.com/hanwen/go-fuse/fuse/nodefs/api.go
generated
vendored
Normal 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
|
||||
}
|
||||
75
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultfile.go
generated
vendored
Normal file
75
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultfile.go
generated
vendored
Normal 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
|
||||
}
|
||||
172
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultnode.go
generated
vendored
Normal file
172
vendor/github.com/hanwen/go-fuse/fuse/nodefs/defaultnode.go
generated
vendored
Normal 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
118
vendor/github.com/hanwen/go-fuse/fuse/nodefs/dir.go
generated
vendored
Normal 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
261
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files.go
generated
vendored
Normal 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
|
||||
}
|
||||
102
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go
generated
vendored
Normal file
102
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go
generated
vendored
Normal 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)
|
||||
}
|
||||
33
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_linux.go
generated
vendored
Normal file
33
vendor/github.com/hanwen/go-fuse/fuse/nodefs/files_linux.go
generated
vendored
Normal 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)
|
||||
}
|
||||
424
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsconnector.go
generated
vendored
Normal file
424
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsconnector.go
generated
vendored
Normal 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
158
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsmount.go
generated
vendored
Normal 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
487
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go
generated
vendored
Normal 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
24
vendor/github.com/hanwen/go-fuse/fuse/nodefs/fuse.go
generated
vendored
Normal 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
151
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go
generated
vendored
Normal 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
289
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
109
vendor/github.com/hanwen/go-fuse/fuse/nodefs/lockingfile.go
generated
vendored
Normal file
109
vendor/github.com/hanwen/go-fuse/fuse/nodefs/lockingfile.go
generated
vendored
Normal 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
232
vendor/github.com/hanwen/go-fuse/fuse/nodefs/memnode.go
generated
vendored
Normal 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
13
vendor/github.com/hanwen/go-fuse/fuse/nodefs/nodefs.go
generated
vendored
Normal 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
18
vendor/github.com/hanwen/go-fuse/fuse/nodefs/print.go
generated
vendored
Normal 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), ""))
|
||||
}
|
||||
20
vendor/github.com/hanwen/go-fuse/fuse/nodefs/syscall_linux.go
generated
vendored
Normal file
20
vendor/github.com/hanwen/go-fuse/fuse/nodefs/syscall_linux.go
generated
vendored
Normal 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
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
85
vendor/github.com/hanwen/go-fuse/fuse/pathfs/api.go
generated
vendored
Normal 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
61
vendor/github.com/hanwen/go-fuse/fuse/pathfs/copy.go
generated
vendored
Normal 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
122
vendor/github.com/hanwen/go-fuse/fuse/pathfs/default.go
generated
vendored
Normal 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
167
vendor/github.com/hanwen/go-fuse/fuse/pathfs/locking.go
generated
vendored
Normal 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)
|
||||
}
|
||||
183
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go
generated
vendored
Normal file
183
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go
generated
vendored
Normal 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)
|
||||
}
|
||||
47
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback_darwin.go
generated
vendored
Normal file
47
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback_darwin.go
generated
vendored
Normal 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)
|
||||
}
|
||||
49
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback_linux.go
generated
vendored
Normal file
49
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback_linux.go
generated
vendored
Normal 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
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
132
vendor/github.com/hanwen/go-fuse/fuse/pathfs/prefixfs.go
generated
vendored
Normal file
132
vendor/github.com/hanwen/go-fuse/fuse/pathfs/prefixfs.go
generated
vendored
Normal 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))
|
||||
}
|
||||
123
vendor/github.com/hanwen/go-fuse/fuse/pathfs/readonlyfs.go
generated
vendored
Normal file
123
vendor/github.com/hanwen/go-fuse/fuse/pathfs/readonlyfs.go
generated
vendored
Normal 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
|
||||
}
|
||||
144
vendor/github.com/hanwen/go-fuse/fuse/pathfs/syscall_linux.go
generated
vendored
Normal file
144
vendor/github.com/hanwen/go-fuse/fuse/pathfs/syscall_linux.go
generated
vendored
Normal 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
250
vendor/github.com/hanwen/go-fuse/fuse/print.go
generated
vendored
Normal 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
54
vendor/github.com/hanwen/go-fuse/fuse/print_darwin.go
generated
vendored
Normal 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
62
vendor/github.com/hanwen/go-fuse/fuse/print_linux.go
generated
vendored
Normal 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
75
vendor/github.com/hanwen/go-fuse/fuse/read.go
generated
vendored
Normal 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
217
vendor/github.com/hanwen/go-fuse/fuse/request.go
generated
vendored
Normal 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)
|
||||
}
|
||||
13
vendor/github.com/hanwen/go-fuse/fuse/request_darwin.go
generated
vendored
Normal file
13
vendor/github.com/hanwen/go-fuse/fuse/request_darwin.go
generated
vendored
Normal 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
13
vendor/github.com/hanwen/go-fuse/fuse/request_linux.go
generated
vendored
Normal 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
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
32
vendor/github.com/hanwen/go-fuse/fuse/server_darwin.go
generated
vendored
Normal 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
42
vendor/github.com/hanwen/go-fuse/fuse/server_linux.go
generated
vendored
Normal 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
17
vendor/github.com/hanwen/go-fuse/fuse/splice_darwin.go
generated
vendored
Normal 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
97
vendor/github.com/hanwen/go-fuse/fuse/splice_linux.go
generated
vendored
Normal 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
139
vendor/github.com/hanwen/go-fuse/fuse/syscall_darwin.go
generated
vendored
Normal 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
49
vendor/github.com/hanwen/go-fuse/fuse/syscall_linux.go
generated
vendored
Normal 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
9
vendor/github.com/hanwen/go-fuse/fuse/typeprint.go
generated
vendored
Normal 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
470
vendor/github.com/hanwen/go-fuse/fuse/types.go
generated
vendored
Normal 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
153
vendor/github.com/hanwen/go-fuse/fuse/types_darwin.go
generated
vendored
Normal 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
121
vendor/github.com/hanwen/go-fuse/fuse/types_linux.go
generated
vendored
Normal 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
333
vendor/github.com/hanwen/go-fuse/fuse/upgrade.go
generated
vendored
Normal 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
70
vendor/github.com/hanwen/go-fuse/splice/copy.go
generated
vendored
Normal 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
68
vendor/github.com/hanwen/go-fuse/splice/pair.go
generated
vendored
Normal 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
22
vendor/github.com/hanwen/go-fuse/splice/pair_darwin.go
generated
vendored
Normal 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
37
vendor/github.com/hanwen/go-fuse/splice/pair_linux.go
generated
vendored
Normal 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
119
vendor/github.com/hanwen/go-fuse/splice/pool.go
generated
vendored
Normal 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
90
vendor/github.com/hanwen/go-fuse/splice/splice.go
generated
vendored
Normal 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
1
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
logrus
|
||||
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
Normal 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
123
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal 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
21
vendor/github.com/sirupsen/logrus/LICENSE
generated
vendored
Normal 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
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
64
vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
Normal 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
14
vendor/github.com/sirupsen/logrus/appveyor.yml
generated
vendored
Normal 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
26
vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
Normal 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
288
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
Normal 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
Loading…
Add table
Add a link
Reference in a new issue