sysopen权限被拒绝

5
我正在尝试修复git-svn中的间歇性错误。问题仅在Windows XP上出现,使用Cygwin git(perl v5.10.1)和msysGit(perl v5.8.8)均有此问题。
对于任何涉及提取的操作,我可以完成部分操作,然后该操作会因以下类似消息而失败:
无法打开.git/svn/refs/remotes/trunk/.rev_map.cc05479a-e8ea-436f-8d71-e07493b7796c.lock:设备或资源忙,位于/usr/lib/git-core/git-svn line 5240
但是,确切的锁定文件和行号并不总是相同。我已将实际问题追踪到3679行。
sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)

这将创建一个新的.lock文件,我尝试了相应的方法但未成功。
open(my $fh, ">", $db_lock)

我检查了文件夹的权限,它是drwxr-xr-x,因此不应该有任何问题,如果有问题,也不会如此不一致。

这可能是因为脚本在快速连续创建并重命名此文件,导致XP无法处理吗?编辑:我怀疑情况是这样的,因为当我使用perl调试器并手动启动每个sysopen的执行时,我获取了100个修订版本,没有任何问题。

编辑:一些Git开发人员更喜欢找出根本原因,而不是采用恰好起作用的黑客行为(我认为是正确的方法)。那么,有谁能帮助我找到拒绝我打开这些.lock文件的罪犯?我有许多工具可以理论上用于此目的,但它们还没有全部完成:

  • 进程资源管理器-显示进程拥有的所有句柄,还可以搜索拥有给定句柄的所有进程。但是,对于短寿命进程或句柄(这就是git svn clone / fetch所做的操作),它效果不佳
  • Unlocker-检测到普通的“权限被拒绝”对话框出现,并找到引起问题的句柄并提供处理方法。但是,当非资源管理器程序遇到基于文件的错误时,它不会出现。
简而言之,我是否有办法在不成为微软员工的情况下获得更多信息?
编辑2:这可能不是Symantec,而是我们在网络计算机上运行的另一个程序。我让一些人调查,他们应该能够至少缩小原因范围。

那么,加入一个循环来重试到一定次数是否是一个好的修复方法,还是太过于粗糙了? - Nate Parsons
open(my $fh, "+<", $db_lock)是否等同于O_RDWR | O_CREAT - mob
@mobrule - 可能是,但重要的是创建。没有读取或写入操作发生。 - Nate Parsons
@Luke:他说是设备或资源忙(又称EBUSY),而不是访问被拒绝。 - ysth
@Luke,使用进程监视器是一个很好的建议。你能在回答中说一下吗,这样我就可以在那里评论了吗?Perl的$!告诉我“权限被拒绝”,但我在进程监视器中看到“FAST IO DISALLOWED”。现在正在查找它的含义。 - Nate Parsons
显示剩余2条评论
4个回答

7
通常情况下,这种行为可以归因于杀毒软件组件保持文件打开并延迟删除。

这也是我最好的猜测。我无法控制运行在机器上的防病毒软件,所以唯一的解决方案是改变Git,对吗?或者只改变msysGit? - Nate Parsons
你能暂时禁用它,看看问题是否消失吗?在你的问题中,你谈论找到和修复根本原因......如果杀毒软件有问题,那么你对git所做的任何更改都只是权宜之计。 - Ben Voigt
或者告诉你的IT部门,Symantec实际上并不起作用,而(你测试过的其他杀毒软件)运行良好。这肯定比在git中添加解决方法要费力,但是(1)还有成千上万的其他应用程序因Norton Antivirus中的错误而遇到问题,你的计算机上有多少个应用程序会遇到这些问题? (2)git团队非常不可能接受这样的解决方法,因此您将不得不为每个新版本的git重新制定解决方法。 - Ben Voigt
Symantec目前还没有给我带来任何问题(至少我不知道),而且我真的怀疑我能否让公司改用其他软件。也许如果我将补丁发送给msysGit? - Nate Parsons
1
@drhorrible:如果Symantec的问题需要“官方”提及,可以参考Cygwin不良应用程序大列表:http://cygwin.com/faq/faq.using.html#faq.using.bloda - ysth
显示剩余3条评论

5

我目前的折中解决方案是将sysopen替换为以下内容

my $fh;
if ($^O eq 'MSWin32' or $^O eq 'cygwin') {
   for my $try (1..10) { # Retry up to 10 times on problematic systems
       sysopen($fh, $db_lock, O_RDWR | O_CREAT);
       last if $fh;
   }
} else {
   sysopen($fh, $db_lock, O_RDWR | O_CREAT);
}

croak "Couldnt open $db_lock: $!\n" unless $fh;'

到目前为止,这种方法运行得相当不错。大部分时间它不会打印任何 '.',偶尔会打印一个,而我还没有看到它连续打印超过一个的情况。这个解决方案是否太过于折中?

编辑:我的代码已被 Ævar Arnfjörð Bjarmason 的优化版本替换。


这很有道理。许多代码缺乏健壮的行为。 - Axeman
1
我建议在那个循环中使用 Time::HiRes::sleep(.01)。另外,也许可以加上 last if $fh || $! != Errno::EBUSY - ysth
仍然没有确定原因,所以我将赏金颁给了自己。 - Nate Parsons

1

我会使用进程监视器(Process Monitor)并让它一直运行,直到再次失败。然后在进程监视器中,您应该可以看到程序访问文件时出现错误(很可能是ACCESS_DENIED或SHARING_VIOLATION)。然后,您可以按文件名进行筛选,并查看打开它的其他进程(如果有的话)。


我认为我得到的是“禁止快速IO”。 我应该在“路径”列上进行过滤,对吗? - Nate Parsons
你可以忽略"FAST IO DISALLOWED"信息,这是正常的。当发生错误时,应该将"Path"列过滤,仅包含导致错误的文件;这样可以显示出访问它的其他进程。 - Luke

1
如果你的程序在任何地方调用了 "fork()" 或 "system()" 或 "exec()",那么这很可能是问题的根源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接