github.com/searKing/golang/go@v1.2.74/os/file.go (about)

     1  // Copyright 2022 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  
    17  	filepath_ "github.com/searKing/golang/go/path/filepath"
    18  )
    19  
    20  const (
    21  	DefaultPermissionFile       os.FileMode = 0666
    22  	DefaultPermissionDirectory  os.FileMode = 0755
    23  	DefaultFlagCreateIfNotExist             = os.O_RDWR | os.O_CREATE
    24  	DefaultFlagCreateTruncate               = os.O_RDWR | os.O_CREATE | os.O_TRUNC
    25  	DefaultFlagCreate                       = DefaultFlagCreateTruncate
    26  	DefaultFlagCreateAppend                 = os.O_RDWR | os.O_CREATE | os.O_APPEND
    27  	DefaultFlagLock                         = os.O_RDWR | os.O_CREATE | os.O_EXCL
    28  )
    29  
    30  func GetAbsBinDir() (dir string, err error) {
    31  	return filepath.Abs(filepath.Dir(os.Args[0]))
    32  }
    33  
    34  func PathExists(path string) (bool, error) {
    35  	_, err := os.Stat(path)
    36  	if err == nil {
    37  		return true, nil
    38  	}
    39  	if os.IsNotExist(err) {
    40  		return false, nil
    41  	}
    42  	return false, err
    43  }
    44  
    45  // RemoveIfExist removes the named file or (empty) directory.
    46  // If the path does not exist, RemoveIfExist returns nil (no error).
    47  // If there is an error, it will be of type *PathError.
    48  func RemoveIfExist(name string) error {
    49  	err := os.Remove(name)
    50  	if err == nil || os.IsNotExist(err) {
    51  		return nil
    52  	}
    53  	return err
    54  }
    55  
    56  // ChtimesNow changes the access and modification times of the named
    57  // file with Now, similar to the Unix utime() or utimes() functions.
    58  //
    59  // The underlying filesystem may truncate or round the values to a
    60  // less precise time unit.
    61  // If there is an error, it will be of type *PathError.
    62  func ChtimesNow(name string) error {
    63  	now := time.Now()
    64  	return os.Chtimes(name, now, now)
    65  }
    66  
    67  // MakeAll creates a directory named path,
    68  // along with any necessary parents, and returns nil,
    69  // or else returns an error.
    70  // If the dir does not exist, it is created with mode 0755 (before umask).
    71  func MakeAll(name string) error {
    72  	return os.MkdirAll(name, DefaultPermissionDirectory)
    73  }
    74  
    75  // Make creates a directory named path and returns nil,
    76  // or else returns an error.
    77  // If the dir does not exist, it is created with mode 0755 (before umask).
    78  func Make(name string) error {
    79  	return os.Mkdir(name, DefaultPermissionDirectory)
    80  }
    81  
    82  // RenameAll renames (moves) oldpath to newpath.
    83  // If newpath already exists and is not a directory, Rename replaces it.
    84  // OS-specific restrictions may apply when oldpath and newpath are in different directories.
    85  // If there is an error, it will be of type *LinkError.
    86  // If the dir does not exist, it is created with mode 0755 (before umask).
    87  func RenameAll(oldpath, newpath string) error {
    88  	return RenameFileAll(oldpath, newpath, DefaultPermissionDirectory)
    89  }
    90  
    91  // RenameFileAll is the generalized open call; most users will use RenameAll instead.
    92  // It renames (moves) oldpath to newpath.
    93  func RenameFileAll(oldpath, newpath string, dirperm os.FileMode) error {
    94  	// file or dir not exists
    95  	if _, err := os.Stat(newpath); err != nil {
    96  		dir, _ := filepath.Split(newpath)
    97  
    98  		if dir != "" {
    99  			// mkdir -p dir
   100  			if err := os.MkdirAll(dir, dirperm); err != nil {
   101  				return err
   102  			}
   103  		}
   104  	}
   105  	return os.Rename(oldpath, newpath)
   106  }
   107  
   108  // TouchAll creates the named file or dir. If the file already exists, it is touched to now.
   109  // If the file does not exist, it is created with mode 0666 (before umask).
   110  // If the dir does not exist, it is created with mode 0755 (before umask).
   111  func TouchAll(path string) (*os.File, error) {
   112  	f, err := OpenFileAll(path, os.O_WRONLY|os.O_CREATE, DefaultPermissionDirectory, DefaultPermissionFile)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if err := ChtimesNow(path); err != nil {
   117  		defer f.Close()
   118  		return nil, err
   119  	}
   120  	return f, nil
   121  }
   122  
   123  // CreateAll creates or truncates the named file or dir. If the file already exists,
   124  // it is truncated. If the file does not exist, it is created with mode 0666 (before umask).
   125  // If the dir does not exist, it is created with mode 0755 (before umask).
   126  func CreateAll(path string) (*os.File, error) {
   127  	return OpenFileAll(path, DefaultFlagCreate, DefaultPermissionDirectory, DefaultPermissionFile)
   128  }
   129  
   130  // CreateAllIfNotExist creates the named file or dir. If the file does not exist, it is created
   131  // with mode 0666 (before umask).
   132  // If the dir does not exist, it is created with mode 0755 (before umask).
   133  // If path is already a directory, CreateAllIfNotExist does nothing and returns nil.
   134  func CreateAllIfNotExist(path string) (*os.File, error) {
   135  	return OpenFileAll(path, DefaultFlagCreateIfNotExist, DefaultPermissionDirectory, DefaultPermissionFile)
   136  }
   137  
   138  // AppendAllIfNotExist appends the named file or dir. If the file does not exist, it is created
   139  // with mode 0666 (before umask).
   140  // If the dir does not exist, it is created with mode 0755 (before umask).
   141  // If path is already a directory, CreateAllIfNotExist does nothing and returns nil.
   142  func AppendAllIfNotExist(path string) (*os.File, error) {
   143  	return OpenFileAll(path, DefaultFlagCreateAppend, DefaultPermissionDirectory, DefaultPermissionFile)
   144  }
   145  
   146  // OpenAll opens the named file or dir for reading. If successful, methods on
   147  // the returned file or dir can be used for reading; the associated file
   148  // descriptor has mode O_RDONLY.
   149  // If there is an error, it will be of type *PathError.
   150  func OpenAll(path string) (*os.File, error) {
   151  	return OpenFileAll(path, os.O_RDONLY, 0, 0)
   152  }
   153  
   154  // LockAll creates the named file or dir. If the file already exists, error returned.
   155  // If the file does not exist, it is created with mode 0666 (before umask).
   156  // If the dir does not exist, it is created with mode 0755 (before umask).
   157  func LockAll(path string) (*os.File, error) {
   158  	return OpenFileAll(path, DefaultFlagLock, DefaultPermissionDirectory, DefaultPermissionFile)
   159  }
   160  
   161  // OpenFileAll is the generalized open call; most users will use OpenAll
   162  // or CreateAll instead. It opens the named file or directory with specified flag
   163  // (O_RDONLY etc.).
   164  // If the file does not exist, and the O_CREATE flag is passed, it is created with mode fileperm (before umask).
   165  // If the directory does not exist, it is created with mode dirperm (before umask).
   166  // If successful, methods on the returned File can be used for I/O.
   167  // If there is an error, it will be of type *PathError.
   168  func OpenFileAll(path string, flag int, dirperm, fileperm os.FileMode) (*os.File, error) {
   169  	dir, file := filepath.Split(path)
   170  	// file or dir exists
   171  	if _, err := os.Stat(path); err == nil {
   172  		return os.OpenFile(path, flag, 0)
   173  	}
   174  
   175  	if dir != "" {
   176  		// mkdir -p dir
   177  		if err := os.MkdirAll(dir, dirperm); err != nil {
   178  			return nil, err
   179  		}
   180  	}
   181  
   182  	// create file if needed
   183  	if file == "" {
   184  		return nil, nil
   185  	}
   186  	return os.OpenFile(path, flag, fileperm)
   187  }
   188  
   189  // CopyAll creates or truncates the dst file or dir, filled with content from src file.
   190  // If the dst file already exists, it is truncated.
   191  // If the dst file does not exist, it is created with mode 0666 (before umask).
   192  // If the dst dir does not exist, it is created with mode 0755 (before umask).
   193  func CopyAll(dst string, src string) error {
   194  	return CopyFileAll(dst, src, DefaultFlagCreate, DefaultPermissionDirectory, DefaultPermissionFile)
   195  }
   196  
   197  // CopyAppendAll creates or appends the dst file or dir, filled with content from src file.
   198  // If the dst file already exists, it is truncated.
   199  // If the dst file does not exist, it is created with mode 0666 (before umask).
   200  // If the dst dir does not exist, it is created with mode 0755 (before umask).
   201  func CopyAppendAll(dst string, src string) error {
   202  	return CopyFileAll(dst, src, DefaultFlagCreateAppend, DefaultPermissionDirectory, DefaultPermissionFile)
   203  }
   204  
   205  // CopyFileAll is the generalized open call; most users will use CopyAll
   206  // or AppendAll instead. It opens the named file or directory with specified flag
   207  // (O_RDONLY etc.).
   208  // If the dst file does not exist, and the O_CREATE flag is passed, it is created with mode fileperm (before umask).
   209  // If the dst directory does not exist, it is created with mode dirperm (before umask).
   210  // If successful, methods on the returned File can be used for I/O.
   211  // If there is an error, it will be of type *PathError.
   212  func CopyFileAll(dst string, src string, flag int, dirperm, fileperm os.FileMode) error {
   213  	srcFile, err := os.Open(src)
   214  	if err != nil {
   215  		return err
   216  	}
   217  	defer srcFile.Close()
   218  
   219  	dstFile, err := OpenFileAll(dst, flag, dirperm, fileperm)
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	defer dstFile.Close()
   225  
   226  	_, err = io.Copy(dstFile, srcFile)
   227  	return err
   228  }
   229  
   230  // Copy creates or truncates the dst file or dir, filled with content from src file.
   231  // If the dst file already exists, it is truncated.
   232  // If the dst file does not exist, it is created with mode 0666 (before umask).
   233  // If the dst dir does not exist, it is created with mode 0755 (before umask).
   234  // parent dirs will not be created, otherwise, use CopyAll instead.
   235  func Copy(dst string, src string) error {
   236  	return CopyFile(dst, src, DefaultFlagCreate, DefaultPermissionFile)
   237  }
   238  
   239  // Append creates or appends the dst file or dir, filled with content from src file.
   240  // If the dst file already exists, it is truncated.
   241  // If the dst file does not exist, it is created with mode 0666 (before umask).
   242  // If the dst dir does not exist, it is created with mode 0755 (before umask).
   243  // parent dirs will not be created, otherwise, use AppendAll instead.
   244  func Append(dst string, src string) error {
   245  	return CopyFile(dst, src, DefaultFlagCreateAppend, DefaultPermissionFile)
   246  }
   247  
   248  // CopyFile is the generalized open call; most users will use Copy
   249  // or Append instead. It opens the named file or directory with specified flag
   250  // (O_RDONLY etc.).
   251  // CopyFile copies from src to dst.
   252  // parent dirs will not be created, otherwise, use CopyFileAll instead.
   253  func CopyFile(dst string, src string, flag int, perm os.FileMode) error {
   254  	srcFile, err := os.Open(src)
   255  	if err != nil {
   256  		return err
   257  	}
   258  	defer srcFile.Close()
   259  
   260  	dstFile, err := os.OpenFile(dst, flag, perm)
   261  	if err != nil {
   262  		return err
   263  	}
   264  
   265  	defer dstFile.Close()
   266  
   267  	_, err = io.Copy(dstFile, srcFile)
   268  	return err
   269  }
   270  
   271  // CopyTruncateAll truncates the original src file in place after creating a copy dst, instead of moving the
   272  // src file to dir and optionally creating a new one src.  It can be used when some program  can‐
   273  // not  be  told  to  close its logfile and thus might continue writing (appending) to the
   274  // previous log file forever.  Note that there is a very small time slice between  copying
   275  // the  file  and  truncating it, so some logging data might be lost.
   276  // parent dirs will be created with dirperm if not exist.
   277  func CopyTruncateAll(dst string, src string) error {
   278  	return CopyTruncateFileAll(dst, src, DefaultFlagCreate, DefaultPermissionDirectory, DefaultPermissionFile, 0)
   279  }
   280  
   281  // AppendTruncateAll truncates the original src file in place after appending or creating a copy dst,
   282  // instead of moving the src file to dir and optionally creating a new one src.
   283  // parent dirs will be created with dirperm if not exist.
   284  func AppendTruncateAll(dst string, src string) error {
   285  	return CopyTruncateFileAll(dst, src, DefaultFlagCreateAppend, DefaultPermissionDirectory, DefaultPermissionFile, 0)
   286  }
   287  
   288  // CopyTruncateFileAll is the generalized open call; most users will use CopyTruncateAll or
   289  // AppendTruncateAll instead. It opens the named file or directory with specified flag (O_RDONLY etc.).
   290  // CopyTruncateFileAll copies from src to dst and truncates src.
   291  // parent dirs will be created with dirperm if not exist.
   292  func CopyTruncateFileAll(dst string, src string, flag int, dirperm, fileperm os.FileMode, size int64) error {
   293  	if err := CopyFileAll(dst, src, flag, dirperm, fileperm); err != nil {
   294  		return err
   295  	}
   296  	return os.Truncate(src, size)
   297  }
   298  
   299  // CopyTruncate truncates the original src file in place after creating a copy dst, instead of moving the
   300  // src file to dir and optionally creating a new one src.  It can be used when some program  can‐
   301  // not  be  told  to  close its logfile and thus might continue writing (appending) to the
   302  // previous log file forever.  Note that there is a very small time slice between  copying
   303  // the  file  and  truncating it, so some logging data might be lost.
   304  func CopyTruncate(dst string, src string) error {
   305  	return CopyTruncateFile(dst, src, DefaultFlagCreate, DefaultPermissionFile, 0)
   306  }
   307  
   308  // AppendTruncate truncates the original src file in place after appending or creating a copy dst,
   309  // instead of moving the src file to dir and optionally creating a new one src.
   310  func AppendTruncate(dst string, src string) error {
   311  	return CopyTruncateFile(dst, src, DefaultFlagCreateAppend, DefaultPermissionFile, 0)
   312  }
   313  
   314  // CopyTruncateFile is the generalized open call; most users will use CopyTruncate or
   315  // AppendTruncate instead. It opens the named file or directory with specified flag (O_RDONLY etc.).
   316  // CopyTruncateFile copies from src to dst and truncates src.
   317  // parent dirs will not be created, otherwise, use CopyTruncateFileAll instead.
   318  // CopyTruncateFile = CopyFile(src->dst) + Truncate(src)
   319  func CopyTruncateFile(dst string, src string, flag int, perm os.FileMode, size int64) error {
   320  	if err := CopyFile(dst, src, flag, perm); err != nil {
   321  		return err
   322  	}
   323  	return os.Truncate(src, size)
   324  }
   325  
   326  // CopyRenameAll makes a copy of the src file, but don't change the original src at all.
   327  // This option can  be used,  for  instance, to  make  a snapshot of the current log file,
   328  // or when some other utility needs to truncate or parse the file.
   329  // parent dirs will be created with dirperm if not exist.
   330  func CopyRenameAll(dst string, src string) error {
   331  	return CopyRenameFileAll(dst, src, DefaultFlagCreateIfNotExist, DefaultPermissionDirectory, DefaultPermissionFile)
   332  }
   333  
   334  // CopyRenameFileAll is the generalized open call; most users will use CopyRenameAll instead.
   335  // It makes a copy of the src file, but don't change the original src at all.
   336  // CopyRenameFileAll renames from src to dst and creates src if not exist.
   337  // parent dirs will be created with dirperm if not exist.
   338  // CopyRenameFileAll = RenameFileAll(src->dst) + OpenFile(src)
   339  func CopyRenameFileAll(dst string, src string, flag int, dirperm, fileperm os.FileMode) error {
   340  	if err := RenameFileAll(src, dst, dirperm); err != nil {
   341  		return err
   342  	}
   343  	f, err := os.OpenFile(src, flag, fileperm)
   344  	if err != nil {
   345  		return err
   346  	}
   347  	defer f.Close()
   348  	return nil
   349  }
   350  
   351  // CopyRename makes a copy of the src file, but don't change the original src at all.  This option can  be
   352  // used,  for  instance,  to  make  a snapshot of the current log file, or when some other
   353  // utility needs to truncate or parse the file.
   354  func CopyRename(dst string, src string) error {
   355  	return CopyRenameFile(dst, src, DefaultFlagCreate, DefaultPermissionFile)
   356  }
   357  
   358  // CopyRenameFile is the generalized open call; most users will use CopyRename instead.
   359  // It opens the named file or directory with specified flag (O_RDONLY etc.).
   360  // CopyTruncateFile copies from src to dst and truncates src.
   361  // parent dirs will not be created, otherwise, use CopyRenameFileAll instead.
   362  func CopyRenameFile(dst string, src string, flag int, perm os.FileMode) error {
   363  	if err := os.Rename(src, dst); err != nil {
   364  		return err
   365  	}
   366  	f, err := os.OpenFile(src, flag, perm)
   367  	if err != nil {
   368  		return err
   369  	}
   370  	defer f.Close()
   371  	return nil
   372  }
   373  
   374  // SameFile reports whether fi1 and fi2 describe the same file.
   375  // Overload os.SameFile by file path
   376  func SameFile(fi1, fi2 string) bool {
   377  	stat1, err := os.Stat(fi1)
   378  	if err != nil {
   379  		return false
   380  	}
   381  
   382  	stat2, err := os.Stat(fi2)
   383  	if err != nil {
   384  		return false
   385  	}
   386  	return os.SameFile(stat1, stat2)
   387  }
   388  
   389  // ReLink creates or replaces newname as a hard link to the oldname file.
   390  // If there is an error, it will be of type *LinkError.
   391  func ReLink(oldname, newname string) error {
   392  	tempLink, err := os.CreateTemp(filepath.Dir(newname), filepath.Base(newname))
   393  	if err != nil {
   394  		return err
   395  	}
   396  	if err = tempLink.Close(); err != nil {
   397  		return err
   398  	}
   399  
   400  	if err = os.Remove(tempLink.Name()); err != nil {
   401  		return err
   402  	}
   403  
   404  	defer os.Remove(tempLink.Name())
   405  	// keep mode the same if newname already exists.
   406  	if fi, err := os.Stat(newname); err == nil {
   407  		if err := os.Chmod(tempLink.Name(), fi.Mode()); err != nil {
   408  			return err
   409  		}
   410  	}
   411  
   412  	if err := os.Link(oldname, tempLink.Name()); err != nil {
   413  		return err
   414  	}
   415  	return os.Rename(tempLink.Name(), newname)
   416  
   417  }
   418  
   419  // ReSymlink creates or replace newname as a symbolic link to oldname.
   420  // If there is an error, it will be of type *LinkError.
   421  func ReSymlink(oldname, newname string) error {
   422  	tempLink, err := os.CreateTemp(filepath.Dir(newname), filepath.Base(newname))
   423  	if err != nil {
   424  		return err
   425  	}
   426  	if err = tempLink.Close(); err != nil {
   427  		return err
   428  	}
   429  
   430  	if err = os.Remove(tempLink.Name()); err != nil {
   431  		return err
   432  	}
   433  
   434  	defer os.Remove(tempLink.Name())
   435  	if err := os.Symlink(oldname, tempLink.Name()); err != nil {
   436  		return err
   437  	}
   438  	// keep mode the same if newname already exists.
   439  	if fi, err := os.Stat(newname); err == nil {
   440  		if err := os.Chmod(tempLink.Name(), fi.Mode()); err != nil {
   441  			return err
   442  		}
   443  	}
   444  
   445  	return os.Rename(tempLink.Name(), newname)
   446  }
   447  
   448  // NextFile creates a new file, opens the file for reading and writing,
   449  // and returns the resulting *os.File.
   450  // The filename is generated by taking pattern and adding a seq increased
   451  // string to the end. If pattern includes a "*", the random string
   452  // replaces the last "*".
   453  // Multiple programs calling NextFile simultaneously
   454  // will not choose the same file. The caller can use f.Name()
   455  // to find the pathname of the file. It is the caller's responsibility
   456  // to remove the file when no longer needed.
   457  func NextFile(pattern string, seq int) (f *os.File, seqUsed int, err error) {
   458  	// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
   459  	// returning prefix as the part before "*" and suffix as the part after "*".
   460  	prefix, suffix := prefixAndSuffix(pattern)
   461  
   462  	for i := 0; i < 10000; i++ {
   463  		seqUsed = seq + i
   464  		name := fmt.Sprintf("%s%d%s", prefix, seqUsed, suffix)
   465  		f, err = LockAll(name)
   466  		if os.IsExist(err) {
   467  			continue
   468  		}
   469  		break
   470  	}
   471  	return
   472  }
   473  
   474  // MaxSeq return max seq set by NextFile
   475  // split pattern by the last wildcard "*"
   476  func MaxSeq(pattern string) (prefix string, seq int, suffix string) {
   477  	// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
   478  	// returning prefix as the part before "*" and suffix as the part after "*".
   479  	prefix, suffix = prefixAndSuffix(pattern)
   480  
   481  	var maxSeq int
   482  	_, _ = filepath_.GlobFunc(fmt.Sprintf("%s*%s", prefix, suffix), func(name string) bool {
   483  		// filepath.Clean fix ./xxx -> xxx
   484  		seqStr := strings.TrimSuffix(strings.TrimPrefix(name, filepath.Clean(prefix)), suffix)
   485  		if seq, err := strconv.Atoi(seqStr); err == nil {
   486  			if seq > maxSeq {
   487  				maxSeq = seq
   488  			}
   489  		}
   490  		return false
   491  	})
   492  	return prefix, maxSeq, suffix
   493  }
   494  
   495  // prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
   496  // returning prefix as the part before "*" and suffix as the part after "*".
   497  func prefixAndSuffix(pattern string) (prefix, suffix string) {
   498  	if pos := strings.LastIndex(pattern, "*"); pos != -1 {
   499  		prefix, suffix = pattern[:pos], pattern[pos+1:]
   500  	} else {
   501  		prefix = pattern
   502  	}
   503  	return
   504  }
   505  
   506  // WriteAll writes data to a file named by filename.
   507  // If the file does not exist, WriteAll creates it with mode 0666 (before umask)
   508  // If the dir does not exist, WriteAll creates it with 0755 (before umask)
   509  // otherwise WriteAll truncates it before writing, without changing permissions.
   510  func WriteAll(filename string, data []byte) error {
   511  	return WriteFileAll(filename, data, DefaultPermissionDirectory, DefaultPermissionFile)
   512  }
   513  
   514  // WriteFileAll is the generalized open call; most users will use WriteAll instead.
   515  // It writes data to a file named by filename.
   516  // If the file does not exist, WriteFileAll creates it with permissions fileperm (before umask)
   517  // If the dir does not exist, WriteFileAll creates it with permissions dirperm (before umask)
   518  // otherwise WriteFileAll truncates it before writing, without changing permissions.
   519  func WriteFileAll(filename string, data []byte, dirperm, fileperm os.FileMode) error {
   520  	return WriteFileAllFrom(filename, bytes.NewReader(data), dirperm, fileperm)
   521  }
   522  
   523  // WriteAllFrom writes data to a file named by filename from r until EOF or error.
   524  // If the file does not exist, WriteAll creates it with mode 0666 (before umask)
   525  // If the dir does not exist, WriteAll creates it with 0755 (before umask)
   526  // otherwise WriteAll truncates it before writing, without changing permissions.
   527  func WriteAllFrom(filename string, r io.Reader) error {
   528  	return WriteFileAllFrom(filename, r, DefaultPermissionDirectory, DefaultPermissionFile)
   529  }
   530  
   531  // WriteFileAllFrom is the generalized open call; most users will use WriteAllFrom instead.
   532  // It writes data to a file named by filename from r until EOF or error.
   533  // If the file does not exist, WriteFileAllFrom creates it with permissions fileperm (before umask)
   534  // If the dir does not exist, WriteFileAllFrom creates it with permissions dirperm (before umask)
   535  // otherwise WriteFileAllFrom truncates it before writing, without changing permissions.
   536  func WriteFileAllFrom(filename string, r io.Reader, dirperm, fileperm os.FileMode) error {
   537  	f, err := OpenFileAll(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, dirperm, fileperm)
   538  	if err != nil {
   539  		return err
   540  	}
   541  	_, err = f.ReadFrom(r)
   542  	if err1 := f.Close(); err == nil {
   543  		err = err1
   544  	}
   545  	return err
   546  }
   547  
   548  // AppendAll appends data to a file named by filename.
   549  // If the file does not exist, AppendAll creates it with mode 0666 (before umask)
   550  // If the dir does not exist, AppendAll creates it with 0755 (before umask)
   551  // (before umask); otherwise AppendAll appends it before writing, without changing permissions.
   552  func AppendAll(filename string, data []byte) error {
   553  	return AppendFileAll(filename, data, DefaultPermissionDirectory, DefaultPermissionFile)
   554  }
   555  
   556  // AppendFileAll is the generalized open call; most users will use AppendAll instead.
   557  // It appends data to a file named by filename.
   558  // If the file does not exist, AppendFileAll creates it with permissions fileperm (before umask)
   559  // If the dir does not exist, AppendFileAll creates it with permissions dirperm (before umask)
   560  // otherwise AppendFileAll appends it before writing, without changing permissions.
   561  func AppendFileAll(filename string, data []byte, dirperm, fileperm os.FileMode) error {
   562  	return AppendFileAllFrom(filename, bytes.NewReader(data), dirperm, fileperm)
   563  }
   564  
   565  // AppendAllFrom appends data to a file named by filename from r until EOF or error.
   566  // If the file does not exist, AppendAllFrom creates it with mode 0666 (before umask)
   567  // If the dir does not exist, AppendAllFrom creates it with 0755 (before umask)
   568  // (before umask); otherwise AppendAllFrom appends it before writing, without changing permissions.
   569  func AppendAllFrom(filename string, r io.Reader) error {
   570  	return AppendFileAllFrom(filename, r, DefaultPermissionDirectory, DefaultPermissionFile)
   571  }
   572  
   573  // AppendFileAllFrom is the generalized open call; most users will use AppendFileFrom instead.
   574  // It appends data to a file named by filename from r until EOF or error.
   575  // If the file does not exist, AppendFileAllFrom creates it with permissions fileperm (before umask)
   576  // If the dir does not exist, AppendFileAllFrom creates it with permissions dirperm (before umask)
   577  // otherwise AppendFileAllFrom appends it before writing, without changing permissions.
   578  func AppendFileAllFrom(filename string, r io.Reader, dirperm, fileperm os.FileMode) error {
   579  	f, err := OpenFileAll(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, dirperm, fileperm)
   580  	if err != nil {
   581  		return err
   582  	}
   583  	_, err = f.ReadFrom(r)
   584  	if err1 := f.Close(); err == nil {
   585  		err = err1
   586  	}
   587  	return err
   588  }
   589  
   590  // WriteRenameAll writes data to a temp file and rename to the new file named by filename.
   591  // If the file does not exist, WriteRenameAll creates it with mode 0666 (before umask)
   592  // If the dir does not exist, WriteRenameAll creates it with 0755 (before umask)
   593  // otherwise WriteRenameAll truncates it before writing, without changing permissions.
   594  func WriteRenameAll(filename string, data []byte) error {
   595  	return WriteRenameFileAll(filename, data, DefaultPermissionDirectory)
   596  }
   597  
   598  // WriteRenameFileAll is the generalized open call; most users will use WriteRenameAll instead.
   599  // WriteRenameFileAll is safer than WriteFileAll as before Write finished, nobody can find the unfinished file.
   600  // It writes data to a temp file and rename to the new file named by filename.
   601  // If the file does not exist, WriteRenameFileAll creates it with permissions fileperm
   602  // If the dir does not exist, WriteRenameFileAll creates it with permissions dirperm
   603  // (before umask); otherwise WriteRenameFileAll truncates it before writing, without changing permissions.
   604  func WriteRenameFileAll(filename string, data []byte, dirperm os.FileMode) error {
   605  	return WriteRenameFileAllFrom(filename, bytes.NewReader(data), dirperm)
   606  }
   607  
   608  // WriteRenameAllFrom writes data to a temp file from r until EOF or error, and rename to the new file named by filename.
   609  // WriteRenameAllFrom is safer than WriteAllFrom as before Write finished, nobody can find the unfinished file.
   610  // If the file does not exist, WriteRenameAllFrom creates it with mode 0666 (before umask)
   611  // If the dir does not exist, WriteRenameAllFrom creates it with 0755 (before umask)
   612  // otherwise WriteRenameAllFrom truncates it before writing, without changing permissions.
   613  func WriteRenameAllFrom(filename string, r io.Reader) error {
   614  	return WriteRenameFileAllFrom(filename, r, DefaultPermissionDirectory)
   615  }
   616  
   617  // WriteRenameFileAllFrom is the generalized open call; most users will use WriteRenameAllFrom instead.
   618  // WriteRenameFileAllFrom is safer than WriteRenameAllFrom as before Write finished, nobody can find the unfinished file.
   619  // It writes data to a temp file and rename to the new file named by filename.
   620  // If the file does not exist, WriteRenameFileAllFrom creates it with permissions fileperm
   621  // If the dir does not exist, WriteRenameFileAllFrom creates it with permissions dirperm
   622  // (before umask); otherwise WriteRenameFileAllFrom truncates it before writing, without changing permissions.
   623  func WriteRenameFileAllFrom(filename string, r io.Reader, dirperm os.FileMode) error {
   624  	tempDir := filepath.Dir(filename)
   625  	if tempDir != "" {
   626  		// mkdir -p dir
   627  		if err := os.MkdirAll(tempDir, dirperm); err != nil {
   628  			return err
   629  		}
   630  	}
   631  
   632  	tempFile, err := os.CreateTemp(tempDir, "")
   633  	if err != nil {
   634  		return err
   635  	}
   636  	defer tempFile.Close()
   637  
   638  	tempFilePath := tempFile.Name()
   639  	defer os.Remove(tempFilePath)
   640  	_, err = tempFile.ReadFrom(r)
   641  	if err != nil {
   642  		return err
   643  	}
   644  	return RenameFileAll(tempFilePath, filename, dirperm)
   645  }
   646  
   647  // TempAll creates a new temporary file in the directory dir,
   648  // opens the file for reading and writing, and returns the resulting *os.File.
   649  // If the file does not exist, TempAll creates it with mode 0600 (before umask)
   650  // If the dir does not exist, TempAll creates it with 0755 (before umask)
   651  // otherwise TempAll truncates it before writing, without changing permissions.
   652  func TempAll(dir, pattern string) (f *os.File, err error) {
   653  	return TempFileAll(dir, pattern, DefaultPermissionDirectory)
   654  }
   655  
   656  // TempFileAll is the generalized open call; most users will use TempAll instead.
   657  // If the directory does not exist, it is created with mode dirperm (before umask).
   658  func TempFileAll(dir, pattern string, dirperm os.FileMode) (f *os.File, err error) {
   659  	if dir != "" {
   660  		// mkdir -p dir
   661  		if err := os.MkdirAll(dir, dirperm); err != nil {
   662  			return nil, err
   663  		}
   664  	}
   665  	return os.CreateTemp(dir, pattern)
   666  }