So this is my test enviorment. I looked at the mirror code example as well as a few others for this. My biggest thing at the moment is just trying ot navigate to a folder or an empty folder.. Since I am deriving my file structure from a SQL DB
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using DokanNet;
using DokanNet.Logging;
using static DokanNet.FormatProviders;
using static DriveMap.ProgressBar;
using FileAccess = DokanNet.FileAccess;
namespace DriveMap
{
class OCIDOKAN : IDokanOperations
{
public static string directoryStr;
private Dictionary<String, FileCaching> FileCache = new Dictionary<String, FileCaching>();
private const FileAccess DataAccess = FileAccess.ReadData | FileAccess.WriteData | FileAccess.AppendData |
FileAccess.Execute |
FileAccess.GenericExecute | FileAccess.GenericWrite |
FileAccess.GenericRead;
private const FileAccess DataWriteAccess = FileAccess.WriteData | FileAccess.AppendData |
FileAccess.Delete |
FileAccess.GenericWrite;
string ConnectionString;
private ConsoleLogger logger = new ConsoleLogger("[OCIDOKAN] ");
public OCIDOKAN()
{
ConnectionString = "Data Source=192.168.0.31;User ID=ocisql;Password=Emagdne1212";
}
public void Cleanup(string fileName, IDokanFileInfo info)
{
Console.WriteLine("Cleanup Stage 1");
Console.WriteLine(GetPath(fileName));
Console.WriteLine("---------------------");
}
public void CloseFile(string fileName, IDokanFileInfo info)
{
Console.WriteLine("CloseFile");
}
public NtStatus CreateFile(string fileName, DokanNet.FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, IDokanFileInfo info)
{
var result = DokanResult.Success;
var filePath = GetPath(fileName);
if (info.IsDirectory)
{
try
{
switch (mode)
{
case FileMode.Open:
if (!Directory.Exists(filePath))
{
try
{
if (!File.GetAttributes(filePath).HasFlag(FileAttributes.Directory))
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.Success);
}
catch (Exception)
{
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.FileNotFound);
}
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.PathNotFound);
}
new DirectoryInfo(filePath).EnumerateFileSystemInfos(@"C:\");
// you can't list the directory
break;
case FileMode.CreateNew:
if (Directory.Exists(filePath))
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.FileExists);
try
{
File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.AlreadyExists);
}
catch (IOException)
{
}
Directory.CreateDirectory(GetPath(fileName));
break;
}
}
catch (UnauthorizedAccessException)
{
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.AccessDenied);
}
}
else
{
var pathExists = true;
var pathIsDirectory = false;
var readWriteAttributes = (access & DataAccess) == 0;
var readAccess = (access & DataWriteAccess) == 0;
try
{
pathExists = (Directory.Exists(filePath) || File.Exists(filePath));
pathIsDirectory = pathExists ? File.GetAttributes(filePath).HasFlag(FileAttributes.Directory) : false;
}
catch (IOException)
{
}
switch (mode)
{
case FileMode.Open:
if (pathExists)
{
// check if driver only wants to read attributes, security info, or open directory
if (readWriteAttributes || pathIsDirectory)
{
if (pathIsDirectory && (access & FileAccess.Delete) == FileAccess.Delete
&& (access & FileAccess.Synchronize) != FileAccess.Synchronize)
//It is a DeleteFile request on a directory
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.AccessDenied);
info.IsDirectory = pathIsDirectory;
info.Context = new object();
// must set it to something if you return DokanError.Success
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
attributes, DokanResult.Success);
}
}
else
{
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.FileNotFound);
}
break;
case FileMode.CreateNew:
if (pathExists)
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.FileExists);
break;
case FileMode.Truncate:
if (!pathExists)
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.FileNotFound);
break;
}
try
{
info.Context = new FileStream(filePath, mode,
readAccess ? System.IO.FileAccess.Read : System.IO.FileAccess.ReadWrite, share, 4096, options);
if (pathExists && (mode == FileMode.OpenOrCreate
|| mode == FileMode.Create))
result = DokanResult.AlreadyExists;
bool fileCreated = mode == FileMode.CreateNew || mode == FileMode.Create || (!pathExists && mode == FileMode.OpenOrCreate);
if (fileCreated)
{
FileAttributes new_attributes = attributes;
new_attributes |= FileAttributes.Archive; // Files are always created as Archive
// FILE_ATTRIBUTE_NORMAL is override if any other attribute is set.
new_attributes &= ~FileAttributes.Normal;
File.SetAttributes(filePath, new_attributes);
}
}
catch (UnauthorizedAccessException) // don't have access rights
{
if (info.Context is FileStream fileStream)
{
// returning AccessDenied cleanup and close won't be called,
// so we have to take care of the stream now
fileStream.Dispose();
info.Context = null;
}
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.AccessDenied);
}
catch (DirectoryNotFoundException)
{
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.PathNotFound);
}
catch (Exception ex)
{
var hr = (uint)Marshal.GetHRForException(ex);
switch (hr)
{
case 0x80070020: //Sharing violation
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
DokanResult.SharingViolation);
default:
throw;
}
}
}
return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
result);
}
public NtStatus DeleteDirectory(string fileName, IDokanFileInfo info)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand SP = new SqlCommand();
SP.Connection = conn;
SP.CommandText = "DELETE FROM OCI_STORAGE_WEBDAV WHERE FILENAME=@FILENAME";
SP.Parameters.AddWithValue("@FILENAME", fileName);
conn.Open();
try
{
SP.ExecuteNonQuery(); //on MoveFile can raise error due directory is exists
}
catch
{
}
}
return DokanResult.Success;
}
public NtStatus DeleteFile(string fileName, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus CreateDirectory(string filename, DokanFileInfo info)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand SP = new SqlCommand();
SP.Connection = conn;
SP.CommandType = CommandType.StoredProcedure;
SP.CommandText = "CreateDirectory";
SP.Parameters.AddWithValue("@filename", filename);
conn.Open();
try
{
SP.ExecuteNonQuery(); //on MoveFile can raise error due directory is exists
}
catch
{
}
}
return DokanResult.Success;
}
public NtStatus FindFiles(string fileName, out IList<FileInformation> files, IDokanFileInfo info)
{
//This creates the directory listing... As of curent this just lists the main directory indicated from SQL Database.
//This queries MSSQL Database for basic file information and applies it and returns it as a LIST to Dokan to create the filesystem.
IList<FileInformation> ListOfShit = new List<FileInformation>();
try
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand CMD = new SqlCommand();
CMD.CommandText = @"SELECT * FROM OCI_STORAGE_WEBDAV";
CMD.CommandType = System.Data.CommandType.Text;
CMD.Connection = conn;
conn.Open();
using (SqlDataReader reader = CMD.ExecuteReader())
{
while (reader.Read())
{
FileInformation fi = new FileInformation();
lock (FileCache)
{
if (reader[6].ToString() == "Directory")
{
FileInformation di = new FileInformation();
//if (FileCache.ContainsKey(di.FileName) == true)
// {
di.Attributes = FileAttributes.Directory;
di.FileName = reader[1].ToString();
di.Length = 0;
di.CreationTime = (DateTime)reader[3];
di.LastAccessTime = (DateTime)reader[4];
di.LastWriteTime = (DateTime)reader[5];
// }
ListOfShit.Add(di);
}
if (reader[6].ToString() == "Archive")
{
//if (FileCache.ContainsKey(fi.FileName) == true)
//{
fi.Attributes = FileAttributes.Archive;
fi.FileName = reader[1].ToString();
fi.Length = (long)reader[2];
fi.CreationTime = (DateTime)reader[3];
fi.LastAccessTime = (DateTime)reader[4];
fi.LastWriteTime = (DateTime)reader[5];
// }
ListOfShit.Add(fi);
}
}
}
files = ListOfShit;
return DokanResult.Success;
}
}
}
catch
{
files = null;
return DokanResult.Error;
}
}
public NtStatus FindFilesWithPattern(string fileName, string searchPattern, out IList<FileInformation> files, IDokanFileInfo info)
{
files = null;
return DokanResult.NotImplemented;
}
public NtStatus FindStreams(string fileName, out IList<FileInformation> streams, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus FlushFileBuffers(string fileName, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus GetDiskFreeSpace(out long freeBytesAvailable, out long totalNumberOfBytes, out long totalNumberOfFreeBytes, IDokanFileInfo info)
{
freeBytesAvailable = 3298535977703 - GetUsedSpace();
totalNumberOfBytes = 3298535977703;
totalNumberOfFreeBytes = 3298535977703 - GetUsedSpace();
return DokanResult.Success;
}
public NtStatus GetFileInformation(string fileName, out FileInformation fileInfo, IDokanFileInfo info)
{
// This extracts the MetaData from the system
var filePath = GetPath(fileName);
FileSystemInfo finfo = new FileInfo(filePath);
fileInfo = new FileInformation();
if (!finfo.Exists)
finfo = new DirectoryInfo(filePath);
if (File.Exists(filePath))
{
FileInfo fi = new FileInfo(filePath);
fileInfo.Length = fi.Length;
fileInfo.Attributes = fi.Attributes;
fileInfo.CreationTime = fi.CreationTime;
fileInfo.FileName = fi.FullName;
fileInfo.LastAccessTime = fi.LastAccessTime;
fileInfo.LastWriteTime = fi.LastWriteTime;
return Trace(nameof(GetFileInformation), fileName, info, DokanResult.Success);
}
else if (Directory.Exists(filePath))
{
info.IsDirectory = true;
DirectoryInfo fi = new DirectoryInfo(filePath);
fileInfo.Attributes = fi.Attributes;
fileInfo.CreationTime = fi.CreationTime;
fileInfo.FileName = fi.FullName;
fileInfo.LastAccessTime = fi.LastAccessTime;
fileInfo.LastWriteTime = fi.LastWriteTime;
return Trace(nameof(GetFileInformation), fileName, info, DokanResult.Success);
}
return Trace(nameof(GetFileInformation), fileName, info, DokanResult.Success);
}
public NtStatus GetFileSecurity(string fileName, out FileSystemSecurity security, AccessControlSections sections, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus GetVolumeInformation(out string volumeLabel, out FileSystemFeatures features, out string fileSystemName, out uint maximumComponentLength, IDokanFileInfo info)
{
volumeLabel = "OCI Project Directory";
fileSystemName = "OCIFS";
maximumComponentLength = 256;
features = FileSystemFeatures.CasePreservedNames | FileSystemFeatures.CaseSensitiveSearch |
FileSystemFeatures.PersistentAcls | FileSystemFeatures.SupportsRemoteStorage |
FileSystemFeatures.UnicodeOnDisk;
return Trace(nameof(GetVolumeInformation), null, info, DokanResult.Success, "out " + volumeLabel,
"out " + features.ToString(), "out " + fileSystemName);
}
public NtStatus LockFile(string fileName, long offset, long length, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus Mounted(IDokanFileInfo info)
{
return DokanResult.Success;
}
public NtStatus MoveFile(string oldName, string newName, bool replace, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus ReadFile(string fileName, byte[] buffer, out int bytesRead, long offset, IDokanFileInfo info)
{
if (info.Context == null) // memory mapped read
{
using (var stream = new FileStream(GetPath(fileName), FileMode.Open, System.IO.FileAccess.Read))
{
stream.Position = offset;
bytesRead = stream.Read(buffer, 0, buffer.Length);
}
}
else // normal read
{
var stream = info.Context as FileStream;
lock (stream) //Protect from overlapped read
{
stream.Position = offset;
bytesRead = stream.Read(buffer, 0, buffer.Length);
}
}
return Trace(nameof(ReadFile), fileName, info, DokanResult.Success, "out " + bytesRead.ToString(),
offset.ToString(CultureInfo.InvariantCulture));
}
public NtStatus SetAllocationSize(string fileName, long length, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus SetEndOfFile(string fileName, long length, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus SetFileAttributes(string fileName, FileAttributes attributes, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus SetFileSecurity(string fileName, FileSystemSecurity security, AccessControlSections sections, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus SetFileTime(string fileName, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus UnlockFile(string fileName, long offset, long length, IDokanFileInfo info)
{
throw new NotImplementedException();
}
public NtStatus Unmounted(IDokanFileInfo info)
{
FileCache.Clear();
return DokanResult.Success;
}
public NtStatus WriteFile(string fileName, byte[] buffer, out int bytesWritten, long offset, IDokanFileInfo info)
{
var append = offset == -1;
if (info.Context == null)
{
using (var stream = new FileStream(GetPath(fileName), append ? FileMode.Append : FileMode.Open, System.IO.FileAccess.Write))
{
{
stream.Position = offset;
}
stream.Write(buffer, 0, buffer.Length);
bytesWritten = buffer.Length;
}
}
else
{
var stream = info.Context as FileStream;
lock (stream) //Protect from overlapped write
{
if (append)
{
if (stream.CanSeek)
{
stream.Seek(0, SeekOrigin.End);
}
else
{
bytesWritten = 0;
return Trace(nameof(WriteFile), fileName, info, DokanResult.Error, "out " + bytesWritten,
offset.ToString(CultureInfo.InvariantCulture));
}
}
else
{
stream.Position = offset;
}
stream.Write(buffer, 0, buffer.Length);
}
bytesWritten = buffer.Length;
}
return Trace(nameof(WriteFile), fileName, info, DokanResult.Success, "out " + bytesWritten.ToString(),
offset.ToString(CultureInfo.InvariantCulture));
}
public Int64 GetUsedSpace()
{
string CX1 = "Data Source=192.168.0.31;User ID=ocisql;Password=Emagdne1212";
string sql = @"select sum(length) from oci_storage_webdav";
string variable;
using (var connection = new SqlConnection(CX1))
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
return Convert.ToInt64(command.ExecuteNonQuery() + 10737412742);
}
}
public string GetPath(string filename)
{
string CX1 = "Data Source=192.168.0.31;User ID=ocisql;Password=Emagdne1212";
string sql = @"SELECT [location] FROM OCI_STORAGE_WEBDAV where [filename] = @filename and [filename] <> ''";
string variable;
using (var connection = new SqlConnection(CX1))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("@filename", filename);
connection.Open();
directoryStr = (string)command.ExecuteScalar() + filename;
//return directoryStr;
return @"C:\Users\cgashlin\Desktop\DokanTest\" + filename;
}
}
protected NtStatus Trace(string method, string fileName, IDokanFileInfo info, NtStatus result,
params object[] parameters)
{
#if TRACE
var extraParameters = parameters != null && parameters.Length > 0
? ", " + string.Join(", ", parameters.Select(x => string.Format(DefaultFormatProvider, "{0}", x)))
: string.Empty;
logger.Debug(DokanFormat($"{method}('{fileName}', {info}{extraParameters}) -> {result}"));
#endif
return result;
}
class FileCaching
{
public MemoryStream MemStream;
public FileInformation FileInfo;
}
private static FileCaching FillFileCache(String filename)
{
FileCaching fc = new FileCaching();
fc.MemStream = new MemoryStream();
fc.FileInfo = new FileInformation();
fc.FileInfo.CreationTime = DateTime.Now;
fc.FileInfo.LastAccessTime = DateTime.Now;
fc.FileInfo.LastWriteTime = DateTime.Now;
fc.FileInfo.Length = 0;
fc.FileInfo.FileName = filename;
return fc;
}
private NtStatus Trace(string method, string fileName, IDokanFileInfo info,
FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes,
NtStatus result)
{
#if TRACE
logger.Debug(
DokanFormat(
$"{method}('{fileName}', {info}, [{access}], [{share}], [{mode}], [{options}], [{attributes}]) -> {result}"));
#endif
return result;
}
}
}