blob: 5d9fb5303955813af93a31199bb683011cad7d41 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package fileutil
16
17import (
18 "fmt"
19 "io"
20 "io/ioutil"
21 "os"
22 "path/filepath"
23
24 "github.com/coreos/pkg/capnslog"
25)
26
27const (
28 // PrivateFileMode grants owner to read/write a file.
29 PrivateFileMode = 0600
30 // PrivateDirMode grants owner to make/remove files inside the directory.
31 PrivateDirMode = 0700
32)
33
34var plog = capnslog.NewPackageLogger("go.etcd.io/etcd", "pkg/fileutil")
35
36// IsDirWriteable checks if dir is writable by writing and removing a file
37// to dir. It returns nil if dir is writable.
38func IsDirWriteable(dir string) error {
39 f := filepath.Join(dir, ".touch")
40 if err := ioutil.WriteFile(f, []byte(""), PrivateFileMode); err != nil {
41 return err
42 }
43 return os.Remove(f)
44}
45
46// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
47// does not exists. TouchDirAll also ensures the given directory is writable.
48func TouchDirAll(dir string) error {
49 // If path is already a directory, MkdirAll does nothing
50 // and returns nil.
51 err := os.MkdirAll(dir, PrivateDirMode)
52 if err != nil {
53 // if mkdirAll("a/text") and "text" is not
54 // a directory, this will return syscall.ENOTDIR
55 return err
56 }
57 return IsDirWriteable(dir)
58}
59
60// CreateDirAll is similar to TouchDirAll but returns error
61// if the deepest directory was not empty.
62func CreateDirAll(dir string) error {
63 err := TouchDirAll(dir)
64 if err == nil {
65 var ns []string
66 ns, err = ReadDir(dir)
67 if err != nil {
68 return err
69 }
70 if len(ns) != 0 {
71 err = fmt.Errorf("expected %q to be empty, got %q", dir, ns)
72 }
73 }
74 return err
75}
76
77// Exist returns true if a file or directory exists.
78func Exist(name string) bool {
79 _, err := os.Stat(name)
80 return err == nil
81}
82
83// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
84// shorten the length of the file.
85func ZeroToEnd(f *os.File) error {
86 // TODO: support FALLOC_FL_ZERO_RANGE
87 off, err := f.Seek(0, io.SeekCurrent)
88 if err != nil {
89 return err
90 }
91 lenf, lerr := f.Seek(0, io.SeekEnd)
92 if lerr != nil {
93 return lerr
94 }
95 if err = f.Truncate(off); err != nil {
96 return err
97 }
98 // make sure blocks remain allocated
99 if err = Preallocate(f, lenf, true); err != nil {
100 return err
101 }
102 _, err = f.Seek(off, io.SeekStart)
103 return err
104}