github.com/searKing/golang/go@v1.2.117/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  	try := 0
   463  	for {
   464  		seqUsed = seq + try
   465  		name := fmt.Sprintf("%s%d%s", prefix, seqUsed, suffix)
   466  		f, err = LockAll(name)
   467  		if os.IsExist(err) {
   468  			if try++; try < 10000 {
   469  				continue
   470  			}
   471  			return nil, 0, &os.PathError{Op: "nextfile", Path: prefix + "*" + suffix, Err: os.ErrExist}
   472  		}
   473  		return f, seqUsed, err
   474  	}
   475  }
   476  
   477  // MaxSeq return max seq set by NextFile
   478  // split pattern by the last wildcard "*"
   479  func MaxSeq(pattern string) (prefix string, seq int, suffix string) {
   480  	return MaxSeqFunc(pattern, func(name string) bool { return false })
   481  }
   482  
   483  // MaxSeqFunc return hit seq or max seq else set by NextFile
   484  // split pattern by the last wildcard "*"
   485  // All errors that arise visiting files and directories are filtered by fn:
   486  // see the [filepath.WalkFunc] documentation for details.
   487  func MaxSeqFunc(pattern string, handler func(name string) bool) (prefix string, seq int, suffix string) {
   488  	// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
   489  	// returning prefix as the part before "*" and suffix as the part after "*".
   490  	prefix, suffix = prefixAndSuffix(pattern)
   491  
   492  	var hitOrMaxSeq int
   493  	// ignore [os.ErrBadPattern], taken as hitOrMaxSeq is 0
   494  	_ = filepath_.WalkGlob(fmt.Sprintf("%s*%s", prefix, suffix), func(path string) error {
   495  		hit := handler(path)
   496  		// filepath.Clean fix ./xxx -> xxx
   497  		seqStr := strings.TrimSuffix(strings.TrimPrefix(path, filepath.Clean(prefix)), suffix)
   498  		if seq, err := strconv.Atoi(seqStr); err == nil {
   499  			if seq > hitOrMaxSeq || hit {
   500  				hitOrMaxSeq = seq
   501  			}
   502  		} else if hit {
   503  			hitOrMaxSeq = 0
   504  		}
   505  
   506  		if hit {
   507  			return filepath.SkipAll
   508  		}
   509  		return nil
   510  	})
   511  	return prefix, hitOrMaxSeq, suffix
   512  }
   513  
   514  // prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
   515  // returning prefix as the part before "*" and suffix as the part after "*".
   516  func prefixAndSuffix(pattern string) (prefix, suffix string) {
   517  	if pos := strings.LastIndex(pattern, "*"); pos != -1 {
   518  		prefix, suffix = pattern[:pos], pattern[pos+1:]
   519  	} else {
   520  		prefix = pattern
   521  	}
   522  	return prefix, suffix
   523  }
   524  
   525  // WriteAll writes data to a file named by filename.
   526  // If the file does not exist, WriteAll creates it with mode 0666 (before umask)
   527  // If the dir does not exist, WriteAll creates it with 0755 (before umask)
   528  // otherwise WriteAll truncates it before writing, without changing permissions.
   529  func WriteAll(filename string, data []byte) error {
   530  	return WriteFileAll(filename, data, DefaultPermissionDirectory, DefaultPermissionFile)
   531  }
   532  
   533  // WriteFileAll is the generalized open call; most users will use WriteAll instead.
   534  // It writes data to a file named by filename.
   535  // If the file does not exist, WriteFileAll creates it with permissions fileperm (before umask)
   536  // If the dir does not exist, WriteFileAll creates it with permissions dirperm (before umask)
   537  // otherwise WriteFileAll truncates it before writing, without changing permissions.
   538  func WriteFileAll(filename string, data []byte, dirperm, fileperm os.FileMode) error {
   539  	return WriteFileAllFrom(filename, bytes.NewReader(data), dirperm, fileperm)
   540  }
   541  
   542  // WriteAllFrom writes data to a file named by filename from r until EOF or error.
   543  // If the file does not exist, WriteAll creates it with mode 0666 (before umask)
   544  // If the dir does not exist, WriteAll creates it with 0755 (before umask)
   545  // otherwise WriteAll truncates it before writing, without changing permissions.
   546  func WriteAllFrom(filename string, r io.Reader) error {
   547  	return WriteFileAllFrom(filename, r, DefaultPermissionDirectory, DefaultPermissionFile)
   548  }
   549  
   550  // WriteFileAllFrom is the generalized open call; most users will use WriteAllFrom instead.
   551  // It writes data to a file named by filename from r until EOF or error.
   552  // If the file does not exist, WriteFileAllFrom creates it with permissions fileperm (before umask)
   553  // If the dir does not exist, WriteFileAllFrom creates it with permissions dirperm (before umask)
   554  // otherwise WriteFileAllFrom truncates it before writing, without changing permissions.
   555  func WriteFileAllFrom(filename string, r io.Reader, dirperm, fileperm os.FileMode) error {
   556  	f, err := OpenFileAll(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, dirperm, fileperm)
   557  	if err != nil {
   558  		return err
   559  	}
   560  	_, err = f.ReadFrom(r)
   561  	if err1 := f.Close(); err == nil {
   562  		err = err1
   563  	}
   564  	return err
   565  }
   566  
   567  // AppendAll appends data to a file named by filename.
   568  // If the file does not exist, AppendAll creates it with mode 0666 (before umask)
   569  // If the dir does not exist, AppendAll creates it with 0755 (before umask)
   570  // (before umask); otherwise AppendAll appends it before writing, without changing permissions.
   571  func AppendAll(filename string, data []byte) error {
   572  	return AppendFileAll(filename, data, DefaultPermissionDirectory, DefaultPermissionFile)
   573  }
   574  
   575  // AppendFileAll is the generalized open call; most users will use AppendAll instead.
   576  // It appends data to a file named by filename.
   577  // If the file does not exist, AppendFileAll creates it with permissions fileperm (before umask)
   578  // If the dir does not exist, AppendFileAll creates it with permissions dirperm (before umask)
   579  // otherwise AppendFileAll appends it before writing, without changing permissions.
   580  func AppendFileAll(filename string, data []byte, dirperm, fileperm os.FileMode) error {
   581  	return AppendFileAllFrom(filename, bytes.NewReader(data), dirperm, fileperm)
   582  }
   583  
   584  // AppendAllFrom appends data to a file named by filename from r until EOF or error.
   585  // If the file does not exist, AppendAllFrom creates it with mode 0666 (before umask)
   586  // If the dir does not exist, AppendAllFrom creates it with 0755 (before umask)
   587  // (before umask); otherwise AppendAllFrom appends it before writing, without changing permissions.
   588  func AppendAllFrom(filename string, r io.Reader) error {
   589  	return AppendFileAllFrom(filename, r, DefaultPermissionDirectory, DefaultPermissionFile)
   590  }
   591  
   592  // AppendFileAllFrom is the generalized open call; most users will use AppendFileFrom instead.
   593  // It appends data to a file named by filename from r until EOF or error.
   594  // If the file does not exist, AppendFileAllFrom creates it with permissions fileperm (before umask)
   595  // If the dir does not exist, AppendFileAllFrom creates it with permissions dirperm (before umask)
   596  // otherwise AppendFileAllFrom appends it before writing, without changing permissions.
   597  func AppendFileAllFrom(filename string, r io.Reader, dirperm, fileperm os.FileMode) error {
   598  	f, err := OpenFileAll(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, dirperm, fileperm)
   599  	if err != nil {
   600  		return err
   601  	}
   602  	_, err = f.ReadFrom(r)
   603  	if err1 := f.Close(); err == nil {
   604  		err = err1
   605  	}
   606  	return err
   607  }
   608  
   609  // WriteRenameAll writes data to a temp file and rename to the new file named by filename.
   610  // If the file does not exist, WriteRenameAll creates it with mode 0666 (before umask)
   611  // If the dir does not exist, WriteRenameAll creates it with 0755 (before umask)
   612  // otherwise WriteRenameAll truncates it before writing, without changing permissions.
   613  func WriteRenameAll(filename string, data []byte) error {
   614  	return WriteRenameFileAll(filename, data, DefaultPermissionDirectory)
   615  }
   616  
   617  // WriteRenameFileAll is the generalized open call; most users will use WriteRenameAll instead.
   618  // WriteRenameFileAll is safer than WriteFileAll 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, WriteRenameFileAll creates it with permissions fileperm
   621  // If the dir does not exist, WriteRenameFileAll creates it with permissions dirperm
   622  // (before umask); otherwise WriteRenameFileAll truncates it before writing, without changing permissions.
   623  func WriteRenameFileAll(filename string, data []byte, dirperm os.FileMode) error {
   624  	return WriteRenameFileAllFrom(filename, bytes.NewReader(data), dirperm)
   625  }
   626  
   627  // WriteRenameAllFrom writes data to a temp file from r until EOF or error, and rename to the new file named by filename.
   628  // WriteRenameAllFrom is safer than WriteAllFrom as before Write finished, nobody can find the unfinished file.
   629  // If the file does not exist, WriteRenameAllFrom creates it with mode 0666 (before umask)
   630  // If the dir does not exist, WriteRenameAllFrom creates it with 0755 (before umask)
   631  // otherwise WriteRenameAllFrom truncates it before writing, without changing permissions.
   632  func WriteRenameAllFrom(filename string, r io.Reader) error {
   633  	return WriteRenameFileAllFrom(filename, r, DefaultPermissionDirectory)
   634  }
   635  
   636  // WriteRenameFileAllFrom is the generalized open call; most users will use WriteRenameAllFrom instead.
   637  // WriteRenameFileAllFrom is safer than WriteRenameAllFrom as before Write finished, nobody can find the unfinished file.
   638  // It writes data to a temp file and rename to the new file named by filename.
   639  // If the file does not exist, WriteRenameFileAllFrom creates it with permissions fileperm
   640  // If the dir does not exist, WriteRenameFileAllFrom creates it with permissions dirperm
   641  // (before umask); otherwise WriteRenameFileAllFrom truncates it before writing, without changing permissions.
   642  func WriteRenameFileAllFrom(filename string, r io.Reader, dirperm os.FileMode) error {
   643  	tempDir := filepath.Dir(filename)
   644  	if tempDir != "" {
   645  		// mkdir -p dir
   646  		if err := os.MkdirAll(tempDir, dirperm); err != nil {
   647  			return err
   648  		}
   649  	}
   650  
   651  	tempFile, err := os.CreateTemp(tempDir, "")
   652  	if err != nil {
   653  		return err
   654  	}
   655  	defer tempFile.Close()
   656  
   657  	tempFilePath := tempFile.Name()
   658  	defer os.Remove(tempFilePath)
   659  	_, err = tempFile.ReadFrom(r)
   660  	if err != nil {
   661  		return err
   662  	}
   663  	return RenameFileAll(tempFilePath, filename, dirperm)
   664  }
   665  
   666  // TempAll creates a new temporary file in the directory dir,
   667  // opens the file for reading and writing, and returns the resulting *os.File.
   668  // If the file does not exist, TempAll creates it with mode 0600 (before umask)
   669  // If the dir does not exist, TempAll creates it with 0755 (before umask)
   670  // otherwise TempAll truncates it before writing, without changing permissions.
   671  func TempAll(dir, pattern string) (f *os.File, err error) {
   672  	return TempFileAll(dir, pattern, DefaultPermissionDirectory)
   673  }
   674  
   675  // TempFileAll is the generalized open call; most users will use TempAll instead.
   676  // If the directory does not exist, it is created with mode dirperm (before umask).
   677  func TempFileAll(dir, pattern string, dirperm os.FileMode) (f *os.File, err error) {
   678  	if dir != "" {
   679  		// mkdir -p dir
   680  		if err := os.MkdirAll(dir, dirperm); err != nil {
   681  			return nil, err
   682  		}
   683  	}
   684  	return os.CreateTemp(dir, pattern)
   685  }
   686  
   687  // MkdirTempAll creates a new temporary directory in the directory dir
   688  // and returns the pathname of the new directory.
   689  // The new directory's name is generated by adding a random string to the end of pattern.
   690  // If pattern includes a "*", the random string replaces the last "*" instead.
   691  // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
   692  // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
   693  // It is the caller's responsibility to remove the directory when it is no longer needed.
   694  // If the dir does not exist, TempAll creates it with 0755 (before umask)
   695  func MkdirTempAll(dir, pattern string) (string, error) {
   696  	return MkdirTempDirAll(dir, pattern, DefaultPermissionDirectory)
   697  }
   698  
   699  // MkdirTempDirAll is the generalized open call; most users will use MkdirTempAll instead.
   700  // If the directory does not exist, it is created with mode dirperm (before umask).
   701  func MkdirTempDirAll(dir, pattern string, dirperm os.FileMode) (string, error) {
   702  	if dir != "" {
   703  		// mkdir -p dir
   704  		if err := os.MkdirAll(dir, dirperm); err != nil {
   705  			return "", err
   706  		}
   707  	}
   708  	return os.MkdirTemp(dir, pattern)
   709  }