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 = -pContext->liNextHeader;
178 /* start of header is inside of this block */
180 dwOffsetSource = pContext->liNextHeader;
183 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
184 bool bHeaderIsComplete;
186 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
187 /* header (or rest of header) is completely available
190 bHeaderIsComplete = true;
192 /* header will continue in next block */
193 bHeaderIsComplete = false;
194 dwHeaderPartLen = dwSize-dwOffsetSource;
197 /* copy the available portion of header to persistent copy */
198 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
200 /* recalculate position of next header */
201 if (bHeaderIsComplete) {
202 /* convert stream name size (32 bit little endian) to machine type */
204 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
205 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
207 /* convert stream size (64 bit little endian) to machine type */
208 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
209 pContext->liNextHeader += dwDataOffset;
211 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
212 if (dwDataOffset == dwSize)
216 /* stop and continue with next block */
218 pContext->bIsInData = false;
223 /* set "NextHeader" relative to the beginning of the next block */
224 pContext->liNextHeader-= dwSize;
231 /* ===============================================================
235 * ===============================================================
238 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
240 void unix_name_to_win32(POOLMEM **win32_name, char *name);
241 extern "C" HANDLE get_osfhandle(int fd);
245 void binit(BFILE *bfd)
247 memset(bfd, 0, sizeof(BFILE));
249 bfd->mode = BF_CLOSED;
250 bfd->use_backup_api = have_win32_api();
254 * Enables using the Backup API (win32_data).
255 * Returns 1 if function worked
256 * Returns 0 if failed (i.e. do not have Backup API on this machine)
258 bool set_win32_backup(BFILE *bfd)
260 /* We enable if possible here */
261 bfd->use_backup_api = have_win32_api();
262 return bfd->use_backup_api;
266 bool set_portable_backup(BFILE *bfd)
268 bfd->use_backup_api = false;
272 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
280 * Return 1 if we are NOT using Win32 BackupWrite()
283 bool is_portable_backup(BFILE *bfd)
285 return !bfd->use_backup_api;
288 bool have_win32_api()
290 return p_BackupRead && p_BackupWrite;
296 * Return true if we support the stream
297 * false if we do not support the stream
299 * This code is running under Win32, so we
300 * do not need #ifdef on MACOS ...
302 bool is_restore_stream_supported(int stream)
306 /* Streams known not to be supported */
308 case STREAM_GZIP_DATA:
309 case STREAM_SPARSE_GZIP_DATA:
310 case STREAM_WIN32_GZIP_DATA:
312 case STREAM_MACOS_FORK_DATA:
313 case STREAM_HFSPLUS_ATTRIBUTES:
318 case STREAM_GZIP_DATA:
319 case STREAM_SPARSE_GZIP_DATA:
320 case STREAM_WIN32_GZIP_DATA:
322 case STREAM_WIN32_DATA:
323 case STREAM_UNIX_ATTRIBUTES:
324 case STREAM_FILE_DATA:
325 case STREAM_MD5_SIGNATURE:
326 case STREAM_UNIX_ATTRIBUTES_EX:
327 case STREAM_SPARSE_DATA:
328 case STREAM_PROGRAM_NAMES:
329 case STREAM_PROGRAM_DATA:
330 case STREAM_SHA1_SIGNATURE:
331 case 0: /* compatibility with old tapes */
337 HANDLE bget_handle(BFILE *bfd)
342 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
344 POOLMEM *win32_fname;
345 POOLMEM *win32_fname_wchar;
347 DWORD dwaccess, dwflags, dwshare;
349 /* Convert to Windows path format */
350 win32_fname = get_pool_memory(PM_FNAME);
351 win32_fname_wchar = get_pool_memory(PM_FNAME);
353 unix_name_to_win32(&win32_fname, (char *)fname);
355 if (!(p_CreateFileA || p_CreateFileW))
358 if (p_CreateFileW && p_MultiByteToWideChar)
359 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
361 if (flags & O_CREAT) { /* Create */
362 if (bfd->use_backup_api) {
363 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
364 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
366 dwaccess = GENERIC_WRITE;
370 // unicode or ansii open for create write
371 if (p_CreateFileW && p_MultiByteToWideChar) {
372 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
373 dwaccess, /* Requested access */
375 NULL, /* SecurityAttributes */
376 CREATE_ALWAYS, /* CreationDisposition */
377 dwflags, /* Flags and attributes */
378 NULL); /* TemplateFile */
381 bfd->fh = p_CreateFileA(win32_fname,
382 dwaccess, /* Requested access */
384 NULL, /* SecurityAttributes */
385 CREATE_ALWAYS, /* CreationDisposition */
386 dwflags, /* Flags and attributes */
387 NULL); /* TemplateFile */
391 bfd->mode = BF_WRITE;
393 } else if (flags & O_WRONLY) { /* Open existing for write */
394 if (bfd->use_backup_api) {
395 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
396 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
398 dwaccess = GENERIC_WRITE;
402 // unicode or ansii open for open existing write
403 if (p_CreateFileW && p_MultiByteToWideChar) {
404 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
405 dwaccess, /* Requested access */
407 NULL, /* SecurityAttributes */
408 OPEN_EXISTING, /* CreationDisposition */
409 dwflags, /* Flags and attributes */
410 NULL); /* TemplateFile */
413 bfd->fh = p_CreateFileA(win32_fname,
414 dwaccess, /* Requested access */
416 NULL, /* SecurityAttributes */
417 OPEN_EXISTING, /* CreationDisposition */
418 dwflags, /* Flags and attributes */
419 NULL); /* TemplateFile */
423 bfd->mode = BF_WRITE;
426 if (bfd->use_backup_api) {
427 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
428 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
429 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
431 dwaccess = GENERIC_READ;
433 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
436 // unicode or ansii open for open existing read
437 if (p_CreateFileW && p_MultiByteToWideChar) {
438 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
439 dwaccess, /* Requested access */
440 dwshare, /* Share modes */
441 NULL, /* SecurityAttributes */
442 OPEN_EXISTING, /* CreationDisposition */
443 dwflags, /* Flags and attributes */
444 NULL); /* TemplateFile */
447 bfd->fh = p_CreateFileA(win32_fname,
448 dwaccess, /* Requested access */
449 dwshare, /* Share modes */
450 NULL, /* SecurityAttributes */
451 OPEN_EXISTING, /* CreationDisposition */
452 dwflags, /* Flags and attributes */
453 NULL); /* TemplateFile */
459 if (bfd->fh == INVALID_HANDLE_VALUE) {
460 bfd->lerror = GetLastError();
461 bfd->berrno = b_errno_win32;
462 errno = b_errno_win32;
463 bfd->mode = BF_CLOSED;
466 bfd->lpContext = NULL;
467 bfd->win32DecompContext.bIsInData = false;
468 bfd->win32DecompContext.liNextHeader = 0;
469 free_pool_memory(win32_fname_wchar);
470 free_pool_memory(win32_fname);
471 return bfd->mode == BF_CLOSED ? -1 : 1;
475 * Returns 0 on success
478 int bclose(BFILE *bfd)
483 free_pool_memory(bfd->errmsg);
486 if (bfd->mode == BF_CLOSED) {
489 if (bfd->use_backup_api && bfd->mode == BF_READ) {
491 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
493 (DWORD)0, /* bytes to read */
494 &bfd->rw_bytes, /* bytes read */
496 1, /* ProcessSecurity */
497 &bfd->lpContext)) { /* Read context */
498 errno = b_errno_win32;
501 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
503 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
505 (DWORD)0, /* bytes to read */
506 &bfd->rw_bytes, /* bytes written */
508 1, /* ProcessSecurity */
509 &bfd->lpContext)) { /* Write context */
510 errno = b_errno_win32;
514 if (!CloseHandle(bfd->fh)) {
516 errno = b_errno_win32;
518 bfd->mode = BF_CLOSED;
519 bfd->lpContext = NULL;
523 /* Returns: bytes read on success
527 ssize_t bread(BFILE *bfd, void *buf, size_t count)
531 if (bfd->use_backup_api) {
532 if (!p_BackupRead(bfd->fh,
537 1, /* Process Security */
538 &bfd->lpContext)) { /* Context */
539 bfd->lerror = GetLastError();
540 bfd->berrno = b_errno_win32;
541 errno = b_errno_win32;
545 if (!ReadFile(bfd->fh,
550 bfd->lerror = GetLastError();
551 bfd->berrno = b_errno_win32;
552 errno = b_errno_win32;
557 return (ssize_t)bfd->rw_bytes;
560 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
564 if (bfd->use_backup_api) {
565 if (!p_BackupWrite(bfd->fh,
570 1, /* Process Security */
571 &bfd->lpContext)) { /* Context */
572 bfd->lerror = GetLastError();
573 bfd->berrno = b_errno_win32;
574 errno = b_errno_win32;
578 if (!WriteFile(bfd->fh,
583 bfd->lerror = GetLastError();
584 bfd->berrno = b_errno_win32;
585 errno = b_errno_win32;
589 return (ssize_t)bfd->rw_bytes;
592 bool is_bopen(BFILE *bfd)
594 return bfd->mode != BF_CLOSED;
597 off_t blseek(BFILE *bfd, off_t offset, int whence)
599 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
603 #else /* Unix systems */
605 /* ===============================================================
609 * ===============================================================
611 void binit(BFILE *bfd)
613 memset(bfd, 0, sizeof(BFILE));
617 bool have_win32_api()
619 return false; /* no can do */
623 * Enables using the Backup API (win32_data).
624 * Returns true if function worked
625 * Returns false if failed (i.e. do not have Backup API on this machine)
627 bool set_win32_backup(BFILE *bfd)
629 return false; /* no can do */
633 bool set_portable_backup(BFILE *bfd)
635 return true; /* no problem */
639 * Return true if we are writing in portable format
640 * return false if not
642 bool is_portable_backup(BFILE *bfd)
644 return true; /* portable by definition */
647 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
650 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
651 return true; /* already setup */
654 if (python_set_prog(jcr, prog)) {
655 Dmsg1(000, "Set prog=%s\n", prog);
661 Dmsg0(000, "No prog set\n");
668 * This code is running on a non-Win32 machine
670 bool is_restore_stream_supported(int stream)
672 /* No Win32 backup on this machine */
675 case STREAM_GZIP_DATA:
676 case STREAM_SPARSE_GZIP_DATA:
677 case STREAM_WIN32_GZIP_DATA:
679 #ifndef HAVE_DARWIN_OS
680 case STREAM_MACOS_FORK_DATA:
681 case STREAM_HFSPLUS_ATTRIBUTES:
687 case STREAM_GZIP_DATA:
688 case STREAM_SPARSE_GZIP_DATA:
689 case STREAM_WIN32_GZIP_DATA:
691 case STREAM_WIN32_DATA:
692 case STREAM_UNIX_ATTRIBUTES:
693 case STREAM_FILE_DATA:
694 case STREAM_MD5_SIGNATURE:
695 case STREAM_UNIX_ATTRIBUTES_EX:
696 case STREAM_SPARSE_DATA:
697 case STREAM_PROGRAM_NAMES:
698 case STREAM_PROGRAM_DATA:
699 case STREAM_SHA1_SIGNATURE:
700 #ifdef HAVE_DARWIN_OS
701 case STREAM_MACOS_FORK_DATA:
702 case STREAM_HFSPLUS_ATTRIBUTES:
704 case 0: /* compatibility with old tapes */
711 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
713 /* Open reader/writer program */
715 Dmsg1(000, "Open file %d\n", bfd->fid);
716 return python_open(bfd, fname, flags, mode);
719 /* Normal file open */
720 bfd->fid = open(fname, flags, mode);
722 Dmsg1(400, "Open file %d\n", bfd->fid);
725 bfd->win32DecompContext.bIsInData = false;
726 bfd->win32DecompContext.liNextHeader = 0;
731 #ifdef HAVE_DARWIN_OS
732 /* Open the resource fork of a file. */
733 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
737 rsrc_fname = get_pool_memory(PM_FNAME);
738 pm_strcpy(rsrc_fname, fname);
739 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
740 bopen(bfd, rsrc_fname, flags, mode);
741 free_pool_memory(rsrc_fname);
747 int bclose(BFILE *bfd)
751 Dmsg1(400, "Close file %d\n", bfd->fid);
753 /* Close reader/writer program */
755 return python_close(bfd);
758 if (bfd->fid == -1) {
762 /* Close normal file */
763 stat = close(bfd->fid);
769 ssize_t bread(BFILE *bfd, void *buf, size_t count)
774 return python_read(bfd, buf, count);
776 stat = read(bfd->fid, buf, count);
781 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
786 return python_write(bfd, buf, count);
788 stat = write(bfd->fid, buf, count);
793 bool is_bopen(BFILE *bfd)
795 return bfd->fid >= 0;
798 off_t blseek(BFILE *bfd, off_t offset, int whence)
801 pos = lseek(bfd->fid, offset, whence);