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_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 */
410 bfd->fh = p_CreateFileA(win32_fname,
411 dwaccess, /* Requested access */
413 NULL, /* SecurityAttributes */
414 CREATE_ALWAYS, /* CreationDisposition */
415 dwflags, /* Flags and attributes */
416 NULL); /* TemplateFile */
419 bfd->mode = BF_WRITE;
421 } else if (flags & O_WRONLY) { /* Open existing for write */
422 if (bfd->use_backup_api) {
423 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
424 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
426 dwaccess = GENERIC_WRITE;
430 // unicode or ansii open for open existing write
431 if (p_CreateFileW && p_MultiByteToWideChar) {
432 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
433 dwaccess, /* Requested access */
435 NULL, /* SecurityAttributes */
436 OPEN_EXISTING, /* CreationDisposition */
437 dwflags, /* Flags and attributes */
438 NULL); /* TemplateFile */
440 bfd->fh = p_CreateFileA(win32_fname,
441 dwaccess, /* Requested access */
443 NULL, /* SecurityAttributes */
444 OPEN_EXISTING, /* CreationDisposition */
445 dwflags, /* Flags and attributes */
446 NULL); /* TemplateFile */
450 bfd->mode = BF_WRITE;
453 if (bfd->use_backup_api) {
454 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
455 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
456 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
458 dwaccess = GENERIC_READ;
460 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
463 // unicode or ansii open for open existing read
464 if (p_CreateFileW && p_MultiByteToWideChar) {
465 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
466 dwaccess, /* Requested access */
467 dwshare, /* Share modes */
468 NULL, /* SecurityAttributes */
469 OPEN_EXISTING, /* CreationDisposition */
470 dwflags, /* Flags and attributes */
471 NULL); /* TemplateFile */
473 bfd->fh = p_CreateFileA(win32_fname,
474 dwaccess, /* Requested access */
475 dwshare, /* Share modes */
476 NULL, /* SecurityAttributes */
477 OPEN_EXISTING, /* CreationDisposition */
478 dwflags, /* Flags and attributes */
479 NULL); /* TemplateFile */
485 if (bfd->fh == INVALID_HANDLE_VALUE) {
486 bfd->lerror = GetLastError();
487 bfd->berrno = b_errno_win32;
488 errno = b_errno_win32;
489 bfd->mode = BF_CLOSED;
492 bfd->lpContext = NULL;
493 bfd->win32DecompContext.bIsInData = false;
494 bfd->win32DecompContext.liNextHeader = 0;
495 free_pool_memory(win32_fname_wchar);
496 free_pool_memory(win32_fname);
497 return bfd->mode == BF_CLOSED ? -1 : 1;
501 * Returns 0 on success
504 int bclose(BFILE *bfd)
509 free_pool_memory(bfd->errmsg);
512 if (bfd->mode == BF_CLOSED) {
515 if (bfd->use_backup_api && bfd->mode == BF_READ) {
517 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
519 (DWORD)0, /* bytes to read */
520 &bfd->rw_bytes, /* bytes read */
522 1, /* ProcessSecurity */
523 &bfd->lpContext)) { /* Read context */
524 errno = b_errno_win32;
527 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
529 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
531 (DWORD)0, /* bytes to read */
532 &bfd->rw_bytes, /* bytes written */
534 1, /* ProcessSecurity */
535 &bfd->lpContext)) { /* Write context */
536 errno = b_errno_win32;
540 if (!CloseHandle(bfd->fh)) {
542 errno = b_errno_win32;
544 bfd->mode = BF_CLOSED;
545 bfd->lpContext = NULL;
549 /* Returns: bytes read on success
553 ssize_t bread(BFILE *bfd, void *buf, size_t count)
557 if (bfd->use_backup_api) {
558 if (!p_BackupRead(bfd->fh,
563 1, /* Process Security */
564 &bfd->lpContext)) { /* Context */
565 bfd->lerror = GetLastError();
566 bfd->berrno = b_errno_win32;
567 errno = b_errno_win32;
571 if (!ReadFile(bfd->fh,
576 bfd->lerror = GetLastError();
577 bfd->berrno = b_errno_win32;
578 errno = b_errno_win32;
583 return (ssize_t)bfd->rw_bytes;
586 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
590 if (bfd->use_backup_api) {
591 if (!p_BackupWrite(bfd->fh,
596 1, /* Process Security */
597 &bfd->lpContext)) { /* Context */
598 bfd->lerror = GetLastError();
599 bfd->berrno = b_errno_win32;
600 errno = b_errno_win32;
604 if (!WriteFile(bfd->fh,
609 bfd->lerror = GetLastError();
610 bfd->berrno = b_errno_win32;
611 errno = b_errno_win32;
615 return (ssize_t)bfd->rw_bytes;
618 bool is_bopen(BFILE *bfd)
620 return bfd->mode != BF_CLOSED;
623 off_t blseek(BFILE *bfd, off_t offset, int whence)
625 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
629 #else /* Unix systems */
631 /* ===============================================================
635 * ===============================================================
637 void binit(BFILE *bfd)
639 memset(bfd, 0, sizeof(BFILE));
643 bool have_win32_api()
645 return false; /* no can do */
649 * Enables using the Backup API (win32_data).
650 * Returns true if function worked
651 * Returns false if failed (i.e. do not have Backup API on this machine)
653 bool set_win32_backup(BFILE *bfd)
655 return false; /* no can do */
659 bool set_portable_backup(BFILE *bfd)
661 return true; /* no problem */
665 * Return true if we are writing in portable format
666 * return false if not
668 bool is_portable_backup(BFILE *bfd)
670 return true; /* portable by definition */
673 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
676 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
677 return true; /* already setup */
680 if (python_set_prog(jcr, prog)) {
681 Dmsg1(000, "Set prog=%s\n", prog);
687 Dmsg0(000, "No prog set\n");
694 * This code is running on a non-Win32 machine
696 bool is_restore_stream_supported(int stream)
698 /* No Win32 backup on this machine */
701 case STREAM_GZIP_DATA:
702 case STREAM_SPARSE_GZIP_DATA:
703 case STREAM_WIN32_GZIP_DATA:
705 #ifndef HAVE_DARWIN_OS
706 case STREAM_MACOS_FORK_DATA:
707 case STREAM_HFSPLUS_ATTRIBUTES:
713 case STREAM_GZIP_DATA:
714 case STREAM_SPARSE_GZIP_DATA:
715 case STREAM_WIN32_GZIP_DATA:
717 case STREAM_WIN32_DATA:
718 case STREAM_UNIX_ATTRIBUTES:
719 case STREAM_FILE_DATA:
720 case STREAM_MD5_DIGEST:
721 case STREAM_UNIX_ATTRIBUTES_EX:
722 case STREAM_SPARSE_DATA:
723 case STREAM_PROGRAM_NAMES:
724 case STREAM_PROGRAM_DATA:
725 case STREAM_SHA1_DIGEST:
727 case STREAM_SHA256_DIGEST:
728 case STREAM_SHA512_DIGEST:
731 case STREAM_SIGNED_DIGEST:
732 case STREAM_ENCRYPTED_FILE_DATA:
733 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
734 case STREAM_ENCRYPTED_WIN32_DATA:
735 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
737 #ifdef HAVE_DARWIN_OS
738 case STREAM_MACOS_FORK_DATA:
739 case STREAM_HFSPLUS_ATTRIBUTES:
741 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
742 #endif /* HAVE_CRYPTO */
743 #endif /* HAVE_DARWIN_OS */
744 case 0: /* compatibility with old tapes */
751 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
753 /* Open reader/writer program */
755 Dmsg1(000, "Open file %d\n", bfd->fid);
756 return python_open(bfd, fname, flags, mode);
759 /* Normal file open */
760 Dmsg1(400, "open file %s\n", fname);
761 /* We use fnctl to set O_NOATIME if requested to avoid open error */
762 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
763 /* Set O_NOATIME if possible */
764 if (bfd->fid != -1 && flags & O_NOATIME) {
765 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
766 if (oldflags == -1) {
771 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
772 /* EPERM means setting O_NOATIME was not allowed */
773 if (ret == -1 && errno != EPERM) {
781 Dmsg1(400, "Open file %d\n", bfd->fid);
784 bfd->win32DecompContext.bIsInData = false;
785 bfd->win32DecompContext.liNextHeader = 0;
790 #ifdef HAVE_DARWIN_OS
791 /* Open the resource fork of a file. */
792 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
796 rsrc_fname = get_pool_memory(PM_FNAME);
797 pm_strcpy(rsrc_fname, fname);
798 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
799 bopen(bfd, rsrc_fname, flags, mode);
800 free_pool_memory(rsrc_fname);
806 int bclose(BFILE *bfd)
810 Dmsg1(400, "Close file %d\n", bfd->fid);
812 /* Close reader/writer program */
814 return python_close(bfd);
817 if (bfd->fid == -1) {
821 /* Close normal file */
822 stat = close(bfd->fid);
828 ssize_t bread(BFILE *bfd, void *buf, size_t count)
833 return python_read(bfd, buf, count);
835 stat = read(bfd->fid, buf, count);
840 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
845 return python_write(bfd, buf, count);
847 stat = write(bfd->fid, buf, count);
852 bool is_bopen(BFILE *bfd)
854 return bfd->fid >= 0;
857 off_t blseek(BFILE *bfd, off_t offset, int whence)
860 pos = lseek(bfd->fid, offset, whence);