Skip to content

Commit

Permalink
Fixed bug #7873 : IO error reading file, The parameter is incorrect.
Browse files Browse the repository at this point in the history
  • Loading branch information
hvlad committed Nov 25, 2023
1 parent 8789caf commit f8571de
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 21 deletions.
4 changes: 4 additions & 0 deletions src/common/os/os_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#define FLOCK flock
#endif

const ULONG DEFAULT_SECTOR_SIZE = 4096;

namespace os_utils
{

Expand All @@ -88,6 +90,8 @@ namespace os_utils
void setCloseOnExec(int fd); // posix only
FILE* fopen(const char* pathname, const char* mode);

ULONG getPhysicalSectorSize(const Firebird::PathName& fileName);

// return a binary string that uniquely identifies the file
#ifdef WIN_NT
void getUniqueFileId(HANDLE fd, Firebird::UCharBuffer& id);
Expand Down
6 changes: 6 additions & 0 deletions src/common/os/posix/os_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ FILE* fopen(const char* pathname, const char* mode)
return f;
}

ULONG getPhysicalSectorSize(const PathName& fileName)
{
// return safe value
return DEFAULT_SECTOR_SIZE;
}

static void makeUniqueFileId(const struct STAT& statistics, UCharBuffer& id)
{
const size_t len1 = sizeof(statistics.st_dev);
Expand Down
42 changes: 42 additions & 0 deletions src/common/os/win32/os_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

#include <aclapi.h>
#include <Winsock2.h>
#include <winioctl.h>

using namespace Firebird;

Expand Down Expand Up @@ -408,6 +409,47 @@ FILE* fopen(const char* pathname, const char* mode)
return ::fopen(pathname, mode);
}

ULONG getPhysicalSectorSize(const PathName& fileName)
{
// Fallback to the safe value
ULONG ret = DEFAULT_SECTOR_SIZE;

// Device name could be set as \\.\PhysicalDrive0 or as \\.\a:
// The second form is used below for simplicity.

string deviceName = "\\\\.\\";
deviceName.append(fileName.c_str(), 2);

HANDLE hDevice = CreateFile(deviceName.c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0, NULL);

if (hDevice != INVALID_HANDLE_VALUE)
{
STORAGE_PROPERTY_QUERY qry;
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR desc;
DWORD readSize = 0;

qry.PropertyId = StorageAccessAlignmentProperty;
qry.QueryType = PropertyStandardQuery;

if (DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&qry, sizeof(qry),
&desc, sizeof(desc),
&readSize, NULL))
{
ret = desc.BytesPerPhysicalSector;
}

CloseHandle(hDevice);
}

return ret;
}

void getUniqueFileId(HANDLE fd, UCharBuffer& id)
{
entryLoader.init();
Expand Down
16 changes: 13 additions & 3 deletions src/jrd/jrd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7592,11 +7592,21 @@ static JAttachment* create_attachment(const PathName& alias_name,

static void check_single_maintenance(thread_db* tdbb)
{
UCHAR spare_memory[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
UCHAR* header_page_buffer = FB_ALIGN(spare_memory, PAGE_ALIGNMENT);
Database* const dbb = tdbb->getDatabase();

const ULONG sectorSize = (dbb->dbb_flags & DBB_no_fs_cache) ?
os_utils::getPhysicalSectorSize(dbb->dbb_filename) :
PAGE_ALIGNMENT;

const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);

HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
UCHAR* header_page_buffer = temp.getBuffer(headerSize + sectorSize);

header_page_buffer = FB_ALIGN(header_page_buffer, PAGE_ALIGNMENT);
Ods::header_page* const header_page = reinterpret_cast<Ods::header_page*>(header_page_buffer);

PIO_header(tdbb, header_page_buffer, RAW_HEADER_SIZE);
PIO_header(tdbb, header_page_buffer, headerSize);

if ((header_page->hdr_flags & Ods::hdr_shutdown_mask) == Ods::hdr_shutdown_single)
{
Expand Down
13 changes: 10 additions & 3 deletions src/jrd/pag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1261,10 +1261,17 @@ void PAG_header_init(thread_db* tdbb)
// and unit of transfer is a multiple of physical disk
// sector for raw disk access.

UCHAR temp_buffer[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
UCHAR* const temp_page = FB_ALIGN(temp_buffer, PAGE_ALIGNMENT);
const ULONG sectorSize = (dbb->dbb_flags & DBB_no_fs_cache) ?
os_utils::getPhysicalSectorSize(dbb->dbb_filename) :
PAGE_ALIGNMENT;

PIO_header(tdbb, temp_page, RAW_HEADER_SIZE);
const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);

HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
UCHAR* temp_buffer = temp.getBuffer(headerSize + sectorSize);
UCHAR* const temp_page = FB_ALIGN(temp_buffer, sectorSize);

PIO_header(tdbb, temp_page, headerSize);
const header_page* header = (header_page*) temp_page;

if (header->hdr_header.pag_type != pag_header || header->hdr_sequence)
Expand Down
4 changes: 4 additions & 0 deletions src/utilities/gstat/dba.epp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,10 @@ int gstat(Firebird::UtilSvc* uSvc)
expandDatabaseName(fileName, tempStr, NULL);
fileName = tempStr;

// If file will be opened with no buffering (direct IO), make sure that
// temp buffer is aligned on the disk physical sector size and IO size
// is multiply of sector size.

dba_fil* current = db_open(fileName.c_str(), fileName.length());

SCHAR temp[RAW_HEADER_SIZE];
Expand Down
31 changes: 16 additions & 15 deletions src/utilities/nbackup/nbackup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@
#define O_LARGEFILE 0
#endif

// How much we align memory when reading database header.
// Sector alignment of memory is necessary to use unbuffered IO on Windows.
// Actually, sectors may be bigger than 1K, but let's be consistent with
// JRD regarding the matter for the moment.
const FB_SIZE_T SECTOR_ALIGNMENT = PAGE_ALIGNMENT;

using namespace Firebird;

namespace
Expand Down Expand Up @@ -1199,7 +1193,7 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
ULONG prev_scn = 0;
char prev_guid[GUID_BUFF_SIZE] = "";
char str_guid[GUID_BUFF_SIZE] = "";
Ods::pag* page_buff = NULL;

attach_database();
ULONG page_writes = 0, page_reads = 0;

Expand Down Expand Up @@ -1339,12 +1333,18 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
open_database_scan();

// Read database header
char unaligned_header_buffer[RAW_HEADER_SIZE + SECTOR_ALIGNMENT];

auto header = reinterpret_cast<Ods::header_page*>(
FB_ALIGN(unaligned_header_buffer, SECTOR_ALIGNMENT));
const ULONG sectorSize = os_utils::getPhysicalSectorSize(dbname);
const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);

Array<UCHAR> unaligned_header_buffer;
Ods::header_page* header = nullptr;
{ // scope
UCHAR* buf = unaligned_header_buffer.getBuffer(headerSize + sectorSize);
header = reinterpret_cast<Ods::header_page*>(FB_ALIGN(buf, sectorSize));
} // end scope

if (read_file(dbase, header, RAW_HEADER_SIZE) != RAW_HEADER_SIZE)
if (read_file(dbase, header, headerSize) != headerSize)
status_exception::raise(Arg::Gds(isc_nbackup_err_eofhdrdb) << dbname.c_str() << Arg::Num(1));

if (!Ods::isSupported(header))
Expand All @@ -1361,9 +1361,10 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
status_exception::raise(Arg::Gds(isc_nbackup_db_notlock) << Arg::Num(header->hdr_flags));

Array<UCHAR> unaligned_page_buffer;
Ods::pag* page_buff = nullptr;
{ // scope
UCHAR* buf = unaligned_page_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT);
page_buff = reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, SECTOR_ALIGNMENT));
UCHAR* buf = unaligned_page_buffer.getBuffer(header->hdr_page_size + sectorSize);
page_buff = reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, sectorSize));
} // end scope

ULONG db_size = db_size_pages;
Expand Down Expand Up @@ -1430,8 +1431,8 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
Array<UCHAR> unaligned_scns_buffer;
Ods::scns_page* scns = NULL, *scns_buf = NULL;
{ // scope
UCHAR* buf = unaligned_scns_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT);
scns_buf = reinterpret_cast<Ods::scns_page*>(FB_ALIGN(buf, SECTOR_ALIGNMENT));
UCHAR* buf = unaligned_scns_buffer.getBuffer(header->hdr_page_size + sectorSize);
scns_buf = reinterpret_cast<Ods::scns_page*>(FB_ALIGN(buf, sectorSize));
}

while (true)
Expand Down

0 comments on commit f8571de

Please sign in to comment.