ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dir.c
Go to the documentation of this file.
00001 /* $Id: dir.c 55866 2012-02-25 21:09:28Z khornicek $
00002  *
00003  * COPYRIGHT:       See COPYING in the top level directory
00004  * PROJECT:         ReactOS system libraries
00005  * FILE:            lib/kernel32/client/file/dir.c
00006  * PURPOSE:         Directory functions
00007  * PROGRAMMER:      Pierre Schweitzer (pierre@reactos.org)
00008  */
00009 
00010 /* INCLUDES ******************************************************************/
00011 
00012 #include <k32.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 /* Short File Name length in chars (8.3) */
00017 #define SFN_LENGTH 12
00018 
00019 /* Match a volume name like:
00020  * \\?\Volume{GUID}
00021  */
00022 #define IS_VOLUME_NAME(s, l)                       \
00023   ((l == 96 || (l == 98 && s[48] == '\\')) &&      \
00024    s[0] == '\\'&& (s[1] == '?' || s[1] == '\\') && \
00025    s[2] == '?' && s[3] == '\\' && s[4] == 'V' &&   \
00026    s[5] == 'o' && s[6] == 'l' && s[7] == 'u' &&    \
00027    s[8] == 'm' && s[9] == 'e' && s[10] == '{' &&   \
00028    s[19] == '-' && s[24] == '-' && s[29] == '-' && \
00029    s[34] == '-' && s[47] == '}')
00030 
00031 /* FIXME - Get it out of here */
00032 typedef struct _REPARSE_DATA_BUFFER {
00033     ULONG  ReparseTag;
00034     USHORT ReparseDataLength;
00035     USHORT Reserved;
00036     union {
00037         struct {
00038             USHORT SubstituteNameOffset;
00039             USHORT SubstituteNameLength;
00040             USHORT PrintNameOffset;
00041             USHORT PrintNameLength;
00042             ULONG Flags;
00043             WCHAR PathBuffer[1];
00044         } SymbolicLinkReparseBuffer;
00045         struct {
00046             USHORT SubstituteNameOffset;
00047             USHORT SubstituteNameLength;
00048             USHORT PrintNameOffset;
00049             USHORT PrintNameLength;
00050             WCHAR PathBuffer[1];
00051         } MountPointReparseBuffer;
00052         struct {
00053             UCHAR  DataBuffer[1];
00054         } GenericReparseBuffer;
00055     };
00056 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
00057 
00058 /* FUNCTIONS *****************************************************************/
00059 
00060 /*
00061  * @implemented
00062  */
00063 BOOL
00064 WINAPI
00065 CreateDirectoryA(IN LPCSTR lpPathName,
00066                  IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
00067 {
00068     PUNICODE_STRING PathNameW;
00069 
00070     PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
00071     if (!PathNameW)
00072     {
00073         return FALSE;
00074     }
00075 
00076     return CreateDirectoryW(PathNameW->Buffer,
00077                             lpSecurityAttributes);
00078 }
00079 
00080 /*
00081  * @implemented
00082  */
00083 BOOL
00084 WINAPI
00085 CreateDirectoryExA(IN LPCSTR lpTemplateDirectory,
00086                    IN LPCSTR lpNewDirectory,
00087                    IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
00088 {
00089     PUNICODE_STRING TemplateDirectoryW;
00090     UNICODE_STRING NewDirectoryW;
00091     BOOL ret;
00092 
00093     TemplateDirectoryW = Basep8BitStringToStaticUnicodeString(lpTemplateDirectory);
00094     if (!TemplateDirectoryW)
00095     {
00096         return FALSE;
00097     }
00098 
00099     if (!Basep8BitStringToDynamicUnicodeString(&NewDirectoryW, lpNewDirectory))
00100     {
00101         return FALSE;
00102     }
00103 
00104     ret = CreateDirectoryExW(TemplateDirectoryW->Buffer,
00105                              NewDirectoryW.Buffer,
00106                              lpSecurityAttributes);
00107 
00108     RtlFreeUnicodeString(&NewDirectoryW);
00109 
00110     return ret;
00111 }
00112 
00113 /*
00114  * @implemented
00115  */
00116 BOOL
00117 WINAPI
00118 CreateDirectoryW(IN LPCWSTR lpPathName,
00119                  IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
00120 {
00121     DWORD Length;
00122     NTSTATUS Status;
00123     HANDLE DirectoryHandle;
00124     UNICODE_STRING NtPathU;
00125     PWSTR PathUBuffer, FilePart;
00126     IO_STATUS_BLOCK IoStatusBlock;
00127     RTL_RELATIVE_NAME_U RelativeName;
00128     OBJECT_ATTRIBUTES ObjectAttributes;
00129 
00130     /* Get relative name */
00131     if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
00132     {
00133         SetLastError(ERROR_PATH_NOT_FOUND);
00134         return FALSE;
00135     }
00136 
00137     /* Check if path length is < MAX_PATH (with space for file name).
00138      * If not, prefix is required.
00139      */
00140     if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpPathName[0] != L'\\' &&
00141         lpPathName[1] != L'\\' && lpPathName[2] != L'?' && lpPathName[3] != L'\\')
00142     {
00143         /* Get file name position and full path length */
00144         Length = GetFullPathNameW(lpPathName, 0, NULL, &FilePart);
00145         if (Length == 0)
00146         {
00147             RtlReleaseRelativeName(&RelativeName);
00148             RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
00149             SetLastError(ERROR_FILENAME_EXCED_RANGE);
00150             return FALSE;
00151         }
00152 
00153         /* Keep place for 8.3 file name */
00154         Length += SFN_LENGTH;
00155         /* No prefix, so, must be smaller than MAX_PATH */
00156         if (Length > MAX_PATH)
00157         {
00158             RtlReleaseRelativeName(&RelativeName);
00159             RtlFreeHeap(GetProcessHeap(), 0, NtPathU.Buffer);
00160             SetLastError(ERROR_FILENAME_EXCED_RANGE);
00161             return FALSE;
00162         }
00163     }
00164 
00165     /* Save buffer to allow later freeing */
00166     PathUBuffer = NtPathU.Buffer;
00167 
00168     /* If we have relative name (and root dir), use them instead */
00169     if (RelativeName.RelativeName.Length != 0)
00170     {
00171         NtPathU.Length = RelativeName.RelativeName.Length;
00172         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
00173         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
00174     }
00175     else
00176     {
00177         RelativeName.ContainingDirectory = NULL;
00178     }
00179 
00180     InitializeObjectAttributes(&ObjectAttributes,
00181                                &NtPathU,
00182                                OBJ_CASE_INSENSITIVE,
00183                                RelativeName.ContainingDirectory,
00184                                (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
00185 
00186     Status = NtCreateFile(&DirectoryHandle,
00187                           FILE_LIST_DIRECTORY | SYNCHRONIZE,
00188                           &ObjectAttributes,
00189                           &IoStatusBlock,
00190                           NULL,
00191                           FILE_ATTRIBUTE_NORMAL,
00192                           FILE_SHARE_READ | FILE_SHARE_WRITE,
00193                           FILE_CREATE,
00194                           FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
00195                           NULL,
00196                           0);
00197 
00198     RtlReleaseRelativeName(&RelativeName);
00199     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00200 
00201     if (NT_SUCCESS(Status))
00202     {
00203         NtClose(DirectoryHandle);
00204         return TRUE;
00205     }
00206 
00207     if (RtlIsDosDeviceName_U(lpPathName))
00208     {
00209         Status = STATUS_NOT_A_DIRECTORY;
00210     }
00211 
00212     BaseSetLastNTError(Status);
00213     return FALSE;
00214 }
00215 
00216 /*
00217  * @implemented
00218  */
00219 BOOL
00220 WINAPI
00221 CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory,
00222                    IN LPCWSTR lpNewDirectory,
00223                    IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
00224 {
00225     DWORD Length;
00226     NTSTATUS Status;
00227     PVOID EaBuffer = NULL;
00228     BOOL ReparsePoint = FALSE;
00229     IO_STATUS_BLOCK IoStatusBlock;
00230     FILE_EA_INFORMATION FileEaInfo;
00231     ULONG EaLength = 0, StreamSize;
00232     OBJECT_ATTRIBUTES ObjectAttributes;
00233     FILE_BASIC_INFORMATION FileBasicInfo;
00234     PREPARSE_DATA_BUFFER ReparseDataBuffer;
00235     HANDLE TemplateHandle, DirectoryHandle;
00236     PFILE_STREAM_INFORMATION FileStreamInfo;
00237     FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
00238     UNICODE_STRING NtPathU, NtTemplatePathU, NewDirectory;
00239     RTL_RELATIVE_NAME_U RelativeName, TemplateRelativeName;
00240     PWSTR TemplateBuffer, PathUBuffer, FilePart, SubstituteName;        
00241 
00242     /* Get relative name of the template */
00243     if (!RtlDosPathNameToRelativeNtPathName_U(lpTemplateDirectory, &NtTemplatePathU, NULL, &TemplateRelativeName))
00244     {
00245         SetLastError(ERROR_PATH_NOT_FOUND);
00246         return FALSE;
00247     }
00248 
00249     /* Save buffer for further freeing */
00250     TemplateBuffer = NtTemplatePathU.Buffer;
00251 
00252     /* If we have relative name (and root dir), use them instead */
00253     if (TemplateRelativeName.RelativeName.Length != 0)
00254     {
00255         NtTemplatePathU.Length = TemplateRelativeName.RelativeName.Length;
00256         NtTemplatePathU.MaximumLength = TemplateRelativeName.RelativeName.MaximumLength;
00257         NtTemplatePathU.Buffer = TemplateRelativeName.RelativeName.Buffer;
00258     }
00259     else
00260     {
00261         TemplateRelativeName.ContainingDirectory = NULL;
00262     }
00263 
00264     InitializeObjectAttributes(&ObjectAttributes,
00265                                &NtTemplatePathU,
00266                                OBJ_CASE_INSENSITIVE,
00267                                NULL,
00268                                NULL);
00269 
00270     /* Open template directory */
00271     Status = NtOpenFile(&TemplateHandle,
00272                         FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
00273                         &ObjectAttributes,
00274                         &IoStatusBlock,
00275                         FILE_SHARE_READ | FILE_SHARE_WRITE,
00276                         FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
00277     if (!NT_SUCCESS(Status))
00278     {
00279         if (Status != STATUS_INVALID_PARAMETER)
00280         {
00281             RtlReleaseRelativeName(&TemplateRelativeName);
00282             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00283             BaseSetLastNTError(Status);
00284             return FALSE;
00285         }
00286 
00287 OpenWithoutReparseSupport:
00288         /* Opening failed due to lacking reparse points support in the FSD, try without */
00289         Status = NtOpenFile(&TemplateHandle,
00290                             FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
00291                             &ObjectAttributes,
00292                             &IoStatusBlock,
00293                             FILE_SHARE_READ | FILE_SHARE_WRITE,
00294                             FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
00295 
00296         if (!NT_SUCCESS(Status))
00297         {
00298             RtlReleaseRelativeName(&TemplateRelativeName);
00299             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00300             BaseSetLastNTError(Status);
00301             return FALSE;
00302         }
00303 
00304         /* Request file attributes */
00305         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
00306         Status = NtQueryInformationFile(TemplateHandle,
00307                                         &IoStatusBlock,
00308                                         &FileBasicInfo,
00309                                         sizeof(FileBasicInfo),
00310                                         FileBasicInformation);
00311         if (!NT_SUCCESS(Status))
00312         {
00313             RtlReleaseRelativeName(&TemplateRelativeName);
00314             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00315             CloseHandle(TemplateHandle);
00316             BaseSetLastNTError(Status);
00317             return FALSE;
00318 
00319         }
00320     }
00321     else
00322     {
00323         /* Request file attributes */
00324         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
00325         Status = NtQueryInformationFile(TemplateHandle,
00326                                         &IoStatusBlock,
00327                                         &FileBasicInfo,
00328                                         sizeof(FileBasicInfo),
00329                                         FileBasicInformation);
00330         if (!NT_SUCCESS(Status))
00331         {
00332             RtlReleaseRelativeName(&TemplateRelativeName);
00333             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00334             CloseHandle(TemplateHandle);
00335             BaseSetLastNTError(Status);
00336             return FALSE;
00337 
00338         }
00339 
00340         /* If it is a reparse point, then get information about it */
00341         if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
00342         {
00343             Status = NtQueryInformationFile(TemplateHandle,
00344                                             &IoStatusBlock,
00345                                             &FileTagInfo,
00346                                             sizeof(FileTagInfo),
00347                                             FileAttributeTagInformation);
00348             if (!NT_SUCCESS(Status))
00349             {
00350                 RtlReleaseRelativeName(&TemplateRelativeName);
00351                 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00352                 CloseHandle(TemplateHandle);
00353                 BaseSetLastNTError(Status);
00354                 return FALSE;
00355             }
00356 
00357             /* Only mount points are supported, retry without if anything different */
00358             if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
00359             {
00360                 CloseHandle(TemplateHandle);
00361                 goto OpenWithoutReparseSupport;
00362             }
00363 
00364             /* Mark we are playing with a reparse point */
00365             ReparsePoint = TRUE;
00366         }
00367     }
00368 
00369     /* Get relative name of the directory */
00370     if (!RtlDosPathNameToRelativeNtPathName_U(lpNewDirectory, &NtPathU, NULL, &RelativeName))
00371     {
00372         RtlReleaseRelativeName(&TemplateRelativeName);
00373         RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00374         NtClose(TemplateHandle);
00375         SetLastError(ERROR_PATH_NOT_FOUND);
00376         return FALSE;
00377     }
00378 
00379     /* Save its buffer for further freeing */
00380     PathUBuffer = NtPathU.Buffer;
00381 
00382     /* Template & directory can't be the same */
00383     if (RtlEqualUnicodeString(&NtPathU,
00384                               &NtTemplatePathU,
00385                               TRUE))
00386     {
00387         RtlReleaseRelativeName(&RelativeName);
00388         RtlReleaseRelativeName(&TemplateRelativeName);
00389         RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00390         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00391         NtClose(TemplateHandle);
00392         SetLastError(ERROR_INVALID_NAME);
00393         return FALSE;
00394     }
00395 
00396     RtlReleaseRelativeName(&TemplateRelativeName);
00397     RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
00398 
00399     /* Check if path length is < MAX_PATH (with space for file name).
00400      * If not, prefix is required.
00401      */
00402     if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpNewDirectory[0] != L'\\' &&
00403         lpNewDirectory[1] != L'\\' && lpNewDirectory[2] != L'?' && lpNewDirectory[3] != L'\\')
00404     {
00405         /* Get file name position and full path length */
00406         Length = GetFullPathNameW(lpNewDirectory, 0, NULL, &FilePart);
00407         if (Length == 0)
00408         {
00409             RtlReleaseRelativeName(&RelativeName);
00410             RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00411             CloseHandle(TemplateHandle);
00412             SetLastError(ERROR_FILENAME_EXCED_RANGE);
00413             return FALSE;
00414         }
00415 
00416         /* Keep place for 8.3 file name */
00417         Length += SFN_LENGTH;
00418         /* No prefix, so, must be smaller than MAX_PATH */
00419         if (Length > MAX_PATH)
00420         {
00421             RtlReleaseRelativeName(&RelativeName);
00422             RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00423             CloseHandle(TemplateHandle);
00424             SetLastError(ERROR_FILENAME_EXCED_RANGE);
00425             return FALSE;
00426         }
00427     }
00428 
00429     /* If we have relative name (and root dir), use them instead */
00430     if (RelativeName.RelativeName.Length != 0)
00431     {
00432         NtPathU.Length = RelativeName.RelativeName.Length;
00433         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
00434         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
00435     }
00436     else
00437     {
00438         RelativeName.ContainingDirectory = NULL;
00439     }
00440 
00441     /* Get extended attributes */
00442     Status = NtQueryInformationFile(TemplateHandle,
00443                                     &IoStatusBlock,
00444                                     &FileEaInfo,
00445                                     sizeof(FileEaInfo),
00446                                     FileEaInformation);
00447     if (!NT_SUCCESS(Status))
00448     {
00449         RtlReleaseRelativeName(&RelativeName);
00450         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00451         CloseHandle(TemplateHandle);
00452         BaseSetLastNTError(Status);
00453         return FALSE;
00454     } 
00455 
00456     /* Start reading extended attributes */
00457     if (FileEaInfo.EaSize != 0)
00458     {
00459         for (EaLength = FileEaInfo.EaSize * 2; ; EaLength = EaLength * 2)
00460         {
00461             /* Allocate buffer for reading */
00462             EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, EaLength);
00463             if (!EaBuffer)
00464             {
00465                 RtlReleaseRelativeName(&RelativeName);
00466                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00467                 CloseHandle(TemplateHandle);
00468                 BaseSetLastNTError(STATUS_NO_MEMORY);
00469                 return FALSE;
00470             }
00471 
00472             /* Query EAs */
00473             Status = NtQueryEaFile(TemplateHandle,
00474                                    &IoStatusBlock,
00475                                    EaBuffer,
00476                                    EaLength,
00477                                    FALSE,
00478                                    NULL,
00479                                    0,
00480                                    NULL,
00481                                    TRUE);
00482             if (!NT_SUCCESS(Status))
00483             {
00484                 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
00485                 IoStatusBlock.Information = 0;
00486             }
00487 
00488             /* If we don't fail because of too small buffer, stop here */
00489             if (Status != STATUS_BUFFER_OVERFLOW &&
00490                 Status != STATUS_BUFFER_TOO_SMALL)
00491             {
00492                 EaLength = IoStatusBlock.Information;
00493                 break;
00494             }
00495         }
00496     }
00497 
00498     InitializeObjectAttributes(&ObjectAttributes,
00499                                &NtPathU,
00500                                OBJ_CASE_INSENSITIVE,
00501                                RelativeName.ContainingDirectory,
00502                                (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
00503 
00504     /* Ensure attributes are valid */
00505     FileBasicInfo.FileAttributes &= FILE_ATTRIBUTE_VALID_FLAGS;
00506 
00507     /* Create the new directory */
00508     Status = NtCreateFile(&DirectoryHandle,
00509                           FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES |
00510                           FILE_READ_ATTRIBUTES | (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? FILE_ADD_FILE : 0),
00511                           &ObjectAttributes,
00512                           &IoStatusBlock,
00513                           NULL,
00514                           FileBasicInfo.FileAttributes,
00515                           FILE_SHARE_READ | FILE_SHARE_WRITE,
00516                           FILE_CREATE,
00517                           FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00518                           FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT,
00519                           EaBuffer,
00520                           EaLength);
00521     if (!NT_SUCCESS(Status))
00522     {
00523         if (Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED)
00524         {
00525             /* If creation failed, it might be because FSD doesn't support reparse points
00526              * Retry without asking for such support in case template is not a reparse point
00527              */
00528             if (!ReparsePoint)
00529             {
00530                 Status = NtCreateFile(&DirectoryHandle,
00531                                       FILE_LIST_DIRECTORY | SYNCHRONIZE |
00532                                       FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES,
00533                                       &ObjectAttributes,
00534                                       &IoStatusBlock,
00535                                       NULL,
00536                                       FileBasicInfo.FileAttributes,
00537                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
00538                                       FILE_CREATE,
00539                                       FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00540                                       FILE_OPEN_FOR_BACKUP_INTENT,
00541                                       EaBuffer,
00542                                       EaLength);
00543             }
00544             else
00545             {
00546                 RtlReleaseRelativeName(&RelativeName);
00547                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00548                 if (EaBuffer)
00549                 {
00550                     RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
00551                 }
00552                 CloseHandle(TemplateHandle);
00553                 BaseSetLastNTError(Status);
00554                 return FALSE;
00555             }
00556         }
00557     }
00558 
00559     RtlReleaseRelativeName(&RelativeName);
00560     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00561     if (EaBuffer)
00562     {
00563         RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
00564     }
00565 
00566     if (!NT_SUCCESS(Status))
00567     {
00568         NtClose(TemplateHandle);
00569         if (RtlIsDosDeviceName_U(lpNewDirectory))
00570         {
00571             Status = STATUS_NOT_A_DIRECTORY;
00572         }
00573         BaseSetLastNTError(Status);
00574         return FALSE;
00575     }
00576 
00577     /* If template is a reparse point, copy reparse data */
00578     if (ReparsePoint)
00579     {
00580         ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
00581                                             MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00582         if (!ReparseDataBuffer)
00583         {
00584             NtClose(TemplateHandle);
00585             NtClose(DirectoryHandle);
00586             SetLastError(STATUS_NO_MEMORY);
00587             return FALSE;
00588         }
00589 
00590         /* First query data */
00591         Status = NtFsControlFile(TemplateHandle,
00592                                  NULL,
00593                                  NULL,
00594                                  NULL,
00595                                  &IoStatusBlock,
00596                                  FSCTL_GET_REPARSE_POINT,
00597                                  NULL,
00598                                  0,
00599                                  ReparseDataBuffer,
00600                                  MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00601         if (!NT_SUCCESS(Status))
00602         {
00603             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00604             NtClose(TemplateHandle);
00605             NtClose(DirectoryHandle);
00606             SetLastError(Status);
00607             return FALSE;
00608         }
00609 
00610         /* Once again, ensure it is a mount point */
00611         if (ReparseDataBuffer->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
00612         {
00613             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00614             NtClose(TemplateHandle);
00615             NtClose(DirectoryHandle);
00616             SetLastError(STATUS_OBJECT_NAME_INVALID);
00617             return FALSE;
00618         }
00619 
00620         /* Get volume name */
00621         SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
00622                                  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
00623         if (IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
00624         {
00625             /* Prepare to define a new mount point for that volume */
00626             RtlInitUnicodeString(&NewDirectory, lpNewDirectory);
00627             NewDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewDirectory.Length + 2 * sizeof(WCHAR));
00628             if (!NewDirectory.Buffer)
00629             {
00630                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00631                 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00632                 NtClose(TemplateHandle);
00633                 NtClose(DirectoryHandle);
00634                 return FALSE;
00635             }
00636 
00637             RtlCopyMemory(&NewDirectory.Buffer, lpNewDirectory, NewDirectory.Length);
00638             if (NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] != L'\\')
00639             {
00640                 NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] = L'\\';
00641                 NewDirectory.Buffer[(NewDirectory.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
00642             }
00643 
00644             /* Define a new mount point for that volume */
00645             SetVolumeMountPointW(NewDirectory.Buffer, SubstituteName);
00646 
00647             RtlFreeHeap(RtlGetProcessHeap(), 0, NewDirectory.Buffer);
00648             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00649             NtClose(TemplateHandle);
00650             NtClose(DirectoryHandle);
00651             return TRUE;
00652         }
00653 
00654         /* Otherwise copy data raw */
00655         Status = NtFsControlFile(DirectoryHandle,
00656                                  NULL,
00657                                  NULL,
00658                                  NULL,
00659                                  &IoStatusBlock,
00660                                  FSCTL_SET_REPARSE_POINT,
00661                                  ReparseDataBuffer,
00662                                  ReparseDataBuffer->ReparseDataLength +
00663                                  FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer),
00664                                  NULL,
00665                                  0);
00666 
00667         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00668         NtClose(TemplateHandle);
00669         NtClose(DirectoryHandle);
00670 
00671         if (NT_SUCCESS(Status))
00672         {
00673             return TRUE;
00674         }
00675 
00676         BaseSetLastNTError(Status);
00677         return FALSE;
00678     }
00679     /* In case it's not a reparse point, handle streams on the file */
00680     else
00681     {
00682         for (StreamSize = 0x1000; ; StreamSize = StreamSize * 2)
00683         {
00684             FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, StreamSize);
00685             if (!FileStreamInfo)
00686             {
00687                 BaseMarkFileForDelete(DirectoryHandle, FileBasicInfo.FileAttributes);
00688                 SetLastError(STATUS_NO_MEMORY);
00689                 break;
00690             }
00691 
00692             /* Query stream information */
00693             Status = NtQueryInformationFile(TemplateHandle,
00694                                             &IoStatusBlock,
00695                                             FileStreamInfo,
00696                                             StreamSize,
00697                                             FileStreamInformation);
00698             if (NT_SUCCESS(Status))
00699             {
00700                 break;
00701             }
00702 
00703             RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
00704             FileStreamInfo = NULL;
00705 
00706             /* If it failed, ensure that's not because of too small buffer */
00707             if (Status != STATUS_BUFFER_OVERFLOW &&
00708                 Status != STATUS_BUFFER_TOO_SMALL)
00709             {
00710                 break;
00711             }
00712         }
00713 
00714         if (!NT_SUCCESS(Status) || IoStatusBlock.Information == 0)
00715         {
00716             if (FileStreamInfo)
00717             {
00718                 RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
00719             }
00720 
00721             NtClose(TemplateHandle);
00722             NtClose(DirectoryHandle);
00723             return TRUE;
00724         }
00725 
00726 #if 1
00727         /* FIXME: TODO */
00728         DPRINT1("Warning: streams copying is unimplemented!\n");
00729         RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
00730         NtClose(TemplateHandle);
00731         NtClose(DirectoryHandle);
00732 #endif
00733         return TRUE;
00734     }
00735 }
00736 
00737 /*
00738  * @implemented
00739  */
00740 BOOL
00741 WINAPI
00742 RemoveDirectoryA(IN LPCSTR lpPathName)
00743 {
00744     PUNICODE_STRING PathNameW;
00745 
00746     PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
00747     if (!PathNameW)
00748     {
00749         return FALSE;
00750     }
00751 
00752     return RemoveDirectoryW(PathNameW->Buffer);
00753 }
00754 
00755 /*
00756  * @implemented
00757  */
00758 BOOL
00759 WINAPI
00760 RemoveDirectoryW(IN LPCWSTR lpPathName)
00761 {
00762     NTSTATUS Status;
00763     DWORD BytesReturned;
00764     HANDLE DirectoryHandle;
00765     IO_STATUS_BLOCK IoStatusBlock;
00766     UNICODE_STRING NtPathU, PathName;
00767     RTL_RELATIVE_NAME_U RelativeName;
00768     PWSTR PathUBuffer, SubstituteName;
00769     OBJECT_ATTRIBUTES ObjectAttributes;
00770     PREPARSE_DATA_BUFFER ReparseDataBuffer;
00771     FILE_DISPOSITION_INFORMATION FileDispInfo;
00772     FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
00773 
00774     /* Get relative name */
00775     if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
00776     {
00777         SetLastError(ERROR_PATH_NOT_FOUND);
00778         return FALSE;
00779     }
00780 
00781     /* Save buffer to allow later freeing */
00782     PathUBuffer = NtPathU.Buffer;
00783 
00784     /* If we have relative name (and root dir), use them instead */
00785     if (RelativeName.RelativeName.Length != 0)
00786     {
00787         NtPathU.Length = RelativeName.RelativeName.Length;
00788         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
00789         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
00790     }
00791     else
00792     {
00793         RelativeName.ContainingDirectory = NULL;
00794     }
00795 
00796     InitializeObjectAttributes(&ObjectAttributes,
00797                                &NtPathU,
00798                                OBJ_CASE_INSENSITIVE,
00799                                RelativeName.ContainingDirectory,
00800                                NULL);
00801 
00802     /* Try to open directory */
00803     Status = NtOpenFile(&DirectoryHandle,
00804                         DELETE | SYNCHRONIZE | FAILED_ACCESS_ACE_FLAG,
00805                         &ObjectAttributes,
00806                         &IoStatusBlock,
00807                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
00808                         FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00809                         FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
00810     if (!NT_SUCCESS(Status))
00811     {
00812         /* We only accept failure for reparse points not being supported */
00813         if (Status != STATUS_INVALID_PARAMETER)
00814         {
00815             goto Cleanup;
00816         }
00817 
00818         /* Try to open, with reparse points support */
00819         Status = NtOpenFile(&DirectoryHandle,
00820                             DELETE | SYNCHRONIZE,
00821                             &ObjectAttributes,
00822                             &IoStatusBlock,
00823                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
00824                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00825                             FILE_OPEN_FOR_BACKUP_INTENT);
00826         if (!NT_SUCCESS(Status))
00827         {
00828             goto Cleanup;
00829         }
00830 
00831         /* Success, mark directory */
00832         goto MarkFileForDelete;
00833     }
00834 
00835     /* Get information about file (and reparse point) */
00836     Status = NtQueryInformationFile(DirectoryHandle,
00837                                     &IoStatusBlock,
00838                                     &FileTagInfo,
00839                                     sizeof(FileTagInfo),
00840                                     FileAttributeTagInformation);
00841     if (!NT_SUCCESS(Status))
00842     {
00843         /* FSD might not support querying reparse points information */
00844         if (Status != STATUS_NOT_IMPLEMENTED &&
00845             Status != STATUS_INVALID_PARAMETER)
00846         {
00847             goto CleanupHandle;
00848         }
00849 
00850         /* If that's the case, then just delete directory */
00851         goto MarkFileForDelete;
00852     }
00853 
00854     /* If that's not a reparse point, nothing more to do than just delete */
00855     if (!(FileTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
00856     {
00857         goto MarkFileForDelete;
00858     }
00859 
00860     /* Check if that's a mount point */
00861     if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
00862     {
00863         /* It's not */
00864         NtClose(DirectoryHandle);
00865 
00866         /* So, try to reopen directory, ignoring mount point */
00867         Status = NtOpenFile(&DirectoryHandle,
00868                             DELETE | SYNCHRONIZE,
00869                             &ObjectAttributes,
00870                             &IoStatusBlock,
00871                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
00872                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00873                             FILE_OPEN_FOR_BACKUP_INTENT);
00874         if (NT_SUCCESS(Status))
00875         {
00876             /* It succeed, we can safely delete directory (and ignore reparse point) */
00877             goto MarkFileForDelete;
00878         }
00879 
00880         /* If it failed, only allow case where IO mount point was ignored */
00881         if (Status != STATUS_IO_REPARSE_TAG_NOT_HANDLED)
00882         {
00883             goto Cleanup;
00884         }
00885 
00886         /* Reopen with reparse point support */
00887         Status = NtOpenFile(&DirectoryHandle,
00888                             DELETE | SYNCHRONIZE,
00889                             &ObjectAttributes,
00890                             &IoStatusBlock,
00891                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
00892                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
00893                             FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
00894         if (NT_SUCCESS(Status))
00895         {
00896             /* And mark for delete */
00897             goto MarkFileForDelete;
00898         }
00899 
00900         goto Cleanup;
00901     }
00902 
00903     /* Here, we have a mount point, prepare to query information about it */
00904     ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
00905                                         MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00906     if (!ReparseDataBuffer)
00907     {
00908         RtlReleaseRelativeName(&RelativeName);
00909         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00910         NtClose(DirectoryHandle);
00911         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00912         return FALSE;
00913     }
00914 
00915     /* Query */
00916     if (!DeviceIoControl(DirectoryHandle,
00917                          FSCTL_GET_REPARSE_POINT,
00918                          NULL, 0,
00919                          ReparseDataBuffer,
00920                          MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
00921                          &BytesReturned,
00922                          NULL))
00923     {
00924         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00925         goto MarkFileForDelete;
00926     }
00927 
00928     /* Get volume name */
00929     SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
00930                              ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
00931     if (!IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
00932     {
00933         /* This is not a volume, we can safely delete */
00934         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00935         goto MarkFileForDelete;
00936     }
00937 
00938     /* Prepare to delete mount point */
00939     RtlInitUnicodeString(&PathName, lpPathName);
00940     PathName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathName.Length + 2 * sizeof(WCHAR));
00941     if (!PathName.Buffer)
00942     {
00943         RtlReleaseRelativeName(&RelativeName);
00944         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00945         NtClose(DirectoryHandle);
00946         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00947         return FALSE;
00948     }
00949 
00950     RtlCopyMemory(&PathName.Buffer, lpPathName, PathName.Length);
00951     if (PathName.Buffer[PathName.Length / sizeof(WCHAR)] != L'\\')
00952     {
00953         PathName.Buffer[PathName.Length / sizeof(WCHAR)] = L'\\';
00954         PathName.Buffer[(PathName.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
00955     }
00956 
00957     /* Delete mount point for that volume */
00958     DeleteVolumeMountPointW(PathName.Buffer);
00959     RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
00960     RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
00961 
00962     /* And mark directory for delete */
00963 MarkFileForDelete:
00964     RtlReleaseRelativeName(&RelativeName);
00965     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00966 
00967     /* Mark & set */
00968     FileDispInfo.DeleteFile = TRUE;
00969     Status = NtSetInformationFile(DirectoryHandle,
00970                                   &IoStatusBlock,
00971                                   &FileDispInfo,
00972                                   sizeof(FILE_DISPOSITION_INFORMATION),
00973                                   FileDispositionInformation);
00974     NtClose(DirectoryHandle);
00975 
00976     if (!NT_SUCCESS(Status))
00977     {
00978         BaseSetLastNTError(Status);
00979         return FALSE;
00980     }
00981 
00982     return TRUE;
00983 
00984 CleanupHandle:
00985     NtClose(DirectoryHandle);
00986 
00987 Cleanup:
00988     RtlReleaseRelativeName(&RelativeName);
00989     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
00990     BaseSetLastNTError(Status);
00991     return FALSE;
00992 }
00993 
00994 /* EOF */

Generated on Sun May 27 2012 04:18:12 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.