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