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_prog(BFILE *bfd, char *prog, JCR *jcr)
318 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
320 bfd->cmd_plugin = true;
326 * Return 1 if we are NOT using Win32 BackupWrite()
329 bool is_portable_backup(BFILE *bfd)
331 return !bfd->use_backup_api;
334 bool have_win32_api()
336 return p_BackupRead && p_BackupWrite;
341 * Return true if we support the stream
342 * false if we do not support the stream
344 * This code is running under Win32, so we
345 * do not need #ifdef on MACOS ...
347 bool is_restore_stream_supported(int stream)
351 /* Streams known not to be supported */
353 case STREAM_GZIP_DATA:
354 case STREAM_SPARSE_GZIP_DATA:
355 case STREAM_WIN32_GZIP_DATA:
357 case STREAM_MACOS_FORK_DATA:
358 case STREAM_HFSPLUS_ATTRIBUTES:
359 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
364 case STREAM_GZIP_DATA:
365 case STREAM_SPARSE_GZIP_DATA:
366 case STREAM_WIN32_GZIP_DATA:
368 case STREAM_WIN32_DATA:
369 case STREAM_UNIX_ATTRIBUTES:
370 case STREAM_FILE_DATA:
371 case STREAM_MD5_DIGEST:
372 case STREAM_UNIX_ATTRIBUTES_EX:
373 case STREAM_SPARSE_DATA:
374 case STREAM_PROGRAM_NAMES:
375 case STREAM_PROGRAM_DATA:
376 case STREAM_SHA1_DIGEST:
378 case STREAM_SHA256_DIGEST:
379 case STREAM_SHA512_DIGEST:
382 case STREAM_SIGNED_DIGEST:
383 case STREAM_ENCRYPTED_FILE_DATA:
384 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
385 case STREAM_ENCRYPTED_WIN32_DATA:
386 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
388 case 0: /* compatibility with old tapes */
394 HANDLE bget_handle(BFILE *bfd)
399 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
401 POOLMEM *win32_fname;
402 POOLMEM *win32_fname_wchar;
404 DWORD dwaccess, dwflags, dwshare;
406 /* Convert to Windows path format */
407 win32_fname = get_pool_memory(PM_FNAME);
408 win32_fname_wchar = get_pool_memory(PM_FNAME);
410 unix_name_to_win32(&win32_fname, (char *)fname);
412 if (!(p_CreateFileA || p_CreateFileW))
415 if (p_CreateFileW && p_MultiByteToWideChar)
416 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
418 if (flags & O_CREAT) { /* Create */
419 if (bfd->use_backup_api) {
420 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
421 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
423 dwaccess = GENERIC_WRITE;
427 if (p_CreateFileW && p_MultiByteToWideChar) {
428 // unicode open for create write
429 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
430 dwaccess, /* Requested access */
432 NULL, /* SecurityAttributes */
433 CREATE_ALWAYS, /* CreationDisposition */
434 dwflags, /* Flags and attributes */
435 NULL); /* TemplateFile */
438 bfd->fh = p_CreateFileA(win32_fname,
439 dwaccess, /* Requested access */
441 NULL, /* SecurityAttributes */
442 CREATE_ALWAYS, /* CreationDisposition */
443 dwflags, /* Flags and attributes */
444 NULL); /* TemplateFile */
447 bfd->mode = BF_WRITE;
449 } else if (flags & O_WRONLY) { /* Open existing for write */
450 if (bfd->use_backup_api) {
451 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
452 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
454 dwaccess = GENERIC_WRITE;
458 if (p_CreateFileW && p_MultiByteToWideChar) {
459 // unicode open for open existing write
460 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
461 dwaccess, /* Requested access */
463 NULL, /* SecurityAttributes */
464 OPEN_EXISTING, /* CreationDisposition */
465 dwflags, /* Flags and attributes */
466 NULL); /* TemplateFile */
469 bfd->fh = p_CreateFileA(win32_fname,
470 dwaccess, /* Requested access */
472 NULL, /* SecurityAttributes */
473 OPEN_EXISTING, /* CreationDisposition */
474 dwflags, /* Flags and attributes */
475 NULL); /* TemplateFile */
479 bfd->mode = BF_WRITE;
482 if (bfd->use_backup_api) {
483 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
484 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
485 FILE_FLAG_OPEN_REPARSE_POINT;
486 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
488 dwaccess = GENERIC_READ;
490 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
493 if (p_CreateFileW && p_MultiByteToWideChar) {
494 // unicode open for open existing read
495 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
496 dwaccess, /* Requested access */
497 dwshare, /* Share modes */
498 NULL, /* SecurityAttributes */
499 OPEN_EXISTING, /* CreationDisposition */
500 dwflags, /* Flags and attributes */
501 NULL); /* TemplateFile */
504 bfd->fh = p_CreateFileA(win32_fname,
505 dwaccess, /* Requested access */
506 dwshare, /* Share modes */
507 NULL, /* SecurityAttributes */
508 OPEN_EXISTING, /* CreationDisposition */
509 dwflags, /* Flags and attributes */
510 NULL); /* TemplateFile */
516 if (bfd->fh == INVALID_HANDLE_VALUE) {
517 bfd->lerror = GetLastError();
518 bfd->berrno = b_errno_win32;
519 errno = b_errno_win32;
520 bfd->mode = BF_CLOSED;
523 bfd->lpContext = NULL;
524 bfd->win32DecompContext.bIsInData = false;
525 bfd->win32DecompContext.liNextHeader = 0;
526 free_pool_memory(win32_fname_wchar);
527 free_pool_memory(win32_fname);
528 return bfd->mode == BF_CLOSED ? -1 : 1;
532 * Returns 0 on success
535 int bclose(BFILE *bfd)
540 free_pool_memory(bfd->errmsg);
543 if (bfd->mode == BF_CLOSED) {
546 if (bfd->use_backup_api && bfd->mode == BF_READ) {
548 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
550 (DWORD)0, /* bytes to read */
551 &bfd->rw_bytes, /* bytes read */
553 1, /* ProcessSecurity */
554 &bfd->lpContext)) { /* Read context */
555 errno = b_errno_win32;
558 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
560 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
562 (DWORD)0, /* bytes to read */
563 &bfd->rw_bytes, /* bytes written */
565 1, /* ProcessSecurity */
566 &bfd->lpContext)) { /* Write context */
567 errno = b_errno_win32;
571 if (!CloseHandle(bfd->fh)) {
573 errno = b_errno_win32;
575 bfd->mode = BF_CLOSED;
576 bfd->lpContext = NULL;
577 bfd->cmd_plugin = false;
581 /* Returns: bytes read on success
585 ssize_t bread(BFILE *bfd, void *buf, size_t count)
589 if (bfd->use_backup_api) {
590 if (!p_BackupRead(bfd->fh,
595 1, /* Process Security */
596 &bfd->lpContext)) { /* Context */
597 bfd->lerror = GetLastError();
598 bfd->berrno = b_errno_win32;
599 errno = b_errno_win32;
603 if (!ReadFile(bfd->fh,
608 bfd->lerror = GetLastError();
609 bfd->berrno = b_errno_win32;
610 errno = b_errno_win32;
615 return (ssize_t)bfd->rw_bytes;
618 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
622 if (bfd->use_backup_api) {
623 if (!p_BackupWrite(bfd->fh,
628 1, /* Process Security */
629 &bfd->lpContext)) { /* Context */
630 bfd->lerror = GetLastError();
631 bfd->berrno = b_errno_win32;
632 errno = b_errno_win32;
636 if (!WriteFile(bfd->fh,
641 bfd->lerror = GetLastError();
642 bfd->berrno = b_errno_win32;
643 errno = b_errno_win32;
647 return (ssize_t)bfd->rw_bytes;
650 bool is_bopen(BFILE *bfd)
652 return bfd->mode != BF_CLOSED;
655 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
657 LONG offset_low = (LONG)offset;
658 LONG offset_high = (LONG)(offset >> 32);
661 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
663 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
664 return (boffset_t)-1;
667 return ((boffset_t)offset_high << 32) | dwResult;
670 #else /* Unix systems */
672 /* ===============================================================
676 * ===============================================================
678 void binit(BFILE *bfd)
680 memset(bfd, 0, sizeof(BFILE));
684 bool have_win32_api()
686 return false; /* no can do */
690 * Enables using the Backup API (win32_data).
691 * Returns true if function worked
692 * Returns false if failed (i.e. do not have Backup API on this machine)
694 bool set_win32_backup(BFILE *bfd)
696 return false; /* no can do */
700 bool set_portable_backup(BFILE *bfd)
702 return true; /* no problem */
706 * Return true if we are writing in portable format
707 * return false if not
709 bool is_portable_backup(BFILE *bfd)
711 return true; /* portable by definition */
714 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
719 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
721 bfd->cmd_plugin = true;
727 * This code is running on a non-Win32 machine
729 bool is_restore_stream_supported(int stream)
731 /* No Win32 backup on this machine */
734 case STREAM_GZIP_DATA:
735 case STREAM_SPARSE_GZIP_DATA:
736 case STREAM_WIN32_GZIP_DATA:
738 #ifndef HAVE_DARWIN_OS
739 case STREAM_MACOS_FORK_DATA:
740 case STREAM_HFSPLUS_ATTRIBUTES:
746 case STREAM_GZIP_DATA:
747 case STREAM_SPARSE_GZIP_DATA:
748 case STREAM_WIN32_GZIP_DATA:
750 case STREAM_WIN32_DATA:
751 case STREAM_UNIX_ATTRIBUTES:
752 case STREAM_FILE_DATA:
753 case STREAM_MD5_DIGEST:
754 case STREAM_UNIX_ATTRIBUTES_EX:
755 case STREAM_SPARSE_DATA:
756 case STREAM_PROGRAM_NAMES:
757 case STREAM_PROGRAM_DATA:
758 case STREAM_SHA1_DIGEST:
760 case STREAM_SHA256_DIGEST:
761 case STREAM_SHA512_DIGEST:
764 case STREAM_SIGNED_DIGEST:
765 case STREAM_ENCRYPTED_FILE_DATA:
766 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
767 case STREAM_ENCRYPTED_WIN32_DATA:
768 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
770 #ifdef HAVE_DARWIN_OS
771 case STREAM_MACOS_FORK_DATA:
772 case STREAM_HFSPLUS_ATTRIBUTES:
774 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
775 #endif /* HAVE_CRYPTO */
776 #endif /* HAVE_DARWIN_OS */
777 case 0: /* compatibility with old tapes */
784 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
786 if (bfd->cmd_plugin && plugin_bopen) {
787 return plugin_bopen(bfd->jcr, fname, flags, mode);
790 /* Normal file open */
791 Dmsg1(400, "open file %s\n", fname);
792 /* We use fnctl to set O_NOATIME if requested to avoid open error */
793 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
794 /* Set O_NOATIME if possible */
795 if (bfd->fid != -1 && flags & O_NOATIME) {
796 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
797 if (oldflags == -1) {
802 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
803 /* EPERM means setting O_NOATIME was not allowed */
804 if (ret == -1 && errno != EPERM) {
812 bfd->m_flags = flags;
813 Dmsg1(400, "Open file %d\n", bfd->fid);
816 bfd->win32DecompContext.bIsInData = false;
817 bfd->win32DecompContext.liNextHeader = 0;
819 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
820 if (bfd->fid != -1 && flags & O_RDONLY) {
821 int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
822 Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
829 #ifdef HAVE_DARWIN_OS
830 /* Open the resource fork of a file. */
831 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
835 rsrc_fname = get_pool_memory(PM_FNAME);
836 pm_strcpy(rsrc_fname, fname);
837 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
838 bopen(bfd, rsrc_fname, flags, mode);
839 free_pool_memory(rsrc_fname);
845 int bclose(BFILE *bfd)
849 Dmsg1(400, "Close file %d\n", bfd->fid);
851 if (bfd->cmd_plugin && plugin_bclose) {
852 return plugin_bclose(bfd->jcr);
855 if (bfd->fid == -1) {
858 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
859 if (bfd->m_flags & O_RDONLY) {
860 fdatasync(bfd->fid); /* sync the file */
861 /* Tell OS we don't need it any more */
862 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
866 /* Close normal file */
867 stat = close(bfd->fid);
870 bfd->cmd_plugin = false;
874 ssize_t bread(BFILE *bfd, void *buf, size_t count)
878 if (bfd->cmd_plugin && plugin_bread) {
879 return plugin_bread(bfd->jcr, buf, count);
882 stat = read(bfd->fid, buf, count);
887 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
891 if (bfd->cmd_plugin && plugin_bwrite) {
892 return plugin_bwrite(bfd->jcr, buf, count);
894 stat = write(bfd->fid, buf, count);
899 bool is_bopen(BFILE *bfd)
901 return bfd->fid >= 0;
904 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
908 if (bfd->cmd_plugin && plugin_bwrite) {
909 return plugin_blseek(bfd->jcr, offset, whence);
911 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);