00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "ntfs.h"
00029
00030 #define NDEBUG
00031 #include <debug.h>
00032
00033
00034
00035
00036
00037
00038 #if 0
00039 static NTSTATUS
00040 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
00041 PVOID *Context,
00042 PVOID *Block,
00043 PLARGE_INTEGER StreamOffset,
00044 ULONG DirLength,
00045 PVOID *Ptr,
00046 PWSTR Name,
00047 PULONG pIndex,
00048 PULONG pIndex2)
00049
00050
00051
00052 {
00053 PDIR_RECORD Record;
00054 NTSTATUS Status;
00055 ULONG Index = 0;
00056 ULONG Offset = 0;
00057 ULONG BlockOffset = 0;
00058
00059 Record = (PDIR_RECORD)*Block;
00060 while(Index < *pIndex)
00061 {
00062 BlockOffset += Record->RecordLength;
00063 Offset += Record->RecordLength;
00064
00065 Record = (PDIR_RECORD)(*Block + BlockOffset);
00066 if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
00067 {
00068 DPRINT("Map next sector\n");
00069 CcUnpinData(*Context);
00070 StreamOffset->QuadPart += BLOCKSIZE;
00071 Offset = ROUND_UP(Offset, BLOCKSIZE);
00072 BlockOffset = 0;
00073
00074 if (!CcMapData(DeviceExt->StreamFileObject,
00075 StreamOffset,
00076 BLOCKSIZE, TRUE,
00077 Context, Block))
00078 {
00079 DPRINT("CcMapData() failed\n");
00080 return(STATUS_UNSUCCESSFUL);
00081 }
00082 Record = (PDIR_RECORD)(*Block + BlockOffset);
00083 }
00084
00085 if (Offset >= DirLength)
00086 return(STATUS_NO_MORE_ENTRIES);
00087
00088 Index++;
00089 }
00090
00091 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
00092 Index, Record->RecordLength, Offset);
00093
00094 if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
00095 {
00096 wcscpy(Name, L".");
00097 }
00098 else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
00099 {
00100 wcscpy(Name, L"..");
00101 }
00102 else
00103 {
00104 if (DeviceExt->CdInfo.JolietLevel == 0)
00105 {
00106 ULONG i;
00107
00108 for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
00109 Name[i] = (WCHAR)Record->FileId[i];
00110 Name[i] = 0;
00111 }
00112 else
00113 {
00114 CdfsSwapString(Name, Record->FileId, Record->FileIdLength);
00115 }
00116 }
00117
00118 DPRINT("Name '%S'\n", Name);
00119
00120 *Ptr = Record;
00121
00122 *pIndex = Index;
00123
00124 return(STATUS_SUCCESS);
00125 }
00126
00127
00128 static NTSTATUS
00129 CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
00130 PFCB Fcb,
00131 PFCB Parent,
00132 PWSTR FileToFind,
00133 PULONG pDirIndex,
00134 PULONG pDirIndex2)
00135
00136
00137
00138 {
00139 WCHAR name[256];
00140 WCHAR TempStr[2];
00141 PVOID Block;
00142 NTSTATUS Status;
00143 ULONG len;
00144 ULONG DirIndex;
00145 ULONG Offset;
00146 ULONG Read;
00147 BOOLEAN IsRoot;
00148 PVOID Context = NULL;
00149 ULONG DirSize;
00150 PUCHAR Ptr;
00151 PDIR_RECORD Record;
00152 LARGE_INTEGER StreamOffset;
00153
00154 DPRINT("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n",
00155 Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
00156 DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",
00157 Fcb->PathName, Fcb->ObjectName);
00158
00159 IsRoot = FALSE;
00160 DirIndex = 0;
00161 if (wcslen (FileToFind) == 0)
00162 {
00163 CHECKPOINT;
00164 TempStr[0] = (WCHAR) '.';
00165 TempStr[1] = 0;
00166 FileToFind = (PWSTR)&TempStr;
00167 }
00168
00169 if (Parent)
00170 {
00171 if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
00172 {
00173 IsRoot = TRUE;
00174 }
00175 }
00176 else
00177 {
00178 IsRoot = TRUE;
00179 }
00180
00181 if (IsRoot == TRUE)
00182 {
00183 StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
00184 DirSize = DeviceExt->CdInfo.RootSize;
00185
00186
00187 if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
00188 || (FileToFind[0] == '.' && FileToFind[1] == 0))
00189 {
00190
00191 RtlZeroMemory(Fcb, sizeof(FCB));
00192
00193 Fcb->PathName[0]='\\';
00194 Fcb->ObjectName = &Fcb->PathName[1];
00195 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
00196 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
00197 Fcb->Entry.FileFlags = 0x02;
00198
00199 if (pDirIndex)
00200 *pDirIndex = 0;
00201 if (pDirIndex2)
00202 *pDirIndex2 = 0;
00203 DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
00204 return (STATUS_SUCCESS);
00205 }
00206 }
00207 else
00208 {
00209 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
00210 DirSize = Parent->Entry.DataLengthL;
00211 }
00212
00213 DPRINT("StreamOffset %I64u DirSize %lu\n", StreamOffset.QuadPart, DirSize);
00214
00215 if (pDirIndex && (*pDirIndex))
00216 DirIndex = *pDirIndex;
00217
00218 if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
00219 BLOCKSIZE, TRUE, &Context, &Block))
00220 {
00221 DPRINT("CcMapData() failed\n");
00222 return(STATUS_UNSUCCESSFUL);
00223 }
00224
00225 Ptr = (PUCHAR)Block;
00226 while(TRUE)
00227 {
00228 Record = (PDIR_RECORD)Ptr;
00229 if (Record->RecordLength == 0)
00230 {
00231 DPRINT1("Stopped!\n");
00232 break;
00233 }
00234
00235 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
00236 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
00237
00238 Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
00239 DirSize, (PVOID*)&Ptr, name, &DirIndex, pDirIndex2);
00240 if (Status == STATUS_NO_MORE_ENTRIES)
00241 {
00242 break;
00243 }
00244 else if (Status == STATUS_UNSUCCESSFUL)
00245 {
00246
00247 return(Status);
00248 }
00249
00250 DPRINT("Name '%S'\n", name);
00251
00252 if (wstrcmpjoki(name, FileToFind))
00253 {
00254 if (Parent && Parent->PathName)
00255 {
00256 len = wcslen(Parent->PathName);
00257 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
00258 Fcb->ObjectName=&Fcb->PathName[len];
00259 if (len != 1 || Fcb->PathName[0] != '\\')
00260 {
00261 Fcb->ObjectName[0] = '\\';
00262 Fcb->ObjectName = &Fcb->ObjectName[1];
00263 }
00264 }
00265 else
00266 {
00267 Fcb->ObjectName=Fcb->PathName;
00268 Fcb->ObjectName[0]='\\';
00269 Fcb->ObjectName=&Fcb->ObjectName[1];
00270 }
00271
00272 DPRINT("PathName '%S' ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
00273
00274 memcpy(&Fcb->Entry, Ptr, sizeof(DIR_RECORD));
00275 wcsncpy(Fcb->ObjectName, name, MAX_PATH);
00276 if (pDirIndex)
00277 *pDirIndex = DirIndex;
00278
00279 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
00280 Fcb->PathName, Fcb->ObjectName, DirIndex);
00281
00282 CcUnpinData(Context);
00283
00284 return(STATUS_SUCCESS);
00285 }
00286
00287
00288 Ptr = Ptr + Record->RecordLength;
00289 DirIndex++;
00290
00291 if (((ULONG)Ptr - (ULONG)Block) >= DirSize)
00292 {
00293 DPRINT("Stopped!\n");
00294 break;
00295 }
00296 }
00297
00298 CcUnpinData(Context);
00299
00300 if (pDirIndex)
00301 *pDirIndex = DirIndex;
00302
00303 return(STATUS_UNSUCCESSFUL);
00304 }
00305
00306
00307 static NTSTATUS
00308 CdfsGetNameInformation(PFCB Fcb,
00309 PDEVICE_EXTENSION DeviceExt,
00310 PFILE_NAMES_INFORMATION Info,
00311 ULONG BufferLength)
00312 {
00313 ULONG Length;
00314
00315 DPRINT("CdfsGetNameInformation() called\n");
00316
00317 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
00318 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
00319 return(STATUS_BUFFER_OVERFLOW);
00320
00321 Info->FileNameLength = Length;
00322 Info->NextEntryOffset =
00323 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
00324 memcpy(Info->FileName, Fcb->ObjectName, Length);
00325
00326 return(STATUS_SUCCESS);
00327 }
00328
00329
00330 static NTSTATUS
00331 CdfsGetDirectoryInformation(PFCB Fcb,
00332 PDEVICE_EXTENSION DeviceExt,
00333 PFILE_DIRECTORY_INFORMATION Info,
00334 ULONG BufferLength)
00335 {
00336 ULONG Length;
00337
00338 DPRINT("CdfsGetDirectoryInformation() called\n");
00339
00340 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
00341 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
00342 return(STATUS_BUFFER_OVERFLOW);
00343
00344 Info->FileNameLength = Length;
00345 Info->NextEntryOffset =
00346 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
00347 memcpy(Info->FileName, Fcb->ObjectName, Length);
00348
00349
00350 CdfsDateTimeToFileTime(Fcb,
00351 &Info->CreationTime);
00352 CdfsDateTimeToFileTime(Fcb,
00353 &Info->LastAccessTime);
00354 CdfsDateTimeToFileTime(Fcb,
00355 &Info->LastWriteTime);
00356 CdfsDateTimeToFileTime(Fcb,
00357 &Info->ChangeTime);
00358
00359
00360 CdfsFileFlagsToAttributes(Fcb,
00361 &Info->FileAttributes);
00362
00363 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
00364
00365
00366 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
00367
00368
00369
00370 return(STATUS_SUCCESS);
00371 }
00372
00373
00374 static NTSTATUS
00375 CdfsGetFullDirectoryInformation(PFCB Fcb,
00376 PDEVICE_EXTENSION DeviceExt,
00377 PFILE_FULL_DIRECTORY_INFORMATION Info,
00378 ULONG BufferLength)
00379 {
00380 ULONG Length;
00381
00382 DPRINT("CdfsGetFullDirectoryInformation() called\n");
00383
00384 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
00385 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
00386 return(STATUS_BUFFER_OVERFLOW);
00387
00388 Info->FileNameLength = Length;
00389 Info->NextEntryOffset =
00390 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
00391 memcpy(Info->FileName, Fcb->ObjectName, Length);
00392
00393
00394 CdfsDateTimeToFileTime(Fcb,
00395 &Info->CreationTime);
00396 CdfsDateTimeToFileTime(Fcb,
00397 &Info->LastAccessTime);
00398 CdfsDateTimeToFileTime(Fcb,
00399 &Info->LastWriteTime);
00400 CdfsDateTimeToFileTime(Fcb,
00401 &Info->ChangeTime);
00402
00403
00404 CdfsFileFlagsToAttributes(Fcb,
00405 &Info->FileAttributes);
00406
00407 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
00408
00409
00410 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
00411
00412
00413 Info->EaSize = 0;
00414
00415 return(STATUS_SUCCESS);
00416 }
00417
00418
00419 static NTSTATUS
00420 CdfsGetBothDirectoryInformation(PFCB Fcb,
00421 PDEVICE_EXTENSION DeviceExt,
00422 PFILE_BOTH_DIRECTORY_INFORMATION Info,
00423 ULONG BufferLength)
00424 {
00425 ULONG Length;
00426
00427 DPRINT("CdfsGetBothDirectoryInformation() called\n");
00428
00429 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
00430 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
00431 return(STATUS_BUFFER_OVERFLOW);
00432
00433 Info->FileNameLength = Length;
00434 Info->NextEntryOffset =
00435 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
00436 memcpy(Info->FileName, Fcb->ObjectName, Length);
00437
00438
00439 CdfsDateTimeToFileTime(Fcb,
00440 &Info->CreationTime);
00441 CdfsDateTimeToFileTime(Fcb,
00442 &Info->LastAccessTime);
00443 CdfsDateTimeToFileTime(Fcb,
00444 &Info->LastWriteTime);
00445 CdfsDateTimeToFileTime(Fcb,
00446 &Info->ChangeTime);
00447
00448
00449 CdfsFileFlagsToAttributes(Fcb,
00450 &Info->FileAttributes);
00451
00452 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
00453
00454
00455 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
00456
00457
00458 Info->EaSize = 0;
00459
00460 if (DeviceExt->CdInfo.JolietLevel == 0)
00461 {
00462
00463 Info->ShortNameLength = Length;
00464 memcpy(Info->ShortName, Fcb->ObjectName, Length);
00465 }
00466 else
00467 {
00468
00469
00470
00471
00472 Info->ShortName[0] = 0;
00473 Info->ShortNameLength = 0;
00474 }
00475
00476 return(STATUS_SUCCESS);
00477 }
00478 #endif
00479
00480 NTSTATUS
00481 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
00482 {
00483 PIRP Irp;
00484
00485
00486
00487 PUNICODE_STRING SearchPattern = NULL;
00488
00489 ULONG FileIndex = 0;
00490 PUCHAR Buffer = NULL;
00491 PFILE_NAMES_INFORMATION Buffer0 = NULL;
00492
00493 PNTFS_CCB Ccb;
00494
00495 BOOLEAN First = FALSE;
00496 PIO_STACK_LOCATION Stack;
00497 PFILE_OBJECT FileObject;
00498
00499
00500 DPRINT1("NtfsQueryDirectory() called\n");
00501
00502 ASSERT(IrpContext);
00503 Irp = IrpContext->Irp;
00504
00505
00506
00507 Stack = IoGetCurrentIrpStackLocation(Irp);
00508 FileObject = Stack->FileObject;
00509
00510 Ccb = (PNTFS_CCB)FileObject->FsContext2;
00511
00512
00513
00514
00515 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
00516
00517 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
00518
00519
00520 if (SearchPattern != NULL)
00521 {
00522 if (!Ccb->DirectorySearchPattern)
00523 {
00524 First = TRUE;
00525 Ccb->DirectorySearchPattern =
00526 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_NTFS);
00527 if (!Ccb->DirectorySearchPattern)
00528 {
00529 return(STATUS_INSUFFICIENT_RESOURCES);
00530 }
00531
00532 memcpy(Ccb->DirectorySearchPattern,
00533 SearchPattern->Buffer,
00534 SearchPattern->Length);
00535 Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
00536 }
00537 }
00538 else if (!Ccb->DirectorySearchPattern)
00539 {
00540 First = TRUE;
00541 Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
00542 if (!Ccb->DirectorySearchPattern)
00543 {
00544 return(STATUS_INSUFFICIENT_RESOURCES);
00545 }
00546 Ccb->DirectorySearchPattern[0] = L'*';
00547 Ccb->DirectorySearchPattern[1] = 0;
00548 }
00549 DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
00550
00551
00552 if (Stack->Flags & SL_INDEX_SPECIFIED)
00553 {
00554 Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
00555 }
00556 else if (First || (Stack->Flags & SL_RESTART_SCAN))
00557 {
00558 Ccb->Entry = 0;
00559 }
00560
00561
00562 if (Irp->MdlAddress)
00563 {
00564 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
00565 }
00566 else
00567 {
00568 Buffer = Irp->UserBuffer;
00569 }
00570 DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
00571 #if 0
00572 TempFcb.ObjectName = TempFcb.PathName;
00573 while (Status == STATUS_SUCCESS && BufferLength > 0)
00574 {
00575 Status = CdfsFindFile(DeviceExtension,
00576 &TempFcb,
00577 Fcb,
00578 Ccb->DirectorySearchPattern,
00579 &Ccb->Entry,
00580 NULL);
00581 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
00582
00583 if (NT_SUCCESS(Status))
00584 {
00585 switch (FileInformationClass)
00586 {
00587 case FileNameInformation:
00588 Status = CdfsGetNameInformation(&TempFcb,
00589 DeviceExtension,
00590 (PFILE_NAMES_INFORMATION)Buffer,
00591 BufferLength);
00592 break;
00593
00594 case FileDirectoryInformation:
00595 Status = CdfsGetDirectoryInformation(&TempFcb,
00596 DeviceExtension,
00597 (PFILE_DIRECTORY_INFORMATION)Buffer,
00598 BufferLength);
00599 break;
00600
00601 case FileFullDirectoryInformation:
00602 Status = CdfsGetFullDirectoryInformation(&TempFcb,
00603 DeviceExtension,
00604 (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
00605 BufferLength);
00606 break;
00607
00608 case FileBothDirectoryInformation:
00609 Status = NtfsGetBothDirectoryInformation(&TempFcb,
00610 DeviceExtension,
00611 (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,
00612 BufferLength);
00613 break;
00614
00615 default:
00616 Status = STATUS_INVALID_INFO_CLASS;
00617 }
00618
00619 if (Status == STATUS_BUFFER_OVERFLOW)
00620 {
00621 if (Buffer0)
00622 {
00623 Buffer0->NextEntryOffset = 0;
00624 }
00625 break;
00626 }
00627 }
00628 else
00629 {
00630 if (Buffer0)
00631 {
00632 Buffer0->NextEntryOffset = 0;
00633 }
00634
00635 if (First)
00636 {
00637 Status = STATUS_NO_SUCH_FILE;
00638 }
00639 else
00640 {
00641 Status = STATUS_NO_MORE_FILES;
00642 }
00643 break;
00644 }
00645
00646 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
00647 Buffer0->FileIndex = FileIndex++;
00648 Ccb->Entry++;
00649
00650 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
00651 {
00652 break;
00653 }
00654 BufferLength -= Buffer0->NextEntryOffset;
00655 Buffer += Buffer0->NextEntryOffset;
00656 }
00657 #endif
00658
00659 if (Buffer0)
00660 {
00661 Buffer0->NextEntryOffset = 0;
00662 }
00663
00664 if (FileIndex > 0)
00665 {
00666
00667 }
00668
00669
00670 return(STATUS_NO_MORE_FILES);
00671 }
00672
00673
00674
00675 NTSTATUS NTAPI
00676 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
00677 PIRP Irp)
00678 {
00679 PNTFS_IRP_CONTEXT IrpContext = NULL;
00680 NTSTATUS Status = STATUS_UNSUCCESSFUL;
00681
00682 DPRINT1("NtfsDirectoryControl() called\n");
00683
00684 FsRtlEnterFileSystem();
00685 ASSERT(DeviceObject);
00686 ASSERT(Irp);
00687
00688 NtfsIsIrpTopLevel(Irp);
00689
00690 IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
00691 if (IrpContext)
00692 {
00693 switch (IrpContext->MinorFunction)
00694 {
00695 case IRP_MN_QUERY_DIRECTORY:
00696 Status = NtfsQueryDirectory(IrpContext);
00697 break;
00698
00699 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
00700 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
00701 Status = STATUS_NOT_IMPLEMENTED;
00702 break;
00703
00704 default:
00705 Status = STATUS_INVALID_DEVICE_REQUEST;
00706 break;
00707 }
00708 }
00709 else
00710 Status = STATUS_INSUFFICIENT_RESOURCES;
00711
00712 Irp->IoStatus.Status = Status;
00713 Irp->IoStatus.Information = 0;
00714 IoCompleteRequest(Irp, IO_NO_INCREMENT);
00715
00716 if (IrpContext)
00717 ExFreePoolWithTag(IrpContext, 'PRIN');
00718
00719 IoSetTopLevelIrp(NULL);
00720 FsRtlExitFileSystem();
00721 return Status;
00722 }
00723
00724