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 }