mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:03:03 +01:00
Implemented CORE-2666: Make it possible to use API to do remote backups/restores
This commit is contained in:
parent
4d1651a327
commit
477e14a820
@ -134,7 +134,7 @@ List of existing trace sessions
|
||||
- user: <string>
|
||||
- date: YYYY-MM-DD HH:NN:SS
|
||||
- flags: <string>
|
||||
|
||||
|
||||
"name" is trace session name and not printed if empty.
|
||||
"user" is creator user name
|
||||
"date" is session start date and time
|
||||
@ -149,4 +149,45 @@ List of existing trace sessions
|
||||
Output of every service is obtained as usually using isc_service_query call
|
||||
with isc_info_svc_line or isc_info_svc_to_eof information items.
|
||||
|
||||
See also README.trace_services
|
||||
See also README.trace_services
|
||||
|
||||
|
||||
4) Services API extension - running gbak at server side with .fbk at the client.
|
||||
(Alex Peshkov, peshkoff@mail.ru, 2011-2012)
|
||||
|
||||
This way of doing backups is specially efficient when one needs to perform
|
||||
backup/restore operation for database, located on ther server accessed using
|
||||
internet, due to serious performance instrease.
|
||||
|
||||
The simplest way to use this feature is fbsvcmgr. To backup database run
|
||||
approximately the following:
|
||||
fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \
|
||||
action_backup -dbname some.fdb -bkp_file stdout >some.fbk
|
||||
|
||||
and to restore it:
|
||||
fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \
|
||||
action_restore -dbname some.fdb -bkp_file stdin <some.fbk
|
||||
|
||||
Please notice - you can't use "verbose" switch when performing backup because
|
||||
data channel from server to client is used to deliver blocks of fbk files. You
|
||||
will get appropriate error message if you try to do it. When restoring database
|
||||
verbose mode may be used without limitations.
|
||||
|
||||
If you want to perform backup/restore from your own program, you should use
|
||||
services API for it. Backup is very simple - just pass "stdout" as backup file
|
||||
name to server and use isc_info_svc_to_eof in isc_service_query() call. Data,
|
||||
returned by repeating calls to isc_service_query() (certainly with
|
||||
isc_info_svc_to_eof tag) is a stream, representing image of backup file. Restore
|
||||
is a bit more tricky. Client sends new spb parameter isc_info_svc_stdin to server
|
||||
in isc_service_query(). If service needs some data in stdin, it returns
|
||||
isc_info_svc_stdin in query results, followed by 4-bytes value - number of bytes
|
||||
server is ready to accept from client. (0 value means no more data is needed right
|
||||
now.) The main trick is that client should NOT send more data than requested by
|
||||
server - this causes an error "Size of data is more than requested". The data is
|
||||
sent in next isc_service_query() call in the send_items block, using
|
||||
isc_info_svc_line tag in tradition form: isc_info_svc_line, 2 bytes length, data.
|
||||
When server needs next portion, it once more returns non-zero isc_info_svc_stdin
|
||||
value from isc_service_query().
|
||||
|
||||
A sample of how services API should be used for remote backup and restore can be
|
||||
found in source code of fbsvcmgr.
|
||||
|
@ -1255,12 +1255,17 @@ int gbak(Firebird::UtilSvc* uSvc)
|
||||
// Close the gbak file handles if they still open
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
{
|
||||
if (file->fil_fd != INVALID_HANDLE_VALUE)
|
||||
close_platf(file->fil_fd);
|
||||
if (exit_code != FINI_OK &&
|
||||
(tdgbl->action->act_action == ACT_backup_split || tdgbl->action->act_action == ACT_backup))
|
||||
if (file->fil_fd != GBAK_STDIN_DESC() && file->fil_fd != GBAK_STDOUT_DESC())
|
||||
{
|
||||
unlink_platf(file->fil_name.c_str());
|
||||
if (file->fil_fd != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
close_platf(file->fil_fd);
|
||||
}
|
||||
if (exit_code != FINI_OK &&
|
||||
(tdgbl->action->act_action == ACT_backup_split || tdgbl->action->act_action == ACT_backup))
|
||||
{
|
||||
unlink_platf(file->fil_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1840,10 +1845,10 @@ static gbak_action open_files(const TEXT* file1,
|
||||
}
|
||||
if (fil->fil_name == "stdout")
|
||||
{
|
||||
if (tdgbl->action->act_total >= 2 || fil->fil_next)
|
||||
if (tdgbl->action->act_total >= 2 || fil->fil_next || sw_verbose)
|
||||
{
|
||||
BURP_error(266, true);
|
||||
// msg 266 standard output is not supported when using split operation
|
||||
// msg 266 standard output is not supported when using split operation or in verbose mode
|
||||
flag = QUIT;
|
||||
break;
|
||||
}
|
||||
@ -1855,6 +1860,7 @@ static gbak_action open_files(const TEXT* file1,
|
||||
#endif
|
||||
tdgbl->uSvc->setDataMode(true);
|
||||
fil->fil_fd = GBAK_STDOUT_DESC();
|
||||
tdgbl->stdIoMode = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
@ -1959,10 +1965,13 @@ static gbak_action open_files(const TEXT* file1,
|
||||
{
|
||||
fil->fil_fd = GBAK_STDIN_DESC();
|
||||
tdgbl->file_desc = fil->fil_fd;
|
||||
tdgbl->stdIoMode = true;
|
||||
tdgbl->gbl_sw_files = fil->fil_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
tdgbl->stdIoMode = false;
|
||||
|
||||
// open first file
|
||||
#ifdef WIN_NT
|
||||
if ((fil->fil_fd = MVOL_open(fil->fil_name.c_str(), MODE_READ, OPEN_EXISTING)) ==
|
||||
|
@ -871,10 +871,11 @@ public:
|
||||
BurpGlobals(Firebird::UtilSvc* us)
|
||||
: ThreadData(ThreadData::tddGBL),
|
||||
defaultCollations(*getDefaultMemoryPool()),
|
||||
flag_on_line(true),
|
||||
uSvc(us),
|
||||
verboseInterval(10000),
|
||||
flag_on_line(true),
|
||||
firstMap(true),
|
||||
verboseInterval(10000)
|
||||
stdIoMode(false)
|
||||
{
|
||||
// this is VERY dirty hack to keep current behaviour
|
||||
memset (&gbl_database_file_name, 0,
|
||||
@ -886,8 +887,6 @@ public:
|
||||
// would be set to FINI_OK (==0) in exit_local
|
||||
}
|
||||
|
||||
Firebird::Array<Firebird::Pair<Firebird::NonPooled<Firebird::MetaName, Firebird::MetaName> > >
|
||||
defaultCollations;
|
||||
const TEXT* gbl_database_file_name;
|
||||
TEXT gbl_backup_start_time[30];
|
||||
bool gbl_sw_verbose;
|
||||
@ -1034,10 +1033,13 @@ public:
|
||||
char veryEnd;
|
||||
//starting after this members must be initialized in constructor explicitly
|
||||
|
||||
bool flag_on_line; // indicates whether we will bring the database on-line
|
||||
Firebird::Array<Firebird::Pair<Firebird::NonPooled<Firebird::MetaName, Firebird::MetaName> > >
|
||||
defaultCollations;
|
||||
Firebird::UtilSvc* uSvc;
|
||||
bool firstMap; // this is the first time we entered get_mapping()
|
||||
ULONG verboseInterval; // How many records should be backed up or restored before we show this message
|
||||
bool flag_on_line; // indicates whether we will bring the database on-line
|
||||
bool firstMap; // this is the first time we entered get_mapping()
|
||||
bool stdIoMode; // stdin or stdout is used as backup file
|
||||
};
|
||||
|
||||
// CVC: This aux routine declared here to not force inclusion of burp.h with burp_proto.h
|
||||
@ -1048,16 +1050,7 @@ void BURP_exit_local(int code, BurpGlobals* tdgbl);
|
||||
const int FINI_DB_NOT_ONLINE = 2;
|
||||
|
||||
// I/O definitions
|
||||
|
||||
#ifndef IO_BUFFER_SIZE
|
||||
#ifdef BUFSIZ
|
||||
const int GBAK_IO_BUFFER_SIZE = (16 * (BUFSIZ));
|
||||
#else
|
||||
const int GBAK_IO_BUFFER_SIZE = (16 * (1024));
|
||||
#endif
|
||||
#else
|
||||
const int GBAK_IO_BUFFER_SIZE = (16 * (IO_BUFFER_SIZE));
|
||||
#endif
|
||||
const int GBAK_IO_BUFFER_SIZE = SVC_IO_BUFFER_SIZE;
|
||||
|
||||
/* Burp will always write a backup in multiples of the following number
|
||||
* of bytes. The initial value is the smallest which ensures that writes
|
||||
|
@ -100,6 +100,7 @@ static void put_numeric(SCHAR, int);
|
||||
static bool read_header(DESC, ULONG*, USHORT*, bool);
|
||||
static bool write_header(DESC, ULONG, bool);
|
||||
static DESC next_volume(DESC, ULONG, bool);
|
||||
static void mvol_read(int*, UCHAR**);
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
@ -109,15 +110,16 @@ FB_UINT64 MVOL_fini_read()
|
||||
{
|
||||
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
||||
|
||||
if (strcmp(tdgbl->mvol_old_file, "stdin") != 0)
|
||||
if (!tdgbl->stdIoMode)
|
||||
{
|
||||
close_platf(tdgbl->file_desc);
|
||||
}
|
||||
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc) {
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,15 +141,19 @@ FB_UINT64 MVOL_fini_write(int* io_cnt, UCHAR** io_ptr)
|
||||
|
||||
MVOL_write(rec_end, io_cnt, io_ptr);
|
||||
flush_platf(tdgbl->file_desc);
|
||||
if (strcmp(tdgbl->mvol_old_file, "stdout") != 0)
|
||||
|
||||
if (!tdgbl->stdIoMode)
|
||||
{
|
||||
close_platf(tdgbl->file_desc);
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
}
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
tdgbl->file_desc = INVALID_HANDLE_VALUE;
|
||||
BURP_free(tdgbl->mvol_io_header);
|
||||
tdgbl->mvol_io_header = NULL;
|
||||
@ -255,12 +261,48 @@ void MVOL_init_write(const char* file_name, int* cnt, UCHAR** ptr)
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Read a buffer's worth of data. (common)
|
||||
//
|
||||
int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
{
|
||||
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
||||
|
||||
if (tdgbl->stdIoMode && tdgbl->uSvc->isService())
|
||||
{
|
||||
tdgbl->uSvc->started();
|
||||
tdgbl->mvol_io_cnt = tdgbl->uSvc->getBytes(tdgbl->mvol_io_buffer, tdgbl->mvol_io_buffer_size);
|
||||
if (!tdgbl->mvol_io_cnt)
|
||||
{
|
||||
BURP_error_redirect(0, 220);
|
||||
// msg 220 Unexpected I/O error while reading from backup file
|
||||
}
|
||||
tdgbl->mvol_io_ptr = tdgbl->mvol_io_buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
mvol_read(cnt, ptr);
|
||||
}
|
||||
|
||||
tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt;
|
||||
file_not_empty();
|
||||
|
||||
if (ptr)
|
||||
*ptr = tdgbl->mvol_io_ptr + 1;
|
||||
if (cnt)
|
||||
*cnt = tdgbl->mvol_io_cnt - 1;
|
||||
|
||||
return *tdgbl->mvol_io_ptr;
|
||||
}
|
||||
|
||||
|
||||
#ifndef WIN_NT
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Read a buffer's worth of data. (non-WIN_NT)
|
||||
//
|
||||
int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
static void mvol_read(int* cnt, UCHAR** ptr)
|
||||
{
|
||||
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
||||
|
||||
@ -295,14 +337,6 @@ int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt;
|
||||
file_not_empty();
|
||||
|
||||
*ptr = tdgbl->mvol_io_ptr + 1;
|
||||
*cnt = tdgbl->mvol_io_cnt - 1;
|
||||
|
||||
return *tdgbl->mvol_io_ptr;
|
||||
}
|
||||
|
||||
|
||||
@ -311,7 +345,7 @@ int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
//
|
||||
// Read a buffer's worth of data. (WIN_NT)
|
||||
//
|
||||
int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
static void mvol_read(int* cnt, UCHAR** ptr)
|
||||
{
|
||||
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
||||
|
||||
@ -343,14 +377,6 @@ int MVOL_read(int* cnt, UCHAR** ptr)
|
||||
// msg 50 unexpected end of file on backup file
|
||||
}
|
||||
}
|
||||
|
||||
tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt;
|
||||
file_not_empty();
|
||||
|
||||
*ptr = tdgbl->mvol_io_ptr + 1;
|
||||
*cnt = tdgbl->mvol_io_cnt - 1;
|
||||
|
||||
return *tdgbl->mvol_io_ptr;
|
||||
}
|
||||
#endif // !WIN_NT
|
||||
|
||||
@ -507,78 +533,22 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
|
||||
const ULONG size_to_write = BURP_UP_TO_BLOCK(*io_ptr - tdgbl->mvol_io_buffer);
|
||||
ULONG left = size_to_write;
|
||||
|
||||
for (ptr = tdgbl->mvol_io_buffer; left > 0; ptr += cnt, left -= cnt)
|
||||
if (tdgbl->stdIoMode && tdgbl->uSvc->isService())
|
||||
{
|
||||
if (tdgbl->action->act_action == ACT_backup_split)
|
||||
tdgbl->uSvc->started();
|
||||
tdgbl->uSvc->putBytes(tdgbl->mvol_io_buffer, left);
|
||||
left = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ptr = tdgbl->mvol_io_buffer; left > 0; ptr += cnt, left -= cnt)
|
||||
{
|
||||
// Write to the current file till fil_lingth > 0, otherwise
|
||||
// switch to the next one
|
||||
if (tdgbl->action->act_file->fil_length == 0)
|
||||
{
|
||||
if (tdgbl->action->act_file->fil_next)
|
||||
{
|
||||
close_platf(tdgbl->file_desc);
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
tdgbl->action->act_file = tdgbl->action->act_file->fil_next;
|
||||
tdgbl->file_desc = tdgbl->action->act_file->fil_fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a last file. Keep writing in a hope that there is
|
||||
// enough free disk space ...
|
||||
tdgbl->action->act_file->fil_length = MAX_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const size_t nBytesToWrite =
|
||||
(tdgbl->action->act_action == ACT_backup_split &&
|
||||
tdgbl->action->act_file->fil_length < left) ?
|
||||
tdgbl->action->act_file->fil_length : left;
|
||||
|
||||
#ifndef WIN_NT
|
||||
cnt = write(tdgbl->file_desc, ptr, nBytesToWrite);
|
||||
#else
|
||||
|
||||
DWORD ret = 0;
|
||||
if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL))
|
||||
{
|
||||
ret = GetLastError();
|
||||
}
|
||||
#endif // !WIN_NT
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
||||
if (cnt > 0)
|
||||
{
|
||||
tdgbl->mvol_cumul_count += cnt;
|
||||
file_not_empty();
|
||||
if (tdgbl->action->act_action == ACT_backup_split)
|
||||
{
|
||||
if (tdgbl->action->act_file->fil_length < left)
|
||||
tdgbl->action->act_file->fil_length = 0;
|
||||
else
|
||||
tdgbl->action->act_file->fil_length -= left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cnt ||
|
||||
#ifndef WIN_NT
|
||||
errno == ENOSPC || errno == EIO || errno == ENXIO ||
|
||||
errno == EFBIG)
|
||||
#else
|
||||
ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
|
||||
#endif // !WIN_NT
|
||||
{
|
||||
if (tdgbl->action->act_action == ACT_backup_split)
|
||||
// Write to the current file till fil_lingth > 0, otherwise
|
||||
// switch to the next one
|
||||
if (tdgbl->action->act_file->fil_length == 0)
|
||||
{
|
||||
// Close the current file and switch to the next one.
|
||||
// If there is no more specified files left then
|
||||
// issue an error and give up
|
||||
if (tdgbl->action->act_file->fil_next)
|
||||
{
|
||||
close_platf(tdgbl->file_desc);
|
||||
@ -587,89 +557,154 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
BURP_print(true, 272, SafeArg() <<
|
||||
tdgbl->action->act_file->fil_name.c_str() <<
|
||||
tdgbl->action->act_file->fil_length <<
|
||||
tdgbl->action->act_file->fil_next->fil_name.c_str());
|
||||
// msg 272 Warning -- free disk space exhausted for file %s,
|
||||
// the rest of the bytes (%d) will be written to file %s
|
||||
tdgbl->action->act_file->fil_next->fil_length +=
|
||||
tdgbl->action->act_file->fil_length;
|
||||
tdgbl->action->act_file = tdgbl->action->act_file->fil_next;
|
||||
tdgbl->file_desc = tdgbl->action->act_file->fil_fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a last file. Keep writing in a hope that there is
|
||||
// enough free disk space ...
|
||||
tdgbl->action->act_file->fil_length = MAX_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const size_t nBytesToWrite =
|
||||
(tdgbl->action->act_action == ACT_backup_split &&
|
||||
tdgbl->action->act_file->fil_length < left) ?
|
||||
tdgbl->action->act_file->fil_length : left;
|
||||
|
||||
#ifndef WIN_NT
|
||||
cnt = write(tdgbl->file_desc, ptr, nBytesToWrite);
|
||||
#else
|
||||
|
||||
DWORD ret = 0;
|
||||
if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL))
|
||||
{
|
||||
ret = GetLastError();
|
||||
}
|
||||
#endif // !WIN_NT
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
||||
if (cnt > 0)
|
||||
{
|
||||
tdgbl->mvol_cumul_count += cnt;
|
||||
file_not_empty();
|
||||
if (tdgbl->action->act_action == ACT_backup_split)
|
||||
{
|
||||
if (tdgbl->action->act_file->fil_length < left)
|
||||
tdgbl->action->act_file->fil_length = 0;
|
||||
else
|
||||
tdgbl->action->act_file->fil_length -= left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cnt ||
|
||||
#ifndef WIN_NT
|
||||
errno == ENOSPC || errno == EIO || errno == ENXIO ||
|
||||
errno == EFBIG)
|
||||
#else
|
||||
ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
|
||||
#endif // !WIN_NT
|
||||
{
|
||||
if (tdgbl->action->act_action == ACT_backup_split)
|
||||
{
|
||||
// Close the current file and switch to the next one.
|
||||
// If there is no more specified files left then
|
||||
// issue an error and give up
|
||||
if (tdgbl->action->act_file->fil_next)
|
||||
{
|
||||
close_platf(tdgbl->file_desc);
|
||||
for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next)
|
||||
{
|
||||
if (file->fil_fd == tdgbl->file_desc)
|
||||
file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE;
|
||||
BURP_print(true, 272, SafeArg() <<
|
||||
tdgbl->action->act_file->fil_name.c_str() <<
|
||||
tdgbl->action->act_file->fil_length <<
|
||||
tdgbl->action->act_file->fil_next->fil_name.c_str());
|
||||
// msg 272 Warning -- free disk space exhausted for file %s,
|
||||
// the rest of the bytes (%d) will be written to file %s
|
||||
tdgbl->action->act_file->fil_next->fil_length +=
|
||||
tdgbl->action->act_file->fil_length;
|
||||
tdgbl->action->act_file = tdgbl->action->act_file->fil_next;
|
||||
tdgbl->file_desc = tdgbl->action->act_file->fil_fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
BURP_error(270, true);
|
||||
// msg 270 free disk space exhausted
|
||||
}
|
||||
cnt = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tdgbl->uSvc->isService())
|
||||
{
|
||||
BURP_error(270, true);
|
||||
// msg 270 free disk space exhausted
|
||||
}
|
||||
cnt = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tdgbl->uSvc->isService())
|
||||
// Note: there is an assumption here, that if header data is being
|
||||
// written, it is really being rewritten, so at least all the
|
||||
// header data will be written
|
||||
|
||||
if (left != size_to_write)
|
||||
{
|
||||
// Wrote some, move remainder up in buffer.
|
||||
|
||||
// NOTE: We should NOT use memcpy here. We're moving overlapped
|
||||
// data and memcpy does not guanantee the order the data
|
||||
// is moved in
|
||||
memcpy(tdgbl->mvol_io_data, ptr, left);
|
||||
}
|
||||
left += tdgbl->mvol_io_data - tdgbl->mvol_io_header;
|
||||
bool full_buffer;
|
||||
if (left >= tdgbl->mvol_io_buffer_size)
|
||||
full_buffer = true;
|
||||
else
|
||||
full_buffer = false;
|
||||
tdgbl->file_desc = next_volume(tdgbl->file_desc, MODE_WRITE, full_buffer);
|
||||
if (full_buffer)
|
||||
{
|
||||
left -= tdgbl->mvol_io_buffer_size;
|
||||
memcpy(tdgbl->mvol_io_data,
|
||||
tdgbl->mvol_io_header + tdgbl->mvol_io_buffer_size,
|
||||
left);
|
||||
tdgbl->mvol_cumul_count += tdgbl->mvol_io_buffer_size;
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
||||
}
|
||||
else
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_header;
|
||||
break;
|
||||
}
|
||||
else if (!SYSCALL_INTERRUPTED(errno))
|
||||
{
|
||||
BURP_error(270, true);
|
||||
// msg 270 free disk space exhausted
|
||||
BURP_error_redirect(0, 221);
|
||||
// msg 221 Unexpected I/O error while writing to backup file
|
||||
}
|
||||
|
||||
// Note: there is an assumption here, that if header data is being
|
||||
// written, it is really being rewritten, so at least all the
|
||||
// header data will be written
|
||||
|
||||
if (left != size_to_write)
|
||||
{
|
||||
// Wrote some, move remainder up in buffer.
|
||||
|
||||
// NOTE: We should NOT use memcpy here. We're moving overlapped
|
||||
// data and memcpy does not guanantee the order the data
|
||||
// is moved in
|
||||
memcpy(tdgbl->mvol_io_data, ptr, left);
|
||||
}
|
||||
left += tdgbl->mvol_io_data - tdgbl->mvol_io_header;
|
||||
bool full_buffer;
|
||||
if (left >= tdgbl->mvol_io_buffer_size)
|
||||
full_buffer = true;
|
||||
else
|
||||
full_buffer = false;
|
||||
tdgbl->file_desc = next_volume(tdgbl->file_desc, MODE_WRITE, full_buffer);
|
||||
if (full_buffer)
|
||||
{
|
||||
left -= tdgbl->mvol_io_buffer_size;
|
||||
memcpy(tdgbl->mvol_io_data,
|
||||
tdgbl->mvol_io_header + tdgbl->mvol_io_buffer_size,
|
||||
left);
|
||||
tdgbl->mvol_cumul_count += tdgbl->mvol_io_buffer_size;
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
||||
}
|
||||
else
|
||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_header;
|
||||
break;
|
||||
}
|
||||
else if (!SYSCALL_INTERRUPTED(errno))
|
||||
{
|
||||
BURP_error_redirect(0, 221);
|
||||
// msg 221 Unexpected I/O error while writing to backup file
|
||||
if (left < cnt) { // this is impossible, but...
|
||||
cnt = left;
|
||||
}
|
||||
}
|
||||
if (left < cnt) { // this is impossible, but...
|
||||
cnt = left;
|
||||
}
|
||||
|
||||
} // for
|
||||
} // for
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
int dbg_cnt;
|
||||
if (debug_on)
|
||||
{
|
||||
for (dbg_cnt = 0; dbg_cnt < cnt; dbg_cnt++)
|
||||
printf("%d,\n", *(ptr + dbg_cnt));
|
||||
int dbg_cnt;
|
||||
if (debug_on)
|
||||
{
|
||||
for (dbg_cnt = 0; dbg_cnt < cnt; dbg_cnt++)
|
||||
printf("%d,\n", *(ptr + dbg_cnt));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// After the first block of first volume is written (using a default block size)
|
||||
// change the block size to one that reflects the user's blocking factor. By
|
||||
@ -1069,13 +1104,21 @@ static bool read_header(DESC handle, ULONG* buffer_size, USHORT* format, bool in
|
||||
|
||||
// Headers are a version number, and a volume number
|
||||
|
||||
if (tdgbl->stdIoMode && tdgbl->uSvc->isService())
|
||||
{
|
||||
tdgbl->uSvc->started();
|
||||
tdgbl->mvol_io_cnt = tdgbl->uSvc->getBytes(tdgbl->mvol_io_buffer, tdgbl->mvol_io_buffer_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef WIN_NT
|
||||
tdgbl->mvol_io_cnt = read(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size);
|
||||
tdgbl->mvol_io_cnt = read(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size);
|
||||
#else
|
||||
DWORD bytesRead = 0;
|
||||
ReadFile(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size, &bytesRead, NULL);
|
||||
tdgbl->mvol_io_cnt = bytesRead;
|
||||
DWORD bytesRead = 0;
|
||||
ReadFile(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size, &bytesRead, NULL);
|
||||
tdgbl->mvol_io_cnt = bytesRead;
|
||||
#endif
|
||||
}
|
||||
if (!tdgbl->mvol_io_cnt)
|
||||
BURP_error_redirect(0, 45); // maybe there's a better message
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#endif
|
||||
#include "../burp/split/spit.h"
|
||||
#include "../common/classes/Switches.h"
|
||||
#include "../burp/std_desc.h"
|
||||
#include "../burp/burpswi.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
@ -61,6 +62,53 @@ static const int mode_read = O_RDONLY;
|
||||
static const int mode_write = O_WRONLY | O_CREAT;
|
||||
static const int mask = 0666;
|
||||
|
||||
static DESC open_platf(const char* name, int writeFlag)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
return CreateFile(name, writeFlag ? GENERIC_WRITE : GENERIC_READ, 0, NULL,
|
||||
writeFlag ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
#else
|
||||
return open(name, writeFlag ? mode_write : mode_read, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int read_platf(DESC file, void* buf, int count)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
DWORD act;
|
||||
if (!ReadFile(file, buf, count, &act, NULL))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return act;
|
||||
#else
|
||||
return read(file, buf, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int write_platf(DESC file, const void* buf, int count)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
DWORD act;
|
||||
if (!WriteFile(file, buf, count, &act, NULL))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return act;
|
||||
#else
|
||||
return write(file, buf, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void close_platf(DESC file)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
CloseHandle(file);
|
||||
#else
|
||||
close(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Definitions for GSPLIT
|
||||
enum gsplit_option
|
||||
{
|
||||
@ -291,7 +339,7 @@ int main( int argc, char* argv[])
|
||||
switch (sw_replace)
|
||||
{
|
||||
case IN_SW_SPIT_SP:
|
||||
input_file_desc = GBAK_STDIN_DESC;
|
||||
input_file_desc = GBAK_STDIN_DESC();
|
||||
ret_cd = gen_multy_bakup_files(file_list, input_file_desc, file_num);
|
||||
if (ret_cd == FB_FAILURE)
|
||||
{
|
||||
@ -610,8 +658,8 @@ static int gen_multy_bakup_files(b_fil* file_list, FILE_DESC input_file_desc, SL
|
||||
file_size = fl_ptr->b_fil_size - header_rec_len;
|
||||
file_name = fl_ptr->b_fil_name;
|
||||
|
||||
output_fl_desc = open(file_name, mode_write, mask);
|
||||
if (output_fl_desc == -1)
|
||||
output_fl_desc = open_platf(file_name, 1);
|
||||
if (output_fl_desc == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
free(io_buffer);
|
||||
fprintf(stderr, "can not open back up file %s\n", file_name);
|
||||
@ -681,8 +729,8 @@ static int gen_multy_bakup_files(b_fil* file_list, FILE_DESC input_file_desc, SL
|
||||
file_size = fl_ptr->b_fil_size - header_rec_len;
|
||||
file_name = fl_ptr->b_fil_name;
|
||||
|
||||
output_fl_desc = open(file_name, mode_write, mask);
|
||||
if (output_fl_desc == -1)
|
||||
output_fl_desc = open_platf(file_name, 1);
|
||||
if (output_fl_desc == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
free(io_buffer);
|
||||
fprintf(stderr, "can not open back up file %s\n", file_name);
|
||||
@ -793,21 +841,21 @@ static int read_and_write(FILE_DESC input_file_desc,
|
||||
if (*byte_read + io_size > file_size)
|
||||
{
|
||||
last_read_size = (SLONG) (file_size - *byte_read);
|
||||
read_cnt = read(input_file_desc, *io_buffer, last_read_size);
|
||||
read_cnt = read_platf(input_file_desc, *io_buffer, last_read_size);
|
||||
}
|
||||
else
|
||||
read_cnt = read(input_file_desc, *io_buffer, io_size);
|
||||
read_cnt = read_platf(input_file_desc, *io_buffer, io_size);
|
||||
|
||||
switch (read_cnt)
|
||||
{
|
||||
case 0: // no more data to be read
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
*end_of_input = true;
|
||||
*byte_read = *byte_read + read_cnt;
|
||||
return FB_SUCCESS;
|
||||
|
||||
case -1: // read failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
fprintf(stderr, "fail to read input from stdin, errno = %d\n", errno);
|
||||
return FB_FAILURE;
|
||||
|
||||
@ -816,12 +864,12 @@ static int read_and_write(FILE_DESC input_file_desc,
|
||||
break;
|
||||
}
|
||||
|
||||
const SLONG write_cnt = write(output_fl_desc, *io_buffer, read_cnt);
|
||||
const SLONG write_cnt = write_platf(output_fl_desc, *io_buffer, read_cnt);
|
||||
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default:
|
||||
@ -829,7 +877,7 @@ static int read_and_write(FILE_DESC input_file_desc,
|
||||
return FB_SUCCESS;
|
||||
|
||||
// write less data than it reads in
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
*byte_write = write_cnt;
|
||||
return FILE_IS_FULL;
|
||||
}
|
||||
@ -858,17 +906,17 @@ static int final_read_and_write(FILE_DESC input_file_desc,
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
const SLONG read_cnt = read(input_file_desc, *io_buffer, io_size);
|
||||
const SLONG read_cnt = read_platf(input_file_desc, *io_buffer, io_size);
|
||||
|
||||
switch (read_cnt)
|
||||
{
|
||||
case 0: // no more data to be read
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
*end_of_input = true;
|
||||
return FB_SUCCESS;
|
||||
|
||||
case -1: // read failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
fprintf(stderr, "problem when reading input file, errno = %d\n", errno);
|
||||
return FB_FAILURE;
|
||||
|
||||
@ -876,12 +924,12 @@ static int final_read_and_write(FILE_DESC input_file_desc,
|
||||
break;
|
||||
}
|
||||
|
||||
const SLONG write_cnt = write(output_fl_desc, *io_buffer, read_cnt);
|
||||
const SLONG write_cnt = write_platf(output_fl_desc, *io_buffer, read_cnt);
|
||||
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default:
|
||||
@ -889,7 +937,7 @@ static int final_read_and_write(FILE_DESC input_file_desc,
|
||||
return FB_SUCCESS;
|
||||
|
||||
fprintf(stderr, "There is no enough space to write to back up file %s\n", file_name);
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -914,7 +962,7 @@ static int join_multy_bakup_files( b_fil* file_list)
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
FILE_DESC output_fl_desc = GBAK_STDOUT_DESC;
|
||||
FILE_DESC output_fl_desc = GBAK_STDOUT_DESC();
|
||||
|
||||
// See comment near the beginning of gen_multy_bakup_files() as it
|
||||
// also applies to read_and_write_for_join().
|
||||
@ -974,18 +1022,18 @@ static int read_and_write_for_join(FILE_DESC output_fl_desc,
|
||||
TEXT num_arr[5], total_arr[5];
|
||||
header_rec hdr_rec;
|
||||
|
||||
FILE_DESC input_fl_desc = open(file_name, mode_read);
|
||||
FILE_DESC input_fl_desc = open_platf(file_name, mode_read);
|
||||
|
||||
if (input_fl_desc == -1)
|
||||
if (input_fl_desc == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "can not open input file %s\n", file_name);
|
||||
return FB_FAILURE;
|
||||
}
|
||||
|
||||
int read_cnt = read(input_fl_desc, io_buffer, header_rec_len);
|
||||
int read_cnt = read_platf(input_fl_desc, io_buffer, header_rec_len);
|
||||
if (read_cnt != static_cast<int>(header_rec_len))
|
||||
{
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
fprintf(stderr, "progam fails to read gsplit header record in back-up file%s\n", file_name);
|
||||
return FB_FAILURE;
|
||||
}
|
||||
@ -994,7 +1042,7 @@ static int read_and_write_for_join(FILE_DESC output_fl_desc,
|
||||
SLONG ret_cd = strncmp(char_ptr1, header_rec_name, sizeof(hdr_rec.name) - 1);
|
||||
if (ret_cd != 0)
|
||||
{
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
fprintf(stderr, "gsplit: expected GSPLIT description record\n");
|
||||
fprintf(stderr, "gsplit: Exiting before completion due to errors\n");
|
||||
return FB_FAILURE;
|
||||
@ -1026,13 +1074,13 @@ static int read_and_write_for_join(FILE_DESC output_fl_desc,
|
||||
|
||||
if ((num_int != cnt) || (num_int > *total_int))
|
||||
{
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
fprintf(stderr, "gsplit: join backup file is out of sequence\n");
|
||||
fprintf(stderr, "gsplit: Exiting before completion due to errors\n");
|
||||
return FB_FAILURE;
|
||||
}
|
||||
|
||||
read_cnt = read(input_fl_desc, io_buffer, IO_BUFFER_SIZE);
|
||||
read_cnt = read_platf(input_fl_desc, io_buffer, IO_BUFFER_SIZE);
|
||||
|
||||
|
||||
while (true)
|
||||
@ -1040,23 +1088,23 @@ static int read_and_write_for_join(FILE_DESC output_fl_desc,
|
||||
switch (read_cnt)
|
||||
{
|
||||
case 0: // no more data to be read
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
return FB_SUCCESS;
|
||||
|
||||
case -1: // read failed
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default: // this is the last read
|
||||
break;
|
||||
}
|
||||
|
||||
SLONG write_cnt = write(output_fl_desc, io_buffer, read_cnt);
|
||||
SLONG write_cnt = write_platf(output_fl_desc, io_buffer, read_cnt);
|
||||
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(input_fl_desc);
|
||||
close_platf(input_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default:
|
||||
@ -1064,7 +1112,7 @@ static int read_and_write_for_join(FILE_DESC output_fl_desc,
|
||||
break;
|
||||
}
|
||||
|
||||
read_cnt = read(input_fl_desc, io_buffer, IO_BUFFER_SIZE);
|
||||
read_cnt = read_platf(input_fl_desc, io_buffer, IO_BUFFER_SIZE);
|
||||
|
||||
} // end of while (true) loop
|
||||
}
|
||||
@ -1150,11 +1198,11 @@ static int write_header(const b_fil* fl_ptr,
|
||||
ret_cd = set_hdr_str(header_str, file_name, pos, strlen(file_name));
|
||||
|
||||
SLONG end, indx;
|
||||
SLONG write_cnt = write(output_fl_desc, header_str, header_rec_len);
|
||||
SLONG write_cnt = write_platf(output_fl_desc, header_str, header_rec_len);
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default:
|
||||
@ -1202,14 +1250,14 @@ static int flush_io_buff(const UCHAR* remaining_io,
|
||||
SLONG write_cnt;
|
||||
|
||||
if (file_size > remaining_io_len)
|
||||
write_cnt = write(output_fl_desc, remaining_io, remaining_io_len);
|
||||
write_cnt = write_platf(output_fl_desc, remaining_io, remaining_io_len);
|
||||
else // file_size <= remaining_io_len
|
||||
write_cnt = write(output_fl_desc, remaining_io, (unsigned int) file_size);
|
||||
write_cnt = write_platf(output_fl_desc, remaining_io, (unsigned int) file_size);
|
||||
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
*flush_done = false;
|
||||
return FB_FAILURE;
|
||||
|
||||
@ -1219,7 +1267,7 @@ static int flush_io_buff(const UCHAR* remaining_io,
|
||||
else
|
||||
{
|
||||
// could not write out all remaining data
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
*flush_done = false;
|
||||
}
|
||||
*byte_write = write_cnt;
|
||||
@ -1245,18 +1293,18 @@ static int final_flush_io_buff(const UCHAR* remaining_io,
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
SLONG write_cnt = write(output_fl_desc, remaining_io, remaining_io_len);
|
||||
SLONG write_cnt = write_platf(output_fl_desc, remaining_io, remaining_io_len);
|
||||
switch (write_cnt)
|
||||
{
|
||||
case -1: // write failed
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
|
||||
default:
|
||||
if (write_cnt == remaining_io_len) // write ok
|
||||
return FB_SUCCESS;
|
||||
|
||||
close(output_fl_desc);
|
||||
close_platf(output_fl_desc);
|
||||
return FB_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,3 @@ const int MAX_NUM_OF_FILES = 9999;
|
||||
const int MIN_FILE_SIZE = M_BYTES;
|
||||
const char NEW_LINE = '\n';
|
||||
const char TERMINAL = '\0';
|
||||
|
||||
typedef int FILE_DESC;
|
||||
|
||||
const FILE_DESC GBAK_STDIN_DESC = 0; // standard input file descriptor
|
||||
const FILE_DESC GBAK_STDOUT_DESC = 1; // standard output file descriptor
|
||||
|
@ -61,4 +61,6 @@ const int INVALID_HANDLE_VALUE = -1;
|
||||
|
||||
#endif //WIN_NT
|
||||
|
||||
typedef DESC FILE_DESC;
|
||||
|
||||
#endif //GBAK_STD_DESC_H
|
||||
|
@ -137,6 +137,7 @@ public:
|
||||
virtual void putSLong(char, SLONG) { }
|
||||
virtual void putChar(char, char) { }
|
||||
virtual void putBytes(const UCHAR*, size_t) { }
|
||||
virtual ULONG getBytes(UCHAR*, ULONG) { return 0; }
|
||||
virtual void setServiceStatus(const ISC_STATUS*) { }
|
||||
virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) { }
|
||||
virtual const ISC_STATUS* getStatus() { return 0; }
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
virtual void putSLong(char, SLONG) = 0;
|
||||
virtual void putChar(char, char) = 0;
|
||||
virtual void putBytes(const UCHAR*, size_t) = 0;
|
||||
virtual ULONG getBytes(UCHAR*, ULONG) = 0;
|
||||
virtual void setServiceStatus(const ISC_STATUS*) = 0;
|
||||
virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) = 0;
|
||||
virtual const ISC_STATUS* getStatus() = 0;
|
||||
|
@ -1143,6 +1143,7 @@ bool isRunningCheck(const UCHAR* items, unsigned int length)
|
||||
case isc_info_svc_limbo_trans:
|
||||
case isc_info_svc_running:
|
||||
case isc_info_svc_get_users:
|
||||
case isc_info_svc_stdin:
|
||||
if (state == S_INF)
|
||||
{
|
||||
(Firebird::Arg::Gds(isc_random) << "Wrong info items combination").raise();
|
||||
|
@ -334,6 +334,7 @@
|
||||
#define isc_info_svc_running 67 /* Checks to see if a service is running on an attachment */
|
||||
#define isc_info_svc_get_users 68 /* Returns the user information from isc_action_svc_display_users */
|
||||
#define isc_info_svc_auth_block 69 /* Sets authentication block for service query() call */
|
||||
#define isc_info_svc_stdin 78 /* Returns maximum size of data, needed as stdin for service */
|
||||
|
||||
|
||||
/******************************************************
|
||||
|
@ -939,7 +939,7 @@ Data source : @4"}, /* eds_statement */
|
||||
{336331015, "file @1 out of sequence"}, /* gbak_file_outof_sequence */
|
||||
{336331016, "can't join -- one of the files missing"}, /* gbak_join_file_missing */
|
||||
{336331017, " standard input is not supported when using join operation"}, /* gbak_stdin_not_supptd */
|
||||
{336331018, "standard output is not supported when using split operation"}, /* gbak_stdout_not_supptd */
|
||||
{336331018, "standard output is not supported when using split operation or in verbose mode"}, /* gbak_stdout_not_supptd */
|
||||
{336331019, "backup file @1 might be corrupt"}, /* gbak_bkup_corrupt */
|
||||
{336331020, "database file specification missing"}, /* gbak_unk_db_file_spec */
|
||||
{336331021, "can't write a header record to file @1"}, /* gbak_hdr_write_failed */
|
||||
|
216
src/jrd/svc.cpp
216
src/jrd/svc.cpp
@ -119,6 +119,7 @@ const int SVC_user_none = 0;
|
||||
const int GET_LINE = 1;
|
||||
const int GET_EOF = 2;
|
||||
const int GET_BINARY = 4;
|
||||
const int GET_ONCE = 8;
|
||||
|
||||
const char* const SPB_SEC_USERNAME = "isc_spb_sec_username";
|
||||
|
||||
@ -433,6 +434,7 @@ void Service::started()
|
||||
|
||||
void Service::finish()
|
||||
{
|
||||
svc_sem_full.release();
|
||||
finish(SVC_finished);
|
||||
}
|
||||
|
||||
@ -661,7 +663,7 @@ void Service::need_admin_privs(Arg::StatusVector& status, const char* message)
|
||||
bool Service::ck_space_for_numeric(UCHAR*& info, const UCHAR* const end)
|
||||
{
|
||||
if ((info + 1 + sizeof(ULONG)) > end)
|
||||
{
|
||||
{
|
||||
if (info < end)
|
||||
*info++ = isc_info_truncated;
|
||||
return false;
|
||||
@ -706,7 +708,9 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
|
||||
svc_command_line(getPool()),
|
||||
svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remote_process(getPool()),
|
||||
svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_callback),
|
||||
svc_current_guard(NULL)
|
||||
svc_current_guard(NULL),
|
||||
svc_stdin_size_requested(0), svc_stdin_buffer(NULL), svc_stdin_size_preload(0),
|
||||
svc_stdin_preload_requested(0), svc_stdin_user_size(0)
|
||||
{
|
||||
initStatus();
|
||||
ThreadIdHolder holdId(svc_thread_strings);
|
||||
@ -1004,6 +1008,8 @@ void Service::shutdownServices()
|
||||
{
|
||||
if (all[pos]->svc_flags & SVC_thd_running)
|
||||
all[pos]->svc_detach_sem.release();
|
||||
if (all[pos]->svc_stdin_size_requested)
|
||||
all[pos]->svc_stdin_semaphore.release();
|
||||
}
|
||||
|
||||
for (pos = 0; pos < all.getCount(); )
|
||||
@ -1035,18 +1041,22 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
UCHAR item;
|
||||
UCHAR buffer[MAXPATHLEN];
|
||||
USHORT l, length, version, get_flags;
|
||||
UCHAR* stdin_request_notification = NULL;
|
||||
|
||||
ThreadIdHolder holdId(svc_thread_strings);
|
||||
|
||||
// Setup the status vector
|
||||
Arg::StatusVector status;
|
||||
|
||||
ULONG requestFromPut = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Process the send portion of the query first.
|
||||
USHORT timeout = 0;
|
||||
const UCHAR* items = send_items;
|
||||
const UCHAR* const end_items = items + send_item_length;
|
||||
|
||||
while (items < end_items && *items != isc_info_end)
|
||||
{
|
||||
switch ((item = *items++))
|
||||
@ -1064,10 +1074,10 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
switch (item)
|
||||
{
|
||||
case isc_info_svc_line:
|
||||
put(items, l);
|
||||
requestFromPut = put(items, l);
|
||||
break;
|
||||
case isc_info_svc_message:
|
||||
put(items - 3, l + 3);
|
||||
//put(items - 3, l + 3);
|
||||
break;
|
||||
case isc_info_svc_timeout:
|
||||
timeout = (USHORT) gds__vax_integer(items, l);
|
||||
@ -1311,6 +1321,21 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
} // scope
|
||||
break;
|
||||
|
||||
case isc_info_svc_stdin:
|
||||
// Check - is stdin data required for server
|
||||
if (!ck_space_for_numeric(info, end))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*info++ = item;
|
||||
if (!stdin_request_notification)
|
||||
{
|
||||
stdin_request_notification = info;
|
||||
}
|
||||
ADD_SPB_NUMERIC(info, 0);
|
||||
|
||||
break;
|
||||
|
||||
case isc_info_svc_user_dbpath:
|
||||
if (svc_user_flag & SVC_user_dba)
|
||||
{
|
||||
@ -1335,7 +1360,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
*info++ = isc_info_truncated;
|
||||
break;
|
||||
}
|
||||
put(&item, 1);
|
||||
//put(&item, 1);
|
||||
get(&item, 1, GET_BINARY, 0, &length);
|
||||
get(buffer, 2, GET_BINARY, 0, &length);
|
||||
l = (USHORT) gds__vax_integer(buffer, 2);
|
||||
@ -1380,7 +1405,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
break;
|
||||
|
||||
case isc_info_svc_total_length:
|
||||
put(&item, 1);
|
||||
//put(&item, 1);
|
||||
get(&item, 1, GET_BINARY, 0, &length);
|
||||
get(buffer, 2, GET_BINARY, 0, &length);
|
||||
l = (USHORT) gds__vax_integer(buffer, 2);
|
||||
@ -1413,6 +1438,11 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
break;
|
||||
}
|
||||
|
||||
if (requestFromPut)
|
||||
{
|
||||
get_flags |= GET_ONCE;
|
||||
}
|
||||
|
||||
get(info + 3, end - (info + 5), get_flags, timeout, &length);
|
||||
|
||||
// If the read timed out, return the data, if any, & a timeout
|
||||
@ -1428,7 +1458,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
{
|
||||
*info++ = isc_info_svc_timeout;
|
||||
}
|
||||
else
|
||||
else //if (!svc_stdin_size_requested)
|
||||
{
|
||||
if (!length && !(svc_flags & SVC_finished))
|
||||
{
|
||||
@ -1458,6 +1488,8 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
const SLONG number = info - start_info;
|
||||
fb_assert(number > 0);
|
||||
memmove(start_info + 7, start_info, number);
|
||||
if (stdin_request_notification)
|
||||
stdin_request_notification += 7;
|
||||
USHORT length2 = INF_convert(number, buffer);
|
||||
fb_assert(length2 == 4); // We only accept SLONG
|
||||
INF_put_item(isc_info_length, length2, buffer, start_info, end, true);
|
||||
@ -1470,6 +1502,23 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
|
||||
recv_item_length, recv_items, res_successful);
|
||||
}
|
||||
|
||||
if (!requestFromPut)
|
||||
{
|
||||
requestFromPut = svc_stdin_size_requested;
|
||||
}
|
||||
|
||||
if (requestFromPut)
|
||||
{
|
||||
if (stdin_request_notification)
|
||||
{
|
||||
ADD_SPB_NUMERIC(stdin_request_notification, requestFromPut);
|
||||
}
|
||||
else
|
||||
{
|
||||
(Arg::Gds(isc_random) << "No request from user for stdin data").raise();
|
||||
}
|
||||
}
|
||||
|
||||
if (status.hasData())
|
||||
{
|
||||
status.raise();
|
||||
@ -1538,10 +1587,10 @@ void Service::query(USHORT send_item_length,
|
||||
switch (item)
|
||||
{
|
||||
case isc_info_svc_line:
|
||||
put(items, l);
|
||||
//put(items, l);
|
||||
break;
|
||||
case isc_info_svc_message:
|
||||
put(items - 3, l + 3);
|
||||
//put(items - 3, l + 3);
|
||||
break;
|
||||
case isc_info_svc_timeout:
|
||||
timeout = (USHORT) gds__vax_integer(items, l);
|
||||
@ -1764,7 +1813,7 @@ void Service::query(USHORT send_item_length,
|
||||
*info++ = isc_info_truncated;
|
||||
break;
|
||||
}
|
||||
put(&item, 1);
|
||||
//put(&item, 1);
|
||||
get(&item, 1, GET_BINARY, 0, &length);
|
||||
get(buffer, 2, GET_BINARY, 0, &length);
|
||||
l = (USHORT) gds__vax_integer(buffer, 2);
|
||||
@ -1809,7 +1858,7 @@ void Service::query(USHORT send_item_length,
|
||||
break;
|
||||
|
||||
case isc_info_svc_total_length:
|
||||
put(&item, 1);
|
||||
//put(&item, 1);
|
||||
get(&item, 1, GET_BINARY, 0, &length);
|
||||
get(buffer, 2, GET_BINARY, 0, &length);
|
||||
l = (USHORT) gds__vax_integer(buffer, 2);
|
||||
@ -2181,19 +2230,29 @@ bool Service::full() const
|
||||
|
||||
void Service::enqueue(const UCHAR* s, ULONG len)
|
||||
{
|
||||
static int transferCount = 0;
|
||||
|
||||
if (checkForShutdown() || (svc_flags & SVC_detached))
|
||||
{
|
||||
svc_sem_full.release();
|
||||
return;
|
||||
}
|
||||
|
||||
while (len)
|
||||
{
|
||||
// Wait for space in buffer
|
||||
bool flagFirst = true;
|
||||
while (full())
|
||||
{
|
||||
THREAD_SLEEP(ENQUEUE_DEQUEUE_DELAY);
|
||||
if (flagFirst)
|
||||
{
|
||||
svc_sem_full.release();
|
||||
flagFirst = false;
|
||||
}
|
||||
svc_sem_empty.tryEnter(1, 0);
|
||||
if (checkForShutdown() || (svc_flags & SVC_detached))
|
||||
{
|
||||
svc_sem_full.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2211,10 +2270,12 @@ void Service::enqueue(const UCHAR* s, ULONG len)
|
||||
}
|
||||
|
||||
memcpy(&svc_stdout[svc_stdout_tail], s, cnt);
|
||||
transferCount += cnt;
|
||||
svc_stdout_tail = add_val(svc_stdout_tail, cnt);
|
||||
s += cnt;
|
||||
len -= cnt;
|
||||
}
|
||||
svc_sem_full.release();
|
||||
}
|
||||
|
||||
|
||||
@ -2235,6 +2296,7 @@ void Service::get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, US
|
||||
svc_flags &= ~SVC_timeout;
|
||||
}
|
||||
|
||||
bool flagFirst = true;
|
||||
while (length)
|
||||
{
|
||||
if ((empty() && (svc_flags & SVC_finished)) || checkForShutdown())
|
||||
@ -2244,7 +2306,24 @@ void Service::get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, US
|
||||
|
||||
if (empty())
|
||||
{
|
||||
THREAD_SLEEP(ENQUEUE_DEQUEUE_DELAY);
|
||||
if (svc_stdin_size_requested && (!(flags & GET_BINARY)))
|
||||
{
|
||||
// service needs data from user - notify him
|
||||
break;
|
||||
}
|
||||
|
||||
if (flagFirst)
|
||||
{
|
||||
svc_sem_empty.release();
|
||||
flagFirst = false;
|
||||
}
|
||||
|
||||
if (flags & GET_ONCE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
svc_sem_full.tryEnter(1, 0);
|
||||
}
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
GETTIMEOFDAY(&end_time);
|
||||
@ -2264,6 +2343,7 @@ void Service::get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, US
|
||||
|
||||
while (head != svc_stdout_tail && length > 0)
|
||||
{
|
||||
flagFirst = true;
|
||||
const UCHAR ch = svc_stdout[head];
|
||||
head = add_one(head);
|
||||
length--;
|
||||
@ -2283,12 +2363,100 @@ void Service::get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, US
|
||||
|
||||
svc_stdout_head = head;
|
||||
}
|
||||
svc_sem_empty.release();
|
||||
}
|
||||
|
||||
|
||||
void Service::put(const UCHAR* /*buffer*/, USHORT /*length*/)
|
||||
ULONG Service::put(const UCHAR* buffer, ULONG length)
|
||||
{
|
||||
// Nothing
|
||||
MutexLockGuard guard(svc_stdin_mutex);
|
||||
|
||||
// check length correctness
|
||||
if (length > svc_stdin_size_requested && length > svc_stdin_preload_requested)
|
||||
{
|
||||
(Arg::Gds(isc_random) << "Size of data is more than requested").raise();
|
||||
}
|
||||
|
||||
if (svc_stdin_size_requested) // service waits for data from us
|
||||
{
|
||||
svc_stdin_user_size = MIN(length, svc_stdin_size_requested);
|
||||
memcpy(svc_stdin_buffer, buffer, svc_stdin_user_size);
|
||||
// reset satisfied request
|
||||
ULONG blockSize = svc_stdin_size_requested;
|
||||
svc_stdin_size_requested = 0;
|
||||
// let data be used
|
||||
svc_stdin_semaphore.release();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// reset used block of data
|
||||
length -= svc_stdin_user_size;
|
||||
buffer += svc_stdin_user_size;
|
||||
|
||||
if (length == 0) // ask user to preload next block of data
|
||||
{
|
||||
if (!svc_stdin_preload)
|
||||
{
|
||||
svc_stdin_preload.reset(FB_NEW(getPool()) UCHAR[PRELOAD_BUFFER_SIZE]);
|
||||
}
|
||||
|
||||
svc_stdin_preload_requested = MIN(blockSize, PRELOAD_BUFFER_SIZE);
|
||||
return svc_stdin_preload_requested;
|
||||
}
|
||||
}
|
||||
|
||||
// Store data in preload buffer
|
||||
fb_assert(length <= PRELOAD_BUFFER_SIZE);
|
||||
fb_assert(length <= svc_stdin_preload_requested);
|
||||
fb_assert(svc_stdin_size_preload == 0);
|
||||
|
||||
memcpy(svc_stdin_preload, buffer, length);
|
||||
svc_stdin_size_preload = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ULONG Service::getBytes(UCHAR* buffer, ULONG size)
|
||||
{
|
||||
{ // Guard scope
|
||||
MutexLockGuard guard(svc_stdin_mutex);
|
||||
|
||||
if (svc_flags & SVC_detached) // no more data for this service please
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svc_stdin_size_preload != 0) // use data, preloaded by user
|
||||
{
|
||||
// Use data from preload buffer
|
||||
size = MIN(size, svc_stdin_size_preload);
|
||||
memcpy(buffer, svc_stdin_preload, size);
|
||||
if (size < svc_stdin_size_preload)
|
||||
{
|
||||
// not good, client should not request so small block
|
||||
svc_stdin_size_preload -= size;
|
||||
memmove(svc_stdin_preload, svc_stdin_preload + size, svc_stdin_size_preload);
|
||||
}
|
||||
else
|
||||
{
|
||||
svc_stdin_size_preload = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Request new data portion
|
||||
svc_stdin_size_requested = size;
|
||||
svc_stdin_buffer = buffer;
|
||||
// Wakeup Service::query() if it waits for data from service
|
||||
svc_sem_full.release();
|
||||
}
|
||||
|
||||
// Wait for data from client
|
||||
svc_stdin_semaphore.enter();
|
||||
return svc_stdin_user_size;
|
||||
}
|
||||
|
||||
|
||||
@ -2308,8 +2476,26 @@ void Service::finish(USHORT flag)
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
if (svc_flags & SVC_detached)
|
||||
{
|
||||
svc_sem_empty.release();
|
||||
|
||||
// if service waits for data from us - return EOF
|
||||
{ // guard scope
|
||||
MutexLockGuard guard(svc_stdin_mutex);
|
||||
|
||||
if (svc_stdin_size_requested)
|
||||
{
|
||||
svc_stdin_user_size = 0;
|
||||
svc_stdin_semaphore.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (svc_flags & SVC_finished)
|
||||
{
|
||||
svc_sem_full.release();
|
||||
svc_flags &= ~SVC_thd_running;
|
||||
}
|
||||
else
|
||||
|
@ -38,6 +38,17 @@
|
||||
#include "../common/UtilSvc.h"
|
||||
#include "../common/classes/Switches.h"
|
||||
#include "../common/classes/ClumpletReader.h"
|
||||
#include "../burp/split/spit.h"
|
||||
|
||||
#ifndef IO_BUFFER_SIZE
|
||||
#ifdef BUFSIZ
|
||||
const int SVC_IO_BUFFER_SIZE = (16 * (BUFSIZ));
|
||||
#else // BUFSIZ
|
||||
const int SVC_IO_BUFFER_SIZE = (16 * (1024));
|
||||
#endif // BUFSIZ
|
||||
#else // IO_BUFFER_SIZE
|
||||
const int SVC_IO_BUFFER_SIZE = (16 * (IO_BUFFER_SIZE));
|
||||
#endif // IO_BUFFER_SIZE
|
||||
|
||||
// forward decl.
|
||||
|
||||
@ -121,6 +132,8 @@ public: // utilities interface with service
|
||||
virtual void putChar(char tag, char val);
|
||||
// put raw bytes to svc_stdout
|
||||
virtual void putBytes(const UCHAR*, size_t);
|
||||
// get raw bytes from svc_stdin
|
||||
virtual ULONG getBytes(UCHAR*, ULONG);
|
||||
// append status_vector to service's status
|
||||
virtual void setServiceStatus(const ISC_STATUS* status_vector);
|
||||
// append error message to service's status
|
||||
@ -218,8 +231,9 @@ private:
|
||||
bool checkForShutdown();
|
||||
// Transfer data from svc_stdout into buffer
|
||||
void get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, USHORT* return_length);
|
||||
// Designed to send output to a service - does nothing.
|
||||
void put(const UCHAR* buffer, USHORT length);
|
||||
// Sends stdin for a service
|
||||
// Returns number of bytes service wants more
|
||||
ULONG put(const UCHAR* buffer, ULONG length);
|
||||
|
||||
// Increment circular buffer pointer
|
||||
static ULONG add_one(ULONG i);
|
||||
@ -301,6 +315,8 @@ public:
|
||||
private:
|
||||
StatusStringsHelper svc_thread_strings;
|
||||
|
||||
Firebird::Semaphore svc_sem_empty, svc_sem_full;
|
||||
|
||||
//Service existence guard
|
||||
class ExistenceGuard
|
||||
{
|
||||
@ -318,6 +334,23 @@ private:
|
||||
|
||||
Firebird::Mutex svc_existence_lock;
|
||||
ExistenceGuard* svc_current_guard;
|
||||
|
||||
// Data pipe from client to service
|
||||
Firebird::Semaphore svc_stdin_semaphore;
|
||||
Firebird::Mutex svc_stdin_mutex;
|
||||
// Size of data, requested by service (set in getBytes, reset in put)
|
||||
ULONG svc_stdin_size_requested;
|
||||
// Buffer passed by service
|
||||
UCHAR* svc_stdin_buffer;
|
||||
// Size of data, preloaded by user (set in put, reset in getBytes)
|
||||
ULONG svc_stdin_size_preload;
|
||||
// Buffer for datam preloaded by user
|
||||
Firebird::AutoPtr<UCHAR> svc_stdin_preload;
|
||||
// Size of data, requested from user to preload (set in getBytes)
|
||||
ULONG svc_stdin_preload_requested;
|
||||
// Size of data, placed into svc_stdin_buffer (set in put)
|
||||
ULONG svc_stdin_user_size;
|
||||
static const ULONG PRELOAD_BUFFER_SIZE = SVC_IO_BUFFER_SIZE;
|
||||
};
|
||||
|
||||
} //namespace Jrd
|
||||
|
@ -2144,7 +2144,7 @@ ERROR: Backup incomplete', NULL, NULL);
|
||||
('gbak_file_outof_sequence', 'open_files', 'burp.c', NULL, 12, 263, NULL, 'file @1 out of sequence', NULL, NULL);
|
||||
('gbak_join_file_missing', 'open_files', 'burp.c', NULL, 12, 264, NULL, 'can''t join -- one of the files missing', NULL, NULL);
|
||||
('gbak_stdin_not_supptd', 'open_files', 'burp.c', NULL, 12, 265, NULL, ' standard input is not supported when using join operation', NULL, NULL);
|
||||
('gbak_stdout_not_supptd', 'open_files', 'burp.c', NULL, 12, 266, NULL, 'standard output is not supported when using split operation', NULL, NULL);
|
||||
('gbak_stdout_not_supptd', 'open_files', 'burp.c', NULL, 12, 266, NULL, 'standard output is not supported when using split operation or in verbose mode', NULL, NULL);
|
||||
('gbak_bkup_corrupt', 'open_files', 'burp.c', NULL, 12, 267, NULL, 'backup file @1 might be corrupt', NULL, NULL);
|
||||
('gbak_unk_db_file_spec', 'open_files', 'burp.c', NULL, 12, 268, NULL, 'database file specification missing', NULL, NULL);
|
||||
('gbak_hdr_write_failed', 'MVOL_init_write', 'mvol.c', NULL, 12, 269, NULL, 'can''t write a header record to file @1', NULL, NULL);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../common/classes/MsgPrint.h"
|
||||
#include "../jrd/license.h"
|
||||
#include "../burp/std_desc.h"
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
@ -481,7 +482,7 @@ const SvcSwitches traceChgStateOptions[] =
|
||||
|
||||
const SvcSwitches actionSwitch[] =
|
||||
{
|
||||
{"action_backup", putSingleTag, backupOptions, isc_action_svc_backup, isc_info_svc_line},
|
||||
{"action_backup", putSingleTag, backupOptions, isc_action_svc_backup, isc_info_svc_to_eof},
|
||||
{"action_restore", putSingleTag, restoreOptions, isc_action_svc_restore, isc_info_svc_line},
|
||||
{"action_properties", putSingleTag, propertiesOptions, isc_action_svc_properties, 0},
|
||||
{"action_repair", putSingleTag, repairOptions, isc_action_svc_repair, 0},
|
||||
@ -533,9 +534,23 @@ bool printLine(const char*& p)
|
||||
|
||||
bool printData(const char*& p)
|
||||
{
|
||||
static DESC binout = INVALID_HANDLE_VALUE;
|
||||
if (binout == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
binout = GBAK_STDOUT_DESC();
|
||||
}
|
||||
|
||||
string s;
|
||||
bool rc = getLine(s, p);
|
||||
printf ("%s", s.c_str());
|
||||
if (rc)
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
DWORD cnt;
|
||||
WriteFile(binout, s.c_str(), s.length(), &cnt, NULL);
|
||||
#else
|
||||
write(binout, s.c_str(), s.length());
|
||||
#endif
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -615,12 +630,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool printInfo(const char* p, UserPrint& up)
|
||||
bool printInfo(const char* p, size_t pSize, UserPrint& up, ULONG& stdinRq)
|
||||
{
|
||||
bool ret = false;
|
||||
bool ignoreTruncation = false;
|
||||
stdinRq = 0;
|
||||
const char* const end = p + pSize;
|
||||
|
||||
while (*p != isc_info_end)
|
||||
while (p < end && *p != isc_info_end)
|
||||
{
|
||||
switch (*p++)
|
||||
{
|
||||
@ -775,9 +792,10 @@ bool printInfo(const char* p, UserPrint& up)
|
||||
case isc_info_truncated:
|
||||
if (!ignoreTruncation)
|
||||
{
|
||||
printf("%s\n", getMessage(18).c_str());
|
||||
return false;
|
||||
printf("\n%s\n", getMessage(18).c_str());
|
||||
}
|
||||
fflush(stdout);
|
||||
ret = true;
|
||||
break;
|
||||
|
||||
case isc_info_svc_timeout:
|
||||
@ -785,12 +803,24 @@ bool printInfo(const char* p, UserPrint& up)
|
||||
ret = true;
|
||||
break;
|
||||
|
||||
case isc_info_svc_stdin:
|
||||
stdinRq = getNumeric(p);
|
||||
if (stdinRq > 0)
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
status_exception::raise(Arg::Gds(isc_fbsvcmgr_query_err) <<
|
||||
Arg::Num(static_cast<unsigned char>(p[-1])));
|
||||
#ifdef DEV_BUILD
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -968,6 +998,8 @@ int main(int ac, char** av)
|
||||
|
||||
if (spbItems.getBufferLength() > 0)
|
||||
{
|
||||
spbItems.insertTag(isc_info_svc_stdin);
|
||||
|
||||
// use one second timeout to poll service
|
||||
char send[16];
|
||||
char* p = send;
|
||||
@ -977,10 +1009,53 @@ int main(int ac, char** av)
|
||||
*p++ = isc_info_end;
|
||||
|
||||
char results[maxbuf];
|
||||
UserPrint up;
|
||||
UserPrint uPrint;
|
||||
ULONG stdinRequest = 0;
|
||||
Array<char> stdinBuffer;
|
||||
do
|
||||
{
|
||||
if (isc_service_query(status, &svc_handle, 0, p - send, send,
|
||||
char *sendBlock = send;
|
||||
USHORT sendSize = p - send;
|
||||
if (stdinRequest)
|
||||
{
|
||||
--sendSize;
|
||||
size_t len = sendSize;
|
||||
len += (1 + 2 + stdinRequest);
|
||||
if (len > MAX_USHORT - 1)
|
||||
{
|
||||
len = MAX_USHORT - 1;
|
||||
stdinRequest = len - (1 + 2) - sendSize;
|
||||
}
|
||||
sendBlock = stdinBuffer.getBuffer(len + 1);
|
||||
memcpy(sendBlock, send, sendSize);
|
||||
|
||||
static DESC binIn = INVALID_HANDLE_VALUE;
|
||||
if (binIn == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
binIn = GBAK_STDIN_DESC();
|
||||
}
|
||||
|
||||
#ifdef WIN_NT
|
||||
DWORD n;
|
||||
if (!ReadFile(binIn, &sendBlock[sendSize + 1 + 2], stdinRequest, &n, NULL))
|
||||
#else
|
||||
int n = read(binIn, &sendBlock[sendSize + 1 + 2], stdinRequest);
|
||||
if (n < 0)
|
||||
#endif
|
||||
{
|
||||
perror("stdin");
|
||||
break;
|
||||
}
|
||||
stdinRequest = n;
|
||||
sendBlock[sendSize] = isc_info_svc_line;
|
||||
sendBlock[sendSize + 1] = stdinRequest;
|
||||
sendBlock[sendSize + 2] = stdinRequest >> 8;
|
||||
sendBlock [sendSize + 1 + 2 + stdinRequest] = isc_info_end;
|
||||
sendSize += (1 + 2 + stdinRequest + 1);
|
||||
|
||||
stdinRequest = 0;
|
||||
}
|
||||
if (isc_service_query(status, &svc_handle, 0, sendSize, sendBlock,
|
||||
static_cast<USHORT>(spbItems.getBufferLength()),
|
||||
reinterpret_cast<const char*>(spbItems.getBuffer()),
|
||||
sizeof(results), results))
|
||||
@ -989,10 +1064,14 @@ int main(int ac, char** av)
|
||||
isc_service_detach(status, &svc_handle);
|
||||
return 1;
|
||||
}
|
||||
} while (printInfo(results, up) && !terminated);
|
||||
} while (printInfo(results, sizeof(results), uPrint, stdinRequest) && !terminated);
|
||||
}
|
||||
|
||||
isc_service_detach(status, &svc_handle);
|
||||
if (isc_service_detach(status, &svc_handle))
|
||||
{
|
||||
isc_print_status(status);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch (const Exception& e)
|
||||
|
@ -903,12 +903,18 @@ void TracePluginImpl::appendServiceQueryParams(size_t send_item_length,
|
||||
case isc_info_svc_to_eof:
|
||||
recv_query.printf(NEWLINE "\t\t retrieve as much of the server output as will fit in the supplied buffer");
|
||||
break;
|
||||
|
||||
case isc_info_svc_limbo_trans:
|
||||
recv_query.printf(NEWLINE "\t\t retrieve the limbo transactions");
|
||||
break;
|
||||
|
||||
case isc_info_svc_get_users:
|
||||
recv_query.printf(NEWLINE "\t\t retrieve the user information");
|
||||
break;
|
||||
|
||||
case isc_info_svc_stdin:
|
||||
recv_query.printf(NEWLINE "\t\t retrieve the size of data to send to the server");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user