使用fileutil :: traverse时如何处理权限被拒绝

时间:2013-07-13 19:51:53

标签: tcl

问题

我不是Tcl新手,这个问题困扰着我。我想遍历目录树,并处理或忽略那些我没有权限的子目录或文件。这是一个小样本代码:

#!/usr/bin/env tclsh

package require fileutil::traverse

proc errorHandler {absPath errorMessage} {
    puts "ERROR: $absPath $errorMessage"
}

# Main
set searchDir /tmp
fileutil::traverse t $searchDir -errorcmd errorHandler

puts "\nFiles in $searchDir:"
t foreach fileName {
    puts $fileName
}

输出:

...
couldn't read directory "/tmp/launchd-56801.nzZRsA/": permission denied
    while executing
"glob -nocomplain -directory $current -types f          -- *"
    (procedure "GLOBF" line 2)
    invoked from within
"GLOBF $top"
    (procedure "::fileutil::traverse::Snit_methodnext" line 44)
    invoked from within
"$self next currentfile"
    (procedure "::fileutil::traverse::Snit_methodforeach" line 11)
    invoked from within
"t foreach fileName {
    puts $fileName
}"
    (file "./traverser1.tcl" line 17)

我知道问题:我没有权限阅读某些子目录。这就是我为每个文档放入错误处理程序的原因。但是,从未调用该错误处理程序。我怀疑这是Tcl中的一个错误,但这可能意味着我误解了文档并且没有使用正确的包。我感谢任何帮助或建议来解决这个问题。

我的环境

  • Mac OS X Moutain Lion
  • Tcl 8.5.9

更新

我查看了适用于Mac OS X 10.8.4 Moutain Lion和1.15版本的1.12版fileutil::traverse的来源 - 最新版本。我找到的是:

method next {fvar} {
    # code ...
    if {![ACCESS $top]} {
        Error ...
        ...

但对于Tcl 8.4或更高版本,ACCESS的实现是:

proc ::fileutil::traverse::ACCESS {args} {return 1}

而Tcl 8.3的实现是:

proc ::fileutil::traverse::ACCESS {current} {
    if {[catch {
        set h [pwd] ; cd $current ; cd $h
    }]} {return 0}
    return 1
}

当我用8.3版本替换8.4版本时,一切正常。这告诉我这是代码中的错误。我不知道为什么会这样。

1 个答案:

答案 0 :(得分:2)

我通过添加预过滤器找到了解决方法,该过滤器尝试cd进入目录并在目录可访问时返回True:

#!/usr/bin/env tclsh

package require fileutil::traverse

# isAccessible: determines if the directory is accessible by attempting to cd into it
proc isAccessible {absPath} {
    set currentDir [pwd]
    if {[catch {cd $absPath}]} {
        set chdirOK False
    } else {
        set chdirOK True
    }
    cd $currentDir
    return $chdirOK
}

# Main
set searchDir /tmp
fileutil::traverse t $searchDir -prefilter isAccessible

puts "\nFiles in $searchDir:"
t foreach fileName {
    puts $fileName
}

更新

Donal的建议是一个伟大的建议:它有效,短而甜:

proc isAccessible {absPath} {
    return [file readable $absPath]
}

我们甚至可以完全放弃isAccessible

fileutil::traverse t $searchDir -prefilter "file readable"