]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/bfile.c
Added xattr interface found in AIX 6.x and higher which mimics the Linux/OSF interfac...
[bacula/bacula] / bacula / src / findlib / bfile.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Bacula low level File I/O routines.  This routine simulates
30  *    open(), read(), write(), and close(), but using native routines.
31  *    I.e. on Windows, we use Windows APIs.
32  *
33  *    Kern Sibbald, April MMIII
34  *
35  */
36
37 #include "bacula.h"
38 #include "find.h"
39
40 const int dbglvl = 200;
41
42 int       (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode) = NULL;
43 int       (*plugin_bclose)(BFILE *bfd) = NULL;
44 ssize_t   (*plugin_bread)(BFILE *bfd, void *buf, size_t count) = NULL;
45 ssize_t   (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count) = NULL;
46 boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence) = NULL;
47
48
49 #ifdef HAVE_DARWIN_OS
50 #include <sys/paths.h>
51 #endif
52
53 #if !defined(HAVE_FDATASYNC)
54 #define fdatasync(fd)
55 #endif
56
57 #ifdef HAVE_WIN32
58 void pause_msg(const char *file, const char *func, int line, const char *msg)
59 {
60    char buf[1000];
61    if (msg) {
62       bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
63    } else {
64       bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
65    }
66    MessageBox(NULL, buf, "Pause", MB_OK);
67 }
68 #endif
69
70 /* ===============================================================
71  *
72  *            U N I X   AND   W I N D O W S
73  *
74  * ===============================================================
75  */
76
77 bool is_win32_stream(int stream)
78 {
79    switch (stream) {
80    case STREAM_WIN32_DATA:
81    case STREAM_WIN32_GZIP_DATA:
82    case STREAM_ENCRYPTED_WIN32_DATA:
83    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
84       return true;
85    }
86    return false;
87 }
88
89 const char *stream_to_ascii(int stream)
90 {
91    static char buf[20];
92
93    switch (stream) {
94    case STREAM_UNIX_ATTRIBUTES:
95       return _("Unix attributes");
96    case STREAM_FILE_DATA:
97       return _("File data");
98    case STREAM_MD5_DIGEST:
99       return _("MD5 digest");
100    case STREAM_GZIP_DATA:
101       return _("GZIP data");
102    case STREAM_UNIX_ATTRIBUTES_EX:
103       return _("Extended attributes");
104    case STREAM_SPARSE_DATA:
105       return _("Sparse data");
106    case STREAM_SPARSE_GZIP_DATA:
107       return _("GZIP sparse data");
108    case STREAM_PROGRAM_NAMES:
109       return _("Program names");
110    case STREAM_PROGRAM_DATA:
111       return _("Program data");
112    case STREAM_SHA1_DIGEST:
113       return _("SHA1 digest");
114    case STREAM_WIN32_DATA:
115       return _("Win32 data");
116    case STREAM_WIN32_GZIP_DATA:
117       return _("Win32 GZIP data");
118    case STREAM_MACOS_FORK_DATA:
119       return _("MacOS Fork data");
120    case STREAM_HFSPLUS_ATTRIBUTES:
121       return _("HFS+ attribs");
122    case STREAM_UNIX_ACCESS_ACL:
123       return _("Standard Unix ACL attribs");
124    case STREAM_UNIX_DEFAULT_ACL:
125       return _("Default Unix ACL attribs");
126    case STREAM_SHA256_DIGEST:
127       return _("SHA256 digest");
128    case STREAM_SHA512_DIGEST:
129       return _("SHA512 digest");
130    case STREAM_SIGNED_DIGEST:
131       return _("Signed digest");
132    case STREAM_ENCRYPTED_FILE_DATA:
133       return _("Encrypted File data");
134    case STREAM_ENCRYPTED_WIN32_DATA:
135       return _("Encrypted Win32 data");
136    case STREAM_ENCRYPTED_SESSION_DATA:
137       return _("Encrypted session data");
138    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
139       return _("Encrypted GZIP data");
140    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
141       return _("Encrypted Win32 GZIP data");
142    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
143       return _("Encrypted MacOS fork data");
144    case STREAM_ACL_AIX_TEXT:
145       return _("AIX Specific ACL attribs");
146    case STREAM_ACL_DARWIN_ACCESS_ACL:
147       return _("Darwin Specific ACL attribs");
148    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
149       return _("FreeBSD Specific Default ACL attribs");
150    case STREAM_ACL_FREEBSD_ACCESS_ACL:
151       return _("FreeBSD Specific Access ACL attribs");
152    case STREAM_ACL_HPUX_ACL_ENTRY:
153       return _("HPUX Specific ACL attribs");
154    case STREAM_ACL_IRIX_DEFAULT_ACL:
155       return _("Irix Specific Default ACL attribs");
156    case STREAM_ACL_IRIX_ACCESS_ACL:
157       return _("Irix Specific Access ACL attribs");
158    case STREAM_ACL_LINUX_DEFAULT_ACL:
159       return _("Linux Specific Default ACL attribs");
160    case STREAM_ACL_LINUX_ACCESS_ACL:
161       return _("Linux Specific Access ACL attribs");
162    case STREAM_ACL_TRU64_DEFAULT_ACL:
163       return _("OSF1 Specific Default ACL attribs");
164    case STREAM_ACL_TRU64_ACCESS_ACL:
165       return _("OSF1 Specific Access ACL attribs");
166    case STREAM_ACL_SOLARIS_ACLENT:
167       return _("Solaris Specific ACL attribs");
168    case STREAM_ACL_SOLARIS_ACE:
169       return _("Solaris Specific ACL attribs");
170    case STREAM_XATTR_AIX:
171       return _("AIX Specific Extended attribs");
172    case STREAM_XATTR_OPENBSD:
173       return _("OpenBSD Specific Extended attribs");
174    case STREAM_XATTR_SOLARIS_SYS:
175       return _("Solaris Specific Extensible attribs or System Extended attribs");
176    case STREAM_XATTR_SOLARIS:
177       return _("Solaris Specific Extended attribs");
178    case STREAM_XATTR_DARWIN:
179       return _("Darwin Specific Extended attribs");
180    case STREAM_XATTR_FREEBSD:
181       return _("FreeBSD Specific Extended attribs");
182    case STREAM_XATTR_LINUX:
183       return _("Linux Specific Extended attribs");
184    case STREAM_XATTR_NETBSD:
185       return _("NetBSD Specific Extended attribs");
186    default:
187       sprintf(buf, "%d", stream);
188       return (const char *)buf;
189    }
190 }
191
192 /**   
193  *  Convert a 64 bit little endian to a big endian
194  */
195 void int64_LE2BE(int64_t* pBE, const int64_t v)
196 {
197    /* convert little endian to big endian */
198    if (htonl(1) != 1L) { /* no work if on little endian machine */
199       memcpy(pBE, &v, sizeof(int64_t));
200    } else {
201       int i;
202       uint8_t rv[sizeof(int64_t)];
203       uint8_t *pv = (uint8_t *) &v;
204
205       for (i = 0; i < 8; i++) {
206          rv[i] = pv[7 - i];
207       }
208       memcpy(pBE, &rv, sizeof(int64_t));
209    }    
210 }
211
212 /**
213  *  Convert a 32 bit little endian to a big endian
214  */
215 void int32_LE2BE(int32_t* pBE, const int32_t v)
216 {
217    /* convert little endian to big endian */
218    if (htonl(1) != 1L) { /* no work if on little endian machine */
219       memcpy(pBE, &v, sizeof(int32_t));
220    } else {
221       int i;
222       uint8_t rv[sizeof(int32_t)];
223       uint8_t *pv = (uint8_t *) &v;
224
225       for (i = 0; i < 4; i++) {
226          rv[i] = pv[3 - i];
227       }
228       memcpy(pBE, &rv, sizeof(int32_t));
229    }    
230 }
231
232
233 /**
234  *  Read a BackupRead block and pull out the file data
235  */
236 bool processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, ssize_t dwSize)
237 {
238    /* pByte contains the buffer 
239       dwSize the len to be processed.  function assumes to be
240       called in successive incremental order over the complete
241       BackupRead stream beginning at pos 0 and ending at the end.
242     */
243
244    PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
245    bool bContinue = false;
246    int64_t dwDataOffset = 0;
247    int64_t dwDataLen;
248
249    /* Win32 Stream Header size without name of stream.
250     * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*); 
251     */
252    int32_t dwSizeHeader = 20; 
253
254    do {
255       if (pContext->liNextHeader >= dwSize) {
256          dwDataLen = dwSize-dwDataOffset;
257          bContinue = false; /* 1 iteration is enough */
258       } else {
259          dwDataLen = pContext->liNextHeader-dwDataOffset;
260          bContinue = true; /* multiple iterations may be necessary */
261       }
262
263       /* flush */
264       /* copy block of real DATA */
265       if (pContext->bIsInData) {
266          if (bwrite(bfd, ((char *)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
267             return false;
268       }
269
270       if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
271          int32_t dwOffsetTarget;
272          int32_t dwOffsetSource;
273
274          if (pContext->liNextHeader < 0) {
275             /* start of header was before this block, so we
276              * continue with the part in the current block 
277              */
278             dwOffsetTarget = -pContext->liNextHeader;
279             dwOffsetSource = 0;
280          } else {
281             /* start of header is inside of this block */
282             dwOffsetTarget = 0;
283             dwOffsetSource = pContext->liNextHeader;
284          }
285
286          int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
287          bool bHeaderIsComplete;
288
289          if (dwHeaderPartLen <= dwSize-dwOffsetSource) {
290             /* header (or rest of header) is completely available
291                in current block 
292              */
293             bHeaderIsComplete = true;
294          } else {
295             /* header will continue in next block */
296             bHeaderIsComplete = false;
297             dwHeaderPartLen = dwSize-dwOffsetSource;
298          }
299
300          /* copy the available portion of header to persistent copy */
301          memcpy(((char *)&pContext->header_stream)+dwOffsetTarget, ((char *)pBuffer)+dwOffsetSource, dwHeaderPartLen);
302
303          /* recalculate position of next header */
304          if (bHeaderIsComplete) {
305             /* convert stream name size (32 bit little endian) to machine type */
306             int32_t dwNameSize; 
307             int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
308             dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
309
310             /* convert stream size (64 bit little endian) to machine type */
311             int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
312             pContext->liNextHeader += dwDataOffset;
313
314             pContext->bIsInData = pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
315             if (dwDataOffset == dwSize)
316                bContinue = false;
317          } else {
318             /* stop and continue with next block */
319             bContinue = false;
320             pContext->bIsInData = false;
321          }
322       }
323    } while (bContinue);
324
325    /* set "NextHeader" relative to the beginning of the next block */
326    pContext->liNextHeader-= dwSize;
327
328    return TRUE;
329 }
330
331
332
333 /* ===============================================================
334  *
335  *            W I N D O W S
336  *
337  * ===============================================================
338  */
339
340 #if defined(HAVE_WIN32)
341
342 void unix_name_to_win32(POOLMEM **win32_name, char *name);
343 extern "C" HANDLE get_osfhandle(int fd);
344
345
346 void binit(BFILE *bfd)
347 {
348    memset(bfd, 0, sizeof(BFILE));
349    bfd->fid = -1;
350    bfd->mode = BF_CLOSED;
351    bfd->use_backup_api = have_win32_api();
352    bfd->cmd_plugin = false;
353 }
354
355 /*
356  * Enables using the Backup API (win32_data).
357  *   Returns 1 if function worked
358  *   Returns 0 if failed (i.e. do not have Backup API on this machine)
359  */
360 bool set_win32_backup(BFILE *bfd)
361 {
362    /* We enable if possible here */
363    bfd->use_backup_api = have_win32_api();
364    return bfd->use_backup_api;
365 }
366
367
368 bool set_portable_backup(BFILE *bfd)
369 {
370    bfd->use_backup_api = false;
371    return true;
372 }
373
374 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
375 {
376    bfd->cmd_plugin = true;
377    bfd->jcr = jcr;
378    return true;
379 }
380
381 /*
382  * Return 1 if we are NOT using Win32 BackupWrite()
383  * return 0 if are
384  */
385 bool is_portable_backup(BFILE *bfd)
386 {
387    return !bfd->use_backup_api;
388 }
389
390 bool have_win32_api()
391 {
392    return p_BackupRead && p_BackupWrite;
393 }
394
395
396 /*
397  * Return true  if we support the stream
398  *        false if we do not support the stream
399  *
400  *  This code is running under Win32, so we
401  *    do not need #ifdef on MACOS ...
402  */
403 bool is_restore_stream_supported(int stream)
404 {
405    switch (stream) {
406
407 /* Streams known not to be supported */
408 #ifndef HAVE_LIBZ
409    case STREAM_GZIP_DATA:
410    case STREAM_SPARSE_GZIP_DATA:
411    case STREAM_WIN32_GZIP_DATA:
412 #endif
413    case STREAM_MACOS_FORK_DATA:
414    case STREAM_HFSPLUS_ATTRIBUTES:
415    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
416       return false;
417
418    /* Known streams */
419 #ifdef HAVE_LIBZ
420    case STREAM_GZIP_DATA:
421    case STREAM_SPARSE_GZIP_DATA:
422    case STREAM_WIN32_GZIP_DATA:
423 #endif
424    case STREAM_WIN32_DATA:
425    case STREAM_UNIX_ATTRIBUTES:
426    case STREAM_FILE_DATA:
427    case STREAM_MD5_DIGEST:
428    case STREAM_UNIX_ATTRIBUTES_EX:
429    case STREAM_SPARSE_DATA:
430    case STREAM_PROGRAM_NAMES:
431    case STREAM_PROGRAM_DATA:
432    case STREAM_SHA1_DIGEST:
433 #ifdef HAVE_SHA2
434    case STREAM_SHA256_DIGEST:
435    case STREAM_SHA512_DIGEST:
436 #endif
437 #ifdef HAVE_CRYPTO
438    case STREAM_SIGNED_DIGEST:
439    case STREAM_ENCRYPTED_FILE_DATA:
440    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
441    case STREAM_ENCRYPTED_WIN32_DATA:
442    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
443 #endif
444    case 0:                            /* compatibility with old tapes */
445       return true;
446    }
447    return false;
448 }
449
450 HANDLE bget_handle(BFILE *bfd)
451 {
452    return bfd->fh;
453 }
454
455 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
456 {
457    POOLMEM *win32_fname;
458    POOLMEM *win32_fname_wchar;
459
460    DWORD dwaccess, dwflags, dwshare;
461
462    /* Convert to Windows path format */
463    win32_fname = get_pool_memory(PM_FNAME);
464    win32_fname_wchar = get_pool_memory(PM_FNAME);
465    
466    unix_name_to_win32(&win32_fname, (char *)fname);
467
468    if (bfd->cmd_plugin && plugin_bopen) {
469       int rtnstat;
470       Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
471       rtnstat = plugin_bopen(bfd, fname, flags, mode);
472       Dmsg1(50, "return from plugin_bopen status=%d\n", rtnstat);
473       if (rtnstat >= 0) {
474          if (flags & O_CREAT || flags & O_WRONLY) {   /* Open existing for write */
475             Dmsg1(50, "plugin_open for write OK file=%s.\n", fname);
476             bfd->mode = BF_WRITE;
477          } else {
478             Dmsg1(50, "plugin_open for read OK file=%s.\n", fname);
479             bfd->mode = BF_READ;
480          }
481       } else {
482          bfd->mode = BF_CLOSED;
483          Dmsg1(000, "==== plugin_bopen returned bad status=%d\n", rtnstat);
484       }
485       free_pool_memory(win32_fname_wchar);
486       free_pool_memory(win32_fname);
487       return bfd->mode == BF_CLOSED ? -1 : 1;
488    }
489    Dmsg0(50, "=== NO plugin\n");
490
491    if (!(p_CreateFileA || p_CreateFileW)) {
492       Dmsg0(50, "No CreateFileA and no CreateFileW!!!!!\n");
493       return 0;
494    }
495
496    if (p_CreateFileW && p_MultiByteToWideChar) {
497       make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
498    }
499
500    if (flags & O_CREAT) {             /* Create */
501       if (bfd->use_backup_api) {
502          dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
503          dwflags = FILE_FLAG_BACKUP_SEMANTICS;
504       } else {
505          dwaccess = GENERIC_WRITE;
506          dwflags = 0;
507       }
508
509       if (p_CreateFileW && p_MultiByteToWideChar) {   
510          // unicode open for create write
511          Dmsg1(100, "Create CreateFileW=%s\n", win32_fname);
512          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
513                 dwaccess,                /* Requested access */
514                 0,                       /* Shared mode */
515                 NULL,                    /* SecurityAttributes */
516                 CREATE_ALWAYS,           /* CreationDisposition */
517                 dwflags,                 /* Flags and attributes */
518                 NULL);                   /* TemplateFile */
519       } else {
520          // ascii open
521          Dmsg1(100, "Create CreateFileA=%s\n", win32_fname);
522          bfd->fh = p_CreateFileA(win32_fname,
523                 dwaccess,                /* Requested access */
524                 0,                       /* Shared mode */
525                 NULL,                    /* SecurityAttributes */
526                 CREATE_ALWAYS,           /* CreationDisposition */
527                 dwflags,                 /* Flags and attributes */
528                 NULL);                   /* TemplateFile */
529       }
530
531       bfd->mode = BF_WRITE;
532
533    } else if (flags & O_WRONLY) {     /* Open existing for write */
534       if (bfd->use_backup_api) {
535          dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
536          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
537       } else {
538          dwaccess = GENERIC_WRITE;
539          dwflags = 0;
540       }
541
542       if (p_CreateFileW && p_MultiByteToWideChar) {   
543          // unicode open for open existing write
544          Dmsg1(100, "Write only CreateFileW=%s\n", win32_fname);
545          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
546                 dwaccess,                /* Requested access */
547                 0,                       /* Shared mode */
548                 NULL,                    /* SecurityAttributes */
549                 OPEN_EXISTING,           /* CreationDisposition */
550                 dwflags,                 /* Flags and attributes */
551                 NULL);                   /* TemplateFile */
552       } else {
553          // ascii open
554          Dmsg1(100, "Write only CreateFileA=%s\n", win32_fname);
555          bfd->fh = p_CreateFileA(win32_fname,
556                 dwaccess,                /* Requested access */
557                 0,                       /* Shared mode */
558                 NULL,                    /* SecurityAttributes */
559                 OPEN_EXISTING,           /* CreationDisposition */
560                 dwflags,                 /* Flags and attributes */
561                 NULL);                   /* TemplateFile */
562
563       }
564
565       bfd->mode = BF_WRITE;
566
567    } else {                           /* Read */
568       if (bfd->use_backup_api) {
569          dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
570          dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
571                    FILE_FLAG_OPEN_REPARSE_POINT;
572          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
573       } else {
574          dwaccess = GENERIC_READ;
575          dwflags = 0;
576          dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
577       }
578
579       if (p_CreateFileW && p_MultiByteToWideChar) {   
580          // unicode open for open existing read
581          Dmsg1(100, "Read CreateFileW=%s\n", win32_fname);
582          bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
583                 dwaccess,                /* Requested access */
584                 dwshare,                 /* Share modes */
585                 NULL,                    /* SecurityAttributes */
586                 OPEN_EXISTING,           /* CreationDisposition */
587                 dwflags,                 /* Flags and attributes */
588                 NULL);                   /* TemplateFile */
589       } else {
590          // ascii open 
591          Dmsg1(100, "Read CreateFileA=%s\n", win32_fname);
592          bfd->fh = p_CreateFileA(win32_fname,
593                 dwaccess,                /* Requested access */
594                 dwshare,                 /* Share modes */
595                 NULL,                    /* SecurityAttributes */
596                 OPEN_EXISTING,           /* CreationDisposition */
597                 dwflags,                 /* Flags and attributes */
598                 NULL);                   /* TemplateFile */
599       }
600
601       bfd->mode = BF_READ;
602    }
603
604    if (bfd->fh == INVALID_HANDLE_VALUE) {
605       bfd->lerror = GetLastError();
606       bfd->berrno = b_errno_win32;
607       errno = b_errno_win32;
608       bfd->mode = BF_CLOSED;
609    }
610    bfd->errmsg = NULL;
611    bfd->lpContext = NULL;
612    bfd->win32DecompContext.bIsInData = false;
613    bfd->win32DecompContext.liNextHeader = 0;
614    free_pool_memory(win32_fname_wchar);
615    free_pool_memory(win32_fname);
616    return bfd->mode == BF_CLOSED ? -1 : 1;
617 }
618
619 /*
620  * Returns  0 on success
621  *         -1 on error
622  */
623 int bclose(BFILE *bfd)
624 {
625    int stat = 0;
626
627    if (bfd->mode == BF_CLOSED) {
628       Dmsg0(50, "=== BFD already closed.\n");
629       return 0;
630    }
631
632    if (bfd->cmd_plugin && plugin_bclose) {
633       stat = plugin_bclose(bfd);
634       Dmsg0(50, "==== BFD closed!!!\n");
635       goto all_done;
636    }
637
638    /*
639     * We need to tell the API to release the buffer it
640     *  allocated in lpContext.  We do so by calling the
641     *  API one more time, but with the Abort bit set.
642     */
643    if (bfd->use_backup_api && bfd->mode == BF_READ) {
644       BYTE buf[10];
645       if (bfd->lpContext && !p_BackupRead(bfd->fh,
646               buf,                    /* buffer */
647               (DWORD)0,               /* bytes to read */
648               &bfd->rw_bytes,         /* bytes read */
649               1,                      /* Abort */
650               1,                      /* ProcessSecurity */
651               &bfd->lpContext)) {     /* Read context */
652          errno = b_errno_win32;
653          stat = -1;
654       }
655    } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
656       BYTE buf[10];
657       if (bfd->lpContext && !p_BackupWrite(bfd->fh,
658               buf,                    /* buffer */
659               (DWORD)0,               /* bytes to read */
660               &bfd->rw_bytes,         /* bytes written */
661               1,                      /* Abort */
662               1,                      /* ProcessSecurity */
663               &bfd->lpContext)) {     /* Write context */
664          errno = b_errno_win32;
665          stat = -1;
666       }
667    }
668    if (!CloseHandle(bfd->fh)) {
669       stat = -1;
670       errno = b_errno_win32;
671    }
672
673 all_done:
674    if (bfd->errmsg) {
675       free_pool_memory(bfd->errmsg);
676       bfd->errmsg = NULL;
677    }
678    bfd->mode = BF_CLOSED;
679    bfd->lpContext = NULL;
680    bfd->cmd_plugin = false;
681    return stat;
682 }
683
684 /* Returns: bytes read on success
685  *           0         on EOF
686  *          -1         on error
687  */
688 ssize_t bread(BFILE *bfd, void *buf, size_t count)
689 {
690    bfd->rw_bytes = 0;
691
692    if (bfd->cmd_plugin && plugin_bread) {
693       return plugin_bread(bfd, buf, count);
694    }
695
696    if (bfd->use_backup_api) {
697       if (!p_BackupRead(bfd->fh,
698            (BYTE *)buf,
699            count,
700            &bfd->rw_bytes,
701            0,                           /* no Abort */
702            1,                           /* Process Security */
703            &bfd->lpContext)) {          /* Context */
704          bfd->lerror = GetLastError();
705          bfd->berrno = b_errno_win32;
706          errno = b_errno_win32;
707          return -1;
708       }
709    } else {
710       if (!ReadFile(bfd->fh,
711            buf,
712            count,
713            &bfd->rw_bytes,
714            NULL)) {
715          bfd->lerror = GetLastError();
716          bfd->berrno = b_errno_win32;
717          errno = b_errno_win32;
718          return -1;
719       }
720    }
721
722    return (ssize_t)bfd->rw_bytes;
723 }
724
725 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
726 {
727    bfd->rw_bytes = 0;
728
729    if (bfd->cmd_plugin && plugin_bwrite) {
730       return plugin_bwrite(bfd, buf, count);
731    }
732
733    if (bfd->use_backup_api) {
734       if (!p_BackupWrite(bfd->fh,
735            (BYTE *)buf,
736            count,
737            &bfd->rw_bytes,
738            0,                           /* No abort */
739            1,                           /* Process Security */
740            &bfd->lpContext)) {          /* Context */
741          bfd->lerror = GetLastError();
742          bfd->berrno = b_errno_win32;
743          errno = b_errno_win32;
744          return -1;
745       }
746    } else {
747       if (!WriteFile(bfd->fh,
748            buf,
749            count,
750            &bfd->rw_bytes,
751            NULL)) {
752          bfd->lerror = GetLastError();
753          bfd->berrno = b_errno_win32;
754          errno = b_errno_win32;
755          return -1;
756       }
757    }
758    return (ssize_t)bfd->rw_bytes;
759 }
760
761 bool is_bopen(BFILE *bfd)
762 {
763    return bfd->mode != BF_CLOSED;
764 }
765
766 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
767 {
768    LONG  offset_low = (LONG)offset;
769    LONG  offset_high = (LONG)(offset >> 32);
770    DWORD dwResult;
771
772    if (bfd->cmd_plugin && plugin_blseek) {
773       return plugin_blseek(bfd, offset, whence);
774    }
775
776    dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
777
778    if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
779       return (boffset_t)-1;
780    }
781
782    return ((boffset_t)offset_high << 32) | dwResult;
783 }
784
785 #else  /* Unix systems */
786
787 /* ===============================================================
788  *
789  *            U N I X
790  *
791  * ===============================================================
792  */
793 void binit(BFILE *bfd)
794 {
795    memset(bfd, 0, sizeof(BFILE));
796    bfd->fid = -1;
797 }
798
799 bool have_win32_api()
800 {
801    return false;                       /* no can do */
802 }
803
804 /*
805  * Enables using the Backup API (win32_data).
806  *   Returns true  if function worked
807  *   Returns false if failed (i.e. do not have Backup API on this machine)
808  */
809 bool set_win32_backup(BFILE *bfd)
810 {
811    return false;                       /* no can do */
812 }
813
814
815 bool set_portable_backup(BFILE *bfd)
816 {
817    return true;                        /* no problem */
818 }
819
820 /*
821  * Return true  if we are writing in portable format
822  * return false if not
823  */
824 bool is_portable_backup(BFILE *bfd)
825 {
826    return true;                       /* portable by definition */
827 }
828
829 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
830 {
831    return false;
832 }
833
834 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
835 {
836    bfd->cmd_plugin = true;
837    bfd->jcr = jcr;
838    return true;
839 }
840
841 /* 
842  * This code is running on a non-Win32 machine 
843  */
844 bool is_restore_stream_supported(int stream)
845 {
846    /* No Win32 backup on this machine */
847      switch (stream) {
848 #ifndef HAVE_LIBZ
849    case STREAM_GZIP_DATA:
850    case STREAM_SPARSE_GZIP_DATA:
851    case STREAM_WIN32_GZIP_DATA:    
852 #endif
853 #ifndef HAVE_DARWIN_OS
854    case STREAM_MACOS_FORK_DATA:
855    case STREAM_HFSPLUS_ATTRIBUTES:
856 #endif
857       return false;
858
859    /* Known streams */
860 #ifdef HAVE_LIBZ
861    case STREAM_GZIP_DATA:
862    case STREAM_SPARSE_GZIP_DATA:
863    case STREAM_WIN32_GZIP_DATA:    
864 #endif
865    case STREAM_WIN32_DATA:
866    case STREAM_UNIX_ATTRIBUTES:
867    case STREAM_FILE_DATA:
868    case STREAM_MD5_DIGEST:
869    case STREAM_UNIX_ATTRIBUTES_EX:
870    case STREAM_SPARSE_DATA:
871    case STREAM_PROGRAM_NAMES:
872    case STREAM_PROGRAM_DATA:
873    case STREAM_SHA1_DIGEST:
874 #ifdef HAVE_SHA2
875    case STREAM_SHA256_DIGEST:
876    case STREAM_SHA512_DIGEST:
877 #endif
878 #ifdef HAVE_CRYPTO
879    case STREAM_SIGNED_DIGEST:
880    case STREAM_ENCRYPTED_FILE_DATA:
881    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
882    case STREAM_ENCRYPTED_WIN32_DATA:
883    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
884 #endif
885 #ifdef HAVE_DARWIN_OS
886    case STREAM_MACOS_FORK_DATA:
887    case STREAM_HFSPLUS_ATTRIBUTES:
888 #ifdef HAVE_CRYPTO
889    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
890 #endif /* HAVE_CRYPTO */
891 #endif /* HAVE_DARWIN_OS */
892    case 0:   /* compatibility with old tapes */
893       return true;
894
895    }
896    return false;
897 }
898
899 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
900 {
901    if (bfd->cmd_plugin && plugin_bopen) {
902       Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
903       bfd->fid = plugin_bopen(bfd, fname, flags, mode);
904       Dmsg1(50, "Plugin bopen stat=%d\n", bfd->fid);
905       return bfd->fid;
906    }
907
908    /* Normal file open */
909    Dmsg1(dbglvl, "open file %s\n", fname);
910
911    /* We use fnctl to set O_NOATIME if requested to avoid open error */
912    bfd->fid = open(fname, flags & ~O_NOATIME, mode);
913
914    /* Set O_NOATIME if possible */
915    if (bfd->fid != -1 && flags & O_NOATIME) {
916       int oldflags = fcntl(bfd->fid, F_GETFL, 0);
917       if (oldflags == -1) {
918          bfd->berrno = errno;
919          close(bfd->fid);
920          bfd->fid = -1;
921       } else {
922          int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
923         /* EPERM means setting O_NOATIME was not allowed  */
924          if (ret == -1 && errno != EPERM) {
925             bfd->berrno = errno;
926             close(bfd->fid);
927             bfd->fid = -1;
928          }
929       }
930    }
931    bfd->berrno = errno;
932    bfd->m_flags = flags;
933    Dmsg1(400, "Open file %d\n", bfd->fid);
934    errno = bfd->berrno;
935
936    bfd->win32DecompContext.bIsInData = false;
937    bfd->win32DecompContext.liNextHeader = 0;
938
939 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
940    if (bfd->fid != -1 && flags & O_RDONLY) {
941       int stat = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
942       Dmsg2(400, "Did posix_fadvise on %s stat=%d\n", fname, stat);
943    }
944 #endif
945
946    return bfd->fid;
947 }
948
949 #ifdef HAVE_DARWIN_OS
950 /* Open the resource fork of a file. */
951 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
952 {
953    POOLMEM *rsrc_fname;
954
955    rsrc_fname = get_pool_memory(PM_FNAME);
956    pm_strcpy(rsrc_fname, fname);
957    pm_strcat(rsrc_fname, _PATH_RSRCFORKSPEC);
958    bopen(bfd, rsrc_fname, flags, mode);
959    free_pool_memory(rsrc_fname);
960    return bfd->fid;
961 }
962 #else
963 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
964 {
965    return -1;
966 }
967 #endif
968
969
970 int bclose(BFILE *bfd)
971 {
972    int stat;
973
974    Dmsg1(400, "Close file %d\n", bfd->fid);
975
976    if (bfd->cmd_plugin && plugin_bclose) {
977       stat = plugin_bclose(bfd);
978       bfd->fid = -1;
979       bfd->cmd_plugin = false;
980    }
981
982    if (bfd->fid == -1) {
983       return 0;
984    }
985 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
986    if (bfd->m_flags & O_RDONLY) {
987       fdatasync(bfd->fid);            /* sync the file */
988       /* Tell OS we don't need it any more */
989       posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
990    }
991 #endif
992
993    /* Close normal file */
994    stat = close(bfd->fid);
995    bfd->berrno = errno;
996    bfd->fid = -1;
997    bfd->cmd_plugin = false;
998    return stat;
999 }
1000
1001 ssize_t bread(BFILE *bfd, void *buf, size_t count)
1002 {
1003    ssize_t stat;
1004
1005    if (bfd->cmd_plugin && plugin_bread) {
1006       return plugin_bread(bfd, buf, count);
1007    }
1008
1009    stat = read(bfd->fid, buf, count);
1010    bfd->berrno = errno;
1011    return stat;
1012 }
1013
1014 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
1015 {
1016    ssize_t stat;
1017
1018    if (bfd->cmd_plugin && plugin_bwrite) {
1019       return plugin_bwrite(bfd, buf, count);
1020    }
1021    stat = write(bfd->fid, buf, count);
1022    bfd->berrno = errno;
1023    return stat;
1024 }
1025
1026 bool is_bopen(BFILE *bfd)
1027 {
1028    return bfd->fid >= 0;
1029 }
1030
1031 boffset_t blseek(BFILE *bfd, boffset_t offset, int whence)
1032 {
1033    boffset_t pos;
1034
1035    if (bfd->cmd_plugin && plugin_bwrite) {
1036       return plugin_blseek(bfd, offset, whence);
1037    }
1038    pos = (boffset_t)lseek(bfd->fid, offset, whence);
1039    bfd->berrno = errno;
1040    return pos;
1041 }
1042
1043 #endif