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 }