]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/bfile.c
f7a65f0b2b007cb83ca00a13899f731efacd7025
[bacula/bacula] / bacula / src / findlib / bfile.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2008 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
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.
27 */
28 /*
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.
32  *
33  *    Kern Sibbald, April MMIII
34  *
35  *   Version $Id$
36  *
37  */
38
39 #include "bacula.h"
40 #include "find.h"
41
42 const int dbglvl = 200;
43
44 int       (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL;
45 int       (*plugin_bclose)(BFILE *bfd) = NULL;
46 ssize_t   (*plugin_bread)(BFILE *bfd, void *buf, size_t count) = NULL;
47 ssize_t   (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count) = NULL;
48 boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence) = NULL;
49
50
51 #ifdef HAVE_DARWIN_OS
52 #include <sys/paths.h>
53 #endif
54
55 #if !defined(HAVE_FDATASYNC)
56 #define fdatasync(fd)
57 #endif
58
59 #ifdef HAVE_WIN32
60 void pause_msg(const char *file, const char *func, int line, const char *msg)
61 {
62    char buf[1000];
63    if (msg) {
64       bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
65    } else {
66       bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
67    }
68    MessageBox(NULL, buf, "Pause", MB_OK);
69 }
70 #endif
71
72 /* ===============================================================
73  *
74  *            U N I X   AND   W I N D O W S
75  *
76  * ===============================================================
77  */
78
79 bool is_win32_stream(int stream)
80 {
81    switch (stream) {
82    case STREAM_WIN32_DATA:
83    case STREAM_WIN32_GZIP_DATA:
84    case STREAM_ENCRYPTED_WIN32_DATA:
85    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
86       return true;
87    }
88    return false;
89 }
90
91 const char *stream_to_ascii(int stream)
92 {
93    static char buf[20];
94
95    switch (stream) {
96    case STREAM_UNIX_ATTRIBUTES:
97       return _("Unix attributes");
98    case STREAM_FILE_DATA:
99       return _("File data");
100    case STREAM_MD5_DIGEST:
101       return _("MD5 digest");
102    case STREAM_GZIP_DATA:
103       return _("GZIP data");
104    case STREAM_UNIX_ATTRIBUTES_EX:
105       return _("Extended attributes");
106    case STREAM_SPARSE_DATA:
107       return _("Sparse data");
108    case STREAM_SPARSE_GZIP_DATA:
109       return _("GZIP sparse data");
110    case STREAM_PROGRAM_NAMES:
111       return _("Program names");
112    case STREAM_PROGRAM_DATA:
113       return _("Program data");
114    case STREAM_SHA1_DIGEST:
115       return _("SHA1 digest");
116    case STREAM_WIN32_DATA:
117       return _("Win32 data");
118    case STREAM_WIN32_GZIP_DATA:
119       return _("Win32 GZIP data");
120    case STREAM_MACOS_FORK_DATA:
121       return _("MacOS Fork data");
122    case STREAM_HFSPLUS_ATTRIBUTES:
123       return _("HFS+ attribs");
124    case STREAM_UNIX_ACCESS_ACL:
125       return _("Standard Unix ACL attribs");
126    case STREAM_UNIX_DEFAULT_ACL:
127       return _("Default Unix ACL attribs");
128    case STREAM_SHA256_DIGEST:
129       return _("SHA256 digest");
130    case STREAM_SHA512_DIGEST:
131       return _("SHA512 digest");
132    case STREAM_SIGNED_DIGEST:
133       return _("Signed digest");
134    case STREAM_ENCRYPTED_FILE_DATA:
135       return _("Encrypted File data");
136    case STREAM_ENCRYPTED_WIN32_DATA:
137       return _("Encrypted Win32 data");
138    case STREAM_ENCRYPTED_SESSION_DATA:
139       return _("Encrypted session data");
140    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
141       return _("Encrypted GZIP data");
142    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
143       return _("Encrypted Win32 GZIP data");
144    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
145       return _("Encrypted MacOS fork data");
146    case STREAM_ACL_AIX_TEXT:
147       return _("AIX Specific ACL attribs");
148    case STREAM_ACL_DARWIN_ACCESS_ACL:
149       return _("Darwin Specific ACL attribs");
150    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
151       return _("FreeBSD Specific Default ACL attribs");
152    case STREAM_ACL_FREEBSD_ACCESS_ACL:
153       return _("FreeBSD Specific Access ACL attribs");
154    case STREAM_ACL_HPUX_ACL_ENTRY:
155       return _("HPUX Specific ACL attribs");
156    case STREAM_ACL_IRIX_DEFAULT_ACL:
157       return _("Irix Specific Default ACL attribs");
158    case STREAM_ACL_IRIX_ACCESS_ACL:
159       return _("Irix Specific Access ACL attribs");
160    case STREAM_ACL_LINUX_DEFAULT_ACL:
161       return _("Linux Specific Default ACL attribs");
162    case STREAM_ACL_LINUX_ACCESS_ACL:
163       return _("Linux Specific Access ACL attribs");
164    case STREAM_ACL_TRU64_DEFAULT_ACL:
165       return _("OSF1 Specific Default ACL attribs");
166    case STREAM_ACL_TRU64_ACCESS_ACL:
167       return _("OSF1 Specific Access ACL attribs");
168    case STREAM_ACL_SOLARIS_ACLENT:
169       return _("Solaris Specific ACL attribs");
170    case STREAM_ACL_SOLARIS_ACE:
171       return _("Solaris Specific ACL attribs");
172    case STREAM_XATTR_DARWIN:
173       return _("Darwin Specific Extended attribs");
174    case STREAM_XATTR_FREEBSD:
175       return _("FreeBSD Specific Extended attribs");
176    case STREAM_XATTR_LINUX:
177       return _("Linux Specific Extended attribs");
178    case STREAM_XATTR_NETBSD:
179       return _("NetBSD Specific Extended attribs");
180    default:
181       sprintf(buf, "%d", stream);
182       return (const char *)buf;
183    }
184 }
185
186    
187 void int64_LE2BE(int64_t* pBE, const int64_t v)
188 {
189    /* convert little endian to big endian */
190    if (htonl(1) != 1L) { /* no work if on little endian machine */
191       memcpy(pBE, &v, sizeof(int64_t));
192    } else {
193       int i;
194       uint8_t rv[sizeof(int64_t)];
195       uint8_t *pv = (uint8_t *) &v;
196
197       for (i = 0; i < 8; i++) {
198          rv[i] = pv[7 - i];
199       }
200       memcpy(pBE, &rv, sizeof(int64_t));
201    }    
202 }
203
204
205 void int32_LE2BE(int32_t* pBE, const int32_t v)
206 {
207    /* convert little endian to big endian */
208    if (htonl(1) != 1L) { /* no work if on little endian machine */
209       memcpy(pBE, &v, sizeof(int32_t));
210    } else {
211       int i;
212       uint8_t rv[sizeof(int32_t)];
213       uint8_t *pv = (uint8_t *) &v;
214
215       for (i = 0; i < 4; i++) {
216          rv[i] = pv[3 - i];
217       }
218       memcpy(pBE, &rv, sizeof(int32_t));
219    }    
220 }
221
222
223 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
224 {
225    /* pByte contains the buffer 
226       dwSize the len to be processed.  function assumes to be
227       called in successive incremental order over the complete
228       BackupRead stream beginning at pos 0 and ending at the end.
229     */
230
231    PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
232    bool bContinue = false;
233    int64_t dwDataOffset = 0;
234    int64_t dwDataLen;
235
236    /* Win32 Stream Header size without name of stream.
237     * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*); 
238     */
239    int32_t dwSizeHeader = 20; 
240
241    do {
242       if (pContext->liNextHeader >= dwSize) {
243          dwDataLen = dwSize-dwDataOffset;
244          bContinue = false; /* 1 iteration is enough */
245       } else {
246          dwDataLen = pContext->liNextHeader-dwDataOffset;
247          bContinue = true; /* multiple iterations may be necessary */
248       }
249
250       /* flush */
251       /* copy block of real DATA */
252       if (pContext->bIsInData) {
253          if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
254             return false;
255       }
256
257       if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
258          int32_t dwOffsetTarget;
259          int32_t dwOffsetSource;
260
261          if (pContext->liNextHeader < 0) {
262             /* start of header was before this block, so we
263              * continue with the part in the current block 
264              */
265             dwOffsetTarget = -pContext->liNextHeader;
266             dwOffsetSource = 0;
267          } else {
268             /* start of header is inside of this block */
269             dwOffsetTarget = 0;
270             dwOffsetSource = pContext->liNextHeader;
271          }
272
273          int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
274          bool bHeaderIsComplete;
275
276          if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
277             /* header (or rest of header) is completely available
278                in current block 
279              */
280             bHeaderIsComplete = true;
281          } else {
282             /* header will continue in next block */
283             bHeaderIsComplete = false;
284             dwHeaderPartLen = dwSize-dwOffsetSource;
285          }
286
287          /* copy the available portion of header to persistent copy */
288          memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
289
290          /* recalculate position of next header */
291          if (bHeaderIsComplete) {
292             /* convert stream name size (32 bit little endian) to machine type */
293             int32_t dwNameSize; 
294             int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
295             dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
296
297             /* convert stream size (64 bit little endian) to machine type */
298             int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
299             pContext->liNextHeader += dwDataOffset;
300
301             pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
302             if (dwDataOffset == dwSize)
303                bContinue = false;
304          } else {
305             /* stop and continue with next block */
306             bContinue = false;
307             pContext->bIsInData = false;
308          }
309       }
310    } while (bContinue);
311
312    /* set "NextHeader" relative to the beginning of the next block */
313    pContext->liNextHeader-= dwSize;
314
315    return TRUE;
316 }
317
318
319
320 /* ===============================================================
321  *
322  *            W I N D O W S
323  *
324  * ===============================================================
325  */
326
327 #if defined(HAVE_WIN32)
328
329 void unix_name_to_win32(POOLMEM **win32_name, char *name);
330 extern "C" HANDLE get_osfhandle(int fd);
331
332
333 void binit(BFILE *bfd)
334 {
335    memset(bfd, 0, sizeof(BFILE));
336    bfd->fid = -1;
337    bfd->mode = BF_CLOSED;
338    bfd->use_backup_api = have_win32_api();
339    bfd->cmd_plugin = false;
340 }
341
342 /*
343  * Enables using the Backup API (win32_data).
344  *   Returns 1 if function worked
345  *   Returns 0 if failed (i.e. do not have Backup API on this machine)
346  */
347 bool set_win32_backup(BFILE *bfd)
348 {
349    /* We enable if possible here */
350    bfd->use_backup_api = have_win32_api();
351    return bfd->use_backup_api;
352 }
353
354
355 bool set_portable_backup(BFILE *bfd)
356 {
357    bfd->use_backup_api = false;
358    return true;
359 }
360
361 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
362 {
363    bfd->cmd_plugin = true;
364    bfd->jcr = jcr;
365    return true;
366 }
367
368 /*
369  * Return 1 if we are NOT using Win32 BackupWrite()
370  * return 0 if are
371  */
372 bool is_portable_backup(BFILE *bfd)
373 {
374    return !bfd->use_backup_api;
375 }
376
377 bool have_win32_api()
378 {
379    return p_BackupRead && p_BackupWrite;
380 }
381
382
383 /*
384  * Return true  if we support the stream
385  *        false if we do not support the stream
386  *
387  *  This code is running under Win32, so we
388  *    do not need #ifdef on MACOS ...
389  */
390 bool is_restore_stream_supported(int stream)
391 {
392    switch (stream) {
393
394 /* Streams known not to be supported */
395 #ifndef HAVE_LIBZ
396    case STREAM_GZIP_DATA:
397    case STREAM_SPARSE_GZIP_DATA:
398    case STREAM_WIN32_GZIP_DATA:
399 #endif
400    case STREAM_MACOS_FORK_DATA:
401    case STREAM_HFSPLUS_ATTRIBUTES:
402    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
403       return false;
404
405    /* Known streams */
406 #ifdef HAVE_LIBZ
407    case STREAM_GZIP_DATA:
408    case STREAM_SPARSE_GZIP_DATA:
409    case STREAM_WIN32_GZIP_DATA:
410 #endif
411    case STREAM_WIN32_DATA:
412    case STREAM_UNIX_ATTRIBUTES:
413    case STREAM_FILE_DATA:
414    case STREAM_MD5_DIGEST:
415    case STREAM_UNIX_ATTRIBUTES_EX:
416    case STREAM_SPARSE_DATA:
417    case STREAM_PROGRAM_NAMES:
418    case STREAM_PROGRAM_DATA:
419    case STREAM_SHA1_DIGEST:
420 #ifdef HAVE_SHA2
421    case STREAM_SHA256_DIGEST:
422    case STREAM_SHA512_DIGEST:
423 #endif
424 #ifdef HAVE_CRYPTO
425    case STREAM_SIGNED_DIGEST:
426    case STREAM_ENCRYPTED_FILE_DATA:
427    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
428    case STREAM_ENCRYPTED_WIN32_DATA:
429    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
430 #endif
431    case 0:                            /* compatibility with old tapes */
432       return true;
433    }
434    return false;
435 }
436
437 HANDLE bget_handle(BFILE *bfd)
438 {
439    return bfd->fh;
440 }
441
442 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
443 {
444    POOLMEM *win32_fname;
445    POOLMEM *win32_fname_wchar;
446
447    DWORD dwaccess, dwflags, dwshare;
448
449    /* Convert to Windows path format */
450    win32_fname = get_pool_memory(PM_FNAME);
451    win32_fname_wchar = get_pool_memory(PM_FNAME);
452    
453    unix_name_to_win32(&win32_fname, (char *)fname);
454
455    if (bfd->cmd_plugin && plugin_bopen) {
456       int rtnstat;
457       Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
458       rtnstat = plugin_bopen(bfd, fname, flags, mode);
459       Dmsg1(50, "return from plugin_bopen status=%d\n", rtnstat);
460       if (rtnstat >= 0) {
461          if (flags & O_CREAT || flags & O_WRONLY) {   /* Open existing for write */
462             Dmsg1(50, "plugin_open for write OK file=%s.\n", fname);
463             bfd->mode = BF_WRITE;
464          } else {
465             Dmsg1(50, "plugin_open for read OK file=%s.\n", fname);
466             bfd->mode = BF_READ;
467          }
468       } else {
469          bfd->mode = BF_CLOSED;
470          Dmsg1(000, "==== plugin_bopen returned bad status=%d\n", rtnstat);
471       }
472       free_pool_memory(win32_fname_wchar);
473       free_pool_memory(win32_fname);
474       return bfd->mode == BF_CLOSED ? -1 : 1;
475    }
476    Dmsg0(50, "=== NOT plugin\n");
477
478    if (!(p_CreateFileA || p_CreateFileW))
479       return 0;
480
481    if (p_CreateFileW && p_MultiByteToWideChar)
482       make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
483
484    if (flags & O_CREAT) {             /* Create */
485       if (bfd->use_backup_api) {
486          dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
487          dwflags = FILE_FLAG_BACKUP_SEMANTICS;
488       } else {
489          dwaccess = GENERIC_WRITE;
490          dwflags = 0;
491       }
492
493       if (p_CreateFileW && p_MultiByteToWideChar) {   
494          // unicode open for create write
495          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
496                 dwaccess,                /* Requested access */
497                 0,                       /* Shared mode */
498                 NULL,                    /* SecurityAttributes */
499                 CREATE_ALWAYS,           /* CreationDisposition */
500                 dwflags,                 /* Flags and attributes */
501                 NULL);                   /* TemplateFile */
502       } else {
503          // ascii open
504          bfd->fh = p_CreateFileA(win32_fname,
505                 dwaccess,                /* Requested access */
506                 0,                       /* Shared mode */
507                 NULL,                    /* SecurityAttributes */
508                 CREATE_ALWAYS,           /* CreationDisposition */
509                 dwflags,                 /* Flags and attributes */
510                 NULL);                   /* TemplateFile */
511       }
512
513       bfd->mode = BF_WRITE;
514
515    } else if (flags & O_WRONLY) {     /* Open existing for write */
516       if (bfd->use_backup_api) {
517          dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
518          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
519       } else {
520          dwaccess = GENERIC_WRITE;
521          dwflags = 0;
522       }
523
524       if (p_CreateFileW && p_MultiByteToWideChar) {   
525          // unicode open for open existing write
526          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
527                 dwaccess,                /* Requested access */
528                 0,                       /* Shared mode */
529                 NULL,                    /* SecurityAttributes */
530                 OPEN_EXISTING,           /* CreationDisposition */
531                 dwflags,                 /* Flags and attributes */
532                 NULL);                   /* TemplateFile */
533       } else {
534          // ascii open
535          bfd->fh = p_CreateFileA(win32_fname,
536                 dwaccess,                /* Requested access */
537                 0,                       /* Shared mode */
538                 NULL,                    /* SecurityAttributes */
539                 OPEN_EXISTING,           /* CreationDisposition */
540                 dwflags,                 /* Flags and attributes */
541                 NULL);                   /* TemplateFile */
542
543       }
544
545       bfd->mode = BF_WRITE;
546
547    } else {                           /* Read */
548       if (bfd->use_backup_api) {
549          dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
550          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
551                    FILE_FLAG_OPEN_REPARSE_POINT;
552          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
553       } else {
554          dwaccess = GENERIC_READ;
555          dwflags = 0;
556          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
557       }
558
559       if (p_CreateFileW && p_MultiByteToWideChar) {   
560          // unicode open for open existing read
561          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
562                 dwaccess,                /* Requested access */
563                 dwshare,                 /* Share modes */
564                 NULL,                    /* SecurityAttributes */
565                 OPEN_EXISTING,           /* CreationDisposition */
566                 dwflags,                 /* Flags and attributes */
567                 NULL);                   /* TemplateFile */
568       } else {
569          // ascii open 
570          bfd->fh = p_CreateFileA(win32_fname,
571                 dwaccess,                /* Requested access */
572                 dwshare,                 /* Share modes */
573                 NULL,                    /* SecurityAttributes */
574                 OPEN_EXISTING,           /* CreationDisposition */
575                 dwflags,                 /* Flags and attributes */
576                 NULL);                   /* TemplateFile */
577       }
578
579       bfd->mode = BF_READ;
580    }
581
582    if (bfd->fh == INVALID_HANDLE_VALUE) {
583       bfd->lerror = GetLastError();
584       bfd->berrno = b_errno_win32;
585       errno = b_errno_win32;
586       bfd->mode = BF_CLOSED;
587    }
588    bfd->errmsg = NULL;
589    bfd->lpContext = NULL;
590    bfd->win32DecompContext.bIsInData = false;
591    bfd->win32DecompContext.liNextHeader = 0;
592    free_pool_memory(win32_fname_wchar);
593    free_pool_memory(win32_fname);
594    return bfd->mode == BF_CLOSED ? -1 : 1;
595 }
596
597 /*
598  * Returns  0 on success
599  *         -1 on error
600  */
601 int bclose(BFILE *bfd)
602 {
603    int stat = 0;
604
605    if (bfd->errmsg) {
606       free_pool_memory(bfd->errmsg);
607       bfd->errmsg = NULL;
608    }
609    if (bfd->mode == BF_CLOSED) {
610       Dmsg0(50, "=== BFD already closed.\n");
611       return 0;
612    }
613
614    if (bfd->cmd_plugin && plugin_bclose) {
615       stat = plugin_bclose(bfd);
616       Dmsg0(50, "==== BFD closed!!!\n");
617       goto all_done;
618    }
619
620    /*
621     * We need to tell the API to release the buffer it
622     *  allocated in lpContext.  We do so by calling the
623     *  API one more time, but with the Abort bit set.
624     */
625    if (bfd->use_backup_api && bfd->mode == BF_READ) {
626       BYTE buf[10];
627       if (bfd->lpContext && !p_BackupRead(bfd->fh,
628               buf,                    /* buffer */
629               (DWORD)0,               /* bytes to read */
630               &bfd->rw_bytes,         /* bytes read */
631               1,                      /* Abort */
632               1,                      /* ProcessSecurity */
633               &bfd->lpContext)) {     /* Read context */
634          errno = b_errno_win32;
635          stat = -1;
636       }
637    } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
638       BYTE buf[10];
639       if (bfd->lpContext && !p_BackupWrite(bfd->fh,
640               buf,                    /* buffer */
641               (DWORD)0,               /* bytes to read */
642               &bfd->rw_bytes,         /* bytes written */
643               1,                      /* Abort */
644               1,                      /* ProcessSecurity */
645               &bfd->lpContext)) {     /* Write context */
646          errno = b_errno_win32;
647          stat = -1;
648       }
649    }
650    if (!CloseHandle(bfd->fh)) {
651       stat = -1;
652       errno = b_errno_win32;
653    }
654
655 all_done:
656    bfd->mode = BF_CLOSED;
657    bfd->lpContext = NULL;
658    bfd->cmd_plugin = false;
659    return stat;
660 }
661
662 /* Returns: bytes read on success
663  *           0         on EOF
664  *          -1         on error
665  */
666 ssize_t bread(BFILE *bfd, void *buf, size_t count)
667 {
668    bfd->rw_bytes = 0;
669
670    if (bfd->cmd_plugin && plugin_bread) {
671       return plugin_bread(bfd, buf, count);
672    }
673
674    if (bfd->use_backup_api) {
675       if (!p_BackupRead(bfd->fh,
676            (BYTE *)buf,
677            count,
678            &bfd->rw_bytes,
679            0,                           /* no Abort */
680            1,                           /* Process Security */
681            &bfd->lpContext)) {          /* Context */
682          bfd->lerror = GetLastError();
683          bfd->berrno = b_errno_win32;
684          errno = b_errno_win32;
685          return -1;
686       }
687    } else {
688       if (!ReadFile(bfd->fh,
689            buf,
690            count,
691            &bfd->rw_bytes,
692            NULL)) {
693          bfd->lerror = GetLastError();
694          bfd->berrno = b_errno_win32;
695          errno = b_errno_win32;
696          return -1;
697       }
698    }
699
700    return (ssize_t)bfd->rw_bytes;
701 }
702
703 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
704 {
705    bfd->rw_bytes = 0;
706
707    if (bfd->cmd_plugin && plugin_bwrite) {
708       return plugin_bwrite(bfd, buf, count);
709    }
710
711    if (bfd->use_backup_api) {
712       if (!p_BackupWrite(bfd->fh,
713            (BYTE *)buf,
714            count,
715            &bfd->rw_bytes,
716            0,                           /* No abort */
717            1,                           /* Process Security */
718            &bfd->lpContext)) {          /* Context */
719          bfd->lerror = GetLastError();
720          bfd->berrno = b_errno_win32;
721          errno = b_errno_win32;
722          return -1;
723       }
724    } else {
725       if (!WriteFile(bfd->fh,
726            buf,
727            count,
728            &bfd->rw_bytes,
729            NULL)) {
730          bfd->lerror = GetLastError();
731          bfd->berrno = b_errno_win32;
732          errno = b_errno_win32;
733          return -1;
734       }
735    }
736    return (ssize_t)bfd->rw_bytes;
737 }
738
739 bool is_bopen(BFILE *bfd)
740 {
741    return bfd->mode != BF_CLOSED;
742 }
743
744 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
745 {
746    LONG  offset_low = (LONG)offset;
747    LONG  offset_high = (LONG)(offset >> 32);
748    DWORD dwResult;
749
750    if (bfd->cmd_plugin && plugin_blseek) {
751       return plugin_blseek(bfd, offset, whence);
752    }
753
754    dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
755
756    if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
757       return (boffset_t)-1;
758    }
759
760    return ((boffset_t)offset_high << 32) | dwResult;
761 }
762
763 #else  /* Unix systems */
764
765 /* ===============================================================
766  *
767  *            U N I X
768  *
769  * ===============================================================
770  */
771 void binit(BFILE *bfd)
772 {
773    memset(bfd, 0, sizeof(BFILE));
774    bfd->fid = -1;
775 }
776
777 bool have_win32_api()
778 {
779    return false;                       /* no can do */
780 }
781
782 /*
783  * Enables using the Backup API (win32_data).
784  *   Returns true  if function worked
785  *   Returns false if failed (i.e. do not have Backup API on this machine)
786  */
787 bool set_win32_backup(BFILE *bfd)
788 {
789    return false;                       /* no can do */
790 }
791
792
793 bool set_portable_backup(BFILE *bfd)
794 {
795    return true;                        /* no problem */
796 }
797
798 /*
799  * Return true  if we are writing in portable format
800  * return false if not
801  */
802 bool is_portable_backup(BFILE *bfd)
803 {
804    return true;                       /* portable by definition */
805 }
806
807 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
808 {
809    return false;
810 }
811
812 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
813 {
814    bfd->cmd_plugin = true;
815    bfd->jcr = jcr;
816    return true;
817 }
818
819 /* 
820  * This code is running on a non-Win32 machine 
821  */
822 bool is_restore_stream_supported(int stream)
823 {
824    /* No Win32 backup on this machine */
825      switch (stream) {
826 #ifndef HAVE_LIBZ
827    case STREAM_GZIP_DATA:
828    case STREAM_SPARSE_GZIP_DATA:
829    case STREAM_WIN32_GZIP_DATA:    
830 #endif
831 #ifndef HAVE_DARWIN_OS
832    case STREAM_MACOS_FORK_DATA:
833    case STREAM_HFSPLUS_ATTRIBUTES:
834 #endif
835       return false;
836
837    /* Known streams */
838 #ifdef HAVE_LIBZ
839    case STREAM_GZIP_DATA:
840    case STREAM_SPARSE_GZIP_DATA:
841    case STREAM_WIN32_GZIP_DATA:    
842 #endif
843    case STREAM_WIN32_DATA:
844    case STREAM_UNIX_ATTRIBUTES:
845    case STREAM_FILE_DATA:
846    case STREAM_MD5_DIGEST:
847    case STREAM_UNIX_ATTRIBUTES_EX:
848    case STREAM_SPARSE_DATA:
849    case STREAM_PROGRAM_NAMES:
850    case STREAM_PROGRAM_DATA:
851    case STREAM_SHA1_DIGEST:
852 #ifdef HAVE_SHA2
853    case STREAM_SHA256_DIGEST:
854    case STREAM_SHA512_DIGEST:
855 #endif
856 #ifdef HAVE_CRYPTO
857    case STREAM_SIGNED_DIGEST:
858    case STREAM_ENCRYPTED_FILE_DATA:
859    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
860    case STREAM_ENCRYPTED_WIN32_DATA:
861    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
862 #endif
863 #ifdef HAVE_DARWIN_OS
864    case STREAM_MACOS_FORK_DATA:
865    case STREAM_HFSPLUS_ATTRIBUTES:
866 #ifdef HAVE_CRYPTO
867    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
868 #endif /* HAVE_CRYPTO */
869 #endif /* HAVE_DARWIN_OS */
870    case 0:   /* compatibility with old tapes */
871       return true;
872
873    }
874    return false;
875 }
876
877 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
878 {
879    if (bfd->cmd_plugin && plugin_bopen) {
880       Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
881       bfd->fid = plugin_bopen(bfd, fname, flags, mode);
882       Dmsg1(50, "Plugin bopen stat=%d\n", bfd->fid);
883       return bfd->fid;
884    }
885
886    /* Normal file open */
887    Dmsg1(dbglvl, "open file %s\n", fname);
888
889    /* We use fnctl to set O_NOATIME if requested to avoid open error */
890    bfd->fid = open(fname, flags & ~O_NOATIME, mode);
891
892    /* Set O_NOATIME if possible */
893    if (bfd->fid != -1 && flags & O_NOATIME) {
894       int oldflags = fcntl(bfd->fid, F_GETFL, 0);
895       if (oldflags == -1) {
896          bfd->berrno = errno;
897          close(bfd->fid);
898          bfd->fid = -1;
899       } else {
900          int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
901         /* EPERM means setting O_NOATIME was not allowed  */
902          if (ret == -1 && errno != EPERM) {
903             bfd->berrno = errno;
904             close(bfd->fid);
905             bfd->fid = -1;
906          }
907       }
908    }
909    bfd->berrno = errno;
910    bfd->m_flags = flags;
911    Dmsg1(400, "Open file %d\n", bfd->fid);
912    errno = bfd->berrno;
913
914    bfd->win32DecompContext.bIsInData = false;
915    bfd->win32DecompContext.liNextHeader = 0;
916
917 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
918    if (bfd->fid != -1 && flags & O_RDONLY) {
919       int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
920       Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
921    }
922 #endif
923
924    return bfd->fid;
925 }
926
927 #ifdef HAVE_DARWIN_OS
928 /* Open the resource fork of a file. */
929 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
930 {
931    POOLMEM *rsrc_fname;
932
933    rsrc_fname = get_pool_memory(PM_FNAME);
934    pm_strcpy(rsrc_fname, fname);
935    pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
936    bopen(bfd, rsrc_fname, flags, mode);
937    free_pool_memory(rsrc_fname);
938    return bfd->fid;
939 }
940 #endif
941
942
943 int bclose(BFILE *bfd)
944 {
945    int stat;
946
947    Dmsg1(400, "Close file %d\n", bfd->fid);
948
949    if (bfd->cmd_plugin && plugin_bclose) {
950       stat = plugin_bclose(bfd);
951       bfd->fid = -1;
952       bfd->cmd_plugin = false;
953    }
954
955    if (bfd->fid == -1) {
956       return 0;
957    }
958 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
959    if (bfd->m_flags & O_RDONLY) {
960       fdatasync(bfd->fid);            /* sync the file */
961       /* Tell OS we don't need it any more */
962       posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
963    }
964 #endif
965
966    /* Close normal file */
967    stat = close(bfd->fid);
968    bfd->berrno = errno;
969    bfd->fid = -1;
970    bfd->cmd_plugin = false;
971    return stat;
972 }
973
974 ssize_t bread(BFILE *bfd, void *buf, size_t count)
975 {
976    ssize_t stat;
977
978    if (bfd->cmd_plugin && plugin_bread) {
979       return plugin_bread(bfd, buf, count);
980    }
981
982    stat = read(bfd->fid, buf, count);
983    bfd->berrno = errno;
984    return stat;
985 }
986
987 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
988 {
989    ssize_t stat;
990
991    if (bfd->cmd_plugin && plugin_bwrite) {
992       return plugin_bwrite(bfd, buf, count);
993    }
994    stat = write(bfd->fid, buf, count);
995    bfd->berrno = errno;
996    return stat;
997 }
998
999 bool is_bopen(BFILE *bfd)
1000 {
1001    return bfd->fid >= 0;
1002 }
1003
1004 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
1005 {
1006    boffset_t pos;
1007
1008    if (bfd->cmd_plugin && plugin_bwrite) {
1009       return plugin_blseek(bfd, offset, whence);
1010    }
1011    pos = (boffset_t)lseek(bfd->fid, offset, whence);
1012    bfd->berrno = errno;
1013    return pos;
1014 }
1015
1016 #endif