|  | 
|  | 1 | +// Licensed to the .NET Foundation under one or more agreements. | 
|  | 2 | +// The .NET Foundation licenses this file to you under the MIT license. | 
|  | 3 | + | 
|  | 4 | +using System.IO; | 
|  | 5 | +using System.Threading; | 
|  | 6 | +using System.Collections.Generic; | 
|  | 7 | +using System.Runtime.InteropServices; | 
|  | 8 | +using System.Diagnostics; | 
|  | 9 | + | 
|  | 10 | +namespace System | 
|  | 11 | +{ | 
|  | 12 | +    public static partial class Environment | 
|  | 13 | +    { | 
|  | 14 | +        private static Dictionary<SpecialFolder, string>? s_specialFolders; | 
|  | 15 | + | 
|  | 16 | +        private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) | 
|  | 17 | +        { | 
|  | 18 | +            if (s_specialFolders == null) | 
|  | 19 | +            { | 
|  | 20 | +                Interlocked.CompareExchange(ref s_specialFolders, new Dictionary<SpecialFolder, string>(), null); | 
|  | 21 | +            } | 
|  | 22 | + | 
|  | 23 | +            string? path; | 
|  | 24 | +            lock (s_specialFolders) | 
|  | 25 | +            { | 
|  | 26 | +                if (!s_specialFolders.TryGetValue(folder, out path)) | 
|  | 27 | +                { | 
|  | 28 | +                    path = GetSpecialFolder(folder) ?? string.Empty; | 
|  | 29 | +                    s_specialFolders[folder] = path; | 
|  | 30 | +                } | 
|  | 31 | +            } | 
|  | 32 | +            return path; | 
|  | 33 | +        } | 
|  | 34 | + | 
|  | 35 | +        private static string? GetSpecialFolder(SpecialFolder folder) | 
|  | 36 | +        { | 
|  | 37 | +            string? home = null; | 
|  | 38 | +            try | 
|  | 39 | +            { | 
|  | 40 | +                home = PersistedFiles.GetHomeDirectory(); | 
|  | 41 | +            } | 
|  | 42 | +            catch (Exception exc) | 
|  | 43 | +            { | 
|  | 44 | +                Debug.Fail($"Unable to get home directory: {exc}"); | 
|  | 45 | +            } | 
|  | 46 | + | 
|  | 47 | +            // Fall back to '/' when we can't determine the home directory. | 
|  | 48 | +            // This location isn't writable by non-root users which provides some safeguard | 
|  | 49 | +            // that the application doesn't write data which is meant to be private. | 
|  | 50 | +            if (string.IsNullOrEmpty(home)) | 
|  | 51 | +            { | 
|  | 52 | +                home = "/"; | 
|  | 53 | +            } | 
|  | 54 | + | 
|  | 55 | +            switch (folder) | 
|  | 56 | +            { | 
|  | 57 | +                case SpecialFolder.Personal: | 
|  | 58 | +                case SpecialFolder.LocalApplicationData: | 
|  | 59 | +                    return home; | 
|  | 60 | + | 
|  | 61 | +                case SpecialFolder.ApplicationData: | 
|  | 62 | +                    return Path.Combine(home, ".config"); | 
|  | 63 | + | 
|  | 64 | +                case SpecialFolder.Desktop: | 
|  | 65 | +                case SpecialFolder.DesktopDirectory: | 
|  | 66 | +                    return Path.Combine(home, "Desktop"); | 
|  | 67 | + | 
|  | 68 | +                case SpecialFolder.MyMusic: | 
|  | 69 | +                    return Path.Combine(home, "Music"); | 
|  | 70 | + | 
|  | 71 | +                case SpecialFolder.MyPictures: | 
|  | 72 | +                    return Path.Combine(home, "Pictures"); | 
|  | 73 | + | 
|  | 74 | +                case SpecialFolder.Templates: | 
|  | 75 | +                    return Path.Combine(home, "Templates"); | 
|  | 76 | + | 
|  | 77 | +                case SpecialFolder.MyVideos: | 
|  | 78 | +                    return Path.Combine(home, "Videos"); | 
|  | 79 | + | 
|  | 80 | +                case SpecialFolder.CommonTemplates: | 
|  | 81 | +                    return "/usr/share/templates"; | 
|  | 82 | + | 
|  | 83 | +                case SpecialFolder.Fonts: | 
|  | 84 | +                    return Path.Combine(home, ".fonts"); | 
|  | 85 | + | 
|  | 86 | +                case SpecialFolder.UserProfile: | 
|  | 87 | +                    return GetEnvironmentVariable("HOME"); | 
|  | 88 | + | 
|  | 89 | +                case SpecialFolder.CommonApplicationData: | 
|  | 90 | +                    return "/usr/share"; | 
|  | 91 | + | 
|  | 92 | +                default: | 
|  | 93 | +                    return string.Empty; | 
|  | 94 | +            } | 
|  | 95 | +        } | 
|  | 96 | +    } | 
|  | 97 | +} | 
0 commit comments