github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/sysfs/rename_windows.go (about)

     1  package sysfs
     2  
     3  import (
     4  	"os"
     5  	"syscall"
     6  
     7  	"github.com/wasilibs/wazerox/experimental/sys"
     8  )
     9  
    10  func rename(from, to string) sys.Errno {
    11  	if from == to {
    12  		return 0
    13  	}
    14  
    15  	var fromIsDir, toIsDir bool
    16  	if fromStat, errno := stat(from); errno != 0 {
    17  		return errno // failed to stat from
    18  	} else {
    19  		fromIsDir = fromStat.Mode.IsDir()
    20  	}
    21  	if toStat, errno := stat(to); errno == sys.ENOENT {
    22  		return syscallRename(from, to) // file or dir to not-exist is ok
    23  	} else if errno != 0 {
    24  		return errno // failed to stat to
    25  	} else {
    26  		toIsDir = toStat.Mode.IsDir()
    27  	}
    28  
    29  	// Now, handle known cases
    30  	switch {
    31  	case !fromIsDir && toIsDir: // file to dir
    32  		return sys.EISDIR
    33  	case !fromIsDir && !toIsDir: // file to file
    34  		// Use os.Rename instead of syscall.Rename to overwrite a file.
    35  		// This uses MoveFileEx instead of MoveFile (used by syscall.Rename).
    36  		return sys.UnwrapOSError(os.Rename(from, to))
    37  	case fromIsDir && !toIsDir: // dir to file
    38  		return sys.ENOTDIR
    39  	default: // dir to dir
    40  
    41  		// We can't tell if a directory is empty or not, via stat information.
    42  		// Reading the directory is expensive, as it can buffer large amounts
    43  		// of data on fail. Instead, speculatively try to remove the directory.
    44  		// This is only one syscall and won't buffer anything.
    45  		if errno := rmdir(to); errno == 0 || errno == sys.ENOENT {
    46  			return syscallRename(from, to)
    47  		} else {
    48  			return errno
    49  		}
    50  	}
    51  }
    52  
    53  func syscallRename(from string, to string) sys.Errno {
    54  	return sys.UnwrapOSError(syscall.Rename(from, to))
    55  }