Tcl Library Source Code

Changes On Branch tkt-9f4c0e3e95-ak
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch tkt-9f4c0e3e95-ak Excluding Merge-Ins

This is equivalent to a diff from e1f5469305 to 5438cefd17

2017-05-29
18:36
Merged fix for tar::get (Ticket 9f4c0e3e95). check-in: 21cf0660cc user: aku tags: trunk
18:34
Fixed issue. Further modified tar::get to throw an error when not finding the requeste file. Updated docs and tests to match. Bumped version to 0.11. Closed-Leaf check-in: 5438cefd17 user: aku tags: tkt-9f4c0e3e95-ak
18:05
Converted example into testcases. Issue confirmed. check-in: d5f927261b user: aku tags: tkt-9f4c0e3e95-ak
17:17
Merged last bit from ticket branch. Final. check-in: e1f5469305 user: aku tags: trunk
17:16
Added another test to validate the the Critcl implementation is truly ok. Closed-Leaf check-in: 1a871993e4 user: aku tags: tkt-39ab616d8f-ak
17:05
Merged fix for ticket 39ab616d8f (struct::graph dfs pre walk multi-entry issue) check-in: 89bf85ed39 user: aku tags: trunk

Changes to modules/tar/pkgIndex.tcl.

1
2
3
4
5
if {![package vsatisfies [package provide Tcl] 8.4]} {
    # PRAGMA: returnok
    return
}
package ifneeded tar 0.10 [list source [file join $dir tar.tcl]]




|
1
2
3
4
5
if {![package vsatisfies [package provide Tcl] 8.4]} {
    # PRAGMA: returnok
    return
}
package ifneeded tar 0.11 [list source [file join $dir tar.tcl]]

Changes to modules/tar/tar.man.

1
2
3
4
5
6
7
8
[vset PACKAGE_VERSION 0.10]
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin tar n [vset PACKAGE_VERSION]]
[keywords archive]
[keywords {tape archive}]
[keywords tar]
[moddesc   {Tar file handling}]
[titledesc {Tar file creation, extraction & manipulation}]
|







1
2
3
4
5
6
7
8
[vset PACKAGE_VERSION 0.11]
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin tar n [vset PACKAGE_VERSION]]
[keywords archive]
[keywords {tape archive}]
[keywords tar]
[moddesc   {Tar file handling}]
[titledesc {Tar file creation, extraction & manipulation}]
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
% foreach {file size} [::tar::untar tarball.tar -glob *.jpg] {
puts "Extracted $file ($size bytes)"
}
}]

[call [cmd ::tar::get] [arg tarball] [arg fileName] [opt [option -chan]]]

Returns the contents of [arg fileName] from the [arg tarball]
[para]

[example {
% set readme [::tar::get tarball.tar doc/README] {
% puts $readme
}
}]

[para]
If the option [option -chan] is present [arg tarball] is interpreted as an open channel.

It is assumed that the channel was opened for reading, and configured for binary input.
The command will [emph not] close the channel.




[call [cmd ::tar::create] [arg tarball] [arg files] [arg args]]

Creates a new tar file containing the [arg files]. [arg files] must be specified
as a single argument which is a proper list of filenames.

[list_begin options]







|
<

|





<
|
>
|
|
>
>
>







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
% foreach {file size} [::tar::untar tarball.tar -glob *.jpg] {
puts "Extracted $file ($size bytes)"
}
}]

[call [cmd ::tar::get] [arg tarball] [arg fileName] [opt [option -chan]]]

Returns the contents of [arg fileName] from the [arg tarball].


[para][example {
% set readme [::tar::get tarball.tar doc/README] {
% puts $readme
}
}]


[para] If the option [option -chan] is present [arg tarball] is
interpreted as an open channel.  It is assumed that the channel was
opened for reading, and configured for binary input.  The command will
[emph not] close the channel.

[para] An error is thrown when [arg fileName] is not found in the tar
archive.

[call [cmd ::tar::create] [arg tarball] [arg files] [arg args]]

Creates a new tar file containing the [arg files]. [arg files] must be specified
as a single argument which is a proper list of filenames.

[list_begin options]

Changes to modules/tar/tar.tcl.

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
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tar.tcl,v 1.17 2012/09/11 17:22:24 andreas_kupries Exp $

package require Tcl 8.4
package provide tar 0.10

namespace eval ::tar {}

proc ::tar::parseOpts {acc opts} {
    array set flags $acc
    foreach {x y} $acc {upvar $x $x}
    
    set len [llength $opts]
    set i 0
    while {$i < $len} {
        set name [string trimleft [lindex $opts $i] -]
        if {![info exists flags($name)]} {return -code error "unknown option \"$name\""}



        if {$flags($name) == 1} {
            set $name [lindex $opts [expr {$i + 1}]]
            incr i $flags($name)
        } elseif {$flags($name) > 1} {
            set $name [lrange $opts [expr {$i + 1}] [expr {$i + $flags($name)}]]
            incr i $flags($name)
        } else {







|











|
>
>
>







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
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tar.tcl,v 1.17 2012/09/11 17:22:24 andreas_kupries Exp $

package require Tcl 8.4
package provide tar 0.11

namespace eval ::tar {}

proc ::tar::parseOpts {acc opts} {
    array set flags $acc
    foreach {x y} $acc {upvar $x $x}
    
    set len [llength $opts]
    set i 0
    while {$i < $len} {
        set name [string trimleft [lindex $opts $i] -]
        if {![info exists flags($name)]} {
	    return -errorcode {TAR INVALID OPTION} \
		-code error "unknown option \"$name\""
	}
        if {$flags($name) == 1} {
            set $name [lindex $opts [expr {$i + 1}]]
            incr i $flags($name)
        } elseif {$flags($name) > 1} {
            set $name [lrange $opts [expr {$i + 1}] [expr {$i + $flags($name)}]]
            incr i $flags($name)
        } else {
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
    if {$pad == 512} {return 0}
    return $pad
}

proc ::tar::seekorskip {ch off wh} {
    if {[tell $ch] < 0} {
	if {$wh!="current"} {

	    error "WHENCE=$wh not supported on non-seekable channel $ch"
	}
	skip $ch $off
	return
    }
    seek $ch $off $wh
    return
}







>
|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    if {$pad == 512} {return 0}
    return $pad
}

proc ::tar::seekorskip {ch off wh} {
    if {[tell $ch] < 0} {
	if {$wh!="current"} {
	    return -code error -errorcode [LIST TAR INVALID WHENCE $wh] \
		"WHENCE=$wh not supported on non-seekable channel $ch"
	}
	skip $ch $off
	return
    }
    seek $ch $off $wh
    return
}
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
	set fh [::open $tar]
	fconfigure $fh -encoding binary -translation lf -eofchar {}
    }
    while {![eof $fh]} {
	set data [read $fh 512]
        array set header [readHeader $data]
	HandleLongLink $fh header
        if {$header(name) == ""} break
	if {$header(prefix) != ""} {append header(prefix) /}
        set name [string trimleft $header(prefix)$header(name) /]
        if {$name == $file} {
            set file [read $fh $header(size)]
            if {!$chan} {
		close $fh
	    }
            return $file
        }
        seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
    }
    if {!$chan} {
	close $fh
    }
    return {}

}

proc ::tar::untar {tar args} {
    set nooverwrite 0
    set data 0
    set nomtime 0
    set noperms 0







|
|

|











|
>







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
	set fh [::open $tar]
	fconfigure $fh -encoding binary -translation lf -eofchar {}
    }
    while {![eof $fh]} {
	set data [read $fh 512]
        array set header [readHeader $data]
	HandleLongLink $fh header
        if {$header(name) eq ""} break
	if {$header(prefix) ne ""} {append header(prefix) /}
        set name [string trimleft $header(prefix)$header(name) /]
        if {$name eq $file} {
            set file [read $fh $header(size)]
            if {!$chan} {
		close $fh
	    }
            return $file
        }
        seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
    }
    if {!$chan} {
	close $fh
    }
    return -code error -errorcode {TAR MISSING FILE} \
	"Tar \"$tar\": File \"$file\" not found"
}

proc ::tar::untar {tar args} {
    set nooverwrite 0
    set data 0
    set nomtime 0
    set noperms 0
375
376
377
378
379
380
381

382
383
384
385

386
387
388
389
390
391
392
393
    set osize  [format %o $A(size)]
    set ogid   [format %o $A(gid)]
    set ouid   [format %o $A(uid)]
    set omtime [format %o $A(mtime)]
    
    set name [string trimleft $name /]
    if {[string length $name] > 255} {

        return -code error "path name over 255 chars"
    } elseif {[string length $name] > 100} {
	set common [string range $name end-99 154]
	if {[set splitpoint [string first / $common]] == -1} {

	    return -code error "path name cannot be split into prefix and name"
	}
	set prefix [string range $name 0 end-100][string range $common 0 $splitpoint-1]
	set name   [string range $common $splitpoint+1 end][string range $name 155 end]
    } else {
        set prefix ""
    }








>
|



>
|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
    set osize  [format %o $A(size)]
    set ogid   [format %o $A(gid)]
    set ouid   [format %o $A(uid)]
    set omtime [format %o $A(mtime)]
    
    set name [string trimleft $name /]
    if {[string length $name] > 255} {
        return -code error -errorcode {TAR BAD PATH LENGTH} \
	    "path name over 255 chars"
    } elseif {[string length $name] > 100} {
	set common [string range $name end-99 154]
	if {[set splitpoint [string first / $common]] == -1} {
	    return -code error -errorcode {TAR BAD PATH UNSPLITTABLE} \
		"path name cannot be split into prefix and name"
	}
	set prefix [string range $name 0 end-100][string range $common 0 $splitpoint-1]
	set name   [string range $common $splitpoint+1 end][string range $name 155 end]
    } else {
        set prefix ""
    }

Changes to modules/tar/tar.test.

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
    seek $chan1 0
    lappend res [string trim [tar::get $chan1 $tmpdir/one/two/a -chan]]
} -cleanup {
    cleanup1
} -result {tartest/one/a tartest/one/two/a tartest/one/three/a hello2}


test tar-bug-2840180 {} -setup {
    setup2
} -body {
    tar::create $chan1 [list $tmpdir/[large-path]/a] -chan
    seek $chan1 0

    # What the package sees.
    lappend res {*}[tar::contents $chan1 -chan]
    close $chan1

    # What a regular tar package sees.
    lappend res [exec 2> $tmpfile.err tar tvf $tmpfile]
    join $res \n
} -cleanup {
    cleanup2
} -match glob -result [join [list \
				 tartest/[large-path]/a \
				 "* tartest/[large-path]/a" \
				] \n]





















# -------------------------------------------------------------------------
testsuiteCleanup







|


















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



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
    seek $chan1 0
    lappend res [string trim [tar::get $chan1 $tmpdir/one/two/a -chan]]
} -cleanup {
    cleanup1
} -result {tartest/one/a tartest/one/two/a tartest/one/three/a hello2}


test tar-bug-2840180 {Ticket 2840180} -setup {
    setup2
} -body {
    tar::create $chan1 [list $tmpdir/[large-path]/a] -chan
    seek $chan1 0

    # What the package sees.
    lappend res {*}[tar::contents $chan1 -chan]
    close $chan1

    # What a regular tar package sees.
    lappend res [exec 2> $tmpfile.err tar tvf $tmpfile]
    join $res \n
} -cleanup {
    cleanup2
} -match glob -result [join [list \
				 tartest/[large-path]/a \
				 "* tartest/[large-path]/a" \
				] \n]

# -------------------------------------------------------------------------

test tar-tkt-9f4c0e3e95-1.0 {Ticket 9f4c0e3e95, A} -setup {
    set tarfile [setup-tkt-9f4c0e3e95]
} -body {
    string trim [tar::get $tarfile 02]
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -result {zero-two}

test tar-tkt-9f4c0e3e95-1.1 {Ticket 9f4c0e3e95, B, } -setup {
    set tarfile [setup-tkt-9f4c0e3e95]
} -body {
    tar::get $tarfile 0b10
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -returnCodes error -result {Tar "tartest/t.tar": File "0b10" not found}

# -------------------------------------------------------------------------
testsuiteCleanup

Changes to modules/tar/tests/support.tcl.

120
121
122
123
124
125
126























	    uid 15103
	    gid 19103
	    size 100
	    mtime 5706776103
	}
    }
}






























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
	    uid 15103
	    gid 19103
	    size 100
	    mtime 5706776103
	}
    }
}

proc setup-tkt-9f4c0e3e95 {} {
    variable tmpdir tartest

    tcltest::makeDirectory $tmpdir
    tcltest::makeFile {zero-two}   $tmpdir/02
    tcltest::makeFile {number two} $tmpdir/2

    set here [pwd]
    cd $tmpdir
    tar::create t.tar {2 02}
    cd $here

    return $tmpdir/t.tar
}

proc cleanup-tkt-9f4c0e3e95 {} {
    variable tmpdir
    tcltest::removeFile      $tmpdir/2
    tcltest::removeFile      $tmpdir/02
    tcltest::removeDirectory $tmpdir
    return
}