storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/os-readdir_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package cmd 21 22 import ( 23 "io" 24 "os" 25 "syscall" 26 ) 27 28 func access(name string) error { 29 _, err := os.Lstat(name) 30 return err 31 } 32 33 // Return all the entries at the directory dirPath. 34 func readDir(dirPath string) (entries []string, err error) { 35 return readDirN(dirPath, -1) 36 } 37 38 // readDirFn applies the fn() function on each entries at dirPath, doesn't recurse into 39 // the directory itself, if the dirPath doesn't exist this function doesn't return 40 // an error. 41 func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error) error { 42 f, err := os.Open(dirPath) 43 if err != nil { 44 if osErrToFileErr(err) == errFileNotFound { 45 return nil 46 } 47 return osErrToFileErr(err) 48 } 49 defer f.Close() 50 51 // Check if file or dir. This is the quickest way. 52 // Do not remove this check, on windows syscall.FindNextFile 53 // would throw an exception if Fd() points to a file 54 // instead of a directory, we need to quickly fail 55 // in such situations - this workadound is expected. 56 if _, err = f.Seek(0, io.SeekStart); err == nil { 57 return errFileNotFound 58 } 59 60 data := &syscall.Win32finddata{} 61 for { 62 e := syscall.FindNextFile(syscall.Handle(f.Fd()), data) 63 if e != nil { 64 if e == syscall.ERROR_NO_MORE_FILES { 65 break 66 } else { 67 if isSysErrPathNotFound(e) { 68 return nil 69 } 70 err = osErrToFileErr(&os.PathError{ 71 Op: "FindNextFile", 72 Path: dirPath, 73 Err: e, 74 }) 75 if err == errFileNotFound { 76 return nil 77 } 78 return err 79 } 80 } 81 name := syscall.UTF16ToString(data.FileName[0:]) 82 if name == "" || name == "." || name == ".." { // Useless names 83 continue 84 } 85 86 var typ os.FileMode = 0 // regular file 87 switch { 88 case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0: 89 // Reparse point is a symlink 90 fi, err := os.Stat(pathJoin(dirPath, string(name))) 91 if err != nil { 92 // It got deleted in the meantime, not found 93 // or returns too many symlinks ignore this 94 // file/directory. 95 if osIsNotExist(err) || isSysErrPathNotFound(err) || 96 isSysErrTooManySymlinks(err) { 97 continue 98 } 99 return err 100 } 101 102 if fi.IsDir() { 103 // Ignore symlinked directories. 104 continue 105 } 106 107 typ = fi.Mode() 108 case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0: 109 typ = os.ModeDir 110 } 111 112 if e = filter(name, typ); e == errDoneForNow { 113 // filtering requested to return by caller. 114 return nil 115 } 116 } 117 118 return nil 119 } 120 121 // Return N entries at the directory dirPath. If count is -1, return all entries 122 func readDirN(dirPath string, count int) (entries []string, err error) { 123 f, err := os.Open(dirPath) 124 if err != nil { 125 return nil, osErrToFileErr(err) 126 } 127 defer f.Close() 128 129 // Check if file or dir. This is the quickest way. 130 // Do not remove this check, on windows syscall.FindNextFile 131 // would throw an exception if Fd() points to a file 132 // instead of a directory, we need to quickly fail 133 // in such situations - this workadound is expected. 134 if _, err = f.Seek(0, io.SeekStart); err == nil { 135 return nil, errFileNotFound 136 } 137 138 data := &syscall.Win32finddata{} 139 handle := syscall.Handle(f.Fd()) 140 141 for count != 0 { 142 e := syscall.FindNextFile(handle, data) 143 if e != nil { 144 if e == syscall.ERROR_NO_MORE_FILES { 145 break 146 } else { 147 return nil, osErrToFileErr(&os.PathError{ 148 Op: "FindNextFile", 149 Path: dirPath, 150 Err: e, 151 }) 152 } 153 } 154 155 name := syscall.UTF16ToString(data.FileName[0:]) 156 if name == "" || name == "." || name == ".." { // Useless names 157 continue 158 } 159 160 switch { 161 case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0: 162 // Reparse point is a symlink 163 fi, err := os.Stat(pathJoin(dirPath, string(name))) 164 if err != nil { 165 // It got deleted in the meantime, not found 166 // or returns too many symlinks ignore this 167 // file/directory. 168 if osIsNotExist(err) || isSysErrPathNotFound(err) || 169 isSysErrTooManySymlinks(err) { 170 continue 171 } 172 return nil, err 173 } 174 175 if fi.IsDir() { 176 // directory symlinks are ignored. 177 continue 178 } 179 case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0: 180 name = name + SlashSeparator 181 } 182 183 count-- 184 entries = append(entries, name) 185 186 } 187 188 return entries, nil 189 } 190 191 func globalSync() { 192 // no-op on windows 193 }