mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 00:52:16 -06:00
add options to set default chmod (#181)
the unix-permissions of new files/folders can now be changed * global-option --chmod-f, volflag chmod_f for files * global-option --chmod-d, volflag chmod_d for directories the expected value is a standard three-digit octal value (User/Group/Other) such as 755, 750, 644, 640, etc
This commit is contained in:
parent
14fa369fae
commit
9921c43e3a
|
@ -863,6 +863,43 @@ def get_sects():
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"chmod",
|
||||||
|
"file/folder permissions",
|
||||||
|
dedent(
|
||||||
|
"""
|
||||||
|
global-option \033[33m--chmod-f\033[0m and volflag \033[33mchmod_f\033[0m specifies the unix-permission to use when creating a new file
|
||||||
|
|
||||||
|
similarly, \033[33m--chmod-d\033[0m and \033[33mchmod_d\033[0m sets the directory/folder perm
|
||||||
|
|
||||||
|
the value is a three-digit octal number such as 755, 750, 644, etc.
|
||||||
|
|
||||||
|
first digit = "User"; permission for the unix-user
|
||||||
|
second digit = "Group"; permission for the unix-group
|
||||||
|
third digit = "Other"; permission for all other users/groups
|
||||||
|
|
||||||
|
for files:
|
||||||
|
0 = --- = no access
|
||||||
|
1 = --x = can execute the file as a program
|
||||||
|
2 = -w- = can write
|
||||||
|
3 = -wx = can write and execute
|
||||||
|
4 = r-- = can read
|
||||||
|
5 = r-x = can read and execute
|
||||||
|
6 = rw- = can read and write
|
||||||
|
7 = rwx = can read, write, execute
|
||||||
|
|
||||||
|
for directories/folders:
|
||||||
|
0 = --- = no access
|
||||||
|
1 = --x = can read files in folder but not list contents
|
||||||
|
2 = -w- = n/a
|
||||||
|
3 = -wx = can create files but not list
|
||||||
|
4 = r-- = can list, but not read/write
|
||||||
|
5 = r-x = can list and read files
|
||||||
|
6 = rw- = n/a
|
||||||
|
7 = rwx = can read, write, list
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"pwhash",
|
"pwhash",
|
||||||
"password hashing",
|
"password hashing",
|
||||||
|
@ -1013,6 +1050,8 @@ def add_upload(ap):
|
||||||
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")
|
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")
|
||||||
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)")
|
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)")
|
||||||
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-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("--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)")
|
||||||
|
|
|
@ -120,6 +120,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.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
|
||||||
self.bupc: dict[str, int] = {} # byte tracker cache
|
self.bupc: dict[str, int] = {} # byte tracker cache
|
||||||
|
@ -280,7 +282,7 @@ class Lim(object):
|
||||||
if not dirs:
|
if not dirs:
|
||||||
# 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)
|
bos.mkdir(sub, self.chmod_d)
|
||||||
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]))
|
||||||
|
@ -295,7 +297,7 @@ 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)
|
bos.mkdir(sub, self.chmod_d)
|
||||||
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")
|
||||||
|
@ -2074,6 +2076,7 @@ class AuthSrv(object):
|
||||||
|
|
||||||
all_mte = {}
|
all_mte = {}
|
||||||
errors = False
|
errors = False
|
||||||
|
free_umask = False
|
||||||
for vol in vfs.all_nodes.values():
|
for vol in vfs.all_nodes.values():
|
||||||
if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
|
if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
|
||||||
vol.flags["e2ds"] = True
|
vol.flags["e2ds"] = True
|
||||||
|
@ -2130,6 +2133,27 @@ class AuthSrv(object):
|
||||||
t = 'volume "/%s" has invalid %stry [%s]'
|
t = 'volume "/%s" has invalid %stry [%s]'
|
||||||
raise Exception(t % (vol.vpath, k, vol.flags.get(k + "try")))
|
raise Exception(t % (vol.vpath, k, vol.flags.get(k + "try")))
|
||||||
|
|
||||||
|
for k in ("chmod_d", "chmod_f"):
|
||||||
|
is_d = k == "chmod_d"
|
||||||
|
zs = vol.flags.get(k, "")
|
||||||
|
if not zs and is_d:
|
||||||
|
zs = "755"
|
||||||
|
if not zs:
|
||||||
|
vol.flags.pop(k, None)
|
||||||
|
continue
|
||||||
|
if not re.match("^[0-7]{3}$", zs):
|
||||||
|
t = "config-option '%s' must be a three-digit octal value such as [755] or [644] but the value was [%s]"
|
||||||
|
t = t % (k, zs)
|
||||||
|
self.log(t, 1)
|
||||||
|
raise Exception(t)
|
||||||
|
zi = int(zs, 8)
|
||||||
|
vol.flags[k] = zi
|
||||||
|
if (is_d and zi != 0o755) or not is_d:
|
||||||
|
free_umask = True
|
||||||
|
|
||||||
|
if vol.lim:
|
||||||
|
vol.lim.chmod_d = vol.flags["chmod_d"]
|
||||||
|
|
||||||
if vol.flags.get("og"):
|
if vol.flags.get("og"):
|
||||||
self.args.uqe = True
|
self.args.uqe = True
|
||||||
|
|
||||||
|
@ -2359,6 +2383,10 @@ class AuthSrv(object):
|
||||||
if errors:
|
if errors:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
setattr(self.args, "free_umask", free_umask)
|
||||||
|
if free_umask:
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
vfs.bubble_flags()
|
vfs.bubble_flags()
|
||||||
|
|
||||||
have_e2d = False
|
have_e2d = False
|
||||||
|
|
|
@ -25,14 +25,21 @@ def listdir(p: str = ".") -> list[str]:
|
||||||
|
|
||||||
|
|
||||||
def makedirs(name: str, mode: int = 0o755, exist_ok: bool = True) -> bool:
|
def makedirs(name: str, mode: int = 0o755, exist_ok: bool = True) -> bool:
|
||||||
|
# os.makedirs does 777 for all but leaf; this does mode on all
|
||||||
|
todo = []
|
||||||
bname = fsenc(name)
|
bname = fsenc(name)
|
||||||
try:
|
while bname:
|
||||||
os.makedirs(bname, mode)
|
if os.path.isdir(bname):
|
||||||
return True
|
break
|
||||||
except:
|
todo.append(bname)
|
||||||
if not exist_ok or not os.path.isdir(bname):
|
bname = os.path.dirname(bname)
|
||||||
raise
|
if not todo:
|
||||||
|
if not exist_ok:
|
||||||
|
os.mkdir(bname) # to throw
|
||||||
return False
|
return False
|
||||||
|
for zb in todo[::-1]:
|
||||||
|
os.mkdir(zb, mode)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def mkdir(p: str, mode: int = 0o755) -> None:
|
def mkdir(p: str, mode: int = 0o755) -> None:
|
||||||
|
|
|
@ -78,6 +78,8 @@ def vf_vmap() -> dict[str, str]:
|
||||||
}
|
}
|
||||||
for k in (
|
for k in (
|
||||||
"bup_ck",
|
"bup_ck",
|
||||||
|
"chmod_d",
|
||||||
|
"chmod_f",
|
||||||
"dbd",
|
"dbd",
|
||||||
"forget_ip",
|
"forget_ip",
|
||||||
"hsortn",
|
"hsortn",
|
||||||
|
@ -169,6 +171,8 @@ flagcats = {
|
||||||
"safededup": "verify on-disk data before using it for dedup",
|
"safededup": "verify on-disk data before using it for dedup",
|
||||||
"noclone": "take dupe data from clients, even if available on HDD",
|
"noclone": "take dupe data from clients, even if available on HDD",
|
||||||
"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_f=644": "unix-permission for new files",
|
||||||
"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",
|
||||||
|
|
|
@ -229,7 +229,7 @@ class FtpFs(AbstractedFS):
|
||||||
r = "r" in mode
|
r = "r" in mode
|
||||||
w = "w" in mode or "a" in mode or "+" in mode
|
w = "w" in mode or "a" in mode or "+" in mode
|
||||||
|
|
||||||
ap = self.rv2a(filename, r, w)[0]
|
ap, vfs, _ = self.rv2a(filename, r, w)
|
||||||
self.validpath(ap)
|
self.validpath(ap)
|
||||||
if w:
|
if w:
|
||||||
try:
|
try:
|
||||||
|
@ -261,7 +261,11 @@ class FtpFs(AbstractedFS):
|
||||||
|
|
||||||
wunlink(self.log, ap, VF_CAREFUL)
|
wunlink(self.log, ap, VF_CAREFUL)
|
||||||
|
|
||||||
return open(fsenc(ap), mode, self.args.iobuf)
|
ret = open(fsenc(ap), mode, self.args.iobuf)
|
||||||
|
if w and "chmod_f" in vfs.flags:
|
||||||
|
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def chdir(self, path: str) -> None:
|
def chdir(self, path: str) -> None:
|
||||||
nwd = join(self.cwd, path)
|
nwd = join(self.cwd, path)
|
||||||
|
@ -292,8 +296,9 @@ class FtpFs(AbstractedFS):
|
||||||
) = avfs.can_access("", self.h.uname)
|
) = avfs.can_access("", self.h.uname)
|
||||||
|
|
||||||
def mkdir(self, path: str) -> None:
|
def mkdir(self, path: str) -> None:
|
||||||
ap = self.rv2a(path, w=True)[0]
|
ap, vfs, _ = self.rv2a(path, w=True)
|
||||||
bos.makedirs(ap) # filezilla expects this
|
chmod = vfs.flags["chmod_d"]
|
||||||
|
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)
|
||||||
|
|
|
@ -2068,7 +2068,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)
|
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
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]
|
||||||
|
@ -2127,6 +2127,8 @@ class HttpCli(object):
|
||||||
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}
|
||||||
|
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
|
||||||
|
@ -2175,7 +2177,7 @@ class HttpCli(object):
|
||||||
if self.args.nw:
|
if self.args.nw:
|
||||||
fn = os.devnull
|
fn = os.devnull
|
||||||
else:
|
else:
|
||||||
bos.makedirs(fdir)
|
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||||
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)
|
||||||
|
@ -2307,7 +2309,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)
|
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||||
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
|
||||||
|
@ -2593,7 +2595,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)
|
bos.makedirs(dst, vfs.flags["chmod_d"])
|
||||||
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):
|
||||||
|
@ -3028,7 +3030,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)
|
bos.makedirs(fn, vfs.flags["chmod_d"])
|
||||||
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")
|
||||||
|
@ -3070,6 +3072,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:
|
||||||
|
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||||
|
|
||||||
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
||||||
self.redirect(vpath, "?edit")
|
self.redirect(vpath, "?edit")
|
||||||
|
@ -3143,7 +3147,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)
|
bos.makedirs(fdir_base, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
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 ""
|
||||||
|
@ -3238,8 +3242,11 @@ 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)
|
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -3343,7 +3350,7 @@ class HttpCli(object):
|
||||||
if nullwrite:
|
if nullwrite:
|
||||||
fdir = ap2 = ""
|
fdir = ap2 = ""
|
||||||
else:
|
else:
|
||||||
bos.makedirs(fdir)
|
bos.makedirs(fdir, vfs.flags["chmod_d"])
|
||||||
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)
|
||||||
|
@ -3464,6 +3471,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:
|
||||||
|
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||||
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)
|
||||||
|
|
||||||
|
@ -3514,7 +3523,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)
|
bos.makedirs(fp, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
fp = os.path.join(fp, fn)
|
fp = os.path.join(fp, fn)
|
||||||
rem = "{}/{}".format(rp, fn).strip("/")
|
rem = "{}/{}".format(rp, fn).strip("/")
|
||||||
|
@ -3582,13 +3591,15 @@ 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):
|
if bos.makedirs(dp, vfs.flags["chmod_d"]):
|
||||||
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:
|
||||||
|
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||||
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)
|
bos.mkdir(dp, vfs.flags["chmod_d"])
|
||||||
hidedir(dp)
|
hidedir(dp)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -3627,6 +3638,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:
|
||||||
|
os.fchmod(f.fileno(), vfs.flags["chmod_f"])
|
||||||
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)
|
bos.makedirs(ap2, vfs2.flags["chmod_d"])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ class SMB(object):
|
||||||
t = "blocked mkdir (no-write-acc %s): /%s @%s"
|
t = "blocked mkdir (no-write-acc %s): /%s @%s"
|
||||||
yeet(t % (vfs.axs.uwrite, vpath, uname))
|
yeet(t % (vfs.axs.uwrite, vpath, uname))
|
||||||
|
|
||||||
return bos.mkdir(ap)
|
return bos.mkdir(ap, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
def _stat(self, vpath: str, *a: Any, **ka: Any) -> os.stat_result:
|
def _stat(self, vpath: str, *a: Any, **ka: Any) -> os.stat_result:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -27,6 +27,7 @@ if True: # pylint: disable=using-constant-test
|
||||||
|
|
||||||
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
|
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
|
||||||
from .authsrv import BAD_CFG, AuthSrv
|
from .authsrv import BAD_CFG, AuthSrv
|
||||||
|
from .bos import bos
|
||||||
from .cert import ensure_cert
|
from .cert import ensure_cert
|
||||||
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
|
||||||
from .pwhash import HAVE_ARGON2
|
from .pwhash import HAVE_ARGON2
|
||||||
|
@ -1118,7 +1119,7 @@ class SvcHub(object):
|
||||||
|
|
||||||
fn = sel_fn
|
fn = sel_fn
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.dirname(fn))
|
bos.makedirs(os.path.dirname(fn))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1135,6 +1136,9 @@ class SvcHub(object):
|
||||||
|
|
||||||
lh = codecs.open(fn, "w", encoding="utf-8", errors="replace")
|
lh = codecs.open(fn, "w", encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
if getattr(self.args, "free_umask", False):
|
||||||
|
os.fchmod(lh.fileno(), 0o644)
|
||||||
|
|
||||||
argv = [pybin] + self.argv
|
argv = [pybin] + self.argv
|
||||||
if hasattr(shlex, "quote"):
|
if hasattr(shlex, "quote"):
|
||||||
argv = [shlex.quote(x) for x in argv]
|
argv = [shlex.quote(x) for x in argv]
|
||||||
|
|
|
@ -387,14 +387,18 @@ class Tftpd(object):
|
||||||
if not a:
|
if not a:
|
||||||
a = (self.args.iobuf,)
|
a = (self.args.iobuf,)
|
||||||
|
|
||||||
return open(ap, mode, *a, **ka)
|
ret = open(ap, mode, *a, **ka)
|
||||||
|
if wr and "chmod_f" in vfs.flags:
|
||||||
|
os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def _mkdir(self, vpath: str, *a) -> None:
|
def _mkdir(self, vpath: str, *a) -> None:
|
||||||
vfs, _, ap = self._v2a("mkdir", vpath, [False, True])
|
vfs, _, ap = self._v2a("mkdir", vpath, [False, True])
|
||||||
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)
|
return bos.mkdir(ap, vfs.flags["chmod_d"])
|
||||||
|
|
||||||
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,7 +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)
|
||||||
bos.makedirs(os.path.join(thdir, "w"))
|
chmod = 0o700 if self.args.free_umask else 0o755
|
||||||
|
bos.makedirs(os.path.join(thdir, "w"), 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):
|
||||||
|
|
|
@ -915,7 +915,8 @@ class Up2k(object):
|
||||||
# only need to protect register_vpath but all in one go feels right
|
# only need to protect register_vpath but all in one go feels right
|
||||||
for vol in vols:
|
for vol in vols:
|
||||||
try:
|
try:
|
||||||
bos.makedirs(vol.realpath) # gonna happen at snap anyways
|
# mkdir gonna happen at snap anyways;
|
||||||
|
bos.makedirs(vol.realpath, vol.flags["chmod_d"])
|
||||||
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)"
|
||||||
|
@ -1141,6 +1142,20 @@ class Up2k(object):
|
||||||
del fl[k1]
|
del fl[k1]
|
||||||
else:
|
else:
|
||||||
fl[k1] = ",".join(x for x in fl[k1])
|
fl[k1] = ",".join(x for x in fl[k1])
|
||||||
|
|
||||||
|
if fl["chmod_d"] == int(self.args.chmod_d, 8):
|
||||||
|
fl.pop("chmod_d")
|
||||||
|
try:
|
||||||
|
if fl["chmod_f"] == int(self.args.chmod_f or "-1", 8):
|
||||||
|
fl.pop("chmod_f")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
for k in ("chmod_f", "chmod_d"):
|
||||||
|
try:
|
||||||
|
fl[k] = "%o" % (fl[k])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
a = [
|
a = [
|
||||||
(ft if v is True else ff if v is False else fv).format(k, str(v))
|
(ft if v is True else ff if v is False else fv).format(k, str(v))
|
||||||
for k, v in fl.items()
|
for k, v in fl.items()
|
||||||
|
@ -3290,7 +3305,7 @@ class Up2k(object):
|
||||||
reg,
|
reg,
|
||||||
"up2k._get_volsize",
|
"up2k._get_volsize",
|
||||||
)
|
)
|
||||||
bos.makedirs(ap2)
|
bos.makedirs(ap2, vfs.flags["chmod_d"])
|
||||||
vfs.lim.nup(cj["addr"])
|
vfs.lim.nup(cj["addr"])
|
||||||
vfs.lim.bup(cj["addr"], cj["size"])
|
vfs.lim.bup(cj["addr"], cj["size"])
|
||||||
|
|
||||||
|
@ -3397,11 +3412,11 @@ class Up2k(object):
|
||||||
self.log(t % (mts - mtc, mts, mtc, fp))
|
self.log(t % (mts - mtc, mts, mtc, fp))
|
||||||
ow = False
|
ow = False
|
||||||
|
|
||||||
|
ptop = job["ptop"]
|
||||||
|
vf = self.flags.get(ptop) or {}
|
||||||
if ow:
|
if ow:
|
||||||
self.log("replacing existing file at %r" % (fp,))
|
self.log("replacing existing file at %r" % (fp,))
|
||||||
cur = None
|
cur = None
|
||||||
ptop = job["ptop"]
|
|
||||||
vf = self.flags.get(ptop) or {}
|
|
||||||
st = bos.stat(fp)
|
st = bos.stat(fp)
|
||||||
try:
|
try:
|
||||||
vrel = vjoin(job["prel"], fname)
|
vrel = vjoin(job["prel"], fname)
|
||||||
|
@ -3421,8 +3436,13 @@ class Up2k(object):
|
||||||
else:
|
else:
|
||||||
dip = self.hub.iphash.s(ip)
|
dip = self.hub.iphash.s(ip)
|
||||||
|
|
||||||
suffix = "-%.6f-%s" % (ts, dip)
|
f, ret = ren_open(
|
||||||
f, ret = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
|
fname,
|
||||||
|
"wb",
|
||||||
|
fdir=fdir,
|
||||||
|
suffix="-%.6f-%s" % (ts, dip),
|
||||||
|
chmod=vf.get("chmod_f", -1),
|
||||||
|
)
|
||||||
f.close()
|
f.close()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -4277,7 +4297,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))
|
bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
|
||||||
|
|
||||||
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
|
||||||
|
@ -4453,7 +4473,7 @@ 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))
|
bos.mkdir(dvn.canonical(drem), dvn.flags["chmod_d"])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -4523,7 +4543,7 @@ class Up2k(object):
|
||||||
|
|
||||||
is_xvol = svn.realpath != dvn.realpath
|
is_xvol = svn.realpath != dvn.realpath
|
||||||
|
|
||||||
bos.makedirs(os.path.dirname(dabs))
|
bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
|
||||||
|
|
||||||
if is_dirlink:
|
if is_dirlink:
|
||||||
dlabs = absreal(sabs)
|
dlabs = absreal(sabs)
|
||||||
|
@ -5030,8 +5050,13 @@ class Up2k(object):
|
||||||
else:
|
else:
|
||||||
dip = self.hub.iphash.s(job["addr"])
|
dip = self.hub.iphash.s(job["addr"])
|
||||||
|
|
||||||
suffix = "-%.6f-%s" % (job["t0"], dip)
|
f, job["tnam"] = ren_open(
|
||||||
f, job["tnam"] = ren_open(tnam, "wb", fdir=pdir, suffix=suffix)
|
tnam,
|
||||||
|
"wb",
|
||||||
|
fdir=pdir,
|
||||||
|
suffix="-%.6f-%s" % (job["t0"], dip),
|
||||||
|
chmod=vf.get("chmod_f", -1),
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
abspath = djoin(pdir, job["tnam"])
|
abspath = djoin(pdir, job["tnam"])
|
||||||
sprs = job["sprs"]
|
sprs = job["sprs"]
|
||||||
|
|
|
@ -1585,6 +1585,7 @@ 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)
|
||||||
|
|
||||||
if fname == os.devnull:
|
if fname == os.devnull:
|
||||||
return fun(fname, *args, **kwargs), fname
|
return fun(fname, *args, **kwargs), fname
|
||||||
|
@ -1628,6 +1629,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:
|
||||||
|
os.fchmod(f2.fileno(), chmod)
|
||||||
|
|
||||||
|
if chmod >= 0:
|
||||||
|
os.fchmod(f.fileno(), chmod)
|
||||||
|
|
||||||
return f, fname
|
return f, fname
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import subprocess as sp
|
||||||
|
|
||||||
# to convert the copyparty --help to html, run this in xfce4-terminal @ 140x43:
|
# to convert the copyparty --help to html, run this in xfce4-terminal @ 140x43:
|
||||||
_ = r""""
|
_ = r""""
|
||||||
echo; for a in '' -bind -accounts -flags -handlers -hooks -urlform -exp -ls -dbd -pwhash -zm; do
|
echo; for a in '' -bind -accounts -flags -handlers -hooks -urlform -exp -ls -dbd -chmod -pwhash -zm; do
|
||||||
./copyparty-sfx.py --help$a 2>/dev/null; printf '\n\n\n%0139d\n\n\n'; done # xfce4-terminal @ 140x43
|
./copyparty-sfx.py --help$a 2>/dev/null; printf '\n\n\n%0139d\n\n\n'; done # xfce4-terminal @ 140x43
|
||||||
"""
|
"""
|
||||||
# click [edit] => [select all]
|
# click [edit] => [select all]
|
||||||
|
|
|
@ -23,7 +23,7 @@ exit 0
|
||||||
|
|
||||||
|
|
||||||
# first open an infinitely wide console (this is why you own an ultrawide) and copypaste this into it:
|
# first open an infinitely wide console (this is why you own an ultrawide) and copypaste this into it:
|
||||||
for a in '' -bind -accounts -flags -handlers -hooks -urlform -exp -ls -dbd -pwhash -zm; do
|
for a in '' -bind -accounts -flags -handlers -hooks -urlform -exp -ls -dbd -chmod -pwhash -zm; do
|
||||||
./copyparty-sfx.py --help$a 2>/dev/null; printf '\n\n\n%0255d\n\n\n'; done
|
./copyparty-sfx.py --help$a 2>/dev/null; printf '\n\n\n%0255d\n\n\n'; done
|
||||||
|
|
||||||
# then copypaste all of the output by pressing ctrl-shift-a, ctrl-shift-c
|
# then copypaste all of the output by pressing ctrl-shift-a, ctrl-shift-c
|
||||||
|
|
|
@ -161,7 +161,7 @@ class Cfg(Namespace):
|
||||||
ex = "db_act forget_ip idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
ex = "db_act forget_ip idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
||||||
ka.update(**{k: 0 for k in ex.split()})
|
ka.update(**{k: 0 for k in ex.split()})
|
||||||
|
|
||||||
ex = "ah_alg bname chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR"
|
ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR"
|
||||||
ka.update(**{k: "" for k in ex.split()})
|
ka.update(**{k: "" for k in ex.split()})
|
||||||
|
|
||||||
ex = "ban_403 ban_404 ban_422 ban_pw ban_url spinner"
|
ex = "ban_403 ban_404 ban_422 ban_pw ban_url spinner"
|
||||||
|
@ -181,6 +181,7 @@ class Cfg(Namespace):
|
||||||
c=c,
|
c=c,
|
||||||
E=E,
|
E=E,
|
||||||
bup_ck="sha512",
|
bup_ck="sha512",
|
||||||
|
chmod_d="755",
|
||||||
dbd="wal",
|
dbd="wal",
|
||||||
dk_salt="b" * 16,
|
dk_salt="b" * 16,
|
||||||
fk_salt="a" * 16,
|
fk_salt="a" * 16,
|
||||||
|
|
Loading…
Reference in a new issue