Class: File

Inherits:
Object
  • Object
show all
Extended by:
Windows::File::Functions
Includes:
Windows::File::Constants, Windows::File::Structs
Defined in:
lib/win32/file.rb

Constant Summary collapse

WIN32_FILE_VERSION =

The version of the win32-file library

'0.8.0'

Constants included from Windows::File::Constants

Windows::File::Constants::DRIVE_CDROM, Windows::File::Constants::DRIVE_RAMDISK, Windows::File::Constants::DRIVE_REMOVABLE, Windows::File::Constants::FILE_ATTRIBUTE_NORMAL, Windows::File::Constants::FILE_ATTRIBUTE_REPARSE_POINT, Windows::File::Constants::FILE_FLAG_BACKUP_SEMANTICS, Windows::File::Constants::FILE_FLAG_OPEN_REPARSE_POINT, Windows::File::Constants::FILE_SHARE_READ, Windows::File::Constants::FILE_SHARE_WRITE, Windows::File::Constants::FILE_TYPE_CHAR, Windows::File::Constants::FILE_TYPE_UNKNOWN, Windows::File::Constants::FILE_WRITE_ATTRIBUTES, Windows::File::Constants::GENERIC_READ, Windows::File::Constants::GENERIC_WRITE, Windows::File::Constants::INVALID_FILE_ATTRIBUTES, Windows::File::Constants::INVALID_HANDLE_VALUE, Windows::File::Constants::IO_REPARSE_TAG_SYMLINK, Windows::File::Constants::NO_ERROR, Windows::File::Constants::OPEN_EXISTING

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Windows::File::Functions

attach_pfunc

Class Method Details

.atime(file, time = nil) ⇒ Object

Returns the file’s last access time. If a time argument is provided, it sets the file’s access time. The time argument may be a Time object or a numeric value.



373
374
375
376
# File 'lib/win32/file.rb', line 373

def self.atime(file, time = nil)
  set_filetime(file, nil, time) if time
  File::Stat.new(file).atime
end

.basename(file, suffix = nil) ⇒ Object

Returns the last component of the filename given in filename. If suffix is given and present at the end of filename, it is removed. Any extension can be removed by giving an extension of “.*”.

This was reimplemented because the current version does not handle UNC paths properly, i.e. it should not return anything less than the root. In most other respects it is identical to the current implementation, except that it does not strip the drive letter on a root path.

Unlike MRI, this version will convert all forward slashes to backslashes automatically.

Examples:

File.basename("C:\\foo\\bar.txt")         -> "bar.txt"
File.basename("C:\\foo\\bar.txt", ".txt") -> "bar"
File.basename("\\\\foo\\bar")             -> "\\\\foo\\bar"


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/win32/file.rb', line 51

def self.basename(file, suffix = nil)
  file = string_check(file)
  suffix = string_check(suffix) if suffix

  return file if file.empty? # Return an empty path as-is.


  encoding = file.encoding
  wfile = file.wincode

  # Return a root path as-is.

  if PathIsRootW(wfile)
    return file.tr(File::SEPARATOR, File::ALT_SEPARATOR)
  end

  ptr = FFI::MemoryPointer.from_string(wfile)

  PathStripPathW(ptr) # Gives us the basename


  if suffix
    if suffix == '.*'
      PathRemoveExtensionW(ptr)
    else
      ext = PathFindExtensionW(ptr).read_string(suffix.length * 2).wstrip

      if ext == suffix
        PathRemoveExtensionW(ptr)
      end
    end
  end

  wfile = ptr.read_bytes(wfile.size * 2).split("\000\000").first.tr(0.chr, '')
  file = wfile.encode(encoding)[/^[^\0]*/]
  file.sub!(/\\+\z/, '') # Trim trailing slashes


  ptr.free

  file
end

.blksize(file) ⇒ Object

Returns the filesystem’s block size.



380
381
382
# File 'lib/win32/file.rb', line 380

def self.blksize(file)
  File::Stat.new(file).blksize
end

.blockdev?(file) ⇒ Boolean

Returns whether or not the file is a block device. For MS Windows a block device is a removable drive, cdrom or ramdisk.

Returns:

  • (Boolean)


387
388
389
390
# File 'lib/win32/file.rb', line 387

def self.blockdev?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).blockdev?
end

.chardev?(file) ⇒ Boolean

Returns whether or not the file is a character device.

Returns:

  • (Boolean)


394
395
396
397
# File 'lib/win32/file.rb', line 394

def self.chardev?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).chardev?
end

.ctime(file, time = nil) ⇒ Object

Returns the file’s creation time. If a time argument is provided, it sets the file’s creation time. The time argument may be a Time object or a numeric value.



403
404
405
406
# File 'lib/win32/file.rb', line 403

def self.ctime(file, time = nil)
  set_filetime(file, time) if time
  File::Stat.new(file).ctime
end

.directory?(file) ⇒ Boolean

Returns whether or not the file is a directory.

Returns:

  • (Boolean)


410
411
412
413
# File 'lib/win32/file.rb', line 410

def self.directory?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).directory?
end

.dirname(file) ⇒ Object

Returns all components of the filename given in filename except the last one.

This was reimplemented because the current version does not handle UNC paths properly, i.e. it should not return anything less than the root. In all other respects it is identical to the current implementation.

Also, this method will convert all forward slashes to backslashes.

Examples:

File.dirname("C:\\foo\\bar\\baz.txt") -> "C:\\foo\\bar"
File.dirname("\\\\foo\\bar")          -> "\\\\foo\\bar"


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/win32/file.rb', line 104

def self.dirname(file)
  file = string_check(file)

  # Short circuit for empty paths

  return '.' if file.empty?

  # Store original encoding, restore it later

  encoding = file.encoding

  # Convert to UTF-16LE

  wfile = file.wincode

  # Return a root path as-is.

  if PathIsRootW(wfile)
    return file.tr(File::SEPARATOR, File::ALT_SEPARATOR)
  end

  ptr = FFI::MemoryPointer.from_string(wfile)

  # Remove trailing slashes if present

  while result = PathRemoveBackslashW(ptr)
    break unless result.empty?
  end

  # Remove trailing file name if present

  unless PathRemoveFileSpecW(ptr)
    raise SystemCallError.new("PathRemoveFileSpec", FFI.errno)
  end

  wfile = ptr.read_bytes(wfile.size * 2).split("\000\000").first

  # Empty paths, short relative paths

  if wfile.nil? or wfile.empty?
    return '.'
  end

  # Return to original encoding

  file = wfile.tr(0.chr, '').encode(encoding)

  ptr.free

  file
end

.executable?(file) ⇒ Boolean Also known as: executable_real?

Returns whether or not the file is executable.

Returns:

  • (Boolean)


417
418
419
420
# File 'lib/win32/file.rb', line 417

def self.executable?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).executable?
end

.file?(file) ⇒ Boolean

Returns whether or not the file is a regular file.

Returns:

  • (Boolean)


424
425
426
427
# File 'lib/win32/file.rb', line 424

def self.file?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).file?
end

.ftype(file) ⇒ Object

Identifies the type of file. The return string is one of ‘file’, ‘directory’, ‘characterSpecial’, ‘socket’ or ‘unknown’.



432
433
434
# File 'lib/win32/file.rb', line 432

def self.ftype(file)
  File::Stat.new(file).ftype
end

.grpowned?(file) ⇒ Boolean

Returns true if the process owner’s ID is the same as one of the file’s groups.

Returns:

  • (Boolean)


438
439
440
441
# File 'lib/win32/file.rb', line 438

def self.grpowned?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).grpowned?
end

.join(*args) ⇒ Object

Join path string components together into a single string.

This method was reimplemented so that it automatically converts forward slashes to backslashes. It is otherwise identical to the core File.join method.

Examples:

File.join("C:", "foo", "bar") # => C:\foo\bar
File.join("foo", "bar")       # => foo\bar


159
160
161
# File 'lib/win32/file.rb', line 159

def self.join(*args)
  return join_orig(*args).tr("/", "\\")
end

.join_origObject



15
# File 'lib/win32/file.rb', line 15

alias_method :join_orig, :join

.long_path(file) ⇒ Object

Returns path in long format. For example, if ‘SOMEFI~1.TXT’ was the argument provided, and the short representation for ‘somefile.txt’, then this method would return ‘somefile.txt’.

Note that certain file system optimizations may prevent this method from working as expected. In that case, you will get back the file name in 8.3 format.



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/win32/file.rb', line 188

def self.long_path(file)
  buffer = FFI::Buffer.new(:wint_t, 1024, true)
  wfile  = string_check(file).wincode

  length = GetLongPathNameW(wfile, buffer, buffer.size)

  if length == 0 || length > buffer.size / 2
    raise SystemCallError.new('GetLongPathName', FFI.errno)
  end

  buffer.read_bytes(length * 2).wstrip
end

.lstatObject

Returns a File::Stat object as defined in the win32-file-stat library.



518
519
520
# File 'lib/win32/file.rb', line 518

def self.stat(file)
  File::Stat.new(file)
end

.mtime(file, time = nil) ⇒ Object

Returns the file’s creation time. If a time argument is provided, it sets the file’s creation time. The time argument may be a Time object or a numeric value.



447
448
449
450
# File 'lib/win32/file.rb', line 447

def self.mtime(file, time = nil)
  set_filetime(file, nil, nil, time) if time
  File::Stat.new(file).mtime
end

.owned?(file) ⇒ Boolean

Returns whether or not the current process owner is the owner of the file.

Returns:

  • (Boolean)


454
455
456
457
# File 'lib/win32/file.rb', line 454

def self.owned?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).owned?
end

.pipe?(file) ⇒ Boolean Also known as: socket?

Returns whether or not the file is a pipe.

Returns:

  • (Boolean)


461
462
463
464
# File 'lib/win32/file.rb', line 461

def self.pipe?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).pipe?
end

.readable?(file) ⇒ Boolean

Returns whether or not the file is readable by the process owner.

Returns:

  • (Boolean)


468
469
470
471
# File 'lib/win32/file.rb', line 468

def self.readable?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).readable?
end

.readable_real?(file) ⇒ Boolean

Synonym for File.readable?

Returns:

  • (Boolean)


475
476
477
478
# File 'lib/win32/file.rb', line 475

def self.readable_real?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).readable_real?
end

Returns the path of the of the symbolic link referred to by file.

Unlike unixy platforms, this will raise an error if the link is stale.



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/win32/file.rb', line 326

def self.readlink(file)
  file = string_check(file)

  if exist?(file) && !symlink?(file)
    raise SystemCallError.new(22) # EINVAL, match the spec

  end

  wfile = file.wincode
  path  = 0.chr * 1024

  if File.directory?(file)
    flags = FILE_FLAG_BACKUP_SEMANTICS
  else
    flags = FILE_ATTRIBUTE_NORMAL
  end

  begin
    handle = CreateFileW(
      wfile,
      GENERIC_READ,
      FILE_SHARE_READ,
      nil,
      OPEN_EXISTING,
      flags,
      0
    )

    if handle == INVALID_HANDLE_VALUE
      raise SystemCallError.new('CreateFile', FFI.errno)
    end

    if GetFinalPathNameByHandleW(handle, path, path.size/2, 0) == 0
      raise SystemCallError.new('GetFinalPathNameByHandle', FFI.errno)
    end
  ensure
    CloseHandle(handle)
  end

  path.wstrip[4..-1] # Remove leading backslashes + question mark

end

.realdirpath(file, relative_to = nil) ⇒ Object

Converts path to a full file path, with all symlinks resolved and relative paths made absolute. If a second parameter if present, it is used as the base for resolving leading relative path segments.

Unlike File.realpath, an error is not raised if the final path created using a relative path argument doesn’t exist. – On Windows we only modify the realpath method if the file is a symlink.



282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/win32/file.rb', line 282

def self.realdirpath(file, relative_to = nil)
  file = string_check(file)

  if symlink?(file)
    if relative_to
      File.join(relative_to, File.basename(readlink(file)))
    else
      readlink(file)
    end
  else
    realdirpath_orig(file, relative_to)
  end
end

.realdirpath_origObject



17
# File 'lib/win32/file.rb', line 17

alias_method :realdirpath_orig, :realdirpath

.realpath(file, relative_to = nil) ⇒ Object

Converts path to a full file path, with all symlinks resolved and relative paths made absolute. If a second parameter if present, it is used as the base for resolving leading relative path segments. – On Windows we only modify the realpath method if the file is a symlink.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/win32/file.rb', line 302

def self.realpath(file, relative_to = nil)
  file = string_check(file)
  relative_to = string_check(relative_to) if relative_to

  if symlink?(file)
    if relative_to
      result = File.join(relative_to, File.basename(readlink(file)))
      if File.exist?(result)
        result
      else
        raise SystemCallError.new(result, 2) # Errno::ENOENT

      end
    else
      readlink(file)
    end
  else
    realpath_orig(file, relative_to)
  end
end

.realpath_origObject



16
# File 'lib/win32/file.rb', line 16

alias_method :realpath_orig, :realpath

.short_path(file) ⇒ Object

Returns path in 8.3 format. For example, ‘c:documentation.doc’ would be returned as ‘c:docume~1.doc’.



204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/win32/file.rb', line 204

def self.short_path(file)
  buffer = FFI::Buffer.new(:wint_t, 1024, true)
  wfile  = string_check(file).wincode

  length = GetShortPathNameW(wfile, buffer, buffer.size)

  if length == 0 || length > buffer.size / 2
    raise SystemCallError.new('GetShortPathName', FFI.errno)
  end

  buffer.read_bytes(length * 2).wstrip
end

.split(file) ⇒ Object

Splits the given string into a directory and a file component and returns them in a two element array. This was reimplemented because the current version does not handle UNC paths properly.



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/win32/file.rb', line 167

def self.split(file)
  file = string_check(file)
  array = []

  if file.empty? || PathIsRootW(file.wincode)
    array.push(file, '')
  else
    array.push(File.dirname(file), File.basename(file))
  end

  array
end

.stat(file) ⇒ Object

Returns a File::Stat object as defined in the win32-file-stat library.



482
483
484
# File 'lib/win32/file.rb', line 482

def self.stat(file)
  File::Stat.new(file)
end

Creates a symbolic link called new_name for the file or directory old_name.

This method requires Windows Vista or later to work. Otherwise, it returns nil as per MRI.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/win32/file.rb', line 223

def self.symlink(target, link)
  target = string_check(target)
  link = string_check(link)

  flags = File.directory?(target) ? 1 : 0

  wlink = link.wincode
  wtarget = target.wincode

  unless CreateSymbolicLinkW(wlink, wtarget, flags)
    raise SystemCallError.new('CreateSymbolicLink', FFI.errno)
  end

  0 # Comply with spec

end

.symlink?(file) ⇒ Boolean

Returns whether or not file is a symlink.

Returns:

  • (Boolean)


241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/win32/file.rb', line 241

def self.symlink?(file)
  return false unless File.exist?(file)

  bool  = false
  wfile = string_check(file).wincode

  attrib = GetFileAttributesW(wfile)

  if attrib == INVALID_FILE_ATTRIBUTES
    raise SystemCallError.new('GetFileAttributes', FFI.errno)
  end

  if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0
    begin
      find_data = WIN32_FIND_DATA.new
      handle = FindFirstFileW(wfile, find_data)

      if handle == INVALID_HANDLE_VALUE
        raise SystemCallError.new('FindFirstFile', FFI.errno)
      end

      if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
        bool = true
      end
    ensure
      CloseHandle(handle)
    end
  end

  bool
end

.world_readable?(file) ⇒ Boolean

Returns whether or not the file is readable by others. Note that this merely returns true or false, not permission bits (or nil).

Returns:

  • (Boolean)


489
490
491
492
# File 'lib/win32/file.rb', line 489

def self.world_readable?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).world_readable?
end

.world_writable?(file) ⇒ Boolean

Returns whether or not the file is writable by others. Note that this merely returns true or false, not permission bits (or nil).

Returns:

  • (Boolean)


497
498
499
500
# File 'lib/win32/file.rb', line 497

def self.world_writable?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).world_writable?
end

.writable?(file) ⇒ Boolean

Returns whether or not the file is writable by the current process owner.

Returns:

  • (Boolean)


504
505
506
507
# File 'lib/win32/file.rb', line 504

def self.writable?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).writable?
end

.writable_real?(file) ⇒ Boolean

Synonym for File.writable?

Returns:

  • (Boolean)


511
512
513
514
# File 'lib/win32/file.rb', line 511

def self.writable_real?(file)
  return false unless File.exist?(file)
  File::Stat.new(file).writable_real?
end

Instance Method Details

#statObject

Same as MRI, except it returns a stat object using the win32-file-stat gem.



527
528
529
# File 'lib/win32/file.rb', line 527

def stat
  File::Stat.new(self.path)
end