github.com/tetratelabs/wazero@v1.2.1/internal/sysfs/rename_windows.go (about)

     1  package sysfs
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"syscall"
     7  
     8  	"github.com/tetratelabs/wazero/internal/platform"
     9  )
    10  
    11  func Rename(from, to string) syscall.Errno {
    12  	if from == to {
    13  		return 0
    14  	}
    15  
    16  	fromStat, err := os.Stat(from)
    17  	if err != nil {
    18  		return syscall.ENOENT
    19  	}
    20  
    21  	if toStat, err := os.Stat(to); err == nil {
    22  		fromIsDir, toIsDir := fromStat.IsDir(), toStat.IsDir()
    23  		if fromIsDir && !toIsDir { // dir to file
    24  			return syscall.ENOTDIR
    25  		} else if !fromIsDir && toIsDir { // file to dir
    26  			return syscall.EISDIR
    27  		} else if !fromIsDir && !toIsDir { // file to file
    28  			// Use os.Rename instead of syscall.Rename in order to allow the overrides of the existing file.
    29  			// Underneath os.Rename, it uses MoveFileEx instead of MoveFile (used by syscall.Rename).
    30  			return platform.UnwrapOSError(os.Rename(from, to))
    31  		} else { // dir to dir
    32  			if dirs, _ := os.ReadDir(to); len(dirs) == 0 {
    33  				// On Windows, renaming to the empty dir will be rejected,
    34  				// so first we remove the empty dir, and then rename to it.
    35  				if err := os.Remove(to); err != nil {
    36  					return platform.UnwrapOSError(err)
    37  				}
    38  				return platform.UnwrapOSError(syscall.Rename(from, to))
    39  			}
    40  			return syscall.ENOTEMPTY
    41  		}
    42  	} else if !errors.Is(err, syscall.ENOENT) { // Failed to stat the destination.
    43  		return platform.UnwrapOSError(err)
    44  	} else { // Destination not-exist.
    45  		return platform.UnwrapOSError(syscall.Rename(from, to))
    46  	}
    47  }