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