1// Package fs is a generic file system interface for rclone object storage systems
2package fs
3
4import (
5	"context"
6	"io"
7	"math"
8	"time"
9
10	"github.com/pkg/errors"
11)
12
13// Constants
14const (
15	// ModTimeNotSupported is a very large precision value to show
16	// mod time isn't supported on this Fs
17	ModTimeNotSupported = 100 * 365 * 24 * time.Hour
18	// MaxLevel is a sentinel representing an infinite depth for listings
19	MaxLevel = math.MaxInt32
20)
21
22// Globals
23var (
24	// ErrorNotFoundInConfigFile is returned by NewFs if not found in config file
25	ErrorNotFoundInConfigFile        = errors.New("didn't find section in config file")
26	ErrorCantPurge                   = errors.New("can't purge directory")
27	ErrorCantCopy                    = errors.New("can't copy object - incompatible remotes")
28	ErrorCantMove                    = errors.New("can't move object - incompatible remotes")
29	ErrorCantDirMove                 = errors.New("can't move directory - incompatible remotes")
30	ErrorCantUploadEmptyFiles        = errors.New("can't upload empty files to this remote")
31	ErrorDirExists                   = errors.New("can't copy directory - destination already exists")
32	ErrorCantSetModTime              = errors.New("can't set modified time")
33	ErrorCantSetModTimeWithoutDelete = errors.New("can't set modified time without deleting existing object")
34	ErrorDirNotFound                 = errors.New("directory not found")
35	ErrorObjectNotFound              = errors.New("object not found")
36	ErrorLevelNotSupported           = errors.New("level value not supported")
37	ErrorListAborted                 = errors.New("list aborted")
38	ErrorListBucketRequired          = errors.New("bucket or container name is needed in remote")
39	ErrorIsFile                      = errors.New("is a file not a directory")
40	ErrorIsDir                       = errors.New("is a directory not a file")
41	ErrorNotAFile                    = errors.New("is not a regular file")
42	ErrorNotDeleting                 = errors.New("not deleting files as there were IO errors")
43	ErrorNotDeletingDirs             = errors.New("not deleting directories as there were IO errors")
44	ErrorOverlapping                 = errors.New("can't sync or move files on overlapping remotes")
45	ErrorDirectoryNotEmpty           = errors.New("directory not empty")
46	ErrorImmutableModified           = errors.New("immutable file modified")
47	ErrorPermissionDenied            = errors.New("permission denied")
48	ErrorCantShareDirectories        = errors.New("this backend can't share directories with link")
49	ErrorNotImplemented              = errors.New("optional feature not implemented")
50	ErrorCommandNotFound             = errors.New("command not found")
51	ErrorFileNameTooLong             = errors.New("file name too long")
52)
53
54// CheckClose is a utility function used to check the return from
55// Close in a defer statement.
56func CheckClose(c io.Closer, err *error) {
57	cerr := c.Close()
58	if *err == nil {
59		*err = cerr
60	}
61}
62
63// FileExists returns true if a file remote exists.
64// If remote is a directory, FileExists returns false.
65func FileExists(ctx context.Context, fs Fs, remote string) (bool, error) {
66	_, err := fs.NewObject(ctx, remote)
67	if err != nil {
68		if err == ErrorObjectNotFound || err == ErrorNotAFile || err == ErrorPermissionDenied {
69			return false, nil
70		}
71		return false, err
72	}
73	return true, nil
74}
75
76// GetModifyWindow calculates the maximum modify window between the given Fses
77// and the Config.ModifyWindow parameter.
78func GetModifyWindow(ctx context.Context, fss ...Info) time.Duration {
79	window := GetConfig(ctx).ModifyWindow
80	for _, f := range fss {
81		if f != nil {
82			precision := f.Precision()
83			if precision == ModTimeNotSupported {
84				return ModTimeNotSupported
85			}
86			if precision > window {
87				window = precision
88			}
89		}
90	}
91	return window
92}
93