Module: Tins::SecureWrite

Included in:
IO
Defined in:
lib/tins/secure_write.rb

Overview

A module that provides secure file writing capabilities.

This module extends objects with a method to write data to files in a way that ensures atomicity and prevents partial writes, making it safer for concurrent access.

Instance Method Summary collapse

Instance Method Details

#secure_write(filename, content = nil, mode = 'w') {|File| ... } ⇒ Integer

Write to a file atomically by creating a temporary file and renaming it. This ensures that readers will either see the complete old content or the complete new content, never partial writes.

Examples:

With content

File.secure_write('config.json', '{"timeout": 30}')

With block

File.secure_write('output.txt') do |f|
  f.write("Hello, World!")
end

Parameters:

  • filename (String, #to_s)

    The target filename

  • content (String, nil) (defaults to: nil)

    The content to write (optional)

  • mode (String) (defaults to: 'w')

    File open mode (default: ‘w’)

Yields:

  • (File)

    If a block is given, yields the temporary file handle

Returns:

  • (Integer)

    The number of bytes written

Raises:

  • (ArgumentError)

    If neither content nor block is provided



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/tins/secure_write.rb', line 26

def secure_write(filename, content = nil, mode = 'w')
  temp = File.new(filename.to_s + ".tmp.#$$.#{Time.now.to_f}", mode)
  if content.nil? and block_given?
    yield temp
  elsif !content.nil?
    temp.write content
  else
    raise ArgumentError, "either content or block argument required"
  end
  temp.fsync
  size = temp.stat.size
  temp.close
  File.rename temp.path, filename
  size
ensure
  if temp
    temp.closed? or temp.close
    File.file?(temp.path) and File.unlink temp.path
  end
end