github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/samples/errorfs/error_fs.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package errorfs
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"reflect"
    22  	"sync"
    23  	"syscall"
    24  
    25  	"github.com/scaleoutsean/fusego/fuseops"
    26  	"github.com/scaleoutsean/fusego/fuseutil"
    27  )
    28  
    29  const FooContents = "xxxx"
    30  
    31  const fooInodeID = fuseops.RootInodeID + 1
    32  
    33  var fooAttrs = fuseops.InodeAttributes{
    34  	Nlink: 1,
    35  	Size:  uint64(len(FooContents)),
    36  	Mode:  0444,
    37  }
    38  
    39  // A file system whose sole contents are a file named "foo" containing the
    40  // string defined by FooContents.
    41  //
    42  // The file system can be configured to returned canned errors for particular
    43  // operations using the method SetError.
    44  type FS interface {
    45  	fuseutil.FileSystem
    46  
    47  	// Cause the file system to return the supplied error for all future
    48  	// operations matching the supplied type.
    49  	SetError(t reflect.Type, err syscall.Errno)
    50  }
    51  
    52  func New() (FS, error) {
    53  	return &errorFS{
    54  		errors: make(map[reflect.Type]syscall.Errno),
    55  	}, nil
    56  }
    57  
    58  type errorFS struct {
    59  	fuseutil.NotImplementedFileSystem
    60  
    61  	mu sync.Mutex
    62  
    63  	// GUARDED_BY(mu)
    64  	errors map[reflect.Type]syscall.Errno
    65  }
    66  
    67  // LOCKS_EXCLUDED(fs.mu)
    68  func (fs *errorFS) SetError(t reflect.Type, err syscall.Errno) {
    69  	fs.mu.Lock()
    70  	defer fs.mu.Unlock()
    71  
    72  	fs.errors[t] = err
    73  }
    74  
    75  // LOCKS_EXCLUDED(fs.mu)
    76  func (fs *errorFS) transformError(op interface{}, err *error) bool {
    77  	fs.mu.Lock()
    78  	defer fs.mu.Unlock()
    79  
    80  	cannedErr, ok := fs.errors[reflect.TypeOf(op)]
    81  	if ok {
    82  		*err = cannedErr
    83  		return true
    84  	}
    85  
    86  	return false
    87  }
    88  
    89  ////////////////////////////////////////////////////////////////////////
    90  // File system methods
    91  ////////////////////////////////////////////////////////////////////////
    92  
    93  // LOCKS_EXCLUDED(fs.mu)
    94  func (fs *errorFS) GetInodeAttributes(
    95  	ctx context.Context,
    96  	op *fuseops.GetInodeAttributesOp) error {
    97  	var err error
    98  	if fs.transformError(op, &err) {
    99  		return err
   100  	}
   101  
   102  	// Figure out which inode the request is for.
   103  	switch {
   104  	case op.Inode == fuseops.RootInodeID:
   105  		op.Attributes = fuseops.InodeAttributes{
   106  			Mode: os.ModeDir | 0777,
   107  		}
   108  
   109  	case op.Inode == fooInodeID:
   110  		op.Attributes = fooAttrs
   111  
   112  	default:
   113  		return fmt.Errorf("Unknown inode: %d", op.Inode)
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  func (fs *errorFS) StatFS(
   120  	ctx context.Context,
   121  	op *fuseops.StatFSOp) error {
   122  	return nil
   123  }
   124  
   125  // LOCKS_EXCLUDED(fs.mu)
   126  func (fs *errorFS) LookUpInode(
   127  	ctx context.Context,
   128  	op *fuseops.LookUpInodeOp) error {
   129  	var err error
   130  	if fs.transformError(op, &err) {
   131  		return err
   132  	}
   133  
   134  	// Is this a known inode?
   135  	if !(op.Parent == fuseops.RootInodeID && op.Name == "foo") {
   136  		return syscall.ENOENT
   137  	}
   138  
   139  	op.Entry.Child = fooInodeID
   140  	op.Entry.Attributes = fooAttrs
   141  
   142  	return nil
   143  }
   144  
   145  // LOCKS_EXCLUDED(fs.mu)
   146  func (fs *errorFS) OpenFile(
   147  	ctx context.Context,
   148  	op *fuseops.OpenFileOp) error {
   149  	var err error
   150  	if fs.transformError(op, &err) {
   151  		return err
   152  	}
   153  
   154  	if op.Inode != fooInodeID {
   155  		return fmt.Errorf("Unsupported inode ID: %d", op.Inode)
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  // LOCKS_EXCLUDED(fs.mu)
   162  func (fs *errorFS) ReadFile(
   163  	ctx context.Context,
   164  	op *fuseops.ReadFileOp) error {
   165  	var err error
   166  	if fs.transformError(op, &err) {
   167  		return err
   168  	}
   169  
   170  	if op.Inode != fooInodeID || op.Offset != 0 {
   171  		return fmt.Errorf("Unexpected request: %#v", op)
   172  	}
   173  
   174  	op.BytesRead = copy(op.Dst, FooContents)
   175  
   176  	return nil
   177  }
   178  
   179  // LOCKS_EXCLUDED(fs.mu)
   180  func (fs *errorFS) OpenDir(
   181  	ctx context.Context,
   182  	op *fuseops.OpenDirOp) error {
   183  	var err error
   184  	if fs.transformError(op, &err) {
   185  		return err
   186  	}
   187  
   188  	if op.Inode != fuseops.RootInodeID {
   189  		return fmt.Errorf("Unsupported inode ID: %d", op.Inode)
   190  	}
   191  
   192  	return nil
   193  }
   194  
   195  // LOCKS_EXCLUDED(fs.mu)
   196  func (fs *errorFS) ReadDir(
   197  	ctx context.Context,
   198  	op *fuseops.ReadDirOp) error {
   199  	var err error
   200  	if fs.transformError(op, &err) {
   201  		return err
   202  	}
   203  
   204  	if op.Inode != fuseops.RootInodeID || op.Offset != 0 {
   205  		return fmt.Errorf("Unexpected request: %#v", op)
   206  	}
   207  
   208  	op.BytesRead = fuseutil.WriteDirent(
   209  		op.Dst,
   210  		fuseutil.Dirent{
   211  			Offset: 0,
   212  			Inode:  fooInodeID,
   213  			Name:   "foo",
   214  			Type:   fuseutil.DT_File,
   215  		})
   216  
   217  	return nil
   218  }