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