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  }