Remove all files created by specifed user - c#

I have quotas-enabled drive and I want to remove all files created by specifed user (actually a set of applications that runs using special account) from that drive. How can I do this without recursivly checking all files and folders on HDD is it created by specifed user or not? I just need to get "iterator".

Take a look on following example
[Test]
public void Test()
{
string user = #"Domain\UserName";
var files = Directory.EnumerateFiles(#"C:\TestFolder")
.Where(x => IsOwner(x, user));
Parallel.ForEach(files, File.Delete);
}
private static bool IsOwner(string filePath, string user)
{
return string.Equals(File.GetAccessControl(filePath).GetOwner(typeof (NTAccount)).Value, user,
StringComparison.OrdinalIgnoreCase);
}

In term of improving performance, I think you could use Task Parallel Library when using recursive algorithm to search file and folder.
Another way, you could do that Lucence was a useful framework for search and it was already published version for .NET

Actually, you can do that iteratively and very efficiently using USN Change Journal, see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363798.aspx. With proper use of filtering, you can get list of files created by specific user within specific time period.
On the other hand, this technique is quite complicated and is suitable for time-critical applications; if efficiency is not the focal point of your application, I'd choose simpler solution.

Related

How not to allow running some parts of a script by different users at the exact moment of time?

everyone!
I do a small project for my company and I use C#. I have a script for my project. But before this day, my colleagues and I had an idea that the script would be used by users one by one. For example, if there are a user A and user B, there can be the order where the user B runs the script and only then the user A can run the script.
Today the decision was made to give the users the possibility to run the script freely without the predetermined order. And now I have some thoughts. Here the part of the script:
if (Directory.Exists(#"H:\" + doc_number + #"\detached") == false)
{
Directory.CreateDirectory(#"H:\" + doc_number + #"\detached");
File.WriteAllBytes(#"H:\" + doc_number + #"\detached\1.cms", signature_bytes);
}
else
{
string[] files = Directory.GetFiles(#"H:\" + doc_number + #"\detached"); int files_number = files.Length;
File.WriteAllBytes(#"H:\" + doc_number + #"\detached\" + Convert.ToString(files_number + 1) + ".cms", signature_bytes);
}
Firstly, there is a check of the existence of a directory. If it doesn't exist, the directory will be created and the first file will be added there. Otherwise, we just count the number of files in the directory and then create a new file with a name which is the number of the files in the folder plus one.
However, I'm thinking about the situation when the user A and the user B were at the beginning of this part of the script at the same time and the condition for both would be positive so it wouldn't be executed correctly. Or if one of them started running this part earlier but his or her PC was less powerful so while creating the directory another user would go through the condition, counting files and start creating a file before the first user which would be also incorrect.
I don't know how likely one of these situations are. if so, how can I solve it?
Indeed, you can run into concurrency issues. And you are correct that you can't rely on the existence of a directory to decide what branch to take in your if statement because you might have operations execute in this order:
User A: Checks for directory. Does not exist.
User B: Checks for directory. Does not exist.
User A: Creates directory, enters if branch.
User B: Creates directory, enters if branch.
If the code was running in one process on one machine but in multiple threads, you could use a lock statement.
If the code was running on different processes on the same machine, you could use a cross-process coordination method such as a Mutex.
The question implies that the code runs on different computers but accesses the same file system. In this case, a lock file is a common mechanism to coordinate access to a shared resource. In this approach, you would attempt to create a file and lock it. If that file already exists and is locked by another process, you know someone else got there first. Depending on your needs, a common scenario is to wait for the lock on the file to go away then acquire the lock yourself and continue.
This strategy also works for the other 2 cases above, though is less efficient.
For information about how to create a file with a lock, see
How to lock a file with C#?
There are some issues with your code. For example, what would happen if a file is deleted? The number of files in the directory would be different than the number of the last file, and you can end up trying to write a file that already exists. Also, please use Path.Combine to create paths, it is safer. You also don't need to check if the directory exists, since Directory.Create will do nothing if it already exists.
Common for all solutions bellow:
string baseDir = Path.Combine("H:",doc_number, "detached");
Directory.Create(baseDir);
If you just want any number of users to create files in the same directory, some solutions that are more safe:
Use a GUID:
var guid = Guid.NewGuid();
var file = Path.Combine(baseDir, $"{guid}.cms");
File.WriteAllBytes(file, signature_bytes);
Iterate, trying to create a new file:
bool created = false;
int index = 1;
while(!created)
{
//Check first if the file exists, and gets the next available index
var file = Path.Combine(baseDir, $"{index}.cms");
while(File.Exists(file))
{
file = Path.Combine(baseDir, $"{++index}.cms");
}
//Handle race conditions, if the file was created after we checked
try
{
//Try create the file, not allowing others to acess it while open
using var stream = File.Open(file,FileMode.CreateNew,FileAccess.Write,FileShare.None);
stream.Write(signature_bytes);
created = true;
}
catch (IOException) //If the file already exists, try the next index
{
++index;
}
}

Intercept MS Windows 'SendTo' menu calls?

SCENARIO
I manage and organize many files during the day, the SendTo is the most used feature that I use on Windows.
PROBLEM
By default, when the user clicks an item/link of the contextmenu to send the files, the O.S does not show any kind of advise/notifier indicating that the files are copying to the selected destination.
I consider it a very wrong design issue because for big files its OK ...a progressbar will be shown, but if the files are to small it will not show any progressbar/visual indicator so is not possible to ensure that the files are copied (without manual effort) because I'm human and I could click outside the SendTo contextmenu by error.
So, I would like to develop a personal mini-tool that will help me to optimize my time showing me a notifier window wherever on the screen when I send/copy files using the SendTo feature from the contextmenu, and only the SendTo feature.
QUESTION
In just simple words, I want to detect a copy/send operation from SendTo menu to ensure that the click was done properly on the menu item (and not outside the menu), by also providing additional basic info such as the source folder, the destination folder, and the amount of files or the filepaths.
Any ideas to start developing this tool in the right direction?.
I will be grateful for a code example in C# or else VB.Net, preferably this last.
APPROACH
Since I don't know how to start doing this I mean which could be the easiest or the efficient way to intercept those SendTo calls, firstly I thought to hook the CopyFile or CopyFileEx API functions, but they do not provide the information that I need because that function will be called in any kind of copy operation and not only when I use the SendTo Feature, so I'm lost.
I'm not sure if I should investigate more about internal calls, or maybe investigate more about the windows contextmenu itself instead of messing with function hooks and ugly things that I could avoid.
My main idea is to develop a hidden WinForms (or else a windows service) that stays in background waiting for when I use the SendTo feature (when I click on an item of the SendTo menu) and then show any kind of visual indicator on the screen to ensure that I properly clicked that menu-item and maybe inform about the amount of files that I'm moving and where I'm moving them.
RESEARCH
Here is a code example that I think it demostrates how to instantiate the SendTo com object to create your own?, but its written in c++ and I'm not sure if the example is helpful because my intention is not to replace the SendTo menu but I'll keep this useful info here it it serves for something else:
How to add(enable) standard "Send To" context menu option in a namespace extension
The KNOWNFOLDERID constants docs gives some useful info about the SendTo folder, again I'm not sure if this could help maybe for a read/access monitoring approach?, I just keep the info here:
GUID: {8983036C-27C0-404B-8F08-102D10DCFD74}
Default Path: %APPDATA%\Microsoft\Windows\SendTo
Legacy Default Path: %USERPROFILE%\SendTo
In the Shell Extension Handlers docs there is a Copy hook handler which I don't know if it has relation with the SendTo's COM component and if that could help me in some way,
the same ignorance for IContextMenu::InvokeCommand method reference which maybe I could intercept it to identify a SendTo invocation?
By the moment I feel like flying blind.
I recently found this A managed "Send To" menu class but again its a example written in C/C++ (I think is the same source before) which I don't understand at all and again I'm not sure if that could help me because I repeat that replacing SendTo is not what I have in mind (just because I don't know how to properly do it avoiding all possible risks, I prefer to still let Windows logic copy/send the files, I just want to detect the copy operation to retrieve info)
EXPECTED RESULTS AND USAGE
Step 1:
Select a random file and use the SendTo menu (in my language, Spanish, the command name is 'Enviar a')
Step 2:
Let the .net application's logic (working in background) intercept the SendTo operation to retrieve info.
(I only need help with this step)
Step 3:
Display the info somewhere over the screen to ensure that the SendTo operation was performed, to ensure that I properly clicked the SendTo item (My Link).
(That popup is just a simulation, I don't know any way to retrieve all that info)
It's really simple to do once you understand what SendTo really does, and it doesn't involves COM or shell extensions at all. Basically, the send to menu is populated with the content of the SendTo folder of the user profile (C:\Users\\AppData\Roaming\Microsoft\Windows\SendTo by default in Windows 6.x).
When clicked, if the option is a shortcut to a folder it will copy the files there, but if there is a shortcut to a program (or a program executable itself) it will run that program, passing the paths of the selected files as command-line arguments.
From there, it's really trivial to make some program that simply takes paths as arguments, present some kind of notification and then copies the files or do whatever you want with them.
A quick and dirty example could be as follow (in C#, but could be done with anything else really):
private static void Main(string[] args)
{
if(MessageBox.Show("Are you sure you want to copy files?", "Copy files", MessageBoxButtons.YesNo) == DialogResult.No) return;
foreach (string file in args)
File.Copy(file, Path.Combine("c:\\temp", Path.GetFileName(file));
}
This just ask for confirmation for copying a bunch of files. Note that this really doesn't "intercepts" the send to menu, but rather handles it completely, so it's the program responsability to do any meaningful action. A more serious implementation could use the built-in Windows copy dialog and display some screen with progress or anything else, that's up to your needs.
It could also take some more parameters on the command line. When you place a shortcut in the SendTo folder, the destination could add some more parameters that will be passed as the first ones (before the file names). For example the destination of the shortcut can read c:\program files\copyfiles.exe c:\temp to pass the destination folder instead of hardcoding. The called program must then interpret the first parameter as the destination path and subsequent ones as the source files.
I've had to do something like this before. You don't even have to intercept the SendTo() function, you only need to make sure the the file has arrived. How about FileSystemWatcher if it's on the same computer?
You could use a watcher to watch before you send it, then, if the file successfully arrives at it's destination, you can display a successful message, and then kill the watcher.
Code Example
// Create a FileSystemWatcher property.
FileSystemWatcher fsw { get; set; }
// So we can set the FileToWatch within WatchFilesBeforeTransfer().
private string FileToWatch { get; set; }
private void WatchFilesBeforeTransfer(string FileName, string DestinationFolder)
{
fsw = new FileSystemWatcher();
fsw.Path = DestinationFolder;
FileToWatch = FileName;
// Only if you need support for multiple directories. Code example note included.
fsw.InclueSubdirectories = true;
// We'll be searching for the file name and directory.
fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName
// If it's simply moving the file to another location on the computer.
fsw.Renamed += new RenamedEventHandler(FileRenamed);
// If it was copied, not moved or renamed.
fsw.Created += new FileSystemEventHandler(FileCreated);
fsw.EnableRaisingEvents = true;
}
// If the file is just renamed. (Move/Rename)
private void FileRenamed(Object source, RenamedEventArgs e)
{
// Do something.
// Note that the full filename is accessed by e.FullPath.
if (e.Name == FileToWatch)
{
DisplaySuccessfulMessage(e.Name);
KillFileWatcher();
}
}
// If creating a new file. (Copied)
private void FileCreated(Object source, FileSystemEventArgs e)
{
// Do something.
// Note that the full filename is accessed by e.FullPath.
if (e.Name == FileToWatch)
{
DisplaySuccessfulMessage(e.Name);
KillFileWatcher();
}
}
private void KillFileWatcher()
{
fsw.Dispose();
}
You can access the desired property information (like in your popup gif) in this way:
Folder name: Path.GetDirectory(e.FullPath); (like "C:\yo\")
Full file name: e.FullPath (like "C:\yo\hey.exe")
File name: e.Name (like "hey.exe")
Non-code execution process:
Before you initiate SendTo(), create an instance of the FileSystemWatcher property, and have it watch for a specific Folder/File name combination, which should show up in the watched folder: WatchFilesBeforeTransfer(FileName, DestinationFolder).
Initiate SendTo().
File received? DisplaySuccessfulSendToMessage(), KillFileWatcher();
???
Profit.
UPDATE:
I just realized that's just for one file. If you want to check for multiple files, you could either create multiple FileWatcher instances (not recommended), or use a List<string> object, like this:
private void SendTo(List<string> FileCollection)
{
// Clear your previous FileList.
FileList.Clear();
foreach (string file in FileCollection)
{
FileList.Add(file);
}
// Rest of the code.
}
List<string> FileList { get; set; }
private void WatchFilesBeforeTransfer(string DestinationFolder)
{
// Same code as before, but delete FileToWatch.
}
private void FileRenamed(Object source, RenamedEventArgs e)
{
foreach (string file in FileList)
{
if (e.Name == file)
{
// Do stuff.
}
}
}
private void FileCreated(Object source, FileSystemEventArgs e)
{
foreach (string file in FileList)
{
if (e.Name == file)
{
// Do stuff.
}
}
}
Hope this helps!
I'm afraid this ain't that easy.
I was playing around with the FileSystemWatcher on this, but with only partly success.
Something that should definitely work are File system drivers but this looks like just too, well, look at it...
In the end it might be the easiest way to write your own shell extension to access the SendTo folder, and use this instead of the SentTo command which would give you full control.
These might be some starters:
Windows shell extensions
Shell Context Menus
Maybe I come a little bit late to answer my own question, which was published on year 2015, but it wasn't until few days ago that I became interested in this matter again, with much more experience and knowledge gained in .NET after these years to start from scratch and try to understand everything that I did not understood in the past.
I just discovered that, as #Ňɏssa Pøngjǣrdenlarp already commented in the comments box, apparently the most viable way to accomplish this would be to implement my own SendTo context menu and use IFileOperationProgressSink interface to report progress, which for this firstly I need to depend on the usage of IFileOperation interface.
The reason to use the IFileOperation interface is because it seems the only way offered in the Windows API to let the developer perform multiple file operations (copy, move, rename, create or delete) all at once within the same progress dialog UI. This is probably the interface used by the system when the user selects multiple files or directories (via the SendTo menu or just CTRL+C and CTRL+V) to move or copy them at once, because it only shows one progress dialog with all the copy operations queued in it...
So clearly IFileOperation and IFileOperationProgressSink interfaces were what I need. But from what I know there is no managed implementation of these interfaces in the .NET framework namespaces (neither in the Microsoft's WindowsAPICodePack library), which seems somewhat inexcusable to me considering that these interfaces exists since the era of Windows VISTA or even earlier, and it is an indisputable improvement being the totally opposite of any built-in members that you can think of to perform copy, move, rename, create or delete operations, like for example System.IO.File.Copy or Microsoft.VisualBasic.FileIO.FileSystem.CopyFile method. All of them only supports a single operation and only on a single progress dialog at once.
So I focused to investigate on that suggested solution, and I ended up finding a good implementation of IFileOperation and IFileOperationProgressSink interfaces in this repository:
https://github.com/misterhaan/au.Shared/tree/master/IO/Files.FileOperation
And this one which is the original implementation that I found on a old Microsoft's article which also comes with a good PDF reading to learn some things:
https://github.com/mlaily/MSDNMagazine2007-.NET-Matters-IFileOperation-in-Windows-Vista
https://learn.microsoft.com/en-us/archive/msdn-magazine/2007/december/net-matters-ifileoperation-in-windows-vista
Actually, for what I've discussed in this thread to do since year 2015, delving into the use of the IFileOperationProgressSink interface to report progress would not be necessary (only if I really want a deep progress information), since it is enough to determine that the copy was started / the call to IFileOperation.PerformOperations function was performed, and if any problems occur during the copy then it will appear in the progress dialog UI.
But of course what is still necessary is to develop a shell-extension of a custom SendTo menu to replace the one built into Windows. Shell-extensions could be developed with SharpShell library.
I develop in VB.NET language. I managed to extend and document their IFileOperation implementation and the wrapper, and updated the enums adding the newer, missing values added for Windows 7 and Windows 8.
If it can be helpful for someone, I'm going to attach the IFIleOperation and the wrapper in Vb.NET all in a new answer (because it exceeds the maximum character limit allowed for a post).
Note that in my implementation of IFileOperation interface and the wrapper class with name FileSystemOperation you will find some return types and missing classes or methods (like HRESULT return type or NativeMethods class), I just can't share all in one place, but these missing things are things that any experienced programmer will know how to resolve (eg. change HRESULT to UInteger type, and go to Pinvoke.net to find any missing method from my NativeMethods class).
UPDATE
It seems that StackOverflow doesn't allow me to add another answer, so I'll upload my implementation on PasteBin instead:
Class FileSystemOperation
https://pastebin.com/nvgLWEXu
Interface IFileOperation
https://pastebin.com/GzammHtu
Interface IFileOperationProgressSink
https://pastebin.com/jf9JjzyH
Class ComObjectDisposer(Of T As Class)
https://pastebin.com/7mPeawWr
Enum TransferSourceFlags
https://pastebin.com/V7wSSEvv
Enum FileOperationFlags
https://pastebin.com/A223w9XY
That's all.

C# code or library to Update virtual directory contents without breaking clients

I have a lot of regularly updating static content that is made available via HTTP through IIS as a Virtual Directory. I have a C# application that updates this static content. The static content represents a matching set.
This content changes regularly and is validated before being made available to clients. I am currently doing a Directory Copy using this code but it is a bit brute force.
The content has a manifest file with version information. I know I can update the manifest file last but I don't want to pull the rug from under clients that are already downloading older content and leave them with a dirty set of files.
What is the recommended way to do a folder replace so that existing clients don't get a mixed up version of the file set? This must be common but I cannot find any libraries or best practice guidance to do this.
I've looked things like rsync for Windows and other backup/restore style tools but they all seem like overkill and generally don't have an API.
I ended up using the Microsoft Sync Framework. It worked out reasonably well. There are still a few bugs. Here's a good intro to the framework.
This is the significant part of my implementation.
public static bool DirectorySynchronisation(string sourceFiles, string targetFiles)
{
Trace.Info("Beginning Directory Sync");
try
{
Trace.Info("... between source location: {0} and targeted location: {1}", sourceFiles, targetFiles);
//Exclude metadata from sync.
var fileSyncScopeFilter = new FileSyncScopeFilter();
fileSyncScopeFilter.FileNameExcludes.Add("metadata.abc");
// Create file system provider
var source = new FileSyncProvider(Guid.NewGuid(), sourceFiles, fileSyncScopeFilter, FileSyncOptions.None);
var target = new FileSyncProvider(Guid.NewGuid(), targetFiles);
// Ask providers to detect changes
source.DetectChanges();
target.DetectChanges();
// Sync changes
SyncOrchestrator agent = new SyncOrchestrator
{
LocalProvider = source,
RemoteProvider = target,
Direction = SyncDirectionOrder.Upload //One way only
};
agent.Synchronize();
Trace.Info("Completed Directory Sync");
return true;
}
catch (Exception exception)
{
Trace.Info("Exception thrown while syncing files");
Trace.Exception(exception);
return false;
}
}
Hope this helps someone.

Is it possible that HttpServerUtility.MapPath locks the file?

Two functions in our standard ASP.NET app are:
private static void SaveToFileSystem(AttributeFileAttachment attach, int paId)
{
string fileName = GetAttachmentFullName(attach.FileName, paId);
File.WriteAllBytes(fileName, attach.Content);
}
public static string GetAttachmentFullName(string name, int paId)
{
HttpContext ctx = Util.Util.GetHttpContext();
return string.Format("{0}{1}_{2}_{3}",
ctx.Server.MapPath("<some variable to get the path>" + "attributeFileAttachments\\"),
ctx.Session.SessionID,
paId,
name);
}
when File.WriteAllBytes is executed it returns exception:
he process cannot access the file '\\d$\Home\\attributeFileAttachments\' because it is being used by another process.
The essence are two lines:
ctx.Server.MapPath... (Microsoft code)
and File.WriteAllBytes...
that work on the same file.
It turns out that HttpServerUtility.MapPath locks the file and leaves it locked !?
I don't see any comments on that in official documentation nor I see anybody complains on that.
But it can't be anything else, since the two lines are consecutive.
When I modify fileName for File.WriteAllBytes in immediate window just a bit, the writing succeeds, since that new file is not locked.
One more thing I have noticed is that this happens only and always for some of the attachment files.
Thank you for the time and any advice.

C# Search for subdirectory (not for files)

Every example I see seems to be for recursively getting files in subdirectories uses files only. What I'm trying to do is search a folder for a particular subdirectory named "xxx" then save that path to a variable so I can use it for other things.
Is this possible without looping through all the directories and comparing by name?
Well
Directory.GetDirectories(root);
will return you an array of the subdirectories.
You can then use Linq to find the one you're interested in:
IEnumerable<string> list = Directory.GetDirectories(root).Where(s => s.Equals("test"));
which isn't a loop in your code, but is still a loop nevertheless. So the ultimate answer is that "no you can't find a folder 'test' without looping".
You could add .SingleOrDefault() to the Linq, but that would depend on what you wanted to do if your "test" folder couldn't be found.
If you change the GetDirectories call to include the SearchOption SearchOption.AllDirectories then it will do the recursion for you as well. This version supports searching - you have to supply a search string - though in .NET Framework it's case sensitive searching. To return all sub directories you pass "*" as the search term.
Obviously in this case the call could return more than one item if there was more than one folder named "test" in your directory tree.
var foldersFound = Directory.GetDirectories(root, "test", SearchOption.AllDirectories)
This will return a string array with all the folders found with the given name. You can change the last parameter so that it only checks top level directories and you can change root to adjust where it is starting from.
First of all, "No, it is not possible without looping through all the directories and comparing by name".
I believe your real question is "Is there an existing API which will handle looping through all the directories and comparing by name for me?"
Yes, there is. It's called Directory.Exists():
var xxxPath = Path.Combine(parentFolder, "xxx");
if (Directory.Exists(xxxPath))
savedPath = xxxPath;
Yes, I believe that the only available solution (short of third party libraries) is a recursive search for the directory via name comparison.
You can use Windows Search which provides api for .Net too. Here is more detailed information: Windows Search 4.0 for Developers
Here is a snippet for searching for a folder using two filters while considering for the UnauthorizedAccessException, it can be refactored to use only one filter:
public static string FindGitPath(string firstFilter, string secondFilter, string initialPath)
{
string gitPath = string.Empty;
foreach (var i in Directory.GetDirectories(initialPath)) {
try {
foreach (var f in Directory.GetDirectories(i, firstFilter, SearchOption.AllDirectories)) {
foreach (var s in Directory.GetDirectories(f)) {
if (s == Path.Combine(f,secondFilter)) {
gitPath = f;
break;
}
}
}
} catch (UnauthorizedAccessException) {
Console.WriteLine("Path is not accessible: {0}", i);
}
}
return gitPath;
}
Usage example:
Console.WriteLine("Retrieved the git database folder as {0}", FindGitPath("database",".git", "c:\\"));

Categories