github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/ppapi/file_nacl.go (about)

     1  // Copyright 2014 The Go Authors. 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 ppapi
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"time"
    13  	"unsafe"
    14  )
    15  
    16  var (
    17  	errFileIOCreateFailed     = errors.New("FileIO creation failed")
    18  	errFileSystemCreateFailed = errors.New("filesystem creation failed")
    19  	errFileRefParentFailed    = errors.New("FileRef.Parent failed")
    20  	errNegativeFilePosition   = errors.New("negative file position")
    21  )
    22  
    23  // FileSystem specifies the file system type associated with a file.  For
    24  // example, the filesystem specifies whether a file is persistent or temporary.
    25  type FileSystem struct {
    26  	Resource
    27  	instance Instance
    28  }
    29  
    30  // Type returns the type of the file system.
    31  func (fs FileSystem) Type() FileSystemType {
    32  	return ppb_filesystem_get_type(fs.id)
    33  }
    34  
    35  // OpenFS opens the file system.
    36  //
    37  // A file system must be opened before running any other operation on it.
    38  //
    39  // Note that this does not request quota; to do that, you must either invoke
    40  // requestQuota from JavaScript:
    41  // http://www.html5rocks.com/en/tutorials/file/filesystem/#toc-requesting-quota
    42  // or set the unlimitedStorage permission for Chrome Web Store apps:
    43  // http://code.google.com/chrome/extensions/manifest.html#permissions.
    44  func (fs FileSystem) OpenFS(expectedSize int64) error {
    45  	code := ppb_filesystem_open(fs.id, expectedSize, ppNullCompletionCallback)
    46  	return decodeError(Error(code))
    47  }
    48  
    49  // Remove deletes a file or directory.
    50  //
    51  // If the name refers to a directory, then the directory must be empty. It is an
    52  // error to delete a file or directory that is in use. It is not valid to delete
    53  // a file in the external file system.
    54  func (fs FileSystem) Remove(name string) error {
    55  	ref, err := fs.CreateFileRef(name)
    56  	if err != nil {
    57  		return &os.PathError{Op: "Remove", Path: name, Err: err}
    58  	}
    59  	defer ref.Release()
    60  	if err := ref.Delete(); err != nil {
    61  		return &os.PathError{Op: "Remove", Path: name, Err: err}
    62  	}
    63  	return nil
    64  }
    65  
    66  // RemoveAll removes path and any children it contains. It removes everything it
    67  // can but returns the first error it encounters. If the path does not exist,
    68  // RemoveAll returns nil (no error).
    69  func (fs FileSystem) RemoveAll(name string) error {
    70  	ref, err := fs.CreateFileRef(name)
    71  	if err != nil {
    72  		return &os.PathError{Op: "RemoveAll", Path: name, Err: err}
    73  	}
    74  	defer ref.Release()
    75  
    76  	// Stat the file.
    77  	info, err := ref.Stat()
    78  	if err != nil {
    79  		if err == ppErrors[PP_ERROR_FILENOTFOUND] {
    80  			return nil
    81  		}
    82  		return &os.PathError{Op: "RemoveAll", Path: name, Err: err}
    83  	}
    84  
    85  	// If it is a directory, delete the entries recursively.
    86  	if info.IsDir() {
    87  		names, err := fs.Readdirnames(name)
    88  		if err != nil {
    89  			return err
    90  		}
    91  		for _, name := range names {
    92  			if err := fs.RemoveAll(name); err != nil {
    93  				return err
    94  			}
    95  		}
    96  	}
    97  
    98  	// Remove the file.
    99  	if err := ref.Delete(); err != nil {
   100  		return &os.PathError{Op: "RemoveAll", Path: name, Err: err}
   101  	}
   102  	return nil
   103  }
   104  
   105  // Rename renames a file.
   106  //
   107  // It is an error to rename a file or directory that is in use. It is not valid
   108  // to rename a file in the external file system.
   109  func (fs FileSystem) Rename(fromName, toName string) error {
   110  	fromRef, err := fs.CreateFileRef(fromName)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	defer fromRef.Release()
   115  
   116  	toRef, err := fs.CreateFileRef(toName)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	defer toRef.Release()
   121  
   122  	return fromRef.Rename(toRef)
   123  }
   124  
   125  // Mkdir creates a new directory with the specified name and permission bits. If
   126  // there is an error, it will be of type *PathError.
   127  //
   128  // It is not valid to make a directory in the external file system.
   129  func (fs FileSystem) Mkdir(name string) error {
   130  	ref, err := fs.CreateFileRef(name)
   131  	if err != nil {
   132  		return &os.PathError{Op: "Mkdir", Path: name, Err: err}
   133  	}
   134  	defer ref.Release()
   135  
   136  	if err := ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE); err != nil {
   137  		return &os.PathError{Op: "Mkdir", Path: name, Err: err}
   138  	}
   139  	return nil
   140  }
   141  
   142  // MkdirAll creates a directory named path, along with any necessary parents,
   143  // and returns nil, or else returns an error. The permission bits perm are used
   144  // for all directories that MkdirAll creates. If path is already a directory,
   145  // MkdirAll does nothing and returns nil.
   146  func (fs FileSystem) MkdirAll(name string) error {
   147  	ref, err := fs.CreateFileRef(name)
   148  	if err != nil {
   149  		return &os.PathError{Op: "Mkdir", Path: name, Err: err}
   150  	}
   151  	defer ref.Release()
   152  
   153  	if err := ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS); err != nil {
   154  		return &os.PathError{Op: "Mkdir", Path: name, Err: err}
   155  	}
   156  	return nil
   157  }
   158  
   159  // Readdirnames reads and returns a slice of names from the directory f.
   160  func (fs FileSystem) Readdirnames(name string) ([]string, error) {
   161  	ref, err := fs.CreateFileRef(name)
   162  	if err != nil {
   163  		return nil, &os.PathError{Op: "Readdirnames", Path: name, Err: err}
   164  	}
   165  	defer ref.Release()
   166  
   167  	entries, err := ref.ReadDirectoryEntries()
   168  	if err != nil {
   169  		return nil, &os.PathError{Op: "Readdirnames", Path: name, Err: err}
   170  	}
   171  
   172  	names := make([]string, len(entries))
   173  	for i, entry := range entries {
   174  		name, err := entry.File.Path()
   175  		if err != nil {
   176  			return nil, &os.PathError{Op: "Readdirnames", Path: name, Err: err}
   177  		}
   178  		names[i] = name
   179  	}
   180  	return names, nil
   181  }
   182  
   183  // Stat queries info about a file or directory.
   184  //
   185  // You must have access to read this file or directory if it exists in the
   186  // external filesystem.
   187  func (fs FileSystem) Stat(name string) (info FileInfo, err error) {
   188  	ref, e := fs.CreateFileRef(name)
   189  	if e != nil {
   190  		err = &os.PathError{Op: "Stat", Path: name, Err: e}
   191  		return
   192  	}
   193  	defer ref.Release()
   194  
   195  	info, e = ref.Stat()
   196  	if e != nil {
   197  		err = &os.PathError{Op: "Stat", Path: name, Err: e}
   198  		return
   199  	}
   200  	return
   201  }
   202  
   203  // Chtimes changes the access and modification times of the named file, similar
   204  // to the Unix utime() or utimes() functions.
   205  //
   206  // The underlying filesystem may truncate or round the values to a less precise
   207  // time unit. If there is an error, it will be of type *PathError.
   208  func (fs FileSystem) Chtimes(name string, atime, mtime time.Time) error {
   209  	ref, err := fs.CreateFileRef(name)
   210  	if err != nil {
   211  		return &os.PathError{Op: "Chtimes", Path: name, Err: err}
   212  	}
   213  	defer ref.Release()
   214  	if err := ref.Touch(atime, mtime); err != nil {
   215  		return &os.PathError{Op: "Chtimes", Path: name, Err: err}
   216  	}
   217  	return nil
   218  }
   219  
   220  // Open opens the named file for reading. If successful, methods on the returned
   221  // file can be used for reading; the associated file has mode O_RDONLY. If there
   222  // is an error, it will be of type *PathError.
   223  func (fs FileSystem) Open(name string) (*FileIO, error) {
   224  	return fs.OpenFile(name, os.O_RDONLY)
   225  }
   226  
   227  // Create creates the named file mode 0666 (before umask), truncating it if it
   228  // already exists. If successful, methods on the returned File can be used for
   229  // I/O; the associated file has mode O_RDWR. If there is an error, it will be of
   230  // type *PathError.
   231  func (fs FileSystem) Create(name string) (*FileIO, error) {
   232  	return fs.OpenFile(name, os.O_RDWR|os.O_TRUNC|os.O_CREATE)
   233  }
   234  
   235  // OpenFile is the generalized open call; most users will use Open or Create
   236  // instead. It opens the named file with specified flag (O_RDONLY etc.) and
   237  // perm, (0666 etc.) if applicable. If successful, methods on the returned File
   238  // can be used for I/O. If there is an error, it will be of type *PathError.
   239  func (fs FileSystem) OpenFile(name string, flag int) (*FileIO, error) {
   240  	ref, err := fs.CreateFileRef(name)
   241  	if err != nil {
   242  		return nil, &os.PathError{Op: "CreateFileRef", Path: name, Err: err}
   243  	}
   244  	defer ref.Release()
   245  
   246  	file, err := fs.instance.CreateFileIO()
   247  	if err != nil {
   248  		return nil, &os.PathError{Op: "CreateFileIO", Path: name, Err: err}
   249  	}
   250  
   251  	var pflag FileOpenFlag
   252  	if flag&os.O_RDONLY != 0 {
   253  		pflag |= PP_FILEOPENFLAG_READ
   254  	}
   255  	if flag&os.O_WRONLY != 0 {
   256  		pflag |= PP_FILEOPENFLAG_WRITE
   257  	}
   258  	if flag&os.O_RDWR != 0 {
   259  		pflag |= PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE
   260  	}
   261  	if flag&os.O_CREATE != 0 {
   262  		pflag |= PP_FILEOPENFLAG_CREATE
   263  	}
   264  	if flag&os.O_EXCL != 0 {
   265  		pflag |= PP_FILEOPENFLAG_EXCLUSIVE
   266  	}
   267  	if flag&os.O_TRUNC != 0 {
   268  		pflag |= PP_FILEOPENFLAG_TRUNCATE
   269  	}
   270  	if flag&os.O_APPEND != 0 {
   271  		pflag |= PP_FILEOPENFLAG_APPEND
   272  	}
   273  	if err := file.Open(ref, pflag); err != nil {
   274  		file.Release()
   275  		return nil, &os.PathError{Op: "Open", Path: name, Err: err}
   276  	}
   277  	return &file, nil
   278  }
   279  
   280  // FileInfo represents information about a file, such as size, type, and
   281  // creation time.
   282  //
   283  // Implements os.FileInfo.
   284  type FileInfo struct {
   285  	Filename            string
   286  	Len                 int64
   287  	Type                FileType
   288  	FSType              FileSystemType
   289  	CTime, ATime, MTime time.Time
   290  }
   291  
   292  var _ os.FileInfo = &FileInfo{}
   293  
   294  func (in FileInfo) toPP(out *pp_FileInfo) {
   295  	*(*int64)(unsafe.Pointer(&out[0])) = in.Len
   296  	*(*FileType)(unsafe.Pointer(&out[8])) = in.Type
   297  	*(*FileSystemType)(unsafe.Pointer(&out[12])) = in.FSType
   298  	*(*pp_Time)(unsafe.Pointer(&out[16])) = toPPTime(in.CTime)
   299  	*(*pp_Time)(unsafe.Pointer(&out[24])) = toPPTime(in.ATime)
   300  	*(*pp_Time)(unsafe.Pointer(&out[32])) = toPPTime(in.MTime)
   301  }
   302  
   303  func (out *FileInfo) fromPP(name string, in pp_FileInfo) {
   304  	out.Filename = name
   305  	out.Len = *(*int64)(unsafe.Pointer(&in[0]))
   306  	out.Type = *(*FileType)(unsafe.Pointer(&in[8]))
   307  	out.FSType = *(*FileSystemType)(unsafe.Pointer(&in[12]))
   308  	out.CTime = fromPPTime(*(*pp_Time)(unsafe.Pointer(&in[16])))
   309  	out.ATime = fromPPTime(*(*pp_Time)(unsafe.Pointer(&in[24])))
   310  	out.MTime = fromPPTime(*(*pp_Time)(unsafe.Pointer(&in[32])))
   311  }
   312  
   313  func (info *FileInfo) Name() string {
   314  	return info.Filename
   315  }
   316  
   317  func (info *FileInfo) Size() int64 {
   318  	return info.Len
   319  }
   320  
   321  func (info *FileInfo) Mode() os.FileMode {
   322  	return 0666
   323  }
   324  
   325  func (info *FileInfo) ModTime() time.Time {
   326  	return info.MTime
   327  }
   328  
   329  func (info *FileInfo) IsDir() bool {
   330  	return info.Type == PP_FILETYPE_DIRECTORY
   331  }
   332  
   333  func (info *FileInfo) Sys() interface{} {
   334  	return nil
   335  }
   336  
   337  // DirectoryEntry is an entry in a directory.
   338  type DirectoryEntry struct {
   339  	File FileRef
   340  	Type FileType
   341  }
   342  
   343  func (in DirectoryEntry) toPP(out *pp_DirectoryEntry) {
   344  	*(*pp_Resource)(unsafe.Pointer(&out[0])) = in.File.id
   345  	*(*FileType)(unsafe.Pointer(&out[4])) = in.Type
   346  }
   347  
   348  func (out *DirectoryEntry) fromPP(in pp_DirectoryEntry) {
   349  	out.File.id = *(*pp_Resource)(unsafe.Pointer(&in[0]))
   350  	out.Type = *(*FileType)(unsafe.Pointer(&in[4]))
   351  }
   352  
   353  // FileRef represents a "weak pointer" to a file in a file system.
   354  type FileRef struct {
   355  	Resource
   356  }
   357  
   358  // CreateFileRef creates a weak pointer to a file in the given file system.
   359  // The returned ref must be released explicitly with the Release method.
   360  func (fs FileSystem) CreateFileRef(path string) (ref FileRef, err error) {
   361  	b := append([]byte(path), byte(0))
   362  	id := ppb_fileref_create(fs.id, &b[0])
   363  	if id == 0 {
   364  		err = fmt.Errorf("can't create file %q", path)
   365  		return
   366  	}
   367  	ref.id = id
   368  	return
   369  }
   370  
   371  // Delete deletes a file or directory.
   372  //
   373  // If the ref refers to a directory, then the directory must be empty. It is an
   374  // error to delete a file or directory that is in use. It is not valid to delete
   375  // a file in the external file system.
   376  func (ref FileRef) Delete() error {
   377  	code := ppb_fileref_delete(ref.id, ppNullCompletionCallback)
   378  	return decodeError(Error(code))
   379  }
   380  
   381  // GetParent returns the parent directory of this file.
   382  //
   383  // If file_ref points to the root of the filesystem, then the root is returned.
   384  func (ref FileRef) Parent() (parent FileRef, err error) {
   385  	id := ppb_fileref_get_parent(ref.id)
   386  	if id == 0 {
   387  		err = errFileRefParentFailed
   388  		return
   389  	}
   390  	parent.id = id
   391  	return
   392  }
   393  
   394  // Name returns the name of the file.
   395  func (ref FileRef) Name() (string, error) {
   396  	var ppVar pp_Var
   397  	ppb_fileref_get_name(&ppVar, ref.id)
   398  	v := makeVar(ppVar)
   399  	s, err := v.AsString()
   400  	v.Release()
   401  	return s, err
   402  }
   403  
   404  // Path returns the full path of the file.
   405  func (ref FileRef) Path() (string, error) {
   406  	var ppVar pp_Var
   407  	ppb_fileref_get_path(&ppVar, ref.id)
   408  	v := makeVar(ppVar)
   409  	s, err := v.AsString()
   410  	v.Release()
   411  	return s, err
   412  }
   413  
   414  // Rename renames a file or directory.
   415  //
   416  // Arguments file_ref and new_file_ref must both refer to files in the same file
   417  // system. It is an error to rename a file or directory that is in use. It is
   418  // not valid to rename a file in the external file system.
   419  func (ref FileRef) Rename(newName FileRef) error {
   420  	code := ppb_fileref_rename(ref.id, newName.id, ppNullCompletionCallback)
   421  	return decodeError(Error(code))
   422  }
   423  
   424  // MakeDirectory makes a new directory in the file system according to the given
   425  // flags, which is a bit-mask of the MakeDirectoryFlag values.
   426  //
   427  // It is not valid to make a directory in the external file system.
   428  func (ref FileRef) MakeDirectory(flags MakeDirectoryFlag) error {
   429  	code := ppb_fileref_make_directory(ref.id, int32(flags), ppNullCompletionCallback)
   430  	return decodeError(Error(code))
   431  }
   432  
   433  // Stat queries info about a file or directory.
   434  //
   435  // You must have access to read this file or directory if it exists in the
   436  // external filesystem.
   437  func (ref FileRef) Stat() (info FileInfo, err error) {
   438  	var name string
   439  	name, err = ref.Name()
   440  	if err != nil {
   441  		return
   442  	}
   443  	var ppInfo pp_FileInfo
   444  	code := ppb_fileref_query(ref.id, &ppInfo, ppNullCompletionCallback)
   445  	if code < 0 {
   446  		err = decodeError(Error(code))
   447  		return
   448  	}
   449  	info.fromPP(name, ppInfo)
   450  	return
   451  }
   452  
   453  // Touch Updates time stamps for a file.
   454  //
   455  // You must have write access to the file if it exists in the external filesystem.
   456  func (ref FileRef) Touch(atime, mtime time.Time) error {
   457  	code := ppb_fileref_touch(ref.id, toPPTime(atime), toPPTime(mtime), ppNullCompletionCallback)
   458  	return decodeError(Error(code))
   459  }
   460  
   461  // ReadDirectoryEntries reads all entries in a directory.
   462  func (ref FileRef) ReadDirectoryEntries() (entries []DirectoryEntry, err error) {
   463  	var aout pp_ArrayOutput
   464  	var alloc arrayOutputBuffer
   465  	init_array_output(&aout, &alloc)
   466  	code := ppb_fileref_read_directory_entries(ref.id, aout, ppNullCompletionCallback)
   467  	if code < 0 {
   468  		err = decodeError(Error(code))
   469  		return
   470  	}
   471  
   472  	count := alloc.count
   473  	for i := uint32(0); i < count; i++ {
   474  		ppEntry := (*pp_DirectoryEntry)(unsafe.Pointer(&alloc.buffer[i*alloc.size]))
   475  		var entry DirectoryEntry
   476  		entry.fromPP(*ppEntry)
   477  		entries = append(entries, entry)
   478  	}
   479  	return
   480  }
   481  
   482  // FileIO is used to operate on regular files.
   483  type FileIO struct {
   484  	Resource
   485  	name     string
   486  	position int64
   487  }
   488  
   489  // Open opens the specified regular file for I/O according to the given open
   490  // flags, which is a bit-mask of the PP_FileOpenFlags values.
   491  //
   492  // Upon success, the corresponding file is classified as "in use" by this FileIO
   493  // object until such time as the FileIO object is closed or destroyed.
   494  func (file *FileIO) Open(ref FileRef, openFlags FileOpenFlag) error {
   495  	name, err := ref.Name()
   496  	if err != nil {
   497  		return err
   498  	}
   499  	code := ppb_fileio_open(file.id, ref.id, int32(openFlags), ppNullCompletionCallback)
   500  	if code >= 0 {
   501  		file.name = name
   502  	}
   503  	if openFlags&PP_FILEOPENFLAG_APPEND != 0 {
   504  		info, err := file.Stat()
   505  		if err != nil {
   506  			return err
   507  		}
   508  		file.position = info.Len
   509  	}
   510  	return decodeError(Error(code))
   511  }
   512  
   513  // Close cancels any IO that may be pending, and closes the FileIO object.
   514  //
   515  // Any pending callbacks will still run, reporting PP_ERROR_ABORTED if pending
   516  // IO was interrupted. It is not valid to call Open() again after a call to this
   517  // method. Note: If the FileIO object is destroyed, and it is still open, then
   518  // it will be implicitly closed, so you are not required to call Close().
   519  func (file *FileIO) Close() error {
   520  	ppb_fileio_close(file.id)
   521  	return nil
   522  }
   523  
   524  // Sync flushes changes to disk.
   525  //
   526  // This call can be very expensive! The FileIO object must have been opened with
   527  // write access and there must be no other operations pending.
   528  func (file *FileIO) Sync() error {
   529  	code := ppb_fileio_flush(file.id, ppNullCompletionCallback)
   530  	return decodeError(Error(code))
   531  }
   532  
   533  // Stat queries info about the file opened by this FileIO object.
   534  //
   535  // The FileIO object must be opened, and there must be no other operations
   536  // pending.
   537  func (file *FileIO) Stat() (info FileInfo, err error) {
   538  	var ppInfo pp_FileInfo
   539  	code := ppb_fileio_query(file.id, &ppInfo, ppNullCompletionCallback)
   540  	if code < 0 {
   541  		err = decodeError(Error(code))
   542  		return
   543  	}
   544  	info.fromPP(file.name, ppInfo)
   545  	return
   546  }
   547  
   548  // Read reads up to len(b) bytes from the File. It returns the number of bytes
   549  // read and an error, if any. EOF is signaled by a zero count with err set to
   550  // io.EOF.
   551  func (file *FileIO) Read(buf []byte) (n int, err error) {
   552  	amount, err := file.ReadAt(buf, file.position)
   553  	file.position += int64(amount)
   554  	return amount, err
   555  }
   556  
   557  // Write writes len(b) bytes to the File. It returns the number of bytes written
   558  // and an error, if any. Write returns a non-nil error when n != len(b).
   559  func (file *FileIO) Write(buf []byte) (n int, err error) {
   560  	amount, err := file.WriteAt(buf, file.position)
   561  	file.position += int64(amount)
   562  	return amount, err
   563  }
   564  
   565  // WriteString is like Write, but writes the contents of string s rather than a
   566  // slice of bytes.
   567  func (file *FileIO) WriteString(s string) (n int, err error) {
   568  	return file.Write([]byte(s))
   569  }
   570  
   571  // ReadAtOffset reads from an offset in the file.  Does not affect the current
   572  // file position.
   573  //
   574  // The size of the buf must be large enough to hold the specified number of
   575  // bytes to read. This function might perform a partial read, meaning all the
   576  // requested bytes might not be returned, even if the end of the file has not
   577  // been reached. The FileIO object must have been opened with read access.
   578  func (file *FileIO) ReadAt(buf []byte, off int64) (amount int, err error) {
   579  	code := ppb_fileio_read(file.id, off, &buf[0], int32(len(buf)), ppNullCompletionCallback)
   580  	if code < 0 {
   581  		err = decodeError(Error(code))
   582  		return
   583  	}
   584  	if code == 0 {
   585  		err = io.EOF
   586  		return
   587  	}
   588  	amount = int(code)
   589  	return
   590  }
   591  
   592  // WriteAt writes to an offset in the file.  Does not affect the current
   593  // file position.
   594  //
   595  // This function might perform a partial write. The FileIO object must have been
   596  // opened with write access.
   597  func (file *FileIO) WriteAt(buf []byte, off int64) (amount int, err error) {
   598  	code := ppb_fileio_write(file.id, off, &buf[0], int32(len(buf)), ppNullCompletionCallback)
   599  	if code < 0 {
   600  		err = decodeError(Error(code))
   601  		return
   602  	}
   603  	if code == 0 {
   604  		err = io.EOF
   605  		return
   606  	}
   607  	amount = int(code)
   608  	return
   609  }
   610  
   611  // Seek sets the offset for the next Read or Write on file to offset,
   612  // interpreted according to whence: 0 means relative to the origin of the file,
   613  // 1 means relative to the current offset, and 2 means relative to the end. It
   614  // returns the new offset and an error, if any.
   615  func (file *FileIO) Seek(offset int64, whence int) (ret int64, err error) {
   616  	switch whence {
   617  	case 0:
   618  		file.position = offset
   619  	case 1:
   620  		if offset > file.position {
   621  			err = errNegativeFilePosition
   622  			return
   623  		}
   624  		file.position += offset
   625  	case 2:
   626  		var info FileInfo
   627  		info, err = file.Stat()
   628  		if err != nil {
   629  			return
   630  		}
   631  		p := info.Len + offset
   632  		if p < 0 {
   633  			err = errNegativeFilePosition
   634  			return
   635  		}
   636  		file.position = p
   637  	}
   638  	ret = file.position
   639  	return
   640  }
   641  
   642  // Truncate sets the length of the file.
   643  //
   644  // If the file size is extended, then the extended area of the file is
   645  // zero-filled. The FileIO object must have been opened with write access and
   646  // there must be no other operations pending.
   647  func (file *FileIO) Truncate(length int64) error {
   648  	code := ppb_fileio_set_length(file.id, length, ppNullCompletionCallback)
   649  	return decodeError(Error(code))
   650  }
   651  
   652  // Touch Updates time stamps for the file opened by this FileIO object.
   653  //
   654  // This function will fail if the FileIO object has not been opened. The FileIO
   655  // object must be opened, and there must be no other operations pending.
   656  func (file *FileIO) Touch(atime, mtime time.Time) error {
   657  	code := ppb_fileio_touch(file.id, toPPTime(atime), toPPTime(mtime), ppNullCompletionCallback)
   658  	return decodeError(Error(code))
   659  }
   660  
   661  // CreateFileSystem creates a file system with the given type.
   662  func (inst Instance) CreateFileSystem(ty FileSystemType) (fs FileSystem, err error) {
   663  	id := ppb_filesystem_create(inst.id, ty)
   664  	if id == 0 {
   665  		err = errFileSystemCreateFailed
   666  		return
   667  	}
   668  	fs.instance = inst
   669  	fs.id = id
   670  	return
   671  }
   672  
   673  // CreateFileIO creates a new FileIO object.
   674  func (inst Instance) CreateFileIO() (file FileIO, err error) {
   675  	id := ppb_fileio_create(inst.id)
   676  	if id == 0 {
   677  		err = errFileIOCreateFailed
   678  		return
   679  	}
   680  	file.id = id
   681  	return
   682  }