Skip to content
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

Environment.GetFolderPath() doesn't support all KNOWNFOLDERID's #554

Open
sba923 opened this issue Dec 5, 2019 · 55 comments
Open

Environment.GetFolderPath() doesn't support all KNOWNFOLDERID's #554

sba923 opened this issue Dec 5, 2019 · 55 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Runtime
Milestone

Comments

@sba923
Copy link

sba923 commented Dec 5, 2019

(Redirecting from (PowerShell/PowerShell#11240))

It should be possible to retrieve the location of all "special folders" instead of hardcoding them (or assuming they are just subfolders of the user's profile folder).

As of today, Environment.GetFolderPath() (which reportedly relies on SHGetKnownFolderPath()) doesn't support all KNOWNFOLDERID's. Here's a few of the ones that are not supported:

FOLDERID_Downloads
FOLDERID_DocumentsLibrary
FOLDERID_CameraRoll

This piece of code

using System;

namespace GetFolderPath
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (Environment.SpecialFolder folder in (Environment.SpecialFolder[]) Enum.GetValues(typeof(Environment.SpecialFolder)))
            {
                Console.WriteLine("{0,-30}{1}", folder, Environment.GetFolderPath(folder));
            }
        }
    }
}

outputs only this subset of folder paths:

Desktop                       C:\Users\joe\Desktop
Programs                      C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
MyDocuments                   C:\Users\joe\Documents
MyDocuments                   C:\Users\joe\Documents
Favorites                     C:\Users\joe\Favorites
Startup                       C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Recent                        C:\Users\joe\AppData\Roaming\Microsoft\Windows\Recent
SendTo                        C:\Users\joe\AppData\Roaming\Microsoft\Windows\SendTo
StartMenu                     C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu
MyMusic                       C:\Users\joe\Music
MyVideos                      C:\Users\joe\Videos
DesktopDirectory              C:\Users\joe\Desktop
MyComputer                    
NetworkShortcuts              C:\Users\joe\AppData\Roaming\Microsoft\Windows\Network Shortcuts
Fonts                         C:\windows\Fonts
Templates                     C:\Users\joe\AppData\Roaming\Microsoft\Windows\Templates
CommonStartMenu               C:\ProgramData\Microsoft\Windows\Start Menu
CommonPrograms                C:\ProgramData\Microsoft\Windows\Start Menu\Programs
CommonStartup                 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
CommonDesktopDirectory        C:\Users\Public\Desktop
ApplicationData               C:\Users\joe\AppData\Roaming
PrinterShortcuts              
LocalApplicationData          C:\Users\joe\AppData\Local
InternetCache                 C:\Users\joe\AppData\Local\Microsoft\Windows\INetCache
Cookies                       C:\Users\joe\AppData\Local\Microsoft\Windows\INetCookies
History                       C:\Users\joe\AppData\Local\Microsoft\Windows\History
CommonApplicationData         C:\ProgramData
Windows                       C:\windows
System                        C:\windows\system32
ProgramFiles                  C:\Program Files
MyPictures                    C:\Users\joe\Pictures
UserProfile                   C:\Users\joe
SystemX86                     C:\windows\SysWOW64
ProgramFilesX86               C:\Program Files (x86)
CommonProgramFiles            C:\Program Files\Common Files
CommonProgramFilesX86         C:\Program Files (x86)\Common Files
CommonTemplates               C:\ProgramData\Microsoft\Windows\Templates
CommonDocuments               C:\Users\Public\Documents
CommonAdminTools              C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools
AdminTools                    C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools
CommonMusic                   C:\Users\Public\Music
CommonPictures                C:\Users\Public\Pictures
CommonVideos                  C:\Users\Public\Videos
Resources                     C:\windows\resources
LocalizedResources            
CommonOemLinks                
CDBurning                     C:\Users\joe\AppData\Local\Microsoft\Windows\Burn\Burn
@danmoseley
Copy link
Member

Looks like this is because on .NET Framework, Environment.GetFolderPath() uses ShGetFolderPath which cannot give you the downloads folder (it has no CSIDL value). On .NET Core, perhaps to accommodate long paths, we already changed to ShGetKnownFolderPath. This takes KNOWNFOLDERID and Downloads has one of these.

This is essentially an API request for new members of Environment.SpecialFolders. Someone interested in this should make a list of proposed additions. Note that they ideally all have some meaning on Mac and Linux. We should not add "CameraRoll" unless it's actually important. Downloads seems pretty basic though.

@danmoseley danmoseley added the api-needs-work API needs work before it is approved, it is NOT ready for implementation label Feb 24, 2020
@ChadSimmons
Copy link

If it's documented, I recommend including it since determining importance is a fool's errand. For example, CameraRoll might not be important to many, but since it is included in One Drive Known Folder Move it is of interest to people trying to use that.
Definitely include

  • CameraRoll
  • Screenshots

@danmoseley
Copy link
Member

If it's documented, I recommend including it since determining importance is a fool's errand.

Maybe if Windows was the only relevant OS, but it is not: as the list gets longer there are more entries without clear mappings on various Linux distros, macOS, Android, iOS, etc. We can take guesses or return empty string but that potentially makes life harder for folks trying to target those OS, who must now figure out which members of the enumeration are going to be useful. Eg., what should CameraRoll return on Ubuntu? Maybe there is no mapping, or several possible mappings. If I'm writing a photo editor app, should I offer it in my "open file" picker?

We are already returning empty string in quite a few cases for Unix

And for example on about 30 cases on iOS
https://github.com/mono/mono/blob/c5b88ec4f323f2bdb7c7d0a595ece28dae66579c/mcs/class/corlib/System/Environment.iOS.cs#L91

@sba923
Copy link
Author

sba923 commented May 19, 2020

Sure, Windows is not the only targeted OS. I'm a great advocate of non-Windows .NET Core / PowerShell.

But OTOH, not all code / scripts is / are written to be xplat!

I hate that I have to write weird code (mainly on Windows) to determine where the Downloads folder resides...

@danmoseley
Copy link
Member

It would be good to improve the doc so it has a big table showing what works on what platform. It looks like it's not been updated for cross plat.

https://docs.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=netcore-3.1

@sba923
Copy link
Author

sba923 commented May 19, 2020

Yes! And that big table would have Windows-only entries ;-) Or "not MacOS" entries. Whatever.

@joperezr joperezr removed the untriaged New issue has not been triaged by the area owner label Jul 6, 2020
@joperezr joperezr added this to the Future milestone Jul 6, 2020
MichalStrehovsky pushed a commit to MichalStrehovsky/runtime that referenced this issue Mar 25, 2021
@jeffhandley
Copy link
Member

Per #57133, we should consider the Saved Games folder as a candidate too.

@AtomicBlom
Copy link

In the interest of pushing this forward I've put together a spreadsheet of all the KnownFolderIds that are missing, as well as whether they're usable on *nix or mac.

What I don't have is a good way to collaborate on these, as I'm not a mac or *nix user so I'm not sure what the sane defaults would be.

(read-only view of the spreadsheet)
https://1drv.ms/x/s!Aqd0GRdPyzYske0aoWS8kUiTamIu7A?e=bBfntf

One thing that struck me as a bit odd while I was working on this is that MyComputer is a valid SpecialFolder. This is the only KnownFolderId which is marked as a Virtual folder, and I don't think it will EVER return a valid path on Windows.

@RayKoopa
Copy link

RayKoopa commented Apr 23, 2022

This seems to be the newest discussion on this topic.
I got my feet wet and tried implementing the "Downloads" and "Public" folder with these paths, given they seem requested the most:

Folder Linux1 macOS2 iOS2 Windows3
Downloads XDG_DOWNLOAD_DIR or <home>/Downloads <home>/Downloads <personal>/Downloads FOLDERID_Downloads
Public XDG_PUBLICSHARE_DIR or <home>/Public <home>/Public - FOLDERID_Public4

1 Judging from existing code and https://wiki.archlinux.org/title/XDG_user_directories
2 Judging from existing code and screenshots (I do not own Apple hardware)
3 https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid
4 This path is the same for all users on Windows. Unlike Linux and macOS, there is no user-specific Public folder on Windows.

I noticed some things while doing so:

  • The System.Environment.SpecialFolder enum uses Windows' deprecated CSIDL values. To add non-CSIDL folder values, I started the new values at 0x10000 as it is larger than any possible CSIDL value. This shouldn't be too much of an issue as the enum uses the default underlying type of int which remains unchanged.
  • I named the new enum value for the "Downloads" folder MyDownloads in the style of MyDocuments, MyPictures, and MyVideos - I recall Windows 7 reintroducing the "My" prefix after it was dropped in Vista, but I don't remember if this was the case for the Downloads folder too simply Downloads (it never used a "My" prefix as I originally thought, and this would match the native FOLDERID_Downloads aswell).
  • I named the new enum value for the "Public" folder PublicDirectory in the style of DesktopDirectory and CommonDesktopDirectory, as Public is a reserved keyword in VB.NET, despite this no longer matching the native FOLDERID_Public definition. The GUID string constant in Interop.Shell32.KnownFolders is still named Public to match the native declaration and seems used by internal C# code only.
  • The existing code to resolve the SpecialFolder.MyVideos seems incorrect on OSX as the macOS user folder is named Movies and not Videos. Are XDG variables even defined in macOS, the preprocessor block below seems to state the opposite? Impossible to change now without breaking the behavior of existing apps, and offtopic for this issue.
    Already mentioned / handled by SpecialFolder.MyDocuments / Personal returning wrong path for Unix #63214 (comment); should definitely be a separate PR / issue.
  • This should probably also be added to VB.NET's SpecialDirectories, though its properties do not even cover the existing SpecialFolder enum and were probably just meant for "portability" from original VB6 code. Not worth it given that reason.

I did not tackle the "Saved Games" folder as only Windows has it, and the discussion went into the direction of focusing folders that have viable cross-platform paths first.

If you are interested, I can write an API Proposal to add these two folders. Wanted to hear some feedback on this existing issue first :-)

@danmoseley
Copy link
Member

danmoseley commented Apr 24, 2022

I named the new enum value for the "Downloads" folder MyDownloads in the style of MyDocuments, MyPictures, and MyVideos - I recall Windows 7 reintroducing the "My" prefix after it was dropped in Vista, but I don't remember if this was the case for the Downloads folder too.

On my Windows 7 VM, only Documents, Music, Pictures, and Videos have the My prefix. (Matches https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid)

@danmoseley
Copy link
Member

. Are XDG variables even defined in macOS, the preprocessor block below seems to state the opposite

I don't have a Mac but I don't believe so. If Macs have a "movies" folder then we should implement it to return that for SpecialFolders.MyVideos. That's just a bug fix -- #68323

BTW, I found #25577 and #63214 -- lots of discussion here, as no maintainers like me have sat down and organized.

I wouldn't bother to add to the VB enum as you point out.

It would be great to open an API proposal for those two, and any others you believe (based on all these discussions) seem to make general sense. Perhaps we can end up closing all these issues..

@danmoseley
Copy link
Member

BTW @RayKoopa thanks for reviving this. And @AtomicBlom for the spreadsheet, which I pasted here in case it gets lost. https://gist.github.com/danmoseley/edb3708c1bacc2998890e44e7ea4e4d4

@RayKoopa
Copy link

Thank you for checking on the folder names and other discussions.

I'm still sorting my notes a bit from the many comments written throughout the years, but have updated mine above (which I slightly use as my blueprint for an API proposal):

For simplicity, at the moment I'd prefer to only focus on the "missing user folders" common to Linux / macOS / Windows, e.g. "Downloads" and "Public" (despite the latter not being a user-specific folder on Windows, but I think that is neglectible since everyone has access to it by default).

@sba923
Copy link
Author

sba923 commented Apr 24, 2022

BTW @RayKoopa thanks for reviving this. And @AtomicBlom for the spreadsheet, which I pasted here in case it gets lost. https://gist.github.com/danmoseley/edb3708c1bacc2998890e44e7ea4e4d4

Thanks for saving the spreadsheet.

Shouldn't it include a column indicating what is currently supported by .NET (might even depen on version?)?

@RayKoopa
Copy link

Phew, I've now dug through related issues, PRs and API proposals.

They currently block me moving forward with my blueprint above as they make valid points in that extending the enum may not be a good idea. However, I cannot rate how important the points made are today:

So either

  1. the points made are discarded and the enum is extended for a quick / "short-term" solution that will probably be deprecated in the future anyway
  2. the points made are respected and the new API proposal is resurrected instead for a "long-term" solution

What do? 🤔

@AtomicBlom
Copy link

I would honestly like to see a short-term fix in place for at least the user folders.

I stumbled across and became invested in this task after I became aware of how few developers were making use of the "Saved Games" folder in windows, and many games scatter their saved games everywhere across local app data, roaming app data, my documents, etc. All this means that for games that don't cloud save, it's very difficult to back them all up

I wanted to make sure that my games used what I perceive to be the best location for them, and I want to promote that there is a location for saved games, However the Enum value doesn't work for non-windows platforms, so it's back to square one.

@RayKoopa
Copy link

I would honestly like to see a short-term fix in place for at least the user folders.

Me too. The only "real" reason against short-term extending the enum because "code assuming it maps to Windows' CSIDLs would break" is valid but exotic. What would be a use case for that? Any code doing this...

  • uses deprecated behavior as CSIDLs only exist for compatiblity in Windows since 16 years, in all versions supported by new .NET (Core).
  • relies on the undocumented fact that the underlying enum values ever mapped to CSIDLs. While the values are listed in MSDN, there is no mention of them actually being CSIDLs.
  • can still relatively easily bail out of handling the values as CSIDLs (when iterating over all enum values or whatever) if the enum is extended as I suggested above - with new values starting at 0x10000, higher than any valid CSIDL flag combination.

I became aware of how few developers were making use of the "Saved Games" folder in windows

However the Enum value doesn't work for non-windows platform

These two reasons actually made me exclude the "Saved Games" in an API Proposal I'd write so far, and only focus on the more commonly requested "Downloads" and "Public" first - unless maintainers are okay with "Saved Games" returning "yet another" String.Empty on Linux and macOS. Would definitely make .NET more inviting for game developers given the almost nonexistant adoption of this folder after Vista used it for Purble Place etc. :-)

@Miepee
Copy link
Contributor

Miepee commented Apr 25, 2022

This seems to be the newest discussion on this topic. I got my feet wet and tried implementing the "Downloads" and "Public" folder with these paths, given they seem requested the most:

Just wanted to leave a quick note, that the public directory functions a little differently between Windows and Linux/MacOS.
On Windows, there only exists one public folder which every user has access to. On Linux/MacOS, every user has it's own public folder that the other users can access. This should get documented, just so that developers are aware of it.

Also, this may just be a thing that's unclear due to it being short, but for the Linux assignments, it shouldn't be an "or", rather a "fallback" should the former variable not exist. If you're using ReadXdgDirectory then it's already handled for you there.

@RayKoopa
Copy link

RayKoopa commented May 6, 2022

Before this stales away again, should I push ahead and make an API proposal as I outlined above? To recap:

🟢 Extend SpecialFolder starting at value 0x10000 with folders commonly available cross-platform:

SpecialFolder macOS iOS Linux (with XDG) Linux Windows
Downloads ~/Downloads NSDocumentDirectory/Downloads XDG_DOWNLOAD_DIR ~/Downloads FOLDERID_Downloads
PublicDirectory ~/Public - XDG_PUBLICSHARE_DIR ~/Public FOLDERID_Public
PublicDesktop - - - - FOLDERID_PublicDesktop
PublicDocuments - - - - FOLDERID_PublicDocuments
PublicDownloads - - - - FOLDERID_PublicDownloads
PublicMusic - - - - FOLDERID_PublicMusic
PublicVideos - - - - FOLDERID_PublicVideos
SavedGames - - - - FOLDERID_SavedGames

Reasoning:

  • The enum is extended at 0x10000 due to the undocumented fact that the existing values map to Windows' CSIDLs, and 0x10000 is the first invalid CSIDL combination.

    • The CSIDL API is deprecated, not used by .NET anymore, and does not allow querying the folders above anyway.
    • Extending the enum would only break code relying on this undocumented fact, affecting those enumerating SpecialFolder via reflection and / or using those values for actual CSIDLs means.
  • ~ is the home directory as it is already determined.

  • XDG... variables are used on Linux if they exist, otherwise the non-XDG path is used as a fallback.

  • The Public folder is named PublicDirectory to not clash with keywords (e.g. VB.NET).

    • The public (sub) folder is per-system on Windows, and per-user on Linux and macOS. iOS has no such folders.
    • Adding Public... sub folders is required for Windows as they may be redirected outside of the parent PublicDirectory. Otherwise it could lead to developers looking for them to incorrectly hardcode parts of their path again by assuming they are children (the same issue currently with the Downloads and Public folders themselves).
  • SavedGames is included as it is the only remaining Windows user folder meaningful to developers. The others I do not recommend adding as they have a very special meaning only to one Windows app / component:

    SpecialFolder Windows only Used by / meant for
    ❌ Contacts FOLDERID_Contacts Windows Contacts contact files.
    ❌ Links FOLDERID_Links File Explorer pinned location shortcut files (< Windows 10 only).
    ❌ Searches FOLDERID_Searches Parameterized Windows Search query files.

For consistency, the following two breaking changes already mentioned in #63214 should be proposed aswell:

🟠 Change SpecialFolder.MyDocuments on Unix to point to the actual "Documents" sub folder, not the home directory:

Behavior macOS iOS Linux (with XDG) Linux
Current ~ NSDocumentDirectory ~ ~
Proposed ~/Documents NSDocumentDirectory XDG_DOCUMENTS_DIR ~/Documents

🟠 Change SpecialFolder.MyVideos to point to macOS' "Movies" folder as it does not actually have a "Videos" folder:

Behavior macOS iOS
Current ~/Videos NSDocumentDirectory/Videos
Proposed ~/Movies NSDocumentDirectory/Movies

This has already been started just recently here: #68610. I will wait on the acceptance / merge of that PR first before continuing with the new folder proposal to prevent clashes / confusion.

@danmoseley
Copy link
Member

Linking #68610 here as well...

@RayKoopa
Copy link

RayKoopa commented May 6, 2022

Thanks for letting me know. I crossed out the breaking changes in my recap that are already started there and wait for the outcome of the PR / discussions first.

@soc
Copy link

soc commented May 6, 2022

This looks reasonable, but I want to ask for clarification regarding the public subfolders on Linux:

Are the subfolder names fixed to the values mentioned above or are the translated values of the personal download/music/document/... folders used?

Sadly those folders are locale-dependent (seemingly every OS needs to make that mistake at least once) and in my opinion using a fixed language for public subdirs would be wrong:

If XDG_DOWNLOAD_DIR was /home/me/Heruntergeladenes, then PublicDownloads should be /home/soc/Öffentlich/Heruntergeladenes, not /home/soc/Öffentlich/Downloads.

So XDG_PUBLICSHARE_DIR/Downloads should be something like XDG_PUBLICSHARE_DIR/last-path-component(XDG_DOWNLOAD_DIR) to avoid English folder names on non-English systems.

@RayKoopa
Copy link

RayKoopa commented May 6, 2022

Thanks for opening the discussion on that.

I included the paths returned on Unix based on the currently used fallback names, and only added them for "convenience".
But I also share the decision to not return a path at all for them since they simply don't exist in Unix, and cannot be retrieved in any meaningful way:

  • macOS is said to always uses English folder names. That's fine.
  • Ubuntu 22.04 apparently localizes the physical folder name per-user. It states to run xdg-user-dirs-update, which translates the keys specified in /etc/xdg/user-dirs.defaults for each folder with the language set in ~/.config/user-dirs.locale, but I don't know how to query the translations like xdg-user-dirs-update does (in a way that would be reasonable while querying a folder path). And then I'm only talking about Ubuntu 22.04 here, not any other distro.
  • User folders could have been redirected to paths whose last segment don't make sense being appended to Public. Like a user redirecting all his sub folders to just his home when he doesn't like them, or in a folder named after a company, customer, or literally whatever. Extracting that segment may be completely unwanted and confusing "magic" and in the worst case even expose names in a shared folder which nobody should see. Detecting which names should not be used would be fool's errand.

So if you ask me, either use hardcoded English names, or not return any paths for these folders on Unix.
For simplicity and comparable behavior to other folders not supported on a system, I'd even prefer not returning a path.

@soc
Copy link

soc commented May 7, 2022

@RayKoopa

I don't know how to query the translations like xdg-user-dirs-update does

That's exactly what ReadXdgDirectory does – there is no need for anything beyond what's already implemented.

redirecting all his sub folders to just his home when he doesn't like them

I think this is already spelled out in the spec. There is no reason why subdirs should behave differently.

expose names in a shared folder which nobody should see

That's a good point!

or not return any paths for these folders on Unix

That also sounds fine to me.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

That's exactly what ReadXdgDirectory does – there is no need for anything beyond what's already implemented.

ReadXdgDirectory queries a full user folder path, not the system's translation for a folder name to be appended to the public folder. As mentioned, the user folder path cannot be processed in any way for that.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Agree here that the public subfolders should rather not return anything at all on Linux.

For consistency's sake, should MacOS not return anything for those subfolder as well then? Since they also technically do not exist there, and from what I understand from the docs they'd rather have only Users use those. Not to mention that those folders are translated in MacOS. Not via naming, but by having a .localized in the folder which the file explorer will then use to show a localized name of that folder. I.e. from Documents to Dokumente. Having suddenly English-named folders in a non-English environment would be a little weird, which could get mitigated by .NET always creating that .localized file, but that sounds like it'd create even more issues.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

Yeah, whenever I mentioned "Unix", I meant both macOS and Linux. And I agree, adding exceptionally much magic for determining these folder's names or getting them localized is not meaningful here.

After this discussion and my own personal reconsideration, I updated my recap to return empty paths on those systems.
After all, the reason the public subfolders were added was only because they are important on Windows. :-)

EDIT: Now my last bullet "Other "special" folders (like Windows' "Saved Games" or "Public Desktop") are not included due to them having no meaningful cross-platform counterpart." looks a little dumb. I could just aswell add those folders for Windows-only now.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Links | Stores Explorer pinned location shortcut files on < Windows 10.

Considering that Win7 is now EOL, with there only coming security updates, and everything before already being not supported, is this really worth adding?

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

Probably not - yet Windows 7 is still in extended support, and apparently going to be supported in .NET 7. I don't know about the support periods of Windows 8 right now but would assume they're longer. According to just this it would be better to add it.

However, the only use-case I could think of is someone designing their own OpenFileDialog or wanting to display user favorites - but they'd need special logic for Windows 10 anyway as it uses a different storage for managing "Quick Access". The Links folder still exists in Windows 10 but has no real use anymore IIRC (I think I actually deleted mine completely...).

EDIT: I rated this use case as quite exotic and moved that folder to ❌.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

You also might wanna include the PublicDesktop to the big table as well, since it's just another public subfolder.
NVM just remembered that PublicDesktop serves a different function

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

You're actually right, it should be in there given "Desktop" by itself is a common user folder on all systems, which I forgot. Adjusted my comment.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Behavior macOS iOS
Current ~/Videos ~/Videos
Proposed ~/Movies ~/Movies

#68610 does not move the iOS myVideos to Movies, only does for MacOS.
I honestly have no idea about anything iOS related, but from I've seen, file system access is very limited. The current iOS bindings for example return <DocumentsFolder>/Movies <DocumentsFolder>/Videos instead.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

I don't have an iPhone or iOS emulator here too, so I wonder if a participant of this discussion could check for the existence of either "Movies" or "Videos" on a relatively clean device / installation.

The current iOS bindings for example return <DocumentsFolder>/Movies instead.

To me that line of code looks like ~/Videos though, I understood your comment as ~/Documents/Movies.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

To me that line of code looks like ~/Videos though, I understood your comment as ~/Documents/Movies.

Last part was a typo, meant <DocumentsFolder>/Videos instead.

Look at: Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");. Quick reminder that Personal is the same as MyDocuments. Aka, this returns <DocumentsFolder> + Videos.

It should probably be still changed to <DocumentsFolder>/Movies tho, just to keep it consistent.

I also used <DocumentsFolder> here for a reason since it's very likely not in ~/Documents. Personal is called via NSDocumentDirecctory so this'll likely return the documents folder inside the sandboxed iOS app.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Just realized, that this also means that the iOS part in your Documents table is wrong as well. The Documents entry on iOS, from what I can see, doesn't need any updating at all.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

Look at: Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");. Quick reminder that Personal is the same as MyDocuments.

Right, I thought SpecialFolder.Personal is SpecialFolder.UserProfile (since that's what it always sounded like). Sorry about the confusion.

But I'm getting a bit more confused now, please let me know if I understood correctly:

  • Given NSMoviesDirectory, NSMusicDirectory etc, the user folder paths are at ~/Movies, ~/Music etc. as shown in my table above.
  • If you fix SpecialFolder.MyDocuments&SpecialFolder.Personal to return what would be NSDocumentDirectory / ~/Documents, then the code you linked to needs fixing and should use SpecialFolder.UserProfile instead of SpecialFolder.Personal.
  • Otherwise you would change the path to user folders like ~/Music to ~/Documents/Music that don't exist at all, have no meaning on the platform, and break existing applications.

Just realized, that this also means that the iOS part in your Documents table is wrong as well. The Documents entry on iOS, from what I can see, doesn't need any updating at all.

Understood and adjusted. Didn't expect the iOS code to be like "that" :-)

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Given NSMoviesDirectory, NSMusicDirectory etc, the user folder paths are at ~/Movies, ~/Music etc. as shown in my table above.

You need to differentiate here between iOS and MacOS.
In iOS, the NSDirectories are from what I can see never actually invoked except for NSDocumentsDirectory. In the file I linked, all the user folder paths redirect to <DocumentsFolder>/<UserFolder> instead of the filesystem one, due to the way iOS apps are sandboxed. NSDocumentsDirectory is also a different path from HOME.
On MacOS, while the NSDirectories are also never invoked, it (almost) returns the same directories as them. So yes.

If you fix SpecialFolder.MyDocuments&SpecialFolder.Personal to return what would be NSDocumentDirectory / ~/Documents, then the code you linked to needs fixing and should use SpecialFolder.UserProfile instead of SpecialFolder.Personal.

Nope, the way it is right now is intended. The UNIX changes do not affect iOS; iOS already invokes NSDocumentsDirectory for Personal/MyDocuments and checks HOME for UserProfile. And again, it uses NSDocumentsDirectory because of iOS apps are all sandboxed.

Otherwise you would change the path to user folders like ~/Music to ~/Documents/Music that don't exist at all, have no meaning on the platform, and break existing applications.

Sorry, I don't get quite what you're meaning with this.

If you're confused about the sandboxing and haven't looked at the doc I linked above:

For security purposes, an iOS app’s interactions with the file system are limited to the directories inside the app’s sandbox directory. [...] An app is generally prohibited from accessing or creating files outside its container directories.

In other words, no access to HOME, hence why all iOS folders instead point to their specifically designed directories.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

If I understood correctly, this means iOS apps have no way of accessing the ~/Music folders etc., and there's only a ~/Documents folder which is seen as the "user root folder"? Which is why the only way to retrieve a custom "Music" folder would be in ~/Documents/Music?

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

NSDocumentsDirectory != ~/Documents/ for iOS.
All programs on iOS are their own little folder, similar to an AppImage on Linux if you've ever dealt with those. So it points more to <wherever iOS stores apps>/MyApp/Documents/ as seen here:
image

this means iOS apps have no way of accessing the ~/Music folders etc.

It seems possible to do via NSSearchPathDirectory.NSMusicDirectory (or for the Apple docs here). I assume the reason why .NET links to local sandboxed folders instead is because unless there's a specific need to, apps shouldn't just break out of their sandbox. The docs for example never even mention anything iOS filesystem related outside of the sandbox:

users of iOS devices do not have direct access to the file system and apps are expected to follow this convention.

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

Okay, understood. Logically I'll just stay inside the sandboxed folders like .NET already does then, adding the Downloads folder like so:

return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Downloads");

I hope my iOS columns in my recap above are now correct at least.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

An Android column is missing as well btw. You can see current mappings here: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Environment.Android.cs#L35

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

I did not find the Android specific part which is why I thought it's handled by the "Linux (without XDG)" column. The linked file does not exist on the master branch, I suppose it is handled by Unix now, but I am not sure.

@Miepee
Copy link
Contributor

Miepee commented May 7, 2022

Sorry wrong link. Edited it.
From a first glance, it seems that Android folders should get some changing as well. I'd personally like to do the a seperate issue for that after #68610 gets merged, something I already mentioned in a comment of #63214

@RayKoopa
Copy link

RayKoopa commented May 7, 2022

Yeah, from my first uneducated look on that it seems that Personal/MyDocuments is "incorrect" on Android too. Should go in sync with your existing changes on macOS / Linux. Also, I'm not sure why UserProfile is retrieved from the HOME environment variable unlike the home path in that method itself using PersistedFiles.GetHomeDirectory(); even if there are technical reasons, the naming is very confusing to say the least.

I'll definitely wait until you finished your changes to not clash with them, and then update my post above to include Android.
New special folders have been asked for since their introduction in Windows Vista, they can certainly wait a bit more :-)

@soc
Copy link

soc commented May 7, 2022

ReadXdgDirectory queries a full user folder path, not the system's translation for a folder name to be appended to the public folder. As mentioned, the user folder path cannot be processed in any way for that.

The full folder path contains the user-desired name – searching for some translation that the user may or may not have chosen is not the correct approach – that's why I suggested XDG_PUBLICSHARE_DIR/last-path-component(XDG_DOWNLOAD_DIR).

Now, as mentioned, leaking that name might not be a good idea, so I'd be in favor of omitting the dir on Linux completely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Runtime
Projects
None yet
Development

No branches or pull requests