No error is given when trying to save to an unwriteable path
Describe the bug
The default save location is set to / and since the user doesn't have rights to write there, the file isn't saved and there is no note about it. This happens for example, when you haven't saved the document yet and are closing rnote. Lost a few documents this way already. I know that for some people it sets the home directory as the default save location.
To Reproduce
Steps to reproduce the behavior:
- Open rnote
- make changes
- close the window without saving
- click on save on the dialog
Expected behavior
I expect the Dialog to either give a writeable path or to at least error and give the option to change the path, when trying to save to an unwriteable location.
Console Output
~> flatpak --env=RUST_LOG=DEBUG --env=RUST_BACKTRACE=1 run com.github.flxzt.rnote
2025-02-16T11:51:31.159936Z DEBUG rnote: .. tracing subscriber initialized.
2025-02-16T11:51:31.714604Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for svg id=None
2025-02-16T11:51:31.714626Z DEBUG selectors::matching: Matching complex selector :root for svg id=None
2025-02-16T11:51:31.714632Z DEBUG selectors::matching: Matching complex selector image for svg id=None
2025-02-16T11:51:31.714636Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.714640Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.714644Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.714647Z DEBUG selectors::matching: Matching complex selector defs for svg id=None
2025-02-16T11:51:31.714651Z DEBUG selectors::matching: Matching complex selector clipPath for svg id=None
2025-02-16T11:51:31.714655Z DEBUG selectors::matching: Matching complex selector mask for svg id=None
2025-02-16T11:51:31.714664Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.714669Z DEBUG selectors::matching: Matching complex selector desc for svg id=None
2025-02-16T11:51:31.714677Z DEBUG selectors::matching: Matching complex selector title for svg id=None
2025-02-16T11:51:31.714687Z DEBUG selectors::matching: Matching complex selector metadata for svg id=None
2025-02-16T11:51:31.714695Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.714701Z DEBUG selectors::matching: Matching complex selector linearGradient for svg id=None
2025-02-16T11:51:31.714706Z DEBUG selectors::matching: Matching complex selector radialGradient for svg id=None
2025-02-16T11:51:31.714710Z DEBUG selectors::matching: Matching complex selector script for svg id=None
2025-02-16T11:51:31.714716Z DEBUG selectors::matching: Matching complex selector style for svg id=None
2025-02-16T11:51:31.714721Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.714726Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for svg id=None
2025-02-16T11:51:31.714733Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for g id=None
2025-02-16T11:51:31.714738Z DEBUG selectors::matching: Matching complex selector image for g id=None
2025-02-16T11:51:31.714742Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.714745Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.714750Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.714755Z DEBUG selectors::matching: Matching complex selector defs for g id=None
2025-02-16T11:51:31.714759Z DEBUG selectors::matching: Matching complex selector clipPath for g id=None
2025-02-16T11:51:31.714764Z DEBUG selectors::matching: Matching complex selector mask for g id=None
2025-02-16T11:51:31.714769Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.714773Z DEBUG selectors::matching: Matching complex selector desc for g id=None
2025-02-16T11:51:31.714778Z DEBUG selectors::matching: Matching complex selector title for g id=None
2025-02-16T11:51:31.714782Z DEBUG selectors::matching: Matching complex selector metadata for g id=None
2025-02-16T11:51:31.714787Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.714792Z DEBUG selectors::matching: Matching complex selector linearGradient for g id=None
2025-02-16T11:51:31.714796Z DEBUG selectors::matching: Matching complex selector radialGradient for g id=None
2025-02-16T11:51:31.714801Z DEBUG selectors::matching: Matching complex selector script for g id=None
2025-02-16T11:51:31.714806Z DEBUG selectors::matching: Matching complex selector style for g id=None
2025-02-16T11:51:31.714810Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.714815Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for g id=None
2025-02-16T11:51:31.714820Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for rect id=None
2025-02-16T11:51:31.714825Z DEBUG selectors::matching: Matching complex selector image for rect id=None
2025-02-16T11:51:31.714830Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.714834Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.714839Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.714844Z DEBUG selectors::matching: Matching complex selector defs for rect id=None
2025-02-16T11:51:31.714848Z DEBUG selectors::matching: Matching complex selector clipPath for rect id=None
2025-02-16T11:51:31.714853Z DEBUG selectors::matching: Matching complex selector mask for rect id=None
2025-02-16T11:51:31.714858Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.714862Z DEBUG selectors::matching: Matching complex selector desc for rect id=None
2025-02-16T11:51:31.714866Z DEBUG selectors::matching: Matching complex selector title for rect id=None
2025-02-16T11:51:31.714872Z DEBUG selectors::matching: Matching complex selector metadata for rect id=None
2025-02-16T11:51:31.714877Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.714882Z DEBUG selectors::matching: Matching complex selector linearGradient for rect id=None
2025-02-16T11:51:31.714886Z DEBUG selectors::matching: Matching complex selector radialGradient for rect id=None
2025-02-16T11:51:31.714891Z DEBUG selectors::matching: Matching complex selector script for rect id=None
2025-02-16T11:51:31.714896Z DEBUG selectors::matching: Matching complex selector style for rect id=None
2025-02-16T11:51:31.714900Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.714905Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for rect id=None
2025-02-16T11:51:31.716680Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for svg id=None
2025-02-16T11:51:31.716697Z DEBUG selectors::matching: Matching complex selector :root for svg id=None
2025-02-16T11:51:31.716702Z DEBUG selectors::matching: Matching complex selector image for svg id=None
2025-02-16T11:51:31.716706Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.716710Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.716714Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.716718Z DEBUG selectors::matching: Matching complex selector defs for svg id=None
2025-02-16T11:51:31.716721Z DEBUG selectors::matching: Matching complex selector clipPath for svg id=None
2025-02-16T11:51:31.716725Z DEBUG selectors::matching: Matching complex selector mask for svg id=None
2025-02-16T11:51:31.716729Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.716733Z DEBUG selectors::matching: Matching complex selector desc for svg id=None
2025-02-16T11:51:31.716737Z DEBUG selectors::matching: Matching complex selector title for svg id=None
2025-02-16T11:51:31.716741Z DEBUG selectors::matching: Matching complex selector metadata for svg id=None
2025-02-16T11:51:31.716747Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.716754Z DEBUG selectors::matching: Matching complex selector linearGradient for svg id=None
2025-02-16T11:51:31.716758Z DEBUG selectors::matching: Matching complex selector radialGradient for svg id=None
2025-02-16T11:51:31.716765Z DEBUG selectors::matching: Matching complex selector script for svg id=None
2025-02-16T11:51:31.716770Z DEBUG selectors::matching: Matching complex selector style for svg id=None
2025-02-16T11:51:31.716775Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.716780Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for svg id=None
2025-02-16T11:51:31.716787Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for g id=None
2025-02-16T11:51:31.716792Z DEBUG selectors::matching: Matching complex selector image for g id=None
2025-02-16T11:51:31.716797Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.716801Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.716806Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.716811Z DEBUG selectors::matching: Matching complex selector defs for g id=None
2025-02-16T11:51:31.716816Z DEBUG selectors::matching: Matching complex selector clipPath for g id=None
2025-02-16T11:51:31.716820Z DEBUG selectors::matching: Matching complex selector mask for g id=None
2025-02-16T11:51:31.716825Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.716828Z DEBUG selectors::matching: Matching complex selector desc for g id=None
2025-02-16T11:51:31.716835Z DEBUG selectors::matching: Matching complex selector title for g id=None
2025-02-16T11:51:31.716839Z DEBUG selectors::matching: Matching complex selector metadata for g id=None
2025-02-16T11:51:31.716844Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.716848Z DEBUG selectors::matching: Matching complex selector linearGradient for g id=None
2025-02-16T11:51:31.716853Z DEBUG selectors::matching: Matching complex selector radialGradient for g id=None
2025-02-16T11:51:31.716858Z DEBUG selectors::matching: Matching complex selector script for g id=None
2025-02-16T11:51:31.716862Z DEBUG selectors::matching: Matching complex selector style for g id=None
2025-02-16T11:51:31.716867Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.716871Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for g id=None
2025-02-16T11:51:31.716876Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for rect id=None
2025-02-16T11:51:31.716881Z DEBUG selectors::matching: Matching complex selector image for rect id=None
2025-02-16T11:51:31.716886Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.716890Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.716895Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.716900Z DEBUG selectors::matching: Matching complex selector defs for rect id=None
2025-02-16T11:51:31.716904Z DEBUG selectors::matching: Matching complex selector clipPath for rect id=None
2025-02-16T11:51:31.716909Z DEBUG selectors::matching: Matching complex selector mask for rect id=None
2025-02-16T11:51:31.716913Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.716918Z DEBUG selectors::matching: Matching complex selector desc for rect id=None
2025-02-16T11:51:31.716922Z DEBUG selectors::matching: Matching complex selector title for rect id=None
2025-02-16T11:51:31.716927Z DEBUG selectors::matching: Matching complex selector metadata for rect id=None
2025-02-16T11:51:31.716931Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.716936Z DEBUG selectors::matching: Matching complex selector linearGradient for rect id=None
2025-02-16T11:51:31.716941Z DEBUG selectors::matching: Matching complex selector radialGradient for rect id=None
2025-02-16T11:51:31.716945Z DEBUG selectors::matching: Matching complex selector script for rect id=None
2025-02-16T11:51:31.716950Z DEBUG selectors::matching: Matching complex selector style for rect id=None
2025-02-16T11:51:31.716954Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.716959Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for rect id=None
2025-02-16T11:51:31.717628Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for svg id=None
2025-02-16T11:51:31.717640Z DEBUG selectors::matching: Matching complex selector :root for svg id=None
2025-02-16T11:51:31.717646Z DEBUG selectors::matching: Matching complex selector image for svg id=None
2025-02-16T11:51:31.717651Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.717661Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.717666Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.717671Z DEBUG selectors::matching: Matching complex selector defs for svg id=None
2025-02-16T11:51:31.717675Z DEBUG selectors::matching: Matching complex selector clipPath for svg id=None
2025-02-16T11:51:31.717680Z DEBUG selectors::matching: Matching complex selector mask for svg id=None
2025-02-16T11:51:31.717685Z DEBUG selectors::matching: Matching complex selector marker for svg id=None
2025-02-16T11:51:31.717689Z DEBUG selectors::matching: Matching complex selector desc for svg id=None
2025-02-16T11:51:31.717694Z DEBUG selectors::matching: Matching complex selector title for svg id=None
2025-02-16T11:51:31.717699Z DEBUG selectors::matching: Matching complex selector metadata for svg id=None
2025-02-16T11:51:31.717703Z DEBUG selectors::matching: Matching complex selector pattern for svg id=None
2025-02-16T11:51:31.717708Z DEBUG selectors::matching: Matching complex selector linearGradient for svg id=None
2025-02-16T11:51:31.717713Z DEBUG selectors::matching: Matching complex selector radialGradient for svg id=None
2025-02-16T11:51:31.717717Z DEBUG selectors::matching: Matching complex selector script for svg id=None
2025-02-16T11:51:31.717722Z DEBUG selectors::matching: Matching complex selector style for svg id=None
2025-02-16T11:51:31.717726Z DEBUG selectors::matching: Matching complex selector symbol for svg id=None
2025-02-16T11:51:31.717731Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for svg id=None
2025-02-16T11:51:31.717737Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for g id=None
2025-02-16T11:51:31.717742Z DEBUG selectors::matching: Matching complex selector image for g id=None
2025-02-16T11:51:31.717747Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.717751Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.717756Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.717760Z DEBUG selectors::matching: Matching complex selector defs for g id=None
2025-02-16T11:51:31.717765Z DEBUG selectors::matching: Matching complex selector clipPath for g id=None
2025-02-16T11:51:31.717769Z DEBUG selectors::matching: Matching complex selector mask for g id=None
2025-02-16T11:51:31.717774Z DEBUG selectors::matching: Matching complex selector marker for g id=None
2025-02-16T11:51:31.717778Z DEBUG selectors::matching: Matching complex selector desc for g id=None
2025-02-16T11:51:31.717783Z DEBUG selectors::matching: Matching complex selector title for g id=None
2025-02-16T11:51:31.717788Z DEBUG selectors::matching: Matching complex selector metadata for g id=None
2025-02-16T11:51:31.717792Z DEBUG selectors::matching: Matching complex selector pattern for g id=None
2025-02-16T11:51:31.717797Z DEBUG selectors::matching: Matching complex selector linearGradient for g id=None
2025-02-16T11:51:31.717801Z DEBUG selectors::matching: Matching complex selector radialGradient for g id=None
2025-02-16T11:51:31.717806Z DEBUG selectors::matching: Matching complex selector script for g id=None
2025-02-16T11:51:31.717810Z DEBUG selectors::matching: Matching complex selector style for g id=None
2025-02-16T11:51:31.717815Z DEBUG selectors::matching: Matching complex selector symbol for g id=None
2025-02-16T11:51:31.717819Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for g id=None
2025-02-16T11:51:31.717825Z DEBUG selectors::matching: Matching complex selector :not(:root)svg for rect id=None
2025-02-16T11:51:31.717829Z DEBUG selectors::matching: Matching complex selector image for rect id=None
2025-02-16T11:51:31.717834Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.717838Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.717843Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.717847Z DEBUG selectors::matching: Matching complex selector defs for rect id=None
2025-02-16T11:51:31.717852Z DEBUG selectors::matching: Matching complex selector clipPath for rect id=None
2025-02-16T11:51:31.717857Z DEBUG selectors::matching: Matching complex selector mask for rect id=None
2025-02-16T11:51:31.717861Z DEBUG selectors::matching: Matching complex selector marker for rect id=None
2025-02-16T11:51:31.717866Z DEBUG selectors::matching: Matching complex selector desc for rect id=None
2025-02-16T11:51:31.717870Z DEBUG selectors::matching: Matching complex selector title for rect id=None
2025-02-16T11:51:31.717875Z DEBUG selectors::matching: Matching complex selector metadata for rect id=None
2025-02-16T11:51:31.717879Z DEBUG selectors::matching: Matching complex selector pattern for rect id=None
2025-02-16T11:51:31.717884Z DEBUG selectors::matching: Matching complex selector linearGradient for rect id=None
2025-02-16T11:51:31.717889Z DEBUG selectors::matching: Matching complex selector radialGradient for rect id=None
2025-02-16T11:51:31.717893Z DEBUG selectors::matching: Matching complex selector script for rect id=None
2025-02-16T11:51:31.717898Z DEBUG selectors::matching: Matching complex selector style for rect id=None
2025-02-16T11:51:31.717902Z DEBUG selectors::matching: Matching complex selector symbol for rect id=None
2025-02-16T11:51:31.717908Z DEBUG selectors::matching: Matching complex selector :host(use) > symbol for rect id=None
2025-02-16T11:51:31.729583Z DEBUG rnote_engine::store: State has not changed, no need to record.
(rnote:2): Gtk-CRITICAL **: 12:51:57.169: The layout manager of type GtkBoxLayout 0x56251b4320c0 does not create GtkLayoutChild instances
Desktop:
- OS: OpenSUSE Tumbleweed
- App Version: Rnote v0.11.0
- Installation Source: Flatpak from Flathub
- Desktop Environment: KDE Plasma 6
- Display Server: Wayland
- Input Source: Mouse and Keyboard, On-Screen-Tablet on a convertible
You can change the save location like this:
Also, you can give rnote permission to other file locations using Flatseal.
Maybe i should adjust the title. My main issue isn't really that the default save location is set to /, but that it doesn't give an error when clicking on "Save" when an unwriteable path is selected. That way you lose what you just added to the newly created document.
Also, changing the permissions on the flatpak, wont change the fact that a normal user can't write to /.
You are right. I could reproduce the behavior. You should add "change workspace directory to root" in steps to reproduce the behavior. For other unwriteable paths than root, rnote does show error.
You should add "change workspace directory to root" in steps to reproduce the behavior.
I didn't change anything personally, thats why i didn't include it.
Maybe this happens because of permissions issue + the walkup function https://github.com/flxzt/rnote/blob/58087a1909b09b8f7f904e179de08956080c94fe/crates/rnote-ui/src/utils.rs#L245 (fails to find a path until only / is left)
This is a weird bug. This only seems to happen in flatpak release builds on linux (and not debug nor meson builds). For some reason the same call to the same function with the same arguments does not give the same result when it is called from the "save" option upon trying to quit rnote.
I thought I could find a difference between the two situations but no. The same call will either fail correctly or silently without errors.
(Actually there is a slight difference:
- When saving to
/after selecting this folder, we get
save_document_to_file, Some("/run/user/1000/doc/15b4b937/New Document.rnote")
- when closing the application, we get
save_document_to_file, Some("/New Document.rnote")
instead, and the difference is that we used/did not use the file picker for /
)
There's other issues with the function, we can early return with errors without setting self.set_save_in_progress(true); so we can end up in the following situation
1- Save to an unwritable destination (from a classical save call) 2- See the "saved failed" popup 3- Try to quit the app 4- Be stuck as the app is preventing closing the app as it thinks we are still trying to save the file (and we won't be able to save either as the app will still think we are saving to a file but not yet finished)
Maybe we can change the strategy and test after writing the file if it actually exists. Hopefully this can catch this
The issue is flatpak-related.
Basically, because of the sandboxing, even if we give an unwritable path, saving won't (apparently) fail because we'll be writing to a temp or sandboxed filesystem. Hence from the rnote pov, the path exists, we are able to write to the file and everything is good. But we may as well write to a temp location that will disappear as soon as the app quits.
The only way for this to be reliable is to force for flatpak to open the file picker to choose the file location EVEN if the location is set because that way we will fail correctly if we give an unwritable path (because we will be going through the flatpak portal for choosing a location and this gives a little more info).
A crude way to do this is to call the dialog to save to a file until there is an output file registered (it's removed if it fails) though that doesn't take into account cancelling/closing the window (maybe we'd have to backtrack and re ask if it's okay not to save in that case). What's not cool is that forces two code paths (one for flatpak and one for everything else, with the detection possible using the return value of std::env::var("FLATPAK_ID") on linux). I don't see another way.
Maybe another softer way would be to require the first save operation to be done through the file picker. Then all is good after (because we will then have checked that we have the write access to the saved file). This can be done by checking the value of the canvas.output_file(). It's to none for a new file, set to the file we opened if we open a file (in that case we have the right permissions because we were able to read), and on save from the file picker. Though we'd still have some issues with the close dialog
I wonder If I can rely on the state of the workspace bar. If the workspace is successful in displaying the folder, do we have the rights to write to that location ? In that case we could
- see if there is an output file : no issue in that case
- see if the location is from a workspace that succeeded in displaying the folder (so we have the rights to it), then it should be okay
- otherwise (if flatpak) open the file chooser