| /** |
| * Copyright 2011-2015 Quickstep Technologies LLC. |
| * Copyright 2015 Pivotal Software, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| **/ |
| |
| #define __STDC_FORMAT_MACROS |
| |
| #include "storage/FileManagerWindows.hpp" |
| |
| #define WIN32_LEAN_AND_MEAN |
| #include <io.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| #include <cerrno> |
| #include <cinttypes> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| |
| #include "storage/StorageBlockInfo.hpp" |
| #include "storage/StorageConstants.hpp" |
| #include "storage/StorageErrors.hpp" |
| #include "utility/Macros.hpp" |
| #include "utility/StringUtil.hpp" |
| |
| using std::size_t; |
| using std::strerror; |
| using std::string; |
| using std::uint64_t; |
| |
| namespace quickstep { |
| |
| block_id_counter FileManagerWindows::getMaxUsedBlockCounter(const block_id_domain block_domain) const { |
| const string block_domain_str(ToZeroPaddedString(block_domain, kBlockIdDomainLengthInDigits)); |
| |
| string glob_pattern(storage_path_); |
| glob_pattern.append("qsblk_"); |
| glob_pattern.append(block_domain_str); |
| glob_pattern.append("_*.qsb"); |
| |
| WIN32_FIND_DATA find_data; |
| HANDLE find_handle = INVALID_HANDLE_VALUE; |
| DWORD error_code = 0; |
| |
| find_handle = FindFirstFile(glob_pattern.c_str(), &find_data); |
| if (find_handle == INVALID_HANDLE_VALUE) { |
| error_code = GetLastError(); |
| if (error_code != ERROR_FILE_NOT_FOUND) { |
| LOG_WARNING("Failed to retrieve blockfiles with error_code: " << error_code); |
| } |
| return 0; |
| } |
| |
| string filename_pattern("qsblk_"); |
| filename_pattern.append(block_domain_str); |
| filename_pattern.append("_%"); |
| filename_pattern.append(SCNu64); |
| filename_pattern.append(".qsb"); |
| |
| block_id_counter counter_max = 0, counter; |
| do { |
| if (sscanf(find_data.cFileName, filename_pattern.c_str(), &counter) == 1 |
| && counter > counter_max) { |
| counter_max = counter; |
| } |
| } while (FindNextFile(find_handle, &find_data) != 0); |
| |
| error_code = GetLastError(); |
| if (error_code != ERROR_NO_MORE_FILES) { |
| LOG_WARNING("Failed to FindNextFile with error_code: " << error_code); |
| } |
| |
| if (FindClose(find_handle) == 0) { |
| LOG_WARNING("Failed to close the file with error_code: " << GetLastError()); |
| } |
| |
| return counter_max; |
| } |
| |
| size_t FileManagerWindows::numSlots(const block_id block) const { |
| string filename(blockFilename(block)); |
| WIN32_FILE_ATTRIBUTE_DATA file_stat; |
| |
| if (!GetFileAttributesEx(filename.c_str(), GetFileExInfoStandard, &file_stat)) { |
| DWORD error_code = GetLastError(); |
| if (error_code != ERROR_FILE_NOT_FOUND) { |
| LOG_WARNING("Failed to retrieve info about file " << filename << " with error_code: " << error_code); |
| } |
| return 0; |
| } |
| |
| uint64_t file_size = (static_cast<uint64_t>(file_stat.nFileSizeHigh) << 32) | file_stat.nFileSizeLow; |
| |
| if ((file_size % kSlotSizeBytes) != 0) { |
| LOG(FATAL) << "The file " << filename << " was corrupted."; |
| } |
| |
| return static_cast<size_t>(file_size / kSlotSizeBytes); |
| } |
| |
| bool FileManagerWindows::deleteBlockOrBlob(const block_id block) { |
| string filename(blockFilename(block)); |
| |
| if ((DeleteFile(filename.c_str()) != 0) || (GetLastError() == ERROR_FILE_NOT_FOUND)) { |
| return true; |
| } else { |
| LOG_WARNING("Failed to delete file " << filename << " with error_code: " << GetLastError()); |
| } |
| } |
| |
| bool FileManagerWindows::readBlockOrBlob(const block_id block, |
| void *buffer, |
| const size_t length) { |
| DEBUG_ASSERT(buffer); |
| DEBUG_ASSERT(length % kSlotSizeBytes == 0); |
| |
| string filename(blockFilename(block)); |
| |
| FILE *file = fopen(filename.c_str(), "rb"); |
| if (file == nullptr) { |
| // Note: On most, but not all, library implementations, the errno variable |
| // is set to a system-specific error code on failure. |
| LOG_WARNING("Failed to open file " << filename << " with error: " << strerror(errno)); |
| return false; |
| } |
| |
| const size_t bytes = std::fread(buffer, sizeof(char), length, file); |
| const bool result_is_ok = (bytes == length); |
| if (!result_is_ok) { |
| if (std::feof(file)) { |
| LOG_WARNING("Failed to read file " << filename << " since EOF was reached unexpectedly"); |
| } else { |
| LOG_WARNING("Failed to read file " << filename << " with error: " << strerror(ferror(file))); |
| clearerr(file); |
| } |
| } |
| |
| if (fclose(file)) { |
| // Note: fclose does not set errno on failure. |
| LOG_WARNING("Failed to close file " << filename); |
| } |
| |
| return result_is_ok; |
| } |
| |
| bool FileManagerWindows::writeBlockOrBlob(const block_id block, |
| const void *buffer, |
| const size_t length) { |
| DEBUG_ASSERT(buffer); |
| DEBUG_ASSERT(length % kSlotSizeBytes == 0); |
| |
| string filename(blockFilename(block)); |
| |
| FILE *file = fopen(filename.c_str(), "wb"); |
| if (file == nullptr) { |
| // Note: On most, but not all, library implementations, the errno variable |
| // is set to a system-specific error code on failure. |
| LOG_WARNING("Failed to open file " << filename << " with error: " << strerror(errno)); |
| return false; |
| } |
| |
| const size_t bytes = std::fwrite(buffer, sizeof(char), length, file); |
| const bool result_is_ok = (bytes == length); |
| if (!result_is_ok) { |
| LOG_WARNING("Failed to write file " << filename << " with error: " << strerror(ferror(file))); |
| clearerr(file); |
| } |
| |
| if (fflush(file)) { |
| LOG_WARNING("Failed to flush file " << filename << " with error: " << strerror(ferror(file))); |
| } |
| |
| if (!FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(file))))) { |
| LOG_WARNING("Failed to re-flush file " << filename << " with error: " << strerror(ferror(file))); |
| } |
| |
| if (fclose(file)) { |
| // Note: fclose does not set errno on failure. |
| LOG_WARNING("Failed to close file " << filename); |
| } |
| |
| return result_is_ok; |
| } |
| |
| } // namespace quickstep |