ruby-stemp 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +36 -0
- data/ext/extconf.rb +23 -0
- data/ext/stemp.c +170 -0
- data/test/ts_stemp.rb +91 -0
- metadata +49 -0
data/README
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
STemp - Secure tempfile extension for Ruby
|
2
|
+
|
3
|
+
Pure Ruby tempfile implementations appear to suffer from well-known race
|
4
|
+
conditions. The 'mkstemp' family of functions now popular on Linux & *BSD
|
5
|
+
attempt to work around these issues. This module makes them available to
|
6
|
+
Ruby programmers on platforms where they are present.
|
7
|
+
|
8
|
+
Note that you should set your +umask+ appropriately when using this library:
|
9
|
+
not all implementations of these functions use a reasonable file creation mask
|
10
|
+
by default.
|
11
|
+
|
12
|
+
Author:: Cian Synnott <cian@gmail.com>
|
13
|
+
Copyright:: Copyright (c) 2006 Cian Synnott
|
14
|
+
License:: MIT License
|
15
|
+
|
16
|
+
Copyright (c) 2006 Cian Synnott
|
17
|
+
|
18
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
19
|
+
of this software and associated documentation files (the "Software"), to
|
20
|
+
deal in the Software without restriction, including without limitation the
|
21
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
22
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
23
|
+
furnished to do so, subject to the following conditions:
|
24
|
+
|
25
|
+
The above copyright notice and this permission notice shall be included in
|
26
|
+
all copies or substantial portions of the Software.
|
27
|
+
|
28
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
29
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
31
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
32
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
33
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
34
|
+
IN THE SOFTWARE.
|
35
|
+
|
36
|
+
$Id: README 5 2006-11-15 00:15:44Z cian $
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Ruby extension configuration for STemp
|
3
|
+
#
|
4
|
+
# STemp - Secure tempfile extension for Ruby
|
5
|
+
#
|
6
|
+
# Author:: Cian Synnott <cian@gmail.com>
|
7
|
+
# Copyright:: Copyright (c) 2006 Cian Synnott
|
8
|
+
# License:: MIT License
|
9
|
+
#
|
10
|
+
# For license info, see the README file bundled with this package.
|
11
|
+
#
|
12
|
+
# $Id: extconf.rb 5 2006-11-15 00:15:44Z cian $
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'mkmf'
|
16
|
+
|
17
|
+
if have_func('mkdtemp') and have_func('mkstemp') and have_func('tmpfile')
|
18
|
+
then
|
19
|
+
create_makefile('stemp')
|
20
|
+
else
|
21
|
+
puts "One or more of 'mkdtemp', 'mkstemp' and 'tmpfile' is not available"
|
22
|
+
end
|
23
|
+
|
data/ext/stemp.c
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
/* STemp - Secure tempfile extension for Ruby
|
2
|
+
*
|
3
|
+
* Pure Ruby tempfile implementations appear to suffer from well-known race
|
4
|
+
* conditions. The 'mkstemp' family of functions now popular on Linux & *BSD
|
5
|
+
* attempt to work around these issues. This module makes them available to
|
6
|
+
* Ruby programmers on platforms where they are present.
|
7
|
+
*
|
8
|
+
* Author:: Cian Synnott <cian@gmail.com>
|
9
|
+
* Copyright:: Copyright (c) 2006 Cian Synnott
|
10
|
+
* License:: MIT License
|
11
|
+
*
|
12
|
+
* Copyright (c) 2006 Cian Synnott
|
13
|
+
*
|
14
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
15
|
+
* of this software and associated documentation files (the "Software"), to
|
16
|
+
* deal in the Software without restriction, including without limitation the
|
17
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
18
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
19
|
+
* furnished to do so, subject to the following conditions:
|
20
|
+
*
|
21
|
+
* The above copyright notice and this permission notice shall be included in
|
22
|
+
* all copies or substantial portions of the Software.
|
23
|
+
*
|
24
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
29
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
30
|
+
* IN THE SOFTWARE.
|
31
|
+
*
|
32
|
+
* $Id: stemp.c 5 2006-11-15 00:15:44Z cian $
|
33
|
+
*/
|
34
|
+
|
35
|
+
#include "ruby.h"
|
36
|
+
|
37
|
+
#include <unistd.h>
|
38
|
+
#include <errno.h>
|
39
|
+
|
40
|
+
VALUE mSTemp;
|
41
|
+
|
42
|
+
static void raise_systemcallerror(int, char *);
|
43
|
+
|
44
|
+
/* call-seq:
|
45
|
+
* STemp.mkdtemp(template) -> String
|
46
|
+
*
|
47
|
+
* Wraps <tt>mkdtemp(3)</tt> for Ruby. See <tt>man mkdtemp</tt> on your system
|
48
|
+
* for exact semantics.
|
49
|
+
*
|
50
|
+
* Notes:
|
51
|
+
* - <tt>template</tt> is overwritten with the eventual directory name.
|
52
|
+
* - raises a <tt>SystemCallError</tt> if any of the syscalls involved fail.
|
53
|
+
*
|
54
|
+
*/
|
55
|
+
static VALUE stemp_mkdtemp(VALUE self, VALUE template) {
|
56
|
+
VALUE duckstr;
|
57
|
+
char *ret;
|
58
|
+
|
59
|
+
SafeStringValue(template);
|
60
|
+
|
61
|
+
duckstr = StringValue(template);
|
62
|
+
|
63
|
+
ret = mkdtemp(RSTRING(duckstr)->ptr);
|
64
|
+
|
65
|
+
if (NULL == ret) raise_systemcallerror(errno, "in mkdtemp");
|
66
|
+
|
67
|
+
return duckstr;
|
68
|
+
}
|
69
|
+
|
70
|
+
/* call-seq:
|
71
|
+
* STemp.mkstemp(template) -> File
|
72
|
+
*
|
73
|
+
* Wraps <tt>mkstemp(3)</tt> for Ruby. See <tt>man mkstemp</tt> on your system
|
74
|
+
* for exact semantics.
|
75
|
+
*
|
76
|
+
* Notes:
|
77
|
+
* - returns a File object rather than a simple file descriptor.
|
78
|
+
* - <tt>template</tt> is overwritten with the eventual directory name.
|
79
|
+
* - raises a <tt>SystemCallError</tt> if any of the syscalls involved fail.
|
80
|
+
* - the Debian manpage for <tt>mkstemp</tt> suggests you shouldn't use it, but
|
81
|
+
* rather stick with <tt>tmpfile</tt>. However, I think it's better all
|
82
|
+
* round to have the choice; there are times when you want to know the
|
83
|
+
* tempfile name.
|
84
|
+
*/
|
85
|
+
static VALUE stemp_mkstemp(VALUE self, VALUE template) {
|
86
|
+
VALUE duckstr, filedesc, file;
|
87
|
+
int fd;
|
88
|
+
|
89
|
+
SafeStringValue(template);
|
90
|
+
|
91
|
+
duckstr = StringValue(template);
|
92
|
+
|
93
|
+
fd = mkstemp(RSTRING(duckstr)->ptr);
|
94
|
+
|
95
|
+
if (-1 == fd) raise_systemcallerror(errno, "in mkstemp");
|
96
|
+
|
97
|
+
filedesc = INT2FIX(fd);
|
98
|
+
|
99
|
+
file = rb_class_new_instance(1, &filedesc,
|
100
|
+
rb_const_get(rb_cObject, rb_intern("File")));
|
101
|
+
|
102
|
+
return file;
|
103
|
+
}
|
104
|
+
|
105
|
+
/* call-seq:
|
106
|
+
* STemp.tmpfile -> File
|
107
|
+
*
|
108
|
+
* Wraps <tt>tmpfile(3)</tt> for Ruby. See <tt>man tmpfile</tt> on your system
|
109
|
+
* for exact semantics.
|
110
|
+
*
|
111
|
+
* Notes:
|
112
|
+
* - raises a <tt>SystemCallError</tt> if any of the syscalls involved fail.
|
113
|
+
*/
|
114
|
+
static VALUE stemp_tmpfile(VALUE self) {
|
115
|
+
VALUE filedesc, file;
|
116
|
+
FILE *fp;
|
117
|
+
|
118
|
+
fp = tmpfile();
|
119
|
+
|
120
|
+
if (NULL == fp) raise_systemcallerror(errno, "in tmpfile");
|
121
|
+
|
122
|
+
/* A shame to have to move back to fileno from the FILE *, but there doesn't
|
123
|
+
* seem to be a clean way to do this in Ruby's C bindings otherwise.
|
124
|
+
* Note that fileno() is not ANSI C, but should be present wherever mkstemp
|
125
|
+
* and company are. */
|
126
|
+
filedesc = INT2FIX(fileno(fp));
|
127
|
+
|
128
|
+
file = rb_class_new_instance(1, &filedesc,
|
129
|
+
rb_const_get(rb_cObject, rb_intern("File")));
|
130
|
+
|
131
|
+
return file;
|
132
|
+
}
|
133
|
+
|
134
|
+
/* raise_systemcallerror - Raise a SystemCallError
|
135
|
+
*
|
136
|
+
* A utility routine for the actual methods defined here.
|
137
|
+
*
|
138
|
+
* Args:
|
139
|
+
* - num: the system error number, probably errno
|
140
|
+
* - msg: a message to attach
|
141
|
+
*/
|
142
|
+
static void raise_systemcallerror(int num, char *msg) {
|
143
|
+
VALUE excobj, excno, *params;
|
144
|
+
|
145
|
+
/* Construct argument list */
|
146
|
+
excno = INT2FIX(num);
|
147
|
+
params = &excno;
|
148
|
+
|
149
|
+
excobj = rb_class_new_instance(1, params,
|
150
|
+
rb_const_get(rb_cObject, rb_intern("SystemCallError")));
|
151
|
+
|
152
|
+
/* I go about this in a somewhat strange way because of the way
|
153
|
+
* SystemCallError works. Its 'new' method creates an object of the
|
154
|
+
* appropriate subclass of Errno based on the number you give it. However,
|
155
|
+
* rb_raise takes a _class_, not an instance. */
|
156
|
+
rb_raise(rb_funcall(excobj, rb_intern("class"), 0), msg);
|
157
|
+
}
|
158
|
+
|
159
|
+
/* STemp - secure tempfile extension for Ruby
|
160
|
+
*
|
161
|
+
* Note that you should set your +umask+ appropriately when using this library:
|
162
|
+
* not all implementations of these functions use a reasonable file creation
|
163
|
+
* mask by default.
|
164
|
+
*/
|
165
|
+
void Init_stemp() {
|
166
|
+
mSTemp = rb_define_module("STemp");
|
167
|
+
rb_define_singleton_method(mSTemp, "mkdtemp", stemp_mkdtemp, 1);
|
168
|
+
rb_define_singleton_method(mSTemp, "mkstemp", stemp_mkstemp, 1);
|
169
|
+
rb_define_singleton_method(mSTemp, "tmpfile", stemp_tmpfile, 0);
|
170
|
+
}
|
data/test/ts_stemp.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# Unit tests for STemp
|
3
|
+
#
|
4
|
+
# STemp - Secure tempfile extension for Ruby
|
5
|
+
#
|
6
|
+
# Author:: Cian Synnott <cian@gmail.com>
|
7
|
+
# Copyright:: Copyright (c) 2006 Cian Synnott
|
8
|
+
# License:: MIT License
|
9
|
+
#
|
10
|
+
# For license info, see the README file bundled with this package.
|
11
|
+
#
|
12
|
+
# $Id: ts_stemp.rb 5 2006-11-15 00:15:44Z cian $
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'test/unit'
|
16
|
+
require 'fileutils'
|
17
|
+
require 'tmpdir'
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'stemp'
|
21
|
+
|
22
|
+
# Tests for STemp
|
23
|
+
class TestSTemp < Test::Unit::TestCase
|
24
|
+
WRITE = "#{Dir.tmpdir}/test-stemp-write"
|
25
|
+
NOWRITE = "#{Dir.tmpdir}/test-stemp-nowrite"
|
26
|
+
|
27
|
+
def setup
|
28
|
+
# Create writeable and unwriteable directory 'fixtures'
|
29
|
+
FileUtils.mkdir(WRITE, :mode => 0700)
|
30
|
+
FileUtils.mkdir(NOWRITE, :mode => 0500)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Tests for +mkdtemp+.
|
34
|
+
def test_mkdtemp
|
35
|
+
# If we're getting the correct EACCES exceptions here, the exception
|
36
|
+
# handling in mkdtemp is working. Don't bother if we're root. :op
|
37
|
+
unless Process.euid == 0
|
38
|
+
dirname = "#{NOWRITE}/dir-XXXXXX"
|
39
|
+
assert_raise(Errno::EACCES) { STemp.mkdtemp(dirname) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Normal behaviour. Remember to check side-effect.
|
43
|
+
dirname = "#{WRITE}/dir-XXXXXX"
|
44
|
+
newname = STemp.mkdtemp(dirname)
|
45
|
+
assert_equal(newname, dirname)
|
46
|
+
assert_not_equal(dirname, "#{WRITE}/dir-XXXXXX")
|
47
|
+
assert(File.directory?(dirname))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Tests for +mkstemp+.
|
51
|
+
def test_mkstemp
|
52
|
+
# See comments above on first assertion.
|
53
|
+
unless Process.euid == 0
|
54
|
+
filename = "#{NOWRITE}/file-XXXXXX"
|
55
|
+
assert_raise(Errno::EACCES) { STemp.mkstemp(filename) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Test creating a file, writing to it etc. and that it exists at the end.
|
59
|
+
filename = "#{WRITE}/file-XXXXXX"
|
60
|
+
f = STemp.mkstemp(filename)
|
61
|
+
assert_not_equal(filename, "#{WRITE}/file-XXXXXX")
|
62
|
+
text = nil
|
63
|
+
assert_nothing_raised do
|
64
|
+
f.puts 'test string'
|
65
|
+
f.rewind
|
66
|
+
text = f.read
|
67
|
+
f.close
|
68
|
+
end
|
69
|
+
assert_equal(text, "test string\n")
|
70
|
+
assert(File.exists?(filename))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Tests for +tmpfile+.
|
74
|
+
def test_tmpfile
|
75
|
+
# Test creating a file, writing to it etc.
|
76
|
+
f = STemp.tmpfile
|
77
|
+
text = nil
|
78
|
+
assert_nothing_raised do
|
79
|
+
f.puts 'test string'
|
80
|
+
f.rewind
|
81
|
+
text = f.read
|
82
|
+
f.close
|
83
|
+
end
|
84
|
+
assert_equal(text, "test string\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
def teardown
|
88
|
+
FileUtils.rm_rf(WRITE)
|
89
|
+
FileUtils.rm_rf(NOWRITE)
|
90
|
+
end
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: ruby-stemp
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "1.0"
|
7
|
+
date: 2006-11-15 00:00:00 +00:00
|
8
|
+
summary: Secure tempfile extension for Ruby
|
9
|
+
require_paths:
|
10
|
+
- .
|
11
|
+
email: cian@gmail.com
|
12
|
+
homepage: http://code.google.com/p/ruby-stemp
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: stemp
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Cian Synnott
|
30
|
+
files:
|
31
|
+
- ext/extconf.rb
|
32
|
+
- ext/stemp.c
|
33
|
+
- test/ts_stemp.rb
|
34
|
+
- README
|
35
|
+
test_files:
|
36
|
+
- test/ts_stemp.rb
|
37
|
+
rdoc_options:
|
38
|
+
- --main
|
39
|
+
- README
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
executables: []
|
43
|
+
|
44
|
+
extensions:
|
45
|
+
- ext/extconf.rb
|
46
|
+
requirements: []
|
47
|
+
|
48
|
+
dependencies: []
|
49
|
+
|