2
0
mirror of https://github.com/dominicusin/zfs-win synced 2025-08-30 13:57:58 +00:00

dokan callbacks, directory listing, file attributes

This commit is contained in:
gabest11 2010-07-24 10:33:51 +00:00
parent 8f21175190
commit e49cdd1a4a
16 changed files with 1591 additions and 69 deletions

326
dokan/dokan.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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_

BIN
dokan/dokan.lib Normal file

Binary file not shown.

View File

@ -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());

View File

@ -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<DataSet*>& 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;
}
}

View File

@ -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<DataSet*> 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<DataSet*>& mpl);
// TODO: directory browsing functions, handle mount-points transparently
bool Find(const wchar_t* path, dnode_phys_t& dn);
};
}

View File

@ -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);

View File

@ -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;
}

View File

@ -35,11 +35,14 @@ namespace ZFS
Close();
}
bool Pool::Open(const char* name, const std::list<std::wstring>& paths)
bool Pool::Open(const std::list<std::wstring>& 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;

View File

@ -38,7 +38,7 @@ namespace ZFS
Pool();
virtual ~Pool();
bool Open(const char* name, const std::list<std::wstring>& paths);
bool Open(const std::list<std::wstring>& paths, const char* name = NULL);
void Close();
bool Read(std::vector<uint8_t>& buff, blkptr_t* bp, size_t count);

249
zfs-win/String.cpp Normal file
View File

@ -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);
}
}

87
zfs-win/String.h Normal file
View File

@ -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<class T> 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<class T, class U, typename SEP> 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<class T, typename SEP> T Implode(const std::list<T>& src, SEP sep)
{
T s;
if(!src.empty())
{
auto i = src.begin();
for(;;)
{
s += *i++;
if(i == src.end())
{
break;
}
s += sep;
}
}
return s;
}
}

View File

@ -22,19 +22,745 @@
#include "stdafx.h"
#include "Pool.h"
#include "DataSet.h"
#include <time.h>
#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 <drive> <dataset> <pool>\n"
" list <pool>\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<std::wstring> paths;
/*
for(int i = 2; i < argc; i++)
std::list<std::wstring> 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<std::wstring> 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<ZFS::DataSet*> 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;
}

View File

@ -30,6 +30,7 @@
#include <windows.h>
#include <wincrypt.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdint.h>

View File

@ -50,7 +50,7 @@
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>$(OutDir)zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(OutDir)zlib.lib;$(SolutionDir)dokan\dokan.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -60,7 +60,7 @@
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>$(OutDir)zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(OutDir)zlib.lib;$(SolutionDir)dokan\dokan.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -72,6 +72,7 @@
<ClInclude Include="NameValueList.h" />
<ClInclude Include="ObjectSet.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="String.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="Pool.h" />
<ClInclude Include="ZapObject.h" />
@ -91,6 +92,7 @@
<ClCompile Include="Pool.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="String.cpp" />
<ClCompile Include="ZapObject.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -51,6 +51,9 @@
<ClInclude Include="DataSet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="String.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -86,5 +89,8 @@
<ClCompile Include="DataSet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="String.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -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