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