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
|
||||
* [upload rules](#upload-rules) - set upload rules using volflags
|
||||
* [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)
|
||||
* [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
|
||||
|
@ -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`
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
* `: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("--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("--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("--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)")
|
||||
|
|
|
@ -140,6 +140,8 @@ class Lim(object):
|
|||
self.reg: Optional[dict[str, dict[str, Any]]] = None # up2k registry
|
||||
|
||||
self.chmod_d = 0o755
|
||||
self.uid = self.gid = -1
|
||||
self.chown = False
|
||||
|
||||
self.nups: dict[str, list[float]] = {} # num tracker
|
||||
self.bups: dict[str, list[tuple[float, int]]] = {} # byte tracker list
|
||||
|
@ -302,6 +304,8 @@ class Lim(object):
|
|||
# no branches yet; make one
|
||||
sub = os.path.join(path, "0")
|
||||
bos.mkdir(sub, self.chmod_d)
|
||||
if self.chown:
|
||||
os.chown(sub, self.uid, self.gid)
|
||||
else:
|
||||
# try newest branch only
|
||||
sub = os.path.join(path, str(dirs[-1]))
|
||||
|
@ -317,6 +321,8 @@ class Lim(object):
|
|||
# make a branch
|
||||
sub = os.path.join(path, str(dirs[-1] + 1))
|
||||
bos.mkdir(sub, self.chmod_d)
|
||||
if self.chown:
|
||||
os.chown(sub, self.uid, self.gid)
|
||||
ret = self.dive(sub, lvs - 1)
|
||||
if ret is None:
|
||||
raise Pebkac(500, "rotation bug")
|
||||
|
@ -2181,7 +2187,7 @@ class AuthSrv(object):
|
|||
if vf not in vol.flags:
|
||||
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():
|
||||
if k in vol.flags:
|
||||
vol.flags[k] = int(vol.flags[k])
|
||||
|
@ -2218,8 +2224,17 @@ class AuthSrv(object):
|
|||
if (is_d and zi != 0o755) or not is_d:
|
||||
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:
|
||||
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"):
|
||||
self.args.uqe = True
|
||||
|
|
|
@ -9,8 +9,11 @@ from . import path as path
|
|||
if True: # pylint: disable=using-constant-test
|
||||
from typing import Any, Optional
|
||||
|
||||
_ = (path,)
|
||||
__all__ = ["path"]
|
||||
MKD_755 = {"chmod_d": 0o755}
|
||||
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
|
||||
# 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)
|
||||
|
||||
|
||||
def chown(p: str, uid: int, gid: int) -> None:
|
||||
return os.chown(fsenc(p), uid, gid)
|
||||
|
||||
|
||||
def listdir(p: str = ".") -> list[str]:
|
||||
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
|
||||
todo = []
|
||||
bname = fsenc(name)
|
||||
|
@ -37,9 +44,13 @@ def makedirs(name: str, mode: int = 0o755, exist_ok: bool = True) -> bool:
|
|||
if not exist_ok:
|
||||
os.mkdir(bname) # to throw
|
||||
return False
|
||||
mode = vf["chmod_d"]
|
||||
chown = "chown" in vf
|
||||
for zb in todo[::-1]:
|
||||
try:
|
||||
os.mkdir(zb, mode)
|
||||
if chown:
|
||||
os.chown(zb, vf["uid"], vf["gid"])
|
||||
except:
|
||||
if os.path.isdir(zb):
|
||||
continue
|
||||
|
|
|
@ -114,6 +114,8 @@ def vf_vmap() -> dict[str, str]:
|
|||
"unlist",
|
||||
"u2abort",
|
||||
"u2ts",
|
||||
"uid",
|
||||
"gid",
|
||||
"ups_who",
|
||||
"zip_who",
|
||||
"zipmaxn",
|
||||
|
@ -175,6 +177,8 @@ flagcats = {
|
|||
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
||||
"chmod_d=755": "unix-permission for new dirs/folders",
|
||||
"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",
|
||||
"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",
|
||||
|
|
|
@ -31,6 +31,7 @@ from .util import (
|
|||
relchk,
|
||||
runhook,
|
||||
sanitize_fn,
|
||||
set_fperms,
|
||||
vjoin,
|
||||
wunlink,
|
||||
)
|
||||
|
@ -262,8 +263,8 @@ class FtpFs(AbstractedFS):
|
|||
wunlink(self.log, ap, VF_CAREFUL)
|
||||
|
||||
ret = open(fsenc(ap), mode, self.args.iobuf)
|
||||
if w and "chmod_f" in vfs.flags:
|
||||
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
||||
if w and "fperms" in vfs.flags:
|
||||
set_fperms(ret, vfs.flags)
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -297,8 +298,7 @@ class FtpFs(AbstractedFS):
|
|||
|
||||
def mkdir(self, path: str) -> None:
|
||||
ap, vfs, _ = self.rv2a(path, w=True)
|
||||
chmod = vfs.flags["chmod_d"]
|
||||
bos.makedirs(ap, chmod) # filezilla expects this
|
||||
bos.makedirs(ap, vf=vfs.flags) # filezilla expects this
|
||||
|
||||
def listdir(self, path: str) -> list[str]:
|
||||
vpath = join(self.cwd, path)
|
||||
|
|
|
@ -103,6 +103,7 @@ from .util import (
|
|||
sanitize_vpath,
|
||||
sendfile_kern,
|
||||
sendfile_py,
|
||||
set_fperms,
|
||||
stat_resource,
|
||||
ub64dec,
|
||||
ub64enc,
|
||||
|
@ -2086,7 +2087,7 @@ class HttpCli(object):
|
|||
fdir, fn = os.path.split(fdir)
|
||||
rem, _ = vsplit(rem)
|
||||
|
||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||
bos.makedirs(fdir, vf=vfs.flags)
|
||||
|
||||
open_ka: dict[str, Any] = {"fun": open}
|
||||
open_a = ["wb", self.args.iobuf]
|
||||
|
@ -2144,9 +2145,7 @@ class HttpCli(object):
|
|||
if nameless:
|
||||
fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
|
||||
|
||||
params = {"suffix": suffix, "fdir": fdir}
|
||||
if "chmod_f" in vfs.flags:
|
||||
params["chmod"] = vfs.flags["chmod_f"]
|
||||
params = {"suffix": suffix, "fdir": fdir, "vf": vfs.flags}
|
||||
if self.args.nw:
|
||||
params = {}
|
||||
fn = os.devnull
|
||||
|
@ -2195,7 +2194,7 @@ class HttpCli(object):
|
|||
if self.args.nw:
|
||||
fn = os.devnull
|
||||
else:
|
||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||
bos.makedirs(fdir, vf=vfs.flags)
|
||||
path = os.path.join(fdir, fn)
|
||||
if not nameless:
|
||||
self.vpath = vjoin(self.vpath, fn)
|
||||
|
@ -2327,7 +2326,7 @@ class HttpCli(object):
|
|||
if self.args.hook_v:
|
||||
log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
|
||||
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)
|
||||
atomic_move(self.log, path, path2, vfs.flags)
|
||||
path = path2
|
||||
|
@ -2613,7 +2612,7 @@ class HttpCli(object):
|
|||
dst = vfs.canonical(rem)
|
||||
try:
|
||||
if not bos.path.isdir(dst):
|
||||
bos.makedirs(dst, vfs.flags["chmod_d"])
|
||||
bos.makedirs(dst, vf=vfs.flags)
|
||||
except OSError as ex:
|
||||
self.log("makedirs failed %r" % (dst,))
|
||||
if not bos.path.isdir(dst):
|
||||
|
@ -3060,7 +3059,7 @@ class HttpCli(object):
|
|||
raise Pebkac(405, 'folder "/%s" already exists' % (vpath,))
|
||||
|
||||
try:
|
||||
bos.makedirs(fn, vfs.flags["chmod_d"])
|
||||
bos.makedirs(fn, vf=vfs.flags)
|
||||
except OSError as ex:
|
||||
if ex.errno == errno.EACCES:
|
||||
raise Pebkac(500, "the server OS denied write-access")
|
||||
|
@ -3102,8 +3101,8 @@ class HttpCli(object):
|
|||
|
||||
with open(fsenc(fn), "wb") as f:
|
||||
f.write(b"`GRUNNUR`\n")
|
||||
if "chmod_f" in vfs.flags:
|
||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||
if "fperms" in vfs.flags:
|
||||
set_fperms(f, vfs.flags)
|
||||
|
||||
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
||||
self.redirect(vpath, "?edit")
|
||||
|
@ -3177,7 +3176,7 @@ class HttpCli(object):
|
|||
)
|
||||
upload_vpath = "{}/{}".format(vfs.vpath, rem).strip("/")
|
||||
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)
|
||||
zs = self.uparam.get("want") or self.headers.get("accept") or ""
|
||||
|
@ -3210,7 +3209,7 @@ class HttpCli(object):
|
|||
if 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 not self.can_delete:
|
||||
|
@ -3272,11 +3271,8 @@ class HttpCli(object):
|
|||
else:
|
||||
open_args["fdir"] = fdir
|
||||
|
||||
if "chmod_f" in vfs.flags:
|
||||
open_args["chmod"] = vfs.flags["chmod_f"]
|
||||
|
||||
if p_file and not nullwrite:
|
||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||
bos.makedirs(fdir, vf=vfs.flags)
|
||||
|
||||
# reserve destination filename
|
||||
f, fname = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
|
||||
|
@ -3380,7 +3376,7 @@ class HttpCli(object):
|
|||
if nullwrite:
|
||||
fdir = ap2 = ""
|
||||
else:
|
||||
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||
bos.makedirs(fdir, vf=vfs.flags)
|
||||
atomic_move(self.log, abspath, ap2, vfs.flags)
|
||||
abspath = ap2
|
||||
sz = bos.path.getsize(abspath)
|
||||
|
@ -3501,8 +3497,8 @@ class HttpCli(object):
|
|||
ft = "{}:{}".format(self.ip, self.addr[1])
|
||||
ft = "{}\n{}\n{}\n".format(ft, msg.rstrip(), errmsg)
|
||||
f.write(ft.encode("utf-8"))
|
||||
if "chmod_f" in vfs.flags:
|
||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||
if "fperms" in vfs.flags:
|
||||
set_fperms(f, vfs.flags)
|
||||
except Exception as ex:
|
||||
suf = "\nfailed to write the upload report: {}".format(ex)
|
||||
|
||||
|
@ -3553,7 +3549,7 @@ class HttpCli(object):
|
|||
lim = vfs.get_dbv(rem)[0].lim
|
||||
if lim:
|
||||
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)
|
||||
rem = "{}/{}".format(rp, fn).strip("/")
|
||||
|
@ -3621,15 +3617,17 @@ class HttpCli(object):
|
|||
zs = ub64enc(zb).decode("ascii")[:24].lower()
|
||||
dp = "%s/md/%s/%s/%s" % (dbv.histpath, zs[:2], zs[2:4], zs)
|
||||
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:
|
||||
f.write(afsenc(vrd))
|
||||
if "chmod_f" in vfs.flags:
|
||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||
if "fperms" in vfs.flags:
|
||||
set_fperms(f, vfs.flags)
|
||||
elif hist_cfg == "s":
|
||||
dp = os.path.join(mdir, ".hist")
|
||||
try:
|
||||
bos.mkdir(dp, vfs.flags["chmod_d"])
|
||||
if "chown" in vfs.flags:
|
||||
bos.chown(dp, vfs.flags["uid"], vfs.flags["gid"])
|
||||
hidedir(dp)
|
||||
except:
|
||||
pass
|
||||
|
@ -3668,8 +3666,8 @@ class HttpCli(object):
|
|||
wunlink(self.log, fp, vfs.flags)
|
||||
|
||||
with open(fsenc(fp), "wb", self.args.iobuf) as f:
|
||||
if "chmod_f" in vfs.flags:
|
||||
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||
if "fperms" in vfs.flags:
|
||||
set_fperms(f, vfs.flags)
|
||||
sz, sha512, _ = hashcopy(p_data, f, None, 0, self.args.s_wr_slp)
|
||||
|
||||
if lim:
|
||||
|
|
|
@ -320,7 +320,7 @@ class SMB(object):
|
|||
|
||||
self.hub.up2k.handle_mv(uname, "1.7.6.2", vp1, vp2)
|
||||
try:
|
||||
bos.makedirs(ap2, vfs2.flags["chmod_d"])
|
||||
bos.makedirs(ap2, vf=vfs2.flags)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ from .util import (
|
|||
exclude_dotfiles,
|
||||
min_ex,
|
||||
runhook,
|
||||
set_fperms,
|
||||
undot,
|
||||
vjoin,
|
||||
vsplit,
|
||||
|
@ -388,8 +389,8 @@ class Tftpd(object):
|
|||
a = (self.args.iobuf,)
|
||||
|
||||
ret = open(ap, mode, *a, **ka)
|
||||
if wr and "chmod_f" in vfs.flags:
|
||||
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
||||
if wr and "fperms" in vfs.flags:
|
||||
set_fperms(ret, vfs.flags)
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -398,7 +399,9 @@ class Tftpd(object):
|
|||
if "*" not in vfs.axs.uwrite:
|
||||
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:
|
||||
# return bos.unlink(self._v2a("stat", vpath, *a)[1])
|
||||
|
|
|
@ -269,8 +269,8 @@ class ThumbSrv(object):
|
|||
self.log("joined waiting room for %r" % (tpath,))
|
||||
except:
|
||||
thdir = os.path.dirname(tpath)
|
||||
chmod = 0o700 if self.args.free_umask else 0o755
|
||||
bos.makedirs(os.path.join(thdir, "w"), chmod)
|
||||
chmod = bos.MKD_700 if self.args.free_umask else bos.MKD_755
|
||||
bos.makedirs(os.path.join(thdir, "w"), vf=chmod)
|
||||
|
||||
inf_path = os.path.join(thdir, "dir.txt")
|
||||
if not bos.path.exists(inf_path):
|
||||
|
|
|
@ -916,7 +916,7 @@ class Up2k(object):
|
|||
for vol in vols:
|
||||
try:
|
||||
# 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)
|
||||
except Exception as ex:
|
||||
self.volstate[vol.vpath] = "OFFLINE (cannot access folder)"
|
||||
|
@ -3309,7 +3309,7 @@ class Up2k(object):
|
|||
reg,
|
||||
"up2k._get_volsize",
|
||||
)
|
||||
bos.makedirs(ap2, vfs.flags["chmod_d"])
|
||||
bos.makedirs(ap2, vf=vfs.flags)
|
||||
vfs.lim.nup(cj["addr"])
|
||||
vfs.lim.bup(cj["addr"], cj["size"])
|
||||
|
||||
|
@ -3445,7 +3445,7 @@ class Up2k(object):
|
|||
"wb",
|
||||
fdir=fdir,
|
||||
suffix="-%.6f-%s" % (ts, dip),
|
||||
chmod=vf.get("chmod_f", -1),
|
||||
vf=vf,
|
||||
)
|
||||
f.close()
|
||||
return ret
|
||||
|
@ -4304,7 +4304,7 @@ class Up2k(object):
|
|||
self.log(t, 1)
|
||||
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(
|
||||
svn_dbv.realpath, srem_dbv
|
||||
|
@ -4480,7 +4480,10 @@ class Up2k(object):
|
|||
vp = vjoin(dvp, rem)
|
||||
try:
|
||||
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:
|
||||
pass
|
||||
|
||||
|
@ -4550,7 +4553,7 @@ class Up2k(object):
|
|||
|
||||
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:
|
||||
dlabs = absreal(sabs)
|
||||
|
@ -5062,7 +5065,7 @@ class Up2k(object):
|
|||
"wb",
|
||||
fdir=pdir,
|
||||
suffix="-%.6f-%s" % (job["t0"], dip),
|
||||
chmod=vf.get("chmod_f", -1),
|
||||
vf=vf,
|
||||
)
|
||||
try:
|
||||
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)
|
||||
fdir = kwargs.pop("fdir", 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:
|
||||
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)
|
||||
with open(fsenc(fp2), "wb") as f2:
|
||||
f2.write(orig_name.encode("utf-8"))
|
||||
if chmod >= 0:
|
||||
os.fchmod(f2.fileno(), chmod)
|
||||
if fperms:
|
||||
set_fperms(f2, vf)
|
||||
|
||||
if chmod >= 0:
|
||||
os.fchmod(f.fileno(), chmod)
|
||||
if fperms:
|
||||
set_fperms(f, vf)
|
||||
|
||||
return f, fname
|
||||
|
||||
|
@ -2565,6 +2566,14 @@ def lsof(log: "NamedLogger", abspath: str) -> None:
|
|||
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(
|
||||
log: "NamedLogger", src: str, dst: str, atomic: bool, flags: dict[str, Any]
|
||||
) -> 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"
|
||||
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"
|
||||
ka.update(**{k: 1 for k in ex.split()})
|
||||
|
||||
|
|
Loading…
Reference in a new issue