copyparty 1.18.5__py3-none-any.whl → 1.18.7__py3-none-any.whl

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/httpcli.py CHANGED
@@ -33,7 +33,7 @@ except:
33
33
 
34
34
  from .__init__ import ANYWIN, PY2, RES, TYPE_CHECKING, EnvParams, unicode
35
35
  from .__version__ import S_VERSION
36
- from .authsrv import VFS # typechk
36
+ from .authsrv import LEELOO_DALLAS, VFS # typechk
37
37
  from .bos import bos
38
38
  from .star import StreamTar
39
39
  from .stolen.qrcodegen import QrCode, qr2svg
@@ -79,8 +79,10 @@ from .util import (
79
79
  hidedir,
80
80
  html_bescape,
81
81
  html_escape,
82
+ html_sh_esc,
82
83
  humansize,
83
84
  ipnorm,
85
+ json_hesc,
84
86
  justcopy,
85
87
  load_resource,
86
88
  loadpy,
@@ -103,6 +105,7 @@ from .util import (
103
105
  sanitize_vpath,
104
106
  sendfile_kern,
105
107
  sendfile_py,
108
+ set_fperms,
106
109
  stat_resource,
107
110
  ub64dec,
108
111
  ub64enc,
@@ -617,6 +620,9 @@ class HttpCli(object):
617
620
  ) or self.args.idp_h_key in self.headers
618
621
 
619
622
  if trusted_key and trusted_xff:
623
+ if idp_usr.lower() == LEELOO_DALLAS:
624
+ self.loud_reply("send her back", status=403)
625
+ return False
620
626
  self.asrv.idp_checkin(self.conn.hsrv.broker, idp_usr, idp_grp)
621
627
  else:
622
628
  if not trusted_key:
@@ -1105,15 +1111,18 @@ class HttpCli(object):
1105
1111
  else:
1106
1112
  return True
1107
1113
 
1114
+ host = self.host.lower()
1115
+ if host.startswith("["):
1116
+ if "]:" in host:
1117
+ host = host.split("]:")[0] + "]"
1118
+ else:
1119
+ host = host.split(":")[0]
1120
+
1108
1121
  oh = self.out_headers
1109
1122
  origin = origin.lower()
1110
- good_origins = self.args.acao + [
1111
- "%s://%s"
1112
- % (
1113
- "https" if self.is_https else "http",
1114
- self.host.lower().split(":")[0],
1115
- )
1116
- ]
1123
+ proto = "https" if self.is_https else "http"
1124
+ good_origins = self.args.acao + ["%s://%s" % (proto, host)]
1125
+
1117
1126
  if "pw" in ih or re.sub(r"(:[0-9]{1,5})?/?$", "", origin) in good_origins:
1118
1127
  good_origin = True
1119
1128
  bad_hdrs = ("",)
@@ -1570,6 +1579,18 @@ class HttpCli(object):
1570
1579
  self.log("inaccessible: %r" % ("/" + self.vpath,))
1571
1580
  raise Pebkac(401, "authenticate")
1572
1581
 
1582
+ if "quota-available-bytes" in props and not self.args.nid:
1583
+ bfree, btot, _ = get_df(vn.realpath, False)
1584
+ if btot:
1585
+ df = {
1586
+ "quota-available-bytes": str(bfree),
1587
+ "quota-used-bytes": str(btot - bfree),
1588
+ }
1589
+ else:
1590
+ df = {}
1591
+ else:
1592
+ df = {}
1593
+
1573
1594
  fgen = itertools.chain([topdir], fgen)
1574
1595
  vtop = vjoin(self.args.R, vjoin(vn.vpath, rem))
1575
1596
 
@@ -1612,6 +1633,9 @@ class HttpCli(object):
1612
1633
  ap = os.path.join(tap, x["vp"])
1613
1634
  pvs["getcontenttype"] = html_escape(guess_mime(rp, ap))
1614
1635
  pvs["getcontentlength"] = str(st.st_size)
1636
+ elif df:
1637
+ pvs.update(df)
1638
+ df = {}
1615
1639
 
1616
1640
  for k, v in pvs.items():
1617
1641
  if k not in props:
@@ -2060,7 +2084,7 @@ class HttpCli(object):
2060
2084
  fdir, fn = os.path.split(fdir)
2061
2085
  rem, _ = vsplit(rem)
2062
2086
 
2063
- bos.makedirs(fdir, vfs.flags["chmod_d"])
2087
+ bos.makedirs(fdir, vf=vfs.flags)
2064
2088
 
2065
2089
  open_ka = {"fun": open}
2066
2090
  open_a = ["wb", self.args.iobuf]
@@ -2117,9 +2141,7 @@ class HttpCli(object):
2117
2141
  if nameless:
2118
2142
  fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
2119
2143
 
2120
- params = {"suffix": suffix, "fdir": fdir}
2121
- if "chmod_f" in vfs.flags:
2122
- params["chmod"] = vfs.flags["chmod_f"]
2144
+ params = {"suffix": suffix, "fdir": fdir, "vf": vfs.flags}
2123
2145
  if self.args.nw:
2124
2146
  params = {}
2125
2147
  fn = os.devnull
@@ -2167,7 +2189,7 @@ class HttpCli(object):
2167
2189
  if self.args.nw:
2168
2190
  fn = os.devnull
2169
2191
  else:
2170
- bos.makedirs(fdir, vfs.flags["chmod_d"])
2192
+ bos.makedirs(fdir, vf=vfs.flags)
2171
2193
  path = os.path.join(fdir, fn)
2172
2194
  if not nameless:
2173
2195
  self.vpath = vjoin(self.vpath, fn)
@@ -2299,7 +2321,7 @@ class HttpCli(object):
2299
2321
  if self.args.hook_v:
2300
2322
  log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
2301
2323
  fdir, self.vpath, fn, (vfs, rem) = x
2302
- bos.makedirs(fdir, vfs.flags["chmod_d"])
2324
+ bos.makedirs(fdir, vf=vfs.flags)
2303
2325
  path2 = os.path.join(fdir, fn)
2304
2326
  atomic_move(self.log, path, path2, vfs.flags)
2305
2327
  path = path2
@@ -2584,7 +2606,7 @@ class HttpCli(object):
2584
2606
  dst = vfs.canonical(rem)
2585
2607
  try:
2586
2608
  if not bos.path.isdir(dst):
2587
- bos.makedirs(dst, vfs.flags["chmod_d"])
2609
+ bos.makedirs(dst, vf=vfs.flags)
2588
2610
  except OSError as ex:
2589
2611
  self.log("makedirs failed %r" % (dst,))
2590
2612
  if not bos.path.isdir(dst):
@@ -2900,6 +2922,7 @@ class HttpCli(object):
2900
2922
 
2901
2923
  ok, msg = self.asrv.chpw(self.conn.hsrv.broker, self.uname, pwd)
2902
2924
  if ok:
2925
+ self.cbonk(self.conn.hsrv.gpwc, pwd, "pw", "too many password changes")
2903
2926
  ok, msg = self.get_pwd_cookie(pwd)
2904
2927
  if ok:
2905
2928
  msg = "new password OK"
@@ -3010,6 +3033,9 @@ class HttpCli(object):
3010
3033
  self.gctx = vpath
3011
3034
  vpath = undot(vpath)
3012
3035
  vfs, rem = self.asrv.vfs.get(vpath, self.uname, False, True)
3036
+ if "nosub" in vfs.flags:
3037
+ raise Pebkac(403, "mkdir is forbidden below this folder")
3038
+
3013
3039
  rem = sanitize_vpath(rem, "/")
3014
3040
  fn = vfs.canonical(rem)
3015
3041
 
@@ -3023,7 +3049,7 @@ class HttpCli(object):
3023
3049
  raise Pebkac(405, 'folder "/%s" already exists' % (vpath,))
3024
3050
 
3025
3051
  try:
3026
- bos.makedirs(fn, vfs.flags["chmod_d"])
3052
+ bos.makedirs(fn, vf=vfs.flags)
3027
3053
  except OSError as ex:
3028
3054
  if ex.errno == errno.EACCES:
3029
3055
  raise Pebkac(500, "the server OS denied write-access")
@@ -3064,8 +3090,8 @@ class HttpCli(object):
3064
3090
 
3065
3091
  with open(fsenc(fn), "wb") as f:
3066
3092
  f.write(b"`GRUNNUR`\n")
3067
- if "chmod_f" in vfs.flags:
3068
- os.fchmod(f.fileno(), vfs.flags["chmod_f"])
3093
+ if "fperms" in vfs.flags:
3094
+ set_fperms(f, vfs.flags)
3069
3095
 
3070
3096
  vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
3071
3097
  self.redirect(vpath, "?edit")
@@ -3139,7 +3165,7 @@ class HttpCli(object):
3139
3165
  )
3140
3166
  upload_vpath = "{}/{}".format(vfs.vpath, rem).strip("/")
3141
3167
  if not nullwrite:
3142
- bos.makedirs(fdir_base, vfs.flags["chmod_d"])
3168
+ bos.makedirs(fdir_base, vf=vfs.flags)
3143
3169
 
3144
3170
  rnd, lifetime, xbu, xau = self.upload_flags(vfs)
3145
3171
  zs = self.uparam.get("want") or self.headers.get("accept") or ""
@@ -3172,7 +3198,7 @@ class HttpCli(object):
3172
3198
  if rnd:
3173
3199
  fname = rand_name(fdir, fname, rnd)
3174
3200
 
3175
- open_args = {"fdir": fdir, "suffix": suffix}
3201
+ open_args = {"fdir": fdir, "suffix": suffix, "vf": vfs.flags}
3176
3202
 
3177
3203
  if "replace" in self.uparam:
3178
3204
  if not self.can_delete:
@@ -3234,11 +3260,8 @@ class HttpCli(object):
3234
3260
  else:
3235
3261
  open_args["fdir"] = fdir
3236
3262
 
3237
- if "chmod_f" in vfs.flags:
3238
- open_args["chmod"] = vfs.flags["chmod_f"]
3239
-
3240
3263
  if p_file and not nullwrite:
3241
- bos.makedirs(fdir, vfs.flags["chmod_d"])
3264
+ bos.makedirs(fdir, vf=vfs.flags)
3242
3265
 
3243
3266
  # reserve destination filename
3244
3267
  f, fname = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
@@ -3342,7 +3365,7 @@ class HttpCli(object):
3342
3365
  if nullwrite:
3343
3366
  fdir = ap2 = ""
3344
3367
  else:
3345
- bos.makedirs(fdir, vfs.flags["chmod_d"])
3368
+ bos.makedirs(fdir, vf=vfs.flags)
3346
3369
  atomic_move(self.log, abspath, ap2, vfs.flags)
3347
3370
  abspath = ap2
3348
3371
  sz = bos.path.getsize(abspath)
@@ -3463,8 +3486,8 @@ class HttpCli(object):
3463
3486
  ft = "{}:{}".format(self.ip, self.addr[1])
3464
3487
  ft = "{}\n{}\n{}\n".format(ft, msg.rstrip(), errmsg)
3465
3488
  f.write(ft.encode("utf-8"))
3466
- if "chmod_f" in vfs.flags:
3467
- os.fchmod(f.fileno(), vfs.flags["chmod_f"])
3489
+ if "fperms" in vfs.flags:
3490
+ set_fperms(f, vfs.flags)
3468
3491
  except Exception as ex:
3469
3492
  suf = "\nfailed to write the upload report: {}".format(ex)
3470
3493
 
@@ -3514,7 +3537,7 @@ class HttpCli(object):
3514
3537
  lim = vfs.get_dbv(rem)[0].lim
3515
3538
  if lim:
3516
3539
  fp, rp = lim.all(self.ip, rp, clen, vfs.realpath, fp, self.conn.hsrv.broker)
3517
- bos.makedirs(fp, vfs.flags["chmod_d"])
3540
+ bos.makedirs(fp, vf=vfs.flags)
3518
3541
 
3519
3542
  fp = os.path.join(fp, fn)
3520
3543
  rem = "{}/{}".format(rp, fn).strip("/")
@@ -3582,15 +3605,17 @@ class HttpCli(object):
3582
3605
  zs = ub64enc(zb).decode("ascii")[:24].lower()
3583
3606
  dp = "%s/md/%s/%s/%s" % (dbv.histpath, zs[:2], zs[2:4], zs)
3584
3607
  self.log("moving old version to %s/%s" % (dp, mfile2))
3585
- if bos.makedirs(dp, vfs.flags["chmod_d"]):
3608
+ if bos.makedirs(dp, vf=vfs.flags):
3586
3609
  with open(os.path.join(dp, "dir.txt"), "wb") as f:
3587
3610
  f.write(afsenc(vrd))
3588
- if "chmod_f" in vfs.flags:
3589
- os.fchmod(f.fileno(), vfs.flags["chmod_f"])
3611
+ if "fperms" in vfs.flags:
3612
+ set_fperms(f, vfs.flags)
3590
3613
  elif hist_cfg == "s":
3591
3614
  dp = os.path.join(mdir, ".hist")
3592
3615
  try:
3593
3616
  bos.mkdir(dp, vfs.flags["chmod_d"])
3617
+ if "chown" in vfs.flags:
3618
+ bos.chown(dp, vfs.flags["uid"], vfs.flags["gid"])
3594
3619
  hidedir(dp)
3595
3620
  except:
3596
3621
  pass
@@ -3628,8 +3653,8 @@ class HttpCli(object):
3628
3653
  wunlink(self.log, fp, vfs.flags)
3629
3654
 
3630
3655
  with open(fsenc(fp), "wb", self.args.iobuf) as f:
3631
- if "chmod_f" in vfs.flags:
3632
- os.fchmod(f.fileno(), vfs.flags["chmod_f"])
3656
+ if "fperms" in vfs.flags:
3657
+ set_fperms(f, vfs.flags)
3633
3658
  sz, sha512, _ = hashcopy(p_data, f, None, 0, self.args.s_wr_slp)
3634
3659
 
3635
3660
  if lim:
@@ -4866,11 +4891,8 @@ class HttpCli(object):
4866
4891
  else:
4867
4892
  rip = host
4868
4893
 
4869
- # safer than html_escape/quotep since this avoids both XSS and shell-stuff
4870
- pw = re.sub(r"[<>&$?`\"']", "_", self.pw or "hunter2")
4871
- vp = re.sub(r"[<>&$?`\"']", "_", self.uparam["hc"] or "").lstrip("/")
4872
- pw = pw.replace(" ", "%20")
4873
- vp = vp.replace(" ", "%20")
4894
+ vp = (self.uparam["hc"] or "").lstrip("/")
4895
+ pw = self.pw or "hunter2"
4874
4896
  if pw in self.asrv.sesa:
4875
4897
  pw = "hunter2"
4876
4898
 
@@ -4879,14 +4901,14 @@ class HttpCli(object):
4879
4901
  args=self.args,
4880
4902
  accs=bool(self.asrv.acct),
4881
4903
  s="s" if self.is_https else "",
4882
- rip=rip,
4883
- ep=ep,
4884
- vp=vp,
4885
- rvp=vjoin(self.args.R, vp),
4886
- host=host,
4887
- hport=hport,
4904
+ rip=html_sh_esc(rip),
4905
+ ep=html_sh_esc(ep),
4906
+ vp=html_sh_esc(vp),
4907
+ rvp=html_sh_esc(vjoin(self.args.R, vp)),
4908
+ host=html_sh_esc(host),
4909
+ hport=html_sh_esc(hport),
4888
4910
  aname=aname,
4889
- pw=pw,
4911
+ pw=html_sh_esc(pw),
4890
4912
  )
4891
4913
  self.reply(html.encode("utf-8"))
4892
4914
  return True
@@ -5548,7 +5570,7 @@ class HttpCli(object):
5548
5570
  self.reply(jtxt.encode("utf-8", "replace"), mime="application/json")
5549
5571
  return True
5550
5572
 
5551
- html = self.j2s("rups", this=self, v=jtxt)
5573
+ html = self.j2s("rups", this=self, v=json_hesc(jtxt))
5552
5574
  self.reply(html.encode("utf-8"), status=200)
5553
5575
  return True
5554
5576
 
@@ -5612,15 +5634,15 @@ class HttpCli(object):
5612
5634
  raise Pebkac(500, "sqlite3 not found on server; sharing is disabled")
5613
5635
  raise Pebkac(500, "server busy, cannot create share; please retry in a bit")
5614
5636
 
5637
+ skey = self.uparam.get("skey") or self.vpath.split("/")[-1]
5638
+
5615
5639
  if self.args.shr_v:
5616
- self.log("handle_eshare: " + self.req)
5640
+ self.log("handle_eshare: " + skey)
5617
5641
 
5618
5642
  cur = idx.get_shr()
5619
5643
  if not cur:
5620
5644
  raise Pebkac(400, "huh, sharing must be disabled in the server config...")
5621
5645
 
5622
- skey = self.vpath.split("/")[-1]
5623
-
5624
5646
  rows = cur.execute("select un, t1 from sh where k = ?", (skey,)).fetchall()
5625
5647
  un = rows[0][0] if rows and rows[0] else ""
5626
5648
 
@@ -6129,13 +6151,13 @@ class HttpCli(object):
6129
6151
  self.log("#wow #whoa")
6130
6152
 
6131
6153
  if not self.args.nid:
6132
- free, total, _ = get_df(abspath, False)
6133
- if total is not None:
6154
+ free, total, zs = get_df(abspath, False)
6155
+ if total:
6134
6156
  h1 = humansize(free or 0)
6135
6157
  h2 = humansize(total)
6136
6158
  srv_info.append("{} free of {}".format(h1, h2))
6137
- elif free is not None:
6138
- srv_info.append(humansize(free, True) + " free")
6159
+ elif zs:
6160
+ self.log("diskfree(%r): %s" % (abspath, zs), 3)
6139
6161
 
6140
6162
  srv_infot = "</span> // <span>".join(srv_info)
6141
6163
 
copyparty/httpsrv.py CHANGED
@@ -120,6 +120,7 @@ class HttpSrv(object):
120
120
  self.nm = NetMap([], [])
121
121
  self.ssdp = None
122
122
  self.gpwd = Garda(self.args.ban_pw)
123
+ self.gpwc = Garda(self.args.ban_pwc)
123
124
  self.g404 = Garda(self.args.ban_404)
124
125
  self.g403 = Garda(self.args.ban_403)
125
126
  self.g422 = Garda(self.args.ban_422, False)
copyparty/mtag.py CHANGED
@@ -160,12 +160,13 @@ def au_unpk(
160
160
  znil = [x for x in znil if "cover" in x[0]] or znil
161
161
  znil = [x for x in znil if CBZ_01.search(x[0])] or znil
162
162
  t = "cbz: %d files, %d hits" % (nf, len(znil))
163
+ using = sorted(znil)[0][1].filename
163
164
  if znil:
164
- t += ", using " + znil[0][1].filename
165
+ t += ", using " + using
165
166
  log(t)
166
167
  if not znil:
167
168
  raise Exception("no images inside cbz")
168
- fi = zf.open(znil[0][1])
169
+ fi = zf.open(using)
169
170
 
170
171
  else:
171
172
  raise Exception("unknown compression %s" % (pk,))
copyparty/smbd.py CHANGED
@@ -317,7 +317,7 @@ class SMB(object):
317
317
 
318
318
  self.hub.up2k.handle_mv(uname, "1.7.6.2", vp1, vp2)
319
319
  try:
320
- bos.makedirs(ap2, vfs2.flags["chmod_d"])
320
+ bos.makedirs(ap2, vf=vfs2.flags)
321
321
  except:
322
322
  pass
323
323
 
copyparty/svchub.py CHANGED
@@ -45,6 +45,7 @@ from .util import (
45
45
  HAVE_PSUTIL,
46
46
  HAVE_SQLITE3,
47
47
  HAVE_ZMQ,
48
+ RE_ANSI,
48
49
  URL_BUG,
49
50
  UTC,
50
51
  VERSIONS,
@@ -54,7 +55,6 @@ from .util import (
54
55
  HMaccas,
55
56
  ODict,
56
57
  alltrace,
57
- ansi_re,
58
58
  build_netmap,
59
59
  expat_ver,
60
60
  gzip,
@@ -162,6 +162,7 @@ class SvcHub(object):
162
162
  # for non-http clients (ftp, tftp)
163
163
  self.bans = {}
164
164
  self.gpwd = Garda(self.args.ban_pw)
165
+ self.gpwc = Garda(self.args.ban_pwc)
165
166
  self.g404 = Garda(self.args.ban_404)
166
167
  self.g403 = Garda(self.args.ban_403)
167
168
  self.g422 = Garda(self.args.ban_422, False)
@@ -1398,9 +1399,9 @@ class SvcHub(object):
1398
1399
  if self.no_ansi:
1399
1400
  fmt = "%s %-21s %s\n"
1400
1401
  if "\033" in msg:
1401
- msg = ansi_re.sub("", msg)
1402
+ msg = RE_ANSI.sub("", msg)
1402
1403
  if "\033" in src:
1403
- src = ansi_re.sub("", src)
1404
+ src = RE_ANSI.sub("", src)
1404
1405
  elif c:
1405
1406
  if isinstance(c, int):
1406
1407
  msg = "\033[3%sm%s\033[0m" % (c, msg)
copyparty/tftpd.py CHANGED
@@ -45,6 +45,7 @@ from .util import (
45
45
  exclude_dotfiles,
46
46
  min_ex,
47
47
  runhook,
48
+ set_fperms,
48
49
  undot,
49
50
  vjoin,
50
51
  vsplit,
@@ -385,8 +386,8 @@ class Tftpd(object):
385
386
  a = (self.args.iobuf,)
386
387
 
387
388
  ret = open(ap, mode, *a, **ka)
388
- if wr and "chmod_f" in vfs.flags:
389
- os.fchmod(ret.fileno(), vfs.flags["chmod_f"])
389
+ if wr and "fperms" in vfs.flags:
390
+ set_fperms(ret, vfs.flags)
390
391
 
391
392
  return ret
392
393
 
@@ -395,7 +396,9 @@ class Tftpd(object):
395
396
  if "*" not in vfs.axs.uwrite:
396
397
  yeet("blocked mkdir; folder not world-writable: /%s" % (vpath,))
397
398
 
398
- return bos.mkdir(ap, vfs.flags["chmod_d"])
399
+ bos.mkdir(ap, vfs.flags["chmod_d"])
400
+ if "chown" in vfs.flags:
401
+ bos.chown(ap, vfs.flags["uid"], vfs.flags["gid"])
399
402
 
400
403
  def _unlink(self, vpath ) :
401
404
  # return bos.unlink(self._v2a("stat", vpath, *a)[1])
copyparty/th_srv.py CHANGED
@@ -266,8 +266,8 @@ class ThumbSrv(object):
266
266
  self.log("joined waiting room for %r" % (tpath,))
267
267
  except:
268
268
  thdir = os.path.dirname(tpath)
269
- chmod = 0o700 if self.args.free_umask else 0o755
270
- bos.makedirs(os.path.join(thdir, "w"), chmod)
269
+ chmod = bos.MKD_700 if self.args.free_umask else bos.MKD_755
270
+ bos.makedirs(os.path.join(thdir, "w"), vf=chmod)
271
271
 
272
272
  inf_path = os.path.join(thdir, "dir.txt")
273
273
  if not bos.path.exists(inf_path):
copyparty/up2k.py CHANGED
@@ -911,7 +911,7 @@ class Up2k(object):
911
911
  for vol in vols:
912
912
  try:
913
913
  # mkdir gonna happen at snap anyways;
914
- bos.makedirs(vol.realpath, vol.flags["chmod_d"])
914
+ bos.makedirs(vol.realpath, vf=vol.flags)
915
915
  dir_is_empty(self.log_func, not self.args.no_scandir, vol.realpath)
916
916
  except Exception as ex:
917
917
  self.volstate[vol.vpath] = "OFFLINE (cannot access folder)"
@@ -3293,7 +3293,7 @@ class Up2k(object):
3293
3293
  reg,
3294
3294
  "up2k._get_volsize",
3295
3295
  )
3296
- bos.makedirs(ap2, vfs.flags["chmod_d"])
3296
+ bos.makedirs(ap2, vf=vfs.flags)
3297
3297
  vfs.lim.nup(cj["addr"])
3298
3298
  vfs.lim.bup(cj["addr"], cj["size"])
3299
3299
 
@@ -3429,7 +3429,7 @@ class Up2k(object):
3429
3429
  "wb",
3430
3430
  fdir=fdir,
3431
3431
  suffix="-%.6f-%s" % (ts, dip),
3432
- chmod=vf.get("chmod_f", -1),
3432
+ vf=vf,
3433
3433
  )
3434
3434
  f.close()
3435
3435
  return ret
@@ -3460,6 +3460,8 @@ class Up2k(object):
3460
3460
 
3461
3461
  linked = False
3462
3462
  try:
3463
+ if "reflink" in flags:
3464
+ raise Exception("reflink")
3463
3465
  if not is_mv and not flags.get("dedup"):
3464
3466
  raise Exception("dedup is disabled in config")
3465
3467
 
@@ -3516,7 +3518,8 @@ class Up2k(object):
3516
3518
 
3517
3519
  linked = True
3518
3520
  except Exception as ex:
3519
- self.log("cannot link; creating copy: " + repr(ex))
3521
+ if str(ex) != "reflink":
3522
+ self.log("cannot link; creating copy: " + repr(ex))
3520
3523
  if bos.path.isfile(src):
3521
3524
  csrc = src
3522
3525
  elif fsrc and bos.path.isfile(fsrc):
@@ -4280,7 +4283,7 @@ class Up2k(object):
4280
4283
  self.log(t, 1)
4281
4284
  raise Pebkac(405, t)
4282
4285
 
4283
- bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
4286
+ bos.makedirs(os.path.dirname(dabs), vf=dvn.flags)
4284
4287
 
4285
4288
  c1, w, ftime_, fsize_, ip, at = self._find_from_vpath(
4286
4289
  svn_dbv.realpath, srem_dbv
@@ -4455,7 +4458,10 @@ class Up2k(object):
4455
4458
  vp = vjoin(dvp, rem)
4456
4459
  try:
4457
4460
  dvn, drem = self.vfs.get(vp, uname, False, True)
4458
- bos.mkdir(dvn.canonical(drem), dvn.flags["chmod_d"])
4461
+ dap = dvn.canonical(drem)
4462
+ bos.mkdir(dap, dvn.flags["chmod_d"])
4463
+ if "chown" in dvn.flags:
4464
+ bos.chown(dap, dvn.flags["uid"], dvn.flags["gid"])
4459
4465
  except:
4460
4466
  pass
4461
4467
 
@@ -4525,7 +4531,7 @@ class Up2k(object):
4525
4531
 
4526
4532
  is_xvol = svn.realpath != dvn.realpath
4527
4533
 
4528
- bos.makedirs(os.path.dirname(dabs), dvn.flags["chmod_d"])
4534
+ bos.makedirs(os.path.dirname(dabs), vf=dvn.flags)
4529
4535
 
4530
4536
  if is_dirlink:
4531
4537
  dlabs = absreal(sabs)
@@ -5035,7 +5041,7 @@ class Up2k(object):
5035
5041
  "wb",
5036
5042
  fdir=pdir,
5037
5043
  suffix="-%.6f-%s" % (job["t0"], dip),
5038
- chmod=vf.get("chmod_f", -1),
5044
+ vf=vf,
5039
5045
  )
5040
5046
  try:
5041
5047
  abspath = djoin(pdir, job["tnam"])