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