summaryrefslogtreecommitdiffstats
path: root/lib/puppet/util/file_locking.rb
blob: 8b194ed83fac4825ce17294453dcb20ffbb18a9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
require 'puppet/util'

module Puppet::Util::FileLocking
  module_function

  # Create a shared lock for reading
  def readlock(file)
    raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
    Puppet::Util.sync(file).synchronize(Sync::SH) do
      File.open(file) { |f|
        f.lock_shared { |lf| yield lf }
      }
    end
  end

  # Create an exclusive lock for writing, and do the writing in a
  # tmp file.
  def writelock(file, mode = nil)
    raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(file))
    raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
    tmpfile = file + ".tmp"

    unless mode
      # It's far more likely that the file will be there than not, so it's
      # better to stat once to check for existence and mode.
      # If we can't stat, it's most likely because the file's not there,
      # but could also be because the directory isn't readable, in which case
      # we won't be able to write anyway.
      begin
        mode = File.stat(file).mode
      rescue
        mode = 0600
      end
    end

    Puppet::Util.sync(file).synchronize(Sync::EX) do
      File.open(file, "w", mode) do |rf|
        rf.lock_exclusive do |lrf|
          yield lrf
        end
      end
    end
  end
end