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