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 void pause_msg(const char *file, const char *func, int line, const char *msg)
62 bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
64 bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
66 MessageBox(NULL, buf, "Pause", MB_OK);
70 /* ===============================================================
72 * U N I X AND W I N D O W S
74 * ===============================================================
77 bool is_win32_stream(int stream)
80 case STREAM_WIN32_DATA:
81 case STREAM_WIN32_GZIP_DATA:
82 case STREAM_ENCRYPTED_WIN32_DATA:
83 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
89 const char *stream_to_ascii(int stream)
94 case STREAM_UNIX_ATTRIBUTES:
95 return _("Unix attributes");
96 case STREAM_FILE_DATA:
97 return _("File data");
98 case STREAM_MD5_DIGEST:
99 return _("MD5 digest");
100 case STREAM_GZIP_DATA:
101 return _("GZIP data");
102 case STREAM_UNIX_ATTRIBUTES_EX:
103 return _("Extended attributes");
104 case STREAM_SPARSE_DATA:
105 return _("Sparse data");
106 case STREAM_SPARSE_GZIP_DATA:
107 return _("GZIP sparse data");
108 case STREAM_PROGRAM_NAMES:
109 return _("Program names");
110 case STREAM_PROGRAM_DATA:
111 return _("Program data");
112 case STREAM_SHA1_DIGEST:
113 return _("SHA1 digest");
114 case STREAM_WIN32_DATA:
115 return _("Win32 data");
116 case STREAM_WIN32_GZIP_DATA:
117 return _("Win32 GZIP data");
118 case STREAM_MACOS_FORK_DATA:
119 return _("MacOS Fork data");
120 case STREAM_HFSPLUS_ATTRIBUTES:
121 return _("HFS+ attribs");
122 case STREAM_UNIX_ACCESS_ACL:
123 return _("Standard Unix ACL attribs");
124 case STREAM_UNIX_DEFAULT_ACL:
125 return _("Default Unix ACL attribs");
126 case STREAM_SHA256_DIGEST:
127 return _("SHA256 digest");
128 case STREAM_SHA512_DIGEST:
129 return _("SHA512 digest");
130 case STREAM_SIGNED_DIGEST:
131 return _("Signed digest");
132 case STREAM_ENCRYPTED_FILE_DATA:
133 return _("Encrypted File data");
134 case STREAM_ENCRYPTED_WIN32_DATA:
135 return _("Encrypted Win32 data");
136 case STREAM_ENCRYPTED_SESSION_DATA:
137 return _("Encrypted session data");
138 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
139 return _("Encrypted GZIP data");
140 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
141 return _("Encrypted Win32 GZIP data");
142 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
143 return _("Encrypted MacOS fork data");
145 sprintf(buf, "%d", stream);
146 return (const char *)buf;
151 void int64_LE2BE(int64_t* pBE, const int64_t v)
153 /* convert little endian to big endian */
154 if (htonl(1) != 1L) { /* no work if on little endian machine */
155 memcpy(pBE, &v, sizeof(int64_t));
158 uint8_t rv[sizeof(int64_t)];
159 uint8_t *pv = (uint8_t *) &v;
161 for (i = 0; i < 8; i++) {
164 memcpy(pBE, &rv, sizeof(int64_t));
169 void int32_LE2BE(int32_t* pBE, const int32_t v)
171 /* convert little endian to big endian */
172 if (htonl(1) != 1L) { /* no work if on little endian machine */
173 memcpy(pBE, &v, sizeof(int32_t));
176 uint8_t rv[sizeof(int32_t)];
177 uint8_t *pv = (uint8_t *) &v;
179 for (i = 0; i < 4; i++) {
182 memcpy(pBE, &rv, sizeof(int32_t));
187 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
189 /* pByte contains the buffer
190 dwSize the len to be processed. function assumes to be
191 called in successive incremental order over the complete
192 BackupRead stream beginning at pos 0 and ending at the end.
195 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
196 bool bContinue = false;
197 int64_t dwDataOffset = 0;
200 /* Win32 Stream Header size without name of stream.
201 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
203 int32_t dwSizeHeader = 20;
206 if (pContext->liNextHeader >= dwSize) {
207 dwDataLen = dwSize-dwDataOffset;
208 bContinue = false; /* 1 iteration is enough */
210 dwDataLen = pContext->liNextHeader-dwDataOffset;
211 bContinue = true; /* multiple iterations may be necessary */
215 /* copy block of real DATA */
216 if (pContext->bIsInData) {
217 if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
221 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
222 int32_t dwOffsetTarget;
223 int32_t dwOffsetSource;
225 if (pContext->liNextHeader < 0) {
226 /* start of header was before this block, so we
227 * continue with the part in the current block
229 dwOffsetTarget = -pContext->liNextHeader;
232 /* start of header is inside of this block */
234 dwOffsetSource = pContext->liNextHeader;
237 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
238 bool bHeaderIsComplete;
240 if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
241 /* header (or rest of header) is completely available
244 bHeaderIsComplete = true;
246 /* header will continue in next block */
247 bHeaderIsComplete = false;
248 dwHeaderPartLen = dwSize-dwOffsetSource;
251 /* copy the available portion of header to persistent copy */
252 memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
254 /* recalculate position of next header */
255 if (bHeaderIsComplete) {
256 /* convert stream name size (32 bit little endian) to machine type */
258 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
259 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
261 /* convert stream size (64 bit little endian) to machine type */
262 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
263 pContext->liNextHeader += dwDataOffset;
265 pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
266 if (dwDataOffset == dwSize)
269 /* stop and continue with next block */
271 pContext->bIsInData = false;
276 /* set "NextHeader" relative to the beginning of the next block */
277 pContext->liNextHeader-= dwSize;
284 /* ===============================================================
288 * ===============================================================
291 #if defined(HAVE_WIN32)
293 void unix_name_to_win32(POOLMEM **win32_name, char *name);
294 extern "C" HANDLE get_osfhandle(int fd);
297 void binit(BFILE *bfd)
299 memset(bfd, 0, sizeof(BFILE));
301 bfd->mode = BF_CLOSED;
302 bfd->use_backup_api = have_win32_api();
303 bfd->cmd_plugin = false;
307 * Enables using the Backup API (win32_data).
308 * Returns 1 if function worked
309 * Returns 0 if failed (i.e. do not have Backup API on this machine)
311 bool set_win32_backup(BFILE *bfd)
313 /* We enable if possible here */
314 bfd->use_backup_api = have_win32_api();
315 return bfd->use_backup_api;
319 bool set_portable_backup(BFILE *bfd)
321 bfd->use_backup_api = false;
325 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
327 bfd->cmd_plugin = true;
333 * Return 1 if we are NOT using Win32 BackupWrite()
336 bool is_portable_backup(BFILE *bfd)
338 return !bfd->use_backup_api;
341 bool have_win32_api()
343 return p_BackupRead && p_BackupWrite;
348 * Return true if we support the stream
349 * false if we do not support the stream
351 * This code is running under Win32, so we
352 * do not need #ifdef on MACOS ...
354 bool is_restore_stream_supported(int stream)
358 /* Streams known not to be supported */
360 case STREAM_GZIP_DATA:
361 case STREAM_SPARSE_GZIP_DATA:
362 case STREAM_WIN32_GZIP_DATA:
364 case STREAM_MACOS_FORK_DATA:
365 case STREAM_HFSPLUS_ATTRIBUTES:
366 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
371 case STREAM_GZIP_DATA:
372 case STREAM_SPARSE_GZIP_DATA:
373 case STREAM_WIN32_GZIP_DATA:
375 case STREAM_WIN32_DATA:
376 case STREAM_UNIX_ATTRIBUTES:
377 case STREAM_FILE_DATA:
378 case STREAM_MD5_DIGEST:
379 case STREAM_UNIX_ATTRIBUTES_EX:
380 case STREAM_SPARSE_DATA:
381 case STREAM_PROGRAM_NAMES:
382 case STREAM_PROGRAM_DATA:
383 case STREAM_SHA1_DIGEST:
385 case STREAM_SHA256_DIGEST:
386 case STREAM_SHA512_DIGEST:
389 case STREAM_SIGNED_DIGEST:
390 case STREAM_ENCRYPTED_FILE_DATA:
391 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
392 case STREAM_ENCRYPTED_WIN32_DATA:
393 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
395 case 0: /* compatibility with old tapes */
401 HANDLE bget_handle(BFILE *bfd)
406 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
408 POOLMEM *win32_fname;
409 POOLMEM *win32_fname_wchar;
411 DWORD dwaccess, dwflags, dwshare;
413 /* Convert to Windows path format */
414 win32_fname = get_pool_memory(PM_FNAME);
415 win32_fname_wchar = get_pool_memory(PM_FNAME);
417 unix_name_to_win32(&win32_fname, (char *)fname);
419 if (bfd->cmd_plugin && plugin_bopen) {
421 Dmsg1(000, "call plugin_bopen fname=%s\n", fname);
422 rtnstat = plugin_bopen(bfd->jcr, fname, flags, mode);
423 free_pool_memory(win32_fname_wchar);
424 free_pool_memory(win32_fname);
428 if (!(p_CreateFileA || p_CreateFileW))
431 if (p_CreateFileW && p_MultiByteToWideChar)
432 make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
434 if (flags & O_CREAT) { /* Create */
435 if (bfd->use_backup_api) {
436 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
437 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
439 dwaccess = GENERIC_WRITE;
443 if (p_CreateFileW && p_MultiByteToWideChar) {
444 // unicode open for create write
445 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
446 dwaccess, /* Requested access */
448 NULL, /* SecurityAttributes */
449 CREATE_ALWAYS, /* CreationDisposition */
450 dwflags, /* Flags and attributes */
451 NULL); /* TemplateFile */
454 bfd->fh = p_CreateFileA(win32_fname,
455 dwaccess, /* Requested access */
457 NULL, /* SecurityAttributes */
458 CREATE_ALWAYS, /* CreationDisposition */
459 dwflags, /* Flags and attributes */
460 NULL); /* TemplateFile */
463 bfd->mode = BF_WRITE;
465 } else if (flags & O_WRONLY) { /* Open existing for write */
466 if (bfd->use_backup_api) {
467 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
468 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
470 dwaccess = GENERIC_WRITE;
474 if (p_CreateFileW && p_MultiByteToWideChar) {
475 // unicode open for open existing write
476 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
477 dwaccess, /* Requested access */
479 NULL, /* SecurityAttributes */
480 OPEN_EXISTING, /* CreationDisposition */
481 dwflags, /* Flags and attributes */
482 NULL); /* TemplateFile */
485 bfd->fh = p_CreateFileA(win32_fname,
486 dwaccess, /* Requested access */
488 NULL, /* SecurityAttributes */
489 OPEN_EXISTING, /* CreationDisposition */
490 dwflags, /* Flags and attributes */
491 NULL); /* TemplateFile */
495 bfd->mode = BF_WRITE;
498 if (bfd->use_backup_api) {
499 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
500 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
501 FILE_FLAG_OPEN_REPARSE_POINT;
502 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
504 dwaccess = GENERIC_READ;
506 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
509 if (p_CreateFileW && p_MultiByteToWideChar) {
510 // unicode open for open existing read
511 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
512 dwaccess, /* Requested access */
513 dwshare, /* Share modes */
514 NULL, /* SecurityAttributes */
515 OPEN_EXISTING, /* CreationDisposition */
516 dwflags, /* Flags and attributes */
517 NULL); /* TemplateFile */
520 bfd->fh = p_CreateFileA(win32_fname,
521 dwaccess, /* Requested access */
522 dwshare, /* Share modes */
523 NULL, /* SecurityAttributes */
524 OPEN_EXISTING, /* CreationDisposition */
525 dwflags, /* Flags and attributes */
526 NULL); /* TemplateFile */
532 if (bfd->fh == INVALID_HANDLE_VALUE) {
533 bfd->lerror = GetLastError();
534 bfd->berrno = b_errno_win32;
535 errno = b_errno_win32;
536 bfd->mode = BF_CLOSED;
539 bfd->lpContext = NULL;
540 bfd->win32DecompContext.bIsInData = false;
541 bfd->win32DecompContext.liNextHeader = 0;
542 free_pool_memory(win32_fname_wchar);
543 free_pool_memory(win32_fname);
544 return bfd->mode == BF_CLOSED ? -1 : 1;
548 * Returns 0 on success
551 int bclose(BFILE *bfd)
556 free_pool_memory(bfd->errmsg);
559 if (bfd->mode == BF_CLOSED) {
563 if (bfd->cmd_plugin && plugin_bclose) {
564 stat = plugin_bclose(bfd->jcr);
569 * We need to tell the API to release the buffer it
570 * allocated in lpContext. We do so by calling the
571 * API one more time, but with the Abort bit set.
573 if (bfd->use_backup_api && bfd->mode == BF_READ) {
575 if (bfd->lpContext && !p_BackupRead(bfd->fh,
577 (DWORD)0, /* bytes to read */
578 &bfd->rw_bytes, /* bytes read */
580 1, /* ProcessSecurity */
581 &bfd->lpContext)) { /* Read context */
582 errno = b_errno_win32;
585 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
587 if (bfd->lpContext && !p_BackupWrite(bfd->fh,
589 (DWORD)0, /* bytes to read */
590 &bfd->rw_bytes, /* bytes written */
592 1, /* ProcessSecurity */
593 &bfd->lpContext)) { /* Write context */
594 errno = b_errno_win32;
598 if (!CloseHandle(bfd->fh)) {
600 errno = b_errno_win32;
604 bfd->mode = BF_CLOSED;
605 bfd->lpContext = NULL;
606 bfd->cmd_plugin = false;
610 /* Returns: bytes read on success
614 ssize_t bread(BFILE *bfd, void *buf, size_t count)
618 if (bfd->cmd_plugin && plugin_bread) {
619 return plugin_bread(bfd->jcr, buf, count);
622 if (bfd->use_backup_api) {
623 if (!p_BackupRead(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 (!ReadFile(bfd->fh,
641 bfd->lerror = GetLastError();
642 bfd->berrno = b_errno_win32;
643 errno = b_errno_win32;
648 return (ssize_t)bfd->rw_bytes;
651 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
655 if (bfd->cmd_plugin && plugin_bwrite) {
656 return plugin_bwrite(bfd->jcr, buf, count);
659 if (bfd->use_backup_api) {
660 if (!p_BackupWrite(bfd->fh,
665 1, /* Process Security */
666 &bfd->lpContext)) { /* Context */
667 bfd->lerror = GetLastError();
668 bfd->berrno = b_errno_win32;
669 errno = b_errno_win32;
673 if (!WriteFile(bfd->fh,
678 bfd->lerror = GetLastError();
679 bfd->berrno = b_errno_win32;
680 errno = b_errno_win32;
684 return (ssize_t)bfd->rw_bytes;
687 bool is_bopen(BFILE *bfd)
689 return bfd->mode != BF_CLOSED;
692 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
694 LONG offset_low = (LONG)offset;
695 LONG offset_high = (LONG)(offset >> 32);
698 if (bfd->cmd_plugin && plugin_bwrite) {
699 return plugin_blseek(bfd->jcr, offset, whence);
702 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
704 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
705 return (boffset_t)-1;
708 return ((boffset_t)offset_high << 32) | dwResult;
711 #else /* Unix systems */
713 /* ===============================================================
717 * ===============================================================
719 void binit(BFILE *bfd)
721 memset(bfd, 0, sizeof(BFILE));
725 bool have_win32_api()
727 return false; /* no can do */
731 * Enables using the Backup API (win32_data).
732 * Returns true if function worked
733 * Returns false if failed (i.e. do not have Backup API on this machine)
735 bool set_win32_backup(BFILE *bfd)
737 return false; /* no can do */
741 bool set_portable_backup(BFILE *bfd)
743 return true; /* no problem */
747 * Return true if we are writing in portable format
748 * return false if not
750 bool is_portable_backup(BFILE *bfd)
752 return true; /* portable by definition */
755 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
760 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
762 bfd->cmd_plugin = true;
768 * This code is running on a non-Win32 machine
770 bool is_restore_stream_supported(int stream)
772 /* No Win32 backup on this machine */
775 case STREAM_GZIP_DATA:
776 case STREAM_SPARSE_GZIP_DATA:
777 case STREAM_WIN32_GZIP_DATA:
779 #ifndef HAVE_DARWIN_OS
780 case STREAM_MACOS_FORK_DATA:
781 case STREAM_HFSPLUS_ATTRIBUTES:
787 case STREAM_GZIP_DATA:
788 case STREAM_SPARSE_GZIP_DATA:
789 case STREAM_WIN32_GZIP_DATA:
791 case STREAM_WIN32_DATA:
792 case STREAM_UNIX_ATTRIBUTES:
793 case STREAM_FILE_DATA:
794 case STREAM_MD5_DIGEST:
795 case STREAM_UNIX_ATTRIBUTES_EX:
796 case STREAM_SPARSE_DATA:
797 case STREAM_PROGRAM_NAMES:
798 case STREAM_PROGRAM_DATA:
799 case STREAM_SHA1_DIGEST:
801 case STREAM_SHA256_DIGEST:
802 case STREAM_SHA512_DIGEST:
805 case STREAM_SIGNED_DIGEST:
806 case STREAM_ENCRYPTED_FILE_DATA:
807 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
808 case STREAM_ENCRYPTED_WIN32_DATA:
809 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
811 #ifdef HAVE_DARWIN_OS
812 case STREAM_MACOS_FORK_DATA:
813 case STREAM_HFSPLUS_ATTRIBUTES:
815 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
816 #endif /* HAVE_CRYPTO */
817 #endif /* HAVE_DARWIN_OS */
818 case 0: /* compatibility with old tapes */
825 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
827 if (bfd->cmd_plugin && plugin_bopen) {
828 Dmsg1(000, "call plugin_bopen fname=%s\n", fname);
829 return plugin_bopen(bfd->jcr, fname, flags, mode);
832 /* Normal file open */
833 Dmsg1(100, "open file %s\n", fname);
835 /* We use fnctl to set O_NOATIME if requested to avoid open error */
836 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
838 /* Set O_NOATIME if possible */
839 if (bfd->fid != -1 && flags & O_NOATIME) {
840 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
841 if (oldflags == -1) {
846 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
847 /* EPERM means setting O_NOATIME was not allowed */
848 if (ret == -1 && errno != EPERM) {
856 bfd->m_flags = flags;
857 Dmsg1(400, "Open file %d\n", bfd->fid);
860 bfd->win32DecompContext.bIsInData = false;
861 bfd->win32DecompContext.liNextHeader = 0;
863 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
864 if (bfd->fid != -1 && flags & O_RDONLY) {
865 int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
866 Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
873 #ifdef HAVE_DARWIN_OS
874 /* Open the resource fork of a file. */
875 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
879 rsrc_fname = get_pool_memory(PM_FNAME);
880 pm_strcpy(rsrc_fname, fname);
881 pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
882 bopen(bfd, rsrc_fname, flags, mode);
883 free_pool_memory(rsrc_fname);
889 int bclose(BFILE *bfd)
893 Dmsg1(400, "Close file %d\n", bfd->fid);
895 if (bfd->cmd_plugin && plugin_bclose) {
896 stat = plugin_bclose(bfd->jcr);
898 bfd->cmd_plugin = false;
901 if (bfd->fid == -1) {
904 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
905 if (bfd->m_flags & O_RDONLY) {
906 fdatasync(bfd->fid); /* sync the file */
907 /* Tell OS we don't need it any more */
908 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
912 /* Close normal file */
913 stat = close(bfd->fid);
916 bfd->cmd_plugin = false;
920 ssize_t bread(BFILE *bfd, void *buf, size_t count)
924 if (bfd->cmd_plugin && plugin_bread) {
925 return plugin_bread(bfd->jcr, buf, count);
928 stat = read(bfd->fid, buf, count);
933 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
937 if (bfd->cmd_plugin && plugin_bwrite) {
938 return plugin_bwrite(bfd->jcr, buf, count);
940 stat = write(bfd->fid, buf, count);
945 bool is_bopen(BFILE *bfd)
947 return bfd->fid >= 0;
950 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
954 if (bfd->cmd_plugin && plugin_bwrite) {
955 return plugin_blseek(bfd->jcr, offset, whence);
957 pos = (boffset_t)lseek(bfd->fid, (off_t)offset, whence);