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