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