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