2

I want a safe way to get all of the files nested under the user folder (nominally C:\Users\TheUsersName). The problem is that most of the folders there are reparse points, so just iterating/recursing over the folder's folders will not return those folders, and therefore not the files under them as well.

The simple but unwanted solutions would be either to

  1. hard code those folders. - never a good idea. What if in the future a new one is added or one removed.
  2. for the UserProfile folder only, retrieve the folders that any reparse points under it point to. - not safe - may become cyclic.

So to sum up: is there any safe way to get all files under the user folder including those nested under the reparse points there?

Since (judging by the comments) it seems like this isn't clear. I'll state this explicitly:

I don't want to get the targets of the reparse points. Not even only in the specific case of UserProfile. Because there might be one pointing to UserProfile itself or a folder that contains it. I want some list of the normal (though not 'real') folders that are there like 'Documents' (which I would assume would not point to a folder that contains the UserProfile and therefore would not become cyclic). Or some other clean solution.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
ispiro
  • 26,556
  • 38
  • 136
  • 291
  • 1
    the title states ***get all folders...*** but the content states ***a safe way to get all the files...*** what should I do now? – ΦXocę 웃 Пepeúpa ツ Sep 05 '17 at 10:46
  • 1
    @ΦXocę웃Пepeúpaツ Well, I want the files, but the problem lies with the folders. But I see your point. I'm trying to think of a solution now. – ispiro Sep 05 '17 at 10:47
  • 1
    You can use Environment.UserFolder, insert it into FolderInfo and proceed from there. Is that what you meant? – Yaron Sep 05 '17 at 10:57
  • @Yaron You mean `DirectoryInfo`. The problem is that that folder's "folders" are not all _real_ folders. From [the docs](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree) "The .NET Framework methods such as GetFiles and GetDirectories will not return any subdirectories under a reparse point. ". (That's a good thing.) – ispiro Sep 05 '17 at 11:01
  • See: https://stackoverflow.com/questions/2302416/in-net-how-to-obtain-the-target-of-a-symbolic-link-or-reparse-point and google query to get to that was: c# get folder reparse point – Sorceri Sep 07 '17 at 17:22
  • @Sorceri Thanks. But that wasn't the question. I even suggested that as a (bad) option in my question. – ispiro Sep 07 '17 at 17:24
  • @ispiro you need to use Pinvoke to get the security attributes to check for the reparse point on a folder. Then can use the above to obtain those files. I will dig up a sample and post later, FindFirst, FindNextFile ect – Sorceri Sep 07 '17 at 17:33
  • A loop on `DirectoryInfo(@"c:\users\simon").GetDirectories()` does return all directories I see in explorer and cmd.exe. "most of the folders there are reparse points" not sure what you mean by that. – Simon Mourier Sep 07 '17 at 17:47
  • Well your question is confusing as you seem to contradict yourself here: So to sum up: is there any safe way to get all files under the user folder including those nested under the reparse points there? – Sorceri Sep 07 '17 at 17:58
  • @SimonMourier You appear to be correct. I based the question on my past experience (perhaps it was correct on Windows 7 and is not so now that the libraries have been deprecated.) I still see, though, that Documents does not appear to be a real folder as I'm getting an exception trying to get _its_ directories. I can't delete the question, so I think I'll edit it. You may post your comment as an answer, though. – ispiro Sep 07 '17 at 18:04
  • `string userprofileFolder = Environment.GetEnvironmentVariable("USERPROFILE"));` From there you should be able to use `DirectoryInfo(userprofileFolder).GetDirectories();` to get directory ` – Nkosi Sep 07 '17 at 18:04

1 Answers1

2

A simple loop like that:

foreach (var dir in new DirectoryInfo(@"c:\users\smo").GetDirectories())
{
    .... 
}

should return all folders in c:\users\smo.

As a side, note, a folder can't be a reparse point. A reparse point is some optional binary data associated with a file or folder. That data has a type ("tag") that indicates what to do with this extra information. One type of reparse point is a "mount point", used for the mounted folders feature. There are also NTFS symbolic links that use reparse points. I think you were talking about symbolic links here.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • The real question I think is how to avoid infinite recursion when you drill down into a folder like %USERPROFILE%. E.g. AppData\Local\Application Data\Application Data\Application Data\Application Data... – shurik Sep 07 '17 at 21:46
  • Thanks. (The system tells me I can't award the bounty yet.) In Windows 7, perhaps because of the "libraries", I would get exceptions when trying to get sub directories of some folders like documents. Now, it seems, I only get an error from "My Documents", and not from "Documents". – ispiro Sep 07 '17 at 21:46
  • @shurik Thanks. I originally thought that I'd have these recursion traps since I thought I'd need to go through reparse points. But since I don't - I just won't, and therefore the OS will take care of avoiding reparse points, as [the docs](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree) say "The .NET Framework methods such as GetFiles and GetDirectories will not return any subdirectories under a reparse point. ". – ispiro Sep 07 '17 at 21:50
  • @ispiro - how do you get those exceptions in the first place? from the explorer UI? from, code this will also work `new DirectoryInfo(@"c:\documents and settings\all users").GetDirectories()` – Simon Mourier Sep 07 '17 at 22:02
  • I read the doc, not sure, possibly I am missing something. I create a junction and a quick POC in C# and for me it does return sub-directories under the junction. foreach (var d in Directory.GetDirectories(@"D:\Temp\tptest", "*", System.IO.SearchOption.AllDirectories)) { Console.WriteLine(d); } prints: D:\Temp\tptest\dir D:\Temp\tptest\junction D:\Temp\tptest\dir\dir2 D:\Temp\tptest\junction\dir2 – shurik Sep 07 '17 at 22:02
  • @SimonMourier Iterate over all of the folders you get under user profile, and get _their_ folders. You'll see that you get exceptions when trying to get the directories of something called "my documents", though the folder called "documents" is fine. (the more plentiful exceptions were on a Win7 computer). – ispiro Sep 07 '17 at 22:08
  • Regarding exception, I get the same Access Denied error even in windows explorer. Somewhat related: https://answers.microsoft.com/en-us/windows/forum/windows_vista-files/cusersdickapplication-data-is-not-accessible/63159b50-efba-4941-a6d0-7e58d1ccba9c?auth=1 It does not explain why though. But the side effect is that probably for %USERPROFILE% it helps you to avoid the infinite loop – shurik Sep 07 '17 at 22:15
  • A quick test show 71K+ directories under my %USERPROFILE% w/o any recursivity issue. Only some report access denied which is normal, and totally unrelated to reparse points. – Simon Mourier Sep 07 '17 at 22:20
  • @SimonMourier In general there won't be any infinite loops. But if a user creates a reparse point pointing to a folder above itself - it will. And I as a developer want to handle that gracefully. – ispiro Sep 08 '17 at 10:06