internal virtual void OnEntryEvent(ref Structs.EntryEventArgs e) { if (EntryWatcher != null) { EntryWatcher(ref e); } }
public Structs.WriteResult Move(string Destination) { WriteResult Result = new WriteResult(); // Get the destination folder Folder D = Drive.FolderFromPath(Destination); if (D.FullPath == this.Parent.FullPath || D.FullPath.Contains(this.FullPath)) { Result.Entry = this; return Result; } for (int i = 0; i < D.Folders().Length; i++) { if (D.Folders()[i].Name.ToLower() == Name.ToLower()) { Result.CouldNotWrite = true; Result.Entry = D.Folders()[i]; Result.ConflictingEntryPath = Result.Entry.FullPath; Result.AttemptedEntryToMove = this; return Result; } } for (int i = 0; i < D.Files().Length; i++) { if (D.Files()[i].Name.ToLower() == Name.ToLower()) { Result.CouldNotWrite = true; Result.Entry = D.Files()[i]; Result.ConflictingEntryPath = Result.Entry.FullPath; Result.AttemptedEntryToMove = this; return Result; } } // Get the offset for a new folder in the destination EntryFunctions ef = new EntryFunctions(D); long Offset = ef.GetNewEntryOffset(D); EntryData f = this.EntryData; byte NameSize = this.EntryData.NameSize; // Mark this entry as deleted and write it f.NameSize = 0xE5; ef.CreateNewEntry(f); // Reset the size of that name... f.NameSize = NameSize; // Set the offset to that of the new folder f.EntryOffset = Offset; // Write the entry ef.CreateNewEntry(f); this.EntryData = f; if (f.EntryOffset >= VariousFunctions.GetBlockOffset(this.BlocksOccupied[BlocksOccupied.Length - 1], this) + this.PartitionInfo.ClusterSize) { List<uint> blocks = this.BlocksOccupied.ToList(); blocks.Add(VariousFunctions.GetBlockFromOffset(f.EntryOffset, this.PartitionInfo)); this.BlocksOccupied = blocks.ToArray(); } if (Parent != null) { if (!this.IsFolder) { Parent.cachedFiles.Remove((File)this); Parent.cachedDeletedFiles.Add((File)this); } else { Parent.cachedFolders.Remove((Folder)this); Parent.cachedDeletedFolders.Add((Folder)this); } } Structs.EntryEventArgs ea = new EntryEventArgs(); ea.Deleting = true; ea.FullParentPath = this.Parent.FullPath; ea.ModifiedEntry = this; ea.ParentFolder = this.Parent; if (Parent != null) { if (Parent.EntryEventNull) { if (this.IsFolder) { if (!((Folder)this).EntryEventNull) { ((Folder)this).OnEntryEvent(ref ea); } } } else { Parent.OnEntryEvent(ref ea); } } else if (this.IsFolder) { if (!((Folder)this).EntryEventNull) { ((Folder)this).OnEntryEvent(ref ea); } } this.Parent = D; this.FullPath = this.Parent.FullPath + "\\" + Name; Structs.EntryEventArgs MovedEA = new EntryEventArgs(); MovedEA.Deleting = false; MovedEA.FullParentPath = this.Parent.FullPath; MovedEA.ModifiedEntry = this; MovedEA.ParentFolder = this.Parent; if (Parent != null) { if (Parent.EntryEventNull) { if (this.IsFolder) { if (!((Folder)this).EntryEventNull) { ((Folder)this).OnEntryEvent(ref MovedEA); } } } else { Parent.OnEntryEvent(ref MovedEA); } if (!this.IsFolder) { Parent.cachedFiles.Add((File)this); } else { Parent.cachedFolders.Add((Folder)this); } } else if (this.IsFolder) { if (!((Folder)this).EntryEventNull) { ((Folder)this).OnEntryEvent(ref MovedEA); } } Result.Entry = this; return Result; }
/// <summary> /// Deletes the file from the parent folder, clears the FAT chain, etc. /// </summary> public void Delete() { if (this.IsDeleted) { return; } // File action (event) Structs.FileAction fa = new FileAction(); fa.FullPath = this.FullPath; fa.MaxValue = 2; OnFileAction(ref fa); // Create the entry functions so we can clear the FAT chain EntryFunctions ef = new EntryFunctions(this); if (Size != 0) { // Get the FAT chain uint[] FatChain = this.BlocksOccupied; // Clear the FAT chain ef.ClearFATChain(FatChain); // Add to the remaining space on the drive if (Drive.Remaining != ~0UL) { Drive.Remaining += (ulong)(FatChain.Length * PartitionInfo.ClusterSize); } // Dispose of the FatChain FatChain = null; } // Change the progress fa.Progress = 1; OnFileAction(ref fa); // Get the new entry data that we're going to write EntryData ed = this.EntryData; // Mark it as deleted ed.NameSize = 0xE5; // "Create" a new entry (writing the old one with the size of 0xE5 ef.CreateNewEntry(ed); // Change progress fa.Progress = 2; OnFileAction(ref fa); // Reset the entry data this.EntryData = ed; // Other event EntryEventArgs eea = new EntryEventArgs(); eea.FullParentPath = Parent.FullPath; eea.ModifiedEntry = this; eea.ParentFolder = this.Parent; eea.Deleting = true; if (Parent != null) { Parent.cachedFiles.Remove(this); Parent.cachedDeletedFiles.Add(this); try { Parent.OnEntryEvent(ref eea); } catch { } } }
internal virtual void OnEntryEvent(ref EntryEventArgs e) { Drive.OnEntryEvent(ref e); }
/// <summary> /// Deletes all files and subfolders contained in this, and the folder itself /// </summary> public void Delete() { /* We're setting return deleted entries to false because: * 1.) We're deleting these folders, so the property doesn't matter anyway * 2.) We don't want to delete a deleted folder * 3.) Pickles */ ReturnDeletedEntries = false; // Loop for each folder in this foreach (Folder f in Folders()) { // While we're looping, we want to check if the user wants // to cancel the current action. If they do, then we stop and return if (fa.Cancel) { fa.Cancel = false; return; } // Set the folder action event so we can update stuff f.FolderAction += new FolderActionChanged(f_FolderAction); if (!f.IsDeleted) { // Call to delete the folder f.Delete(); } } // Now, loop through each file foreach (File f in Files()) { // If they want us to cancel... if (fa.Cancel) { // Set the cancel to false, then return fa.Cancel = false; return; } // Set the file action so we can update stuff again f.FileAction +=new FileActionChanged(f_FileAction); if (!f.IsDeleted) { // Delete the file f.Delete(); } } // Update our progress fa.CurrentFile = this.Name; fa.CurrentFilePath = this.FullPath; fa.MaxValue = 2; fa.Progress = 0; OnFolderAction(ref fa); // Clear the FAT chain of this folder EntryFunctions ef = new EntryFunctions(this); ef.ClearFATChain(this.BlocksOccupied); // Increase the remaining size left on the drive if (Drive.Remaining != ~0UL) { Drive.Remaining += (ulong)(this.BlocksOccupied.Length * PartitionInfo.ClusterSize); } // Update our progress again fa.Progress = 1; OnFolderAction(ref fa); // Create a new instance of the entry data EntryData ed = this.EntryData; // Set the size to 0xE5 (mark for deletion) ed.NameSize = 0xE5; // Re-write the entry data ef.CreateNewEntry(ed); // Reset this guy's entry data this.EntryData = ed; // Update our progress fa.Progress = 2; OnFolderAction(ref fa); // Remove this folder from the parent's cached stuff if (this.Parent != null) { this.Parent.cachedFolders.Remove(this); this.Parent.cachedDeletedFolders.Add(this); } // Update the FINAL progress EntryEventArgs eea = new EntryEventArgs(); eea.FullParentPath = Parent.FullPath; eea.ModifiedEntry = this; eea.ParentFolder = this.Parent; eea.Deleting = true; if (this.Parent != null && !this.Parent.EntryEventNull) { Parent.OnEntryEvent(ref eea); } else if (!this.EntryEventNull) { this.OnEntryEvent(ref eea); } }
/// <summary> /// Creates a new folder /// </summary> /// <param name="Name">New folder name</param> /// <returns>The existing file or folder will be returned if applicable, otherwise returns null (no problems encountered)</returns> public Structs.WriteResult CreateNewFolder(string Name) { WriteResult Result = new WriteResult(); Folders(); Console.WriteLine("Getting folders... comparing names"); for (int i = 0; i < cachedFolders.Count; i++) { if (cachedFolders[i].Name.ToLower() == Name.ToLower()) { Result.CouldNotWrite = true; Result.Entry = cachedFolders[i]; Result.ConflictingEntryPath = Result.Entry.FullPath; return Result; } } Console.WriteLine("Getting files... comparing names"); for (int i = 0; i < cachedFiles.Count; i++) { if (cachedFiles[i].Name.ToLower() == Name.ToLower()) { Result.CouldNotWrite = true; Result.Entry = cachedFiles[i]; Result.ConflictingEntryPath = Result.Entry.FullPath; return Result; } } EntryFunctions ef = new EntryFunctions(this); Console.WriteLine("Creating new folder"); Folder f = new Folder(this.PartitionInfo, ef.GetNewEntry(this, 0, new Geometry.Flags[] { Geometry.Flags.Directory }, Name), this.Drive); // Check if the new folder was created on a new cluster if (f.EntryOffset >= VariousFunctions.GetBlockOffset(this.BlocksOccupied[BlocksOccupied.Length - 1], this) + this.PartitionInfo.ClusterSize) { List<uint> blocks = this.BlocksOccupied.ToList(); blocks.Add(VariousFunctions.GetBlockFromOffset(f.EntryOffset, this.PartitionInfo)); this.BlocksOccupied = blocks.ToArray(); } Console.WriteLine("Writing FAT chain"); ef.WriteFATChain(new uint[] { f.EntryData.StartingCluster }); f.FullPath = this.FullPath + "\\" + f.Name; f.Parent = this; Streams.Writer w = this.Drive.Writer(); w.BaseStream.Position = f.StartingOffset; byte[] FF = new byte[PartitionInfo.ClusterSize]; for (int i = 0; i < FF.Length; i++) { FF[i] = 0xFF; } Console.WriteLine("Writing FF"); w.Write(FF); //Console.WriteLine("Closing stream"); //w.Close(); this.cachedFolders.Add(f); EntryEventArgs eea = new EntryEventArgs(); eea.FullParentPath = FullPath; eea.ModifiedEntry = f; eea.ParentFolder = this; OnEntryEvent(ref eea); Console.WriteLine("Updating entry modified time"); UpdateModifiedTime(); Result.Entry = f; return Result; }
/// <summary> /// Creates a new file from the given path /// </summary> /// <param name="Path">Path to the file</param> /// <returns>Returns a WriteResult with a bool indicating whether or not there were problems writing the file. If true, then the Entry property will be the conflicting entry</returns> public Structs.WriteResult CreateNewFile(string Path) { // Check to see if the file they want to use is currently in use try { System.IO.FileStream fs = System.IO.File.Open(Path, System.IO.FileMode.Open); // Check file length if (fs.Length > UInt32.MaxValue) { throw new Exception("File size too large! Must be smaller than " + UInt32.MaxValue.ToString() + " bytes!"); } // File was good, continue fs.Close(); } catch (Exception x) { Console.WriteLine("Error occured when creating new file. File in use"); throw x; } if (fa.Cancel) { return new WriteResult() { CouldNotWrite = false, }; } System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); EntryEventArgs eea = new EntryEventArgs(); string NewName = System.IO.Path.GetFileName(Path); fa.CurrentFilePath = this.FullPath + "\\" + NewName; fa.CurrentFile = NewName; fa.MaxValue = 1; fa.Progress = 0; OnFolderAction(ref fa); WriteResult Return = new WriteResult(); Console.WriteLine("Comparing folder/file names"); foreach (Folder f in Folders()) { if (f.Name.ToLower() == NewName.ToLower()) { Return.Entry = f; Return.CouldNotWrite = true; Return.ConflictingEntryPath = f.FullPath; return Return; } } foreach (File f in Files()) { if (f.Name.ToLower() == NewName.ToLower()) { Return.Entry = f; Return.CouldNotWrite = true; Return.ConflictingEntryPath = f.FullPath; return Return; } } if (new System.IO.FileInfo(Path).Length == 0) { Console.WriteLine("Creating null file"); EntryData newE = new EntryFunctions(this).GetNewEntry(this, 0, new Geometry.Flags[0], NewName); try { Console.WriteLine("Getting blocks needed"); int BlocksNeeded = 1; Console.WriteLine(sw.Elapsed.ToString()); List<uint> Blocks = new List<uint>(); Console.WriteLine("Getting new entry"); if (newE.EntryOffset >= VariousFunctions.GetBlockOffset(this.BlocksOccupied[BlocksOccupied.Length - 1], this) + this.PartitionInfo.ClusterSize) { List<uint> blocks = this.BlocksOccupied.ToList(); blocks.Add(VariousFunctions.GetBlockFromOffset(newE.EntryOffset, this.PartitionInfo)); this.BlocksOccupied = blocks.ToArray(); } Console.WriteLine(sw.Elapsed.ToString()); Blocks.Add(newE.StartingCluster); // Write the file data... // FileAction to be used fa.MaxValue = Blocks.Count; File f = new File(this.PartitionInfo, newE, this.Drive); f.Parent = this; f.FullPath = this.FullPath + "\\" + f.Name; eea.ModifiedEntry = f; Return.Entry = f; this.cachedFiles.Add(f); fa.Progress = Blocks.Count; } // This excpetion here is going to be that we're out of space... catch (Exception x) { Console.WriteLine("Exception thrown, deleting written entry"); // Delete this entry newE.NameSize = 0xE5; // Create a new entry functions class so we can get rid of this entry EntryFunctions ef = new EntryFunctions(this); // Clear the FAT chain Console.WriteLine("Clearing FAT chain"); ef.ClearFATChain(new uint[] { newE.StartingCluster }); // Mark this entry as deleted ef.CreateNewEntry(newE); throw x; } } else { Console.WriteLine(sw.Elapsed.ToString()); Console.WriteLine("Getting blocks needed"); int BlocksNeeded = (int)(VariousFunctions.UpToNearestCluster(new System.IO.FileInfo(Path).Length, PartitionInfo.ClusterSize) / PartitionInfo.ClusterSize); Console.WriteLine(sw.Elapsed.ToString()); List<uint> Blocks = new List<uint>(); Console.WriteLine("Getting new entry"); EntryData newE = new EntryFunctions(this).GetNewEntry(this, (uint)new System.IO.FileInfo(Path).Length, new Geometry.Flags[0], NewName); if (newE.EntryOffset >= VariousFunctions.GetBlockOffset(this.BlocksOccupied[BlocksOccupied.Length - 1], this) + this.PartitionInfo.ClusterSize) { List<uint> blocks = this.BlocksOccupied.ToList(); blocks.Add(VariousFunctions.GetBlockFromOffset(newE.EntryOffset, this.PartitionInfo)); this.BlocksOccupied = blocks.ToArray(); } Console.WriteLine(sw.Elapsed.ToString()); Blocks.Add(newE.StartingCluster); try { Console.WriteLine("Getting free blocks"); Blocks.AddRange(Drive.GetFreeBlocks(this, BlocksNeeded - 1, newE.StartingCluster, 0, false)); Console.WriteLine(sw.Elapsed.ToString()); } // This excpetion here is going to be that we're out of space... catch (Exception x) { Console.WriteLine("Exception thrown, deleting written entry"); // Delete this entry newE.NameSize = 0xE5; // Create a new entry functions class so we can get rid of this entry EntryFunctions ef = new EntryFunctions(this); // Clear the FAT chain Console.WriteLine("Clearing FAT chain"); ef.ClearFATChain(new uint[] { newE.StartingCluster }); // Mark this entry as deleted ef.CreateNewEntry(newE); throw x; } Console.WriteLine("Writing FAT chain"); // Write that FAT chain new EntryFunctions(this).WriteFATChain(Blocks.ToArray()); Console.WriteLine(sw.Elapsed.ToString()); // Write the file data... // FileAction to be used fa.MaxValue = Blocks.Count; // The IO to read the file Streams.Reader FileReader = null; try { FileReader = new CLKsFATXLib.Streams.Reader(new System.IO.FileStream(Path, System.IO.FileMode.Open)); } catch { System.Threading.Thread.Sleep(1000); try { FileReader = new CLKsFATXLib.Streams.Reader(new System.IO.FileStream(Path, System.IO.FileMode.Open)); } catch (Exception x) { Console.WriteLine("Exception thrown, deleting written entry"); // Delete this entry newE.NameSize = 0xE5; // Create a new entry functions class so we can get rid of this entry EntryFunctions ef = new EntryFunctions(this); // Clear the FAT chain Console.WriteLine("Clearing FAT chain"); ef.ClearFATChain(Blocks.ToArray()); // Mark this entry as deleted ef.CreateNewEntry(newE); throw x; } } // The IO to write to the destination file Streams.Writer FileWriter = Drive.Writer(); // Loop for each block... for (int i = 0; i < Blocks.Count - 1; i++) { if (fa.Cancel) { Console.WriteLine("Cancel engaged"); FileReader.Close(); File newfile = new File(this.PartitionInfo, newE, this.Drive); newfile.Parent = this; newfile.FullPath = this.FullPath + "\\" + newfile.Name; this.cachedFiles.Add(newfile); eea.FullParentPath = FullPath; eea.ModifiedEntry = newfile; eea.ParentFolder = this; OnEntryEvent(ref eea); UpdateModifiedTime(); Return.Entry = newfile; return Return; } // Set the position to the beginning of the block FileWriter.BaseStream.Position = VariousFunctions.GetBlockOffset(Blocks[i], this); for (int j = 1, k = 0; j <= 0x100; j++, k++) { if (i + k == Blocks.Count - 1) { //Console.WriteLine("Writing part of file"); FileWriter.Write(FileReader.ReadBytes((int)PartitionInfo.ClusterSize * k)); i += k; fa.Progress += k; break; } else if (Blocks[i + k] == Blocks.Count - 2 || Blocks[i + k] + 1 != Blocks[i + j] || j == 10) { //Console.WriteLine("Writing part of file"); FileWriter.Write(FileReader.ReadBytes((int)PartitionInfo.ClusterSize * j)); i += k; fa.Progress += j; break; } } OnFolderAction(ref fa); } Console.WriteLine(sw.Elapsed.ToString()); // For the last cluster, we don't know how long it is... so we use // this nifty function I made to do that for us Console.WriteLine("Seeking to final cluster"); FileWriter.BaseStream.Position = VariousFunctions.GetBlockOffset(Blocks[Blocks.Count - 1], this); // Read/write data byte[] ToWrite = new byte[(int)VariousFunctions.UpToNearest200(VariousFunctions.RemainingData(BlocksNeeded, new System.IO.FileInfo(Path).Length, this))]; if ((int)VariousFunctions.RemainingData(BlocksNeeded, new System.IO.FileInfo(Path).Length, this) < (int)VariousFunctions.UpToNearest200((int)VariousFunctions.RemainingData(BlocksNeeded, new System.IO.FileInfo(Path).Length, this))) { for (int i = (int)VariousFunctions.RemainingData(BlocksNeeded, new System.IO.FileInfo(Path).Length, this) + 1; i < ToWrite.Length; i++) { ToWrite[i] = 0xFF; } } byte[] Buffer = FileReader.ReadBytes((int)VariousFunctions.RemainingData(BlocksNeeded, new System.IO.FileInfo(Path).Length, this)); Array.Copy(Buffer, 0, ToWrite, 0, Buffer.Length); Buffer = null; Console.WriteLine("Writing final cluster"); FileWriter.Write(ToWrite); fa.Progress++; OnFolderAction(ref fa); Console.WriteLine("Closing streams"); FileReader.Close(); Console.WriteLine(sw.Elapsed.ToString()); File newF = new File(this.PartitionInfo, newE, this.Drive); newF.Parent = this; newF.FullPath = this.FullPath + "\\" + newF.Name; this.cachedFiles.Add(newF); Return.Entry = newF; eea.ModifiedEntry = newF; } eea.FullParentPath = FullPath; eea.ParentFolder = this; OnEntryEvent(ref eea); UpdateModifiedTime(); return Return; }
/// <summary> /// Creates a new, emptry file from the given path /// </summary> /// <param name="Path">Path to the file</param> /// <returns>Returns a WriteResult with a bool indicating whether or not there were problems writing the file. If true, then the Entry property will be the conflicting entry</returns> public Structs.WriteResult CreateFile(string NewName) { WriteResult Return = new WriteResult(); EntryEventArgs eea = new EntryEventArgs(); fa.CurrentFilePath = this.FullPath + "\\" + NewName; fa.CurrentFile = NewName; fa.MaxValue = 1; fa.Progress = 0; OnFolderAction(ref fa); foreach (Folder f in Folders()) { if (f.Name.ToLower() == NewName.ToLower()) { Return.Entry = f; Return.CouldNotWrite = true; Return.ConflictingEntryPath = f.FullPath; return Return; } } foreach (File f in Files()) { if (f.Name.ToLower() == NewName.ToLower()) { Return.Entry = f; Return.CouldNotWrite = true; Return.ConflictingEntryPath = f.FullPath; return Return; } } EntryData newE = new EntryFunctions(this).GetNewEntry(this, 0, new Geometry.Flags[0], NewName); int BlocksNeeded = 1; List<uint> Blocks = new List<uint>(); Console.WriteLine("Getting new entry"); if (newE.EntryOffset >= VariousFunctions.GetBlockOffset(this.BlocksOccupied[BlocksOccupied.Length - 1], this) + this.PartitionInfo.ClusterSize) { List<uint> blocks = this.BlocksOccupied.ToList(); blocks.Add(VariousFunctions.GetBlockFromOffset(newE.EntryOffset, this.PartitionInfo)); this.BlocksOccupied = blocks.ToArray(); } { Blocks.Add(newE.StartingCluster); // Write the file data... // FileAction to be used fa.MaxValue = Blocks.Count; OnFolderAction(ref fa); File f = new File(this.PartitionInfo, newE, this.Drive); f.Parent = this; f.FullPath = this.FullPath + "\\" + f.Name; eea.ModifiedEntry = f; Return.Entry = f; this.cachedFiles.Add(f); fa.Progress = Blocks.Count; OnFolderAction(ref fa); eea.FullParentPath = FullPath; eea.ParentFolder = this; OnEntryEvent(ref eea); return Return; } }