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_SIGNATURE:
74 return _("MD5 signature");
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_SIGNATURE:
84 return _("SHA1 signature");
85 case STREAM_MACOS_FORK_DATA:
86 return _("HFS+ resource fork");
87 case STREAM_HFSPLUS_ATTRIBUTES:
88 return _("HFS+ Finder Info");
90 sprintf(buf, "%d", stream);
91 return (const char *)buf;
96 void int64_LE2BE(int64_t* pBE, const int64_t v)
98 /* convert little endian to big endian */
99 if (htonl(1) != 1L) { /* no work if on little endian machine */
100 memcpy(pBE, &v, sizeof(int64_t));
103 uint8_t rv[sizeof(int64_t)];
104 uint8_t *pv = (uint8_t *) &v;
106 for (i = 0; i < 8; i++) {
109 memcpy(pBE, &rv, sizeof(int64_t));
114 void int32_LE2BE(int32_t* pBE, const int32_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(int32_t));
121 uint8_t rv[sizeof(int32_t)];
122 uint8_t *pv = (uint8_t *) &v;
124 for (i = 0; i < 4; i++) {
127 memcpy(pBE, &rv, sizeof(int32_t));
132 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
134 /* pByte contains the buffer
135 dwSize the len to be processed. function assumes to be
136 called in successive incremental order over the complete
137 BackupRead stream beginning at pos 0 and ending at the end.
140 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
141 bool bContinue = false;
142 int64_t dwDataOffset = 0;
145 /* Win32 Stream Header size without name of stream.
146 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
148 int32_t dwSizeHeader = 20;
151 if (pContext->liNextHeader >= dwSize) {
152 dwDataLen = dwSize-dwDataOffset;
153 bContinue = false; /* 1 iteration is enough */
156 dwDataLen = pContext->liNextHeader-dwDataOffset;
157 bContinue = TRUE; /* multiple iterations may be necessary */
161 /* copy block of real DATA */
162 if (pContext->bIsInData) {
163 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
167 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
168 int32_t dwOffsetTarget;
169 int32_t dwOffsetSource;
171 if (pContext->liNextHeader < 0) {
172 /* start of header was before this block, so we
173 * continue with the part in the current block
175 dwOffsetTarget = abs (pContext->liNextHeader);
179 /* start of header is inside of this block */
181 dwOffsetSource = pContext->liNextHeader;
184 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
185 bool bHeaderIsComplete;
187 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
188 /* header (or rest of header) is completely available
191 bHeaderIsComplete = true;
193 /* header will continue in next block */
194 bHeaderIsComplete = false;
195 dwHeaderPartLen = dwSize-dwOffsetSource;
198 /* copy the available portion of header to persistent copy */
199 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
201 /* recalculate position of next header */
202 if (bHeaderIsComplete) {
203 /* convert stream name size (32 bit little endian) to machine type */
205 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
206 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
208 /* convert stream size (64 bit little endian) to machine type */
209 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
210 pContext->liNextHeader += dwDataOffset;
212 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
213 if (dwDataOffset == dwSize)
217 /* stop and continue with next block */
219 pContext->bIsInData = false;
224 /* set "NextHeader" relative to the beginning of the next block */
225 pContext->liNextHeader-= dwSize;
232 /* ===============================================================
236 * ===============================================================
239 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
241 void unix_name_to_win32(POOLMEM **win32_name, char *name);
242 extern "C" HANDLE get_osfhandle(int fd);
246 void binit(BFILE *bfd)
248 memset(bfd, 0, sizeof(BFILE));
250 bfd->mode = BF_CLOSED;
251 bfd->use_backup_api = have_win32_api();
255 * Enables using the Backup API (win32_data).
256 * Returns 1 if function worked
257 * Returns 0 if failed (i.e. do not have Backup API on this machine)
259 bool set_win32_backup(BFILE *bfd)
261 /* We enable if possible here */
262 bfd->use_backup_api = have_win32_api();
263 return bfd->use_backup_api;
267 bool set_portable_backup(BFILE *bfd)
269 bfd->use_backup_api = false;
273 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
281 * Return 1 if we are NOT using Win32 BackupWrite()
284 bool is_portable_backup(BFILE *bfd)
286 return !bfd->use_backup_api;
289 bool have_win32_api()
291 return p_BackupRead && p_BackupWrite;
297 * Return true if we support the stream
298 * false if we do not support the stream
300 * This code is running under Win32, so we
301 * do not need #ifdef on MACOS ...
303 bool is_restore_stream_supported(int stream)
307 /* Streams known not to be supported */
309 case STREAM_GZIP_DATA:
310 case STREAM_SPARSE_GZIP_DATA:
311 case STREAM_WIN32_GZIP_DATA:
313 case STREAM_MACOS_FORK_DATA:
314 case STREAM_HFSPLUS_ATTRIBUTES:
319 case STREAM_GZIP_DATA:
320 case STREAM_SPARSE_GZIP_DATA:
321 case STREAM_WIN32_GZIP_DATA:
323 case STREAM_WIN32_DATA:
324 case STREAM_UNIX_ATTRIBUTES:
325 case STREAM_FILE_DATA:
326 case STREAM_MD5_SIGNATURE:
327 case STREAM_UNIX_ATTRIBUTES_EX:
328 case STREAM_SPARSE_DATA:
329 case STREAM_PROGRAM_NAMES:
330 case STREAM_PROGRAM_DATA:
331 case STREAM_SHA1_SIGNATURE:
332 case 0: /* compatibility with old tapes */
338 HANDLE bget_handle(BFILE *bfd)
343 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
345 POOLMEM *win32_fname;
346 POOLMEM *win32_fname_wchar;
348 DWORD dwaccess, dwflags, dwshare;
350 /* Convert to Windows path format */
351 win32_fname = get_pool_memory(PM_FNAME);
352 win32_fname_wchar = get_pool_memory(PM_FNAME);
354 unix_name_to_win32(&win32_fname, (char *)fname);
356 if (!(p_CreateFileA || p_CreateFileW))
359 if (p_CreateFileW && p_MultiByteToWideChar)
360 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
362 if (flags & O_CREAT) { /* Create */
363 if (bfd->use_backup_api) {
364 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
365 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
367 dwaccess = GENERIC_WRITE;
371 // unicode or ansii open for create write
372 if (p_CreateFileW && p_MultiByteToWideChar) {
373 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
374 dwaccess, /* Requested access */
376 NULL, /* SecurityAttributes */
377 CREATE_ALWAYS, /* CreationDisposition */
378 dwflags, /* Flags and attributes */
379 NULL); /* TemplateFile */
382 bfd->fh = p_CreateFileA(win32_fname,
383 dwaccess, /* Requested access */
385 NULL, /* SecurityAttributes */
386 CREATE_ALWAYS, /* CreationDisposition */
387 dwflags, /* Flags and attributes */
388 NULL); /* TemplateFile */
392 bfd->mode = BF_WRITE;
394 } else if (flags & O_WRONLY) { /* Open existing for write */
395 if (bfd->use_backup_api) {
396 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
397 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
399 dwaccess = GENERIC_WRITE;
403 // unicode or ansii open for open existing write
404 if (p_CreateFileW && p_MultiByteToWideChar) {
405 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
406 dwaccess, /* Requested access */
408 NULL, /* SecurityAttributes */
409 OPEN_EXISTING, /* CreationDisposition */
410 dwflags, /* Flags and attributes */
411 NULL); /* TemplateFile */
414 bfd->fh = p_CreateFileA(win32_fname,
415 dwaccess, /* Requested access */
417 NULL, /* SecurityAttributes */
418 OPEN_EXISTING, /* CreationDisposition */
419 dwflags, /* Flags and attributes */
420 NULL); /* TemplateFile */
424 bfd->mode = BF_WRITE;
427 if (bfd->use_backup_api) {
428 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
429 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
430 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
432 dwaccess = GENERIC_READ;
434 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
437 // unicode or ansii open for open existing read
438 if (p_CreateFileW && p_MultiByteToWideChar) {
439 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
440 dwaccess, /* Requested access */
441 dwshare, /* Share modes */
442 NULL, /* SecurityAttributes */
443 OPEN_EXISTING, /* CreationDisposition */
444 dwflags, /* Flags and attributes */
445 NULL); /* TemplateFile */
448 bfd->fh = p_CreateFileA(win32_fname,
449 dwaccess, /* Requested access */
450 dwshare, /* Share modes */
451 NULL, /* SecurityAttributes */
452 OPEN_EXISTING, /* CreationDisposition */
453 dwflags, /* Flags and attributes */
454 NULL); /* TemplateFile */
460 if (bfd->fh == INVALID_HANDLE_VALUE) {
461 bfd->lerror = GetLastError();
462 bfd->berrno = b_errno_win32;
463 errno = b_errno_win32;
464 bfd->mode = BF_CLOSED;
467 bfd->lpContext = NULL;
468 bfd->win32DecompContext.bIsInData = false;
469 bfd->win32DecompContext.liNextHeader = 0;
470 free_pool_memory(win32_fname_wchar);
471 free_pool_memory(win32_fname);
472 return bfd->mode == BF_CLOSED ? -1 : 1;
476 * Returns 0 on success
479 int bclose(BFILE *bfd)
484 free_pool_memory(bfd->errmsg);
487 if (bfd->mode == BF_CLOSED) {
490 if (bfd->use_backup_api && bfd->mode == BF_READ) {
492 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
494 (DWORD)0, /* bytes to read */
495 &bfd->rw_bytes, /* bytes read */
497 1, /* ProcessSecurity */
498 &bfd->lpContext)) { /* Read context */
499 errno = b_errno_win32;
502 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
504 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
506 (DWORD)0, /* bytes to read */
507 &bfd->rw_bytes, /* bytes written */
509 1, /* ProcessSecurity */
510 &bfd->lpContext)) { /* Write context */
511 errno = b_errno_win32;
515 if (!CloseHandle(bfd->fh)) {
517 errno = b_errno_win32;
519 bfd->mode = BF_CLOSED;
520 bfd->lpContext = NULL;
524 /* Returns: bytes read on success
528 ssize_t bread(BFILE *bfd, void *buf, size_t count)
532 if (bfd->use_backup_api) {
533 if (!p_BackupRead(bfd->fh,
538 1, /* Process Security */
539 &bfd->lpContext)) { /* Context */
540 bfd->lerror = GetLastError();
541 bfd->berrno = b_errno_win32;
542 errno = b_errno_win32;
546 if (!ReadFile(bfd->fh,
551 bfd->lerror = GetLastError();
552 bfd->berrno = b_errno_win32;
553 errno = b_errno_win32;
558 return (ssize_t)bfd->rw_bytes;
561 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
565 if (bfd->use_backup_api) {
566 if (!p_BackupWrite(bfd->fh,
571 1, /* Process Security */
572 &bfd->lpContext)) { /* Context */
573 bfd->lerror = GetLastError();
574 bfd->berrno = b_errno_win32;
575 errno = b_errno_win32;
579 if (!WriteFile(bfd->fh,
584 bfd->lerror = GetLastError();
585 bfd->berrno = b_errno_win32;
586 errno = b_errno_win32;
590 return (ssize_t)bfd->rw_bytes;
593 bool is_bopen(BFILE *bfd)
595 return bfd->mode != BF_CLOSED;
598 off_t blseek(BFILE *bfd, off_t offset, int whence)
600 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
604 #else /* Unix systems */
606 /* ===============================================================
610 * ===============================================================
612 void binit(BFILE *bfd)
614 memset(bfd, 0, sizeof(BFILE));
618 bool have_win32_api()
620 return false; /* no can do */
624 * Enables using the Backup API (win32_data).
625 * Returns true if function worked
626 * Returns false if failed (i.e. do not have Backup API on this machine)
628 bool set_win32_backup(BFILE *bfd)
630 return false; /* no can do */
634 bool set_portable_backup(BFILE *bfd)
636 return true; /* no problem */
640 * Return true if we are writing in portable format
641 * return false if not
643 bool is_portable_backup(BFILE *bfd)
645 return true; /* portable by definition */
648 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
651 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
652 return true; /* already setup */
655 if (python_set_prog(jcr, prog)) {
656 Dmsg1(000, "Set prog=%s\n", prog);
662 Dmsg0(000, "No prog set\n");
669 * This code is running on a non-Win32 machine
671 bool is_restore_stream_supported(int stream)
673 /* No Win32 backup on this machine */
676 case STREAM_GZIP_DATA:
677 case STREAM_SPARSE_GZIP_DATA:
678 case STREAM_WIN32_GZIP_DATA:
680 #ifndef HAVE_DARWIN_OS
681 case STREAM_MACOS_FORK_DATA:
682 case STREAM_HFSPLUS_ATTRIBUTES:
688 case STREAM_GZIP_DATA:
689 case STREAM_SPARSE_GZIP_DATA:
690 case STREAM_WIN32_GZIP_DATA:
692 case STREAM_WIN32_DATA:
693 case STREAM_UNIX_ATTRIBUTES:
694 case STREAM_FILE_DATA:
695 case STREAM_MD5_SIGNATURE:
696 case STREAM_UNIX_ATTRIBUTES_EX:
697 case STREAM_SPARSE_DATA:
698 case STREAM_PROGRAM_NAMES:
699 case STREAM_PROGRAM_DATA:
700 case STREAM_SHA1_SIGNATURE:
701 #ifdef HAVE_DARWIN_OS
702 case STREAM_MACOS_FORK_DATA:
703 case STREAM_HFSPLUS_ATTRIBUTES:
705 case 0: /* compatibility with old tapes */
712 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
714 /* Open reader/writer program */
716 Dmsg1(000, "Open file %d\n", bfd->fid);
717 return python_open(bfd, fname, flags, mode);
720 /* Normal file open */
721 bfd->fid = open(fname, flags, mode);
723 Dmsg1(400, "Open file %d\n", bfd->fid);
726 bfd->win32DecompContext.bIsInData = false;
727 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);