file-temp 1.1.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. data/CHANGES +50 -43
  2. data/MANIFEST +6 -6
  3. data/README +56 -61
  4. data/Rakefile +61 -61
  5. data/file-temp.gemspec +26 -26
  6. data/lib/file/temp.rb +254 -225
  7. data/test/test_file_temp.rb +120 -108
  8. metadata +40 -66
data/CHANGES CHANGED
@@ -1,43 +1,50 @@
1
- = 1.1.5 - 17-Jul-2011
2
- * Now stores file path information if the file is retained on the filesystem.
3
- Thanks go to joerixaop for the patch.
4
- * The TMPDIR fallback determination on Windows is no longer hard coded.
5
-
6
- = 1.1.4 - 16-Sep-2010
7
- * The File::Temp.temp_name method has been altered on Unix systems. It
8
- no longer prefixes TMPDIR to the name since it was redundant and could
9
- generate a bogus path.
10
- * Set the license to Artistic 2.0.
11
- * Set the test task as the default Rake task.
12
-
13
- = 1.1.3 - 14-Sep-2010
14
- * Fixed potential libc linker failure.
15
-
16
- = 1.1.2 - 28-Apr-2010
17
- * Explicitly link against libc for Unix versions.
18
- * Refactored the Rakefile. An old install task was removed and the gem
19
- related tasks were placed under the 'gem' namespace.
20
-
21
- = 1.1.1 - 24-Oct-2009
22
- * Removed the 'use' library as a dependency.
23
-
24
- = 1.1.0 - 21-Oct-2009
25
- * Now pure Ruby, using FFI.
26
- * Fixed RF Bug #26757 - FILE pointer leak. Thanks go to Eric Wong for the spot.
27
- * Renamed and refactored the test file slightly.
28
- * Updated the gemspec.
29
-
30
- = 1.0.0 - 12-Apr-2008
31
- * Added security via umask().
32
- * Version bump to 1.0.0.
33
-
34
- = 0.1.2 - 6-Jun-2007
35
- * Gemspec fix (forgot the temp.h file - oops).
36
- * Added an extra test.
37
-
38
- = 0.1.1 - 2-Jun-2007
39
- * Core code and test case now work properly on MS Windows.
40
- * Now uses MS VC++ 8 functions when available (tmpfile_s, _sopen_s).
41
-
42
- = 0.1.0 - 1-Jun-2007
43
- * Initial release.
1
+ = 1.2.0 - 10-Apr-2012
2
+ * Removed the old FileTemp alias for File::Temp. It was deprecated and
3
+ has now been officially removed.
4
+ * Some refactoring of the custom internal Windows functions.
5
+ * Nicer error handling if certain FFI functions fail.
6
+ * Made the FFI functions private.
7
+
8
+ = 1.1.5 - 17-Jul-2011
9
+ * Now stores file path information if the file is retained on the filesystem.
10
+ Thanks go to joerixaop for the patch.
11
+ * The TMPDIR fallback determination on Windows is no longer hard coded.
12
+
13
+ = 1.1.4 - 16-Sep-2010
14
+ * The File::Temp.temp_name method has been altered on Unix systems. It
15
+ no longer prefixes TMPDIR to the name since it was redundant and could
16
+ generate a bogus path.
17
+ * Set the license to Artistic 2.0.
18
+ * Set the test task as the default Rake task.
19
+
20
+ = 1.1.3 - 14-Sep-2010
21
+ * Fixed potential libc linker failure.
22
+
23
+ = 1.1.2 - 28-Apr-2010
24
+ * Explicitly link against libc for Unix versions.
25
+ * Refactored the Rakefile. An old install task was removed and the gem
26
+ related tasks were placed under the 'gem' namespace.
27
+
28
+ = 1.1.1 - 24-Oct-2009
29
+ * Removed the 'use' library as a dependency.
30
+
31
+ = 1.1.0 - 21-Oct-2009
32
+ * Now pure Ruby, using FFI.
33
+ * Fixed RF Bug #26757 - FILE pointer leak. Thanks go to Eric Wong for the spot.
34
+ * Renamed and refactored the test file slightly.
35
+ * Updated the gemspec.
36
+
37
+ = 1.0.0 - 12-Apr-2008
38
+ * Added security via umask().
39
+ * Version bump to 1.0.0.
40
+
41
+ = 0.1.2 - 6-Jun-2007
42
+ * Gemspec fix (forgot the temp.h file - oops).
43
+ * Added an extra test.
44
+
45
+ = 0.1.1 - 2-Jun-2007
46
+ * Core code and test case now work properly on MS Windows.
47
+ * Now uses MS VC++ 8 functions when available (tmpfile_s, _sopen_s).
48
+
49
+ = 0.1.0 - 1-Jun-2007
50
+ * Initial release.
data/MANIFEST CHANGED
@@ -1,7 +1,7 @@
1
- * CHANGES
2
- * MANIFEST
3
- * README
4
- * Rakefile
5
- * file-temp.gemspec
6
- * lib/file/temp.rb
1
+ * CHANGES
2
+ * MANIFEST
3
+ * README
4
+ * Rakefile
5
+ * file-temp.gemspec
6
+ * lib/file/temp.rb
7
7
  * test/test_file_temp.rb
data/README CHANGED
@@ -1,61 +1,56 @@
1
- == Description
2
- The file-temp library is an alternate way to handle tempfile generation.
3
-
4
- == Requirements
5
- ffi 0.5.0 or later
6
-
7
- == Synopsis
8
- require 'file/temp'
9
-
10
- fh = File::Temp.new
11
- fh.puts "hello"
12
- fh.close # => Tempfile automatically deleted
13
-
14
- fh = File::Temp.new(false)
15
- fh.puts "world"
16
- fh.close # => Tempfile still on your filesystem
17
-
18
- == Installation
19
- === Rubygems
20
- gem install file-temp
21
-
22
- === Standard Installation
23
- rake test (optional)
24
- rake install
25
-
26
- == Motivation
27
- Ruby's tempfile.rb is overwrought and susceptible to race conditions. This
28
- This library uses your system's native tmpfile() or mkstemp() functions
29
- instead of trying to handle race conditions manually via pure Ruby.
30
-
31
- This library is also more secure because it restricts file permission via
32
- umask() for files created with mkstemp().
33
-
34
- Finally, this library subclasses the File class. This means you get almost
35
- exactly the same interface as the File class. The only difference is the
36
- constructor.
37
-
38
- == JRuby
39
- As of JRuby 1.4.0 this library will not work with JRuby because it does
40
- not support low level systems programming.
41
-
42
- == MS Windows
43
- You may need to use the mingw build in order to use this library.
44
-
45
- == License
46
- Artistic 2.0
47
-
48
- == Copyright
49
- (C) 2007-2009 Daniel J. Berger
50
- All Rights Reserved
51
-
52
- == Warranty
53
- This library is provided "as is" and without any express or
54
- implied warranties, including, without limitation, the implied
55
- warranties of merchantability and fitness for a particular purpose.
56
-
57
- == Author
58
- Daniel J. Berger
59
-
60
- == See also
61
- tmpfile(), mkstemp(), tmpnam()
1
+ == Description
2
+ The file-temp library is an alternate way to handle tempfile generation.
3
+
4
+ == Requirements
5
+ ffi 0.5.0 or later
6
+
7
+ == Installation
8
+ gem install file-temp
9
+
10
+ == Synopsis
11
+ require 'file/temp'
12
+
13
+ fh = File::Temp.new
14
+ fh.puts "hello"
15
+ fh.close # => Tempfile automatically deleted
16
+
17
+ fh = File::Temp.new(false)
18
+ fh.puts "world"
19
+ fh.close # => Tempfile still on your filesystem
20
+
21
+ == Motivation
22
+ Ruby's tempfile.rb is overwrought and susceptible to race conditions. This
23
+ This library uses your system's native tmpfile() or mkstemp() functions
24
+ instead of trying to handle race conditions manually via pure Ruby.
25
+
26
+ This library is also more secure because it restricts file permission via
27
+ umask() for files created with mkstemp().
28
+
29
+ Finally, this library subclasses the File class. This means you get almost
30
+ exactly the same interface as the File class. The only difference is the
31
+ constructor.
32
+
33
+ == JRuby
34
+ I'm afraid this library will not work with JRuby due to limitations
35
+ of JRuby itself.
36
+
37
+ == MS Windows
38
+ You may need to use the mingw build in order to use this library.
39
+
40
+ == License
41
+ Artistic 2.0
42
+
43
+ == Copyright
44
+ (C) 2007-2012 Daniel J. Berger
45
+ All Rights Reserved
46
+
47
+ == Warranty
48
+ This library is provided "as is" and without any express or
49
+ implied warranties, including, without limitation, the implied
50
+ warranties of merchantability and fitness for a particular purpose.
51
+
52
+ == Author
53
+ Daniel J. Berger
54
+
55
+ == See also
56
+ tmpfile(), mkstemp(), tmpnam()
data/Rakefile CHANGED
@@ -1,61 +1,61 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/testtask'
4
-
5
- CLEAN.include('**/*.tar', '**/*.zip', '**/*.gz', '**/*.bz2')
6
- CLEAN.include('**/*.rbc', '**/*.gem')
7
-
8
- namespace 'gem' do
9
- desc 'Create the file-temp gem'
10
- task :create => [:clean] do
11
- spec = eval(IO.read('file-temp.gemspec'))
12
- Gem::Builder.new(spec).build
13
- end
14
-
15
- desc 'Install the file-temp gem'
16
- task :install => [:create] do
17
- file = Dir["*.gem"].first
18
- sh "gem install #{file}"
19
- end
20
- end
21
-
22
- # Export the contents of the library to an archive. Note that this requires
23
- # presence of the .gitattributes file in order to prevent the .git contents
24
- # from being included.
25
- #
26
- # It also appears that I must add a trailing slash to the prefix manually.
27
- # As of git 1.6.4.3 it does not automaticaly add it, despite what the docs
28
- # say.
29
- #
30
- namespace 'export' do
31
- spec = eval(IO.read('file-temp.gemspec'))
32
- file = 'file-temp-' + spec.version.to_s
33
- pref = file + '/' # Git does not add the trailing slash, despite what the docs say.
34
-
35
- desc 'Export to a .tar.gz file'
36
- task :gzip => [:clean] do
37
- file += '.tar'
38
- sh "git archive --prefix #{pref} --output #{file} master"
39
- sh "gzip #{file}"
40
- end
41
-
42
- desc 'Export to a .tar.bz2 file'
43
- task :bzip2 => [:clean] do
44
- file += '.tar'
45
- sh "git archive --prefix #{pref} --output #{file} master"
46
- sh "bzip2 -f #{file}"
47
- end
48
-
49
- desc 'Export to a .zip file'
50
- task :zip => [:clean] do
51
- file += '.zip'
52
- sh "git archive --prefix #{pref} --output #{file} --format zip master"
53
- end
54
- end
55
-
56
- Rake::TestTask.new do |t|
57
- t.verbose = true
58
- t.warning = true
59
- end
60
-
61
- task :default => :test
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ CLEAN.include('**/*.tar', '**/*.zip', '**/*.gz', '**/*.bz2')
6
+ CLEAN.include('**/*.rbc', '**/*.gem')
7
+
8
+ namespace 'gem' do
9
+ desc 'Create the file-temp gem'
10
+ task :create => [:clean] do
11
+ spec = eval(IO.read('file-temp.gemspec'))
12
+ Gem::Builder.new(spec).build
13
+ end
14
+
15
+ desc 'Install the file-temp gem'
16
+ task :install => [:create] do
17
+ file = Dir["*.gem"].first
18
+ sh "gem install #{file}"
19
+ end
20
+ end
21
+
22
+ # Export the contents of the library to an archive. Note that this requires
23
+ # presence of the .gitattributes file in order to prevent the .git contents
24
+ # from being included.
25
+ #
26
+ # It also appears that I must add a trailing slash to the prefix manually.
27
+ # As of git 1.6.4.3 it does not automaticaly add it, despite what the docs
28
+ # say.
29
+ #
30
+ namespace 'export' do
31
+ spec = eval(IO.read('file-temp.gemspec'))
32
+ file = 'file-temp-' + spec.version.to_s
33
+ pref = file + '/' # Git does not add the trailing slash, despite what the docs say.
34
+
35
+ desc 'Export to a .tar.gz file'
36
+ task :gzip => [:clean] do
37
+ file += '.tar'
38
+ sh "git archive --prefix #{pref} --output #{file} master"
39
+ sh "gzip #{file}"
40
+ end
41
+
42
+ desc 'Export to a .tar.bz2 file'
43
+ task :bzip2 => [:clean] do
44
+ file += '.tar'
45
+ sh "git archive --prefix #{pref} --output #{file} master"
46
+ sh "bzip2 -f #{file}"
47
+ end
48
+
49
+ desc 'Export to a .zip file'
50
+ task :zip => [:clean] do
51
+ file += '.zip'
52
+ sh "git archive --prefix #{pref} --output #{file} --format zip master"
53
+ end
54
+ end
55
+
56
+ Rake::TestTask.new do |t|
57
+ t.verbose = true
58
+ t.warning = true
59
+ end
60
+
61
+ task :default => :test
@@ -1,26 +1,26 @@
1
- require 'rubygems'
2
-
3
- Gem::Specification.new do |spec|
4
- spec.name = 'file-temp'
5
- spec.version = '1.1.5'
6
- spec.author = 'Daniel J. Berger'
7
- spec.license = 'Artistic 2.0'
8
- spec.email = 'djberg96@gmail.com'
9
- spec.homepage = 'http://www.rubyforge.org/projects/shards'
10
- spec.summary = 'An alternative way to generate temp files'
11
- spec.test_file = 'test/test_file_temp.rb'
12
- spec.files = Dir['**/*'].delete_if{ |item| item.include?('git') }
13
-
14
- spec.extra_rdoc_files = ['CHANGES', 'README', 'MANIFEST']
15
- spec.rubyforge_project = 'shards'
16
- spec.required_ruby_version = '>= 1.8.6'
17
-
18
- spec.add_dependency('ffi', '>= 0.5.0')
19
- spec.add_development_dependency('test-unit', '>= 2.2.0')
20
-
21
- spec.description = <<-EOF
22
- The file-temp library provides an alternative approach to generating
23
- temporary files. Features included improved security, a superior
24
- interface, and better support for MS Windows.
25
- EOF
26
- end
1
+ require 'rubygems'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'file-temp'
5
+ spec.version = '1.2.0'
6
+ spec.author = 'Daniel J. Berger'
7
+ spec.license = 'Artistic 2.0'
8
+ spec.email = 'djberg96@gmail.com'
9
+ spec.homepage = 'http://www.rubyforge.org/projects/shards'
10
+ spec.summary = 'An alternative way to generate temp files'
11
+ spec.test_file = 'test/test_file_temp.rb'
12
+ spec.files = Dir['**/*'].delete_if{ |item| item.include?('git') }
13
+
14
+ spec.extra_rdoc_files = ['CHANGES', 'README', 'MANIFEST']
15
+ spec.rubyforge_project = 'shards'
16
+ spec.required_ruby_version = '>= 1.8.6'
17
+
18
+ spec.add_dependency('ffi', '>= 1.0.0')
19
+ spec.add_development_dependency('test-unit', '>= 2.4.0')
20
+
21
+ spec.description = <<-EOF
22
+ The file-temp library provides an alternative approach to generating
23
+ temporary files. Features included improved security, a superior
24
+ interface, and better support for MS Windows.
25
+ EOF
26
+ end
@@ -1,225 +1,254 @@
1
- require 'rbconfig'
2
- require 'ffi'
3
-
4
- class File::Temp < File
5
- extend FFI::Library
6
-
7
- # :stopdoc:
8
-
9
- private
10
-
11
- # True if operating system is MS Windows
12
- WINDOWS = Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw|windows/i
13
-
14
- if WINDOWS
15
- ffi_lib 'msvcrt'
16
-
17
- attach_function '_close', [:int], :int
18
- attach_function 'fclose', [:pointer], :int
19
- attach_function '_fdopen', [:int, :string], :pointer
20
- attach_function '_fileno', [:pointer], :int
21
- attach_function '_mktemp', [:string], :string
22
- attach_function '_open', [:string, :int, :int], :int
23
- attach_function '_open_osfhandle', [:long, :int], :int
24
- attach_function 'tmpnam', [:string], :string
25
- attach_function '_umask', [:int], :int
26
-
27
- ffi_lib 'kernel32'
28
-
29
- attach_function 'CloseHandle', [:long], :bool
30
- attach_function 'CreateFileA', [:string, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :long
31
- attach_function 'DeleteFileA', [:string], :bool
32
- attach_function 'GetTempPathA', [:long, :string], :long
33
- attach_function 'GetTempFileNameA', [:string, :string, :uint, :pointer], :uint
34
-
35
- S_IWRITE = 128
36
- S_IREAD = 256
37
- BINARY = 0x8000
38
- SHORT_LIVED = 0x1000
39
- GENERIC_READ = 0x80000000
40
- GENERIC_WRITE = 0x40000000
41
- CREATE_ALWAYS = 2
42
-
43
- FILE_ATTRIBUTE_NORMAL = 0x00000080
44
- FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
45
- INVALID_HANDLE_VALUE = -1
46
- else
47
- ffi_lib FFI::Library::LIBC
48
-
49
- attach_function 'fileno', [:pointer], :int
50
- attach_function 'mkstemp', [:string], :int
51
- attach_function 'umask', [:int], :int
52
- attach_function 'tmpfile', [], :pointer
53
- attach_function 'fclose', [:pointer], :int
54
- attach_function 'tmpnam', [:string], :string
55
- end
56
-
57
- public
58
-
59
- # :startdoc:
60
-
61
- # The version of the file-temp library.
62
- VERSION = '1.1.5'
63
-
64
- if WINDOWS
65
- # The temporary directory used on MS Windows.
66
- TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['USERPROFILE'] || get_temp_path()
67
- else
68
- # The temporary directory used on Unix.
69
- TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['TMPDIR'] || '/tmp'
70
- end
71
-
72
- # The name of the file. This is only retained if the first argument to the
73
- # constructor is false.
74
- attr_reader :path
75
-
76
- # Creates a new, anonymous, temporary file in your File::Temp::TMPDIR
77
- # directory
78
- #
79
- # If the +delete+ option is set to true (the default) then the temporary file
80
- # will be deleted automatically as soon as all references to it are closed.
81
- # Otherwise, the file will live on in your File::Temp::TMPDIR path.
82
- #
83
- # If the +delete+ option is set to false, then the file is not deleted. In
84
- # addition, you can supply a string +template+ that the system replaces with
85
- # a unique filename. This template should end with 3 to 6 'X' characters.
86
- # The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
87
- # file lives in the directory where it was created.
88
- #
89
- # The +template+ argument is ignored if the +delete+ argument is true.
90
- #
91
- # Example:
92
- #
93
- # fh = File::Temp.new(true, 'rb_file_temp_XXXXXX') => file
94
- # fh.puts 'hello world'
95
- # fh.close
96
- #
97
- def initialize(delete = true, template = 'rb_file_temp_XXXXXX')
98
- @fptr = nil
99
-
100
- if delete
101
- @fptr = tmpfile()
102
- fd = WINDOWS ? _fileno(@fptr) : fileno(@fptr)
103
- else
104
- begin
105
- if WINDOWS
106
- template = _mktemp(template)
107
- omask = _umask(077)
108
- else
109
- omask = umask(077)
110
- end
111
-
112
- @path = File.join(TMPDIR, template)
113
- fd = mkstemp(@path)
114
-
115
- raise SystemCallError, 'mkstemp()' if fd < 0
116
- ensure
117
- WINDOWS ? _umask(omask) : umask(omask)
118
- end
119
- end
120
-
121
- super(fd, 'wb+')
122
- end
123
-
124
- # The close method was overridden to ensure the internal file pointer we
125
- # created in the constructor is closed. It is otherwise identical to the
126
- # File#close method.
127
- #
128
- def close
129
- super
130
- fclose(@fptr) if @fptr
131
- end
132
-
133
- # Generates a unique file name.
134
- #
135
- # Note that a file is not actually generated on the filesystem.
136
- #
137
- def self.temp_name
138
- if WINDOWS
139
- TMPDIR + tmpnam(nil) << '.tmp'
140
- else
141
- tmpnam(nil) << '.tmp'
142
- end
143
- end
144
-
145
- private
146
-
147
- if WINDOWS
148
- def get_temp_path
149
- buf = 1.chr * 1024
150
-
151
- if GetTempPathA(buf.length, buf) == 0
152
- raise SystemCallError, 'GetTempPath()'
153
- end
154
-
155
- buf[ /^[^\0]*/ ].chop # remove trailing slash
156
- end
157
-
158
- # The version of tmpfile() implemented by Microsoft is unacceptable.
159
- # It attempts to write to C:\ (root) instead of a temporary directory.
160
- # This is not only bad behavior, it won't work on Windows 7 and later
161
- # without admin rights due to security restrictions.
162
- #
163
- # This is a custom implementation based on some code from the Cairo
164
- # project.
165
- #
166
- def tmpfile
167
- file_name = get_temp_path()
168
- buf = 1.chr * 1024
169
-
170
- if GetTempFileNameA(file_name, 'rb_', 0, buf) == 0
171
- raise SystemCallError, 'GetTempFileName()'
172
- end
173
-
174
- file_name = buf[ /^[^\0]*/ ]
175
-
176
- handle = CreateFileA(
177
- file_name,
178
- GENERIC_READ | GENERIC_WRITE,
179
- 0,
180
- nil,
181
- CREATE_ALWAYS,
182
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
183
- 0
184
- )
185
-
186
- if handle == INVALID_HANDLE_VALUE
187
- DeleteFileA(file_name)
188
- raise SystemCallError, 'CreateFile()'
189
- end
190
-
191
- fd = _open_osfhandle(handle, 0)
192
-
193
- if fd < 0
194
- CloseHandle(handle)
195
- raise SystemCallError, 'open_osfhandle()'
196
- end
197
-
198
- fp = _fdopen(fd, 'w+b')
199
-
200
- if fp.nil?
201
- _close(fd)
202
- raise SystemCallError, 'fdopen()'
203
- end
204
-
205
- fp
206
- end
207
-
208
- # The MS C runtime does not define a mkstemp() function, so we've
209
- # created one here.
210
- #
211
- def mkstemp(template)
212
- flags = RDWR | BINARY | CREAT | EXCL | SHORT_LIVED
213
- pmode = S_IREAD | S_IWRITE
214
-
215
- fd = _open(template, flags, pmode)
216
-
217
- raise SystemCallError, 'mkstemp()' if fd < 0
218
-
219
- fd
220
- end
221
- end
222
- end
223
-
224
- # For backwards compatability
225
- FileTemp = File::Temp
1
+ require 'ffi'
2
+ require 'tmpdir'
3
+
4
+ class File::Temp < File
5
+ extend FFI::Library
6
+ ffi_lib FFI::Library::LIBC
7
+
8
+ # :stopdoc:
9
+
10
+ private
11
+
12
+ if File::ALT_SEPARATOR
13
+ attach_function :_close, [:int], :int
14
+ attach_function :fclose, [:pointer], :int
15
+ attach_function :_fdopen, [:int, :string], :pointer
16
+ attach_function :_fileno, [:pointer], :int
17
+ attach_function :_mktemp_s, [:pointer, :size_t], :int
18
+ attach_function :_open, [:string, :int, :int], :int
19
+ attach_function :_open_osfhandle, [:long, :int], :int
20
+ attach_function :tmpnam, [:string], :string
21
+
22
+ ffi_lib :kernel32
23
+
24
+ attach_function :CloseHandle, [:long], :bool
25
+ attach_function :CreateFileA, [:string, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :long
26
+ attach_function :DeleteFileA, [:string], :bool
27
+ attach_function :FormatMessageA, [:long, :long, :long, :long, :pointer, :long, :pointer], :long
28
+ attach_function :GetLastError, [], :int
29
+ attach_function :GetTempPathA, [:long, :pointer], :long
30
+ attach_function :GetTempFileNameA, [:string, :string, :uint, :pointer], :uint
31
+
32
+ private_class_method :_close, :_fdopen, :_mktemp_s, :_open, :_open_osfhandle
33
+ private_class_method :CloseHandle, :CreateFileA, :DeleteFileA, :FormatMessageA
34
+ private_class_method :GetLastError, :GetTempPathA, :GetTempFileNameA
35
+
36
+ S_IWRITE = 128
37
+ S_IREAD = 256
38
+ BINARY = 0x8000
39
+ SHORT_LIVED = 0x1000
40
+ GENERIC_READ = 0x80000000
41
+ GENERIC_WRITE = 0x40000000
42
+ CREATE_ALWAYS = 2
43
+
44
+ FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
45
+ FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
46
+
47
+ FILE_ATTRIBUTE_NORMAL = 0x00000080
48
+ FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
49
+ INVALID_HANDLE_VALUE = -1
50
+ else
51
+ attach_function :fclose, [:pointer], :int
52
+ attach_function :_fileno, :fileno, [:pointer], :int
53
+ attach_function :mkstemp, [:string], :int
54
+ attach_function :strerror, [:int], :string
55
+ attach_function :tmpfile, [], :pointer
56
+ attach_function :tmpnam, [:string], :string
57
+
58
+ private_class_method :mkstemp, :strerror, :tmpfile
59
+ end
60
+
61
+ private_class_method :fclose, :_fileno, :tmpnam
62
+
63
+ public
64
+
65
+ # :startdoc:
66
+
67
+ # The version of the file-temp library.
68
+ VERSION = '1.2.0'
69
+
70
+ # The temporary directory used on MS Windows or Unix.
71
+ if File::ALT_SEPARATOR
72
+ TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['USERPROFILE'] || Dir.tmpdir
73
+ else
74
+ TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['TMPDIR'] || Dir.tmpdir
75
+ end
76
+
77
+ # The name of the file. This is only retained if the first argument to the
78
+ # constructor is false.
79
+ attr_reader :path
80
+
81
+ # Creates a new, anonymous, temporary file in your File::Temp::TMPDIR
82
+ # directory
83
+ #
84
+ # If the +delete+ option is set to true (the default) then the temporary file
85
+ # will be deleted automatically as soon as all references to it are closed.
86
+ # Otherwise, the file will live on in your File::Temp::TMPDIR path.
87
+ #
88
+ # If the +delete+ option is set to false, then the file is not deleted. In
89
+ # addition, you can supply a string +template+ that the system replaces with
90
+ # a unique filename. This template should end with 3 to 6 'X' characters.
91
+ # The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
92
+ # file lives in the directory where it was created.
93
+ #
94
+ # The +template+ argument is ignored if the +delete+ argument is true.
95
+ #
96
+ # Example:
97
+ #
98
+ # fh = File::Temp.new(true, 'rb_file_temp_XXXXXX') => file
99
+ # fh.puts 'hello world'
100
+ # fh.close
101
+ #
102
+ def initialize(delete = true, template = 'rb_file_temp_XXXXXX')
103
+ @fptr = nil
104
+
105
+ if delete
106
+ @fptr = tmpfile()
107
+ fd = _fileno(@fptr)
108
+ else
109
+ begin
110
+ omask = File.umask(077)
111
+
112
+ if File::ALT_SEPARATOR
113
+ ptr = FFI::MemoryPointer.from_string(template.dup)
114
+
115
+ if _mktemp_s(ptr, ptr.size) != 0
116
+ raise SystemCallError, '_mktemp_s function failed: ' + get_error
117
+ end
118
+
119
+ template = ptr.read_string
120
+ end
121
+
122
+ @path = File.join(TMPDIR, template)
123
+ fd = mkstemp(@path)
124
+
125
+ if fd < 0
126
+ raise SystemCallError, 'mkstemp function failed: ' + get_error
127
+ end
128
+ ensure
129
+ File.umask(omask)
130
+ end
131
+ end
132
+
133
+ super(fd, 'wb+')
134
+ end
135
+
136
+ # The close method was overridden to ensure the internal file pointer we
137
+ # created in the constructor is closed. It is otherwise identical to the
138
+ # File#close method.
139
+ #
140
+ def close
141
+ super
142
+ fclose(@fptr) if @fptr
143
+ end
144
+
145
+ # Generates a unique file name.
146
+ #
147
+ # Note that a file is not actually generated on the filesystem.
148
+ #
149
+ def self.temp_name
150
+ if File::ALT_SEPARATOR
151
+ TMPDIR + tmpnam(nil) << '.tmp'
152
+ else
153
+ tmpnam(nil) << '.tmp'
154
+ end
155
+ end
156
+
157
+ private
158
+
159
+ def get_error
160
+ if File::ALT_SEPARATOR
161
+ errno = GetLastError()
162
+ buffer = FFI::MemoryPointer.new(:char, 512)
163
+ flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
164
+
165
+ FormatMessageA(flags, 0, errno, 0, buffer, buffer.size, nil)
166
+
167
+ buffer.read_string
168
+ else
169
+ strerror(FFI.errno)
170
+ end
171
+ end
172
+
173
+ if File::ALT_SEPARATOR
174
+
175
+ # Simple wrapper around the GetTempPath function.
176
+ #
177
+ def get_temp_path
178
+ buf = FFI::MemoryPointer.new(:char, 1024)
179
+
180
+ if GetTempPathA(buf.size, buf) == 0
181
+ raise SystemCallError, 'GetTempPathA function failed: ' + get_error
182
+ end
183
+
184
+ buf.read_string.chop # remove trailing slash
185
+ end
186
+
187
+ # The version of tmpfile() implemented by Microsoft is unacceptable.
188
+ # It attempts to write to C:\ (root) instead of a temporary directory.
189
+ # This is not only bad behavior, it won't work on Windows 7 and later
190
+ # without admin rights due to security restrictions.
191
+ #
192
+ # This is a custom implementation based on some code from the Cairo
193
+ # project.
194
+ #
195
+ def tmpfile
196
+ file_name = get_temp_path()
197
+ buf = FFI::MemoryPointer.new(:char, 1024)
198
+
199
+ if GetTempFileNameA(file_name, 'rb_', 0, buf) == 0
200
+ raise SystemCallError, 'GetTempFileNameA function failed: ' + get_error
201
+ end
202
+
203
+ file_name = buf.read_string
204
+
205
+ handle = CreateFileA(
206
+ file_name,
207
+ GENERIC_READ | GENERIC_WRITE,
208
+ 0,
209
+ nil,
210
+ CREATE_ALWAYS,
211
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
212
+ 0
213
+ )
214
+
215
+ if handle == INVALID_HANDLE_VALUE
216
+ DeleteFileA(file_name)
217
+ raise SystemCallError, 'CreateFileA function failed: ' + get_error
218
+ end
219
+
220
+ fd = _open_osfhandle(handle, 0)
221
+
222
+ if fd < 0
223
+ CloseHandle(handle)
224
+ raise SystemCallError, '_open_osfhandle function failed: ' + get_error
225
+ end
226
+
227
+ fp = _fdopen(fd, 'w+b')
228
+
229
+ if fp.nil?
230
+ _close(fd)
231
+ CloseHandle(handle)
232
+ raise SystemCallError, 'fdopen function failed: ' + get_error
233
+ end
234
+
235
+ fp
236
+ end
237
+
238
+ # The MS C runtime does not define a mkstemp() function, so we've
239
+ # created one here.
240
+ #
241
+ def mkstemp(template)
242
+ flags = RDWR | BINARY | CREAT | EXCL | SHORT_LIVED
243
+ pmode = S_IREAD | S_IWRITE
244
+
245
+ fd = _open(template, flags, pmode)
246
+
247
+ if fd < 0
248
+ raise SystemCallError, '_open function failed: ' + get_error
249
+ end
250
+
251
+ fd
252
+ end
253
+ end
254
+ end
@@ -1,108 +1,120 @@
1
- ######################################################################
2
- # test_file_temp.rb
3
- #
4
- # Test suite for the file-temp library. These tests should be run
5
- # via the 'rake test' task.
6
- ######################################################################
7
- require 'rubygems'
8
- gem 'test-unit'
9
-
10
- require 'test/unit'
11
- require 'file/temp'
12
- require 'rbconfig'
13
-
14
- class TC_File_Temp < Test::Unit::TestCase
15
- WINDOWS = Config::CONFIG['host_os'] =~ /mswin|win32|msdos|cygwin|mingw|windows/i
16
-
17
- def setup
18
- @dir = File::Temp::TMPDIR
19
- @template = 'file-temp-test-XXXXX'
20
- @fh = nil
21
-
22
- # Because Dir[] doesn't work right with backslashes
23
- @dir = @dir.tr("\\", "/") if WINDOWS
24
- end
25
-
26
- def test_file_temp_version
27
- assert_equal('1.1.5', File::Temp::VERSION)
28
- end
29
-
30
- def test_file_temp_threaded
31
- threads = []
32
- assert_nothing_raised{ 100.times{ threads << Thread.new{ File::Temp.new }}}
33
- assert_nothing_raised{ threads.join }
34
- end
35
-
36
- def test_file_temp_tmpdir
37
- assert_not_nil(File::Temp::TMPDIR)
38
- assert_kind_of(String, File::Temp::TMPDIR)
39
- end
40
-
41
- def test_file_temp_auto_delete
42
- assert_nothing_raised{ @fh = File::Temp.new }
43
- assert_nothing_raised{ @fh.print "hello" }
44
- assert_nothing_raised{ @fh.close }
45
- end
46
-
47
- def test_file_temp_no_delete
48
- assert_nothing_raised{ @fh = File::Temp.new(false) }
49
- assert_nothing_raised{ @fh.print "hello" }
50
- assert_nothing_raised{ @fh.close }
51
- assert_true(Dir["#{@dir}/rb_file_temp*"].length == 1)
52
- end
53
-
54
- def test_file_temp_no_delete_with_template
55
- assert_nothing_raised{ File::Temp.new(false, 'temp_foo_XXXXXX').close }
56
- assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
57
- end
58
-
59
- def test_file_temp_no_delete_with_block
60
- assert_nothing_raised{ File::Temp.open(false, 'temp_foo_XXXXXX'){ |fh| fh.puts "hello" } }
61
- assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
62
- end
63
-
64
- def test_file_temp_expected_errors
65
- assert_raise(TypeError, ArgumentError){ @fh = File::Temp.new(false, 1) }
66
- assert_raise(ArgumentError){ @fh = File::Temp.new(true, 'temp_bar_XXXXX', 1) }
67
- end
68
-
69
- def test_file_temp_name_basic_functionality
70
- assert_respond_to(File::Temp, :temp_name)
71
- assert_nothing_raised{ File::Temp.temp_name }
72
- assert_kind_of(String, File::Temp.temp_name)
73
- end
74
-
75
- def test_file_temp_name
76
- assert_equal('.tmp', File.extname(File::Temp.temp_name))
77
- end
78
-
79
- def test_file_temp_path_basic_functionality
80
- temp = File::Temp.new
81
- assert_respond_to(temp, :path)
82
- end
83
-
84
- def test_file_temp_path_is_nil_if_delete_option_is_true
85
- temp = File::Temp.new
86
- assert_nil(temp.path)
87
- end
88
-
89
- def test_file_temp_path_is_not_nil_if_delete_option_is_false
90
- temp = File::Temp.new(false)
91
- assert_not_nil(temp.path)
92
- end
93
-
94
- def teardown
95
- @dir = nil
96
- @template = nil
97
- @fh.close if @fh && !@fh.closed?
98
- @fh = nil
99
-
100
- Dir["temp_*"].each{ |f| File.delete(f) }
101
- Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
102
-
103
- Dir.chdir(File::Temp::TMPDIR) do
104
- Dir["temp_*"].each{ |f| File.delete(f) }
105
- Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
106
- end
107
- end
108
- end
1
+ ######################################################################
2
+ # test_file_temp.rb
3
+ #
4
+ # Test suite for the file-temp library. These tests should be run
5
+ # via the 'rake test' task.
6
+ ######################################################################
7
+ require 'rubygems'
8
+ require 'test-unit'
9
+ require 'file/temp'
10
+
11
+ class TC_File_Temp < Test::Unit::TestCase
12
+ WINDOWS = File::ALT_SEPARATOR
13
+
14
+ def setup
15
+ @dir = File::Temp::TMPDIR
16
+ @template = 'file-temp-test-XXXXX'
17
+ @fh = nil
18
+
19
+ # Because Dir[] doesn't work right with backslashes
20
+ @dir = @dir.tr("\\", "/") if WINDOWS
21
+ end
22
+
23
+ def test_file_temp_version
24
+ assert_equal('1.2.0', File::Temp::VERSION)
25
+ end
26
+
27
+ def test_file_temp_threaded
28
+ threads = []
29
+ assert_nothing_raised{ 100.times{ threads << Thread.new{ File::Temp.new }}}
30
+ assert_nothing_raised{ threads.join }
31
+ end
32
+
33
+ def test_file_temp_tmpdir
34
+ assert_not_nil(File::Temp::TMPDIR)
35
+ assert_kind_of(String, File::Temp::TMPDIR)
36
+ end
37
+
38
+ def test_file_temp_auto_delete
39
+ assert_nothing_raised{ @fh = File::Temp.new }
40
+ assert_nothing_raised{ @fh.print "hello" }
41
+ assert_nothing_raised{ @fh.close }
42
+ end
43
+
44
+ def test_file_temp_no_delete
45
+ assert_nothing_raised{ @fh = File::Temp.new(false) }
46
+ assert_nothing_raised{ @fh.print "hello" }
47
+ assert_nothing_raised{ @fh.close }
48
+ assert_true(Dir["#{@dir}/rb_file_temp*"].length == 1)
49
+ end
50
+
51
+ def test_file_temp_no_delete_with_template
52
+ assert_nothing_raised{ File::Temp.new(false, 'temp_foo_XXXXXX').close }
53
+ assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
54
+ end
55
+
56
+ def test_file_temp_no_delete_with_block
57
+ assert_nothing_raised{ File::Temp.open(false, 'temp_foo_XXXXXX'){ |fh| fh.puts "hello" } }
58
+ assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
59
+ end
60
+
61
+ def test_file_temp_expected_errors
62
+ assert_raise(TypeError, ArgumentError){ @fh = File::Temp.new(false, 1) }
63
+ assert_raise(ArgumentError){ @fh = File::Temp.new(true, 'temp_bar_XXXXX', 1) }
64
+ end
65
+
66
+ def test_file_temp_name_basic_functionality
67
+ assert_respond_to(File::Temp, :temp_name)
68
+ assert_nothing_raised{ File::Temp.temp_name }
69
+ assert_kind_of(String, File::Temp.temp_name)
70
+ end
71
+
72
+ def test_file_temp_name
73
+ assert_equal('.tmp', File.extname(File::Temp.temp_name))
74
+ end
75
+
76
+ def test_file_temp_path_basic_functionality
77
+ @fh = File::Temp.new
78
+ assert_respond_to(@fh, :path)
79
+ end
80
+
81
+ def test_file_temp_path_is_nil_if_delete_option_is_true
82
+ @fh = File::Temp.new
83
+ assert_nil(@fh.path)
84
+ end
85
+
86
+ def test_file_temp_path_is_not_nil_if_delete_option_is_false
87
+ @fh = File::Temp.new(false)
88
+ assert_not_nil(@fh.path)
89
+ end
90
+
91
+ def test_ffi_functions_are_private
92
+ methods = File::Temp.methods(false).map{ |e| e.to_s }
93
+ assert_false(methods.include?('_fileno'))
94
+ assert_false(methods.include?('mkstemp'))
95
+ assert_false(methods.include?('_umask'))
96
+ assert_false(methods.include?('fclose'))
97
+ assert_false(methods.include?('strerror'))
98
+ assert_false(methods.include?('tmpnam'))
99
+ assert_false(methods.include?('CloseHandle'))
100
+ assert_false(methods.include?('CreateFileA'))
101
+ assert_false(methods.include?('DeleteFileA'))
102
+ assert_false(methods.include?('GetTempPathA'))
103
+ assert_false(methods.include?('GetTempFileNameA'))
104
+ end
105
+
106
+ def teardown
107
+ @dir = nil
108
+ @template = nil
109
+ @fh.close if @fh && !@fh.closed?
110
+ @fh = nil
111
+
112
+ Dir["temp_*"].each{ |f| File.delete(f) }
113
+ Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
114
+
115
+ Dir.chdir(File::Temp::TMPDIR) do
116
+ Dir["temp_*"].each{ |f| File.delete(f) }
117
+ Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
118
+ end
119
+ end
120
+ end
metadata CHANGED
@@ -1,65 +1,49 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: file-temp
3
- version: !ruby/object:Gem::Version
4
- hash: 25
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 1
9
- - 5
10
- version: 1.1.5
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Daniel J. Berger
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-07-17 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-04-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: ffi
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &22367490 !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 11
29
- segments:
30
- - 0
31
- - 5
32
- - 0
33
- version: 0.5.0
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0
34
22
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: test-unit
38
23
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *22367490
25
+ - !ruby/object:Gem::Dependency
26
+ name: test-unit
27
+ requirement: &22367140 !ruby/object:Gem::Requirement
40
28
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 7
45
- segments:
46
- - 2
47
- - 2
48
- - 0
49
- version: 2.2.0
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 2.4.0
50
33
  type: :development
51
- version_requirements: *id002
52
- description: " The file-temp library provides an alternative approach to generating\n temporary files. Features included improved security, a superior\n interface, and better support for MS Windows.\n"
34
+ prerelease: false
35
+ version_requirements: *22367140
36
+ description: ! " The file-temp library provides an alternative approach to generating\n
37
+ \ temporary files. Features included improved security, a superior\n interface,
38
+ and better support for MS Windows.\n"
53
39
  email: djberg96@gmail.com
54
40
  executables: []
55
-
56
41
  extensions: []
57
-
58
- extra_rdoc_files:
42
+ extra_rdoc_files:
59
43
  - CHANGES
60
44
  - README
61
45
  - MANIFEST
62
- files:
46
+ files:
63
47
  - CHANGES
64
48
  - file-temp.gemspec
65
49
  - lib/file/temp.rb
@@ -68,39 +52,29 @@ files:
68
52
  - README
69
53
  - test/test_file_temp.rb
70
54
  homepage: http://www.rubyforge.org/projects/shards
71
- licenses:
55
+ licenses:
72
56
  - Artistic 2.0
73
57
  post_install_message:
74
58
  rdoc_options: []
75
-
76
- require_paths:
59
+ require_paths:
77
60
  - lib
78
- required_ruby_version: !ruby/object:Gem::Requirement
61
+ required_ruby_version: !ruby/object:Gem::Requirement
79
62
  none: false
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- hash: 59
84
- segments:
85
- - 1
86
- - 8
87
- - 6
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
88
66
  version: 1.8.6
89
- required_rubygems_version: !ruby/object:Gem::Requirement
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
68
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- hash: 3
95
- segments:
96
- - 0
97
- version: "0"
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
98
73
  requirements: []
99
-
100
74
  rubyforge_project: shards
101
- rubygems_version: 1.8.3
75
+ rubygems_version: 1.8.11
102
76
  signing_key:
103
77
  specification_version: 3
104
78
  summary: An alternative way to generate temp files
105
- test_files:
79
+ test_files:
106
80
  - test/test_file_temp.rb