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