diff --git a/dokan/dokan.h b/dokan/dokan.h
new file mode 100644
index 0000000..7ef823f
--- /dev/null
+++ b/dokan/dokan.h
@@ -0,0 +1,326 @@
+/*
+ Dokan : user-mode file system library for Windows
+
+ Copyright (C) 2008 Hiroki Asakawa info@dokan-dev.net
+
+ http://dokan-dev.net/en
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free
+Software Foundation; either version 3 of the License, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program. If not, see .
+*/
+
+
+#ifndef _DOKAN_H_
+#define _DOKAN_H_
+
+#define DOKAN_DRIVER_NAME L"dokan.sys"
+
+#ifndef _M_X64
+ #ifdef _EXPORTING
+ #define DOKANAPI __declspec(dllimport) __stdcall
+ #else
+ #define DOKANAPI __declspec(dllexport) __stdcall
+ #endif
+#else
+ #define DOKANAPI
+#endif
+
+#define DOKAN_CALLBACK __stdcall
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define DOKAN_OPTION_DEBUG 1 // ouput debug message
+#define DOKAN_OPTION_STDERR 2 // ouput debug message to stderr
+#define DOKAN_OPTION_ALT_STREAM 4 // use alternate stream
+#define DOKAN_OPTION_KEEP_ALIVE 8 // use auto unmount
+#define DOKAN_OPTION_NETWORK 16 // use network drive
+#define DOKAN_OPTION_REMOVABLE 32 // use removable drive
+
+typedef struct _DOKAN_OPTIONS {
+ WCHAR DriveLetter; // drive letter to be mounted
+ USHORT ThreadCount; // number of threads to be used
+ ULONG Options; // combination of DOKAN_OPTIONS_*
+ ULONG64 GlobalContext; // FileSystem can use this variable
+} DOKAN_OPTIONS, *PDOKAN_OPTIONS;
+
+typedef struct _DOKAN_FILE_INFO {
+ ULONG64 Context; // FileSystem can use this variable
+ ULONG64 DokanContext; // Don't touch this
+ PDOKAN_OPTIONS DokanOptions; // A pointer to DOKAN_OPTIONS which was passed to DokanMain.
+ ULONG ProcessId; // process id for the thread that originally requested a given I/O operation
+ UCHAR IsDirectory; // requesting a directory file
+ UCHAR DeleteOnClose; // Delete on when "cleanup" is called
+ UCHAR PagingIo; // Read or write is paging IO.
+ UCHAR SynchronousIo; // Read or write is synchronous IO.
+ UCHAR Nocache;
+ UCHAR WriteToEndOfFile; // If true, write to the current end of file instead of Offset parameter.
+
+} DOKAN_FILE_INFO, *PDOKAN_FILE_INFO;
+
+
+// FillFileData
+// add an entry in FindFiles
+// return 1 if buffer is full, otherwise 0
+// (currently never return 1)
+typedef int (WINAPI *PFillFindData) (PWIN32_FIND_DATAW, PDOKAN_FILE_INFO);
+
+typedef struct _DOKAN_OPERATIONS {
+
+ // When an error occurs, return negative value.
+ // Usually you should return GetLastError() * -1.
+
+
+ // CreateFile
+ // If file is a directory, CreateFile (not OpenDirectory) may be called.
+ // In this case, CreateFile should return 0 when that directory can be opened.
+ // You should set TRUE on DokanFileInfo->IsDirectory when file is a directory.
+ // When CreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS and a file already exists,
+ // you should return ERROR_ALREADY_EXISTS(183) (not negative value)
+ int (DOKAN_CALLBACK *CreateFile) (
+ LPCWSTR, // FileName
+ DWORD, // DesiredAccess
+ DWORD, // ShareMode
+ DWORD, // CreationDisposition
+ DWORD, // FlagsAndAttributes
+ //HANDLE, // TemplateFile
+ PDOKAN_FILE_INFO);
+
+ int (DOKAN_CALLBACK *OpenDirectory) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+ int (DOKAN_CALLBACK *CreateDirectory) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+ // When FileInfo->DeleteOnClose is true, you must delete the file in Cleanup.
+ int (DOKAN_CALLBACK *Cleanup) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+ int (DOKAN_CALLBACK *CloseFile) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+ int (DOKAN_CALLBACK *ReadFile) (
+ LPCWSTR, // FileName
+ LPVOID, // Buffer
+ DWORD, // NumberOfBytesToRead
+ LPDWORD, // NumberOfBytesRead
+ LONGLONG, // Offset
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *WriteFile) (
+ LPCWSTR, // FileName
+ LPCVOID, // Buffer
+ DWORD, // NumberOfBytesToWrite
+ LPDWORD, // NumberOfBytesWritten
+ LONGLONG, // Offset
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *FlushFileBuffers) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *GetFileInformation) (
+ LPCWSTR, // FileName
+ LPBY_HANDLE_FILE_INFORMATION, // Buffer
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *FindFiles) (
+ LPCWSTR, // PathName
+ PFillFindData, // call this function with PWIN32_FIND_DATAW
+ PDOKAN_FILE_INFO); // (see PFillFindData definition)
+
+
+ // You should implement either FindFiles or FindFilesWithPattern
+ int (DOKAN_CALLBACK *FindFilesWithPattern) (
+ LPCWSTR, // PathName
+ LPCWSTR, // SearchPattern
+ PFillFindData, // call this function with PWIN32_FIND_DATAW
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *SetFileAttributes) (
+ LPCWSTR, // FileName
+ DWORD, // FileAttributes
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *SetFileTime) (
+ LPCWSTR, // FileName
+ CONST FILETIME*, // CreationTime
+ CONST FILETIME*, // LastAccessTime
+ CONST FILETIME*, // LastWriteTime
+ PDOKAN_FILE_INFO);
+
+
+ // You should not delete file on DeleteFile or DeleteDirectory.
+ // When DeleteFile or DeleteDirectory, you must check whether
+ // you can delete or not, and return 0 (when you can delete it)
+ // or appropriate error codes such as -ERROR_DIR_NOT_EMPTY,
+ // -ERROR_SHARING_VIOLATION.
+ // When you return 0 (ERROR_SUCCESS), you get Cleanup with
+ // FileInfo->DeleteOnClose set TRUE, you delete the file.
+ int (DOKAN_CALLBACK *DeleteFile) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+ int (DOKAN_CALLBACK *DeleteDirectory) (
+ LPCWSTR, // FileName
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *MoveFile) (
+ LPCWSTR, // ExistingFileName
+ LPCWSTR, // NewFileName
+ BOOL, // ReplaceExisiting
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *SetEndOfFile) (
+ LPCWSTR, // FileName
+ LONGLONG, // Length
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *SetAllocationSize) (
+ LPCWSTR, // FileName
+ LONGLONG, // Length
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *LockFile) (
+ LPCWSTR, // FileName
+ LONGLONG, // ByteOffset
+ LONGLONG, // Length
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *UnlockFile) (
+ LPCWSTR, // FileName
+ LONGLONG,// ByteOffset
+ LONGLONG,// Length
+ PDOKAN_FILE_INFO);
+
+
+ // Neither GetDiskFreeSpace nor GetVolumeInformation
+ // save the DokanFileContext->Context.
+ // Before these methods are called, CreateFile may not be called.
+ // (ditto CloseFile and Cleanup)
+
+ // see Win32 API GetDiskFreeSpaceEx
+ int (DOKAN_CALLBACK *GetDiskFreeSpace) (
+ PULONGLONG, // FreeBytesAvailable
+ PULONGLONG, // TotalNumberOfBytes
+ PULONGLONG, // TotalNumberOfFreeBytes
+ PDOKAN_FILE_INFO);
+
+
+ // see Win32 API GetVolumeInformation
+ int (DOKAN_CALLBACK *GetVolumeInformation) (
+ LPWSTR, // VolumeNameBuffer
+ DWORD, // VolumeNameSize in num of chars
+ LPDWORD,// VolumeSerialNumber
+ LPDWORD,// MaximumComponentLength in num of chars
+ LPDWORD,// FileSystemFlags
+ LPWSTR, // FileSystemNameBuffer
+ DWORD, // FileSystemNameSize in num of chars
+ PDOKAN_FILE_INFO);
+
+
+ int (DOKAN_CALLBACK *Unmount) (
+ PDOKAN_FILE_INFO);
+
+} DOKAN_OPERATIONS, *PDOKAN_OPERATIONS;
+
+
+
+/* DokanMain returns error codes */
+#define DOKAN_SUCCESS 0
+#define DOKAN_ERROR -1 /* General Error */
+#define DOKAN_DRIVE_LETTER_ERROR -2 /* Bad Drive letter */
+#define DOKAN_DRIVER_INSTALL_ERROR -3 /* Can't install driver */
+#define DOKAN_START_ERROR -4 /* Driver something wrong */
+#define DOKAN_MOUNT_ERROR -5 /* Can't assign a drive letter */
+
+
+int DOKANAPI
+DokanMain(
+ PDOKAN_OPTIONS DokanOptions,
+ PDOKAN_OPERATIONS DokanOperations);
+
+
+BOOL DOKANAPI
+DokanUnmount(
+ WCHAR DriveLetter);
+
+
+// DokanIsNameInExpression
+// check whether Name can match Expression
+// Expression can contain wildcard characters (? and *)
+BOOL DOKANAPI
+DokanIsNameInExpression(
+ LPCWSTR Expression, // matching pattern
+ LPCWSTR Name, // file name
+ BOOL IgnoreCase);
+
+
+ULONG DOKANAPI
+DokanVersion();
+
+ULONG DOKANAPI
+DokanDriverVersion();
+
+// DokanResetTimeout
+// extends the time out of the current IO operation in driver.
+BOOL DOKANAPI
+DokanResetTimeout(
+ ULONG Timeout, // timeout in millisecond
+ PDOKAN_FILE_INFO DokanFileInfo);
+
+
+
+// for internal use
+// don't call
+BOOL DOKANAPI
+DokanServiceInstall(
+ LPCWSTR ServiceName,
+ DWORD ServiceType,
+ LPCWSTR ServiceFullPath);
+
+BOOL DOKANAPI
+DokanServiceDelete(
+ LPCWSTR ServiceName);
+
+BOOL DOKANAPI
+DokanNetworkProviderInstall();
+
+BOOL DOKANAPI
+DokanNetworkProviderUninstall();
+
+BOOL DOKANAPI
+DokanSetDebugMode(ULONG Mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _DOKAN_H_
diff --git a/dokan/dokan.lib b/dokan/dokan.lib
new file mode 100644
index 0000000..8b5eef9
Binary files /dev/null and b/dokan/dokan.lib differ
diff --git a/zfs-win/BlockReader.cpp b/zfs-win/BlockReader.cpp
index f47bc8f..c928c18 100644
--- a/zfs-win/BlockReader.cpp
+++ b/zfs-win/BlockReader.cpp
@@ -50,6 +50,10 @@ namespace ZFS
{
m_bpl.push_back(new blkptr_t(bp[i]));
}
+ else
+ {
+ ASSERT(bp[i].lsize == 0);
+ }
}
}
else
@@ -62,6 +66,10 @@ namespace ZFS
{
l.push_back(new blkptr_t(bp[i]));
}
+ else
+ {
+ ASSERT(bp[i].lsize == 0);
+ }
}
m_bpl.insert(m_bpl.begin(), l.begin(), l.end());
diff --git a/zfs-win/DataSet.cpp b/zfs-win/DataSet.cpp
index 42137fc..fc8ff41 100644
--- a/zfs-win/DataSet.cpp
+++ b/zfs-win/DataSet.cpp
@@ -21,25 +21,26 @@
#include "stdafx.h"
#include "DataSet.h"
+#include "String.h"
namespace ZFS
{
DataSet::DataSet(Pool* pool)
: m_pool(pool)
+ , m_head(NULL)
{
}
DataSet::~DataSet()
{
- for(auto i = m_children.begin(); i != m_children.end(); i++)
- {
- delete *i;
- }
+ RemoveAll();
}
bool DataSet::Init(ObjectSet& os, const char* name, size_t root_index)
{
- m_name = name != NULL ? name : m_pool->m_name.c_str();
+ RemoveAll();
+
+ m_name = name;
dnode_phys_t dn;
@@ -67,6 +68,16 @@ namespace ZFS
m_dataset = *(dsl_dataset_phys_t*)dn.bonus();
+ if(m_dataset.bp.type == DMU_OT_OBJSET)
+ {
+ m_head = new ObjectSet(m_pool);
+
+ if(!m_head->Init(&m_dataset.bp, 1))
+ {
+ return false;
+ }
+ }
+
if(os.Read((size_t)m_dir.props_zapobj, &dn, DMU_OT_DSL_PROPS))
{
ZFS::ZapObject zap(m_pool);
@@ -107,6 +118,50 @@ namespace ZFS
return true;
}
+ void DataSet::RemoveAll()
+ {
+ for(auto i = m_children.begin(); i != m_children.end(); i++)
+ {
+ delete *i;
+ }
+
+ if(m_head != NULL)
+ {
+ delete m_head;
+
+ m_head = NULL;
+ }
+ }
+
+ void DataSet::SetDefaults(DataSet* parent)
+ {
+ // TODO
+
+ for(auto i = m_children.begin(); i != m_children.end(); i++)
+ {
+ (*i)->SetDefaults(this);
+ }
+ }
+
+ bool DataSet::Init(blkptr_t* bp, size_t count)
+ {
+ ObjectSet os(m_pool);
+
+ if(!os.Init(bp, count))
+ {
+ return false;
+ }
+
+ if(!Init(os, m_pool->m_name.c_str()))
+ {
+ return false;
+ }
+
+ SetDefaults(NULL);
+
+ return true;
+ }
+
void DataSet::GetMountPoints(std::list& mpl)
{
if(!m_mountpoint.empty())
@@ -119,4 +174,81 @@ namespace ZFS
(*i)->GetMountPoints(mpl);
}
}
+
+ bool DataSet::Find(const wchar_t* path, dnode_phys_t& dn)
+ {
+ if(m_head == NULL)
+ {
+ return false;
+ }
+
+ std::wstring s = path;
+
+ for(size_t i = 0; i < s.size(); i++)
+ {
+ if(s[i] == '\\') s[i] = '/';
+ }
+
+ if(s[0] != '/')
+ {
+ return false;
+ }
+
+ if(!m_head->Read("ROOT", &dn, DMU_OT_DIRECTORY_CONTENTS))
+ {
+ return false;
+ }
+
+ if(s == L"/")
+ {
+ return true;
+ }
+
+ std::wstring::size_type i = 1;
+
+ do
+ {
+ if(dn.type != DMU_OT_DIRECTORY_CONTENTS)
+ {
+ return false;
+ }
+
+ std::wstring::size_type j = s.find('/', i);
+
+ std::wstring dir = s.substr(i, j - i);
+
+ wprintf(L"%d-%d %s\n", i, j, dir.c_str());
+
+ i = j != std::string::npos ? j + 1 : std::string::npos;
+
+ ZFS::ZapObject zap(m_pool);
+
+ if(!zap.Init(dn.blkptr, dn.nblkptr))
+ {
+ return false;
+ }
+
+ std::string name = Util::UTF16To8(dir.c_str());
+
+ uint64_t index = 0;
+
+ if(!zap.Lookup(name.c_str(), index))
+ {
+ return false;
+ }
+
+ if(!m_head->Read((size_t)ZFS_DIRENT_OBJ(index), &dn))
+ {
+ return false;
+ }
+
+ if(dn.type != DMU_OT_DIRECTORY_CONTENTS && dn.type != DMU_OT_PLAIN_FILE_CONTENTS)
+ {
+ return false;
+ }
+ }
+ while(i != std::string::npos);
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/zfs-win/DataSet.h b/zfs-win/DataSet.h
index 1cd7d37..09d4630 100644
--- a/zfs-win/DataSet.h
+++ b/zfs-win/DataSet.h
@@ -30,21 +30,24 @@ namespace ZFS
{
Pool* m_pool;
+ bool Init(ObjectSet& os, const char* name = NULL, size_t root_index = -1);
+ void RemoveAll();
+ void SetDefaults(DataSet* parent);
+
public:
dsl_dir_phys_t m_dir; // TODO: store its properties instead
dsl_dataset_phys_t m_dataset; // TODO: store its properties instead
std::string m_name;
std::string m_mountpoint;
std::list m_children;
+ ObjectSet* m_head;
public:
DataSet(Pool* pool);
virtual ~DataSet();
- bool Init(ObjectSet& os, const char* name = NULL, size_t root_index = -1);
-
+ bool Init(blkptr_t* bp, size_t count);
void GetMountPoints(std::list& mpl);
-
- // TODO: directory browsing functions, handle mount-points transparently
+ bool Find(const wchar_t* path, dnode_phys_t& dn);
};
}
\ No newline at end of file
diff --git a/zfs-win/Device.cpp b/zfs-win/Device.cpp
index 5adeb98..778b195 100644
--- a/zfs-win/Device.cpp
+++ b/zfs-win/Device.cpp
@@ -194,7 +194,7 @@ namespace ZFS
{
Close();
- m_handle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
+ m_handle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
if(m_handle == INVALID_HANDLE_VALUE)
{
@@ -323,6 +323,18 @@ namespace ZFS
size_t Device::Read(void* buff, uint64_t size)
{
+ if(0)
+ {
+ LARGE_INTEGER li, li2;
+
+ li.QuadPart = 0;
+
+ if(SetFilePointerEx(m_handle, li, &li2, FILE_CURRENT))
+ {
+ printf("%I64d - %I64d (%I64d)\n", li2.QuadPart, li2.QuadPart + size, size);
+ }
+ }
+
DWORD read = 0;
ReadFile(m_handle, buff, (DWORD)size, &read, NULL);
diff --git a/zfs-win/ObjectSet.cpp b/zfs-win/ObjectSet.cpp
index 3c7be6c..65b4f3e 100644
--- a/zfs-win/ObjectSet.cpp
+++ b/zfs-win/ObjectSet.cpp
@@ -95,7 +95,7 @@ namespace ZFS
return false;
}
- if(!m_dnode_reader->Read(dn, sizeof(dnode_phys_t), sizeof(dnode_phys_t) * index))
+ if(!m_dnode_reader->Read(dn, sizeof(dnode_phys_t), (uint64_t)index * sizeof(dnode_phys_t)))
{
return false;
}
diff --git a/zfs-win/Pool.cpp b/zfs-win/Pool.cpp
index d260b8d..2960f2d 100644
--- a/zfs-win/Pool.cpp
+++ b/zfs-win/Pool.cpp
@@ -35,11 +35,14 @@ namespace ZFS
Close();
}
- bool Pool::Open(const char* name, const std::list& paths)
+ bool Pool::Open(const std::list& paths, const char* name)
{
Close();
- m_name = name;
+ if(name != NULL)
+ {
+ m_name = name;
+ }
for(auto i = paths.begin(); i != paths.end(); i++)
{
@@ -50,6 +53,11 @@ namespace ZFS
return false;
}
+ if(m_name.empty())
+ {
+ m_name = dev->m_desc.pool.name;
+ }
+
if(m_name == dev->m_desc.pool.name && (m_guid == 0 || m_guid == dev->m_desc.pool.guid))
{
m_guid = dev->m_desc.pool.guid;
diff --git a/zfs-win/Pool.h b/zfs-win/Pool.h
index 76f57ec..9dc0ef4 100644
--- a/zfs-win/Pool.h
+++ b/zfs-win/Pool.h
@@ -38,7 +38,7 @@ namespace ZFS
Pool();
virtual ~Pool();
- bool Open(const char* name, const std::list& paths);
+ bool Open(const std::list& paths, const char* name = NULL);
void Close();
bool Read(std::vector& buff, blkptr_t* bp, size_t count);
diff --git a/zfs-win/String.cpp b/zfs-win/String.cpp
new file mode 100644
index 0000000..31e2476
--- /dev/null
+++ b/zfs-win/String.cpp
@@ -0,0 +1,249 @@
+#include "stdafx.h"
+#include "String.h"
+
+namespace Util
+{
+ std::wstring Format(const wchar_t* fmt, ...)
+ {
+ va_list args;
+ va_start(args, fmt);
+
+ wchar_t* buff = NULL;
+
+ std::wstring str;
+
+ int len = _vscwprintf(fmt, args) + 1;
+
+ if(len > 0)
+ {
+ buff = new wchar_t[len];
+
+ vswprintf_s(buff, len, fmt, args);
+
+ str = std::wstring(buff, len - 1);
+ }
+
+ va_end(args);
+
+ delete [] buff;
+
+ return str;
+ }
+
+ std::string Format(const char* fmt, ...)
+ {
+ va_list args;
+ va_start(args, fmt);
+
+ char* buff = NULL;
+
+ std::string str;
+
+ int len = _vscprintf(fmt, args) + 1;
+
+ if(len > 0)
+ {
+ buff = new char[len];
+
+ vsprintf_s(buff, len, fmt, args);
+
+ str = std::string(buff, len - 1);
+ }
+
+ va_end(args);
+
+ delete [] buff;
+
+ return str;
+ }
+
+ std::wstring TrimLeft(const std::wstring& s, LPCWSTR chrs)
+ {
+ std::wstring::size_type i = s.find_first_not_of(chrs);
+
+ return i != std::wstring::npos ? s.substr(i) : std::wstring();
+ }
+
+ std::wstring TrimRight(const std::wstring& s, LPCWSTR chrs)
+ {
+ std::wstring::size_type i = s.find_last_not_of(chrs);
+
+ return i != std::wstring::npos ? s.substr(0, i + 1) : s;
+ }
+
+ std::wstring Trim(const std::wstring& s, LPCWSTR chrs)
+ {
+ return TrimLeft(TrimRight(s, chrs), chrs);
+ }
+
+ std::string TrimLeft(const std::string& s, LPCSTR chrs)
+ {
+ std::string::size_type i = s.find_first_not_of(chrs);
+
+ return i != std::string::npos ? s.substr(i) : std::string();
+ }
+
+ std::string TrimRight(const std::string& s, LPCSTR chrs)
+ {
+ std::string::size_type i = s.find_last_not_of(chrs);
+
+ return i != std::string::npos ? s.substr(0, i + 1) : s;
+ }
+
+ std::string Trim(const std::string& s, LPCSTR chrs)
+ {
+ return TrimLeft(TrimRight(s, chrs), chrs);
+ }
+
+ std::wstring MakeUpper(const std::wstring& s)
+ {
+ std::wstring str = s;
+
+ if(!str.empty()) _wcsupr(&str[0]);
+
+ return str;
+ }
+
+ std::wstring MakeLower(const std::wstring& s)
+ {
+ std::wstring str = s;
+
+ if(!str.empty()) _wcslwr(&str[0]);
+
+ return str;
+ }
+
+ std::string MakeUpper(const std::string& s)
+ {
+ std::string str = s;
+
+ if(!str.empty()) strupr(&str[0]);
+
+ return str;
+ }
+
+ std::string MakeLower(const std::string& s)
+ {
+ std::string str = s;
+
+ if(!str.empty()) strlwr(&str[0]);
+
+ return str;
+ }
+
+ std::wstring UTF8To16(LPCSTR s)
+ {
+ std::wstring ret;
+
+ int n = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0) - 1;
+
+ if(n >= 0)
+ {
+ wchar_t* buff = new wchar_t[n + 1];
+
+ n = MultiByteToWideChar(CP_UTF8, 0, s, -1, buff, n + 1);
+
+ if(n > 0)
+ {
+ ret = std::wstring(buff);
+ }
+
+ delete [] buff;
+ }
+
+ return ret;
+ }
+
+ std::string UTF16To8(LPCWSTR s)
+ {
+ std::string ret;
+
+ int n = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL) - 1;
+
+ if(n >= 0)
+ {
+ char* buff = new char[n + 1];
+
+ n = WideCharToMultiByte(CP_UTF8, 0, s, -1, buff, n + 1, NULL, NULL);
+
+ if(n > 0)
+ {
+ ret = std::string(buff);
+ }
+
+ delete [] buff;
+ }
+
+ return ret;
+ }
+
+ DWORD CharSetToCodePage(DWORD charset)
+ {
+ if(charset == CP_UTF8) return CP_UTF8;
+ if(charset == CP_UTF7) return CP_UTF7;
+
+ CHARSETINFO cs = {0};
+
+ TranslateCharsetInfo((DWORD*)charset, &cs, TCI_SRCCHARSET);
+
+ return cs.ciACP;
+ }
+
+ std::string ConvertMBCS(const std::string& s, DWORD src, DWORD dst)
+ {
+ wchar_t* utf16 = new wchar_t[s.size() + 1];
+
+ memset(utf16, 0, (s.size() + 1) * sizeof(wchar_t));
+
+ char* mbcs = new char[s.size() * 6 + 1];
+
+ memset(mbcs, 0, s.size() * 6 + 1);
+
+ int len = MultiByteToWideChar(CharSetToCodePage(src), 0, s.c_str(), s.size(), utf16, (s.size() + 1) * sizeof(wchar_t));
+
+ WideCharToMultiByte(CharSetToCodePage(dst), 0, utf16, len, mbcs, s.size() * 6, NULL, NULL);
+
+ std::string res = mbcs;
+
+ delete [] utf16;
+ delete [] mbcs;
+
+ return res;
+ }
+
+ std::wstring ConvertMBCS(const std::string& s, DWORD src)
+ {
+ return UTF8To16(ConvertMBCS(s, src, CP_UTF8).c_str());
+ }
+
+ std::wstring CombinePath(LPCWSTR dir, LPCWSTR fn)
+ {
+ wchar_t buff[MAX_PATH];
+
+ PathCombine(buff, dir, fn);
+
+ return std::wstring(buff);
+ }
+
+ std::wstring RemoveFileSpec(LPCWSTR path)
+ {
+ WCHAR buff[MAX_PATH];
+
+ wcscpy(buff, path);
+
+ PathRemoveFileSpec(buff);
+
+ return std::wstring(buff);
+ }
+
+ std::wstring RemoveFileExt(LPCWSTR path)
+ {
+ WCHAR buff[MAX_PATH];
+
+ wcscpy(buff, path);
+
+ PathRemoveExtension(buff);
+
+ return std::wstring(buff);
+ }
+}
\ No newline at end of file
diff --git a/zfs-win/String.h b/zfs-win/String.h
new file mode 100644
index 0000000..49ca0a8
--- /dev/null
+++ b/zfs-win/String.h
@@ -0,0 +1,87 @@
+#pragma once
+
+namespace Util
+{
+ extern std::wstring Format(const wchar_t* fmt, ...);
+ extern std::string Format(const char* fmt, ...);
+ extern std::wstring TrimLeft(const std::wstring& s, LPCWSTR chrs = L" \t\r\n");
+ extern std::wstring TrimRight(const std::wstring& s, LPCWSTR chrs = L" \t\r\n");
+ extern std::wstring Trim(const std::wstring& s, LPCWSTR chrs = L" \t\r\n");
+ extern std::string TrimLeft(const std::string& s, LPCSTR chrs = " \t\r\n");
+ extern std::string TrimRight(const std::string& s, LPCSTR chrs = " \t\r\n");
+ extern std::string Trim(const std::string& s, LPCSTR chrs = " \t\r\n");
+ extern std::wstring MakeUpper(const std::wstring& s);
+ extern std::wstring MakeLower(const std::wstring& s);
+ extern std::string MakeUpper(const std::string& s);
+ extern std::string MakeLower(const std::string& s);
+ extern std::wstring UTF8To16(LPCSTR s);
+ extern std::string UTF16To8(LPCWSTR s);
+ extern DWORD CharSetToCodePage(DWORD charset);
+ extern std::string ConvertMBCS(const std::string& s, DWORD src, DWORD dst);
+ extern std::wstring ConvertMBCS(const std::string& s, DWORD src);
+ extern std::wstring CombinePath(LPCWSTR dir, LPCWSTR fn);
+ extern std::wstring RemoveFileSpec(LPCWSTR path);
+ extern std::wstring RemoveFileExt(LPCWSTR path);
+
+ template void Replace(T& s, typename T::const_pointer src, typename T::const_pointer dst)
+ {
+ int i = 0;
+
+ int src_size = T(src).size();
+ int dst_size = T(dst).size();
+
+ while((i = s.find(src, i)) != std::string::npos)
+ {
+ s.replace(i, src_size, dst);
+
+ i += dst_size;
+ }
+ }
+
+ template T Explode(const T& str, U& tokens, SEP sep, int limit = 0)
+ {
+ tokens.clear();
+
+ for(int i = 0, j = 0; ; i = j + 1)
+ {
+ j = str.find_first_of(sep, i);
+
+ if(j == T::npos || tokens.size() == limit - 1)
+ {
+ tokens.push_back(Trim(str.substr(i)));
+
+ break;
+ }
+ else
+ {
+ tokens.push_back(Trim(str.substr(i, j - i)));
+ }
+ }
+
+ return tokens.front();
+ }
+
+ template T Implode(const std::list& src, SEP sep)
+ {
+ T s;
+
+ if(!src.empty())
+ {
+ auto i = src.begin();
+
+ for(;;)
+ {
+ s += *i++;
+
+ if(i == src.end())
+ {
+ break;
+ }
+
+ s += sep;
+ }
+ }
+
+ return s;
+ }
+}
\ No newline at end of file
diff --git a/zfs-win/main.cpp b/zfs-win/main.cpp
index 09c5aad..023c926 100644
--- a/zfs-win/main.cpp
+++ b/zfs-win/main.cpp
@@ -22,19 +22,745 @@
#include "stdafx.h"
#include "Pool.h"
#include "DataSet.h"
-#include
+#include "String.h"
+#include "../dokan/dokan.h"
+
+using namespace Util;
+
+namespace ZFS
+{
+ class Context
+ {
+ public:
+ Pool pool;
+ DataSet* root;
+ DataSet* mounted;
+ std::wstring name;
+
+ Context() {root = mounted = NULL;}
+ ~Context() {delete root;}
+ };
+
+ static void UnixTimeToFileTime(uint64_t t, FILETIME* pft)
+ {
+ // http://support.microsoft.com/kb/167296
+
+ *(uint64_t*)pft = (t * 10000000) + 116444736000000000ull;
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(pft, &st);
+ t = t;
+ }
+
+ static int WINAPI CreateFile(
+ LPCWSTR FileName,
+ DWORD AccessMode,
+ DWORD ShareMode,
+ DWORD CreationDisposition,
+ DWORD FlagsAndAttributes,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ dnode_phys_t dn;
+
+ memset(&dn, 0, sizeof(dn));
+
+ if(!ctx->mounted->Find(FileName, dn))
+ {
+ dn.type = 0;
+ }
+
+ switch(CreationDisposition)
+ {
+ case CREATE_NEW:
+ return dn.type != 0 ? -ERROR_FILE_EXISTS : -ERROR_ACCESS_DENIED;
+ case CREATE_ALWAYS:
+ return -ERROR_ACCESS_DENIED;
+ case TRUNCATE_EXISTING:
+ return dn.type == 0 ? -ERROR_FILE_NOT_FOUND : -ERROR_ACCESS_DENIED;
+ case OPEN_EXISTING:
+ if(dn.type == 0) return -ERROR_FILE_NOT_FOUND;
+ break;
+ case OPEN_ALWAYS:
+ if(dn.type == 0) return -ERROR_ACCESS_DENIED;
+ break;
+ default:
+ return -1;
+ }
+
+ if(dn.type == DMU_OT_DIRECTORY_CONTENTS)
+ {
+ DokanFileInfo->IsDirectory = 1;
+ }
+
+ DokanFileInfo->Context = (ULONG64)new dnode_phys_t(dn);
+
+ return CreationDisposition == OPEN_ALWAYS ? ERROR_ALREADY_EXISTS : 0;
+ }
+
+ static int WINAPI OpenDirectory(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ dnode_phys_t dn;
+
+ if(!ctx->mounted->Find(FileName, dn) || dn.type != DMU_OT_DIRECTORY_CONTENTS)
+ {
+ return -ERROR_PATH_NOT_FOUND;
+ }
+
+ DokanFileInfo->Context = (ULONG64)new dnode_phys_t(dn);
+
+ return 0;
+ }
+
+ static int WINAPI CreateDirectory(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI Cleanup(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ if(DokanFileInfo->Context != 0)
+ {
+ dnode_phys_t* dn = (dnode_phys_t*)DokanFileInfo->Context;
+
+ delete dn;
+
+ DokanFileInfo->Context = 0;
+ }
+
+ return 0;
+ }
+
+ static int WINAPI CloseFile(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ if(DokanFileInfo->Context != 0)
+ {
+ dnode_phys_t* dn = (dnode_phys_t*)DokanFileInfo->Context;
+
+ delete dn;
+
+ DokanFileInfo->Context = 0;
+ }
+
+ return 0;
+ }
+
+ static int WINAPI ReadFile(
+ LPCWSTR FileName,
+ LPVOID Buffer,
+ DWORD BufferLength,
+ LPDWORD ReadLength,
+ LONGLONG Offset,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI WriteFile(
+ LPCWSTR FileName,
+ LPCVOID Buffer,
+ DWORD NumberOfBytesToWrite,
+ LPDWORD NumberOfBytesWritten,
+ LONGLONG Offset,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI FlushFileBuffers(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI GetFileInformation(
+ LPCWSTR FileName,
+ LPBY_HANDLE_FILE_INFORMATION HandleFileInformation,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ dnode_phys_t* dn = (dnode_phys_t*)DokanFileInfo->Context;
+
+ znode_phys_t* node = (znode_phys_t*)dn->bonus();
+
+ UnixTimeToFileTime(node->crtime[0], &HandleFileInformation->ftCreationTime);
+ UnixTimeToFileTime(node->atime[0], &HandleFileInformation->ftLastAccessTime);
+ UnixTimeToFileTime(node->mtime[0], &HandleFileInformation->ftLastWriteTime);
+
+ HandleFileInformation->dwFileAttributes = 0;
+
+ if(1)
+ {
+ HandleFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; // TODO
+ }
+
+ if(dn->type == DMU_OT_DIRECTORY_CONTENTS)
+ {
+ HandleFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ HandleFileInformation->dwVolumeSerialNumber = 0;
+ HandleFileInformation->nFileSizeLow = (DWORD)(node->size);
+ HandleFileInformation->nFileSizeHigh = (DWORD)(node->size >> 32);
+ HandleFileInformation->nNumberOfLinks = 1;
+ HandleFileInformation->nFileIndexLow = 0;
+ HandleFileInformation->nFileIndexHigh = 0;
+
+ return 0;
+ }
+
+ static int WINAPI FindFiles(
+ LPCWSTR FileName,
+ PFillFindData FillFindData,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI FindFilesWithPattern(
+ LPCWSTR PathName,
+ LPCWSTR SearchPattern,
+ PFillFindData Callback, // call this function with PWIN32_FIND_DATAW
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s %s\n", __FUNCTIONW__, PathName, SearchPattern);
+
+ if(DokanFileInfo->Context != 0)
+ {
+ dnode_phys_t* dn = (dnode_phys_t*)DokanFileInfo->Context;
+
+ if(dn->type != DMU_OT_DIRECTORY_CONTENTS)
+ {
+ return -1;
+ }
+
+ ZFS::ZapObject zap(&ctx->pool);
+
+ if(!zap.Init(dn->blkptr, dn->nblkptr))
+ {
+ return -1;
+ }
+
+ for(auto i = zap.begin(); i != zap.end(); i++)
+ {
+ uint64_t index = 0;
+
+ if(!zap.Lookup(i->first.c_str(), index))
+ {
+ return false;
+ }
+
+ dnode_phys_t subdn;
+
+ if(!ctx->mounted->m_head->Read((size_t)ZFS_DIRENT_OBJ(index), &subdn))
+ {
+ return false;
+ }
+
+ znode_phys_t* node = (znode_phys_t*)subdn.bonus();
+
+ WIN32_FIND_DATAW fd;
+
+ fd.dwFileAttributes = 0;
+
+ if(1)
+ {
+ fd.dwFileAttributes |= FILE_ATTRIBUTE_READONLY; // TODO
+ }
+
+ if(subdn.type == DMU_OT_DIRECTORY_CONTENTS)
+ {
+ fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ UnixTimeToFileTime(node->crtime[0], &fd.ftCreationTime);
+ UnixTimeToFileTime(node->atime[0], &fd.ftLastAccessTime);
+ UnixTimeToFileTime(node->mtime[0], &fd.ftLastWriteTime);
+
+ fd.nFileSizeLow = (DWORD)(node->size);
+ fd.nFileSizeHigh = (DWORD)(node->size >> 32);
+
+ std::wstring fn = Util::UTF8To16(i->first.c_str());
+
+ wcscpy(fd.cFileName, fn.c_str());
+
+ fd.cAlternateFileName[0] = 0; // ???
+
+ if(Callback(&fd, DokanFileInfo) != 0)
+ {
+ break;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ static int WINAPI SetFileAttributes(
+ LPCWSTR FileName,
+ DWORD FileAttributes,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI SetFileTime(
+ LPCWSTR FileName,
+ CONST FILETIME* CreationTime,
+ CONST FILETIME* LastAccessTime,
+ CONST FILETIME* LastWriteTime,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI DeleteFile(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI DeleteDirectory(
+ LPCWSTR FileName,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI MoveFile(
+ LPCWSTR FileName, // existing file name
+ LPCWSTR NewFileName,
+ BOOL ReplaceIfExisting,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI SetEndOfFile(
+ LPCWSTR FileName,
+ LONGLONG ByteOffset,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI SetAllocationSize(
+ LPCWSTR FileName,
+ LONGLONG AllocSize,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI LockFile(
+ LPCWSTR FileName,
+ LONGLONG ByteOffset,
+ LONGLONG Length,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI UnlockFile(
+ LPCWSTR FileName,
+ LONGLONG ByteOffset,
+ LONGLONG Length,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s: %s\n", __FUNCTIONW__, FileName);
+
+ return -ERROR_ACCESS_DENIED;
+ }
+
+ static int WINAPI GetDiskFreeSpace(
+ PULONGLONG FreeBytesAvailable,
+ PULONGLONG TotalNumberOfBytes,
+ PULONGLONG TotalNumberOfFreeBytes,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s\n", __FUNCTIONW__);
+
+ uint64_t total = 0;
+
+ for(auto i = ctx->pool.m_vdevs.begin(); i != ctx->pool.m_vdevs.end(); i++)
+ {
+ VirtualDevice* vdev = *i;
+
+ if(vdev->type == "raidz")
+ {
+ size_t count = vdev->children.size();
+
+ if(count > 1)
+ {
+ total += vdev->asize * (count - vdev->nparity) / count;
+ }
+ }
+ else if(vdev->type == "mirror")
+ {
+ size_t count = vdev->children.size();
+
+ if(count > 0)
+ {
+ total += vdev->asize / count;
+ }
+ }
+ else
+ {
+ total += vdev->asize;
+ }
+ }
+
+ if(TotalNumberOfBytes != NULL)
+ {
+ *TotalNumberOfBytes = total;
+ }
+
+ if(TotalNumberOfFreeBytes != NULL)
+ {
+ *TotalNumberOfFreeBytes = total - ctx->root->m_dir.used_bytes;
+ }
+
+ if(FreeBytesAvailable != NULL)
+ {
+ *FreeBytesAvailable = total - ctx->root->m_dir.used_bytes;
+ }
+
+ return 0;
+ }
+
+ static int WINAPI GetVolumeInformation(
+ LPWSTR VolumeNameBuffer,
+ DWORD VolumeNameSize,
+ LPDWORD VolumeSerialNumber,
+ LPDWORD MaximumComponentLength,
+ LPDWORD FileSystemFlags,
+ LPWSTR FileSystemNameBuffer,
+ DWORD FileSystemNameSize,
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s\n", __FUNCTIONW__);
+
+ if(VolumeNameBuffer != NULL)
+ {
+ wcscpy(VolumeNameBuffer, ctx->name.c_str());
+ }
+
+ if(VolumeSerialNumber != NULL)
+ {
+ *VolumeSerialNumber = 0;
+ }
+
+ if(MaximumComponentLength != NULL)
+ {
+ *MaximumComponentLength = 256;
+ }
+
+ if(FileSystemFlags != NULL)
+ {
+ *FileSystemFlags =
+ FILE_CASE_SENSITIVE_SEARCH |
+ FILE_CASE_PRESERVED_NAMES |
+ FILE_UNICODE_ON_DISK |
+ FILE_READ_ONLY_VOLUME;
+ }
+
+ if(FileSystemNameBuffer != NULL)
+ {
+ wcscpy(FileSystemNameBuffer, L"ZFS");
+ }
+
+ return 0;
+ }
+
+ static int WINAPI Unmount(
+ DOKAN_FILE_INFO* DokanFileInfo)
+ {
+ Context* ctx = (Context*)DokanFileInfo->DokanOptions->GlobalContext;
+
+ wprintf(L"%s\n", __FUNCTIONW__);
+
+ return 0;
+ }
+}
+
+static void usage()
+{
+ printf(
+ "ZFS for Windows\n"
+ "\n"
+ "commands:\n"
+ " mount \n"
+ " list \n"
+ "\n"
+ "pool:\n"
+ " Any combination of devices (\\\\.\\PhysicalDriveN) or files.\n"
+ "\n"
+ "examples:\n"
+ " zfs-win.exe mount m \"rpool/ROOT/opensolaris\" \"\\\\.\\PhysicalDrive1\" \"\\\\.\\PhysicalDrive2\"\n"
+ );
+}
int _tmain(int argc, _TCHAR* argv[])
{
- // this is just a test, recreating the steps of "ZFS On-Disk Data Walk (Or: Where's My Data)" (google for it)
+ if(argc < 2) {usage(); return -1;}
+ wchar_t drive = 0;
std::list paths;
- /*
- for(int i = 2; i < argc; i++)
+ std::list dataset;
+
+ if(wcsicmp(argv[1], L"mount") == 0)
{
- paths.push_back(argv[i]);
+ if(argc < 5) {usage(); return -1;}
+
+ drive = argv[2][0];
+
+ Util::Explode(std::wstring(argv[3]), dataset, L"/");
+
+ for(int i = 4; i < argc; i++)
+ {
+ paths.push_back(argv[i]);
+ }
}
+ else if(wcsicmp(argv[1], L"list") == 0)
+ {
+ if(argc < 3) {usage(); return -1;}
+
+ for(int i = 2; i < argc; i++)
+ {
+ paths.push_back(argv[i]);
+ }
+
+ return -1; // TODO
+ }
+
+ if(paths.empty()) {usage(); return -1;}
+
+ /*
+
+ paths.clear();
+
+ paths.push_back(L"\\\\.\\PhysicalDrive1");
+ paths.push_back(L"\\\\.\\PhysicalDrive2");
+ paths.push_back(L"\\\\.\\PhysicalDrive3");
+ paths.push_back(L"\\\\.\\PhysicalDrive4");
+
+ Util::Explode(std::wstring(L"share/backup"), dataset, L"/");
+
*/
+
+ ZFS::Context ctx;
+
+ std::wstring name = dataset.front();
+
+ dataset.pop_front();
+
+ if(!ctx.pool.Open(paths, UTF16To8(name.c_str()).c_str()))
+ {
+ printf("Failed to open pool\n");
+
+ return -1;
+ }
+
+ ctx.root = new ZFS::DataSet(&ctx.pool);
+
+ if(!ctx.root->Init(&ctx.pool.m_devs.front()->m_active->rootbp, 1))
+ {
+ printf("Failed to read root dataset\n");
+
+ return -1;
+ }
+
+ ZFS::DataSet* ds = ctx.root;
+
+ ctx.name = name;
+
+ while(!dataset.empty())
+ {
+ name = dataset.front();
+
+ dataset.pop_front();
+
+ ZFS::DataSet* ds2 = NULL;
+
+ for(auto i = ds->m_children.begin(); i != ds->m_children.end(); i++)
+ {
+ if((*i)->m_name == UTF16To8(name.c_str()))
+ {
+ ds2 = *i;
+
+ break;
+ }
+ }
+
+ if(ds2 == NULL) {usage(); return -1;}
+
+ ds = ds2;
+
+ // ctx.name += L"/" + name;
+ }
+
+ ctx.mounted = ds;
+
+ //
+
+ DOKAN_OPTIONS options;
+
+ memset(&options, 0, sizeof(DOKAN_OPTIONS));
+
+ options.DriveLetter = drive;
+ options.GlobalContext = (ULONG64)&ctx;
+ options.ThreadCount = 1; // TODO
+ options.Options = DOKAN_OPTION_KEEP_ALIVE;
+
+ #ifdef _DEBUG
+
+ options.Options |= DOKAN_OPTION_DEBUG;
+
+ #endif
+
+ DOKAN_OPERATIONS ops;
+
+ memset(&ops, 0, sizeof(DOKAN_OPERATIONS));
+
+ ops.CreateFile = ZFS::CreateFile;
+ ops.OpenDirectory = ZFS::OpenDirectory;
+ ops.CreateDirectory = ZFS::CreateDirectory;
+ ops.Cleanup = ZFS::Cleanup;
+ ops.CloseFile = ZFS::CloseFile;
+ ops.ReadFile = ZFS::ReadFile;
+ ops.WriteFile = ZFS::WriteFile;
+ ops.FlushFileBuffers = ZFS::FlushFileBuffers;
+ ops.GetFileInformation = ZFS::GetFileInformation;
+ ops.FindFiles = ZFS::FindFiles;
+ ops.FindFilesWithPattern = ZFS::FindFilesWithPattern;
+ ops.SetFileAttributes = ZFS::SetFileAttributes;
+ ops.SetFileTime = ZFS::SetFileTime;
+ ops.DeleteFile = ZFS::DeleteFile;
+ ops.DeleteDirectory = ZFS::DeleteDirectory;
+ ops.MoveFile = ZFS::MoveFile;
+ ops.SetEndOfFile = ZFS::SetEndOfFile;
+ ops.SetAllocationSize = ZFS::SetAllocationSize;
+ ops.LockFile = ZFS::LockFile;
+ ops.UnlockFile = ZFS::UnlockFile;
+ ops.GetDiskFreeSpace = ZFS::GetDiskFreeSpace;
+ ops.GetVolumeInformation = ZFS::GetVolumeInformation;
+ ops.Unmount = ZFS::Unmount;
+
+ switch(int status = DokanMain(&options, &ops))
+ {
+ case DOKAN_SUCCESS:
+ printf("Success\n");
+ break;
+ case DOKAN_ERROR:
+ printf("Error\n");
+ break;
+ case DOKAN_DRIVE_LETTER_ERROR:
+ printf("Bad Drive letter\n");
+ break;
+ case DOKAN_DRIVER_INSTALL_ERROR:
+ printf("Can't install driver\n");
+ break;
+ case DOKAN_START_ERROR:
+ printf("Driver something wrong\n");
+ break;
+ case DOKAN_MOUNT_ERROR:
+ printf("Can't assign a drive letter\n");
+ break;
+ default:
+ printf("Unknown error: %d\n", status);
+ break;
+ }
+
+ // std::list paths;
+
/*
const char* name = "mpool";
@@ -48,6 +774,7 @@ int _tmain(int argc, _TCHAR* argv[])
paths.push_back(L"D:\\Virtual Machines\\ZFSVM\\ZFSVM7-flat.vmdk");
paths.push_back(L"D:\\Virtual Machines\\ZFSVM\\ZFSVM8-flat.vmdk");
*/
+
/*
const char* name = "share";
@@ -56,57 +783,18 @@ int _tmain(int argc, _TCHAR* argv[])
paths.push_back(L"\\\\.\\PhysicalDrive3");
paths.push_back(L"\\\\.\\PhysicalDrive4");
*/
- /**/
+
+ /*
const char* name = "rpool";
paths.push_back(L"D:\\Virtual Machines\\OpenSolaris\\OpenSolaris-flat.vmdk");
-
- ZFS::Pool pool;
+ */
- if(!pool.Open(name, paths))
- {
- return -1;
- }
+ /*
+ const char* name = "rpool";
- ZFS::Device* dev = pool.m_devs.front();
-
- ZFS::ObjectSet os(&pool);
-
- if(os.Init(&dev->m_active->rootbp, 1))
- {
- ZFS::DataSet ds(&pool);
-
- if(ds.Init(os))
- {
- std::list mpl;
-
- ds.GetMountPoints(mpl);
-
- for(auto i = mpl.begin(); i != mpl.end(); i++)
- {
- if((*i)->m_mountpoint != "/") continue;
-
- ZFS::ObjectSet os(&pool);
-
- if(os.Init(&(*i)->m_dataset.bp, 1))
- {
- dnode_phys_t root;
-
- if(os.Read("ROOT", &root, DMU_OT_DIRECTORY_CONTENTS))
- {
- znode_phys_t* node = (znode_phys_t*)root.bonus();
-
- ZFS::ZapObject zap(&pool);
-
- if(zap.Init(root.blkptr, root.nblkptr))
- {
- int i = 0;
- }
- }
- }
- }
- }
- }
+ paths.push_back(L"D:\\Virtual Machines\\ZFS1VM\\ZFS1VM-flat.vmdk");
+ */
return 0;
}
diff --git a/zfs-win/stdafx.h b/zfs-win/stdafx.h
index ee8e568..3071ec3 100644
--- a/zfs-win/stdafx.h
+++ b/zfs-win/stdafx.h
@@ -30,6 +30,7 @@
#include
#include
+#include
#include
#include
diff --git a/zfs-win/zfs-win.vcxproj b/zfs-win/zfs-win.vcxproj
index c6e5eaa..98bbca1 100644
--- a/zfs-win/zfs-win.vcxproj
+++ b/zfs-win/zfs-win.vcxproj
@@ -50,7 +50,7 @@
Console
- $(OutDir)zlib.lib;%(AdditionalDependencies)
+ $(OutDir)zlib.lib;$(SolutionDir)dokan\dokan.lib;shlwapi.lib;%(AdditionalDependencies)
@@ -60,7 +60,7 @@
Console
- $(OutDir)zlib.lib;%(AdditionalDependencies)
+ $(OutDir)zlib.lib;$(SolutionDir)dokan\dokan.lib;shlwapi.lib;%(AdditionalDependencies)
@@ -72,6 +72,7 @@
+
@@ -91,6 +92,7 @@
+
diff --git a/zfs-win/zfs-win.vcxproj.filters b/zfs-win/zfs-win.vcxproj.filters
index 782e0de..604a575 100644
--- a/zfs-win/zfs-win.vcxproj.filters
+++ b/zfs-win/zfs-win.vcxproj.filters
@@ -51,6 +51,9 @@
Header Files
+
+ Header Files
+
@@ -86,5 +89,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/zfs-win/zfs.h b/zfs-win/zfs.h
index ac830bb..b5e9946 100644
--- a/zfs-win/zfs.h
+++ b/zfs-win/zfs.h
@@ -963,8 +963,8 @@ struct zfs_acl_phys_t
* 12 bits are unused.
*/
-#define ZFS_DIRENT_TYPE(de) BF64_GET(de, 60, 4)
-#define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48)
+#define ZFS_DIRENT_TYPE(de) ((de) >> 60)
+#define ZFS_DIRENT_OBJ(de) ((de) & 0xFFFFFFFFFFFFull)
/*
* This is the persistent portion of the znode. It is stored