1209 lines
46 KiB
C++
1209 lines
46 KiB
C++
/*
|
|
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
|
*
|
|
* Licensed under the BSD License, see LICENSE file for details.
|
|
*
|
|
*/
|
|
|
|
#include "cbfs/cbfs_adapter.h"
|
|
|
|
#include <string>
|
|
|
|
#include "cbfs/cbfs_enumeration_context.h"
|
|
#include "cbfs/cbfs_license.h"
|
|
#include "cbfs/cbfs_options.h"
|
|
#include "libxtreemfs/client.h"
|
|
#include "libxtreemfs/file_handle.h"
|
|
#include "libxtreemfs/helper.h"
|
|
#include "libxtreemfs/system_user_mapping.h"
|
|
#include "libxtreemfs/user_mapping.h"
|
|
#include "libxtreemfs/volume.h"
|
|
#include "libxtreemfs/xtreemfs_exception.h"
|
|
#include "util/logging.h"
|
|
#include "util/error_log.h"
|
|
|
|
using namespace std;
|
|
using namespace xtreemfs::pbrpc;
|
|
using namespace xtreemfs::util;
|
|
|
|
namespace xtreemfs {
|
|
|
|
#define DelegateCheckFlag(val, flag) \
|
|
if (val & flag) { DbgPrint(L"\t" L#flag L"\n"); }
|
|
|
|
#define CATCH_AND_CONVERT_ERRORS \
|
|
catch (const PosixErrorException& e) { \
|
|
throw ECBFSError(ConvertXtreemFSErrnoToWindows(e.posix_errno())); \
|
|
} catch (const XtreemFSException&) { \
|
|
throw ECBFSError(EIO); \
|
|
} catch (const exception& e) { \
|
|
ErrorLog::error_log->AppendError( \
|
|
"A non-XtreemFS exception occurred: " \
|
|
+ string(e.what())); \
|
|
throw ECBFSError(EIO); \
|
|
}
|
|
|
|
/** Calls Sender->GetTag() to return the current CbFSAdapter instance. */
|
|
static xtreemfs::CbFSAdapter* Adapter(CallbackFileSystem* Sender) {
|
|
return reinterpret_cast<xtreemfs::CbFSAdapter*>(Sender->GetTag());
|
|
}
|
|
|
|
/** Unimplemented. */
|
|
static void DelegateMount(CallbackFileSystem* sender) {}
|
|
|
|
/** Unimplemented. */
|
|
static void DelegateUnmount(CallbackFileSystem* sender) {}
|
|
|
|
static void DelegateGetVolumeSize(CallbackFileSystem* Sender,
|
|
__int64* TotalNumberOfSectors,
|
|
__int64* NumberOfFreeSectors) {
|
|
Adapter(Sender)->GetVolumeSize(Sender,TotalNumberOfSectors, NumberOfFreeSectors); // NOLINT
|
|
}
|
|
|
|
static void DelegateGetVolumeLabel(CallbackFileSystem* Sender,
|
|
LPTSTR VolumeLabel) {
|
|
Adapter(Sender)->GetVolumeLabel(Sender, VolumeLabel);
|
|
}
|
|
|
|
static void DelegateSetVolumeLabel(CallbackFileSystem* Sender,
|
|
LPCTSTR VolumeLabel) {
|
|
throw ECBFSError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
static void DelegateGetVolumeId(CallbackFileSystem* Sender, PDWORD VolumeID) {
|
|
Adapter(Sender)->GetVolumeId(Sender, VolumeID);
|
|
}
|
|
|
|
/** Unimplemented. */
|
|
static void DelegateOpenVolume(CallbackFileSystem* Sender) {}
|
|
|
|
/** Unimplemented. */
|
|
static void DelegateCloseVolume(CallbackFileSystem* Sender) {}
|
|
|
|
static void DelegateCreateFile(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
DWORD FileAttributes,
|
|
DWORD ShareMode,
|
|
PVOID* FileHandleContext) {
|
|
Adapter(Sender)->CreateFile(Sender, FileName, DesiredAccess, FileAttributes, ShareMode, FileHandleContext); // NOLINT
|
|
|
|
CbFSAdapter::DebugPrintCreateFile(L"CreateFile", FileName, DesiredAccess, FileAttributes, ShareMode, *FileHandleContext);
|
|
}
|
|
|
|
static void DelegateOpenFile(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
DWORD ShareMode,
|
|
PVOID* FileHandleContext) {
|
|
Adapter(Sender)->OpenFile(Sender, FileName, DesiredAccess, ShareMode, FileHandleContext); // NOLINT
|
|
|
|
CbFSAdapter::DebugPrintCreateFile(L"OpenFile", FileName, DesiredAccess, 0, ShareMode, *FileHandleContext);
|
|
}
|
|
|
|
static void DelegateCloseFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext) {
|
|
if (FileHandleContext != NULL && Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "CloseFile " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << endl;
|
|
}
|
|
Adapter(Sender)->CloseFile(Sender, FileInfo, FileHandleContext);
|
|
}
|
|
|
|
static void DelegateGetFileInfo(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
LPBOOL FileExists,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
__int64* EndOfFile,
|
|
__int64* AllocationSize,
|
|
__int64* FileId,
|
|
PDWORD FileAttributes,
|
|
LPTSTR LongFileName OPTIONAL,
|
|
PWORD LongFileNameLength OPTIONAL) {
|
|
Adapter(Sender)->GetFileInfo(Sender, FileName, FileExists, CreationTime, LastAccessTime, LastWriteTime, EndOfFile, AllocationSize, FileId, FileAttributes, LongFileName, LongFileNameLength); // NOLINT
|
|
|
|
CbFSAdapter::DebugPrintCreateFile(L"GetFileInfo", FileName, 0, *FileAttributes, 0, 0);
|
|
}
|
|
|
|
static void DelegateEnumerateDirectory(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* DirectoryInfo,
|
|
PVOID* EnumerationContext,
|
|
LPCTSTR Mask,
|
|
INT Index,
|
|
BOOL Restart,
|
|
LPBOOL FileFound,
|
|
LPTSTR FileName,
|
|
PDWORD FileNameLength,
|
|
LPTSTR ShortFileName OPTIONAL,
|
|
PUCHAR ShortFileNameLength OPTIONAL,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
__int64* EndOfFile,
|
|
__int64* AllocationSize,
|
|
__int64* FileId,
|
|
PDWORD FileAttributes) {
|
|
Adapter(Sender)->EnumerateDirectory(Sender, DirectoryInfo, EnumerationContext, Mask, Index, Restart, FileFound, FileName, FileNameLength, ShortFileName, ShortFileNameLength, CreationTime, LastAccessTime, LastWriteTime, EndOfFile, AllocationSize, FileId, FileAttributes); // NOLINT
|
|
}
|
|
|
|
static void DelegateCloseEnumeration(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* DirectoryInfo,
|
|
PVOID EnumerationContext) {
|
|
Adapter(Sender)->CloseEnumeration(Sender, DirectoryInfo, EnumerationContext);
|
|
}
|
|
|
|
static void DelegateSetFileAttributes(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
DWORD FileAttributes) {
|
|
CbFSAdapter::DebugPrintCreateFile(L"SetFileAttributes", FileInfo->get_FileNameBuffer(), 0, FileAttributes, 0, 0);
|
|
|
|
Adapter(Sender)->SetFileAttributes(Sender, FileInfo, FileHandleContext, CreationTime, LastAccessTime, LastWriteTime, FileAttributes); // NOLINT
|
|
}
|
|
|
|
static void DelegateCanFileBeDeleted(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
BOOL* CanBeDeleted) {
|
|
Adapter(Sender)->CanFileBeDeleted(Sender, FileInfo, CanBeDeleted);
|
|
}
|
|
|
|
|
|
static void DelegateDeleteFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo) {
|
|
Adapter(Sender)->DeleteFile(Sender, FileInfo);
|
|
}
|
|
|
|
/** Unimplemented. */
|
|
static void DelegateSetAllocationSize(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 AllocationSize) {}
|
|
|
|
static void DelegateSetEndOfFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 EndOfFile) {
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "SetEndOfFile " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << " s: " << EndOfFile << endl;
|
|
}
|
|
|
|
Adapter(Sender)->SetEndOfFile(Sender, FileInfo, FileHandleContext, EndOfFile);
|
|
}
|
|
|
|
static void DelegateRenameOrMoveFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
LPCTSTR NewFileName) {
|
|
Adapter(Sender)->RenameOrMoveFile(Sender, FileInfo, NewFileName);
|
|
}
|
|
|
|
static void DelegateReadFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 Position,
|
|
PVOID Buffer,
|
|
DWORD BytesToRead,
|
|
PDWORD BytesRead) {
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "ReadFile " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << " s: " << BytesToRead << " o:" << Position << endl;
|
|
}
|
|
|
|
Adapter(Sender)->ReadFile(Sender, FileInfo, FileHandleContext, Position, Buffer, BytesToRead, BytesRead); // NOLINT
|
|
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "ReadFile succeeded " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << " s:" << BytesToRead << " o:" << Position << " r:" << *BytesRead << endl;
|
|
}
|
|
}
|
|
|
|
static void DelegateWriteFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 Position,
|
|
PVOID Buffer,
|
|
DWORD BytesToWrite,
|
|
PDWORD BytesWritten) {
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "WriteFile " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << " s: " << BytesToWrite << " o:" << Position << endl;
|
|
}
|
|
|
|
Adapter(Sender)->WriteFile(Sender, FileInfo, FileHandleContext, Position, Buffer, BytesToWrite, BytesWritten); // NOLINT
|
|
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "WriteFile succeeded " << CbFSAdapter::WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer())
|
|
<< " handle: 0x" << FileHandleContext << " s:" << BytesToWrite << " o:" << Position << " w:" << *BytesWritten << endl;
|
|
}
|
|
}
|
|
|
|
static void DelegateIsDirectoryEmpty(CallbackFileSystem* Sender,
|
|
LPWSTR FileName,
|
|
LPBOOL IsEmpty) {
|
|
Adapter(Sender)->IsDirectoryEmpty(Sender, FileName, IsEmpty);
|
|
}
|
|
|
|
static void DelegateStorageEjected(CallbackFileSystem* Sender) {
|
|
Adapter(Sender)->StorageEjected(Sender);
|
|
}
|
|
|
|
void CbFSAdapter::DbgPrint(LPCWSTR format, ...) {
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
WCHAR buffer[512];
|
|
va_list argp;
|
|
va_start(argp, format);
|
|
vswprintf_s(buffer, sizeof(buffer)/sizeof(WCHAR), format, argp);
|
|
va_end(argp);
|
|
|
|
Logging::log->getLog(LEVEL_DEBUG) << ConvertWindowsToUTF8(buffer);
|
|
}
|
|
}
|
|
|
|
void CbFSAdapter::GetVolumeSize(CallbackFileSystem* Sender,
|
|
__int64* TotalNumberOfSectors,
|
|
__int64* NumberOfFreeSectors) {
|
|
try {
|
|
boost::scoped_ptr<StatVFS> stat(volume_->StatFS(user_credentials_));
|
|
*NumberOfFreeSectors =
|
|
stat->bavail() * stat->bsize() / cbfs_.GetSectorSize();
|
|
*TotalNumberOfSectors =
|
|
stat->blocks() * stat->bsize() / cbfs_.GetSectorSize();
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
void CbFSAdapter::GetVolumeLabel(CallbackFileSystem* Sender,
|
|
LPTSTR VolumeLabel) {
|
|
wcsncpy(VolumeLabel, volume_label_.c_str(), kMaxVolumeLabelLength);
|
|
VolumeLabel[kMaxVolumeLabelLength] = '\0';
|
|
}
|
|
|
|
void CbFSAdapter::GetVolumeId(CallbackFileSystem* Sender, PDWORD VolumeID) {
|
|
// TODO(mberlin): What to fill in here?
|
|
*VolumeID = 0x12345678;
|
|
}
|
|
|
|
void CbFSAdapter::DebugPrintCreateFile(
|
|
LPCWSTR OperationType,
|
|
LPCTSTR FileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
DWORD FileAttributes,
|
|
DWORD ShareMode,
|
|
PVOID FileHandleContext) {
|
|
DbgPrint(L"%s : %s Handle : 0x%x\n", OperationType, FileName, FileHandleContext);
|
|
|
|
DbgPrint(L"\tShareMode = 0x%x\n", ShareMode);
|
|
|
|
DelegateCheckFlag(ShareMode, FILE_SHARE_READ);
|
|
DelegateCheckFlag(ShareMode, FILE_SHARE_WRITE);
|
|
DelegateCheckFlag(ShareMode, FILE_SHARE_DELETE);
|
|
|
|
DbgPrint(L"\tDesiredAccess = 0x%x\n", DesiredAccess);
|
|
|
|
DelegateCheckFlag(DesiredAccess, GENERIC_READ);
|
|
DelegateCheckFlag(DesiredAccess, GENERIC_WRITE);
|
|
DelegateCheckFlag(DesiredAccess, GENERIC_EXECUTE);
|
|
|
|
DelegateCheckFlag(DesiredAccess, DELETE);
|
|
DelegateCheckFlag(DesiredAccess, FILE_READ_DATA);
|
|
DelegateCheckFlag(DesiredAccess, FILE_READ_ATTRIBUTES);
|
|
DelegateCheckFlag(DesiredAccess, FILE_READ_EA);
|
|
DelegateCheckFlag(DesiredAccess, READ_CONTROL);
|
|
DelegateCheckFlag(DesiredAccess, FILE_WRITE_DATA);
|
|
DelegateCheckFlag(DesiredAccess, FILE_WRITE_ATTRIBUTES);
|
|
DelegateCheckFlag(DesiredAccess, FILE_WRITE_EA);
|
|
DelegateCheckFlag(DesiredAccess, FILE_APPEND_DATA);
|
|
DelegateCheckFlag(DesiredAccess, WRITE_DAC);
|
|
DelegateCheckFlag(DesiredAccess, WRITE_OWNER);
|
|
DelegateCheckFlag(DesiredAccess, SYNCHRONIZE);
|
|
DelegateCheckFlag(DesiredAccess, FILE_EXECUTE);
|
|
DelegateCheckFlag(DesiredAccess, STANDARD_RIGHTS_READ);
|
|
DelegateCheckFlag(DesiredAccess, STANDARD_RIGHTS_WRITE);
|
|
DelegateCheckFlag(DesiredAccess, STANDARD_RIGHTS_EXECUTE);
|
|
|
|
DbgPrint(L"\tFileAttributes = 0x%x\n", FileAttributes);
|
|
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_ARCHIVE);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_ENCRYPTED);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_HIDDEN);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_OFFLINE);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_READONLY);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_SYSTEM);
|
|
DelegateCheckFlag(FileAttributes, FILE_ATTRIBUTE_TEMPORARY);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_WRITE_THROUGH);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_OVERLAPPED);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_NO_BUFFERING);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_RANDOM_ACCESS);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_SEQUENTIAL_SCAN);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_DELETE_ON_CLOSE);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_BACKUP_SEMANTICS);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_POSIX_SEMANTICS);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_OPEN_REPARSE_POINT);
|
|
DelegateCheckFlag(FileAttributes, FILE_FLAG_OPEN_NO_RECALL);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_ANONYMOUS);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_IDENTIFICATION);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_IMPERSONATION);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_DELEGATION);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_CONTEXT_TRACKING);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_EFFECTIVE_ONLY);
|
|
DelegateCheckFlag(FileAttributes, SECURITY_SQOS_PRESENT);
|
|
|
|
DbgPrint(L"\n");
|
|
}
|
|
|
|
void CbFSAdapter::CreateFile(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
DWORD FileAttributes,
|
|
DWORD ShareMode,
|
|
PVOID* FileHandleContext) {
|
|
string path(WindowsPathToUTF8Unix(FileName));
|
|
|
|
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
try {
|
|
// TODO(mberlin): Let user specify a different default mode.
|
|
// TODO(mberlin): Store attributes for directories?
|
|
volume_->MakeDirectory(user_credentials_, path, 0777);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
} else {
|
|
// What to do if file exists and this is called? Use O_TRUNC, because:
|
|
// CbFS FAQ:
|
|
// "So if your OnCreateFile handler is called, you need to create the file.
|
|
// If the file exists and CBFS knows it, receiving OnCreateFile means that
|
|
// the file was requested for opening with "CreateAlways" flag, which
|
|
// means that you need to truncate the existing file."
|
|
// Source: http://www.eldos.com/cbfs/articles/6747.php
|
|
|
|
// TODO(mberlin): What happens if path is a dir and a file shall be created?
|
|
|
|
// TODO(mberlin): Evaluation of ShareMode can only be implemented by locking
|
|
// the file. See MSDN description of CreateFile:
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx // NOLINT
|
|
try {
|
|
// TODO(mberlin): Let user specify a different default mode.
|
|
uint32_t mode = 0666;
|
|
if ((FileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
|
|
mode = 0444;
|
|
}
|
|
|
|
int open_flags = ConvertFlagsWindowsToXtreemFS(DesiredAccess)
|
|
| SYSTEM_V_FCNTL_H_O_CREAT
|
|
| SYSTEM_V_FCNTL_H_O_TRUNC;
|
|
|
|
FileHandle* file_handle = volume_->OpenFile(
|
|
user_credentials_,
|
|
path,
|
|
static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(open_flags),
|
|
mode,
|
|
FileAttributes);
|
|
*FileHandleContext = reinterpret_cast<PVOID>(file_handle);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::OpenFile(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
DWORD ShareMode,
|
|
PVOID* FileHandleContext) {
|
|
string path(WindowsPathToUTF8Unix(FileName));
|
|
|
|
try {
|
|
// TODO(mberlin): What to do here when the function throws?
|
|
// This should throw an error when the path does not exist.
|
|
if (IsDirectory(path)) {
|
|
return;
|
|
}
|
|
|
|
//if (DesiredAccess == FILE_READ_ATTRIBUTES) {
|
|
// // No need to open files solely for reading attributes.
|
|
// return;
|
|
//}
|
|
|
|
// TODO(mberlin): Handle situations where desiredAccess is only set to SYNCHRONIZE. // NOLINT
|
|
|
|
FileHandle* file_handle = volume_->OpenFile(
|
|
user_credentials_,
|
|
path,
|
|
ConvertFlagsWindowsToXtreemFS(DesiredAccess));
|
|
*FileHandleContext = reinterpret_cast<PVOID>(file_handle);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::CloseFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext) {
|
|
FileHandle* file_handle = reinterpret_cast<FileHandle*>(FileHandleContext);
|
|
|
|
if (file_handle == NULL) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
file_handle->Close();
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::GetFileInfo(CallbackFileSystem* Sender,
|
|
LPCTSTR FileName,
|
|
LPBOOL FileExists,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
__int64* EndOfFile,
|
|
__int64* AllocationSize,
|
|
__int64* FileId,
|
|
PDWORD FileAttributes,
|
|
LPTSTR LongFileName OPTIONAL,
|
|
PWORD LongFileNameLength OPTIONAL) {
|
|
string path(WindowsPathToUTF8Unix(FileName));
|
|
|
|
*FileExists = false;
|
|
|
|
if (!xctl_.checkXctlFile(path)) {
|
|
Stat stat;
|
|
|
|
try {
|
|
volume_->GetAttr(user_credentials_, path, &stat);
|
|
|
|
*FileExists = true;
|
|
|
|
ConvertXtreemFSStatToCbFS(stat,
|
|
CreationTime,
|
|
LastAccessTime,
|
|
LastWriteTime,
|
|
EndOfFile,
|
|
AllocationSize,
|
|
FileId,
|
|
FileAttributes,
|
|
LongFileName,
|
|
LongFileNameLength);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
//} else {
|
|
// // TODO(mberlin): Fix this for Windows.
|
|
// return xctl_.getattr(0, 0, path, statbuf);
|
|
//}
|
|
}
|
|
|
|
void CbFSAdapter::ConvertXtreemFSStatToCbFS(const xtreemfs::pbrpc::Stat& stat,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
__int64* EndOfFile,
|
|
__int64* AllocationSize,
|
|
__int64* FileId,
|
|
PDWORD FileAttributes,
|
|
LPTSTR LongFileName OPTIONAL,
|
|
PWORD LongFileNameLength OPTIONAL) {
|
|
XtreemFSTimeToWinTime(stat.ctime_ns(),
|
|
&CreationTime->dwLowDateTime,
|
|
&CreationTime->dwHighDateTime);
|
|
XtreemFSTimeToWinTime(stat.atime_ns(),
|
|
&LastAccessTime->dwLowDateTime,
|
|
&LastAccessTime->dwHighDateTime);
|
|
XtreemFSTimeToWinTime(stat.mtime_ns(),
|
|
&LastWriteTime->dwLowDateTime,
|
|
&LastWriteTime->dwHighDateTime);
|
|
|
|
*EndOfFile = stat.size();
|
|
*AllocationSize = *EndOfFile;
|
|
*FileId = stat.ino();
|
|
|
|
// TODO(mberlin): Merge read only attribute if file cannot be edited?
|
|
*FileAttributes = stat.attributes();
|
|
if (*FileAttributes == 0) {
|
|
// TODO(mberlin): Remove this if it's not needed.
|
|
//*FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
if (IsDirectory(stat)) {
|
|
*FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::EnumerateDirectory(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* DirectoryInfo,
|
|
PVOID* EnumerationContext,
|
|
LPCTSTR Mask,
|
|
INT Index,
|
|
BOOL Restart,
|
|
LPBOOL FileFound,
|
|
LPTSTR FileName,
|
|
PDWORD FileNameLength,
|
|
LPTSTR ShortFileName OPTIONAL,
|
|
PUCHAR ShortFileNameLength OPTIONAL,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
__int64* EndOfFile,
|
|
__int64* AllocationSize,
|
|
__int64* FileId,
|
|
PDWORD FileAttributes) {
|
|
try {
|
|
// Windows is looking for a specific file if the mask has no "*" or "?".
|
|
if (wstring(Mask).find_first_of(TEXT("*?")) == string::npos) {
|
|
if (!Restart) {
|
|
// We probably answered that already.
|
|
*FileFound = false;
|
|
return;
|
|
}
|
|
|
|
wstring full_path(DirectoryInfo->get_FileNameBuffer());
|
|
if (full_path != TEXT("\\")) {
|
|
// Except for the root directory, the trailing slash has to be added.
|
|
full_path += TEXT("\\");
|
|
}
|
|
full_path += wstring(Mask);
|
|
|
|
wcsncpy(FileName, Mask, kMaxFileNameLength);
|
|
*FileNameLength = wcslen(FileName);
|
|
|
|
GetFileInfo(Sender,
|
|
full_path.c_str(),
|
|
FileFound,
|
|
CreationTime,
|
|
LastAccessTime,
|
|
LastWriteTime,
|
|
EndOfFile,
|
|
AllocationSize,
|
|
FileId,
|
|
FileAttributes,
|
|
NULL,
|
|
NULL);
|
|
return;
|
|
}
|
|
|
|
string path_directory(WindowsPathToUTF8Unix(
|
|
DirectoryInfo->get_FileNameBuffer()));
|
|
*FileFound = false;
|
|
CbFSEnumerationContext* enum_ctx =
|
|
reinterpret_cast<CbFSEnumerationContext*>(*EnumerationContext);
|
|
|
|
if (Restart && enum_ctx != NULL) {
|
|
// Directory was already opened, but we have to read it from the start now.
|
|
if (enum_ctx->offset == 0) {
|
|
enum_ctx->next_index = 0;
|
|
} else {
|
|
delete enum_ctx;
|
|
enum_ctx = NULL;
|
|
*EnumerationContext = NULL;
|
|
}
|
|
}
|
|
|
|
if (enum_ctx == NULL) {
|
|
// No context created yet.
|
|
enum_ctx = new CbFSEnumerationContext();
|
|
*EnumerationContext = reinterpret_cast<PVOID>(enum_ctx);
|
|
}
|
|
|
|
bool dot_dir_seen = false;
|
|
do {
|
|
if (enum_ctx->dir_entries != NULL &&
|
|
enum_ctx->next_index == enum_ctx->dir_entries->entries_size() &&
|
|
enum_ctx->next_index < options_->readdir_chunk_size) {
|
|
// We reached the end of the dir listing.
|
|
*FileFound = false;
|
|
break;
|
|
}
|
|
|
|
// Existing chunk was completely processed, drop it.
|
|
if (enum_ctx->dir_entries != NULL &&
|
|
enum_ctx->next_index == options_->readdir_chunk_size) {
|
|
delete enum_ctx->dir_entries;
|
|
enum_ctx->dir_entries = NULL;
|
|
enum_ctx->offset += options_->readdir_chunk_size;
|
|
}
|
|
|
|
// Directory entries not available yet or we have to get the next chunk.
|
|
if (enum_ctx->dir_entries == NULL) {
|
|
enum_ctx->dir_entries = volume_->ReadDir(
|
|
user_credentials_,
|
|
path_directory,
|
|
enum_ctx->offset,
|
|
options_->readdir_chunk_size,
|
|
false); // names_only = false
|
|
enum_ctx->next_index = 0;
|
|
if (enum_ctx->dir_entries->entries_size() == 0) {
|
|
// We reached the end of the dir listing.
|
|
*FileFound = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const DirectoryEntry& entry =
|
|
enum_ctx->dir_entries->entries(enum_ctx->next_index);
|
|
enum_ctx->next_index++;
|
|
|
|
if (entry.name() == "." || entry.name() == "..") {
|
|
dot_dir_seen = true;
|
|
} else {
|
|
dot_dir_seen = false;
|
|
}
|
|
|
|
if (!dot_dir_seen) {
|
|
*FileFound = true;
|
|
// TODO(mberlin): Parse mask. Maybe use the function from here: http://msdn.microsoft.com/en-us/library/bb773727%28VS.85%29.aspx // NOLINT
|
|
|
|
ConvertUTF8ToWindows(entry.name(), FileName, kMaxFileNameLength);
|
|
*FileNameLength = wcslen(FileName);
|
|
|
|
ConvertXtreemFSStatToCbFS(entry.stbuf(),
|
|
CreationTime,
|
|
LastAccessTime,
|
|
LastWriteTime,
|
|
EndOfFile,
|
|
AllocationSize,
|
|
FileId,
|
|
FileAttributes,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
} while (dot_dir_seen);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::CloseEnumeration(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* DirectoryInfo,
|
|
PVOID EnumerationContext) {
|
|
delete reinterpret_cast<CbFSEnumerationContext*>(EnumerationContext);
|
|
}
|
|
|
|
void CbFSAdapter::SetEndOfFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 EndOfFile) {
|
|
FileHandle* file_handle = reinterpret_cast<FileHandle*>(FileHandleContext);
|
|
|
|
if (file_handle == NULL) {
|
|
Logging::log->getLog(LEVEL_ERROR)
|
|
<< "Crashing since CbFS tried to execute truncate() on a file"
|
|
" which was not opened. Path: "
|
|
<< WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer()) << endl;
|
|
assert(file_handle != NULL);
|
|
}
|
|
|
|
try {
|
|
file_handle->Truncate(user_credentials_, EndOfFile);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
void CbFSAdapter::SetFileAttributes(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
PFILETIME CreationTime,
|
|
PFILETIME LastAccessTime,
|
|
PFILETIME LastWriteTime,
|
|
DWORD FileAttributes) {
|
|
try {
|
|
string path(WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer()));
|
|
|
|
Stat stat;
|
|
InitializeStat(&stat);
|
|
int to_set = 0;
|
|
if (CreationTime != NULL) {
|
|
stat.set_ctime_ns(ConvertWinTimeToXtreemFSTime(CreationTime->dwLowDateTime, CreationTime->dwHighDateTime));
|
|
to_set |= SETATTR_CTIME;
|
|
}
|
|
if (LastAccessTime != NULL) {
|
|
stat.set_atime_ns(ConvertWinTimeToXtreemFSTime(LastAccessTime->dwLowDateTime, LastAccessTime->dwHighDateTime));
|
|
to_set |= SETATTR_ATIME;
|
|
}
|
|
if (LastWriteTime != NULL) {
|
|
stat.set_mtime_ns(ConvertWinTimeToXtreemFSTime(LastWriteTime->dwLowDateTime, LastWriteTime->dwHighDateTime));
|
|
to_set |= SETATTR_MTIME;
|
|
}
|
|
|
|
if (FileAttributes != 0) {
|
|
stat.set_attributes(FileAttributes);
|
|
to_set |= SETATTR_ATTRIBUTES;
|
|
}
|
|
|
|
if (to_set != 0) {
|
|
// TODO(mberlin): Do not update stat if cached entry is identical.
|
|
volume_->SetAttr(user_credentials_,
|
|
path,
|
|
stat,
|
|
static_cast<Setattrs>(to_set));
|
|
}
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::CanFileBeDeleted(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
BOOL* CanBeDeleted) {
|
|
// TODO(mberlin): For now we skip this check. However, according to the docu
|
|
// Windows cannot return an error when deleting files and
|
|
// therefore checks beforehand if it's allowed to.
|
|
*CanBeDeleted = TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::DeleteFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo) {
|
|
string path(WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer()));
|
|
|
|
if (FileInfo->get_Attributes() & FILE_ATTRIBUTE_DIRECTORY) {
|
|
try {
|
|
volume_->DeleteDirectory(user_credentials_, path);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
} else {
|
|
try {
|
|
volume_->Unlink(user_credentials_, path);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::RenameOrMoveFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
LPCTSTR NewFileName) {
|
|
try {
|
|
volume_->Rename(user_credentials_,
|
|
WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer()),
|
|
WindowsPathToUTF8Unix(NewFileName));
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::ReadFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 Position,
|
|
PVOID Buffer,
|
|
DWORD BytesToRead,
|
|
PDWORD BytesRead) {
|
|
FileHandle* file_handle = reinterpret_cast<FileHandle*>(FileHandleContext);
|
|
|
|
try {
|
|
//bool close_file_after_read = false;
|
|
//string path(WindowsPathToUTF8Unix(FileInfo->get_FileNameBuffer()));
|
|
//if (file_handle == NULL) {
|
|
// file_handle = volume_->OpenFile(user_credentials_,
|
|
// path,
|
|
// SYSTEM_V_FCNTL_H_O_RDONLY);
|
|
// close_file_after_read = true;
|
|
// if (Logging::log->loggingActive(LEVEL_INFO)) {
|
|
// Logging::log->getLog(LEVEL_INFO) << "Had to open a file temporarily for"
|
|
// " reading since it was not opened in OpenFile(). Path: " << path <<
|
|
// " Read request: s: " << BytesToRead << " o: " << Position << endl;
|
|
// }
|
|
//}
|
|
|
|
*BytesRead = file_handle->Read(reinterpret_cast<char*>(Buffer),
|
|
BytesToRead,
|
|
Position);
|
|
|
|
//if (close_file_after_read) {
|
|
// file_handle->Close();
|
|
//}
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::WriteFile(CallbackFileSystem* Sender,
|
|
CbFsFileInfo* FileInfo,
|
|
PVOID FileHandleContext,
|
|
__int64 Position,
|
|
PVOID Buffer,
|
|
DWORD BytesToWrite,
|
|
PDWORD BytesWritten) {
|
|
FileHandle* file_handle = reinterpret_cast<FileHandle*>(FileHandleContext);
|
|
|
|
try {
|
|
*BytesWritten = file_handle->Write(reinterpret_cast<char*>(Buffer),
|
|
BytesToWrite,
|
|
Position);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void CbFSAdapter::IsDirectoryEmpty(CallbackFileSystem* Sender,
|
|
LPWSTR FileName,
|
|
LPBOOL IsEmpty) {
|
|
try {
|
|
// TODO(mberlin): Find out how often this gets called and if it makes more
|
|
// sense to read the whole directory and let it get cached
|
|
// or only read one entry.
|
|
boost::scoped_ptr<DirectoryEntries> entries(volume_->ReadDir(
|
|
user_credentials_,
|
|
WindowsPathToUTF8Unix(FileName),
|
|
0,
|
|
3, // Three entries since "." and ".." are the first two ones.
|
|
true)); // names_only
|
|
// Empty if the directory has only "." and ".." as entries.
|
|
*IsEmpty = (entries->entries_size() == 2);
|
|
} CATCH_AND_CONVERT_ERRORS
|
|
}
|
|
|
|
void CbFSAdapter::StorageEjected(CallbackFileSystem* Sender) {
|
|
boost::mutex::scoped_lock lock(device_ejected_mutex_);
|
|
device_ejected_ = true;
|
|
device_ejected_cond_.notify_all();
|
|
}
|
|
|
|
void CbFSAdapter::WaitForEjection() {
|
|
boost::mutex::scoped_lock lock(device_ejected_mutex_);
|
|
while (!device_ejected_) {
|
|
device_ejected_cond_.wait(lock);
|
|
}
|
|
}
|
|
|
|
CbFSAdapter::CbFSAdapter(CbFSOptions* options)
|
|
: options_(options), xctl_("/.xctl$$$"), device_ejected_(false) {
|
|
wstring volume_label_prefix(L"XtreemFS (");
|
|
wstring volume_label_suffix(L")");
|
|
wstring volume_label_dots(L"...");
|
|
wstring xtreemfs_url = ConvertUTF8ToWindows(options_->xtreemfs_url);
|
|
|
|
volume_label_ = volume_label_prefix;
|
|
size_t chars_left = kMaxVolumeLabelLength - volume_label_prefix.size()
|
|
- volume_label_suffix.size();
|
|
if (xtreemfs_url.size() <= chars_left) {
|
|
volume_label_ += xtreemfs_url;
|
|
} else {
|
|
volume_label_ += xtreemfs_url.substr(0,
|
|
chars_left - volume_label_dots.size())
|
|
+ volume_label_dots;
|
|
}
|
|
volume_label_ += volume_label_suffix;
|
|
|
|
// Required for CbFS library. kCbFSRegistrationKey is defined in
|
|
// cbfs_license.h which is not publicly available. If you want to help
|
|
// developing the CbFSAdapter, kindly ask the
|
|
cbfs_.SetRegistrationKey(kCbFSRegistrationKey); // NOLINT
|
|
|
|
cbfs_.SetTag(this);
|
|
|
|
cbfs_.SetMaxFileNameLength(kMaxFileNameLength);
|
|
|
|
cbfs_.SetStorageType(CallbackFileSystem::stDiskPnP);
|
|
cbfs_.SetStorageCharacteristics(
|
|
static_cast<CallbackFileSystem::CbFsStorageCharacteristics>(
|
|
cbfs_.GetStorageCharacteristics() | CallbackFileSystem::scShowInEjectionTray | CallbackFileSystem::scAllowEjection)
|
|
);
|
|
|
|
cbfs_.SetOnMount(DelegateMount);
|
|
cbfs_.SetOnUnmount(DelegateUnmount);
|
|
cbfs_.SetOnGetVolumeSize(DelegateGetVolumeSize);
|
|
cbfs_.SetOnGetVolumeLabel(DelegateGetVolumeLabel);
|
|
cbfs_.SetOnSetVolumeLabel(DelegateSetVolumeLabel);
|
|
cbfs_.SetOnGetVolumeId(DelegateGetVolumeId);
|
|
cbfs_.SetOnOpenVolume(DelegateOpenVolume);
|
|
cbfs_.SetOnCloseVolume(DelegateCloseVolume);
|
|
cbfs_.SetOnCreateFile(DelegateCreateFile);
|
|
cbfs_.SetOnOpenFile(DelegateOpenFile);
|
|
cbfs_.SetOnCloseFile(DelegateCloseFile);
|
|
cbfs_.SetOnGetFileInfo(DelegateGetFileInfo);
|
|
cbfs_.SetOnEnumerateDirectory(DelegateEnumerateDirectory);
|
|
cbfs_.SetOnCloseEnumeration(DelegateCloseEnumeration);
|
|
cbfs_.SetOnSetAllocationSize(DelegateSetAllocationSize);
|
|
cbfs_.SetOnSetEndOfFile(DelegateSetEndOfFile);
|
|
cbfs_.SetOnSetFileAttributes(DelegateSetFileAttributes);
|
|
cbfs_.SetOnCanFileBeDeleted(DelegateCanFileBeDeleted);
|
|
cbfs_.SetOnDeleteFile(DelegateDeleteFile);
|
|
cbfs_.SetOnRenameOrMoveFile(DelegateRenameOrMoveFile);
|
|
cbfs_.SetOnReadFile(DelegateReadFile);
|
|
cbfs_.SetOnWriteFile(DelegateWriteFile);
|
|
cbfs_.SetOnIsDirectoryEmpty(DelegateIsDirectoryEmpty);
|
|
cbfs_.SetOnStorageEjected(DelegateStorageEjected);
|
|
}
|
|
|
|
CbFSAdapter::~CbFSAdapter() {
|
|
}
|
|
|
|
void CbFSAdapter::Start() {
|
|
// Start logging manually (although it would be automatically started by
|
|
// ClientImplementation()) as its required by UserMapping.
|
|
initialize_logger(options_->log_level_string,
|
|
options_->log_file_path,
|
|
LEVEL_WARN);
|
|
|
|
// Setup Usermapping.
|
|
system_user_mapping_.reset(SystemUserMapping::GetSystemUserMapping());
|
|
system_user_mapping_->GetUserCredentialsForCurrentUser(&user_credentials_);
|
|
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
|
Logging::log->getLog(LEVEL_DEBUG) << "Executing all operations on behalf of"
|
|
" username: " << user_credentials_.username()
|
|
<< " and group: " << user_credentials_.groups(0) << endl;
|
|
}
|
|
|
|
// Create new Client.
|
|
client_.reset(Client::CreateClient(options_->service_addresses,
|
|
user_credentials_,
|
|
options_->GenerateSSLOptions(),
|
|
*options_,
|
|
Client::kDefaultClient));
|
|
client_->Start();
|
|
// Open Volume.
|
|
volume_ = client_->OpenVolume(options_->volume_name,
|
|
options_->GenerateSSLOptions(),
|
|
*options_);
|
|
|
|
xctl_.set_volume(volume_);
|
|
|
|
// Try to access Volume. If it fails, an error will be thrown.
|
|
delete volume_->ReadDir(user_credentials_,
|
|
"/",
|
|
0, // offset
|
|
options_->readdir_chunk_size, // count
|
|
false); // Do not get stat entries = false.
|
|
|
|
// TODO(mberlin): Put this into a common function used by Dokan- and
|
|
// FuseAdapter.
|
|
// Check the attributes of the Volume.
|
|
boost::scoped_ptr<listxattrResponse> xattrs(
|
|
volume_->ListXAttrs(user_credentials_, "/", false));
|
|
for (int i = 0; i < xattrs->xattrs_size(); ++i) {
|
|
const xtreemfs::pbrpc::XAttr& xattr = xattrs->xattrs(i);
|
|
|
|
// First grid user mapping wins.
|
|
if (!options_->grid_auth_mode_globus && !options_->grid_auth_mode_unicore) {
|
|
if (xattr.name() == "xtreemfs.volattr.globus_gridmap") {
|
|
options_->grid_auth_mode_globus = true;
|
|
options_->additional_user_mapping_type = UserMapping::kGlobus;
|
|
if (options_->grid_gridmap_location.empty()) {
|
|
options_->grid_gridmap_location =
|
|
options_->grid_gridmap_location_default_globus;
|
|
}
|
|
Logging::log->getLog(LEVEL_INFO) << "Using Globus gridmap file "
|
|
<< options_->grid_gridmap_location << endl;
|
|
}
|
|
|
|
if (xattr.name() == "xtreemfs.volattr.unicore_uudb") {
|
|
options_->grid_auth_mode_unicore = true;
|
|
options_->additional_user_mapping_type = UserMapping::kUnicore;
|
|
if (options_->grid_gridmap_location.empty()) {
|
|
options_->grid_gridmap_location =
|
|
options_->grid_gridmap_location_default_unicore;
|
|
}
|
|
Logging::log->getLog(LEVEL_INFO) << "Using Unicore uudb file "
|
|
<< options_->grid_gridmap_location << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the user specified an additional user mapping in options.
|
|
UserMapping* additional_user_mapping = UserMapping::CreateUserMapping(
|
|
options_->additional_user_mapping_type,
|
|
*options_);
|
|
if (additional_user_mapping) {
|
|
system_user_mapping_->RegisterAdditionalUserMapping(
|
|
additional_user_mapping);
|
|
system_user_mapping_->StartAdditionalUserMapping();
|
|
|
|
// Retrieve user_credentials again, this time using the additional mapping.
|
|
system_user_mapping_->GetUserCredentialsForCurrentUser(&user_credentials_);
|
|
}
|
|
|
|
// The user mapping is no longer needed since we don't refresh the credentials
|
|
if (system_user_mapping_.get()) {
|
|
system_user_mapping_->StopAdditionalUserMapping();
|
|
}
|
|
|
|
// Init CBFS.
|
|
try {
|
|
cbfs_.CreateStorage();
|
|
cbfs_.MountMedia(1000 * max(options_->request_timeout_s,
|
|
options_->connect_timeout_s));
|
|
|
|
// TODO(mberlin): Set XtreemFS logo as icon.
|
|
const string first_dir_replica =
|
|
options_->service_addresses.GetAddresses().front();
|
|
cbfs_.AddMountingPoint(ConvertUTF8ToWindows(
|
|
options_->mount_point
|
|
+ ";"
|
|
+ first_dir_replica.substr(
|
|
0,
|
|
first_dir_replica.find_last_of(":"))
|
|
+ ";"
|
|
+ options_->volume_name).c_str(),
|
|
CBFS_SYMLINK_NETWORK | CBFS_SYMLINK_NETWORK_ALLOW_MAP_AS_DRIVE,
|
|
NULL);
|
|
} catch (ECBFSError e) {
|
|
string error = "Failed to mount the volume: " + ECBFSErrorToString(e);
|
|
Logging::log->getLog(LEVEL_ERROR) << error << endl;
|
|
throw XtreemFSException(error);
|
|
}
|
|
}
|
|
|
|
void CbFSAdapter::Stop() {
|
|
try {
|
|
cbfs_.UnmountMedia(true);
|
|
} catch (ECBFSError e) {
|
|
Logging::log->getLog(LEVEL_ERROR)
|
|
<< "Failed to un-mount the volume. Make sure all open files are"
|
|
" closed. " << ECBFSErrorToString(e) << endl;
|
|
|
|
}
|
|
|
|
StopWithoutUnmount();
|
|
}
|
|
|
|
void CbFSAdapter::StopWithoutUnmount() {
|
|
try {
|
|
cbfs_.DeleteStorage(true);
|
|
} catch (ECBFSError e) {
|
|
Logging::log->getLog(LEVEL_ERROR)
|
|
<< "Failed to delete the storage. Make sure all open files are"
|
|
" closed. " << ECBFSErrorToString(e) << endl;
|
|
|
|
}
|
|
|
|
// Shutdown() Client. That does also invoke a volume->Close().
|
|
if (client_.get()) {
|
|
client_->Shutdown();
|
|
}
|
|
}
|
|
|
|
std::string CbFSAdapter::ECBFSErrorToString(ECBFSError& e) {
|
|
string error = ConvertWindowsToUTF8(e.Message());
|
|
if (!error.empty() && error[error.length()-1] == '\n') {
|
|
error.erase(error.length() - 1);
|
|
}
|
|
|
|
return "Error code: " + boost::lexical_cast<string>(e.ErrorCode())
|
|
+ " Message: " + error;
|
|
}
|
|
|
|
int CbFSAdapter::ConvertXtreemFSErrnoToWindows(
|
|
xtreemfs::pbrpc::POSIXErrno xtreemfs_errno) {
|
|
switch (xtreemfs_errno) {
|
|
case POSIX_ERROR_EACCES:
|
|
return ERROR_ACCESS_DENIED;
|
|
case POSIX_ERROR_EEXIST:
|
|
return ERROR_ALREADY_EXISTS;
|
|
case POSIX_ERROR_ENOENT:
|
|
return ERROR_FILE_NOT_FOUND;
|
|
// TODO(fhupfeld): map remaining ones
|
|
case POSIX_ERROR_EPERM:
|
|
return EPERM;
|
|
case POSIX_ERROR_EINTR:
|
|
return EINTR;
|
|
case POSIX_ERROR_EIO:
|
|
return EIO;
|
|
case POSIX_ERROR_EAGAIN:
|
|
return EAGAIN;
|
|
case POSIX_ERROR_EXDEV:
|
|
return EXDEV;
|
|
case POSIX_ERROR_ENODEV:
|
|
return ENODEV;
|
|
case POSIX_ERROR_ENOTDIR:
|
|
return ENOTDIR;
|
|
case POSIX_ERROR_EISDIR:
|
|
return EISDIR;
|
|
case POSIX_ERROR_EINVAL:
|
|
return EINVAL;
|
|
case POSIX_ERROR_ENOTEMPTY:
|
|
return ENOTEMPTY;
|
|
case POSIX_ERROR_ENODATA:
|
|
return ENODATA;
|
|
default:
|
|
return xtreemfs_errno;
|
|
}
|
|
}
|
|
|
|
std::string CbFSAdapter::WindowsPathToUTF8Unix(const wchar_t* from) {
|
|
string utf8;
|
|
ConvertWindowsToUTF8(from, &utf8);
|
|
|
|
// Suppress trailing slash.
|
|
if (utf8.length() > 1 && utf8[utf8.length() - 1] == '\\') {
|
|
utf8.resize(utf8.length() - 1);
|
|
}
|
|
|
|
// Replace Windows path delimiters with Unix ones.
|
|
char* pos = &(utf8[0]);
|
|
while (*pos != 0) {
|
|
if (*pos == '\\') {
|
|
*pos = '/';
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
return utf8;
|
|
}
|
|
|
|
void CbFSAdapter::XtreemFSTimeToWinTime(uint64_t utime_ns,
|
|
DWORD* lower,
|
|
DWORD* upper) {
|
|
// Windows starts on Jan 1, 1601 (UTC), counting in 100 nanoseconds steps.
|
|
LONGLONG wintime = utime_ns / 100 + 116444736000000000LL;
|
|
*lower = static_cast<DWORD>(wintime & 0xFFFFffff);
|
|
*upper = static_cast<DWORD>(wintime >> 32);
|
|
}
|
|
|
|
boost::uint64_t CbFSAdapter::ConvertWinTimeToXtreemFSTime(DWORD lower,
|
|
DWORD upper) {
|
|
if (lower == 0 && upper == 0) {
|
|
return 0;
|
|
}
|
|
if (upper == 0xFFFFFFFF && lower == 0xFFFFFFFF) {
|
|
return -1; // Error
|
|
}
|
|
|
|
int64_t utime = static_cast<boost::int64_t>(upper) << 32 |
|
|
static_cast<boost::int64_t>(lower);
|
|
return (utime - 116444736000000000LL) * 100;
|
|
}
|
|
|
|
bool CbFSAdapter::IsDirectory(const xtreemfs::pbrpc::Stat& stat) {
|
|
return stat.mode() & SYSTEM_V_FCNTL_H_S_IFDIR ? true : false;
|
|
}
|
|
|
|
bool CbFSAdapter::IsDirectory(const std::string& path) {
|
|
Stat stat;
|
|
volume_->GetAttr(user_credentials_, path, &stat);
|
|
return IsDirectory(stat);
|
|
}
|
|
|
|
xtreemfs::pbrpc::SYSTEM_V_FCNTL CbFSAdapter::ConvertFlagsWindowsToXtreemFS(
|
|
const ACCESS_MASK desired_access) {
|
|
bool read = false;
|
|
bool write = false;
|
|
read |= (desired_access & FILE_READ_ATTRIBUTES) != 0;
|
|
read |= (desired_access & FILE_READ_DATA) != 0;
|
|
read |= (desired_access & FILE_READ_EA) != 0;
|
|
read |= (desired_access & STANDARD_RIGHTS_READ) != 0;
|
|
write |= (desired_access & FILE_WRITE_ATTRIBUTES) != 0;
|
|
write |= (desired_access & FILE_WRITE_DATA) != 0;
|
|
write |= (desired_access & FILE_WRITE_EA) != 0;
|
|
write |= (desired_access & STANDARD_RIGHTS_WRITE) != 0;
|
|
|
|
int open_flags = 0;
|
|
if (read && write) {
|
|
open_flags = SYSTEM_V_FCNTL_H_O_RDWR;
|
|
} else if (read) {
|
|
open_flags = SYSTEM_V_FCNTL_H_O_RDONLY;
|
|
} else if (write) {
|
|
open_flags = SYSTEM_V_FCNTL_H_O_WRONLY;
|
|
}
|
|
|
|
if ((desired_access & FILE_APPEND_DATA ) != 0) {
|
|
open_flags |= SYSTEM_V_FCNTL_H_O_APPEND;
|
|
}
|
|
|
|
return static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(open_flags);
|
|
}
|
|
|
|
} // namespace xtreemfs
|