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