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
97 void int64_LE2BE(int64_t* pBE, const int64_t v)
99 /* convert little endian to big endian */
100 if (htonl(1) != 1L) { /* no work if on little endian machine */
101 memcpy(pBE, &v, sizeof(int64_t));
104 uint8_t rv[sizeof(int64_t)];
105 uint8_t *pv = (uint8_t *) &v;
107 for (i = 0; i < 8; i++) {
110 memcpy(pBE, &rv, sizeof(int64_t));
115 void int32_LE2BE(int32_t* pBE, const int32_t v)
117 /* convert little endian to big endian */
118 if (htonl(1) != 1L) { /* no work if on little endian machine */
119 memcpy(pBE, &v, sizeof(int32_t));
122 uint8_t rv[sizeof(int32_t)];
123 uint8_t *pv = (uint8_t *) &v;
125 for (i = 0; i < 4; i++) {
128 memcpy(pBE, &rv, sizeof(int32_t));
133 BOOL processWin32BackupAPIBlock (BFILE *bfd, void *pBuffer, size_t dwSize)
135 /* pByte contains the buffer
136 dwSize the len to be processed. function assumes to be
137 called in successive incremental order over the complete
138 BackupRead stream beginning at pos 0 and ending at the end.
141 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
142 bool bContinue = FALSE;
143 int64_t dwDataOffset = 0;
146 /* Win32 Stream Header size without name of stream.
147 * = sizeof (WIN32_STREAM_ID)- sizeof(WCHAR*);
149 int32_t dwSizeHeader = 20;
152 if (pContext->liNextHeader >= dwSize) {
153 dwDataLen = dwSize-dwDataOffset;
154 bContinue = FALSE; /* 1 iteration is enough */
157 dwDataLen = pContext->liNextHeader-dwDataOffset;
158 bContinue = TRUE; /* multiple iterations may be necessary */
162 /* copy block of real DATA */
163 if (pContext->bIsInData) {
164 if (bwrite(bfd, ((LPBYTE)pBuffer)+dwDataOffset, dwDataLen) != (ssize_t)dwDataLen)
168 if (pContext->liNextHeader < dwSize) {/* is a header in this block ? */
169 int32_t dwOffsetTarget;
170 int32_t dwOffsetSource;
172 if (pContext->liNextHeader < 0) {
173 /* start of header was before this block, so we
174 * continue with the part in the current block
176 dwOffsetTarget = abs (pContext->liNextHeader);
180 /* start of header is inside of this block */
182 dwOffsetSource = pContext->liNextHeader;
185 int32_t dwHeaderPartLen = dwSizeHeader-dwOffsetTarget;
186 bool bHeaderIsComplete;
188 if (dwHeaderPartLen <= dwSize-dwOffsetSource)
189 /* header (or rest of header) is completely available
192 bHeaderIsComplete = TRUE;
194 /* header will continue in next block */
195 bHeaderIsComplete = FALSE;
196 dwHeaderPartLen = dwSize-dwOffsetSource;
199 /* copy the available portion of header to persistent copy */
200 memcpy (((LPBYTE) &pContext->header_stream)+dwOffsetTarget, ((LPBYTE) pBuffer)+dwOffsetSource, dwHeaderPartLen);
202 /* recalculate position of next header */
203 if (bHeaderIsComplete) {
204 /* convert stream name size (32 bit little endian) to machine type */
206 int32_LE2BE (&dwNameSize, pContext->header_stream.dwStreamNameSize);
207 dwDataOffset = dwNameSize+pContext->liNextHeader+dwSizeHeader;
209 /* convert stream size (64 bit little endian) to machine type */
210 int64_LE2BE (&(pContext->liNextHeader), pContext->header_stream.Size);
211 pContext->liNextHeader += dwDataOffset;
213 pContext->bIsInData = pContext->header_stream.dwStreamId == BACKUP_DATA;
214 if (dwDataOffset == dwSize)
218 /* stop and continue with next block */
220 pContext->bIsInData = FALSE;
225 /* set "NextHeader" relative to the beginning of the next block */
226 pContext->liNextHeader-= dwSize;
234 /* ===============================================================
238 * ===============================================================
241 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
243 void unix_name_to_win32(POOLMEM **win32_name, char *name);
244 extern "C" HANDLE get_osfhandle(int fd);
248 void binit(BFILE *bfd)
250 memset(bfd, 0, sizeof(BFILE));
252 bfd->mode = BF_CLOSED;
253 bfd->use_backup_api = have_win32_api();
257 * Enables using the Backup API (win32_data).
258 * Returns 1 if function worked
259 * Returns 0 if failed (i.e. do not have Backup API on this machine)
261 bool set_win32_backup(BFILE *bfd)
263 /* We enable if possible here */
264 bfd->use_backup_api = have_win32_api();
265 return bfd->use_backup_api;
269 bool set_portable_backup(BFILE *bfd)
271 bfd->use_backup_api = false;
275 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
283 * Return 1 if we are NOT using Win32 BackupWrite()
286 bool is_portable_backup(BFILE *bfd)
288 return !bfd->use_backup_api;
291 bool have_win32_api()
293 return p_BackupRead && p_BackupWrite;
299 * Return true if we support the stream
300 * false if we do not support the stream
302 bool is_stream_supported(int stream)
304 /* With Win32 backup on this machine */
306 case STREAM_WIN32_DATA:
308 case STREAM_WIN32_GZIP_DATA:
310 #ifdef USE_WIN32STREAMEXTRACTION
313 return have_win32_api();
316 /* Streams known not to be supported */
318 case STREAM_GZIP_DATA:
319 case STREAM_SPARSE_GZIP_DATA:
320 case STREAM_WIN32_GZIP_DATA:
322 case STREAM_MACOS_FORK_DATA:
323 case STREAM_HFSPLUS_ATTRIBUTES:
328 case STREAM_GZIP_DATA:
329 case STREAM_SPARSE_GZIP_DATA:
331 case STREAM_UNIX_ATTRIBUTES:
332 case STREAM_FILE_DATA:
333 case STREAM_MD5_SIGNATURE:
334 case STREAM_UNIX_ATTRIBUTES_EX:
335 case STREAM_SPARSE_DATA:
336 case STREAM_PROGRAM_NAMES:
337 case STREAM_PROGRAM_DATA:
338 case STREAM_SHA1_SIGNATURE:
339 case 0: /* compatibility with old tapes */
345 HANDLE bget_handle(BFILE *bfd)
350 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
352 POOLMEM *win32_fname;
353 POOLMEM *win32_fname_wchar;
355 DWORD dwaccess, dwflags, dwshare;
357 /* Convert to Windows path format */
358 win32_fname = get_pool_memory(PM_FNAME);
359 win32_fname_wchar = get_pool_memory(PM_FNAME);
361 unix_name_to_win32(&win32_fname, (char *)fname);
363 if (!(p_CreateFileA || p_CreateFileW))
366 if (p_CreateFileW && p_MultiByteToWideChar)
367 UTF8_2_wchar(&win32_fname_wchar, win32_fname);
369 if (flags & O_CREAT) { /* Create */
370 if (bfd->use_backup_api) {
371 dwaccess = GENERIC_WRITE|FILE_ALL_ACCESS|WRITE_OWNER|WRITE_DAC|ACCESS_SYSTEM_SECURITY;
372 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
374 dwaccess = GENERIC_WRITE;
378 // unicode or ansii open for create write
379 if (p_CreateFileW && p_MultiByteToWideChar) {
380 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
381 dwaccess, /* Requested access */
383 NULL, /* SecurityAttributes */
384 CREATE_ALWAYS, /* CreationDisposition */
385 dwflags, /* Flags and attributes */
386 NULL); /* TemplateFile */
389 bfd->fh = p_CreateFileA(win32_fname,
390 dwaccess, /* Requested access */
392 NULL, /* SecurityAttributes */
393 CREATE_ALWAYS, /* CreationDisposition */
394 dwflags, /* Flags and attributes */
395 NULL); /* TemplateFile */
399 bfd->mode = BF_WRITE;
401 } else if (flags & O_WRONLY) { /* Open existing for write */
402 if (bfd->use_backup_api) {
403 dwaccess = GENERIC_WRITE|WRITE_OWNER|WRITE_DAC;
404 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
406 dwaccess = GENERIC_WRITE;
410 // unicode or ansii open for open existing write
411 if (p_CreateFileW && p_MultiByteToWideChar) {
412 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
413 dwaccess, /* Requested access */
415 NULL, /* SecurityAttributes */
416 OPEN_EXISTING, /* CreationDisposition */
417 dwflags, /* Flags and attributes */
418 NULL); /* TemplateFile */
421 bfd->fh = p_CreateFileA(win32_fname,
422 dwaccess, /* Requested access */
424 NULL, /* SecurityAttributes */
425 OPEN_EXISTING, /* CreationDisposition */
426 dwflags, /* Flags and attributes */
427 NULL); /* TemplateFile */
431 bfd->mode = BF_WRITE;
434 if (bfd->use_backup_api) {
435 dwaccess = GENERIC_READ|READ_CONTROL|ACCESS_SYSTEM_SECURITY;
436 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
437 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
439 dwaccess = GENERIC_READ;
441 dwshare = FILE_SHARE_READ|FILE_SHARE_WRITE;
444 // unicode or ansii open for open existing read
445 if (p_CreateFileW && p_MultiByteToWideChar) {
446 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
447 dwaccess, /* Requested access */
448 dwshare, /* Share modes */
449 NULL, /* SecurityAttributes */
450 OPEN_EXISTING, /* CreationDisposition */
451 dwflags, /* Flags and attributes */
452 NULL); /* TemplateFile */
455 bfd->fh = p_CreateFileA(win32_fname,
456 dwaccess, /* Requested access */
457 dwshare, /* Share modes */
458 NULL, /* SecurityAttributes */
459 OPEN_EXISTING, /* CreationDisposition */
460 dwflags, /* Flags and attributes */
461 NULL); /* TemplateFile */
467 if (bfd->fh == INVALID_HANDLE_VALUE) {
468 bfd->lerror = GetLastError();
469 bfd->berrno = b_errno_win32;
470 errno = b_errno_win32;
471 bfd->mode = BF_CLOSED;
474 bfd->lpContext = NULL;
475 #ifdef USE_WIN32STREAMEXTRACTION
476 bfd->win32DecompContext.bIsInData = FALSE;
477 bfd->win32DecompContext.liNextHeader = 0;
479 free_pool_memory(win32_fname_wchar);
480 free_pool_memory(win32_fname);
481 return bfd->mode == BF_CLOSED ? -1 : 1;
485 * Returns 0 on success
488 int bclose(BFILE *bfd)
493 free_pool_memory(bfd->errmsg);
496 if (bfd->mode == BF_CLOSED) {
499 if (bfd->use_backup_api && bfd->mode == BF_READ) {
501 if (!bfd->lpContext && !p_BackupRead(bfd->fh,
503 (DWORD)0, /* bytes to read */
504 &bfd->rw_bytes, /* bytes read */
506 1, /* ProcessSecurity */
507 &bfd->lpContext)) { /* Read context */
508 errno = b_errno_win32;
511 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
513 if (!bfd->lpContext && !p_BackupWrite(bfd->fh,
515 (DWORD)0, /* bytes to read */
516 &bfd->rw_bytes, /* bytes written */
518 1, /* ProcessSecurity */
519 &bfd->lpContext)) { /* Write context */
520 errno = b_errno_win32;
524 if (!CloseHandle(bfd->fh)) {
526 errno = b_errno_win32;
528 bfd->mode = BF_CLOSED;
529 bfd->lpContext = NULL;
533 /* Returns: bytes read on success
537 ssize_t bread(BFILE *bfd, void *buf, size_t count)
541 if (bfd->use_backup_api) {
542 if (!p_BackupRead(bfd->fh,
547 1, /* Process Security */
548 &bfd->lpContext)) { /* Context */
549 bfd->lerror = GetLastError();
550 bfd->berrno = b_errno_win32;
551 errno = b_errno_win32;
555 if (!ReadFile(bfd->fh,
560 bfd->lerror = GetLastError();
561 bfd->berrno = b_errno_win32;
562 errno = b_errno_win32;
567 return (ssize_t)bfd->rw_bytes;
570 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
574 if (bfd->use_backup_api) {
575 if (!p_BackupWrite(bfd->fh,
580 1, /* Process Security */
581 &bfd->lpContext)) { /* Context */
582 bfd->lerror = GetLastError();
583 bfd->berrno = b_errno_win32;
584 errno = b_errno_win32;
588 if (!WriteFile(bfd->fh,
593 bfd->lerror = GetLastError();
594 bfd->berrno = b_errno_win32;
595 errno = b_errno_win32;
599 return (ssize_t)bfd->rw_bytes;
602 bool is_bopen(BFILE *bfd)
604 return bfd->mode != BF_CLOSED;
607 off_t blseek(BFILE *bfd, off_t offset, int whence)
609 /* ****FIXME**** this must be implemented if we want to read Win32 Archives */
613 #else /* Unix systems */
615 /* ===============================================================
619 * ===============================================================
621 void binit(BFILE *bfd)
623 memset(bfd, 0, sizeof(BFILE));
627 bool have_win32_api()
629 return false; /* no can do */
633 * Enables using the Backup API (win32_data).
634 * Returns true if function worked
635 * Returns false if failed (i.e. do not have Backup API on this machine)
637 bool set_win32_backup(BFILE *bfd)
639 return false; /* no can do */
643 bool set_portable_backup(BFILE *bfd)
645 return true; /* no problem */
649 * Return true if we are writing in portable format
650 * return false if not
652 bool is_portable_backup(BFILE *bfd)
654 return true; /* portable by definition */
657 bool set_prog(BFILE *bfd, char *prog, JCR *jcr)
660 if (bfd->prog && strcmp(prog, bfd->prog) == 0) {
661 return true; /* already setup */
664 if (python_set_prog(jcr, prog)) {
665 Dmsg1(000, "Set prog=%s\n", prog);
671 Dmsg0(000, "No prog set\n");
678 bool is_stream_supported(int stream)
680 /* No Win32 backup on this machine */
683 case STREAM_GZIP_DATA:
684 case STREAM_SPARSE_GZIP_DATA:
685 case STREAM_WIN32_GZIP_DATA:
687 #ifndef USE_WIN32STREAMEXTRACTION
688 case STREAM_WIN32_DATA:
690 #ifndef HAVE_DARWIN_OS
691 case STREAM_MACOS_FORK_DATA:
692 case STREAM_HFSPLUS_ATTRIBUTES:
698 case STREAM_GZIP_DATA:
699 case STREAM_SPARSE_GZIP_DATA:
701 #ifdef USE_WIN32STREAMEXTRACTION
702 case STREAM_WIN32_DATA:
704 case STREAM_WIN32_GZIP_DATA:
707 case STREAM_UNIX_ATTRIBUTES:
708 case STREAM_FILE_DATA:
709 case STREAM_MD5_SIGNATURE:
710 case STREAM_UNIX_ATTRIBUTES_EX:
711 case STREAM_SPARSE_DATA:
712 case STREAM_PROGRAM_NAMES:
713 case STREAM_PROGRAM_DATA:
714 case STREAM_SHA1_SIGNATURE:
715 #ifdef HAVE_DARWIN_OS
716 case STREAM_MACOS_FORK_DATA:
717 case STREAM_HFSPLUS_ATTRIBUTES:
719 case 0: /* compatibility with old tapes */
726 int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
728 /* Open reader/writer program */
730 Dmsg1(000, "Open file %d\n", bfd->fid);
731 return python_open(bfd, fname, flags, mode);
734 /* Normal file open */
735 bfd->fid = open(fname, flags, mode);
737 Dmsg1(400, "Open file %d\n", bfd->fid);
740 #ifdef USE_WIN32STREAMEXTRACTION
741 bfd->win32DecompContext.bIsInData = FALSE;
742 bfd->win32DecompContext.liNextHeader = 0;
748 #ifdef HAVE_DARWIN_OS
749 /* Open the resource fork of a file. */
750 int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
755 fname_len = strlen(fname);
756 rsrc_fname = get_pool_memory(PM_FNAME);
757 bstrncpy(rsrc_fname, fname, fname_len + 1);
758 bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC,
759 strlen(_PATH_RSRCFORKSPEC) + 1);
760 bopen(bfd, rsrc_fname, flags, mode);
761 free_pool_memory(rsrc_fname);
767 int bclose(BFILE *bfd)
771 Dmsg1(400, "Close file %d\n", bfd->fid);
773 /* Close reader/writer program */
775 return python_close(bfd);
778 if (bfd->fid == -1) {
782 /* Close normal file */
783 stat = close(bfd->fid);
789 ssize_t bread(BFILE *bfd, void *buf, size_t count)
794 return python_read(bfd, buf, count);
796 stat = read(bfd->fid, buf, count);
801 ssize_t bwrite(BFILE *bfd, void *buf, size_t count)
806 return python_write(bfd, buf, count);
808 stat = write(bfd->fid, buf, count);
813 bool is_bopen(BFILE *bfd)
815 return bfd->fid >= 0;
818 off_t blseek(BFILE *bfd, off_t offset, int whence)
821 pos = lseek(bfd->fid, offset, whence);