Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "attribs.h"
4 : #include "berrno.h"
5 : #include "bfile.h"
6 : #include "log.h"
7 :
8 : #ifdef HAVE_DARWIN_OS
9 : #include <sys/paths.h>
10 : #endif
11 :
12 11 : void bfile_free(struct BFILE **bfd)
13 : {
14 11 : free_v((void **)bfd);
15 11 : }
16 :
17 : #ifdef HAVE_WIN32
18 : static ssize_t bfile_write_windows(struct BFILE *bfd, void *buf, size_t count);
19 : #endif
20 :
21 : #define min(a,b) \
22 : ({ __typeof__ (a) _a = (a); \
23 : __typeof__ (b) _b = (b); \
24 : _a < _b ? _a : _b; })
25 :
26 0 : static void setup_vss_strip(struct BFILE *bfd)
27 : {
28 0 : memset(&bfd->mysid, 0, sizeof(struct mysid));
29 0 : bfd->mysid.needed_s=bsidsize;
30 0 : }
31 :
32 0 : static ssize_t bfile_write_vss_strip(struct BFILE *bfd, void *buf, size_t count)
33 : {
34 0 : size_t mycount;
35 0 : struct mysid *mysid;
36 0 : struct bsid *sid;
37 :
38 0 : mysid=&bfd->mysid;
39 0 : sid=&mysid->sid;
40 0 : char *cp=(char *)buf;
41 0 : mycount=count;
42 :
43 0 : while(mycount)
44 : {
45 0 : if(mysid->needed_s)
46 : {
47 0 : size_t sidlen=bsidsize-mysid->needed_s;
48 0 : int got=min(mysid->needed_s, mycount);
49 :
50 0 : memcpy((char *)sid+sidlen, cp, got);
51 :
52 0 : cp+=got;
53 0 : mycount-=got;
54 0 : mysid->needed_s-=got;
55 :
56 0 : if(!mysid->needed_s) {
57 0 : mysid->needed_d=sid->Size+sid->dwStreamNameSize;
58 : // If the stream is completely empty, start
59 : // reading a new VSS header.
60 0 : if (!mysid->needed_d)
61 0 : mysid->needed_s=bsidsize;
62 : }
63 : }
64 0 : if(mysid->needed_d)
65 : {
66 0 : size_t wrote;
67 0 : int got=min(mysid->needed_d, mycount);
68 :
69 0 : if(sid->dwStreamId==1)
70 : {
71 : #ifdef HAVE_WIN32
72 : if((wrote=bfile_write_windows(bfd,
73 : cp, got))<=0)
74 : return -1;
75 : #else
76 0 : if((wrote=write(bfd->fd,
77 : cp, got))<=0)
78 : return -1;
79 : #endif
80 : }
81 : else
82 0 : wrote=got;
83 :
84 0 : cp+=wrote;
85 0 : mycount-=wrote;
86 0 : mysid->needed_d-=wrote;
87 0 : if(!mysid->needed_d)
88 0 : mysid->needed_s=bsidsize;
89 : }
90 : }
91 :
92 0 : return count;
93 : }
94 :
95 : #ifdef HAVE_WIN32
96 :
97 : extern "C" HANDLE get_osfhandle(int fd);
98 :
99 : static void bfile_set_win32_api(struct BFILE *bfd, int on)
100 : {
101 : if(have_win32_api() && on)
102 : bfd->use_backup_api=1;
103 : else
104 : bfd->use_backup_api=0;
105 : }
106 :
107 : int have_win32_api(void)
108 : {
109 : return p_BackupRead && p_BackupWrite;
110 : }
111 :
112 : // Windows flags for the OpenEncryptedFileRaw functions
113 : #define CREATE_FOR_EXPORT 0
114 : // These are already defined
115 : //#define CREATE_FOR_IMPORT 1
116 : //#define CREATE_FOR_DIR 2
117 : //#define OVERWRITE_HIDDEN 4
118 :
119 : // Return 0 for success, non zero for error.
120 : static int bfile_open_encrypted(struct BFILE *bfd,
121 : const char *fname, int flags, mode_t mode)
122 : {
123 : ULONG ulFlags=0;
124 : char *win32_fname_wchar=NULL;
125 :
126 : bfd->mode=BF_CLOSED;
127 : if(!(win32_fname_wchar=make_win32_path_UTF8_2_wchar_w(fname)))
128 : {
129 : logp("could not get widename!");
130 : goto end;
131 : }
132 :
133 : if((flags & O_CREAT) /* Create */
134 : || (flags & O_WRONLY)) /* Open existing for write */
135 : {
136 : ulFlags |= CREATE_FOR_IMPORT;
137 : ulFlags |= OVERWRITE_HIDDEN;
138 : if(bfd->winattr & FILE_ATTRIBUTE_DIRECTORY)
139 : {
140 : mkdir(fname, 0777);
141 : ulFlags |= CREATE_FOR_DIR;
142 : }
143 : }
144 : else
145 : {
146 : /* Open existing for read */
147 : ulFlags=CREATE_FOR_EXPORT;
148 : }
149 :
150 : if(p_OpenEncryptedFileRawW((LPCWSTR)win32_fname_wchar,
151 : ulFlags, &(bfd->pvContext)))
152 : bfd->mode=BF_CLOSED;
153 : else
154 : bfd->mode=BF_READ;
155 :
156 : end:
157 : free_w(&win32_fname_wchar);
158 : return bfd->mode==BF_CLOSED;
159 : }
160 :
161 : static int bfile_error(struct BFILE *bfd)
162 : {
163 : if(bfd)
164 : {
165 : bfd->lerror=GetLastError();
166 : bfd->berrno=b_errno_win32;
167 : }
168 : errno=b_errno_win32;
169 : return -1;
170 : }
171 :
172 : // Return 0 for success, non zero for error.
173 : static int bfile_open(struct BFILE *bfd, struct asfd *asfd,
174 : const char *fname, int flags, mode_t mode)
175 : {
176 : DWORD dwaccess;
177 : DWORD dwflags;
178 : DWORD dwshare;
179 : char *win32_fname_wchar=NULL;
180 :
181 : bfd->mode=BF_CLOSED;
182 :
183 : if(bfd->winattr & FILE_ATTRIBUTE_ENCRYPTED)
184 : return bfile_open_encrypted(bfd, fname, flags, mode);
185 :
186 : if(!(win32_fname_wchar=make_win32_path_UTF8_2_wchar_w(fname)))
187 : {
188 : logp("could not get widename!");
189 : goto end;
190 : }
191 :
192 : if(flags & O_CREAT)
193 : {
194 : /* Create */
195 :
196 : if(bfd->winattr & FILE_ATTRIBUTE_DIRECTORY)
197 : mkdir(fname, 0777);
198 :
199 : if(bfd->use_backup_api)
200 : {
201 : dwaccess=GENERIC_WRITE
202 : | FILE_ALL_ACCESS
203 : | WRITE_OWNER
204 : | WRITE_DAC
205 : | ACCESS_SYSTEM_SECURITY;
206 : dwflags=FILE_FLAG_BACKUP_SEMANTICS;
207 : }
208 : else
209 : {
210 : dwaccess=GENERIC_WRITE;
211 : dwflags=0;
212 : }
213 :
214 : // unicode open for create write
215 : bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
216 : dwaccess, /* Requested access */
217 : 0, /* Shared mode */
218 : NULL, /* SecurityAttributes */
219 : CREATE_ALWAYS, /* CreationDisposition */
220 : dwflags, /* Flags and attributes */
221 : NULL); /* TemplateFile */
222 :
223 : bfd->mode=BF_WRITE;
224 : }
225 : else if(flags & O_WRONLY)
226 : {
227 : /* Open existing for write */
228 : if(bfd->use_backup_api)
229 : {
230 : dwaccess=GENERIC_WRITE
231 : | WRITE_OWNER
232 : | WRITE_DAC;
233 : dwflags=FILE_FLAG_BACKUP_SEMANTICS
234 : | FILE_FLAG_OPEN_REPARSE_POINT;
235 : }
236 : else
237 : {
238 : dwaccess=GENERIC_WRITE;
239 : dwflags=0;
240 : }
241 :
242 : // unicode open for open existing write
243 : bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
244 : dwaccess, /* Requested access */
245 : 0, /* Shared mode */
246 : NULL, /* SecurityAttributes */
247 : OPEN_EXISTING, /* CreationDisposition */
248 : dwflags, /* Flags and attributes */
249 : NULL); /* TemplateFile */
250 :
251 : bfd->mode=BF_WRITE;
252 : }
253 : else
254 : {
255 : /* Read */
256 : if(bfd->use_backup_api)
257 : {
258 : dwaccess=GENERIC_READ|READ_CONTROL
259 : | ACCESS_SYSTEM_SECURITY;
260 : dwflags=FILE_FLAG_BACKUP_SEMANTICS
261 : | FILE_FLAG_SEQUENTIAL_SCAN
262 : | FILE_FLAG_OPEN_REPARSE_POINT;
263 : dwshare=FILE_SHARE_READ
264 : | FILE_SHARE_WRITE
265 : | FILE_SHARE_DELETE;
266 : }
267 : else
268 : {
269 : dwaccess=GENERIC_READ;
270 : dwflags=0;
271 : dwshare=FILE_SHARE_READ
272 : | FILE_SHARE_WRITE;
273 : }
274 :
275 : // unicode open for open existing read
276 : bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
277 : dwaccess, /* Requested access */
278 : dwshare, /* Share modes */
279 : NULL, /* SecurityAttributes */
280 : OPEN_EXISTING, /* CreationDisposition */
281 : dwflags, /* Flags and attributes */
282 : NULL); /* TemplateFile */
283 :
284 : bfd->mode=BF_READ;
285 : }
286 :
287 : if(bfd->fh==INVALID_HANDLE_VALUE)
288 : {
289 : bfile_error(bfd);
290 : bfd->mode=BF_CLOSED;
291 : }
292 : else
293 : {
294 : free_w(&bfd->path);
295 : if(!(bfd->path=strdup_w(fname, __func__)))
296 : goto end;
297 : }
298 : end:
299 : bfd->lpContext=NULL;
300 : free_w(&win32_fname_wchar);
301 :
302 : if(bfd->vss_strip)
303 : setup_vss_strip(bfd);
304 :
305 : return bfd->mode==BF_CLOSED;
306 : }
307 :
308 : static int bfile_close_encrypted(struct BFILE *bfd, struct asfd *asfd)
309 : {
310 : CloseEncryptedFileRaw(bfd->pvContext);
311 : if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
312 : attribs_set(asfd,
313 : bfd->path, &bfd->statp, bfd->winattr, bfd->cntr);
314 : bfd->pvContext=NULL;
315 : bfd->mode=BF_CLOSED;
316 : free_w(&bfd->path);
317 : return 0;
318 : }
319 :
320 : // Return 0 on success, -1 on error.
321 : static int bfile_close(struct BFILE *bfd, struct asfd *asfd)
322 : {
323 : int ret=-1;
324 :
325 : if(!bfd) return 0;
326 :
327 : if(bfd->mode==BF_CLOSED)
328 : {
329 : ret=0;
330 : goto end;
331 : }
332 :
333 : if(bfd->winattr & FILE_ATTRIBUTE_ENCRYPTED)
334 : return bfile_close_encrypted(bfd, asfd);
335 :
336 : /*
337 : * We need to tell the API to release the buffer it
338 : * allocated in lpContext. We do so by calling the
339 : * API one more time, but with the Abort bit set.
340 : */
341 : if(bfd->use_backup_api && bfd->mode==BF_READ)
342 : {
343 : BYTE buf[10];
344 : if(bfd->lpContext
345 : && !p_BackupRead(bfd->fh,
346 : buf, /* buffer */
347 : (DWORD)0, /* bytes to read */
348 : &bfd->rw_bytes, /* bytes read */
349 : 1, /* Abort */
350 : 1, /* ProcessSecurity */
351 : &bfd->lpContext)) /* Read context */
352 : {
353 : bfile_error(NULL);
354 : goto end;
355 : }
356 : }
357 : else if(bfd->use_backup_api && bfd->mode==BF_WRITE)
358 : {
359 : BYTE buf[10];
360 : if(bfd->lpContext
361 : && !p_BackupWrite(bfd->fh,
362 : buf, /* buffer */
363 : (DWORD)0, /* bytes to read */
364 : &bfd->rw_bytes, /* bytes written */
365 : 1, /* Abort */
366 : 1, /* ProcessSecurity */
367 : &bfd->lpContext)) /* Write context */
368 : {
369 : bfile_error(NULL);
370 : goto end;
371 : }
372 : }
373 : if(!CloseHandle(bfd->fh))
374 : {
375 : bfile_error(NULL);
376 : goto end;
377 : }
378 :
379 : if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
380 : attribs_set(asfd,
381 : bfd->path, &bfd->statp, bfd->winattr, bfd->cntr);
382 : bfd->lpContext=NULL;
383 : bfd->mode=BF_CLOSED;
384 :
385 : ret=0;
386 : end:
387 : free_w(&bfd->path);
388 : return ret;
389 : }
390 :
391 : // Returns: bytes read on success, or 0 on EOF, -1 on error.
392 : static ssize_t bfile_read(struct BFILE *bfd, void *buf, size_t count)
393 : {
394 : bfd->rw_bytes=0;
395 :
396 : if(bfd->use_backup_api)
397 : {
398 : if(!p_BackupRead(bfd->fh,
399 : (BYTE *)buf,
400 : count,
401 : &bfd->rw_bytes,
402 : 0, /* no Abort */
403 : 1, /* Process Security */
404 : &bfd->lpContext)) /* Context */
405 : return bfile_error(bfd);
406 : }
407 : else
408 : {
409 : if(!ReadFile(bfd->fh,
410 : buf,
411 : count,
412 : &bfd->rw_bytes,
413 : NULL))
414 : return bfile_error(bfd);
415 : }
416 :
417 : return (ssize_t)bfd->rw_bytes;
418 : }
419 :
420 : static ssize_t bfile_write_windows(struct BFILE *bfd, void *buf, size_t count)
421 : {
422 : bfd->rw_bytes = 0;
423 :
424 : if(bfd->use_backup_api)
425 : {
426 : if(!p_BackupWrite(bfd->fh,
427 : (BYTE *)buf,
428 : count,
429 : &bfd->rw_bytes,
430 : 0, /* No abort */
431 : 1, /* Process Security */
432 : &bfd->lpContext)) /* Context */
433 : return bfile_error(bfd);
434 : }
435 : else
436 : {
437 : if(!WriteFile(bfd->fh,
438 : buf,
439 : count,
440 : &bfd->rw_bytes,
441 : NULL))
442 : return bfile_error(bfd);
443 : }
444 : return (ssize_t)bfd->rw_bytes;
445 : }
446 :
447 : static ssize_t bfile_write(struct BFILE *bfd, void *buf, size_t count)
448 : {
449 : if(bfd->vss_strip)
450 : return bfile_write_vss_strip(bfd, buf, count);
451 : return bfile_write_windows(bfd, buf, count);
452 : }
453 :
454 : #else
455 :
456 26 : static int bfile_close(struct BFILE *bfd, struct asfd *asfd)
457 : {
458 26 : if(!bfd || bfd->mode==BF_CLOSED) return 0;
459 :
460 16 : if(!close(bfd->fd))
461 : {
462 16 : if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
463 4 : attribs_set(asfd, bfd->path,
464 : &bfd->statp, bfd->winattr, bfd->cntr);
465 16 : bfd->mode=BF_CLOSED;
466 16 : bfd->fd=-1;
467 16 : free_w(&bfd->path);
468 16 : return 0;
469 : }
470 0 : free_w(&bfd->path);
471 0 : return -1;
472 : }
473 :
474 16 : static int bfile_open(struct BFILE *bfd,
475 : struct asfd *asfd, const char *fname, int flags, mode_t mode)
476 : {
477 16 : if(!bfd) return 0;
478 16 : if(bfd->mode!=BF_CLOSED && bfd->close(bfd, asfd))
479 : return -1;
480 16 : if((bfd->fd=open(fname, flags, mode))<0)
481 : return -1;
482 16 : if(flags & O_CREAT || flags & O_WRONLY)
483 4 : bfd->mode=BF_WRITE;
484 : else
485 12 : bfd->mode=BF_READ;
486 16 : free_w(&bfd->path);
487 16 : if(!(bfd->path=strdup_w(fname, __func__)))
488 : return -1;
489 16 : if(bfd->vss_strip)
490 0 : setup_vss_strip(bfd);
491 : return 0;
492 : }
493 :
494 16 : static ssize_t bfile_read(struct BFILE *bfd, void *buf, size_t count)
495 : {
496 16 : return read(bfd->fd, buf, count);
497 : }
498 :
499 4 : static ssize_t bfile_write(struct BFILE *bfd, void *buf, size_t count)
500 : {
501 4 : if(bfd->vss_strip)
502 0 : return bfile_write_vss_strip(bfd, buf, count);
503 :
504 4 : return write(bfd->fd, buf, count);
505 : }
506 :
507 : #endif
508 :
509 12 : static int bfile_open_for_send(
510 : struct BFILE *bfd,
511 : struct asfd *asfd,
512 : const char *fname,
513 : int use_backup_api,
514 : int64_t winattr,
515 : int atime,
516 : struct cntr *cntr
517 : ) {
518 12 : if(bfd->mode!=BF_CLOSED)
519 : {
520 : #ifdef HAVE_WIN32
521 : if(bfd->path && !strcmp(bfd->path, fname))
522 : {
523 : // Already open after reading the VSS data.
524 : // Time now for the actual file data.
525 : return 0;
526 : }
527 : else
528 : {
529 : #endif
530 : // Close the open bfd so that it can be
531 : // used again
532 0 : bfd->close(bfd, asfd);
533 : #ifdef HAVE_WIN32
534 : }
535 : #endif
536 : }
537 :
538 12 : bfile_init(bfd, use_backup_api, winattr, cntr);
539 20 : if(bfile_open(bfd, asfd, fname, O_RDONLY|O_BINARY
540 : #ifdef O_NOFOLLOW
541 : |O_NOFOLLOW
542 : #endif
543 : #ifdef O_NOATIME
544 : |(atime?0:O_NOATIME)
545 : #endif
546 : , 0))
547 : {
548 0 : struct berrno be;
549 0 : berrno_init(&be);
550 0 : logw(asfd, cntr,
551 : "Could not open %s: %s\n",
552 0 : fname, berrno_bstrerror(&be, errno));
553 0 : return -1;
554 : }
555 : return 0;
556 : }
557 :
558 4 : static void bfile_set_vss_strip(struct BFILE *bfd, int on)
559 : {
560 4 : bfd->vss_strip=on;
561 4 : }
562 :
563 30 : void bfile_setup_funcs(struct BFILE *bfd)
564 : {
565 30 : bfd->open=bfile_open;
566 30 : bfd->close=bfile_close;
567 30 : bfd->read=bfile_read;
568 30 : bfd->write=bfile_write;
569 30 : bfd->open_for_send=bfile_open_for_send;
570 : #ifdef HAVE_WIN32
571 : bfd->set_win32_api=bfile_set_win32_api;
572 : #endif
573 30 : bfd->set_vss_strip=bfile_set_vss_strip;
574 0 : }
575 :
576 30 : void bfile_init(
577 : struct BFILE *bfd,
578 : int use_backup_api,
579 : int64_t winattr,
580 : struct cntr *cntr
581 : ) {
582 30 : memset(bfd, 0, sizeof(struct BFILE));
583 30 : bfd->mode=BF_CLOSED;
584 30 : bfd->winattr=winattr;
585 30 : bfd->cntr=cntr;
586 30 : if(!bfd->open) bfile_setup_funcs(bfd);
587 : #ifdef HAVE_WIN32
588 : bfile_set_win32_api(bfd, use_backup_api);
589 : #else
590 30 : bfd->fd=-1;
591 : #endif
592 30 : }
593 :
594 10 : struct BFILE *bfile_alloc(void)
595 : {
596 10 : return (struct BFILE *)calloc_w(1, sizeof(struct BFILE), __func__);
597 : }
|