8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 06:03:02 +01:00
firebird-mirror/src/burp/burp.cpp

2334 lines
58 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Backup and Restore Program
* MODULE: burp.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Command line interpreter for backup/restore
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
* conditionals, as the engine now fully supports
* readonly databases.
2002-02-16 03:21:35 +01:00
*
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "EPSON" defines
*
2002-10-30 07:40:58 +01:00
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
#include "memory_routines.h"
2004-04-29 00:00:03 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "../common/common.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ibase.h"
#include <stdarg.h>
#include "../jrd/ibsetjmp.h"
#include "../jrd/msg_encode.h"
#include "../jrd/ods.h" // to get MAX_PAGE_SIZE
2004-05-03 23:43:56 +02:00
#include "../jrd/svc.h"
2008-01-16 07:11:50 +01:00
#include "../jrd/constants.h"
2001-05-23 15:26:42 +02:00
#include "../burp/burp.h"
#include "../burp/std_desc.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/license.h"
#include "../common/classes/timestamp.h"
2001-05-23 15:26:42 +02:00
#include "../burp/burp_proto.h"
#include "../burp/backu_proto.h"
#include "../burp/mvol_proto.h"
#include "../burp/resto_proto.h"
2010-10-12 10:02:57 +02:00
#include "../yvalve/gds_proto.h"
#include "../common/gdsassert.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/Switches.h"
#include "../burp/burpswi.h"
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include "../common/utils_proto.h"
#ifdef HAVE_UNISTD_H
2001-05-23 15:26:42 +02:00
#include <unistd.h>
#endif
#include <fcntl.h>
#ifdef HAVE_IO_H
#include <io.h>
#endif
2001-05-23 15:26:42 +02:00
#ifndef O_CREAT
#include <sys/types.h>
#include <sys/file.h>
#endif
using MsgFormat::SafeArg;
const char* fopen_write_type = "w";
const char* fopen_read_type = "r";
2001-05-23 15:26:42 +02:00
2008-05-23 15:27:47 +02:00
const int open_mask = 0666;
const char switch_char = '-';
2001-05-23 15:26:42 +02:00
const char* const output_suppress = "SUPPRESS";
const int burp_msg_fac = 12;
2009-11-06 06:26:54 +01:00
const int MIN_VERBOSE_INTERVAL = 100;
2001-05-23 15:26:42 +02:00
enum gbak_action
{
QUIT = 0,
BACKUP = 1 ,
RESTORE = 2
//FDESC = 3 // CVC: Unused
};
static void close_out_transaction(gbak_action, isc_tr_handle*);
2009-01-03 10:14:29 +01:00
//static void enable_signals();
//static void excp_handler();
2004-01-13 10:52:19 +01:00
static SLONG get_number(const SCHAR*);
static ULONG get_size(const SCHAR*, burp_fil*);
static gbak_action open_files(const TEXT *, const TEXT**, bool, USHORT,
const Firebird::ClumpletWriter&);
static int api_gbak(Firebird::UtilSvc*, const Switches& switches);
static void burp_output(bool err, const SCHAR*, ...) ATTRIBUTE_FORMAT(2,3);
static void burp_usage(const Switches& switches);
static Switches::in_sw_tab_t* findSwitchOrThrow(Switches& switches, Firebird::string& sw);
2001-05-23 15:26:42 +02:00
// fil.fil_length is ULONG
const ULONG KBYTE = 1024;
const ULONG MBYTE = KBYTE * KBYTE;
const ULONG GBYTE = MBYTE * KBYTE;
2001-05-23 15:26:42 +02:00
THREAD_ENTRY_DECLARE BURP_main(THREAD_ENTRY_PARAM arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ m a i n
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Entrypoint for GBAK via services manager.
2001-05-23 15:26:42 +02:00
*
**************************************/
2008-01-16 07:11:50 +01:00
Firebird::UtilSvc* uSvc = (Firebird::UtilSvc*) arg;
int exit_code = FINI_OK;
2001-05-23 15:26:42 +02:00
try {
exit_code = gbak(uSvc);
}
catch (const Firebird::Exception& e)
{
ISC_STATUS_ARRAY status;
e.stuff_exception(status);
uSvc->initStatus();
uSvc->setServiceStatus(status);
exit_code = FB_FAILURE;
}
2001-05-23 15:26:42 +02:00
uSvc->finish();
2008-01-16 07:11:50 +01:00
return (THREAD_ENTRY_RETURN)(IPTR) exit_code;
2001-05-23 15:26:42 +02:00
}
static int api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches)
2001-05-23 15:26:42 +02:00
{
2008-01-16 07:11:50 +01:00
/**********************************************
2001-05-23 15:26:42 +02:00
*
2008-01-16 07:11:50 +01:00
* a p i _ g b a k
2001-05-23 15:26:42 +02:00
*
2008-01-16 07:11:50 +01:00
**********************************************
2001-05-23 15:26:42 +02:00
*
* Functional description
2008-01-16 07:11:50 +01:00
* Run gbak using services APIs
2001-05-23 15:26:42 +02:00
*
2008-01-16 07:11:50 +01:00
**********************************************/
Firebird::string usr, pswd, service;
bool flag_restore = false;
bool flag_verbose = false;
#ifdef TRUSTED_AUTH
bool flag_trusted = false;
#endif
bool flag_verbint = false;
ULONG verbint_val = 0;
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
Firebird::UtilSvc::ArgvType& argv = uSvc->argv;
const int argc = uSvc->argv.getCount();
2009-06-27 08:23:36 +02:00
for (int itr = 1; itr < argc; ++itr)
2008-01-16 07:11:50 +01:00
{
const Switches::in_sw_tab_t* inSw = switches.findSwitch(argv[itr]);
2008-01-16 07:11:50 +01:00
if (! inSw)
2001-05-23 15:26:42 +02:00
{
2008-01-16 07:11:50 +01:00
continue;
2001-05-23 15:26:42 +02:00
}
2008-01-16 07:11:50 +01:00
switch (inSw->in_sw)
2001-05-23 15:26:42 +02:00
{
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_C: // create database
case IN_SW_BURP_R: // replace database
case IN_SW_BURP_RECREATE: // recreate database
2003-09-10 19:52:12 +02:00
flag_restore = true;
2001-05-23 15:26:42 +02:00
break;
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_USER: // default user name
case IN_SW_BURP_PASS: // default password
case IN_SW_BURP_SE: // service name
2008-01-16 07:11:50 +01:00
if (itr >= argc - 1)
{
int errnum = inSw->in_sw == IN_SW_BURP_USER ? 188 : // user name parameter missing
inSw->in_sw == IN_SW_BURP_PASS ? 189 : // password parameter missing
273; // service name parameter missing
BURP_error(errnum, true);
2003-12-22 11:00:59 +01:00
}
2008-12-01 10:21:31 +01:00
else
2008-01-16 07:11:50 +01:00
{
argv[itr++] = 0;
2008-12-02 08:09:49 +01:00
switch (inSw->in_sw)
2008-01-16 07:11:50 +01:00
{
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_USER: // default user name
2008-01-16 07:11:50 +01:00
usr = argv[itr];
break;
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_PASS: // default password
2008-01-16 07:11:50 +01:00
pswd = argv[itr];
uSvc->hidePasswd(argv, itr);
break;
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_SE: // service name
2008-01-16 07:11:50 +01:00
service = argv[itr];
break;
}
argv[itr] = 0;
2001-05-23 15:26:42 +02:00
}
break;
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_V: // verify actions
if (flag_verbint)
BURP_error(329, true); // verify (verbose) and verbint options are mutually exclusive
2003-09-10 19:52:12 +02:00
flag_verbose = true;
2001-05-23 15:26:42 +02:00
break;
case IN_SW_BURP_VERBINT: // verify with explicit reporting interval for records
if (flag_verbose)
BURP_error(329, true); // verify (verbose) and verbint options are mutually exclusive
if (flag_verbint)
BURP_error(333, true, SafeArg() << inSw->in_sw_name << verbint_val);
if (itr >= argc - 1)
BURP_error(326, true); // verbose interval value parameter missing
argv[itr++] = 0;
verbint_val = get_number(argv[itr]);
2009-11-06 06:26:54 +01:00
if (verbint_val < MIN_VERBOSE_INTERVAL)
{
// verbose interval value cannot be smaller than @1
BURP_error(327, true, SafeArg() << MIN_VERBOSE_INTERVAL);
}
flag_verbint = true;
argv[itr] = 0;
break;
#ifdef TRUSTED_AUTH
case IN_SW_BURP_TRUSTED_AUTH: // use trusted auth
flag_trusted = true;
2008-01-16 07:11:50 +01:00
argv[itr] = 0;
break;
#endif
2001-05-23 15:26:42 +02:00
}
}
2008-01-16 07:11:50 +01:00
if (usr.isEmpty())
2001-05-23 15:26:42 +02:00
{
2008-01-16 07:11:50 +01:00
#ifdef TRUSTED_AUTH
if (!flag_trusted)
#endif
{
fb_utils::readenv(ISC_USER, usr);
}
}
2008-01-16 07:11:50 +01:00
if (pswd.isEmpty())
{
2008-01-16 07:11:50 +01:00
#ifdef TRUSTED_AUTH
if (!flag_trusted)
#endif
{
fb_utils::readenv(ISC_PASSWORD, pswd);
}
}
2003-12-22 11:00:59 +01:00
ISC_STATUS_ARRAY status;
2007-05-08 17:13:57 +02:00
FB_API_HANDLE svc_handle = 0;
2008-12-01 10:21:31 +01:00
2007-05-08 17:13:57 +02:00
try
{
2007-05-08 17:13:57 +02:00
Firebird::ClumpletWriter spb(Firebird::ClumpletWriter::SpbAttach, 4096, isc_spb_current_version);
2009-04-17 16:10:11 +02:00
// isc_spb_user_name
// isc_spb_password
// isc_spb_trusted_auth
// isc_spb_options
2007-05-08 17:13:57 +02:00
2008-12-01 10:21:31 +01:00
if (usr.hasData())
2007-05-08 17:13:57 +02:00
{
spb.insertString(isc_spb_user_name, usr);
}
2008-12-01 10:21:31 +01:00
if (pswd.hasData())
2007-05-08 17:13:57 +02:00
{
spb.insertString(isc_spb_password, pswd);
}
2008-01-16 07:11:50 +01:00
#ifdef TRUSTED_AUTH
if (flag_trusted)
2007-05-08 17:13:57 +02:00
{
spb.insertTag(isc_spb_trusted_auth);
}
#endif
2008-12-01 10:21:31 +01:00
// Fill command line options
2007-05-08 17:13:57 +02:00
Firebird::string options;
2009-06-27 08:23:36 +02:00
for (int itr = 1; itr < argc; ++itr)
2007-05-08 17:13:57 +02:00
{
2008-01-16 07:11:50 +01:00
if (!argv[itr])
{
continue;
}
Firebird::UtilSvc::addStringWithSvcTrmntr(argv[itr], options);
2007-05-08 17:13:57 +02:00
}
options.rtrim();
2007-05-08 17:13:57 +02:00
spb.insertString(isc_spb_command_line, options);
2008-12-01 10:21:31 +01:00
if (isc_service_attach(status, 0, service.c_str(), &svc_handle,
2007-05-08 17:13:57 +02:00
spb.getBufferLength(), reinterpret_cast<const char*>(spb.getBuffer())))
{
BURP_print_status(status);
BURP_print(true, 83);
2008-12-01 10:21:31 +01:00
// msg 83 Exiting before completion due to errors
2007-05-08 17:13:57 +02:00
return FINI_ERROR;
}
char thd[10];
2007-05-08 17:13:57 +02:00
// 'isc_action_svc_restore/isc_action_svc_backup'
// 'isc_spb_verbose'
// 'isc_spb_verbint'
char* thd_ptr = thd;
2008-01-16 07:11:50 +01:00
if (flag_restore)
2007-05-08 17:13:57 +02:00
*thd_ptr++ = isc_action_svc_restore;
else
*thd_ptr++ = isc_action_svc_backup;
2008-01-16 07:11:50 +01:00
if (flag_verbose)
2007-05-08 17:13:57 +02:00
*thd_ptr++ = isc_spb_verbose;
if (flag_verbint)
{
*thd_ptr++ = isc_spb_verbint;
//stream verbint_val into a SPB
put_vax_long(reinterpret_cast<UCHAR*>(thd_ptr), verbint_val);
thd_ptr += sizeof(SLONG);
}
const USHORT thdlen = thd_ptr - thd;
fb_assert(thdlen <= sizeof(thd));
2007-05-08 17:13:57 +02:00
if (isc_service_start(status, &svc_handle, NULL, thdlen, thd))
{
BURP_print_status(status);
isc_service_detach(status, &svc_handle);
BURP_print(true, 83); // msg 83 Exiting before completion due to errors
return FINI_ERROR;
}
2007-05-08 17:13:57 +02:00
const char sendbuf[] = { isc_info_svc_line };
char respbuf[1024];
const char* sl;
do {
if (isc_service_query(status, &svc_handle, NULL, 0, NULL,
sizeof(sendbuf), sendbuf,
sizeof(respbuf), respbuf))
{
BURP_print_status(status);
isc_service_detach(status, &svc_handle);
BURP_print(true, 83); // msg 83 Exiting before completion due to errors
2007-05-08 17:13:57 +02:00
return FINI_ERROR;
}
2007-05-08 17:13:57 +02:00
char* p = respbuf;
sl = p;
2008-01-16 07:11:50 +01:00
if (*p++ == isc_info_svc_line)
{
2007-05-08 17:13:57 +02:00
const ISC_USHORT len = (ISC_USHORT) isc_vax_integer(p, sizeof(ISC_USHORT));
p += sizeof(ISC_USHORT);
if (!len)
{
if (*p == isc_info_data_not_ready)
continue;
if (*p == isc_info_end)
2007-05-08 17:13:57 +02:00
break;
}
2009-06-25 12:50:11 +02:00
fb_assert(p + len < respbuf + sizeof(respbuf));
2007-05-08 17:13:57 +02:00
p[len] = '\0';
burp_output(false, "%s\n", p);
}
2007-05-08 17:13:57 +02:00
} while (*sl == isc_info_svc_line);
2007-05-08 17:13:57 +02:00
isc_service_detach(status, &svc_handle);
return FINI_OK;
}
2007-05-09 04:03:49 +02:00
catch (const Firebird::Exception& e)
2007-05-08 17:13:57 +02:00
{
e.stuff_exception(status);
BURP_print_status(status);
if (svc_handle)
{
isc_service_detach(status, &svc_handle);
}
BURP_print(true, 83); // msg 83 Exiting before completion due to errors
2007-05-08 17:13:57 +02:00
return FINI_ERROR;
}
}
static Switches::in_sw_tab_t* findSwitchOrThrow(Switches& switches, Firebird::string& sw)
2008-01-16 07:11:50 +01:00
{
/**************************************
*
* f i n d S w i t c h O r T h r o w
2008-01-16 07:11:50 +01:00
*
**************************************
*
* Functional description
* Returns pointer to in_sw_tab entry for current switch
* If not a switch, returns 0.
* If no match, throws.
2008-01-16 07:11:50 +01:00
*
**************************************/
bool invalid = false;
Switches::in_sw_tab_t* rc = switches.findSwitchMod(sw, &invalid);
if (rc)
return rc;
2008-01-16 07:11:50 +01:00
if (invalid)
2008-01-16 07:11:50 +01:00
{
BURP_print(true, 137, sw.c_str());
2008-12-01 10:21:31 +01:00
// msg 137 unknown switch %s
burp_usage(switches);
2008-01-16 07:11:50 +01:00
BURP_error(1, true);
// msg 1: found unknown switch
}
2009-11-06 02:21:14 +01:00
return NULL;
2008-01-16 07:11:50 +01:00
}
int gbak(Firebird::UtilSvc* uSvc)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g b a k
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-01-16 07:11:50 +01:00
* Routine called by command line utility and services API.
2001-05-23 15:26:42 +02:00
*
**************************************/
gbak_action action = QUIT;
2008-01-16 07:11:50 +01:00
int exit_code = FINI_ERROR;
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
BurpGlobals sgbl(uSvc);
BurpGlobals *tdgbl = &sgbl;
BurpGlobals::putSpecific(tdgbl);
2008-01-16 07:11:50 +01:00
tdgbl->burp_throw = true;
2001-05-23 15:26:42 +02:00
tdgbl->file_desc = INVALID_HANDLE_VALUE;
2008-01-16 07:11:50 +01:00
Firebird::UtilSvc::ArgvType& argv = uSvc->argv;
2008-04-21 14:14:16 +02:00
const int argc = uSvc->argv.getCount();
2001-05-23 15:26:42 +02:00
try
2008-01-16 07:11:50 +01:00
{
// Copy the static const table to a local array for processing.
Switches switches(reference_burp_in_sw_table, FB_NELEM(reference_burp_in_sw_table), true, true);
2001-05-23 15:26:42 +02:00
// test for "-service" switch
if (switches.exists(IN_SW_BURP_SE, argv.begin(), 1, argc))
return api_gbak(uSvc, switches);
uSvc->started();
2001-05-23 15:26:42 +02:00
2009-11-06 11:47:32 +01:00
if (argc <= 1)
{
burp_usage(switches);
BURP_exit_local(FINI_ERROR, tdgbl);
}
2001-05-23 15:26:42 +02:00
if (argc == 2 && strcmp(argv[1], "-?") == 0)
{
burp_usage(switches);
BURP_exit_local(FINI_OK, tdgbl);
}
USHORT sw_replace = 0;
2001-05-23 15:26:42 +02:00
2004-01-13 10:52:19 +01:00
tdgbl->gbl_sw_compress = true;
tdgbl->gbl_sw_convert_ext_tables = false;
tdgbl->gbl_sw_transportable = true;
tdgbl->gbl_sw_ignore_limbo = false;
2001-05-23 15:26:42 +02:00
tdgbl->gbl_sw_blk_factor = 0;
2004-01-13 10:52:19 +01:00
tdgbl->gbl_sw_no_reserve = false;
tdgbl->gbl_sw_old_descriptions = false;
tdgbl->gbl_sw_mode = false;
2001-05-23 15:26:42 +02:00
tdgbl->gbl_sw_skip_count = 0;
tdgbl->action = NULL;
2004-01-13 10:52:19 +01:00
burp_fil* file = NULL;
burp_fil* file_list = NULL;
2001-05-23 15:26:42 +02:00
tdgbl->io_buffer_size = GBAK_IO_BUFFER_SIZE;
2008-12-01 10:21:31 +01:00
const char none[] = "-*NONE*";
bool verbint = false;
bool noGarbage = false, ignoreDamaged = false, noDbTrig = false;
bool transportableMentioned = false;
2008-12-01 10:21:31 +01:00
2008-01-16 07:11:50 +01:00
for (int itr = 1; itr < argc; ++itr)
{
Firebird::string str = argv[itr];
if (str.isEmpty())
{
continue;
}
if (str[str.length() - 1] == ',')
{
str.erase(str.length() - 1, 1);
// Let's ignore single comma
if (str.isEmpty())
continue;
2008-01-16 07:11:50 +01:00
}
2001-05-23 15:26:42 +02:00
2008-05-23 15:27:47 +02:00
if (str[0] != switch_char)
2008-01-16 07:11:50 +01:00
{
2008-12-01 10:21:31 +01:00
if (!file || file->fil_length || !get_size(argv[itr], file))
2008-01-16 07:11:50 +01:00
{
2009-04-17 16:10:11 +02:00
// Miserable thing must be a filename
// (dummy in a length for the backup file
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
file = FB_NEW(*getDefaultMemoryPool()) burp_fil(*getDefaultMemoryPool());
file->fil_name = str.ToPathName();
file->fil_length = file_list ? 0 : MAX_LENGTH;
2001-05-23 15:26:42 +02:00
file->fil_next = file_list;
file_list = file;
}
2008-05-23 15:27:47 +02:00
continue;
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
if (str.length() == 1)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
str = none;
}
2001-05-23 15:26:42 +02:00
Switches::in_sw_tab_t* const in_sw_tab = findSwitchOrThrow(switches, str);
2008-05-23 15:27:47 +02:00
fb_assert(in_sw_tab);
//in_sw_tab->in_sw_state = true; It's not enough with switches that have multiple spellings
switches.activate(in_sw_tab->in_sw);
switch (in_sw_tab->in_sw)
2008-05-23 15:27:47 +02:00
{
case IN_SW_BURP_RECREATE:
2008-01-16 07:11:50 +01:00
{
int real_sw = IN_SW_BURP_C;
if ((itr < argc - 1) && (*argv[itr + 1] != switch_char))
2008-01-16 07:11:50 +01:00
{
// find optional BURP_SW_OVERWRITE parameter
Firebird::string next(argv[itr + 1]);
next.upper();
if (strstr(BURP_SW_OVERWRITE, next.c_str()) == BURP_SW_OVERWRITE)
{
real_sw = IN_SW_BURP_R;
itr++;
}
}
// replace IN_SW_BURP_RECREATE by IN_SW_BURP_R or IN_SW_BURP_C
in_sw_tab->in_sw_state = false;
switches.activate(real_sw);
}
break;
case IN_SW_BURP_S:
if (tdgbl->gbl_sw_skip_count)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_skip_count);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
{
BURP_error(200, true);
2008-12-01 10:21:31 +01:00
// msg 200: missing parameter for the number of bytes to be skipped
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_skip_count = get_number(argv[itr]);
if (!tdgbl->gbl_sw_skip_count)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(201, true, argv[itr]);
2008-12-01 10:21:31 +01:00
// msg 201: expected number of bytes to be skipped, encountered "%s"
2001-05-23 15:26:42 +02:00
}
break;
case IN_SW_BURP_P:
if (tdgbl->gbl_sw_page_size)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_page_size);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(2, true);
2008-12-01 10:21:31 +01:00
// msg 2 page size parameter missing
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_page_size = (USHORT) get_number(argv[itr]);
if (!tdgbl->gbl_sw_page_size)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(12, true, argv[itr]);
2008-12-01 10:21:31 +01:00
// msg 12 expected page size, encountered "%s"
2001-05-23 15:26:42 +02:00
}
break;
case IN_SW_BURP_BU:
if (tdgbl->gbl_sw_page_buffers)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_page_buffers);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(258, true);
2008-12-01 10:21:31 +01:00
// msg 258 page buffers parameter missing
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_page_buffers = get_number(argv[itr]);
if (!tdgbl->gbl_sw_page_buffers)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(259, true, argv[itr]);
2008-12-01 10:21:31 +01:00
// msg 259 expected page buffers, encountered "%s"
2001-05-23 15:26:42 +02:00
}
break;
case IN_SW_BURP_MODE:
if (tdgbl->gbl_sw_mode)
2009-11-06 02:21:14 +01:00
{
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name <<
(tdgbl->gbl_sw_mode_val ? BURP_SW_MODE_RO : BURP_SW_MODE_RW));
2009-11-06 02:21:14 +01:00
}
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(279, true);
2008-12-01 10:21:31 +01:00
// msg 279: "read_only" or "read_write" required
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
str = argv[itr];
str.upper();
2008-05-23 15:27:47 +02:00
if (str == BURP_SW_MODE_RO)
tdgbl->gbl_sw_mode_val = true;
else if (str == BURP_SW_MODE_RW)
tdgbl->gbl_sw_mode_val = false;
else
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(279, true);
2008-12-01 10:21:31 +01:00
// msg 279: "read_only" or "read_write" required
2006-12-08 19:38:15 +01:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_mode = true;
break;
case IN_SW_BURP_PASS:
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(189, true);
2008-12-01 10:21:31 +01:00
// password parameter missing
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
uSvc->hidePasswd(argv, itr);
if (tdgbl->gbl_sw_password)
{
BURP_error(307, true);
// too many passwords provided
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_password = argv[itr];
break;
case IN_SW_BURP_FETCHPASS:
if (++itr >= argc)
{
BURP_error(189, true);
2008-12-01 10:21:31 +01:00
// password parameter missing
}
if (tdgbl->gbl_sw_password)
{
BURP_error(307, true);
// too many passwords provided
}
2008-12-02 08:09:49 +01:00
switch (fb_utils::fetchPassword(argv[itr], tdgbl->gbl_sw_password))
{
case fb_utils::FETCH_PASS_OK:
break;
case fb_utils::FETCH_PASS_FILE_OPEN_ERROR:
BURP_error(308, true, MsgFormat::SafeArg() << argv[itr] << errno);
// error @2 opening password file @1
break;
case fb_utils::FETCH_PASS_FILE_READ_ERROR:
BURP_error(309, true, MsgFormat::SafeArg() << argv[itr] << errno);
// error @2 reading password file @1
break;
case fb_utils::FETCH_PASS_FILE_EMPTY:
BURP_error(310, true, MsgFormat::SafeArg() << argv[itr]);
// password file @1 is empty
break;
}
break;
case IN_SW_BURP_USER:
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(188, true);
2008-12-01 10:21:31 +01:00
// user name parameter missing
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_user = argv[itr];
break;
case IN_SW_BURP_TRUSTED_USER:
2008-05-23 15:27:47 +02:00
uSvc->checkService();
if (++itr >= argc)
{
2008-05-23 15:27:47 +02:00
BURP_error(188, true);
2008-12-01 10:21:31 +01:00
// trusted user name parameter missing
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_tr_user = argv[itr];
break;
case IN_SW_BURP_ROLE:
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
{
2008-05-23 15:27:47 +02:00
BURP_error(253, true);
// SQL role parameter missing
2008-12-01 10:21:31 +01:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_sql_role = argv[itr];
break;
case IN_SW_BURP_FA:
if (tdgbl->gbl_sw_blk_factor)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_blk_factor);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
{
BURP_error(182, true);
2008-12-01 10:21:31 +01:00
// msg 182 blocking factor parameter missing
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_blk_factor = get_number(argv[itr]);
if (!tdgbl->gbl_sw_blk_factor)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(183, true, argv[itr]);
2008-12-01 10:21:31 +01:00
// msg 183 expected blocking factor, encountered "%s"
2001-05-23 15:26:42 +02:00
}
break;
case IN_SW_BURP_FIX_FSS_DATA:
if (tdgbl->gbl_sw_fix_fss_data)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_fix_fss_data);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
2008-01-16 07:11:50 +01:00
{
2008-05-23 15:27:47 +02:00
BURP_error(304, true);
// Character set parameter missing
2008-12-01 10:21:31 +01:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_fix_fss_data = argv[itr];
break;
case IN_SW_BURP_FIX_FSS_METADATA:
if (tdgbl->gbl_sw_fix_fss_metadata)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->gbl_sw_fix_fss_metadata);
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
{
BURP_error(304, true);
// Character set parameter missing
2008-12-01 10:21:31 +01:00
}
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_fix_fss_metadata = argv[itr];
break;
case IN_SW_BURP_SE:
2008-05-23 15:27:47 +02:00
if (++itr >= argc)
{
BURP_error(273, true);
2008-12-01 10:21:31 +01:00
// msg 273: service name parameter missing
2008-05-23 15:27:47 +02:00
}
2008-12-01 10:21:31 +01:00
// skip a service specification
2008-05-23 15:27:47 +02:00
in_sw_tab->in_sw_state = false;
break;
case IN_SW_BURP_Y:
2008-05-23 15:27:47 +02:00
{
// want to do output redirect handling now instead of waiting
const TEXT* redirect = NULL;
if (++itr < argc)
2008-01-16 07:11:50 +01:00
{
redirect = argv[itr];
if (*redirect == switch_char)
{
redirect = NULL;
}
}
if (!redirect)
{
BURP_error(4, true);
// msg 4 redirect location for output is not specified
}
Firebird::string up(redirect);
up.upper();
tdgbl->sw_redirect = (up == output_suppress) ? NOOUTPUT : REDIRECT;
if (tdgbl->sw_redirect == REDIRECT) // not NOREDIRECT, and not NOOUTPUT
{
// Make sure the status file doesn't already exist
FILE* tmp_outfile = fopen(redirect, fopen_read_type);
2009-11-06 02:21:14 +01:00
if (tmp_outfile)
{
BURP_print(true, 66, redirect);
// msg 66 can't open status and error output file %s
fclose(tmp_outfile);
BURP_exit_local(FINI_ERROR, tdgbl);
}
if (! (tdgbl->output_file = fopen(redirect, fopen_write_type)))
{
BURP_print(true, 66, redirect);
// msg 66 can't open status and error output file %s
BURP_exit_local(FINI_ERROR, tdgbl);
}
2001-05-23 15:26:42 +02:00
}
2008-05-23 15:27:47 +02:00
}
break;
case IN_SW_BURP_VERBINT:
2008-05-23 15:27:47 +02:00
{
if (tdgbl->gbl_sw_verbose)
BURP_error(329, true); // verify (verbose) and verbint options are mutually exclusive
if (verbint)
BURP_error(333, true, SafeArg() << in_sw_tab->in_sw_name << tdgbl->verboseInterval);
if (++itr >= argc)
BURP_error(326, true); // verbose interval parameter missing
ULONG verbint_val = get_number(argv[itr]);
2009-11-06 06:26:54 +01:00
if (verbint_val < MIN_VERBOSE_INTERVAL)
{
// verbose interval value cannot be smaller than @1
BURP_error(327, true, SafeArg() << MIN_VERBOSE_INTERVAL);
}
tdgbl->verboseInterval = verbint_val;
verbint = true;
2008-05-23 15:27:47 +02:00
}
break;
case IN_SW_BURP_V:
if (verbint)
BURP_error(329, true); // verify (verbose) and verbint options are mutually exclusive
if (tdgbl->gbl_sw_verbose)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_verbose = true;
break;
case IN_SW_BURP_CO:
if (tdgbl->gbl_sw_convert_ext_tables)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_convert_ext_tables = true;
break;
case IN_SW_BURP_E:
if (!tdgbl->gbl_sw_compress)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_compress = false;
break;
case IN_SW_BURP_G:
if (noGarbage)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
noGarbage = true;
break;
case IN_SW_BURP_I:
if (tdgbl->gbl_sw_deactivate_indexes)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_deactivate_indexes = true;
break;
case IN_SW_BURP_IG:
if (ignoreDamaged)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
ignoreDamaged = true;
break;
case IN_SW_BURP_K:
if (tdgbl->gbl_sw_kill)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_kill = true;
break;
2001-05-23 15:26:42 +02:00
case IN_SW_BURP_L:
if (tdgbl->gbl_sw_ignore_limbo)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_ignore_limbo = true;
break;
2008-01-16 07:11:50 +01:00
case IN_SW_BURP_M:
if (tdgbl->gbl_sw_meta)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_meta = true;
break;
case IN_SW_BURP_N:
if (tdgbl->gbl_sw_novalidity)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_novalidity = true;
break;
case IN_SW_BURP_NOD:
if (noDbTrig)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
noDbTrig = true;
break;
case IN_SW_BURP_O:
if (tdgbl->gbl_sw_incremental)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_incremental = true;
break;
case IN_SW_BURP_OL:
if (tdgbl->gbl_sw_old_descriptions)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_old_descriptions = true;
break;
case IN_SW_BURP_US:
if (tdgbl->gbl_sw_no_reserve)
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
tdgbl->gbl_sw_no_reserve = true;
break;
case IN_SW_BURP_NT: // Backup non-transportable format
if (transportableMentioned)
2008-05-23 15:27:47 +02:00
{
if (tdgbl->gbl_sw_transportable)
BURP_error(332, true, SafeArg() << "NT" << "T");
else
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
2008-05-23 15:27:47 +02:00
}
tdgbl->gbl_sw_transportable = false;
transportableMentioned = true;
break;
case IN_SW_BURP_T:
if (transportableMentioned)
{
if (!tdgbl->gbl_sw_transportable)
BURP_error(332, true, SafeArg() << "NT" << "T");
else
BURP_error(334, true, SafeArg() << in_sw_tab->in_sw_name);
}
tdgbl->gbl_sw_transportable = true;
transportableMentioned = true;
break;
}
2008-05-25 03:39:16 +02:00
} // for
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
// reverse the linked list of file blocks
2001-05-23 15:26:42 +02:00
tdgbl->gbl_sw_files = NULL;
burp_fil* next_file = NULL;
2009-11-06 11:47:32 +01:00
for (file = file_list; file; file = next_file)
{
2001-05-23 15:26:42 +02:00
next_file = file->fil_next;
file->fil_next = tdgbl->gbl_sw_files;
tdgbl->gbl_sw_files = file;
}
2008-12-01 10:21:31 +01:00
// pop off the obviously boring ones, plus do some checking
2001-05-23 15:26:42 +02:00
const TEXT* file1 = NULL;
2008-04-21 14:14:16 +02:00
const TEXT* file2 = NULL;
2008-12-01 10:21:31 +01:00
for (file = tdgbl->gbl_sw_files; file; file = file->fil_next)
2008-01-16 07:11:50 +01:00
{
2001-05-23 15:26:42 +02:00
if (!file1)
2008-01-16 07:11:50 +01:00
file1 = file->fil_name.c_str();
2001-05-23 15:26:42 +02:00
else if (!file2)
2008-01-16 07:11:50 +01:00
file2 = file->fil_name.c_str();
2001-05-23 15:26:42 +02:00
for (file_list = file->fil_next; file_list;
2003-09-14 03:08:18 +02:00
file_list = file_list->fil_next)
{
2008-01-16 07:11:50 +01:00
if (file->fil_name == file_list->fil_name)
{
BURP_error(9, true);
2008-12-01 10:21:31 +01:00
// msg 9 mutiple sources or destinations specified
2008-01-16 07:11:50 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
// Initialize 'dpb'
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
dpb.insertString(isc_dpb_gbak_attach, GDS_VERSION, strlen(GDS_VERSION));
dpb.insertByte(isc_dpb_gsec_attach, 1); // make it possible to have local security backups
uSvc->getAddressPath(dpb);
2001-05-23 15:26:42 +02:00
// We call getTableMod() because we are interested in the items that were activated previously,
// not in the original, unchanged table that "switches" took as parameter in the constructor.
for (const Switches::in_sw_tab_t* in_sw_tab = switches.getTableMod();
in_sw_tab->in_sw_name; in_sw_tab++)
2008-05-23 15:27:47 +02:00
{
if (!in_sw_tab->in_sw_state)
continue;
2008-12-01 10:21:31 +01:00
2008-05-23 15:27:47 +02:00
switch (in_sw_tab->in_sw)
{
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_B:
2008-05-23 15:27:47 +02:00
if (sw_replace)
BURP_error(5, true);
2008-12-01 10:21:31 +01:00
// msg 5 conflicting switches for backup/restore
2008-05-23 15:27:47 +02:00
sw_replace = IN_SW_BURP_B;
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_C:
2008-05-23 15:27:47 +02:00
if (sw_replace == IN_SW_BURP_B)
BURP_error(5, true);
2008-12-01 10:21:31 +01:00
// msg 5 conflicting switches for backup/restore
2008-05-23 15:27:47 +02:00
if (sw_replace != IN_SW_BURP_R)
sw_replace = IN_SW_BURP_C;
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_G:
2008-05-23 15:27:47 +02:00
dpb.insertTag(isc_dpb_no_garbage_collect);
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_IG:
2008-05-23 15:27:47 +02:00
dpb.insertByte(isc_dpb_damaged, 1);
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_MODE:
// checked before, seems irrelevant to activate it again
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_mode = true;
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_NOD:
2008-05-23 15:27:47 +02:00
dpb.insertByte(isc_dpb_no_db_triggers, 1);
break;
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_PASS:
case IN_SW_BURP_FETCHPASS:
2009-01-03 10:14:29 +01:00
dpb.insertString(tdgbl->uSvc->isService() ? isc_dpb_password_enc : isc_dpb_password,
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_password, strlen(tdgbl->gbl_sw_password));
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_R:
2008-05-23 15:27:47 +02:00
if (sw_replace == IN_SW_BURP_B)
BURP_error(5, true);
2008-12-01 10:21:31 +01:00
// msg 5 conflicting switches for backup/restore
2008-05-23 15:27:47 +02:00
sw_replace = IN_SW_BURP_R;
break;
2001-05-23 15:26:42 +02:00
/*
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_U:
2008-05-23 15:27:47 +02:00
BURP_error(7, true);
2008-12-01 10:21:31 +01:00
// msg 7 protection isn't there yet
2008-05-23 15:27:47 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_ROLE:
dpb.insertString(isc_dpb_sql_role_name,
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_sql_role, strlen(tdgbl->gbl_sw_sql_role));
break;
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_USER:
2009-01-03 10:14:29 +01:00
dpb.insertString(isc_dpb_user_name, tdgbl->gbl_sw_user, strlen(tdgbl->gbl_sw_user));
2008-05-23 15:27:47 +02:00
break;
2001-05-23 15:26:42 +02:00
case IN_SW_BURP_TRUSTED_USER:
2008-05-23 15:27:47 +02:00
uSvc->checkService();
dpb.deleteWithTag(isc_dpb_trusted_auth);
2009-01-03 10:14:29 +01:00
dpb.insertString(isc_dpb_trusted_auth, tdgbl->gbl_sw_tr_user, strlen(tdgbl->gbl_sw_tr_user));
2008-05-23 15:27:47 +02:00
break;
2008-01-16 07:11:50 +01:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_TRUSTED_ROLE:
2008-05-23 15:27:47 +02:00
uSvc->checkService();
dpb.deleteWithTag(isc_dpb_trusted_role);
dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
break;
#ifdef TRUSTED_AUTH
case IN_SW_BURP_TRUSTED_AUTH:
2008-05-23 15:27:47 +02:00
if (!dpb.find(isc_dpb_trusted_auth))
{
dpb.insertTag(isc_dpb_trusted_auth);
}
break;
2006-12-08 19:38:15 +01:00
#endif
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
case IN_SW_BURP_Z:
BURP_print(false, 91, GDS_VERSION);
2008-12-01 10:21:31 +01:00
// msg 91 gbak version %s
2008-05-23 15:27:47 +02:00
tdgbl->gbl_sw_version = true;
break;
2001-05-23 15:26:42 +02:00
2008-05-23 15:27:47 +02:00
default:
break;
2001-05-23 15:26:42 +02:00
}
}
if (!sw_replace)
sw_replace = IN_SW_BURP_B;
if (sw_replace == IN_SW_BURP_B)
{
for (burp_fil* f = tdgbl->gbl_sw_files; f; f = f->fil_next)
{
if (f->fil_name == "stdout")
{
2010-05-08 04:25:58 +02:00
// the very first thing to do to not corrupt backup file...
tdgbl->uSvc->setDataMode(true);
}
}
}
2001-05-23 15:26:42 +02:00
if (tdgbl->gbl_sw_page_size)
{
if (sw_replace == IN_SW_BURP_B)
BURP_error(8, true); // msg 8 page size is allowed only on restore or create
int temp = tdgbl->gbl_sw_page_size;
for (int curr_pg_size = MIN_NEW_PAGE_SIZE; curr_pg_size <= MAX_PAGE_SIZE; curr_pg_size <<= 1)
2001-05-23 15:26:42 +02:00
{
2009-08-05 04:12:46 +02:00
if (temp <= curr_pg_size)
{
temp = curr_pg_size;
break;
2001-05-23 15:26:42 +02:00
}
}
if (temp > MAX_PAGE_SIZE)
{
BURP_error(3, true, SafeArg() << tdgbl->gbl_sw_page_size);
2008-12-01 10:21:31 +01:00
// msg 3 Page size specified (%ld) greater than limit (MAX_PAGE_SIZE bytes)
2001-05-23 15:26:42 +02:00
}
2009-11-06 11:47:32 +01:00
if (temp != tdgbl->gbl_sw_page_size)
{
BURP_print(false, 103, SafeArg() << tdgbl->gbl_sw_page_size << temp);
2008-12-01 10:21:31 +01:00
// msg 103 page size specified (%ld bytes) rounded up to %ld bytes
2001-05-23 15:26:42 +02:00
tdgbl->gbl_sw_page_size = temp;
}
}
if (sw_replace == IN_SW_BURP_B)
{
if (tdgbl->gbl_sw_page_buffers)
BURP_error(260, true); // msg 260 page buffers is allowed only on restore or create
int errNum = IN_SW_BURP_0;
if (tdgbl->gbl_sw_fix_fss_data)
errNum = IN_SW_BURP_FIX_FSS_DATA;
else if (tdgbl->gbl_sw_fix_fss_metadata)
errNum = IN_SW_BURP_FIX_FSS_METADATA;
else if (tdgbl->gbl_sw_deactivate_indexes)
errNum = IN_SW_BURP_I;
else if (tdgbl->gbl_sw_kill)
errNum = IN_SW_BURP_K;
else if (tdgbl->gbl_sw_mode)
errNum = IN_SW_BURP_MODE;
else if (tdgbl->gbl_sw_novalidity)
errNum = IN_SW_BURP_N;
else if (tdgbl->gbl_sw_incremental)
errNum = IN_SW_BURP_O;
else if (tdgbl->gbl_sw_skip_count)
errNum = IN_SW_BURP_S;
else if (tdgbl->gbl_sw_no_reserve)
errNum = IN_SW_BURP_US;
if (errNum != IN_SW_BURP_0)
{
const char* msg = switches.findNameByTag(errNum);
BURP_error(330, true, SafeArg() << msg);
}
}
else
{
fb_assert(sw_replace == IN_SW_BURP_C || sw_replace == IN_SW_BURP_R);
int errNum = IN_SW_BURP_0;
if (tdgbl->gbl_sw_convert_ext_tables)
errNum = IN_SW_BURP_CO;
else if (!tdgbl->gbl_sw_compress)
errNum = IN_SW_BURP_E;
else if (tdgbl->gbl_sw_blk_factor)
errNum = IN_SW_BURP_FA;
else if (noGarbage)
errNum = IN_SW_BURP_G;
else if (ignoreDamaged)
errNum = IN_SW_BURP_IG;
else if (tdgbl->gbl_sw_ignore_limbo)
errNum = IN_SW_BURP_L;
else if (noDbTrig)
errNum = IN_SW_BURP_NOD;
else if (transportableMentioned)
{
if (tdgbl->gbl_sw_transportable)
errNum = IN_SW_BURP_T;
else
errNum = IN_SW_BURP_NT;
}
else if (tdgbl->gbl_sw_old_descriptions)
errNum = IN_SW_BURP_OL;
if (errNum != IN_SW_BURP_0)
{
const char* msg = switches.findNameByTag(errNum);
BURP_error(331, true, SafeArg() << msg);
}
2001-05-23 15:26:42 +02:00
}
if (!tdgbl->gbl_sw_blk_factor || sw_replace != IN_SW_BURP_B)
tdgbl->gbl_sw_blk_factor = 1;
if (verbint)
tdgbl->gbl_sw_verbose = true;
2001-05-23 15:26:42 +02:00
if (!file2)
BURP_error(10, true);
2008-12-01 10:21:31 +01:00
// msg 10 requires both input and output filenames
2001-05-23 15:26:42 +02:00
if (!strcmp(file1, file2))
BURP_error(11, true);
2008-12-01 10:21:31 +01:00
// msg 11 input and output have the same name. Disallowed.
2001-05-23 15:26:42 +02:00
2008-04-21 14:14:16 +02:00
{ // scope
// The string result produced by ctime contains exactly 26 characters and
// gbl_backup_start_time is TEXT[30], but let's make sure we don't overflow
// due to any change.
const time_t clock = time(NULL);
fb_utils::copy_terminate(tdgbl->gbl_backup_start_time, ctime(&clock),
sizeof(tdgbl->gbl_backup_start_time));
TEXT* nlp = tdgbl->gbl_backup_start_time + strlen(tdgbl->gbl_backup_start_time) - 1;
if (*nlp == '\n')
*nlp = 0;
} // scope
2001-05-23 15:26:42 +02:00
tdgbl->action = (burp_act*) BURP_alloc_zero(ACT_LEN);
2001-05-23 15:26:42 +02:00
tdgbl->action->act_total = 0;
tdgbl->action->act_file = NULL;
tdgbl->action->act_action = ACT_unknown;
2009-01-03 10:14:29 +01:00
action = open_files(file1, &file2, tdgbl->gbl_sw_verbose, sw_replace, dpb);
2001-05-23 15:26:42 +02:00
MVOL_init(tdgbl->io_buffer_size);
2008-12-01 10:21:31 +01:00
int result;
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
tdgbl->uSvc->started();
2009-01-03 10:14:29 +01:00
switch (action)
{
2008-12-01 10:21:31 +01:00
case RESTORE:
tdgbl->gbl_sw_overwrite = (sw_replace == IN_SW_BURP_R);
2001-05-23 15:26:42 +02:00
result = RESTORE_restore(file1, file2);
break;
2008-12-01 10:21:31 +01:00
case BACKUP:
2001-05-23 15:26:42 +02:00
result = BACKUP_backup(file1, file2);
break;
2008-12-01 10:21:31 +01:00
case QUIT:
2001-05-23 15:26:42 +02:00
BURP_abort();
2004-08-26 21:09:07 +02:00
return 0;
2008-12-01 10:21:31 +01:00
2004-08-26 21:09:07 +02:00
default:
// result undefined
fb_assert(false);
return 0;
2001-05-23 15:26:42 +02:00
}
if (result != FINI_OK && result != FINI_DB_NOT_ONLINE)
BURP_abort();
2004-03-07 08:58:55 +01:00
BURP_exit_local(result, tdgbl);
2001-12-24 03:51:06 +01:00
} // try
2008-01-16 07:11:50 +01:00
catch (const Firebird::LongJump&)
2001-12-24 03:51:06 +01:00
{
2008-12-01 10:21:31 +01:00
// All calls to exit_local(), normal and error exits, wind up here
2008-01-16 07:11:50 +01:00
tdgbl->burp_throw = false;
exit_code = tdgbl->exit_code;
}
2001-12-24 03:51:06 +01:00
2008-01-16 07:11:50 +01:00
catch (const Firebird::Exception& e)
{
// Non-burp exception was caught
tdgbl->burp_throw = false;
2008-01-16 07:11:50 +01:00
e.stuff_exception(tdgbl->status_vector);
BURP_print_status(tdgbl->status_vector, true);
BURP_print(true, 83); // msg 83 Exiting before completion due to errors
exit_code = FINI_ERROR;
2008-01-16 07:11:50 +01:00
}
2001-12-24 03:51:06 +01:00
2008-12-01 10:21:31 +01:00
// Close the gbak file handles if they still open
2008-01-16 07:11:50 +01:00
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 &&
2009-01-03 10:14:29 +01:00
(tdgbl->action->act_action == ACT_backup_split || tdgbl->action->act_action == ACT_backup))
{
2008-01-16 07:11:50 +01:00
unlink_platf(file->fil_name.c_str());
2001-12-24 03:51:06 +01:00
}
2008-01-16 07:11:50 +01:00
}
2001-12-24 03:51:06 +01:00
2008-12-01 10:21:31 +01:00
// Detach from database to release system resources
2009-11-06 11:47:32 +01:00
if (tdgbl->db_handle != 0)
{
2008-01-16 07:11:50 +01:00
close_out_transaction(action, &tdgbl->tr_handle);
close_out_transaction(action, &tdgbl->global_trans);
if (isc_detach_database(tdgbl->status_vector, &tdgbl->db_handle))
{
BURP_print_status(tdgbl->status_vector, true);
2001-12-24 03:51:06 +01:00
}
2008-01-16 07:11:50 +01:00
}
2001-12-24 03:51:06 +01:00
2008-12-01 10:21:31 +01:00
// Close the status output file
2009-11-06 11:47:32 +01:00
if (tdgbl->sw_redirect == REDIRECT && tdgbl->output_file != NULL)
{
2008-01-16 07:11:50 +01:00
fclose(tdgbl->output_file);
tdgbl->output_file = NULL;
}
2001-12-24 03:51:06 +01:00
2008-12-01 10:21:31 +01:00
// Free all unfreed memory used by GBAK itself
2009-11-06 11:47:32 +01:00
while (tdgbl->head_of_mem_list != NULL)
{
2008-01-16 07:11:50 +01:00
UCHAR* mem = tdgbl->head_of_mem_list;
tdgbl->head_of_mem_list = *((UCHAR **) tdgbl->head_of_mem_list);
gds__free(mem);
}
2001-12-24 03:51:06 +01:00
2008-01-16 07:11:50 +01:00
BurpGlobals::restoreSpecific();
2001-12-24 03:51:06 +01:00
2008-01-16 07:11:50 +01:00
#if defined(DEBUG_GDS_ALLOC)
if (!uSvc->isService())
{
2001-12-24 03:51:06 +01:00
gds_alloc_report(0, __FILE__, __LINE__);
2008-01-16 07:11:50 +01:00
}
2001-12-24 03:51:06 +01:00
#endif
2008-01-16 07:11:50 +01:00
return exit_code;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
2009-01-03 10:14:29 +01:00
void BURP_abort()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ a b o r t
*
**************************************
*
* Functional description
* Abandon a failed operation.
*
**************************************/
2004-07-03 02:13:46 +02:00
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
2001-05-23 15:26:42 +02:00
2010-11-15 18:03:30 +01:00
if (!tdgbl->uSvc->isService())
{
BURP_print(true, 83);
// msg 83 Exiting before completion due to errors
}
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
tdgbl->uSvc->started();
2001-05-23 15:26:42 +02:00
2004-01-13 10:52:19 +01:00
BURP_exit_local(FINI_ERROR, tdgbl);
2001-05-23 15:26:42 +02:00
}
2009-01-03 10:14:29 +01:00
void BURP_error(USHORT errcode, bool abort, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ e r r o r
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
*
**************************************/
2004-07-03 02:13:46 +02:00
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
tdgbl->uSvc->setServiceStatus(burp_msg_fac, errcode, arg);
2008-01-16 07:11:50 +01:00
tdgbl->uSvc->started();
if (!tdgbl->uSvc->isService())
{
BURP_msg_partial(true, 256); // msg 256: gbak: ERROR:
BURP_msg_put(true, errcode, arg);
}
if (abort)
2008-01-16 07:11:50 +01:00
{
BURP_abort();
2008-01-16 07:11:50 +01:00
}
}
2009-01-03 10:14:29 +01:00
void BURP_error(USHORT errcode, bool abort, const char* str)
{
/**************************************
*
* B U R P _ e r r o r
*
**************************************
*
* Functional description
* Format and print an error message, then punt.
*
**************************************/
BURP_error(errcode, abort, SafeArg() << str);
2001-05-23 15:26:42 +02:00
}
2009-01-03 10:14:29 +01:00
void BURP_error_redirect(const ISC_STATUS* status_vector, USHORT errcode, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ e r r o r _ r e d i r e c t
*
**************************************
*
* Functional description
* Issue error message. Output messages then abort.
*
**************************************/
BURP_print_status(status_vector, true);
BURP_error(errcode, true, arg);
2001-05-23 15:26:42 +02:00
}
// **********************************
// B U R P _ e x i t _ l o c a l
// **********************************
2004-01-13 10:52:19 +01:00
// Raises an exception when the old SEH system would jump to another place.
// **********************************
2004-07-03 02:13:46 +02:00
void BURP_exit_local(int code, BurpGlobals* tdgbl)
2004-01-13 10:52:19 +01:00
{
2004-03-01 05:57:43 +01:00
tdgbl->exit_code = code;
if (tdgbl->burp_throw)
throw Firebird::LongJump();
2004-01-13 10:52:19 +01:00
}
void BURP_msg_partial(bool err, USHORT number, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ m s g _ p a r t i a l
*
**************************************
*
* Functional description
* Retrieve a message from the error file,
2001-05-23 15:26:42 +02:00
* format it, and print it without a newline.
*
**************************************/
TEXT buffer[256];
fb_msg_format(NULL, burp_msg_fac, number, sizeof(buffer), buffer, arg);
burp_output(err, "%s", buffer);
2001-05-23 15:26:42 +02:00
}
void BURP_msg_put(bool err, USHORT number, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ m s g _ p u t
*
**************************************
*
* Functional description
* Retrieve a message from the error file, format it, and print it.
*
**************************************/
TEXT buffer[256];
fb_msg_format(NULL, burp_msg_fac, number, sizeof(buffer), buffer, arg);
burp_output(err, "%s\n", buffer);
2001-05-23 15:26:42 +02:00
}
2009-01-03 10:14:29 +01:00
void BURP_msg_get(USHORT number, TEXT* output_msg, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ m s g _ g e t
*
**************************************
*
* Functional description
* Retrieve a message from the error file, format it and copy it to the buffer
*
**************************************/
2004-10-30 07:41:25 +02:00
TEXT buffer[BURP_MSG_GET_SIZE];
2001-05-23 15:26:42 +02:00
fb_msg_format(NULL, burp_msg_fac, number, sizeof(buffer), buffer, arg);
strcpy(output_msg, buffer);
2001-05-23 15:26:42 +02:00
}
2003-12-22 11:00:59 +01:00
void BURP_output_version(void* arg1, const TEXT* arg2)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ o u t p u t _ v e r s i o n
*
**************************************
*
* Functional description
* Callback routine for access method
* printing (specifically show version);
* will accept.
*
**************************************/
burp_output(false, static_cast<const char*>(arg1), arg2);
2001-05-23 15:26:42 +02:00
}
void BURP_print(bool err, USHORT number, const SafeArg& arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ p r i n t
*
**************************************
*
* Functional description
* Display a formatted error message
* in a way that VMS or civilized systems
* will accept.
*
**************************************/
BURP_msg_partial(err, 169); // msg 169: gbak:
BURP_msg_put(err, number, arg);
}
void BURP_print(bool err, USHORT number, const char* str)
{
/**************************************
*
* B U R P _ p r i n t
*
**************************************
*
* Functional description
* Display a formatted error message
* in a way that VMS or civilized systems
* will accept.
*
**************************************/
static const SafeArg dummy;
BURP_msg_partial(err, 169, dummy); // msg 169: gbak:
BURP_msg_put(err, number, SafeArg() << str);
2001-05-23 15:26:42 +02:00
}
void BURP_print_status(const ISC_STATUS* status_vector, bool flagStuff)
{
/**************************************
*
* B U R P _ p r i n t _ s t a t u s
*
**************************************
*
* Functional description
* Print error message. Use fb_interpret
* to allow redirecting output.
*
**************************************/
2010-05-08 04:25:58 +02:00
if (status_vector)
{
2003-12-22 11:00:59 +01:00
const ISC_STATUS* vector = status_vector;
2008-01-16 07:11:50 +01:00
2010-05-08 04:25:58 +02:00
if (flagStuff)
{
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
tdgbl->uSvc->setServiceStatus(vector);
tdgbl->uSvc->started();
2010-05-08 04:25:58 +02:00
if (tdgbl->uSvc->isService())
{
return;
}
}
SCHAR s[1024];
2010-05-08 04:25:58 +02:00
if (fb_interpret(s, sizeof(s), &vector))
{
BURP_msg_partial(true, 256); // msg 256: gbak: ERROR:
burp_output(true, "%s\n", s);
2010-05-08 04:25:58 +02:00
while (fb_interpret(s, sizeof(s), &vector))
{
BURP_msg_partial(true, 256); // msg 256: gbak: ERROR:
burp_output(true, " %s\n", s);
}
}
}
}
void BURP_print_warning(const ISC_STATUS* status_vector)
{
/**************************************
*
* B U R P _ p r i n t _ w a r n i n g
*
**************************************
*
* Functional description
* Print warning message. Use fb_interpret
* to allow redirecting output.
*
**************************************/
2009-01-03 10:14:29 +01:00
if (status_vector)
{
2008-12-01 10:21:31 +01:00
// skip the error, assert that one does not exist
2003-11-08 00:15:33 +01:00
fb_assert(status_vector[0] == isc_arg_gds);
2003-11-04 00:59:24 +01:00
fb_assert(status_vector[1] == 0);
2010-05-08 04:25:58 +02:00
2008-12-01 10:21:31 +01:00
// print the warning message
const ISC_STATUS* vector = &status_vector[2];
SCHAR s[1024];
2010-05-08 04:25:58 +02:00
if (fb_interpret(s, sizeof(s), &vector))
{
BURP_msg_partial(true, 255); // msg 255: gbak: WARNING:
burp_output(true, "%s\n", s);
2010-05-08 04:25:58 +02:00
while (fb_interpret(s, sizeof(s), &vector))
{
BURP_msg_partial(true, 255); // msg 255: gbak: WARNING:
burp_output(true, " %s\n", s);
}
}
}
}
2009-01-03 10:14:29 +01:00
void BURP_verbose(USHORT number, const SafeArg& arg)
{
/**************************************
*
* B U R P _ v e r b o s e
*
**************************************
*
* Functional description
* Calls BURP_print for displaying a formatted error message
* but only for verbose output. If not verbose then calls
2009-02-02 11:39:49 +01:00
* user defined yielding function.
*
**************************************/
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
if (tdgbl->gbl_sw_verbose)
BURP_print(false, number, arg);
else
burp_output(false, "%s", "");
}
2009-01-03 10:14:29 +01:00
void BURP_verbose(USHORT number, const char* str)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* B U R P _ v e r b o s e
*
**************************************
*
* Functional description
* Calls BURP_print for displaying a formatted error message
* but only for verbose output. If not verbose then calls
* user defined yieding function.
*
**************************************/
2004-07-03 02:13:46 +02:00
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
2001-05-23 15:26:42 +02:00
if (tdgbl->gbl_sw_verbose)
BURP_print(false, number, str);
2001-05-23 15:26:42 +02:00
else
burp_output(false, "%s", "");
2001-05-23 15:26:42 +02:00
}
2009-01-03 10:14:29 +01:00
static void close_out_transaction(gbak_action action, isc_tr_handle* handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c l o s e _ o u t _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Make a transaction go away. This is
* important as we need to detach from the
* database so all engine allocated memory is
* returned to the system.
*
**************************************/
2009-01-03 10:14:29 +01:00
if (*handle != 0)
{
ISC_STATUS_ARRAY status_vector;
2009-04-17 16:10:11 +02:00
if (action == RESTORE)
{
// Even if the restore failed, commit the transaction so that
// a partial database is at least recovered.
2001-05-23 15:26:42 +02:00
isc_commit_transaction(status_vector, handle);
2009-11-06 11:47:32 +01:00
if (status_vector[1])
{
2009-04-17 16:10:11 +02:00
// If we can't commit - have to roll it back, as
// we need to close all outstanding transactions before
// we can detach from the database.
2001-05-23 15:26:42 +02:00
isc_rollback_transaction(status_vector, handle);
if (status_vector[1])
BURP_print_status(status_vector);
}
}
else
2009-01-03 20:02:04 +01:00
{
2009-04-17 16:10:11 +02:00
// A backup shouldn't touch any data - we ensure that
// by never writing data during a backup, but let's double
// ensure it by doing a rollback
2009-01-03 10:14:29 +01:00
if (isc_rollback_transaction(status_vector, handle))
BURP_print_status(status_vector);
2009-01-03 20:02:04 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
2003-12-22 11:00:59 +01:00
static SLONG get_number( const SCHAR* string)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ n u m b e r
*
**************************************
*
* Functional description
* Convert a string to binary, complaining bitterly if
* the string is bum.
* CVC: where does it complain? It does return zero, nothing else.
* Worse, this function doesn't check for overflow.
2001-05-23 15:26:42 +02:00
**************************************/
SCHAR c;
SLONG value = 0;
2001-05-23 15:26:42 +02:00
2009-11-06 02:21:14 +01:00
for (const SCHAR* p = string; c = *p++;)
{
2001-05-23 15:26:42 +02:00
if (c < '0' || c > '9')
return 0;
value *= 10;
value += c - '0';
}
return value;
}
static gbak_action open_files(const TEXT* file1,
const TEXT** file2,
2004-01-13 10:52:19 +01:00
bool sw_verbose,
USHORT sw_replace,
const Firebird::ClumpletWriter& dpb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* o p e n _ f i l e s
*
**************************************
*
* Functional description
* from the input file names and
* positions, guess what the users
* intention was. Return the type
* of the first file, plus open file
* and db handle.
*
**************************************/
2004-07-03 02:13:46 +02:00
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
ISC_STATUS_ARRAY temp_status;
ISC_STATUS* status_vector = temp_status;
2001-05-23 15:26:42 +02:00
2009-04-17 16:10:11 +02:00
// try to attach the database using the first file_name
2001-05-23 15:26:42 +02:00
if (sw_replace != IN_SW_BURP_C && sw_replace != IN_SW_BURP_R)
2008-06-03 08:14:59 +02:00
{
if (!isc_attach_database(status_vector,
2009-01-03 10:14:29 +01:00
(SSHORT) 0, file1,
2001-05-23 15:26:42 +02:00
&tdgbl->db_handle,
dpb.getBufferLength(),
2008-06-03 08:14:59 +02:00
reinterpret_cast<const char*>(dpb.getBuffer())))
2001-05-23 15:26:42 +02:00
{
2009-11-06 11:47:32 +01:00
if (sw_replace != IN_SW_BURP_B)
{
2008-12-01 10:21:31 +01:00
// msg 13 REPLACE specified, but the first file %s is a database
BURP_error(13, true, file1);
2001-05-23 15:26:42 +02:00
if (isc_detach_database(status_vector, &tdgbl->db_handle)) {
BURP_print_status(status_vector, true);
2001-05-23 15:26:42 +02:00
}
return QUIT;
}
2009-11-06 11:47:32 +01:00
if (tdgbl->gbl_sw_version)
{
2008-12-01 10:21:31 +01:00
// msg 139 Version(s) for database "%s"
BURP_print(false, 139, file1);
isc_version(&tdgbl->db_handle, BURP_output_version, (void*) "\t%s\n");
2001-05-23 15:26:42 +02:00
}
if (sw_verbose)
BURP_print(false, 166, file1); // msg 166: readied database %s for backup
2001-05-23 15:26:42 +02:00
}
else if (sw_replace == IN_SW_BURP_B ||
2008-12-31 06:06:08 +01:00
(status_vector[1] != isc_io_error && status_vector[1] != isc_bad_db_format))
2004-12-24 09:52:39 +01:00
{
BURP_print_status(status_vector, true);
2001-05-23 15:26:42 +02:00
return QUIT;
}
2008-06-03 08:14:59 +02:00
}
2001-05-23 15:26:42 +02:00
2004-01-13 10:52:19 +01:00
burp_fil* fil = 0;
2009-01-03 10:14:29 +01:00
if (sw_replace == IN_SW_BURP_B)
{
2001-05-23 15:26:42 +02:00
2008-12-01 10:21:31 +01:00
// Now it is safe to skip a db file
2001-05-23 15:26:42 +02:00
tdgbl->gbl_sw_backup_files = tdgbl->gbl_sw_files->fil_next;
tdgbl->gbl_sw_files = tdgbl->gbl_sw_files->fil_next;
2008-01-16 07:11:50 +01:00
fb_assert(tdgbl->gbl_sw_files->fil_name == *file2);
2001-05-23 15:26:42 +02:00
gbak_action flag = BACKUP;
2001-05-23 15:26:42 +02:00
tdgbl->action->act_action = ACT_backup;
for (fil = tdgbl->gbl_sw_files; fil; fil = fil->fil_next)
{
2008-12-01 10:21:31 +01:00
// adjust the file size first
FB_UINT64 fsize = fil->fil_length;
2001-05-23 15:26:42 +02:00
switch (fil->fil_size_code)
{
case size_n:
break;
case size_k:
fsize *= KBYTE;
2001-05-23 15:26:42 +02:00
break;
case size_m:
fsize *= MBYTE;
2001-05-23 15:26:42 +02:00
break;
case size_g:
fsize *= GBYTE;
2001-05-23 15:26:42 +02:00
break;
case size_e:
2008-01-16 07:11:50 +01:00
BURP_error(262, true, fil->fil_name.c_str());
// msg 262 size specification either missing or incorrect for file %s
2001-05-23 15:26:42 +02:00
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2001-05-23 15:26:42 +02:00
break;
}
// CVC: Check for overflow: 4g is already out of bounds.
if (fsize > FB_UINT64(MAX_ULONG))
BURP_error(262, true, fil->fil_name.c_str());
fil->fil_length = static_cast<ULONG>(fsize);
2001-05-23 15:26:42 +02:00
2004-12-26 05:09:06 +01:00
if ((fil->fil_seq = ++tdgbl->action->act_total) >= 2)
2001-05-23 15:26:42 +02:00
{
tdgbl->action->act_action = ACT_backup_split;
}
if (sw_verbose)
{
BURP_print(false, 75, fil->fil_name.c_str()); // msg 75 creating file %s
2001-05-23 15:26:42 +02:00
}
2008-01-16 07:11:50 +01:00
if (fil->fil_name == "stdout")
2001-05-23 15:26:42 +02:00
{
if (tdgbl->action->act_total >= 2 || fil->fil_next)
{
BURP_error(266, true);
// msg 266 standard output is not supported when using split operation
2001-05-23 15:26:42 +02:00
flag = QUIT;
break;
}
2009-04-22 03:58:40 +02:00
2009-04-17 16:10:11 +02:00
// We ignore SIGPIPE so that we can report an IO error when we
// try to write to the broken pipe.
2001-05-23 15:26:42 +02:00
#ifndef WIN_NT
signal(SIGPIPE, SIG_IGN);
#endif
tdgbl->uSvc->setDataMode(true);
fil->fil_fd = GBAK_STDOUT_DESC();
2001-05-23 15:26:42 +02:00
break;
}
else
{
#ifdef WIN_NT
2009-01-03 10:14:29 +01:00
if ((fil->fil_fd = MVOL_open(fil->fil_name.c_str(), MODE_WRITE, CREATE_ALWAYS)) ==
INVALID_HANDLE_VALUE)
2001-05-23 15:26:42 +02:00
#else
2008-01-16 07:11:50 +01:00
if ((fil->fil_fd = open(fil->fil_name.c_str(), MODE_WRITE, open_mask)) == -1)
2008-12-01 10:21:31 +01:00
#endif // WIN_NT
2001-05-23 15:26:42 +02:00
{
2008-01-16 07:11:50 +01:00
BURP_error(65, false, fil->fil_name.c_str());
// msg 65 can't open backup file %s
2001-05-23 15:26:42 +02:00
flag = QUIT;
break;
}
}
if (fil->fil_length == 0)
{
if (fil->fil_next)
{
2008-01-16 07:11:50 +01:00
BURP_error(262, true, fil->fil_name.c_str());
// msg 262 size specification either missing or incorrect for file %s
2001-05-23 15:26:42 +02:00
flag = QUIT;
break;
}
else
{
fil->fil_length = MAX_LENGTH;
// Write as much as possible to the last file
2001-05-23 15:26:42 +02:00
}
}
if (fil->fil_length < MIN_SPLIT_SIZE)
{
BURP_error(271, true, SafeArg() << fil->fil_length << MIN_SPLIT_SIZE);
2008-12-01 10:21:31 +01:00
// msg file size given (%d) is less than minimum allowed (%d)
2001-05-23 15:26:42 +02:00
flag = QUIT;
break;
}
}
if (flag == BACKUP)
{
tdgbl->action->act_file = tdgbl->gbl_sw_files;
tdgbl->file_desc = tdgbl->gbl_sw_files->fil_fd;
}
else
{
if (isc_detach_database(status_vector, &tdgbl->db_handle))
{
BURP_print_status(status_vector);
}
}
return flag;
}
2009-04-22 03:58:40 +02:00
// If we got to here, then we're really not backing up a database,
2009-04-17 16:10:11 +02:00
// so open a backup file.
2009-04-22 03:58:40 +02:00
// There are four possible cases such as:
//
// 1. restore single backup file to single db file
// 2. restore single backup file to multiple db files
// 3. restore multiple backup files (join operation) to single db file
// 4. restore multiple backup files (join operation) to multiple db files
//
// Just looking at the command line, we can't say for sure whether it is a
// specification of the last file to be join or it is a specification of the
// primary db file (case 4), for example:
//
// gbak -c gbk1 gbk2 gbk3 db1 200 db2 500 db3 -v
// ^^^
// db1 could be either the last file to be join or primary db file
//
// Since 'gbk' and 'gsplit' formats are different (gsplit file has its own
// header record) hence we can use it as follows:
//
// - open first file
// - read & check a header record
//
// If a header is identified as a 'gsplit' one then we know exactly how
// many files need to be join and in which order. We keep opening a file by
// file till we reach the last one to be join. During this step we check
// that the files are accessible and are in proper order. It gives us
// possibility to let silly customer know about an error as soon as possible.
// Besides we have to find out which file is going to be a db file.
//
// If header is not identified as a 'gsplit' record then we assume that
// we got a single backup file.
2001-05-23 15:26:42 +02:00
fil = tdgbl->gbl_sw_files;
tdgbl->gbl_sw_backup_files = tdgbl->gbl_sw_files;
tdgbl->action->act_action = ACT_restore;
2008-12-01 10:21:31 +01:00
if (fil->fil_name == "stdin")
2008-01-16 07:11:50 +01:00
{
fil->fil_fd = GBAK_STDIN_DESC();
2001-05-23 15:26:42 +02:00
tdgbl->file_desc = fil->fil_fd;
tdgbl->gbl_sw_files = fil->fil_next;
}
2008-12-01 10:21:31 +01:00
else
2008-01-16 07:11:50 +01:00
{
2008-12-01 10:21:31 +01:00
// open first file
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
2009-01-03 10:14:29 +01:00
if ((fil->fil_fd = MVOL_open(fil->fil_name.c_str(), MODE_READ, OPEN_EXISTING)) ==
2001-05-23 15:26:42 +02:00
INVALID_HANDLE_VALUE)
2009-01-03 10:14:29 +01:00
#else
if ((fil->fil_fd = open(fil->fil_name.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
2001-05-23 15:26:42 +02:00
#endif
{
2008-01-16 07:11:50 +01:00
BURP_error(65, true, fil->fil_name.c_str());
2008-12-01 10:21:31 +01:00
// msg 65 can't open backup file %s
2001-05-23 15:26:42 +02:00
return QUIT;
}
if (sw_verbose)
2008-01-16 07:11:50 +01:00
{
BURP_print(false, 100, fil->fil_name.c_str());
// msg 100 opened file %s
2008-01-16 07:11:50 +01:00
}
2008-12-01 10:21:31 +01:00
// read and check a header record
2001-05-23 15:26:42 +02:00
tdgbl->action->act_file = fil;
int seq = 1;
2009-01-02 10:48:57 +01:00
if (MVOL_split_hdr_read())
{
2001-05-23 15:26:42 +02:00
tdgbl->action->act_action = ACT_restore_join;
2008-12-01 10:21:31 +01:00
// number of files to be join
2004-10-30 07:41:25 +02:00
const int total = tdgbl->action->act_total;
2008-12-01 10:21:31 +01:00
if (fil->fil_seq != seq || seq > total)
2008-01-16 07:11:50 +01:00
{
BURP_error(263, true, fil->fil_name.c_str());
2008-12-01 10:21:31 +01:00
// msg 263 file %s out of sequence
2001-05-23 15:26:42 +02:00
return QUIT;
}
2009-01-03 10:14:29 +01:00
for (++seq, fil = fil->fil_next; seq <= total; fil = fil->fil_next, seq++)
{
2008-12-01 10:21:31 +01:00
if (!fil)
2008-01-16 07:11:50 +01:00
{
BURP_error(264, true);
2008-12-01 10:21:31 +01:00
// msg 264 can't join -- one of the files missing
2001-05-23 15:26:42 +02:00
return QUIT;
}
2008-12-01 10:21:31 +01:00
if (fil->fil_name == "stdin")
2008-01-16 07:11:50 +01:00
{
BURP_error(265, true);
2008-12-01 10:21:31 +01:00
// msg 265 standard input is not supported when using join operation
2001-05-23 15:26:42 +02:00
return QUIT;
}
tdgbl->action->act_file = fil;
#ifdef WIN_NT
2009-01-03 10:14:29 +01:00
if ((fil->fil_fd = MVOL_open(fil->fil_name.c_str(), MODE_READ, OPEN_EXISTING)) ==
2001-05-23 15:26:42 +02:00
INVALID_HANDLE_VALUE)
#else
2009-01-03 10:14:29 +01:00
if ((fil->fil_fd = open(fil->fil_name.c_str(), MODE_READ)) == INVALID_HANDLE_VALUE)
2001-05-23 15:26:42 +02:00
#endif
{
2008-01-16 07:11:50 +01:00
BURP_error(65, false, fil->fil_name.c_str());
// msg 65 can't open backup file %s
2001-05-23 15:26:42 +02:00
return QUIT;
}
if (sw_verbose)
2008-01-16 07:11:50 +01:00
{
BURP_print(false, 100, fil->fil_name.c_str());
// msg 100 opened file %s
2008-01-16 07:11:50 +01:00
}
2009-01-02 10:48:57 +01:00
if (MVOL_split_hdr_read())
2008-01-16 07:11:50 +01:00
{
2009-01-03 10:14:29 +01:00
if ((total != tdgbl->action->act_total) || (seq != fil->fil_seq) || (seq > total))
{
2008-01-16 07:11:50 +01:00
BURP_error(263, true, fil->fil_name.c_str());
2008-12-01 10:21:31 +01:00
// msg 263 file %s out of sequence
2001-05-23 15:26:42 +02:00
return QUIT;
}
}
2008-12-01 10:21:31 +01:00
else
2008-01-16 07:11:50 +01:00
{
BURP_error(267, true, fil->fil_name.c_str());
2008-12-01 10:21:31 +01:00
// msg 267 backup file %s might be corrupt
2001-05-23 15:26:42 +02:00
return QUIT;
}
}
tdgbl->action->act_file = tdgbl->gbl_sw_files;
tdgbl->file_desc = tdgbl->action->act_file->fil_fd;
2009-11-06 11:47:32 +01:00
if ((tdgbl->gbl_sw_files = fil) == NULL)
{
BURP_error(268, true);
2008-12-01 10:21:31 +01:00
// msg 268 database file specification missing
2001-05-23 15:26:42 +02:00
return QUIT;
}
}
2009-04-17 16:10:11 +02:00
else
{
// Move pointer to the begining of the file. At this point we
// assume -- this is a single backup file because we were
// not able to read a split header record.
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
2008-01-16 07:11:50 +01:00
if (strnicmp(fil->fil_name.c_str(), "\\\\.\\tape", 8))
2001-05-23 15:26:42 +02:00
SetFilePointer(fil->fil_fd, 0, NULL, FILE_BEGIN);
else
SetTapePosition(fil->fil_fd, TAPE_REWIND, 0, 0, 0, FALSE);
#else
lseek(fil->fil_fd, 0, SEEK_SET);
#endif
tdgbl->file_desc = fil->fil_fd;
tdgbl->gbl_sw_files = fil->fil_next;
}
}
2009-04-17 16:10:11 +02:00
// If we got here, we've opened a backup file, and we're
// thinking about creating or replacing a database.
2001-05-23 15:26:42 +02:00
2008-01-16 07:11:50 +01:00
*file2 = tdgbl->gbl_sw_files->fil_name.c_str();
2001-05-23 15:26:42 +02:00
if (tdgbl->gbl_sw_files->fil_size_code != size_n)
BURP_error(262, true, *file2);
2009-04-17 16:10:11 +02:00
// msg 262 size specification either missing or incorrect for file %s
2001-05-23 15:26:42 +02:00
if ((sw_replace == IN_SW_BURP_C || sw_replace == IN_SW_BURP_R) &&
!isc_attach_database(status_vector,
2009-01-03 10:14:29 +01:00
(SSHORT) 0, *file2,
2001-05-23 15:26:42 +02:00
&tdgbl->db_handle,
dpb.getBufferLength(),
reinterpret_cast<const char*>(dpb.getBuffer())))
2001-05-23 15:26:42 +02:00
{
2009-11-06 11:47:32 +01:00
if (sw_replace == IN_SW_BURP_C)
{
2001-05-23 15:26:42 +02:00
if (isc_detach_database(status_vector, &tdgbl->db_handle)) {
BURP_print_status(status_vector, true);
2001-05-23 15:26:42 +02:00
}
BURP_error(14, true, *file2);
2008-12-01 10:21:31 +01:00
// msg 14 database %s already exists. To replace it, use the -R switch
2001-05-23 15:26:42 +02:00
}
2009-11-06 11:47:32 +01:00
else
{
2001-05-23 15:26:42 +02:00
isc_drop_database(status_vector, &tdgbl->db_handle);
2009-11-06 11:47:32 +01:00
if (tdgbl->db_handle)
{
Firebird::makePermanentVector(status_vector);
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector2;
2001-05-23 15:26:42 +02:00
if (isc_detach_database(status_vector2, &tdgbl->db_handle)) {
BURP_print_status(status_vector2);
}
// Complain only if the drop database entrypoint is available.
2008-12-01 10:21:31 +01:00
// If it isn't, the database will simply be overwritten.
2001-05-23 15:26:42 +02:00
2003-11-08 00:15:33 +01:00
if (status_vector[1] != isc_unavailable)
BURP_error(233, true, *file2);
2008-12-01 10:21:31 +01:00
// msg 233 Cannot drop database %s, might be in use
2001-05-23 15:26:42 +02:00
}
}
}
2009-11-06 11:47:32 +01:00
if (sw_replace == IN_SW_BURP_R && status_vector[1] == isc_adm_task_denied)
{
2009-04-17 16:10:11 +02:00
// if we got an error from attach database and we have replace switch set
// then look for error from attach returned due to not owner, if we are
// not owner then return the error status back up
2009-04-22 03:58:40 +02:00
BURP_error(274, true);
2009-04-17 16:10:11 +02:00
// msg # 274 : Cannot restore over current database, must be sysdba
// or owner of the existing database.
2001-05-23 15:26:42 +02:00
}
2009-04-17 16:10:11 +02:00
// check the file size specification
2008-12-01 10:21:31 +01:00
for (fil = tdgbl->gbl_sw_files; fil; fil = fil->fil_next)
2008-01-16 07:11:50 +01:00
{
2001-05-23 15:26:42 +02:00
if (fil->fil_size_code != size_n)
2008-01-16 07:11:50 +01:00
{
BURP_error(262, true, fil->fil_name.c_str());
2008-12-01 10:21:31 +01:00
// msg 262 size specification either missing or incorrect for file %s
2008-01-16 07:11:50 +01:00
}
2001-05-23 15:26:42 +02:00
}
return RESTORE;
}
static void burp_output(bool err, const SCHAR* format, ...)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* b u r p _ o u t p u t
*
**************************************
*
* Functional description
* Platform independent output routine.
*
**************************************/
va_list arglist;
2004-07-03 02:13:46 +02:00
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
2001-05-23 15:26:42 +02:00
if (tdgbl->sw_redirect != NOOUTPUT && format[0] != '\0')
2008-01-16 07:11:50 +01:00
{
if (tdgbl->sw_redirect == REDIRECT && tdgbl->output_file != NULL)
{
va_start(arglist, format);
vfprintf(tdgbl->output_file, format, arglist);
va_end(arglist);
}
else
{
va_start(arglist, format);
Firebird::string buf;
buf.vprintf(format, arglist);
va_end(arglist);
if (err)
tdgbl->uSvc->outputError(buf.c_str());
else
tdgbl->uSvc->outputVerbose(buf.c_str());
}
2001-05-23 15:26:42 +02:00
}
}
static void burp_usage(const Switches& switches)
{
/**********************************************
*
* b u r p _ u s a g e
*
**********************************************
*
* Functional description
* print usage information
*
**********************************************/
const SafeArg sa(SafeArg() << switch_char);
const SafeArg dummy;
BURP_print(true, 317); // usage
for (int i = 318; i < 323; ++i)
BURP_msg_put(true, i, dummy); // usage
BURP_print(true, 95); // msg 95 legal switches are
const Switches::in_sw_tab_t* const base = switches.getTable();
for (const Switches::in_sw_tab_t* p = base; p->in_sw; ++p)
{
if (p->in_sw_msg && p->in_sw_optype == boMain)
BURP_msg_put(true, p->in_sw_msg, sa);
}
BURP_print(true, 323); // backup options are
for (const Switches::in_sw_tab_t* p = base; p->in_sw; ++p)
{
if (p->in_sw_msg && p->in_sw_optype == boBackup)
BURP_msg_put(true, p->in_sw_msg, sa);
}
BURP_print(true, 324); // restore options are
for (const Switches::in_sw_tab_t* p = base; p->in_sw; ++p)
{
if (p->in_sw_msg && p->in_sw_optype == boRestore)
BURP_msg_put(true, p->in_sw_msg, sa);
}
2008-12-01 10:21:31 +01:00
BURP_print(true, 325); // general options are
for (const Switches::in_sw_tab_t* p = base; p->in_sw; ++p)
2008-05-23 15:27:47 +02:00
{
if (p->in_sw_msg && p->in_sw_optype == boGeneral)
BURP_msg_put(true, p->in_sw_msg, sa);
2008-05-23 15:27:47 +02:00
}
BURP_print(true, 132); // msg 132 switches can be abbreviated to the unparenthesized characters
}
2009-01-03 10:14:29 +01:00
static ULONG get_size(const SCHAR* string, burp_fil* file)
2001-05-23 15:26:42 +02:00
{
/**********************************************
*
* g e t _ s i z e
*
**********************************************
*
* Functional description
* Get size specification for either splitting or
* restoring to multiple files
*
**********************************************/
const ULONG overflow = MAX_ULONG / 10 - 1;
UCHAR c;
ULONG size = 0;
bool digit = false;
2001-05-23 15:26:42 +02:00
file->fil_size_code = size_n;
2009-01-03 10:14:29 +01:00
for (const SCHAR *num = string; c = *num++;)
{
2009-11-06 02:21:14 +01:00
if (isdigit(c))
{
int val = c - '0';
if (size >= overflow)
{
file->fil_size_code = size_e;
size = 0;
break;
}
size = size * 10 + val;
2003-09-10 19:52:12 +02:00
digit = true;
2001-05-23 15:26:42 +02:00
}
2009-01-03 10:14:29 +01:00
else
{
if (isalpha(c))
{
2009-11-06 11:47:32 +01:00
if (!digit)
{
2001-05-23 15:26:42 +02:00
file->fil_size_code = size_e;
size = 0;
break;
}
2009-01-03 10:14:29 +01:00
switch (UPPER(c))
{
2001-05-23 15:26:42 +02:00
case 'K':
file->fil_size_code = size_k;
break;
case 'M':
file->fil_size_code = size_m;
break;
case 'G':
file->fil_size_code = size_g;
break;
default:
file->fil_size_code = size_e;
size = 0;
break;
}
2009-11-06 11:47:32 +01:00
if (*num)
{
2001-05-23 15:26:42 +02:00
file->fil_size_code = size_e;
size = 0;
}
break;
}
}
}
file->fil_length = size;
2009-01-03 10:14:29 +01:00
return size;
2001-05-23 15:26:42 +02:00
}
#ifndef WIN_NT
void close_platf(DESC file)
{
/**********************************************
*
* c l o s e _ p l a t f
*
**********************************************
*
* Functional description
* Truncate and close file - posix version
*
**********************************************/
if (sizeof(off_t) > 4) // 64 bit or b4-bit IO in 32 bit OS
{
#ifndef O_ACCMODE
// Suppose compatibility with KR where 0, 1, 2 were documented for RO, WO and RW in open() still exists
#define O_ACCMODE 3
#endif
2010-11-21 03:36:57 +01:00
off_t fileSize = lseek(file, 0, SEEK_CUR);
if (fileSize != (off_t)(-1))
{
ftruncate(file, fileSize);
}
}
2010-11-21 03:36:57 +01:00
close(file);
}
#endif // WIN_NT