file-temp 1.1.5 → 1.2.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.
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