github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libdokan/file.go (about)

     1  // Copyright 2016 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package libdokan
     6  
     7  import (
     8  	"github.com/keybase/client/go/kbfs/data"
     9  	"github.com/keybase/client/go/kbfs/dokan"
    10  	"github.com/keybase/client/go/kbfs/libkbfs"
    11  	"github.com/keybase/client/go/libkb"
    12  	"golang.org/x/net/context"
    13  )
    14  
    15  // File represents KBFS files.
    16  type File struct {
    17  	FSO
    18  }
    19  
    20  func newFile(folder *Folder, node libkbfs.Node, name string, parent libkbfs.Node) *File {
    21  	f := &File{FSO{
    22  		name:   name,
    23  		parent: parent,
    24  		folder: folder,
    25  		node:   node,
    26  	}}
    27  	f.refcount.Increase()
    28  	return f
    29  }
    30  
    31  // GetFileInformation for dokan.
    32  func (f *File) GetFileInformation(ctx context.Context, fi *dokan.FileInfo) (a *dokan.Stat, err error) {
    33  	f.folder.fs.logEnter(ctx, "File GetFileInformation")
    34  	defer func() { f.folder.reportErr(ctx, libkbfs.ReadMode, err) }()
    35  
    36  	a, err = eiToStat(f.folder.fs.config.KBFSOps().Stat(ctx, f.node))
    37  	if a != nil {
    38  		f.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "File GetFileInformation node=%v => %v", f.node, *a)
    39  	} else {
    40  		f.folder.fs.log.CDebugf(ctx, "File GetFileInformation node=%v => Error %T %v", f.node, err, err)
    41  	}
    42  	return a, err
    43  }
    44  
    45  func (f *File) namePPS() data.PathPartString {
    46  	return f.parent.ChildName(f.name)
    47  }
    48  
    49  // CanDeleteFile - return just nil
    50  // TODO check for permissions here.
    51  func (f *File) CanDeleteFile(ctx context.Context, fi *dokan.FileInfo) error {
    52  	f.folder.fs.logEnterf(ctx, "File CanDeleteFile for %s", f.namePPS())
    53  	return nil
    54  }
    55  
    56  // Cleanup - for dokan, remember to handle deletions.
    57  // If Cleanup is called with non-nil FileInfo that has IsDeleteOnClose()
    58  // no libdokan locks should be held prior to the call.
    59  func (f *File) Cleanup(ctx context.Context, fi *dokan.FileInfo) {
    60  	var err error
    61  	f.folder.fs.logEnter(ctx, "File Cleanup")
    62  	defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
    63  
    64  	f.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Cleanup %v", *f)
    65  	if fi != nil && fi.IsDeleteOnClose() {
    66  		// renameAndDeletionLock should be the first lock to be grabbed in libdokan.
    67  		f.folder.fs.renameAndDeletionLock.Lock()
    68  		defer f.folder.fs.renameAndDeletionLock.Unlock()
    69  		namePPS := f.namePPS()
    70  		f.folder.fs.vlog.CLogf(
    71  			ctx, libkb.VLog1, "Removing (Delete) file in cleanup %s", namePPS)
    72  
    73  		err = f.folder.fs.config.KBFSOps().RemoveEntry(
    74  			ctx, f.parent, namePPS)
    75  	}
    76  
    77  	if f.refcount.Decrease() {
    78  		f.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Forgetting file node")
    79  		f.folder.forgetNode(ctx, f.node)
    80  	}
    81  }
    82  
    83  // FlushFileBuffers performs a (f)sync.
    84  func (f *File) FlushFileBuffers(ctx context.Context, fi *dokan.FileInfo) (err error) {
    85  	f.folder.fs.logEnter(ctx, "File FlushFileBuffers")
    86  	defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
    87  
    88  	return f.folder.fs.config.KBFSOps().SyncAll(ctx, f.node.GetFolderBranch())
    89  }
    90  
    91  // ReadFile for dokan reads.
    92  func (f *File) ReadFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (n int, err error) {
    93  	f.folder.fs.logEnter(ctx, "ReadFile")
    94  	defer func() { f.folder.reportErr(ctx, libkbfs.ReadMode, err) }()
    95  
    96  	var nlarge int64
    97  	nlarge, err = f.folder.fs.config.KBFSOps().Read(ctx, f.node, bs, offset)
    98  
    99  	// This is safe since length of slices always fits into an int
   100  	return int(nlarge), err
   101  }
   102  
   103  // WriteFile for dokan writes.
   104  func (f *File) WriteFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (n int, err error) {
   105  	f.folder.fs.logEnter(ctx, "WriteFile")
   106  	defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
   107  
   108  	if offset == -1 {
   109  		ei, err := f.folder.fs.config.KBFSOps().Stat(ctx, f.node)
   110  		if err != nil {
   111  			return 0, err
   112  		}
   113  		offset = int64(ei.Size)
   114  	}
   115  
   116  	err = f.folder.fs.config.KBFSOps().Write(ctx, f.node, bs, offset)
   117  	return len(bs), err
   118  }
   119  
   120  // SetEndOfFile for dokan (f)truncates.
   121  func (f *File) SetEndOfFile(ctx context.Context, fi *dokan.FileInfo, length int64) (err error) {
   122  	f.folder.fs.logEnter(ctx, "File SetEndOfFile")
   123  	defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
   124  
   125  	return f.folder.fs.config.KBFSOps().Truncate(ctx, f.node, uint64(length))
   126  }
   127  
   128  // SetAllocationSize for dokan (f)truncates but does not grow
   129  // file size (it may fallocate, but that is not done at the
   130  // moment).
   131  func (f *File) SetAllocationSize(ctx context.Context, fi *dokan.FileInfo, newSize int64) (err error) {
   132  	f.folder.fs.logEnter(ctx, "File SetAllocationSize")
   133  	defer func() { f.folder.reportErr(ctx, libkbfs.WriteMode, err) }()
   134  
   135  	ei, err := f.folder.fs.config.KBFSOps().Stat(ctx, f.node)
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	// Refuse to grow the file.
   141  	if int64(ei.Size) <= newSize {
   142  		return nil
   143  	}
   144  
   145  	return f.folder.fs.config.KBFSOps().Truncate(ctx, f.node, uint64(newSize))
   146  }
   147  
   148  // SetFileAttributes for Dokan.
   149  func (f *File) SetFileAttributes(ctx context.Context, fi *dokan.FileInfo, fileAttributes dokan.FileAttribute) error {
   150  	f.folder.fs.logEnterf(ctx, "File SetFileAttributes %X", fileAttributes)
   151  	// TODO handle attributes for real.
   152  	return nil
   153  }