Skip to content

Commit 1e91e49

Browse files
yacchin1205meeseeksmachine
authored andcommitted
Backport PR jupyter-server#1073: Fix rename_file and delete_file to handle hidden files properly
1 parent 74888bc commit 1e91e49

File tree

2 files changed

+69
-80
lines changed

2 files changed

+69
-80
lines changed

jupyter_server/services/contents/filemanager.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,14 +467,14 @@ def delete_file(self, path):
467467
path = path.strip("/")
468468
os_path = self._get_os_path(path)
469469
rm = os.unlink
470-
four_o_four = "file or directory does not exist: %r" % path
471-
472-
if not self.exists(path):
473-
raise web.HTTPError(404, four_o_four)
474470

475471
if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
476472
raise web.HTTPError(400, f"Cannot delete file or directory {os_path!r}")
477473

474+
four_o_four = "file or directory does not exist: %r" % path
475+
if not self.exists(path):
476+
raise web.HTTPError(404, four_o_four)
477+
478478
def _check_trash(os_path):
479479
if sys.platform in {"win32", "darwin"}:
480480
return True
@@ -803,6 +803,10 @@ async def delete_file(self, path):
803803
path = path.strip("/")
804804
os_path = self._get_os_path(path)
805805
rm = os.unlink
806+
807+
if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
808+
raise web.HTTPError(400, f"Cannot delete file or directory {os_path!r}")
809+
806810
if not os.path.exists(os_path):
807811
raise web.HTTPError(404, "File or directory does not exist: %s" % os_path)
808812

@@ -874,6 +878,11 @@ async def rename_file(self, old_path, new_path):
874878
new_os_path = self._get_os_path(new_path)
875879
old_os_path = self._get_os_path(old_path)
876880

881+
if (
882+
is_hidden(old_os_path, self.root_dir) or is_hidden(new_os_path, self.root_dir)
883+
) and not self.allow_hidden:
884+
raise web.HTTPError(400, f"Cannot rename file or directory {old_os_path!r}")
885+
877886
# Should we proceed with the move?
878887
if os.path.exists(new_os_path) and not samefile(old_os_path, new_os_path):
879888
raise web.HTTPError(409, "File already exists: %s" % new_path)

tests/services/contents/test_manager.py

Lines changed: 56 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -264,34 +264,26 @@ async def test_403(jp_file_contents_manager_class, tmp_path):
264264
async def test_400(jp_file_contents_manager_class, tmp_path):
265265
# Test Delete behavior
266266
# Test delete of file in hidden directory
267-
with pytest.raises(HTTPError) as excinfo:
268-
td = str(tmp_path)
269-
cm = jp_file_contents_manager_class(root_dir=td)
270-
hidden_dir = ".hidden"
271-
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
272-
_make_dir(cm, hidden_dir)
273-
model = await ensure_async(cm.new(path=file_in_hidden_path))
274-
os_path = cm._get_os_path(model["path"])
267+
td = str(tmp_path)
268+
cm = jp_file_contents_manager_class(root_dir=td)
269+
hidden_dir = ".hidden"
270+
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
271+
_make_dir(cm, hidden_dir)
275272

276-
try:
277-
result = await ensure_async(cm.delete_file(os_path))
278-
except HTTPError as e:
279-
assert e.status_code == 400
273+
with pytest.raises(HTTPError) as excinfo:
274+
await ensure_async(cm.delete_file(file_in_hidden_path))
275+
assert excinfo.value.status_code == 400
280276

281277
# Test delete hidden file in visible directory
282-
with pytest.raises(HTTPError) as excinfo:
283-
td = str(tmp_path)
284-
cm = jp_file_contents_manager_class(root_dir=td)
285-
hidden_dir = "visible"
286-
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
287-
_make_dir(cm, hidden_dir)
288-
model = await ensure_async(cm.new(path=file_in_hidden_path))
289-
os_path = cm._get_os_path(model["path"])
278+
td = str(tmp_path)
279+
cm = jp_file_contents_manager_class(root_dir=td)
280+
hidden_dir = "visible"
281+
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
282+
_make_dir(cm, hidden_dir)
290283

291-
try:
292-
result = await ensure_async(cm.delete_file(os_path))
293-
except HTTPError as e:
294-
assert e.status_code == 400
284+
with pytest.raises(HTTPError) as excinfo:
285+
await ensure_async(cm.delete_file(file_in_hidden_path))
286+
assert excinfo.value.status_code == 400
295287

296288
# Test Save behavior
297289
# Test save of file in hidden directory
@@ -326,68 +318,56 @@ async def test_400(jp_file_contents_manager_class, tmp_path):
326318

327319
# Test rename behavior
328320
# Test rename with source file in hidden directory
329-
with pytest.raises(HTTPError) as excinfo:
330-
td = str(tmp_path)
331-
cm = jp_file_contents_manager_class(root_dir=td)
332-
hidden_dir = ".hidden"
333-
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
334-
_make_dir(cm, hidden_dir)
335-
model = await ensure_async(cm.new(path=file_in_hidden_path))
336-
old_path = cm._get_os_path(model["path"])
337-
new_path = "new.txt"
321+
td = str(tmp_path)
322+
cm = jp_file_contents_manager_class(root_dir=td)
323+
hidden_dir = ".hidden"
324+
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
325+
_make_dir(cm, hidden_dir)
326+
old_path = file_in_hidden_path
327+
new_path = "new.txt"
338328

339-
try:
340-
result = await ensure_async(cm.rename_file(old_path, new_path))
341-
except HTTPError as e:
342-
assert e.status_code == 400
329+
with pytest.raises(HTTPError) as excinfo:
330+
await ensure_async(cm.rename_file(old_path, new_path))
331+
assert excinfo.value.status_code == 400
343332

344333
# Test rename of dest file in hidden directory
345-
with pytest.raises(HTTPError) as excinfo:
346-
td = str(tmp_path)
347-
cm = jp_file_contents_manager_class(root_dir=td)
348-
hidden_dir = ".hidden"
349-
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
350-
_make_dir(cm, hidden_dir)
351-
model = await ensure_async(cm.new(path=file_in_hidden_path))
352-
new_path = cm._get_os_path(model["path"])
353-
old_path = "old.txt"
334+
td = str(tmp_path)
335+
cm = jp_file_contents_manager_class(root_dir=td)
336+
hidden_dir = ".hidden"
337+
file_in_hidden_path = os.path.join(hidden_dir, "visible.txt")
338+
_make_dir(cm, hidden_dir)
339+
new_path = file_in_hidden_path
340+
old_path = "old.txt"
354341

355-
try:
356-
result = await ensure_async(cm.rename_file(old_path, new_path))
357-
except HTTPError as e:
358-
assert e.status_code == 400
342+
with pytest.raises(HTTPError) as excinfo:
343+
await ensure_async(cm.rename_file(old_path, new_path))
344+
assert excinfo.value.status_code == 400
359345

360346
# Test rename with hidden source file in visible directory
361-
with pytest.raises(HTTPError) as excinfo:
362-
td = str(tmp_path)
363-
cm = jp_file_contents_manager_class(root_dir=td)
364-
hidden_dir = "visible"
365-
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
366-
_make_dir(cm, hidden_dir)
367-
model = await ensure_async(cm.new(path=file_in_hidden_path))
368-
old_path = cm._get_os_path(model["path"])
369-
new_path = "new.txt"
347+
td = str(tmp_path)
348+
cm = jp_file_contents_manager_class(root_dir=td)
349+
hidden_dir = "visible"
350+
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
351+
_make_dir(cm, hidden_dir)
352+
old_path = file_in_hidden_path
353+
new_path = "new.txt"
370354

371-
try:
372-
result = await ensure_async(cm.rename_file(old_path, new_path))
373-
except HTTPError as e:
374-
assert e.status_code == 400
355+
with pytest.raises(HTTPError) as excinfo:
356+
await ensure_async(cm.rename_file(old_path, new_path))
357+
assert excinfo.value.status_code == 400
375358

376359
# Test rename with hidden dest file in visible directory
377-
with pytest.raises(HTTPError) as excinfo:
378-
td = str(tmp_path)
379-
cm = jp_file_contents_manager_class(root_dir=td)
380-
hidden_dir = "visible"
381-
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
382-
_make_dir(cm, hidden_dir)
383-
model = await ensure_async(cm.new(path=file_in_hidden_path))
384-
new_path = cm._get_os_path(model["path"])
385-
old_path = "old.txt"
360+
td = str(tmp_path)
361+
cm = jp_file_contents_manager_class(root_dir=td)
362+
hidden_dir = "visible"
363+
file_in_hidden_path = os.path.join(hidden_dir, ".hidden.txt")
364+
_make_dir(cm, hidden_dir)
365+
new_path = file_in_hidden_path
366+
old_path = "old.txt"
386367

387-
try:
388-
result = await ensure_async(cm.rename_file(old_path, new_path))
389-
except HTTPError as e:
390-
assert e.status_code == 400
368+
with pytest.raises(HTTPError) as excinfo:
369+
await ensure_async(cm.rename_file(old_path, new_path))
370+
assert excinfo.value.status_code == 400
391371

392372

393373
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Can't test hidden files on Windows")

0 commit comments

Comments
 (0)