// acquireLock locks the lock file for the given user's authorized_keys.d.
// A lock file is created if it doesn't already exist.
// The locking is currently a simple coarse-grained mutex held for the
// Open()-Close() duration, implemented using a lock file in the user's ~/.
func acquireLock(u *user.User) (*os.File, error) {
	f, err := as_user.OpenFile(u, lockFilePath(u),
		syscall.O_CREAT|syscall.O_RDONLY, 0600)
	if err != nil {
		return nil, err
	}
	if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
		f.Close()
		return nil, err
	}
	return f, nil
}
// Replace replaces the opened key with the supplied data.
func (ak *SSHAuthorizedKey) Replace(keys []byte) error {
	sp := stageFilePath(ak.origin.user)
	sf, err := as_user.OpenFile(ak.origin.user, sp,
		syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer os.Remove(sp)
	if _, err = sf.Write(keys); err != nil {
		return err
	}
	if err := sf.Close(); err != nil {
		return err
	}
	return as_user.Rename(ak.origin.user, sp, ak.Path)
}
// Sync synchronizes the user's ~/.ssh/authorized_keys file with the
// current authorized_keys.d directory state.
func (akd *SSHAuthorizedKeysDir) Sync() error {
	sp := stageFilePath(akd.user)
	sf, err := as_user.OpenFile(akd.user, sp,
		syscall.O_CREAT|syscall.O_TRUNC|syscall.O_WRONLY, 0600)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			sf.Close()
			os.Remove(sp)
		}
	}()

	if err := akd.WalkKeys(func(k *SSHAuthorizedKey) error {
		if !k.Disabled {
			kb, err := ioutil.ReadFile(k.Path)
			if err != nil {
				return err
			}
			kb = append(kb, '\n')
			if _, err := sf.Write(kb); err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		return err
	}

	if err := sf.Close(); err != nil {
		return err
	}

	err = as_user.Rename(akd.user, sp, authKeysFilePath(akd.user))
	if err != nil {
		return err
	}

	return nil
}