2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula low level File I/O routines. This routine simulates
30 * open(), read(), write(), and close(), but using native routines.
31 * I.e. on Windows, we use Windows APIs.
33 * Kern Sibbald, April MMIII
42 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
43 int (*plugin_bclose)(JCR *jcr) = NULL;
44 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
45 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
46 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
50 #include <sys/paths.h>
53 #if !defined(HAVE_FDATASYNC)
58 /* ===============================================================
60 * U N I X AND W I N D O W S
62 * ===============================================================
65 bool is_win32_stream(int stream)
68 case STREAM_WIN32_DATA:
69 case STREAM_WIN32_GZIP_DATA:
70 case STREAM_ENCRYPTED_WIN32_DATA:
71 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
77 const char *stream_to_ascii(int stream)
82 case STREAM_UNIX_ATTRIBUTES:
83 return _("Unix attributes");
84 case STREAM_FILE_DATA:
85 return _("File data");
86 case STREAM_MD5_DIGEST:
87 return _("MD5 digest");
88 case STREAM_GZIP_DATA:
89 return _("GZIP data");
90 case STREAM_UNIX_ATTRIBUTES_EX:
91 return _("Extended attributes");
92 case STREAM_SPARSE_DATA:
93 return _("Sparse data");
94 case STREAM_SPARSE_GZIP_DATA:
95 return _("GZIP sparse data");
96 case STREAM_PROGRAM_NAMES:
97 return _("Program names");
98 case STREAM_PROGRAM_DATA:
99 return _("Program data");
100 case STREAM_SHA1_DIGEST:
101 return _("SHA1 digest");
102 case STREAM_WIN32_DATA:
103 return _("Win32 data");
104 case STREAM_WIN32_GZIP_DATA:
105 return _("Win32 GZIP data");
106 case STREAM_MACOS_FORK_DATA:
107 return _("MacOS Fork data");
108 case STREAM_HFSPLUS_ATTRIBUTES:
109 return _("HFS+ attribs");
110 case STREAM_UNIX_ACCESS_ACL:
111 return _("Standard Unix ACL attribs");
112 case STREAM_UNIX_DEFAULT_ACL:
113 return _("Default Unix ACL attribs");
114 case STREAM_SHA256_DIGEST:
115 return _("SHA256 digest");
116 case STREAM_SHA512_DIGEST:
117 return _("SHA512 digest");
118 case STREAM_SIGNED_DIGEST:
119 return _("Signed digest");
120 case STREAM_ENCRYPTED_FILE_DATA:
121 return _("Encrypted File data");
122 case STREAM_ENCRYPTED_WIN32_DATA:
123 return _("Encrypted Win32 data");
124 case STREAM_ENCRYPTED_SESSION_DATA:
125 return _("Encrypted session data");
126 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
127 return _("Encrypted GZIP data");
128 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
129 return _("Encrypted Win32 GZIP data");
130 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
131 return _("Encrypted MacOS fork data");
133 sprintf(buf, "%d", stream);
134 return (const char *)buf;
139 void int64_LE2BE(int64_t* pBE, const int64_t v)
141 /* convert little endian to big endian */
142 if (htonl(1) != 1L) { /* no work if on little endian machine */
143 memcpy(pBE, &v, sizeof(int64_t));
146 uint8_t rv[sizeof(int64_t)];
147 uint8_t *pv = (uint8_t *) &v;
149 for (i = 0; i < 8; i++) {
152 memcpy(pBE, &rv, sizeof(int64_t));
157 void int32_LE2BE(int32_t* pBE, const int32_t v)
159 /* convert little endian to big endian */
160 if (htonl(1) != 1L) { /* no work if on little endian machine */
161 memcpy(pBE, &v, sizeof(int32_t));
164 uint8_t rv[sizeof(int32_t)];
165 uint8_t *pv = (uint8_t *) &v;
167 for (i = 0; i < 4; i++) {
170 memcpy(pBE, &rv, sizeof(int32_t));
175 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
177 /* pByte contains the buffer
178 dwSize the len to be processed. function assumes to be
179 called in successive incremental order over the complete
180 BackupRead stream beginning at pos 0 and ending at the end.
183 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
184 bool bContinue = false;
185 int64_t dwDataOffset = 0;
188 /* Win32 Stream Header size without name of stream.
189 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
191 int32_t dwSizeHeader = 20;
194 if (pContext->liNextHeader >= dwSize) {
195 dwDataLen = dwSize-dwDataOffset;
196 bContinue = false; /* 1 iteration is enough */
198 dwDataLen = pContext->liNextHeader-dwDataOffset;
199 bContinue = true; /* multiple iterations may be necessary */
203 /* copy block of real DATA */
204 if (pContext->bIsInData) {
205 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
209 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
210 int32_t dwOffsetTarget;
211 int32_t dwOffsetSource;
213 if (pContext->liNextHeader < 0) {
214 /* start of header was before this block, so we
215 * continue with the part in the current block
217 dwOffsetTarget = -pContext->liNextHeader;
220 /* start of header is inside of this block */
222 dwOffsetSource = pContext->liNextHeader;
225 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
226 bool bHeaderIsComplete;
228 if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
229 /* header (or rest of header) is completely available
232 bHeaderIsComplete = true;
234 /* header will continue in next block */
235 bHeaderIsComplete = false;
236 dwHeaderPartLen = dwSize-dwOffsetSource;
239 /* copy the available portion of header to persistent copy */
240 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
242 /* recalculate position of next header */
243 if (bHeaderIsComplete) {
244 /* convert stream name size (32 bit little endian) to machine type */
246 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
247 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
249 /* convert stream size (64 bit little endian) to machine type */
250 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
251 pContext->liNextHeader += dwDataOffset;
253 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
254 if (dwDataOffset == dwSize)
257 /* stop and continue with next block */
259 pContext->bIsInData = false;
264 /* set "NextHeader" relative to the beginning of the next block */
265 pContext->liNextHeader-= dwSize;
272 /* ===============================================================
276 * ===============================================================
279 #if defined(HAVE_WIN32)
281 void unix_name_to_win32(POOLMEM **win32_name, char *name);
282 extern "C" HANDLE get_osfhandle(int fd);
285 void binit(BFILE *bfd)
287 memset(bfd, 0, sizeof(BFILE));
289 bfd->mode = BF_CLOSED;
290 bfd->use_backup_api = have_win32_api();
291 bfd->cmd_plugin = false;
295 * Enables using the Backup API (win32_data).
296 * Returns 1 if function worked
297 * Returns 0 if failed (i.e. do not have Backup API on this machine)
299 bool set_win32_backup(BFILE *bfd)
301 /* We enable if possible here */
302 bfd->use_backup_api = have_win32_api();
303 return bfd->use_backup_api;
307 bool set_portable_backup(BFILE *bfd)
309 bfd->use_backup_api = false;
313 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
315 bfd->cmd_plugin = true;
321 * Return 1 if we are NOT using Win32 BackupWrite()
324 bool is_portable_backup(BFILE *bfd)
326 return !bfd->use_backup_api;
329 bool have_win32_api()
331 return p_BackupRead && p_BackupWrite;
336 * Return true if we support the stream
337 * false if we do not support the stream
339 * This code is running under Win32, so we
340 * do not need #ifdef on MACOS ...
342 bool is_restore_stream_supported(int stream)
346 /* Streams known not to be supported */
348 case STREAM_GZIP_DATA:
349 case STREAM_SPARSE_GZIP_DATA:
350 case STREAM_WIN32_GZIP_DATA:
352 case STREAM_MACOS_FORK_DATA:
353 case STREAM_HFSPLUS_ATTRIBUTES:
354 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
359 case STREAM_GZIP_DATA:
360 case STREAM_SPARSE_GZIP_DATA:
361 case STREAM_WIN32_GZIP_DATA:
363 case STREAM_WIN32_DATA:
364 case STREAM_UNIX_ATTRIBUTES:
365 case STREAM_FILE_DATA:
366 case STREAM_MD5_DIGEST:
367 case STREAM_UNIX_ATTRIBUTES_EX:
368 case STREAM_SPARSE_DATA:
369 case STREAM_PROGRAM_NAMES:
370 case STREAM_PROGRAM_DATA:
371 case STREAM_SHA1_DIGEST:
373 case STREAM_SHA256_DIGEST:
374 case STREAM_SHA512_DIGEST:
377 case STREAM_SIGNED_DIGEST:
378 case STREAM_ENCRYPTED_FILE_DATA:
379 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
380 case STREAM_ENCRYPTED_WIN32_DATA:
381 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
383 case 0: /* compatibility with old tapes */
389 HANDLE bget_handle(BFILE *bfd)
394 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
396 POOLMEM *win32_fname;
397 POOLMEM *win32_fname_wchar;
399 DWORD dwaccess, dwflags, dwshare;
401 /* Convert to Windows path format */
402 win32_fname = get_pool_memory(PM_FNAME);
403 win32_fname_wchar = get_pool_memory(PM_FNAME);
405 unix_name_to_win32(&win32_fname, (char *)fname);
407 if (bfd->cmd_plugin && plugin_bopen) {
409 Dmsg1(000, "call plugin_bopen fname=%s\n", fname);
410 rtnstat = plugin_bopen(bfd->jcr, fname, flags, mode);
411 free_pool_memory(win32_fname_wchar);
412 free_pool_memory(win32_fname);
416 if (!(p_CreateFileA || p_CreateFileW))
419 if (p_CreateFileW && p_MultiByteToWideChar)
420 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
422 if (flags & O_CREAT) { /* Create */
423 if (bfd->use_backup_api) {
424 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
425 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
427 dwaccess = GENERIC_WRITE;
431 if (p_CreateFileW && p_MultiByteToWideChar) {
432 // unicode open for create write
433 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
434 dwaccess, /* Requested access */
436 NULL, /* SecurityAttributes */
437 CREATE_ALWAYS, /* CreationDisposition */
438 dwflags, /* Flags and attributes */
439 NULL); /* TemplateFile */
442 bfd->fh = p_CreateFileA(win32_fname,
443 dwaccess, /* Requested access */
445 NULL, /* SecurityAttributes */
446 CREATE_ALWAYS, /* CreationDisposition */
447 dwflags, /* Flags and attributes */
448 NULL); /* TemplateFile */
451 bfd->mode = BF_WRITE;
453 } else if (flags & O_WRONLY) { /* Open existing for write */
454 if (bfd->use_backup_api) {
455 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
456 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
458 dwaccess = GENERIC_WRITE;
462 if (p_CreateFileW && p_MultiByteToWideChar) {
463 // unicode open for open existing write
464 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
465 dwaccess, /* Requested access */
467 NULL, /* SecurityAttributes */
468 OPEN_EXISTING, /* CreationDisposition */
469 dwflags, /* Flags and attributes */
470 NULL); /* TemplateFile */
473 bfd->fh = p_CreateFileA(win32_fname,
474 dwaccess, /* Requested access */
476 NULL, /* SecurityAttributes */
477 OPEN_EXISTING, /* CreationDisposition */
478 dwflags, /* Flags and attributes */
479 NULL); /* TemplateFile */
483 bfd->mode = BF_WRITE;
486 if (bfd->use_backup_api) {
487 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
488 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
489 FILE_FLAG_OPEN_REPARSE_POINT;
490 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
492 dwaccess = GENERIC_READ;
494 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
497 if (p_CreateFileW && p_MultiByteToWideChar) {
498 // unicode open for open existing read
499 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
500 dwaccess, /* Requested access */
501 dwshare, /* Share modes */
502 NULL, /* SecurityAttributes */
503 OPEN_EXISTING, /* CreationDisposition */
504 dwflags, /* Flags and attributes */
505 NULL); /* TemplateFile */
508 bfd->fh = p_CreateFileA(win32_fname,
509 dwaccess, /* Requested access */
510 dwshare, /* Share modes */
511 NULL, /* SecurityAttributes */
512 OPEN_EXISTING, /* CreationDisposition */
513 dwflags, /* Flags and attributes */
514 NULL); /* TemplateFile */
520 if (bfd->fh == INVALID_HANDLE_VALUE) {
521 bfd->lerror = GetLastError();
522 bfd->berrno = b_errno_win32;
523 errno = b_errno_win32;
524 bfd->mode = BF_CLOSED;
527 bfd->lpContext = NULL;
528 bfd->win32DecompContext.bIsInData = false;
529 bfd->win32DecompContext.liNextHeader = 0;
530 free_pool_memory(win32_fname_wchar);
531 free_pool_memory(win32_fname);
532 return bfd->mode == BF_CLOSED ? -1 : 1;
536 * Returns 0 on success
539 int bclose(BFILE *bfd)
544 free_pool_memory(bfd->errmsg);
547 if (bfd->mode == BF_CLOSED) {
551 if (bfd->cmd_plugin && plugin_bclose) {
552 stat = plugin_bclose(bfd->jcr);
556 if (bfd->use_backup_api && bfd->mode == BF_READ) {
558 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
560 (DWORD)0, /* bytes to read */
561 &bfd->rw_bytes, /* bytes read */
563 1, /* ProcessSecurity */
564 &bfd->lpContext)) { /* Read context */
565 errno = b_errno_win32;
568 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
570 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
572 (DWORD)0, /* bytes to read */
573 &bfd->rw_bytes, /* bytes written */
575 1, /* ProcessSecurity */
576 &bfd->lpContext)) { /* Write context */
577 errno = b_errno_win32;
581 if (!CloseHandle(bfd->fh)) {
583 errno = b_errno_win32;
587 bfd->mode = BF_CLOSED;
588 bfd->lpContext = NULL;
589 bfd->cmd_plugin = false;
593 /* Returns: bytes read on success
597 ssize_t bread(BFILE *bfd, void *buf, size_t count)
601 if (bfd->cmd_plugin && plugin_bread) {
602 return plugin_bread(bfd->jcr, buf, count);
605 if (bfd->use_backup_api) {
606 if (!p_BackupRead(bfd->fh,
611 1, /* Process Security */
612 &bfd->lpContext)) { /* Context */
613 bfd->lerror = GetLastError();
614 bfd->berrno = b_errno_win32;
615 errno = b_errno_win32;
619 if (!ReadFile(bfd->fh,
624 bfd->lerror = GetLastError();
625 bfd->berrno = b_errno_win32;
626 errno = b_errno_win32;
631 return (ssize_t)bfd->rw_bytes;
634 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
638 if (bfd->cmd_plugin && plugin_bwrite) {
639 return plugin_bwrite(bfd->jcr, buf, count);
642 if (bfd->use_backup_api) {
643 if (!p_BackupWrite(bfd->fh,
648 1, /* Process Security */
649 &bfd->lpContext)) { /* Context */
650 bfd->lerror = GetLastError();
651 bfd->berrno = b_errno_win32;
652 errno = b_errno_win32;
656 if (!WriteFile(bfd->fh,
661 bfd->lerror = GetLastError();
662 bfd->berrno = b_errno_win32;
663 errno = b_errno_win32;
667 return (ssize_t)bfd->rw_bytes;
670 bool is_bopen(BFILE *bfd)
672 return bfd->mode != BF_CLOSED;
675 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
677 LONG offset_low = (LONG)offset;
678 LONG offset_high = (LONG)(offset >> 32);
681 if (bfd->cmd_plugin && plugin_bwrite) {
682 return plugin_blseek(bfd->jcr, offset, whence);
685 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
687 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
688 return (boffset_t)-1;
691 return ((boffset_t)offset_high << 32) | dwResult;
694 #else /* Unix systems */
696 /* ===============================================================
700 * ===============================================================
702 void binit(BFILE *bfd)
704 memset(bfd, 0, sizeof(BFILE));
708 bool have_win32_api()
710 return false; /* no can do */
714 * Enables using the Backup API (win32_data).
715 * Returns true if function worked
716 * Returns false if failed (i.e. do not have Backup API on this machine)
718 bool set_win32_backup(BFILE *bfd)
720 return false; /* no can do */
724 bool set_portable_backup(BFILE *bfd)
726 return true; /* no problem */
730 * Return true if we are writing in portable format
731 * return false if not
733 bool is_portable_backup(BFILE *bfd)
735 return true; /* portable by definition */
738 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
743 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
745 bfd->cmd_plugin = true;
751 * This code is running on a non-Win32 machine
753 bool is_restore_stream_supported(int stream)
755 /* No Win32 backup on this machine */
758 case STREAM_GZIP_DATA:
759 case STREAM_SPARSE_GZIP_DATA:
760 case STREAM_WIN32_GZIP_DATA:
762 #ifndef HAVE_DARWIN_OS
763 case STREAM_MACOS_FORK_DATA:
764 case STREAM_HFSPLUS_ATTRIBUTES:
770 case STREAM_GZIP_DATA:
771 case STREAM_SPARSE_GZIP_DATA:
772 case STREAM_WIN32_GZIP_DATA:
774 case STREAM_WIN32_DATA:
775 case STREAM_UNIX_ATTRIBUTES:
776 case STREAM_FILE_DATA:
777 case STREAM_MD5_DIGEST:
778 case STREAM_UNIX_ATTRIBUTES_EX:
779 case STREAM_SPARSE_DATA:
780 case STREAM_PROGRAM_NAMES:
781 case STREAM_PROGRAM_DATA:
782 case STREAM_SHA1_DIGEST:
784 case STREAM_SHA256_DIGEST:
785 case STREAM_SHA512_DIGEST:
788 case STREAM_SIGNED_DIGEST:
789 case STREAM_ENCRYPTED_FILE_DATA:
790 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
791 case STREAM_ENCRYPTED_WIN32_DATA:
792 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
794 #ifdef HAVE_DARWIN_OS
795 case STREAM_MACOS_FORK_DATA:
796 case STREAM_HFSPLUS_ATTRIBUTES:
798 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
799 #endif /* HAVE_CRYPTO */
800 #endif /* HAVE_DARWIN_OS */
801 case 0: /* compatibility with old tapes */
808 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
810 if (bfd->cmd_plugin && plugin_bopen) {
811 Dmsg1(000, "call plugin_bopen fname=%s\n", fname);
812 return plugin_bopen(bfd->jcr, fname, flags, mode);
815 /* Normal file open */
816 Dmsg1(100, "open file %s\n", fname);
818 /* We use fnctl to set O_NOATIME if requested to avoid open error */
819 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
821 /* Set O_NOATIME if possible */
822 if (bfd->fid != -1 && flags & O_NOATIME) {
823 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
824 if (oldflags == -1) {
829 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
830 /* EPERM means setting O_NOATIME was not allowed */
831 if (ret == -1 && errno != EPERM) {
839 bfd->m_flags = flags;
840 Dmsg1(400, "Open file %d\n", bfd->fid);
843 bfd->win32DecompContext.bIsInData = false;
844 bfd->win32DecompContext.liNextHeader = 0;
846 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
847 if (bfd->fid != -1 && flags & O_RDONLY) {
848 int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
849 Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
856 #ifdef HAVE_DARWIN_OS
857 /* Open the resource fork of a file. */
858 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
862 rsrc_fname = get_pool_memory(PM_FNAME);
863 pm_strcpy(rsrc_fname, fname);
864 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
865 bopen(bfd, rsrc_fname, flags, mode);
866 free_pool_memory(rsrc_fname);
872 int bclose(BFILE *bfd)
876 Dmsg1(400, "Close file %d\n", bfd->fid);
878 if (bfd->cmd_plugin && plugin_bclose) {
879 stat = plugin_bclose(bfd->jcr);
881 bfd->cmd_plugin = false;
884 if (bfd->fid == -1) {
887 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
888 if (bfd->m_flags & O_RDONLY) {
889 fdatasync(bfd->fid); /* sync the file */
890 /* Tell OS we don't need it any more */
891 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
895 /* Close normal file */
896 stat = close(bfd->fid);
899 bfd->cmd_plugin = false;
903 ssize_t bread(BFILE *bfd, void *buf, size_t count)
907 if (bfd->cmd_plugin && plugin_bread) {
908 return plugin_bread(bfd->jcr, buf, count);
911 stat = read(bfd->fid, buf, count);
916 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
920 if (bfd->cmd_plugin && plugin_bwrite) {
921 return plugin_bwrite(bfd->jcr, buf, count);
923 stat = write(bfd->fid, buf, count);
928 bool is_bopen(BFILE *bfd)
930 return bfd->fid >= 0;
933 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
937 if (bfd->cmd_plugin && plugin_bwrite) {
938 return plugin_blseek(bfd->jcr, offset, whence);
940 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);