copyparty 1.14.4__tar.gz → 1.15.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {copyparty-1.14.4 → copyparty-1.15.1}/PKG-INFO +39 -6
- {copyparty-1.14.4 → copyparty-1.15.1}/README.md +38 -5
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/__main__.py +14 -6
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/__version__.py +3 -3
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/authsrv.py +95 -8
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/broker_mp.py +4 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/broker_mpw.py +4 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/broker_thr.py +1 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/cfg.py +9 -7
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/httpcli.py +41 -11
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/svchub.py +90 -39
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/up2k.py +156 -44
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/util.py +2 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/a/u2c.py +109 -42
- copyparty-1.15.1/copyparty/web/browser.css.gz +0 -0
- copyparty-1.15.1/copyparty/web/browser.js.gz +0 -0
- copyparty-1.15.1/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/util.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/PKG-INFO +39 -6
- copyparty-1.14.4/copyparty/web/browser.css.gz +0 -0
- copyparty-1.14.4/copyparty/web/browser.js.gz +0 -0
- copyparty-1.14.4/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/LICENSE +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/bos/bos.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/bos/path.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/broker_util.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/cert.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/dxml.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/fsutil.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/ftpd.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/httpconn.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/httpsrv.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/ico.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/mdns.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/metrics.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/mtag.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/multicast.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/pwhash.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/res/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/smbd.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/ssdp.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/star.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/sutil.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/szip.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/tftpd.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/th_cli.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/th_srv.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/u2idx.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/browser.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/browser2.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/cf.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/md.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/mde.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/msg.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/shares.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/shares.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/splash.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/svcs.html +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/pyproject.toml +0 -0
- {copyparty-1.14.4 → copyparty-1.15.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.15.1
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
6
6
|
License: MIT
|
@@ -119,7 +119,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
119
119
|
* [smb server](#smb-server) - unsafe, slow, not recommended for wan
|
120
120
|
* [browser ux](#browser-ux) - tweaking the ui
|
121
121
|
* [opengraph](#opengraph) - discord and social-media embeds
|
122
|
-
* [file
|
122
|
+
* [file deduplication](#file-deduplication) - enable symlink-based upload deduplication
|
123
|
+
* [file indexing](#file-indexing) - enable music search, upload-undo, and better dedup
|
123
124
|
* [exclude-patterns](#exclude-patterns) - to save some time
|
124
125
|
* [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
|
125
126
|
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
@@ -1209,9 +1210,41 @@ NOTE: because discord (and maybe others) strip query args such as `?raw` in open
|
|
1209
1210
|
if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
|
1210
1211
|
|
1211
1212
|
|
1213
|
+
## file deduplication
|
1214
|
+
|
1215
|
+
enable symlink-based upload deduplication globally with `--dedup` or per-volume with volflag `dedup`
|
1216
|
+
|
1217
|
+
when someone tries to upload a file that already exists on the server, the upload will be politely declined and a symlink is created instead, pointing to the nearest copy on disk, thus reducinc disk space usage
|
1218
|
+
|
1219
|
+
**warning:** when enabling dedup, you should also:
|
1220
|
+
* enable indexing with `-e2dsa` or volflag `e2dsa` (see [file indexing](#file-indexing) section below); strongly recommended
|
1221
|
+
* ...and/or `--hardlink-only` to use hardlink-based deduplication instead of symlinks; see explanation below
|
1222
|
+
|
1223
|
+
it will not be safe to rename/delete files if you only enable dedup and none of the above; if you enable indexing then it is not *necessary* to also do hardlinks (but you may still want to)
|
1224
|
+
|
1225
|
+
by default, deduplication is done based on symlinks (symbolic links); these are tiny files which are pointers to the nearest full copy of the file
|
1226
|
+
|
1227
|
+
you can choose to use hardlinks instead of softlinks, globally with `--hardlink-only` or volflag `hardlinkonly`;
|
1228
|
+
|
1229
|
+
advantages of using hardlinks:
|
1230
|
+
* hardlinks are more compatible with other software; they behave entirely like regular files
|
1231
|
+
* you can safely move and rename files using other file managers
|
1232
|
+
* symlinks need to be managed by copyparty to ensure the destinations remain correct
|
1233
|
+
|
1234
|
+
advantages of using symlinks (default):
|
1235
|
+
* each symlink can have its own last-modified timestamp, but a single timestamp is shared by all hardlinks
|
1236
|
+
* symlinks make it more obvious to other software that the file is not a regular file, so this can be less dangerous
|
1237
|
+
* hardlinks look like regular files, so other software may assume they are safe to edit without affecting the other copies
|
1238
|
+
|
1239
|
+
**warning:** if you edit the contents of a deduplicated file, then you will also edit all other copies of that file! This is especially surprising with hardlinks, because they look like regular files, but that same file exists in multiple locations
|
1240
|
+
|
1241
|
+
global-option `--xlink` / volflag `xlink` additionally enables deduplication across volumes, but this is probably buggy and not recommended
|
1242
|
+
|
1243
|
+
|
1244
|
+
|
1212
1245
|
## file indexing
|
1213
1246
|
|
1214
|
-
|
1247
|
+
enable music search, upload-undo, and better dedup
|
1215
1248
|
|
1216
1249
|
file indexing relies on two database tables, the up2k filetree (`-e2d`) and the metadata tags (`-e2t`), stored in `.hist/up2k.db`. Configuration can be done through arguments, volflags, or a mix of both.
|
1217
1250
|
|
@@ -1225,7 +1258,6 @@ through arguments:
|
|
1225
1258
|
* `-e2v` verfies file integrity at startup, comparing hashes from the db
|
1226
1259
|
* `-e2vu` patches the database with the new hashes from the filesystem
|
1227
1260
|
* `-e2vp` panics and kills copyparty instead
|
1228
|
-
* `--xlink` enables deduplication across volumes
|
1229
1261
|
|
1230
1262
|
the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`, `d2ts`, `d2v` for disabling:
|
1231
1263
|
* `-v ~/music::r:c,e2ds,e2tsr` does a full reindex of everything on startup
|
@@ -1238,7 +1270,6 @@ note:
|
|
1238
1270
|
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
|
1239
1271
|
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
|
1240
1272
|
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
1241
|
-
* deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
|
1242
1273
|
|
1243
1274
|
### exclude-patterns
|
1244
1275
|
|
@@ -1978,6 +2009,8 @@ below are some tweaks roughly ordered by usefulness:
|
|
1978
2009
|
* `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
|
1979
2010
|
* `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
|
1980
2011
|
* and also makes thumbnails load faster, regardless of e2d/e2t
|
2012
|
+
* `--dedup` enables deduplication and thus avoids writing to the HDD if someone uploads a dupe
|
2013
|
+
* `--safe-dedup 1` makes deduplication much faster during upload by skipping verification of file contents; safe if there is no other software editing/moving the files in the volumes
|
1981
2014
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
1982
2015
|
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
1983
2016
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
@@ -2032,7 +2065,7 @@ safety profiles:
|
|
2032
2065
|
* `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
|
2033
2066
|
* however note if you edit one file it will also affect the other copies
|
2034
2067
|
* `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
|
2035
|
-
*
|
2068
|
+
* `-nih` removes the server hostname from directory listings
|
2036
2069
|
|
2037
2070
|
* option `-sss` is a shortcut for the above plus:
|
2038
2071
|
* `--no-dav` disables webdav support
|
@@ -65,7 +65,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
65
65
|
* [smb server](#smb-server) - unsafe, slow, not recommended for wan
|
66
66
|
* [browser ux](#browser-ux) - tweaking the ui
|
67
67
|
* [opengraph](#opengraph) - discord and social-media embeds
|
68
|
-
* [file
|
68
|
+
* [file deduplication](#file-deduplication) - enable symlink-based upload deduplication
|
69
|
+
* [file indexing](#file-indexing) - enable music search, upload-undo, and better dedup
|
69
70
|
* [exclude-patterns](#exclude-patterns) - to save some time
|
70
71
|
* [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
|
71
72
|
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
@@ -1155,9 +1156,41 @@ NOTE: because discord (and maybe others) strip query args such as `?raw` in open
|
|
1155
1156
|
if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
|
1156
1157
|
|
1157
1158
|
|
1159
|
+
## file deduplication
|
1160
|
+
|
1161
|
+
enable symlink-based upload deduplication globally with `--dedup` or per-volume with volflag `dedup`
|
1162
|
+
|
1163
|
+
when someone tries to upload a file that already exists on the server, the upload will be politely declined and a symlink is created instead, pointing to the nearest copy on disk, thus reducinc disk space usage
|
1164
|
+
|
1165
|
+
**warning:** when enabling dedup, you should also:
|
1166
|
+
* enable indexing with `-e2dsa` or volflag `e2dsa` (see [file indexing](#file-indexing) section below); strongly recommended
|
1167
|
+
* ...and/or `--hardlink-only` to use hardlink-based deduplication instead of symlinks; see explanation below
|
1168
|
+
|
1169
|
+
it will not be safe to rename/delete files if you only enable dedup and none of the above; if you enable indexing then it is not *necessary* to also do hardlinks (but you may still want to)
|
1170
|
+
|
1171
|
+
by default, deduplication is done based on symlinks (symbolic links); these are tiny files which are pointers to the nearest full copy of the file
|
1172
|
+
|
1173
|
+
you can choose to use hardlinks instead of softlinks, globally with `--hardlink-only` or volflag `hardlinkonly`;
|
1174
|
+
|
1175
|
+
advantages of using hardlinks:
|
1176
|
+
* hardlinks are more compatible with other software; they behave entirely like regular files
|
1177
|
+
* you can safely move and rename files using other file managers
|
1178
|
+
* symlinks need to be managed by copyparty to ensure the destinations remain correct
|
1179
|
+
|
1180
|
+
advantages of using symlinks (default):
|
1181
|
+
* each symlink can have its own last-modified timestamp, but a single timestamp is shared by all hardlinks
|
1182
|
+
* symlinks make it more obvious to other software that the file is not a regular file, so this can be less dangerous
|
1183
|
+
* hardlinks look like regular files, so other software may assume they are safe to edit without affecting the other copies
|
1184
|
+
|
1185
|
+
**warning:** if you edit the contents of a deduplicated file, then you will also edit all other copies of that file! This is especially surprising with hardlinks, because they look like regular files, but that same file exists in multiple locations
|
1186
|
+
|
1187
|
+
global-option `--xlink` / volflag `xlink` additionally enables deduplication across volumes, but this is probably buggy and not recommended
|
1188
|
+
|
1189
|
+
|
1190
|
+
|
1158
1191
|
## file indexing
|
1159
1192
|
|
1160
|
-
|
1193
|
+
enable music search, upload-undo, and better dedup
|
1161
1194
|
|
1162
1195
|
file indexing relies on two database tables, the up2k filetree (`-e2d`) and the metadata tags (`-e2t`), stored in `.hist/up2k.db`. Configuration can be done through arguments, volflags, or a mix of both.
|
1163
1196
|
|
@@ -1171,7 +1204,6 @@ through arguments:
|
|
1171
1204
|
* `-e2v` verfies file integrity at startup, comparing hashes from the db
|
1172
1205
|
* `-e2vu` patches the database with the new hashes from the filesystem
|
1173
1206
|
* `-e2vp` panics and kills copyparty instead
|
1174
|
-
* `--xlink` enables deduplication across volumes
|
1175
1207
|
|
1176
1208
|
the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`, `d2ts`, `d2v` for disabling:
|
1177
1209
|
* `-v ~/music::r:c,e2ds,e2tsr` does a full reindex of everything on startup
|
@@ -1184,7 +1216,6 @@ note:
|
|
1184
1216
|
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
|
1185
1217
|
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
|
1186
1218
|
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
1187
|
-
* deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
|
1188
1219
|
|
1189
1220
|
### exclude-patterns
|
1190
1221
|
|
@@ -1924,6 +1955,8 @@ below are some tweaks roughly ordered by usefulness:
|
|
1924
1955
|
* `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
|
1925
1956
|
* `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
|
1926
1957
|
* and also makes thumbnails load faster, regardless of e2d/e2t
|
1958
|
+
* `--dedup` enables deduplication and thus avoids writing to the HDD if someone uploads a dupe
|
1959
|
+
* `--safe-dedup 1` makes deduplication much faster during upload by skipping verification of file contents; safe if there is no other software editing/moving the files in the volumes
|
1927
1960
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
1928
1961
|
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
1929
1962
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
@@ -1978,7 +2011,7 @@ safety profiles:
|
|
1978
2011
|
* `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
|
1979
2012
|
* however note if you edit one file it will also affect the other copies
|
1980
2013
|
* `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
|
1981
|
-
*
|
2014
|
+
* `-nih` removes the server hostname from directory listings
|
1982
2015
|
|
1983
2016
|
* option `-sss` is a shortcut for the above plus:
|
1984
2017
|
* `--no-dav` disables webdav support
|
@@ -986,9 +986,10 @@ def add_upload(ap):
|
|
986
986
|
ap2.add_argument("--reg-cap", metavar="N", type=int, default=38400, help="max number of uploads to keep in memory when running without \033[33m-e2d\033[0m; roughly 1 MiB RAM per 600")
|
987
987
|
ap2.add_argument("--no-fpool", action="store_true", help="disable file-handle pooling -- instead, repeatedly close and reopen files during upload (bad idea to enable this on windows and/or cow filesystems)")
|
988
988
|
ap2.add_argument("--use-fpool", action="store_true", help="force file-handle pooling, even when it might be dangerous (multiprocessing, filesystems lacking sparse-files support, ...)")
|
989
|
-
ap2.add_argument("--
|
990
|
-
ap2.add_argument("--
|
991
|
-
ap2.add_argument("--
|
989
|
+
ap2.add_argument("--dedup", action="store_true", help="enable symlink-based upload deduplication (volflag=dedup)")
|
990
|
+
ap2.add_argument("--safe-dedup", metavar="N", type=int, default=50, help="how careful to be when deduplicating files; [\033[32m1\033[0m] = just verify the filesize, [\033[32m50\033[0m] = verify file contents have not been altered (volflag=safededup)")
|
991
|
+
ap2.add_argument("--hardlink", action="store_true", help="enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) (volflag=hardlink)")
|
992
|
+
ap2.add_argument("--hardlink-only", action="store_true", help="do not fallback to symlinks when a hardlink cannot be made (volflag=hardlinkonly)")
|
992
993
|
ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
|
993
994
|
ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
|
994
995
|
ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every \033[33mSEC\033[0m seconds; allows resuming incomplete uploads after a server crash")
|
@@ -1060,6 +1061,7 @@ def add_cert(ap, cert_path):
|
|
1060
1061
|
|
1061
1062
|
|
1062
1063
|
def add_auth(ap):
|
1064
|
+
ses_db = os.path.join(E.cfg, "sessions.db")
|
1063
1065
|
ap2 = ap.add_argument_group('IdP / identity provider / user authentication options')
|
1064
1066
|
ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks and assume the request-header \033[33mHN\033[0m contains the username of the requesting user (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy")
|
1065
1067
|
ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control")
|
@@ -1067,6 +1069,9 @@ def add_auth(ap):
|
|
1067
1069
|
ap2.add_argument("--idp-gsep", metavar="RE", type=u, default="|:;+,", help="if there are multiple groups in \033[33m--idp-h-grp\033[0m, they are separated by one of the characters in \033[33mRE\033[0m")
|
1068
1070
|
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
|
1069
1071
|
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
|
1072
|
+
ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)")
|
1073
|
+
ap2.add_argument("--ses-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)")
|
1074
|
+
ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies")
|
1070
1075
|
|
1071
1076
|
|
1072
1077
|
def add_chpw(ap):
|
@@ -1279,6 +1284,7 @@ def add_logging(ap):
|
|
1279
1284
|
ap2.add_argument("--ansi", action="store_true", help="force colors; overrides environment-variable NO_COLOR")
|
1280
1285
|
ap2.add_argument("--no-logflush", action="store_true", help="don't flush the logfile after each write; tiny bit faster")
|
1281
1286
|
ap2.add_argument("--no-voldump", action="store_true", help="do not list volumes and permissions on startup")
|
1287
|
+
ap2.add_argument("--log-utc", action="store_true", help="do not use local timezone; assume the TZ env-var is UTC (tiny bit faster)")
|
1282
1288
|
ap2.add_argument("--log-tdec", metavar="N", type=int, default=3, help="timestamp resolution / number of timestamp decimals")
|
1283
1289
|
ap2.add_argument("--log-badpwd", metavar="N", type=int, default=1, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed")
|
1284
1290
|
ap2.add_argument("--log-conn", action="store_true", help="debug: print tcp-server msgs")
|
@@ -1337,7 +1343,7 @@ def add_transcoding(ap):
|
|
1337
1343
|
def add_db_general(ap, hcores):
|
1338
1344
|
noidx = APPLESAN_TXT if MACOS else ""
|
1339
1345
|
ap2 = ap.add_argument_group('general db options')
|
1340
|
-
ap2.add_argument("-e2d", action="store_true", help="enable up2k database
|
1346
|
+
ap2.add_argument("-e2d", action="store_true", help="enable up2k database; this enables file search, upload-undo, improves deduplication")
|
1341
1347
|
ap2.add_argument("-e2ds", action="store_true", help="scan writable folders for new files on startup; sets \033[33m-e2d\033[0m")
|
1342
1348
|
ap2.add_argument("-e2dsa", action="store_true", help="scans all folders on startup; sets \033[33m-e2ds\033[0m")
|
1343
1349
|
ap2.add_argument("-e2v", action="store_true", help="verify file integrity; rehash all files and compare with db")
|
@@ -1350,7 +1356,7 @@ def add_db_general(ap, hcores):
|
|
1350
1356
|
ap2.add_argument("--re-dhash", action="store_true", help="force a cache rebuild on startup; enable this once if it gets out of sync (should never be necessary)")
|
1351
1357
|
ap2.add_argument("--no-forget", action="store_true", help="never forget indexed files, even when deleted from disk -- makes it impossible to ever upload the same file twice -- only useful for offloading uploads to a cloud service or something (volflag=noforget)")
|
1352
1358
|
ap2.add_argument("--dbd", metavar="PROFILE", default="wal", help="database durability profile; sets the tradeoff between robustness and speed, see \033[33m--help-dbd\033[0m (volflag=dbd)")
|
1353
|
-
ap2.add_argument("--xlink", action="store_true", help="on upload: check all volumes for dupes, not just the target volume (volflag=xlink)")
|
1359
|
+
ap2.add_argument("--xlink", action="store_true", help="on upload: check all volumes for dupes, not just the target volume (probably buggy, not recommended) (volflag=xlink)")
|
1354
1360
|
ap2.add_argument("--hash-mt", metavar="CORES", type=int, default=hcores, help="num cpu cores to use for file hashing; set 0 or 1 for single-core hashing")
|
1355
1361
|
ap2.add_argument("--re-maxage", metavar="SEC", type=int, default=0, help="rescan filesystem for changes every \033[33mSEC\033[0m seconds; 0=off (volflag=scan)")
|
1356
1362
|
ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
|
@@ -1463,6 +1469,7 @@ def run_argparse(
|
|
1463
1469
|
) :
|
1464
1470
|
ap = argparse.ArgumentParser(
|
1465
1471
|
formatter_class=formatter,
|
1472
|
+
usage=argparse.SUPPRESS,
|
1466
1473
|
prog="copyparty",
|
1467
1474
|
description="http file sharing hub v{} ({})".format(S_VERSION, S_BUILD_DT),
|
1468
1475
|
)
|
@@ -1613,6 +1620,7 @@ def main(argv = None, rsrc = None) :
|
|
1613
1620
|
("--hdr-au-usr", "--idp-h-usr"),
|
1614
1621
|
("--idp-h-sep", "--idp-gsep"),
|
1615
1622
|
("--th-no-crop", "--th-crop=n"),
|
1623
|
+
("--never-symlink", "--hardlink-only"),
|
1616
1624
|
]
|
1617
1625
|
for dk, nk in deprecated:
|
1618
1626
|
idx = -1
|
@@ -1637,7 +1645,7 @@ def main(argv = None, rsrc = None) :
|
|
1637
1645
|
argv.extend(["--qr"])
|
1638
1646
|
if ANYWIN or not os.geteuid():
|
1639
1647
|
# win10 allows symlinks if admin; can be unexpected
|
1640
|
-
argv.extend(["-p80,443,3923", "--ign-ebind"
|
1648
|
+
argv.extend(["-p80,443,3923", "--ign-ebind"])
|
1641
1649
|
except:
|
1642
1650
|
pass
|
1643
1651
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2024, 9,
|
3
|
+
VERSION = (1, 15, 1)
|
4
|
+
CODENAME = "fill the drives"
|
5
|
+
BUILD_DT = (2024, 9, 9)
|
6
6
|
|
7
7
|
S_VERSION = ".".join(map(str, VERSION))
|
8
8
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
@@ -833,8 +833,10 @@ class AuthSrv(object):
|
|
833
833
|
|
834
834
|
# fwd-decl
|
835
835
|
self.vfs = VFS(log_func, "", "", AXS(), {})
|
836
|
-
self.acct = {}
|
837
|
-
self.iacct = {}
|
836
|
+
self.acct = {} # uname->pw
|
837
|
+
self.iacct = {} # pw->uname
|
838
|
+
self.ases = {} # uname->session
|
839
|
+
self.sesa = {} # session->uname
|
838
840
|
self.defpw = {}
|
839
841
|
self.grps = {}
|
840
842
|
self.re_pwd = None
|
@@ -1884,6 +1886,11 @@ class AuthSrv(object):
|
|
1884
1886
|
if len(zs) == 3: # fc5 => ffcc55
|
1885
1887
|
vol.flags["tcolor"] = "".join([x * 2 for x in zs])
|
1886
1888
|
|
1889
|
+
if vol.flags.get("neversymlink"):
|
1890
|
+
vol.flags["hardlinkonly"] = True # was renamed
|
1891
|
+
if vol.flags.get("hardlinkonly"):
|
1892
|
+
vol.flags["hardlink"] = True
|
1893
|
+
|
1887
1894
|
for k1, k2 in IMPLICATIONS:
|
1888
1895
|
if k1 in vol.flags:
|
1889
1896
|
vol.flags[k2] = True
|
@@ -1988,9 +1995,6 @@ class AuthSrv(object):
|
|
1988
1995
|
for x in drop:
|
1989
1996
|
vol.flags.pop(x)
|
1990
1997
|
|
1991
|
-
if vol.flags.get("neversymlink") and not vol.flags.get("hardlink"):
|
1992
|
-
vol.flags["copydupes"] = True
|
1993
|
-
|
1994
1998
|
# verify tags mentioned by -mt[mp] are used by -mte
|
1995
1999
|
local_mtp = {}
|
1996
2000
|
local_only_mtp = {}
|
@@ -2069,6 +2073,8 @@ class AuthSrv(object):
|
|
2069
2073
|
|
2070
2074
|
have_e2d = False
|
2071
2075
|
have_e2t = False
|
2076
|
+
have_dedup = False
|
2077
|
+
unsafe_dedup = []
|
2072
2078
|
t = "volumes and permissions:\n"
|
2073
2079
|
for zv in vfs.all_vols.values():
|
2074
2080
|
if not self.warn_anonwrite or verbosity < 5:
|
@@ -2101,6 +2107,11 @@ class AuthSrv(object):
|
|
2101
2107
|
if "e2t" in zv.flags:
|
2102
2108
|
have_e2t = True
|
2103
2109
|
|
2110
|
+
if "dedup" in zv.flags:
|
2111
|
+
have_dedup = True
|
2112
|
+
if "e2d" not in zv.flags and "hardlink" not in zv.flags:
|
2113
|
+
unsafe_dedup.append("/" + zv.vpath)
|
2114
|
+
|
2104
2115
|
t += "\n"
|
2105
2116
|
|
2106
2117
|
if self.warn_anonwrite and verbosity > 4:
|
@@ -2113,10 +2124,17 @@ class AuthSrv(object):
|
|
2113
2124
|
self.log("\n\033[{}\033[0m\n".format(t))
|
2114
2125
|
|
2115
2126
|
if not have_e2t:
|
2116
|
-
t = "hint:
|
2127
|
+
t = "hint: enable multimedia indexing (artist/title/...) with argument -e2ts"
|
2117
2128
|
self.log(t, 6)
|
2118
2129
|
else:
|
2119
|
-
t = "hint:
|
2130
|
+
t = "hint: enable searching and upload-undo with argument -e2dsa"
|
2131
|
+
self.log(t, 6)
|
2132
|
+
|
2133
|
+
if unsafe_dedup:
|
2134
|
+
t = "WARNING: symlink-based deduplication is enabled for some volumes, but without indexing. Please enable -e2dsa and/or --hardlink to avoid problems when moving/renaming files. Affected volumes: %s"
|
2135
|
+
self.log(t % (", ".join(unsafe_dedup)), 3)
|
2136
|
+
elif not have_dedup:
|
2137
|
+
t = "hint: enable upload deduplication with --dedup (but see readme for consequences)"
|
2120
2138
|
self.log(t, 6)
|
2121
2139
|
|
2122
2140
|
zv, _ = vfs.get("/", "*", False, False)
|
@@ -2158,8 +2176,11 @@ class AuthSrv(object):
|
|
2158
2176
|
self.grps = grps
|
2159
2177
|
self.iacct = {v: k for k, v in acct.items()}
|
2160
2178
|
|
2179
|
+
self.load_sessions()
|
2180
|
+
|
2161
2181
|
self.re_pwd = None
|
2162
2182
|
pwds = [re.escape(x) for x in self.iacct.keys()]
|
2183
|
+
pwds.extend(list(self.sesa))
|
2163
2184
|
if pwds:
|
2164
2185
|
if self.ah.on:
|
2165
2186
|
zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)"
|
@@ -2234,6 +2255,72 @@ class AuthSrv(object):
|
|
2234
2255
|
cur.close()
|
2235
2256
|
db.close()
|
2236
2257
|
|
2258
|
+
def load_sessions(self, quiet=False) :
|
2259
|
+
# mutex me
|
2260
|
+
if self.args.no_ses:
|
2261
|
+
self.ases = {}
|
2262
|
+
self.sesa = {}
|
2263
|
+
return
|
2264
|
+
|
2265
|
+
import sqlite3
|
2266
|
+
|
2267
|
+
ases = {}
|
2268
|
+
blen = (self.args.ses_len // 4) * 4 # 3 bytes in 4 chars
|
2269
|
+
blen = (blen * 3) // 4 # bytes needed for ses_len chars
|
2270
|
+
|
2271
|
+
db = sqlite3.connect(self.args.ses_db)
|
2272
|
+
cur = db.cursor()
|
2273
|
+
|
2274
|
+
for uname, sid in cur.execute("select un, si from us"):
|
2275
|
+
if uname in self.acct:
|
2276
|
+
ases[uname] = sid
|
2277
|
+
|
2278
|
+
n = []
|
2279
|
+
q = "insert into us values (?,?,?)"
|
2280
|
+
for uname in self.acct:
|
2281
|
+
if uname not in ases:
|
2282
|
+
sid = ub64enc(os.urandom(blen)).decode("utf-8")
|
2283
|
+
cur.execute(q, (uname, sid, int(time.time())))
|
2284
|
+
ases[uname] = sid
|
2285
|
+
n.append(uname)
|
2286
|
+
|
2287
|
+
if n:
|
2288
|
+
db.commit()
|
2289
|
+
|
2290
|
+
cur.close()
|
2291
|
+
db.close()
|
2292
|
+
|
2293
|
+
self.ases = ases
|
2294
|
+
self.sesa = {v: k for k, v in ases.items()}
|
2295
|
+
if n and not quiet:
|
2296
|
+
t = ", ".join(n[:3])
|
2297
|
+
if len(n) > 3:
|
2298
|
+
t += "..."
|
2299
|
+
self.log("added %d new sessions (%s)" % (len(n), t))
|
2300
|
+
|
2301
|
+
def forget_session(self, broker , uname ) :
|
2302
|
+
with self.mutex:
|
2303
|
+
self._forget_session(uname)
|
2304
|
+
|
2305
|
+
if broker:
|
2306
|
+
broker.ask("_reload_sessions").get()
|
2307
|
+
|
2308
|
+
def _forget_session(self, uname ) :
|
2309
|
+
if self.args.no_ses:
|
2310
|
+
return
|
2311
|
+
|
2312
|
+
import sqlite3
|
2313
|
+
|
2314
|
+
db = sqlite3.connect(self.args.ses_db)
|
2315
|
+
cur = db.cursor()
|
2316
|
+
cur.execute("delete from us where un = ?", (uname,))
|
2317
|
+
db.commit()
|
2318
|
+
cur.close()
|
2319
|
+
db.close()
|
2320
|
+
|
2321
|
+
self.sesa.pop(self.ases.get(uname, ""), "")
|
2322
|
+
self.ases.pop(uname, "")
|
2323
|
+
|
2237
2324
|
def chpw(self, broker , uname, pw) :
|
2238
2325
|
if not self.args.chpw:
|
2239
2326
|
return False, "feature disabled in server config"
|
@@ -2253,7 +2340,7 @@ class AuthSrv(object):
|
|
2253
2340
|
if hpw == self.acct[uname]:
|
2254
2341
|
return False, "that's already your password my dude"
|
2255
2342
|
|
2256
|
-
if hpw in self.iacct:
|
2343
|
+
if hpw in self.iacct or hpw in self.sesa:
|
2257
2344
|
return False, "password is taken"
|
2258
2345
|
|
2259
2346
|
with self.mutex:
|
@@ -72,6 +72,10 @@ class BrokerMp(object):
|
|
72
72
|
for _, proc in enumerate(self.procs):
|
73
73
|
proc.q_pend.put((0, "reload", []))
|
74
74
|
|
75
|
+
def reload_sessions(self) :
|
76
|
+
for _, proc in enumerate(self.procs):
|
77
|
+
proc.q_pend.put((0, "reload_sessions", []))
|
78
|
+
|
75
79
|
def collector(self, proc ) :
|
76
80
|
"""receive message from hub in other process"""
|
77
81
|
while True:
|
@@ -30,6 +30,7 @@ class BrokerThr(BrokerCli):
|
|
30
30
|
self.iphash = HMaccas(os.path.join(self.args.E.cfg, "iphash"), 8)
|
31
31
|
self.httpsrv = HttpSrv(self, None)
|
32
32
|
self.reload = self.noop
|
33
|
+
self.reload_sessions = self.noop
|
33
34
|
|
34
35
|
def shutdown(self) :
|
35
36
|
# self.log("broker", "shutting down")
|
@@ -12,8 +12,7 @@ def vf_bmap() :
|
|
12
12
|
"dav_auth": "davauth",
|
13
13
|
"dav_rt": "davrt",
|
14
14
|
"ed": "dots",
|
15
|
-
"
|
16
|
-
"no_dedup": "copydupes",
|
15
|
+
"hardlink_only": "hardlinkonly",
|
17
16
|
"no_dupe": "nodupe",
|
18
17
|
"no_forget": "noforget",
|
19
18
|
"no_pipe": "nopipe",
|
@@ -23,6 +22,7 @@ def vf_bmap() :
|
|
23
22
|
"no_athumb": "dathumb",
|
24
23
|
}
|
25
24
|
for k in (
|
25
|
+
"dedup",
|
26
26
|
"dotsrch",
|
27
27
|
"e2d",
|
28
28
|
"e2ds",
|
@@ -58,6 +58,7 @@ def vf_vmap() :
|
|
58
58
|
"no_hash": "nohash",
|
59
59
|
"no_idx": "noidx",
|
60
60
|
"re_maxage": "scan",
|
61
|
+
"safe_dedup": "safededup",
|
61
62
|
"th_convt": "convt",
|
62
63
|
"th_size": "thsize",
|
63
64
|
"th_crop": "crop",
|
@@ -129,10 +130,11 @@ permdescs = {
|
|
129
130
|
|
130
131
|
flagcats = {
|
131
132
|
"uploads, general": {
|
133
|
+
"dedup": "enable symlink-based file deduplication",
|
134
|
+
"hardlink": "enable hardlink-based file deduplication,\nwith fallback on symlinks when that is impossible",
|
135
|
+
"hardlinkonly": "dedup with hardlink only, never symlink;\nmake a full copy if hardlink is impossible",
|
136
|
+
"safededup": "verify on-disk data before using it for dedup",
|
132
137
|
"nodupe": "rejects existing files (instead of symlinking them)",
|
133
|
-
"hardlink": "does dedup with hardlinks instead of symlinks",
|
134
|
-
"neversymlink": "disables symlink fallback; full copy instead",
|
135
|
-
"copydupes": "disables dedup, always saves full copies of dupes",
|
136
138
|
"sparse": "force use of sparse files, mainly for s3-backed storage",
|
137
139
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
138
140
|
"nosub": "forces all uploads into the top folder of the vfs",
|
@@ -159,7 +161,7 @@ flagcats = {
|
|
159
161
|
"lifetime=3600": "uploads are deleted after 1 hour",
|
160
162
|
},
|
161
163
|
"database, general": {
|
162
|
-
"e2d": "enable database; makes files searchable + enables upload
|
164
|
+
"e2d": "enable database; makes files searchable + enables upload-undo",
|
163
165
|
"e2ds": "scan writable folders for new files on startup; also sets -e2d",
|
164
166
|
"e2dsa": "scans all folders for new files on startup; also sets -e2d",
|
165
167
|
"e2t": "enable multimedia indexing; makes it possible to search for tags",
|
@@ -177,7 +179,7 @@ flagcats = {
|
|
177
179
|
"noforget": "don't forget files when deleted from disk",
|
178
180
|
"fat32": "avoid excessive reindexing on android sdcardfs",
|
179
181
|
"dbd=[acid|swal|wal|yolo]": "database speed-durability tradeoff",
|
180
|
-
"xlink": "cross-volume dupe detection / linking",
|
182
|
+
"xlink": "cross-volume dupe detection / linking (dangerous)",
|
181
183
|
"xdev": "do not descend into other filesystems",
|
182
184
|
"xvol": "do not follow symlinks leaving the volume root",
|
183
185
|
"dotsrch": "show dotfiles in search results",
|