// AtomicWriteFile updates the filename atomically and works otherwise // like io/ioutil.WriteFile() // // Note that it won't follow symlinks and will replace existing symlinks // with the real file func AtomicWriteFile(filename string, data []byte, perm os.FileMode, flags AtomicWriteFlags) (err error) { if flags&AtomicWriteFollow != 0 { if fn, err := os.Readlink(filename); err == nil || (fn != "" && os.IsNotExist(err)) { if filepath.IsAbs(fn) { filename = fn } else { filename = filepath.Join(filepath.Dir(filename), fn) } } } tmp := filename + "." + strutil.MakeRandomString(12) // XXX: if go switches to use aio_fsync, we need to open the dir for writing dir, err := os.Open(filepath.Dir(filename)) if err != nil { return err } defer dir.Close() fd, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, perm) if err != nil { return err } defer func() { e := fd.Close() if err == nil { err = e } if err != nil { os.Remove(tmp) } }() // according to the docs, Write returns a non-nil error when n != // len(b), so don't worry about short writes. if _, err := fd.Write(data); err != nil { return err } if err := fd.Sync(); err != nil { return err } if err := os.Rename(tmp, filename); err != nil { return err } return dir.Sync() }
func (ts *AtomicWriteTestSuite) TestAtomicWriteFileNoOverwriteTmpExisting(c *C) { tmpdir := c.MkDir() // ensure we always get the same result rand.Seed(1) expectedRandomness := strutil.MakeRandomString(12) // ensure we always get the same result rand.Seed(1) p := filepath.Join(tmpdir, "foo") err := ioutil.WriteFile(p+"."+expectedRandomness, []byte(""), 0644) c.Assert(err, IsNil) err = AtomicWriteFile(p, []byte(""), 0600, 0) c.Assert(err, ErrorMatches, "open .*: file exists") }
// NewSubscriber returns a new subscriber containing the given websocket // connection and type/resource filters set from the query string params in the // supplied http request func NewSubscriber(c websocketConnection, r *http.Request) *Subscriber { s := &Subscriber{ uuid: strutil.MakeRandomString(16), conn: c, } q := r.URL.Query() if len(q["types"]) > 0 { s.types = strings.Split(q["types"][0], ",") } if len(q["resource"]) > 0 { s.resource = q["resource"][0] } return s }
// genClassicScopeName generates an uniq name for the classic scope func genClassicScopeName() string { now := time.Now() ti := fmt.Sprintf("%4d-%02d-%02d_%02d:%02d:%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) return fmt.Sprintf("snappy-classic_%s_%s.scope", ti, strutil.MakeRandomString(5)) }