mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
This change addresses a few racy errors that started appearing in spread once snapshotstate had landed, and some issues that were found during the debugging of same. In particular: * `o/snapshotstate/backend` the runuser wrapper had a bug (or runuser has a bug?) where the -- is needed because runuser's option parsing does not stop at he first non-option. * `o/snapshotstate` In TestRestoreIntegrationFails sometimes one of the restores actually succeeds, and is undone, instead of erroring out. Also, if running as root, don't run the integration tests, as the faking of the user does not amuse runuser * `osutil` have a lock so that if one goroutine tries to mkdirallchown /foo/bar, and another tries to mkdirallchown /foo/baz, they can't both decide they need to make /foo and then have one fail. This is hackish, and needs a proper fix, but contention for the lock is going to be low and fixing it properly will be tricky. We'll do that later.
88 lines
2.1 KiB
Go
88 lines
2.1 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
|
|
/*
|
|
* Copyright (C) 2016 Canonical Ltd
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
package osutil
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/snapcore/snapd/osutil/sys"
|
|
)
|
|
|
|
// XXX: we need to come back and fix this; this is a hack to unblock us.
|
|
// As part of the fixing we should unify with the similar code in
|
|
// cmd/snap-update-ns/utils.(*Secure).MkdirAll
|
|
var mu sync.Mutex
|
|
|
|
// MkdirAllChown is like os.MkdirAll but it calls os.Chown on any
|
|
// directories it creates.
|
|
func MkdirAllChown(path string, perm os.FileMode, uid sys.UserID, gid sys.GroupID) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
return mkdirAllChown(filepath.Clean(path), perm, uid, gid)
|
|
}
|
|
|
|
func mkdirAllChown(path string, perm os.FileMode, uid sys.UserID, gid sys.GroupID) error {
|
|
// split out so filepath.Clean isn't called twice for each inner path
|
|
if s, err := os.Stat(path); err == nil {
|
|
if s.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
// emulate os.MkdirAll
|
|
return &os.PathError{
|
|
Op: "mkdir",
|
|
Path: path,
|
|
Err: syscall.ENOTDIR,
|
|
}
|
|
}
|
|
|
|
dir := filepath.Dir(path)
|
|
if dir != "/" {
|
|
if err := mkdirAllChown(dir, perm, uid, gid); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
cand := path + ".mkdir-new"
|
|
|
|
if err := os.Mkdir(cand, perm); err != nil && !os.IsExist(err) {
|
|
return err
|
|
}
|
|
|
|
if err := sys.ChownPath(cand, uid, gid); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.Rename(cand, path); err != nil {
|
|
return err
|
|
}
|
|
|
|
fd, err := os.Open(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fd.Close()
|
|
|
|
return fd.Sync()
|
|
}
|