# class Chef::FileContentManagement::Deploy::MvUnix

PURPOSE: this strategy is atomic, and attempts to preserve file modes

NOTE: there is no preserve flag to FileUtils.mv, and we want to preserve the dst file

    modes rather than the src file modes (preserve = true is what mv does already, we
    would like preserve = false which is tricky).

### Public Instance Methods

create(file) click to toggle source

    # File lib/chef/file_content_management/deploy/mv_unix.rb, line 30
    def create(file)
      # this is very simple, but it ensures that ownership and file modes take
      # good defaults, in particular mode needs to obey umask on create
      Chef::Log.debug("touching #{file} to create it")
      FileUtils.touch(file)
    end

deploy(src, dst) click to toggle source

    # File lib/chef/file_content_management/deploy/mv_unix.rb, line 37
    def deploy(src, dst)
      # we are only responsible for content so restore the dst files perms
      Chef::Log.debug("reading modes from #{dst} file")
      stat = ::File.stat(dst)
      mode = stat.mode & 07777
      uid  = stat.uid
      gid  = stat.gid

      Chef::Log.debug("applying mode = #{mode.to_s(8)}, uid = #{uid}, gid = #{gid} to #{src}")

      # i own the inode, so should be able to at least chmod it
      ::File.chmod(mode, src)

      # we may be running as non-root in which case because we are doing an mv we cannot preserve
      # the file modes.  after the mv we have a different inode and if we don't have rights to
      # chown/chgrp on the inode then we can't fix the ownership.
      #
      # in the case where i'm running chef-solo on my homedir as myself and some root-shell
      # work has caused dotfiles of mine to change to root-owned, i'm fine with this not being
      # exceptional, and i think most use cases will consider this to not be exceptional, and
      # the right thing is to fix the ownership of the file to the user running the commmand
      # (which requires write perms to the directory, or mv will throw an exception)
      begin
        ::File.chown(uid, nil, src)
      rescue Errno::EPERM
        Chef::Log.warn("Could not set uid = #{uid} on #{src}, file modes not preserved")
      end
      begin
        ::File.chown(nil, gid, src)
      rescue Errno::EPERM
        Chef::Log.warn("Could not set gid = #{gid} on #{src}, file modes not preserved")
      end

      Chef::Log.debug("moving temporary file #{src} into place at #{dst}")
      FileUtils.mv(src, dst)
    end