Securing Temporary Files in C# - c#

When working with an application on C# I am creating a few temporary files using the following logic:
Creating Temp File
private static string CreateTmpFile()
{
string fileName = string.Empty;
try
{
// Get the full name of the newly created Temporary file.
// Note that the GetTempFileName() method actually creates
// a 0-byte file and returns the name of the created file.
fileName = Path.GetTempFileName();
// Craete a FileInfo object to set the file's attributes
FileInfo fileInfo = new FileInfo(fileName);
// Set the Attribute property of this file to Temporary.
// Although this is not completely necessary, the .NET Framework is able
// to optimize the use of Temporary files by keeping them cached in memory.
fileInfo.Attributes = FileAttributes.Temporary;
Console.WriteLine("TEMP file created at: " + fileName);
}
catch (Exception ex)
{
Console.WriteLine("Unable to create TEMP file or set its attributes: " + ex.Message);
}
return fileName;
}
Writing to Temp File
private static void UpdateTmpFile(string tmpFile)
{
try
{
// Write to the temp file.
StreamWriter streamWriter = File.AppendText(tmpFile);
streamWriter.WriteLine("Hello from www.daveoncsharp.com!");
streamWriter.Flush();
streamWriter.Close();
Console.WriteLine("TEMP file updated.");
}
catch (Exception ex)
{
Console.WriteLine("Error writing to TEMP file: " + ex.Message);
}
}
I have also tried and followed some of the implementations found on this link for another question
and am using the following implementations in my code : Storing the file in the AppData Folder for using the ACL
However I have been asked to make sure that :
The temp files cannot be read by anyone(Not even the user) during application runtime,
And to make sure that they are deleted even when force closing the
application
For case 1: The temp files cannot be read by anyone(Not even the user) during application runtime,
How can I implement this for my application files? The temp files contain sensitive data which should not be readable even if the user themselves would like to read. Is there a way I can do that?
For case 2: To make sure that they are deleted even when force closing the
application
Here I would like to make sure than even with force close or a sudden restart the files are deleted.
If Force close: then delete the files before force close
If Restart: then delete the files on next startup
Are these doable?

Related

How to handle partial file so that it will not be pickup by SFTP schedule pick up script?

I have a requirement where
when uploading the files to the pick-up folder, files will be uploaded
with a .tmp (or)._ (or) .filepart extensions and after successful
upload files will be renamed to the original file name.
This is required to avoid any partial pick-up of .xml files by settings on SFTP folder side.
For eg. Upload with .xml.tmp and after successful upload, rename the files to .xml
Any idea on how to achieve this in MVC, C#.
I prefer to do this in a separate folder entirely. And then do a move to the pickup folder.
Then renaming is not required.
private bool IsFileLocked()
{
try
{
FileStream fs = File.OpenWrite(FilePath);
fs.Close();
return false;
}
catch (Exception)
{
Console.WriteLine("File locked: " + FileName);
return true;
}
}
To check if the file is locked prior to attempting to send, might also work, or in conjunction.
I was talking about generating a local file first, once its completely done being written, simply use the File.Move() method, so you move the newly generated file from its "safe" folder, into the pickup folder, that the SFTP is continually looking for files in.
If it is picking up a file you are receiving, then it's just the check prior to attempting to do anything with it.
First of all, once you receive the file stream from the post, the upload is "already" successful (most likely). Therefore, the moment you have the data from the post, you should already be good to write it. The only point I can remotely see here is that, the remote process either checks .xml files constantly so let's say if the .xml file is quite large, and let's assume (which wont be the case) it takes a while for you to write the stream to the remote destination, they do not want to check just part of the xml, they need all of it. If that is the case, something like the following should work (modify it for your needs);
[HttpPost]
public ActionResult Upload()
{
if (Request.Files.Count < 1)
{
ViewBag.Result = "No files were provided";
return PartialView("Error");
}
foreach (string F in Request.Files)
{
var FInfo = Request.Files[F];
var TemporaryFileName = $"{FInfo.FileName}.tmp";
try
{
using (var FStream = new FileStream(TemporaryFileName, FileMode.Create, FileAccess.Write))
{
FInfo.InputStream.CopyTo(FStream);
}
}
catch (Exception e)
{
ViewBag.Result = e.Message;
return PartialView("Error");
}
finally
{
System.IO.File.Move(TemporaryFileName, $"{FInfo.FileName}");
}
}
ViewBag.Result = "Files have been uploaded";
return View();
}

C# move file with 2 mapped drives

I need to move a file existing on a mapped folder named A:\ to another mapped folder B:\ using the code below
File.Move(#"A:\file.txt",#"B:\");
it return the error below
Could not find file 'A:\file.txt'.
i tried to open A:\file.txt in folder explorer and it open the file normally
It looks like File.Move only works for files on local drives.
File.Move actually invokes MoveFile which states that both source and destination should be:
The current name of the file or directory on the local computer.
You would be better by using a combination of File.Copy and File.Delete.
Copy the file from A to B, then delete the file from A.
As stated before, File.Move needs sourceFileName and destFileName.
And you are missing the Filename in the second parameter.
If you want to move you file and keep the same name you can Extract the File name from the sourceFileName with GetFileName and use it in your destFileName
string sourceFileName = #"V:\Nothing.txt";
string destPath = #"T:\";
var fileName = Path.GetFileName(sourceFileName);
File.Move(sourceFileName, destPath + fileName );
Here is a debug code:
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
string path2 = #"c:\temp2\MyTest.txt";
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
Console.WriteLine("The original file does not exists, let's Create it.");
using (FileStream fs = File.Create(path)) {}
}
// Ensure that the target does not exist.
if (File.Exists(path2)) {
Console.WriteLine("The target file already exists, let's Delete it.");
File.Delete(path2);
}
// Move the file.
File.Move(path, path2);
Console.WriteLine("{0} was moved to {1}.", path, path2);
// See if the original exists now.
if (File.Exists(path))
{
Console.WriteLine("The original file still exists, which is unexpected.");
}
else
{
Console.WriteLine("The original file no longer exists, which is expected.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}

C# - Unable to delete a file after copying and overwritting

I am working on an application which reads paths of all the text files from a folder into a list. It reads each file, creates a temporary output file, overwrites the original file with temporary output file and deletes the temporary output file.
Following is my code:
foreach (string lF in multipleFiles)
{
int lineNumber = 0;
using (StreamReader sr = new StreamReader(lF))
{
using (StreamWriter sw = new StreamWriter(lF + "Output"))
{
while (!sr.EndOfStream)
{
//LOGIC
sw.WriteLine(line);
}
}
}
File.Copy(lF + "Output", lF, true);
//File.Delete(lF + "Output");
try
{
File.Delete(lF + "Output"); <--- ERROR HERE
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I am unable to delete the temporary output file due to the following error:
{"The process cannot access the file '' because it is being
used by another process."}
The error does not occur for every file but only a few. None of the files are open or being used by any other application.
How can the temporary file be deleted?
UPDATE: Refereed to Does FileStream.Dispose close the file immediately?
Added Thread.Sleep(1) before File.Delete(), The issue still exists. Tried increasing the sleep value to 5. No luck.
You always run the risk that an virus scanner or some other driver in the stack still holds on to that file or its directory entry. Use some retry mechanisms but that still doesn't guarantee you'll be able to remove that file as the file operations are not atomic, so any process can open that file between your calls trying to delete it.
var path = lf + "Output";
// we iterate a couple of times (10 in this case, increase if needed)
for(var i=0; i < 10; i++)
{
try
{
File.Delete(path);
// this is success, so break out of the loop
break;
} catch (Exception exc)
{
Trace.WriteLine("failed delete #{0} with error {1}", i, exc.Message);
// allow other waiting threads do some work first
// http://blogs.msmvps.com/peterritchie/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program/
Thread.Sleep(0);
// we don't throw, we just iterate again
}
}
if (File.Exists(path))
{
// deletion still not happened
// this is beyond the code can handle
// possible options:
// store the filepath to be deleted on startup
// throw an exception
// format the disk (only joking)
}
Code slightly adapted from my answer here but that was in a different context.

IO Exception - File being used by another process (Can't open file following directory creation)

I have got a project on the go that monitors patients for a vet while they are being operated on and writes the result to a text file. While I was experimenting with the outputting I just let the files save in the Debug folder, which worked fine. However, I've now created a full directory that creates or opens a main folder, and then a sub folder (based on input text from the program), to save the text file into.
private void createDirectory()
{ //create output file in this folder using owner name and current date
//main folder path (contains all files output from system)
string rootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Horse Monitoring Records";
//sub folder path (each patient has individual subfolder)
string subDirectory = rootDirectory + "\\" + txtPatName.Text + "-" + txtOwnerName.Text;
//file name (patient has file created for each operation)
fileName = subDirectory + "\\" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("ddMMyyyy") + ".txt";
if (!Directory.Exists(rootDirectory)) //if main folder does not exist...
{
Directory.CreateDirectory(rootDirectory); //create it in My Documents
}
if (!Directory.Exists(subDirectory)) //if patient sub folder does not exist...
{
Directory.CreateDirectory(subDirectory); //create it in Patient-Owner format
}
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
}
This stage works fine, but as soon as you try to save some data to the text file, it throws to a run time error stating that
The file cannot be accessed because it is being used by another process.
The exception is brought up here:
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
StreamWriter consoleFile = new StreamWriter(fileName);
...
}
When I went and checked out the folder, the relevant sub-folder and file had been created but the text file was blank.
I'm guessing it's something to do with closing the text file after creating the directory, which means it's already open when the system tries to open it. I can't figure out how to sort this issue out though!
The two functions shown above are called like this:
private void btnStart_Click(object sender, EventArgs e)
{
...
//file details entered upon load written to new file - according to PatID
createDirectory();
saveFileDetails();
}
Any suggestions on where to go from here would be very much appreciated!
Thanks,
Mark
The issue here is that you do
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
Right before you try to write to the file. Because you've just created it (if it didn't exist), chances are that the operating system hasn't released the file yet.
Like #Jauch mentioned in the comments, you could skip this check completely and use the StreamWriter overload which will create file if it doesn't exist, or append to it if it does.
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
using (StreamWriter consoleFile = new StreamWriter(fileName, true))
{
// ...
}
}
Alternatively you can use the following to write all of your text at once:
File.AppendAllText(textToWrite, fileName);
File.Create(fileName) returns an open stream to the file which is never closed.
To create an empty file use File.WriteAllBytes(fileName, new byte[0]);
Otherwise the 2 methods can be shortend
private void SaveFileDetails()
{
string subDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"Horse Monitoring Records");
// create the folder hierarchy if not exists. does nothing if already there
Directory.CreateDirectory(subDirectory);
// each patient has individual file
var filepath = Path.Combine(subDirectory,
txtPatName.Text + "-" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("yyyyMMdd") + ".txt");
// creates the file if not exists
using (var writer = new StreamWriter(filepath, append: true, encoding: Encoding.UTF8))
{
// write details
}
}
Note:
merged 2 methods
.NET naming conventions applied
changed dateformat to better sort by name in explorer
StreamWriter implements IDisposable, so wrapping it in a using block can manage closing and disposing the writer and ensuring it is available the next time you want to touch that file. It can also manage creating the text file if it doesn't exist, removing the need to explicitly call File.Create.
StreamWriter consoleFile = new StreamWriter(fileName);
becomes
using (StreamWriter writer = File.AppendText("log.txt"))
{
// writing, etc.
}
or
using (StreamWriter writer = new StreamWriter(fileName, true))
{ // true says "append to file if it exists, create if it doesn't"
// writing, etc.
}
Whatever seems more readable to you will work fine.

C# Why is my code throwing a io.system.directorynotfound?

Why would the code below throw a io.system.directorynotfound exception? I can't recreate the problem myself but another user of my code does see it, any ideas why?
Thanks
try
{
//create path
string strAppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).ToString() + "\\MyApp\\Data\\logs";
//check path exists
if (!System.IO.File.Exists(strAppData))
{
System.IO.Directory.CreateDirectory(strAppData);
}
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(strAppData);
int count = dir.GetFiles().Length;
if (count > 100)
{
string[] files = System.IO.Directory.GetFiles(strAppData);
foreach (string file in files)
{
System.IO.File.Delete(file);
}
}
this.fileName = fileName;
// delete the file if it exists
if (File.Exists(fileName))
{
//delete the file
File.Delete(fileName);
}
// write the data to the file
fs = File.OpenWrite(fileName);
sWriter = new StreamWriter(fs);
sWriter.WriteLine(headerText);
sWriter.Flush();
sWriter.Close();
}
catch (Exception exp)
{
throw new Exception(exp.Message);
}
Have you tried using System.IO.Directory.Exists rather than System.IO.File.Exists when checking to see if the path exists?
You're checking for the existence of a directory using System.IO.File rather than System.IO.Directory. It probably works on your machine because that directory already exists, and so the check doesn't matter.
Either way, you need to remember that the file system is volatile. Rather than checking existence, try to open the resource and handle the exception when it fails.
Check that the directory exists, not the file...
Although you're checking it, and creating it if it doesn't exist. You don't know if they have privelages to create the directory. So your Directory.CreateDirectory call may well be failing too and then sub-sequently the rest of the code will fail
http://msdn.microsoft.com/en-us/library/system.io.file.exists.aspx
"Remarks
The Exists method should not be used for path validation, this method merely checks if the file specified in path exists. Passing an invalid path to Existsl returns false. "
That is your error right there. Your validation does not ensure that the path to the file exists

Categories