Skip to content

Saving a writable file in a non-writable directory is not possible #1515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
krassowski opened this issue Apr 22, 2025 · 1 comment · May be fixed by #1516
Open

Saving a writable file in a non-writable directory is not possible #1515

krassowski opened this issue Apr 22, 2025 · 1 comment · May be fixed by #1516
Labels

Comments

@krassowski
Copy link
Collaborator

krassowski commented Apr 22, 2025

Description

Saving a writable file in a non-writable directory is not possible

Reproduce

  1. mkdir non-writable
  2. touch non-writable/writable.txt
  3. chmod 500 non-writable
  4. chmod 777 non-writable/writable.txt
  5. jupyter lab
  6. Open non-writable/writable.txt, type something, save
  7. See error in UI:
File Save Error for writable.txt
Permission denied: non-writable/writable.txt
  1. 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

@krassowski krassowski added the bug label Apr 22, 2025
@krassowski
Copy link
Collaborator Author

I verified that #1513 does NOT fix this issue (as the problem occurs at a different stage compared to #1502), we will need a separate patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
1 participant