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