1/*
2 * fsop.go
3 *
4 * Copyright 2017-2020 Bill Zissimopoulos
5 */
6/*
7 * This file is part of Cgofuse.
8 *
9 * It is licensed under the MIT license. The full license text can be found
10 * in the License.txt file at the root of this project.
11 */
12
13// Package fuse allows the creation of user mode file systems in Go.
14//
15// A user mode file system is a user mode process that receives file system operations
16// from the OS FUSE layer and satisfies them in user mode. A user mode file system
17// implements the interface FileSystemInterface either directly or by embedding a
18// FileSystemBase struct which provides a default (empty) implementation of all methods
19// in FileSystemInterface.
20//
21// In order to expose the user mode file system to the OS, the file system must be hosted
22// (mounted) by a FileSystemHost. The FileSystemHost Mount() method is used for this
23// purpose.
24//
25// A note on thread-safety: In general FUSE file systems are expected to protect their
26// own data structures. Many FUSE implementations provide a -s command line option that
27// when used, it instructs the FUSE implementation to serialize requests. This option
28// can be passed to the FileSystemHost Mount() method, when the file system is mounted.
29package fuse
30
31import (
32	"strconv"
33	"sync"
34	"time"
35)
36
37// Timespec contains a time as the UNIX time in seconds and nanoseconds.
38// This structure is analogous to the POSIX struct timespec.
39type Timespec struct {
40	Sec  int64
41	Nsec int64
42}
43
44// NewTimespec creates a Timespec from a time.Time.
45func NewTimespec(t time.Time) Timespec {
46	return Timespec{t.Unix(), int64(t.Nanosecond())}
47}
48
49// Now creates a Timespec that contains the current time.
50func Now() Timespec {
51	return NewTimespec(time.Now())
52}
53
54// Time returns the Timespec as a time.Time.
55func (ts *Timespec) Time() time.Time {
56	return time.Unix(ts.Sec, ts.Nsec)
57}
58
59// Statfs_t contains file system information.
60// This structure is analogous to the POSIX struct statvfs (NOT struct statfs).
61// Not all fields are honored by all FUSE implementations.
62type Statfs_t struct {
63	// File system block size.
64	Bsize uint64
65
66	// Fundamental file system block size.
67	Frsize uint64
68
69	// Total number of blocks on file system in units of Frsize.
70	Blocks uint64
71
72	// Total number of free blocks.
73	Bfree uint64
74
75	// Number of free blocks available to non-privileged process.
76	Bavail uint64
77
78	// Total number of file serial numbers.
79	Files uint64
80
81	// Total number of free file serial numbers.
82	Ffree uint64
83
84	// Number of file serial numbers available to non-privileged process.
85	Favail uint64
86
87	// File system ID. [IGNORED]
88	Fsid uint64
89
90	// Bit mask of Flag values. [IGNORED]
91	Flag uint64
92
93	// Maximum filename length.
94	Namemax uint64
95}
96
97// Stat_t contains file metadata information.
98// This structure is analogous to the POSIX struct stat.
99// Not all fields are honored by all FUSE implementations.
100type Stat_t struct {
101	// Device ID of device containing file. [IGNORED]
102	Dev uint64
103
104	// File serial number. [IGNORED unless the use_ino mount option is given.]
105	Ino uint64
106
107	// Mode of file.
108	Mode uint32
109
110	// Number of hard links to the file.
111	Nlink uint32
112
113	// User ID of file.
114	Uid uint32
115
116	// Group ID of file.
117	Gid uint32
118
119	// Device ID (if file is character or block special).
120	Rdev uint64
121
122	// For regular files, the file size in bytes.
123	// For symbolic links, the length in bytes of the
124	// pathname contained in the symbolic link.
125	Size int64
126
127	// Last data access timestamp.
128	Atim Timespec
129
130	// Last data modification timestamp.
131	Mtim Timespec
132
133	// Last file status change timestamp.
134	Ctim Timespec
135
136	// A file system-specific preferred I/O block size for this object.
137	Blksize int64
138
139	// Number of blocks allocated for this object.
140	Blocks int64
141
142	// File creation (birth) timestamp. [OSX and Windows only]
143	Birthtim Timespec
144
145	// BSD flags (UF_*). [OSX and Windows only]
146	Flags uint32
147}
148
149// FileInfo_t contains open file information.
150// This structure is analogous to the FUSE struct fuse_file_info.
151type FileInfo_t struct {
152	// Open flags: a combination of the fuse.O_* constants.
153	Flags int
154
155	// Use direct I/O on this file. [IGNORED on Windows]
156	DirectIo bool
157
158	// Do not invalidate file cache. [IGNORED on Windows]
159	KeepCache bool
160
161	// File is not seekable. [IGNORED on Windows]
162	NonSeekable bool
163
164	// File handle.
165	Fh uint64
166}
167
168/*
169// Lock_t contains file locking information.
170// This structure is analogous to the POSIX struct flock.
171type Lock_t struct {
172	// Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
173	Type int16
174
175	// Flag for starting offset.
176	Whence int16
177
178	// Relative offset in bytes.
179	Start int64
180
181	// Size; if 0 then until EOF.
182	Len int64
183
184	// Process ID of the process holding the lock
185	Pid int
186}
187*/
188
189// FileSystemInterface is the interface that a user mode file system must implement.
190//
191// The file system will receive an Init() call when the file system is created;
192// the Init() call will happen prior to receiving any other file system calls.
193// Note that there are no guarantees on the exact timing of when Init() is called.
194// For example, it cannot be assumed that the file system is mounted at the time
195// the Init() call is received.
196//
197// The file system will receive a Destroy() call when the file system is destroyed;
198// the Destroy() call will always be the last call to be received by the file system.
199// Note that depending on how the file system is terminated the file system may not
200// receive the Destroy() call. For example, it will not receive the Destroy() call
201// if the file system process is forcibly killed.
202//
203// Except for Init() and Destroy() all file system operations must return 0 on success
204// or a FUSE error on failure. To return an error return the NEGATIVE value of a
205// particular error.  For example, to report "file not found" return -fuse.ENOENT.
206type FileSystemInterface interface {
207	// Init is called when the file system is created.
208	Init()
209
210	// Destroy is called when the file system is destroyed.
211	Destroy()
212
213	// Statfs gets file system statistics.
214	Statfs(path string, stat *Statfs_t) int
215
216	// Mknod creates a file node.
217	Mknod(path string, mode uint32, dev uint64) int
218
219	// Mkdir creates a directory.
220	Mkdir(path string, mode uint32) int
221
222	// Unlink removes a file.
223	Unlink(path string) int
224
225	// Rmdir removes a directory.
226	Rmdir(path string) int
227
228	// Link creates a hard link to a file.
229	Link(oldpath string, newpath string) int
230
231	// Symlink creates a symbolic link.
232	Symlink(target string, newpath string) int
233
234	// Readlink reads the target of a symbolic link.
235	Readlink(path string) (int, string)
236
237	// Rename renames a file.
238	Rename(oldpath string, newpath string) int
239
240	// Chmod changes the permission bits of a file.
241	Chmod(path string, mode uint32) int
242
243	// Chown changes the owner and group of a file.
244	Chown(path string, uid uint32, gid uint32) int
245
246	// Utimens changes the access and modification times of a file.
247	Utimens(path string, tmsp []Timespec) int
248
249	// Access checks file access permissions.
250	Access(path string, mask uint32) int
251
252	// Create creates and opens a file.
253	// The flags are a combination of the fuse.O_* constants.
254	Create(path string, flags int, mode uint32) (int, uint64)
255
256	// Open opens a file.
257	// The flags are a combination of the fuse.O_* constants.
258	Open(path string, flags int) (int, uint64)
259
260	// Getattr gets file attributes.
261	Getattr(path string, stat *Stat_t, fh uint64) int
262
263	// Truncate changes the size of a file.
264	Truncate(path string, size int64, fh uint64) int
265
266	// Read reads data from a file.
267	Read(path string, buff []byte, ofst int64, fh uint64) int
268
269	// Write writes data to a file.
270	Write(path string, buff []byte, ofst int64, fh uint64) int
271
272	// Flush flushes cached file data.
273	Flush(path string, fh uint64) int
274
275	// Release closes an open file.
276	Release(path string, fh uint64) int
277
278	// Fsync synchronizes file contents.
279	Fsync(path string, datasync bool, fh uint64) int
280
281	// Lock performs a file locking operation.
282	//Lock(path string, cmd int, lock *Lock_t, fh uint64) int
283
284	// Opendir opens a directory.
285	Opendir(path string) (int, uint64)
286
287	// Readdir reads a directory.
288	Readdir(path string,
289		fill func(name string, stat *Stat_t, ofst int64) bool,
290		ofst int64,
291		fh uint64) int
292
293	// Releasedir closes an open directory.
294	Releasedir(path string, fh uint64) int
295
296	// Fsyncdir synchronizes directory contents.
297	Fsyncdir(path string, datasync bool, fh uint64) int
298
299	// Setxattr sets extended attributes.
300	Setxattr(path string, name string, value []byte, flags int) int
301
302	// Getxattr gets extended attributes.
303	Getxattr(path string, name string) (int, []byte)
304
305	// Removexattr removes extended attributes.
306	Removexattr(path string, name string) int
307
308	// Listxattr lists extended attributes.
309	Listxattr(path string, fill func(name string) bool) int
310}
311
312// FileSystemOpenEx is the interface that wraps the OpenEx and CreateEx methods.
313//
314// OpenEx and CreateEx are similar to Open and Create except that they allow
315// direct manipulation of the FileInfo_t struct (which is analogous to the
316// FUSE struct fuse_file_info).
317type FileSystemOpenEx interface {
318	CreateEx(path string, mode uint32, fi *FileInfo_t) int
319	OpenEx(path string, fi *FileInfo_t) int
320}
321
322// FileSystemChflags is the interface that wraps the Chflags method.
323//
324// Chflags changes the BSD file flags (Windows file attributes). [OSX and Windows only]
325type FileSystemChflags interface {
326	Chflags(path string, flags uint32) int
327}
328
329// FileSystemSetcrtime is the interface that wraps the Setcrtime method.
330//
331// Setcrtime changes the file creation (birth) time. [OSX and Windows only]
332type FileSystemSetcrtime interface {
333	Setcrtime(path string, tmsp Timespec) int
334}
335
336// FileSystemSetchgtime is the interface that wraps the Setchgtime method.
337//
338// Setchgtime changes the file change (ctime) time. [OSX and Windows only]
339type FileSystemSetchgtime interface {
340	Setchgtime(path string, tmsp Timespec) int
341}
342
343// Error encapsulates a FUSE error code. In some rare circumstances it is useful
344// to signal an error to the FUSE layer by boxing the error code using Error and
345// calling panic(). The FUSE layer will recover and report the boxed error code
346// to the OS.
347type Error int
348
349var errorStringMap map[Error]string
350var errorStringOnce sync.Once
351
352func (self Error) Error() string {
353	errorStringOnce.Do(func() {
354		errorStringMap = make(map[Error]string)
355		for _, i := range errorStrings {
356			errorStringMap[Error(-i.errc)] = i.errs
357		}
358	})
359
360	if 0 <= self {
361		return strconv.Itoa(int(self))
362	} else {
363		if errs, ok := errorStringMap[self]; ok {
364			return "-fuse." + errs
365		}
366		return "fuse.Error(" + strconv.Itoa(int(self)) + ")"
367	}
368}
369
370func (self Error) String() string {
371	return self.Error()
372}
373
374func (self Error) GoString() string {
375	return self.Error()
376}
377
378var _ error = (*Error)(nil)
379
380// FileSystemBase provides default implementations of the methods in FileSystemInterface.
381// The default implementations are either empty or return -ENOSYS to signal that the
382// file system does not implement a particular operation to the FUSE layer.
383type FileSystemBase struct {
384}
385
386// Init is called when the file system is created.
387// The FileSystemBase implementation does nothing.
388func (*FileSystemBase) Init() {
389}
390
391// Destroy is called when the file system is destroyed.
392// The FileSystemBase implementation does nothing.
393func (*FileSystemBase) Destroy() {
394}
395
396// Statfs gets file system statistics.
397// The FileSystemBase implementation returns -ENOSYS.
398func (*FileSystemBase) Statfs(path string, stat *Statfs_t) int {
399	return -ENOSYS
400}
401
402// Mknod creates a file node.
403// The FileSystemBase implementation returns -ENOSYS.
404func (*FileSystemBase) Mknod(path string, mode uint32, dev uint64) int {
405	return -ENOSYS
406}
407
408// Mkdir creates a directory.
409// The FileSystemBase implementation returns -ENOSYS.
410func (*FileSystemBase) Mkdir(path string, mode uint32) int {
411	return -ENOSYS
412}
413
414// Unlink removes a file.
415// The FileSystemBase implementation returns -ENOSYS.
416func (*FileSystemBase) Unlink(path string) int {
417	return -ENOSYS
418}
419
420// Rmdir removes a directory.
421// The FileSystemBase implementation returns -ENOSYS.
422func (*FileSystemBase) Rmdir(path string) int {
423	return -ENOSYS
424}
425
426// Link creates a hard link to a file.
427// The FileSystemBase implementation returns -ENOSYS.
428func (*FileSystemBase) Link(oldpath string, newpath string) int {
429	return -ENOSYS
430}
431
432// Symlink creates a symbolic link.
433// The FileSystemBase implementation returns -ENOSYS.
434func (*FileSystemBase) Symlink(target string, newpath string) int {
435	return -ENOSYS
436}
437
438// Readlink reads the target of a symbolic link.
439// The FileSystemBase implementation returns -ENOSYS.
440func (*FileSystemBase) Readlink(path string) (int, string) {
441	return -ENOSYS, ""
442}
443
444// Rename renames a file.
445// The FileSystemBase implementation returns -ENOSYS.
446func (*FileSystemBase) Rename(oldpath string, newpath string) int {
447	return -ENOSYS
448}
449
450// Chmod changes the permission bits of a file.
451// The FileSystemBase implementation returns -ENOSYS.
452func (*FileSystemBase) Chmod(path string, mode uint32) int {
453	return -ENOSYS
454}
455
456// Chown changes the owner and group of a file.
457// The FileSystemBase implementation returns -ENOSYS.
458func (*FileSystemBase) Chown(path string, uid uint32, gid uint32) int {
459	return -ENOSYS
460}
461
462// Utimens changes the access and modification times of a file.
463// The FileSystemBase implementation returns -ENOSYS.
464func (*FileSystemBase) Utimens(path string, tmsp []Timespec) int {
465	return -ENOSYS
466}
467
468// Access checks file access permissions.
469// The FileSystemBase implementation returns -ENOSYS.
470func (*FileSystemBase) Access(path string, mask uint32) int {
471	return -ENOSYS
472}
473
474// Create creates and opens a file.
475// The flags are a combination of the fuse.O_* constants.
476// The FileSystemBase implementation returns -ENOSYS.
477func (*FileSystemBase) Create(path string, flags int, mode uint32) (int, uint64) {
478	return -ENOSYS, ^uint64(0)
479}
480
481// Open opens a file.
482// The flags are a combination of the fuse.O_* constants.
483// The FileSystemBase implementation returns -ENOSYS.
484func (*FileSystemBase) Open(path string, flags int) (int, uint64) {
485	return -ENOSYS, ^uint64(0)
486}
487
488// Getattr gets file attributes.
489// The FileSystemBase implementation returns -ENOSYS.
490func (*FileSystemBase) Getattr(path string, stat *Stat_t, fh uint64) int {
491	return -ENOSYS
492}
493
494// Truncate changes the size of a file.
495// The FileSystemBase implementation returns -ENOSYS.
496func (*FileSystemBase) Truncate(path string, size int64, fh uint64) int {
497	return -ENOSYS
498}
499
500// Read reads data from a file.
501// The FileSystemBase implementation returns -ENOSYS.
502func (*FileSystemBase) Read(path string, buff []byte, ofst int64, fh uint64) int {
503	return -ENOSYS
504}
505
506// Write writes data to a file.
507// The FileSystemBase implementation returns -ENOSYS.
508func (*FileSystemBase) Write(path string, buff []byte, ofst int64, fh uint64) int {
509	return -ENOSYS
510}
511
512// Flush flushes cached file data.
513// The FileSystemBase implementation returns -ENOSYS.
514func (*FileSystemBase) Flush(path string, fh uint64) int {
515	return -ENOSYS
516}
517
518// Release closes an open file.
519// The FileSystemBase implementation returns -ENOSYS.
520func (*FileSystemBase) Release(path string, fh uint64) int {
521	return -ENOSYS
522}
523
524// Fsync synchronizes file contents.
525// The FileSystemBase implementation returns -ENOSYS.
526func (*FileSystemBase) Fsync(path string, datasync bool, fh uint64) int {
527	return -ENOSYS
528}
529
530/*
531// Lock performs a file locking operation.
532// The FileSystemBase implementation returns -ENOSYS.
533func (*FileSystemBase) Lock(path string, cmd int, lock *Lock_t, fh uint64) int {
534	return -ENOSYS
535}
536*/
537
538// Opendir opens a directory.
539// The FileSystemBase implementation returns -ENOSYS.
540func (*FileSystemBase) Opendir(path string) (int, uint64) {
541	return -ENOSYS, ^uint64(0)
542}
543
544// Readdir reads a directory.
545// The FileSystemBase implementation returns -ENOSYS.
546func (*FileSystemBase) Readdir(path string,
547	fill func(name string, stat *Stat_t, ofst int64) bool,
548	ofst int64,
549	fh uint64) int {
550	return -ENOSYS
551}
552
553// Releasedir closes an open directory.
554// The FileSystemBase implementation returns -ENOSYS.
555func (*FileSystemBase) Releasedir(path string, fh uint64) int {
556	return -ENOSYS
557}
558
559// Fsyncdir synchronizes directory contents.
560// The FileSystemBase implementation returns -ENOSYS.
561func (*FileSystemBase) Fsyncdir(path string, datasync bool, fh uint64) int {
562	return -ENOSYS
563}
564
565// Setxattr sets extended attributes.
566// The FileSystemBase implementation returns -ENOSYS.
567func (*FileSystemBase) Setxattr(path string, name string, value []byte, flags int) int {
568	return -ENOSYS
569}
570
571// Getxattr gets extended attributes.
572// The FileSystemBase implementation returns -ENOSYS.
573func (*FileSystemBase) Getxattr(path string, name string) (int, []byte) {
574	return -ENOSYS, nil
575}
576
577// Removexattr removes extended attributes.
578// The FileSystemBase implementation returns -ENOSYS.
579func (*FileSystemBase) Removexattr(path string, name string) int {
580	return -ENOSYS
581}
582
583// Listxattr lists extended attributes.
584// The FileSystemBase implementation returns -ENOSYS.
585func (*FileSystemBase) Listxattr(path string, fill func(name string) bool) int {
586	return -ENOSYS
587}
588
589var _ FileSystemInterface = (*FileSystemBase)(nil)
590