mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Start using new errors package (#8207)
This commit is contained in:
parent
e12f52e2c6
commit
a7be313230
@ -18,6 +18,7 @@ package hdfs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -280,7 +281,7 @@ func hdfsToObjectErr(ctx context.Context, err error, params ...string) error {
|
|||||||
return minio.PrefixAccessDenied{Bucket: bucket, Object: object}
|
return minio.PrefixAccessDenied{Bucket: bucket, Object: object}
|
||||||
}
|
}
|
||||||
return minio.BucketAlreadyOwnedByYou{Bucket: bucket}
|
return minio.BucketAlreadyOwnedByYou{Bucket: bucket}
|
||||||
case isSysErrNotEmpty(err):
|
case errors.Is(err, syscall.ENOTEMPTY):
|
||||||
if object != "" {
|
if object != "" {
|
||||||
return minio.PrefixAccessDenied{Bucket: bucket, Object: object}
|
return minio.PrefixAccessDenied{Bucket: bucket, Object: object}
|
||||||
}
|
}
|
||||||
@ -387,20 +388,6 @@ func (n *hdfsObjects) ListObjects(ctx context.Context, bucket, prefix, marker, d
|
|||||||
return minio.ListObjects(ctx, n, bucket, prefix, marker, delimiter, maxKeys, n.listPool, n.listDirFactory(), getObjectInfo, getObjectInfo)
|
return minio.ListObjects(ctx, n, bucket, prefix, marker, delimiter, maxKeys, n.listPool, n.listDirFactory(), getObjectInfo, getObjectInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given error corresponds to ENOTEMPTY for unix
|
|
||||||
// and ERROR_DIR_NOT_EMPTY for windows (directory not empty).
|
|
||||||
func isSysErrNotEmpty(err error) bool {
|
|
||||||
if err == syscall.ENOTEMPTY {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if pathErr, ok := err.(*os.PathError); ok {
|
|
||||||
if pathErr.Err == syscall.ENOTEMPTY {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteObject deletes a file path if its empty. If it's successfully deleted,
|
// deleteObject deletes a file path if its empty. If it's successfully deleted,
|
||||||
// it will recursively move up the tree, deleting empty parent directories
|
// it will recursively move up the tree, deleting empty parent directories
|
||||||
// until it finds one with files in it. Returns nil for a non-empty directory.
|
// until it finds one with files in it. Returns nil for a non-empty directory.
|
||||||
@ -411,16 +398,13 @@ func (n *hdfsObjects) deleteObject(basePath, deletePath string) error {
|
|||||||
|
|
||||||
// Attempt to remove path.
|
// Attempt to remove path.
|
||||||
if err := n.clnt.Remove(deletePath); err != nil {
|
if err := n.clnt.Remove(deletePath); err != nil {
|
||||||
switch {
|
if errors.Is(err, syscall.ENOTEMPTY) {
|
||||||
case err == syscall.ENOTEMPTY:
|
|
||||||
case isSysErrNotEmpty(err):
|
|
||||||
// Ignore errors if the directory is not empty. The server relies on
|
// Ignore errors if the directory is not empty. The server relies on
|
||||||
// this functionality, and sometimes uses recursion that should not
|
// this functionality, and sometimes uses recursion that should not
|
||||||
// error on parent directories.
|
// error on parent directories.
|
||||||
return nil
|
return nil
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trailing slash is removed when found to ensure
|
// Trailing slash is removed when found to ensure
|
||||||
|
@ -175,7 +175,7 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
|
|||||||
name := getOpName(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name())
|
name := getOpName(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name())
|
||||||
|
|
||||||
// Setup a http request body recorder
|
// Setup a http request body recorder
|
||||||
reqHeaders := cloneHeader(r.Header)
|
reqHeaders := r.Header.Clone()
|
||||||
reqHeaders.Set("Content-Length", strconv.Itoa(int(r.ContentLength)))
|
reqHeaders.Set("Content-Length", strconv.Itoa(int(r.ContentLength)))
|
||||||
reqHeaders.Set("Host", r.Host)
|
reqHeaders.Set("Host", r.Host)
|
||||||
for _, enc := range r.TransferEncoding {
|
for _, enc := range r.TransferEncoding {
|
||||||
@ -211,7 +211,7 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
|
|||||||
|
|
||||||
rs := trace.ResponseInfo{
|
rs := trace.ResponseInfo{
|
||||||
Time: time.Now().UTC(),
|
Time: time.Now().UTC(),
|
||||||
Headers: cloneHeader(respBodyRecorder.Header()),
|
Headers: respBodyRecorder.Header().Clone(),
|
||||||
StatusCode: respBodyRecorder.statusCode,
|
StatusCode: respBodyRecorder.statusCode,
|
||||||
Body: respBodyRecorder.Body(),
|
Body: respBodyRecorder.Body(),
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -24,86 +25,54 @@ import (
|
|||||||
|
|
||||||
// Function not implemented error
|
// Function not implemented error
|
||||||
func isSysErrNoSys(err error) bool {
|
func isSysErrNoSys(err error) bool {
|
||||||
if err == syscall.ENOSYS {
|
return errors.Is(err, syscall.ENOSYS)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.ENOSYS
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not supported error
|
// Not supported error
|
||||||
func isSysErrOpNotSupported(err error) bool {
|
func isSysErrOpNotSupported(err error) bool {
|
||||||
if err == syscall.EOPNOTSUPP {
|
return errors.Is(err, syscall.EOPNOTSUPP)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.EOPNOTSUPP
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No space left on device error
|
// No space left on device error
|
||||||
func isSysErrNoSpace(err error) bool {
|
func isSysErrNoSpace(err error) bool {
|
||||||
if err == syscall.ENOSPC {
|
return errors.Is(err, syscall.ENOSPC)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.ENOSPC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input/output error
|
// Input/output error
|
||||||
func isSysErrIO(err error) bool {
|
func isSysErrIO(err error) bool {
|
||||||
if err == syscall.EIO {
|
return errors.Is(err, syscall.EIO)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.EIO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given error corresponds to EISDIR (is a directory).
|
// Check if the given error corresponds to EISDIR (is a directory).
|
||||||
func isSysErrIsDir(err error) bool {
|
func isSysErrIsDir(err error) bool {
|
||||||
if err == syscall.EISDIR {
|
return errors.Is(err, syscall.EISDIR)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.EISDIR
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given error corresponds to ENOTDIR (is not a directory).
|
// Check if the given error corresponds to ENOTDIR (is not a directory).
|
||||||
func isSysErrNotDir(err error) bool {
|
func isSysErrNotDir(err error) bool {
|
||||||
if err == syscall.ENOTDIR {
|
return errors.Is(err, syscall.ENOTDIR)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.ENOTDIR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given error corresponds to the ENAMETOOLONG (name too long).
|
// Check if the given error corresponds to the ENAMETOOLONG (name too long).
|
||||||
func isSysErrTooLong(err error) bool {
|
func isSysErrTooLong(err error) bool {
|
||||||
if err == syscall.ENAMETOOLONG {
|
return errors.Is(err, syscall.ENAMETOOLONG)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && pathErr.Err == syscall.ENAMETOOLONG
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given error corresponds to ENOTEMPTY for unix
|
// Check if the given error corresponds to ENOTEMPTY for unix
|
||||||
// and ERROR_DIR_NOT_EMPTY for windows (directory not empty).
|
// and ERROR_DIR_NOT_EMPTY for windows (directory not empty).
|
||||||
func isSysErrNotEmpty(err error) bool {
|
func isSysErrNotEmpty(err error) bool {
|
||||||
if err == syscall.ENOTEMPTY {
|
if errors.Is(err, syscall.ENOTEMPTY) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if pathErr, ok := err.(*os.PathError); ok {
|
var pathErr *os.PathError
|
||||||
|
if errors.As(err, &pathErr) {
|
||||||
if runtime.GOOS == globalWindowsOSName {
|
if runtime.GOOS == globalWindowsOSName {
|
||||||
if errno, _ok := pathErr.Err.(syscall.Errno); _ok && errno == 0x91 {
|
var errno syscall.Errno
|
||||||
|
if errors.As(pathErr.Err, &errno) {
|
||||||
// ERROR_DIR_NOT_EMPTY
|
// ERROR_DIR_NOT_EMPTY
|
||||||
return true
|
return errno == 0x91
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pathErr.Err == syscall.ENOTEMPTY {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -113,10 +82,12 @@ func isSysErrPathNotFound(err error) bool {
|
|||||||
if runtime.GOOS != globalWindowsOSName {
|
if runtime.GOOS != globalWindowsOSName {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if pathErr, ok := err.(*os.PathError); ok {
|
var pathErr *os.PathError
|
||||||
if errno, _ok := pathErr.Err.(syscall.Errno); _ok && errno == 0x03 {
|
if errors.As(err, &pathErr) {
|
||||||
|
var errno syscall.Errno
|
||||||
|
if errors.As(pathErr.Err, &errno) {
|
||||||
// ERROR_PATH_NOT_FOUND
|
// ERROR_PATH_NOT_FOUND
|
||||||
return true
|
return errno == 0x03
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -128,20 +99,22 @@ func isSysErrHandleInvalid(err error) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Check if err contains ERROR_INVALID_HANDLE errno
|
// Check if err contains ERROR_INVALID_HANDLE errno
|
||||||
errno, ok := err.(syscall.Errno)
|
var pathErr *os.PathError
|
||||||
return ok && errno == 0x6
|
if errors.As(err, &pathErr) {
|
||||||
|
var errno syscall.Errno
|
||||||
|
if errors.As(pathErr.Err, &errno) {
|
||||||
|
// ERROR_PATH_NOT_FOUND
|
||||||
|
return errno == 0x6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSysErrCrossDevice(err error) bool {
|
func isSysErrCrossDevice(err error) bool {
|
||||||
e, ok := err.(*os.LinkError)
|
return errors.Is(err, syscall.EXDEV)
|
||||||
return ok && e.Err == syscall.EXDEV
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if given error corresponds to too many open files
|
// Check if given error corresponds to too many open files
|
||||||
func isSysErrTooManyFiles(err error) bool {
|
func isSysErrTooManyFiles(err error) bool {
|
||||||
if err == syscall.ENFILE || err == syscall.EMFILE {
|
return errors.Is(err, syscall.ENFILE) || errors.Is(err, syscall.EMFILE)
|
||||||
return true
|
|
||||||
}
|
|
||||||
pathErr, ok := err.(*os.PathError)
|
|
||||||
return ok && (pathErr.Err == syscall.ENFILE || pathErr.Err == syscall.EMFILE)
|
|
||||||
}
|
}
|
||||||
|
17
cmd/posix.go
17
cmd/posix.go
@ -19,6 +19,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -845,17 +846,11 @@ func (s *posix) ReadAll(volume, path string) (buf []byte, err error) {
|
|||||||
return nil, errFileNotFound
|
return nil, errFileNotFound
|
||||||
} else if os.IsPermission(err) {
|
} else if os.IsPermission(err) {
|
||||||
return nil, errFileAccessDenied
|
return nil, errFileAccessDenied
|
||||||
} else if pathErr, ok := err.(*os.PathError); ok {
|
} else if errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.EISDIR) {
|
||||||
switch pathErr.Err {
|
return nil, errFileNotFound
|
||||||
case syscall.ENOTDIR, syscall.EISDIR:
|
} else if isSysErrHandleInvalid(err) {
|
||||||
return nil, errFileNotFound
|
// This case is special and needs to be handled for windows.
|
||||||
default:
|
return nil, errFileNotFound
|
||||||
if isSysErrHandleInvalid(pathErr.Err) {
|
|
||||||
// This case is special and needs to be handled for windows.
|
|
||||||
return nil, errFileNotFound
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, pathErr
|
|
||||||
} else if isSysErrIO(err) {
|
} else if isSysErrIO(err) {
|
||||||
return nil, errFaultyDisk
|
return nil, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
@ -80,27 +80,15 @@ func errorToUIErr(err error) uiErr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show a generic message for known golang errors
|
// Show a generic message for known golang errors
|
||||||
switch e := err.(type) {
|
if errors.Is(err, syscall.EADDRINUSE) {
|
||||||
case *net.OpError:
|
return uiErrPortAlreadyInUse(err).Msg("Specified port is already in use")
|
||||||
if e.Op == "listen" {
|
} else if errors.Is(err, syscall.EACCES) {
|
||||||
if oe, ok := e.Err.(*os.SyscallError); ok {
|
return uiErrPortAccess(err).Msg("Insufficient permissions to use specified port")
|
||||||
if oe.Err == syscall.EADDRINUSE {
|
} else if os.IsPermission(err) {
|
||||||
return uiErrPortAlreadyInUse(e).Msg("Specified port '" + e.Addr.String() + "' is already in use")
|
return uiErrNoPermissionsToAccessDirFiles(err).Msg("Insufficient permissions to access path")
|
||||||
} else if oe.Err == syscall.EACCES {
|
} else if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||||
return uiErrPortAccess(e).Msg("Insufficient permissions to use specified port '" + e.Addr.String() + "'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *os.PathError:
|
|
||||||
if os.IsPermission(e) {
|
|
||||||
return uiErrNoPermissionsToAccessDirFiles(e).Msg("Insufficient permissions to access path, `" + e.Path + "`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch err {
|
|
||||||
case io.ErrUnexpectedEOF:
|
|
||||||
return uiErrUnexpectedDataContent(err)
|
return uiErrUnexpectedDataContent(err)
|
||||||
default:
|
} else {
|
||||||
// Failed to identify what type of error this, return a simple UI error
|
// Failed to identify what type of error this, return a simple UI error
|
||||||
return uiErr{msg: err.Error()}
|
return uiErr{msg: err.Error()}
|
||||||
}
|
}
|
||||||
|
16
cmd/utils.go
16
cmd/utils.go
@ -53,25 +53,13 @@ func IsErrIgnored(err error, ignoredErrs ...error) bool {
|
|||||||
// IsErr returns whether given error is exact error.
|
// IsErr returns whether given error is exact error.
|
||||||
func IsErr(err error, errs ...error) bool {
|
func IsErr(err error, errs ...error) bool {
|
||||||
for _, exactErr := range errs {
|
for _, exactErr := range errs {
|
||||||
if err == exactErr {
|
if errors.Is(err, exactErr) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a copy of http.Header
|
|
||||||
func cloneHeader(h http.Header) http.Header {
|
|
||||||
h2 := make(http.Header, len(h))
|
|
||||||
for k, vv := range h {
|
|
||||||
vv2 := make([]string, len(vv))
|
|
||||||
copy(vv2, vv)
|
|
||||||
h2[k] = vv2
|
|
||||||
|
|
||||||
}
|
|
||||||
return h2
|
|
||||||
}
|
|
||||||
|
|
||||||
func request2BucketObjectName(r *http.Request) (bucketName, objectName string) {
|
func request2BucketObjectName(r *http.Request) (bucketName, objectName string) {
|
||||||
path, err := getResource(r.URL.Path, r.Host, globalDomainNames)
|
path, err := getResource(r.URL.Path, r.Host, globalDomainNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -289,7 +277,7 @@ var globalProfiler minioProfiler
|
|||||||
|
|
||||||
// dump the request into a string in JSON format.
|
// dump the request into a string in JSON format.
|
||||||
func dumpRequest(r *http.Request) string {
|
func dumpRequest(r *http.Request) string {
|
||||||
header := cloneHeader(r.Header)
|
header := r.Header.Clone()
|
||||||
header.Set("Host", r.Host)
|
header.Set("Host", r.Host)
|
||||||
// Replace all '%' to '%%' so that printer format parser
|
// Replace all '%' to '%%' so that printer format parser
|
||||||
// to ignore URL encoded values.
|
// to ignore URL encoded values.
|
||||||
|
@ -30,30 +30,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests http.Header clone.
|
|
||||||
func TestCloneHeader(t *testing.T) {
|
|
||||||
headers := []http.Header{
|
|
||||||
{
|
|
||||||
"Content-Type": {"text/html; charset=UTF-8"},
|
|
||||||
"Content-Length": {"0"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Content-Length": {"0", "1", "2"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Expires": {"-1"},
|
|
||||||
"Content-Length": {"0"},
|
|
||||||
"Content-Encoding": {"gzip"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, header := range headers {
|
|
||||||
clonedHeader := cloneHeader(header)
|
|
||||||
if !reflect.DeepEqual(header, clonedHeader) {
|
|
||||||
t.Errorf("Test %d failed", i+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests maximum object size.
|
// Tests maximum object size.
|
||||||
func TestMaxObjectSize(t *testing.T) {
|
func TestMaxObjectSize(t *testing.T) {
|
||||||
sizes := []struct {
|
sizes := []struct {
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
package lock
|
package lock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
@ -39,7 +38,11 @@ func lockedOpenFile(path string, flag int, perm os.FileMode, lockType int) (*Loc
|
|||||||
case syscall.O_RDWR | syscall.O_CREAT:
|
case syscall.O_RDWR | syscall.O_CREAT:
|
||||||
lockType |= syscall.LOCK_EX
|
lockType |= syscall.LOCK_EX
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unsupported flag (%d)", flag)
|
return nil, &os.PathError{
|
||||||
|
Op: "open",
|
||||||
|
Path: path,
|
||||||
|
Err: syscall.EINVAL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(path, flag|syscall.O_SYNC, perm)
|
f, err := os.OpenFile(path, flag|syscall.O_SYNC, perm)
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
package lock
|
package lock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
@ -39,7 +38,11 @@ func lockedOpenFile(path string, flag int, perm os.FileMode, rlockType int) (*Lo
|
|||||||
case syscall.O_RDWR | syscall.O_CREAT:
|
case syscall.O_RDWR | syscall.O_CREAT:
|
||||||
lockType = syscall.F_WRLCK
|
lockType = syscall.F_WRLCK
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unsupported flag (%d)", flag)
|
return nil, &os.PathError{
|
||||||
|
Op: "open",
|
||||||
|
Path: path,
|
||||||
|
Err: syscall.EINVAL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var lock = syscall.Flock_t{
|
var lock = syscall.Flock_t{
|
||||||
|
Loading…
Reference in New Issue
Block a user