github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/os_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 // Copyright (c) 2015-2021 MinIO, Inc. 5 // 6 // This file is part of MinIO Object Storage stack 7 // 8 // This program is free software: you can redistribute it and/or modify 9 // it under the terms of the GNU Affero General Public License as published by 10 // the Free Software Foundation, either version 3 of the License, or 11 // (at your option) any later version. 12 // 13 // This program is distributed in the hope that it will be useful 14 // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 // GNU Affero General Public License for more details. 17 // 18 // You should have received a copy of the GNU Affero General Public License 19 // along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21 package cmd 22 23 import ( 24 "os" 25 "path/filepath" 26 "syscall" 27 ) 28 29 func access(name string) error { 30 _, err := os.Lstat(name) 31 return err 32 } 33 34 func osMkdirAll(dirPath string, perm os.FileMode, _ string) error { 35 // baseDir is not honored in windows platform 36 return os.MkdirAll(dirPath, perm) 37 } 38 39 // readDirFn applies the fn() function on each entries at dirPath, doesn't recurse into 40 // the directory itself, if the dirPath doesn't exist this function doesn't return 41 // an error. 42 func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error) error { 43 // Ensure we don't pick up files as directories. 44 globAll := filepath.Clean(dirPath) + `\*` 45 globAllP, err := syscall.UTF16PtrFromString(globAll) 46 if err != nil { 47 return errInvalidArgument 48 } 49 data := &syscall.Win32finddata{} 50 handle, err := syscall.FindFirstFile(globAllP, data) 51 if err != nil { 52 if err = syscallErrToFileErr(dirPath, err); err == errFileNotFound { 53 return nil 54 } 55 return err 56 } 57 defer syscall.FindClose(handle) 58 59 for ; ; err = syscall.FindNextFile(handle, data) { 60 if err != nil { 61 if err == syscall.ERROR_NO_MORE_FILES { 62 break 63 } else { 64 if isSysErrPathNotFound(err) { 65 return nil 66 } 67 err = osErrToFileErr(&os.PathError{ 68 Op: "FindNextFile", 69 Path: dirPath, 70 Err: err, 71 }) 72 if err == errFileNotFound { 73 return nil 74 } 75 return err 76 } 77 } 78 name := syscall.UTF16ToString(data.FileName[0:]) 79 if name == "" || name == "." || name == ".." { // Useless names 80 continue 81 } 82 83 var typ os.FileMode // regular file 84 switch { 85 case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0: 86 // Reparse point is a symlink 87 fi, err := os.Stat(pathJoin(dirPath, name)) 88 if err != nil { 89 // It got deleted in the meantime, not found 90 // or returns too many symlinks ignore this 91 // file/directory. 92 if osIsNotExist(err) || isSysErrPathNotFound(err) || 93 isSysErrTooManySymlinks(err) { 94 continue 95 } 96 return err 97 } 98 99 if fi.IsDir() { 100 // Ignore symlinked directories. 101 continue 102 } 103 104 typ = fi.Mode() 105 case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0: 106 typ = os.ModeDir 107 } 108 109 if err = filter(name, typ); err == errDoneForNow { 110 // filtering requested to return by caller. 111 return nil 112 } 113 } 114 115 return nil 116 } 117 118 // Return N entries at the directory dirPath. 119 func readDirWithOpts(dirPath string, opts readDirOpts) (entries []string, err error) { 120 // Ensure we don't pick up files as directories. 121 globAll := filepath.Clean(dirPath) + `\*` 122 globAllP, err := syscall.UTF16PtrFromString(globAll) 123 if err != nil { 124 return nil, errInvalidArgument 125 } 126 data := &syscall.Win32finddata{} 127 handle, err := syscall.FindFirstFile(globAllP, data) 128 if err != nil { 129 return nil, syscallErrToFileErr(dirPath, err) 130 } 131 132 defer syscall.FindClose(handle) 133 134 count := opts.count 135 for ; count != 0; err = syscall.FindNextFile(handle, data) { 136 if err != nil { 137 if err == syscall.ERROR_NO_MORE_FILES { 138 break 139 } else { 140 return nil, osErrToFileErr(&os.PathError{ 141 Op: "FindNextFile", 142 Path: dirPath, 143 Err: err, 144 }) 145 } 146 } 147 148 name := syscall.UTF16ToString(data.FileName[0:]) 149 if name == "" || name == "." || name == ".." { // Useless names 150 continue 151 } 152 153 switch { 154 case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0: 155 // Reparse point is a symlink 156 fi, err := os.Stat(pathJoin(dirPath, name)) 157 if err != nil { 158 // It got deleted in the meantime, not found 159 // or returns too many symlinks ignore this 160 // file/directory. 161 if osIsNotExist(err) || isSysErrPathNotFound(err) || 162 isSysErrTooManySymlinks(err) { 163 continue 164 } 165 return nil, err 166 } 167 168 if !opts.followDirSymlink && fi.IsDir() { 169 // directory symlinks are ignored. 170 continue 171 } 172 case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0: 173 name += SlashSeparator 174 } 175 176 count-- 177 entries = append(entries, name) 178 179 } 180 181 return entries, nil 182 } 183 184 func globalSync() { 185 // no-op on windows 186 } 187 188 func syscallErrToFileErr(dirPath string, err error) error { 189 switch err { 190 case nil: 191 return nil 192 case syscall.ERROR_FILE_NOT_FOUND: 193 return errFileNotFound 194 case syscall.ERROR_ACCESS_DENIED: 195 return errFileAccessDenied 196 default: 197 // Fails on file not found and when not a directory. 198 return osErrToFileErr(&os.PathError{ 199 Op: "FindNextFile", 200 Path: dirPath, 201 Err: err, 202 }) 203 } 204 }