e428fef9fb50906bc8ca5f31a5a5f519e288c821
[reactos.git] / reactos / drivers / filesystems / btrfs / create.c
1 /* Copyright (c) Mark Harmstone 2016
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #ifndef __REACTOS__
19 #include <sys/stat.h>
20 #endif /* __REACTOS__ */
21 #include "btrfs_drv.h"
22
23 extern PDEVICE_OBJECT devobj;
24
25 BOOL STDCALL find_file_in_dir_with_crc32(device_extension* Vcb, PUNICODE_STRING filename, UINT32 crc32, root* r,
26 UINT64 parinode, root** subvol, UINT64* inode, UINT8* type, PANSI_STRING utf8) {
27 DIR_ITEM* di;
28 KEY searchkey;
29 traverse_ptr tp, tp2, next_tp;
30 BOOL b;
31 NTSTATUS Status;
32 ULONG stringlen;
33
34 TRACE("(%p, %.*S, %08x, %p, %llx, %p, %p, %p)\n", Vcb, filename->Length / sizeof(WCHAR), filename->Buffer, crc32, r, parinode, subvol, inode, type);
35
36 searchkey.obj_id = parinode;
37 searchkey.obj_type = TYPE_DIR_ITEM;
38 searchkey.offset = crc32;
39
40 Status = find_item(Vcb, r, &tp, &searchkey, FALSE);
41 if (!NT_SUCCESS(Status)) {
42 ERR("error - find_item returned %08x\n", Status);
43 return FALSE;
44 }
45
46 TRACE("found item %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
47
48 if (!keycmp(&searchkey, &tp.item->key)) {
49 UINT32 size = tp.item->size;
50
51 // found by hash
52
53 if (tp.item->size < sizeof(DIR_ITEM)) {
54 WARN("(%llx;%llx,%x,%llx) was %u bytes, expected at least %u\n", r->id, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
55 } else {
56 di = (DIR_ITEM*)tp.item->data;
57
58 while (size > 0) {
59 if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + di->m + di->n)) {
60 WARN("(%llx,%x,%llx) is truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
61 break;
62 }
63
64 size -= sizeof(DIR_ITEM) - sizeof(char);
65 size -= di->n;
66 size -= di->m;
67
68 Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, di->name, di->n);
69 if (!NT_SUCCESS(Status)) {
70 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
71 } else {
72 WCHAR* utf16 = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
73 UNICODE_STRING us;
74
75 if (!utf16) {
76 ERR("out of memory\n");
77 return FALSE;
78 }
79
80 Status = RtlUTF8ToUnicodeN(utf16, stringlen, &stringlen, di->name, di->n);
81
82 if (!NT_SUCCESS(Status)) {
83 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
84 } else {
85 us.Buffer = utf16;
86 us.Length = us.MaximumLength = (USHORT)stringlen;
87
88 if (FsRtlAreNamesEqual(filename, &us, TRUE, NULL)) {
89 if (di->key.obj_type == TYPE_ROOT_ITEM) {
90 LIST_ENTRY* le = Vcb->roots.Flink;
91
92 if (subvol) {
93 *subvol = NULL;
94
95 while (le != &Vcb->roots) {
96 root* r2 = CONTAINING_RECORD(le, root, list_entry);
97
98 if (r2->id == di->key.obj_id) {
99 *subvol = r2;
100 break;
101 }
102
103 le = le->Flink;
104 }
105 }
106
107 if (inode)
108 *inode = SUBVOL_ROOT_INODE;
109
110 if (type)
111 *type = BTRFS_TYPE_DIRECTORY;
112 } else {
113 if (subvol)
114 *subvol = r;
115
116 if (inode)
117 *inode = di->key.obj_id;
118
119 if (type)
120 *type = di->type;
121 }
122
123 if (utf8) {
124 utf8->MaximumLength = di->n;
125 utf8->Length = utf8->MaximumLength;
126 utf8->Buffer = ExAllocatePoolWithTag(PagedPool, utf8->MaximumLength, ALLOC_TAG);
127 if (!utf8->Buffer) {
128 ERR("out of memory\n");
129 ExFreePool(utf16);
130 return FALSE;
131 }
132
133 RtlCopyMemory(utf8->Buffer, di->name, di->n);
134 }
135
136 ExFreePool(utf16);
137
138 // TRACE("found %.*S by hash at (%llx,%llx)\n", filename->Length / sizeof(WCHAR), filename->Buffer, (*subvol)->id, *inode);
139
140 return TRUE;
141 }
142 }
143
144 ExFreePool(utf16);
145 }
146
147 di = (DIR_ITEM*)&di->name[di->n + di->m];
148 }
149 }
150 }
151
152 searchkey.obj_id = parinode;
153 searchkey.obj_type = TYPE_DIR_INDEX;
154 searchkey.offset = 2;
155
156 Status = find_item(Vcb, r, &tp2, &searchkey, FALSE);
157 if (!NT_SUCCESS(Status)) {
158 ERR("error - find_item returned %08x\n", Status);
159 return FALSE;
160 }
161
162 tp = tp2;
163
164 TRACE("found item %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
165
166 if (keycmp(&tp.item->key, &searchkey) == -1) {
167 if (find_next_item(Vcb, &tp, &next_tp, FALSE)) {
168 tp = next_tp;
169
170 TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
171 }
172 }
173
174 if (tp.item->key.obj_id != parinode || tp.item->key.obj_type != TYPE_DIR_INDEX)
175 return FALSE;
176
177 b = TRUE;
178 do {
179 TRACE("key: %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
180 di = (DIR_ITEM*)tp.item->data;
181
182 if (tp.item->size < sizeof(DIR_ITEM) || tp.item->size < (sizeof(DIR_ITEM) - 1 + di->m + di->n)) {
183 WARN("(%llx,%x,%llx) is truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
184 } else {
185 TRACE("%.*s\n", di->n, di->name);
186
187 Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, di->name, di->n);
188 if (!NT_SUCCESS(Status)) {
189 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
190 } else {
191 WCHAR* utf16 = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
192 UNICODE_STRING us;
193
194 if (!utf16) {
195 ERR("out of memory\n");
196 return FALSE;
197 }
198
199 Status = RtlUTF8ToUnicodeN(utf16, stringlen, &stringlen, di->name, di->n);
200
201 if (!NT_SUCCESS(Status)) {
202 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
203 } else {
204 us.Buffer = utf16;
205 us.Length = us.MaximumLength = (USHORT)stringlen;
206
207 if (FsRtlAreNamesEqual(filename, &us, TRUE, NULL)) {
208 if (di->key.obj_type == TYPE_ROOT_ITEM) {
209 LIST_ENTRY* le = Vcb->roots.Flink;
210
211 if (subvol) {
212 *subvol = NULL;
213
214 while (le != &Vcb->roots) {
215 root* r2 = CONTAINING_RECORD(le, root, list_entry);
216
217 if (r2->id == di->key.obj_id) {
218 *subvol = r2;
219 break;
220 }
221
222 le = le->Flink;
223 }
224 }
225
226 if (inode)
227 *inode = SUBVOL_ROOT_INODE;
228
229 if (type)
230 *type = BTRFS_TYPE_DIRECTORY;
231 } else {
232 if (subvol)
233 *subvol = r;
234
235 if (inode)
236 *inode = di->key.obj_id;
237
238 if (type)
239 *type = di->type;
240 }
241 // TRACE("found %.*S at (%llx,%llx)\n", filename->Length / sizeof(WCHAR), filename->Buffer, (*subvol)->id, *inode);
242
243 if (utf8) {
244 utf8->MaximumLength = di->n;
245 utf8->Length = utf8->MaximumLength;
246 utf8->Buffer = ExAllocatePoolWithTag(PagedPool, utf8->MaximumLength, ALLOC_TAG);
247 if (!utf8->Buffer) {
248 ERR("out of memory\n");
249 ExFreePool(utf16);
250
251 return FALSE;
252 }
253
254 RtlCopyMemory(utf8->Buffer, di->name, di->n);
255 }
256
257 ExFreePool(utf16);
258
259 return TRUE;
260 }
261 }
262
263 ExFreePool(utf16);
264 }
265 }
266
267 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
268
269 if (b) {
270 tp = next_tp;
271
272 b = tp.item->key.obj_id == parinode && tp.item->key.obj_type == TYPE_DIR_INDEX;
273 }
274 } while (b);
275
276 return FALSE;
277 }
278
279 fcb* create_fcb() {
280 fcb* fcb;
281
282 fcb = ExAllocatePoolWithTag(PagedPool, sizeof(struct _fcb), ALLOC_TAG);
283 if (!fcb) {
284 ERR("out of memory\n");
285 return NULL;
286 }
287
288 #ifdef DEBUG_FCB_REFCOUNTS
289 WARN("allocating fcb %p\n", fcb);
290 #endif
291 RtlZeroMemory(fcb, sizeof(struct _fcb));
292
293 fcb->Header.NodeTypeCode = BTRFS_NODE_TYPE_FCB;
294 fcb->Header.NodeByteSize = sizeof(struct _fcb);
295
296 fcb->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _fcb_nonpaged), ALLOC_TAG);
297 if (!fcb->nonpaged) {
298 ERR("out of memory\n");
299 ExFreePool(fcb);
300 return NULL;
301 }
302 RtlZeroMemory(fcb->nonpaged, sizeof(struct _fcb_nonpaged));
303
304 ExInitializeResourceLite(&fcb->nonpaged->paging_resource);
305 fcb->Header.PagingIoResource = &fcb->nonpaged->paging_resource;
306
307 ExInitializeFastMutex(&fcb->nonpaged->HeaderMutex);
308 FsRtlSetupAdvancedHeader(&fcb->Header, &fcb->nonpaged->HeaderMutex);
309
310 fcb->refcount = 1;
311 #ifdef DEBUG_FCB_REFCOUNTS
312 WARN("fcb %p: refcount now %i\n", fcb, fcb->refcount);
313 #endif
314
315 ExInitializeResourceLite(&fcb->nonpaged->resource);
316 fcb->Header.Resource = &fcb->nonpaged->resource;
317
318 FsRtlInitializeFileLock(&fcb->lock, NULL, NULL);
319
320 return fcb;
321 }
322
323 file_ref* create_fileref() {
324 file_ref* fr;
325
326 fr = ExAllocatePoolWithTag(PagedPool, sizeof(file_ref), ALLOC_TAG);
327 if (!fr) {
328 ERR("out of memory\n");
329 return NULL;
330 }
331
332 RtlZeroMemory(fr, sizeof(file_ref));
333
334 fr->refcount = 1;
335
336 #ifdef DEBUG_FCB_REFCOUNTS
337 WARN("fileref %p: refcount now %i\n", fr, fr->refcount);
338 #endif
339
340 InitializeListHead(&fr->children);
341
342 return fr;
343 }
344
345 static BOOL STDCALL find_file_in_dir(device_extension* Vcb, PUNICODE_STRING filename, root* r,
346 UINT64 parinode, root** subvol, UINT64* inode, UINT8* type, PANSI_STRING utf8) {
347 char* fn;
348 UINT32 crc32;
349 BOOL ret;
350 ULONG utf8len;
351 NTSTATUS Status;
352
353 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, filename->Buffer, filename->Length);
354 if (!NT_SUCCESS(Status)) {
355 ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status);
356 return FALSE;
357 }
358
359 fn = ExAllocatePoolWithTag(PagedPool, utf8len, ALLOC_TAG);
360 if (!fn) {
361 ERR("out of memory\n");
362 return FALSE;
363 }
364
365 Status = RtlUnicodeToUTF8N(fn, utf8len, &utf8len, filename->Buffer, filename->Length);
366 if (!NT_SUCCESS(Status)) {
367 ExFreePool(fn);
368 ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
369 return FALSE;
370 }
371
372 TRACE("%.*s\n", utf8len, fn);
373
374 crc32 = calc_crc32c(0xfffffffe, (UINT8*)fn, (ULONG)utf8len);
375 TRACE("crc32c(%.*s) = %08x\n", utf8len, fn, crc32);
376
377 ret = find_file_in_dir_with_crc32(Vcb, filename, crc32, r, parinode, subvol, inode, type, utf8);
378
379 return ret;
380 }
381
382 static BOOL find_stream(device_extension* Vcb, fcb* fcb, PUNICODE_STRING stream, PUNICODE_STRING newstreamname, UINT32* size, UINT32* hash, PANSI_STRING xattr) {
383 NTSTATUS Status;
384 ULONG utf8len;
385 char* utf8;
386 UINT32 crc32;
387 KEY searchkey;
388 traverse_ptr tp, next_tp;
389 BOOL success = FALSE, b;
390
391 static char xapref[] = "user.";
392 ULONG xapreflen = strlen(xapref);
393
394 TRACE("(%p, %p, %.*S)\n", Vcb, fcb, stream->Length / sizeof(WCHAR), stream->Buffer);
395
396 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, stream->Buffer, stream->Length);
397 if (!NT_SUCCESS(Status)) {
398 ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status);
399 return FALSE;
400 }
401
402 TRACE("utf8len = %u\n", utf8len);
403
404 utf8 = ExAllocatePoolWithTag(PagedPool, xapreflen + utf8len + 1, ALLOC_TAG);
405 if (!utf8) {
406 ERR("out of memory\n");
407 goto end;
408 }
409
410 RtlCopyMemory(utf8, xapref, xapreflen);
411
412 Status = RtlUnicodeToUTF8N(&utf8[xapreflen], utf8len, &utf8len, stream->Buffer, stream->Length);
413 if (!NT_SUCCESS(Status)) {
414 ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
415 goto end;
416 }
417
418 utf8len += xapreflen;
419 utf8[utf8len] = 0;
420
421 TRACE("utf8 = %s\n", utf8);
422
423 crc32 = calc_crc32c(0xfffffffe, (UINT8*)utf8, utf8len);
424 TRACE("crc32 = %08x\n", crc32);
425
426 searchkey.obj_id = fcb->inode;
427 searchkey.obj_type = TYPE_XATTR_ITEM;
428 searchkey.offset = crc32;
429
430 Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE);
431 if (!NT_SUCCESS(Status)) {
432 ERR("error - find_item returned %08x\n", Status);
433 goto end;
434 }
435
436 if (!keycmp(&tp.item->key, &searchkey)) {
437 if (tp.item->size < sizeof(DIR_ITEM)) {
438 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
439 } else {
440 ULONG len = tp.item->size, xasize;
441 DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
442
443 TRACE("found match on hash\n");
444
445 while (len > 0) {
446 if (len < sizeof(DIR_ITEM) || len < sizeof(DIR_ITEM) - 1 + di->m + di->n) {
447 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
448 break;
449 }
450
451 if (RtlCompareMemory(di->name, utf8, utf8len) == utf8len) {
452 TRACE("found exact match for %s\n", utf8);
453
454 *size = di->m;
455 *hash = tp.item->key.offset;
456
457 xattr->Buffer = ExAllocatePoolWithTag(PagedPool, di->n + 1, ALLOC_TAG);
458 if (!xattr->Buffer) {
459 ERR("out of memory\n");
460 goto end;
461 }
462
463 xattr->Length = xattr->MaximumLength = di->n;
464 RtlCopyMemory(xattr->Buffer, di->name, di->n);
465 xattr->Buffer[di->n] = 0;
466
467 success = TRUE;
468 goto end;
469 }
470
471 xasize = sizeof(DIR_ITEM) - 1 + di->m + di->n;
472
473 if (len > xasize) {
474 len -= xasize;
475 di = (DIR_ITEM*)&di->name[di->m + di->n];
476 } else
477 break;
478 }
479 }
480 }
481
482 searchkey.offset = 0;
483
484 Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE);
485 if (!NT_SUCCESS(Status)) {
486 ERR("error - find_item returned %08x\n", Status);
487 goto end;
488 }
489
490 do {
491 if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_XATTR_ITEM && tp.item->key.offset != crc32) {
492 if (tp.item->size < sizeof(DIR_ITEM)) {
493 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
494 } else {
495 ULONG len = tp.item->size, xasize;
496 DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
497 ULONG utf16len;
498
499 TRACE("found xattr with hash %08x\n", (UINT32)tp.item->key.offset);
500
501 while (len > 0) {
502 if (len < sizeof(DIR_ITEM) || len < sizeof(DIR_ITEM) - 1 + di->m + di->n) {
503 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
504 break;
505 }
506
507 if (di->n > xapreflen && RtlCompareMemory(di->name, xapref, xapreflen) == xapreflen) {
508 TRACE("found potential xattr %.*s\n", di->n, di->name);
509 }
510
511 Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[xapreflen], di->n - xapreflen);
512 if (!NT_SUCCESS(Status)) {
513 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
514 } else {
515 WCHAR* utf16 = ExAllocatePoolWithTag(PagedPool, utf16len, ALLOC_TAG);
516 if (!utf16) {
517 ERR("out of memory\n");
518 goto end;
519 }
520
521 Status = RtlUTF8ToUnicodeN(utf16, utf16len, &utf16len, &di->name[xapreflen], di->n - xapreflen);
522
523 if (!NT_SUCCESS(Status)) {
524 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
525 } else {
526 UNICODE_STRING us;
527
528 us.Buffer = utf16;
529 us.Length = us.MaximumLength = (USHORT)utf16len;
530
531 if (FsRtlAreNamesEqual(stream, &us, TRUE, NULL)) {
532 TRACE("found case-insensitive match for %s\n", utf8);
533
534 *newstreamname = us;
535 *size = di->m;
536 *hash = tp.item->key.offset;
537
538 xattr->Buffer = ExAllocatePoolWithTag(PagedPool, di->n + 1, ALLOC_TAG);
539 if (!xattr->Buffer) {
540 ERR("out of memory\n");
541 ExFreePool(utf16);
542 goto end;
543 }
544
545 xattr->Length = xattr->MaximumLength = di->n;
546 RtlCopyMemory(xattr->Buffer, di->name, di->n);
547 xattr->Buffer[di->n] = 0;
548
549 success = TRUE;
550 goto end;
551 }
552 }
553
554 ExFreePool(utf16);
555 }
556
557 xasize = sizeof(DIR_ITEM) - 1 + di->m + di->n;
558
559 if (len > xasize) {
560 len -= xasize;
561 di = (DIR_ITEM*)&di->name[di->m + di->n];
562 } else
563 break;
564 }
565 }
566 }
567
568 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
569 if (b) {
570 tp = next_tp;
571
572 if (next_tp.item->key.obj_id > fcb->inode || next_tp.item->key.obj_type > TYPE_XATTR_ITEM)
573 break;
574 }
575 } while (b);
576
577 end:
578 ExFreePool(utf8);
579
580 return success;
581 }
582
583 static NTSTATUS split_path(PUNICODE_STRING path, UNICODE_STRING** parts, ULONG* num_parts, BOOL* stream) {
584 ULONG len, i, j, np;
585 BOOL has_stream;
586 UNICODE_STRING* ps;
587 WCHAR* buf;
588
589 np = 1;
590
591 len = path->Length / sizeof(WCHAR);
592 if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\'))
593 len--;
594
595 has_stream = FALSE;
596 for (i = 0; i < len; i++) {
597 if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
598 np++;
599 has_stream = FALSE;
600 } else if (path->Buffer[i] == ':') {
601 has_stream = TRUE;
602 }
603 }
604
605 if (has_stream)
606 np++;
607
608 ps = ExAllocatePoolWithTag(PagedPool, np * sizeof(UNICODE_STRING), ALLOC_TAG);
609 if (!ps) {
610 ERR("out of memory\n");
611 return STATUS_INSUFFICIENT_RESOURCES;
612 }
613
614 RtlZeroMemory(ps, np * sizeof(UNICODE_STRING));
615
616 buf = path->Buffer;
617
618 j = 0;
619 for (i = 0; i < len; i++) {
620 if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
621 ps[j].Buffer = buf;
622 ps[j].Length = (&path->Buffer[i] - buf) * sizeof(WCHAR);
623 ps[j].MaximumLength = ps[j].Length;
624
625 buf = &path->Buffer[i+1];
626 j++;
627 }
628 }
629
630 ps[j].Buffer = buf;
631 ps[j].Length = (&path->Buffer[i] - buf) * sizeof(WCHAR);
632 ps[j].MaximumLength = ps[j].Length;
633
634 if (has_stream) {
635 static WCHAR datasuf[] = {':','$','D','A','T','A',0};
636 UNICODE_STRING dsus;
637
638 dsus.Buffer = datasuf;
639 dsus.Length = dsus.MaximumLength = wcslen(datasuf) * sizeof(WCHAR);
640
641 for (i = 0; i < ps[j].Length / sizeof(WCHAR); i++) {
642 if (ps[j].Buffer[i] == ':') {
643 ps[j+1].Buffer = &ps[j].Buffer[i+1];
644 ps[j+1].Length = ps[j].Length - (i * sizeof(WCHAR)) - sizeof(WCHAR);
645
646 ps[j].Length = i * sizeof(WCHAR);
647 ps[j].MaximumLength = ps[j].Length;
648
649 j++;
650
651 break;
652 }
653 }
654
655 // FIXME - should comparison be case-insensitive?
656 // remove :$DATA suffix
657 if (ps[j].Length >= dsus.Length && RtlCompareMemory(&ps[j].Buffer[(ps[j].Length - dsus.Length)/sizeof(WCHAR)], dsus.Buffer, dsus.Length) == dsus.Length)
658 ps[j].Length -= dsus.Length;
659
660 if (ps[j].Length == 0) {
661 np--;
662 has_stream = FALSE;
663 }
664 }
665
666 // if path is just stream name, remove first empty item
667 if (has_stream && path->Length >= sizeof(WCHAR) && path->Buffer[0] == ':') {
668 ps[0] = ps[1];
669 np--;
670 }
671
672 // for (i = 0; i < np; i++) {
673 // ERR("part %u: %u, (%.*S)\n", i, ps[i].Length, ps[i].Length / sizeof(WCHAR), ps[i].Buffer);
674 // }
675
676 *num_parts = np;
677 *parts = ps;
678 *stream = has_stream;
679
680 return STATUS_SUCCESS;
681 }
682
683 // #ifdef DEBUG_FCB_REFCOUNTS
684 // static void print_fcbs(device_extension* Vcb) {
685 // fcb* fcb = Vcb->fcbs;
686 //
687 // while (fcb) {
688 // ERR("fcb %p (%.*S): refcount %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount);
689 //
690 // fcb = fcb->next;
691 // }
692 // }
693 // #endif
694
695 static file_ref* search_fileref_children(file_ref* dir, PUNICODE_STRING name) {
696 LIST_ENTRY* le;
697 file_ref *c, *deleted = NULL;
698 #ifdef DEBUG_FCB_REFCOUNTS
699 ULONG rc;
700 #endif
701
702 le = dir->children.Flink;
703 while (le != &dir->children) {
704 c = CONTAINING_RECORD(le, file_ref, list_entry);
705
706 if (c->refcount > 0 && FsRtlAreNamesEqual(&c->filepart, name, TRUE, NULL)) {
707 if (c->deleted) {
708 deleted = c;
709 } else {
710 #ifdef DEBUG_FCB_REFCOUNTS
711 rc = InterlockedIncrement(&c->refcount);
712 WARN("fileref %p: refcount now %i (%S)\n", c, rc, file_desc_fileref(c));
713 #else
714 InterlockedIncrement(&c->refcount);
715 #endif
716 return c;
717 }
718 }
719
720 le = le->Flink;
721 }
722
723 if (deleted) {
724 #ifdef DEBUG_FCB_REFCOUNTS
725 rc = InterlockedIncrement(&deleted->refcount);
726 WARN("fileref %p: refcount now %i (%S)\n", deleted, rc, file_desc_fileref(deleted));
727 #else
728 InterlockedIncrement(&deleted->refcount);
729 #endif
730 }
731
732 return deleted;
733 }
734
735 static NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb) {
736 KEY searchkey;
737 traverse_ptr tp;
738 NTSTATUS Status;
739 fcb* fcb;
740
741 if (!IsListEmpty(&subvol->fcbs)) {
742 LIST_ENTRY* le = subvol->fcbs.Flink;
743
744 while (le != &subvol->fcbs) {
745 fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
746
747 if (fcb->inode == inode && !fcb->ads) {
748 #ifdef DEBUG_FCB_REFCOUNTS
749 LONG rc = InterlockedIncrement(&fcb->refcount);
750
751 WARN("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol->id, fcb->inode);
752 #else
753 InterlockedIncrement(&fcb->refcount);
754 #endif
755
756 *pfcb = fcb;
757 return STATUS_SUCCESS;
758 }
759
760 le = le->Flink;
761 }
762 }
763
764 fcb = create_fcb();
765 if (!fcb) {
766 ERR("out of memory\n");
767 return STATUS_INSUFFICIENT_RESOURCES;
768 }
769
770 fcb->Vcb = Vcb;
771
772 fcb->subvol = subvol;
773 fcb->inode = inode;
774 fcb->type = type;
775
776 searchkey.obj_id = inode;
777 searchkey.obj_type = TYPE_INODE_ITEM;
778 searchkey.offset = 0xffffffffffffffff;
779
780 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
781 if (!NT_SUCCESS(Status)) {
782 ERR("error - find_item returned %08x\n", Status);
783 free_fcb(fcb);
784 return Status;
785 }
786
787 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
788 ERR("couldn't find INODE_ITEM for inode %llx in subvol %llx\n", inode, subvol->id);
789 free_fcb(fcb);
790 return STATUS_INTERNAL_ERROR;
791 }
792
793 if (tp.item->size > 0)
794 RtlCopyMemory(&fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
795
796 fcb->atts = get_file_attributes(Vcb, &fcb->inode_item, fcb->subvol, fcb->inode, fcb->type, utf8->Buffer[0] == '.', FALSE);
797
798 fcb_get_sd(fcb, parent);
799
800 InsertTailList(&subvol->fcbs, &fcb->list_entry);
801
802 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
803
804 if (fcb->inode_item.st_size == 0 || (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_SYMLINK)) {
805 fcb->Header.AllocationSize.QuadPart = 0;
806 fcb->Header.FileSize.QuadPart = 0;
807 fcb->Header.ValidDataLength.QuadPart = 0;
808 } else {
809 EXTENT_DATA* ed;
810
811 searchkey.obj_id = fcb->inode;
812 searchkey.obj_type = TYPE_EXTENT_DATA;
813 searchkey.offset = 0xffffffffffffffff;
814
815 Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
816 if (!NT_SUCCESS(Status)) {
817 ERR("error - find_item returned %08x\n", Status);
818 free_fcb(fcb);
819 return Status;
820 }
821
822 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
823 ERR("error - could not find EXTENT_DATA items for inode %llx in subvol %llx\n", fcb->inode, fcb->subvol->id);
824 free_fcb(fcb);
825 return STATUS_INTERNAL_ERROR;
826 }
827
828 if (tp.item->size < sizeof(EXTENT_DATA)) {
829 ERR("(%llx,%x,%llx) was %llx bytes, expected at least %llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
830 tp.item->size, sizeof(EXTENT_DATA));
831
832 free_fcb(fcb);
833 return STATUS_INTERNAL_ERROR;
834 }
835
836 ed = (EXTENT_DATA*)tp.item->data;
837
838 if (ed->type == EXTENT_TYPE_INLINE)
839 fcb->Header.AllocationSize.QuadPart = fcb->inode_item.st_size;
840 else
841 fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
842
843 fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
844 fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
845 }
846
847 *pfcb = fcb;
848 return STATUS_SUCCESS;
849 }
850
851 static NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr,
852 UINT32 streamsize, UINT32 streamhash, fcb* parent, fcb** pfcb) {
853 fcb* fcb;
854
855 if (!IsListEmpty(&subvol->fcbs)) {
856 LIST_ENTRY* le = subvol->fcbs.Flink;
857
858 while (le != &subvol->fcbs) {
859 fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
860
861 if (fcb->inode == inode && fcb->ads && fcb->adsxattr.Length == xattr->Length &&
862 RtlCompareMemory(fcb->adsxattr.Buffer, xattr->Buffer, fcb->adsxattr.Length) == fcb->adsxattr.Length) {
863 #ifdef DEBUG_FCB_REFCOUNTS
864 LONG rc = InterlockedIncrement(&fcb->refcount);
865
866 WARN("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol->id, fcb->inode);
867 #else
868 InterlockedIncrement(&fcb->refcount);
869 #endif
870
871 *pfcb = fcb;
872 return STATUS_SUCCESS;
873 }
874
875 le = le->Flink;
876 }
877 }
878
879 fcb = create_fcb();
880 if (!fcb) {
881 ERR("out of memory\n");
882 return STATUS_INSUFFICIENT_RESOURCES;
883 }
884
885 fcb->Vcb = Vcb;
886
887 fcb->subvol = parent->subvol;
888 fcb->inode = parent->inode;
889 fcb->type = parent->type;
890 fcb->ads = TRUE;
891 fcb->adssize = streamsize;
892 fcb->adshash = streamhash;
893 fcb->adsxattr = *xattr;
894
895 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
896 fcb->Header.AllocationSize.QuadPart = fcb->adssize;
897 fcb->Header.FileSize.QuadPart = fcb->adssize;
898 fcb->Header.ValidDataLength.QuadPart = fcb->adssize;
899
900 TRACE("stream found: size = %x, hash = %08x\n", fcb->adssize, fcb->adshash);
901
902 InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
903
904 *pfcb = fcb;
905
906 return STATUS_SUCCESS;
907 }
908
909 NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed) {
910 UNICODE_STRING fnus2;
911 file_ref *dir, *sf, *sf2;
912 ULONG i, num_parts;
913 UNICODE_STRING* parts = NULL;
914 BOOL has_stream;
915 NTSTATUS Status;
916
917 TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, unparsed);
918
919 if (Vcb->removing)
920 return STATUS_ACCESS_DENIED;
921
922 fnus2 = *fnus;
923
924 if (fnus2.Length < sizeof(WCHAR) && !related) {
925 ERR("error - fnus was too short\n");
926 return STATUS_INTERNAL_ERROR;
927 }
928
929 if (related && fnus->Length == 0) {
930 #ifdef DEBUG_FCB_REFCOUNTS
931 LONG rc = InterlockedIncrement(&related->refcount);
932 WARN("fileref %p: refcount now %i\n", related, rc);
933 #else
934 InterlockedIncrement(&related->refcount);
935 #endif
936
937
938 *pfr = related;
939 return STATUS_SUCCESS;
940 }
941
942 if (related) {
943 dir = related;
944 } else {
945 if (fnus2.Buffer[0] != '\\') {
946 ERR("error - filename %.*S did not begin with \\\n", fnus2.Length / sizeof(WCHAR), fnus2.Buffer);
947 return STATUS_OBJECT_PATH_NOT_FOUND;
948 }
949
950 if (fnus2.Length == sizeof(WCHAR)) {
951 #ifdef DEBUG_FCB_REFCOUNTS
952 LONG rc = InterlockedIncrement(&Vcb->root_fileref->refcount);
953 WARN("fileref %p: refcount now %i (root)\n", Vcb->root_fileref, rc);
954 #else
955 InterlockedIncrement(&Vcb->root_fileref->refcount);
956 #endif
957 *pfr = Vcb->root_fileref;
958 return STATUS_SUCCESS;
959 }
960
961 dir = Vcb->root_fileref;
962
963 fnus2.Buffer++;
964 fnus2.Length -= sizeof(WCHAR);
965 fnus2.MaximumLength -= sizeof(WCHAR);
966 }
967
968 if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
969 WARN("passed related fileref which isn't a directory (%S) (fnus = %.*S)\n",
970 file_desc_fileref(related), fnus->Length / sizeof(WCHAR), fnus->Buffer);
971 return STATUS_OBJECT_PATH_NOT_FOUND;
972 }
973
974 if (fnus->Length == 0) {
975 num_parts = 0;
976 } else {
977 Status = split_path(&fnus2, &parts, &num_parts, &has_stream);
978 if (!NT_SUCCESS(Status)) {
979 ERR("split_path returned %08x\n", Status);
980 return Status;
981 }
982 }
983
984 sf = dir;
985 dir->refcount++;
986 #ifdef DEBUG_FCB_REFCOUNTS
987 WARN("fileref %p: refcount now %i (%S)\n", dir, dir->refcount, file_desc_fileref(dir));
988 #endif
989
990 if (parent) {
991 num_parts--;
992
993 if (has_stream && num_parts > 0) {
994 num_parts--;
995 has_stream = FALSE;
996 }
997 }
998
999 if (num_parts == 0) {
1000 Status = STATUS_SUCCESS;
1001 *pfr = dir;
1002 goto end2;
1003 }
1004
1005 for (i = 0; i < num_parts; i++) {
1006 BOOL lastpart = (i == num_parts-1) || (i == num_parts-2 && has_stream);
1007
1008 sf2 = search_fileref_children(sf, &parts[i]);
1009
1010 if (sf2 && sf2->fcb->type != BTRFS_TYPE_DIRECTORY && !lastpart) {
1011 WARN("passed path including file as subdirectory\n");
1012 free_fileref(sf2);
1013
1014 Status = STATUS_OBJECT_PATH_NOT_FOUND;
1015 goto end;
1016 }
1017
1018 if (!sf2) {
1019 if (has_stream && i == num_parts - 1) {
1020 UNICODE_STRING streamname;
1021 ANSI_STRING xattr;
1022 UINT32 streamsize, streamhash;
1023
1024 streamname.Buffer = NULL;
1025 streamname.Length = streamname.MaximumLength = 0;
1026 xattr.Buffer = NULL;
1027 xattr.Length = xattr.MaximumLength = 0;
1028
1029 // FIXME - check if already opened
1030
1031 if (!find_stream(Vcb, sf->fcb, &parts[i], &streamname, &streamsize, &streamhash, &xattr)) {
1032 TRACE("could not find stream %.*S\n", parts[i].Length / sizeof(WCHAR), parts[i].Buffer);
1033
1034 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1035 goto end;
1036 } else {
1037 ULONG fnlen;
1038 fcb* fcb;
1039 #ifdef DEBUG_FCB_REFCOUNTS
1040 LONG rc;
1041 #endif
1042
1043 if (streamhash == EA_DOSATTRIB_HASH && xattr.Length == strlen(EA_DOSATTRIB) &&
1044 RtlCompareMemory(xattr.Buffer, EA_DOSATTRIB, xattr.Length) == xattr.Length) {
1045 WARN("not allowing user.DOSATTRIB to be opened as stream\n");
1046
1047 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1048 goto end;
1049 }
1050
1051 Status = open_fcb_stream(Vcb, sf->fcb->subvol, sf->fcb->inode, &xattr, streamsize, streamhash, sf->fcb, &fcb);
1052 if (!NT_SUCCESS(Status)) {
1053 ERR("open_fcb_stream returned %08x\n", Status);
1054 goto end;
1055 }
1056
1057 sf2 = create_fileref();
1058 if (!sf2) {
1059 ERR("out of memory\n");
1060 free_fcb(fcb);
1061 Status = STATUS_INSUFFICIENT_RESOURCES;
1062 goto end;
1063 }
1064
1065 sf2->fcb = fcb;
1066
1067 if (streamname.Buffer) // case has changed
1068 sf2->filepart = streamname;
1069 else {
1070 sf2->filepart.MaximumLength = sf2->filepart.Length = parts[i].Length;
1071 sf2->filepart.Buffer = ExAllocatePoolWithTag(PagedPool, sf2->filepart.MaximumLength, ALLOC_TAG);
1072 if (!sf2->filepart.Buffer) {
1073 ERR("out of memory\n");
1074 free_fileref(sf2);
1075 Status = STATUS_INSUFFICIENT_RESOURCES;
1076 goto end;
1077 }
1078
1079 RtlCopyMemory(sf2->filepart.Buffer, parts[i].Buffer, parts[i].Length);
1080 }
1081
1082 sf2->name_offset = sf->full_filename.Length / sizeof(WCHAR);
1083
1084 if (sf != Vcb->root_fileref)
1085 sf2->name_offset++;
1086
1087 fnlen = (sf2->name_offset * sizeof(WCHAR)) + sf2->filepart.Length;
1088
1089 sf2->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, fnlen, ALLOC_TAG);
1090 if (!sf2->full_filename.Buffer) {
1091 ERR("out of memory\n");
1092 free_fileref(sf2);
1093 Status = STATUS_INSUFFICIENT_RESOURCES;
1094 goto end;
1095 }
1096
1097 sf2->full_filename.Length = sf2->full_filename.MaximumLength = fnlen;
1098 RtlCopyMemory(sf2->full_filename.Buffer, sf->full_filename.Buffer, sf->full_filename.Length);
1099
1100 sf2->full_filename.Buffer[sf->full_filename.Length / sizeof(WCHAR)] = ':';
1101
1102 RtlCopyMemory(&sf2->full_filename.Buffer[sf2->name_offset], sf2->filepart.Buffer, sf2->filepart.Length);
1103
1104 // FIXME - make sure all functions know that ADS FCBs won't have a valid SD or INODE_ITEM
1105
1106 sf2->parent = (struct _file_ref*)sf;
1107 InsertTailList(&sf->children, &sf2->list_entry);
1108
1109 #ifdef DEBUG_FCB_REFCOUNTS
1110 rc = InterlockedIncrement(&sf->refcount);
1111 WARN("fileref %p: refcount now %i\n", sf, rc);
1112 #else
1113 InterlockedIncrement(&sf->refcount);
1114 #endif
1115 }
1116 } else {
1117 root* subvol;
1118 UINT64 inode;
1119 UINT8 type;
1120 ANSI_STRING utf8;
1121 #ifdef DEBUG_FCB_REFCOUNTS
1122 LONG rc;
1123 #endif
1124
1125 if (!find_file_in_dir(Vcb, &parts[i], sf->fcb->subvol, sf->fcb->inode, &subvol, &inode, &type, &utf8)) {
1126 TRACE("could not find %.*S\n", parts[i].Length / sizeof(WCHAR), parts[i].Buffer);
1127
1128 Status = lastpart ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND;
1129 goto end;
1130 } else {
1131 fcb* fcb;
1132 ULONG strlen, fnlen;
1133
1134 if (type != BTRFS_TYPE_DIRECTORY && !lastpart) {
1135 WARN("passed path including file as subdirectory\n");
1136
1137 Status = STATUS_OBJECT_PATH_NOT_FOUND;
1138 goto end;
1139 }
1140
1141 Status = open_fcb(Vcb, subvol, inode, type, &utf8, sf->fcb, &fcb);
1142 if (!NT_SUCCESS(Status)) {
1143 ERR("open_fcb returned %08x\n", Status);
1144 goto end;
1145 }
1146
1147 sf2 = create_fileref();
1148 if (!sf2) {
1149 ERR("out of memory\n");
1150 free_fcb(fcb);
1151 Status = STATUS_INSUFFICIENT_RESOURCES;
1152 goto end;
1153 }
1154
1155 sf2->fcb = fcb;
1156
1157 sf2->utf8 = utf8;
1158
1159 Status = RtlUTF8ToUnicodeN(NULL, 0, &strlen, utf8.Buffer, utf8.Length);
1160 if (!NT_SUCCESS(Status)) {
1161 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
1162 free_fileref(sf2);
1163 goto end;
1164 }
1165
1166 sf2->filepart.MaximumLength = sf2->filepart.Length = strlen;
1167 sf2->filepart.Buffer = ExAllocatePoolWithTag(PagedPool, sf2->filepart.MaximumLength, ALLOC_TAG);
1168 if (!sf2->filepart.Buffer) {
1169 ERR("out of memory\n");
1170 free_fileref(sf2);
1171 Status = STATUS_INSUFFICIENT_RESOURCES;
1172 goto end;
1173 }
1174
1175 Status = RtlUTF8ToUnicodeN(sf2->filepart.Buffer, strlen, &strlen, utf8.Buffer, utf8.Length);
1176 if (!NT_SUCCESS(Status)) {
1177 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
1178 free_fileref(sf2);
1179 goto end;
1180 }
1181
1182 sf2->name_offset = sf->full_filename.Length / sizeof(WCHAR);
1183
1184 if (sf != Vcb->root_fileref)
1185 sf2->name_offset++;
1186
1187 fnlen = (sf2->name_offset * sizeof(WCHAR)) + sf2->filepart.Length;
1188
1189 sf2->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, fnlen, ALLOC_TAG);
1190 if (!sf2->full_filename.Buffer) {
1191 ERR("out of memory\n");
1192 free_fileref(sf2);
1193 Status = STATUS_INSUFFICIENT_RESOURCES;
1194 goto end;
1195 }
1196
1197 sf2->full_filename.Length = sf2->full_filename.MaximumLength = fnlen;
1198 RtlCopyMemory(sf2->full_filename.Buffer, sf->full_filename.Buffer, sf->full_filename.Length);
1199
1200 if (sf != Vcb->root_fileref)
1201 sf2->full_filename.Buffer[sf->full_filename.Length / sizeof(WCHAR)] = '\\';
1202
1203 RtlCopyMemory(&sf2->full_filename.Buffer[sf2->name_offset], sf2->filepart.Buffer, sf2->filepart.Length);
1204
1205 sf2->parent = (struct _file_ref*)sf;
1206 InsertTailList(&sf->children, &sf2->list_entry);
1207 #ifdef DEBUG_FCB_REFCOUNTS
1208 rc = InterlockedIncrement(&sf->refcount);
1209 WARN("fileref %p: refcount now %i\n", sf, rc);
1210 #else
1211 InterlockedIncrement(&sf->refcount);
1212 #endif
1213 }
1214 }
1215 }
1216
1217 if (i == num_parts - 1)
1218 break;
1219
1220 if (sf2->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
1221 Status = STATUS_REPARSE;
1222
1223 if (unparsed)
1224 *unparsed = fnus->Length - ((parts[i+1].Buffer - fnus->Buffer - 1) * sizeof(WCHAR));
1225
1226 break;
1227 }
1228
1229 free_fileref(sf);
1230 sf = sf2;
1231 }
1232
1233 if (Status != STATUS_REPARSE)
1234 Status = STATUS_SUCCESS;
1235 *pfr = sf2;
1236
1237 end:
1238 free_fileref(sf);
1239
1240 end2:
1241 if (parts)
1242 ExFreePool(parts);
1243
1244 TRACE("returning %08x\n", Status);
1245
1246 return Status;
1247 }
1248
1249 static NTSTATUS STDCALL file_create2(PIRP Irp, device_extension* Vcb, PUNICODE_STRING fpus, file_ref* parfileref, ULONG options, file_ref** pfr, LIST_ENTRY* rollback) {
1250 NTSTATUS Status;
1251 fcb* fcb;
1252 ULONG utf8len;
1253 char* utf8 = NULL;
1254 UINT32 crc32;
1255 UINT64 dirpos, inode;
1256 KEY searchkey;
1257 traverse_ptr tp;
1258 INODE_ITEM *dirii, *ii;
1259 UINT8 type;
1260 ULONG disize;
1261 DIR_ITEM *di, *di2;
1262 LARGE_INTEGER time;
1263 BTRFS_TIME now;
1264 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1265 ANSI_STRING utf8as;
1266 ULONG defda;
1267 file_ref* fileref;
1268 #ifdef DEBUG_FCB_REFCOUNTS
1269 LONG rc;
1270 #endif
1271
1272 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
1273 if (!NT_SUCCESS(Status))
1274 return Status;
1275
1276 utf8 = ExAllocatePoolWithTag(PagedPool, utf8len + 1, ALLOC_TAG);
1277 if (!utf8) {
1278 ERR("out of memory\n");
1279 return STATUS_INSUFFICIENT_RESOURCES;
1280 }
1281
1282 Status = RtlUnicodeToUTF8N(utf8, utf8len, &utf8len, fpus->Buffer, fpus->Length);
1283 if (!NT_SUCCESS(Status)) {
1284 ExFreePool(utf8);
1285 return Status;
1286 }
1287
1288 utf8[utf8len] = 0;
1289
1290 crc32 = calc_crc32c(0xfffffffe, (UINT8*)utf8, utf8len);
1291
1292 dirpos = find_next_dir_index(Vcb, parfileref->fcb->subvol, parfileref->fcb->inode);
1293 if (dirpos == 0) {
1294 Status = STATUS_INTERNAL_ERROR;
1295 ExFreePool(utf8);
1296 return Status;
1297 }
1298
1299 TRACE("filename = %s, crc = %08x, dirpos = %llx\n", utf8, crc32, dirpos);
1300
1301 KeQuerySystemTime(&time);
1302 win_time_to_unix(time, &now);
1303
1304 // TRACE("parfcb->inode_item.st_size was %llx\n", parfcb->inode_item.st_size);
1305 parfileref->fcb->inode_item.st_size += utf8len * 2;
1306 // TRACE("parfcb->inode_item.st_size was %llx\n", parfcb->inode_item.st_size);
1307 parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
1308 parfileref->fcb->inode_item.sequence++;
1309 parfileref->fcb->inode_item.st_ctime = now;
1310 parfileref->fcb->inode_item.st_mtime = now;
1311
1312 searchkey.obj_id = parfileref->fcb->inode;
1313 searchkey.obj_type = TYPE_INODE_ITEM;
1314 searchkey.offset = 0xffffffffffffffff;
1315
1316 Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, FALSE);
1317 if (!NT_SUCCESS(Status)) {
1318 ERR("error - find_item returned %08x\n", Status);
1319 ExFreePool(utf8);
1320 return Status;
1321 }
1322
1323 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
1324 ERR("error - could not find INODE_ITEM for parent directory %llx in subvol %llx\n", parfileref->fcb->inode, parfileref->fcb->subvol->id);
1325 ExFreePool(utf8);
1326 return STATUS_INTERNAL_ERROR;
1327 }
1328
1329 dirii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1330 if (!dirii) {
1331 ERR("out of memory\n");
1332 ExFreePool(utf8);
1333 return STATUS_INSUFFICIENT_RESOURCES;
1334 }
1335
1336 RtlCopyMemory(dirii, &parfileref->fcb->inode_item, sizeof(INODE_ITEM));
1337 delete_tree_item(Vcb, &tp, rollback);
1338
1339 insert_tree_item(Vcb, parfileref->fcb->subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, dirii, sizeof(INODE_ITEM), NULL, rollback);
1340
1341 if (parfileref->fcb->subvol->lastinode == 0)
1342 get_last_inode(Vcb, parfileref->fcb->subvol);
1343
1344 inode = parfileref->fcb->subvol->lastinode + 1;
1345
1346 type = options & FILE_DIRECTORY_FILE ? BTRFS_TYPE_DIRECTORY : BTRFS_TYPE_FILE;
1347
1348 disize = sizeof(DIR_ITEM) - 1 + utf8len;
1349 di = ExAllocatePoolWithTag(PagedPool, disize, ALLOC_TAG);
1350 if (!di) {
1351 ERR("out of memory\n");
1352 ExFreePool(utf8);
1353 return STATUS_INSUFFICIENT_RESOURCES;
1354 }
1355
1356 di->key.obj_id = inode;
1357 di->key.obj_type = TYPE_INODE_ITEM;
1358 di->key.offset = 0;
1359 di->transid = Vcb->superblock.generation;
1360 di->m = 0;
1361 di->n = (UINT16)utf8len;
1362 di->type = type;
1363 RtlCopyMemory(di->name, utf8, utf8len);
1364
1365 insert_tree_item(Vcb, parfileref->fcb->subvol, parfileref->fcb->inode, TYPE_DIR_INDEX, dirpos, di, disize, NULL, rollback);
1366
1367 di2 = ExAllocatePoolWithTag(PagedPool, disize, ALLOC_TAG);
1368 if (!di2) {
1369 ERR("out of memory\n");
1370 ExFreePool(utf8);
1371 return STATUS_INSUFFICIENT_RESOURCES;
1372 }
1373
1374 RtlCopyMemory(di2, di, disize);
1375
1376 Status = add_dir_item(Vcb, parfileref->fcb->subvol, parfileref->fcb->inode, crc32, di2, disize, rollback);
1377 if (!NT_SUCCESS(Status)) {
1378 ERR("add_dir_item returned %08x\n", Status);
1379 ExFreePool(utf8);
1380 return Status;
1381 }
1382
1383 utf8as.Buffer = utf8;
1384 utf8as.Length = utf8as.MaximumLength = utf8len;
1385
1386 Status = add_inode_ref(Vcb, parfileref->fcb->subvol, inode, parfileref->fcb->inode, dirpos, &utf8as, rollback);
1387 if (!NT_SUCCESS(Status)) {
1388 ERR("add_inode_ref returned %08x\n", Status);
1389 ExFreePool(utf8);
1390 return Status;
1391 }
1392
1393 // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
1394
1395 TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
1396
1397 IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1398
1399 defda = 0;
1400
1401 if (utf8[0] == '.')
1402 defda |= FILE_ATTRIBUTE_HIDDEN;
1403
1404 if (options & FILE_DIRECTORY_FILE) {
1405 defda |= FILE_ATTRIBUTE_DIRECTORY;
1406 IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1407 }
1408
1409 TRACE("defda = %x\n", defda);
1410
1411 if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
1412 IrpSp->Parameters.Create.FileAttributes = defda;
1413
1414 if (IrpSp->Parameters.Create.FileAttributes != defda) {
1415 char val[64];
1416
1417 sprintf(val, "0x%x", IrpSp->Parameters.Create.FileAttributes);
1418
1419 Status = set_xattr(Vcb, parfileref->fcb->subvol, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8*)val, strlen(val), rollback);
1420 if (!NT_SUCCESS(Status)) {
1421 ERR("set_xattr returned %08x\n", Status);
1422 ExFreePool(utf8);
1423 return Status;
1424 }
1425 }
1426
1427 parfileref->fcb->subvol->lastinode++;
1428
1429 fcb = create_fcb();
1430 if (!fcb) {
1431 ERR("out of memory\n");
1432 ExFreePool(utf8);
1433 return STATUS_INSUFFICIENT_RESOURCES;
1434 }
1435
1436 fcb->Vcb = Vcb;
1437
1438 fcb->inode_item.generation = Vcb->superblock.generation;
1439 fcb->inode_item.transid = Vcb->superblock.generation;
1440 fcb->inode_item.st_size = 0;
1441 fcb->inode_item.st_blocks = 0;
1442 fcb->inode_item.block_group = 0;
1443 fcb->inode_item.st_nlink = 1;
1444 // fcb->inode_item.st_uid = UID_NOBODY; // FIXME?
1445 fcb->inode_item.st_gid = GID_NOBODY; // FIXME?
1446 fcb->inode_item.st_mode = parfileref->fcb ? (parfileref->fcb->inode_item.st_mode & ~S_IFDIR) : 0755; // use parent's permissions by default
1447 fcb->inode_item.st_rdev = 0;
1448 fcb->inode_item.flags = 0;
1449 fcb->inode_item.sequence = 1;
1450 fcb->inode_item.st_atime = now;
1451 fcb->inode_item.st_ctime = now;
1452 fcb->inode_item.st_mtime = now;
1453 fcb->inode_item.otime = now;
1454
1455 if (type == BTRFS_TYPE_DIRECTORY)
1456 fcb->inode_item.st_mode |= S_IFDIR;
1457 else {
1458 fcb->inode_item.st_mode |= S_IFREG;
1459 fcb->inode_item.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); // remove executable bit if not directory
1460 }
1461
1462 // inherit nodatacow flag from parent directory
1463 if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW) {
1464 fcb->inode_item.flags |= BTRFS_INODE_NODATACOW;
1465
1466 if (type != BTRFS_TYPE_DIRECTORY)
1467 fcb->inode_item.flags |= BTRFS_INODE_NODATASUM;
1468 }
1469
1470 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1471 fcb->Header.AllocationSize.QuadPart = 0;
1472 fcb->Header.FileSize.QuadPart = 0;
1473 fcb->Header.ValidDataLength.QuadPart = 0;
1474
1475 fcb->atts = IrpSp->Parameters.Create.FileAttributes;
1476
1477 #ifdef DEBUG_FCB_REFCOUNTS
1478 rc = InterlockedIncrement(&parfileref->fcb->refcount);
1479 WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
1480 #else
1481 InterlockedIncrement(&parfileref->fcb->refcount);
1482 #endif
1483 fcb->subvol = parfileref->fcb->subvol;
1484 fcb->inode = inode;
1485 fcb->type = type;
1486
1487 Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
1488
1489 if (!NT_SUCCESS(Status)) {
1490 ERR("fcb_get_new_sd returned %08x\n", Status);
1491 free_fcb(fcb);
1492 return Status;
1493 }
1494
1495 fileref = create_fileref();
1496 if (!fileref) {
1497 ERR("out of memory\n");
1498 free_fcb(fcb);
1499 return STATUS_INSUFFICIENT_RESOURCES;
1500 }
1501
1502 fileref->fcb = fcb;
1503
1504 fileref->utf8.MaximumLength = fileref->utf8.Length = utf8len;
1505 fileref->utf8.Buffer = utf8;
1506
1507 fileref->filepart = *fpus;
1508
1509 Status = set_xattr(Vcb, parfileref->fcb->subvol, inode, EA_NTACL, EA_NTACL_HASH, (UINT8*)fcb->sd, RtlLengthSecurityDescriptor(fcb->sd), rollback);
1510 if (!NT_SUCCESS(Status)) {
1511 ERR("set_xattr returned %08x\n", Status);
1512 free_fileref(fileref);
1513 return Status;
1514 }
1515
1516 fileref->full_filename.Length = parfileref->full_filename.Length + (parfileref->full_filename.Length == sizeof(WCHAR) ? 0 : sizeof(WCHAR)) + fileref->filepart.Length;
1517 fileref->full_filename.MaximumLength = fileref->full_filename.Length;
1518 fileref->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->full_filename.Length, ALLOC_TAG);
1519 if (!fileref->full_filename.Buffer) {
1520 ERR("out of memory\n");
1521 free_fileref(fileref);
1522 return STATUS_INSUFFICIENT_RESOURCES;
1523 }
1524
1525 RtlCopyMemory(fileref->full_filename.Buffer, parfileref->full_filename.Buffer, parfileref->full_filename.Length);
1526
1527 if (parfileref->full_filename.Length > sizeof(WCHAR))
1528 fileref->full_filename.Buffer[parfileref->full_filename.Length / sizeof(WCHAR)] = '\\';
1529
1530 RtlCopyMemory(&fileref->full_filename.Buffer[(parfileref->full_filename.Length / sizeof(WCHAR)) + (parfileref->full_filename.Length == sizeof(WCHAR) ? 0 : 1)],
1531 fileref->filepart.Buffer, fileref->filepart.Length);
1532
1533 ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1534 if (!ii) {
1535 ERR("out of memory\n");
1536 free_fileref(fileref);
1537 return STATUS_INSUFFICIENT_RESOURCES;
1538 }
1539
1540 if (Irp->Overlay.AllocationSize.QuadPart > 0) {
1541 Status = extend_file(fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, rollback);
1542
1543 if (!NT_SUCCESS(Status)) {
1544 ERR("extend_file returned %08x\n", Status);
1545 free_fileref(fileref);
1546 return Status;
1547 }
1548 }
1549
1550 RtlCopyMemory(ii, &fcb->inode_item, sizeof(INODE_ITEM));
1551 insert_tree_item(Vcb, fcb->subvol, inode, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, rollback);
1552
1553 fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
1554 fcb->subvol->root_item.ctime = now;
1555
1556 fileref->parent = parfileref;
1557 InsertTailList(&parfileref->children, &fileref->list_entry);
1558 #ifdef DEBUG_FCB_REFCOUNTS
1559 rc = InterlockedIncrement(&parfileref->refcount);
1560 WARN("fileref %p: refcount now %i\n", parfileref, rc);
1561 #else
1562 InterlockedIncrement(&parfileref->refcount);
1563 #endif
1564
1565 InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
1566
1567 *pfr = fileref;
1568
1569 TRACE("created new file %S in subvol %llx, inode %llx\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode);
1570
1571 return STATUS_SUCCESS;
1572 }
1573
1574 static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJECT FileObject, PUNICODE_STRING fnus, ULONG disposition, ULONG options, LIST_ENTRY* rollback) {
1575 NTSTATUS Status;
1576 // fcb *fcb, *parfcb = NULL;
1577 file_ref *fileref, *parfileref = NULL, *related;
1578 ULONG i, j;
1579 // ULONG utf8len;
1580 ccb* ccb;
1581 static WCHAR datasuf[] = {':','$','D','A','T','A',0};
1582 UNICODE_STRING dsus, fpus, stream;
1583 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1584 ULONG access;
1585 PACCESS_STATE access_state = IrpSp->Parameters.Create.SecurityContext->AccessState;
1586 #ifdef DEBUG_FCB_REFCOUNTS
1587 LONG oc;
1588 #endif
1589
1590 TRACE("(%p, %p, %p, %.*S, %x, %x)\n", Irp, Vcb, FileObject, fnus->Length / sizeof(WCHAR), fnus->Buffer, disposition, options);
1591
1592 if (Vcb->readonly)
1593 return STATUS_MEDIA_WRITE_PROTECTED;
1594
1595 dsus.Buffer = datasuf;
1596 dsus.Length = dsus.MaximumLength = wcslen(datasuf) * sizeof(WCHAR);
1597 fpus.Buffer = NULL;
1598
1599 if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
1600 struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
1601
1602 related = relatedccb->fileref;
1603 } else
1604 related = NULL;
1605
1606 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
1607 Status = open_fileref(Vcb, &parfileref, &FileObject->FileName, related, TRUE, NULL);
1608 ExReleaseResourceLite(&Vcb->fcb_lock);
1609 if (!NT_SUCCESS(Status))
1610 goto end;
1611
1612 if (parfileref->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
1613 Status = STATUS_OBJECT_PATH_NOT_FOUND;
1614 goto end;
1615 }
1616
1617 if (parfileref->fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY) {
1618 Status = STATUS_ACCESS_DENIED;
1619 goto end;
1620 }
1621
1622 i = (fnus->Length / sizeof(WCHAR))-1;
1623 while ((fnus->Buffer[i] == '\\' || fnus->Buffer[i] == '/') && i > 0) { i--; }
1624
1625 j = i;
1626
1627 while (i > 0 && fnus->Buffer[i-1] != '\\' && fnus->Buffer[i-1] != '/') { i--; }
1628
1629 fpus.MaximumLength = (j - i + 2) * sizeof(WCHAR);
1630 fpus.Buffer = ExAllocatePoolWithTag(PagedPool, fpus.MaximumLength, ALLOC_TAG);
1631 if (!fpus.Buffer) {
1632 ERR("out of memory\n");
1633 Status = STATUS_INSUFFICIENT_RESOURCES;
1634 goto end;
1635 }
1636
1637 fpus.Length = (j - i + 1) * sizeof(WCHAR);
1638
1639 RtlCopyMemory(fpus.Buffer, &fnus->Buffer[i], (j - i + 1) * sizeof(WCHAR));
1640 fpus.Buffer[j - i + 1] = 0;
1641
1642 if (fpus.Length > dsus.Length) { // check for :$DATA suffix
1643 UNICODE_STRING lb;
1644
1645 lb.Buffer = &fpus.Buffer[(fpus.Length - dsus.Length)/sizeof(WCHAR)];
1646 lb.Length = lb.MaximumLength = dsus.Length;
1647
1648 TRACE("lb = %.*S\n", lb.Length/sizeof(WCHAR), lb.Buffer);
1649
1650 if (FsRtlAreNamesEqual(&dsus, &lb, TRUE, NULL)) {
1651 TRACE("ignoring :$DATA suffix\n");
1652
1653 fpus.Length -= lb.Length;
1654
1655 if (fpus.Length > sizeof(WCHAR) && fpus.Buffer[(fpus.Length-1)/sizeof(WCHAR)] == ':')
1656 fpus.Length -= sizeof(WCHAR);
1657
1658 TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer);
1659 }
1660 }
1661
1662 stream.Length = 0;
1663
1664 for (i = 0; i < fpus.Length/sizeof(WCHAR); i++) {
1665 if (fpus.Buffer[i] == ':') {
1666 stream.Length = fpus.Length - (i*sizeof(WCHAR)) - sizeof(WCHAR);
1667 stream.Buffer = &fpus.Buffer[i+1];
1668 fpus.Buffer[i] = 0;
1669 fpus.Length = i * sizeof(WCHAR);
1670 break;
1671 }
1672 }
1673
1674 if (stream.Length > 0) {
1675 file_ref* newpar;
1676 fcb* fcb;
1677 static char xapref[] = "user.";
1678 ULONG xapreflen = strlen(xapref), fnlen;
1679 LARGE_INTEGER time;
1680 BTRFS_TIME now;
1681 KEY searchkey;
1682 traverse_ptr tp;
1683 INODE_ITEM* ii;
1684 ULONG utf8len;
1685 UINT64 offset;
1686 #ifdef DEBUG_FCB_REFCOUNTS
1687 LONG rc;
1688 #endif
1689
1690 TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer);
1691 TRACE("stream = %.*S\n", stream.Length / sizeof(WCHAR), stream.Buffer);
1692
1693 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
1694 Status = open_fileref(Vcb, &newpar, &fpus, parfileref, FALSE, NULL);
1695 ExReleaseResourceLite(&Vcb->fcb_lock);
1696
1697 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
1698 UNICODE_STRING fpus2;
1699
1700 if (!SeAccessCheck(parfileref->fcb->sd, &access_state->SubjectSecurityContext, FALSE, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
1701 IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, &access, &Status)) {
1702 WARN("SeAccessCheck failed, returning %08x\n", Status);
1703 goto end;
1704 }
1705
1706 if (!is_file_name_valid(&fpus))
1707 return STATUS_OBJECT_NAME_INVALID;
1708
1709 fpus2.Length = fpus2.MaximumLength = fpus.Length;
1710 fpus2.Buffer = ExAllocatePoolWithTag(PagedPool, fpus2.MaximumLength, ALLOC_TAG);
1711
1712 if (!fpus2.Buffer) {
1713 ERR("out of memory\n");
1714 Status = STATUS_INSUFFICIENT_RESOURCES;
1715 goto end;
1716 }
1717
1718 RtlCopyMemory(fpus2.Buffer, fpus.Buffer, fpus2.Length);
1719
1720 Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, &newpar, rollback);
1721
1722 if (!NT_SUCCESS(Status)) {
1723 ERR("file_create2 returned %08x\n", Status);
1724 ExFreePool(fpus2.Buffer);
1725 goto end;
1726 }
1727
1728 // FIXME - send notification
1729 } else if (!NT_SUCCESS(Status)) {
1730 ERR("open_fileref returned %08x\n", Status);
1731 goto end;
1732 }
1733
1734 free_fileref(parfileref);
1735 parfileref = newpar;
1736
1737 if (!SeAccessCheck(parfileref->fcb->sd, &access_state->SubjectSecurityContext, FALSE, access_state->OriginalDesiredAccess, 0, NULL,
1738 IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, &access, &Status)) {
1739 WARN("SeAccessCheck failed, returning %08x\n", Status);
1740 goto end;
1741 }
1742
1743 if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK) {
1744 WARN("parent not file or symlink\n");
1745 Status = STATUS_INVALID_PARAMETER;
1746 goto end;
1747 }
1748
1749 if (options & FILE_DIRECTORY_FILE) {
1750 WARN("tried to create directory as stream\n");
1751 Status = STATUS_INVALID_PARAMETER;
1752 goto end;
1753 }
1754
1755 fcb = create_fcb();
1756 if (!fcb) {
1757 ERR("out of memory\n");
1758 Status = STATUS_INSUFFICIENT_RESOURCES;
1759 goto end;
1760 }
1761
1762 fcb->Vcb = Vcb;
1763
1764 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1765 fcb->Header.AllocationSize.QuadPart = 0;
1766 fcb->Header.FileSize.QuadPart = 0;
1767 fcb->Header.ValidDataLength.QuadPart = 0;
1768
1769 #ifdef DEBUG_FCB_REFCOUNTS
1770 rc = InterlockedIncrement(&parfileref->fcb->refcount);
1771 WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
1772 #else
1773 InterlockedIncrement(&parfileref->fcb->refcount);
1774 #endif
1775 fcb->subvol = parfileref->fcb->subvol;
1776 fcb->inode = parfileref->fcb->inode;
1777 fcb->type = parfileref->fcb->type;
1778
1779 fcb->ads = TRUE;
1780 fcb->adssize = 0;
1781
1782 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, stream.Buffer, stream.Length);
1783 if (!NT_SUCCESS(Status)) {
1784 ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status);
1785 free_fcb(fcb);
1786 goto end;
1787 }
1788
1789 fcb->adsxattr.Length = utf8len + xapreflen;
1790 fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1;
1791 fcb->adsxattr.Buffer = ExAllocatePoolWithTag(PagedPool, fcb->adsxattr.MaximumLength, ALLOC_TAG);
1792 if (!fcb->adsxattr.Buffer) {
1793 ERR("out of memory\n");
1794 free_fcb(fcb);
1795 Status = STATUS_INSUFFICIENT_RESOURCES;
1796 goto end;
1797 }
1798
1799 RtlCopyMemory(fcb->adsxattr.Buffer, xapref, xapreflen);
1800
1801 Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[xapreflen], utf8len, &utf8len, stream.Buffer, stream.Length);
1802 if (!NT_SUCCESS(Status)) {
1803 ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
1804 free_fcb(fcb);
1805 goto end;
1806 }
1807
1808 fcb->adsxattr.Buffer[fcb->adsxattr.Length] = 0;
1809
1810 TRACE("adsxattr = %s\n", fcb->adsxattr.Buffer);
1811
1812 fcb->adshash = calc_crc32c(0xfffffffe, (UINT8*)fcb->adsxattr.Buffer, fcb->adsxattr.Length);
1813 TRACE("adshash = %08x\n", fcb->adshash);
1814
1815 fileref = create_fileref();
1816 if (!fileref) {
1817 ERR("out of memory\n");
1818 free_fcb(fcb);
1819 Status = STATUS_INSUFFICIENT_RESOURCES;
1820 goto end;
1821 }
1822
1823 fileref->fcb = fcb;
1824
1825 fileref->name_offset = parfileref->full_filename.Length / sizeof(WCHAR);
1826 if (parfileref != Vcb->root_fileref)
1827 fileref->name_offset++;
1828
1829 fileref->filepart.MaximumLength = fileref->filepart.Length = stream.Length;
1830 fileref->filepart.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->filepart.MaximumLength, ALLOC_TAG);
1831 if (!fileref->filepart.Buffer) {
1832 ERR("out of memory\n");
1833 free_fileref(fileref);
1834 Status = STATUS_INSUFFICIENT_RESOURCES;
1835 goto end;
1836 }
1837
1838 RtlCopyMemory(fileref->filepart.Buffer, stream.Buffer, stream.Length);
1839
1840 fnlen = (fileref->name_offset * sizeof(WCHAR)) + fileref->filepart.Length;
1841
1842 fileref->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, fnlen, ALLOC_TAG);
1843 if (!fileref->full_filename.Buffer) {
1844 ERR("out of memory\n");
1845 free_fileref(fileref);
1846 Status = STATUS_INSUFFICIENT_RESOURCES;
1847 goto end;
1848 }
1849
1850 fileref->full_filename.Length = fileref->full_filename.MaximumLength = fnlen;
1851 RtlCopyMemory(fileref->full_filename.Buffer, parfileref->full_filename.Buffer, parfileref->full_filename.Length);
1852
1853 fileref->full_filename.Buffer[parfileref->full_filename.Length / sizeof(WCHAR)] = ':';
1854
1855 RtlCopyMemory(&fileref->full_filename.Buffer[fileref->name_offset], fileref->filepart.Buffer, fileref->filepart.Length);
1856 TRACE("full_filename = %.*S\n", fileref->full_filename.Length / sizeof(WCHAR), fileref->full_filename.Buffer);
1857
1858 Status = set_xattr(Vcb, parfileref->fcb->subvol, parfileref->fcb->inode, fcb->adsxattr.Buffer, fcb->adshash, (UINT8*)"", 0, rollback);
1859 if (!NT_SUCCESS(Status)) {
1860 ERR("set_xattr returned %08x\n", Status);
1861 free_fileref(fileref);
1862 goto end;
1863 }
1864
1865 InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
1866
1867 KeQuerySystemTime(&time);
1868 win_time_to_unix(time, &now);
1869
1870 parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
1871 parfileref->fcb->inode_item.sequence++;
1872 parfileref->fcb->inode_item.st_ctime = now;
1873
1874 searchkey.obj_id = parfileref->fcb->inode;
1875 searchkey.obj_type = TYPE_INODE_ITEM;
1876 searchkey.offset = 0xffffffffffffffff;
1877
1878 Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, FALSE);
1879 if (!NT_SUCCESS(Status)) {
1880 ERR("error - find_item returned %08x\n", Status);
1881 free_fileref(fileref);
1882 goto end;
1883 }
1884
1885 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
1886 delete_tree_item(Vcb, &tp, rollback);
1887 offset = tp.item->key.offset;
1888 } else {
1889 WARN("could not find INODE_ITEM for inode %llx in subvol %llx\n", searchkey.obj_id, parfileref->fcb->subvol->id);
1890 offset = 0;
1891 }
1892
1893 ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1894 if (!ii) {
1895 ERR("out of memory\n");
1896 Status = STATUS_INSUFFICIENT_RESOURCES;
1897 free_fileref(fileref);
1898 goto end;
1899 }
1900
1901 RtlCopyMemory(ii, &parfileref->fcb->inode_item, sizeof(INODE_ITEM));
1902
1903 insert_tree_item(Vcb, parfileref->fcb->subvol, parfileref->fcb->inode, TYPE_INODE_ITEM, offset, ii, sizeof(INODE_ITEM), NULL, rollback);
1904
1905 parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
1906 parfileref->fcb->subvol->root_item.ctime = now;
1907
1908 fileref->parent = (struct _file_ref*)parfileref;
1909 InsertTailList(&parfileref->children, &fileref->list_entry);
1910 #ifdef DEBUG_FCB_REFCOUNTS
1911 rc = InterlockedIncrement(&parfileref->refcount);
1912 WARN("fileref %p: refcount now %i\n", parfileref, rc);
1913 #else
1914 InterlockedIncrement(&parfileref->refcount);
1915 #endif
1916
1917 ExFreePool(fpus.Buffer);
1918 fpus.Buffer = NULL;
1919 } else {
1920 if (!SeAccessCheck(parfileref->fcb->sd, &access_state->SubjectSecurityContext, FALSE, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
1921 IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, &access, &Status)) {
1922 WARN("SeAccessCheck failed, returning %08x\n", Status);
1923 goto end;
1924 }
1925
1926 if (!is_file_name_valid(&fpus)) {
1927 Status = STATUS_OBJECT_NAME_INVALID;
1928 goto end;
1929 }
1930
1931 Status = file_create2(Irp, Vcb, &fpus, parfileref, options, &fileref, rollback);
1932
1933 if (!NT_SUCCESS(Status)) {
1934 ERR("file_create2 returned %08x\n", Status);
1935 goto end;
1936 }
1937 }
1938
1939 FileObject->FsContext = fileref->fcb;
1940
1941 ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
1942 if (!ccb) {
1943 ERR("out of memory\n");
1944 Status = STATUS_INSUFFICIENT_RESOURCES;
1945 free_fileref(fileref);
1946 goto end;
1947 }
1948
1949 RtlZeroMemory(ccb, sizeof(*ccb));
1950
1951 ccb->fileref = fileref;
1952
1953 ccb->NodeType = BTRFS_NODE_TYPE_CCB;
1954 ccb->NodeSize = sizeof(ccb);
1955 ccb->disposition = disposition;
1956 ccb->options = options;
1957 ccb->query_dir_offset = 0;
1958 RtlInitUnicodeString(&ccb->query_string, NULL);
1959 ccb->has_wildcard = FALSE;
1960 ccb->specific_file = FALSE;
1961 ccb->access = access;
1962
1963 #ifdef DEBUG_FCB_REFCOUNTS
1964 oc = InterlockedIncrement(&fileref->fcb->open_count);
1965 ERR("fcb %p: open_count now %i\n", fileref->fcb, oc);
1966 #else
1967 InterlockedIncrement(&fileref->fcb->open_count);
1968 #endif
1969
1970 FileObject->FsContext2 = ccb;
1971
1972 FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
1973
1974 // TRACE("returning FCB %p with parent %p\n", fcb, parfcb);
1975
1976 Status = consider_write(Vcb);
1977
1978 if (NT_SUCCESS(Status)) {
1979 // ULONG fnlen;
1980 //
1981 // fcb->name_offset = fcb->par->full_filename.Length / sizeof(WCHAR);
1982 //
1983 // if (fcb->par != Vcb->root_fcb)
1984 // fcb->name_offset++;
1985 //
1986 // fnlen = (fcb->name_offset * sizeof(WCHAR)) + fcb->filepart.Length;
1987 //
1988 // fcb->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, fnlen, ALLOC_TAG);
1989 // if (!fcb->full_filename.Buffer) {
1990 // ERR("out of memory\n");
1991 // Status = STATUS_INSUFFICIENT_RESOURCES;
1992 // goto end;
1993 // }
1994 //
1995 // fcb->full_filename.Length = fcb->full_filename.MaximumLength = fnlen;
1996 // RtlCopyMemory(fcb->full_filename.Buffer, fcb->par->full_filename.Buffer, fcb->par->full_filename.Length);
1997 //
1998 // if (fcb->par != Vcb->root_fcb)
1999 // fcb->full_filename.Buffer[fcb->par->full_filename.Length / sizeof(WCHAR)] = '\\';
2000 //
2001 // RtlCopyMemory(&fcb->full_filename.Buffer[fcb->name_offset], fcb->filepart.Buffer, fcb->filepart.Length);
2002
2003 send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED);
2004
2005 goto end2;
2006 }
2007
2008 end:
2009 if (fpus.Buffer)
2010 ExFreePool(fpus.Buffer);
2011
2012 end2:
2013 if (parfileref)
2014 free_fileref(parfileref);
2015
2016 return Status;
2017 }
2018
2019 static __inline void debug_create_options(ULONG RequestedOptions) {
2020 if (RequestedOptions != 0) {
2021 ULONG options = RequestedOptions;
2022
2023 TRACE("requested options:\n");
2024
2025 if (options & FILE_DIRECTORY_FILE) {
2026 TRACE(" FILE_DIRECTORY_FILE\n");
2027 options &= ~FILE_DIRECTORY_FILE;
2028 }
2029
2030 if (options & FILE_WRITE_THROUGH) {
2031 TRACE(" FILE_WRITE_THROUGH\n");
2032 options &= ~FILE_WRITE_THROUGH;
2033 }
2034
2035 if (options & FILE_SEQUENTIAL_ONLY) {
2036 TRACE(" FILE_SEQUENTIAL_ONLY\n");
2037 options &= ~FILE_SEQUENTIAL_ONLY;
2038 }
2039
2040 if (options & FILE_NO_INTERMEDIATE_BUFFERING) {
2041 TRACE(" FILE_NO_INTERMEDIATE_BUFFERING\n");
2042 options &= ~FILE_NO_INTERMEDIATE_BUFFERING;
2043 }
2044
2045 if (options & FILE_SYNCHRONOUS_IO_ALERT) {
2046 TRACE(" FILE_SYNCHRONOUS_IO_ALERT\n");
2047 options &= ~FILE_SYNCHRONOUS_IO_ALERT;
2048 }
2049
2050 if (options & FILE_SYNCHRONOUS_IO_NONALERT) {
2051 TRACE(" FILE_SYNCHRONOUS_IO_NONALERT\n");
2052 options &= ~FILE_SYNCHRONOUS_IO_NONALERT;
2053 }
2054
2055 if (options & FILE_NON_DIRECTORY_FILE) {
2056 TRACE(" FILE_NON_DIRECTORY_FILE\n");
2057 options &= ~FILE_NON_DIRECTORY_FILE;
2058 }
2059
2060 if (options & FILE_CREATE_TREE_CONNECTION) {
2061 TRACE(" FILE_CREATE_TREE_CONNECTION\n");
2062 options &= ~FILE_CREATE_TREE_CONNECTION;
2063 }
2064
2065 if (options & FILE_COMPLETE_IF_OPLOCKED) {
2066 TRACE(" FILE_COMPLETE_IF_OPLOCKED\n");
2067 options &= ~FILE_COMPLETE_IF_OPLOCKED;
2068 }
2069
2070 if (options & FILE_NO_EA_KNOWLEDGE) {
2071 TRACE(" FILE_NO_EA_KNOWLEDGE\n");
2072 options &= ~FILE_NO_EA_KNOWLEDGE;
2073 }
2074
2075 if (options & FILE_OPEN_REMOTE_INSTANCE) {
2076 TRACE(" FILE_OPEN_REMOTE_INSTANCE\n");
2077 options &= ~FILE_OPEN_REMOTE_INSTANCE;
2078 }
2079
2080 if (options & FILE_RANDOM_ACCESS) {
2081 TRACE(" FILE_RANDOM_ACCESS\n");
2082 options &= ~FILE_RANDOM_ACCESS;
2083 }
2084
2085 if (options & FILE_DELETE_ON_CLOSE) {
2086 TRACE(" FILE_DELETE_ON_CLOSE\n");
2087 options &= ~FILE_DELETE_ON_CLOSE;
2088 }
2089
2090 if (options & FILE_OPEN_BY_FILE_ID) {
2091 TRACE(" FILE_OPEN_BY_FILE_ID\n");
2092 options &= ~FILE_OPEN_BY_FILE_ID;
2093 }
2094
2095 if (options & FILE_OPEN_FOR_BACKUP_INTENT) {
2096 TRACE(" FILE_OPEN_FOR_BACKUP_INTENT\n");
2097 options &= ~FILE_OPEN_FOR_BACKUP_INTENT;
2098 }
2099
2100 if (options & FILE_NO_COMPRESSION) {
2101 TRACE(" FILE_NO_COMPRESSION\n");
2102 options &= ~FILE_NO_COMPRESSION;
2103 }
2104
2105 #if NTDDI_VERSION >= NTDDI_WIN7
2106 if (options & FILE_OPEN_REQUIRING_OPLOCK) {
2107 TRACE(" FILE_OPEN_REQUIRING_OPLOCK\n");
2108 options &= ~FILE_OPEN_REQUIRING_OPLOCK;
2109 }
2110
2111 if (options & FILE_DISALLOW_EXCLUSIVE) {
2112 TRACE(" FILE_DISALLOW_EXCLUSIVE\n");
2113 options &= ~FILE_DISALLOW_EXCLUSIVE;
2114 }
2115 #endif
2116
2117 if (options & FILE_RESERVE_OPFILTER) {
2118 TRACE(" FILE_RESERVE_OPFILTER\n");
2119 options &= ~FILE_RESERVE_OPFILTER;
2120 }
2121
2122 if (options & FILE_OPEN_REPARSE_POINT) {
2123 TRACE(" FILE_OPEN_REPARSE_POINT\n");
2124 options &= ~FILE_OPEN_REPARSE_POINT;
2125 }
2126
2127 if (options & FILE_OPEN_NO_RECALL) {
2128 TRACE(" FILE_OPEN_NO_RECALL\n");
2129 options &= ~FILE_OPEN_NO_RECALL;
2130 }
2131
2132 if (options & FILE_OPEN_FOR_FREE_SPACE_QUERY) {
2133 TRACE(" FILE_OPEN_FOR_FREE_SPACE_QUERY\n");
2134 options &= ~FILE_OPEN_FOR_FREE_SPACE_QUERY;
2135 }
2136
2137 if (options)
2138 TRACE(" unknown options: %x\n", options);
2139 } else {
2140 TRACE("requested options: (none)\n");
2141 }
2142 }
2143
2144 NTSTATUS update_inode_item(device_extension* Vcb, root* subvol, UINT64 inode, INODE_ITEM* ii, LIST_ENTRY* rollback) {
2145 KEY searchkey;
2146 traverse_ptr tp;
2147 INODE_ITEM* newii;
2148 NTSTATUS Status;
2149 UINT64 offset = 0;
2150
2151 searchkey.obj_id = inode;
2152 searchkey.obj_type = TYPE_INODE_ITEM;
2153 searchkey.offset = 0xffffffffffffffff;
2154
2155 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
2156 if (!NT_SUCCESS(Status)) {
2157 ERR("error - find_item returned %08x\n", Status);
2158 return Status;
2159 }
2160
2161 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
2162 delete_tree_item(Vcb, &tp, rollback);
2163
2164 offset = tp.item->key.offset;
2165 } else {
2166 WARN("could not find INODE_ITEM for inode %llx in subvol %llx\n", searchkey.obj_id, subvol->id);
2167 }
2168
2169 newii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
2170 if (!newii) {
2171 ERR("out of memory\n");
2172 return STATUS_INSUFFICIENT_RESOURCES;
2173 }
2174
2175 RtlCopyMemory(newii, ii, sizeof(INODE_ITEM));
2176
2177 insert_tree_item(Vcb, subvol, inode, TYPE_INODE_ITEM, offset, newii, sizeof(INODE_ITEM), NULL, rollback);
2178
2179 return STATUS_SUCCESS;
2180 }
2181
2182 static NTSTATUS get_reparse_block(fcb* fcb, UINT8** data) {
2183 NTSTATUS Status;
2184
2185 if (fcb->type == BTRFS_TYPE_FILE || fcb->type == BTRFS_TYPE_SYMLINK) {
2186 ULONG size, bytes_read, i;
2187
2188 if (fcb->inode_item.st_size < sizeof(ULONG)) {
2189 WARN("file was too short to be a reparse point\n");
2190 return STATUS_INVALID_PARAMETER;
2191 }
2192
2193 // 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
2194 size = min(0x10007, fcb->inode_item.st_size);
2195
2196 *data = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
2197 if (!*data) {
2198 ERR("out of memory\n");
2199 return STATUS_INSUFFICIENT_RESOURCES;
2200 }
2201
2202 Status = read_file(fcb->Vcb, fcb->subvol, fcb->inode, *data, 0, size, &bytes_read);
2203 if (!NT_SUCCESS(Status)) {
2204 ERR("read_file returned %08x\n", Status);
2205 ExFreePool(*data);
2206 return Status;
2207 }
2208
2209 if (fcb->type == BTRFS_TYPE_SYMLINK) {
2210 ULONG stringlen, subnamelen, printnamelen, reqlen;
2211 REPARSE_DATA_BUFFER* rdb;
2212
2213 Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, (char*)*data, bytes_read);
2214 if (!NT_SUCCESS(Status)) {
2215 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
2216 ExFreePool(*data);
2217 return Status;
2218 }
2219
2220 subnamelen = stringlen;
2221 printnamelen = stringlen;
2222
2223 reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
2224
2225 rdb = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2226
2227 if (!rdb) {
2228 ERR("out of memory\n");
2229 ExFreePool(*data);
2230 return STATUS_INSUFFICIENT_RESOURCES;
2231 }
2232
2233 rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
2234 rdb->ReparseDataLength = reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer);
2235 rdb->Reserved = 0;
2236
2237 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
2238 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
2239 rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
2240 rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
2241 rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
2242
2243 Status = RtlUTF8ToUnicodeN(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2244 stringlen, &stringlen, (char*)*data, size);
2245
2246 if (!NT_SUCCESS(Status)) {
2247 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
2248 ExFreePool(rdb);
2249 ExFreePool(*data);
2250 return Status;
2251 }
2252
2253 for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
2254 if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
2255 rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
2256 }
2257
2258 RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
2259 &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2260 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
2261
2262 ExFreePool(*data);
2263
2264 *data = (UINT8*)rdb;
2265 } else {
2266 Status = FsRtlValidateReparsePointBuffer(bytes_read, (REPARSE_DATA_BUFFER*)*data);
2267 if (!NT_SUCCESS(Status)) {
2268 ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
2269 ExFreePool(*data);
2270 return Status;
2271 }
2272 }
2273 } else {
2274 UINT16 datalen;
2275
2276 if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_REPARSE, EA_REPARSE_HASH, data, &datalen))
2277 return STATUS_INTERNAL_ERROR;
2278
2279 if (!*data)
2280 return STATUS_INTERNAL_ERROR;
2281
2282 if (datalen < sizeof(ULONG)) {
2283 WARN("xattr was too short to be a reparse point\n");
2284 ExFreePool(*data);
2285 return STATUS_INTERNAL_ERROR;
2286 }
2287
2288 Status = FsRtlValidateReparsePointBuffer(datalen, (REPARSE_DATA_BUFFER*)*data);
2289 if (!NT_SUCCESS(Status)) {
2290 ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
2291 ExFreePool(*data);
2292 return Status;
2293 }
2294 }
2295
2296 return STATUS_SUCCESS;
2297 }
2298
2299 static NTSTATUS STDCALL open_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_ENTRY* rollback) {
2300 PFILE_OBJECT FileObject;
2301 ULONG RequestedDisposition;
2302 ULONG options;
2303 NTSTATUS Status;
2304 ccb* ccb;
2305 device_extension* Vcb = DeviceObject->DeviceExtension;
2306 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
2307 ULONG access;
2308 PACCESS_STATE access_state = Stack->Parameters.Create.SecurityContext->AccessState;
2309 USHORT unparsed;
2310 file_ref *related, *fileref;
2311 #ifdef DEBUG_FCB_REFCOUNTS
2312 LONG oc;
2313 #endif
2314
2315 Irp->IoStatus.Information = 0;
2316
2317 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
2318 options = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
2319
2320 if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) {
2321 WARN("error - supersede requested with FILE_DIRECTORY_FILE\n");
2322 Status = STATUS_INVALID_PARAMETER;
2323 goto exit;
2324 }
2325
2326 if (options & FILE_OPEN_BY_FILE_ID) {
2327 WARN("FILE_OPEN_BY_FILE_ID not supported\n");
2328 Status = STATUS_NOT_IMPLEMENTED;
2329 goto exit;
2330 }
2331
2332 FileObject = Stack->FileObject;
2333
2334 debug_create_options(options);
2335
2336 switch (RequestedDisposition) {
2337 case FILE_SUPERSEDE:
2338 TRACE("requested disposition: FILE_SUPERSEDE\n");
2339 break;
2340
2341 case FILE_CREATE:
2342 TRACE("requested disposition: FILE_CREATE\n");
2343 break;
2344
2345 case FILE_OPEN:
2346 TRACE("requested disposition: FILE_OPEN\n");
2347 break;
2348
2349 case FILE_OPEN_IF:
2350 TRACE("requested disposition: FILE_OPEN_IF\n");
2351 break;
2352
2353 case FILE_OVERWRITE:
2354 TRACE("requested disposition: FILE_OVERWRITE\n");
2355 break;
2356
2357 case FILE_OVERWRITE_IF:
2358 TRACE("requested disposition: FILE_OVERWRITE_IF\n");
2359 break;
2360
2361 default:
2362 ERR("unknown disposition: %x\n", RequestedDisposition);
2363 Status = STATUS_NOT_IMPLEMENTED;
2364 goto exit;
2365 }
2366
2367 TRACE("(%.*S)\n", FileObject->FileName.Length / sizeof(WCHAR), FileObject->FileName.Buffer);
2368 TRACE("FileObject = %p\n", FileObject);
2369
2370 if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) {
2371 Status = STATUS_MEDIA_WRITE_PROTECTED;
2372 goto exit;
2373 }
2374
2375 // FIXME - if Vcb->readonly or subvol readonly, don't allow the write ACCESS_MASK flags
2376
2377 if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
2378 struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
2379
2380 related = relatedccb->fileref;
2381 } else
2382 related = NULL;
2383
2384 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2385 Status = open_fileref(Vcb, &fileref, &FileObject->FileName, related, Stack->Flags & SL_OPEN_TARGET_DIRECTORY, &unparsed);
2386 ExReleaseResourceLite(&Vcb->fcb_lock);
2387
2388 if (Status == STATUS_REPARSE) {
2389 REPARSE_DATA_BUFFER* data;
2390
2391 Status = get_reparse_block(fileref->fcb, (UINT8**)&data);
2392 if (!NT_SUCCESS(Status)) {
2393 ERR("get_reparse_block returned %08x\n", Status);
2394
2395 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2396 free_fileref(fileref);
2397 ExReleaseResourceLite(&Vcb->fcb_lock);
2398 goto exit;
2399 }
2400
2401 Status = STATUS_REPARSE;
2402 RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
2403
2404 data->Reserved = unparsed;
2405
2406 Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
2407
2408 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2409 free_fileref(fileref);
2410 ExReleaseResourceLite(&Vcb->fcb_lock);
2411 goto exit;
2412 }
2413
2414 if (NT_SUCCESS(Status) && fileref->deleted) {
2415 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2416 free_fileref(fileref);
2417 ExReleaseResourceLite(&Vcb->fcb_lock);
2418
2419 Status = STATUS_OBJECT_NAME_NOT_FOUND;
2420 goto exit; // FIXME?
2421 }
2422
2423 if (NT_SUCCESS(Status)) {
2424 if (RequestedDisposition == FILE_CREATE) {
2425 TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref));
2426 Status = STATUS_OBJECT_NAME_COLLISION;
2427 free_fileref(fileref);
2428 goto exit;
2429 }
2430 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
2431 if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
2432 TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
2433 goto exit;
2434 }
2435 } else {
2436 TRACE("open_fileref returned %08x\n", Status);
2437 goto exit;
2438 }
2439
2440 if (NT_SUCCESS(Status)) { // file already exists
2441 file_ref* sf;
2442
2443 if (Vcb->readonly && RequestedDisposition == FILE_OVERWRITE_IF) {
2444 Status = STATUS_MEDIA_WRITE_PROTECTED;
2445 free_fileref(fileref);
2446 goto exit;
2447 }
2448
2449 if (fileref->fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY && (RequestedDisposition == FILE_SUPERSEDE ||
2450 RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)) {
2451 Status = STATUS_ACCESS_DENIED;
2452 free_fileref(fileref);
2453 goto exit;
2454 }
2455
2456 TRACE("deleted = %s\n", fileref->deleted ? "TRUE" : "FALSE");
2457
2458 sf = fileref;
2459 while (sf) {
2460 if (sf->delete_on_close) {
2461 WARN("could not open as deletion pending\n");
2462 Status = STATUS_DELETE_PENDING;
2463
2464 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2465 free_fileref(fileref);
2466 ExReleaseResourceLite(&Vcb->fcb_lock);
2467 goto exit;
2468 }
2469 sf = sf->parent;
2470 }
2471
2472 if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)) {
2473 Status = STATUS_ACCESS_DENIED;
2474 free_fileref(fileref);
2475 goto exit;
2476 }
2477
2478 if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
2479 UINT8* data;
2480
2481 /* How reparse points work from the point of view of the filesystem appears to
2482 * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
2483 * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own
2484 * translation. If we instead return the reparse tag in Information, and store
2485 * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer,
2486 * IopSymlinkProcessReparse will do the translation for us. */
2487
2488 Status = get_reparse_block(fileref->fcb, &data);
2489 if (!NT_SUCCESS(Status)) {
2490 ERR("get_reparse_block returned %08x\n", Status);
2491
2492 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2493 free_fileref(fileref);
2494 ExReleaseResourceLite(&Vcb->fcb_lock);
2495 goto exit;
2496 }
2497
2498 Status = STATUS_REPARSE;
2499 RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
2500
2501 Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
2502
2503 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2504 free_fileref(fileref);
2505 ExReleaseResourceLite(&Vcb->fcb_lock);
2506 goto exit;
2507 }
2508
2509 if (!SeAccessCheck(fileref->fcb->ads ? fileref->parent->fcb->sd : fileref->fcb->sd, &access_state->SubjectSecurityContext, FALSE, access_state->OriginalDesiredAccess, 0, NULL,
2510 IoGetFileObjectGenericMapping(), Stack->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, &access, &Status)) {
2511 WARN("SeAccessCheck failed, returning %08x\n", Status);
2512
2513 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2514 free_fileref(fileref);
2515 ExReleaseResourceLite(&Vcb->fcb_lock);
2516 goto exit;
2517 }
2518
2519 if (fileref->fcb->open_count > 0) {
2520 Status = IoCheckShareAccess(access, Stack->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, TRUE);
2521
2522 if (!NT_SUCCESS(Status)) {
2523 WARN("IoCheckShareAccess failed, returning %08x\n", Status);
2524
2525 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2526 free_fileref(fileref);
2527 ExReleaseResourceLite(&Vcb->fcb_lock);
2528 goto exit;
2529 }
2530 } else {
2531 IoSetShareAccess(access, Stack->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
2532 }
2533
2534 if (access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
2535 if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite)) {
2536 Status = (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
2537
2538 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2539 free_fileref(fileref);
2540 ExReleaseResourceLite(&Vcb->fcb_lock);
2541 goto exit;
2542 }
2543 }
2544
2545 if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
2546 ULONG defda;
2547
2548 if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
2549 WARN("cannot overwrite readonly file\n");
2550 Status = STATUS_ACCESS_DENIED;
2551 free_fileref(fileref);
2552 goto exit;
2553 }
2554
2555 // FIXME - where did we get this from?
2556 // if (fcb->refcount > 1) {
2557 // WARN("cannot overwrite open file (fcb = %p, refcount = %u)\n", fcb, fcb->refcount);
2558 // Status = STATUS_ACCESS_DENIED;
2559 // free_fcb(fcb);
2560 // goto exit;
2561 // }
2562
2563 // FIXME - make sure not ADS!
2564 Status = truncate_file(fileref->fcb, fileref->fcb->inode_item.st_size, rollback);
2565 if (!NT_SUCCESS(Status)) {
2566 ERR("truncate_file returned %08x\n", Status);
2567 free_fileref(fileref);
2568 goto exit;
2569 }
2570
2571 if (Irp->Overlay.AllocationSize.QuadPart > 0) {
2572 Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, rollback);
2573
2574 if (!NT_SUCCESS(Status)) {
2575 ERR("extend_file returned %08x\n", Status);
2576 free_fileref(fileref);
2577 goto exit;
2578 }
2579 }
2580
2581 Status = update_inode_item(Vcb, fileref->fcb->subvol, fileref->fcb->inode, &fileref->fcb->inode_item, rollback);
2582 if (!NT_SUCCESS(Status)) {
2583 ERR("update_inode_item returned %08x\n", Status);
2584 free_fileref(fileref);
2585 goto exit;
2586 }
2587
2588 defda = get_file_attributes(Vcb, &fileref->fcb->inode_item, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
2589 fileref->filepart.Length > 0 && fileref->filepart.Buffer[0] == '.', TRUE);
2590
2591 if (RequestedDisposition == FILE_SUPERSEDE)
2592 fileref->fcb->atts = Stack->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
2593 else
2594 fileref->fcb->atts |= Stack->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
2595
2596 if (Stack->Parameters.Create.FileAttributes != defda) {
2597 char val[64];
2598
2599 sprintf(val, "0x%x", Stack->Parameters.Create.FileAttributes);
2600
2601 Status = set_xattr(Vcb, fileref->fcb->subvol, fileref->fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8*)val, strlen(val), rollback);
2602 if (!NT_SUCCESS(Status)) {
2603 ERR("set_xattr returned %08x\n", Status);
2604 free_fileref(fileref);
2605 goto exit;
2606 }
2607 } else
2608 delete_xattr(Vcb, fileref->fcb->subvol, fileref->fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, rollback);
2609
2610 // FIXME - truncate streams
2611 // FIXME - do we need to alter parent directory's times?
2612 // FIXME - send notifications
2613
2614 Status = consider_write(Vcb);
2615 if (!NT_SUCCESS(Status)) {
2616 ERR("consider_write returned %08x\n", Status);
2617 free_fileref(fileref);
2618 goto exit;
2619 }
2620 }
2621
2622 if (options & FILE_NON_DIRECTORY_FILE && fileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
2623 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2624 free_fileref(fileref);
2625 ExReleaseResourceLite(&Vcb->fcb_lock);
2626
2627 Status = STATUS_FILE_IS_A_DIRECTORY;
2628 goto exit;
2629 } else if (options & FILE_DIRECTORY_FILE && fileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
2630 TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref));
2631
2632 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2633 free_fileref(fileref);
2634 ExReleaseResourceLite(&Vcb->fcb_lock);
2635
2636 Status = STATUS_NOT_A_DIRECTORY;
2637 goto exit;
2638 }
2639
2640 FileObject->FsContext = fileref->fcb;
2641
2642 ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
2643 if (!ccb) {
2644 ERR("out of memory\n");
2645
2646 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
2647 free_fileref(fileref);
2648 ExReleaseResourceLite(&Vcb->fcb_lock);
2649
2650 Status = STATUS_INSUFFICIENT_RESOURCES;
2651 goto exit;
2652 }
2653
2654 RtlZeroMemory(ccb, sizeof(*ccb));
2655
2656 ccb->NodeType = BTRFS_NODE_TYPE_CCB;
2657 ccb->NodeSize = sizeof(ccb);
2658 ccb->disposition = RequestedDisposition;
2659 ccb->options = options;
2660 ccb->query_dir_offset = 0;
2661 RtlInitUnicodeString(&ccb->query_string, NULL);
2662 ccb->has_wildcard = FALSE;
2663 ccb->specific_file = FALSE;
2664 ccb->access = access;
2665
2666 ccb->fileref = fileref;
2667
2668 FileObject->FsContext2 = ccb;
2669
2670 FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
2671
2672 if (NT_SUCCESS(Status)) {
2673 switch (RequestedDisposition) {
2674 case FILE_SUPERSEDE:
2675 Irp->IoStatus.Information = FILE_SUPERSEDED;
2676 break;
2677
2678 case FILE_OPEN:
2679 case FILE_OPEN_IF:
2680 Irp->IoStatus.Information = FILE_OPENED;
2681 break;
2682
2683 case FILE_OVERWRITE:
2684 case FILE_OVERWRITE_IF:
2685 Irp->IoStatus.Information = FILE_OVERWRITTEN;
2686 break;
2687 }
2688 }
2689
2690 #ifdef DEBUG_FCB_REFCOUNTS
2691 oc = InterlockedIncrement(&fileref->fcb->open_count);
2692 ERR("fcb %p: open_count now %i\n", fileref->fcb, oc);
2693 #else
2694 InterlockedIncrement(&fileref->fcb->open_count);
2695 #endif
2696 } else {
2697 Status = file_create(Irp, DeviceObject->DeviceExtension, FileObject, &FileObject->FileName, RequestedDisposition, options, rollback);
2698 Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
2699 }
2700
2701 if (NT_SUCCESS(Status) && !(options & FILE_NO_INTERMEDIATE_BUFFERING))
2702 FileObject->Flags |= FO_CACHE_SUPPORTED;
2703
2704 exit:
2705 if (NT_SUCCESS(Status)) {
2706 if (!FileObject->Vpb)
2707 FileObject->Vpb = DeviceObject->Vpb;
2708 } else {
2709 if (Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND)
2710 TRACE("returning %08x\n", Status);
2711 }
2712
2713 return Status;
2714 }
2715
2716 NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
2717 NTSTATUS Status;
2718 PIO_STACK_LOCATION IrpSp;
2719 device_extension* Vcb = NULL;
2720 BOOL top_level;
2721 LIST_ENTRY rollback;
2722
2723 TRACE("create (flags = %x)\n", Irp->Flags);
2724
2725 InitializeListHead(&rollback);
2726
2727 FsRtlEnterFileSystem();
2728
2729 top_level = is_top_level(Irp);
2730
2731 /* return success if just called for FS device object */
2732 if (DeviceObject == devobj) {
2733 TRACE("create called for FS device object\n");
2734
2735 Irp->IoStatus.Information = FILE_OPENED;
2736 Status = STATUS_SUCCESS;
2737
2738 goto exit;
2739 }
2740
2741 Vcb = DeviceObject->DeviceExtension;
2742 ExAcquireResourceSharedLite(&Vcb->load_lock, TRUE);
2743
2744 IrpSp = IoGetCurrentIrpStackLocation(Irp);
2745
2746 if (IrpSp->Flags != 0) {
2747 UINT32 flags = IrpSp->Flags;
2748
2749 TRACE("flags:\n");
2750
2751 if (flags & SL_CASE_SENSITIVE) {
2752 TRACE("SL_CASE_SENSITIVE\n");
2753 flags &= ~SL_CASE_SENSITIVE;
2754 }
2755
2756 if (flags & SL_FORCE_ACCESS_CHECK) {
2757 TRACE("SL_FORCE_ACCESS_CHECK\n");
2758 flags &= ~SL_FORCE_ACCESS_CHECK;
2759 }
2760
2761 if (flags & SL_OPEN_PAGING_FILE) {
2762 TRACE("SL_OPEN_PAGING_FILE\n");
2763 flags &= ~SL_OPEN_PAGING_FILE;
2764 }
2765
2766 if (flags & SL_OPEN_TARGET_DIRECTORY) {
2767 TRACE("SL_OPEN_TARGET_DIRECTORY\n");
2768 flags &= ~SL_OPEN_TARGET_DIRECTORY;
2769 }
2770
2771 if (flags & SL_STOP_ON_SYMLINK) {
2772 TRACE("SL_STOP_ON_SYMLINK\n");
2773 flags &= ~SL_STOP_ON_SYMLINK;
2774 }
2775
2776 if (flags)
2777 WARN("unknown flags: %x\n", flags);
2778 } else {
2779 TRACE("flags: (none)\n");
2780 }
2781
2782 // Vpb = DeviceObject->DeviceExtension;
2783
2784 // TRACE("create called for something other than FS device object\n");
2785
2786 // opening volume
2787 // FIXME - also check if RelatedFileObject is Vcb
2788 if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) {
2789 ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
2790 ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
2791 #ifdef DEBUG_FCB_REFCOUNTS
2792 LONG rc, oc;
2793 #endif
2794
2795 TRACE("open operation for volume\n");
2796
2797 if (RequestedDisposition != FILE_OPEN &&
2798 RequestedDisposition != FILE_OPEN_IF)
2799 {
2800 Status = STATUS_ACCESS_DENIED;
2801 goto exit;
2802 }
2803
2804 if (RequestedOptions & FILE_DIRECTORY_FILE)
2805 {
2806 Status = STATUS_NOT_A_DIRECTORY;
2807 goto exit;
2808 }
2809
2810 #ifdef DEBUG_FCB_REFCOUNTS
2811 rc = InterlockedIncrement(&Vcb->volume_fcb->refcount);
2812 oc = InterlockedIncrement(&Vcb->volume_fcb->open_count);
2813 WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc);
2814 WARN("fcb %p: open_count now %i (volume)\n", Vcb->volume_fcb, oc);
2815 #else
2816 InterlockedIncrement(&Vcb->volume_fcb->refcount);
2817 InterlockedIncrement(&Vcb->volume_fcb->open_count);
2818 #endif
2819 IrpSp->FileObject->FsContext = Vcb->volume_fcb;
2820
2821 IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object;
2822
2823 Irp->IoStatus.Information = FILE_OPENED;
2824 Status = STATUS_SUCCESS;
2825 } else {
2826 BOOL exclusive, skip_lock;
2827 ULONG disposition;
2828
2829 TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length / sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer);
2830
2831 if (IrpSp->FileObject->RelatedFileObject)
2832 TRACE("related file = %S\n", file_desc(IrpSp->FileObject->RelatedFileObject));
2833
2834 disposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
2835
2836 // We acquire the lock exclusively if there's the possibility we might be writing
2837 exclusive = disposition != FILE_OPEN;
2838
2839 // Don't lock again if we're being called from within CcCopyRead etc.
2840 skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
2841
2842 if (!skip_lock)
2843 acquire_tree_lock(Vcb, exclusive);
2844
2845 // ExAcquireResourceExclusiveLite(&Vpb->DirResource, TRUE);
2846 // Status = NtfsCreateFile(DeviceObject,
2847 // Irp);
2848 Status = open_file(DeviceObject, Irp, &rollback);
2849 // ExReleaseResourceLite(&Vpb->DirResource);
2850
2851 if (exclusive && !NT_SUCCESS(Status))
2852 do_rollback(Vcb, &rollback);
2853 else
2854 clear_rollback(&rollback);
2855
2856 if (!skip_lock)
2857 release_tree_lock(Vcb, exclusive);
2858
2859 // Status = STATUS_ACCESS_DENIED;
2860 }
2861
2862 exit:
2863 Irp->IoStatus.Status = Status;
2864 IoCompleteRequest( Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT );
2865 // IoCompleteRequest( Irp, IO_DISK_INCREMENT );
2866
2867 TRACE("create returning %08x\n", Status);
2868
2869 ExReleaseResourceLite(&Vcb->load_lock);
2870
2871 if (top_level)
2872 IoSetTopLevelIrp(NULL);
2873
2874 FsRtlExitFileSystem();
2875
2876 return Status;
2877 }