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