===================================
License:
-For the most part, Bacula is licensed under the GPL version 2
-this code is listed under Copyright Free Software Foundation
-Europe e.V. What follows are the addition(s) to the GPL version
-2 license, for code that is copyrighted as noted above.
+For the most part, Bacula is licensed under the GPL version 2 this
+code is listed under Copyright Free Software Foundation Europe e.V.
+What follows is the addition(s) to the GPL version 2 license, that
+applys to code that is copyrighted by the Free Software Foundation
+Europe e.V.
Linking:
As a special exception to the GPLv2, the Bacula Project gives
permission to link the code of its release of Bacula with the OpenSSL
project's "OpenSSL" library (or with modified versions of it that use
the same license as the "OpenSSL" library), and distribute the linked
-executables. You must obey the GNU General Public License in all
-respects for all of the code used other than "OpenSSL". If you modify
-a particular file, you may extend this exception to your version of the file,
-but you are not obligated to do so. If you do not wish this exception
-to apply to your code, clearly indicate so in the file.
+executables. You must obey the GNU General Public License in all
+respects for all of the code used other than "OpenSSL".
===================================
Item 1: Accurate restoration of renamed/deleted files
Date: 28 November 2005
Origin: Martin Simmons (martin at lispworks dot com)
- Status: Robert Nelson will implement this
+ Status:
What: When restoring a fileset for a specified date (including "most
recent"), Bacula should give you exactly the files and directories
JobFiles,JobBytes,VolumeName
FROM Client,Job,JobMedia,Media,FileSet
WHERE Client.Name='%1'
- AND Client.ClientId=Job.ClientId
- AND JobStatus='T' AND Job.FileSetId=FileSet.FileSetId
+ AND Client.ClientId=Job.ClientId AND Job.Type='B'
+ AND Job.JobStatus='T' AND Job.FileSetId=FileSet.FileSetId
AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId
ORDER BY Job.StartTime;
# 6
POOLMEM *sd_auth_key;
sd_auth_key = get_memory(dir->msglen);
- if (debug_level == 3) {
- Dmsg1(000, "<dird: %s", dir->msg);
- }
if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
&jcr->VolSessionId, &jcr->VolSessionTime,
sd_auth_key) != 5) {
return 0;
}
jcr->sd_auth_key = bstrdup(sd_auth_key);
- if (debug_level == 3) {
- Dmsg1(000, "sd_auth_key=%s\n", jcr->sd_auth_key);
- }
free_pool_memory(sd_auth_key);
Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
extern QApplication *app;
int bvsnprintf(char *str, int32_t size, const char *format, va_list ap);
+bool isWin32Path(QString &fullPath);
#endif /* _BAT_H_ */
#include "pages.h"
#include "bat.h"
+/* A global function */
+bool isWin32Path(QString &fullPath)
+{
+ char *buf = fullPath.left(2).toUtf8().data();
+
+ return buf[1] == ':' && B_ISALPHA(buf[0]);
+}
+
+
/*
* dockPage
* This function is intended to be called from within the Pages class to pull
{
QString newdir = newdirr;
QString fullpath = m_cwd + newdirr;
- QRegExp regex("^/[a-z]:/$");
bool ok = true;
bool windrive = false;
}
/* add unix '/' directory first */
- if (m_dirPaths.empty() && (regex.indexIn(fullpath,0) == -1)) {
+ if (m_dirPaths.empty() && !isWin32Path(fullpath)) {
QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
m_dirTreeItems.insert(item, text);
}
- if (regex.indexIn(fullpath,0) == 0) {
+ if (isWin32Path(fullpath)) {
/* this is a windows drive */
if (mainWin->m_miscDebug) {
Pmsg0(000, "Need to do windows \"letter\":/\n");
}
- fullpath.replace(0,1,"");
windrive = true;
}
*/
if (item->text(1).endsWith("/")) {
QString fullpath = m_cwd + item->text(1);
- /* check for fullpath = "/c:/" */
- QRegExp regex("^/[a-z]:/");
- if (regex.indexIn(fullpath,0) == 0) /* remove leading '/' */
- fullpath.replace(0,1,"");
QTreeWidgetItem *item = m_dirPaths.value(fullpath);
if (item) {
directoryWidget->setCurrentItem(item);
m_populated = false;
dockPage();
- m_winRegExpDrive.setPattern("^[a-zA-Z]:/$");
- m_winRegExpPath.setPattern("^[a-zA-Z]:/");
- m_slashregex.setPattern("/");
m_debugCnt = 0;
m_debugTrap = true;
Pmsg1(000, "Done with query %i results\n", results.count());
QStringList fieldlist;
foreach(QString resultline, results) {
- m_debugCnt += 1;
- prBar2->setValue(m_debugCnt);
+ /* Update progress bar periodically */
+ if ((++m_debugCnt && 0x3FF) == 0) {
+ prBar2->setValue(m_debugCnt);
+ }
fieldlist = resultline.split("\t");
int fieldcnt = 0;
QString field;
*/
void restoreTree::parseDirectory(QString &dir_in)
{
- /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
+ /* m_debugTrap is to only print debugs for a few occurennces of calling parseDirectory
* instead of printing out what could potentially a whole bunch */
if (m_debugCnt > 2)
m_debugTrap = false;
- /* Clean up the directory string remove some funny char after last '/' */
- QRegExp rgx("[^/]$");
- int lastslash = rgx.indexIn(dir_in);
- if (lastslash != -1)
- dir_in.replace(lastslash, dir_in.length()-lastslash, "");
+ /* Truncate everything after the last / */
+ if (dir_in.right(1) != "/") {
+ dir_in.truncate(dir_in.lastIndexOf("/") + 1);
+ }
if ((mainWin->m_miscDebug) && (m_debugTrap))
Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
/* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
* if not added into tree, then try /etc/ and somedir/ if not added, then try
* / and etc/ . That should succeed, then add the ones that failed in reverse */
- while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
+ while (((index = dir_in.lastIndexOf("/", -2)) != -1) && (!done)) {
direct = path = dir_in;
path.replace(index+1, dir_in.length()-index-1,"");
direct.replace(0, index+1, "");
}
}
+
/*
* Function called from fill directory when a directory is found to see if this
* directory exists in the directory pane and then add it to the directory pane
if (!m_slashTrap) {
/* add unix '/' directory first */
- if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
+ if (m_dirPaths.empty() && isWin32Path(fullPath)) {
m_slashTrap = true;
QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
QString text("/");
m_dirPaths.insert(text, item);
}
/* no need to check for windows drive if unix */
- if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
+ if (isWin32Path(m_cwd)) {
if (!m_dirPaths.contains(m_cwd)) {
/* this is a windows drive add the base widget */
QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
bool done = false;
QString fullPath = fullPath_in;
QString direct, path;
- while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
+ while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
direct = path = fullPath;
path.replace(index+1, fullPath.length()-index-1, "");
direct.replace(0, index+1, "");
{
int qversion = 0;
QString directory, fileName;
- int index = m_slashregex.lastIndexIn(fullPath, -2);
+ int index = fullPath.lastIndexOf("/", -2);
if (index != -1) {
directory = fileName = fullPath;
directory.replace(index+1, fullPath.length()-index-1, "");
{
int qfileIndex = 0;
QString directory, fileName;
- int index = m_slashregex.lastIndexIn(fullPath, -2);
+ int index = fullPath.lastIndexOf("/", -2);
if (index != -1) {
directory = fileName = fullPath;
directory.replace(index+1, fullPath.length()-index-1, "");
bool m_dropdownChanged;
QRegExp m_winRegExpDrive;
QRegExp m_winRegExpPath;
- QRegExp m_slashregex;
bool m_slashTrap;
QHash<QString, QTreeWidgetItem *> m_dirPaths;
QString m_checkedJobs, m_prevJobCombo, m_prevClientCombo, m_prevFileSetCombo;
return false;
}
memset(&vol, 0, sizeof(vol));
- Dmsg2(100, "<dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, "<dird %s", dir->msg);
n = sscanf(dir->msg, OK_media, vol.VolCatName,
&vol.VolCatJobs, &vol.VolCatFiles,
&vol.VolCatBlocks, &vol.VolCatBytes,
&vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
&vol.LabelType, &vol.VolMediaId);
if (n != 22) {
- Dmsg4(100, "Bad response from Dir jid=%u fields=%d, len=%d: %s",
- (uint32_t)jcr->JobId, n, dir->msglen, dir->msg);
+ Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s",
+ n, dir->msglen, dir->msg);
Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
return false;
}
bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
dcr->VolCatInfo = vol; /* structure assignment */
- Dmsg3(100, "do_reqest_vol_info return true jid=%u slot=%d Volume=%s\n",
- (uint32_t)jcr->JobId, vol.Slot, vol.VolCatName);
+ Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
+ vol.Slot, vol.VolCatName);
return true;
}
bash_spaces(dcr->VolCatInfo.VolCatName);
dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
writing==GET_VOL_INFO_FOR_WRITE?1:0);
- Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, ">dird %s", dir->msg);
unbash_spaces(dcr->VolCatInfo.VolCatName);
bool ok = do_get_volume_info(dcr);
V(vol_info_mutex);
dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
unbash_spaces(dcr->media_type);
unbash_spaces(dcr->pool_name);
- Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, ">dird %s", dir->msg);
bool ok = do_get_volume_info(dcr);
if (ok) {
if (!is_volume_in_use(dcr)) {
found = true;
break;
} else {
- Dmsg2(100, "jid=%u Volume %s is in use.\n", (uint32_t)jcr->JobId, dcr->VolumeName);
+ Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
dcr->volume_in_use = true;
continue;
}
edit_int64(vol->VolWriteTime, ed4),
edit_uint64(vol->VolFirstWritten, ed5),
vol->VolCatParts);
- Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, ">dird %s", dir->msg);
/* Do not lock device here because it may be locked from label */
if (!do_get_volume_info(dcr)) {
vol->VolCatName, jcr->errmsg);
goto bail_out;
}
- Dmsg2(420, "get_volume_info() jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(420, "get_volume_info() %s", dir->msg);
/* Update dev Volume info in case something changed (e.g. expired) */
dev->VolCatInfo = dcr->VolCatInfo;
ok = true;
dcr->StartBlock, dcr->EndBlock,
dcr->Copy, dcr->Stripe,
edit_uint64(dcr->VolMediaId, ed1));
- Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, ">dird %s", dir->msg);
if (bnet_recv(dir) <= 0) {
Dmsg0(190, "create_jobmedia error bnet_recv\n");
Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
dir->bstrerror());
return false;
}
- Dmsg2(100, "<dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ Dmsg1(100, "<dird %s", dir->msg);
if (strcmp(dir->msg, OK_create) != 0) {
Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
ser_uint32(rec->data_len);
ser_bytes(rec->data, rec->data_len);
dir->msglen = ser_length(dir->msg);
- Dmsg2(1800, ">dird jid=%u: %s\n", (uint32_t)jcr->JobId, dir->msg); /* Attributes */
+ Dmsg1(1800, ">dird %s\n", dir->msg); /* Attributes */
return dir->send();
}
class VOLRES {
public:
dlink link;
- char *vol_name;
- DEVICE *dev;
+ char *vol_name; /* Volume name */
+ DEVICE *dev; /* Pointer to device to which we are attached */
+ bool released; /* set when the Volume can be released */
};
if (dev) {
len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
sendit(msg.c_str(), len, arg);
- len = Mmsg(msg, " Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0,
- dev->num_writers, dev->reserved_device);
+ len = Mmsg(msg, " Reader=%d writers=%d reserved=%d released=%d\n",
+ dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released);
sendit(msg.c_str(), len, arg);
} else {
- len = Mmsg(msg, "%s no dev\n", vol->vol_name);
+ len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released);
sendit(msg.c_str(), len, arg);
}
}
Dmsg3(dbglvl, "Volume busy could not swap vol=%s from dev=%s to %s\n",
VolumeName, vol->dev->print_name(), dev->print_name());
vol = NULL; /* device busy */
+ goto get_out;
}
}
}
dev->vol = vol;
get_out:
+ if (vol) {
+ vol->released = false;
+ }
debug_list_volumes("end new volume");
unlock_volumes();
return vol;
* explicitly read in this drive. This allows the SD to remember
* where the tapes are or last were.
*/
+ dev->vol->released = true;
if (dev->is_tape() || dev->is_autochanger()) {
return true;
} else {
if (vol->dev) {
Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
} else {
- Dmsg2(dbglvl, "free vol_list Volume=%s dev=%p\n", vol->vol_name, vol->dev);
+ Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
}
free(vol->vol_name);
vol->vol_name = NULL;
{
char *p, *q;
- if ((p = strchr(from_addr, '<')) == NULL) {
+ if ((p = strchr(addr, '<')) == NULL) {
snprintf(buf, buf_len, "<%s>", addr);
} else {
/* Copy <addr> */
#undef VERSION
#define VERSION "2.3.6"
-#define BDATE "30 September 2007"
-#define LSMDATE "30Sep07"
+#define BDATE "05 October 2007"
+#define LSMDATE "05Oct07"
#define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n"
#define BYEAR "2007" /* year for copyright messages in progs */
Technical notes on version 2.3
General:
+05Oct07
+kes Fix listing performance problems in bat. Pointed out by
+ Chris Howells.
+kes Remove old debug code.
+kes Fix bat code that tests for Win32. This should fix bug #968
+kes Query 5 list wrong Vol after migration. This fixes bug #960
04Oct07
-ebl Fix #969 where user can't change Replace option in
- restore menu.
-30Sep07
+ebl Fix #969 where user can't change Replace option in restore menu.
+5ASep07
kes Save jcr in thread specific data (tsd) for each thread.
kes Make Dmsg() print JobId as -%u.
kes Make Jmsg, Emsg, and others automatically pickup the jobid
This reduces unnecessary error messages.
24Sep07
kes Correct search boolean for getting Volume info
-ebl Cleanup batch code. Probably fixes bug #965.
+ebl Cleanup batch insert code. Probably fixes bug #965.
kes Back out one small change to the reservation system (reserving a volume).
kes Rework how a Volume is mounted. It is now much more intelligent and
will always attempt to use any mounted volume if possible and reduces