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 */
173 dwDataLen = pContext->liNextHeader-dwDataOffset;
174 bContinue = true; /* multiple iterations may be necessary */
178 /* copy block of real DATA */
179 if (pContext->bIsInData) {
180 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
184 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
185 int32_t dwOffsetTarget;
186 int32_t dwOffsetSource;
188 if (pContext->liNextHeader < 0) {
189 /* start of header was before this block, so we
190 * continue with the part in the current block
192 dwOffsetTarget = -pContext->liNextHeader;
195 /* start of header is inside of this block */
197 dwOffsetSource = pContext->liNextHeader;
200 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
201 bool bHeaderIsComplete;
203 if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
204 /* header (or rest of header) is completely available
207 bHeaderIsComplete = true;
209 /* header will continue in next block */
210 bHeaderIsComplete = false;
211 dwHeaderPartLen = dwSize-dwOffsetSource;
214 /* copy the available portion of header to persistent copy */
215 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
217 /* recalculate position of next header */
218 if (bHeaderIsComplete) {
219 /* convert stream name size (32 bit little endian) to machine type */
221 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
222 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
224 /* convert stream size (64 bit little endian) to machine type */
225 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
226 pContext->liNextHeader += dwDataOffset;
228 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
229 if (dwDataOffset == dwSize)
232 /* stop and continue with next block */
234 pContext->bIsInData = false;
239 /* set "NextHeader" relative to the beginning of the next block */
240 pContext->liNextHeader-= dwSize;
247 /* ===============================================================
251 * ===============================================================
254 #if defined(HAVE_WIN32)
256 void unix_name_to_win32(POOLMEM **win32_name, char *name);
257 extern "C" HANDLE get_osfhandle(int fd);
260 void binit(BFILE *bfd)
262 memset(bfd, 0, sizeof(BFILE));
264 bfd->mode = BF_CLOSED;
265 bfd->use_backup_api = have_win32_api();
269 * Enables using the Backup API (win32_data).
270 * Returns 1 if function worked
271 * Returns 0 if failed (i.e. do not have Backup API on this machine)
273 bool set_win32_backup(BFILE *bfd)
275 /* We enable if possible here */
276 bfd->use_backup_api = have_win32_api();
277 return bfd->use_backup_api;
281 bool set_portable_backup(BFILE *bfd)
283 bfd->use_backup_api = false;
287 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
295 * Return 1 if we are NOT using Win32 BackupWrite()
298 bool is_portable_backup(BFILE *bfd)
300 return !bfd->use_backup_api;
303 bool have_win32_api()
305 return p_BackupRead && p_BackupWrite;
310 * Return true if we support the stream
311 * false if we do not support the stream
313 * This code is running under Win32, so we
314 * do not need #ifdef on MACOS ...
316 bool is_restore_stream_supported(int stream)
320 /* Streams known not to be supported */
322 case STREAM_GZIP_DATA:
323 case STREAM_SPARSE_GZIP_DATA:
324 case STREAM_WIN32_GZIP_DATA:
326 case STREAM_MACOS_FORK_DATA:
327 case STREAM_HFSPLUS_ATTRIBUTES:
328 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
333 case STREAM_GZIP_DATA:
334 case STREAM_SPARSE_GZIP_DATA:
335 case STREAM_WIN32_GZIP_DATA:
337 case STREAM_WIN32_DATA:
338 case STREAM_UNIX_ATTRIBUTES:
339 case STREAM_FILE_DATA:
340 case STREAM_MD5_DIGEST:
341 case STREAM_UNIX_ATTRIBUTES_EX:
342 case STREAM_SPARSE_DATA:
343 case STREAM_PROGRAM_NAMES:
344 case STREAM_PROGRAM_DATA:
345 case STREAM_SHA1_DIGEST:
347 case STREAM_SHA256_DIGEST:
348 case STREAM_SHA512_DIGEST:
351 case STREAM_SIGNED_DIGEST:
352 case STREAM_ENCRYPTED_FILE_DATA:
353 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
354 case STREAM_ENCRYPTED_WIN32_DATA:
355 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
357 case 0: /* compatibility with old tapes */
363 HANDLE bget_handle(BFILE *bfd)
368 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
370 POOLMEM *win32_fname;
371 POOLMEM *win32_fname_wchar;
373 DWORD dwaccess, dwflags, dwshare;
375 /* Convert to Windows path format */
376 win32_fname = get_pool_memory(PM_FNAME);
377 win32_fname_wchar = get_pool_memory(PM_FNAME);
379 unix_name_to_win32(&win32_fname, (char *)fname);
381 if (!(p_CreateFileA || p_CreateFileW))
384 if (p_CreateFileW && p_MultiByteToWideChar)
385 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
387 if (flags & O_CREAT) { /* Create */
388 if (bfd->use_backup_api) {
389 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
390 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
392 dwaccess = GENERIC_WRITE;
396 // unicode or ansii open for create write
397 if (p_CreateFileW && p_MultiByteToWideChar) {
398 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
399 dwaccess, /* Requested access */
401 NULL, /* SecurityAttributes */
402 CREATE_ALWAYS, /* CreationDisposition */
403 dwflags, /* Flags and attributes */
404 NULL); /* TemplateFile */
406 bfd->fh = p_CreateFileA(win32_fname,
407 dwaccess, /* Requested access */
409 NULL, /* SecurityAttributes */
410 CREATE_ALWAYS, /* CreationDisposition */
411 dwflags, /* Flags and attributes */
412 NULL); /* TemplateFile */
415 bfd->mode = BF_WRITE;
417 } else if (flags & O_WRONLY) { /* Open existing for write */
418 if (bfd->use_backup_api) {
419 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
420 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
422 dwaccess = GENERIC_WRITE;
426 // unicode or ansii open for open existing write
427 if (p_CreateFileW && p_MultiByteToWideChar) {
428 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
429 dwaccess, /* Requested access */
431 NULL, /* SecurityAttributes */
432 OPEN_EXISTING, /* CreationDisposition */
433 dwflags, /* Flags and attributes */
434 NULL); /* TemplateFile */
436 bfd->fh = p_CreateFileA(win32_fname,
437 dwaccess, /* Requested access */
439 NULL, /* SecurityAttributes */
440 OPEN_EXISTING, /* CreationDisposition */
441 dwflags, /* Flags and attributes */
442 NULL); /* TemplateFile */
446 bfd->mode = BF_WRITE;
449 if (bfd->use_backup_api) {
450 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
451 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
452 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
454 dwaccess = GENERIC_READ;
456 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
459 // unicode or ansii open for open existing read
460 if (p_CreateFileW && p_MultiByteToWideChar) {
461 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
462 dwaccess, /* Requested access */
463 dwshare, /* Share modes */
464 NULL, /* SecurityAttributes */
465 OPEN_EXISTING, /* CreationDisposition */
466 dwflags, /* Flags and attributes */
467 NULL); /* TemplateFile */
469 bfd->fh = p_CreateFileA(win32_fname,
470 dwaccess, /* Requested access */
471 dwshare, /* Share modes */
472 NULL, /* SecurityAttributes */
473 OPEN_EXISTING, /* CreationDisposition */
474 dwflags, /* Flags and attributes */
475 NULL); /* TemplateFile */
481 if (bfd->fh == INVALID_HANDLE_VALUE) {
482 bfd->lerror = GetLastError();
483 bfd->berrno = b_errno_win32;
484 errno = b_errno_win32;
485 bfd->mode = BF_CLOSED;
488 bfd->lpContext = NULL;
489 bfd->win32DecompContext.bIsInData = false;
490 bfd->win32DecompContext.liNextHeader = 0;
491 free_pool_memory(win32_fname_wchar);
492 free_pool_memory(win32_fname);
493 return bfd->mode == BF_CLOSED ? -1 : 1;
497 * Returns 0 on success
500 int bclose(BFILE *bfd)
505 free_pool_memory(bfd->errmsg);
508 if (bfd->mode == BF_CLOSED) {
511 if (bfd->use_backup_api && bfd->mode == BF_READ) {
513 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
515 (DWORD)0, /* bytes to read */
516 &bfd->rw_bytes, /* bytes read */
518 1, /* ProcessSecurity */
519 &bfd->lpContext)) { /* Read context */
520 errno = b_errno_win32;
523 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
525 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
527 (DWORD)0, /* bytes to read */
528 &bfd->rw_bytes, /* bytes written */
530 1, /* ProcessSecurity */
531 &bfd->lpContext)) { /* Write context */
532 errno = b_errno_win32;
536 if (!CloseHandle(bfd->fh)) {
538 errno = b_errno_win32;
540 bfd->mode = BF_CLOSED;
541 bfd->lpContext = NULL;
545 /* Returns: bytes read on success
549 ssize_t bread(BFILE *bfd, void *buf, size_t count)
553 if (bfd->use_backup_api) {
554 if (!p_BackupRead(bfd->fh,
559 1, /* Process Security */
560 &bfd->lpContext)) { /* Context */
561 bfd->lerror = GetLastError();
562 bfd->berrno = b_errno_win32;
563 errno = b_errno_win32;
567 if (!ReadFile(bfd->fh,
572 bfd->lerror = GetLastError();
573 bfd->berrno = b_errno_win32;
574 errno = b_errno_win32;
579 return (ssize_t)bfd->rw_bytes;
582 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
586 if (bfd->use_backup_api) {
587 if (!p_BackupWrite(bfd->fh,
592 1, /* Process Security */
593 &bfd->lpContext)) { /* Context */
594 bfd->lerror = GetLastError();
595 bfd->berrno = b_errno_win32;
596 errno = b_errno_win32;
600 if (!WriteFile(bfd->fh,
605 bfd->lerror = GetLastError();
606 bfd->berrno = b_errno_win32;
607 errno = b_errno_win32;
611 return (ssize_t)bfd->rw_bytes;
614 bool is_bopen(BFILE *bfd)
616 return bfd->mode != BF_CLOSED;
619 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
621 LONG offset_low = (LONG)offset;
622 LONG offset_high = (LONG)(offset >> 32);
625 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
627 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
628 return (boffset_t)-1;
631 return ((boffset_t)offset_high << 32) | dwResult;
634 #else /* Unix systems */
636 /* ===============================================================
640 * ===============================================================
642 void binit(BFILE *bfd)
644 memset(bfd, 0, sizeof(BFILE));
648 bool have_win32_api()
650 return false; /* no can do */
654 * Enables using the Backup API (win32_data).
655 * Returns true if function worked
656 * Returns false if failed (i.e. do not have Backup API on this machine)
658 bool set_win32_backup(BFILE *bfd)
660 return false; /* no can do */
664 bool set_portable_backup(BFILE *bfd)
666 return true; /* no problem */
670 * Return true if we are writing in portable format
671 * return false if not
673 bool is_portable_backup(BFILE *bfd)
675 return true; /* portable by definition */
678 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
681 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
682 return true; /* already setup */
685 if (python_set_prog(jcr, prog)) {
686 Dmsg1(000, "Set prog=%s\n", prog);
692 Dmsg0(000, "No prog set\n");
699 * This code is running on a non-Win32 machine
701 bool is_restore_stream_supported(int stream)
703 /* No Win32 backup on this machine */
706 case STREAM_GZIP_DATA:
707 case STREAM_SPARSE_GZIP_DATA:
708 case STREAM_WIN32_GZIP_DATA:
710 #ifndef HAVE_DARWIN_OS
711 case STREAM_MACOS_FORK_DATA:
712 case STREAM_HFSPLUS_ATTRIBUTES:
718 case STREAM_GZIP_DATA:
719 case STREAM_SPARSE_GZIP_DATA:
720 case STREAM_WIN32_GZIP_DATA:
722 case STREAM_WIN32_DATA:
723 case STREAM_UNIX_ATTRIBUTES:
724 case STREAM_FILE_DATA:
725 case STREAM_MD5_DIGEST:
726 case STREAM_UNIX_ATTRIBUTES_EX:
727 case STREAM_SPARSE_DATA:
728 case STREAM_PROGRAM_NAMES:
729 case STREAM_PROGRAM_DATA:
730 case STREAM_SHA1_DIGEST:
732 case STREAM_SHA256_DIGEST:
733 case STREAM_SHA512_DIGEST:
736 case STREAM_SIGNED_DIGEST:
737 case STREAM_ENCRYPTED_FILE_DATA:
738 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
739 case STREAM_ENCRYPTED_WIN32_DATA:
740 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
742 #ifdef HAVE_DARWIN_OS
743 case STREAM_MACOS_FORK_DATA:
744 case STREAM_HFSPLUS_ATTRIBUTES:
746 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
747 #endif /* HAVE_CRYPTO */
748 #endif /* HAVE_DARWIN_OS */
749 case 0: /* compatibility with old tapes */
756 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
758 /* Open reader/writer program */
760 Dmsg1(000, "Open file %d\n", bfd->fid);
761 return python_open(bfd, fname, flags, mode);
764 /* Normal file open */
765 Dmsg1(400, "open file %s\n", fname);
766 /* We use fnctl to set O_NOATIME if requested to avoid open error */
767 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
768 /* Set O_NOATIME if possible */
769 if (bfd->fid != -1 && flags & O_NOATIME) {
770 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
771 if (oldflags == -1) {
776 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
777 /* EPERM means setting O_NOATIME was not allowed */
778 if (ret == -1 && errno != EPERM) {
786 Dmsg1(400, "Open file %d\n", bfd->fid);
789 bfd->win32DecompContext.bIsInData = false;
790 bfd->win32DecompContext.liNextHeader = 0;
795 #ifdef HAVE_DARWIN_OS
796 /* Open the resource fork of a file. */
797 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
801 rsrc_fname = get_pool_memory(PM_FNAME);
802 pm_strcpy(rsrc_fname, fname);
803 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
804 bopen(bfd, rsrc_fname, flags, mode);
805 free_pool_memory(rsrc_fname);
811 int bclose(BFILE *bfd)
815 Dmsg1(400, "Close file %d\n", bfd->fid);
817 /* Close reader/writer program */
819 return python_close(bfd);
822 if (bfd->fid == -1) {
826 /* Close normal file */
827 stat = close(bfd->fid);
833 ssize_t bread(BFILE *bfd, void *buf, size_t count)
838 return python_read(bfd, buf, count);
840 stat = read(bfd->fid, buf, count);
845 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
850 return python_write(bfd, buf, count);
852 stat = write(bfd->fid, buf, count);
857 bool is_bopen(BFILE *bfd)
859 return bfd->fid >= 0;
862 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
865 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);