Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(774)

Side by Side Diff: obsolete/Microsoft.VisualStudio.Project/ProjectSecurityChecker.cs

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /// Copyright (c) Microsoft Corporation. All rights reserved.
2
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.IO;
9 using System.Runtime.InteropServices;
10 using System.Security.Permissions;
11 using System.Text;
12 using Microsoft.VisualStudio;
13 using Microsoft.VisualStudio.Build.ComInteropWrapper;
14 using Microsoft.VisualStudio.Shell;
15 using Microsoft.VisualStudio.Shell.Interop;
16 using Microsoft.Win32;
17
18 namespace Microsoft.VisualStudio.Project
19 {
20 /// <summary>
21 /// Does security validation of a project before loading the project
22 /// </summary>
23 public class ProjectSecurityChecker : IDisposable
24 {
25 #region constants
26 /// <summary>
27 /// The dangereous target property.
28 /// </summary>
29 internal const string DangerousTargetProperty = "LoadTimeSensiti veTargets";
30
31 /// <summary>
32 /// The dangereous properties property.
33 /// </summary>
34 internal const string DangerousPropertyProperty = "LoadTimeSensi tiveProperties";
35
36 /// <summary>
37 /// The dangereous items property.
38 /// </summary>
39 internal const string DangerousItemsProperty = "LoadTimeSensitiv eItems";
40
41 /// <summary>
42 /// The check item locations property.
43 /// </summary>
44 internal const string CheckItemLocationProperty = "LoadTimeCheck ItemLocation";
45
46 /// <summary>
47 /// The dangereous list item separator.
48 /// </summary>
49 internal const string DangerousListSeparator = ";";
50
51 /// <summary>
52 /// The project directory property.
53 /// </summary>
54 internal const string ProjectDirectoryProperty = "MSBuildProject Directory";
55
56 /// <summary>
57 /// The default dangereous properties.
58 /// </summary>
59 internal const string DefaultDangerousProperties = "LoadTimeSens itiveTargets;LoadTimeSensitiveProperties;LoadTimeSensitiveItems;LoadTimeCheckIte mLocation;";
60
61 /// <summary>
62 /// The default dangereous targets.
63 /// </summary>
64 internal const string DefaultDangerousTargets = "Compile;GetFram eworkPaths;AllProjectOutputGroups;AllProjectOutputGroupsDependencies;CopyRunEnvi ronmentFiles;ResolveComReferences;ResolveAssemblyReferences;ResolveNativeReferen ces;";
65
66 /// <summary>
67 /// The default dangereous items.
68 /// </summary>
69 internal const string DefaultDangerousItems = ";";
70
71 /// <summary>
72 /// Defined the safe imports subkey in the registry.
73 /// </summary>
74 internal const string SafeImportsSubkey = @"MSBuild\SafeImports" ;
75 #endregion
76
77 #region fields
78 /// <summary>
79 /// Defines an object that will be a mutex for this object for s ynchronizing thread calls.
80 /// </summary>
81 private static volatile object Mutex = new object();
82
83 /// <summary>
84 /// Flag determining if the object has been disposed.
85 /// </summary>
86 private bool isDisposed;
87
88 /// <summary>
89 /// The associated project shim for the project file
90 /// </summary>
91 private ProjectShim projectShim;
92
93 /// <summary>
94 /// The security check helper object used to call out to do nece ssary security checkings.
95 /// </summary>
96 private SecurityCheckHelper securityCheckHelper = new SecurityCh eckHelper();
97
98 /// <summary>
99 /// The associated service provider.
100 /// </summary>
101 private IServiceProvider serviceProvider;
102
103 #endregion
104
105 #region properties
106 /// <summary>
107 /// The associated project shim for the project file
108 /// </summary>
109 /// <devremark>The project shim is made internal in order to be able to be passed to the user project.</devremark>
110 internal protected ProjectShim ProjectShim
111 {
112 get { return this.projectShim; }
113 }
114
115 /// <summary>
116 /// The security check helper that will be used to perform the n ecessary checkings.
117 /// </summary>
118 protected SecurityCheckHelper SecurityCheckHelper
119 {
120 get { return this.securityCheckHelper; }
121 }
122
123 /// <summary>
124 /// The associated service provider.
125 /// </summary>
126 protected IServiceProvider ServiceProvider
127 {
128 get
129 {
130 return this.serviceProvider;
131 }
132 }
133 #endregion
134
135 #region ctors
136 /// <summary>
137 /// Overloaded Constructor
138 /// </summary>
139 /// <param name="projectFilePath">path to the project file</para m>
140 /// <param name="serviceProvider">A service provider.</param>
141 public ProjectSecurityChecker(IServiceProvider serviceProvider, string projectFilePath)
142 {
143 if(serviceProvider == null)
144 {
145 throw new ArgumentNullException("serviceProvider ");
146 }
147
148 if(String.IsNullOrEmpty(projectFilePath))
149 {
150 throw new ArgumentException(SR.GetString(SR.Para meterCannotBeNullOrEmpty, CultureInfo.CurrentUICulture), "projectFilePath");
151 }
152
153 this.serviceProvider = serviceProvider;
154
155 // Instantiate a new project shim that we are going to u se for security checkings.
156 EngineShim engine = new EngineShim();
157 this.projectShim = engine.CreateNewProject();
158 this.projectShim.Load(projectFilePath);
159 }
160 #endregion
161
162 #region IDisposable Members
163
164 /// <summary>
165 /// The IDispose interface Dispose method for disposing the obje ct determinastically.
166 /// </summary>
167 public void Dispose()
168 {
169 this.Dispose(true);
170 GC.SuppressFinalize(this);
171 }
172
173 #endregion
174
175 #region virtual methods
176 /// <summary>
177 /// Check if the project is safe at load/design time
178 /// </summary>
179 /// <param name="securityErrorMessage">If the project is not saf e contains an error message, describing the reason.</param>
180 /// <returns>true if the project is safe, false otherwise</retur ns>
181 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
182 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
183 public virtual bool IsProjectSafeAtLoadTime(out string securityE rrorMessage)
184 {
185 securityErrorMessage = String.Empty;
186
187 StringBuilder securityMessageMaker = new StringBuilder() ;
188 int counter = 0;
189 string tempMessage;
190
191 // STEP 1: Check direct imports.
192 if(!this.IsProjectSafeWithImports(out tempMessage))
193 {
194 ProjectSecurityChecker.FormatMessage(securityMes sageMaker, ++counter, tempMessage);
195 securityErrorMessage = tempMessage;
196 }
197
198 // STEP 2: Check dangerous properties
199 if(!this.IsProjectSafeWithProperties(out tempMessage))
200 {
201 ProjectSecurityChecker.FormatMessage(securityMes sageMaker, ++counter, tempMessage);
202 securityErrorMessage = tempMessage;
203 }
204
205 // STEP 3: Check dangerous targets
206 if(!this.IsProjectSafeWithTargets(out tempMessage))
207 {
208 ProjectSecurityChecker.FormatMessage(securityMes sageMaker, ++counter, tempMessage);
209 securityErrorMessage = tempMessage;
210 }
211
212 // STEP 4: Check dangerous items
213 if(!this.IsProjectSafeWithItems(out tempMessage))
214 {
215 ProjectSecurityChecker.FormatMessage(securityMes sageMaker, ++counter, tempMessage);
216 securityErrorMessage = tempMessage;
217 }
218
219 // STEP 5: Check UsingTask tasks
220 if(!this.IsProjectSafeWithUsingTasks(out tempMessage))
221 {
222 ProjectSecurityChecker.FormatMessage(securityMes sageMaker, ++counter, tempMessage);
223 securityErrorMessage = tempMessage;
224 }
225
226 // STEP 6: Check for items defined within the LoadTimeCh eckItemLocation, whether they are defined in safe locations
227 if(!this.CheckItemsLocation(out tempMessage))
228 {
229 securityMessageMaker.AppendFormat(CultureInfo.Cu rrentCulture, "{0}: ", (++counter).ToString(CultureInfo.CurrentCulture));
230 securityMessageMaker.AppendLine(tempMessage);
231 securityErrorMessage = tempMessage;
232 }
233
234 if(counter > 1)
235 {
236 securityErrorMessage = securityMessageMaker.ToSt ring();
237 }
238
239 return String.IsNullOrEmpty(securityErrorMessage);
240 }
241
242 /// <summary>
243 /// Checks if the project is safe with imports. The project file is considered
244 /// unsafe if it contains any imports not registered in the safe import regkey.
245 /// </summary>
246 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
247 /// <returns>true if the project is safe regarding imports.</ret urns>
248 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
249 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
250 protected virtual bool IsProjectSafeWithImports(out string secur ityErrorMessage)
251 {
252 securityErrorMessage = String.Empty;
253
254 // Now get the directly imports and do the comparision.
255 string[] directImports = this.securityCheckHelper.GetDir ectlyImportedProjects(this.projectShim);
256 if(directImports != null && directImports.Length > 0)
257 {
258 IList<string> safeImportList = ProjectSecurityCh ecker.GetSafeImportList();
259
260 for(int i = 0; i < directImports.Length; i++)
261 {
262 string fileToCheck = directImports[i];
263 if(!ProjectSecurityChecker.IsSafeImport( safeImportList, fileToCheck))
264 {
265 using(RegistryKey root = VSRegis try.RegistryRoot(__VsLocalRegistryType.RegType_Configuration))
266 {
267 securityErrorMessage = S tring.Format(CultureInfo.CurrentCulture, SR.GetString(SR.DetailsImport, CultureI nfo.CurrentUICulture), Path.GetFileName(this.projectShim.FullFileName), fileToCh eck, Path.Combine(root.Name, SafeImportsSubkey));
268 }
269
270 return false;
271 }
272 }
273 }
274
275 return true;
276 }
277
278
279
280 /// <summary>
281 /// Checks if the project is safe regarding properties.
282 /// </summary>
283 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
284 /// <returns>true if the project has only safe properties.</retu rns>
285 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
286 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
287 protected virtual bool IsProjectSafeWithProperties(out string se curityErrorMessage)
288 {
289 securityErrorMessage = String.Empty;
290
291 // Now ask the security check heper for the safe propert ies.
292 string reasonForFailure;
293 bool isUserFile;
294 bool isProjectSafe = this.securityCheckHelper.IsProjectS afe(ProjectSecurityChecker.DangerousPropertyProperty,
295 ProjectSecurityC hecker.DefaultDangerousProperties,
296 this.projectShim ,
297 null,
298 SecurityCheckPas s.Properties,
299 out reasonForFai lure,
300 out isUserFile);
301
302 if(!isProjectSafe)
303 {
304 securityErrorMessage = this.GetMessageString(rea sonForFailure, SR.DetailsProperty);
305 }
306
307 return isProjectSafe;
308 }
309
310 /// <summary>
311 /// Checks if the project is safe regarding targets.
312 /// </summary>
313 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
314 /// <returns>true if the project has only safe targets.</returns >
315 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
316 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
317 protected virtual bool IsProjectSafeWithTargets(out string secur ityErrorMessage)
318 {
319 securityErrorMessage = String.Empty;
320
321 // Now ask the security check heper for the safe targets .
322 string reasonForFailure;
323 bool isUserFile;
324 bool isProjectSafe = this.securityCheckHelper.IsProjectS afe(ProjectSecurityChecker.DangerousTargetProperty,
325 ProjectSecurityC hecker.DefaultDangerousTargets,
326 this.projectShim ,
327 null,
328 SecurityCheckPas s.Targets,
329 out reasonForFai lure,
330 out isUserFile);
331
332 if(!isProjectSafe)
333 {
334 securityErrorMessage = this.GetMessageString(rea sonForFailure, SR.DetailsTarget);
335 }
336
337 return isProjectSafe;
338 }
339
340 /// <summary>
341 /// Checks if the project is safe regarding items.
342 /// </summary>
343 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
344 /// <returns>true if the project has only safe items.</returns>
345 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
346 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
347 protected virtual bool IsProjectSafeWithItems(out string securit yErrorMessage)
348 {
349 securityErrorMessage = String.Empty;
350
351 // Now ask the security check heper for the safe items.
352 string reasonForFailure;
353 bool isUserFile;
354 bool isProjectSafe = this.securityCheckHelper.IsProjectS afe(ProjectSecurityChecker.DangerousItemsProperty,
355 ProjectSecurityC hecker.DefaultDangerousItems,
356 this.projectShim ,
357 null,
358 SecurityCheckPas s.Items,
359 out reasonForFai lure,
360 out isUserFile);
361
362 if(!isProjectSafe)
363 {
364 securityErrorMessage = this.GetMessageString(rea sonForFailure, SR.DetailsItem);
365 }
366
367 return isProjectSafe;
368 }
369
370 /// <summary>
371 /// Checks if the project is safe with using tasks.
372 /// </summary>
373 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
374 /// <returns>true if the project has no using tasks defined in t he project file.</returns>
375 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
376 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
377 protected virtual bool IsProjectSafeWithUsingTasks(out string se curityErrorMessage)
378 {
379 securityErrorMessage = String.Empty;
380
381 string[] usingTasks = this.securityCheckHelper.GetNonImp ortedUsingTasks(this.projectShim);
382
383 if(usingTasks != null && usingTasks.Length > 0)
384 {
385 securityErrorMessage = String.Format(CultureInfo .CurrentCulture, SR.GetString(SR.DetailsUsingTask, CultureInfo.CurrentUICulture) , Path.GetFileName(this.projectShim.FullFileName), usingTasks[0]);
386 return false;
387 }
388
389 return true;
390 }
391
392 /// <summary>
393 /// If the project contains the LoadTimeCheckItemsWithinProject Cone property, the method verifies that all the items listed in there are within the project cone.
394 /// Also checks that the project is not in Program Files or Win dows if the property was there.
395 /// </summary>
396 /// <param name="securityErrorMessage">At return describes the r eason why the projects is not considered safe.</param>
397 /// <returns>true if the project has no badly defined project it ems.</returns>
398 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi gn", "CA1021:AvoidOutParameters", MessageId = "0#",
399 Justification = "The error message needs to be an out pa rameter. We are following here the Try... method patterns.")]
400 protected virtual bool CheckItemsLocation(out string securityErr orMessage)
401 {
402 securityErrorMessage = String.Empty;
403
404 // Get the <LoadTimeCheckItemLocation> property from the project
405 string itemLocationProperty = this.projectShim.GetEvalua tedProperty(ProjectSecurityChecker.CheckItemLocationProperty);
406
407 if(String.IsNullOrEmpty(itemLocationProperty))
408 {
409 return true;
410 }
411
412 // Takes a semicolon separated list of entries, splits t hem and puts them into a list with values trimmed.
413 string[] items = itemLocationProperty.Split(ProjectSecur ityChecker.DangerousListSeparator.ToCharArray(), StringSplitOptions.RemoveEmptyE ntries);
414
415 IList<string> itemsToCheck = new List<string>();
416 foreach(string item in items)
417 {
418 itemsToCheck.Add(item.Trim());
419 }
420
421 // Now check the items for being defined in a safe locat ion.
422 string reasonForFailure;
423 ItemSecurityChecker itemsSecurityChecker = new ItemSecur ityChecker(this.serviceProvider, this.projectShim.FullFileName);
424 if(!itemsSecurityChecker.CheckItemsSecurity(this.project Shim, itemsToCheck, out reasonForFailure))
425 {
426 securityErrorMessage = String.Format(CultureInfo .CurrentCulture, SR.GetString(SR.DetailsItemLocation, CultureInfo.CurrentUICultu re), Path.GetFileName(this.projectShim.FullFileName), reasonForFailure);
427 return false;
428 }
429
430 return true;
431 }
432
433
434 /// <summary>
435 /// The method that does the cleanup.
436 /// </summary>
437 /// <param name="disposing">true if called from IDispose.Dispose ; false if called from Finalizer.</param>
438 protected virtual void Dispose(bool disposing)
439 {
440 // Everybody can go here.
441 if(!this.isDisposed)
442 {
443 // Synchronize calls to the Dispose simultanious ly.
444 lock(Mutex)
445 {
446 if(disposing)
447 {
448 this.projectShim.ParentEngine.Un loadProject(this.projectShim);
449 }
450
451 this.isDisposed = true;
452 }
453 }
454 }
455 #endregion
456
457 #region helper methods
458 /// <summary>
459 /// Gets a message string that has an associated format with a r eason for failure.
460 /// </summary>
461 /// <param name="reasonForFailure"></param>
462 /// <param name="resourceID"></param>
463 /// <returns></returns>
464 internal string GetMessageString(string reasonForFailure, string resourceID)
465 {
466 Debug.Assert(!String.IsNullOrEmpty(reasonForFailure), "T he reason for failure should not be empty or null");
467 Debug.Assert(!String.IsNullOrEmpty(resourceID), "The res ource id string cannot be empty");
468
469 return String.Format(CultureInfo.CurrentCulture, SR.GetS tring(resourceID, Path.GetFileName(this.projectShim.FullFileName), reasonForFail ure));
470 }
471
472 /// <summary>
473 /// Generates a format string that will be pushed to the More De tailed dialog.
474 /// </summary>
475 /// <param name="securityMessageMaker">The Stringbuilder object containing the formatted message.</param>
476 /// <param name="counter">The 'issue' number.</param>
477 /// <param name="securityErrorMessage">The message to format.</p aram>
478 private static void FormatMessage(StringBuilder securityMessageM aker, int counter, string securityErrorMessage)
479 {
480 securityMessageMaker.AppendFormat(CultureInfo.CurrentCul ture, "{0}: ", counter.ToString(CultureInfo.CurrentCulture));
481 securityMessageMaker.AppendLine(securityErrorMessage);
482 securityMessageMaker.Append(Environment.NewLine);
483 }
484
485 /// <summary>
486 /// Returns a set of file info's describing the files in the Saf eImports registry location.
487 /// </summary>
488 /// <returns>A set of FileInfo objects describing the files in t he SafeImports location.</returns>
489 private static IList<string> GetSafeImportList()
490 {
491 List<string> importsList = new List<string>();
492
493 using(RegistryKey root = VSRegistry.RegistryRoot(__VsLoc alRegistryType.RegType_Configuration))
494 {
495 if(root != null)
496 {
497 using(RegistryKey key = root.OpenSubKey( SafeImportsSubkey))
498 {
499 if(key != null)
500 {
501 foreach(string value in key.GetValueNames())
502 {
503 string keyValue = key.GetValue(value, String.Empty, RegistryValueOptions.None) as string;
504 // Make sure tha t the environment variables are expanded.
505 keyValue = Syste m.Environment.ExpandEnvironmentVariables(keyValue);
506 Uri uri;
507 if(!String.IsNul lOrEmpty(keyValue) && Uri.TryCreate(keyValue, UriKind.Absolute, out uri) && uri. IsAbsoluteUri)
508 {
509 importsL ist.Add(keyValue);
510 }
511 }
512 }
513 }
514 }
515 }
516
517 return importsList;
518 }
519
520 /// <summary>
521 /// Checks if an import is a safe import.
522 /// </summary>
523 /// <param name="safeImportsList">A list of safe imports from te h registry.</param>
524 /// <param name="fileToCheck">The file to check.</param>
525 /// <returns>true if the file to check can be found in the safe import list</returns>
526 private static bool IsSafeImport(IList<string> safeImportsList, string fileToCheck)
527 {
528 foreach(string safeImport in safeImportsList)
529 {
530 if(NativeMethods.IsSamePath(safeImport, fileToCh eck))
531 {
532 return true;
533 }
534 }
535
536 return false;
537 }
538 #endregion
539
540 #region nested types
541 /// <summary>
542 /// Class for checking that the items defined in LoadTimeCheckIt emLocation are being defined in safe locations.
543 /// </summary>
544 private class ItemSecurityChecker
545 {
546 #region fields
547 /// <summary>
548 /// The associated service provider.
549 /// </summary>
550 private IServiceProvider serviceProvider;
551
552 /// <summary>
553 /// The solutionFolder;
554 /// </summary>
555 private Uri solutionFolder;
556
557 /// <summary>
558 /// The project folder
559 /// </summary>
560 private Uri projectFolder;
561
562 /// <summary>
563 /// The set of special folders.
564 /// </summary>
565 private IList<Uri> specialFolders;
566 #endregion
567
568 #region ctors
569 /// <summary>
570 /// Overloaded Constructor
571 /// </summary>
572 /// <param name="projectFilePath">path to the project fi le</param>
573 /// <param name="serviceProvider">A service provider.</p aram>
574 internal ItemSecurityChecker(IServiceProvider servicePro vider, string projectFullPath)
575 {
576 this.serviceProvider = serviceProvider;
577
578 // Initialize the project and solution folders.
579 this.SetProjectFolder(projectFullPath);
580 this.SetSolutionFolder();
581
582 // Set the special folders. Maybe this should be a static.
583 this.specialFolders = ItemSecurityChecker.SetSpe cialFolders();
584 }
585 #endregion
586
587 #region methods
588 /// <summary>
589 /// Checks whether a set of project items described by t he LoadTimeCheckItemLocation are in a safe location.
590 /// </summary>
591 /// <param name="projectShim">The project shim containin g the items to be checked.</param>
592 /// <param name="itemsToCheck">The list of items to chec k if they are in the project cone.</param>
593 /// <param name="reasonForFailure">The reason for failur e if any of the files fails</param>
594 /// <returns>true if all project items are in the projec t cone. Otherwise false.</returns>
595 internal bool CheckItemsSecurity(ProjectShim projectShim , IList<string> itemsToCheck, out string reasonForFailure)
596 {
597 reasonForFailure = String.Empty;
598
599 // If nothing to check assume that everything is ok.
600 if(itemsToCheck == null)
601 {
602 return true;
603 }
604
605 Debug.Assert(projectShim != null, "Cannot check the items if no project has been defined!");
606
607 foreach(string itemName in itemsToCheck)
608 {
609 BuildItemGroupShim group = projectShim.G etEvaluatedItemsByNameIgnoringCondition(itemName);
610 if(group != null)
611 {
612 IEnumerator enumerator = group.G etEnumerator();
613 while(enumerator.MoveNext())
614 {
615 BuildItemShim item = enu merator.Current as BuildItemShim;
616
617 string finalItem = item. FinalItemSpec;
618
619 if(!String.IsNullOrEmpty (finalItem))
620 {
621 // Perform the a ctual check - start with normalizing the path. Relative paths
622 // should be tre ated as relative to the project file.
623 string fullPath = this.GetFullPath(finalItem);
624
625 // If the fullpa th of the item is suspiciously short do not check it.
626 if(fullPath.Leng th >= 3)
627 {
628 Uri uri = null;
629
630 // If we cannot create a uri from the item path return with the error
631 if(!Uri. TryCreate(fullPath, UriKind.Absolute, out uri))
632 {
633 reasonForFailure = fullPath;
634 return false;
635 }
636
637 // Check if the item points to a network share
638 if(uri.I sUnc)
639 {
640 reasonForFailure = fullPath;
641 return false;
642 }
643
644 // Check if the item is located in a drive root directory
645 if(uri.S egments.Length == 3 && uri.Segments[1] == ":" && uri.Segments[2][0] == Path.Dire ctorySeparatorChar)
646 {
647 reasonForFailure = fullPath;
648 return false;
649 }
650
651 //Check if the item is not in a special folder.
652 foreach( Uri specialFolder in this.specialFolders)
653 {
654 if(ItemSecurityChecker.IsItemInCone(uri, specialFolder))
655 {
656 reasonForFailure = fullPath;
657 return false;
658 }
659 }
660 }
661 else
662 {
663 reasonFo rFailure = fullPath;
664 return f alse;
665 }
666 }
667 }
668 }
669 }
670
671 return true;
672 }
673
674
675 /// <summary>
676 /// Gets the list of special directories. This method sh ould be optimized if called more then once.
677 /// </summary>
678 /// <returns>The list of special directories</returns>
679 private static IList<Uri> SetSpecialFolders()
680 {
681 string[] specialFolderArray = new string[5]
682 {
683 Environment.GetFolderPath(Environment.SpecialFolder.System),
684 Environment.GetFolderPath(Environment.SpecialFolder.ProgramFi les),
685 Environment.GetFolderPath(Environment.SpecialFolder.Startup),
686 ItemSecurityChecker.GetSpecialDirectoryFromNative(NativeMetho ds.ExtendedSpecialFolder.Windows),
687 ItemSecurityChecker.GetSpecialDirectoryFromNative(NativeMetho ds.ExtendedSpecialFolder.CommonStartup)
688 };
689
690 List<Uri> specialFolders = new List<Uri>(5);
691
692 // Add trailing backslash to the folders.
693 foreach(string specialFolder in specialFolderArr ay)
694 {
695 string tempFolder = specialFolder;
696 if(!tempFolder.EndsWith("\\", StringComp arison.Ordinal))
697 {
698 tempFolder += "\\";
699 }
700
701 specialFolders.Add(new Uri(tempFolder));
702 }
703
704 return specialFolders;
705 }
706
707 /// <summary>
708 /// Some special folders are not supported by System.Env ironment.GetFolderPath. Get these special folders using p/invoke.
709 /// </summary>
710 /// <param name="specialFolder">The type of special fold er to retrieve.</param>
711 /// <returns>The folder path</returns>
712 private static string GetSpecialDirectoryFromNative(Nati veMethods.ExtendedSpecialFolder extendedSpecialFolder)
713 {
714 string specialFolder = null;
715 IntPtr buffer = IntPtr.Zero;
716
717 // Demand Unmanaged code permission. It should b e normal to demand UnmanagedCodePermission from an assembly integrating into VS.
718 new SecurityPermission(SecurityPermissionFlag.Un managedCode).Demand();
719 try
720 {
721 buffer = Marshal.AllocHGlobal((NativeMet hods.MAX_PATH + 1) * 2);
722 IntPtr[] pathIdentifier = new IntPtr[1];
723
724 if(ErrorHandler.Succeeded(UnsafeNativeMe thods.SHGetSpecialFolderLocation(IntPtr.Zero, (int)extendedSpecialFolder, pathId entifier)) && UnsafeNativeMethods.SHGetPathFromIDList(pathIdentifier[0], buffer) )
725 {
726 specialFolder = Marshal.PtrToStr ingAuto(buffer);
727 }
728 }
729 finally
730 {
731 if(buffer != IntPtr.Zero)
732 {
733 Marshal.FreeHGlobal(buffer);
734 }
735 }
736
737
738 return specialFolder;
739 }
740
741
742 /// <summary>
743 /// Checks if the itemToCheck is in the cone of the base Uri.
744 /// </summary>
745 /// <param name="itemToCheck">The item to check</param>
746 /// <param name="baseUri">The base to the item. This sho uld define a folder.</param>
747 /// <returns>true if the item to check is in the cone of the baseUri.</returns>
748 private static bool IsItemInCone(Uri itemToCheck, Uri ba seUri)
749 {
750 Debug.Assert(itemToCheck != null && baseUri != n ull, "Cannot check for items since the input is wrong");
751 Debug.Assert(!NativeMethods.IsSamePath(Path.GetD irectoryName(baseUri.LocalPath), baseUri.LocalPath), "The " + baseUri.LocalPath + " is not a folder!");
752
753 return (itemToCheck.IsFile && baseUri.IsFile &&
754 String.Compare(itemToCheck.LocalPath, 0, baseUri.LocalPath, 0, baseUri.LocalPath.Length, StringComparison.OrdinalIgnoreC ase) == 0);
755 }
756
757 /// <summary>
758 /// Sets the solution folder.
759 /// </summary>
760 private void SetSolutionFolder()
761 {
762 if(this.solutionFolder != null)
763 {
764 return;
765 }
766
767 IVsSolution solution = this.serviceProvider.GetS ervice(typeof(SVsSolution)) as IVsSolution;
768 Debug.Assert(solution != null, "Could not retrie ve the solution service from the global service provider");
769
770 string solutionDirectory, solutionFile, userOpti onsFile;
771
772 // We do not want to throw. If we cannot set the solution related constants we set them to empty string.
773 ErrorHandler.ThrowOnFailure(solution.GetSolution Info(out solutionDirectory, out solutionFile, out userOptionsFile));
774
775 if(String.IsNullOrEmpty(solutionDirectory))
776 {
777 return;
778 }
779
780 // Make sure the solution dir ends with a backsl ash
781 if(solutionDirectory[solutionDirectory.Length - 1] != Path.DirectorySeparatorChar)
782 {
783 solutionDirectory += Path.DirectorySepar atorChar;
784 }
785
786 Uri.TryCreate(solutionDirectory, UriKind.Absolut e, out this.solutionFolder);
787
788 Debug.Assert(this.solutionFolder != null, "Could not create the Uri for the solution folder");
789 }
790
791 /// <summary>
792 /// Sets the project folder.
793 /// </summary>
794 /// <param name="projectFullPath">The path to the projec t</param>
795 private void SetProjectFolder(string projectFullPath)
796 {
797 if(this.projectFolder != null)
798 {
799 return;
800 }
801
802 string tempProjectFolder = Path.GetDirectoryName (projectFullPath);
803
804 // Make sure the project dir ends with a backsla sh
805 if(!tempProjectFolder.EndsWith("\\", StringCompa rison.Ordinal) && !tempProjectFolder.EndsWith("/", StringComparison.Ordinal))
806 {
807 tempProjectFolder += "\\";
808 }
809
810 Uri.TryCreate(tempProjectFolder, UriKind.Absolut e, out this.projectFolder);
811
812 Debug.Assert(this.projectFolder != null, "Could not create the Uri for the project folder");
813 }
814
815 /// <summary>
816 /// Gets the fullpath of an item.
817 /// Relative pathes are treated as relative to the proje ct file.
818 /// </summary>
819 /// <param name="item">The item.</param>
820 /// <returns>The ful path of the item.</returns>
821 private string GetFullPath(string item)
822 {
823 Url url;
824 if(Path.IsPathRooted(item))
825 {
826 // Use absolute path
827 url = new Microsoft.VisualStudio.Shell.U rl(item);
828 }
829 else
830 {
831 // Path is relative, so make it relative to project path
832 url = new Url(new Url(this.projectFolder .LocalPath), item);
833 }
834
835 return url.AbsoluteUrl;
836 }
837 #endregion
838 }
839 #endregion
840 }
841 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698