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