1 /* Copyright (c) Mark Harmstone 2016-17 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 #include "btrfs_drv.h" 19 20 FAST_IO_DISPATCH FastIoDispatch; 21 22 _Function_class_(FAST_IO_QUERY_BASIC_INFO) 23 #ifdef __REACTOS__ 24 static BOOLEAN NTAPI fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION fbi, 25 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 26 #else 27 static BOOLEAN fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION fbi, 28 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 29 #endif 30 fcb* fcb; 31 ccb* ccb; 32 33 FsRtlEnterFileSystem(); 34 35 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fbi, IoStatus, DeviceObject); 36 37 if (!FileObject) { 38 FsRtlExitFileSystem(); 39 return FALSE; 40 } 41 42 fcb = FileObject->FsContext; 43 44 if (!fcb) { 45 FsRtlExitFileSystem(); 46 return FALSE; 47 } 48 49 ccb = FileObject->FsContext2; 50 51 if (!ccb) { 52 FsRtlExitFileSystem(); 53 return FALSE; 54 } 55 56 if (!(ccb->access & (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES))) { 57 FsRtlExitFileSystem(); 58 return FALSE; 59 } 60 61 if (fcb->ads) { 62 if (!ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) { 63 FsRtlExitFileSystem(); 64 return FALSE; 65 } 66 67 fcb = ccb->fileref->parent->fcb; 68 } 69 70 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { 71 FsRtlExitFileSystem(); 72 return FALSE; 73 } 74 75 if (fcb == fcb->Vcb->dummy_fcb) { 76 LARGE_INTEGER time; 77 78 KeQuerySystemTime(&time); 79 fbi->CreationTime = fbi->LastAccessTime = fbi->LastWriteTime = fbi->ChangeTime = time; 80 } else { 81 fbi->CreationTime.QuadPart = unix_time_to_win(&fcb->inode_item.otime); 82 fbi->LastAccessTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_atime); 83 fbi->LastWriteTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_mtime); 84 fbi->ChangeTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_ctime); 85 } 86 87 fbi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts; 88 89 IoStatus->Status = STATUS_SUCCESS; 90 IoStatus->Information = sizeof(FILE_BASIC_INFORMATION); 91 92 ExReleaseResourceLite(fcb->Header.Resource); 93 94 FsRtlExitFileSystem(); 95 96 return TRUE; 97 } 98 99 _Function_class_(FAST_IO_QUERY_STANDARD_INFO) 100 #ifdef __REACTOS__ 101 static BOOLEAN NTAPI fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION fsi, 102 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 103 #else 104 static BOOLEAN fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION fsi, 105 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 106 #endif 107 fcb* fcb; 108 ccb* ccb; 109 BOOL ads; 110 ULONG adssize; 111 112 FsRtlEnterFileSystem(); 113 114 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fsi, IoStatus, DeviceObject); 115 116 if (!FileObject) { 117 FsRtlExitFileSystem(); 118 return FALSE; 119 } 120 121 fcb = FileObject->FsContext; 122 ccb = FileObject->FsContext2; 123 124 if (!fcb) { 125 FsRtlExitFileSystem(); 126 return FALSE; 127 } 128 129 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { 130 FsRtlExitFileSystem(); 131 return FALSE; 132 } 133 134 ads = fcb->ads; 135 136 if (ads) { 137 struct _fcb* fcb2; 138 139 if (!ccb || !ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) { 140 ExReleaseResourceLite(fcb->Header.Resource); 141 FsRtlExitFileSystem(); 142 return FALSE; 143 } 144 145 adssize = fcb->adsdata.Length; 146 147 fcb2 = ccb->fileref->parent->fcb; 148 149 ExReleaseResourceLite(fcb->Header.Resource); 150 151 fcb = fcb2; 152 153 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { 154 FsRtlExitFileSystem(); 155 return FALSE; 156 } 157 158 fsi->AllocationSize.QuadPart = fsi->EndOfFile.QuadPart = adssize; 159 fsi->NumberOfLinks = fcb->inode_item.st_nlink; 160 fsi->Directory = FALSE; 161 } else { 162 fsi->AllocationSize.QuadPart = fcb_alloc_size(fcb); 163 fsi->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size; 164 fsi->NumberOfLinks = fcb->inode_item.st_nlink; 165 fsi->Directory = S_ISDIR(fcb->inode_item.st_mode); 166 } 167 168 fsi->DeletePending = ccb->fileref ? ccb->fileref->delete_on_close : FALSE; 169 170 IoStatus->Status = STATUS_SUCCESS; 171 IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION); 172 173 ExReleaseResourceLite(fcb->Header.Resource); 174 175 FsRtlExitFileSystem(); 176 177 return TRUE; 178 } 179 180 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE) 181 #ifdef __REACTOS__ 182 static BOOLEAN NTAPI fast_io_check_if_possible(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, 183 ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus, 184 PDEVICE_OBJECT DeviceObject) { 185 #else 186 static BOOLEAN fast_io_check_if_possible(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, 187 ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus, 188 PDEVICE_OBJECT DeviceObject) { 189 #endif 190 fcb* fcb = FileObject->FsContext; 191 LARGE_INTEGER len2; 192 193 UNUSED(Wait); 194 UNUSED(IoStatus); 195 UNUSED(DeviceObject); 196 197 len2.QuadPart = Length; 198 199 if (CheckForReadOperation) { 200 if (FsRtlFastCheckLockForRead(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess())) 201 return TRUE; 202 } else { 203 if (!fcb->Vcb->readonly && !is_subvol_readonly(fcb->subvol, NULL) && FsRtlFastCheckLockForWrite(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess())) 204 return TRUE; 205 } 206 207 return FALSE; 208 } 209 210 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO) 211 #ifdef __REACTOS__ 212 static BOOLEAN NTAPI fast_io_query_network_open_info(PFILE_OBJECT FileObject, BOOLEAN Wait, FILE_NETWORK_OPEN_INFORMATION* fnoi, 213 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 214 #else 215 static BOOLEAN fast_io_query_network_open_info(PFILE_OBJECT FileObject, BOOLEAN Wait, FILE_NETWORK_OPEN_INFORMATION* fnoi, 216 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 217 #endif 218 fcb* fcb; 219 ccb* ccb; 220 file_ref* fileref; 221 222 FsRtlEnterFileSystem(); 223 224 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, Wait, fnoi, IoStatus, DeviceObject); 225 226 RtlZeroMemory(fnoi, sizeof(FILE_NETWORK_OPEN_INFORMATION)); 227 228 fcb = FileObject->FsContext; 229 230 if (!fcb || fcb == fcb->Vcb->volume_fcb) { 231 FsRtlExitFileSystem(); 232 return FALSE; 233 } 234 235 ccb = FileObject->FsContext2; 236 237 if (!ccb) { 238 FsRtlExitFileSystem(); 239 return FALSE; 240 } 241 242 fileref = ccb->fileref; 243 244 if (fcb == fcb->Vcb->dummy_fcb) { 245 LARGE_INTEGER time; 246 247 KeQuerySystemTime(&time); 248 fnoi->CreationTime = fnoi->LastAccessTime = fnoi->LastWriteTime = fnoi->ChangeTime = time; 249 } else { 250 INODE_ITEM* ii; 251 252 if (fcb->ads) { 253 if (!fileref || !fileref->parent) { 254 ERR("no fileref for stream\n"); 255 FsRtlExitFileSystem(); 256 return FALSE; 257 } 258 259 ii = &fileref->parent->fcb->inode_item; 260 } else 261 ii = &fcb->inode_item; 262 263 fnoi->CreationTime.QuadPart = unix_time_to_win(&ii->otime); 264 fnoi->LastAccessTime.QuadPart = unix_time_to_win(&ii->st_atime); 265 fnoi->LastWriteTime.QuadPart = unix_time_to_win(&ii->st_mtime); 266 fnoi->ChangeTime.QuadPart = unix_time_to_win(&ii->st_ctime); 267 } 268 269 if (fcb->ads) { 270 fnoi->AllocationSize.QuadPart = fnoi->EndOfFile.QuadPart = fcb->adsdata.Length; 271 fnoi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts; 272 } else { 273 fnoi->AllocationSize.QuadPart = fcb_alloc_size(fcb); 274 fnoi->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size; 275 fnoi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts; 276 } 277 278 FsRtlExitFileSystem(); 279 280 return TRUE; 281 } 282 283 _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE) 284 #ifdef __REACTOS__ 285 static NTSTATUS NTAPI fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) { 286 #else 287 static NTSTATUS fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) { 288 #endif 289 fcb* fcb; 290 291 UNUSED(EndingOffset); 292 UNUSED(DeviceObject); 293 294 fcb = FileObject->FsContext; 295 296 if (!fcb) 297 return STATUS_INVALID_PARAMETER; 298 299 // Make sure we don't get interrupted by the flush thread, which can cause a deadlock 300 301 if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, FALSE)) 302 return STATUS_CANT_WAIT; 303 304 // Ideally this would be PagingIoResource, but that doesn't play well with copy-on-write, 305 // as we can't guarantee that we won't need to do any reallocations. 306 307 *ResourceToRelease = fcb->Header.Resource; 308 309 if (!ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE)) { 310 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 311 return STATUS_CANT_WAIT; 312 } 313 314 return STATUS_SUCCESS; 315 } 316 317 _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE) 318 #ifdef __REACTOS__ 319 static NTSTATUS NTAPI fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject) { 320 #else 321 static NTSTATUS fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject) { 322 #endif 323 fcb* fcb; 324 325 UNUSED(DeviceObject); 326 327 fcb = FileObject->FsContext; 328 329 ExReleaseResourceLite(ResourceToRelease); 330 331 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 332 333 return STATUS_SUCCESS; 334 } 335 336 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH) 337 #ifdef __REACTOS__ 338 static NTSTATUS NTAPI fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) { 339 #else 340 static NTSTATUS fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) { 341 #endif 342 UNUSED(FileObject); 343 UNUSED(DeviceObject); 344 345 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 346 347 return STATUS_SUCCESS; 348 } 349 350 _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH) 351 #ifdef __REACTOS__ 352 static NTSTATUS NTAPI fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) { 353 #else 354 static NTSTATUS fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) { 355 #endif 356 UNUSED(FileObject); 357 UNUSED(DeviceObject); 358 359 if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) 360 IoSetTopLevelIrp(NULL); 361 362 return STATUS_SUCCESS; 363 } 364 365 _Function_class_(FAST_IO_WRITE) 366 #ifdef __REACTOS__ 367 static BOOLEAN NTAPI fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 368 #else 369 static BOOLEAN fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { 370 #endif 371 if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject)) { 372 fcb* fcb = FileObject->FsContext; 373 374 fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart; 375 376 return TRUE; 377 } 378 379 return FALSE; 380 } 381 382 void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) { 383 RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch)); 384 385 FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); 386 387 FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible; 388 FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info; 389 FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info; 390 FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info; 391 FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write; 392 FastIoDispatch.ReleaseForModWrite = fast_io_release_for_mod_write; 393 FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush; 394 FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush; 395 FastIoDispatch.FastIoWrite = fast_io_write; 396 FastIoDispatch.FastIoRead = FsRtlCopyRead; 397 FastIoDispatch.MdlRead = FsRtlMdlReadDev; 398 FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev; 399 FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev; 400 FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev; 401 402 *fiod = &FastIoDispatch; 403 } 404