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 }