github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/vfs/memfs/memfs_file.go (about) 1 // 2 // Copyright 2020 The AVFS authors 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package memfs 18 19 import ( 20 "io" 21 "io/fs" 22 "time" 23 24 "github.com/avfs/avfs" 25 ) 26 27 // Chdir changes the current working directory to the file, 28 // which must be a directory. 29 // If there is an error, it will be of type *PathError. 30 func (f *MemFile) Chdir() error { 31 const op = "chdir" 32 33 if f == nil { 34 return fs.ErrInvalid 35 } 36 37 f.mu.Lock() 38 defer f.mu.Unlock() 39 40 if f.name == "" { 41 return fs.ErrInvalid 42 } 43 44 if f.nd == nil { 45 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 46 } 47 48 _, ok := f.nd.(*dirNode) 49 if !ok { 50 err := error(avfs.ErrNotADirectory) 51 if f.vfs.OSType() == avfs.OsWindows { 52 err = avfs.ErrWinDirNameInvalid 53 } 54 55 return &fs.PathError{Op: op, Path: f.name, Err: err} 56 } 57 58 _ = f.vfs.SetCurDir(f.name) 59 60 return nil 61 } 62 63 // Chmod changes the mode of the file to mode. 64 // If there is an error, it will be of type *PathError. 65 func (f *MemFile) Chmod(mode fs.FileMode) error { 66 const op = "chmod" 67 68 if f == nil { 69 return fs.ErrInvalid 70 } 71 72 f.mu.Lock() 73 defer f.mu.Unlock() 74 75 if f.name == "" { 76 return fs.ErrInvalid 77 } 78 79 if f.nd == nil { 80 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 81 } 82 83 nd := f.nd 84 85 nd.Lock() 86 defer nd.Unlock() 87 88 if !nd.setMode(mode, f.vfs.User()) { 89 return &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.PermDenied} 90 } 91 92 return nil 93 } 94 95 // Chown changes the numeric uid and gid of the named file. 96 // If there is an error, it will be of type *PathError. 97 // 98 // On Windows, it always returns the syscall.EWINDOWS error, wrapped 99 // in *PathError. 100 func (f *MemFile) Chown(uid, gid int) error { 101 const op = "chown" 102 103 if f == nil { 104 return fs.ErrInvalid 105 } 106 107 f.mu.Lock() 108 defer f.mu.Unlock() 109 110 if f.name == "" { 111 return fs.ErrInvalid 112 } 113 114 if f.nd == nil { 115 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 116 } 117 118 if f.vfs.OSType() == avfs.OsWindows { 119 return &fs.PathError{Op: op, Path: f.name, Err: avfs.ErrWinNotSupported} 120 } 121 122 nd := f.nd 123 124 nd.Lock() 125 defer nd.Unlock() 126 127 if !nd.checkPermission(avfs.OpenWrite, f.vfs.User()) { 128 return &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.OpNotPermitted} 129 } 130 131 nd.setOwner(uid, gid) 132 133 return nil 134 } 135 136 // Close closes the File, rendering it unusable for I/O. 137 // On files that support SetDeadline, any pending I/O operations will 138 // be canceled and return immediately with an error. 139 func (f *MemFile) Close() error { 140 const op = "close" 141 142 if f == nil { 143 return fs.ErrInvalid 144 } 145 146 f.mu.Lock() 147 defer f.mu.Unlock() 148 149 if f.nd == nil { 150 if f.name == "" { 151 return fs.ErrInvalid 152 } 153 154 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 155 } 156 157 f.dirEntries = nil 158 f.dirNames = nil 159 f.nd = nil 160 161 return nil 162 } 163 164 // Fd returns the integer Unix file descriptor referencing the open file. 165 // The file descriptor is valid only until f.Close is called or f is garbage collected. 166 // On Unix systems this will cause the SetDeadline methods to stop working. 167 func (f *MemFile) Fd() uintptr { 168 return ^(uintptr(0)) 169 } 170 171 // Name returns the link of the file as presented to Open. 172 func (f *MemFile) Name() string { 173 if f == nil { 174 panic("") 175 } 176 177 f.mu.RLock() 178 name := f.name 179 f.mu.RUnlock() 180 181 return name 182 } 183 184 // Read reads up to len(b) bytes from the MemFile. 185 // It returns the number of bytes read and any error encountered. 186 // At end of file, Read returns 0, io.EOF. 187 func (f *MemFile) Read(b []byte) (n int, err error) { 188 const op = "read" 189 190 if f == nil { 191 return 0, fs.ErrInvalid 192 } 193 194 f.mu.Lock() 195 defer f.mu.Unlock() 196 197 if f.name == "" { 198 return 0, fs.ErrInvalid 199 } 200 201 if f.nd == nil { 202 return 0, &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 203 } 204 205 nd, ok := f.nd.(*fileNode) 206 if !ok { 207 err = avfs.ErrIsADirectory 208 if f.vfs.OSType() == avfs.OsWindows { 209 err = avfs.ErrWinIncorrectFunc 210 } 211 212 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 213 } 214 215 if f.openMode&avfs.OpenRead == 0 { 216 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.BadFileDesc} 217 } 218 219 nd.mu.RLock() 220 n = copy(b, nd.data[f.at:]) 221 nd.mu.RUnlock() 222 223 f.at += int64(n) 224 225 if n == 0 { 226 return 0, io.EOF 227 } 228 229 return n, nil 230 } 231 232 // ReadAt reads len(b) bytes from the File starting at byte offset off. 233 // It returns the number of bytes read and the error, if any. 234 // ReadAt always returns a non-nil error when n < len(b). 235 // At end of file, that error is io.EOF. 236 func (f *MemFile) ReadAt(b []byte, off int64) (n int, err error) { 237 const op = "read" 238 239 if f == nil { 240 return 0, fs.ErrInvalid 241 } 242 243 f.mu.RLock() 244 defer f.mu.RUnlock() 245 246 if f.name == "" { 247 return 0, fs.ErrInvalid 248 } 249 250 if f.nd == nil { 251 return 0, &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 252 } 253 254 nd, ok := f.nd.(*fileNode) 255 if !ok { 256 err = avfs.ErrIsADirectory 257 if f.vfs.OSType() == avfs.OsWindows { 258 err = avfs.ErrWinIncorrectFunc 259 } 260 261 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 262 } 263 264 if off < 0 { 265 return 0, &fs.PathError{Op: "readat", Path: f.name, Err: avfs.ErrNegativeOffset} 266 } 267 268 if f.openMode&avfs.OpenRead == 0 { 269 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.BadFileDesc} 270 } 271 272 nd.mu.RLock() 273 defer nd.mu.RUnlock() 274 275 if int(off) > len(nd.data) { 276 return 0, io.EOF 277 } 278 279 n = copy(b, nd.data[off:]) 280 if n < len(b) { 281 return n, io.EOF 282 } 283 284 return n, nil 285 } 286 287 // ReadDir reads the contents of the directory associated with the file f 288 // and returns a slice of DirEntry values in directory order. 289 // Subsequent calls on the same file will yield later DirEntry records in the directory. 290 // 291 // If n > 0, ReadDir returns at most n DirEntry records. 292 // In this case, if ReadDir returns an empty slice, it will return an error explaining why. 293 // At the end of a directory, the error is io.EOF. 294 // 295 // If n <= 0, ReadDir returns all the DirEntry records remaining in the directory. 296 // When it succeeds, it returns a nil error (not io.EOF). 297 func (f *MemFile) ReadDir(n int) (entries []fs.DirEntry, err error) { 298 if f == nil { 299 return nil, fs.ErrInvalid 300 } 301 302 f.mu.Lock() 303 defer f.mu.Unlock() 304 305 if f.name == "" { 306 return nil, fs.ErrInvalid 307 } 308 309 op := "readdirent" 310 if f.vfs.OSType() == avfs.OsWindows { 311 op = "readdir" 312 } 313 314 if f.nd == nil { 315 err = avfs.ErrFileClosing 316 if f.vfs.OSType() == avfs.OsWindows { 317 err = avfs.ErrWinInvalidHandle 318 } 319 320 return nil, &fs.PathError{Op: op, Path: f.name, Err: err} 321 } 322 323 nd, ok := f.nd.(*dirNode) 324 if !ok { 325 return nil, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.NotADirectory} 326 } 327 328 if n <= 0 || f.dirEntries == nil { 329 nd.mu.RLock() 330 entries = nd.dirEntries() 331 nd.mu.RUnlock() 332 333 f.dirIndex = 0 334 335 if n <= 0 { 336 f.dirEntries = nil 337 338 return entries, nil 339 } 340 341 f.dirEntries = entries 342 } 343 344 start := f.dirIndex 345 if start >= len(f.dirEntries) { 346 f.dirIndex = 0 347 f.dirEntries = nil 348 349 return nil, io.EOF 350 } 351 352 end := start + n 353 if end > len(f.dirEntries) { 354 end = len(f.dirEntries) 355 } 356 357 f.dirIndex = end 358 359 return f.dirEntries[start:end], nil 360 } 361 362 // Readdirnames reads and returns a slice of names from the directory f. 363 // 364 // If n > 0, Readdirnames returns at most n names. In this case, if 365 // Readdirnames returns an empty slice, it will return a non-nil error 366 // explaining why. At the end of a directory, the error is io.EOF. 367 // 368 // If n <= 0, Readdirnames returns all the names from the directory in 369 // a single slice. In this case, if Readdirnames succeeds (reads all 370 // the way to the end of the directory), it returns the slice and a 371 // nil error. If it encounters an error before the end of the 372 // directory, Readdirnames returns the names read until that point and 373 // a non-nil error. 374 func (f *MemFile) Readdirnames(n int) (names []string, err error) { 375 if f == nil { 376 return nil, fs.ErrInvalid 377 } 378 379 f.mu.Lock() 380 defer f.mu.Unlock() 381 382 if f.name == "" { 383 return nil, fs.ErrInvalid 384 } 385 386 op := "readdirent" 387 if f.vfs.OSType() == avfs.OsWindows { 388 op = "readdir" 389 } 390 391 if f.nd == nil { 392 err = avfs.ErrFileClosing 393 if f.vfs.OSType() == avfs.OsWindows { 394 err = avfs.ErrWinInvalidHandle 395 } 396 397 return nil, &fs.PathError{Op: op, Path: f.name, Err: err} 398 } 399 400 nd, ok := f.nd.(*dirNode) 401 if !ok { 402 return nil, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.NotADirectory} 403 } 404 405 if n <= 0 || f.dirNames == nil { 406 nd.mu.RLock() 407 names = nd.dirNames() 408 nd.mu.RUnlock() 409 410 f.dirIndex = 0 411 412 if n <= 0 { 413 f.dirNames = nil 414 415 return names, nil 416 } 417 418 f.dirNames = names 419 } 420 421 start := f.dirIndex 422 if start >= len(f.dirNames) { 423 f.dirIndex = 0 424 f.dirNames = nil 425 426 return nil, io.EOF 427 } 428 429 end := start + n 430 if end > len(f.dirNames) { 431 end = len(f.dirNames) 432 } 433 434 f.dirIndex = end 435 436 return f.dirNames[start:end], nil 437 } 438 439 // Seek sets the offset for the next Read or Write on file to offset, interpreted 440 // according to whence: 0 means relative to the origin of the file, 1 means 441 // relative to the current offset, and 2 means relative to the end. 442 // It returns the new offset and an error, if any. 443 // The behavior of Seek on a file opened with O_APPEND is not specified. 444 func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) { 445 const op = "seek" 446 447 if f == nil { 448 return 0, fs.ErrInvalid 449 } 450 451 f.mu.Lock() 452 defer f.mu.Unlock() 453 454 if f.name == "" { 455 return 0, fs.ErrInvalid 456 } 457 458 if f.nd == nil { 459 return 0, &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 460 } 461 462 nd, ok := f.nd.(*fileNode) 463 if !ok { 464 return 0, nil 465 } 466 467 nd.mu.RLock() 468 size := int64(len(nd.data)) 469 nd.mu.RUnlock() 470 471 switch whence { 472 case io.SeekStart: 473 if offset < 0 { 474 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.InvalidArgument} 475 } 476 477 f.at = offset 478 case io.SeekCurrent: 479 if f.at+offset < 0 { 480 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.InvalidArgument} 481 } 482 483 f.at += offset 484 case io.SeekEnd: 485 if size+offset < 0 { 486 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.InvalidArgument} 487 } 488 489 f.at = size + offset 490 default: 491 if f.vfs.OSType() != avfs.OsWindows { 492 return 0, &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.InvalidArgument} 493 } 494 495 return 0, nil 496 } 497 498 return f.at, nil 499 } 500 501 // Stat returns the FileInfo structure describing file. 502 // If there is an error, it will be of type *PathError. 503 func (f *MemFile) Stat() (info fs.FileInfo, err error) { 504 if f == nil { 505 return nil, fs.ErrInvalid 506 } 507 508 f.mu.RLock() 509 defer f.mu.RUnlock() 510 511 if f.name == "" { 512 return nil, fs.ErrInvalid 513 } 514 515 op := "stat" 516 if f.vfs.OSType() == avfs.OsWindows { 517 op = "GetFileType" 518 } 519 520 if f.nd == nil { 521 err = avfs.ErrFileClosing 522 if f.vfs.OSType() == avfs.OsWindows { 523 err = avfs.ErrWinInvalidHandle 524 } 525 526 return &MemInfo{}, &fs.PathError{Op: op, Path: f.name, Err: err} 527 } 528 529 name := f.vfs.Base(f.name) 530 fst := f.nd.fillStatFrom(name) 531 532 return fst, nil 533 } 534 535 // Sync commits the current contents of the file to stable storage. 536 // Typically, this means flushing the file system's in-memory copy 537 // of recently written data to disk. 538 func (f *MemFile) Sync() error { 539 const op = "sync" 540 541 if f == nil { 542 return fs.ErrInvalid 543 } 544 545 f.mu.RLock() 546 defer f.mu.RUnlock() 547 548 if f.name == "" { 549 return fs.ErrInvalid 550 } 551 552 if f.nd == nil { 553 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 554 } 555 556 return nil 557 } 558 559 // Truncate changes the size of the file. 560 // It does not change the I/O offset. 561 // If there is an error, it will be of type *PathError. 562 func (f *MemFile) Truncate(size int64) error { 563 const op = "truncate" 564 565 if f == nil { 566 return fs.ErrInvalid 567 } 568 569 f.mu.RLock() 570 defer f.mu.RUnlock() 571 572 if f.name == "" { 573 return fs.ErrInvalid 574 } 575 576 if size < 0 { 577 return &fs.PathError{Op: op, Path: f.name, Err: f.vfs.err.InvalidArgument} 578 } 579 580 if f.nd == nil { 581 return &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 582 } 583 584 nd, ok := f.nd.(*fileNode) 585 if !ok { 586 err := error(avfs.ErrInvalidArgument) 587 if f.vfs.OSType() == avfs.OsWindows { 588 err = avfs.ErrWinAccessDenied 589 } 590 591 return &fs.PathError{Op: op, Path: f.name, Err: err} 592 } 593 594 if f.openMode&avfs.OpenWrite == 0 { 595 err := error(avfs.ErrInvalidArgument) 596 if f.vfs.OSType() == avfs.OsWindows { 597 err = avfs.ErrWinAccessDenied 598 } 599 600 return &fs.PathError{Op: op, Path: f.name, Err: err} 601 } 602 603 nd.mu.Lock() 604 605 nd.truncate(size) 606 nd.mtime = time.Now().UnixNano() 607 608 nd.mu.Unlock() 609 610 return nil 611 } 612 613 // Write writes len(b) bytes to the File. 614 // It returns the number of bytes written and an error, if any. 615 // Write returns a non-nil error when n != len(b). 616 func (f *MemFile) Write(b []byte) (n int, err error) { 617 const op = "write" 618 619 if f == nil { 620 return 0, fs.ErrInvalid 621 } 622 623 f.mu.Lock() 624 defer f.mu.Unlock() 625 626 if f.name == "" { 627 return 0, fs.ErrInvalid 628 } 629 630 if f.nd == nil { 631 return 0, &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 632 } 633 634 nd, ok := f.nd.(*fileNode) 635 if !ok { 636 err = avfs.ErrBadFileDesc 637 if f.vfs.OSType() == avfs.OsWindows { 638 err = avfs.ErrWinAccessDenied 639 } 640 641 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 642 } 643 644 if f.openMode&avfs.OpenWrite == 0 { 645 err = avfs.ErrBadFileDesc 646 if f.vfs.OSType() == avfs.OsWindows { 647 err = avfs.ErrWinAccessDenied 648 } 649 650 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 651 } 652 653 nd.mu.Lock() 654 655 n = copy(nd.data[f.at:], b) 656 if n < len(b) { 657 nd.data = append(nd.data, b[n:]...) 658 n = len(b) 659 } 660 661 nd.mtime = time.Now().UnixNano() 662 663 nd.mu.Unlock() 664 665 f.at += int64(n) 666 667 return n, nil 668 } 669 670 // WriteAt writes len(b) bytes to the File starting at byte offset off. 671 // It returns the number of bytes written and an error, if any. 672 // WriteAt returns a non-nil error when n != len(b). 673 func (f *MemFile) WriteAt(b []byte, off int64) (n int, err error) { 674 const op = "write" 675 676 if f == nil { 677 return 0, fs.ErrInvalid 678 } 679 680 if off < 0 { 681 return 0, &fs.PathError{Op: "writeat", Path: f.name, Err: avfs.ErrNegativeOffset} 682 } 683 684 f.mu.RLock() 685 defer f.mu.RUnlock() 686 687 if f.name == "" { 688 return 0, fs.ErrInvalid 689 } 690 691 if f.nd == nil { 692 return 0, &fs.PathError{Op: op, Path: f.name, Err: fs.ErrClosed} 693 } 694 695 nd, ok := f.nd.(*fileNode) 696 if !ok { 697 err = avfs.ErrBadFileDesc 698 if f.vfs.OSType() == avfs.OsWindows { 699 err = avfs.ErrWinAccessDenied 700 } 701 702 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 703 } 704 705 if f.openMode&avfs.OpenWrite == 0 { 706 err = avfs.ErrBadFileDesc 707 if f.vfs.OSType() == avfs.OsWindows { 708 err = avfs.ErrWinAccessDenied 709 } 710 711 return 0, &fs.PathError{Op: op, Path: f.name, Err: err} 712 } 713 714 nd.mu.Lock() 715 716 diff := off + int64(len(b)) - nd.size() 717 if diff > 0 { 718 nd.data = append(nd.data, make([]byte, diff)...) 719 } 720 721 n = copy(nd.data[off:], b) 722 723 nd.mtime = time.Now().UnixNano() 724 725 nd.mu.Unlock() 726 727 return n, nil 728 } 729 730 // WriteString is like Write, but writes the contents of string s rather than 731 // a slice of bytes. 732 func (f *MemFile) WriteString(s string) (n int, err error) { 733 return f.Write([]byte(s)) 734 } 735 736 // MemInfo is the implementation of FileInfo returned by Stat and Lstat. 737 738 // Info returns the FileInfo for the file or subdirectory described by the entry. 739 // The returned FileInfo may be from the time of the original directory read 740 // or from the time of the call to Info. If the file has been removed or renamed 741 // since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). 742 // If the entry denotes a symbolic link, Info reports the information about the link itself, 743 // not the link's target. 744 func (info *MemInfo) Info() (fs.FileInfo, error) { 745 return info, nil 746 } 747 748 // IsDir reports whether the entry describes a directory. 749 func (info *MemInfo) IsDir() bool { 750 return info.mode.IsDir() 751 } 752 753 // Mode returns the file mode bits. 754 func (info *MemInfo) Mode() fs.FileMode { 755 return info.mode 756 } 757 758 // ModTime returns the modification time. 759 func (info *MemInfo) ModTime() time.Time { 760 return time.Unix(0, info.mtime) 761 } 762 763 // Name returns the base name of the file. 764 func (info *MemInfo) Name() string { 765 return info.name 766 } 767 768 // Size returns the length in bytes for regular files; system-dependent for others. 769 func (info *MemInfo) Size() int64 { 770 return info.size 771 } 772 773 // Sys returns the underlying data source (can return nil). 774 func (info *MemInfo) Sys() any { 775 return info 776 } 777 778 // Type returns the type bits for the entry. 779 // The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. 780 func (info *MemInfo) Type() fs.FileMode { 781 return info.mode & fs.ModeType 782 } 783 784 // Gid returns the group id. 785 func (info *MemInfo) Gid() int { 786 return info.gid 787 } 788 789 // Uid returns the user id. 790 func (info *MemInfo) Uid() int { 791 return info.uid 792 } 793 794 // Nlink returns the number of hard links. 795 func (info *MemInfo) Nlink() uint64 { 796 return uint64(info.nlink) 797 }