X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=inline;f=bacula%2Fsrc%2Ffindlib%2Fbfile.c;h=6d2d797c6ffd625e9ac41ac0c01aad03993e06e6;hb=2a7fda9473a7ac2669f59e9ff0dec1cba8b12ef1;hp=2e2ae4f6081bf2f6e9558f2b6e2a108d971fc14f;hpb=17b1afbb44930eaaa23aa6cf1136d6842970f908;p=bacula%2Fbacula diff --git a/bacula/src/findlib/bfile.c b/bacula/src/findlib/bfile.c index 2e2ae4f608..6d2d797c6f 100644 --- a/bacula/src/findlib/bfile.c +++ b/bacula/src/findlib/bfile.c @@ -1,46 +1,72 @@ /* - * Bacula low level File I/O routines. This routine simulates - * open(), read(), write(), and close(), but using native routines. - * I.e. on Windows, we use Windows APIs. - * - * Kern Sibbald, April MMIII - * - * Version $Id$ - * - */ -/* - Copyright (C) 2003-2005 Kern Sibbald + Bacula® - The Network Backup Solution - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + Copyright (C) 2003-2010 Free Software Foundation Europe e.V. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Bacula low level File I/O routines. This routine simulates + * open(), read(), write(), and close(), but using native routines. + * I.e. on Windows, we use Windows APIs. + * + * Kern Sibbald, April MMIII + * */ #include "bacula.h" #include "find.h" -bool (*python_set_prog)(JCR *jcr, const char *prog) = NULL; -int (*python_open)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL; -int (*python_close)(BFILE *bfd) = NULL; -ssize_t (*python_read)(BFILE *bfd, void *buf, size_t count) = NULL; -ssize_t (*python_write)(BFILE *bfd, void *buf, size_t count) = NULL; +const int dbglvl = 200; + +int (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL; +int (*plugin_bclose)(BFILE *bfd) = NULL; +ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count) = NULL; +ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count) = NULL; +boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence) = NULL; + #ifdef HAVE_DARWIN_OS #include #endif +#if !defined(HAVE_FDATASYNC) +#define fdatasync(fd) +#endif + +#ifdef HAVE_WIN32 +void pause_msg(const char *file, const char *func, int line, const char *msg) +{ + char buf[1000]; + if (msg) { + bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg); + } else { + bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line); + } + MessageBox(NULL, buf, "Pause", MB_OK); +} +#endif + /* =============================================================== * * U N I X AND W I N D O W S @@ -53,6 +79,8 @@ bool is_win32_stream(int stream) switch (stream) { case STREAM_WIN32_DATA: case STREAM_WIN32_GZIP_DATA: + case STREAM_ENCRYPTED_WIN32_DATA: + case STREAM_ENCRYPTED_WIN32_GZIP_DATA: return true; } return false; @@ -63,40 +91,249 @@ const char *stream_to_ascii(int stream) static char buf[20]; switch (stream) { - case STREAM_GZIP_DATA: - return "GZIP data"; - case STREAM_SPARSE_GZIP_DATA: - return "GZIP sparse data"; - case STREAM_WIN32_DATA: - return "Win32 data"; - case STREAM_WIN32_GZIP_DATA: - return "Win32 GZIP data"; case STREAM_UNIX_ATTRIBUTES: - return "File attributes"; + return _("Unix attributes"); case STREAM_FILE_DATA: - return "File data"; - case STREAM_MD5_SIGNATURE: - return "MD5 signature"; + return _("File data"); + case STREAM_MD5_DIGEST: + return _("MD5 digest"); + case STREAM_GZIP_DATA: + return _("GZIP data"); case STREAM_UNIX_ATTRIBUTES_EX: - return "Extended attributes"; + return _("Extended attributes"); case STREAM_SPARSE_DATA: - return "Sparse data"; + return _("Sparse data"); + case STREAM_SPARSE_GZIP_DATA: + return _("GZIP sparse data"); case STREAM_PROGRAM_NAMES: - return "Program names"; + return _("Program names"); case STREAM_PROGRAM_DATA: - return "Program data"; - case STREAM_SHA1_SIGNATURE: - return "SHA1 signature"; + return _("Program data"); + case STREAM_SHA1_DIGEST: + return _("SHA1 digest"); + case STREAM_WIN32_DATA: + return _("Win32 data"); + case STREAM_WIN32_GZIP_DATA: + return _("Win32 GZIP data"); case STREAM_MACOS_FORK_DATA: - return "HFS+ resource fork"; + return _("MacOS Fork data"); case STREAM_HFSPLUS_ATTRIBUTES: - return "HFS+ Finder Info"; + return _("HFS+ attribs"); + case STREAM_UNIX_ACCESS_ACL: + return _("Standard Unix ACL attribs"); + case STREAM_UNIX_DEFAULT_ACL: + return _("Default Unix ACL attribs"); + case STREAM_SHA256_DIGEST: + return _("SHA256 digest"); + case STREAM_SHA512_DIGEST: + return _("SHA512 digest"); + case STREAM_SIGNED_DIGEST: + return _("Signed digest"); + case STREAM_ENCRYPTED_FILE_DATA: + return _("Encrypted File data"); + case STREAM_ENCRYPTED_WIN32_DATA: + return _("Encrypted Win32 data"); + case STREAM_ENCRYPTED_SESSION_DATA: + return _("Encrypted session data"); + case STREAM_ENCRYPTED_FILE_GZIP_DATA: + return _("Encrypted GZIP data"); + case STREAM_ENCRYPTED_WIN32_GZIP_DATA: + return _("Encrypted Win32 GZIP data"); + case STREAM_ENCRYPTED_MACOS_FORK_DATA: + return _("Encrypted MacOS fork data"); + case STREAM_ACL_AIX_TEXT: + return _("AIX Specific ACL attribs"); + case STREAM_ACL_DARWIN_ACCESS_ACL: + return _("Darwin Specific ACL attribs"); + case STREAM_ACL_FREEBSD_DEFAULT_ACL: + return _("FreeBSD Specific Default ACL attribs"); + case STREAM_ACL_FREEBSD_ACCESS_ACL: + return _("FreeBSD Specific Access ACL attribs"); + case STREAM_ACL_HPUX_ACL_ENTRY: + return _("HPUX Specific ACL attribs"); + case STREAM_ACL_IRIX_DEFAULT_ACL: + return _("Irix Specific Default ACL attribs"); + case STREAM_ACL_IRIX_ACCESS_ACL: + return _("Irix Specific Access ACL attribs"); + case STREAM_ACL_LINUX_DEFAULT_ACL: + return _("Linux Specific Default ACL attribs"); + case STREAM_ACL_LINUX_ACCESS_ACL: + return _("Linux Specific Access ACL attribs"); + case STREAM_ACL_TRU64_DEFAULT_ACL: + return _("OSF1 Specific Default ACL attribs"); + case STREAM_ACL_TRU64_ACCESS_ACL: + return _("OSF1 Specific Access ACL attribs"); + case STREAM_ACL_SOLARIS_ACLENT: + return _("Solaris Specific ACL attribs"); + case STREAM_ACL_SOLARIS_ACE: + return _("Solaris Specific ACL attribs"); + case STREAM_ACL_AFS_TEXT: + return _("AFS Specific ACL attribs"); + case STREAM_ACL_AIX_AIXC: + return _("AIX Specific ACL attribs"); + case STREAM_ACL_AIX_NFS4: + return _("AIX Specific ACL attribs"); + case STREAM_XATTR_AIX: + return _("AIX Specific Extended attribs"); + case STREAM_XATTR_OPENBSD: + return _("OpenBSD Specific Extended attribs"); + case STREAM_XATTR_SOLARIS_SYS: + return _("Solaris Specific Extensible attribs or System Extended attribs"); + case STREAM_XATTR_SOLARIS: + return _("Solaris Specific Extended attribs"); + case STREAM_XATTR_DARWIN: + return _("Darwin Specific Extended attribs"); + case STREAM_XATTR_FREEBSD: + return _("FreeBSD Specific Extended attribs"); + case STREAM_XATTR_LINUX: + return _("Linux Specific Extended attribs"); + case STREAM_XATTR_NETBSD: + return _("NetBSD Specific Extended attribs"); default: sprintf(buf, "%d", stream); return (const char *)buf; } } +/** + * Convert a 64 bit little endian to a big endian + */ +void int64_LE2BE(int64_t* pBE, const int64_t v) +{ + /* convert little endian to big endian */ + if (htonl(1) != 1L) { /* no work if on little endian machine */ + memcpy(pBE, &v, sizeof(int64_t)); + } else { + int i; + uint8_t rv[sizeof(int64_t)]; + uint8_t *pv = (uint8_t *) &v; + + for (i = 0; i < 8; i++) { + rv[i] = pv[7 - i]; + } + memcpy(pBE, &rv, sizeof(int64_t)); + } +} + +/** + * Convert a 32 bit little endian to a big endian + */ +void int32_LE2BE(int32_t* pBE, const int32_t v) +{ + /* convert little endian to big endian */ + if (htonl(1) != 1L) { /* no work if on little endian machine */ + memcpy(pBE, &v, sizeof(int32_t)); + } else { + int i; + uint8_t rv[sizeof(int32_t)]; + uint8_t *pv = (uint8_t *) &v; + + for (i = 0; i < 4; i++) { + rv[i] = pv[3 - i]; + } + memcpy(pBE, &rv, sizeof(int32_t)); + } +} + + +/** + * Read a BackupRead block and pull out the file data + */ +bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize) +{ + /* pByte contains the buffer + dwSize the len to be processed. function assumes to be + called in successive incremental order over the complete + BackupRead stream beginning at pos 0 and ending at the end. + */ + + PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext); + bool bContinue = false; + int64_t dwDataOffset = 0; + int64_t dwDataLen; + + /* Win32 Stream Header size without name of stream. + * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*); + */ + int32_t dwSizeHeader = 20; + + do { + if (pContext->liNextHeader >= dwSize) { + dwDataLen = dwSize-dwDataOffset; + bContinue = false; /* 1 iteration is enough */ + } else { + dwDataLen = pContext->liNextHeader-dwDataOffset; + bContinue = true; /* multiple iterations may be necessary */ + } + + /* flush */ + /* copy block of real DATA */ + if (pContext->bIsInData) { + if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen) + return false; + } + + if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */ + int32_t dwOffsetTarget; + int32_t dwOffsetSource; + + if (pContext->liNextHeader < 0) { + /* start of header was before this block, so we + * continue with the part in the current block + */ + dwOffsetTarget = -pContext->liNextHeader; + dwOffsetSource = 0; + } else { + /* start of header is inside of this block */ + dwOffsetTarget = 0; + dwOffsetSource = pContext->liNextHeader; + } + + int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget; + bool bHeaderIsComplete; + + if (dwHeaderPartLen <= dwSize-dwOffsetSource) { + /* header (or rest of header) is completely available + in current block + */ + bHeaderIsComplete = true; + } else { + /* header will continue in next block */ + bHeaderIsComplete = false; + dwHeaderPartLen = dwSize-dwOffsetSource; + } + + /* copy the available portion of header to persistent copy */ + memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen); + + /* recalculate position of next header */ + if (bHeaderIsComplete) { + /* convert stream name size (32 bit little endian) to machine type */ + int32_t dwNameSize; + int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize); + dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader; + + /* convert stream size (64 bit little endian) to machine type */ + int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size); + pContext->liNextHeader += dwDataOffset; + + pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA; + if (dwDataOffset == dwSize) + bContinue = false; + } else { + /* stop and continue with next block */ + bContinue = false; + pContext->bIsInData = false; + } + } + } while (bContinue); + + /* set "NextHeader" relative to the beginning of the next block */ + pContext->liNextHeader-= dwSize; + + return TRUE; +} + /* =============================================================== @@ -106,19 +343,19 @@ const char *stream_to_ascii(int stream) * =============================================================== */ -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) +#if defined(HAVE_WIN32) void unix_name_to_win32(POOLMEM **win32_name, char *name); extern "C" HANDLE get_osfhandle(int fd); - void binit(BFILE *bfd) { memset(bfd, 0, sizeof(BFILE)); bfd->fid = -1; bfd->mode = BF_CLOSED; bfd->use_backup_api = have_win32_api(); + bfd->cmd_plugin = false; } /* @@ -140,11 +377,11 @@ bool set_portable_backup(BFILE *bfd) return true; } -bool set_prog(BFILE *bfd, char *prog, JCR *jcr) +bool set_cmd_plugin(BFILE *bfd, JCR *jcr) { - bfd->prog = prog; + bfd->cmd_plugin = true; bfd->jcr = jcr; - return false; + return true; } /* @@ -162,41 +399,54 @@ bool have_win32_api() } - /* - * Return 1 if we support the stream - * 0 if we do not support the stream + * Return true if we support the stream + * false if we do not support the stream + * + * This code is running under Win32, so we + * do not need #ifdef on MACOS ... */ -bool is_stream_supported(int stream) +bool is_restore_stream_supported(int stream) { - /* No Win32 backup on this machine */ switch (stream) { + +/* Streams known not to be supported */ #ifndef HAVE_LIBZ case STREAM_GZIP_DATA: case STREAM_SPARSE_GZIP_DATA: - return 0; -#endif - case STREAM_WIN32_DATA: case STREAM_WIN32_GZIP_DATA: - return have_win32_api(); - +#endif case STREAM_MACOS_FORK_DATA: case STREAM_HFSPLUS_ATTRIBUTES: + case STREAM_ENCRYPTED_MACOS_FORK_DATA: return false; /* Known streams */ #ifdef HAVE_LIBZ case STREAM_GZIP_DATA: case STREAM_SPARSE_GZIP_DATA: + case STREAM_WIN32_GZIP_DATA: #endif + case STREAM_WIN32_DATA: case STREAM_UNIX_ATTRIBUTES: case STREAM_FILE_DATA: - case STREAM_MD5_SIGNATURE: + case STREAM_MD5_DIGEST: case STREAM_UNIX_ATTRIBUTES_EX: case STREAM_SPARSE_DATA: case STREAM_PROGRAM_NAMES: case STREAM_PROGRAM_DATA: - case STREAM_SHA1_SIGNATURE: + case STREAM_SHA1_DIGEST: +#ifdef HAVE_SHA2 + case STREAM_SHA256_DIGEST: + case STREAM_SHA512_DIGEST: +#endif +#ifdef HAVE_CRYPTO + case STREAM_SIGNED_DIGEST: + case STREAM_ENCRYPTED_FILE_DATA: + case STREAM_ENCRYPTED_FILE_GZIP_DATA: + case STREAM_ENCRYPTED_WIN32_DATA: + case STREAM_ENCRYPTED_WIN32_GZIP_DATA: +#endif case 0: /* compatibility with old tapes */ return true; } @@ -211,16 +461,47 @@ HANDLE bget_handle(BFILE *bfd) int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) { POOLMEM *win32_fname; + POOLMEM *win32_fname_wchar; + DWORD dwaccess, dwflags, dwshare; /* Convert to Windows path format */ win32_fname = get_pool_memory(PM_FNAME); + win32_fname_wchar = get_pool_memory(PM_FNAME); + unix_name_to_win32(&win32_fname, (char *)fname); -#if USE_WIN32_UNICODE - WCHAR win32_fname_wchar[MAX_PATH_UNICODE]; - UTF8_2_wchar(win32_fname_wchar, win32_fname, MAX_PATH_UNICODE); -#endif + if (bfd->cmd_plugin && plugin_bopen) { + int rtnstat; + Dmsg1(50, "call plugin_bopen fname=%s\n", fname); + rtnstat = plugin_bopen(bfd, fname, flags, mode); + Dmsg1(50, "return from plugin_bopen status=%d\n", rtnstat); + if (rtnstat >= 0) { + if (flags & O_CREAT || flags & O_WRONLY) { /* Open existing for write */ + Dmsg1(50, "plugin_open for write OK file=%s.\n", fname); + bfd->mode = BF_WRITE; + } else { + Dmsg1(50, "plugin_open for read OK file=%s.\n", fname); + bfd->mode = BF_READ; + } + } else { + bfd->mode = BF_CLOSED; + Dmsg1(000, "==== plugin_bopen returned bad status=%d\n", rtnstat); + } + free_pool_memory(win32_fname_wchar); + free_pool_memory(win32_fname); + return bfd->mode == BF_CLOSED ? -1 : 1; + } + Dmsg0(50, "=== NO plugin\n"); + + if (!(p_CreateFileA || p_CreateFileW)) { + Dmsg0(50, "No CreateFileA and no CreateFileW!!!!!\n"); + return 0; + } + + if (p_CreateFileW && p_MultiByteToWideChar) { + make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname); + } if (flags & O_CREAT) { /* Create */ if (bfd->use_backup_api) { @@ -231,46 +512,69 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) dwflags = 0; } + if (p_CreateFileW && p_MultiByteToWideChar) { + // unicode open for create write + Dmsg1(100, "Create CreateFileW=%s\n", win32_fname); + bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar, + dwaccess, /* Requested access */ + 0, /* Shared mode */ + NULL, /* SecurityAttributes */ + CREATE_ALWAYS, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + } else { + // ascii open + Dmsg1(100, "Create CreateFileA=%s\n", win32_fname); + bfd->fh = p_CreateFileA(win32_fname, + dwaccess, /* Requested access */ + 0, /* Shared mode */ + NULL, /* SecurityAttributes */ + CREATE_ALWAYS, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + } -#if USE_WIN32_UNICODE - bfd->fh = CreateFileW(win32_fname_wchar, -#else - bfd->fh = CreateFile(win32_fname, -#endif - dwaccess, /* Requested access */ - 0, /* Shared mode */ - NULL, /* SecurityAttributes */ - CREATE_ALWAYS, /* CreationDisposition */ - dwflags, /* Flags and attributes */ - NULL); /* TemplateFile */ bfd->mode = BF_WRITE; } else if (flags & O_WRONLY) { /* Open existing for write */ if (bfd->use_backup_api) { dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC; - dwflags = FILE_FLAG_BACKUP_SEMANTICS; + dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT; } else { dwaccess = GENERIC_WRITE; dwflags = 0; } -#if USE_WIN32_UNICODE - bfd->fh = CreateFileW(win32_fname_wchar, -#else - bfd->fh = CreateFile(win32_fname, -#endif - dwaccess, /* Requested access */ - 0, /* Shared mode */ - NULL, /* SecurityAttributes */ - OPEN_EXISTING, /* CreationDisposition */ - dwflags, /* Flags and attributes */ - NULL); /* TemplateFile */ + if (p_CreateFileW && p_MultiByteToWideChar) { + // unicode open for open existing write + Dmsg1(100, "Write only CreateFileW=%s\n", win32_fname); + bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar, + dwaccess, /* Requested access */ + 0, /* Shared mode */ + NULL, /* SecurityAttributes */ + OPEN_EXISTING, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + } else { + // ascii open + Dmsg1(100, "Write only CreateFileA=%s\n", win32_fname); + bfd->fh = p_CreateFileA(win32_fname, + dwaccess, /* Requested access */ + 0, /* Shared mode */ + NULL, /* SecurityAttributes */ + OPEN_EXISTING, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + + } + bfd->mode = BF_WRITE; } else { /* Read */ if (bfd->use_backup_api) { dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY; - dwflags = FILE_FLAG_BACKUP_SEMANTICS; + dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN | + FILE_FLAG_OPEN_REPARSE_POINT; dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE; } else { dwaccess = GENERIC_READ; @@ -278,17 +582,28 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE; } -#if USE_WIN32_UNICODE - bfd->fh = CreateFileW(win32_fname_wchar, -#else - bfd->fh = CreateFile(win32_fname, -#endif - dwaccess, /* Requested access */ - dwshare, /* Share modes */ - NULL, /* SecurityAttributes */ - OPEN_EXISTING, /* CreationDisposition */ - dwflags, /* Flags and attributes */ - NULL); /* TemplateFile */ + if (p_CreateFileW && p_MultiByteToWideChar) { + // unicode open for open existing read + Dmsg1(100, "Read CreateFileW=%s\n", win32_fname); + bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar, + dwaccess, /* Requested access */ + dwshare, /* Share modes */ + NULL, /* SecurityAttributes */ + OPEN_EXISTING, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + } else { + // ascii open + Dmsg1(100, "Read CreateFileA=%s\n", win32_fname); + bfd->fh = p_CreateFileA(win32_fname, + dwaccess, /* Requested access */ + dwshare, /* Share modes */ + NULL, /* SecurityAttributes */ + OPEN_EXISTING, /* CreationDisposition */ + dwflags, /* Flags and attributes */ + NULL); /* TemplateFile */ + } + bfd->mode = BF_READ; } @@ -300,6 +615,9 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) } bfd->errmsg = NULL; bfd->lpContext = NULL; + bfd->win32DecompContext.bIsInData = false; + bfd->win32DecompContext.liNextHeader = 0; + free_pool_memory(win32_fname_wchar); free_pool_memory(win32_fname); return bfd->mode == BF_CLOSED ? -1 : 1; } @@ -312,16 +630,25 @@ int bclose(BFILE *bfd) { int stat = 0; - if (bfd->errmsg) { - free_pool_memory(bfd->errmsg); - bfd->errmsg = NULL; - } if (bfd->mode == BF_CLOSED) { + Dmsg0(50, "=== BFD already closed.\n"); return 0; } + + if (bfd->cmd_plugin && plugin_bclose) { + stat = plugin_bclose(bfd); + Dmsg0(50, "==== BFD closed!!!\n"); + goto all_done; + } + + /* + * We need to tell the API to release the buffer it + * allocated in lpContext. We do so by calling the + * API one more time, but with the Abort bit set. + */ if (bfd->use_backup_api && bfd->mode == BF_READ) { BYTE buf[10]; - if (!bfd->lpContext && !p_BackupRead(bfd->fh, + if (bfd->lpContext && !p_BackupRead(bfd->fh, buf, /* buffer */ (DWORD)0, /* bytes to read */ &bfd->rw_bytes, /* bytes read */ @@ -333,7 +660,7 @@ int bclose(BFILE *bfd) } } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) { BYTE buf[10]; - if (!bfd->lpContext && !p_BackupWrite(bfd->fh, + if (bfd->lpContext && !p_BackupWrite(bfd->fh, buf, /* buffer */ (DWORD)0, /* bytes to read */ &bfd->rw_bytes, /* bytes written */ @@ -348,8 +675,15 @@ int bclose(BFILE *bfd) stat = -1; errno = b_errno_win32; } + +all_done: + if (bfd->errmsg) { + free_pool_memory(bfd->errmsg); + bfd->errmsg = NULL; + } bfd->mode = BF_CLOSED; bfd->lpContext = NULL; + bfd->cmd_plugin = false; return stat; } @@ -361,6 +695,10 @@ ssize_t bread(BFILE *bfd, void *buf, size_t count) { bfd->rw_bytes = 0; + if (bfd->cmd_plugin && plugin_bread) { + return plugin_bread(bfd, buf, count); + } + if (bfd->use_backup_api) { if (!p_BackupRead(bfd->fh, (BYTE *)buf, @@ -394,6 +732,10 @@ ssize_t bwrite(BFILE *bfd, void *buf, size_t count) { bfd->rw_bytes = 0; + if (bfd->cmd_plugin && plugin_bwrite) { + return plugin_bwrite(bfd, buf, count); + } + if (bfd->use_backup_api) { if (!p_BackupWrite(bfd->fh, (BYTE *)buf, @@ -427,10 +769,23 @@ bool is_bopen(BFILE *bfd) return bfd->mode != BF_CLOSED; } -off_t blseek(BFILE *bfd, off_t offset, int whence) +boffset_t blseek(BFILE *bfd, boffset_t offset, int whence) { - /* ****FIXME**** this must be implemented if we want to read Win32 Archives */ - return -1; + LONG offset_low = (LONG)offset; + LONG offset_high = (LONG)(offset >> 32); + DWORD dwResult; + + if (bfd->cmd_plugin && plugin_blseek) { + return plugin_blseek(bfd, offset, whence); + } + + dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence); + + if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { + return (boffset_t)-1; + } + + return ((boffset_t)offset_high << 32) | dwResult; } #else /* Unix systems */ @@ -479,35 +834,28 @@ bool is_portable_backup(BFILE *bfd) bool set_prog(BFILE *bfd, char *prog, JCR *jcr) { -#ifdef HAVE_PYTHON - if (bfd->prog && strcmp(prog, bfd->prog) == 0) { - return true; /* already setup */ - } - - if (python_set_prog(jcr, prog)) { - Dmsg1(000, "Set prog=%s\n", prog); - bfd->prog = prog; - bfd->jcr = jcr; - return true; - } -#endif - Dmsg0(000, "No prog set\n"); - bfd->prog = NULL; return false; - } +bool set_cmd_plugin(BFILE *bfd, JCR *jcr) +{ + bfd->cmd_plugin = true; + bfd->jcr = jcr; + return true; +} -bool is_stream_supported(int stream) +/* + * This code is running on a non-Win32 machine + */ +bool is_restore_stream_supported(int stream) { /* No Win32 backup on this machine */ - switch (stream) { + switch (stream) { #ifndef HAVE_LIBZ case STREAM_GZIP_DATA: case STREAM_SPARSE_GZIP_DATA: + case STREAM_WIN32_GZIP_DATA: #endif - case STREAM_WIN32_DATA: - case STREAM_WIN32_GZIP_DATA: #ifndef HAVE_DARWIN_OS case STREAM_MACOS_FORK_DATA: case STREAM_HFSPLUS_ATTRIBUTES: @@ -518,69 +866,89 @@ bool is_stream_supported(int stream) #ifdef HAVE_LIBZ case STREAM_GZIP_DATA: case STREAM_SPARSE_GZIP_DATA: + case STREAM_WIN32_GZIP_DATA: #endif + case STREAM_WIN32_DATA: case STREAM_UNIX_ATTRIBUTES: case STREAM_FILE_DATA: - case STREAM_MD5_SIGNATURE: + case STREAM_MD5_DIGEST: case STREAM_UNIX_ATTRIBUTES_EX: case STREAM_SPARSE_DATA: case STREAM_PROGRAM_NAMES: case STREAM_PROGRAM_DATA: - case STREAM_SHA1_SIGNATURE: + case STREAM_SHA1_DIGEST: +#ifdef HAVE_SHA2 + case STREAM_SHA256_DIGEST: + case STREAM_SHA512_DIGEST: +#endif +#ifdef HAVE_CRYPTO + case STREAM_SIGNED_DIGEST: + case STREAM_ENCRYPTED_FILE_DATA: + case STREAM_ENCRYPTED_FILE_GZIP_DATA: + case STREAM_ENCRYPTED_WIN32_DATA: + case STREAM_ENCRYPTED_WIN32_GZIP_DATA: +#endif #ifdef HAVE_DARWIN_OS case STREAM_MACOS_FORK_DATA: case STREAM_HFSPLUS_ATTRIBUTES: -#endif - case 0: /* compatibility with old tapes */ +#ifdef HAVE_CRYPTO + case STREAM_ENCRYPTED_MACOS_FORK_DATA: +#endif /* HAVE_CRYPTO */ +#endif /* HAVE_DARWIN_OS */ + case 0: /* compatibility with old tapes */ return true; } - return 0; + return false; } -/* Old file reader code */ -#ifdef xxx - if (bfd->prog) { - POOLMEM *ecmd = get_pool_memory(PM_FNAME); - ecmd = edit_job_codes(bfd->jcr, ecmd, bfd->prog, fname); - const char *pmode; - if (flags & O_RDONLY) { - pmode = "r"; - } else { - pmode = "w"; - } - bfd->bpipe = open_bpipe(ecmd, 0, pmode); - if (bfd->bpipe == NULL) { +int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) +{ + if (bfd->cmd_plugin && plugin_bopen) { + Dmsg1(50, "call plugin_bopen fname=%s\n", fname); + bfd->fid = plugin_bopen(bfd, fname, flags, mode); + Dmsg1(50, "Plugin bopen stat=%d\n", bfd->fid); + return bfd->fid; + } + + /* Normal file open */ + Dmsg1(dbglvl, "open file %s\n", fname); + + /* We use fnctl to set O_NOATIME if requested to avoid open error */ + bfd->fid = open(fname, flags & ~O_NOATIME, mode); + + /* Set O_NOATIME if possible */ + if (bfd->fid != -1 && flags & O_NOATIME) { + int oldflags = fcntl(bfd->fid, F_GETFL, 0); + if (oldflags == -1) { bfd->berrno = errno; + close(bfd->fid); bfd->fid = -1; - free_pool_memory(ecmd); - return -1; - } - free_pool_memory(ecmd); - if (flags & O_RDONLY) { - bfd->fid = fileno(bfd->bpipe->rfd); } else { - bfd->fid = fileno(bfd->bpipe->wfd); + int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME); + /* EPERM means setting O_NOATIME was not allowed */ + if (ret == -1 && errno != EPERM) { + bfd->berrno = errno; + close(bfd->fid); + bfd->fid = -1; + } } - errno = 0; - return bfd->fid; } -#endif + bfd->berrno = errno; + bfd->m_flags = flags; + Dmsg1(400, "Open file %d\n", bfd->fid); + errno = bfd->berrno; + bfd->win32DecompContext.bIsInData = false; + bfd->win32DecompContext.liNextHeader = 0; -int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) -{ - /* Open reader/writer program */ - if (bfd->prog) { - Dmsg1(000, "Open file %d\n", bfd->fid); - return python_open(bfd, fname, flags, mode); +#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED) + if (bfd->fid != -1 && flags & O_RDONLY) { + int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED); + Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat); } +#endif - /* Normal file open */ - bfd->fid = open(fname, flags, mode); - bfd->berrno = errno; - Dmsg1(400, "Open file %d\n", bfd->fid); - errno = bfd->berrno; return bfd->fid; } @@ -589,17 +957,19 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode) { POOLMEM *rsrc_fname; - size_t fname_len; - fname_len = strlen(fname); rsrc_fname = get_pool_memory(PM_FNAME); - bstrncpy(rsrc_fname, fname, fname_len + 1); - bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC, - strlen(_PATH_RSRCFORKSPEC) + 1); + pm_strcpy(rsrc_fname, fname); + pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC); bopen(bfd, rsrc_fname, flags, mode); free_pool_memory(rsrc_fname); return bfd->fid; } +#else +int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode) +{ + return -1; +} #endif @@ -609,19 +979,28 @@ int bclose(BFILE *bfd) Dmsg1(400, "Close file %d\n", bfd->fid); - /* Close reader/writer program */ - if (bfd->prog) { - return python_close(bfd); + if (bfd->cmd_plugin && plugin_bclose) { + stat = plugin_bclose(bfd); + bfd->fid = -1; + bfd->cmd_plugin = false; } if (bfd->fid == -1) { return 0; } +#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) + if (bfd->m_flags & O_RDONLY) { + fdatasync(bfd->fid); /* sync the file */ + /* Tell OS we don't need it any more */ + posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED); + } +#endif /* Close normal file */ stat = close(bfd->fid); bfd->berrno = errno; bfd->fid = -1; + bfd->cmd_plugin = false; return stat; } @@ -629,9 +1008,10 @@ ssize_t bread(BFILE *bfd, void *buf, size_t count) { ssize_t stat; - if (bfd->prog) { - return python_read(bfd, buf, count); + if (bfd->cmd_plugin && plugin_bread) { + return plugin_bread(bfd, buf, count); } + stat = read(bfd->fid, buf, count); bfd->berrno = errno; return stat; @@ -641,8 +1021,8 @@ ssize_t bwrite(BFILE *bfd, void *buf, size_t count) { ssize_t stat; - if (bfd->prog) { - return python_write(bfd, buf, count); + if (bfd->cmd_plugin && plugin_bwrite) { + return plugin_bwrite(bfd, buf, count); } stat = write(bfd->fid, buf, count); bfd->berrno = errno; @@ -654,12 +1034,16 @@ bool is_bopen(BFILE *bfd) return bfd->fid >= 0; } -off_t blseek(BFILE *bfd, off_t offset, int whence) +boffset_t blseek(BFILE *bfd, boffset_t offset, int whence) { - off_t pos; - pos = lseek(bfd->fid, offset, whence); - bfd->berrno = errno; - return pos; + boffset_t pos; + + if (bfd->cmd_plugin && plugin_bwrite) { + return plugin_blseek(bfd, offset, whence); + } + pos = (boffset_t)lseek(bfd->fid, offset, whence); + bfd->berrno = errno; + return pos; } #endif