]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/bfile.c
kes Add cmd_plugin flag to jcr so we can globally know if a
[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(000, "call plugin_bopen fname=%s\n", fname);
424       rtnstat = plugin_bopen(bfd, fname, flags, mode);
425       if (rtnstat >= 0) {
426          if (flags & O_CREAT || flags & O_WRONLY) {   /* Open existing for write */
427             bfd->mode = BF_WRITE;
428          } else {
429             bfd->mode = BF_READ;
430          }
431       } else {
432          bfd->mode = BF_CLOSED;
433       }
434       free_pool_memory(win32_fname_wchar);
435       free_pool_memory(win32_fname);
436       return bfd->mode == BF_CLOSED ? -1 : 1;
437    }
438
439    if (!(p_CreateFileA || p_CreateFileW))
440       return 0;
441
442    if (p_CreateFileW && p_MultiByteToWideChar)
443       make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
444
445    if (flags & O_CREAT) {             /* Create */
446       if (bfd->use_backup_api) {
447          dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
448          dwflags = FILE_FLAG_BACKUP_SEMANTICS;
449       } else {
450          dwaccess = GENERIC_WRITE;
451          dwflags = 0;
452       }
453
454       if (p_CreateFileW && p_MultiByteToWideChar) {   
455          // unicode open for create write
456          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
457                 dwaccess,                /* Requested access */
458                 0,                       /* Shared mode */
459                 NULL,                    /* SecurityAttributes */
460                 CREATE_ALWAYS,           /* CreationDisposition */
461                 dwflags,                 /* Flags and attributes */
462                 NULL);                   /* TemplateFile */
463       } else {
464          // ascii open
465          bfd->fh = p_CreateFileA(win32_fname,
466                 dwaccess,                /* Requested access */
467                 0,                       /* Shared mode */
468                 NULL,                    /* SecurityAttributes */
469                 CREATE_ALWAYS,           /* CreationDisposition */
470                 dwflags,                 /* Flags and attributes */
471                 NULL);                   /* TemplateFile */
472       }
473
474       bfd->mode = BF_WRITE;
475
476    } else if (flags & O_WRONLY) {     /* Open existing for write */
477       if (bfd->use_backup_api) {
478          dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
479          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
480       } else {
481          dwaccess = GENERIC_WRITE;
482          dwflags = 0;
483       }
484
485       if (p_CreateFileW && p_MultiByteToWideChar) {   
486          // unicode open for open existing write
487          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
488                 dwaccess,                /* Requested access */
489                 0,                       /* Shared mode */
490                 NULL,                    /* SecurityAttributes */
491                 OPEN_EXISTING,           /* CreationDisposition */
492                 dwflags,                 /* Flags and attributes */
493                 NULL);                   /* TemplateFile */
494       } else {
495          // ascii open
496          bfd->fh = p_CreateFileA(win32_fname,
497                 dwaccess,                /* Requested access */
498                 0,                       /* Shared mode */
499                 NULL,                    /* SecurityAttributes */
500                 OPEN_EXISTING,           /* CreationDisposition */
501                 dwflags,                 /* Flags and attributes */
502                 NULL);                   /* TemplateFile */
503
504       }
505
506       bfd->mode = BF_WRITE;
507
508    } else {                           /* Read */
509       if (bfd->use_backup_api) {
510          dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
511          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
512                    FILE_FLAG_OPEN_REPARSE_POINT;
513          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
514       } else {
515          dwaccess = GENERIC_READ;
516          dwflags = 0;
517          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
518       }
519
520       if (p_CreateFileW && p_MultiByteToWideChar) {   
521          // unicode open for open existing read
522          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
523                 dwaccess,                /* Requested access */
524                 dwshare,                 /* Share modes */
525                 NULL,                    /* SecurityAttributes */
526                 OPEN_EXISTING,           /* CreationDisposition */
527                 dwflags,                 /* Flags and attributes */
528                 NULL);                   /* TemplateFile */
529       } else {
530          // ascii open 
531          bfd->fh = p_CreateFileA(win32_fname,
532                 dwaccess,                /* Requested access */
533                 dwshare,                 /* Share modes */
534                 NULL,                    /* SecurityAttributes */
535                 OPEN_EXISTING,           /* CreationDisposition */
536                 dwflags,                 /* Flags and attributes */
537                 NULL);                   /* TemplateFile */
538       }
539
540       bfd->mode = BF_READ;
541    }
542
543    if (bfd->fh == INVALID_HANDLE_VALUE) {
544       bfd->lerror = GetLastError();
545       bfd->berrno = b_errno_win32;
546       errno = b_errno_win32;
547       bfd->mode = BF_CLOSED;
548    }
549    bfd->errmsg = NULL;
550    bfd->lpContext = NULL;
551    bfd->win32DecompContext.bIsInData = false;
552    bfd->win32DecompContext.liNextHeader = 0;
553    free_pool_memory(win32_fname_wchar);
554    free_pool_memory(win32_fname);
555    return bfd->mode == BF_CLOSED ? -1 : 1;
556 }
557
558 /*
559  * Returns  0 on success
560  *         -1 on error
561  */
562 int bclose(BFILE *bfd)
563 {
564    int stat = 0;
565
566    if (bfd->errmsg) {
567       free_pool_memory(bfd->errmsg);
568       bfd->errmsg = NULL;
569    }
570    if (bfd->mode == BF_CLOSED) {
571       return 0;
572    }
573
574    if (bfd->cmd_plugin && plugin_bclose) {
575       stat = plugin_bclose(bfd);
576       goto all_done;
577    }
578
579    /*
580     * We need to tell the API to release the buffer it
581     *  allocated in lpContext.  We do so by calling the
582     *  API one more time, but with the Abort bit set.
583     */
584    if (bfd->use_backup_api && bfd->mode == BF_READ) {
585       BYTE buf[10];
586       if (bfd->lpContext && !p_BackupRead(bfd->fh,
587               buf,                    /* buffer */
588               (DWORD)0,               /* bytes to read */
589               &bfd->rw_bytes,         /* bytes read */
590               1,                      /* Abort */
591               1,                      /* ProcessSecurity */
592               &bfd->lpContext)) {     /* Read context */
593          errno = b_errno_win32;
594          stat = -1;
595       }
596    } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
597       BYTE buf[10];
598       if (bfd->lpContext && !p_BackupWrite(bfd->fh,
599               buf,                    /* buffer */
600               (DWORD)0,               /* bytes to read */
601               &bfd->rw_bytes,         /* bytes written */
602               1,                      /* Abort */
603               1,                      /* ProcessSecurity */
604               &bfd->lpContext)) {     /* Write context */
605          errno = b_errno_win32;
606          stat = -1;
607       }
608    }
609    if (!CloseHandle(bfd->fh)) {
610       stat = -1;
611       errno = b_errno_win32;
612    }
613
614 all_done:
615    bfd->mode = BF_CLOSED;
616    bfd->lpContext = NULL;
617    bfd->cmd_plugin = false;
618    return stat;
619 }
620
621 /* Returns: bytes read on success
622  *           0         on EOF
623  *          -1         on error
624  */
625 ssize_t bread(BFILE *bfd, void *buf, size_t count)
626 {
627    bfd->rw_bytes = 0;
628
629    if (bfd->cmd_plugin && plugin_bread) {
630       return plugin_bread(bfd, buf, count);
631    }
632
633    if (bfd->use_backup_api) {
634       if (!p_BackupRead(bfd->fh,
635            (BYTE *)buf,
636            count,
637            &bfd->rw_bytes,
638            0,                           /* no Abort */
639            1,                           /* Process Security */
640            &bfd->lpContext)) {          /* Context */
641          bfd->lerror = GetLastError();
642          bfd->berrno = b_errno_win32;
643          errno = b_errno_win32;
644          return -1;
645       }
646    } else {
647       if (!ReadFile(bfd->fh,
648            buf,
649            count,
650            &bfd->rw_bytes,
651            NULL)) {
652          bfd->lerror = GetLastError();
653          bfd->berrno = b_errno_win32;
654          errno = b_errno_win32;
655          return -1;
656       }
657    }
658
659    return (ssize_t)bfd->rw_bytes;
660 }
661
662 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
663 {
664    bfd->rw_bytes = 0;
665
666    if (bfd->cmd_plugin && plugin_bwrite) {
667       return plugin_bwrite(bfd, buf, count);
668    }
669
670    if (bfd->use_backup_api) {
671       if (!p_BackupWrite(bfd->fh,
672            (BYTE *)buf,
673            count,
674            &bfd->rw_bytes,
675            0,                           /* No abort */
676            1,                           /* Process Security */
677            &bfd->lpContext)) {          /* Context */
678          bfd->lerror = GetLastError();
679          bfd->berrno = b_errno_win32;
680          errno = b_errno_win32;
681          return -1;
682       }
683    } else {
684       if (!WriteFile(bfd->fh,
685            buf,
686            count,
687            &bfd->rw_bytes,
688            NULL)) {
689          bfd->lerror = GetLastError();
690          bfd->berrno = b_errno_win32;
691          errno = b_errno_win32;
692          return -1;
693       }
694    }
695    return (ssize_t)bfd->rw_bytes;
696 }
697
698 bool is_bopen(BFILE *bfd)
699 {
700    return bfd->mode != BF_CLOSED;
701 }
702
703 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
704 {
705    LONG  offset_low = (LONG)offset;
706    LONG  offset_high = (LONG)(offset >> 32);
707    DWORD dwResult;
708
709    if (bfd->cmd_plugin && plugin_bwrite) {
710       return plugin_blseek(bfd, offset, whence);
711    }
712
713    dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
714
715    if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
716       return (boffset_t)-1;
717    }
718
719    return ((boffset_t)offset_high << 32) | dwResult;
720 }
721
722 #else  /* Unix systems */
723
724 /* ===============================================================
725  *
726  *            U N I X
727  *
728  * ===============================================================
729  */
730 void binit(BFILE *bfd)
731 {
732    memset(bfd, 0, sizeof(BFILE));
733    bfd->fid = -1;
734 }
735
736 bool have_win32_api()
737 {
738    return false;                       /* no can do */
739 }
740
741 /*
742  * Enables using the Backup API (win32_data).
743  *   Returns true  if function worked
744  *   Returns false if failed (i.e. do not have Backup API on this machine)
745  */
746 bool set_win32_backup(BFILE *bfd)
747 {
748    return false;                       /* no can do */
749 }
750
751
752 bool set_portable_backup(BFILE *bfd)
753 {
754    return true;                        /* no problem */
755 }
756
757 /*
758  * Return true  if we are writing in portable format
759  * return false if not
760  */
761 bool is_portable_backup(BFILE *bfd)
762 {
763    return true;                       /* portable by definition */
764 }
765
766 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
767 {
768    return false;
769 }
770
771 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
772 {
773    bfd->cmd_plugin = true;
774    bfd->jcr = jcr;
775    return true;
776 }
777
778 /* 
779  * This code is running on a non-Win32 machine 
780  */
781 bool is_restore_stream_supported(int stream)
782 {
783    /* No Win32 backup on this machine */
784      switch (stream) {
785 #ifndef HAVE_LIBZ
786    case STREAM_GZIP_DATA:
787    case STREAM_SPARSE_GZIP_DATA:
788    case STREAM_WIN32_GZIP_DATA:    
789 #endif
790 #ifndef HAVE_DARWIN_OS
791    case STREAM_MACOS_FORK_DATA:
792    case STREAM_HFSPLUS_ATTRIBUTES:
793 #endif
794       return false;
795
796    /* Known streams */
797 #ifdef HAVE_LIBZ
798    case STREAM_GZIP_DATA:
799    case STREAM_SPARSE_GZIP_DATA:
800    case STREAM_WIN32_GZIP_DATA:    
801 #endif
802    case STREAM_WIN32_DATA:
803    case STREAM_UNIX_ATTRIBUTES:
804    case STREAM_FILE_DATA:
805    case STREAM_MD5_DIGEST:
806    case STREAM_UNIX_ATTRIBUTES_EX:
807    case STREAM_SPARSE_DATA:
808    case STREAM_PROGRAM_NAMES:
809    case STREAM_PROGRAM_DATA:
810    case STREAM_SHA1_DIGEST:
811 #ifdef HAVE_SHA2
812    case STREAM_SHA256_DIGEST:
813    case STREAM_SHA512_DIGEST:
814 #endif
815 #ifdef HAVE_CRYPTO
816    case STREAM_SIGNED_DIGEST:
817    case STREAM_ENCRYPTED_FILE_DATA:
818    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
819    case STREAM_ENCRYPTED_WIN32_DATA:
820    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
821 #endif
822 #ifdef HAVE_DARWIN_OS
823    case STREAM_MACOS_FORK_DATA:
824    case STREAM_HFSPLUS_ATTRIBUTES:
825 #ifdef HAVE_CRYPTO
826    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
827 #endif /* HAVE_CRYPTO */
828 #endif /* HAVE_DARWIN_OS */
829    case 0:   /* compatibility with old tapes */
830       return true;
831
832    }
833    return false;
834 }
835
836 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
837 {
838    if (bfd->cmd_plugin && plugin_bopen) {
839       Dmsg1(000, "call plugin_bopen fname=%s\n", fname);
840       return plugin_bopen(bfd, fname, flags, mode);
841    }
842
843    /* Normal file open */
844    Dmsg1(dbglvl, "open file %s\n", fname);
845
846    /* We use fnctl to set O_NOATIME if requested to avoid open error */
847    bfd->fid = open(fname, flags & ~O_NOATIME, mode);
848
849    /* Set O_NOATIME if possible */
850    if (bfd->fid != -1 && flags & O_NOATIME) {
851       int oldflags = fcntl(bfd->fid, F_GETFL, 0);
852       if (oldflags == -1) {
853          bfd->berrno = errno;
854          close(bfd->fid);
855          bfd->fid = -1;
856       } else {
857          int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
858         /* EPERM means setting O_NOATIME was not allowed  */
859          if (ret == -1 && errno != EPERM) {
860             bfd->berrno = errno;
861             close(bfd->fid);
862             bfd->fid = -1;
863          }
864       }
865    }
866    bfd->berrno = errno;
867    bfd->m_flags = flags;
868    Dmsg1(400, "Open file %d\n", bfd->fid);
869    errno = bfd->berrno;
870
871    bfd->win32DecompContext.bIsInData = false;
872    bfd->win32DecompContext.liNextHeader = 0;
873
874 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
875    if (bfd->fid != -1 && flags & O_RDONLY) {
876       int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
877       Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
878    }
879 #endif
880
881    return bfd->fid;
882 }
883
884 #ifdef HAVE_DARWIN_OS
885 /* Open the resource fork of a file. */
886 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
887 {
888    POOLMEM *rsrc_fname;
889
890    rsrc_fname = get_pool_memory(PM_FNAME);
891    pm_strcpy(rsrc_fname, fname);
892    pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
893    bopen(bfd, rsrc_fname, flags, mode);
894    free_pool_memory(rsrc_fname);
895    return bfd->fid;
896 }
897 #endif
898
899
900 int bclose(BFILE *bfd)
901 {
902    int stat;
903
904    Dmsg1(400, "Close file %d\n", bfd->fid);
905
906    if (bfd->cmd_plugin && plugin_bclose) {
907       stat = plugin_bclose(bfd);
908       bfd->fid = -1;
909       bfd->cmd_plugin = false;
910    }
911
912    if (bfd->fid == -1) {
913       return 0;
914    }
915 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
916    if (bfd->m_flags & O_RDONLY) {
917       fdatasync(bfd->fid);            /* sync the file */
918       /* Tell OS we don't need it any more */
919       posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
920    }
921 #endif
922
923    /* Close normal file */
924    stat = close(bfd->fid);
925    bfd->berrno = errno;
926    bfd->fid = -1;
927    bfd->cmd_plugin = false;
928    return stat;
929 }
930
931 ssize_t bread(BFILE *bfd, void *buf, size_t count)
932 {
933    ssize_t stat;
934
935    if (bfd->cmd_plugin && plugin_bread) {
936       return plugin_bread(bfd, buf, count);
937    }
938
939    stat = read(bfd->fid, buf, count);
940    bfd->berrno = errno;
941    return stat;
942 }
943
944 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
945 {
946    ssize_t stat;
947
948    if (bfd->cmd_plugin && plugin_bwrite) {
949       return plugin_bwrite(bfd, buf, count);
950    }
951    stat = write(bfd->fid, buf, count);
952    bfd->berrno = errno;
953    return stat;
954 }
955
956 bool is_bopen(BFILE *bfd)
957 {
958    return bfd->fid >= 0;
959 }
960
961 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
962 {
963    boffset_t pos;
964
965    if (bfd->cmd_plugin && plugin_bwrite) {
966       return plugin_blseek(bfd, offset, whence);
967    }
968    pos = (boffset_t)lseek(bfd->fid, offset, whence);
969    bfd->berrno = errno;
970    return pos;
971 }
972
973 #endif