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