mirror of https://github.com/minio/minio.git
posix: Fix windows performance issues. (#3132)
Do not attempt to fetch volume/drive information for each i/o situation. In our case we do this in all calls `posix.go` this in-turn created a terrible situation for windows. This issue does not affect the i/o path on Unix platforms since statvfs calls are in the range of micro seconds on these platforms. This verification is only needed during startup and we let things fail at a later stage on windows.
This commit is contained in:
parent
a773a6dce6
commit
f3c6c55719
|
@ -42,7 +42,7 @@ func isSysErrIO(err error) bool {
|
||||||
return err != nil && err == syscall.EIO
|
return err != nil && err == syscall.EIO
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 pathErr, ok := err.(*os.PathError); ok {
|
if pathErr, ok := err.(*os.PathError); ok {
|
||||||
switch pathErr.Err {
|
switch pathErr.Err {
|
||||||
|
@ -53,8 +53,19 @@ func isSysErrNotDir(err error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the given error corresponds to the ENAMETOOLONG (name too long).
|
||||||
|
func isSysErrTooLong(err error) bool {
|
||||||
|
if pathErr, ok := err.(*os.PathError); ok {
|
||||||
|
switch pathErr.Err {
|
||||||
|
case syscall.ENAMETOOLONG:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// 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 pathErr, ok := err.(*os.PathError); ok {
|
if pathErr, ok := err.(*os.PathError); ok {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2016 Minio, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSysErrors(t *testing.T) {
|
||||||
|
pathErr := &os.PathError{Err: syscall.ENAMETOOLONG}
|
||||||
|
ok := isSysErrTooLong(pathErr)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected error expecting %s", syscall.ENAMETOOLONG)
|
||||||
|
}
|
||||||
|
pathErr = &os.PathError{Err: syscall.ENOTDIR}
|
||||||
|
ok = isSysErrNotDir(pathErr)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected error expecting %s", syscall.ENOTDIR)
|
||||||
|
}
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
pathErr = &os.PathError{Err: syscall.ENOTEMPTY}
|
||||||
|
ok = isSysErrNotEmpty(pathErr)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected error expecting %s", syscall.ENOTEMPTY)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pathErr = &os.PathError{Err: syscall.Errno(0x91)}
|
||||||
|
ok = isSysErrNotEmpty(pathErr)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Unexpected error expecting 0x91")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
pathErr = &os.PathError{Err: syscall.Errno(0x03)}
|
||||||
|
ok = isSysErrPathNotFound(pathErr)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Unexpected error expecting 0x03")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
cmd/posix.go
117
cmd/posix.go
|
@ -34,9 +34,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fsMinFreeSpace = 1024 * 1024 * 1024
|
fsMinFreeSpace = 1024 * 1024 * 1024 // Min 1GiB free space.
|
||||||
fsMinFreeInodesPercent = 5
|
fsMinFreeInodes = 10000 // Min 10000.
|
||||||
maxAllowedIOError = 5
|
maxAllowedIOError = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// posix - implements StorageAPI interface.
|
// posix - implements StorageAPI interface.
|
||||||
|
@ -57,6 +57,9 @@ func checkPathLength(pathName string) error {
|
||||||
return errFileNameTooLong
|
return errFileNameTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert any '\' to '/'.
|
||||||
|
pathName = filepath.ToSlash(pathName)
|
||||||
|
|
||||||
// Check each path segment length is > 255
|
// Check each path segment length is > 255
|
||||||
for len(pathName) > 0 && pathName != "." && pathName != "/" {
|
for len(pathName) > 0 && pathName != "." && pathName != "/" {
|
||||||
dir, file := slashpath.Dir(pathName), slashpath.Base(pathName)
|
dir, file := slashpath.Dir(pathName), slashpath.Base(pathName)
|
||||||
|
@ -111,7 +114,7 @@ func newPosix(path string) (StorageAPI, error) {
|
||||||
fs := &posix{
|
fs := &posix{
|
||||||
diskPath: diskPath,
|
diskPath: diskPath,
|
||||||
minFreeSpace: fsMinFreeSpace,
|
minFreeSpace: fsMinFreeSpace,
|
||||||
minFreeInodes: fsMinFreeInodesPercent,
|
minFreeInodes: fsMinFreeInodes,
|
||||||
// 1MiB buffer pool for posix internal operations.
|
// 1MiB buffer pool for posix internal operations.
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
|
@ -120,17 +123,21 @@ func newPosix(path string) (StorageAPI, error) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
st, err := os.Stat(preparePath(diskPath))
|
fi, err := os.Stat(preparePath(diskPath))
|
||||||
if err != nil {
|
if err == nil {
|
||||||
if os.IsNotExist(err) {
|
if !fi.IsDir() {
|
||||||
// Disk not found create it.
|
return nil, syscall.ENOTDIR
|
||||||
err = os.MkdirAll(diskPath, 0777)
|
|
||||||
return fs, err
|
|
||||||
}
|
}
|
||||||
return fs, err
|
|
||||||
}
|
}
|
||||||
if !st.IsDir() {
|
if os.IsNotExist(err) {
|
||||||
return fs, syscall.ENOTDIR
|
// Disk not found create it.
|
||||||
|
err = os.MkdirAll(preparePath(diskPath), 0777)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = fs.checkDiskFree(); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return fs, nil
|
return fs, nil
|
||||||
}
|
}
|
||||||
|
@ -150,7 +157,14 @@ func getDiskInfo(diskPath string) (di disk.Info, err error) {
|
||||||
|
|
||||||
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
|
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
|
||||||
func (s *posix) checkDiskFree() (err error) {
|
func (s *posix) checkDiskFree() (err error) {
|
||||||
di, err := getDiskInfo(s.diskPath)
|
// We don't validate disk space or inode utilization on windows.
|
||||||
|
// Each windows calls to 'GetVolumeInformationW' takes around 3-5seconds.
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var di disk.Info
|
||||||
|
di, err = getDiskInfo(preparePath(s.diskPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -166,8 +180,8 @@ func (s *posix) checkDiskFree() (err error) {
|
||||||
// Allow for the available disk to be separately validate and we will validate inodes only if
|
// Allow for the available disk to be separately validate and we will validate inodes only if
|
||||||
// total inodes are provided by the underlying filesystem.
|
// total inodes are provided by the underlying filesystem.
|
||||||
if di.Files != 0 {
|
if di.Files != 0 {
|
||||||
availableFiles := 100 * float64(di.Ffree) / float64(di.Files)
|
availableFiles := int64(di.Ffree)
|
||||||
if int64(availableFiles) <= s.minFreeInodes {
|
if availableFiles <= s.minFreeInodes {
|
||||||
return errDiskFull
|
return errDiskFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +198,7 @@ func (s *posix) String() string {
|
||||||
// DiskInfo provides current information about disk space usage,
|
// DiskInfo provides current information about disk space usage,
|
||||||
// total free inodes and underlying filesystem.
|
// total free inodes and underlying filesystem.
|
||||||
func (s *posix) DiskInfo() (info disk.Info, err error) {
|
func (s *posix) DiskInfo() (info disk.Info, err error) {
|
||||||
return getDiskInfo(s.diskPath)
|
return getDiskInfo(preparePath(s.diskPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVolDir - will convert incoming volume names to
|
// getVolDir - will convert incoming volume names to
|
||||||
|
@ -199,6 +213,20 @@ func (s *posix) getVolDir(volume string) (string, error) {
|
||||||
return volumeDir, nil
|
return volumeDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkDiskFound - validates if disk is available,
|
||||||
|
// returns errDiskNotFound if not found.
|
||||||
|
func (s *posix) checkDiskFound() (err error) {
|
||||||
|
_, err = os.Stat(preparePath(s.diskPath))
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return errDiskNotFound
|
||||||
|
} else if isSysErrTooLong(err) {
|
||||||
|
return errFileNameTooLong
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Make a volume entry.
|
// Make a volume entry.
|
||||||
func (s *posix) MakeVol(volume string) (err error) {
|
func (s *posix) MakeVol(volume string) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -211,8 +239,7 @@ func (s *posix) MakeVol(volume string) (err error) {
|
||||||
return errFaultyDisk
|
return errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate if disk is free.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if err = s.checkDiskFree(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +273,11 @@ func (s *posix) ListVols() (volsInfo []VolInfo, err error) {
|
||||||
return nil, errFaultyDisk
|
return nil, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
volsInfo, err = listVols(s.diskPath)
|
if err = s.checkDiskFound(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
volsInfo, err = listVols(preparePath(s.diskPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -306,8 +337,7 @@ func (s *posix) StatVol(volume string) (volInfo VolInfo, err error) {
|
||||||
return VolInfo{}, errFaultyDisk
|
return VolInfo{}, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return VolInfo{}, err
|
return VolInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,8 +376,7 @@ func (s *posix) DeleteVol(volume string) (err error) {
|
||||||
return errFaultyDisk
|
return errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,8 +410,7 @@ func (s *posix) ListDir(volume, dirPath string) (entries []string, err error) {
|
||||||
return nil, errFaultyDisk
|
return nil, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,8 +447,7 @@ func (s *posix) ReadAll(volume, path string) (buf []byte, err error) {
|
||||||
return nil, errFaultyDisk
|
return nil, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +466,7 @@ func (s *posix) ReadAll(volume, path string) (buf []byte, err error) {
|
||||||
|
|
||||||
// Validate file path length, before reading.
|
// Validate file path length, before reading.
|
||||||
filePath := pathJoin(volumeDir, path)
|
filePath := pathJoin(volumeDir, path)
|
||||||
if err = checkPathLength(filePath); err != nil {
|
if err = checkPathLength(preparePath(filePath)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,8 +510,7 @@ func (s *posix) ReadFile(volume string, path string, offset int64, buf []byte) (
|
||||||
return 0, errFaultyDisk
|
return 0, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +529,7 @@ func (s *posix) ReadFile(volume string, path string, offset int64, buf []byte) (
|
||||||
|
|
||||||
// Validate effective path length before reading.
|
// Validate effective path length before reading.
|
||||||
filePath := pathJoin(volumeDir, path)
|
filePath := pathJoin(volumeDir, path)
|
||||||
if err = checkPathLength(filePath); err != nil {
|
if err = checkPathLength(preparePath(filePath)); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,8 +583,7 @@ func (s *posix) createFile(volume, path string) (f *os.File, err error) {
|
||||||
return nil, errFaultyDisk
|
return nil, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate if disk is free.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if err = s.checkDiskFree(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +601,7 @@ func (s *posix) createFile(volume, path string) (f *os.File, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := pathJoin(volumeDir, path)
|
filePath := pathJoin(volumeDir, path)
|
||||||
if err = checkPathLength(filePath); err != nil {
|
if err = checkPathLength(preparePath(filePath)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,6 +657,11 @@ func (s *posix) PrepareFile(volume, path string, fileSize int64) (err error) {
|
||||||
return errFaultyDisk
|
return errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate if disk is indeed free.
|
||||||
|
if err = s.checkDiskFree(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Create file if not found
|
// Create file if not found
|
||||||
w, err := s.createFile(volume, path)
|
w, err := s.createFile(volume, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -705,8 +735,7 @@ func (s *posix) StatFile(volume, path string) (file FileInfo, err error) {
|
||||||
return FileInfo{}, errFaultyDisk
|
return FileInfo{}, errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return FileInfo{}, err
|
return FileInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,7 +753,7 @@ func (s *posix) StatFile(volume, path string) (file FileInfo, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := slashpath.Join(volumeDir, path)
|
filePath := slashpath.Join(volumeDir, path)
|
||||||
if err = checkPathLength(filePath); err != nil {
|
if err = checkPathLength(preparePath(filePath)); err != nil {
|
||||||
return FileInfo{}, err
|
return FileInfo{}, err
|
||||||
}
|
}
|
||||||
st, err := os.Stat(preparePath(filePath))
|
st, err := os.Stat(preparePath(filePath))
|
||||||
|
@ -802,8 +831,7 @@ func (s *posix) DeleteFile(volume, path string) (err error) {
|
||||||
return errFaultyDisk
|
return errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disk availability.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if _, err = getDiskInfo(s.diskPath); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +851,7 @@ func (s *posix) DeleteFile(volume, path string) (err error) {
|
||||||
// Following code is needed so that we retain "/" suffix if any in
|
// Following code is needed so that we retain "/" suffix if any in
|
||||||
// path argument.
|
// path argument.
|
||||||
filePath := pathJoin(volumeDir, path)
|
filePath := pathJoin(volumeDir, path)
|
||||||
if err = checkPathLength(filePath); err != nil {
|
if err = checkPathLength(preparePath(filePath)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,8 +871,7 @@ func (s *posix) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err e
|
||||||
return errFaultyDisk
|
return errFaultyDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate if disk is free.
|
if err = s.checkDiskFound(); err != nil {
|
||||||
if err = s.checkDiskFree(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,11 +905,11 @@ func (s *posix) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err e
|
||||||
return errFileAccessDenied
|
return errFileAccessDenied
|
||||||
}
|
}
|
||||||
srcFilePath := slashpath.Join(srcVolumeDir, srcPath)
|
srcFilePath := slashpath.Join(srcVolumeDir, srcPath)
|
||||||
if err = checkPathLength(srcFilePath); err != nil {
|
if err = checkPathLength(preparePath(srcFilePath)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dstFilePath := slashpath.Join(dstVolumeDir, dstPath)
|
dstFilePath := slashpath.Join(dstVolumeDir, dstPath)
|
||||||
if err = checkPathLength(dstFilePath); err != nil {
|
if err = checkPathLength(preparePath(dstFilePath)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if srcIsDir {
|
if srcIsDir {
|
||||||
|
|
|
@ -536,23 +536,6 @@ func TestListVols(t *testing.T) {
|
||||||
if _, err = posixStorage.ListVols(); err != errDiskNotFound {
|
if _, err = posixStorage.ListVols(); err != errDiskNotFound {
|
||||||
t.Errorf("Expected to fail with \"%s\", but instead failed with \"%s\"", errDiskNotFound, err)
|
t.Errorf("Expected to fail with \"%s\", but instead failed with \"%s\"", errDiskNotFound, err)
|
||||||
}
|
}
|
||||||
// creating a new posix instance.
|
|
||||||
posixStorage, path, err = newPosixTestSetup()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create posix test setup, %s", err)
|
|
||||||
}
|
|
||||||
defer removeAll(path)
|
|
||||||
// adding the segment of the path length of the volume to be > 255.
|
|
||||||
if posixType, ok := posixStorage.(*posix); ok {
|
|
||||||
// setting the disk Path with name whose segment length > 255.
|
|
||||||
posixType.diskPath = "my-vol-name-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
|
|
||||||
} else {
|
|
||||||
t.Errorf("Expected the StorageAPI to be of type *posix")
|
|
||||||
}
|
|
||||||
if _, err = posixStorage.ListVols(); err != errFileNameTooLong {
|
|
||||||
t.Errorf("Expected to fail with \"%s\", but instead failed with \"%s\"", errFileNameTooLong, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPosixListDir - Tests validate the directory listing functionality provided by posix.ListDir .
|
// TestPosixListDir - Tests validate the directory listing functionality provided by posix.ListDir .
|
||||||
|
|
|
@ -24,6 +24,19 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
// GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
|
||||||
|
// Retrieves information about the amount of space that is available on a disk volume,
|
||||||
|
// which is the total amount of space, the total amount of free space, and the total
|
||||||
|
// amount of free space available to the user that is associated with the calling thread.
|
||||||
|
GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
|
||||||
|
// GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
|
||||||
|
// Retrieves information about the specified disk, including the amount of free space on the disk.
|
||||||
|
GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW")
|
||||||
|
)
|
||||||
|
|
||||||
// GetInfo returns total and free bytes available in a directory, e.g. `C:\`.
|
// GetInfo returns total and free bytes available in a directory, e.g. `C:\`.
|
||||||
// It returns free space available to the user (including quota limitations)
|
// It returns free space available to the user (including quota limitations)
|
||||||
//
|
//
|
||||||
|
@ -34,13 +47,6 @@ func GetInfo(path string) (info Info, err error) {
|
||||||
return Info{}, err
|
return Info{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dll := syscall.MustLoadDLL("kernel32.dll")
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
|
|
||||||
// Retrieves information about the amount of space that is available on a disk volume,
|
|
||||||
// which is the total amount of space, the total amount of free space, and the total
|
|
||||||
// amount of free space available to the user that is associated with the calling thread.
|
|
||||||
GetDiskFreeSpaceEx := dll.MustFindProc("GetDiskFreeSpaceExW")
|
|
||||||
|
|
||||||
lpFreeBytesAvailable := int64(0)
|
lpFreeBytesAvailable := int64(0)
|
||||||
lpTotalNumberOfBytes := int64(0)
|
lpTotalNumberOfBytes := int64(0)
|
||||||
lpTotalNumberOfFreeBytes := int64(0)
|
lpTotalNumberOfFreeBytes := int64(0)
|
||||||
|
@ -61,10 +67,6 @@ func GetInfo(path string) (info Info, err error) {
|
||||||
info.Free = int64(lpFreeBytesAvailable)
|
info.Free = int64(lpFreeBytesAvailable)
|
||||||
info.FSType = getFSType(path)
|
info.FSType = getFSType(path)
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
|
|
||||||
// Retrieves information about the specified disk, including the amount of free space on the disk.
|
|
||||||
GetDiskFreeSpace := dll.MustFindProc("GetDiskFreeSpaceW")
|
|
||||||
|
|
||||||
// Return values of GetDiskFreeSpace()
|
// Return values of GetDiskFreeSpace()
|
||||||
lpSectorsPerCluster := uint32(0)
|
lpSectorsPerCluster := uint32(0)
|
||||||
lpBytesPerSector := uint32(0)
|
lpBytesPerSector := uint32(0)
|
||||||
|
|
|
@ -24,11 +24,13 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// GetVolumeInformation provides windows drive volume information.
|
||||||
|
GetVolumeInformation = kernel32.NewProc("GetVolumeInformationW")
|
||||||
|
)
|
||||||
|
|
||||||
// getFSType returns the filesystem type of the underlying mounted filesystem
|
// getFSType returns the filesystem type of the underlying mounted filesystem
|
||||||
func getFSType(path string) string {
|
func getFSType(path string) string {
|
||||||
dll := syscall.MustLoadDLL("kernel32.dll")
|
|
||||||
GetVolumeInformation := dll.MustFindProc("GetVolumeInformationW")
|
|
||||||
|
|
||||||
var volumeNameSize uint32 = 260
|
var volumeNameSize uint32 = 260
|
||||||
var nFileSystemNameSize, lpVolumeSerialNumber uint32
|
var nFileSystemNameSize, lpVolumeSerialNumber uint32
|
||||||
var lpFileSystemFlags, lpMaximumComponentLength uint32
|
var lpFileSystemFlags, lpMaximumComponentLength uint32
|
||||||
|
|
Loading…
Reference in New Issue