Commit Graph

173 Commits

Author SHA1 Message Date
Jarek Kowalski
dcff6c285d Added support for logging policies (#1472)
* policy: introduced OptionalBool - refactoring

* policy: added logging policy

* testing: added support for symlinks and modtime to mockfs

* logging: exposed NullLogger instance

* upload: emit debug logs according to logging policies

* cli: logging policy support
2021-11-06 10:06:05 -07:00
Eng Zer Jun
c3f4c41591 refactor: move from ioutil.ReadDir to os.ReadDir (#1361)
* refactor: move from ioutil.ReadDir to os.ReadDir

This commit is an addition to PR #1360. According to
`ioutil.ReadDir` documentation (https://pkg.go.dev/io/ioutil#ReadDir),
`os.ReadDir` should be preferred as it is a more efficient and correct
implementation.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>

* perf: optimize localfs scan performance

Reference: https://github.com/kopia/kopia/pull/1361#issuecomment-937345195
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-11-04 16:57:24 -07:00
Jarek Kowalski
0d0f48a7ee clock: discard monotonic clock component in clock.Now() (#1437)
The dual time measurement is described in
https://go.googlesource.com/proposal/+/master/design/12914-monotonic.md

The fix is to discard hidden monotonic time component of time.Time
by converting to unix time and back.

Reviewed usage of clock.Now() and replaced with timetrack.StartTimer()
when measuring time.

The problem in #1402 was that passage of time was measured using
the monotonic time and not wall clock time. When the computer goes
to sleep, monotonic time is still monotonic while wall clock time makes
a leap when the computer wakes up. This is the behavior that
epoch manager (and most other compontents in Kopia) rely upon.

Fixes #1402

Co-authored-by: Julio Lopez <julio+gh@kasten.io>
2021-10-22 15:35:09 -07:00
Jarek Kowalski
e96ddc6105 upload: fix ignoring files after action redirects snapshot directory (#1409)
Fixes #1399
Fixes #1346
2021-10-17 23:02:00 -07:00
Jarek Kowalski
c8b8dc9ec7 localfs: added ReadDir() benchmark (#1396)
$ go test -benchmem -count 5 -benchtime 5s -run=^$ -bench "^BenchmarkReadDir.*$" ./fs/localfs

goos: darwin
goarch: amd64
pkg: github.com/kopia/kopia/fs/localfs
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkReadDir0-8       	  206330	     28408 ns/op	    1880 B/op	      11 allocs/op
BenchmarkReadDir0-8       	  209636	     28399 ns/op	    1928 B/op	      11 allocs/op
BenchmarkReadDir0-8       	  208366	     28569 ns/op	    1880 B/op	      11 allocs/op
BenchmarkReadDir0-8       	  203073	     28888 ns/op	    1880 B/op	      11 allocs/op
BenchmarkReadDir0-8       	  209492	     28477 ns/op	    1928 B/op	      11 allocs/op
BenchmarkReadDir1-8       	  163614	     37236 ns/op	    3736 B/op	      21 allocs/op
BenchmarkReadDir1-8       	  151528	     38796 ns/op	    3736 B/op	      21 allocs/op
BenchmarkReadDir1-8       	  161023	     38420 ns/op	    3736 B/op	      21 allocs/op
BenchmarkReadDir1-8       	  153543	     37262 ns/op	    3736 B/op	      21 allocs/op
BenchmarkReadDir1-8       	  165090	     36362 ns/op	    3736 B/op	      21 allocs/op
BenchmarkReadDir2-8       	  137521	     43338 ns/op	    4456 B/op	      30 allocs/op
BenchmarkReadDir2-8       	  138085	     43866 ns/op	    4456 B/op	      30 allocs/op
BenchmarkReadDir2-8       	  136701	     43389 ns/op	    4456 B/op	      30 allocs/op
BenchmarkReadDir2-8       	  138116	     43342 ns/op	    4456 B/op	      30 allocs/op
BenchmarkReadDir2-8       	  138170	     43379 ns/op	    4456 B/op	      30 allocs/op
BenchmarkReadDir10-8      	   62124	     96602 ns/op	   10104 B/op	      76 allocs/op
BenchmarkReadDir10-8      	   60532	     97361 ns/op	   10104 B/op	      76 allocs/op
BenchmarkReadDir10-8      	   61009	     97615 ns/op	   10104 B/op	      76 allocs/op
BenchmarkReadDir10-8      	   62072	     96550 ns/op	   10104 B/op	      76 allocs/op
BenchmarkReadDir10-8      	   62220	     95925 ns/op	   10104 B/op	      76 allocs/op
BenchmarkReadDir100-8     	    8028	    716714 ns/op	   80763 B/op	     544 allocs/op
BenchmarkReadDir100-8     	    8066	    712266 ns/op	   80755 B/op	     544 allocs/op
BenchmarkReadDir100-8     	    8047	    712203 ns/op	   80755 B/op	     544 allocs/op
BenchmarkReadDir100-8     	    8107	    711148 ns/op	   80752 B/op	     544 allocs/op
BenchmarkReadDir100-8     	    8127	    709227 ns/op	   80753 B/op	     544 allocs/op
BenchmarkReadDir1000-8    	    1558	   3861176 ns/op	  689409 B/op	    5137 allocs/op
BenchmarkReadDir1000-8    	    1566	   3848730 ns/op	  689414 B/op	    5137 allocs/op
BenchmarkReadDir1000-8    	    1516	   3838727 ns/op	  689412 B/op	    5137 allocs/op
BenchmarkReadDir1000-8    	    1550	   3833432 ns/op	  689415 B/op	    5137 allocs/op
BenchmarkReadDir1000-8    	    1557	   3966338 ns/op	  689408 B/op	    5137 allocs/op
BenchmarkReadDir10000-8   	     178	  33901454 ns/op	 7282295 B/op	   51046 allocs/op
BenchmarkReadDir10000-8   	     177	  33865198 ns/op	 7282296 B/op	   51046 allocs/op
BenchmarkReadDir10000-8   	     172	  34687834 ns/op	 7282354 B/op	   51047 allocs/op
BenchmarkReadDir10000-8   	     174	  34483220 ns/op	 7282359 B/op	   51047 allocs/op
BenchmarkReadDir10000-8   	     178	  34227937 ns/op	 7282307 B/op	   51047 allocs/op
PASS
ok  	github.com/kopia/kopia/fs/localfs	268.048s
2021-10-16 10:14:18 -07:00
Jarek Kowalski
8b760b66a8 logging: added memoization of Logger instances per context (#1369) 2021-10-09 05:02:18 -07:00
Jarek Kowalski
2fa7cfb042 localfs: fixed support for snapshotting UNC path root (\\server\path) (#1362)
Fixes #1288
Fixes #1035
Fixes #751
2021-10-06 20:27:45 -07:00
Eng Zer Jun
73e492c9db refactor: move from io/ioutil to io and os package (#1360)
* refactor: move from io/ioutil to io and os package

The io/ioutil package has been deprecated as of Go 1.16, see
https://golang.org/doc/go1.16#ioutil. This commit replaces the existing
io/ioutil functions with their new definitions in io and os packages.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>

* chore: remove //nolint:gosec for os.ReadFile

At the time of this commit, the G304 rule of gosec does not include the
`os.ReadFile` function. We remove `//nolint:gosec` temporarily until
https://github.com/securego/gosec/pull/706 is merged.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-10-06 08:39:10 -07:00
Jarek Kowalski
698d26bdbb localfs: reduce memory usage when scanning short directories (#1343)
* localfs: reduce memory usage when scanning short directories

We read first 100 entries to determine if the directory is short
before forking to goroutines. Also reduced goroutine count, 16 was way
too aggressive.

* localfs: fixed windows-specific behavior where os.Lstat() returns different timestamps than ReadDir()
2021-10-02 16:26:14 -07:00
Pawit Pornkitprasan
b8efb8eaea cachefs: make cache read O(1) instead of O(n) (#1341)
* cachefs: make cache read O(1) instead of O(n)

Move the wrapping of fs.Entry before caching rather than doing
it everytime we try to read from the cache.
2021-10-02 10:09:33 -07:00
Jarek Kowalski
928150fe6b linter: upgrade to 1.42.1 (#1292) 2021-09-14 19:11:39 -07:00
Jarek Kowalski
9e182f131a linter: upgraded to 1.42.0 (#1246) 2021-08-20 18:26:45 -07:00
Robert Kroeger
6fc3bf1af6 Support for shallow restore (#725) 2021-06-08 20:11:43 -07:00
Jarek Kowalski
30ca3e2e6c Upgraded linter to 1.40.1 (#1072)
* tools: upgraded linter to 1.40.1

* lint: fixed nolintlint vionlations

* lint: disabled tagliatele linter

* lint: fixed remaining warnings
2021-05-15 12:12:34 -07:00
Denis Fondras
2b6af55142 Allow to compile Kopia cli on OpenBSD (#983)
* allow to compile Kopia cli on OpenBSD
2021-04-13 12:45:04 -07:00
Jarek Kowalski
74833cefcb cli: added standard --json flags to several commands (#910)
* cli: added standard --json flags to several commands

Fixes #272

* Update flag description

Co-authored-by: Julio López <julio+gh@kasten.io>
2021-03-25 17:55:18 -07:00
Pavan Navarathna
3e76169921 Support for stdin streams (#862)
* Add StreamingFile interface
* unit test for virtualfs
* CLI: Snapshot create support for stdin sources
* Uploader support for fs.StreamingFile
* End to end test for stdin source snapshot
* upload test to improve coverage
2021-03-04 15:34:05 -08:00
Jarek Kowalski
ac9f85967a Added first-class support for fs.ErrorEntry for directory entries that could not be read or are unknown/unsupported (#852)
* policy: added errorHandling.ignoreUnknownTypes flag (defaults to true)

* cli: get/set ignore-unknown-types policy flag

* htmlui: added UI for setting ignore-unknown-types

* htmlui: fixed typo

* fs: return fs.ErrorEntry when a directory entry is not recognized (localfs and repofs)

* upload: explicitly handle unknown entry types by treating them as ignored errors
2021-03-01 06:16:26 -08:00
Jarek Kowalski
e2b9a81ac3 Major CI/CD refactoring and re-added support for ARM/ARM64 runners (#849)
* ci: refactored CI/CD logic & Makefile

- removed all travis CI emulation environment variables and replaced with:

CI_TAG=<empty>|tag
IS_PULL_REQUEST=false|true

- refactored all OS and architecture-specific decisions to use around standard GOOS/GOARCH values instead of uname/OS
- re-added self-hosted runner for ARMHF (3 replicas)
- added brand new self-hosted runner for ARM64 (3 replicas)
- disabled attempts to publish and sign on forks
- improved integration test log output to better see timings and sub-tests
- print longest tests (unit tests and integration) after each run
- verified that all configurations build successfully on a clone (jkowalski/kopia)
- run make setup in parallel

* testing: fixed tests on ARM and ARM64

- fixed ARM-specific alignment issue
- cleaned up test logging
- fixed huge params warning threshold because it was tripping on ARM.
- reduced test complexity to make them fit in 15 minutes
2021-02-23 00:52:54 -08:00
Jarek Kowalski
23273af1cd snapshot: reworked error handling and added fail-fast option (#840)
Fixes #690

This is a breaking change for folks who are expecting snapshots to fail
quickly without writing a snapshot manifest in case of an error.

Before this change, any source read failure would cause the entire
snapshot to fail (and not write a snapshot manifest as a result),
unless `ignoreFileErrors` or `ignoreDirectoryErrors` was set.

The new behavior is to continue snapshotting remaining files and
directories (this can be disabled by passing `--fail-fast` flag or
setting `KOPIA_SNAPSHOT_FAIL_FAST=1` environment variable) and defer
returning an error until the very end.

After snapshotting we will always attempt to write the snapshot manifest
(except when the root of the snapshot itself cannot be opened). In case
of a fail-fast error, the manifest will be marked as 'partial' and
the directory tree will contain only partial set of files.

In case of any errors, the manifest (and each directory object) will
list the number if failures and no more than 10 examples of failed
files/directories along with their respective errors.

Once the snapshot is complete we will return non-zero exit code to the
operating system if there were any fatal errors during snapshotting.

With this change we are repurposing `ignoreFileErrors` and
`ignoreDirectoryErrors` to designate some errors as non-fatal.
Non-fatal errors are reported as warnings in the logs and will not
cause a non-zero exit code to be returned.
2021-02-17 10:29:01 -08:00
Jarek Kowalski
4bf42e337d fix long filenames on Windows (#822)
* windows: fixed handling of long filenames
2021-02-12 09:09:42 -08:00
Jarek Kowalski
1f3b8d4da4 upgrade linter to 1.35 (#786)
* lint: added test that enforces Makefile and GH action linter versions are in sync
* workaround for linter gomnd problem - https://github.com/golangci/golangci-lint/issues/1653
2021-01-16 18:21:16 -08:00
Peter Palotas
ae37719e51 Improved .kopiaignore pattern matching (#773)
* Improved .kopiaignore pattern matching

.kopiaignore pattern matching now (hopefully) conforms to the .gitignore specification (https://git-scm.com/docs/gitignore)

Replaced old package "ignore" with a newly written "wcmatch" that manages the globbing. This should support all the patterns that .gitignore supports.  

Some changes in ignorefs that dealt with how the patterns were matched.

This fixes #571

* Fixed invalid matching of non-rooted patterns that contained a slash.

If a pattern contains a slash in the middle of the pattern this should only match relative to the .gitignore file, i.e. the same as if it started with a '/' according to the .gitignore spec.

Example:
foo/bar should match "/foo/bar", but not "/other/foo/bar".  
whereas 
"bar" matches both "/bar" and "/foo/bar"

* Uncommented previously failing tests.

* Fixed problem with matching "nested" .kopiaignore files.

Ignore-patterns must be applied from the root .kopiaignore down the hierarchy, so that an ignore file in a subdirectory can negate a pattern from a parent directory.

* Uncommented tests that should now work.
2021-01-08 08:13:18 -08:00
Peter Palotas
cd8f3e81b8 Created end-to-end tests verifying .kopiaignore behavior. (#774)
* Created end-to-end tests verifying .kopiaignore behavior.

This is related to #571 and #773, but provided as a separate PR to include tests that did not work before PR #773.

* Commented failing tests.

These tests will be re-enabled when #773 is done.

* Added additional commented tests of .kopiaignore

These will be uncommented in #773.
2021-01-08 07:39:59 -08:00
Jarek Kowalski
e03971fc59 Upgraded linter to v1.33.0 (#734)
* linter: upgraded to 1.33, disabled some linters

* lint: fixed 'errorlint' errors

This ensures that all error comparisons use errors.Is() or errors.As().
We will be wrapping more errors going forward so it's important that
error checks are not strict everywhere.

Verified that there are no exceptions for errorlint linter which
guarantees that.

* lint: fixed or suppressed wrapcheck errors

* lint: nolintlint and misc cleanups

Co-authored-by: Julio López <julio+gh@kasten.io>
2020-12-21 22:39:22 -08:00
Jarek Kowalski
4f7d211f72 Added support for actions that run before&after snapshot roots and before/after specific folders (#722)
* policy: add actions
* fs: added LocalFilesystemPath() which can optionally return local filesystem
  path (if entry is local)
* cli: added support for setting policy actions
* upload: support for executing actions before/after folder (non-inheritable)
  and before/after snapshots (inheritable)
* testing: end-to-end test for actions
* additional tests for actions with embedded scripts
2020-12-21 15:53:21 -08:00
darkdragon-001
ade7975212 Improve ignore logic. (#496)
* Improve ignore logic.

- Add test cases for absolute patterns
- Support globs for absolute patterns

* Test exclude-include (not supported yet).
2020-11-08 17:26:48 -08:00
Erkki Seppälä
6a93e4d5b9 Added support for scanning only one filesystem via files policy (#676)
The new files policy oneFileSystem ignores files that are mounted to
other filesystems similarly to tar's --one-file-system switch. For
example, if this is enabled, backing up / should now automatically
ignore /dev, /proc, etc, so the directory entries themselves don't
appear in the backup. The value of the policy is 'false' by default.

This is implemented by adding a non-windows-field Device (of type
DeviceInfo, reflecting the implementation of Owner) to the Entry
interface. DeviceInfo holds the dev and rdev acquired with stat (same
way as with Owner), but in addition to that it also holds the same
values for the parent directory. It would seem that doing this in some
other way, ie. in ReadDir, would require modifying the ReadDir
interface which seems a too large modification for a feature this
small.

This change introduces a duplication of 'stat' call to the files, as
the Owner feature already does a separate call. I doubt the
performance implications are noticeable, though with some refactoring
both Owner and Device fields could be filled in in one go.

Filling in the field has been placed in fs/localfs/localfs.go where
entryFromChildFileInfo has acquired a third parameter giving the the
parent entry. From that information the Device of the parent is
retrieved, to be passed off to platformSpecificDeviceInfo which does
the rest of the paperwork. Other fs implementations just put in the
default values.

The Dev and Rdev fields returned by the 'stat' call have different
sizes on different platforms, but for convenience they are internally
handled the same. The conversion is done with local_fs_32bit.go and
local_fs_64bit.go which are conditionally compiled on different
platforms.

Finally the actual check of the condition is in ignorefs.go function
shouldIncludeByDevice which is analoguous to the other similarly named
functions.

Co-authored-by: Erkki Seppälä <flux@inside.org>
2020-10-14 22:45:32 -07:00
Jarek Kowalski
4d7f0cb6cd Fixed symlink restore behavior on macOS (#673)
* restore: use symlink-specific APIs instead of chmod, chown and chtimes

* upload: fix updating directory modtime for symlinks

* cli: plumbed through flags to restore to control new behaviors

* localfs: use Lstat() instead of Stat() in Child() method

* testing: added restore tests for new flags
2020-10-10 11:03:35 -07:00
Jarek Kowalski
ff6a414ec5 cli: When listing directory that had errors, print error summary at the end. (#643)
Can be disabled with `--no-error-summary`.
Quick demo: https://asciinema.org/a/2rma0sx2mD6HoIPy6VL0QEFeP

Also refactored fs.Directory to provide Summary optionally.
2020-09-25 09:06:41 -07:00
Jarek Kowalski
6bdcb81712 ignorefs: fixed arm-specific linter warning (#637)
* ignorefs: fixed arm-specific linter warning

* testing: TestServerStart fixes for armhf
2020-09-22 19:04:05 -07:00
Jarek Kowalski
f0b97b960b Fixed checkpointing to not restart the entire upload process (#594)
* object: added Checkpoint() method to object writer

* upload: refactored code structure to allow better checkpointing

* upload: removed Checkpoint() method from UploadProgress

* Update fs/entry.go

Co-authored-by: Julio López <julio+gh@kasten.io>
2020-09-12 22:36:22 -07:00
Jarek Kowalski
29ce1819cb Added support for setting and changing repository client options (description, read-only, hostname, username) (#589)
* repo: refactored client-specific options (hostname,username,description,readonly) into new struct that is JSON-compatible with current config

* cli: added 'repository set-client' to configure parameters of connected repository

* cli: cleaned up 'repository status' output
2020-09-04 13:57:15 -07:00
Jarek Kowalski
ded1ecf936 implemented Cache Directory Tagging Specification + CLI + UI (#565)
Fixes #564

cli: added 'kopia policy set --ignore-cache-dirs' option to control
whether to ignore caches (global default=true)

ui: added checkbox to control 'Ignore Cache Dirs' in policy editor

ignorefs: moved ignoring cache directories to ignorefs layer

Co-authored-by: Julio López <julio+gh@kasten.io>
2020-08-31 21:35:26 -07:00
Jarek Kowalski
1a8fcb086c Added endurance test which tests kopia over long time scale (#558)
Globally replaced all use of time with internal 'clock' package
which provides indirection to time.Now()

Added support for faking clock in Kopia via KOPIA_FAKE_CLOCK_ENDPOINT

logfile: squelch annoying log message

testenv: added faketimeserver which serves time over HTTP

testing: added endurance test which tests kopia over long time scale

This creates kopia repository and simulates usage of Kopia over multiple
months (using accelerated fake time) to trigger effects that are only
visible after long time passage (maintenance, compactions, expirations).

The test is not used part of any test suite yet but will run in
post-submit mode only, preferably 24/7.

testing: refactored internal/clock to only support injection when
'testing' build tag is present
2020-08-26 23:03:46 -07:00
Jarek Kowalski
9a6dea898b Linter upgrade to v1.30.0 (#526)
* fixed godot linter errors
* reformatted source with gofumpt
* disabled some linters
* fixed nolintlint warnings
* fixed gci warnings
* lint: fixed 'nestif' warnings
* lint: fixed 'exhaustive' warnings
* lint: fixed 'gocritic' warnings
* lint: fixed 'noctx' warnings
* lint: fixed 'wsl' warnings
* lint: fixed 'goerr113' warnings
* lint: fixed 'gosec' warnings
* lint: upgraded linter to 1.30.0
* lint: more 'exhaustive' warnings

Co-authored-by: Nick <nick@kasten.io>
2020-08-12 19:28:53 -07:00
Jarek Kowalski
8ead49b779 restore: support for zip, tar and tar.gz restore outputs (#482)
* restore: support for zip, tar and tar.gz restore outputs

Moved restore functionality to its own package.

* Fix enum values in the 'mode' flag

Co-authored-by: Julio López <julio+gh@kasten.io>
2020-07-22 22:56:11 -07:00
Jarek Kowalski
9b68a631e6 Highlight snapshot errors in the UI and CLI (#376)
* upload: exposed numFailed and failedEntries on directory summary

* cli: better present snapshot errors

* htmlui: display snapshot errors
2020-03-22 14:18:47 -07:00
Jarek Kowalski
c8fcae93aa logging: refactored logging
This is mostly mechanical and changes how loggers are instantiated.

Logger is now associated with a context, passed around all methods,
(most methods had ctx, but had to add it in a few missing places).

By default Kopia does not produce any logs, but it can be overridden,
either locally for a nested context, by calling

ctx = logging.WithLogger(ctx, newLoggerFunc)

To override logs globally, call logging.SetDefaultLogger(newLoggerFunc)

This refactoring allowed removing dependency from Kopia repo
and go-logging library (the CLI still uses it, though).

It is now also possible to have all test methods emit logs using
t.Logf() so that they show up in failure reports, which should make
debugging of test failures suck less.
2020-02-25 17:24:44 -08:00
Nick
7367f85afe Snapshot failure test and fix kopia panic for non-executable directories
Adding test to probe snapshot failure. Tests snapshot of non-existent source directory, and then iterates through file permissions for files, directories, and issues snapshot to the source. Permission combinations are applied to a parent directory of the source, source itself, contents of source root when the source is a directory, and contents of a subdirectory in that source root.

Fixing kopia executable panic when a directory's contents can't be read. Previously the only Lstat error responded to was not-exist, letting other errors fall through and passing a nil `os.FileInfo` to the following function call, resulting in panic.
2020-01-20 21:29:55 -08:00
Jarek Kowalski
de71f0f057 fs: added functions Update() and Remove() on fs.Entries which return a copy of entries with specified entry updated or removed 2020-01-05 09:13:41 -08:00
Jarek Kowalski
ac70a38101 lint: upgraded to 1.22.2 and make lint issues a build failure
fixed or silenced linter warnings, mostly due to magic numeric constants
2020-01-03 16:39:30 -08:00
Julio Lopez
1249a255d3 Allow copying to an existing directory
Add some logging
2020-01-02 13:49:28 -08:00
Julio Lopez
ac6e84107e Add CopyOptions and copier structs 2020-01-02 13:49:28 -08:00
Julio Lopez
7361d277e0 Remove special-case handling when target is root directory
No longer needed since directories can be overwritten by default
2020-01-02 13:49:28 -08:00
Julio Lopez
8e9d56fcf2 Trivial: simplify localfs.Directory 2020-01-02 09:50:45 -08:00
Jarek Kowalski
503fa74be5 fs: added Directory.Child() method to look up children by name without necessarily loading all of them 2019-12-30 19:21:17 -08:00
Julio Lopez
ca9ba27c6f Use github.com/natefinch/atomic.WriteFile in copyFileContents 2019-12-10 22:22:32 -08:00
Pavan Navarathna
fb57e828ad Restore command
Behavior:

- Creates top directory on restore
- Fails when target directories or files already exist
- Allows restoring to local root directory
- Restores of file attributes => mod time, mode, owner info
- Only a directory can be specified as a parameter

Not implemented:

- Restoring attributes of the top folder
- Restoring symlinks
- Restoring a single file
2019-12-10 22:22:32 -08:00
Jarek Kowalski
f6d59608ab upload: require *policy.Tree for each upload 2019-12-07 14:24:57 -08:00