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;
49 #include <sys/paths.h>
52 #if !defined(HAVE_FDATASYNC)
57 /* ===============================================================
59 * U N I X AND W I N D O W S
61 * ===============================================================
64 bool is_win32_stream(int stream)
67 case STREAM_WIN32_DATA:
68 case STREAM_WIN32_GZIP_DATA:
69 case STREAM_ENCRYPTED_WIN32_DATA:
70 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
76 const char *stream_to_ascii(int stream)
81 case STREAM_UNIX_ATTRIBUTES:
82 return _("Unix attributes");
83 case STREAM_FILE_DATA:
84 return _("File data");
85 case STREAM_MD5_DIGEST:
86 return _("MD5 digest");
87 case STREAM_GZIP_DATA:
88 return _("GZIP data");
89 case STREAM_UNIX_ATTRIBUTES_EX:
90 return _("Extended attributes");
91 case STREAM_SPARSE_DATA:
92 return _("Sparse data");
93 case STREAM_SPARSE_GZIP_DATA:
94 return _("GZIP sparse data");
95 case STREAM_PROGRAM_NAMES:
96 return _("Program names");
97 case STREAM_PROGRAM_DATA:
98 return _("Program data");
99 case STREAM_SHA1_DIGEST:
100 return _("SHA1 digest");
101 case STREAM_WIN32_DATA:
102 return _("Win32 data");
103 case STREAM_WIN32_GZIP_DATA:
104 return _("Win32 GZIP data");
105 case STREAM_MACOS_FORK_DATA:
106 return _("MacOS Fork data");
107 case STREAM_HFSPLUS_ATTRIBUTES:
108 return _("HFS+ attribs");
109 case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
110 return _("Standard Unix ACL attribs");
111 case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
112 return _("Default Unix ACL attribs");
113 case STREAM_SHA256_DIGEST:
114 return _("SHA256 digest");
115 case STREAM_SHA512_DIGEST:
116 return _("SHA512 digest");
117 case STREAM_SIGNED_DIGEST:
118 return _("Signed digest");
119 case STREAM_ENCRYPTED_FILE_DATA:
120 return _("Encrypted File data");
121 case STREAM_ENCRYPTED_WIN32_DATA:
122 return _("Encrypted Win32 data");
123 case STREAM_ENCRYPTED_SESSION_DATA:
124 return _("Encrypted session data");
125 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
126 return _("Encrypted GZIP data");
127 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
128 return _("Encrypted Win32 GZIP data");
129 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
130 return _("Encrypted MacOS fork data");
132 sprintf(buf, "%d", stream);
133 return (const char *)buf;
138 void int64_LE2BE(int64_t* pBE, const int64_t v)
140 /* convert little endian to big endian */
141 if (htonl(1) != 1L) { /* no work if on little endian machine */
142 memcpy(pBE, &v, sizeof(int64_t));
145 uint8_t rv[sizeof(int64_t)];
146 uint8_t *pv = (uint8_t *) &v;
148 for (i = 0; i < 8; i++) {
151 memcpy(pBE, &rv, sizeof(int64_t));
156 void int32_LE2BE(int32_t* pBE, const int32_t v)
158 /* convert little endian to big endian */
159 if (htonl(1) != 1L) { /* no work if on little endian machine */
160 memcpy(pBE, &v, sizeof(int32_t));
163 uint8_t rv[sizeof(int32_t)];
164 uint8_t *pv = (uint8_t *) &v;
166 for (i = 0; i < 4; i++) {
169 memcpy(pBE, &rv, sizeof(int32_t));
174 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
176 /* pByte contains the buffer
177 dwSize the len to be processed. function assumes to be
178 called in successive incremental order over the complete
179 BackupRead stream beginning at pos 0 and ending at the end.
182 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
183 bool bContinue = false;
184 int64_t dwDataOffset = 0;
187 /* Win32 Stream Header size without name of stream.
188 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
190 int32_t dwSizeHeader = 20;
193 if (pContext->liNextHeader >= dwSize) {
194 dwDataLen = dwSize-dwDataOffset;
195 bContinue = false; /* 1 iteration is enough */
197 dwDataLen = pContext->liNextHeader-dwDataOffset;
198 bContinue = true; /* multiple iterations may be necessary */
202 /* copy block of real DATA */
203 if (pContext->bIsInData) {
204 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
208 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
209 int32_t dwOffsetTarget;
210 int32_t dwOffsetSource;
212 if (pContext->liNextHeader < 0) {
213 /* start of header was before this block, so we
214 * continue with the part in the current block
216 dwOffsetTarget = -pContext->liNextHeader;
219 /* start of header is inside of this block */
221 dwOffsetSource = pContext->liNextHeader;
224 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
225 bool bHeaderIsComplete;
227 if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
228 /* header (or rest of header) is completely available
231 bHeaderIsComplete = true;
233 /* header will continue in next block */
234 bHeaderIsComplete = false;
235 dwHeaderPartLen = dwSize-dwOffsetSource;
238 /* copy the available portion of header to persistent copy */
239 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
241 /* recalculate position of next header */
242 if (bHeaderIsComplete) {
243 /* convert stream name size (32 bit little endian) to machine type */
245 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
246 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
248 /* convert stream size (64 bit little endian) to machine type */
249 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
250 pContext->liNextHeader += dwDataOffset;
252 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
253 if (dwDataOffset == dwSize)
256 /* stop and continue with next block */
258 pContext->bIsInData = false;
263 /* set "NextHeader" relative to the beginning of the next block */
264 pContext->liNextHeader-= dwSize;
271 /* ===============================================================
275 * ===============================================================
278 #if defined(HAVE_WIN32)
280 void unix_name_to_win32(POOLMEM **win32_name, char *name);
281 extern "C" HANDLE get_osfhandle(int fd);
284 void binit(BFILE *bfd)
286 memset(bfd, 0, sizeof(BFILE));
288 bfd->mode = BF_CLOSED;
289 bfd->use_backup_api = have_win32_api();
290 bfd->cmd_plugin = false;
294 * Enables using the Backup API (win32_data).
295 * Returns 1 if function worked
296 * Returns 0 if failed (i.e. do not have Backup API on this machine)
298 bool set_win32_backup(BFILE *bfd)
300 /* We enable if possible here */
301 bfd->use_backup_api = have_win32_api();
302 return bfd->use_backup_api;
306 bool set_portable_backup(BFILE *bfd)
308 bfd->use_backup_api = false;
312 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
317 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
319 bfd->cmd_plugin = true;
325 * Return 1 if we are NOT using Win32 BackupWrite()
328 bool is_portable_backup(BFILE *bfd)
330 return !bfd->use_backup_api;
333 bool have_win32_api()
335 return p_BackupRead && p_BackupWrite;
340 * Return true if we support the stream
341 * false if we do not support the stream
343 * This code is running under Win32, so we
344 * do not need #ifdef on MACOS ...
346 bool is_restore_stream_supported(int stream)
350 /* Streams known not to be supported */
352 case STREAM_GZIP_DATA:
353 case STREAM_SPARSE_GZIP_DATA:
354 case STREAM_WIN32_GZIP_DATA:
356 case STREAM_MACOS_FORK_DATA:
357 case STREAM_HFSPLUS_ATTRIBUTES:
358 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
363 case STREAM_GZIP_DATA:
364 case STREAM_SPARSE_GZIP_DATA:
365 case STREAM_WIN32_GZIP_DATA:
367 case STREAM_WIN32_DATA:
368 case STREAM_UNIX_ATTRIBUTES:
369 case STREAM_FILE_DATA:
370 case STREAM_MD5_DIGEST:
371 case STREAM_UNIX_ATTRIBUTES_EX:
372 case STREAM_SPARSE_DATA:
373 case STREAM_PROGRAM_NAMES:
374 case STREAM_PROGRAM_DATA:
375 case STREAM_SHA1_DIGEST:
377 case STREAM_SHA256_DIGEST:
378 case STREAM_SHA512_DIGEST:
381 case STREAM_SIGNED_DIGEST:
382 case STREAM_ENCRYPTED_FILE_DATA:
383 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
384 case STREAM_ENCRYPTED_WIN32_DATA:
385 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
387 case 0: /* compatibility with old tapes */
393 HANDLE bget_handle(BFILE *bfd)
398 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
400 POOLMEM *win32_fname;
401 POOLMEM *win32_fname_wchar;
403 DWORD dwaccess, dwflags, dwshare;
405 /* Convert to Windows path format */
406 win32_fname = get_pool_memory(PM_FNAME);
407 win32_fname_wchar = get_pool_memory(PM_FNAME);
409 unix_name_to_win32(&win32_fname, (char *)fname);
411 if (!(p_CreateFileA || p_CreateFileW))
414 if (p_CreateFileW && p_MultiByteToWideChar)
415 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
417 if (flags & O_CREAT) { /* Create */
418 if (bfd->use_backup_api) {
419 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
420 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
422 dwaccess = GENERIC_WRITE;
426 if (p_CreateFileW && p_MultiByteToWideChar) {
427 // unicode open for create write
428 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
429 dwaccess, /* Requested access */
431 NULL, /* SecurityAttributes */
432 CREATE_ALWAYS, /* CreationDisposition */
433 dwflags, /* Flags and attributes */
434 NULL); /* TemplateFile */
437 bfd->fh = p_CreateFileA(win32_fname,
438 dwaccess, /* Requested access */
440 NULL, /* SecurityAttributes */
441 CREATE_ALWAYS, /* CreationDisposition */
442 dwflags, /* Flags and attributes */
443 NULL); /* TemplateFile */
446 bfd->mode = BF_WRITE;
448 } else if (flags & O_WRONLY) { /* Open existing for write */
449 if (bfd->use_backup_api) {
450 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
451 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
453 dwaccess = GENERIC_WRITE;
457 if (p_CreateFileW && p_MultiByteToWideChar) {
458 // unicode open for open existing write
459 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
460 dwaccess, /* Requested access */
462 NULL, /* SecurityAttributes */
463 OPEN_EXISTING, /* CreationDisposition */
464 dwflags, /* Flags and attributes */
465 NULL); /* TemplateFile */
468 bfd->fh = p_CreateFileA(win32_fname,
469 dwaccess, /* Requested access */
471 NULL, /* SecurityAttributes */
472 OPEN_EXISTING, /* CreationDisposition */
473 dwflags, /* Flags and attributes */
474 NULL); /* TemplateFile */
478 bfd->mode = BF_WRITE;
481 if (bfd->use_backup_api) {
482 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
483 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
484 FILE_FLAG_OPEN_REPARSE_POINT;
485 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
487 dwaccess = GENERIC_READ;
489 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
492 if (p_CreateFileW && p_MultiByteToWideChar) {
493 // unicode open for open existing read
494 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
495 dwaccess, /* Requested access */
496 dwshare, /* Share modes */
497 NULL, /* SecurityAttributes */
498 OPEN_EXISTING, /* CreationDisposition */
499 dwflags, /* Flags and attributes */
500 NULL); /* TemplateFile */
503 bfd->fh = p_CreateFileA(win32_fname,
504 dwaccess, /* Requested access */
505 dwshare, /* Share modes */
506 NULL, /* SecurityAttributes */
507 OPEN_EXISTING, /* CreationDisposition */
508 dwflags, /* Flags and attributes */
509 NULL); /* TemplateFile */
515 if (bfd->fh == INVALID_HANDLE_VALUE) {
516 bfd->lerror = GetLastError();
517 bfd->berrno = b_errno_win32;
518 errno = b_errno_win32;
519 bfd->mode = BF_CLOSED;
522 bfd->lpContext = NULL;
523 bfd->win32DecompContext.bIsInData = false;
524 bfd->win32DecompContext.liNextHeader = 0;
525 free_pool_memory(win32_fname_wchar);
526 free_pool_memory(win32_fname);
527 return bfd->mode == BF_CLOSED ? -1 : 1;
531 * Returns 0 on success
534 int bclose(BFILE *bfd)
539 free_pool_memory(bfd->errmsg);
542 if (bfd->mode == BF_CLOSED) {
545 if (bfd->use_backup_api && bfd->mode == BF_READ) {
547 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
549 (DWORD)0, /* bytes to read */
550 &bfd->rw_bytes, /* bytes read */
552 1, /* ProcessSecurity */
553 &bfd->lpContext)) { /* Read context */
554 errno = b_errno_win32;
557 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
559 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
561 (DWORD)0, /* bytes to read */
562 &bfd->rw_bytes, /* bytes written */
564 1, /* ProcessSecurity */
565 &bfd->lpContext)) { /* Write context */
566 errno = b_errno_win32;
570 if (!CloseHandle(bfd->fh)) {
572 errno = b_errno_win32;
574 bfd->mode = BF_CLOSED;
575 bfd->lpContext = NULL;
576 bfd->cmd_plugin = false;
580 /* Returns: bytes read on success
584 ssize_t bread(BFILE *bfd, void *buf, size_t count)
588 if (bfd->use_backup_api) {
589 if (!p_BackupRead(bfd->fh,
594 1, /* Process Security */
595 &bfd->lpContext)) { /* Context */
596 bfd->lerror = GetLastError();
597 bfd->berrno = b_errno_win32;
598 errno = b_errno_win32;
602 if (!ReadFile(bfd->fh,
607 bfd->lerror = GetLastError();
608 bfd->berrno = b_errno_win32;
609 errno = b_errno_win32;
614 return (ssize_t)bfd->rw_bytes;
617 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
621 if (bfd->use_backup_api) {
622 if (!p_BackupWrite(bfd->fh,
627 1, /* Process Security */
628 &bfd->lpContext)) { /* Context */
629 bfd->lerror = GetLastError();
630 bfd->berrno = b_errno_win32;
631 errno = b_errno_win32;
635 if (!WriteFile(bfd->fh,
640 bfd->lerror = GetLastError();
641 bfd->berrno = b_errno_win32;
642 errno = b_errno_win32;
646 return (ssize_t)bfd->rw_bytes;
649 bool is_bopen(BFILE *bfd)
651 return bfd->mode != BF_CLOSED;
654 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
656 LONG offset_low = (LONG)offset;
657 LONG offset_high = (LONG)(offset >> 32);
660 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
662 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
663 return (boffset_t)-1;
666 return ((boffset_t)offset_high << 32) | dwResult;
669 #else /* Unix systems */
671 /* ===============================================================
675 * ===============================================================
677 void binit(BFILE *bfd)
679 memset(bfd, 0, sizeof(BFILE));
683 bool have_win32_api()
685 return false; /* no can do */
689 * Enables using the Backup API (win32_data).
690 * Returns true if function worked
691 * Returns false if failed (i.e. do not have Backup API on this machine)
693 bool set_win32_backup(BFILE *bfd)
695 return false; /* no can do */
699 bool set_portable_backup(BFILE *bfd)
701 return true; /* no problem */
705 * Return true if we are writing in portable format
706 * return false if not
708 bool is_portable_backup(BFILE *bfd)
710 return true; /* portable by definition */
713 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
718 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
720 bfd->cmd_plugin = true;
726 * This code is running on a non-Win32 machine
728 bool is_restore_stream_supported(int stream)
730 /* No Win32 backup on this machine */
733 case STREAM_GZIP_DATA:
734 case STREAM_SPARSE_GZIP_DATA:
735 case STREAM_WIN32_GZIP_DATA:
737 #ifndef HAVE_DARWIN_OS
738 case STREAM_MACOS_FORK_DATA:
739 case STREAM_HFSPLUS_ATTRIBUTES:
745 case STREAM_GZIP_DATA:
746 case STREAM_SPARSE_GZIP_DATA:
747 case STREAM_WIN32_GZIP_DATA:
749 case STREAM_WIN32_DATA:
750 case STREAM_UNIX_ATTRIBUTES:
751 case STREAM_FILE_DATA:
752 case STREAM_MD5_DIGEST:
753 case STREAM_UNIX_ATTRIBUTES_EX:
754 case STREAM_SPARSE_DATA:
755 case STREAM_PROGRAM_NAMES:
756 case STREAM_PROGRAM_DATA:
757 case STREAM_SHA1_DIGEST:
759 case STREAM_SHA256_DIGEST:
760 case STREAM_SHA512_DIGEST:
763 case STREAM_SIGNED_DIGEST:
764 case STREAM_ENCRYPTED_FILE_DATA:
765 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
766 case STREAM_ENCRYPTED_WIN32_DATA:
767 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
769 #ifdef HAVE_DARWIN_OS
770 case STREAM_MACOS_FORK_DATA:
771 case STREAM_HFSPLUS_ATTRIBUTES:
773 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
774 #endif /* HAVE_CRYPTO */
775 #endif /* HAVE_DARWIN_OS */
776 case 0: /* compatibility with old tapes */
783 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
785 if (bfd->cmd_plugin && plugin_bopen) {
786 return plugin_bopen(bfd->jcr, fname, flags, mode);
789 /* Normal file open */
790 Dmsg1(400, "open file %s\n", fname);
791 /* We use fnctl to set O_NOATIME if requested to avoid open error */
792 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
793 /* Set O_NOATIME if possible */
794 if (bfd->fid != -1 && flags & O_NOATIME) {
795 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
796 if (oldflags == -1) {
801 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
802 /* EPERM means setting O_NOATIME was not allowed */
803 if (ret == -1 && errno != EPERM) {
811 bfd->m_flags = flags;
812 Dmsg1(400, "Open file %d\n", bfd->fid);
815 bfd->win32DecompContext.bIsInData = false;
816 bfd->win32DecompContext.liNextHeader = 0;
818 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
819 if (bfd->fid != -1 && flags & O_RDONLY) {
820 int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
821 Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
828 #ifdef HAVE_DARWIN_OS
829 /* Open the resource fork of a file. */
830 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
834 rsrc_fname = get_pool_memory(PM_FNAME);
835 pm_strcpy(rsrc_fname, fname);
836 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
837 bopen(bfd, rsrc_fname, flags, mode);
838 free_pool_memory(rsrc_fname);
844 int bclose(BFILE *bfd)
848 Dmsg1(400, "Close file %d\n", bfd->fid);
850 if (bfd->cmd_plugin && plugin_bclose) {
851 return plugin_bclose(bfd->jcr);
854 if (bfd->fid == -1) {
857 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
858 if (bfd->m_flags & O_RDONLY) {
859 fdatasync(bfd->fid); /* sync the file */
860 /* Tell OS we don't need it any more */
861 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
865 /* Close normal file */
866 stat = close(bfd->fid);
869 bfd->cmd_plugin = false;
873 ssize_t bread(BFILE *bfd, void *buf, size_t count)
877 if (bfd->cmd_plugin && plugin_bread) {
878 return plugin_bread(bfd->jcr, buf, count);
881 stat = read(bfd->fid, buf, count);
886 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
890 if (bfd->cmd_plugin && plugin_bwrite) {
891 return plugin_bwrite(bfd->jcr, buf, count);
893 stat = write(bfd->fid, buf, count);
898 bool is_bopen(BFILE *bfd)
900 return bfd->fid >= 0;
903 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
906 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);