Class: PEROBS::RobustFile

Inherits:
Object
  • Object
show all
Defined in:
lib/perobs/RobustFile.rb

Class Method Summary collapse

Class Method Details

.write(name, string) ⇒ Object

This is a more robust version of File::write. It first writes to a temporary file and them atomically renames the new file to the potentially existing old file. This should significantly increase our chances that we never end up with a corrupted file due to problems during the file write.



39
40
41
42
43
44
45
46
47
48
49
50
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
# File 'lib/perobs/RobustFile.rb', line 39

def RobustFile::write(name, string)
  tmp_name = name + '.atomic'

  # Ensure that no file with the temporary name exists.
  if File.exist?(tmp_name)
    PEROBS.log.warn "Found old temporary file #{tmp_name}"
    unless File.exist?(name)
      # If we have a file with the temporary name but no file with the
      # actual name, rename the temporary file to the actual name. We have
      # no idea if that temporary file is good enough, but it's better to
      # have a file with the actual name as backup in case this file write
      # fails.
      begin
        File.rename(tmp_name, name)
      rescue IOError => e
        raise IOError "Could not name old temporary file to #{name}: " +
          e.message
      end
      Log.warn "Found old temporary file but no corresponding original file"
    else
      # Delete the old temporary file.
      begin
        File.delete(tmp_name)
      rescue IOError => e
        PEROBS.log.warn "Could not delete old temporary file " +
          "#{tmp_name}: #{e.message}"
      end
    end
  end

  # Write the temporary file.
  begin
    File.write(tmp_name, string)
  rescue IOError => e
    raise IOError "Could not write file #{tmp_name}: #{e.message}"
  end

  # If the temporary file was written successfully we can rename it to the
  # actual file name and atomically replace the old file if it exists.
  begin
    File.rename(tmp_name, name)
  rescue IOError => e
     raise IOError "Could not rename #{tmp_name} to #{name}: #{e.message}"
  end
end