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