go 操作系统:在AIX上,Remove和RemoveAll无法删除当前目录,

s8vozzvw  于 5个月前  发布在  Go
关注(0)|答案(5)|浏览(55)

在AIX上,unlinkat或rmdir系统调用无法在当前工作目录(CWD)上工作。因此,像以下这样的程序无法删除GOPATH。

$ cat removeall.go
package main

import (
	"io/ioutil"
	"log"
	"os"
)

func main() {
	GOPATH, err := ioutil.TempDir("", "TestRemoveAll")
	if err != nil {
		log.Panic(err)
	}

	if err := os.Chdir(GOPATH); err != nil {
		log.Panic(err)
	}
	if err := os.Remove(GOPATH); err != nil {
		log.Panic(err)
	}
}
$ ./removeall.go
2019/05/22 09:29:19 remove /tmp/TestRemoveAll186232865: device busy
panic: remove /tmp/TestRemoveAll186232865: device busy

goroutine 1 [running]:
log.Panic(0xa00010000088f58, 0x1, 0x1)
        /opt/freeware/src/packages/BUILD/go-root/src/log/log.go:338 +0x9c
main.main()
        /opt/freeware/src/packages/BUILD/go-root/own_test/goprogs/removeall.go:19 +0x138
exit status 2

关于这个问题并没有真正的文档。然而,rmdir似乎会返回EBUSY和unlinkat EPERM。所以,我们应该能够检测到os.Remove是否因为这个原因而失败。但是,如果我们想要修复这个问题,正确的行为是什么呢?
我们是要切换到父目录("/tmp")吗?还是切换到可执行文件夹?还是做其他的事情?
或者我们想要保留这种行为吗?
需要注意的是,当调用os.Removeall时,除了目录本身之外的所有内容仍然会被删除。因此,只剩下一个空目录。但是,由于大多数测试都在进行defer os.Removeall,/tmp中充满了空目录......
其他操作系统是否也存在同样的问题?
编辑:POSIX rmdir没有指定必须执行哪种行为(参见https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html)
如果目录是根目录或任何进程的当前工作目录,则函数的成功与否以及是否应将其设置为[EBUSY]并失败是未指定的。

tjjdgumg

tjjdgumg1#

遗憾的是,POSIX没有定义这一点,因为据我所知,所有其他Unix系统都支持删除当前目录。我认为在这里我们无能为力。在一般情况下,我们不能执行 chdir ,因为这将意外地影响进程中的其他线程。

哪些测试会留下临时目录?看起来像测试辅助函数 chtmpdir ,位于os_test.go中,应该在AIX上删除临时目录,所以也许我们可以调整这些测试以使用 chtmpdir

busg9geu

busg9geu2#

我目前没有一个精确的列表,但它不仅仅涉及到测试。运行完 ./all.bash 后,我剩下的文件夹如下:
cgolife958293113:
cgostdio550024417:
go-build246746664:
go-build331120624:
go-build356351149:
go-build716678653:
go-build756358968:
cgolife 和 cgostdio 是其中的两个测试,它们都在调用 defer os.Removeall。我想我们应该能够在测试结束后返回到启动文件夹,而不影响其他线程。然而,我不知道 go-build 文件夹是从哪里来的。

rkue9o1l

rkue9o1l3#

仅供参考:这个问题,或者类似问题,在Windows上也存在。据我所知,Windows也无法删除一个被锁定的目录(包括当前工作目录)。我已经有一段时间没有运行构建器了,但你可能需要寻找一些特定于Windows的代码。

prdp8dxp

prdp8dxp4#

正如您所说,cgolife 目录来自misc/cgo/life/life_test.go。cgostdio 目录来自misc/cgo/stdio/stdio_test.go。修复这些测试应该很容易。

go-build 目录更有可能是在cmd/go/internal/work/action.go中的go工具创建的。但如果这些目录确实为空,很难知道是什么留下了它们。我建议暂时修改(*Builder).Init中的延迟函数,将go: failed to remove work dir情况更改为调用os.Exit(1)。这应该导致留下它们的测试失败,这样我们就可以看到是什么在做这件事。

zz2j4svz

zz2j4svz5#

FYI: this, or something similar to this was also a problem with windows. As far as I know, windows also can't remove a dir with a lock (including CWD). I haven't ran a builder in a while, but you may want to look for some windows specific code.
There is nothing obvious in os/file_windows.go. Maybe this is done on a case-by-case basis.
The go-build directories are more likely created by the go tool in (*Builder).Init in cmd/go/internal/work/action.go. But if the directories are indeed empty it's hard to know what left them. I suggest temporarily modifying the deferred function in (*Builder).Init to change the go: failed to remove work dir case to call os.Exit(1). That should cause the tests leaving them behind to fail, so we can see what is doing that.
I've tried but nothing occurred... It seems random once again. I'll update misc/cgo tests but will need to investigate more about those go-build.

相关问题