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-2006 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
16 version 2 as amended with additional clauses defined in the
17 file LICENSE in the main source directory.
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
22 the file LICENSE for additional details.
29 bool (*python_set_prog)(JCR *jcr, const char *prog) = NULL;
30 int (*python_open)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL;
31 int (*python_close)(BFILE *bfd) = NULL;
32 ssize_t (*python_read)(BFILE *bfd, void *buf, size_t count) = NULL;
33 ssize_t (*python_write)(BFILE *bfd, void *buf, size_t count) = NULL;
36 #include <sys/paths.h>
39 /* ===============================================================
41 * U N I X AND W I N D O W S
43 * ===============================================================
46 bool is_win32_stream(int stream)
49 case STREAM_WIN32_DATA:
50 case STREAM_WIN32_GZIP_DATA:
51 case STREAM_ENCRYPTED_WIN32_DATA:
52 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
58 const char *stream_to_ascii(int stream)
63 case STREAM_GZIP_DATA:
64 return _("GZIP data");
65 case STREAM_SPARSE_GZIP_DATA:
66 return _("GZIP sparse data");
67 case STREAM_WIN32_DATA:
68 return _("Win32 data");
69 case STREAM_WIN32_GZIP_DATA:
70 return _("Win32 GZIP data");
71 case STREAM_UNIX_ATTRIBUTES:
72 return _("File attributes");
73 case STREAM_FILE_DATA:
74 return _("File data");
75 case STREAM_MD5_DIGEST:
76 return _("MD5 digest");
77 case STREAM_UNIX_ATTRIBUTES_EX:
78 return _("Extended attributes");
79 case STREAM_SPARSE_DATA:
80 return _("Sparse data");
81 case STREAM_PROGRAM_NAMES:
82 return _("Program names");
83 case STREAM_PROGRAM_DATA:
84 return _("Program data");
85 case STREAM_SHA1_DIGEST:
86 return _("SHA1 digest");
87 case STREAM_MACOS_FORK_DATA:
88 return _("HFS+ resource fork");
89 case STREAM_HFSPLUS_ATTRIBUTES:
90 return _("HFS+ Finder Info");
91 case STREAM_SHA256_DIGEST:
92 return _("SHA256 digest");
93 case STREAM_SHA512_DIGEST:
94 return _("SHA512 digest");
95 case STREAM_SIGNED_DIGEST:
96 return _("Signed digest");
97 case STREAM_ENCRYPTED_FILE_DATA:
98 return _("Encrypted File data");
99 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
100 return _("Encrypted GZIP data");
101 case STREAM_ENCRYPTED_WIN32_DATA:
102 return _("Encrypted Win32 data");
103 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
104 return _("Encrypted Win32 GZIP data");
105 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
106 return _("Encrypted HFS+ resource fork");
108 sprintf(buf, "%d", stream);
109 return (const char *)buf;
114 void int64_LE2BE(int64_t* pBE, const int64_t v)
116 /* convert little endian to big endian */
117 if (htonl(1) != 1L) { /* no work if on little endian machine */
118 memcpy(pBE, &v, sizeof(int64_t));
121 uint8_t rv[sizeof(int64_t)];
122 uint8_t *pv = (uint8_t *) &v;
124 for (i = 0; i < 8; i++) {
127 memcpy(pBE, &rv, sizeof(int64_t));
132 void int32_LE2BE(int32_t* pBE, const int32_t v)
134 /* convert little endian to big endian */
135 if (htonl(1) != 1L) { /* no work if on little endian machine */
136 memcpy(pBE, &v, sizeof(int32_t));
139 uint8_t rv[sizeof(int32_t)];
140 uint8_t *pv = (uint8_t *) &v;
142 for (i = 0; i < 4; i++) {
145 memcpy(pBE, &rv, sizeof(int32_t));
150 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
152 /* pByte contains the buffer
153 dwSize the len to be processed. function assumes to be
154 called in successive incremental order over the complete
155 BackupRead stream beginning at pos 0 and ending at the end.
158 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
159 bool bContinue = false;
160 int64_t dwDataOffset = 0;
163 /* Win32 Stream Header size without name of stream.
164 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
166 int32_t dwSizeHeader = 20;
169 if (pContext->liNextHeader >= dwSize) {
170 dwDataLen = dwSize-dwDataOffset;
171 bContinue = false; /* 1 iteration is enough */
174 dwDataLen = pContext->liNextHeader-dwDataOffset;
175 bContinue = true; /* multiple iterations may be necessary */
179 /* copy block of real DATA */
180 if (pContext->bIsInData) {
181 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
185 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
186 int32_t dwOffsetTarget;
187 int32_t dwOffsetSource;
189 if (pContext->liNextHeader < 0) {
190 /* start of header was before this block, so we
191 * continue with the part in the current block
193 dwOffsetTarget = -pContext->liNextHeader;
196 /* start of header is inside of this block */
198 dwOffsetSource = pContext->liNextHeader;
201 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
202 bool bHeaderIsComplete;
204 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
205 /* header (or rest of header) is completely available
208 bHeaderIsComplete = true;
210 /* header will continue in next block */
211 bHeaderIsComplete = false;
212 dwHeaderPartLen = dwSize-dwOffsetSource;
215 /* copy the available portion of header to persistent copy */
216 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
218 /* recalculate position of next header */
219 if (bHeaderIsComplete) {
220 /* convert stream name size (32 bit little endian) to machine type */
222 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
223 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
225 /* convert stream size (64 bit little endian) to machine type */
226 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
227 pContext->liNextHeader += dwDataOffset;
229 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
230 if (dwDataOffset == dwSize)
234 /* stop and continue with next block */
236 pContext->bIsInData = false;
241 /* set "NextHeader" relative to the beginning of the next block */
242 pContext->liNextHeader-= dwSize;
249 /* ===============================================================
253 * ===============================================================
256 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
258 void unix_name_to_win32(POOLMEM **win32_name, char *name);
259 extern "C" HANDLE get_osfhandle(int fd);
263 void binit(BFILE *bfd)
265 memset(bfd, 0, sizeof(BFILE));
267 bfd->mode = BF_CLOSED;
268 bfd->use_backup_api = have_win32_api();
272 * Enables using the Backup API (win32_data).
273 * Returns 1 if function worked
274 * Returns 0 if failed (i.e. do not have Backup API on this machine)
276 bool set_win32_backup(BFILE *bfd)
278 /* We enable if possible here */
279 bfd->use_backup_api = have_win32_api();
280 return bfd->use_backup_api;
284 bool set_portable_backup(BFILE *bfd)
286 bfd->use_backup_api = false;
290 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
298 * Return 1 if we are NOT using Win32 BackupWrite()
301 bool is_portable_backup(BFILE *bfd)
303 return !bfd->use_backup_api;
306 bool have_win32_api()
308 return p_BackupRead && p_BackupWrite;
314 * Return true if we support the stream
315 * false if we do not support the stream
317 * This code is running under Win32, so we
318 * do not need #ifdef on MACOS ...
320 bool is_restore_stream_supported(int stream)
324 /* Streams known not to be supported */
326 case STREAM_GZIP_DATA:
327 case STREAM_SPARSE_GZIP_DATA:
328 case STREAM_WIN32_GZIP_DATA:
330 case STREAM_MACOS_FORK_DATA:
331 case STREAM_HFSPLUS_ATTRIBUTES:
332 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
337 case STREAM_GZIP_DATA:
338 case STREAM_SPARSE_GZIP_DATA:
339 case STREAM_WIN32_GZIP_DATA:
341 case STREAM_WIN32_DATA:
342 case STREAM_UNIX_ATTRIBUTES:
343 case STREAM_FILE_DATA:
344 case STREAM_MD5_DIGEST:
345 case STREAM_UNIX_ATTRIBUTES_EX:
346 case STREAM_SPARSE_DATA:
347 case STREAM_PROGRAM_NAMES:
348 case STREAM_PROGRAM_DATA:
349 case STREAM_SHA1_DIGEST:
351 case STREAM_SHA256_DIGEST:
352 case STREAM_SHA512_DIGEST:
355 case STREAM_SIGNED_DIGEST:
356 case STREAM_ENCRYPTED_FILE_DATA:
357 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
358 case STREAM_ENCRYPTED_WIN32_DATA:
359 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
361 case 0: /* compatibility with old tapes */
367 HANDLE bget_handle(BFILE *bfd)
372 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
374 POOLMEM *win32_fname;
375 POOLMEM *win32_fname_wchar;
377 DWORD dwaccess, dwflags, dwshare;
379 /* Convert to Windows path format */
380 win32_fname = get_pool_memory(PM_FNAME);
381 win32_fname_wchar = get_pool_memory(PM_FNAME);
383 unix_name_to_win32(&win32_fname, (char *)fname);
385 if (!(p_CreateFileA || p_CreateFileW))
388 if (p_CreateFileW && p_MultiByteToWideChar)
389 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
391 if (flags & O_CREAT) { /* Create */
392 if (bfd->use_backup_api) {
393 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
394 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
396 dwaccess = GENERIC_WRITE;
400 // unicode or ansii open for create write
401 if (p_CreateFileW && p_MultiByteToWideChar) {
402 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
403 dwaccess, /* Requested access */
405 NULL, /* SecurityAttributes */
406 CREATE_ALWAYS, /* CreationDisposition */
407 dwflags, /* Flags and attributes */
408 NULL); /* TemplateFile */
411 bfd->fh = p_CreateFileA(win32_fname,
412 dwaccess, /* Requested access */
414 NULL, /* SecurityAttributes */
415 CREATE_ALWAYS, /* CreationDisposition */
416 dwflags, /* Flags and attributes */
417 NULL); /* TemplateFile */
421 bfd->mode = BF_WRITE;
423 } else if (flags & O_WRONLY) { /* Open existing for write */
424 if (bfd->use_backup_api) {
425 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
426 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
428 dwaccess = GENERIC_WRITE;
432 // unicode or ansii open for open existing write
433 if (p_CreateFileW && p_MultiByteToWideChar) {
434 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
435 dwaccess, /* Requested access */
437 NULL, /* SecurityAttributes */
438 OPEN_EXISTING, /* CreationDisposition */
439 dwflags, /* Flags and attributes */
440 NULL); /* TemplateFile */
443 bfd->fh = p_CreateFileA(win32_fname,
444 dwaccess, /* Requested access */
446 NULL, /* SecurityAttributes */
447 OPEN_EXISTING, /* CreationDisposition */
448 dwflags, /* Flags and attributes */
449 NULL); /* TemplateFile */
453 bfd->mode = BF_WRITE;
456 if (bfd->use_backup_api) {
457 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
458 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
459 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
461 dwaccess = GENERIC_READ;
463 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
466 // unicode or ansii open for open existing read
467 if (p_CreateFileW && p_MultiByteToWideChar) {
468 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
469 dwaccess, /* Requested access */
470 dwshare, /* Share modes */
471 NULL, /* SecurityAttributes */
472 OPEN_EXISTING, /* CreationDisposition */
473 dwflags, /* Flags and attributes */
474 NULL); /* TemplateFile */
477 bfd->fh = p_CreateFileA(win32_fname,
478 dwaccess, /* Requested access */
479 dwshare, /* Share modes */
480 NULL, /* SecurityAttributes */
481 OPEN_EXISTING, /* CreationDisposition */
482 dwflags, /* Flags and attributes */
483 NULL); /* TemplateFile */
489 if (bfd->fh == INVALID_HANDLE_VALUE) {
490 bfd->lerror = GetLastError();
491 bfd->berrno = b_errno_win32;
492 errno = b_errno_win32;
493 bfd->mode = BF_CLOSED;
496 bfd->lpContext = NULL;
497 bfd->win32DecompContext.bIsInData = false;
498 bfd->win32DecompContext.liNextHeader = 0;
499 free_pool_memory(win32_fname_wchar);
500 free_pool_memory(win32_fname);
501 return bfd->mode == BF_CLOSED ? -1 : 1;
505 * Returns 0 on success
508 int bclose(BFILE *bfd)
513 free_pool_memory(bfd->errmsg);
516 if (bfd->mode == BF_CLOSED) {
519 if (bfd->use_backup_api && bfd->mode == BF_READ) {
521 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
523 (DWORD)0, /* bytes to read */
524 &bfd->rw_bytes, /* bytes read */
526 1, /* ProcessSecurity */
527 &bfd->lpContext)) { /* Read context */
528 errno = b_errno_win32;
531 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
533 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
535 (DWORD)0, /* bytes to read */
536 &bfd->rw_bytes, /* bytes written */
538 1, /* ProcessSecurity */
539 &bfd->lpContext)) { /* Write context */
540 errno = b_errno_win32;
544 if (!CloseHandle(bfd->fh)) {
546 errno = b_errno_win32;
548 bfd->mode = BF_CLOSED;
549 bfd->lpContext = NULL;
553 /* Returns: bytes read on success
557 ssize_t bread(BFILE *bfd, void *buf, size_t count)
561 if (bfd->use_backup_api) {
562 if (!p_BackupRead(bfd->fh,
567 1, /* Process Security */
568 &bfd->lpContext)) { /* Context */
569 bfd->lerror = GetLastError();
570 bfd->berrno = b_errno_win32;
571 errno = b_errno_win32;
575 if (!ReadFile(bfd->fh,
580 bfd->lerror = GetLastError();
581 bfd->berrno = b_errno_win32;
582 errno = b_errno_win32;
587 return (ssize_t)bfd->rw_bytes;
590 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
594 if (bfd->use_backup_api) {
595 if (!p_BackupWrite(bfd->fh,
600 1, /* Process Security */
601 &bfd->lpContext)) { /* Context */
602 bfd->lerror = GetLastError();
603 bfd->berrno = b_errno_win32;
604 errno = b_errno_win32;
608 if (!WriteFile(bfd->fh,
613 bfd->lerror = GetLastError();
614 bfd->berrno = b_errno_win32;
615 errno = b_errno_win32;
619 return (ssize_t)bfd->rw_bytes;
622 bool is_bopen(BFILE *bfd)
624 return bfd->mode != BF_CLOSED;
627 off_t blseek(BFILE *bfd, off_t offset, int whence)
629 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
633 #else /* Unix systems */
635 /* ===============================================================
639 * ===============================================================
641 void binit(BFILE *bfd)
643 memset(bfd, 0, sizeof(BFILE));
647 bool have_win32_api()
649 return false; /* no can do */
653 * Enables using the Backup API (win32_data).
654 * Returns true if function worked
655 * Returns false if failed (i.e. do not have Backup API on this machine)
657 bool set_win32_backup(BFILE *bfd)
659 return false; /* no can do */
663 bool set_portable_backup(BFILE *bfd)
665 return true; /* no problem */
669 * Return true if we are writing in portable format
670 * return false if not
672 bool is_portable_backup(BFILE *bfd)
674 return true; /* portable by definition */
677 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
680 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
681 return true; /* already setup */
684 if (python_set_prog(jcr, prog)) {
685 Dmsg1(000, "Set prog=%s\n", prog);
691 Dmsg0(000, "No prog set\n");
698 * This code is running on a non-Win32 machine
700 bool is_restore_stream_supported(int stream)
702 /* No Win32 backup on this machine */
705 case STREAM_GZIP_DATA:
706 case STREAM_SPARSE_GZIP_DATA:
707 case STREAM_WIN32_GZIP_DATA:
709 #ifndef HAVE_DARWIN_OS
710 case STREAM_MACOS_FORK_DATA:
711 case STREAM_HFSPLUS_ATTRIBUTES:
717 case STREAM_GZIP_DATA:
718 case STREAM_SPARSE_GZIP_DATA:
719 case STREAM_WIN32_GZIP_DATA:
721 case STREAM_WIN32_DATA:
722 case STREAM_UNIX_ATTRIBUTES:
723 case STREAM_FILE_DATA:
724 case STREAM_MD5_DIGEST:
725 case STREAM_UNIX_ATTRIBUTES_EX:
726 case STREAM_SPARSE_DATA:
727 case STREAM_PROGRAM_NAMES:
728 case STREAM_PROGRAM_DATA:
729 case STREAM_SHA1_DIGEST:
731 case STREAM_SHA256_DIGEST:
732 case STREAM_SHA512_DIGEST:
735 case STREAM_SIGNED_DIGEST:
736 case STREAM_ENCRYPTED_FILE_DATA:
737 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
738 case STREAM_ENCRYPTED_WIN32_DATA:
739 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
741 #ifdef HAVE_DARWIN_OS
742 case STREAM_MACOS_FORK_DATA:
743 case STREAM_HFSPLUS_ATTRIBUTES:
745 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
746 #endif /* HAVE_CRYPTO */
747 #endif /* HAVE_DARWIN_OS */
748 case 0: /* compatibility with old tapes */
755 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
757 /* Open reader/writer program */
759 Dmsg1(000, "Open file %d\n", bfd->fid);
760 return python_open(bfd, fname, flags, mode);
763 /* Normal file open */
764 Dmsg1(400, "open file %s\n", fname);
765 bfd->fid = open(fname, flags, mode);
767 Dmsg1(400, "Open file %d\n", bfd->fid);
770 bfd->win32DecompContext.bIsInData = false;
771 bfd->win32DecompContext.liNextHeader = 0;
776 #ifdef HAVE_DARWIN_OS
777 /* Open the resource fork of a file. */
778 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
782 rsrc_fname = get_pool_memory(PM_FNAME);
783 pm_strcpy(rsrc_fname, fname);
784 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
785 bopen(bfd, rsrc_fname, flags, mode);
786 free_pool_memory(rsrc_fname);
792 int bclose(BFILE *bfd)
796 Dmsg1(400, "Close file %d\n", bfd->fid);
798 /* Close reader/writer program */
800 return python_close(bfd);
803 if (bfd->fid == -1) {
807 /* Close normal file */
808 stat = close(bfd->fid);
814 ssize_t bread(BFILE *bfd, void *buf, size_t count)
819 return python_read(bfd, buf, count);
821 stat = read(bfd->fid, buf, count);
826 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
831 return python_write(bfd, buf, count);
833 stat = write(bfd->fid, buf, count);
838 bool is_bopen(BFILE *bfd)
840 return bfd->fid >= 0;
843 off_t blseek(BFILE *bfd, off_t offset, int whence)
846 pos = lseek(bfd->fid, offset, whence);