mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
per-volume uid/gid; closes #265
This commit is contained in:
parent
a9d07c63ed
commit
f195998865
21
README.md
21
README.md
|
@ -80,6 +80,7 @@ made in Norway 🇳🇴
|
||||||
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
||||||
* [upload rules](#upload-rules) - set upload rules using volflags
|
* [upload rules](#upload-rules) - set upload rules using volflags
|
||||||
* [compress uploads](#compress-uploads) - files can be autocompressed on upload
|
* [compress uploads](#compress-uploads) - files can be autocompressed on upload
|
||||||
|
* [chmod and chown](#chmod-and-chown) - per-volume filesystem-permissions and ownership
|
||||||
* [other flags](#other-flags)
|
* [other flags](#other-flags)
|
||||||
* [database location](#database-location) - in-volume (`.hist/up2k.db`, default) or somewhere else
|
* [database location](#database-location) - in-volume (`.hist/up2k.db`, default) or somewhere else
|
||||||
* [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
|
* [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
|
||||||
|
@ -1649,6 +1650,26 @@ some examples,
|
||||||
allows (but does not force) gz compression if client uploads to `/inc?pk` or `/inc?gz` or `/inc?gz=4`
|
allows (but does not force) gz compression if client uploads to `/inc?pk` or `/inc?gz` or `/inc?gz=4`
|
||||||
|
|
||||||
|
|
||||||
|
## chmod and chown
|
||||||
|
|
||||||
|
per-volume filesystem-permissions and ownership
|
||||||
|
|
||||||
|
by default:
|
||||||
|
* all folders are chmod 755
|
||||||
|
* files are usually chmod 644 (umask-defined)
|
||||||
|
* user/group is whatever copyparty is running as
|
||||||
|
|
||||||
|
this can be configured per-volume:
|
||||||
|
* volflag `chmod_f` sets file permissions; default=`644` (usually)
|
||||||
|
* volflag `chmod_d` sets directory permissions; default=`755`
|
||||||
|
* volflag `uid` sets the owner user-id
|
||||||
|
* volflag `gid` sets the owner group-id
|
||||||
|
|
||||||
|
notes:
|
||||||
|
* `gid` can only be set to one of the groups which the copyparty process is a member of
|
||||||
|
* `uid` can only be set if copyparty is running as root (i appreciate your faith)
|
||||||
|
|
||||||
|
|
||||||
## other flags
|
## other flags
|
||||||
|
|
||||||
* `:c,magic` enables filetype detection for nameless uploads, same as `--magic`
|
* `:c,magic` enables filetype detection for nameless uploads, same as `--magic`
|
||||||
|
|
|
@ -1053,6 +1053,8 @@ def add_upload(ap):
|
||||||
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, ...)")
|
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, ...)")
|
||||||
ap2.add_argument("--chmod-f", metavar="UGO", type=u, default="", help="unix file permissions to use when creating files; default is probably 644 (OS-decided), see --help-chmod. Examples: [\033[32m644\033[0m] = owner-RW + all-R, [\033[32m755\033[0m] = owner-RWX + all-RX, [\033[32m777\033[0m] = full-yolo (volflag=chmod_f)")
|
ap2.add_argument("--chmod-f", metavar="UGO", type=u, default="", help="unix file permissions to use when creating files; default is probably 644 (OS-decided), see --help-chmod. Examples: [\033[32m644\033[0m] = owner-RW + all-R, [\033[32m755\033[0m] = owner-RWX + all-RX, [\033[32m777\033[0m] = full-yolo (volflag=chmod_f)")
|
||||||
ap2.add_argument("--chmod-d", metavar="UGO", type=u, default="755", help="unix file permissions to use when creating directories; see --help-chmod. Examples: [\033[32m755\033[0m] = owner-RW + all-R, [\033[32m777\033[0m] = full-yolo (volflag=chmod_d)")
|
ap2.add_argument("--chmod-d", metavar="UGO", type=u, default="755", help="unix file permissions to use when creating directories; see --help-chmod. Examples: [\033[32m755\033[0m] = owner-RW + all-R, [\033[32m777\033[0m] = full-yolo (volflag=chmod_d)")
|
||||||
|
ap2.add_argument("--uid", metavar="N", type=int, default=-1, help="unix user-id to chown new files/folders to; default = -1 = do-not-change (volflag=uid)")
|
||||||
|
ap2.add_argument("--gid", metavar="N", type=int, default=-1, help="unix group-id to chown new files/folders to; default = -1 = do-not-change (volflag=gid)")
|
||||||
ap2.add_argument("--dedup", action="store_true", help="enable symlink-based upload deduplication (volflag=dedup)")
|
ap2.add_argument("--dedup", action="store_true", help="enable symlink-based upload deduplication (volflag=dedup)")
|
||||||
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)")
|
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)")
|
||||||
ap2.add_argument("--hardlink", action="store_true", help="enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) (volflag=hardlink)")
|
ap2.add_argument("--hardlink", action="store_true", help="enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) (volflag=hardlink)")
|
||||||
|
|
|
@ -140,6 +140,8 @@ class Lim(object):
|
||||||
self.reg: Optional[dict[str, dict[str, Any]]] = None # up2k registry
|
self.reg: Optional[dict[str, dict[str, Any]]] = None # up2k registry
|
||||||
|
|
||||||
self.chmod_d = 0o755
|
self.chmod_d = 0o755
|
||||||
|
self.uid = self.gid = -1
|
||||||
|
self.chown = False
|
||||||
|
|
||||||
self.nups: dict[str, list[float]] = {} # num tracker
|
self.nups: dict[str, list[float]] = {} # num tracker
|
||||||
self.bups: dict[str, list[tuple[float, int]]] = {} # byte tracker list
|
self.bups: dict[str, list[tuple[float, int]]] = {} # byte tracker list
|
||||||
|
@ -302,6 +304,8 @@ class Lim(object):
|
||||||
# no branches yet; make one
|
# no branches yet; make one
|
||||||
sub = os.path.join(path, "0")
|
sub = os.path.join(path, "0")
|
||||||
bos.mkdir(sub, self.chmod_d)
|
bos.mkdir(sub, self.chmod_d)
|
||||||
|
if self.chown:
|
||||||
|
os.chown(sub, self.uid, self.gid)
|
||||||
else:
|
else:
|
||||||
# try newest branch only
|
# try newest branch only
|
||||||
sub = os.path.join(path, str(dirs[-1]))
|
sub = os.path.join(path, str(dirs[-1]))
|
||||||
|
@ -317,6 +321,8 @@ class Lim(object):
|
||||||
# make a branch
|
# make a branch
|
||||||
sub = os.path.join(path, str(dirs[-1] + 1))
|
sub = os.path.join(path, str(dirs[-1] + 1))
|
||||||
bos.mkdir(sub, self.chmod_d)
|
bos.mkdir(sub, self.chmod_d)
|
||||||
|
if self.chown:
|
||||||
|
os.chown(sub, self.uid, self.gid)
|
||||||
ret = self.dive(sub, lvs - 1)
|
ret = self.dive(sub, lvs - 1)
|
||||||
if ret is None:
|
if ret is None:
|
||||||
raise Pebkac(500, "rotation bug")
|
raise Pebkac(500, "rotation bug")
|
||||||
|
@ -2181,7 +2187,7 @@ class AuthSrv(object):
|
||||||
if vf not in vol.flags:
|
if vf not in vol.flags:
|
||||||
vol.flags[vf] = getattr(self.args, ga)
|
vol.flags[vf] = getattr(self.args, ga)
|
||||||
|
|
||||||
zs = "forget_ip nrand tail_who u2abort u2ow ups_who zip_who"
|
zs = "forget_ip gid nrand tail_who u2abort u2ow uid ups_who zip_who"
|
||||||
for k in zs.split():
|
for k in zs.split():
|
||||||
if k in vol.flags:
|
if k in vol.flags:
|
||||||
vol.flags[k] = int(vol.flags[k])
|
vol.flags[k] = int(vol.flags[k])
|
||||||
|
@ -2218,8 +2224,17 @@ class AuthSrv(object):
|
||||||
if (is_d and zi != 0o755) or not is_d:
|
if (is_d and zi != 0o755) or not is_d:
|
||||||
free_umask = True
|
free_umask = True
|
||||||
|
|
||||||
|
vol.flags.pop("chown", None)
|
||||||
|
if vol.flags["uid"] != -1 or vol.flags["gid"] != -1:
|
||||||
|
vol.flags["chown"] = True
|
||||||
|
vol.flags.pop("fperms", None)
|
||||||
|
if "chown" in vol.flags or vol.flags.get("chmod_f"):
|
||||||
|
vol.flags["fperms"] = True
|
||||||
if vol.lim:
|
if vol.lim:
|
||||||
vol.lim.chmod_d = vol.flags["chmod_d"]
|
vol.lim.chmod_d = vol.flags["chmod_d"]
|
||||||
|
vol.lim.chown = "chown" in vol.flags
|
||||||
|
vol.lim.uid = vol.flags["uid"]
|
||||||
|
vol.lim.gid = vol.flags["gid"]
|
||||||
|
|
||||||
if vol.flags.get("og"):
|
if vol.flags.get("og"):
|
||||||
self.args.uqe = True
|
self.args.uqe = True
|
||||||
|
|
|
@ -9,8 +9,11 @@ from . import path as path
|
||||||
if True: # pylint: disable=using-constant-test
|
if True: # pylint: disable=using-constant-test
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
_ = (path,)
|
MKD_755 = {"chmod_d": 0o755}
|
||||||
__all__ = ["path"]
|
MKD_700 = {"chmod_d": 0o700}
|
||||||
|
|
||||||
|
_ = (path, MKD_755, MKD_700)
|
||||||
|
__all__ = ["path", "MKD_755", "MKD_700"]
|
||||||
|
|
||||||
# grep -hRiE '(^|[^a-zA-Z_\.-])os\.' . | gsed -r 's/ /\n/g;s/\(/(\n/g' | grep -hRiE '(^|[^a-zA-Z_\.-])os\.' | sort | uniq -c
|
# grep -hRiE '(^|[^a-zA-Z_\.-])os\.' . | gsed -r 's/ /\n/g;s/\(/(\n/g' | grep -hRiE '(^|[^a-zA-Z_\.-])os\.' | sort | uniq -c
|
||||||
# printf 'os\.(%s)' "$(grep ^def bos/__init__.py | gsed -r 's/^def //;s/\(.*//' | tr '\n' '|' | gsed -r 's/.$//')"
|
# printf 'os\.(%s)' "$(grep ^def bos/__init__.py | gsed -r 's/^def //;s/\(.*//' | tr '\n' '|' | gsed -r 's/.$//')"
|
||||||
|
@ -20,11 +23,15 @@ def chmod(p: str, mode: int) -> None:
|
||||||
return os.chmod(fsenc(p), mode)
|
return os.chmod(fsenc(p), mode)
|
||||||
|
|
||||||
|
|
||||||
|
def chown(p: str, uid: int, gid: int) -> None:
|
||||||
|
return os.chown(fsenc(p), uid, gid)
|
||||||
|
|
||||||
|
|
||||||
def listdir(p: str = ".") -> list[str]:
|
def listdir(p: str = ".") -> list[str]:
|
||||||
return [fsdec(x) for x in os.listdir(fsenc(p))]
|
return [fsdec(x) for x in os.listdir(fsenc(p))]
|
||||||
|
|
||||||
|
|
||||||
def makedirs(name: str, mode: int = 0o755, exist_ok: bool = True) -> bool:
|
def makedirs(name: str, vf: dict[str, Any] = MKD_755, exist_ok: bool = True) -> bool:
|
||||||
# os.makedirs does 777 for all but leaf; this does mode on all
|
# os.makedirs does 777 for all but leaf; this does mode on all
|
||||||
todo = []
|
todo = []
|
||||||
bname = fsenc(name)
|
bname = fsenc(name)
|
||||||
|
@ -37,9 +44,13 @@ def makedirs(name: str, mode: int = 0o755, exist_ok: bool = True) -> bool:
|
||||||
if not exist_ok:
|
if not exist_ok:
|
||||||
os.mkdir(bname) # to throw
|
os.mkdir(bname) # to throw
|
||||||
return False
|
return False
|
||||||
|
mode = vf["chmod_d"]
|
||||||
|
chown = "chown" in vf
|
||||||
for zb in todo[::-1]:
|
for zb in todo[::-1]:
|
||||||
try:
|
try:
|
||||||
os.mkdir(zb, mode)
|
os.mkdir(zb, mode)
|
||||||
|
if chown:
|
||||||
|
os.chown(zb, vf["uid"], vf["gid"])
|
||||||
except:
|
except:
|
||||||
if os.path.isdir(zb):
|
if os.path.isdir(zb):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -114,6 +114,8 @@ def vf_vmap() -> dict[str, str]:
|
||||||
"unlist",
|
"unlist",
|
||||||
"u2abort",
|
"u2abort",
|
||||||
"u2ts",
|
"u2ts",
|
||||||
|
"uid",
|
||||||
|
"gid",
|
||||||
"ups_who",
|
"ups_who",
|
||||||
"zip_who",
|
"zip_who",
|
||||||
"zipmaxn",
|
"zipmaxn",
|
||||||
|
@ -175,6 +177,8 @@ flagcats = {
|
||||||
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
||||||
"chmod_d=755": "unix-permission for new dirs/folders",
|
"chmod_d=755": "unix-permission for new dirs/folders",
|
||||||
"chmod_f=644": "unix-permission for new files",
|
"chmod_f=644": "unix-permission for new files",
|
||||||
|
"uid=573": "change owner of new files/folders to unix-user 573",
|
||||||
|
"gid=999": "change owner of new files/folders to unix-group 999",
|
||||||
"sparse": "force use of sparse files, mainly for s3-backed storage",
|
"sparse": "force use of sparse files, mainly for s3-backed storage",
|
||||||
"nosparse": "deny use of sparse files, mainly for slow storage",
|
"nosparse": "deny use of sparse files, mainly for slow storage",
|
||||||
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
||||||
|
|
|
@ -31,6 +31,7 @@ from .util import (
|
||||||
relchk,
|
relchk,
|
||||||
runhook,
|
runhook,
|
||||||
sanitize_fn,
|
sanitize_fn,
|
||||||
|
set_fperms,
|
||||||
vjoin,
|
vjoin,
|
||||||
wunlink,
|
wunlink,
|
||||||
)
|
)
|
||||||
|
@ -262,8 +263,8 @@ class FtpFs(AbstractedFS):
|
||||||
wunlink(self.log, ap, VF_CAREFUL)
|
wunlink(self.log, ap, VF_CAREFUL)
|
||||||
|
|
||||||
ret = open(fsenc(ap), mode, self.args.iobuf)
|
ret = open(fsenc(ap), mode, self.args.iobuf)
|
||||||
if w and "chmod_f" in vfs.flags:
|
if w and "fperms" in vfs.flags:
|
||||||
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
set_fperms(ret, vfs.flags)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -297,8 +298,7 @@ class FtpFs(AbstractedFS):
|
||||||
|
|
||||||
def mkdir(self, path: str) -> None:
|
def mkdir(self, path: str) -> None:
|
||||||
ap, vfs, _ = self.rv2a(path, w=True)
|
ap, vfs, _ = self.rv2a(path, w=True)
|
||||||
chmod = vfs.flags["chmod_d"]
|
bos.makedirs(ap, vf=vfs.flags) # filezilla expects this
|
||||||
bos.makedirs(ap, chmod) # filezilla expects this
|
|
||||||
|
|
||||||
def listdir(self, path: str) -> list[str]:
|
def listdir(self, path: str) -> list[str]:
|
||||||
vpath = join(self.cwd, path)
|
vpath = join(self.cwd, path)
|
||||||
|
|
|
@ -103,6 +103,7 @@ from .util import (
|
||||||
sanitize_vpath,
|
sanitize_vpath,
|
||||||
sendfile_kern,
|
sendfile_kern,
|
||||||
sendfile_py,
|
sendfile_py,
|
||||||
|
set_fperms,
|
||||||
stat_resource,
|
stat_resource,
|
||||||
ub64dec,
|
ub64dec,
|
||||||
ub64enc,
|
ub64enc,
|
||||||
|
@ -2086,7 +2087,7 @@ class HttpCli(object):
|
||||||
fdir, fn = os.path.split(fdir)
|
fdir, fn = os.path.split(fdir)
|
||||||
rem, _ = vsplit(rem)
|
rem, _ = vsplit(rem)
|
||||||
|
|
||||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
bos.makedirs(fdir, vf=vfs.flags)
|
||||||
|
|
||||||
open_ka: dict[str, Any] = {"fun": open}
|
open_ka: dict[str, Any] = {"fun": open}
|
||||||
open_a = ["wb", self.args.iobuf]
|
open_a = ["wb", self.args.iobuf]
|
||||||
|
@ -2144,9 +2145,7 @@ class HttpCli(object):
|
||||||
if nameless:
|
if nameless:
|
||||||
fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
|
fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
|
||||||
|
|
||||||
params = {"suffix": suffix, "fdir": fdir}
|
params = {"suffix": suffix, "fdir": fdir, "vf": vfs.flags}
|
||||||
if "chmod_f" in vfs.flags:
|
|
||||||
params["chmod"] = vfs.flags["chmod_f"]
|
|
||||||
if self.args.nw:
|
if self.args.nw:
|
||||||
params = {}
|
params = {}
|
||||||
fn = os.devnull
|
fn = os.devnull
|
||||||
|
@ -2195,7 +2194,7 @@ class HttpCli(object):
|
||||||
if self.args.nw:
|
if self.args.nw:
|
||||||
fn = os.devnull
|
fn = os.devnull
|
||||||
else:
|
else:
|
||||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
bos.makedirs(fdir, vf=vfs.flags)
|
||||||
path = os.path.join(fdir, fn)
|
path = os.path.join(fdir, fn)
|
||||||
if not nameless:
|
if not nameless:
|
||||||
self.vpath = vjoin(self.vpath, fn)
|
self.vpath = vjoin(self.vpath, fn)
|
||||||
|
@ -2327,7 +2326,7 @@ class HttpCli(object):
|
||||||
if self.args.hook_v:
|
if self.args.hook_v:
|
||||||
log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
|
log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
|
||||||
fdir, self.vpath, fn, (vfs, rem) = x
|
fdir, self.vpath, fn, (vfs, rem) = x
|
||||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
bos.makedirs(fdir, vf=vfs.flags)
|
||||||
path2 = os.path.join(fdir, fn)
|
path2 = os.path.join(fdir, fn)
|
||||||
atomic_move(self.log, path, path2, vfs.flags)
|
atomic_move(self.log, path, path2, vfs.flags)
|
||||||
path = path2
|
path = path2
|
||||||
|
@ -2613,7 +2612,7 @@ class HttpCli(object):
|
||||||
dst = vfs.canonical(rem)
|
dst = vfs.canonical(rem)
|
||||||
try:
|
try:
|
||||||
if not bos.path.isdir(dst):
|
if not bos.path.isdir(dst):
|
||||||
bos.makedirs(dst, vfs.flags["chmod_d"])
|
bos.makedirs(dst, vf=vfs.flags)
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
self.log("makedirs failed %r" % (dst,))
|
self.log("makedirs failed %r" % (dst,))
|
||||||
if not bos.path.isdir(dst):
|
if not bos.path.isdir(dst):
|
||||||
|
@ -3060,7 +3059,7 @@ class HttpCli(object):
|
||||||
raise Pebkac(405, 'folder "/%s" already exists' % (vpath,))
|
raise Pebkac(405, 'folder "/%s" already exists' % (vpath,))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bos.makedirs(fn, vfs.flags["chmod_d"])
|
bos.makedirs(fn, vf=vfs.flags)
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
if ex.errno == errno.EACCES:
|
if ex.errno == errno.EACCES:
|
||||||
raise Pebkac(500, "the server OS denied write-access")
|
raise Pebkac(500, "the server OS denied write-access")
|
||||||
|
@ -3102,8 +3101,8 @@ class HttpCli(object):
|
||||||
|
|
||||||
with open(fsenc(fn), "wb") as f:
|
with open(fsenc(fn), "wb") as f:
|
||||||
f.write(b"`GRUNNUR`\n")
|
f.write(b"`GRUNNUR`\n")
|
||||||
if "chmod_f" in vfs.flags:
|
if "fperms" in vfs.flags:
|
||||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
set_fperms(f, vfs.flags)
|
||||||
|
|
||||||
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
||||||
self.redirect(vpath, "?edit")
|
self.redirect(vpath, "?edit")
|
||||||
|
@ -3177,7 +3176,7 @@ class HttpCli(object):
|
||||||
)
|
)
|
||||||
upload_vpath = "{}/{}".format(vfs.vpath, rem).strip("/")
|
upload_vpath = "{}/{}".format(vfs.vpath, rem).strip("/")
|
||||||
if not nullwrite:
|
if not nullwrite:
|
||||||
bos.makedirs(fdir_base, vfs.flags["chmod_d"])
|
bos.makedirs(fdir_base, vf=vfs.flags)
|
||||||
|
|
||||||
rnd, lifetime, xbu, xau = self.upload_flags(vfs)
|
rnd, lifetime, xbu, xau = self.upload_flags(vfs)
|
||||||
zs = self.uparam.get("want") or self.headers.get("accept") or ""
|
zs = self.uparam.get("want") or self.headers.get("accept") or ""
|
||||||
|
@ -3210,7 +3209,7 @@ class HttpCli(object):
|
||||||
if rnd:
|
if rnd:
|
||||||
fname = rand_name(fdir, fname, rnd)
|
fname = rand_name(fdir, fname, rnd)
|
||||||
|
|
||||||
open_args = {"fdir": fdir, "suffix": suffix}
|
open_args = {"fdir": fdir, "suffix": suffix, "vf": vfs.flags}
|
||||||
|
|
||||||
if "replace" in self.uparam:
|
if "replace" in self.uparam:
|
||||||
if not self.can_delete:
|
if not self.can_delete:
|
||||||
|
@ -3272,11 +3271,8 @@ class HttpCli(object):
|
||||||
else:
|
else:
|
||||||
open_args["fdir"] = fdir
|
open_args["fdir"] = fdir
|
||||||
|
|
||||||
if "chmod_f" in vfs.flags:
|
|
||||||
open_args["chmod"] = vfs.flags["chmod_f"]
|
|
||||||
|
|
||||||
if p_file and not nullwrite:
|
if p_file and not nullwrite:
|
||||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
bos.makedirs(fdir, vf=vfs.flags)
|
||||||
|
|
||||||
# reserve destination filename
|
# reserve destination filename
|
||||||
f, fname = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
|
f, fname = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
|
||||||
|
@ -3380,7 +3376,7 @@ class HttpCli(object):
|
||||||
if nullwrite:
|
if nullwrite:
|
||||||
fdir = ap2 = ""
|
fdir = ap2 = ""
|
||||||
else:
|
else:
|
||||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
bos.makedirs(fdir, vf=vfs.flags)
|
||||||
atomic_move(self.log, abspath, ap2, vfs.flags)
|
atomic_move(self.log, abspath, ap2, vfs.flags)
|
||||||
abspath = ap2
|
abspath = ap2
|
||||||
sz = bos.path.getsize(abspath)
|
sz = bos.path.getsize(abspath)
|
||||||
|
@ -3501,8 +3497,8 @@ class HttpCli(object):
|
||||||
ft = "{}:{}".format(self.ip, self.addr[1])
|
ft = "{}:{}".format(self.ip, self.addr[1])
|
||||||
ft = "{}\n{}\n{}\n".format(ft, msg.rstrip(), errmsg)
|
ft = "{}\n{}\n{}\n".format(ft, msg.rstrip(), errmsg)
|
||||||
f.write(ft.encode("utf-8"))
|
f.write(ft.encode("utf-8"))
|
||||||
if "chmod_f" in vfs.flags:
|
if "fperms" in vfs.flags:
|
||||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
set_fperms(f, vfs.flags)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
suf = "\nfailed to write the upload report: {}".format(ex)
|
suf = "\nfailed to write the upload report: {}".format(ex)
|
||||||
|
|
||||||
|
@ -3553,7 +3549,7 @@ class HttpCli(object):
|
||||||
lim = vfs.get_dbv(rem)[0].lim
|
lim = vfs.get_dbv(rem)[0].lim
|
||||||
if lim:
|
if lim:
|
||||||
fp, rp = lim.all(self.ip, rp, clen, vfs.realpath, fp, self.conn.hsrv.broker)
|
fp, rp = lim.all(self.ip, rp, clen, vfs.realpath, fp, self.conn.hsrv.broker)
|
||||||
bos.makedirs(fp, vfs.flags["chmod_d"])
|
bos.makedirs(fp, vf=vfs.flags)
|
||||||
|
|
||||||
fp = os.path.join(fp, fn)
|
fp = os.path.join(fp, fn)
|
||||||
rem = "{}/{}".format(rp, fn).strip("/")
|
rem = "{}/{}".format(rp, fn).strip("/")
|
||||||
|
@ -3621,15 +3617,17 @@ class HttpCli(object):
|
||||||
zs = ub64enc(zb).decode("ascii")[:24].lower()
|
zs = ub64enc(zb).decode("ascii")[:24].lower()
|
||||||
dp = "%s/md/%s/%s/%s" % (dbv.histpath, zs[:2], zs[2:4], zs)
|
dp = "%s/md/%s/%s/%s" % (dbv.histpath, zs[:2], zs[2:4], zs)
|
||||||
self.log("moving old version to %s/%s" % (dp, mfile2))
|
self.log("moving old version to %s/%s" % (dp, mfile2))
|
||||||
if bos.makedirs(dp, vfs.flags["chmod_d"]):
|
if bos.makedirs(dp, vf=vfs.flags):
|
||||||
with open(os.path.join(dp, "dir.txt"), "wb") as f:
|
with open(os.path.join(dp, "dir.txt"), "wb") as f:
|
||||||
f.write(afsenc(vrd))
|
f.write(afsenc(vrd))
|
||||||
if "chmod_f" in vfs.flags:
|
if "fperms" in vfs.flags:
|
||||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
set_fperms(f, vfs.flags)
|
||||||
elif hist_cfg == "s":
|
elif hist_cfg == "s":
|
||||||
dp = os.path.join(mdir, ".hist")
|
dp = os.path.join(mdir, ".hist")
|
||||||
try:
|
try:
|
||||||
bos.mkdir(dp, vfs.flags["chmod_d"])
|
bos.mkdir(dp, vfs.flags["chmod_d"])
|
||||||
|
if "chown" in vfs.flags:
|
||||||
|
bos.chown(dp, vfs.flags["uid"], vfs.flags["gid"])
|
||||||
hidedir(dp)
|
hidedir(dp)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -3668,8 +3666,8 @@ class HttpCli(object):
|
||||||
wunlink(self.log, fp, vfs.flags)
|
wunlink(self.log, fp, vfs.flags)
|
||||||
|
|
||||||
with open(fsenc(fp), "wb", self.args.iobuf) as f:
|
with open(fsenc(fp), "wb", self.args.iobuf) as f:
|
||||||
if "chmod_f" in vfs.flags:
|
if "fperms" in vfs.flags:
|
||||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
set_fperms(f, vfs.flags)
|
||||||
sz, sha512, _ = hashcopy(p_data, f, None, 0, self.args.s_wr_slp)
|
sz, sha512, _ = hashcopy(p_data, f, None, 0, self.args.s_wr_slp)
|
||||||
|
|
||||||
if lim:
|
if lim:
|
||||||
|
|
|
@ -320,7 +320,7 @@ class SMB(object):
|
||||||
|
|
||||||
self.hub.up2k.handle_mv(uname, "1.7.6.2", vp1, vp2)
|
self.hub.up2k.handle_mv(uname, "1.7.6.2", vp1, vp2)
|
||||||
try:
|
try:
|
||||||
bos.makedirs(ap2, vfs2.flags["chmod_d"])
|
bos.makedirs(ap2, vf=vfs2.flags)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ from .util import (
|
||||||
exclude_dotfiles,
|
exclude_dotfiles,
|
||||||
min_ex,
|
min_ex,
|
||||||
runhook,
|
runhook,
|
||||||
|
set_fperms,
|
||||||
undot,
|
undot,
|
||||||
vjoin,
|
vjoin,
|
||||||
vsplit,
|
vsplit,
|
||||||
|
@ -388,8 +389,8 @@ class Tftpd(object):
|
||||||
a = (self.args.iobuf,)
|
a = (self.args.iobuf,)
|
||||||
|
|
||||||
ret = open(ap, mode, *a, **ka)
|
ret = open(ap, mode, *a, **ka)
|
||||||
if wr and "chmod_f" in vfs.flags:
|
if wr and "fperms" in vfs.flags:
|
||||||
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
set_fperms(ret, vfs.flags)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -398,7 +399,9 @@ class Tftpd(object):
|
||||||
if "*" not in vfs.axs.uwrite:
|
if "*" not in vfs.axs.uwrite:
|
||||||
yeet("blocked mkdir; folder not world-writable: /%s" % (vpath,))
|
yeet("blocked mkdir; folder not world-writable: /%s" % (vpath,))
|
||||||
|
|
||||||
return bos.mkdir(ap, vfs.flags["chmod_d"])
|
bos.mkdir(ap, vfs.flags["chmod_d"])
|
||||||
|
if "chown" in vfs.flags:
|
||||||
|
bos.chown(ap, vfs.flags["uid"], vfs.flags["gid"])
|
||||||
|
|
||||||
def _unlink(self, vpath: str) -> None:
|
def _unlink(self, vpath: str) -> None:
|
||||||
# return bos.unlink(self._v2a("stat", vpath, *a)[1])
|
# return bos.unlink(self._v2a("stat", vpath, *a)[1])
|
||||||
|
|
|
@ -269,8 +269,8 @@ class ThumbSrv(object):
|
||||||
self.log("joined waiting room for %r" % (tpath,))
|
self.log("joined waiting room for %r" % (tpath,))
|
||||||
except:
|
except:
|
||||||
thdir = os.path.dirname(tpath)
|
thdir = os.path.dirname(tpath)
|
||||||
chmod = 0o700 if self.args.free_umask else 0o755
|
chmod = bos.MKD_700 if self.args.free_umask else bos.MKD_755
|
||||||
bos.makedirs(os.path.join(thdir, "w"), chmod)
|
bos.makedirs(os.path.join(thdir, "w"), vf=chmod)
|
||||||
|
|
||||||
inf_path = os.path.join(thdir, "dir.txt")
|
inf_path = os.path.join(thdir, "dir.txt")
|
||||||
if not bos.path.exists(inf_path):
|
if not bos.path.exists(inf_path):
|
||||||
|
|
|
@ -916,7 +916,7 @@ class Up2k(object):
|
||||||
for vol in vols:
|
for vol in vols:
|
||||||
try:
|
try:
|
||||||
# mkdir gonna happen at snap anyways;
|
# mkdir gonna happen at snap anyways;
|
||||||
bos.makedirs(vol.realpath, vol.flags["chmod_d"])
|
bos.makedirs(vol.realpath, vf=vol.flags)
|
||||||
dir_is_empty(self.log_func, not self.args.no_scandir, vol.realpath)
|
dir_is_empty(self.log_func, not self.args.no_scandir, vol.realpath)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.volstate[vol.vpath] = "OFFLINE (cannot access folder)"
|
self.volstate[vol.vpath] = "OFFLINE (cannot access folder)"
|
||||||
|
@ -3309,7 +3309,7 @@ class Up2k(object):
|
||||||
reg,
|
reg,
|
||||||
"up2k._get_volsize",
|
"up2k._get_volsize",
|
||||||
)
|
)
|
||||||
bos.makedirs(ap2, vfs.flags["chmod_d"])
|
bos.makedirs(ap2, vf=vfs.flags)
|
||||||
vfs.lim.nup(cj["addr"])
|
vfs.lim.nup(cj["addr"])
|
||||||
vfs.lim.bup(cj["addr"], cj["size"])
|
vfs.lim.bup(cj["addr"], cj["size"])
|
||||||
|
|
||||||
|
@ -3445,7 +3445,7 @@ class Up2k(object):
|
||||||
"wb",
|
"wb",
|
||||||
fdir=fdir,
|
fdir=fdir,
|
||||||
suffix="-%.6f-%s" % (ts, dip),
|
suffix="-%.6f-%s" % (ts, dip),
|
||||||
chmod=vf.get("chmod_f", -1),
|
vf=vf,
|
||||||
)
|
)
|
||||||
f.close()
|
f.close()
|
||||||
return ret
|
return ret
|
||||||
|
@ -4304,7 +4304,7 @@ class Up2k(object):
|
||||||
self.log(t, 1)
|
self.log(t, 1)
|
||||||
raise Pebkac(405, t)
|
raise Pebkac(405, t)
|
||||||
|
|
||||||
bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
|
bos.makedirs(os.path.dirname(dabs), vf=dvn.flags)
|
||||||
|
|
||||||
c1, w, ftime_, fsize_, ip, at = self._find_from_vpath(
|
c1, w, ftime_, fsize_, ip, at = self._find_from_vpath(
|
||||||
svn_dbv.realpath, srem_dbv
|
svn_dbv.realpath, srem_dbv
|
||||||
|
@ -4480,7 +4480,10 @@ class Up2k(object):
|
||||||
vp = vjoin(dvp, rem)
|
vp = vjoin(dvp, rem)
|
||||||
try:
|
try:
|
||||||
dvn, drem = self.vfs.get(vp, uname, False, True)
|
dvn, drem = self.vfs.get(vp, uname, False, True)
|
||||||
bos.mkdir(dvn.canonical(drem), dvn.flags["chmod_d"])
|
dap = dvn.canonical(drem)
|
||||||
|
bos.mkdir(dap, dvn.flags["chmod_d"])
|
||||||
|
if "chown" in dvn.flags:
|
||||||
|
bos.chown(dap, dvn.flags["uid"], dvn.flags["gid"])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -4550,7 +4553,7 @@ class Up2k(object):
|
||||||
|
|
||||||
is_xvol = svn.realpath != dvn.realpath
|
is_xvol = svn.realpath != dvn.realpath
|
||||||
|
|
||||||
bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
|
bos.makedirs(os.path.dirname(dabs), vf=dvn.flags)
|
||||||
|
|
||||||
if is_dirlink:
|
if is_dirlink:
|
||||||
dlabs = absreal(sabs)
|
dlabs = absreal(sabs)
|
||||||
|
@ -5062,7 +5065,7 @@ class Up2k(object):
|
||||||
"wb",
|
"wb",
|
||||||
fdir=pdir,
|
fdir=pdir,
|
||||||
suffix="-%.6f-%s" % (job["t0"], dip),
|
suffix="-%.6f-%s" % (job["t0"], dip),
|
||||||
chmod=vf.get("chmod_f", -1),
|
vf=vf,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
abspath = djoin(pdir, job["tnam"])
|
abspath = djoin(pdir, job["tnam"])
|
||||||
|
|
|
@ -1587,7 +1587,8 @@ def ren_open(fname: str, *args: Any, **kwargs: Any) -> tuple[typing.IO[Any], str
|
||||||
fun = kwargs.pop("fun", open)
|
fun = kwargs.pop("fun", open)
|
||||||
fdir = kwargs.pop("fdir", None)
|
fdir = kwargs.pop("fdir", None)
|
||||||
suffix = kwargs.pop("suffix", None)
|
suffix = kwargs.pop("suffix", None)
|
||||||
chmod = kwargs.pop("chmod", -1)
|
vf = kwargs.pop("vf", None)
|
||||||
|
fperms = vf and "fperms" in vf
|
||||||
|
|
||||||
if fname == os.devnull:
|
if fname == os.devnull:
|
||||||
return fun(fname, *args, **kwargs), fname
|
return fun(fname, *args, **kwargs), fname
|
||||||
|
@ -1631,11 +1632,11 @@ def ren_open(fname: str, *args: Any, **kwargs: Any) -> tuple[typing.IO[Any], str
|
||||||
fp2 = os.path.join(fdir, fp2)
|
fp2 = os.path.join(fdir, fp2)
|
||||||
with open(fsenc(fp2), "wb") as f2:
|
with open(fsenc(fp2), "wb") as f2:
|
||||||
f2.write(orig_name.encode("utf-8"))
|
f2.write(orig_name.encode("utf-8"))
|
||||||
if chmod >= 0:
|
if fperms:
|
||||||
os.fchmod(f2.fileno(), chmod)
|
set_fperms(f2, vf)
|
||||||
|
|
||||||
if chmod >= 0:
|
if fperms:
|
||||||
os.fchmod(f.fileno(), chmod)
|
set_fperms(f, vf)
|
||||||
|
|
||||||
return f, fname
|
return f, fname
|
||||||
|
|
||||||
|
@ -2565,6 +2566,14 @@ def lsof(log: "NamedLogger", abspath: str) -> None:
|
||||||
log("lsof failed; " + min_ex(), 3)
|
log("lsof failed; " + min_ex(), 3)
|
||||||
|
|
||||||
|
|
||||||
|
def set_fperms(f: Union[typing.BinaryIO, typing.IO[Any]], vf: dict[str, Any]) -> None:
|
||||||
|
fno = f.fileno()
|
||||||
|
if "chmod_f" in vf:
|
||||||
|
os.fchmod(fno, vf["chmod_f"])
|
||||||
|
if "chown" in vf:
|
||||||
|
os.fchown(fno, vf["uid"], vf["gid"])
|
||||||
|
|
||||||
|
|
||||||
def _fs_mvrm(
|
def _fs_mvrm(
|
||||||
log: "NamedLogger", src: str, dst: str, atomic: bool, flags: dict[str, Any]
|
log: "NamedLogger", src: str, dst: str, atomic: bool, flags: dict[str, Any]
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
|
@ -152,6 +152,9 @@ class Cfg(Namespace):
|
||||||
ex = "ah_cli ah_gen css_browser dbpath hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua ua_nodoc ua_nozip"
|
ex = "ah_cli ah_gen css_browser dbpath hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua ua_nodoc ua_nozip"
|
||||||
ka.update(**{k: None for k in ex.split()})
|
ka.update(**{k: None for k in ex.split()})
|
||||||
|
|
||||||
|
ex = "gid uid"
|
||||||
|
ka.update(**{k: -1 for k in ex.split()})
|
||||||
|
|
||||||
ex = "hash_mt hsortn qdel safe_dedup srch_time tail_fd tail_rate u2abort u2j u2sz"
|
ex = "hash_mt hsortn qdel safe_dedup srch_time tail_fd tail_rate u2abort u2j u2sz"
|
||||||
ka.update(**{k: 1 for k in ex.split()})
|
ka.update(**{k: 1 for k in ex.split()})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue