void File::Touch(StringIn filename, FILETIME fileTime) { #if 0 DWORD creationDisposition = OPEN_ALWAYS; HANDLE hFile = CreateFileW(CStringw(filename), GENERIC_READ | GENERIC_WRITE, 0/*share*/, NULL, creationDisposition, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { IO::StringWriter str; str << "Touch failed for " << filename; raise(IOException(str.str())); } BOOL success; FILE_BASIC_INFO info; success = GetFileInformationByHandleEx(hFile, FileBasicInfo, &info, sizeof(info)); if (!success) { raise_(Exception::FromHResult(HRESULT_FROM_WIN32(GetLastError()))); } info.LastWriteTime.QuadPart = *(uint64*)&fileTime; info.LastAccessTime.QuadPart = *(uint64*)&fileTime; success = SetFileInformationByHandle(hFile, FileBasicInfo, &info, sizeof(info)); if (!success) { raise_(Exception::FromHResult(HRESULT_FROM_WIN32(GetLastError()))); } CloseHandle(hFile); #endif }
int fchmod(int fd, mode_t mode) { HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == INVALID_HANDLE_VALUE) { return -1; } FILE_ATTRIBUTE_TAG_INFO attr{}; if (!GetFileInformationByHandleEx( h, FileAttributeTagInfo, &attr, sizeof(attr))) { return -1; } if (mode & _S_IWRITE) { attr.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; } else { attr.FileAttributes |= FILE_ATTRIBUTE_READONLY; } if (!SetFileInformationByHandle( h, FileAttributeTagInfo, &attr, sizeof(attr))) { return -1; } return 0; }
static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, UINT32 FileAttributes, UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 ChangeTime, FSP_FSCTL_FILE_INFO *FileInfo) { HANDLE Handle = HandleFromContext(FileContext); FILE_BASIC_INFO BasicInfo = { 0 }; if (INVALID_FILE_ATTRIBUTES == FileAttributes) FileAttributes = 0; else if (0 == FileAttributes) FileAttributes = FILE_ATTRIBUTE_NORMAL; BasicInfo.FileAttributes = FileAttributes; BasicInfo.CreationTime.QuadPart = CreationTime; BasicInfo.LastAccessTime.QuadPart = LastAccessTime; BasicInfo.LastWriteTime.QuadPart = LastWriteTime; //BasicInfo.ChangeTime = ChangeTime; if (!SetFileInformationByHandle(Handle, FileBasicInfo, &BasicInfo, sizeof BasicInfo)) return FspNtStatusFromWin32(GetLastError()); return GetFileInfoInternal(Handle, FileInfo); }
BOOL WINAPI_DECL SetFileTime( _In_ HANDLE hFile, _In_opt_ const FILETIME *lpCreationTime, _In_opt_ const FILETIME *lpLastAccessTime, _In_opt_ const FILETIME *lpLastWriteTime ) { FILE_BASIC_INFO basicInfo; BOOL b = GetFileInformationByHandleEx( hFile, FileBasicInfo, &basicInfo, sizeof(basicInfo)); if (b == FALSE) return FALSE; if (lpCreationTime) basicInfo.CreationTime = *(LARGE_INTEGER const *)lpCreationTime; if (lpLastAccessTime) basicInfo.LastAccessTime = *(LARGE_INTEGER const *)lpLastAccessTime; if (lpLastWriteTime) basicInfo.LastWriteTime = *(LARGE_INTEGER const *)lpLastAccessTime; b = SetFileInformationByHandle( hFile, FileBasicInfo, &basicInfo, sizeof(basicInfo)); return b; }
static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize, FSP_FSCTL_FILE_INFO *FileInfo) { HANDLE Handle = HandleFromContext(FileContext); FILE_BASIC_INFO BasicInfo = { 0 }; FILE_ALLOCATION_INFO AllocationInfo = { 0 }; FILE_ATTRIBUTE_TAG_INFO AttributeTagInfo; if (ReplaceFileAttributes) { if (0 == FileAttributes) FileAttributes = FILE_ATTRIBUTE_NORMAL; BasicInfo.FileAttributes = FileAttributes; if (!SetFileInformationByHandle(Handle, FileBasicInfo, &BasicInfo, sizeof BasicInfo)) return FspNtStatusFromWin32(GetLastError()); } else if (0 != FileAttributes) { if (!GetFileInformationByHandleEx(Handle, FileAttributeTagInfo, &AttributeTagInfo, sizeof AttributeTagInfo)) return FspNtStatusFromWin32(GetLastError()); BasicInfo.FileAttributes = FileAttributes | AttributeTagInfo.FileAttributes; if (BasicInfo.FileAttributes ^ FileAttributes) { if (!SetFileInformationByHandle(Handle, FileBasicInfo, &BasicInfo, sizeof BasicInfo)) return FspNtStatusFromWin32(GetLastError()); } } if (!SetFileInformationByHandle(Handle, FileAllocationInfo, &AllocationInfo, sizeof AllocationInfo)) return FspNtStatusFromWin32(GetLastError()); return GetFileInfoInternal(Handle, FileInfo); }
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, UINT64 NewSize, BOOLEAN SetAllocationSize, FSP_FSCTL_FILE_INFO *FileInfo) { HANDLE Handle = HandleFromContext(FileContext); FILE_ALLOCATION_INFO AllocationInfo; FILE_END_OF_FILE_INFO EndOfFileInfo; if (SetAllocationSize) { /* * This file system does not maintain AllocationSize, although NTFS clearly can. * However it must always be FileSize <= AllocationSize and NTFS will make sure * to truncate the FileSize if it sees an AllocationSize < FileSize. * * If OTOH a very large AllocationSize is passed, the call below will increase * the AllocationSize of the underlying file, although our file system does not * expose this fact. This AllocationSize is only temporary as NTFS will reset * the AllocationSize of the underlying file when it is closed. */ AllocationInfo.AllocationSize.QuadPart = NewSize; if (!SetFileInformationByHandle(Handle, FileAllocationInfo, &AllocationInfo, sizeof AllocationInfo)) return FspNtStatusFromWin32(GetLastError()); } else { EndOfFileInfo.EndOfFile.QuadPart = NewSize; if (!SetFileInformationByHandle(Handle, FileEndOfFileInfo, &EndOfFileInfo, sizeof EndOfFileInfo)) return FspNtStatusFromWin32(GetLastError()); } return GetFileInfoInternal(Handle, FileInfo); }
static NTSTATUS SetDelete(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, PWSTR FileName, BOOLEAN DeleteFile) { HANDLE Handle = HandleFromContext(FileContext); FILE_DISPOSITION_INFO DispositionInfo; DispositionInfo.DeleteFile = DeleteFile; if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &DispositionInfo, sizeof DispositionInfo)) return FspNtStatusFromWin32(GetLastError()); return STATUS_SUCCESS; }
bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); FILE_END_OF_FILE_INFO info; info.EndOfFile.QuadPart = size; bool ret = SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info)); if (!ret) { set_system_error(error, GetLastError()); } return ret; }
static int do_SetEndOfFile(int argc, wchar_t **argv) { if (argc != 3) fail("usage: SetEndOfFile FileName Length"); HANDLE h = CreateFileW(argv[1], GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); if (INVALID_HANDLE_VALUE == h) errprint(0); else { FILE_END_OF_FILE_INFO EofInfo; EofInfo.EndOfFile.QuadPart = wcstoull(argv[2], 0, 0); BOOL r = SetFileInformationByHandle(h, FileEndOfFileInfo, &EofInfo, sizeof EofInfo); errprint(r); CloseHandle(h); } return 0; }
static int do_RenameStream(int argc, wchar_t **argv) { if (argc != 4 || ':' != argv[2][0]) fail("usage: RenameStream FileName:ExistingStreamName :NewStreamName ReplaceIfExists"); fail("not implemented!"); #if 0 HANDLE h = CreateFileW(argv[1], DELETE | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); if (INVALID_HANDLE_VALUE == h) errprint(0); else { typedef struct _FILE_RENAME_INFORMATION { BOOLEAN ReplaceIfExists; HANDLE RootDirectory; ULONG FileNameLength; WCHAR FileName[1]; } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; size_t namesize = wcslen(argv[2]) * sizeof(wchar_t); size_t infosize = sizeof(FILE_RENAME_INFORMATION) + namesize; FILE_RENAME_INFORMATION *RenameInfo = _alloca(infosize); memset(RenameInfo, 0, infosize); RenameInfo->ReplaceIfExists = !!(wcstoul(argv[3], 0, 0)); RenameInfo->RootDirectory = 0; RenameInfo->FileNameLength = namesize; memcpy(RenameInfo->FileName, argv[2], namesize); /* * This seems to fail with ERROR_INVALID_HANDLE on Win32 and ERROR_INVALID_NAME on Win64. * Do not have the time to figure the exact reasons why right now. */ BOOL r = SetFileInformationByHandle(h, FileRenameInfo, &RenameInfo, infosize); errprint(r); CloseHandle(h); } #endif return 0; }
boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p , file_storage::iterator fe, file_storage const& fs, int m, error_code& ec) { TORRENT_ASSERT(st != 0); TORRENT_ASSERT(is_complete(p)); TORRENT_ASSERT((m & file::rw_mask) == file::read_only || (m & file::rw_mask) == file::read_write); mutex::scoped_lock l(m_mutex); file_set::iterator i = m_files.find(std::make_pair(st, fs.file_index(*fe))); if (i != m_files.end()) { lru_file_entry& e = i->second; e.last_use = time_now(); if (e.key != st && ((e.mode & file::rw_mask) != file::read_only || (m & file::rw_mask) != file::read_only)) { // this means that another instance of the storage // is using the exact same file. #if BOOST_VERSION >= 103500 ec = errors::file_collision; #endif return boost::intrusive_ptr<file>(); } e.key = st; // if we asked for a file in write mode, // and the cached file is is not opened in // write mode, re-open it if ((((e.mode & file::rw_mask) != file::read_write) && ((m & file::rw_mask) == file::read_write)) || (e.mode & file::no_buffer) != (m & file::no_buffer) || (e.mode & file::random_access) != (m & file::random_access)) { // close the file before we open it with // the new read/write privilages TORRENT_ASSERT(e.file_ptr->refcount() == 1); #if TORRENT_CLOSE_MAY_BLOCK mutex::scoped_lock l(m_closer_mutex); m_queued_for_close.push_back(e.file_ptr); l.unlock(); e.file_ptr = new file; #else e.file_ptr->close(); #endif std::string full_path = combine_path(p, fs.file_path(*fe)); if (!e.file_ptr->open(full_path, m, ec)) { m_files.erase(i); return boost::intrusive_ptr<file>(); } #ifdef TORRENT_WINDOWS // file prio is supported on vista and up #if _WIN32_WINNT >= 0x0600 if (m_low_prio_io) { // TODO: load this function dynamically from Kernel32.dll FILE_IO_PRIORITY_HINT_INFO priorityHint; priorityHint.PriorityHint = IoPriorityHintLow; SetFileInformationByHandle(e.file_ptr->native_handle(), FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint)); } #endif #endif TORRENT_ASSERT(e.file_ptr->is_open()); e.mode = m; } TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer)); return e.file_ptr; } // the file is not in our cache if ((int)m_files.size() >= m_size) { // the file cache is at its maximum size, close // the least recently used (lru) file from it remove_oldest(); } lru_file_entry e; e.file_ptr.reset(new (std::nothrow)file); if (!e.file_ptr) { ec = error_code(ENOMEM, get_posix_category()); return e.file_ptr; } std::string full_path = combine_path(p, fs.file_path(*fe)); if (!e.file_ptr->open(full_path, m, ec)) return boost::intrusive_ptr<file>(); e.mode = m; e.key = st; m_files.insert(std::make_pair(std::make_pair(st, fs.file_index(*fe)), e)); TORRENT_ASSERT(e.file_ptr->is_open()); return e.file_ptr; }
bool os_create_reflink(const std::string &linkname, const std::string &fname) { HANDLE source_handle = CreateFileW(ConvertToWchar(fname).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (source_handle == INVALID_HANDLE_VALUE) return false; BY_HANDLE_FILE_INFORMATION source_info; if (!GetFileInformationByHandle(source_handle, &source_info)) { CloseHandle(source_handle); return false; } LARGE_INTEGER source_size; source_size.LowPart = source_info.nFileSizeLow; source_size.HighPart = source_info.nFileSizeHigh; ULONG ret_bytes; FSCTL_GET_INTEGRITY_INFORMATION_BUFFER get_integrity_info; if (!DeviceIoControl(source_handle, FSCTL_GET_INTEGRITY_INFORMATION, NULL, 0, &get_integrity_info, sizeof(get_integrity_info), &ret_bytes, NULL)) { CloseHandle(source_handle); return false; } HANDLE dest_handle = CreateFileW(ConvertToWchar(linkname).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, source_handle); if (dest_handle == INVALID_HANDLE_VALUE) { CloseHandle(source_handle); return false; } bool has_error = false; if ((source_info.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE)>0 && !DeviceIoControl(dest_handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &ret_bytes, NULL)) { has_error = true; } FSCTL_SET_INTEGRITY_INFORMATION_BUFFER set_integrity_info = { get_integrity_info.ChecksumAlgorithm, get_integrity_info.Reserved, get_integrity_info.Flags }; if (!has_error && !DeviceIoControl(dest_handle, FSCTL_SET_INTEGRITY_INFORMATION, &set_integrity_info, sizeof(set_integrity_info), NULL, 0, NULL, NULL)) { has_error = true; } FILE_END_OF_FILE_INFO eof_info = { source_size }; if(!has_error && !SetFileInformationByHandle(dest_handle, FileEndOfFileInfo, &eof_info, sizeof(eof_info) ) ) { has_error = true; } int64 cluster_size = get_integrity_info.ClusterSizeInBytes; int64 total_reflink = source_size.QuadPart; if(total_reflink%cluster_size!=0) total_reflink = ((total_reflink) / cluster_size + 1 )*cluster_size; int64 max_reflink = cluster_size == 0 ? total_reflink : (4LL * 1024 * 1024 * 1024 - cluster_size); reflink::DUPLICATE_EXTENTS_DATA reflink_data; reflink_data.FileHandle = source_handle; int64 reflinked = 0; while (!has_error && reflinked < total_reflink) { int64 curr_reflink = (std::min)(total_reflink - reflinked, max_reflink); reflink_data.ByteCount.QuadPart = curr_reflink; reflink_data.SourceFileOffset.QuadPart = reflinked; reflink_data.TargetFileOffset.QuadPart = reflinked; if (!DeviceIoControl(dest_handle, reflink::FSCTL_DUPLICATE_EXTENTS_TO_FILE, &reflink_data, sizeof(reflink_data), NULL, 0, &ret_bytes, NULL)) { has_error = true; } reflinked += curr_reflink; } DWORD err = GetLastError(); CloseHandle(source_handle); CloseHandle(dest_handle); if (has_error) { DeleteFileW(ConvertToWchar(linkname).c_str()); SetLastError(err); return false; } return true; }
/** * Accepts a HashRequest structure and attempts to calculate the requested hash * of the provided file using synchronous IO. */ int HashFileWithSyncIO(HashRequest* request, HashProgressCallback* callback) { /* Variables to hold our options. */ char doCRC32 = 0; char doMD5 = 0; char doSHA1 = 0; char doED2k = 0; /* Standard variables (same between platforms) */ CRC32_Context crc32; MD4_Context ed2k; MD5_Context md5; SHA1_Context sha1; uint32_t bytesRead = 0; uint32_t ed2kBlockIdx = 0; uint32_t ed2kBlocks = 0; uint32_t ed2kHashLength = 0; uint8_t ed2kLoopIdx = 0; uint32_t progressLoopCount = 0; uint64_t totalBytesRead = 0; unsigned char* ed2kHashes = NULL; unsigned char* fileData = NULL; /* Platform specific variables */ HANDLE file = NULL; WIN32_FILE_ATTRIBUTE_DATA fileAttributeData = { 0 }; BOOL readFailed = FALSE; FILE_IO_PRIORITY_HINT_INFO priorityHint = { 0 }; /* Simple guard condition. If we have no request, we can't process. */ if (request == NULL) { return -1; } /* clear the result buffer */ SecureZeroMemory(&request->result, 56); /* Set our options */ doCRC32 = request->options & OPTION_CRC32; doMD5 = request->options & OPTION_MD5; doSHA1 = request->options & OPTION_SHA1; doED2k = request->options & OPTION_ED2K; /* If they didn't pass any valid options (or passed 0) for the options, * return since we can't calculate a hash without knowing which hashing * algorithm(s) to use. */ if (!doCRC32 && !doMD5 && !doSHA1 && !doED2k) { return -2; } file = CreateFileW( request->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (file == INVALID_HANDLE_VALUE) { return -4; } /* Set our file priority hint to background. This is only a hint to Windows * that our file IO should be secondary to other scheduled IO. If there is * no other IO at the time, it will run at full speed. */ priorityHint.PriorityHint = IoPriorityHintVeryLow; SetFileInformationByHandle( file, FileIoPriorityHintInfo, &priorityHint, sizeof(priorityHint)); /* Set up our hashes, also calculate the space needed for the ED2k hash if * we were requested to produce an ED2k hash result. */ if (doED2k) { BOOL result = 0; uint64_t fileSize = 0; result = GetFileAttributesExW( request->filename, GetFileExInfoStandard, &fileAttributeData); if (!result) { CloseHandle(file); return -5; } /* Convert the file size from two 32-bit DWORDS to a uint64_t. */ fileSize = (((uint64_t)fileAttributeData.nFileSizeHigh) << 32) | fileAttributeData.nFileSizeLow; /* Determine the number of blocks needed for calculating the file's * ED2k's hash. If the file isn't an even multiple of BLOCKSIZE then we * add one more block. */ ed2kBlocks = (uint32_t)((uint64_t)fileSize / BLOCKSIZE); if (fileSize % BLOCKSIZE > 0) { ++ed2kBlocks; } /* Only allocate an array if we have more than one block to hash. * Files that are smaller in size than BLOCKSIZE simply use the normal * computed MD4 hash. */ if (ed2kBlocks > 1) { ed2kHashLength = ed2kBlocks * 16; ed2kHashes = (unsigned char*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ed2kHashLength); if (ed2kHashes == NULL) { CloseHandle(file); return -6; } } } if (doCRC32) { CRC32_init(&crc32); } if (doMD5) { MD5_init(&md5); } if (doSHA1) { SHA1_init(&sha1); } /* Allocate the file buffer. The BUFFERSIZE constant is a clean multiple of * the BLOCKSIZE for ED2k hashing, which will make for easier looping. */ fileData = (unsigned char*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, BUFFERSIZE); if (fileData == NULL) { CloseHandle(file); if (doED2k && ed2kHashes) { HeapFree(GetProcessHeap(), 0, ed2kHashes); } return -7; } do { if (!ReadFile(file, fileData, BUFFERSIZE, &bytesRead, NULL)) { readFailed = TRUE; break; } if (bytesRead == 0) { break; } /* Update the total bytes read and inform the callback of our progress * if it's time. Don't forget to bail out if they request it. */ totalBytesRead += bytesRead; if (callback && progressLoopCount % 10 == 0) { int32_t result = callback(request->tag, totalBytesRead); if (result != 0) { CloseHandle(file); HeapFree(GetProcessHeap(), 0, fileData); if (doED2k && ed2kHashes) { HeapFree(GetProcessHeap(), 0, ed2kHashes); } return -9; } } ++progressLoopCount; /* Update the hashes with the file data. */ if (doED2k) { /* If we've looped 10 times, finish the current MD4 hash, update * the block counter and set the hash to be initialized again. * Also, if the BUFFERSIZE is ever changed, the loop index will * need to be adjusted as well. */ if (ed2kLoopIdx == 10) { MD4_final(&ed2k, &ed2kHashes[ed2kBlockIdx * 16]); ++ed2kBlockIdx; ed2kLoopIdx = 0; } /* If this is the first loop (or we've just finished a hash) * initialize the MD4 hash for the next block. */ if (ed2kLoopIdx == 0) { MD4_init(&ed2k); } ++ed2kLoopIdx; MD4_update(&ed2k, fileData, bytesRead); } if (doCRC32) { CRC32_update(&crc32, fileData, bytesRead); } if (doMD5) { MD5_update(&md5, fileData, bytesRead); } if (doSHA1) { SHA1_update(&sha1, fileData, bytesRead); } } while (bytesRead != 0); /* Free our file buffer and close the file since we're done with it. */ HeapFree(GetProcessHeap(), 0, fileData); CloseHandle(file); /* If we have a callback, call them one last time informing them of our * final progress (even if we failed). We'll ignore the request to cancel * since we'll be done in no time anyway. */ if (callback) { callback(request->tag, totalBytesRead); } /* If we had a read failure, free up the ed2k hash (if we have one) and * inform our caller that we had a problem. */ if (readFailed) { if (doED2k && ed2kHashes) { HeapFree(GetProcessHeap(), 0, ed2kHashes); } return -8; } /* Finalize all of the hashes that were selected and store the results in * the request result buffer. The order of the hashes are: * 0 - 15: ED2k * 16 - 19: CRC32 * 20 - 35: MD5 * 36 - 55: SHA1 */ if (doED2k) { /* If we just had one block to process directly store the result of the * block in the result buffer. */ if (ed2kBlocks == 1) { MD4_final(&ed2k, &request->result[0]); } else { /* Check to see if we were in the middle of a loop and finalize the * final pending block if we were. */ if (ed2kLoopIdx > 0) { MD4_final(&ed2k, &ed2kHashes[ed2kBlockIdx * 16]); } /* Calculate the MD4 hash of the concatenated hashes from each ED2k * block. The resulting hash is the final ED2k hash. */ MD4_init(&ed2k); MD4_update(&ed2k, ed2kHashes, ed2kHashLength); MD4_final(&ed2k, &request->result[0]); /* Don't forget to free our ED2k buffer. */ HeapFree(GetProcessHeap(), 0, ed2kHashes); } } if (doCRC32) { CRC32_final(&crc32, &request->result[16]); } if (doMD5) { MD5_final(&md5, &request->result[20]); } if (doSHA1) { SHA1_final(&sha1, &request->result[36]); } return 0; }