several other utility programs.
- Full listing of most catalog records (llist command).
- Relabel Purged tapes with the relabel command.
-- Correct misentered path separators on Win32 systems to
+- Correct backwards path separators on Win32 systems to
prevent creating files names with mixed conventions.
- Print IP address on failed connections to servers.
- Cancel command works much better (cancels waiting jobs in Dir
and in SD).
- Now have reasonable (but still small) regression script.
-- New Console commands for aiding scripting (input, output, tee,
- time, wait).
+- New Console commands for aiding scripting (@input, @output, @tee,
+ @time, @version and wait).
Items to note:
- Version 1.29 File daemons can be used with version 1.30. However,
- Fix "access not allowed" for backup of files on WinXP.
- Document new transparent Console commands and wait command.
- Document new immediate File save capability.
+- Document OPTIMIZE TABLE in MySQL
+- Fix watchdog pthread crash on Win32
- Figure out how to use ssh or stunnel to protect Bacula communications.
- Make | and < work on FD side.
- Pass prefix_links to FD.
- Implement a M_SECURITY message class.
+- Implement disk spooling. Two parts: 1. Spool to disk then
+ immediately to tape to speed up tape operations. 2. Spool to
+ disk only when the tape is full, then when a tape is hung move
+ it to tape.
+- From Phil Stracchino:
+ It would probably be a per-client option, and would be called
+ something like, say, "Automatically purge obsoleted jobs". What it
+ would do is, when you successfully complete a Differential backup of a
+ client, it would automatically purge all Incremental backups for that
+ client that are rendered redundant by that Differential. Likewise,
+ when a Full backup on a client completed, it would automatically purge
+ all Differential and Incremental jobs obsoleted by that Full backup.
+ This would let people minimize the number of tapes they're keeping on
+ hand without having to master the art of retention times.
+
- Allow multiple Storage specifications (or multiple names on
a single Storage specification) in the Job record. Thus a job
can be backed up to a number of storage devices.
- Why are save/restore of device different sizes (sparse?) Yup! Fix it.
- Implement some way for the Console to dynamically create a job.
- Restore to a particular time -- e.g. before date, after date.
-- Implement disk spooling
- Solaris -I on tar for include list
- Prohibit backing up archive device (findlib/find_one.c:128)
- Need a verbose mode in restore, perhaps to bsr.
#define STREAM_PROGRAM_NAMES 8 /* program names for program data */
#define STREAM_PROGRAM_DATA 9 /* Data needing program */
#define STREAM_SHA1_SIGNATURE 10 /* SHA1 signature for the file */
+#define STREAM_WIN32_DATA 11 /* Win32 BackupRead data */
+#define STREAM_WIN32_GZIP_DATA 12 /* Gzipped Win32 BackupRead data */
/*
* Internal code for Signature types
$(LIBS) $(DLIB) $(CONS_LIBS) -lbac -lsql -lm
static-console: $(CONSOBJS) ../lib/libbac.a ../cats/libsql.a
- $(CXX) $(LDFLAGS) $(CONS_LDFLAGS) -L../lib -L../cats -o $@ $(CONSOBJS) \
+ $(CXX) -static $(LDFLAGS) $(CONS_LDFLAGS) -L../lib -L../cats -o $@ $(CONSOBJS) \
$(LIBS) $(DLIB) $(CONS_LIBS) -lbac -lsql -lm
strip $@
*/
int waitcmd(UAContext *ua, char *cmd)
{
- usleep(300000);
+ usleep(500000);
for (int running=1; running; ) {
running = 0;
lock_jcr_chain();
client = NULL;
for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
{ }
- unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
+ unique_client = (CLIENT **)malloc(i * sizeof(CLIENT));
/* Find Unique Client address/port */
client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
i = 0;
if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
store->hdr.name);
+ if (ua->jcr->store_bsock) {
+ bnet_close(ua->jcr->store_bsock);
+ ua->jcr->store_bsock = NULL;
+ }
return;
}
Dmsg0(20, _("Connected to storage daemon\n"));
if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
client->hdr.name);
+ if (ua->jcr->file_bsock) {
+ bnet_close(ua->jcr->file_bsock);
+ ua->jcr->file_bsock = NULL;
+ }
return;
}
Dmsg0(20, _("Connected to file daemon\n"));
return 1;
}
+ binit(&ff_pkt->bfd, jcr->use_win_backup_api);
+
/* Open any file with data that we intend to save */
if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
ff_pkt->statp.st_size > 0) ||
}
if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
ff_pkt->ff_errno = errno;
- Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+ Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname,
+ berror(&ff_pkt->bfd));
stop_thread_timer(tid);
return 1;
}
stop_thread_timer(tid);
- } else {
- binit(&ff_pkt->bfd); /* mark file not opened */
}
Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
* Send Attributes header to Storage daemon
* <file-index> <stream> <info>
*/
-/* #ifndef FD_NO_SEND_TEST */
if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
if (is_bopen(&ff_pkt->bfd)) {
bclose(&ff_pkt->bfd);
return 0;
}
bnet_sig(sd, BNET_EOD); /* indicate end of attributes data */
-/* #endif */
/*
* If the file has data, read it and send to the Storage daemon
}
#endif
-/* #ifndef FD_NO_SEND_TEST */
/*
* Send Data header to Storage daemon
* <file-index> <stream> <info>
return 0;
}
Dmsg1(100, ">stored: datahdr %s\n", sd->msg);
-/* #endif */
if (ff_pkt->flags & FO_MD5) {
MD5Init(&md5c);
}
#endif
-/* #ifndef FD_NO_SEND_TEST */
+ /* #ifndef FD_NO_SEND_TEST */
/* Send the buffer to the Storage daemon */
if (!sparseBlock) {
if (ff_pkt->flags & FO_SPARSE) {
}
}
Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
-/* #endif */
+ /* #endif */
jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */
sd->msg = msgsave; /* restore read buffer */
} /* end while read file data */
+
if (sd->msglen < 0) {
Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
- ff_pkt->fname, strerror(errno));
+ ff_pkt->fname, berror(&ff_pkt->bfd));
}
bclose(&ff_pkt->bfd); /* close file */
-/* #ifndef FD_NO_SEND_TEST */
if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */
set_jcr_job_status(jcr, JS_ErrorTerminated);
return 0;
}
-/* #endif */
}
/* Terminate any MD5 signature and send it to Storage daemon and the Director */
if (gotMD5 && ff_pkt->flags & FO_MD5) {
MD5Final(signature, &md5c);
-/* #ifndef FD_NO_SEND_TEST */
bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_MD5_SIGNATURE);
Dmsg1(100, "bfiled>stored:header %s\n", sd->msg);
memcpy(sd->msg, signature, 16);
sd->msglen = 16;
bnet_send(sd);
bnet_sig(sd, BNET_EOD); /* end of MD5 */
-/* #endif */
gotMD5 = 0;
} else if (gotSHA1 && ff_pkt->flags & FO_SHA1) {
/* Terminate any SHA1 signature and send it to Storage daemon and the Director */
SHA1Final(&sha1c, signature);
-/* #ifndef FD_NO_SEND_TEST */
bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_SHA1_SIGNATURE);
Dmsg1(100, "bfiled>stored:header %s\n", sd->msg);
memcpy(sd->msg, signature, 20);
sd->msglen = 20;
bnet_send(sd);
bnet_sig(sd, BNET_EOD); /* end of SHA1 */
-/* #endif */
gotMD5 = 0;
}
return 1;
jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
jcr->dir_bsock = dir;
jcr->ff = init_find_files();
+ jcr->use_win_backup_api = 0;
jcr->start_time = time(NULL);
jcr->last_fname = get_pool_memory(PM_FNAME);
jcr->last_fname[0] = 0;
}
jcr->sd_auth_key = bstrdup(sd_auth_key);
free_pool_memory(sd_auth_key);
+ if (jcr->use_win_backup_api) {
+ SetServicePrivileges(jcr);
+ }
Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
return bnet_fsend(dir, OKjob);
}
wherelen = strlen(jcr->where);
- binit(&bfd);
+ binit(&bfd, jcr->use_win_backup_api);
sd = jcr->store_bsock;
set_jcr_job_status(jcr, JS_Running);
extract = FALSE;
stat = create_file(jcr, fname, ofile, lname, type,
- stream, &statp, attribsEx, &bfd, jcr->replace);
+ stream, &statp, attribsEx, &bfd, jcr->replace,
+ jcr->use_win_backup_api);
switch (stat) {
case CF_ERROR:
case CF_SKIP:
fileAddr = faddr;
if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
- edit_uint64(fileAddr, ec1), ofile, strerror(errno));
+ edit_uint64(fileAddr, ec1), ofile, berror(&bfd));
goto bail_out;
}
}
Dmsg2(30, "Write %u bytes, total before write=%u\n", wsize, total);
if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) {
Dmsg0(0, "===Write error===\n");
- Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), ofile, berror(&bfd));
goto bail_out;
}
total += wsize;
fileAddr = faddr;
if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
- edit_uint64(fileAddr, ec1), ofile, strerror(errno));
+ edit_uint64(fileAddr, ec1), ofile, berror(&bfd));
goto bail_out;
}
}
Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
if ((uLong)bwrite(&bfd, jcr->compress_buf, compress_len) != compress_len) {
Dmsg0(0, "===Write error===\n");
- Jmsg2(jcr, M_ERROR, 0, "Write error on %s: %s\n", ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, "Write error on %s: %s\n", ofile, berror(&bfd));
goto bail_out;
}
total += compress_len;
return 1;
}
+ binit(&bfd, jcr->use_win_backup_api);
if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
ff_pkt->statp.st_size > 0) ||
ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) {
if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0)) < 0) {
ff_pkt->ff_errno = errno;
- Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+ Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"),
+ ff_pkt->fname, berror(&bfd));
return 1;
}
- } else {
- binit(&bfd);
}
encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI);
pm_strcpy(&jcr->last_fname, ff_pkt->fname);
V(jcr->mutex);
-
/*
* Send file attributes to Director
* File_index
}
if (n < 0) {
Jmsg(jcr, M_WARNING, -1, _("Error reading file %s: ERR=%s\n"),
- ff_pkt->fname, strerror(errno));
+ ff_pkt->fname, berror(&bfd));
}
MD5Final(signature, &md5c);
}
if (n < 0) {
Jmsg(jcr, M_WARNING, -1, _("Error reading file %s: ERR=%s\n"),
- ff_pkt->fname, strerror(errno));
+ ff_pkt->fname, berror(&bfd));
}
SHA1Final(&sha1c, signature);
#include "jcr.h"
#ifdef HAVE_CYGWIN
-#include <windows.h>
/* Forward referenced subroutines */
static
int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname,
- int type, int stream, struct stat *statp,
- char *attribsEx, BFILE *ofd);
+ int type, int stream, struct stat *statp,
+ char *attribsEx, BFILE *ofd);
void unix_name_to_win32(POOLMEM **win32_name, char *name);
-extern "C" HANDLE get_osfhandle(int fd);
void win_error(void *jcr, char *prefix, POOLMEM *ofile);
+HANDLE bget_handle(BFILE *bfd);
#endif
/* For old systems that don't have lchown() use chown() */
#endif
/*=============================================================*/
-/* */
-/* *** A l l S y s t e m s *** */
-/* */
+/* */
+/* *** A l l S y s t e m s *** */
+/* */
/*=============================================================*/
* NOTE: we should use rdev as major and minor device if
* it is a block or char device (S_ISCHR(statp->st_mode)
* or S_ISBLK(statp->st_mode)). In all other cases,
- * it is not used.
+ * it is not used.
*
*/
p += to_base64((int64_t)statp->st_dev, p);
p += to_base64((int64_t)statp->st_ctime, p);
*p++ = ' ';
p += to_base64((int64_t)LinkFI, p);
+
/* FreeBSD function */
#ifdef HAVE_CHFLAGS
*p++ = ' ';
p += from_base64(&val, p);
statp->st_dev = val;
- p++; /* skip space */
+ p++; /* skip space */
p += from_base64(&val, p);
statp->st_ino = val;
p++;
} else {
*LinkFI = 0;
}
+
/* FreeBSD user flags */
#ifdef HAVE_CHFLAGS
if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
* ofile is the output filename (may be in a different directory)
*
* Returns: 1 on success
- * 0 on failure
+ * 0 on failure
*/
int set_attributes(void *jcr, char *fname, char *ofile, char *lname,
- int type, int stream, struct stat *statp,
- char *attribsEx, BFILE *ofd)
+ int type, int stream, struct stat *statp,
+ char *attribsEx, BFILE *ofd)
{
- struct utimbuf ut;
+ struct utimbuf ut;
mode_t old_mask;
int stat = 1;
#ifdef HAVE_CYGWIN
if (set_win32_attributes(jcr, fname, ofile, lname, type, stream,
- statp, attribsEx, ofd)) {
+ statp, attribsEx, ofd)) {
return 1;
}
/*
* If Windows stuff failed, e.g. attempt to restore Unix file
- * to Windows, simply fall through and we will do it the
+ * to Windows, simply fall through and we will do it the
* universal way.
*/
#endif
old_mask = umask(0);
if (is_bopen(ofd)) {
- bclose(ofd); /* first close file */
+ bclose(ofd); /* first close file */
}
ut.actime = statp->st_atime;
/* ***FIXME**** optimize -- don't do if already correct */
/*
* For link, change owner of link using lchown, but don't
- * try to do a chmod as that will update the file behind it.
+ * try to do a chmod as that will update the file behind it.
*/
if (type == FT_LNK) {
/* Change owner of link, not of real file */
if (lchown(ofile, statp->st_uid, statp->st_gid) < 0) {
Jmsg2(jcr, M_WARNING, 0, "Unable to set file owner %s: ERR=%s\n",
- ofile, strerror(errno));
- stat = 0;
+ ofile, strerror(errno));
+ stat = 0;
}
} else {
if (chown(ofile, statp->st_uid, statp->st_gid) < 0) {
Jmsg2(jcr, M_WARNING, 0, "Unable to set file owner %s: ERR=%s\n",
- ofile, strerror(errno));
- stat = 0;
+ ofile, strerror(errno));
+ stat = 0;
}
if (chmod(ofile, statp->st_mode) < 0) {
Jmsg2(jcr, M_WARNING, 0, "Unable to set file modes %s: ERR=%s\n",
- ofile, strerror(errno));
- stat = 0;
+ ofile, strerror(errno));
+ stat = 0;
}
/* FreeBSD user flags */
#ifdef HAVE_CHFLAGS
if (chflags(ofile, statp->st_flags) < 0) {
Jmsg2(jcr, M_WARNING, 0, "Unable to set file flags %s: ERR=%s\n",
- ofile, strerror(errno));
- stat = 0;
+ ofile, strerror(errno));
+ stat = 0;
}
-
#endif
/*
* Reset file times.
*/
if (utime(ofile, &ut) < 0) {
Jmsg2(jcr, M_ERROR, 0, "Unable to set file times %s: ERR=%s\n",
- ofile, strerror(errno));
- stat = 0;
+ ofile, strerror(errno));
+ stat = 0;
}
}
umask(old_mask);
/*=============================================================*/
-/* */
-/* * * * U n i x * * * * */
-/* */
+/* */
+/* * * * U n i x * * * * */
+/* */
/*=============================================================*/
#ifndef HAVE_CYGWIN
*/
int encode_attribsEx(void *jcr, char *attribsEx, FF_PKT *ff_pkt)
{
- *attribsEx = 0; /* no extended attributes */
+ *attribsEx = 0; /* no extended attributes */
return STREAM_UNIX_ATTRIBUTES;
}
+void SetServicePrivileges(void *jcr)
+ { }
+
+
#endif
/*=============================================================*/
-/* */
-/* * * * W i n 3 2 * * * * */
-/* */
+/* */
+/* * * * W i n 3 2 * * * * */
+/* */
/*=============================================================*/
#ifdef HAVE_CYGWIN
WIN32_FILE_ATTRIBUTE_DATA atts;
ULARGE_INTEGER li;
- attribsEx[0] = 0; /* no extended attributes */
+ attribsEx[0] = 0; /* no extended attributes */
if (NoGetFileAttributesEx) {
return STREAM_UNIX_ATTRIBUTES;
unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
if (!GetFileAttributesEx(ff_pkt->sys_fname, GetFileExInfoStandard,
- (LPVOID)&atts)) {
+ (LPVOID)&atts)) {
win_error(jcr, "GetFileAttributesEx:", ff_pkt->sys_fname);
return STREAM_WIN32_ATTRIBUTES;
}
FILE_ATTRIBUTE_OFFLINE| \
FILE_ATTRIBUTE_READONLY| \
FILE_ATTRIBUTE_SYSTEM| \
- FILE_ATTRIBUTE_TEMPORARY)
+ FILE_ATTRIBUTE_TEMPORARY)
/*
* ofile is the output filename (may be in a different directory)
*
* Returns: 1 on success
- * 0 on failure
+ * 0 on failure
*/
static
int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname,
- int type, int stream, struct stat *statp,
- char *attribsEx, BFILE *ofd)
+ int type, int stream, struct stat *statp,
+ char *attribsEx, BFILE *ofd)
{
char *p = attribsEx;
int64_t val;
int stat;
POOLMEM *win32_ofile;
- if (!p || !*p) { /* we should have attributes */
+ if (!p || !*p) { /* we should have attributes */
Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", ofile, ofd->fid);
if (is_bopen(ofd)) {
- bclose(ofd);
+ bclose(ofd);
}
return 0;
} else {
p += from_base64(&val, p);
atts.dwFileAttributes = val;
- p++; /* skip space */
+ p++; /* skip space */
p += from_base64(&val, p);
li.QuadPart = val;
atts.ftCreationTime.dwLowDateTime = li.LowPart;
atts.ftCreationTime.dwHighDateTime = li.HighPart;
- p++; /* skip space */
+ p++; /* skip space */
p += from_base64(&val, p);
li.QuadPart = val;
atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
- p++; /* skip space */
+ p++; /* skip space */
p += from_base64(&val, p);
li.QuadPart = val;
atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
if (!is_bopen(ofd)) {
Dmsg1(100, "File not open: %s\n", ofile);
- bopen(ofd, ofile, O_RDWR|O_BINARY, 0); /* attempt to open the file */
+ bopen(ofd, ofile, O_WRONLY|O_BINARY, 0); /* attempt to open the file */
}
if (is_bopen(ofd)) {
Dmsg1(100, "SetFileTime %s\n", ofile);
- stat = SetFileTime(get_osfhandle(ofd->fid),
- &atts.ftCreationTime,
- &atts.ftLastAccessTime,
- &atts.ftLastWriteTime);
+ stat = SetFileTime(bget_handle(ofd),
+ &atts.ftCreationTime,
+ &atts.ftLastAccessTime,
+ &atts.ftLastWriteTime);
if (stat != 1) {
win_error(jcr, "SetFileTime:", win32_ofile);
}
DWORD lerror = GetLastError();
LPTSTR msg;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- lerror,
- 0,
- (LPTSTR)&msg,
- 0,
- NULL);
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ lerror,
+ 0,
+ (LPTSTR)&msg,
+ 0,
+ NULL);
Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
+ strip_trailing_junk(msg);
Jmsg3(jcr, M_INFO, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
LocalFree(msg);
}
cygwin_conv_to_win32_path(name, *win32_name);
}
-#endif /* HAVE_CYGWIN */
+/*
+ * Setup privileges we think we will need. We probably do not need
+ * the SE_SECURITY_NAME, but since nothing seems to be working,
+ * we get it hoping to fix the problems.
+ */
+void SetServicePrivileges(void *jcr)
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tkp;
+ POOLMEM *dummy = "*none*";
+ // Get a token for this process.
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ win_error(jcr, "OpenProcessToken", dummy);
+ /* Forge on anyway */
+ }
+
+ // Get the LUID for the security privilege.
+ if (!LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tkp.Privileges[0].Luid)) {
+ win_error(jcr, "LookupPrivilegeValue", dummy);
+ }
+
+ tkp.PrivilegeCount = 1; // one privilege to set
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ // Get the security privilege for this process.
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES),
+ (PTOKEN_PRIVILEGES)NULL, (PDWORD)0)) {
+ win_error(jcr, "AdjustTokenPrivileges SE_PRIVILEGE_ENABLED", dummy);
+// MessageBox(NULL, "Get security priv failed: AdjustTokePrivileges", "backup", MB_OK);
+ }
+
+ // Get the LUID for the backup privilege.
+ if (!LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tkp.Privileges[0].Luid)) {
+ win_error(jcr, "LookupPrivilegeValue", dummy);
+ }
+
+ tkp.PrivilegeCount = 1; // one privilege to set
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ // Get the backup privilege for this process.
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES),
+ (PTOKEN_PRIVILEGES)NULL, (PDWORD)0)) {
+ win_error(jcr, "AdjustTokenPrivileges SE_BACKUP_NAME", dummy);
+// MessageBox(NULL, "Get backup priv failed: AdjustTokePrivileges", "backup", MB_OK);
+ }
+
+ // Get the LUID for the restore privilege.
+ if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tkp.Privileges[0].Luid)) {
+ win_error(jcr, "LookupPrivilegeValue", dummy);
+ }
+
+ tkp.PrivilegeCount = 1; // one privilege to set
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ // Get the restore privilege for this process.
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES),
+ (PTOKEN_PRIVILEGES)NULL, (PDWORD)0)) {
+ win_error(jcr, "AdjustTokenPrivileges SE_RESTORE_NAME", dummy);
+// MessageBox(NULL, "Get restore priv failed: AdjustTokePrivileges", "restore", MB_OK);
+ }
+}
+
+
+#endif /* HAVE_CYGWIN */
#include "bacula.h"
#include "find.h"
+#ifdef HAVE_CYGWIN
-void binit(BFILE *bfd)
+void unix_name_to_win32(POOLMEM **win32_name, char *name);
+extern "C" HANDLE get_osfhandle(int fd);
+
+
+void binit(BFILE *bfd, int use_win_api)
+{
+ bfd->fid = -1;
+ bfd->mode = BF_CLOSED;
+ bfd->use_win_api = use_win_api;
+ bfd->errmsg = NULL;
+ bfd->lpContext = NULL;
+ bfd->lerror = 0;
+}
+
+HANDLE bget_handle(BFILE *bfd)
+{
+ if (!bfd->use_win_api) {
+ return get_osfhandle(bfd->fid);
+ }
+ return bfd->fh;
+}
+
+int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
+{
+ POOLMEM *win32_fname;
+ if (!bfd->use_win_api) {
+ bfd->fid = open(fname, flags, mode);
+ if (bfd->fid >= 0) {
+ bfd->mode = BF_READ; /* not important if BF_READ or BF_WRITE */
+ }
+ return bfd->fid;
+ }
+
+ /* Convert to Windows path format */
+ win32_fname = get_pool_memory(PM_FNAME);
+ unix_name_to_win32(&win32_fname, (char *)fname);
+
+ if (flags & O_WRONLY) { /* creating */
+ bfd->fh = CreateFile(win32_fname,
+ WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY, /* access */
+ 0, /* shared mode */
+ NULL, /* SecurityAttributes */
+ CREATE_ALWAYS, /* CreationDisposition */
+ FILE_FLAG_BACKUP_SEMANTICS, /* Flags and attributes */
+ NULL); /* TemplateFile */
+
+ if (bfd->fh == INVALID_HANDLE_VALUE) {
+ bfd->lerror = GetLastError();
+ bfd->mode = BF_CLOSED;
+ } else {
+ bfd->mode = BF_WRITE;
+ }
+ } else {
+ bfd->fh = CreateFile(win32_fname,
+ READ_CONTROL|ACCESS_SYSTEM_SECURITY, /* access */
+ 0, /* shared mode */
+ NULL, /* SecurityAttributes */
+ OPEN_EXISTING, /* CreationDisposition */
+ FILE_FLAG_BACKUP_SEMANTICS, /* Flags and attributes */
+ NULL); /* TemplateFile */
+
+ if (bfd->fh == INVALID_HANDLE_VALUE) {
+ bfd->lerror = GetLastError();
+ bfd->mode = BF_CLOSED;
+ } else {
+ bfd->mode = BF_READ;
+ }
+ }
+ bfd->errmsg = NULL;
+ bfd->lpContext = NULL;
+ return bfd->mode == BF_CLOSED ? -1 : 1;
+}
+
+/*
+ * Returns 0 on success
+ * -1 on error
+ */
+int bclose(BFILE *bfd)
+{
+ int stat = 0;
+ if (!bfd->use_win_api) {
+ int stat = close(bfd->fid);
+ bfd->fid = -1;
+ bfd->mode = BF_CLOSED;
+ return stat;
+ }
+ if (bfd->errmsg) {
+ free_pool_memory(bfd->errmsg);
+ bfd->errmsg = NULL;
+ }
+ if (bfd->mode == BF_CLOSED) {
+ return 0;
+ }
+ if (bfd->mode == BF_READ) {
+ BYTE buf[10];
+ if (!bfd->lpContext && !BackupRead(bfd->fh,
+ buf, /* buffer */
+ (DWORD)0, /* bytes to read */
+ &bfd->rw_bytes, /* bytes read */
+ 1, /* Abort */
+ 1, /* ProcessSecurity */
+ &bfd->lpContext)) { /* Read context */
+ stat = -1;
+ }
+ } else {
+ BYTE buf[10];
+ if (!bfd->lpContext && !BackupWrite(bfd->fh,
+ buf, /* buffer */
+ (DWORD)0, /* bytes to read */
+ &bfd->rw_bytes, /* bytes written */
+ 1, /* Abort */
+ 1, /* ProcessSecurity */
+ &bfd->lpContext)) { /* Write context */
+ stat = -1;
+ }
+ }
+ if (!CloseHandle(bfd->fh)) {
+ stat = -1;
+ }
+ bfd->mode = BF_CLOSED;
+ bfd->lpContext = NULL;
+ return stat;
+}
+
+/*
+ * Generate error message
+ */
+char *berror(BFILE *bfd)
+{
+ LPTSTR msg;
+
+ if (!bfd->use_win_api) {
+ return strerror(errno);
+ }
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ bfd->lerror,
+ 0,
+ (LPTSTR)&msg,
+ 0,
+ NULL);
+ strip_trailing_junk(msg);
+ if (!bfd->errmsg) {
+ bfd->errmsg = get_pool_memory(PM_FNAME);
+ }
+ pm_strcpy(&bfd->errmsg, msg);
+ LocalFree(msg);
+ return bfd->errmsg;
+}
+
+/* Returns: bytes read on success
+ * 0 on EOF
+ * -1 on error
+ */
+ssize_t bread(BFILE *bfd, void *buf, size_t count)
+{
+ if (!bfd->use_win_api) {
+ return read(bfd->fid, buf, count);
+ }
+
+ bfd->rw_bytes = 0;
+ BackupRead(bfd->fh,
+ (BYTE *)buf,
+ count,
+ &bfd->rw_bytes,
+ 0, /* no Abort */
+ 1, /* Process Security */
+ &bfd->lpContext); /* Context */
+ if (bfd->rw_bytes > 0) {
+ return (ssize_t)bfd->rw_bytes;
+ }
+ bfd->lerror = GetLastError();
+ return bfd->lerror == 0 ? 0 : -1;
+}
+
+ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
+{
+ DWORD bytes_written = 0;
+ if (!bfd->use_win_api) {
+ return write(bfd->fid, buf, count);
+ }
+ BackupWrite(bfd->fh,
+ (BYTE *)buf,
+ count,
+ &bytes_written,
+ 0, /* No abort */
+ 1, /* Process Security */
+ &bfd->lpContext); /* Context */
+
+ if ((size_t)bfd->rw_bytes == count) {
+ return (ssize_t)bfd->rw_bytes;
+ }
+ bfd->lerror = GetLastError();
+ return bfd->lerror == 0 ? (ssize_t)bfd->rw_bytes : -1;
+}
+
+int is_bopen(BFILE *bfd)
+{
+ return bfd->mode != BF_CLOSED;
+}
+
+off_t blseek(BFILE *bfd, off_t offset, int whence)
+{
+ if (!bfd->use_win_api) {
+ return lseek(bfd->fid, offset, whence);
+ }
+ return -1;
+}
+
+#else /* Unix systems */
+
+/* ===============================================================
+ *
+ * U N I X
+ *
+ * ===============================================================
+ */
+void binit(BFILE *bfd, int use_win_api)
{
bfd->fid = -1;
}
-int bopen(BFILE *bfd, const char *pathname, int flags, mode_t mode)
+int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
{
- return bfd->fid = open(pathname, flags, mode);
+ return bfd->fid = open(fname, flags, mode);
}
int bclose(BFILE *bfd)
{
return lseek(bfd->fid, offset, whence);
}
+
+char *berror(BFILE *bfd)
+{
+ return strerror(errno);
+}
+
+#endif
*/
int create_file(void *jcr, char *fname, char *ofile, char *lname,
int type, int stream, struct stat *statp,
- char *attribsEx, BFILE *ofd, int replace)
+ char *attribsEx, BFILE *ofd, int replace, int win_io)
{
int new_mode, parent_mode, mode;
uid_t uid;
int stat = 0;
int pnl;
- binit(ofd);
+ binit(ofd, win_io);
new_mode = statp->st_mode;
Dmsg2(300, "newmode=%x file=%s\n", new_mode, ofile);
parent_mode = S_IWUSR | S_IXUSR | new_mode;
}
Dmsg1(50, "Create file: %s\n", ofile);
if ((bopen(ofd, ofile, mode, S_IRUSR | S_IWUSR)) < 0) {
- Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, berror(ofd));
return CF_ERROR;
}
return CF_EXTRACT;
if (S_ISFIFO(statp->st_mode)) {
Dmsg1(200, "Restore fifo: %s\n", ofile);
if (mkfifo(ofile, statp->st_mode) != 0 && errno != EEXIST) {
- Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), ofile, berror(ofd));
return CF_ERROR;
}
} else {
Dmsg1(200, "Restore node: %s\n", ofile);
if (mknod(ofile, statp->st_mode, statp->st_rdev) != 0 && errno != EEXIST) {
- Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), ofile, berror(ofd));
return CF_ERROR;
}
}
tid = NULL;
}
if ((bopen(ofd, ofile, mode, 0)) < 0) {
- Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, berror(ofd));
stop_thread_timer(tid);
return CF_ERROR;
}
case FT_LNK:
Dmsg2(130, "FT_LNK should restore: %s -> %s\n", ofile, lname);
if (symlink(lname, ofile) != 0 && errno != EEXIST) {
- Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
- ofile, lname, strerror(errno));
+ Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
+ ofile, lname, berror(ofd));
return CF_ERROR;
}
return CF_CREATED;
case FT_LNKSAVED: /* Hard linked, file already saved */
Dmsg2(130, "Hard link %s => %s\n", ofile, lname);
if (link(lname, ofile) != 0) {
- Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s ==> %s: ERR=%s\n"),
- ofile, lname, strerror(errno));
+ Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s ==> %s: ERR=%s\n"),
+ ofile, lname, berror(ofd));
return CF_ERROR;
}
return CF_CREATED;
case FT_DIR:
Dmsg2(300, "Make dir mode=%o dir=%s\n", new_mode, ofile);
if (make_path(jcr, ofile, new_mode, parent_mode, uid, gid, 0, NULL) != 0) {
- Jmsg1(jcr, M_ERROR, 0, _("Could not make directory: %s\n"), ofile);
+ Jmsg2(jcr, M_ERROR, 0, _("Could not make directory %s: ERR=%s.\n"),
+ ofile, berror(ofd));
return CF_ERROR;
}
return CF_CREATED;
/*
* Status codes returned by create_file()
*/
-#define CF_SKIP 1 /* skip file (not newer or something) */
-#define CF_ERROR 2 /* error creating file */
-#define CF_EXTRACT 3 /* file created, data to extract */
-#define CF_CREATED 4 /* file created, no data to extract */
+#define CF_SKIP 1 /* skip file (not newer or something) */
+#define CF_ERROR 2 /* error creating file */
+#define CF_EXTRACT 3 /* file created, data to extract */
+#define CF_CREATED 4 /* file created, no data to extract */
/*
* NOTE!!! These go on the tape, so don't change them. If
* need be, add to them.
*/
-#define FT_LNKSAVED 1 /* hard link to file already saved */
-#define FT_REGE 2 /* Regular file but empty */
-#define FT_REG 3 /* Regular file */
-#define FT_LNK 4 /* Soft Link */
-#define FT_DIR 5 /* Directory */
-#define FT_SPEC 6 /* Special file -- chr, blk, fifo, sock */
-#define FT_NOACCESS 7 /* Not able to access */
-#define FT_NOFOLLOW 8 /* Could not follow link */
-#define FT_NOSTAT 9 /* Could not stat file */
-#define FT_NOCHG 10 /* Incremental option, file not changed */
-#define FT_DIRNOCHG 11 /* Incremental option, directory not changed */
-#define FT_ISARCH 12 /* Trying to save archive file */
-#define FT_NORECURSE 13 /* No recursion into directory */
-#define FT_NOFSCHG 14 /* Different file system, prohibited */
-#define FT_NOOPEN 15 /* Could not open directory */
-#define FT_RAW 16 /* Raw block device */
-#define FT_FIFO 17 /* Raw fifo device */
+#define FT_LNKSAVED 1 /* hard link to file already saved */
+#define FT_REGE 2 /* Regular file but empty */
+#define FT_REG 3 /* Regular file */
+#define FT_LNK 4 /* Soft Link */
+#define FT_DIR 5 /* Directory */
+#define FT_SPEC 6 /* Special file -- chr, blk, fifo, sock */
+#define FT_NOACCESS 7 /* Not able to access */
+#define FT_NOFOLLOW 8 /* Could not follow link */
+#define FT_NOSTAT 9 /* Could not stat file */
+#define FT_NOCHG 10 /* Incremental option, file not changed */
+#define FT_DIRNOCHG 11 /* Incremental option, directory not changed */
+#define FT_ISARCH 12 /* Trying to save archive file */
+#define FT_NORECURSE 13 /* No recursion into directory */
+#define FT_NOFSCHG 14 /* Different file system, prohibited */
+#define FT_NOOPEN 15 /* Could not open directory */
+#define FT_RAW 16 /* Raw block device */
+#define FT_FIFO 17 /* Raw fifo device */
/* Options saved in "flag" of ff packet */
-#define FO_MD5 0x001 /* Do MD5 checksum */
-#define FO_GZIP 0x002 /* Do Zlib compression */
-#define FO_NO_RECURSION 0x004 /* no recursion in directories */
-#define FO_MULTIFS 0x008 /* multiple file systems */
-#define FO_SPARSE 0x010 /* do sparse file checking */
-#define FO_IF_NEWER 0x020 /* replace if newer */
-#define FO_NOREPLACE 0x040 /* never replace */
-#define FO_READFIFO 0x080 /* read data from fifo */
-#define FO_SHA1 0x100 /* Do SHA1 checksum */
+#define FO_MD5 0x001 /* Do MD5 checksum */
+#define FO_GZIP 0x002 /* Do Zlib compression */
+#define FO_NO_RECURSION 0x004 /* no recursion in directories */
+#define FO_MULTIFS 0x008 /* multiple file systems */
+#define FO_SPARSE 0x010 /* do sparse file checking */
+#define FO_IF_NEWER 0x020 /* replace if newer */
+#define FO_NOREPLACE 0x040 /* never replace */
+#define FO_READFIFO 0x080 /* read data from fifo */
+#define FO_SHA1 0x100 /* Do SHA1 checksum */
/*
* Options saved in "options" of include list
#define OPT_compute_MD5 0x01 /* compute MD5 of file's data */
#define OPT_GZIP_compression 0x02 /* use GZIP compression */
#define OPT_no_recursion 0x04 /* no recursion in directories */
-#define OPT_multifs 0x08 /* multiple file systems */
-#define OPT_sparse 0x10 /* do sparse file checking */
+#define OPT_multifs 0x08 /* multiple file systems */
+#define OPT_sparse 0x10 /* do sparse file checking */
#define OPT_replace_if_newer 0x20 /* replace file if newer */
#define OPT_never_replace 0x40 /* never replace */
-#define OPT_read_fifo 0x80 /* read data from fifo (named pipe) */
+#define OPT_read_fifo 0x80 /* read data from fifo (named pipe) */
#define OPT_compute_SHA1 0x100 /* compute SHA1 of file's data */
struct s_included_file {
struct s_included_file *next;
- int options; /* backup options */
- int level; /* compression level */
- int len; /* length of fname */
- int pattern; /* set if pattern */
- char VerifyOpts[20]; /* Options for verify */
+ int options; /* backup options */
+ int level; /* compression level */
+ int len; /* length of fname */
+ int pattern; /* set if pattern */
+ char VerifyOpts[20]; /* Options for verify */
char fname[1];
};
char fname[1];
};
+#ifdef HAVE_CYGWIN
+
+#include <windows.h>
+
+#define BF_CLOSED 0
+#define BF_READ 1 /* BackupRead */
+#define BF_WRITE 2 /* BackupWrite */
+
+/* Basic low level I/O file packet */
+typedef struct s_bfile {
+ int use_win_api; /* set if using WinAPI */
+ int mode; /* set if file is open */
+ HANDLE fh; /* Win32 file handle */
+ int fid; /* fd if doing Unix style */
+ LPVOID lpContext; /* BackupRead/Write context */
+ POOLMEM *errmsg; /* error message buffer */
+ DWORD rw_bytes; /* Bytes read or written */
+ DWORD lerror; /* Last error code */
+} BFILE;
+
+#else
+
+/* Basic low level I/O file packet */
typedef struct s_bfile {
- int fid; /* file id on Unix */
+ int fid; /* file id on Unix */
} BFILE;
+#endif
+
/*
* Definition of the find_files packet passed as the
* first argument to the find_files callback subroutine.
*/
typedef struct s_ff {
- char *fname; /* filename */
- char *link; /* link if file linked */
- POOLMEM *sys_fname; /* system filename */
- struct stat statp; /* stat packet */
- uint32_t FileIndex; /* FileIndex of this file */
- uint32_t LinkFI; /* FileIndex of main hard linked file */
- struct f_link *linked; /* Set if we are hard linked */
- int type; /* FT_ type from above */
- int flags; /* control flags */
- int ff_errno; /* errno */
- int incremental; /* do incremental save */
- BFILE bfd; /* Bacula file descriptor */
- time_t save_time; /* start of incremental time */
- int mtime_only; /* incremental on mtime_only */
- int dereference; /* follow links */
- int GZIP_level; /* compression level */
- int atime_preserve; /* preserve access times */
- int null_output_device; /* using null output device */
+ char *fname; /* filename */
+ char *link; /* link if file linked */
+ POOLMEM *sys_fname; /* system filename */
+ struct stat statp; /* stat packet */
+ uint32_t FileIndex; /* FileIndex of this file */
+ uint32_t LinkFI; /* FileIndex of main hard linked file */
+ struct f_link *linked; /* Set if we are hard linked */
+ int type; /* FT_ type from above */
+ int flags; /* control flags */
+ int ff_errno; /* errno */
+ int incremental; /* do incremental save */
+ BFILE bfd; /* Bacula file descriptor */
+ time_t save_time; /* start of incremental time */
+ int mtime_only; /* incremental on mtime_only */
+ int dereference; /* follow links */
+ int GZIP_level; /* compression level */
+ int atime_preserve; /* preserve access times */
+ int null_output_device; /* using null output device */
char VerifyOpts[20];
struct s_included_file *included_files_list;
struct s_excluded_file *excluded_files_list;
struct s_excluded_file *excluded_paths_list;
- struct f_link *linklist; /* hard linked files */
+ struct f_link *linklist; /* hard linked files */
} FF_PKT;
int set_attributes(void *jcr, char *fname, char *ofile, char *lname,
int type, int stream, struct stat *statp,
char *attribsEx, BFILE *ofd);
+void SetServicePrivileges(void *jcr);
/* from create_file.c */
int create_file(void *jcr, char *fname, char *ofile, char *lname,
int type, int stream, struct stat *statp,
- char *attribsEx, BFILE *ofd, int replace);
+ char *attribsEx, BFILE *ofd, int replace, int win_io);
/* From find.c */
FF_PKT *init_find_files();
/* from file_io.c */
ssize_t bread(BFILE *bfd, void *buf, size_t count);
-int bopen(BFILE *bfd, const char *pathname, int flags, mode_t mode);
+int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode);
int bclose(BFILE *bfd);
ssize_t bread(BFILE *bfd, void *buf, size_t count);
ssize_t bwrite(BFILE *bfd, void *buf, size_t count);
off_t blseek(BFILE *bfd, off_t offset, int whence);
int is_bopen(BFILE *bfd);
-void binit(BFILE *bfd);
+void binit(BFILE *bfd, int use_win_api);
+char *berror(BFILE *bfd);
uint32_t EndFile;
uint32_t StartBlock;
uint32_t EndBlock;
+ int use_win_backup_api; /* set to use native Win API */
#endif /* FILE_DAEMON */
#ifdef STORAGE_DAEMON
/* */
#define VERSION "1.30"
#define VSTRING "1"
-#define BDATE "14 April 2003"
-#define LSMDATE "14Apr03"
+#define BDATE "16 April 2003"
+#define LSMDATE "16Apr03"
/* Debug flags */
#define DEBUG 1