fusego/conversions.go

480 lines
12 KiB
Go
Raw Normal View History

2015-03-24 06:24:00 +03:00
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-07-27 07:21:36 +03:00
package fuse
2015-03-24 06:24:00 +03:00
2015-03-24 06:36:44 +03:00
import (
2015-07-24 01:02:49 +03:00
"bytes"
2015-07-24 03:04:12 +03:00
"errors"
2015-07-24 03:54:09 +03:00
"os"
"syscall"
2015-03-24 07:00:05 +03:00
"time"
2015-07-24 00:53:16 +03:00
"unsafe"
2015-03-24 07:00:05 +03:00
2015-07-27 07:30:34 +03:00
"github.com/jacobsa/fuse/fuseops"
2015-07-24 07:33:27 +03:00
"github.com/jacobsa/fuse/internal/buffer"
2015-07-23 09:22:32 +03:00
"github.com/jacobsa/fuse/internal/fusekernel"
2015-03-24 06:36:44 +03:00
)
2015-03-24 06:24:00 +03:00
2015-07-27 07:30:34 +03:00
// Convert a kernel message to an appropriate implementation of fuseops.Op. If
// the op is unknown, a special unexported type will be used.
2015-05-05 03:00:18 +03:00
//
2015-07-27 07:30:34 +03:00
// The caller is responsible for arranging for the message to be destroyed.
func convertInMessage(
2015-07-24 07:33:27 +03:00
m *buffer.InMessage,
2015-07-27 07:30:34 +03:00
protocol fusekernel.Protocol) (o fuseops.Op, err error) {
2015-07-24 07:33:27 +03:00
switch m.Header().Opcode {
2015-07-23 09:40:27 +03:00
case fusekernel.OpLookup:
2015-07-24 07:36:59 +03:00
buf := m.ConsumeBytes(m.Len())
2015-07-23 09:40:27 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpLookup")
2015-07-24 03:04:12 +03:00
return
2015-07-23 09:40:27 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.LookUpInodeOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
Name: string(buf[:n-1]),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-23 09:41:34 +03:00
case fusekernel.OpGetattr:
2015-07-27 07:35:26 +03:00
o = &fuseops.GetInodeAttributesOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 00:53:16 +03:00
case fusekernel.OpSetattr:
2015-07-24 07:36:59 +03:00
type input fusekernel.SetattrIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpSetattr")
2015-07-24 03:04:12 +03:00
return
2015-07-24 00:53:16 +03:00
}
2015-07-27 07:32:29 +03:00
to := &fuseops.SetInodeAttributesOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-03-24 06:46:31 +03:00
}
2015-07-27 07:35:26 +03:00
o = to
2015-03-24 08:32:12 +03:00
2015-07-24 00:53:16 +03:00
valid := fusekernel.SetattrValid(in.Valid)
if valid&fusekernel.SetattrSize != 0 {
to.Size = &in.Size
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrMode != 0 {
2015-07-24 08:23:11 +03:00
mode := convertFileMode(in.Mode)
2015-07-24 00:53:16 +03:00
to.Mode = &mode
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrAtime != 0 {
t := time.Unix(int64(in.Atime), int64(in.AtimeNsec))
to.Atime = &t
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:53:16 +03:00
if valid&fusekernel.SetattrMtime != 0 {
t := time.Unix(int64(in.Mtime), int64(in.MtimeNsec))
to.Mtime = &t
2015-03-24 08:32:12 +03:00
}
2015-07-24 00:57:31 +03:00
case fusekernel.OpForget:
2015-07-24 07:36:59 +03:00
type input fusekernel.ForgetIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpForget")
2015-07-24 03:04:12 +03:00
return
2015-07-24 00:57:31 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.ForgetInodeOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 00:57:31 +03:00
N: in.Nlookup,
}
2015-07-24 01:02:49 +03:00
case fusekernel.OpMkdir:
2015-07-24 07:40:43 +03:00
in := (*fusekernel.MkdirIn)(m.Consume(fusekernel.MkdirInSize(protocol)))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpMkdir")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:02:49 +03:00
}
2015-07-24 07:40:43 +03:00
name := m.ConsumeBytes(m.Len())
2015-07-24 01:02:49 +03:00
i := bytes.IndexByte(name, '\x00')
if i < 0 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpMkdir")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:02:49 +03:00
}
name = name[:i]
2015-07-27 07:35:26 +03:00
o = &fuseops.MkDirOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
Name: string(name),
2015-07-24 06:23:39 +03:00
// On Linux, vfs_mkdir calls through to the inode with at most
// permissions and sticky bits set (cf. https://goo.gl/WxgQXk), and fuse
// passes that on directly (cf. https://goo.gl/f31aMo). In other words,
// the fact that this is a directory is implicit in the fact that the
// opcode is mkdir. But we want the correct mode to go through, so ensure
// that os.ModeDir is set.
2015-07-24 08:23:11 +03:00
Mode: convertFileMode(in.Mode) | os.ModeDir,
2015-03-24 06:46:31 +03:00
}
2015-07-24 06:23:39 +03:00
2015-07-24 01:04:03 +03:00
case fusekernel.OpCreate:
2015-07-24 08:13:26 +03:00
in := (*fusekernel.CreateIn)(m.Consume(fusekernel.CreateInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
2015-07-24 08:13:26 +03:00
err = errors.New("Corrupt OpCreate")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:04:03 +03:00
}
2015-07-24 07:40:43 +03:00
name := m.ConsumeBytes(m.Len())
2015-07-24 01:04:03 +03:00
i := bytes.IndexByte(name, '\x00')
if i < 0 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpCreate")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:04:03 +03:00
}
name = name[:i]
2015-07-27 07:35:26 +03:00
o = &fuseops.CreateFileOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
Name: string(name),
Mode: convertFileMode(in.Mode),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:04:59 +03:00
case fusekernel.OpSymlink:
2015-07-24 07:40:43 +03:00
// The message is "newName\0target\0".
names := m.ConsumeBytes(m.Len())
2015-07-24 01:04:59 +03:00
if len(names) == 0 || names[len(names)-1] != 0 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpSymlink")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:04:59 +03:00
}
i := bytes.IndexByte(names, '\x00')
if i < 0 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpSymlink")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:04:59 +03:00
}
newName, target := names[0:i], names[i+1:len(names)-1]
2015-07-27 07:35:26 +03:00
o = &fuseops.CreateSymlinkOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
Name: string(newName),
Target: string(target),
2015-05-19 08:34:14 +03:00
}
2015-07-24 01:07:22 +03:00
case fusekernel.OpRename:
2015-07-24 07:40:43 +03:00
type input fusekernel.RenameIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRename")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:07:22 +03:00
}
2015-07-24 07:40:43 +03:00
names := m.ConsumeBytes(m.Len())
2015-07-24 01:07:22 +03:00
// names should be "old\x00new\x00"
if len(names) < 4 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRename")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:07:22 +03:00
}
if names[len(names)-1] != '\x00' {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRename")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:07:22 +03:00
}
i := bytes.IndexByte(names, '\x00')
if i < 0 {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRename")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:07:22 +03:00
}
oldName, newName := names[:i], names[i+1:len(names)-1]
2015-07-27 07:35:26 +03:00
o = &fuseops.RenameOp{
2015-07-27 07:33:19 +03:00
OldParent: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 01:07:22 +03:00
OldName: string(oldName),
2015-07-27 07:33:19 +03:00
NewParent: fuseops.InodeID(in.Newdir),
2015-07-24 01:07:22 +03:00
NewName: string(newName),
2015-06-25 08:37:04 +03:00
}
2015-07-24 01:08:41 +03:00
case fusekernel.OpUnlink:
2015-07-24 07:40:43 +03:00
buf := m.ConsumeBytes(m.Len())
2015-07-24 01:08:41 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpUnlink")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:08:41 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.UnlinkOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 01:08:41 +03:00
Name: string(buf[:n-1]),
}
2015-07-24 01:09:07 +03:00
case fusekernel.OpRmdir:
2015-07-24 07:40:43 +03:00
buf := m.ConsumeBytes(m.Len())
2015-07-24 01:09:07 +03:00
n := len(buf)
if n == 0 || buf[n-1] != '\x00' {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRmdir")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:09:07 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.RmDirOp{
2015-07-27 07:33:19 +03:00
Parent: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 01:09:07 +03:00
Name: string(buf[:n-1]),
2015-03-24 06:51:07 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:12:07 +03:00
case fusekernel.OpOpen:
2015-07-27 07:35:26 +03:00
o = &fuseops.OpenFileOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 01:12:07 +03:00
}
2015-07-24 01:12:29 +03:00
case fusekernel.OpOpendir:
2015-07-27 07:35:26 +03:00
o = &fuseops.OpenDirOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:10:45 +03:00
case fusekernel.OpRead:
2015-07-24 08:11:31 +03:00
in := (*fusekernel.ReadIn)(m.Consume(fusekernel.ReadInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRead")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:10:45 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.ReadFileOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-27 07:35:26 +03:00
Handle: fuseops.HandleID(in.Fh),
2015-07-24 01:10:45 +03:00
Offset: int64(in.Offset),
Size: int(in.Size),
}
2015-07-24 01:11:24 +03:00
case fusekernel.OpReaddir:
2015-07-24 08:11:31 +03:00
in := (*fusekernel.ReadIn)(m.Consume(fusekernel.ReadInSize(protocol)))
2015-07-24 07:40:43 +03:00
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpReaddir")
2015-07-24 03:04:12 +03:00
return
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-27 07:35:26 +03:00
o = &fuseops.ReadDirOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-27 07:35:26 +03:00
Handle: fuseops.HandleID(in.Fh),
Offset: fuseops.DirOffset(in.Offset),
2015-07-24 01:11:24 +03:00
Size: int(in.Size),
}
2015-07-24 01:13:36 +03:00
case fusekernel.OpRelease:
2015-07-24 07:40:43 +03:00
type input fusekernel.ReleaseIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpRelease")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:13:36 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.ReleaseFileHandleOp{
Handle: fuseops.HandleID(in.Fh),
2015-07-24 01:13:36 +03:00
}
2015-07-24 01:14:02 +03:00
case fusekernel.OpReleasedir:
2015-07-24 07:40:43 +03:00
type input fusekernel.ReleaseIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpReleasedir")
2015-07-24 03:04:12 +03:00
return
2015-03-24 06:56:41 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-27 07:35:26 +03:00
o = &fuseops.ReleaseDirHandleOp{
Handle: fuseops.HandleID(in.Fh),
2015-07-24 01:14:02 +03:00
}
2015-07-24 01:15:52 +03:00
case fusekernel.OpWrite:
2015-07-24 07:41:59 +03:00
in := (*fusekernel.WriteIn)(m.Consume(fusekernel.WriteInSize(protocol)))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpWrite")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:15:52 +03:00
}
2015-07-24 07:41:59 +03:00
buf := m.ConsumeBytes(m.Len())
2015-07-24 01:15:52 +03:00
if len(buf) < int(in.Size) {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpWrite")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:15:52 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.WriteFileOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-27 07:35:26 +03:00
Handle: fuseops.HandleID(in.Fh),
2015-07-24 01:15:52 +03:00
Data: buf,
Offset: int64(in.Offset),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:16:46 +03:00
case fusekernel.OpFsync:
2015-07-24 07:41:59 +03:00
type input fusekernel.FsyncIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpFsync")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:16:46 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.SyncFileOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-27 07:35:26 +03:00
Handle: fuseops.HandleID(in.Fh),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:19:04 +03:00
case fusekernel.OpFlush:
2015-07-24 07:41:59 +03:00
type input fusekernel.FlushIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpFlush")
2015-07-24 03:04:12 +03:00
return
2015-07-24 01:19:04 +03:00
}
2015-07-27 07:35:26 +03:00
o = &fuseops.FlushFileOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-27 07:35:26 +03:00
Handle: fuseops.HandleID(in.Fh),
2015-03-24 06:46:31 +03:00
}
2015-03-24 06:40:58 +03:00
2015-07-24 01:19:32 +03:00
case fusekernel.OpReadlink:
2015-07-27 07:35:26 +03:00
o = &fuseops.ReadSymlinkOp{
2015-07-27 07:33:19 +03:00
Inode: fuseops.InodeID(m.Header().Nodeid),
2015-05-19 09:05:54 +03:00
}
case fusekernel.OpStatfs:
2015-07-27 07:35:26 +03:00
o = &internalStatFSOp{}
case fusekernel.OpInterrupt:
2015-07-24 07:41:59 +03:00
type input fusekernel.InterruptIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
2015-07-24 03:31:07 +03:00
err = errors.New("Corrupt OpInterrupt")
return
}
2015-07-27 07:35:26 +03:00
o = &internalInterruptOp{
FuseID: in.Unique,
}
2015-07-24 09:35:14 +03:00
case fusekernel.OpInit:
type input fusekernel.InitIn
in := (*input)(m.Consume(unsafe.Sizeof(input{})))
if in == nil {
err = errors.New("Corrupt OpInit")
return
}
2015-07-27 07:35:26 +03:00
o = &internalInitOp{
2015-07-24 09:35:14 +03:00
Kernel: fusekernel.Protocol{in.Major, in.Minor},
MaxReadahead: in.MaxReadahead,
Flags: fusekernel.InitFlags(in.Flags),
}
2015-03-24 06:36:44 +03:00
default:
2015-07-27 07:35:26 +03:00
o = &unknownOp{
2015-07-24 07:33:27 +03:00
opCode: m.Header().Opcode,
2015-07-27 07:33:19 +03:00
inode: fuseops.InodeID(m.Header().Nodeid),
2015-07-24 02:58:42 +03:00
}
2015-03-24 06:36:44 +03:00
}
return
}
2015-07-24 04:08:24 +03:00
func convertTime(t time.Time) (secs uint64, nsec uint32) {
totalNano := t.UnixNano()
secs = uint64(totalNano / 1e9)
nsec = uint32(totalNano % 1e9)
return
}
2015-07-24 03:54:09 +03:00
func convertAttributes(
2015-07-27 07:33:19 +03:00
inodeID fuseops.InodeID,
2015-07-27 07:38:18 +03:00
in *fuseops.InodeAttributes,
2015-07-24 03:54:09 +03:00
out *fusekernel.Attr) {
out.Ino = uint64(inodeID)
out.Size = in.Size
out.Atime, out.AtimeNsec = convertTime(in.Atime)
out.Mtime, out.MtimeNsec = convertTime(in.Mtime)
out.Ctime, out.CtimeNsec = convertTime(in.Ctime)
out.SetCrtime(convertTime(in.Crtime))
out.Nlink = in.Nlink
2015-07-24 03:54:09 +03:00
out.Uid = in.Uid
out.Gid = in.Gid
// Set the mode.
2015-07-24 04:49:37 +03:00
out.Mode = uint32(in.Mode) & 0777
2015-07-24 03:54:09 +03:00
switch {
default:
out.Mode |= syscall.S_IFREG
case in.Mode&os.ModeDir != 0:
out.Mode |= syscall.S_IFDIR
case in.Mode&os.ModeDevice != 0:
if in.Mode&os.ModeCharDevice != 0 {
out.Mode |= syscall.S_IFCHR
} else {
out.Mode |= syscall.S_IFBLK
}
case in.Mode&os.ModeNamedPipe != 0:
out.Mode |= syscall.S_IFIFO
case in.Mode&os.ModeSymlink != 0:
out.Mode |= syscall.S_IFLNK
case in.Mode&os.ModeSocket != 0:
out.Mode |= syscall.S_IFSOCK
2015-03-24 07:00:05 +03:00
}
}
// Convert an absolute cache expiration time to a relative time from now for
2015-07-24 03:54:09 +03:00
// consumption by the fuse kernel module.
func convertExpirationTime(t time.Time) (secs uint64, nsecs uint32) {
2015-03-24 07:00:05 +03:00
// Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit
2015-07-24 03:54:09 +03:00
// counts of nanoseconds (cf. http://goo.gl/EJupJV). So negative durations
// are right out. There is no need to cap the positive magnitude, because
// 2^64 seconds is well longer than the 2^63 ns range of time.Duration.
d := t.Sub(time.Now())
if d > 0 {
secs = uint64(d / time.Second)
nsecs = uint32((d % time.Second) / time.Nanosecond)
2015-03-24 07:00:05 +03:00
}
return
}
func convertChildInodeEntry(
2015-07-27 07:38:18 +03:00
in *fuseops.ChildInodeEntry,
out *fusekernel.EntryOut) {
2015-07-24 03:54:09 +03:00
out.Nodeid = uint64(in.Child)
out.Generation = uint64(in.Generation)
out.EntryValid, out.EntryValidNsec = convertExpirationTime(in.EntryExpiration)
out.AttrValid, out.AttrValidNsec = convertExpirationTime(in.AttributesExpiration)
convertAttributes(in.Child, &in.Attributes, &out.Attr)
2015-03-24 07:00:05 +03:00
}
2015-07-24 08:23:11 +03:00
func convertFileMode(unixMode uint32) os.FileMode {
mode := os.FileMode(unixMode & 0777)
switch unixMode & syscall.S_IFMT {
case syscall.S_IFREG:
// nothing
case syscall.S_IFDIR:
mode |= os.ModeDir
case syscall.S_IFCHR:
mode |= os.ModeCharDevice | os.ModeDevice
case syscall.S_IFBLK:
mode |= os.ModeDevice
case syscall.S_IFIFO:
mode |= os.ModeNamedPipe
case syscall.S_IFLNK:
mode |= os.ModeSymlink
case syscall.S_IFSOCK:
mode |= os.ModeSocket
default:
// no idea
mode |= os.ModeDevice
}
if unixMode&syscall.S_ISUID != 0 {
mode |= os.ModeSetuid
}
if unixMode&syscall.S_ISGID != 0 {
mode |= os.ModeSetgid
}
return mode
}