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