This file is indexed.

/usr/share/tcltk/vfs1.3/ftpvfs.tcl is in tcl-vfs 1.3-20080503-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
package provide vfs::ftp 1.0

package require vfs 1.0
package require ftp

namespace eval vfs::ftp {
    # Number of milliseconds for which to cache listings
    variable cacheListingsFor 1000
}

proc vfs::ftp::Mount {dirurl local} {
    set dirurl [string trim $dirurl]
    ::vfs::log "ftp-vfs: attempt to mount $dirurl at $local"
    if {[string index $dirurl end] != "/"} {
	::vfs::log "ftp-vfs: adding missing directory delimiter to mount point"
	append dirurl "/"
    }
    
    set urlRE {(?:ftp://)?(?:([^@:]*)(?::([^@]*))?@)?([^/:]+)(?::([0-9]*))?/(.*/)?$} 
    if {![regexp $urlRE $dirurl - user pass host port path]} {
	return -code error "Sorry I didn't understand\
	  the url address \"$dirurl\""
    }
    
    if {![string length $user]} {
	set user anonymous
    }
    
    if {![string length $port]} {
	set port 21
    }
    
    set fd [::ftp::Open $host $user $pass -port $port -output ::vfs::ftp::log]
    if {$fd == -1} {
	error "Mount failed"
    }
    
    if {$path != ""} {
	if {[catch {
	    ::ftp::Cd $fd $path
	} err]} {
	    ftp::Close $fd
	    error "Opened ftp connection, but then received error: $err"
	}
    }
    
    if {![catch {vfs::filesystem info $dirurl}]} {
	# unmount old mount
	::vfs::log "ftp-vfs: unmounted old mount point at $dirurl"
	vfs::unmount $dirurl
    }
    ::vfs::log "ftp $host, $path mounted at $fd"
    vfs::filesystem mount $local [list vfs::ftp::handler $fd $path]
    # Register command to unmount
    vfs::RegisterMount $local [list ::vfs::ftp::Unmount $fd]
    return $fd
}

# Need this because vfs::log takes just one argument
proc vfs::ftp::log {args} {
    ::vfs::log $args
}

proc vfs::ftp::Unmount {fd local} {
    vfs::filesystem unmount $local
    ::ftp::Close $fd
}

proc vfs::ftp::handler {fd path cmd root relative actualpath args} {
    if {$cmd == "matchindirectory"} {
	eval [list $cmd $fd $relative $actualpath] $args
    } else {
	eval [list $cmd $fd $relative] $args
    }
}

proc vfs::ftp::attributes {fd} { return [list "state"] }
proc vfs::ftp::state {fd args} {
    vfs::attributeCantConfigure "state" "readwrite" $args
}

# If we implement the commands below, we will have a perfect
# virtual file system for remote ftp sites.

proc vfs::ftp::stat {fd name} {
    ::vfs::log "stat $name"
    if {$name == ""} {
	return [list type directory mtime 0 size 0 mode 0777 ino -1 \
	  depth 0 name "" dev -1 uid -1 gid -1 nlink 1]
    }
    # get information on the type of this file
    set ftpInfo [_findFtpInfo $fd $name]
    if {$ftpInfo == ""} { 
	vfs::filesystem posixerror $::vfs::posix(ENOENT)
    }
    ::vfs::log $ftpInfo
    set perms [lindex $ftpInfo 0]
    if {[string index $perms 0] == "d"} {
	lappend res type directory size 0
	set mtime 0
    } else {
	lappend res type file size [ftp::FileSize $fd $name]
	set mtime [ftp::ModTime $fd $name]
    }
    lappend res dev -1 uid -1 gid -1 nlink 1 depth 0 \
      atime $mtime ctime $mtime mtime $mtime mode 0777
    return $res
}

proc vfs::ftp::access {fd name mode} {
    ::vfs::log "ftp-access $name $mode"
    if {$name == ""} { return 1 }
    set info [_findFtpInfo $fd $name]
    if {[string length $info]} {
	return 1
    } else {
	vfs::filesystem posixerror $::vfs::posix(ENOENT)
    }
}

# We've chosen to implement these channels by using a memchan.
# The alternative would be to use temporary files.
proc vfs::ftp::open {fd name mode permissions} {
    ::vfs::log "open $name $mode $permissions"
    # return a list of two elements:
    # 1. first element is the Tcl channel name which has been opened
    # 2. second element (optional) is a command to evaluate when
    #    the channel is closed.
    switch -glob -- $mode {
	"" -
	"r" {
	    ftp::Get $fd $name -variable tmp

	    set filed [vfs::memchan]
	    set encoding [fconfigure $filed -encoding]
	    set eofchar [fconfigure $filed -eofchar]
	    set translation [fconfigure $filed -translation]
	    fconfigure $filed -translation binary
	    puts -nonewline $filed $tmp

	    fconfigure $filed -translation $translation -encoding $encoding -eofchar $eofchar
	    seek $filed 0
	    return [list $filed]
	}
	"a" {
	    # Try to append nothing to the file
	    if {[catch [list ::ftp::Append $fd -data "" $name] err] || !$err} {
		error "Can't open $name for appending"
	    }

	    set filed [vfs::memchan]
	    return [list $filed [list ::vfs::ftp::_closing $fd $name $filed Append]]
	}
	"w*" {
	    # Try to write an empty file
	    if {[catch [list ::ftp::Put $fd -data "" $name] err] || !$err} {
		error "Can't open $name for writing"
	    }

	    set filed [vfs::memchan]
	    return [list $filed [list ::vfs::ftp::_closing $fd $name $filed Put]]
	}
	default {
	    return -code error "illegal access mode \"$mode\""
	}
    }
}

proc vfs::ftp::_closing {fd name filed action} {
    seek $filed 0
    set contents [read $filed]
    set trans [fconfigure $filed -translation]
    if {$trans == "binary"} {
	set oldType [::ftp::Type $fd]
	::ftp::Type $fd binary
    }
    if {![::ftp::$action $fd -data $contents $name]} {
	# Would be better if we could be more specific here, with
	# one of ENETRESET ENETDOWN ENETUNREACH or whatever.
	vfs::filesystem posixerror $::vfs::posix(EIO)
	#error "Failed to write to $name"
    }
    if {[info exists oldType]} {
	::ftp::Type $fd $oldType
    }
}

proc vfs::ftp::_findFtpInfo {fd name} {
    ::vfs::log "findFtpInfo $fd $name"
    set ftpList [cachedList $fd [file dirname $name]]
    foreach p $ftpList {
	foreach {pname other} [_parseListLine $p] {}
	if {$pname == [file tail $name]} {
	    return $other
	}
    }
    return ""
}

proc vfs::ftp::cachedList {fd dir} {
    variable cacheList
    variable cacheListingsFor
    
    # Caches response to prevent going back to the ftp server
    # for common use cases: foreach {f} [glob *] { file stat $f s }
    if {[info exists cacheList($dir)]} {
	return $cacheList($dir)
    }
    set listing [ftp::List $fd $dir]

    set cacheList($dir) $listing
    after $cacheListingsFor [list unset -nocomplain ::vfs::ftp::cacheList($dir)]
    return $listing
}

# Currently returns a list of name and a list of other
# information.  The other information is currently a 
# list of:
# () permissions
# () size
proc vfs::ftp::_parseListLine {line} {
    # Check for filenames with spaces
    if {[regexp {([^ ]|[^0-9] )+$} $line name]} {
	# Check for links
	if {[set idx [string first " -> " $name]] != -1} {
	    incr idx -1
	    set name [string range $name 0 $idx]
	}
    }
    regsub -all "\[ \t\]+" $line " " line
    set items [split $line " "]

    if {![info exists name]} {set name [lindex $items end]}
    lappend other [lindex $items 0]
    if {[string is integer [lindex $items 4]]} {
	lappend other [lindex $items 4]
    }
    
    return [list $name $other]
}

proc vfs::ftp::matchindirectory {fd path actualpath pattern type} {
    ::vfs::log "matchindirectory $fd $path $actualpath $pattern $type"
    set res [list]
    if {![string length $pattern]} {
	# matching a single file
	set ftpInfo [_findFtpInfo $fd $path]
	if {$ftpInfo != ""} {
	    # Now check if types match
	    set perms [lindex $ftpInfo 0]
	    if {[string index $perms 0] == "d"} {
		if {[::vfs::matchDirectories $type]} {
		    lappend res $actualpath
		}
	    } else {
		if {[::vfs::matchFiles $type]} {
		    lappend res $actualpath
		}
	    }
	}
    } else {
	# matching all files in the given directory
	set ftpList [cachedList $fd $path]
	::vfs::log "ftpList: $ftpList"

	foreach p $ftpList {
	    foreach {name perms} [_parseListLine $p] {}
	    if {![string match $pattern $name]} {
		continue 
	    } 
	    if {[::vfs::matchDirectories $type]} {
		if {[string index $perms 0] == "d"} {
		    lappend res [file join $actualpath $name]
		}
	    }
	    if {[::vfs::matchFiles $type]} {
		if {[string index $perms 0] != "d"} {
		    lappend res [file join $actualpath $name]
		}
	    }
	    
	}
    }
 
    return $res
}

proc vfs::ftp::createdirectory {fd name} {
    ::vfs::log "createdirectory $name"
    if {![ftp::MkDir $fd $name]} {
	# Can we be more specific here?
	vfs::filesystem posixerror $::vfs::posix(EACCES)
    }
}

proc vfs::ftp::removedirectory {fd name recursive} {
    ::vfs::log "removedirectory $name $recursive"
    if {![ftp::RmDir $fd $name]} {
	# Can we be more specific here?
	if {$recursive} {
	    vfs::filesystem posixerror $::vfs::posix(EACCES)
	} else {
	    vfs::filesystem posixerror $::vfs::posix(EACCES)
	}
    }
}

proc vfs::ftp::deletefile {fd name} {
    ::vfs::log "deletefile $name"
    if {![ftp::Delete $fd $name]} {
	# Can we be more specific here?
	vfs::filesystem posixerror $::vfs::posix(EACCES)
    }
}

proc vfs::ftp::fileattributes {fd path args} {
    ::vfs::log "fileattributes $args"
    switch -- [llength $args] {
	0 {
	    # list strings
	    return [list]
	}
	1 {
	    # get value
	    set index [lindex $args 0]
	    vfs::filesystem posixerror $::vfs::posix(ENODEV)
	}
	2 {
	    # set value
	    set index [lindex $args 0]
	    set val [lindex $args 1]
	    vfs::filesystem posixerror $::vfs::posix(ENODEV)
	}
    }
}

proc vfs::ftp::utime {fd path actime mtime} {
    # Will throw an error if ftp package is old and only
    # handles 2 arguments.  But that is ok -- Tcl will give the
    # user an appropriate error message.
    ftp::ModTime $fd $path $mtime
}