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 true if we support the stream
252 * false if we do not support the stream
254 bool is_stream_supported(int stream)
256 /* No Win32 backup on this machine */
258 case STREAM_WIN32_DATA:
260 case STREAM_WIN32_GZIP_DATA:
262 #ifdef USE_WIN32STREAMEXTRACTION
265 return have_win32_api();
268 /* Streams known not to be supported */
270 case STREAM_GZIP_DATA:
271 case STREAM_SPARSE_GZIP_DATA:
272 case STREAM_WIN32_GZIP_DATA:
274 case STREAM_MACOS_FORK_DATA:
275 case STREAM_HFSPLUS_ATTRIBUTES:
280 case STREAM_GZIP_DATA:
281 case STREAM_SPARSE_GZIP_DATA:
283 case STREAM_UNIX_ATTRIBUTES:
284 case STREAM_FILE_DATA:
285 case STREAM_MD5_SIGNATURE:
286 case STREAM_UNIX_ATTRIBUTES_EX:
287 case STREAM_SPARSE_DATA:
288 case STREAM_PROGRAM_NAMES:
289 case STREAM_PROGRAM_DATA:
290 case STREAM_SHA1_SIGNATURE:
291 case 0: /* compatibility with old tapes */
297 HANDLE bget_handle(BFILE *bfd)
302 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
304 POOLMEM *win32_fname;
305 POOLMEM *win32_fname_wchar;
307 DWORD dwaccess, dwflags, dwshare;
309 /* Convert to Windows path format */
310 win32_fname = get_pool_memory(PM_FNAME);
311 win32_fname_wchar = get_pool_memory(PM_FNAME);
313 unix_name_to_win32(&win32_fname, (char *)fname);
315 if (!(p_CreateFileA || p_CreateFileW))
318 if (p_CreateFileW && p_MultiByteToWideChar)
319 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
321 if (flags & O_CREAT) { /* Create */
322 if (bfd->use_backup_api) {
323 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
324 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
326 dwaccess = GENERIC_WRITE;
330 // unicode or ansii open for create write
331 if (p_CreateFileW && p_MultiByteToWideChar) {
332 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
333 dwaccess, /* Requested access */
335 NULL, /* SecurityAttributes */
336 CREATE_ALWAYS, /* CreationDisposition */
337 dwflags, /* Flags and attributes */
338 NULL); /* TemplateFile */
341 bfd->fh = p_CreateFileA(win32_fname,
342 dwaccess, /* Requested access */
344 NULL, /* SecurityAttributes */
345 CREATE_ALWAYS, /* CreationDisposition */
346 dwflags, /* Flags and attributes */
347 NULL); /* TemplateFile */
351 bfd->mode = BF_WRITE;
353 } else if (flags & O_WRONLY) { /* Open existing for write */
354 if (bfd->use_backup_api) {
355 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
356 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
358 dwaccess = GENERIC_WRITE;
362 // unicode or ansii open for open existing write
363 if (p_CreateFileW && p_MultiByteToWideChar) {
364 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
365 dwaccess, /* Requested access */
367 NULL, /* SecurityAttributes */
368 OPEN_EXISTING, /* CreationDisposition */
369 dwflags, /* Flags and attributes */
370 NULL); /* TemplateFile */
373 bfd->fh = p_CreateFileA(win32_fname,
374 dwaccess, /* Requested access */
376 NULL, /* SecurityAttributes */
377 OPEN_EXISTING, /* CreationDisposition */
378 dwflags, /* Flags and attributes */
379 NULL); /* TemplateFile */
383 bfd->mode = BF_WRITE;
386 if (bfd->use_backup_api) {
387 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
388 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
389 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
391 dwaccess = GENERIC_READ;
393 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
396 // unicode or ansii open for open existing read
397 if (p_CreateFileW && p_MultiByteToWideChar) {
398 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
399 dwaccess, /* Requested access */
400 dwshare, /* Share modes */
401 NULL, /* SecurityAttributes */
402 OPEN_EXISTING, /* CreationDisposition */
403 dwflags, /* Flags and attributes */
404 NULL); /* TemplateFile */
407 bfd->fh = p_CreateFileA(win32_fname,
408 dwaccess, /* Requested access */
409 dwshare, /* Share modes */
410 NULL, /* SecurityAttributes */
411 OPEN_EXISTING, /* CreationDisposition */
412 dwflags, /* Flags and attributes */
413 NULL); /* TemplateFile */
419 if (bfd->fh == INVALID_HANDLE_VALUE) {
420 bfd->lerror = GetLastError();
421 bfd->berrno = b_errno_win32;
422 errno = b_errno_win32;
423 bfd->mode = BF_CLOSED;
426 bfd->lpContext = NULL;
427 #ifdef USE_WIN32STREAMEXTRACTION
428 bfd->win32DecompContext.bIsInData = FALSE;
429 bfd->win32DecompContext.liNextHeader = 0;
431 free_pool_memory(win32_fname_wchar);
432 free_pool_memory(win32_fname);
433 return bfd->mode == BF_CLOSED ? -1 : 1;
437 * Returns 0 on success
440 int bclose(BFILE *bfd)
445 free_pool_memory(bfd->errmsg);
448 if (bfd->mode == BF_CLOSED) {
451 if (bfd->use_backup_api && bfd->mode == BF_READ) {
453 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
455 (DWORD)0, /* bytes to read */
456 &bfd->rw_bytes, /* bytes read */
458 1, /* ProcessSecurity */
459 &bfd->lpContext)) { /* Read context */
460 errno = b_errno_win32;
463 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
465 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
467 (DWORD)0, /* bytes to read */
468 &bfd->rw_bytes, /* bytes written */
470 1, /* ProcessSecurity */
471 &bfd->lpContext)) { /* Write context */
472 errno = b_errno_win32;
476 if (!CloseHandle(bfd->fh)) {
478 errno = b_errno_win32;
480 bfd->mode = BF_CLOSED;
481 bfd->lpContext = NULL;
485 /* Returns: bytes read on success
489 ssize_t bread(BFILE *bfd, void *buf, size_t count)
493 if (bfd->use_backup_api) {
494 if (!p_BackupRead(bfd->fh,
499 1, /* Process Security */
500 &bfd->lpContext)) { /* Context */
501 bfd->lerror = GetLastError();
502 bfd->berrno = b_errno_win32;
503 errno = b_errno_win32;
507 if (!ReadFile(bfd->fh,
512 bfd->lerror = GetLastError();
513 bfd->berrno = b_errno_win32;
514 errno = b_errno_win32;
519 return (ssize_t)bfd->rw_bytes;
522 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
526 if (bfd->use_backup_api) {
527 if (!p_BackupWrite(bfd->fh,
532 1, /* Process Security */
533 &bfd->lpContext)) { /* Context */
534 bfd->lerror = GetLastError();
535 bfd->berrno = b_errno_win32;
536 errno = b_errno_win32;
540 if (!WriteFile(bfd->fh,
545 bfd->lerror = GetLastError();
546 bfd->berrno = b_errno_win32;
547 errno = b_errno_win32;
551 return (ssize_t)bfd->rw_bytes;
554 bool is_bopen(BFILE *bfd)
556 return bfd->mode != BF_CLOSED;
559 off_t blseek(BFILE *bfd, off_t offset, int whence)
561 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
565 #else /* Unix systems */
567 /* ===============================================================
571 * ===============================================================
573 void binit(BFILE *bfd)
575 memset(bfd, 0, sizeof(BFILE));
579 bool have_win32_api()
581 return false; /* no can do */
585 * Enables using the Backup API (win32_data).
586 * Returns true if function worked
587 * Returns false if failed (i.e. do not have Backup API on this machine)
589 bool set_win32_backup(BFILE *bfd)
591 return false; /* no can do */
595 bool set_portable_backup(BFILE *bfd)
597 return true; /* no problem */
601 * Return true if we are writing in portable format
602 * return false if not
604 bool is_portable_backup(BFILE *bfd)
606 return true; /* portable by definition */
609 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
612 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
613 return true; /* already setup */
616 if (python_set_prog(jcr, prog)) {
617 Dmsg1(000, "Set prog=%s\n", prog);
623 Dmsg0(000, "No prog set\n");
630 bool is_stream_supported(int stream)
632 /* No Win32 backup on this machine */
635 case STREAM_GZIP_DATA:
636 case STREAM_SPARSE_GZIP_DATA:
637 case STREAM_WIN32_GZIP_DATA:
639 #ifndef USE_WIN32STREAMEXTRACTION
640 case STREAM_WIN32_DATA:
642 #ifndef HAVE_DARWIN_OS
643 case STREAM_MACOS_FORK_DATA:
644 case STREAM_HFSPLUS_ATTRIBUTES:
651 case STREAM_GZIP_DATA:
652 case STREAM_SPARSE_GZIP_DATA:
654 #ifdef USE_WIN32STREAMEXTRACTION
655 case STREAM_WIN32_DATA:
657 case STREAM_WIN32_GZIP_DATA:
660 case STREAM_UNIX_ATTRIBUTES:
661 case STREAM_FILE_DATA:
662 case STREAM_MD5_SIGNATURE:
663 case STREAM_UNIX_ATTRIBUTES_EX:
664 case STREAM_SPARSE_DATA:
665 case STREAM_PROGRAM_NAMES:
666 case STREAM_PROGRAM_DATA:
667 case STREAM_SHA1_SIGNATURE:
668 #ifdef HAVE_DARWIN_OS
669 case STREAM_MACOS_FORK_DATA:
670 case STREAM_HFSPLUS_ATTRIBUTES:
672 case 0: /* compatibility with old tapes */
679 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
681 /* Open reader/writer program */
683 Dmsg1(000, "Open file %d\n", bfd->fid);
684 return python_open(bfd, fname, flags, mode);
687 /* Normal file open */
688 bfd->fid = open(fname, flags, mode);
690 Dmsg1(400, "Open file %d\n", bfd->fid);
693 #ifdef USE_WIN32STREAMEXTRACTION
694 bfd->win32DecompContext.bIsInData = FALSE;
695 bfd->win32DecompContext.liNextHeader = 0;
701 #ifdef HAVE_DARWIN_OS
702 /* Open the resource fork of a file. */
703 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
708 fname_len = strlen(fname);
709 rsrc_fname = get_pool_memory(PM_FNAME);
710 bstrncpy(rsrc_fname, fname, fname_len + 1);
711 bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC,
712 strlen(_PATH_RSRCFORKSPEC) + 1);
713 bopen(bfd, rsrc_fname, flags, mode);
714 free_pool_memory(rsrc_fname);
720 int bclose(BFILE *bfd)
724 Dmsg1(400, "Close file %d\n", bfd->fid);
726 /* Close reader/writer program */
728 return python_close(bfd);
731 if (bfd->fid == -1) {
735 /* Close normal file */
736 stat = close(bfd->fid);
742 ssize_t bread(BFILE *bfd, void *buf, size_t count)
747 return python_read(bfd, buf, count);
749 stat = read(bfd->fid, buf, count);
754 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
759 return python_write(bfd, buf, count);
761 stat = write(bfd->fid, buf, count);
766 bool is_bopen(BFILE *bfd)
768 return bfd->fid >= 0;
771 off_t blseek(BFILE *bfd, off_t offset, int whence)
774 pos = lseek(bfd->fid, offset, whence);