Even after removing an icon, os.Remove won’t delete the folder, also no matter what It’s a bug to not be able to remove a folder just because of an icon and people should not have to do manual actions to delete a folder.
It will be resolved when the patch I made on the Go repo will make it in a public release even if it’s not any time
If you want I can make a temporary patch for Syncthing while Go has not updated
More than three days spent proving that there is an issue, I went as far as proposing a solution, identifying exactly where in the code is the issue and patching the os lib.
I know it does because I did a unit test to check with or without patch and yes it has an impact, it’s amazing to have to go this far when I posted the screenshot just so that person under it says it is permission related when obviously it is not just looking at the screenshot 2 centimers over the reply button.
Would be ideal if we could programmatically create a dir with an icon. Then we can just have a unit test on it. Generally maybe just show the steps and outcome once with and once without the change. Then it’ll be clear.
Just to close the debate over the fact that an issue exists
package main
import (
"fmt"
"io/ioutil"
"os"
"syscall"
)
func main() {
path := "./folder_with_icon"
fmt.Println(count_files(path))
err := os.Remove(path + "/desktop.ini")
if err != nil {
panic(err)
}
fmt.Println(count_files(path)) // works fine up to here
err = os.Remove(path)
if err != nil {
panic(err)
}
}
func count_files(path string) int {
files, _ := ioutil.ReadDir(path)
return len(files)
}
func Remove(name string) error {
p, e := syscall.UTF16PtrFromString(name)
if e != nil {
return &os.PathError{Op: "remove", Path: name, Err: e}
}
// Go file interface forces us to know whether
// name is a file or directory. Try both.
e = syscall.DeleteFile(p)
if e == nil {
return nil
}
e1 := syscall.RemoveDirectory(p)
if e1 == nil {
return nil
} else {
//Empty directories with "read-only" attribute on Windows can cause issues so we have to try with chmod to remove it
a, e2 := syscall.GetFileAttributes(p)
if e2 == nil && a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 && os.IsPermission(e1) {
if fs, err := os.Stat(name); err == nil {
if err = os.Chmod(name, os.FileMode(0200|int(fs.Mode()))); err == nil {
e1 = syscall.RemoveDirectory(p)
}
}
}
}
// Both failed: figure out which error to return.
if e1 != e {
a, e2 := syscall.GetFileAttributes(p)
if e2 != nil {
e = e2
} else {
if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
e = e1
} else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 {
if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil {
if e = syscall.DeleteFile(p); e == nil {
return nil
}
}
}
}
}
return &os.PathError{Op: "remove", Path: name, Err: e}
}
Create a folder with an icon next to this code, try to delete with os, look at it fail.
Now look at it with the function patched under it and it works.