@@ -10,6 +10,7 @@ namespace Menees
1010 using System . Linq ;
1111 using System . Security ;
1212 using System . Text ;
13+ using System . Xml ;
1314 using System . Xml . Linq ;
1415
1516 #endregion
@@ -30,11 +31,30 @@ public FileSettingsStore()
3031 {
3132 // Make sure the file exists and isn't zero length. If a process was killed while saving data,
3233 // then the settings store file may be empty. If so, we'll pretend it isn't there.
33- FileInfo file = new ( fileName ) ;
34- if ( file . Exists && file . Length > 0 )
34+ FileInfo fileInfo = new ( fileName ) ;
35+ if ( fileInfo . Exists && fileInfo . Length > 0 )
3536 {
36- this . root = XElement . Load ( fileName ) ;
37- break ;
37+ try
38+ {
39+ // Only read settings from a file that we have *write* access to so if we're running from a remote read-only file share,
40+ // then it will load a local saved file (e.g., from AppData) instead of loading one from the remote read-only share.
41+ using ( FileStream stream = new ( fileName , FileMode . Open , FileAccess . ReadWrite , FileShare . Read ) )
42+ {
43+ this . root = XElement . Load ( stream ) ;
44+ }
45+
46+ break ;
47+ }
48+ catch ( XmlException ex )
49+ {
50+ Log . Warning ( typeof ( FileSettingsStore ) , $ "Unable to load the user settings from { fileName } .", ex ) ;
51+ }
52+ catch ( Exception ex ) when ( Exceptions . IsAccessException ( ex ) )
53+ {
54+ // Ignore the file if we don't have both read and write access to it. If we're running off a read-only share,
55+ // we know Save() can't write back to that location, so we shouldn't read in from that location on startup.
56+ Log . Debug ( typeof ( FileSettingsStore ) , $ "Unable to get read/write access to { fileName } .", ex ) ;
57+ }
3858 }
3959 }
4060
@@ -85,28 +105,15 @@ public void Save()
85105 File . SetAttributes ( fileName , File . GetAttributes ( fileName ) | FileAttributes . Hidden ) ;
86106 break ;
87107 }
88- catch ( IOException inputOutputEx )
89- {
90- errorLogProperties . Add ( fileName , inputOutputEx ) ;
91- }
92- catch ( SecurityException securityEx )
108+ catch ( Exception ex ) when ( Exceptions . IsAccessException ( ex ) )
93109 {
94- errorLogProperties . Add ( fileName , securityEx ) ;
95- }
96- catch ( UnauthorizedAccessException accessEx )
97- {
98- errorLogProperties . Add ( fileName , accessEx ) ;
110+ errorLogProperties . Add ( fileName , ex ) ;
99111 }
100112 }
101113
102114 if ( ! saved )
103115 {
104- const string Message = "Unable to save the user settings to a file store." ;
105-
106- // Log out the exceptions first since we can't pass those additional
107- // details into the new exception we're throwing.
108- Log . Error ( typeof ( FileSettingsStore ) , Message , null , errorLogProperties ) ;
109- throw Exceptions . NewInvalidOperationException ( Message ) ;
116+ throw Exceptions . NewInvalidOperationException ( "Unable to save the user settings to a file store." , errorLogProperties ) ;
110117 }
111118 }
112119
@@ -126,7 +133,10 @@ private static IEnumerable<string> GetPotentialFileNames()
126133 List < string > result = new ( ) ;
127134
128135 // First, try the application's base directory. That gives the best isolation for side-by-side app usage,
129- // but a non-admin user may not have permissions to write to this directory.
136+ // but a non-admin user may not have permissions to write to this directory. Side-by-side isolation is
137+ // important if old and new versions of the software are run on the same machine. (New versions will
138+ // typically be able to read in old settings, but they'll only write out settings in the new format. After
139+ // that "upgrade", the old version wouldn't be able to read the settings in the new format.)
130140 string path = Path . Combine ( ApplicationInfo . BaseDirectory , fileName ) ;
131141 result . Add ( path ) ;
132142
0 commit comments