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
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:
56 const char *stream_to_ascii(int stream)
61 case STREAM_GZIP_DATA:
62 return _("GZIP data");
63 case STREAM_SPARSE_GZIP_DATA:
64 return _("GZIP sparse data");
65 case STREAM_WIN32_DATA:
66 return _("Win32 data");
67 case STREAM_WIN32_GZIP_DATA:
68 return _("Win32 GZIP data");
69 case STREAM_UNIX_ATTRIBUTES:
70 return _("File attributes");
71 case STREAM_FILE_DATA:
72 return _("File data");
73 case STREAM_MD5_DIGEST:
74 return _("MD5 digest");
75 case STREAM_UNIX_ATTRIBUTES_EX:
76 return _("Extended attributes");
77 case STREAM_SPARSE_DATA:
78 return _("Sparse data");
79 case STREAM_PROGRAM_NAMES:
80 return _("Program names");
81 case STREAM_PROGRAM_DATA:
82 return _("Program data");
83 case STREAM_SHA1_DIGEST:
84 return _("SHA1 digest");
85 case STREAM_MACOS_FORK_DATA:
86 return _("HFS+ resource fork");
87 case STREAM_HFSPLUS_ATTRIBUTES:
88 return _("HFS+ Finder Info");
89 case STREAM_SHA256_DIGEST:
90 return _("SHA256 digest");
91 case STREAM_SHA512_DIGEST:
92 return _("SHA512 digest");
93 case STREAM_SIGNED_DIGEST:
94 return _("Signed digest");
96 sprintf(buf, "%d", stream);
97 return (const char *)buf;
102 void int64_LE2BE(int64_t* pBE, const int64_t v)
104 /* convert little endian to big endian */
105 if (htonl(1) != 1L) { /* no work if on little endian machine */
106 memcpy(pBE, &v, sizeof(int64_t));
109 uint8_t rv[sizeof(int64_t)];
110 uint8_t *pv = (uint8_t *) &v;
112 for (i = 0; i < 8; i++) {
115 memcpy(pBE, &rv, sizeof(int64_t));
120 void int32_LE2BE(int32_t* pBE, const int32_t v)
122 /* convert little endian to big endian */
123 if (htonl(1) != 1L) { /* no work if on little endian machine */
124 memcpy(pBE, &v, sizeof(int32_t));
127 uint8_t rv[sizeof(int32_t)];
128 uint8_t *pv = (uint8_t *) &v;
130 for (i = 0; i < 4; i++) {
133 memcpy(pBE, &rv, sizeof(int32_t));
138 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
140 /* pByte contains the buffer
141 dwSize the len to be processed. function assumes to be
142 called in successive incremental order over the complete
143 BackupRead stream beginning at pos 0 and ending at the end.
146 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
147 bool bContinue = false;
148 int64_t dwDataOffset = 0;
151 /* Win32 Stream Header size without name of stream.
152 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
154 int32_t dwSizeHeader = 20;
157 if (pContext->liNextHeader >= dwSize) {
158 dwDataLen = dwSize-dwDataOffset;
159 bContinue = false; /* 1 iteration is enough */
162 dwDataLen = pContext->liNextHeader-dwDataOffset;
163 bContinue = true; /* multiple iterations may be necessary */
167 /* copy block of real DATA */
168 if (pContext->bIsInData) {
169 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
173 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
174 int32_t dwOffsetTarget;
175 int32_t dwOffsetSource;
177 if (pContext->liNextHeader < 0) {
178 /* start of header was before this block, so we
179 * continue with the part in the current block
181 dwOffsetTarget = -pContext->liNextHeader;
184 /* start of header is inside of this block */
186 dwOffsetSource = pContext->liNextHeader;
189 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
190 bool bHeaderIsComplete;
192 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
193 /* header (or rest of header) is completely available
196 bHeaderIsComplete = true;
198 /* header will continue in next block */
199 bHeaderIsComplete = false;
200 dwHeaderPartLen = dwSize-dwOffsetSource;
203 /* copy the available portion of header to persistent copy */
204 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
206 /* recalculate position of next header */
207 if (bHeaderIsComplete) {
208 /* convert stream name size (32 bit little endian) to machine type */
210 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
211 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
213 /* convert stream size (64 bit little endian) to machine type */
214 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
215 pContext->liNextHeader += dwDataOffset;
217 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
218 if (dwDataOffset == dwSize)
222 /* stop and continue with next block */
224 pContext->bIsInData = false;
229 /* set "NextHeader" relative to the beginning of the next block */
230 pContext->liNextHeader-= dwSize;
237 /* ===============================================================
241 * ===============================================================
244 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
246 void unix_name_to_win32(POOLMEM **win32_name, char *name);
247 extern "C" HANDLE get_osfhandle(int fd);
251 void binit(BFILE *bfd)
253 memset(bfd, 0, sizeof(BFILE));
255 bfd->mode = BF_CLOSED;
256 bfd->use_backup_api = have_win32_api();
260 * Enables using the Backup API (win32_data).
261 * Returns 1 if function worked
262 * Returns 0 if failed (i.e. do not have Backup API on this machine)
264 bool set_win32_backup(BFILE *bfd)
266 /* We enable if possible here */
267 bfd->use_backup_api = have_win32_api();
268 return bfd->use_backup_api;
272 bool set_portable_backup(BFILE *bfd)
274 bfd->use_backup_api = false;
278 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
286 * Return 1 if we are NOT using Win32 BackupWrite()
289 bool is_portable_backup(BFILE *bfd)
291 return !bfd->use_backup_api;
294 bool have_win32_api()
296 return p_BackupRead && p_BackupWrite;
302 * Return true if we support the stream
303 * false if we do not support the stream
305 * This code is running under Win32, so we
306 * do not need #ifdef on MACOS ...
308 bool is_restore_stream_supported(int stream)
312 /* Streams known not to be supported */
314 case STREAM_GZIP_DATA:
315 case STREAM_SPARSE_GZIP_DATA:
316 case STREAM_WIN32_GZIP_DATA:
318 case STREAM_MACOS_FORK_DATA:
319 case STREAM_HFSPLUS_ATTRIBUTES:
324 case STREAM_GZIP_DATA:
325 case STREAM_SPARSE_GZIP_DATA:
326 case STREAM_WIN32_GZIP_DATA:
328 case STREAM_WIN32_DATA:
329 case STREAM_UNIX_ATTRIBUTES:
330 case STREAM_FILE_DATA:
331 case STREAM_MD5_DIGEST:
332 case STREAM_UNIX_ATTRIBUTES_EX:
333 case STREAM_SPARSE_DATA:
334 case STREAM_PROGRAM_NAMES:
335 case STREAM_PROGRAM_DATA:
336 case STREAM_SHA1_DIGEST:
338 case STREAM_SHA256_DIGEST:
339 case STREAM_SHA512_DIGEST:
342 case STREAM_SIGNED_DIGEST:
344 case 0: /* compatibility with old tapes */
350 HANDLE bget_handle(BFILE *bfd)
355 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
357 POOLMEM *win32_fname;
358 POOLMEM *win32_fname_wchar;
360 DWORD dwaccess, dwflags, dwshare;
362 /* Convert to Windows path format */
363 win32_fname = get_pool_memory(PM_FNAME);
364 win32_fname_wchar = get_pool_memory(PM_FNAME);
366 unix_name_to_win32(&win32_fname, (char *)fname);
368 if (!(p_CreateFileA || p_CreateFileW))
371 if (p_CreateFileW && p_MultiByteToWideChar)
372 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
374 if (flags & O_CREAT) { /* Create */
375 if (bfd->use_backup_api) {
376 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
377 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
379 dwaccess = GENERIC_WRITE;
383 // unicode or ansii open for create write
384 if (p_CreateFileW && p_MultiByteToWideChar) {
385 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
386 dwaccess, /* Requested access */
388 NULL, /* SecurityAttributes */
389 CREATE_ALWAYS, /* CreationDisposition */
390 dwflags, /* Flags and attributes */
391 NULL); /* TemplateFile */
394 bfd->fh = p_CreateFileA(win32_fname,
395 dwaccess, /* Requested access */
397 NULL, /* SecurityAttributes */
398 CREATE_ALWAYS, /* CreationDisposition */
399 dwflags, /* Flags and attributes */
400 NULL); /* TemplateFile */
404 bfd->mode = BF_WRITE;
406 } else if (flags & O_WRONLY) { /* Open existing for write */
407 if (bfd->use_backup_api) {
408 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
409 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
411 dwaccess = GENERIC_WRITE;
415 // unicode or ansii open for open existing write
416 if (p_CreateFileW && p_MultiByteToWideChar) {
417 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
418 dwaccess, /* Requested access */
420 NULL, /* SecurityAttributes */
421 OPEN_EXISTING, /* CreationDisposition */
422 dwflags, /* Flags and attributes */
423 NULL); /* TemplateFile */
426 bfd->fh = p_CreateFileA(win32_fname,
427 dwaccess, /* Requested access */
429 NULL, /* SecurityAttributes */
430 OPEN_EXISTING, /* CreationDisposition */
431 dwflags, /* Flags and attributes */
432 NULL); /* TemplateFile */
436 bfd->mode = BF_WRITE;
439 if (bfd->use_backup_api) {
440 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
441 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
442 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
444 dwaccess = GENERIC_READ;
446 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
449 // unicode or ansii open for open existing read
450 if (p_CreateFileW && p_MultiByteToWideChar) {
451 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
452 dwaccess, /* Requested access */
453 dwshare, /* Share modes */
454 NULL, /* SecurityAttributes */
455 OPEN_EXISTING, /* CreationDisposition */
456 dwflags, /* Flags and attributes */
457 NULL); /* TemplateFile */
460 bfd->fh = p_CreateFileA(win32_fname,
461 dwaccess, /* Requested access */
462 dwshare, /* Share modes */
463 NULL, /* SecurityAttributes */
464 OPEN_EXISTING, /* CreationDisposition */
465 dwflags, /* Flags and attributes */
466 NULL); /* TemplateFile */
472 if (bfd->fh == INVALID_HANDLE_VALUE) {
473 bfd->lerror = GetLastError();
474 bfd->berrno = b_errno_win32;
475 errno = b_errno_win32;
476 bfd->mode = BF_CLOSED;
479 bfd->lpContext = NULL;
480 bfd->win32DecompContext.bIsInData = false;
481 bfd->win32DecompContext.liNextHeader = 0;
482 free_pool_memory(win32_fname_wchar);
483 free_pool_memory(win32_fname);
484 return bfd->mode == BF_CLOSED ? -1 : 1;
488 * Returns 0 on success
491 int bclose(BFILE *bfd)
496 free_pool_memory(bfd->errmsg);
499 if (bfd->mode == BF_CLOSED) {
502 if (bfd->use_backup_api && bfd->mode == BF_READ) {
504 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
506 (DWORD)0, /* bytes to read */
507 &bfd->rw_bytes, /* bytes read */
509 1, /* ProcessSecurity */
510 &bfd->lpContext)) { /* Read context */
511 errno = b_errno_win32;
514 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
516 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
518 (DWORD)0, /* bytes to read */
519 &bfd->rw_bytes, /* bytes written */
521 1, /* ProcessSecurity */
522 &bfd->lpContext)) { /* Write context */
523 errno = b_errno_win32;
527 if (!CloseHandle(bfd->fh)) {
529 errno = b_errno_win32;
531 bfd->mode = BF_CLOSED;
532 bfd->lpContext = NULL;
536 /* Returns: bytes read on success
540 ssize_t bread(BFILE *bfd, void *buf, size_t count)
544 if (bfd->use_backup_api) {
545 if (!p_BackupRead(bfd->fh,
550 1, /* Process Security */
551 &bfd->lpContext)) { /* Context */
552 bfd->lerror = GetLastError();
553 bfd->berrno = b_errno_win32;
554 errno = b_errno_win32;
558 if (!ReadFile(bfd->fh,
563 bfd->lerror = GetLastError();
564 bfd->berrno = b_errno_win32;
565 errno = b_errno_win32;
570 return (ssize_t)bfd->rw_bytes;
573 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
577 if (bfd->use_backup_api) {
578 if (!p_BackupWrite(bfd->fh,
583 1, /* Process Security */
584 &bfd->lpContext)) { /* Context */
585 bfd->lerror = GetLastError();
586 bfd->berrno = b_errno_win32;
587 errno = b_errno_win32;
591 if (!WriteFile(bfd->fh,
596 bfd->lerror = GetLastError();
597 bfd->berrno = b_errno_win32;
598 errno = b_errno_win32;
602 return (ssize_t)bfd->rw_bytes;
605 bool is_bopen(BFILE *bfd)
607 return bfd->mode != BF_CLOSED;
610 off_t blseek(BFILE *bfd, off_t offset, int whence)
612 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
616 #else /* Unix systems */
618 /* ===============================================================
622 * ===============================================================
624 void binit(BFILE *bfd)
626 memset(bfd, 0, sizeof(BFILE));
630 bool have_win32_api()
632 return false; /* no can do */
636 * Enables using the Backup API (win32_data).
637 * Returns true if function worked
638 * Returns false if failed (i.e. do not have Backup API on this machine)
640 bool set_win32_backup(BFILE *bfd)
642 return false; /* no can do */
646 bool set_portable_backup(BFILE *bfd)
648 return true; /* no problem */
652 * Return true if we are writing in portable format
653 * return false if not
655 bool is_portable_backup(BFILE *bfd)
657 return true; /* portable by definition */
660 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
663 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
664 return true; /* already setup */
667 if (python_set_prog(jcr, prog)) {
668 Dmsg1(000, "Set prog=%s\n", prog);
674 Dmsg0(000, "No prog set\n");
681 * This code is running on a non-Win32 machine
683 bool is_restore_stream_supported(int stream)
685 /* No Win32 backup on this machine */
688 case STREAM_GZIP_DATA:
689 case STREAM_SPARSE_GZIP_DATA:
690 case STREAM_WIN32_GZIP_DATA:
692 #ifndef HAVE_DARWIN_OS
693 case STREAM_MACOS_FORK_DATA:
694 case STREAM_HFSPLUS_ATTRIBUTES:
700 case STREAM_GZIP_DATA:
701 case STREAM_SPARSE_GZIP_DATA:
702 case STREAM_WIN32_GZIP_DATA:
704 case STREAM_WIN32_DATA:
705 case STREAM_UNIX_ATTRIBUTES:
706 case STREAM_FILE_DATA:
707 case STREAM_MD5_DIGEST:
708 case STREAM_UNIX_ATTRIBUTES_EX:
709 case STREAM_SPARSE_DATA:
710 case STREAM_PROGRAM_NAMES:
711 case STREAM_PROGRAM_DATA:
712 case STREAM_SHA1_DIGEST:
714 case STREAM_SHA256_DIGEST:
715 case STREAM_SHA512_DIGEST:
717 #ifdef HAVE_DARWIN_OS
718 case STREAM_MACOS_FORK_DATA:
719 case STREAM_HFSPLUS_ATTRIBUTES:
721 case 0: /* compatibility with old tapes */
728 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
730 /* Open reader/writer program */
732 Dmsg1(000, "Open file %d\n", bfd->fid);
733 return python_open(bfd, fname, flags, mode);
736 /* Normal file open */
737 bfd->fid = open(fname, flags, mode);
739 Dmsg1(400, "Open file %d\n", bfd->fid);
742 bfd->win32DecompContext.bIsInData = false;
743 bfd->win32DecompContext.liNextHeader = 0;
748 #ifdef HAVE_DARWIN_OS
749 /* Open the resource fork of a file. */
750 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
754 rsrc_fname = get_pool_memory(PM_FNAME);
755 pm_strcpy(rsrc_fname, fname);
756 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
757 bopen(bfd, rsrc_fname, flags, mode);
758 free_pool_memory(rsrc_fname);
764 int bclose(BFILE *bfd)
768 Dmsg1(400, "Close file %d\n", bfd->fid);
770 /* Close reader/writer program */
772 return python_close(bfd);
775 if (bfd->fid == -1) {
779 /* Close normal file */
780 stat = close(bfd->fid);
786 ssize_t bread(BFILE *bfd, void *buf, size_t count)
791 return python_read(bfd, buf, count);
793 stat = read(bfd->fid, buf, count);
798 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
803 return python_write(bfd, buf, count);
805 stat = write(bfd->fid, buf, count);
810 bool is_bopen(BFILE *bfd)
812 return bfd->fid >= 0;
815 off_t blseek(BFILE *bfd, off_t offset, int whence)
818 pos = lseek(bfd->fid, offset, whence);