This repository has been archived by the owner on Nov 13, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fileutil_linux.go
144 lines (123 loc) · 4.01 KB
/
fileutil_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2014 Red Hat, Inc
//
// 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.
// +build linux
package fileutil
import (
"fmt"
"os"
"syscall"
"unsafe"
)
func hasHardLinks(fi os.FileInfo) bool {
// On directories, Nlink doesn't make sense when checking for hard links
return !fi.IsDir() && fi.Sys().(*syscall.Stat_t).Nlink > 1
}
func getInode(fi os.FileInfo) uint64 {
return fi.Sys().(*syscall.Stat_t).Ino
}
// These functions are from github.com/docker/docker/pkg/system
// TODO(sgotti) waiting for a utimensat functions accepting flags and a
// LUtimesNano using it in https://github.com/golang/sys/
func LUtimesNano(path string, ts []syscall.Timespec) error {
// These are not currently available in syscall
AT_FDCWD := -100
AT_SYMLINK_NOFOLLOW := 0x100
var _path *byte
_path, err := syscall.BytePtrFromString(path)
if err != nil {
return err
}
if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(AT_FDCWD), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), uintptr(AT_SYMLINK_NOFOLLOW), 0, 0); err != 0 && err != syscall.ENOSYS {
return err
}
return nil
}
// Returns a nil slice and nil error if the xattr is not set
func Lgetxattr(path string, attr string) ([]byte, error) {
pathBytes, err := syscall.BytePtrFromString(path)
if err != nil {
return nil, err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return nil, err
}
dest := make([]byte, 128)
destBytes := unsafe.Pointer(&dest[0])
sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
if errno == syscall.ENODATA {
return nil, nil
}
if errno == syscall.ERANGE {
dest = make([]byte, sz)
destBytes := unsafe.Pointer(&dest[0])
sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
}
if errno != 0 {
return nil, errno
}
return dest[:sz], nil
}
var _zero uintptr
func Lsetxattr(path string, attr string, data []byte, flags int) error {
pathBytes, err := syscall.BytePtrFromString(path)
if err != nil {
return err
}
attrBytes, err := syscall.BytePtrFromString(attr)
if err != nil {
return err
}
var dataBytes unsafe.Pointer
if len(data) > 0 {
dataBytes = unsafe.Pointer(&data[0])
} else {
dataBytes = unsafe.Pointer(&_zero)
}
_, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
if errno != 0 {
return errno
}
return nil
}
// GetDeviceInfo returns the type, major, and minor numbers of a device.
// Kind is 'b' or 'c' for block and character devices, respectively.
// This does not follow symlinks.
func GetDeviceInfo(path string) (kind rune, major uint64, minor uint64, err error) {
d, err := os.Lstat(path)
if err != nil {
return
}
mode := d.Mode()
if mode&os.ModeDevice == 0 {
err = fmt.Errorf("not a device: %s", path)
return
}
stat_t, ok := d.Sys().(*syscall.Stat_t)
if !ok {
err = fmt.Errorf("cannot determine device number")
return
}
return getDeviceInfo(mode, stat_t.Rdev)
}
// Parse the device info out of the mode bits. Separate for testability.
func getDeviceInfo(mode os.FileMode, rdev uint64) (kind rune, major uint64, minor uint64, err error) {
kind = 'b'
if mode&os.ModeCharDevice != 0 {
kind = 'c'
}
major = (rdev >> 8) & 0xfff
minor = (rdev & 0xff) | ((rdev >> 12) & 0xfff00)
return
}