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.
6 * Kern Sibbald, April MMIII
12 Copyright (C) 2003-2005 Kern Sibbald
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.
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.
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;
36 #include <sys/paths.h>
39 /* ===============================================================
41 * U N I X AND W I N D O W S
43 * ===============================================================
46 bool is_win32_stream(int stream)
49 case STREAM_WIN32_DATA:
50 case STREAM_WIN32_GZIP_DATA:
56 const char *stream_to_ascii(int 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");
90 sprintf(buf, "%d", stream);
91 return (const char *)buf;
95 #ifdef USE_WIN32STREAMEXTRACTION
96 BOOL processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, size_t dwSize)
98 /* pByte contains the buffer
99 dwSize the len to be processed. function assumes to be called in successive
100 incremental order over the complete BackupRead stream beginning at pos 0 and
101 ending at the end. */
103 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
104 BOOL bContinue = FALSE;
105 LONGLONG dwDataOffset = 0;
108 /* Win32 Stream Header size without name of stream.
109 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
111 DWORD dwSizeHeader = 20;
114 if (pContext->liNextHeader >= dwSize) {
115 dwDataLen = dwSize-dwDataOffset;
116 bContinue = FALSE; /* 1 iteration is enough */
119 dwDataLen = pContext->liNextHeader-dwDataOffset;
120 bContinue = TRUE; /* multiple iterations may be necessary */
124 /* copy block of real DATA */
125 if (pContext->bIsInData) {
126 if (bwrite(bfd, ((LPBYTE)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
130 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
131 DWORD dwOffsetTarget;
132 DWORD dwOffsetSource;
134 if (pContext->liNextHeader < 0) {
135 /* start of header was before this block,
136 so we continue with the part in the current block */
137 dwOffsetTarget = abs (pContext->liNextHeader);
141 /* start of header is inside of this block */
143 dwOffsetSource = pContext->liNextHeader;
146 DWORD dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
147 BOOL bHeaderIsComplete;
149 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
150 /* header (or rest of header) is completely available in current block */
151 bHeaderIsComplete = TRUE;
153 /* header will continue in next block */
154 bHeaderIsComplete = FALSE;
155 dwHeaderPartLen = dwSize-dwOffsetSource;
158 /* copy the available portion of header to persistent copy */
159 memcpy (((LPBYTE) &pContext->header_stream)+dwOffsetTarget, ((LPBYTE) pBuffer)+dwOffsetSource, dwHeaderPartLen);
161 /* recalculate position of next header */
162 if (bHeaderIsComplete) {
163 dwDataOffset = pContext->liNextHeader+dwSizeHeader+pContext->header_stream.dwStreamNameSize;
164 pContext->liNextHeader = dwDataOffset+pContext->header_stream.Size.QuadPart;
165 pContext->bIsInData = pContext->header_stream.dwStreamId == BACKUP_DATA;
166 if (dwDataOffset == dwSize)
170 /* stop and continue with next block */
172 pContext->bIsInData = FALSE;
177 /* set "NextHeader" relative to the beginning of the next block */
178 pContext->liNextHeader-= dwSize;
186 /* ===============================================================
190 * ===============================================================
193 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
195 void unix_name_to_win32(POOLMEM **win32_name, char *name);
196 extern "C" HANDLE get_osfhandle(int fd);
200 void binit(BFILE *bfd)
202 memset(bfd, 0, sizeof(BFILE));
204 bfd->mode = BF_CLOSED;
205 bfd->use_backup_api = have_win32_api();
209 * Enables using the Backup API (win32_data).
210 * Returns 1 if function worked
211 * Returns 0 if failed (i.e. do not have Backup API on this machine)
213 bool set_win32_backup(BFILE *bfd)
215 /* We enable if possible here */
216 bfd->use_backup_api = have_win32_api();
217 return bfd->use_backup_api;
221 bool set_portable_backup(BFILE *bfd)
223 bfd->use_backup_api = false;
227 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
235 * Return 1 if we are NOT using Win32 BackupWrite()
238 bool is_portable_backup(BFILE *bfd)
240 return !bfd->use_backup_api;
243 bool have_win32_api()
245 return p_BackupRead && p_BackupWrite;
251 * Return 1 if we support the stream
252 * 0 if we do not support the stream
254 bool is_stream_supported(int stream)
256 /* No Win32 backup on this machine */
259 case STREAM_GZIP_DATA:
260 case STREAM_SPARSE_GZIP_DATA:
263 case STREAM_WIN32_DATA:
264 case STREAM_WIN32_GZIP_DATA:
265 #ifdef USE_WIN32STREAMEXTRACTION
268 return have_win32_api();
272 case STREAM_MACOS_FORK_DATA:
273 case STREAM_HFSPLUS_ATTRIBUTES:
278 case STREAM_GZIP_DATA:
279 case STREAM_SPARSE_GZIP_DATA:
281 case STREAM_UNIX_ATTRIBUTES:
282 case STREAM_FILE_DATA:
283 case STREAM_MD5_SIGNATURE:
284 case STREAM_UNIX_ATTRIBUTES_EX:
285 case STREAM_SPARSE_DATA:
286 case STREAM_PROGRAM_NAMES:
287 case STREAM_PROGRAM_DATA:
288 case STREAM_SHA1_SIGNATURE:
289 case 0: /* compatibility with old tapes */
295 HANDLE bget_handle(BFILE *bfd)
300 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
302 POOLMEM *win32_fname;
303 POOLMEM *win32_fname_wchar;
305 DWORD dwaccess, dwflags, dwshare;
307 /* Convert to Windows path format */
308 win32_fname = get_pool_memory(PM_FNAME);
309 win32_fname_wchar = get_pool_memory(PM_FNAME);
311 unix_name_to_win32(&win32_fname, (char *)fname);
313 if (!(p_CreateFileA || p_CreateFileW))
316 if (p_CreateFileW && p_MultiByteToWideChar)
317 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
319 if (flags & O_CREAT) { /* Create */
320 if (bfd->use_backup_api) {
321 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
322 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
324 dwaccess = GENERIC_WRITE;
328 // unicode or ansii open for create write
329 if (p_CreateFileW && p_MultiByteToWideChar) {
330 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
331 dwaccess, /* Requested access */
333 NULL, /* SecurityAttributes */
334 CREATE_ALWAYS, /* CreationDisposition */
335 dwflags, /* Flags and attributes */
336 NULL); /* TemplateFile */
339 bfd->fh = p_CreateFileA(win32_fname,
340 dwaccess, /* Requested access */
342 NULL, /* SecurityAttributes */
343 CREATE_ALWAYS, /* CreationDisposition */
344 dwflags, /* Flags and attributes */
345 NULL); /* TemplateFile */
349 bfd->mode = BF_WRITE;
351 } else if (flags & O_WRONLY) { /* Open existing for write */
352 if (bfd->use_backup_api) {
353 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
354 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
356 dwaccess = GENERIC_WRITE;
360 // unicode or ansii open for open existing write
361 if (p_CreateFileW && p_MultiByteToWideChar) {
362 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
363 dwaccess, /* Requested access */
365 NULL, /* SecurityAttributes */
366 OPEN_EXISTING, /* CreationDisposition */
367 dwflags, /* Flags and attributes */
368 NULL); /* TemplateFile */
371 bfd->fh = p_CreateFileA(win32_fname,
372 dwaccess, /* Requested access */
374 NULL, /* SecurityAttributes */
375 OPEN_EXISTING, /* CreationDisposition */
376 dwflags, /* Flags and attributes */
377 NULL); /* TemplateFile */
381 bfd->mode = BF_WRITE;
384 if (bfd->use_backup_api) {
385 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
386 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
387 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
389 dwaccess = GENERIC_READ;
391 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
394 // unicode or ansii open for open existing read
395 if (p_CreateFileW && p_MultiByteToWideChar) {
396 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
397 dwaccess, /* Requested access */
398 dwshare, /* Share modes */
399 NULL, /* SecurityAttributes */
400 OPEN_EXISTING, /* CreationDisposition */
401 dwflags, /* Flags and attributes */
402 NULL); /* TemplateFile */
405 bfd->fh = p_CreateFileA(win32_fname,
406 dwaccess, /* Requested access */
407 dwshare, /* Share modes */
408 NULL, /* SecurityAttributes */
409 OPEN_EXISTING, /* CreationDisposition */
410 dwflags, /* Flags and attributes */
411 NULL); /* TemplateFile */
417 if (bfd->fh == INVALID_HANDLE_VALUE) {
418 bfd->lerror = GetLastError();
419 bfd->berrno = b_errno_win32;
420 errno = b_errno_win32;
421 bfd->mode = BF_CLOSED;
424 bfd->lpContext = NULL;
425 #ifdef USE_WIN32STREAMEXTRACTION
426 bfd->win32DecompContext.bIsInData = FALSE;
427 bfd->win32DecompContext.liNextHeader = 0;
429 free_pool_memory(win32_fname_wchar);
430 free_pool_memory(win32_fname);
431 return bfd->mode == BF_CLOSED ? -1 : 1;
435 * Returns 0 on success
438 int bclose(BFILE *bfd)
443 free_pool_memory(bfd->errmsg);
446 if (bfd->mode == BF_CLOSED) {
449 if (bfd->use_backup_api && bfd->mode == BF_READ) {
451 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
453 (DWORD)0, /* bytes to read */
454 &bfd->rw_bytes, /* bytes read */
456 1, /* ProcessSecurity */
457 &bfd->lpContext)) { /* Read context */
458 errno = b_errno_win32;
461 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
463 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
465 (DWORD)0, /* bytes to read */
466 &bfd->rw_bytes, /* bytes written */
468 1, /* ProcessSecurity */
469 &bfd->lpContext)) { /* Write context */
470 errno = b_errno_win32;
474 if (!CloseHandle(bfd->fh)) {
476 errno = b_errno_win32;
478 bfd->mode = BF_CLOSED;
479 bfd->lpContext = NULL;
483 /* Returns: bytes read on success
487 ssize_t bread(BFILE *bfd, void *buf, size_t count)
491 if (bfd->use_backup_api) {
492 if (!p_BackupRead(bfd->fh,
497 1, /* Process Security */
498 &bfd->lpContext)) { /* Context */
499 bfd->lerror = GetLastError();
500 bfd->berrno = b_errno_win32;
501 errno = b_errno_win32;
505 if (!ReadFile(bfd->fh,
510 bfd->lerror = GetLastError();
511 bfd->berrno = b_errno_win32;
512 errno = b_errno_win32;
517 return (ssize_t)bfd->rw_bytes;
520 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
524 if (bfd->use_backup_api) {
525 if (!p_BackupWrite(bfd->fh,
530 1, /* Process Security */
531 &bfd->lpContext)) { /* Context */
532 bfd->lerror = GetLastError();
533 bfd->berrno = b_errno_win32;
534 errno = b_errno_win32;
538 if (!WriteFile(bfd->fh,
543 bfd->lerror = GetLastError();
544 bfd->berrno = b_errno_win32;
545 errno = b_errno_win32;
549 return (ssize_t)bfd->rw_bytes;
552 bool is_bopen(BFILE *bfd)
554 return bfd->mode != BF_CLOSED;
557 off_t blseek(BFILE *bfd, off_t offset, int whence)
559 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
563 #else /* Unix systems */
565 /* ===============================================================
569 * ===============================================================
571 void binit(BFILE *bfd)
573 memset(bfd, 0, sizeof(BFILE));
577 bool have_win32_api()
579 return false; /* no can do */
583 * Enables using the Backup API (win32_data).
584 * Returns true if function worked
585 * Returns false if failed (i.e. do not have Backup API on this machine)
587 bool set_win32_backup(BFILE *bfd)
589 return false; /* no can do */
593 bool set_portable_backup(BFILE *bfd)
595 return true; /* no problem */
599 * Return true if we are writing in portable format
600 * return false if not
602 bool is_portable_backup(BFILE *bfd)
604 return true; /* portable by definition */
607 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
610 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
611 return true; /* already setup */
614 if (python_set_prog(jcr, prog)) {
615 Dmsg1(000, "Set prog=%s\n", prog);
621 Dmsg0(000, "No prog set\n");
628 bool is_stream_supported(int stream)
630 /* No Win32 backup on this machine */
633 case STREAM_GZIP_DATA:
634 case STREAM_SPARSE_GZIP_DATA:
635 case STREAM_WIN32_GZIP_DATA:
637 #ifndef USE_WIN32STREAMEXTRACTION
638 case STREAM_WIN32_DATA:
640 #ifndef HAVE_DARWIN_OS
641 case STREAM_MACOS_FORK_DATA:
642 case STREAM_HFSPLUS_ATTRIBUTES:
649 case STREAM_GZIP_DATA:
650 case STREAM_SPARSE_GZIP_DATA:
652 #ifdef USE_WIN32STREAMEXTRACTION
653 case STREAM_WIN32_DATA:
655 case STREAM_WIN32_GZIP_DATA:
658 case STREAM_UNIX_ATTRIBUTES:
659 case STREAM_FILE_DATA:
660 case STREAM_MD5_SIGNATURE:
661 case STREAM_UNIX_ATTRIBUTES_EX:
662 case STREAM_SPARSE_DATA:
663 case STREAM_PROGRAM_NAMES:
664 case STREAM_PROGRAM_DATA:
665 case STREAM_SHA1_SIGNATURE:
666 #ifdef HAVE_DARWIN_OS
667 case STREAM_MACOS_FORK_DATA:
668 case STREAM_HFSPLUS_ATTRIBUTES:
670 case 0: /* compatibility with old tapes */
677 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
679 /* Open reader/writer program */
681 Dmsg1(000, "Open file %d\n", bfd->fid);
682 return python_open(bfd, fname, flags, mode);
685 /* Normal file open */
686 bfd->fid = open(fname, flags, mode);
688 Dmsg1(400, "Open file %d\n", bfd->fid);
691 #ifdef USE_WIN32STREAMEXTRACTION
692 bfd->win32DecompContext.bIsInData = FALSE;
693 bfd->win32DecompContext.liNextHeader = 0;
699 #ifdef HAVE_DARWIN_OS
700 /* Open the resource fork of a file. */
701 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
706 fname_len = strlen(fname);
707 rsrc_fname = get_pool_memory(PM_FNAME);
708 bstrncpy(rsrc_fname, fname, fname_len + 1);
709 bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC,
710 strlen(_PATH_RSRCFORKSPEC) + 1);
711 bopen(bfd, rsrc_fname, flags, mode);
712 free_pool_memory(rsrc_fname);
718 int bclose(BFILE *bfd)
722 Dmsg1(400, "Close file %d\n", bfd->fid);
724 /* Close reader/writer program */
726 return python_close(bfd);
729 if (bfd->fid == -1) {
733 /* Close normal file */
734 stat = close(bfd->fid);
740 ssize_t bread(BFILE *bfd, void *buf, size_t count)
745 return python_read(bfd, buf, count);
747 stat = read(bfd->fid, buf, count);
752 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
757 return python_write(bfd, buf, count);
759 stat = write(bfd->fid, buf, count);
764 bool is_bopen(BFILE *bfd)
766 return bfd->fid >= 0;
769 off_t blseek(BFILE *bfd, off_t offset, int whence)
772 pos = lseek(bfd->fid, offset, whence);