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 bool (*python_set_prog)(JCR *jcr, const char *prog) = NULL;
43 int (*python_open)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL;
44 int (*python_close)(BFILE *bfd) = NULL;
45 ssize_t (*python_read)(BFILE *bfd, void *buf, size_t count) = NULL;
46 ssize_t (*python_write)(BFILE *bfd, void *buf, size_t count) = NULL;
48 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
49 int (*plugin_bclose)(JCR *jcr) = NULL;
50 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
51 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
55 #include <sys/paths.h>
58 #if !defined(HAVE_FDATASYNC)
63 /* ===============================================================
65 * U N I X AND W I N D O W S
67 * ===============================================================
70 bool is_win32_stream(int stream)
73 case STREAM_WIN32_DATA:
74 case STREAM_WIN32_GZIP_DATA:
75 case STREAM_ENCRYPTED_WIN32_DATA:
76 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
82 const char *stream_to_ascii(int stream)
87 case STREAM_UNIX_ATTRIBUTES:
88 return _("Unix attributes");
89 case STREAM_FILE_DATA:
90 return _("File data");
91 case STREAM_MD5_DIGEST:
92 return _("MD5 digest");
93 case STREAM_GZIP_DATA:
94 return _("GZIP data");
95 case STREAM_UNIX_ATTRIBUTES_EX:
96 return _("Extended attributes");
97 case STREAM_SPARSE_DATA:
98 return _("Sparse data");
99 case STREAM_SPARSE_GZIP_DATA:
100 return _("GZIP sparse data");
101 case STREAM_PROGRAM_NAMES:
102 return _("Program names");
103 case STREAM_PROGRAM_DATA:
104 return _("Program data");
105 case STREAM_SHA1_DIGEST:
106 return _("SHA1 digest");
107 case STREAM_WIN32_DATA:
108 return _("Win32 data");
109 case STREAM_WIN32_GZIP_DATA:
110 return _("Win32 GZIP data");
111 case STREAM_MACOS_FORK_DATA:
112 return _("MacOS Fork data");
113 case STREAM_HFSPLUS_ATTRIBUTES:
114 return _("HFS+ attribs");
115 case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
116 return _("Standard Unix ACL attribs");
117 case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
118 return _("Default Unix ACL attribs");
119 case STREAM_SHA256_DIGEST:
120 return _("SHA256 digest");
121 case STREAM_SHA512_DIGEST:
122 return _("SHA512 digest");
123 case STREAM_SIGNED_DIGEST:
124 return _("Signed digest");
125 case STREAM_ENCRYPTED_FILE_DATA:
126 return _("Encrypted File data");
127 case STREAM_ENCRYPTED_WIN32_DATA:
128 return _("Encrypted Win32 data");
129 case STREAM_ENCRYPTED_SESSION_DATA:
130 return _("Encrypted session data");
131 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
132 return _("Encrypted GZIP data");
133 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
134 return _("Encrypted Win32 GZIP data");
135 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
136 return _("Encrypted MacOS fork data");
138 sprintf(buf, "%d", stream);
139 return (const char *)buf;
144 void int64_LE2BE(int64_t* pBE, const int64_t v)
146 /* convert little endian to big endian */
147 if (htonl(1) != 1L) { /* no work if on little endian machine */
148 memcpy(pBE, &v, sizeof(int64_t));
151 uint8_t rv[sizeof(int64_t)];
152 uint8_t *pv = (uint8_t *) &v;
154 for (i = 0; i < 8; i++) {
157 memcpy(pBE, &rv, sizeof(int64_t));
162 void int32_LE2BE(int32_t* pBE, const int32_t v)
164 /* convert little endian to big endian */
165 if (htonl(1) != 1L) { /* no work if on little endian machine */
166 memcpy(pBE, &v, sizeof(int32_t));
169 uint8_t rv[sizeof(int32_t)];
170 uint8_t *pv = (uint8_t *) &v;
172 for (i = 0; i < 4; i++) {
175 memcpy(pBE, &rv, sizeof(int32_t));
180 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
182 /* pByte contains the buffer
183 dwSize the len to be processed. function assumes to be
184 called in successive incremental order over the complete
185 BackupRead stream beginning at pos 0 and ending at the end.
188 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
189 bool bContinue = false;
190 int64_t dwDataOffset = 0;
193 /* Win32 Stream Header size without name of stream.
194 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
196 int32_t dwSizeHeader = 20;
199 if (pContext->liNextHeader >= dwSize) {
200 dwDataLen = dwSize-dwDataOffset;
201 bContinue = false; /* 1 iteration is enough */
203 dwDataLen = pContext->liNextHeader-dwDataOffset;
204 bContinue = true; /* multiple iterations may be necessary */
208 /* copy block of real DATA */
209 if (pContext->bIsInData) {
210 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
214 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
215 int32_t dwOffsetTarget;
216 int32_t dwOffsetSource;
218 if (pContext->liNextHeader < 0) {
219 /* start of header was before this block, so we
220 * continue with the part in the current block
222 dwOffsetTarget = -pContext->liNextHeader;
225 /* start of header is inside of this block */
227 dwOffsetSource = pContext->liNextHeader;
230 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
231 bool bHeaderIsComplete;
233 if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
234 /* header (or rest of header) is completely available
237 bHeaderIsComplete = true;
239 /* header will continue in next block */
240 bHeaderIsComplete = false;
241 dwHeaderPartLen = dwSize-dwOffsetSource;
244 /* copy the available portion of header to persistent copy */
245 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
247 /* recalculate position of next header */
248 if (bHeaderIsComplete) {
249 /* convert stream name size (32 bit little endian) to machine type */
251 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
252 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
254 /* convert stream size (64 bit little endian) to machine type */
255 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
256 pContext->liNextHeader += dwDataOffset;
258 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
259 if (dwDataOffset == dwSize)
262 /* stop and continue with next block */
264 pContext->bIsInData = false;
269 /* set "NextHeader" relative to the beginning of the next block */
270 pContext->liNextHeader-= dwSize;
277 /* ===============================================================
281 * ===============================================================
284 #if defined(HAVE_WIN32)
286 void unix_name_to_win32(POOLMEM **win32_name, char *name);
287 extern "C" HANDLE get_osfhandle(int fd);
290 void binit(BFILE *bfd)
292 memset(bfd, 0, sizeof(BFILE));
294 bfd->mode = BF_CLOSED;
295 bfd->use_backup_api = have_win32_api();
296 bfd->cmd_plugin = false;
300 * Enables using the Backup API (win32_data).
301 * Returns 1 if function worked
302 * Returns 0 if failed (i.e. do not have Backup API on this machine)
304 bool set_win32_backup(BFILE *bfd)
306 /* We enable if possible here */
307 bfd->use_backup_api = have_win32_api();
308 return bfd->use_backup_api;
312 bool set_portable_backup(BFILE *bfd)
314 bfd->use_backup_api = false;
318 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
323 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
325 bfd->cmd_plugin = true;
331 * Return 1 if we are NOT using Win32 BackupWrite()
334 bool is_portable_backup(BFILE *bfd)
336 return !bfd->use_backup_api;
339 bool have_win32_api()
341 return p_BackupRead && p_BackupWrite;
346 * Return true if we support the stream
347 * false if we do not support the stream
349 * This code is running under Win32, so we
350 * do not need #ifdef on MACOS ...
352 bool is_restore_stream_supported(int stream)
356 /* Streams known not to be supported */
358 case STREAM_GZIP_DATA:
359 case STREAM_SPARSE_GZIP_DATA:
360 case STREAM_WIN32_GZIP_DATA:
362 case STREAM_MACOS_FORK_DATA:
363 case STREAM_HFSPLUS_ATTRIBUTES:
364 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
369 case STREAM_GZIP_DATA:
370 case STREAM_SPARSE_GZIP_DATA:
371 case STREAM_WIN32_GZIP_DATA:
373 case STREAM_WIN32_DATA:
374 case STREAM_UNIX_ATTRIBUTES:
375 case STREAM_FILE_DATA:
376 case STREAM_MD5_DIGEST:
377 case STREAM_UNIX_ATTRIBUTES_EX:
378 case STREAM_SPARSE_DATA:
379 case STREAM_PROGRAM_NAMES:
380 case STREAM_PROGRAM_DATA:
381 case STREAM_SHA1_DIGEST:
383 case STREAM_SHA256_DIGEST:
384 case STREAM_SHA512_DIGEST:
387 case STREAM_SIGNED_DIGEST:
388 case STREAM_ENCRYPTED_FILE_DATA:
389 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
390 case STREAM_ENCRYPTED_WIN32_DATA:
391 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
393 case 0: /* compatibility with old tapes */
399 HANDLE bget_handle(BFILE *bfd)
404 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
406 POOLMEM *win32_fname;
407 POOLMEM *win32_fname_wchar;
409 DWORD dwaccess, dwflags, dwshare;
411 /* Convert to Windows path format */
412 win32_fname = get_pool_memory(PM_FNAME);
413 win32_fname_wchar = get_pool_memory(PM_FNAME);
415 unix_name_to_win32(&win32_fname, (char *)fname);
417 if (!(p_CreateFileA || p_CreateFileW))
420 if (p_CreateFileW && p_MultiByteToWideChar)
421 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
423 if (flags & O_CREAT) { /* Create */
424 if (bfd->use_backup_api) {
425 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
426 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
428 dwaccess = GENERIC_WRITE;
432 if (p_CreateFileW && p_MultiByteToWideChar) {
433 // unicode open for create write
434 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
435 dwaccess, /* Requested access */
437 NULL, /* SecurityAttributes */
438 CREATE_ALWAYS, /* CreationDisposition */
439 dwflags, /* Flags and attributes */
440 NULL); /* TemplateFile */
443 bfd->fh = p_CreateFileA(win32_fname,
444 dwaccess, /* Requested access */
446 NULL, /* SecurityAttributes */
447 CREATE_ALWAYS, /* CreationDisposition */
448 dwflags, /* Flags and attributes */
449 NULL); /* TemplateFile */
452 bfd->mode = BF_WRITE;
454 } else if (flags & O_WRONLY) { /* Open existing for write */
455 if (bfd->use_backup_api) {
456 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
457 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
459 dwaccess = GENERIC_WRITE;
463 if (p_CreateFileW && p_MultiByteToWideChar) {
464 // unicode open for open existing write
465 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
466 dwaccess, /* Requested access */
468 NULL, /* SecurityAttributes */
469 OPEN_EXISTING, /* CreationDisposition */
470 dwflags, /* Flags and attributes */
471 NULL); /* TemplateFile */
474 bfd->fh = p_CreateFileA(win32_fname,
475 dwaccess, /* Requested access */
477 NULL, /* SecurityAttributes */
478 OPEN_EXISTING, /* CreationDisposition */
479 dwflags, /* Flags and attributes */
480 NULL); /* TemplateFile */
484 bfd->mode = BF_WRITE;
487 if (bfd->use_backup_api) {
488 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
489 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
490 FILE_FLAG_OPEN_REPARSE_POINT;
491 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
493 dwaccess = GENERIC_READ;
495 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
498 if (p_CreateFileW && p_MultiByteToWideChar) {
499 // unicode open for open existing read
500 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
501 dwaccess, /* Requested access */
502 dwshare, /* Share modes */
503 NULL, /* SecurityAttributes */
504 OPEN_EXISTING, /* CreationDisposition */
505 dwflags, /* Flags and attributes */
506 NULL); /* TemplateFile */
509 bfd->fh = p_CreateFileA(win32_fname,
510 dwaccess, /* Requested access */
511 dwshare, /* Share modes */
512 NULL, /* SecurityAttributes */
513 OPEN_EXISTING, /* CreationDisposition */
514 dwflags, /* Flags and attributes */
515 NULL); /* TemplateFile */
521 if (bfd->fh == INVALID_HANDLE_VALUE) {
522 bfd->lerror = GetLastError();
523 bfd->berrno = b_errno_win32;
524 errno = b_errno_win32;
525 bfd->mode = BF_CLOSED;
528 bfd->lpContext = NULL;
529 bfd->win32DecompContext.bIsInData = false;
530 bfd->win32DecompContext.liNextHeader = 0;
531 free_pool_memory(win32_fname_wchar);
532 free_pool_memory(win32_fname);
533 return bfd->mode == BF_CLOSED ? -1 : 1;
537 * Returns 0 on success
540 int bclose(BFILE *bfd)
545 free_pool_memory(bfd->errmsg);
548 if (bfd->mode == BF_CLOSED) {
551 if (bfd->use_backup_api && bfd->mode == BF_READ) {
553 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
555 (DWORD)0, /* bytes to read */
556 &bfd->rw_bytes, /* bytes read */
558 1, /* ProcessSecurity */
559 &bfd->lpContext)) { /* Read context */
560 errno = b_errno_win32;
563 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
565 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
567 (DWORD)0, /* bytes to read */
568 &bfd->rw_bytes, /* bytes written */
570 1, /* ProcessSecurity */
571 &bfd->lpContext)) { /* Write context */
572 errno = b_errno_win32;
576 if (!CloseHandle(bfd->fh)) {
578 errno = b_errno_win32;
580 bfd->mode = BF_CLOSED;
581 bfd->lpContext = NULL;
582 bfd->cmd_plugin = false;
586 /* Returns: bytes read on success
590 ssize_t bread(BFILE *bfd, void *buf, size_t count)
594 if (bfd->use_backup_api) {
595 if (!p_BackupRead(bfd->fh,
600 1, /* Process Security */
601 &bfd->lpContext)) { /* Context */
602 bfd->lerror = GetLastError();
603 bfd->berrno = b_errno_win32;
604 errno = b_errno_win32;
608 if (!ReadFile(bfd->fh,
613 bfd->lerror = GetLastError();
614 bfd->berrno = b_errno_win32;
615 errno = b_errno_win32;
620 return (ssize_t)bfd->rw_bytes;
623 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
627 if (bfd->use_backup_api) {
628 if (!p_BackupWrite(bfd->fh,
633 1, /* Process Security */
634 &bfd->lpContext)) { /* Context */
635 bfd->lerror = GetLastError();
636 bfd->berrno = b_errno_win32;
637 errno = b_errno_win32;
641 if (!WriteFile(bfd->fh,
646 bfd->lerror = GetLastError();
647 bfd->berrno = b_errno_win32;
648 errno = b_errno_win32;
652 return (ssize_t)bfd->rw_bytes;
655 bool is_bopen(BFILE *bfd)
657 return bfd->mode != BF_CLOSED;
660 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
662 LONG offset_low = (LONG)offset;
663 LONG offset_high = (LONG)(offset >> 32);
666 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
668 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
669 return (boffset_t)-1;
672 return ((boffset_t)offset_high << 32) | dwResult;
675 #else /* Unix systems */
677 /* ===============================================================
681 * ===============================================================
683 void binit(BFILE *bfd)
685 memset(bfd, 0, sizeof(BFILE));
689 bool have_win32_api()
691 return false; /* no can do */
695 * Enables using the Backup API (win32_data).
696 * Returns true if function worked
697 * Returns false if failed (i.e. do not have Backup API on this machine)
699 bool set_win32_backup(BFILE *bfd)
701 return false; /* no can do */
705 bool set_portable_backup(BFILE *bfd)
707 return true; /* no problem */
711 * Return true if we are writing in portable format
712 * return false if not
714 bool is_portable_backup(BFILE *bfd)
716 return true; /* portable by definition */
719 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
724 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
726 bfd->cmd_plugin = true;
732 * This code is running on a non-Win32 machine
734 bool is_restore_stream_supported(int stream)
736 /* No Win32 backup on this machine */
739 case STREAM_GZIP_DATA:
740 case STREAM_SPARSE_GZIP_DATA:
741 case STREAM_WIN32_GZIP_DATA:
743 #ifndef HAVE_DARWIN_OS
744 case STREAM_MACOS_FORK_DATA:
745 case STREAM_HFSPLUS_ATTRIBUTES:
751 case STREAM_GZIP_DATA:
752 case STREAM_SPARSE_GZIP_DATA:
753 case STREAM_WIN32_GZIP_DATA:
755 case STREAM_WIN32_DATA:
756 case STREAM_UNIX_ATTRIBUTES:
757 case STREAM_FILE_DATA:
758 case STREAM_MD5_DIGEST:
759 case STREAM_UNIX_ATTRIBUTES_EX:
760 case STREAM_SPARSE_DATA:
761 case STREAM_PROGRAM_NAMES:
762 case STREAM_PROGRAM_DATA:
763 case STREAM_SHA1_DIGEST:
765 case STREAM_SHA256_DIGEST:
766 case STREAM_SHA512_DIGEST:
769 case STREAM_SIGNED_DIGEST:
770 case STREAM_ENCRYPTED_FILE_DATA:
771 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
772 case STREAM_ENCRYPTED_WIN32_DATA:
773 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
775 #ifdef HAVE_DARWIN_OS
776 case STREAM_MACOS_FORK_DATA:
777 case STREAM_HFSPLUS_ATTRIBUTES:
779 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
780 #endif /* HAVE_CRYPTO */
781 #endif /* HAVE_DARWIN_OS */
782 case 0: /* compatibility with old tapes */
789 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
791 if (bfd->cmd_plugin && plugin_bopen) {
792 return plugin_bopen(bfd->jcr, fname, flags, mode);
795 /* Normal file open */
796 Dmsg1(400, "open file %s\n", fname);
797 /* We use fnctl to set O_NOATIME if requested to avoid open error */
798 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
799 /* Set O_NOATIME if possible */
800 if (bfd->fid != -1 && flags & O_NOATIME) {
801 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
802 if (oldflags == -1) {
807 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
808 /* EPERM means setting O_NOATIME was not allowed */
809 if (ret == -1 && errno != EPERM) {
817 bfd->m_flags = flags;
818 Dmsg1(400, "Open file %d\n", bfd->fid);
821 bfd->win32DecompContext.bIsInData = false;
822 bfd->win32DecompContext.liNextHeader = 0;
824 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
825 if (bfd->fid != -1 && flags & O_RDONLY) {
826 int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
827 Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
834 #ifdef HAVE_DARWIN_OS
835 /* Open the resource fork of a file. */
836 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
840 rsrc_fname = get_pool_memory(PM_FNAME);
841 pm_strcpy(rsrc_fname, fname);
842 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
843 bopen(bfd, rsrc_fname, flags, mode);
844 free_pool_memory(rsrc_fname);
850 int bclose(BFILE *bfd)
854 Dmsg1(400, "Close file %d\n", bfd->fid);
856 if (bfd->cmd_plugin && plugin_bclose) {
857 return plugin_bclose(bfd->jcr);
860 if (bfd->fid == -1) {
863 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
864 if (bfd->m_flags & O_RDONLY) {
865 fdatasync(bfd->fid); /* sync the file */
866 /* Tell OS we don't need it any more */
867 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
871 /* Close normal file */
872 stat = close(bfd->fid);
875 bfd->cmd_plugin = false;
879 ssize_t bread(BFILE *bfd, void *buf, size_t count)
883 if (bfd->cmd_plugin && plugin_bread) {
884 return plugin_bread(bfd->jcr, buf, count);
887 stat = read(bfd->fid, buf, count);
892 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
896 if (bfd->cmd_plugin && plugin_bwrite) {
897 return plugin_bwrite(bfd->jcr, buf, count);
899 stat = write(bfd->fid, buf, count);
904 bool is_bopen(BFILE *bfd)
906 return bfd->fid >= 0;
909 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
912 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);