2 * Bacula low level File I/O routines. This routine simulates
3 * open(), read(), write(), and close(), but using native routines.
4 * I.e. on Windows, we use Windows APIs.
6 * Kern Sibbald, April MMIII
12 Copyright (C) 2003-2005 Kern Sibbald
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of
17 the License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public
25 License along with this program; if not, write to the Free
26 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 bool (*python_set_prog)(JCR *jcr, const char *prog) = NULL;
35 int (*python_open)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL;
36 int (*python_close)(BFILE *bfd) = NULL;
37 ssize_t (*python_read)(BFILE *bfd, void *buf, size_t count) = NULL;
38 ssize_t (*python_write)(BFILE *bfd, void *buf, size_t count) = NULL;
41 #include <sys/paths.h>
44 /* ===============================================================
46 * U N I X AND W I N D O W S
48 * ===============================================================
51 bool is_win32_stream(int stream)
54 case STREAM_WIN32_DATA:
55 case STREAM_WIN32_GZIP_DATA:
61 const char *stream_to_ascii(int stream)
66 case STREAM_GZIP_DATA:
67 return _("GZIP data");
68 case STREAM_SPARSE_GZIP_DATA:
69 return _("GZIP sparse data");
70 case STREAM_WIN32_DATA:
71 return _("Win32 data");
72 case STREAM_WIN32_GZIP_DATA:
73 return _("Win32 GZIP data");
74 case STREAM_UNIX_ATTRIBUTES:
75 return _("File attributes");
76 case STREAM_FILE_DATA:
77 return _("File data");
78 case STREAM_MD5_SIGNATURE:
79 return _("MD5 signature");
80 case STREAM_UNIX_ATTRIBUTES_EX:
81 return _("Extended attributes");
82 case STREAM_SPARSE_DATA:
83 return _("Sparse data");
84 case STREAM_PROGRAM_NAMES:
85 return _("Program names");
86 case STREAM_PROGRAM_DATA:
87 return _("Program data");
88 case STREAM_SHA1_SIGNATURE:
89 return _("SHA1 signature");
90 case STREAM_MACOS_FORK_DATA:
91 return _("HFS+ resource fork");
92 case STREAM_HFSPLUS_ATTRIBUTES:
93 return _("HFS+ Finder Info");
95 sprintf(buf, "%d", stream);
96 return (const char *)buf;
100 #ifdef USE_WIN32STREAMEXTRACTION
101 BOOL processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, size_t dwSize)
103 /* pByte contains the buffer
104 dwSize the len to be processed. function assumes to be called in successive
105 incremental order over the complete BackupRead stream beginning at pos 0 and
106 ending at the end. */
108 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
109 BOOL bContinue = FALSE;
110 LONGLONG dwDataOffset = 0;
113 /* Win32 Stream Header size without name of strem.
114 = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*); */
115 DWORD dwSizeHeader = 20;
118 if (pContext->liNextHeader >= dwSize) {
119 dwDataLen = dwSize-dwDataOffset;
120 bContinue = FALSE; /* 1 iteration is enough */
123 dwDataLen = pContext->liNextHeader-dwDataOffset;
124 bContinue = TRUE; /* multiple iterations may be necessary */
128 /* copy block of real DATA */
129 if (pContext->bIsInData) {
130 if (bwrite(bfd, ((LPBYTE)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
134 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
135 DWORD dwOffsetTarget;
136 DWORD dwOffsetSource;
138 if (pContext->liNextHeader < 0) {
139 /* start of header was before this block,
140 so we continue with the part in the current block */
141 dwOffsetTarget = abs (pContext->liNextHeader);
145 /* start of header is inside of this block */
147 dwOffsetSource = pContext->liNextHeader;
150 DWORD dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
151 BOOL bHeaderIsComplete;
153 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
154 /* header (or rest of header) is completely available in current block */
155 bHeaderIsComplete = TRUE;
157 /* header will continue in next block */
158 bHeaderIsComplete = FALSE;
159 dwHeaderPartLen = dwSize-dwOffsetSource;
162 /* copy the available portion of header to persistent copy */
163 memcpy (((LPBYTE) &pContext->header_stream)+dwOffsetTarget, ((LPBYTE) pBuffer)+dwOffsetSource, dwHeaderPartLen);
165 /* recalculate position of next header */
166 if (bHeaderIsComplete) {
167 dwDataOffset = pContext->liNextHeader+dwSizeHeader+pContext->header_stream.dwStreamNameSize;
168 pContext->liNextHeader = dwDataOffset+pContext->header_stream.Size.QuadPart;
169 pContext->bIsInData = pContext->header_stream.dwStreamId == BACKUP_DATA;
170 if (dwDataOffset == dwSize)
174 /* stop and continue with next block */
176 pContext->bIsInData = FALSE;
181 /* set "NextHeader" relative to the beginning of the next block */
182 pContext->liNextHeader-= dwSize;
190 /* ===============================================================
194 * ===============================================================
197 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
199 void unix_name_to_win32(POOLMEM **win32_name, char *name);
200 extern "C" HANDLE get_osfhandle(int fd);
204 void binit(BFILE *bfd)
206 memset(bfd, 0, sizeof(BFILE));
208 bfd->mode = BF_CLOSED;
209 bfd->use_backup_api = have_win32_api();
213 * Enables using the Backup API (win32_data).
214 * Returns 1 if function worked
215 * Returns 0 if failed (i.e. do not have Backup API on this machine)
217 bool set_win32_backup(BFILE *bfd)
219 /* We enable if possible here */
220 bfd->use_backup_api = have_win32_api();
221 return bfd->use_backup_api;
225 bool set_portable_backup(BFILE *bfd)
227 bfd->use_backup_api = false;
231 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
239 * Return 1 if we are NOT using Win32 BackupWrite()
242 bool is_portable_backup(BFILE *bfd)
244 return !bfd->use_backup_api;
247 bool have_win32_api()
249 return p_BackupRead && p_BackupWrite;
255 * Return 1 if we support the stream
256 * 0 if we do not support the stream
258 bool is_stream_supported(int stream)
260 /* No Win32 backup on this machine */
263 case STREAM_GZIP_DATA:
264 case STREAM_SPARSE_GZIP_DATA:
267 case STREAM_WIN32_DATA:
268 case STREAM_WIN32_GZIP_DATA:
269 #ifdef USE_WIN32STREAMEXTRACTION
272 return have_win32_api();
276 case STREAM_MACOS_FORK_DATA:
277 case STREAM_HFSPLUS_ATTRIBUTES:
282 case STREAM_GZIP_DATA:
283 case STREAM_SPARSE_GZIP_DATA:
285 case STREAM_UNIX_ATTRIBUTES:
286 case STREAM_FILE_DATA:
287 case STREAM_MD5_SIGNATURE:
288 case STREAM_UNIX_ATTRIBUTES_EX:
289 case STREAM_SPARSE_DATA:
290 case STREAM_PROGRAM_NAMES:
291 case STREAM_PROGRAM_DATA:
292 case STREAM_SHA1_SIGNATURE:
293 case 0: /* compatibility with old tapes */
299 HANDLE bget_handle(BFILE *bfd)
304 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
306 POOLMEM *win32_fname;
307 POOLMEM *win32_fname_wchar;
309 DWORD dwaccess, dwflags, dwshare;
311 /* Convert to Windows path format */
312 win32_fname = get_pool_memory(PM_FNAME);
313 win32_fname_wchar = get_pool_memory(PM_FNAME);
315 unix_name_to_win32(&win32_fname, (char *)fname);
317 if (!(p_CreateFileA || p_CreateFileW))
320 if (p_CreateFileW && p_MultiByteToWideChar)
321 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
323 if (flags & O_CREAT) { /* Create */
324 if (bfd->use_backup_api) {
325 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
326 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
328 dwaccess = GENERIC_WRITE;
332 // unicode or ansii open for create write
333 if (p_CreateFileW && p_MultiByteToWideChar) {
334 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
335 dwaccess, /* Requested access */
337 NULL, /* SecurityAttributes */
338 CREATE_ALWAYS, /* CreationDisposition */
339 dwflags, /* Flags and attributes */
340 NULL); /* TemplateFile */
343 bfd->fh = p_CreateFileA(win32_fname,
344 dwaccess, /* Requested access */
346 NULL, /* SecurityAttributes */
347 CREATE_ALWAYS, /* CreationDisposition */
348 dwflags, /* Flags and attributes */
349 NULL); /* TemplateFile */
353 bfd->mode = BF_WRITE;
355 } else if (flags & O_WRONLY) { /* Open existing for write */
356 if (bfd->use_backup_api) {
357 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
358 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
360 dwaccess = GENERIC_WRITE;
364 // unicode or ansii open for open existing write
365 if (p_CreateFileW && p_MultiByteToWideChar) {
366 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
367 dwaccess, /* Requested access */
369 NULL, /* SecurityAttributes */
370 OPEN_EXISTING, /* CreationDisposition */
371 dwflags, /* Flags and attributes */
372 NULL); /* TemplateFile */
375 bfd->fh = p_CreateFileA(win32_fname,
376 dwaccess, /* Requested access */
378 NULL, /* SecurityAttributes */
379 OPEN_EXISTING, /* CreationDisposition */
380 dwflags, /* Flags and attributes */
381 NULL); /* TemplateFile */
385 bfd->mode = BF_WRITE;
388 if (bfd->use_backup_api) {
389 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
390 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
391 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
393 dwaccess = GENERIC_READ;
395 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
398 // unicode or ansii open for open existing read
399 if (p_CreateFileW && p_MultiByteToWideChar) {
400 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
401 dwaccess, /* Requested access */
402 dwshare, /* Share modes */
403 NULL, /* SecurityAttributes */
404 OPEN_EXISTING, /* CreationDisposition */
405 dwflags, /* Flags and attributes */
406 NULL); /* TemplateFile */
409 bfd->fh = p_CreateFileA(win32_fname,
410 dwaccess, /* Requested access */
411 dwshare, /* Share modes */
412 NULL, /* SecurityAttributes */
413 OPEN_EXISTING, /* CreationDisposition */
414 dwflags, /* Flags and attributes */
415 NULL); /* TemplateFile */
421 if (bfd->fh == INVALID_HANDLE_VALUE) {
422 bfd->lerror = GetLastError();
423 bfd->berrno = b_errno_win32;
424 errno = b_errno_win32;
425 bfd->mode = BF_CLOSED;
428 bfd->lpContext = NULL;
429 #ifdef USE_WIN32STREAMEXTRACTION
430 bfd->win32DecompContext.bIsInData = FALSE;
431 bfd->win32DecompContext.liNextHeader = 0;
433 free_pool_memory(win32_fname_wchar);
434 free_pool_memory(win32_fname);
435 return bfd->mode == BF_CLOSED ? -1 : 1;
439 * Returns 0 on success
442 int bclose(BFILE *bfd)
447 free_pool_memory(bfd->errmsg);
450 if (bfd->mode == BF_CLOSED) {
453 if (bfd->use_backup_api && bfd->mode == BF_READ) {
455 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
457 (DWORD)0, /* bytes to read */
458 &bfd->rw_bytes, /* bytes read */
460 1, /* ProcessSecurity */
461 &bfd->lpContext)) { /* Read context */
462 errno = b_errno_win32;
465 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
467 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
469 (DWORD)0, /* bytes to read */
470 &bfd->rw_bytes, /* bytes written */
472 1, /* ProcessSecurity */
473 &bfd->lpContext)) { /* Write context */
474 errno = b_errno_win32;
478 if (!CloseHandle(bfd->fh)) {
480 errno = b_errno_win32;
482 bfd->mode = BF_CLOSED;
483 bfd->lpContext = NULL;
487 /* Returns: bytes read on success
491 ssize_t bread(BFILE *bfd, void *buf, size_t count)
495 if (bfd->use_backup_api) {
496 if (!p_BackupRead(bfd->fh,
501 1, /* Process Security */
502 &bfd->lpContext)) { /* Context */
503 bfd->lerror = GetLastError();
504 bfd->berrno = b_errno_win32;
505 errno = b_errno_win32;
509 if (!ReadFile(bfd->fh,
514 bfd->lerror = GetLastError();
515 bfd->berrno = b_errno_win32;
516 errno = b_errno_win32;
521 return (ssize_t)bfd->rw_bytes;
524 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
528 if (bfd->use_backup_api) {
529 if (!p_BackupWrite(bfd->fh,
534 1, /* Process Security */
535 &bfd->lpContext)) { /* Context */
536 bfd->lerror = GetLastError();
537 bfd->berrno = b_errno_win32;
538 errno = b_errno_win32;
542 if (!WriteFile(bfd->fh,
547 bfd->lerror = GetLastError();
548 bfd->berrno = b_errno_win32;
549 errno = b_errno_win32;
553 return (ssize_t)bfd->rw_bytes;
556 bool is_bopen(BFILE *bfd)
558 return bfd->mode != BF_CLOSED;
561 off_t blseek(BFILE *bfd, off_t offset, int whence)
563 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
567 #else /* Unix systems */
569 /* ===============================================================
573 * ===============================================================
575 void binit(BFILE *bfd)
577 memset(bfd, 0, sizeof(BFILE));
581 bool have_win32_api()
583 return false; /* no can do */
587 * Enables using the Backup API (win32_data).
588 * Returns true if function worked
589 * Returns false if failed (i.e. do not have Backup API on this machine)
591 bool set_win32_backup(BFILE *bfd)
593 return false; /* no can do */
597 bool set_portable_backup(BFILE *bfd)
599 return true; /* no problem */
603 * Return true if we are writing in portable format
604 * return false if not
606 bool is_portable_backup(BFILE *bfd)
608 return true; /* portable by definition */
611 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
614 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
615 return true; /* already setup */
618 if (python_set_prog(jcr, prog)) {
619 Dmsg1(000, "Set prog=%s\n", prog);
625 Dmsg0(000, "No prog set\n");
632 bool is_stream_supported(int stream)
634 /* No Win32 backup on this machine */
637 case STREAM_GZIP_DATA:
638 case STREAM_SPARSE_GZIP_DATA:
640 #ifndef USE_WIN32STREAMEXTRACTION
641 case STREAM_WIN32_DATA:
642 case STREAM_WIN32_GZIP_DATA:
644 #ifndef HAVE_DARWIN_OS
645 case STREAM_MACOS_FORK_DATA:
646 case STREAM_HFSPLUS_ATTRIBUTES:
652 case STREAM_GZIP_DATA:
653 case STREAM_SPARSE_GZIP_DATA:
655 #ifdef USE_WIN32STREAMEXTRACTION
656 case STREAM_WIN32_DATA:
658 #if defined(USE_WIN32STREAMEXTRACTION) && defined(HAVE_LIBZ)
659 case STREAM_WIN32_GZIP_DATA:
661 case STREAM_UNIX_ATTRIBUTES:
662 case STREAM_FILE_DATA:
663 case STREAM_MD5_SIGNATURE:
664 case STREAM_UNIX_ATTRIBUTES_EX:
665 case STREAM_SPARSE_DATA:
666 case STREAM_PROGRAM_NAMES:
667 case STREAM_PROGRAM_DATA:
668 case STREAM_SHA1_SIGNATURE:
669 #ifdef HAVE_DARWIN_OS
670 case STREAM_MACOS_FORK_DATA:
671 case STREAM_HFSPLUS_ATTRIBUTES:
673 case 0: /* compatibility with old tapes */
680 /* Old file reader code */
683 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
684 ecmd = edit_job_codes(bfd->jcr, ecmd, bfd->prog, fname);
686 if (flags & O_RDONLY) {
691 bfd->bpipe = open_bpipe(ecmd, 0, pmode);
692 if (bfd->bpipe == NULL) {
695 free_pool_memory(ecmd);
698 free_pool_memory(ecmd);
699 if (flags & O_RDONLY) {
700 bfd->fid = fileno(bfd->bpipe->rfd);
702 bfd->fid = fileno(bfd->bpipe->wfd);
710 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
712 /* Open reader/writer program */
714 Dmsg1(000, "Open file %d\n", bfd->fid);
715 return python_open(bfd, fname, flags, mode);
718 /* Normal file open */
719 bfd->fid = open(fname, flags, mode);
721 Dmsg1(400, "Open file %d\n", bfd->fid);
724 #ifdef USE_WIN32STREAMEXTRACTION
725 bfd->win32DecompContext.bIsInData = FALSE;
726 bfd->win32DecompContext.liNextHeader = 0;
732 #ifdef HAVE_DARWIN_OS
733 /* Open the resource fork of a file. */
734 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
739 fname_len = strlen(fname);
740 rsrc_fname = get_pool_memory(PM_FNAME);
741 bstrncpy(rsrc_fname, fname, fname_len + 1);
742 bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC,
743 strlen(_PATH_RSRCFORKSPEC) + 1);
744 bopen(bfd, rsrc_fname, flags, mode);
745 free_pool_memory(rsrc_fname);
751 int bclose(BFILE *bfd)
755 Dmsg1(400, "Close file %d\n", bfd->fid);
757 /* Close reader/writer program */
759 return python_close(bfd);
762 if (bfd->fid == -1) {
766 /* Close normal file */
767 stat = close(bfd->fid);
773 ssize_t bread(BFILE *bfd, void *buf, size_t count)
778 return python_read(bfd, buf, count);
780 stat = read(bfd->fid, buf, count);
785 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
790 return python_write(bfd, buf, count);
792 stat = write(bfd->fid, buf, count);
797 bool is_bopen(BFILE *bfd)
799 return bfd->fid >= 0;
802 off_t blseek(BFILE *bfd, off_t offset, int whence)
805 pos = lseek(bfd->fid, offset, whence);