views:

897

answers:

11

It appears that Directory.GetFiles() in C# modifies the Last access date of a file. I've googled for hours and can't seem to find a work around for this issue. Is there anyway to keep all the MAC (Modified, Accessed, Created) attributes of a file? I'm using Directory.GetDirectories(), Directory.GetFiles(), and FileInfo.

Also, the fi.LastAccessTime is giving strange results -- the date is correct, however, the time is off by 2 minutes, or a few hours.

Time of function execution: 10/31/2008 8:35 AM

Program Shows As              Last Access Time
0_PDFIndex.html               - 10/31/2008 8:17:24 AM
AdvancedArithmetic.pdf        - 10/31/2008 8:31:05 AM
AdvancedControlStructures.pdf - 10/30/2008 1:18:00 PM
AoAIX.pdf                     - 10/30/2008 1:18:00 PM
AoATOC.pdf                    - 10/30/2008 12:29:51 PM
AoATOC2.pdf                   - 10/30/2008 1:18:00 PM

Actual                        Last Access Time
0_PDFIndex.html               - 10/31/2008 8:17 AM
AdvancedArithmetic.pdf        - 10/30/2008 12:29 PM
AdvancedControlStructures.pdf - 10/30/2008 12:29 PM
AoAIX.pdf                     - 10/30/2008 12:29 PM
AoATOC.pdf                    - 10/30/2008 12:29 PM
AoATOC2.pdf                   - 10/30/2008 12:29 PM

Below is the method I'm using. If you require more information, please let me know.

Thanks!

public void PopulateTreeView(string directoryValue, ref TreeNode parentNode)
        {
            string[] directoryArray = Directory.GetDirectories(directoryValue);
            string[] fileArray = Directory.GetFiles(directoryValue, "*.*", SearchOption.AllDirectories);

            try
            {
                #region Directories
                if (directoryArray.Length != 0)
                {
                    foreach (string directory in directoryArray)
                    {
                        DirectoryInfo di = new DirectoryInfo(directory);

                        TreeNode dirNode = parentNode.Nodes.Add(di.Name);

                        FileNode fn = new FileNode();
                        fn.bIsDir = true;
                        fn.dir = di;

                        dirNode.Tag = fn;
                        PopulateTreeView(directory, ref dirNode);
                        Application.DoEvents();

                    }
                }
                #endregion

                #region Files
                if (fileArray.Length != 0)
                {
                    foreach (string file in fileArray)
                    {
                        FileInfo fi = new FileInfo(file);

                        TreeNode fileNode = parentNode.Nodes.Add(fi.Name);
                        FileNode fn = new FileNode();
                        fn.bIsDir = false;
                        fn.file = fi;

                        fileNode.Tag = fn;

                        fileNode.ImageIndex = 1;

                        Console.WriteLine(fi.Name + " - " + fi.LastAccessTime);

                    }
                }
                #endregion

            }
            catch (UnauthorizedAccessException)
            {
                parentNode.Nodes.Add("Access denied");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                Application.DoEvents();
            }
        }
+1  A: 

I know this is far from ideal, but u can use fsutil (provided with Windows) to disable last access time writing:

fsutil behavior set disablelastaccess 1

Presumably you'd set it back to 0 once done. You can invoke this using Process.Start from C#, but there must be a better programmatic way (calling into Windows API).

Process.Start("fsutil", "behavior set disablelastaccess 1").WaitForExit();

Do note that this is a global Windows setting and would also affect disk access from outside your app...

dbkk
FSUTIL documentation notes that "Most of these options require a reboot for it to take effect."
GalacticCowboy
A: 

Access times are different from last write times. If you use fi.LastWriteTime I think you will find that the times are the same displayed in explorer or cmd window.

Of course the last access and last write could be the same, but they are not necessarily the same.

A: 

Not sure if this is related or not, but from MSDN:

When first called, FileSystemInfo calls Refresh and returns the cached information on APIs to get attributes and so on. On subsequent calls, you must call Refresh to get the latest copy of the information.

BTW, "LastAccessTime" basically tells you the last time you "looked at" the file. In the absence of stale data, this would always be "now"... Not particularly useful, IMHO.

GalacticCowboy
A: 

GalacticCowboy, It is necessary that this timestamp is unmodified - I work for a forensic company, and we have to prove in court that the file was unmodified while we have the data.

thank you all for you input so far!

Michael G
So what you really want is the "LastModifiedTime", right? And all of these dates can be monkeyed around fairly easily. For forensic purposes you really need a hash of the data, stored by an independent and trusted third party, and then prove that the data's hash still matches.
GalacticCowboy
thats exactly what this program is intended to do it generates hashes of the files and compressed them to an encrypted archive for the client to send to us. i dont need the last access time as it is not a valuable piece of data. however my manager is requesting this and Im at my wits end to deliver.
Michael G
A: 

Access time would show a read only marker, last write would show the file being modified.

+1  A: 

(Reposting this as a response rather than a comment...)

I've just run this snippet of code here, and it's left the last access time alone - I can't reproduce the problem you're seeing, so Directory.GetFiles isn't broken 100% of the time.

Filemon can check whether some other app is doing this: http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx

Tim Robinson
A: 

i know the differences between the attributes. What i need is for the file to remain exactly the same all attributes and meta-data, as if my program never touched the file; this includes the last access date.

Michael G
A: 

I haven't tried this, but Google suggests:

Disable the NTFS Last Access Time Stamp

It's a system-wide change, so be aware of that...

GalacticCowboy
This is probably what FSUTIL (suggested by dbkk) does as well.
GalacticCowboy
yeah, it modifies the same registry entry. is there any way to do this without reboot ?
Michael G
A: 

If you're accessing the disk for forensic purposes then you really should be doing it with the entire hard disk write-protected at the hardware level (and hence this isn't really a programming question).

A Google search for hdd "write protect" will reveal plenty of potential solutions.

Alnitak
A: 

Looks like there really isn't a way to do this with managed code. if there is any win32 api methods that do not modify the LAT please let me know.

Thank you everyone!

Michael G
+1  A: 

If you're doing forensics and you don't want the drive to be modified, why are you mounting it in a writable mode? You should be accessing it read-only to guarantee that you aren't accidentally changing something. Also, I would hope that you're not running your program in the OS of the person who's disk you're examining... you have just added the disk to a machine you control, right?

rmeador
this isn't for a "forensic case". the data is a copy of the original - this is a utility that we're sending to our clients. so we can't set their drives to write protect.
Michael G