Closed
Description
Description
Saving a writable file in a non-writable directory is not possible
Reproduce
mkdir non-writable
touch non-writable/writable.txt
chmod 500 non-writable
chmod 777 non-writable/writable.txt
jupyter lab
- Open
non-writable/writable.txt
, type something, save - See error in UI:
File Save Error for writable.txt
Permission denied: non-writable/writable.txt
- See error in terminal:
Traceback (most recent call last):
File "/jupyter_server/services/contents/fileio.py", line 230, in perm_to_403
yield
File "/jupyter_server/services/contents/fileio.py", line 220, in atomic_writing
with atomic_writing(os_path, *args, **kwargs) as f:
File "/contextlib.py", line 137, in __enter__
return next(self.gen)
^^^^^^^^^^^^^^
File "/jupyter_server/services/contents/fileio.py", line 107, in atomic_writing
copy2_safe(path, tmp_path, log=log)
File "/jupyter_server/services/contents/fileio.py", line 42, in copy2_safe
shutil.copyfile(src, dst)
File "/shutil.py", line 258, in copyfile
with open(dst, 'wb') as fdst:
^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/non-writable/.~writable.txt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/site-packages/tornado/web.py", line 1790, in _execute
result = await result
^^^^^^^^^^^^
File "/jupyter_server/auth/decorator.py", line 73, in inner
return await out
^^^^^^^^^
File "/jupyter_server/services/contents/handlers.py", line 320, in put
await self._save(model, path)
File "/jupyter_server/services/contents/handlers.py", line 245, in _save
model = await ensure_async(self.contents_manager.save(model, path))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/site-packages/jupyter_core/utils/__init__.py", line 198, in ensure_async
result = await obj
^^^^^^^^^
File "/jupyter_server/services/contents/largefilemanager.py", line 133, in save
return await super().save(model, path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/jupyter_server/services/contents/filemanager.py", line 969, in save
await self._save_file(os_path, model["content"], model.get("format"))
File "/jupyter_server/services/contents/fileio.py", line 572, in _save_file
with self.atomic_writing(os_path, text=False) as f:
File "/contextlib.py", line 137, in __enter__
return next(self.gen)
^^^^^^^^^^^^^^
File "/jupyter_server/services/contents/fileio.py", line 217, in atomic_writing
with self.perm_to_403(os_path):
File "/contextlib.py", line 158, in __exit__
self.gen.throw(typ, value, traceback)
File "/jupyter_server/services/contents/fileio.py", line 239, in perm_to_403
raise HTTPError(403, "Permission denied: %s" % path) from e
tornado.web.HTTPError: HTTP 403: Forbidden (Permission denied: non-writable/writable.txt)
Expected behavior
No error, file can be saved.
Maybe:
- skip atomic write in this case?
- still use atomic write but create the temporary file in a temporary directory instead if that is writable?
Context
This is very similar to #1502