1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2003-2010 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7
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 Affero 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 /*
24 * Kern Sibbald, April MMIII
25 */
26 /**
27 * @file
28 * Bareos low level File I/O routines. This routine simulates
29 * open(), read(), write(), and close(), but using native routines.
30 * I.e. on Windows, we use Windows APIs.
31 */
32
33 #include "include/bareos.h"
34 #include "find.h"
35 #include "lib/berrno.h"
36
37 const int debuglevel = 200;
38
39 int (*plugin_bopen)(BareosWinFilePacket* bfd,
40 const char* fname,
41 int flags,
42 mode_t mode) = NULL;
43 int (*plugin_bclose)(BareosWinFilePacket* bfd) = NULL;
44 ssize_t (*plugin_bread)(BareosWinFilePacket* bfd,
45 void* buf,
46 size_t count) = NULL;
47 ssize_t (*plugin_bwrite)(BareosWinFilePacket* bfd,
48 void* buf,
49 size_t count) = NULL;
50 boffset_t (*plugin_blseek)(BareosWinFilePacket* bfd,
51 boffset_t offset,
52 int whence) = NULL;
53
54 #ifdef HAVE_DARWIN_OS
55 #include <sys/paths.h>
56 #endif
57
58 #if !defined(HAVE_FDATASYNC)
59 #define fdatasync(fd)
60 #endif
61
62 #ifdef HAVE_WIN32
PauseMsg(const char * file,const char * func,int line,const char * msg)63 void PauseMsg(const char* file, const char* func, int line, const char* msg)
64 {
65 char buf[1000];
66 if (msg) {
67 Bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
68 } else {
69 Bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
70 }
71 MessageBox(NULL, buf, "Pause", MB_OK);
72 }
73 #endif
74
75 /* ===============================================================
76 *
77 * U N I X AND W I N D O W S
78 *
79 * ===============================================================
80 */
81
is_win32_stream(int stream)82 bool is_win32_stream(int stream)
83 {
84 switch (stream) {
85 case STREAM_WIN32_DATA:
86 case STREAM_WIN32_GZIP_DATA:
87 case STREAM_WIN32_COMPRESSED_DATA:
88 case STREAM_ENCRYPTED_WIN32_DATA:
89 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
90 case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
91 return true;
92 }
93 return false;
94 }
95
stream_to_ascii(int stream)96 const char* stream_to_ascii(int stream)
97 {
98 static char buf[20];
99
100 switch (stream & STREAMMASK_TYPE) {
101 case STREAM_UNIX_ATTRIBUTES:
102 return _("Unix attributes");
103 case STREAM_FILE_DATA:
104 return _("File data");
105 case STREAM_MD5_DIGEST:
106 return _("MD5 digest");
107 case STREAM_GZIP_DATA:
108 return _("GZIP data");
109 case STREAM_COMPRESSED_DATA:
110 return _("Compressed data");
111 case STREAM_UNIX_ATTRIBUTES_EX:
112 return _("Extended attributes");
113 case STREAM_SPARSE_DATA:
114 return _("Sparse data");
115 case STREAM_SPARSE_GZIP_DATA:
116 return _("GZIP sparse data");
117 case STREAM_SPARSE_COMPRESSED_DATA:
118 return _("Compressed sparse data");
119 case STREAM_PROGRAM_NAMES:
120 return _("Program names");
121 case STREAM_PROGRAM_DATA:
122 return _("Program data");
123 case STREAM_SHA1_DIGEST:
124 return _("SHA1 digest");
125 case STREAM_WIN32_DATA:
126 return _("Win32 data");
127 case STREAM_WIN32_GZIP_DATA:
128 return _("Win32 GZIP data");
129 case STREAM_WIN32_COMPRESSED_DATA:
130 return _("Win32 compressed data");
131 case STREAM_MACOS_FORK_DATA:
132 return _("MacOS Fork data");
133 case STREAM_HFSPLUS_ATTRIBUTES:
134 return _("HFS+ attribs");
135 case STREAM_UNIX_ACCESS_ACL:
136 return _("Standard Unix ACL attribs");
137 case STREAM_UNIX_DEFAULT_ACL:
138 return _("Default Unix ACL attribs");
139 case STREAM_SHA256_DIGEST:
140 return _("SHA256 digest");
141 case STREAM_SHA512_DIGEST:
142 return _("SHA512 digest");
143 case STREAM_SIGNED_DIGEST:
144 return _("Signed digest");
145 case STREAM_ENCRYPTED_FILE_DATA:
146 return _("Encrypted File data");
147 case STREAM_ENCRYPTED_WIN32_DATA:
148 return _("Encrypted Win32 data");
149 case STREAM_ENCRYPTED_SESSION_DATA:
150 return _("Encrypted session data");
151 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
152 return _("Encrypted GZIP data");
153 case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
154 return _("Encrypted compressed data");
155 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
156 return _("Encrypted Win32 GZIP data");
157 case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
158 return _("Encrypted Win32 Compressed data");
159 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
160 return _("Encrypted MacOS fork data");
161 case STREAM_ACL_AIX_TEXT:
162 return _("AIX Specific ACL attribs");
163 case STREAM_ACL_DARWIN_ACCESS_ACL:
164 return _("Darwin Specific ACL attribs");
165 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
166 return _("FreeBSD Specific Default ACL attribs");
167 case STREAM_ACL_FREEBSD_ACCESS_ACL:
168 return _("FreeBSD Specific Access ACL attribs");
169 case STREAM_ACL_HPUX_ACL_ENTRY:
170 return _("HPUX Specific ACL attribs");
171 case STREAM_ACL_IRIX_DEFAULT_ACL:
172 return _("Irix Specific Default ACL attribs");
173 case STREAM_ACL_IRIX_ACCESS_ACL:
174 return _("Irix Specific Access ACL attribs");
175 case STREAM_ACL_LINUX_DEFAULT_ACL:
176 return _("Linux Specific Default ACL attribs");
177 case STREAM_ACL_LINUX_ACCESS_ACL:
178 return _("Linux Specific Access ACL attribs");
179 case STREAM_ACL_TRU64_DEFAULT_ACL:
180 return _("TRU64 Specific Default ACL attribs");
181 case STREAM_ACL_TRU64_ACCESS_ACL:
182 return _("TRU64 Specific Access ACL attribs");
183 case STREAM_ACL_SOLARIS_ACLENT:
184 return _("Solaris Specific POSIX ACL attribs");
185 case STREAM_ACL_SOLARIS_ACE:
186 return _("Solaris Specific NFSv4/ZFS ACL attribs");
187 case STREAM_ACL_AFS_TEXT:
188 return _("AFS Specific ACL attribs");
189 case STREAM_ACL_AIX_AIXC:
190 return _("AIX Specific POSIX ACL attribs");
191 case STREAM_ACL_AIX_NFS4:
192 return _("AIX Specific NFSv4 ACL attribs");
193 case STREAM_ACL_FREEBSD_NFS4_ACL:
194 return _("FreeBSD Specific NFSv4/ZFS ACL attribs");
195 case STREAM_ACL_HURD_DEFAULT_ACL:
196 return _("GNU Hurd Specific Default ACL attribs");
197 case STREAM_ACL_HURD_ACCESS_ACL:
198 return _("GNU Hurd Specific Access ACL attribs");
199 case STREAM_XATTR_HURD:
200 return _("GNU Hurd Specific Extended attribs");
201 case STREAM_XATTR_IRIX:
202 return _("IRIX Specific Extended attribs");
203 case STREAM_XATTR_TRU64:
204 return _("TRU64 Specific Extended attribs");
205 case STREAM_XATTR_AIX:
206 return _("AIX Specific Extended attribs");
207 case STREAM_XATTR_OPENBSD:
208 return _("OpenBSD Specific Extended attribs");
209 case STREAM_XATTR_SOLARIS_SYS:
210 return _(
211 "Solaris Specific Extensible attribs or System Extended attribs");
212 case STREAM_XATTR_SOLARIS:
213 return _("Solaris Specific Extended attribs");
214 case STREAM_XATTR_DARWIN:
215 return _("Darwin Specific Extended attribs");
216 case STREAM_XATTR_FREEBSD:
217 return _("FreeBSD Specific Extended attribs");
218 case STREAM_XATTR_LINUX:
219 return _("Linux Specific Extended attribs");
220 case STREAM_XATTR_NETBSD:
221 return _("NetBSD Specific Extended attribs");
222 default:
223 sprintf(buf, "%d", stream);
224 return (const char*)buf;
225 }
226 }
227
228 /**
229 * Convert a 64 bit little endian to a big endian
230 */
int64_LE2BE(int64_t * pBE,const int64_t v)231 static inline void int64_LE2BE(int64_t* pBE, const int64_t v)
232 {
233 /* convert little endian to big endian */
234 if (htonl(1) != 1L) { /* no work if on little endian machine */
235 memcpy(pBE, &v, sizeof(int64_t));
236 } else {
237 int i;
238 uint8_t rv[sizeof(int64_t)];
239 uint8_t* pv = (uint8_t*)&v;
240
241 for (i = 0; i < 8; i++) { rv[i] = pv[7 - i]; }
242 memcpy(pBE, &rv, sizeof(int64_t));
243 }
244 }
245
246 /**
247 * Convert a 32 bit little endian to a big endian
248 */
int32_LE2BE(int32_t * pBE,const int32_t v)249 static inline void int32_LE2BE(int32_t* pBE, const int32_t v)
250 {
251 /* convert little endian to big endian */
252 if (htonl(1) != 1L) { /* no work if on little endian machine */
253 memcpy(pBE, &v, sizeof(int32_t));
254 } else {
255 int i;
256 uint8_t rv[sizeof(int32_t)];
257 uint8_t* pv = (uint8_t*)&v;
258
259 for (i = 0; i < 4; i++) { rv[i] = pv[3 - i]; }
260 memcpy(pBE, &rv, sizeof(int32_t));
261 }
262 }
263
264 /**
265 * Read a BackupRead block and pull out the file data
266 */
processWin32BackupAPIBlock(BareosWinFilePacket * bfd,void * pBuffer,ssize_t dwSize)267 bool processWin32BackupAPIBlock(BareosWinFilePacket* bfd,
268 void* pBuffer,
269 ssize_t dwSize)
270 {
271 /* pByte contains the buffer
272 dwSize the len to be processed. function assumes to be
273 called in successive incremental order over the complete
274 BackupRead stream beginning at pos 0 and ending at the end.
275 */
276
277 PROCESS_WIN32_BACKUPAPIBLOCK_CONTEXT* pContext = &(bfd->win32DecompContext);
278 bool bContinue = false;
279 int64_t dwDataOffset = 0;
280 int64_t dwDataLen;
281
282 /* Win32 Stream Header size without name of stream.
283 * = sizeof (WIN32_STREAM_ID)- sizeof(wchar_t *);
284 */
285 int32_t dwSizeHeader = 20;
286
287 do {
288 if (pContext->liNextHeader >= dwSize) {
289 dwDataLen = dwSize - dwDataOffset;
290 bContinue = false; /* 1 iteration is enough */
291 } else {
292 dwDataLen = pContext->liNextHeader - dwDataOffset;
293 bContinue = true; /* multiple iterations may be necessary */
294 }
295
296 /* flush */
297 /* copy block of real DATA */
298 if (pContext->bIsInData) {
299 if (bwrite(bfd, ((char*)pBuffer) + dwDataOffset, dwDataLen) !=
300 (ssize_t)dwDataLen)
301 return false;
302 }
303
304 if (pContext->liNextHeader < dwSize) { /* is a header in this block ? */
305 int32_t dwOffsetTarget;
306 int32_t dwOffsetSource;
307
308 if (pContext->liNextHeader < 0) {
309 /* start of header was before this block, so we
310 * continue with the part in the current block
311 */
312 dwOffsetTarget = -pContext->liNextHeader;
313 dwOffsetSource = 0;
314 } else {
315 /* start of header is inside of this block */
316 dwOffsetTarget = 0;
317 dwOffsetSource = pContext->liNextHeader;
318 }
319
320 int32_t dwHeaderPartLen = dwSizeHeader - dwOffsetTarget;
321 bool bHeaderIsComplete;
322
323 if (dwHeaderPartLen <= dwSize - dwOffsetSource) {
324 /* header (or rest of header) is completely available
325 in current block
326 */
327 bHeaderIsComplete = true;
328 } else {
329 /* header will continue in next block */
330 bHeaderIsComplete = false;
331 dwHeaderPartLen = dwSize - dwOffsetSource;
332 }
333
334 /* copy the available portion of header to persistent copy */
335 memcpy(((char*)&pContext->header_stream) + dwOffsetTarget,
336 ((char*)pBuffer) + dwOffsetSource, dwHeaderPartLen);
337
338 /* recalculate position of next header */
339 if (bHeaderIsComplete) {
340 /* convert stream name size (32 bit little endian) to machine type */
341 int32_t dwNameSize;
342 int32_LE2BE(&dwNameSize, pContext->header_stream.dwStreamNameSize);
343 dwDataOffset = dwNameSize + pContext->liNextHeader + dwSizeHeader;
344
345 /* convert stream size (64 bit little endian) to machine type */
346 int64_LE2BE(&(pContext->liNextHeader), pContext->header_stream.Size);
347 pContext->liNextHeader += dwDataOffset;
348
349 pContext->bIsInData =
350 pContext->header_stream.dwStreamId == WIN32_BACKUP_DATA;
351 if (dwDataOffset == dwSize) bContinue = false;
352 } else {
353 /* stop and continue with next block */
354 bContinue = false;
355 pContext->bIsInData = false;
356 }
357 }
358 } while (bContinue);
359
360 /* set "NextHeader" relative to the beginning of the next block */
361 pContext->liNextHeader -= dwSize;
362
363 return TRUE;
364 }
365
366 /* ===============================================================
367 *
368 * W I N D O W S
369 *
370 * ===============================================================
371 */
372
373 #if defined(HAVE_WIN32)
374
375 /* Imported Functions */
376 extern void unix_name_to_win32(POOLMEM*& win32_name, const char* name);
377 extern "C" HANDLE get_osfhandle(int fd);
378
binit(BareosWinFilePacket * bfd)379 void binit(BareosWinFilePacket* bfd)
380 {
381 memset(bfd, 0, sizeof(BareosWinFilePacket));
382 bfd->fid = -1;
383 bfd->mode = BF_CLOSED;
384 bfd->use_backup_api = have_win32_api();
385 bfd->cmd_plugin = false;
386 bfd->pvContext = NULL;
387 }
388
389 /**
390 * Enables using the Backup API (win32_data).
391 * Returns 1 if function worked
392 * Returns 0 if failed (i.e. do not have Backup API on this machine)
393 */
set_win32_backup(BareosWinFilePacket * bfd)394 bool set_win32_backup(BareosWinFilePacket* bfd)
395 {
396 /* We enable if possible here */
397 bfd->use_backup_api = have_win32_api();
398 return bfd->use_backup_api;
399 }
400
SetPortableBackup(BareosWinFilePacket * bfd)401 bool SetPortableBackup(BareosWinFilePacket* bfd)
402 {
403 bfd->use_backup_api = false;
404 return true;
405 }
406
SetCmdPlugin(BareosWinFilePacket * bfd,JobControlRecord * jcr)407 bool SetCmdPlugin(BareosWinFilePacket* bfd, JobControlRecord* jcr)
408 {
409 bfd->cmd_plugin = true;
410 bfd->jcr = jcr;
411 return true;
412 }
413
414 /**
415 * Return 1 if we are NOT using Win32 BackupWrite()
416 * return 0 if are
417 */
IsPortableBackup(BareosWinFilePacket * bfd)418 bool IsPortableBackup(BareosWinFilePacket* bfd) { return !bfd->use_backup_api; }
419
have_win32_api()420 bool have_win32_api() { return p_BackupRead && p_BackupWrite; }
421
422 /**
423 * Return true if we support the stream
424 * false if we do not support the stream
425 *
426 * This code is running under Win32, so we do not need #ifdef on MACOS ...
427 */
IsRestoreStreamSupported(int stream)428 bool IsRestoreStreamSupported(int stream)
429 {
430 switch (stream) {
431 /*
432 * Streams known not to be supported
433 */
434 #ifndef HAVE_LIBZ
435 case STREAM_GZIP_DATA:
436 case STREAM_SPARSE_GZIP_DATA:
437 case STREAM_WIN32_GZIP_DATA:
438 #endif
439 case STREAM_MACOS_FORK_DATA:
440 case STREAM_HFSPLUS_ATTRIBUTES:
441 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
442 return false;
443
444 /*
445 * Known streams
446 */
447 #ifdef HAVE_LIBZ
448 case STREAM_GZIP_DATA:
449 case STREAM_SPARSE_GZIP_DATA:
450 case STREAM_WIN32_GZIP_DATA:
451 #endif
452 case STREAM_COMPRESSED_DATA:
453 case STREAM_SPARSE_COMPRESSED_DATA:
454 case STREAM_WIN32_COMPRESSED_DATA:
455 case STREAM_WIN32_DATA:
456 case STREAM_UNIX_ATTRIBUTES:
457 case STREAM_FILE_DATA:
458 case STREAM_MD5_DIGEST:
459 case STREAM_UNIX_ATTRIBUTES_EX:
460 case STREAM_SPARSE_DATA:
461 case STREAM_PROGRAM_NAMES:
462 case STREAM_PROGRAM_DATA:
463 case STREAM_SHA1_DIGEST:
464 #ifdef HAVE_SHA2
465 case STREAM_SHA256_DIGEST:
466 case STREAM_SHA512_DIGEST:
467 #endif
468 #ifdef HAVE_CRYPTO
469 case STREAM_SIGNED_DIGEST:
470 case STREAM_ENCRYPTED_FILE_DATA:
471 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
472 case STREAM_ENCRYPTED_WIN32_DATA:
473 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
474 case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
475 case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
476 #endif /* !HAVE_CRYPTO */
477 case 0: /* compatibility with old tapes */
478 return true;
479 }
480 return false;
481 }
482
BgetHandle(BareosWinFilePacket * bfd)483 HANDLE BgetHandle(BareosWinFilePacket* bfd)
484 {
485 return (bfd->mode == BF_CLOSED) ? INVALID_HANDLE_VALUE : bfd->fh;
486 }
487
488 /**
489 * Windows flags for the OpenEncryptedFileRaw functions.
490 */
491 #ifndef CREATE_FOR_EXPORT
492 #define CREATE_FOR_EXPORT 0
493 #endif
494 #ifndef CREATE_FOR_IMPORT
495 #define CREATE_FOR_IMPORT 1
496 #endif
497 #ifndef CREATE_FOR_DIR
498 #define CREATE_FOR_DIR 2
499 #endif
500 #ifndef OVERWRITE_HIDDEN
501 #define OVERWRITE_HIDDEN 4
502 #endif
503
BopenEncrypted(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)504 static inline int BopenEncrypted(BareosWinFilePacket* bfd,
505 const char* fname,
506 int flags,
507 mode_t mode)
508 {
509 bool is_dir;
510 ULONG ulFlags = 0;
511 POOLMEM* win32_fname;
512 POOLMEM* win32_fname_wchar;
513
514 if (!p_OpenEncryptedFileRawA && !p_OpenEncryptedFileRawW) {
515 Dmsg0(50,
516 "No p_OpenEncryptedFileRawA and no p_OpenEncryptedFileRawW!!!!!\n");
517 return 0;
518 }
519
520 is_dir = S_ISDIR(mode);
521
522 /*
523 * Convert to Windows path format
524 */
525 win32_fname = GetPoolMemory(PM_FNAME);
526 win32_fname_wchar = GetPoolMemory(PM_FNAME);
527
528 unix_name_to_win32(win32_fname, (char*)fname);
529 if (p_OpenEncryptedFileRawW && p_MultiByteToWideChar) {
530 make_win32_path_UTF8_2_wchar(win32_fname_wchar, fname);
531 }
532
533 /*
534 * See if we open the file for create or read-write.
535 */
536 if ((flags & O_CREAT) || (flags & O_WRONLY)) {
537 if (is_dir) {
538 ulFlags |= CREATE_FOR_IMPORT | OVERWRITE_HIDDEN | CREATE_FOR_DIR;
539 } else {
540 ulFlags |= CREATE_FOR_IMPORT | OVERWRITE_HIDDEN;
541 }
542 bfd->mode = BF_WRITE;
543 } else {
544 ulFlags = CREATE_FOR_EXPORT;
545 bfd->mode = BF_READ;
546 }
547
548 if (p_OpenEncryptedFileRawW && p_MultiByteToWideChar) {
549 /*
550 * Unicode open.
551 */
552 Dmsg1(100, "OpenEncryptedFileRawW=%s\n", win32_fname);
553 if (p_OpenEncryptedFileRawW((LPCWSTR)win32_fname_wchar, ulFlags,
554 &(bfd->pvContext))) {
555 bfd->mode = BF_CLOSED;
556 }
557 } else {
558 /*
559 * ASCII open.
560 */
561 Dmsg1(100, "OpenEncryptedFileRawA=%s\n", win32_fname);
562 if (p_OpenEncryptedFileRawA(win32_fname_wchar, ulFlags,
563 &(bfd->pvContext))) {
564 bfd->mode = BF_CLOSED;
565 }
566 }
567
568 FreePoolMemory(win32_fname_wchar);
569 FreePoolMemory(win32_fname);
570
571 bfd->encrypted = true;
572
573 return bfd->mode == BF_CLOSED ? -1 : 1;
574 }
575
BopenNonencrypted(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)576 static inline int BopenNonencrypted(BareosWinFilePacket* bfd,
577 const char* fname,
578 int flags,
579 mode_t mode)
580 {
581 POOLMEM* win32_fname;
582 POOLMEM* win32_fname_wchar;
583 DWORD dwaccess, dwflags, dwshare;
584
585 /*
586 * Convert to Windows path format
587 */
588 win32_fname = GetPoolMemory(PM_FNAME);
589 win32_fname_wchar = GetPoolMemory(PM_FNAME);
590
591 unix_name_to_win32(win32_fname, (char*)fname);
592 if (bfd->cmd_plugin && plugin_bopen) {
593 int rtnstat;
594 Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
595 rtnstat = plugin_bopen(bfd, fname, flags, mode);
596 Dmsg1(50, "return from plugin_bopen status=%d\n", rtnstat);
597 if (rtnstat >= 0) {
598 if (flags & O_CREAT || flags & O_WRONLY) { /* Open existing for write */
599 Dmsg1(50, "plugin_open for write OK file=%s.\n", fname);
600 bfd->mode = BF_WRITE;
601 } else {
602 Dmsg1(50, "plugin_open for read OK file=%s.\n", fname);
603 bfd->mode = BF_READ;
604 }
605 } else {
606 bfd->mode = BF_CLOSED;
607 Dmsg1(000, "==== plugin_bopen returned bad status=%d\n", rtnstat);
608 }
609 FreePoolMemory(win32_fname_wchar);
610 FreePoolMemory(win32_fname);
611 return bfd->mode == BF_CLOSED ? -1 : 1;
612 }
613 Dmsg0(50, "=== NO plugin\n");
614
615 if (!(p_CreateFileA || p_CreateFileW)) {
616 Dmsg0(50, "No CreateFileA and no CreateFileW!!!!!\n");
617 return 0;
618 }
619
620 if (p_CreateFileW && p_MultiByteToWideChar) {
621 make_win32_path_UTF8_2_wchar(win32_fname_wchar, fname);
622 }
623
624 if (flags & O_CREAT) { /* Create */
625 if (bfd->use_backup_api) {
626 dwaccess = GENERIC_WRITE | FILE_ALL_ACCESS | WRITE_OWNER | WRITE_DAC |
627 ACCESS_SYSTEM_SECURITY;
628 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
629 } else {
630 dwaccess = GENERIC_WRITE;
631 dwflags = 0;
632 }
633
634 /*
635 * Unicode open for create write
636 */
637 if (p_CreateFileW && p_MultiByteToWideChar) {
638 Dmsg1(100, "Create CreateFileW=%s\n", win32_fname);
639 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
640 dwaccess, /* Requested access */
641 0, /* Shared mode */
642 NULL, /* SecurityAttributes */
643 CREATE_ALWAYS, /* CreationDisposition */
644 dwflags, /* Flags and attributes */
645 NULL); /* TemplateFile */
646 } else {
647 /*
648 * ASCII open
649 */
650 Dmsg1(100, "Create CreateFileA=%s\n", win32_fname);
651 bfd->fh = p_CreateFileA(win32_fname, dwaccess, /* Requested access */
652 0, /* Shared mode */
653 NULL, /* SecurityAttributes */
654 CREATE_ALWAYS, /* CreationDisposition */
655 dwflags, /* Flags and attributes */
656 NULL); /* TemplateFile */
657 }
658
659 bfd->mode = BF_WRITE;
660 } else if (flags & O_WRONLY) {
661 /*
662 * Open existing for write
663 */
664 if (bfd->use_backup_api) {
665 dwaccess = GENERIC_READ | GENERIC_WRITE | WRITE_OWNER | WRITE_DAC;
666 if (flags & O_NOFOLLOW) {
667 dwflags = FILE_FLAG_BACKUP_SEMANTICS;
668 } else {
669 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
670 }
671 } else {
672 dwaccess = GENERIC_READ | GENERIC_WRITE;
673 dwflags = 0;
674 }
675
676 if (p_CreateFileW && p_MultiByteToWideChar) {
677 /*
678 * unicode open for open existing write
679 */
680 Dmsg1(100, "Write only CreateFileW=%s\n", win32_fname);
681 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
682 dwaccess, /* Requested access */
683 0, /* Shared mode */
684 NULL, /* SecurityAttributes */
685 OPEN_EXISTING, /* CreationDisposition */
686 dwflags, /* Flags and attributes */
687 NULL); /* TemplateFile */
688 } else {
689 /*
690 * ASCII open
691 */
692 Dmsg1(100, "Write only CreateFileA=%s\n", win32_fname);
693 bfd->fh = p_CreateFileA(win32_fname, dwaccess, /* Requested access */
694 0, /* Shared mode */
695 NULL, /* SecurityAttributes */
696 OPEN_EXISTING, /* CreationDisposition */
697 dwflags, /* Flags and attributes */
698 NULL); /* TemplateFile */
699 }
700
701 bfd->mode = BF_WRITE;
702 } else {
703 /*
704 * Open existing for read
705 */
706 if (bfd->use_backup_api) {
707 dwaccess = GENERIC_READ | READ_CONTROL | ACCESS_SYSTEM_SECURITY;
708 if (flags & O_NOFOLLOW) {
709 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN;
710 } else {
711 dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN |
712 FILE_FLAG_OPEN_REPARSE_POINT;
713 }
714 dwshare = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
715 } else {
716 dwaccess = GENERIC_READ;
717 dwflags = 0;
718 dwshare = FILE_SHARE_READ | FILE_SHARE_WRITE;
719 }
720
721 if (p_CreateFileW && p_MultiByteToWideChar) {
722 /*
723 * Unicode open for open existing read
724 */
725 Dmsg1(100, "Read CreateFileW=%s\n", win32_fname);
726 bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
727 dwaccess, /* Requested access */
728 dwshare, /* Share modes */
729 NULL, /* SecurityAttributes */
730 OPEN_EXISTING, /* CreationDisposition */
731 dwflags, /* Flags and attributes */
732 NULL); /* TemplateFile */
733 } else {
734 /*
735 * ASCII open for open existing read
736 */
737 Dmsg1(100, "Read CreateFileA=%s\n", win32_fname);
738 bfd->fh = p_CreateFileA(win32_fname, dwaccess, /* Requested access */
739 dwshare, /* Share modes */
740 NULL, /* SecurityAttributes */
741 OPEN_EXISTING, /* CreationDisposition */
742 dwflags, /* Flags and attributes */
743 NULL); /* TemplateFile */
744 }
745
746 bfd->mode = BF_READ;
747 }
748
749 if (bfd->fh == INVALID_HANDLE_VALUE) {
750 bfd->lerror = GetLastError();
751 bfd->BErrNo = b_errno_win32;
752 errno = b_errno_win32;
753 bfd->mode = BF_CLOSED;
754 }
755
756 bfd->errmsg = NULL;
757 bfd->lpContext = NULL;
758 bfd->win32DecompContext.bIsInData = false;
759 bfd->win32DecompContext.liNextHeader = 0;
760 FreePoolMemory(win32_fname_wchar);
761 FreePoolMemory(win32_fname);
762
763 bfd->encrypted = false;
764
765 return bfd->mode == BF_CLOSED ? -1 : 1;
766 }
767
bopen(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode,dev_t rdev)768 int bopen(BareosWinFilePacket* bfd,
769 const char* fname,
770 int flags,
771 mode_t mode,
772 dev_t rdev)
773 {
774 Dmsg4(100, "bopen: fname %s, flags %08o, mode %04o, rdev %u\n", fname, flags,
775 (mode & ~S_IFMT), rdev);
776
777 /*
778 * If the FILE_ATTRIBUTES_DEDUPED_ITEM bit is set this is a deduped file
779 * we let the bopen function know it should open the file without the
780 * FILE_FLAG_OPEN_REPARSE_POINT flag by setting in the O_NOFOLLOW open flag.
781 */
782 if (rdev & FILE_ATTRIBUTES_DEDUPED_ITEM) { flags |= O_NOFOLLOW; }
783
784 /*
785 * If the FILE_ATTRIBUTE_ENCRYPTED bit is set this is an file on an EFS
786 * filesystem. For that we need some special handling.
787 */
788 if (rdev & FILE_ATTRIBUTE_ENCRYPTED) {
789 return BopenEncrypted(bfd, fname, flags, mode);
790 } else {
791 return BopenNonencrypted(bfd, fname, flags, mode);
792 }
793 }
794
795 /**
796 * Returns 0 on success
797 * -1 on error
798 */
BcloseEncrypted(BareosWinFilePacket * bfd)799 static inline int BcloseEncrypted(BareosWinFilePacket* bfd)
800 {
801 if (bfd->mode == BF_CLOSED) {
802 Dmsg0(50, "=== BFD already closed.\n");
803 return 0;
804 }
805
806 if (!p_CloseEncryptedFileRaw) {
807 Dmsg0(50, "No p_CloseEncryptedFileRaw !!!!!\n");
808 return 0;
809 }
810
811 p_CloseEncryptedFileRaw(bfd->pvContext);
812 bfd->pvContext = NULL;
813 bfd->mode = BF_CLOSED;
814
815 return 0;
816 }
817
818 /**
819 * Returns 0 on success
820 * -1 on error
821 */
BcloseNonencrypted(BareosWinFilePacket * bfd)822 static inline int BcloseNonencrypted(BareosWinFilePacket* bfd)
823 {
824 int status = 0;
825
826 if (bfd->mode == BF_CLOSED) {
827 Dmsg0(50, "=== BFD already closed.\n");
828 return 0;
829 }
830
831 if (bfd->cmd_plugin && plugin_bclose) {
832 status = plugin_bclose(bfd);
833 Dmsg0(50, "==== BFD closed!!!\n");
834 goto all_done;
835 }
836
837 /*
838 * We need to tell the API to release the buffer it
839 * allocated in lpContext. We do so by calling the
840 * API one more time, but with the Abort bit set.
841 */
842 if (bfd->use_backup_api && bfd->mode == BF_READ) {
843 BYTE buf[10];
844 if (bfd->lpContext && !p_BackupRead(bfd->fh, buf, /* buffer */
845 (DWORD)0, /* bytes to read */
846 &bfd->rw_bytes, /* bytes read */
847 1, /* Abort */
848 1, /* ProcessSecurity */
849 &bfd->lpContext)) { /* Read context */
850 errno = b_errno_win32;
851 status = -1;
852 }
853 } else if (bfd->use_backup_api && bfd->mode == BF_WRITE) {
854 BYTE buf[10];
855 if (bfd->lpContext && !p_BackupWrite(bfd->fh, buf, /* buffer */
856 (DWORD)0, /* bytes to read */
857 &bfd->rw_bytes, /* bytes written */
858 1, /* Abort */
859 1, /* ProcessSecurity */
860 &bfd->lpContext)) { /* Write context */
861 errno = b_errno_win32;
862 status = -1;
863 }
864 }
865 if (!CloseHandle(bfd->fh)) {
866 status = -1;
867 errno = b_errno_win32;
868 }
869
870 all_done:
871 if (bfd->errmsg) {
872 FreePoolMemory(bfd->errmsg);
873 bfd->errmsg = NULL;
874 }
875 bfd->mode = BF_CLOSED;
876 bfd->lpContext = NULL;
877 bfd->cmd_plugin = false;
878
879 return status;
880 }
881
882 /**
883 * Returns 0 on success
884 * -1 on error
885 */
bclose(BareosWinFilePacket * bfd)886 int bclose(BareosWinFilePacket* bfd)
887 {
888 if (bfd->encrypted) {
889 return BcloseEncrypted(bfd);
890 } else {
891 return BcloseNonencrypted(bfd);
892 }
893 }
894
895 /* Returns: bytes read on success
896 * 0 on EOF
897 * -1 on error
898 */
bread(BareosWinFilePacket * bfd,void * buf,size_t count)899 ssize_t bread(BareosWinFilePacket* bfd, void* buf, size_t count)
900 {
901 bfd->rw_bytes = 0;
902
903 if (bfd->cmd_plugin && plugin_bread) { return plugin_bread(bfd, buf, count); }
904
905 if (bfd->use_backup_api) {
906 if (!p_BackupRead(bfd->fh, (BYTE*)buf, count, &bfd->rw_bytes,
907 0, /* no Abort */
908 1, /* Process Security */
909 &bfd->lpContext)) { /* Context */
910 bfd->lerror = GetLastError();
911 bfd->BErrNo = b_errno_win32;
912 errno = b_errno_win32;
913 return -1;
914 }
915 } else {
916 if (!ReadFile(bfd->fh, buf, count, &bfd->rw_bytes, NULL)) {
917 bfd->lerror = GetLastError();
918 bfd->BErrNo = b_errno_win32;
919 errno = b_errno_win32;
920 return -1;
921 }
922 }
923
924 return (ssize_t)bfd->rw_bytes;
925 }
926
bwrite(BareosWinFilePacket * bfd,void * buf,size_t count)927 ssize_t bwrite(BareosWinFilePacket* bfd, void* buf, size_t count)
928 {
929 bfd->rw_bytes = 0;
930
931 if (bfd->cmd_plugin && plugin_bwrite) {
932 return plugin_bwrite(bfd, buf, count);
933 }
934
935 if (bfd->use_backup_api) {
936 if (!p_BackupWrite(bfd->fh, (BYTE*)buf, count, &bfd->rw_bytes,
937 0, /* No abort */
938 1, /* Process Security */
939 &bfd->lpContext)) { /* Context */
940 bfd->lerror = GetLastError();
941 bfd->BErrNo = b_errno_win32;
942 errno = b_errno_win32;
943 return -1;
944 }
945 } else {
946 if (!WriteFile(bfd->fh, buf, count, &bfd->rw_bytes, NULL)) {
947 bfd->lerror = GetLastError();
948 bfd->BErrNo = b_errno_win32;
949 errno = b_errno_win32;
950 return -1;
951 }
952 }
953
954 return (ssize_t)bfd->rw_bytes;
955 }
956
IsBopen(BareosWinFilePacket * bfd)957 bool IsBopen(BareosWinFilePacket* bfd) { return bfd->mode != BF_CLOSED; }
958
blseek(BareosWinFilePacket * bfd,boffset_t offset,int whence)959 boffset_t blseek(BareosWinFilePacket* bfd, boffset_t offset, int whence)
960 {
961 LONG offset_low = (LONG)offset;
962 LONG offset_high = (LONG)(offset >> 32);
963 DWORD dwResult;
964
965 if (bfd->cmd_plugin && plugin_blseek) {
966 return plugin_blseek(bfd, offset, whence);
967 }
968
969 dwResult = SetFilePointer(bfd->fh, offset_low, &offset_high, whence);
970
971 if (dwResult == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
972 return (boffset_t)-1;
973 }
974
975 return ((boffset_t)offset_high << 32) | dwResult;
976 }
977
978 #else /* Unix systems */
979
980 /* ===============================================================
981 *
982 * U N I X
983 *
984 * ===============================================================
985 */
binit(BareosWinFilePacket * bfd)986 void binit(BareosWinFilePacket* bfd) { bfd->fid = -1; }
987
have_win32_api()988 bool have_win32_api() { return false; /* no can do */ }
989
990 /**
991 * Enables using the Backup API (win32_data).
992 * Returns true if function worked
993 * Returns false if failed (i.e. do not have Backup API on this machine)
994 */
set_win32_backup(BareosWinFilePacket * bfd)995 bool set_win32_backup(BareosWinFilePacket* bfd)
996 {
997 return false; /* no can do */
998 }
999
SetPortableBackup(BareosWinFilePacket * bfd)1000 bool SetPortableBackup(BareosWinFilePacket* bfd)
1001 {
1002 return true; /* no problem */
1003 }
1004
1005 /**
1006 * Return true if we are writing in portable format
1007 * return false if not
1008 */
IsPortableBackup(BareosWinFilePacket * bfd)1009 bool IsPortableBackup(BareosWinFilePacket* bfd)
1010 {
1011 return true; /* portable by definition */
1012 }
1013
set_prog(BareosWinFilePacket * bfd,char * prog,JobControlRecord * jcr)1014 bool set_prog(BareosWinFilePacket* bfd, char* prog, JobControlRecord* jcr)
1015 {
1016 return false;
1017 }
1018
SetCmdPlugin(BareosWinFilePacket * bfd,JobControlRecord * jcr)1019 bool SetCmdPlugin(BareosWinFilePacket* bfd, JobControlRecord* jcr)
1020 {
1021 bfd->cmd_plugin = true;
1022 bfd->jcr = jcr;
1023 return true;
1024 }
1025
1026 /**
1027 * This code is running on a non-Win32 machine
1028 */
IsRestoreStreamSupported(int stream)1029 bool IsRestoreStreamSupported(int stream)
1030 {
1031 /* No Win32 backup on this machine */
1032 switch (stream) {
1033 #ifndef HAVE_LIBZ
1034 case STREAM_GZIP_DATA:
1035 case STREAM_SPARSE_GZIP_DATA:
1036 case STREAM_WIN32_GZIP_DATA:
1037 #endif
1038 #ifndef HAVE_DARWIN_OS
1039 case STREAM_MACOS_FORK_DATA:
1040 case STREAM_HFSPLUS_ATTRIBUTES:
1041 #endif
1042 return false;
1043
1044 /* Known streams */
1045 #ifdef HAVE_LIBZ
1046 case STREAM_GZIP_DATA:
1047 case STREAM_SPARSE_GZIP_DATA:
1048 case STREAM_WIN32_GZIP_DATA:
1049 #endif
1050 case STREAM_COMPRESSED_DATA:
1051 case STREAM_SPARSE_COMPRESSED_DATA:
1052 case STREAM_WIN32_COMPRESSED_DATA:
1053 case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
1054 case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
1055 case STREAM_WIN32_DATA:
1056 case STREAM_UNIX_ATTRIBUTES:
1057 case STREAM_FILE_DATA:
1058 case STREAM_MD5_DIGEST:
1059 case STREAM_UNIX_ATTRIBUTES_EX:
1060 case STREAM_SPARSE_DATA:
1061 case STREAM_PROGRAM_NAMES:
1062 case STREAM_PROGRAM_DATA:
1063 case STREAM_SHA1_DIGEST:
1064 #ifdef HAVE_SHA2
1065 case STREAM_SHA256_DIGEST:
1066 case STREAM_SHA512_DIGEST:
1067 #endif
1068 #ifdef HAVE_CRYPTO
1069 case STREAM_SIGNED_DIGEST:
1070 case STREAM_ENCRYPTED_FILE_DATA:
1071 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
1072 case STREAM_ENCRYPTED_WIN32_DATA:
1073 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
1074 #endif
1075 #ifdef HAVE_DARWIN_OS
1076 case STREAM_MACOS_FORK_DATA:
1077 case STREAM_HFSPLUS_ATTRIBUTES:
1078 #ifdef HAVE_CRYPTO
1079 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
1080 #endif /* HAVE_CRYPTO */
1081 #endif /* HAVE_DARWIN_OS */
1082 case 0: /* compatibility with old tapes */
1083 return true;
1084 }
1085 return false;
1086 }
1087
bopen(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode,dev_t rdev)1088 int bopen(BareosWinFilePacket* bfd,
1089 const char* fname,
1090 int flags,
1091 mode_t mode,
1092 dev_t rdev)
1093 {
1094 Dmsg4(100, "bopen: fname %s, flags %08o, mode %04o, rdev %u\n", fname, flags,
1095 (mode & ~S_IFMT), rdev);
1096
1097 if (bfd->cmd_plugin && plugin_bopen) {
1098 Dmsg1(400, "call plugin_bopen fname=%s\n", fname);
1099 bfd->fid = plugin_bopen(bfd, fname, flags, mode);
1100 Dmsg1(400, "Plugin bopen stat=%d\n", bfd->fid);
1101 return bfd->fid;
1102 }
1103
1104 /* Normal file open */
1105 Dmsg1(debuglevel, "open file %s\n", fname);
1106
1107 /* We use fnctl to set O_NOATIME if requested to avoid open error */
1108 bfd->fid = open(fname, flags & ~O_NOATIME, mode);
1109
1110 /* Set O_NOATIME if possible */
1111 if (bfd->fid != -1 && flags & O_NOATIME) {
1112 int oldflags = fcntl(bfd->fid, F_GETFL, 0);
1113 if (oldflags == -1) {
1114 bfd->BErrNo = errno;
1115 close(bfd->fid);
1116 bfd->fid = -1;
1117 } else {
1118 int ret = fcntl(bfd->fid, F_SETFL, oldflags | O_NOATIME);
1119 /* EPERM means setting O_NOATIME was not allowed */
1120 if (ret == -1 && errno != EPERM) {
1121 bfd->BErrNo = errno;
1122 close(bfd->fid);
1123 bfd->fid = -1;
1124 }
1125 }
1126 }
1127 bfd->BErrNo = errno;
1128 bfd->flags_ = flags;
1129 Dmsg1(400, "Open file %d\n", bfd->fid);
1130 errno = bfd->BErrNo;
1131
1132 bfd->win32DecompContext.bIsInData = false;
1133 bfd->win32DecompContext.liNextHeader = 0;
1134
1135 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
1136 if (bfd->fid != -1 && flags & O_RDONLY) {
1137 int status = posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_WILLNEED);
1138 Dmsg2(400, "Did posix_fadvise on %s status=%d\n", fname, status);
1139 }
1140 #endif
1141
1142 return bfd->fid;
1143 }
1144
1145 #ifdef HAVE_DARWIN_OS
1146 /**
1147 * Open the resource fork of a file.
1148 */
BopenRsrc(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)1149 int BopenRsrc(BareosWinFilePacket* bfd,
1150 const char* fname,
1151 int flags,
1152 mode_t mode)
1153 {
1154 POOLMEM* rsrc_fname;
1155
1156 rsrc_fname = GetPoolMemory(PM_FNAME);
1157 PmStrcpy(rsrc_fname, fname);
1158 PmStrcat(rsrc_fname, _PATH_RSRCFORKSPEC);
1159 bopen(bfd, rsrc_fname, flags, mode, 0);
1160 FreePoolMemory(rsrc_fname);
1161
1162 return bfd->fid;
1163 }
1164 #else
BopenRsrc(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)1165 int BopenRsrc(BareosWinFilePacket* bfd,
1166 const char* fname,
1167 int flags,
1168 mode_t mode)
1169 {
1170 return -1;
1171 }
1172 #endif
1173
bclose(BareosWinFilePacket * bfd)1174 int bclose(BareosWinFilePacket* bfd)
1175 {
1176 int status;
1177
1178 if (bfd->fid == -1) { return 0; }
1179
1180 Dmsg1(400, "Close file %d\n", bfd->fid);
1181
1182 if (bfd->cmd_plugin && plugin_bclose) {
1183 status = plugin_bclose(bfd);
1184 bfd->fid = -1;
1185 bfd->cmd_plugin = false;
1186 } else {
1187 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
1188 if (bfd->flags_ & O_RDONLY) {
1189 fdatasync(bfd->fid); /* sync the file */
1190 /* Tell OS we don't need it any more */
1191 posix_fadvise(bfd->fid, 0, 0, POSIX_FADV_DONTNEED);
1192 }
1193 #endif
1194
1195 /* Close normal file */
1196 status = close(bfd->fid);
1197 bfd->BErrNo = errno;
1198 bfd->fid = -1;
1199 bfd->cmd_plugin = false;
1200 }
1201
1202 return status;
1203 }
1204
bread(BareosWinFilePacket * bfd,void * buf,size_t count)1205 ssize_t bread(BareosWinFilePacket* bfd, void* buf, size_t count)
1206 {
1207 ssize_t status;
1208
1209 if (bfd->cmd_plugin && plugin_bread) { return plugin_bread(bfd, buf, count); }
1210
1211 status = read(bfd->fid, buf, count);
1212 bfd->BErrNo = errno;
1213 return status;
1214 }
1215
bwrite(BareosWinFilePacket * bfd,void * buf,size_t count)1216 ssize_t bwrite(BareosWinFilePacket* bfd, void* buf, size_t count)
1217 {
1218 ssize_t status;
1219
1220 if (bfd->cmd_plugin && plugin_bwrite) {
1221 return plugin_bwrite(bfd, buf, count);
1222 }
1223 status = write(bfd->fid, buf, count);
1224 bfd->BErrNo = errno;
1225 return status;
1226 }
1227
IsBopen(BareosWinFilePacket * bfd)1228 bool IsBopen(BareosWinFilePacket* bfd) { return bfd->fid >= 0; }
1229
blseek(BareosWinFilePacket * bfd,boffset_t offset,int whence)1230 boffset_t blseek(BareosWinFilePacket* bfd, boffset_t offset, int whence)
1231 {
1232 boffset_t pos;
1233
1234 if (bfd->cmd_plugin && plugin_bwrite) {
1235 return plugin_blseek(bfd, offset, whence);
1236 }
1237 pos = (boffset_t)lseek(bfd->fid, offset, whence);
1238 bfd->BErrNo = errno;
1239 return pos;
1240 }
1241 #endif
1242