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
100 called in successive incremental order over the complete
101 BackupRead stream beginning at pos 0 and ending at the end.
104 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
105 BOOL bContinue = FALSE;
106 LONGLONG dwDataOffset = 0;
109 /* Win32 Stream Header size without name of stream.
110 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
112 DWORD dwSizeHeader = 20;
115 if (pContext->liNextHeader >= dwSize) {
116 dwDataLen = dwSize-dwDataOffset;
117 bContinue = FALSE; /* 1 iteration is enough */
120 dwDataLen = pContext->liNextHeader-dwDataOffset;
121 bContinue = TRUE; /* multiple iterations may be necessary */
125 /* copy block of real DATA */
126 if (pContext->bIsInData) {
127 if (bwrite(bfd, ((LPBYTE)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
131 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
132 DWORD dwOffsetTarget;
133 DWORD dwOffsetSource;
135 if (pContext->liNextHeader < 0) {
136 /* start of header was before this block, so we
137 * continue with the part in the current block
139 dwOffsetTarget = abs (pContext->liNextHeader);
143 /* start of header is inside of this block */
145 dwOffsetSource = pContext->liNextHeader;
148 DWORD dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
149 BOOL bHeaderIsComplete;
151 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
152 /* header (or rest of header) is completely available
155 bHeaderIsComplete = TRUE;
157 /* header will continue in next block */
158 bHeaderIsComplete = FALSE;
159 dwHeaderPartLen = dwSize-dwOffsetSource;
162 /* copy the available portion of header to persistent copy */
163 memcpy (((LPBYTE) &pContext->header_stream)+dwOffsetTarget, ((LPBYTE) pBuffer)+dwOffsetSource, dwHeaderPartLen);
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)
174 /* stop and continue with next block */
176 pContext->bIsInData = FALSE;
181 /* set "NextHeader" relative to the beginning of the next block */
182 pContext->liNextHeader-= dwSize;
190 /* ===============================================================
194 * ===============================================================
197 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
199 void unix_name_to_win32(POOLMEM **win32_name, char *name);
200 extern "C" HANDLE get_osfhandle(int fd);
204 void binit(BFILE *bfd)
206 memset(bfd, 0, sizeof(BFILE));
208 bfd->mode = BF_CLOSED;
209 bfd->use_backup_api = have_win32_api();
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)
217 bool set_win32_backup(BFILE *bfd)
219 /* We enable if possible here */
220 bfd->use_backup_api = have_win32_api();
221 return bfd->use_backup_api;
225 bool set_portable_backup(BFILE *bfd)
227 bfd->use_backup_api = false;
231 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
239 * Return 1 if we are NOT using Win32 BackupWrite()
242 bool is_portable_backup(BFILE *bfd)
244 return !bfd->use_backup_api;
247 bool have_win32_api()
249 return p_BackupRead && p_BackupWrite;
255 * Return true if we support the stream
256 * false if we do not support the stream
258 bool is_stream_supported(int stream)
260 /* No Win32 backup on this machine */
262 case STREAM_WIN32_DATA:
264 case STREAM_WIN32_GZIP_DATA:
266 #ifdef USE_WIN32STREAMEXTRACTION
269 return have_win32_api();
272 /* Streams known not to be supported */
274 case STREAM_GZIP_DATA:
275 case STREAM_SPARSE_GZIP_DATA:
276 case STREAM_WIN32_GZIP_DATA:
278 case STREAM_MACOS_FORK_DATA:
279 case STREAM_HFSPLUS_ATTRIBUTES:
284 case STREAM_GZIP_DATA:
285 case STREAM_SPARSE_GZIP_DATA:
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 */
301 HANDLE bget_handle(BFILE *bfd)
306 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
308 POOLMEM *win32_fname;
309 POOLMEM *win32_fname_wchar;
311 DWORD dwaccess, dwflags, dwshare;
313 /* Convert to Windows path format */
314 win32_fname = get_pool_memory(PM_FNAME);
315 win32_fname_wchar = get_pool_memory(PM_FNAME);
317 unix_name_to_win32(&win32_fname, (char *)fname);
319 if (!(p_CreateFileA || p_CreateFileW))
322 if (p_CreateFileW && p_MultiByteToWideChar)
323 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
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;
330 dwaccess = GENERIC_WRITE;
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 */
339 NULL, /* SecurityAttributes */
340 CREATE_ALWAYS, /* CreationDisposition */
341 dwflags, /* Flags and attributes */
342 NULL); /* TemplateFile */
345 bfd->fh = p_CreateFileA(win32_fname,
346 dwaccess, /* Requested access */
348 NULL, /* SecurityAttributes */
349 CREATE_ALWAYS, /* CreationDisposition */
350 dwflags, /* Flags and attributes */
351 NULL); /* TemplateFile */
355 bfd->mode = BF_WRITE;
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;
362 dwaccess = GENERIC_WRITE;
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 */
371 NULL, /* SecurityAttributes */
372 OPEN_EXISTING, /* CreationDisposition */
373 dwflags, /* Flags and attributes */
374 NULL); /* TemplateFile */
377 bfd->fh = p_CreateFileA(win32_fname,
378 dwaccess, /* Requested access */
380 NULL, /* SecurityAttributes */
381 OPEN_EXISTING, /* CreationDisposition */
382 dwflags, /* Flags and attributes */
383 NULL); /* TemplateFile */
387 bfd->mode = BF_WRITE;
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;
395 dwaccess = GENERIC_READ;
397 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
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 */
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 */
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;
430 bfd->lpContext = NULL;
431 #ifdef USE_WIN32STREAMEXTRACTION
432 bfd->win32DecompContext.bIsInData = FALSE;
433 bfd->win32DecompContext.liNextHeader = 0;
435 free_pool_memory(win32_fname_wchar);
436 free_pool_memory(win32_fname);
437 return bfd->mode == BF_CLOSED ? -1 : 1;
441 * Returns 0 on success
444 int bclose(BFILE *bfd)
449 free_pool_memory(bfd->errmsg);
452 if (bfd->mode == BF_CLOSED) {
455 if (bfd->use_backup_api && bfd->mode == BF_READ) {
457 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
459 (DWORD)0, /* bytes to read */
460 &bfd->rw_bytes, /* bytes read */
462 1, /* ProcessSecurity */
463 &bfd->lpContext)) { /* Read context */
464 errno = b_errno_win32;
467 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
469 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
471 (DWORD)0, /* bytes to read */
472 &bfd->rw_bytes, /* bytes written */
474 1, /* ProcessSecurity */
475 &bfd->lpContext)) { /* Write context */
476 errno = b_errno_win32;
480 if (!CloseHandle(bfd->fh)) {
482 errno = b_errno_win32;
484 bfd->mode = BF_CLOSED;
485 bfd->lpContext = NULL;
489 /* Returns: bytes read on success
493 ssize_t bread(BFILE *bfd, void *buf, size_t count)
497 if (bfd->use_backup_api) {
498 if (!p_BackupRead(bfd->fh,
503 1, /* Process Security */
504 &bfd->lpContext)) { /* Context */
505 bfd->lerror = GetLastError();
506 bfd->berrno = b_errno_win32;
507 errno = b_errno_win32;
511 if (!ReadFile(bfd->fh,
516 bfd->lerror = GetLastError();
517 bfd->berrno = b_errno_win32;
518 errno = b_errno_win32;
523 return (ssize_t)bfd->rw_bytes;
526 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
530 if (bfd->use_backup_api) {
531 if (!p_BackupWrite(bfd->fh,
536 1, /* Process Security */
537 &bfd->lpContext)) { /* Context */
538 bfd->lerror = GetLastError();
539 bfd->berrno = b_errno_win32;
540 errno = b_errno_win32;
544 if (!WriteFile(bfd->fh,
549 bfd->lerror = GetLastError();
550 bfd->berrno = b_errno_win32;
551 errno = b_errno_win32;
555 return (ssize_t)bfd->rw_bytes;
558 bool is_bopen(BFILE *bfd)
560 return bfd->mode != BF_CLOSED;
563 off_t blseek(BFILE *bfd, off_t offset, int whence)
565 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
569 #else /* Unix systems */
571 /* ===============================================================
575 * ===============================================================
577 void binit(BFILE *bfd)
579 memset(bfd, 0, sizeof(BFILE));
583 bool have_win32_api()
585 return false; /* no can do */
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)
593 bool set_win32_backup(BFILE *bfd)
595 return false; /* no can do */
599 bool set_portable_backup(BFILE *bfd)
601 return true; /* no problem */
605 * Return true if we are writing in portable format
606 * return false if not
608 bool is_portable_backup(BFILE *bfd)
610 return true; /* portable by definition */
613 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
616 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
617 return true; /* already setup */
620 if (python_set_prog(jcr, prog)) {
621 Dmsg1(000, "Set prog=%s\n", prog);
627 Dmsg0(000, "No prog set\n");
634 bool is_stream_supported(int stream)
636 /* No Win32 backup on this machine */
639 case STREAM_GZIP_DATA:
640 case STREAM_SPARSE_GZIP_DATA:
641 case STREAM_WIN32_GZIP_DATA:
643 #ifndef USE_WIN32STREAMEXTRACTION
644 case STREAM_WIN32_DATA:
646 #ifndef HAVE_DARWIN_OS
647 case STREAM_MACOS_FORK_DATA:
648 case STREAM_HFSPLUS_ATTRIBUTES:
654 case STREAM_GZIP_DATA:
655 case STREAM_SPARSE_GZIP_DATA:
657 #ifdef USE_WIN32STREAMEXTRACTION
658 case STREAM_WIN32_DATA:
660 case STREAM_WIN32_GZIP_DATA:
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:
675 case 0: /* compatibility with old tapes */
682 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
684 /* Open reader/writer program */
686 Dmsg1(000, "Open file %d\n", bfd->fid);
687 return python_open(bfd, fname, flags, mode);
690 /* Normal file open */
691 bfd->fid = open(fname, flags, mode);
693 Dmsg1(400, "Open file %d\n", bfd->fid);
696 #ifdef USE_WIN32STREAMEXTRACTION
697 bfd->win32DecompContext.bIsInData = FALSE;
698 bfd->win32DecompContext.liNextHeader = 0;
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)
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);
723 int bclose(BFILE *bfd)
727 Dmsg1(400, "Close file %d\n", bfd->fid);
729 /* Close reader/writer program */
731 return python_close(bfd);
734 if (bfd->fid == -1) {
738 /* Close normal file */
739 stat = close(bfd->fid);
745 ssize_t bread(BFILE *bfd, void *buf, size_t count)
750 return python_read(bfd, buf, count);
752 stat = read(bfd->fid, buf, count);
757 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
762 return python_write(bfd, buf, count);
764 stat = write(bfd->fid, buf, count);
769 bool is_bopen(BFILE *bfd)
771 return bfd->fid >= 0;
774 off_t blseek(BFILE *bfd, off_t offset, int whence)
777 pos = lseek(bfd->fid, offset, whence);