ReactOS 0.4.16-dev-297-gc569aee
create.c File Reference
#include "cdprocs.h"
Include dependency graph for create.c:

Go to the source code of this file.

Macros

#define BugCheckFileId   (CDFS_BUG_CHECK_CREATE)
 

Functions

 _When_ (RelatedTypeOfOpen !=UnopenedFileObject, _At_(RelatedCcb, _In_))
 
 _Requires_lock_held_ (_Global_critical_region_)
 

Macro Definition Documentation

◆ BugCheckFileId

#define BugCheckFileId   (CDFS_BUG_CHECK_CREATE)

Definition at line 23 of file create.c.

Function Documentation

◆ _Requires_lock_held_()

_Requires_lock_held_ ( _Global_critical_region_  )

Definition at line 1477 of file create.c.

1527{
1529
1530 BOOLEAN UnlockVcb = FALSE;
1531 BOOLEAN Found;
1532
1533 ULONG StreamOffset;
1534
1535 NODE_TYPE_CODE NodeTypeCode;
1537
1539 BOOLEAN CleanupFileContext = FALSE;
1540
1541 COMPOUND_PATH_ENTRY CompoundPathEntry = {{0}};/* ReactOS Change: GCC "missing braces around initializer" */
1542 BOOLEAN CleanupCompoundPathEntry = FALSE;
1543
1544 FILE_ID FileId;
1545 FILE_ID ParentFileId;
1546
1547 PFCB NextFcb;
1548
1549 PAGED_CODE();
1550
1551 //
1552 // Extract the FileId from the FileObject.
1553 //
1554
1555 RtlCopyMemory( &FileId, IrpSp->FileObject->FileName.Buffer, sizeof( FILE_ID ));
1556
1557 //
1558 // Use a try-finally to facilitate cleanup.
1559 //
1560
1561 _SEH2_TRY {
1562
1563 //
1564 // Go ahead and figure out the TypeOfOpen and NodeType. We can
1565 // get these from the input FileId.
1566 //
1567
1568 if (CdFidIsDirectory( FileId )) {
1569
1571 NodeTypeCode = CDFS_NTC_FCB_INDEX;
1572
1573 //
1574 // If the offset isn't zero then the file Id is bad.
1575 //
1576
1577 if (CdQueryFidDirentOffset( FileId ) != 0) {
1578
1580 }
1581
1582 } else {
1583
1585 NodeTypeCode = CDFS_NTC_FCB_DATA;
1586 }
1587
1588 //
1589 // Acquire the Vcb and check if there is already an Fcb.
1590 // If not we will need to carefully verify the Fcb.
1591 // We will post the request if we don't find the Fcb and this
1592 // request can't wait.
1593 //
1594
1595 CdLockVcb( IrpContext, Vcb );
1596 UnlockVcb = TRUE;
1597
1598 NextFcb = CdLookupFcbTable( IrpContext, Vcb, FileId );
1599
1600 if (NextFcb == NULL) {
1601
1602 //
1603 // Get the path table offset from the file id.
1604 //
1605
1606 StreamOffset = CdQueryFidPathTableOffset( FileId );
1607
1608 //
1609 // Build the parent FileId for this and try looking it
1610 // up in the PathTable.
1611 //
1612
1613 CdSetFidDirentOffset( ParentFileId, 0 );
1614 CdSetFidPathTableOffset( ParentFileId, StreamOffset );
1615 CdFidSetDirectory( ParentFileId );
1616
1617 NextFcb = CdLookupFcbTable( IrpContext, Vcb, ParentFileId );
1618
1619 //
1620 // If not present then walk through the PathTable to this point.
1621 //
1622
1623 if (NextFcb == NULL) {
1624
1625 CdUnlockVcb( IrpContext, Vcb );
1626 UnlockVcb = FALSE;
1627
1628 //
1629 // Check that the path table offset lies within the path
1630 // table.
1631 //
1632
1633 if (StreamOffset > Vcb->PathTableFcb->FileSize.LowPart) {
1634
1636 }
1637
1639 CleanupCompoundPathEntry = TRUE;
1640
1641 //
1642 // Start at the first entry in the PathTable.
1643 //
1644
1645 CdLookupPathEntry( IrpContext,
1646 Vcb->PathTableFcb->StreamOffset,
1647 1,
1648 TRUE,
1650
1651 //
1652 // Continue looking until we have passed our target offset.
1653 //
1654
1655 while (TRUE) {
1656
1657 //
1658 // Move to the next entry.
1659 //
1660
1661 Found = CdLookupNextPathEntry( IrpContext,
1662 &CompoundPathEntry.PathContext,
1663 &CompoundPathEntry.PathEntry );
1664
1665 //
1666 // If we didn't find the entry or are beyond it then the
1667 // input Id is invalid.
1668 //
1669
1670 if (!Found ||
1671 (CompoundPathEntry.PathEntry.PathTableOffset > StreamOffset)) {
1672
1674 }
1675 }
1676
1677 //
1678 // If the FileId specified a directory then we have found
1679 // the entry. Make sure our caller wanted to open a directory.
1680 //
1681
1682 if ((TypeOfOpen == UserDirectoryOpen) &&
1684
1686 }
1687
1688 //
1689 // Lock the Vcb and create the Fcb if necessary.
1690 //
1691
1692 CdLockVcb( IrpContext, Vcb );
1693 UnlockVcb = TRUE;
1694
1695 NextFcb = CdCreateFcb( IrpContext, ParentFileId, NodeTypeCode, &Found );
1696
1697 //
1698 // It's possible that someone got in here ahead of us.
1699 //
1700
1701 if (!Found) {
1702
1703 CdInitializeFcbFromPathEntry( IrpContext,
1704 NextFcb,
1705 NULL,
1706 &CompoundPathEntry.PathEntry );
1707 }
1708
1709 //
1710 // If the user wanted to open a directory then we have found
1711 // it. Store this Fcb into the CurrentFcb and skip the
1712 // directory scan.
1713 //
1714
1716
1717 *CurrentFcb = NextFcb;
1718 NextFcb = NULL;
1719 }
1720 }
1721
1722 //
1723 // Perform the directory scan if we don't already have our target.
1724 //
1725
1726 if (NextFcb != NULL) {
1727
1728 //
1729 // Acquire the parent. We currently own the Vcb lock so
1730 // do this without waiting first.
1731 //
1732
1733 if (!CdAcquireFcbExclusive( IrpContext,
1734 NextFcb,
1735 TRUE )) {
1736
1737 NextFcb->FcbReference += 1;
1738 CdUnlockVcb( IrpContext, Vcb );
1739
1740 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
1741
1742 CdLockVcb( IrpContext, Vcb );
1743 NextFcb->FcbReference -= 1;
1744 CdUnlockVcb( IrpContext, Vcb );
1745
1746 } else {
1747
1748 CdUnlockVcb( IrpContext, Vcb );
1749 }
1750
1751 UnlockVcb = FALSE;
1752
1753 //
1754 // Set up the CurrentFcb pointers. We know there was
1755 // no previous parent in this case.
1756 //
1757
1758 *CurrentFcb = NextFcb;
1759
1760 //
1761 // Calculate the offset in the stream.
1762 //
1763
1764 StreamOffset = CdQueryFidDirentOffset( FileId );
1765
1766 //
1767 // Create the stream file if it doesn't exist. This will update
1768 // the Fcb with the size from the self entry.
1769 //
1770
1771 CdVerifyOrCreateDirStreamFile( IrpContext, NextFcb);
1772
1773 //
1774 // If our offset is beyond the end of the directory then the
1775 // FileId is invalid.
1776 //
1777
1778 if (StreamOffset > NextFcb->FileSize.LowPart) {
1779
1781 }
1782
1783 //
1784 // Otherwise position ourselves at the self entry and walk
1785 // through dirent by dirent until this location is found.
1786 //
1787
1788 CdInitializeFileContext( IrpContext, &FileContext );
1789 CdLookupInitialFileDirent( IrpContext,
1790 NextFcb,
1791 &FileContext,
1792 NextFcb->StreamOffset );
1793
1794 CleanupFileContext = TRUE;
1795
1796 while (TRUE) {
1797
1798 //
1799 // Move to the first entry of the next file.
1800 //
1801
1803 NextFcb,
1804 &FileContext );
1805
1806 //
1807 // If we didn't find the entry or are beyond it then the
1808 // input Id is invalid.
1809 //
1810
1811 if (!Found ||
1812 (FileContext.InitialDirent->Dirent.DirentOffset > StreamOffset)) {
1813
1815 }
1816 }
1817
1818 //
1819 // This better not be a directory. Directory FileIds must
1820 // refer to the self entry for directories.
1821 //
1822
1823 if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
1825
1827 }
1828
1829 //
1830 // Check that our caller wanted to open a file.
1831 //
1832
1834
1836 }
1837
1838 //
1839 // Otherwise we want to collect all of the dirents for this file
1840 // and create an Fcb with this.
1841 //
1842
1843 CdLookupLastFileDirent( IrpContext, NextFcb, &FileContext );
1844
1845 CdLockVcb( IrpContext, Vcb );
1846 UnlockVcb = TRUE;
1847
1848 NextFcb = CdCreateFcb( IrpContext, FileId, NodeTypeCode, &Found );
1849
1850 //
1851 // It's possible that someone has since created this Fcb since we
1852 // first checked. If so then can simply use this. Otherwise
1853 // we need to initialize a new Fcb and attach it to our parent
1854 // and insert it into the Fcb Table.
1855 //
1856
1857 if (!Found) {
1858
1860 NextFcb,
1861 *CurrentFcb,
1862 &FileContext );
1863 }
1864 }
1865
1866 //
1867 // We have the Fcb. Check that the type of the file is compatible with
1868 // the desired type of file to open.
1869 //
1870
1871 } else {
1872
1874
1876
1878 }
1879
1880 } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
1881
1883 }
1884 }
1885
1886 //
1887 // If we have a the previous Fcb and have inserted the next Fcb into
1888 // the Fcb Table. It is safe to release the current Fcb if present
1889 // since it is referenced through the child Fcb.
1890 //
1891
1892 if (*CurrentFcb != NULL) {
1893
1894 CdReleaseFcb( IrpContext, *CurrentFcb );
1895 }
1896
1897 //
1898 // We now know the Fcb and currently hold the Vcb lock.
1899 // Try to acquire this Fcb without waiting. Otherwise we
1900 // need to reference it, drop the Vcb, acquire the Fcb and
1901 // then dereference the Fcb.
1902 //
1903
1904 if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
1905
1906 NextFcb->FcbReference += 1;
1907
1908 CdUnlockVcb( IrpContext, Vcb );
1909
1910 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
1911
1912 CdLockVcb( IrpContext, Vcb );
1913 NextFcb->FcbReference -= 1;
1914 CdUnlockVcb( IrpContext, Vcb );
1915
1916 } else {
1917
1918 CdUnlockVcb( IrpContext, Vcb );
1919 }
1920
1921 UnlockVcb = FALSE;
1922
1923 //
1924 // Move to this Fcb.
1925 //
1926
1927 *CurrentFcb = NextFcb;
1928
1929 // Lock object is acquired using internal state
1931
1932 //
1933 // Check the requested access on this Fcb.
1934 //
1935
1936 if (!CdIllegalFcbAccess( IrpContext,
1937 TypeOfOpen,
1938 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
1939
1940 //
1941 // Call our worker routine to complete the open.
1942 //
1943
1944 Status = CdCompleteFcbOpen( IrpContext,
1945 IrpSp,
1946 Vcb,
1947 CurrentFcb,
1948 TypeOfOpen,
1950 IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
1951
1952 }
1953
1954 try_exit: NOTHING;
1955 } _SEH2_FINALLY {
1956
1957 if (UnlockVcb) {
1958
1959 CdUnlockVcb( IrpContext, Vcb );
1960 }
1961
1962 if (CleanupFileContext) {
1963
1964 CdCleanupFileContext( IrpContext, &FileContext );
1965 }
1966
1967 if (CleanupCompoundPathEntry) {
1968
1970 }
1971 } _SEH2_END;
1972
1973 return Status;
1974}
#define PAGED_CODE()
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
#define CD_ATTRIBUTE_DIRECTORY
Definition: cd.h:354
return Found
Definition: dirsup.c:1270
#define CdIllegalFcbAccess(IC, T, DA)
Definition: cdprocs.h:135
static INLINE VOID CdVerifyOrCreateDirStreamFile(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb)
Definition: cdprocs.h:242
VOID CdInitializeFcbFromFileContext(_In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB Fcb, _In_ PFCB ParentFcb, _In_ PFILE_ENUM_CONTEXT FileContext)
Definition: strucsup.c:1225
BOOLEAN CdLookupNextPathEntry(_In_ PIRP_CONTEXT IrpContext, _Inout_ PPATH_ENUM_CONTEXT PathContext, _Inout_ PPATH_ENTRY PathEntry)
Definition: pathsup.c:207
#define CdInitializeCompoundPathEntry(IC, CP)
Definition: cdprocs.h:763
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:589
_In_ PFCB _In_ PCD_NAME _In_ BOOLEAN _Inout_ PCOMPOUND_PATH_ENTRY CompoundPathEntry
Definition: cdprocs.h:740
#define CdReleaseFcb(IC, F)
Definition: cdprocs.h:1012
VOID CdLookupLastFileDirent(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb, _In_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1426
@ UserDirectoryOpen
Definition: cdprocs.h:576
@ UserFileOpen
Definition: cdprocs.h:577
#define CdLockVcb(IC, V)
Definition: cdprocs.h:1023
PFCB CdLookupFcbTable(_In_ PIRP_CONTEXT IrpContext, _In_ PVCB Vcb, _In_ FILE_ID FileId)
Definition: strucsup.c:2107
#define CdInitializeFileContext(IC, FC)
Definition: cdprocs.h:527
_In_ PFCB _In_ PCD_NAME _In_ BOOLEAN _Inout_ PFILE_ENUM_CONTEXT FileContext
Definition: cdprocs.h:442
VOID CdInitializeFcbFromPathEntry(_In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB Fcb, _In_opt_ PFCB ParentFcb, _In_ PPATH_ENTRY PathEntry)
Definition: strucsup.c:1136
#define CdUnlockVcb(IC, V)
Definition: cdprocs.h:1028
#define CdLookupInitialFileDirent(IC, F, FC, DO)
Definition: cdprocs.h:551
BOOLEAN CdLookupNextInitialFileDirent(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb, _Inout_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1275
#define CdCleanupCompoundPathEntry(IC, CP)
Definition: cdprocs.h:766
#define CdAcquireFcbExclusive(IC, F, I)
Definition: cdprocs.h:1006
PFCB CdCreateFcb(_In_ PIRP_CONTEXT IrpContext, _In_ FILE_ID FileId, _In_ NODE_TYPE_CODE NodeTypeCode, _Out_opt_ PBOOLEAN FcbExisted)
Definition: strucsup.c:986
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Inout_ PFCB * CurrentFcb
Definition: cdprocs.h:801
#define try_return(S)
Definition: cdprocs.h:2179
VOID CdLookupPathEntry(_In_ PIRP_CONTEXT IrpContext, _In_ ULONG PathEntryOffset, _In_ ULONG Ordinal, _In_ BOOLEAN VerifyBounds, _Inout_ PCOMPOUND_PATH_ENTRY CompoundPathEntry)
VOID CdCleanupFileContext(_In_ PIRP_CONTEXT IrpContext, _In_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1636
#define CdFidIsDirectory(I)
Definition: cdstruc.h:1835
#define CdQueryFidDirentOffset(I)
Definition: cdstruc.h:1831
#define CCB_FLAG_OPEN_BY_ID
Definition: cdstruc.h:1103
#define CdSetFidDirentOffset(I, D)
Definition: cdstruc.h:1833
#define CdFidSetDirectory(I)
Definition: cdstruc.h:1836
#define CdQueryFidPathTableOffset(I)
Definition: cdstruc.h:1832
#define CdSetFidPathTableOffset(I, P)
Definition: cdstruc.h:1834
#define _Analysis_suppress_lock_checking_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
USHORT NODE_TYPE_CODE
Definition: nodetype.h:22
#define CDFS_NTC_FCB_INDEX
Definition: nodetype.h:30
#define CDFS_NTC_FCB_DATA
Definition: nodetype.h:31
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
Status
Definition: gdiplustypes.h:25
#define NOTHING
Definition: input_list.c:10
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define Vcb
Definition: cdprocs.h:1415
#define _SEH2_FINALLY
Definition: pseh2_64.h:114
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
Definition: cdstruc.h:1525
ERESOURCE FcbResource
Definition: cdstruc.h:879
Definition: cdstruc.h:902
ULONG FileAttributes
Definition: cdstruc.h:977
__volatile LONG FcbReference
Definition: cdstruc.h:964
PFCB_NONPAGED FcbNonpaged
Definition: cdstruc.h:1003
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
union _IO_STACK_LOCATION::@1579 Parameters
struct _IO_STACK_LOCATION::@3978::@3979 Create
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_FILE_IS_A_DIRECTORY
Definition: udferr_usr.h:164
#define STATUS_NOT_A_DIRECTORY
Definition: udferr_usr.h:169
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135

◆ _When_()

_When_ ( RelatedTypeOfOpen !  = UnopenedFileObject,
_At_(RelatedCcb, _In_  
)

Definition at line 29 of file create.c.

123 :26165, "Esp:1153")
124#endif
125CdCommonCreate (
126 _Inout_ PIRP_CONTEXT IrpContext,
128 )
129
130/*++
131
132Routine Description:
133
134 This is the common routine for opening a file called by both the
135 Fsp and Fsd threads.
136
137 The file can be opened either by name or by file Id either with or without
138 a relative name. The file name field in the file object passed to this routine
139 contains either a unicode string or a 64 bit value which is the file Id.
140 If this is not a Joliet disk then we will convert the unicode name to
141 an Oem string in this routine. If there is a related file object with
142 a name then we will already have converted that name to Oem.
143
144 We will store the full name for the file in the file object on a successful
145 open. We will allocate a larger buffer if necessary and combine the
146 related and file object names. The only exception is the relative open
147 when the related file object is for an OpenByFileId file. If we need to
148 allocate a buffer for a case insensitive name then we allocate it at
149 the tail of the buffer we will store into the file object. The upcased
150 portion will begin immediately after the name defined by the FileName
151 in the file object.
152
153 Once we have the full name in the file object we don't want to split the
154 name in the event of a retry. We use a flag in the IrpContext to indicate
155 that the name has been split.
156
157Arguments:
158
159 Irp - Supplies the Irp to process
160
161Return Value:
162
163 NTSTATUS - This is the status from this open operation.
164
165--*/
166
167{
170
172
173 COMPOUND_PATH_ENTRY CompoundPathEntry = {{0}};/* ReactOS Change: GCC "missing braces around initializer" */
174 BOOLEAN CleanupCompoundPathEntry = FALSE;
175
177 BOOLEAN CleanupFileContext = FALSE;
178 BOOLEAN FoundEntry;
179
180 PVCB Vcb;
181
185
186 BOOLEAN ShortNameMatch;
188
189 BOOLEAN VolumeOpen = FALSE;
190
191 //
192 // We will be acquiring and releasing file Fcb's as we move down the
193 // directory tree during opens. At any time we need to know the deepest
194 // point we have traversed down in the tree in case we need to cleanup
195 // any structures created here.
196 //
197 // CurrentFcb - represents this point. If non-null it means we have
198 // acquired it and need to release it in finally clause.
199 //
200 // NextFcb - represents the NextFcb to walk to but haven't acquired yet.
201 //
202
203 TYPE_OF_OPEN RelatedTypeOfOpen = UnopenedFileObject;
204 PFILE_OBJECT RelatedFileObject;
205 PCCB RelatedCcb = NULL;
206
207 PFCB NextFcb;
209
210 //
211 // During the open we need to combine the related file object name
212 // with the remaining name. We also may need to upcase the file name
213 // in order to do a case-insensitive name comparison. We also need
214 // to restore the name in the file object in the event that we retry
215 // the request. We use the following string variables to manage the
216 // name. We will can put these strings into either Unicode or Ansi
217 // form.
218 //
219 // FileName - Pointer to name as currently stored in the file
220 // object. We store the full name into the file object early in
221 // the open operation.
222 //
223 // RelatedFileName - Pointer to the name in the related file object.
224 //
225 // RemainingName - String containing remaining name to parse.
226 //
227 // MatchingName - Address of name structure in FileContext which matched.
228 // We need this to know whether we matched the long or short name.
229 //
230
232 PUNICODE_STRING RelatedFileName = NULL;
233
234 CD_NAME RemainingName = {{0}};/* ReactOS Change: GCC "missing braces around initializer" */
235 CD_NAME FinalName;
237
238 PAGED_CODE();
239
240 //
241 // If we were called with our file system device object instead of a
242 // volume device object, just complete this request with STATUS_SUCCESS.
243 //
244
245 if (IrpContext->Vcb == NULL) {
246
247 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
248 return STATUS_SUCCESS;
249 }
250
251 //
252 // Get create parameters from the Irp.
253 //
254
257 CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
258
259 //
260 // Do some preliminary checks to make sure the operation is supported.
261 // We fail in the following cases immediately.
262 //
263 // - Open a paging file.
264 // - Open a target directory.
265 // - Open a file with Eas.
266 // - Create a file.
267 //
268
270 (IrpSp->Parameters.Create.EaLength != 0) ||
272
275 }
276
277#if (NTDDI_VERSION >= NTDDI_WIN7)
278 //
279 // CDFS does not support FILE_OPEN_REQUIRING_OPLOCK
280 //
281
283
286 }
287#endif
288
289 //
290 // Copy the Vcb to a local. Assume the starting directory is the root.
291 //
292
293 Vcb = IrpContext->Vcb;
294 NextFcb = Vcb->RootIndexFcb;
295
296 //
297 // Reference our input parameters to make things easier
298 //
299
301 RelatedFileObject = NULL;
302
303 FileName = &FileObject->FileName;
304
305 //
306 // Set up the file object's Vpb pointer in case anything happens.
307 // This will allow us to get a reasonable pop-up.
308 //
309
310 if ((FileObject->RelatedFileObject != NULL) && !OpenByFileId) {
311
312 RelatedFileObject = FileObject->RelatedFileObject;
313 FileObject->Vpb = RelatedFileObject->Vpb;
314
315 RelatedTypeOfOpen = CdDecodeFileObject( IrpContext, RelatedFileObject, &NextFcb, &RelatedCcb );
316
317 //
318 // Fail the request if this is not a user file object.
319 //
320
321 if (RelatedTypeOfOpen < UserVolumeOpen) {
322
325 }
326
327 //
328 // Remember the name in the related file object.
329 //
330
331 RelatedFileName = &RelatedFileObject->FileName;
332 }
333
334 //
335 // If we haven't initialized the names then make sure the strings are valid.
336 // If this an OpenByFileId then verify the file id buffer.
337 //
338 // After this routine returns we know that the full name is in the
339 // FileName buffer and the buffer will hold the upcased portion
340 // of the name yet to parse immediately after the full name in the
341 // buffer. Any trailing backslash has been removed and the flag
342 // in the IrpContext will indicate whether we removed the
343 // backslash.
344 //
345
346 Status = CdNormalizeFileNames( IrpContext,
347 Vcb,
350 RelatedTypeOfOpen,
351 RelatedCcb,
352 RelatedFileName,
353 FileName,
354 &RemainingName );
355
356 //
357 // Return the error code if not successful.
358 //
359
360 if (!NT_SUCCESS( Status )) {
361
362 CdCompleteRequest( IrpContext, Irp, Status );
363 return Status;
364 }
365
366 //
367 // We want to acquire the Vcb. Exclusively for a volume open, shared otherwise.
368 // The file name is empty for a volume open.
369 //
370
371 if ((FileName->Length == 0) &&
372 (RelatedTypeOfOpen <= UserVolumeOpen) &&
373 !OpenByFileId) {
374
375 VolumeOpen = TRUE;
376 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
377
378 } else {
379
380 CdAcquireVcbShared( IrpContext, Vcb, FALSE );
381 }
382
383 //
384 // Use a try-finally to facilitate cleanup.
385 //
386
387 _SEH2_TRY {
388
389 //
390 // Verify that the Vcb is not in an unusable condition. This routine
391 // will raise if not usable.
392 //
393
394 CdVerifyVcb( IrpContext, Vcb );
395
396 //
397 // If the Vcb is locked then we cannot open another file
398 //
399
400 if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
401
403 }
404
405 //
406 // If we are opening this file by FileId then process this immediately
407 // and exit.
408 //
409
410 if (OpenByFileId) {
411
412 //
413 // We only allow Dasd opens of audio disks. Fail this request at
414 // this point.
415 //
416
417 if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
418
420 }
421
422 //
423 // The only create disposition we allow is OPEN.
424 //
425
426 if ((CreateDisposition != FILE_OPEN) &&
428
430 }
431
432 //
433 // Make sure we can wait for this request.
434 //
435
436 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
437
438 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
439 }
440
441 try_return( Status = CdOpenByFileId( IrpContext,
442 IrpSp,
443 Vcb,
444 &CurrentFcb ));
445 }
446
447 //
448 // If we are opening this volume Dasd then process this immediately
449 // and exit.
450 //
451
452 if (VolumeOpen) {
453
454 //
455 // The only create disposition we allow is OPEN.
456 //
457
458 if ((CreateDisposition != FILE_OPEN) &&
460
462 }
463
464 //
465 // If they wanted to open a directory, surprise.
466 //
467
469
471 }
472
473 //
474 // Acquire the Fcb first.
475 //
476
477 CurrentFcb = Vcb->VolumeDasdFcb;
478 CdAcquireFcbExclusive( IrpContext, CurrentFcb, FALSE );
479
480 try_return( Status = CdOpenExistingFcb( IrpContext,
481 IrpSp,
482 &CurrentFcb,
484 FALSE,
485 NULL ));
486 }
487
488 //
489 // At this point CurrentFcb points to the deepest Fcb for this open
490 // in the tree. Let's acquire this Fcb to keep it from being deleted
491 // beneath us.
492 //
493
494 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
495 CurrentFcb = NextFcb;
496
497 //
498 // Do a prefix search if there is more of the name to parse.
499 //
500
501 if (RemainingName.FileName.Length != 0) {
502
503 //
504 // Do the prefix search to find the longest matching name.
505 //
506
507 CdFindPrefix( IrpContext,
508 &CurrentFcb,
509 &RemainingName.FileName,
510 IgnoreCase );
511 }
512
513 //
514 // If the remaining name length is zero then we have found our
515 // target.
516 //
517
518 if (RemainingName.FileName.Length == 0) {
519
520 //
521 // If this is a file so verify the user didn't want to open
522 // a directory.
523 //
524
526
527 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
529
531 }
532
533 //
534 // The only create disposition we allow is OPEN.
535 //
536
537 if ((CreateDisposition != FILE_OPEN) &&
539
541 }
542
543 try_return( Status = CdOpenExistingFcb( IrpContext,
544 IrpSp,
545 &CurrentFcb,
548 RelatedCcb ));
549
550 //
551 // This is a directory. Verify the user didn't want to open
552 // as a file.
553 //
554
555 } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
556
558
559 //
560 // Open the file as a directory.
561 //
562
563 } else {
564
565 //
566 // The only create disposition we allow is OPEN.
567 //
568
569 if ((CreateDisposition != FILE_OPEN) &&
571
573 }
574
575 try_return( Status = CdOpenExistingFcb( IrpContext,
576 IrpSp,
577 &CurrentFcb,
580 RelatedCcb ));
581 }
582 }
583
584 //
585 // We have more work to do. We have a starting Fcb which we own shared.
586 // We also have the remaining name to parse. Walk through the name
587 // component by component looking for the full name.
588 //
589
590 //
591 // Our starting Fcb better be a directory.
592 //
593
595
597 }
598
599 //
600 // If we can't wait then post this request.
601 //
602
603 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
604
605 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
606 }
607
608 //
609 // Make sure the final name has no version string.
610 //
611
612 FinalName.VersionString.Length = 0;
613
614 while (TRUE) {
615
616 ShortNameMatch = FALSE;
617
618 //
619 // Split off the next component from the name.
620 //
621
622 CdDissectName( IrpContext,
623 &RemainingName.FileName,
624 &FinalName.FileName );
625
626 //
627 // Go ahead and look this entry up in the path table.
628 //
629
631 CleanupCompoundPathEntry = TRUE;
632
633 FoundEntry = CdFindPathEntry( IrpContext,
635 &FinalName,
638
639 //
640 // If we didn't find the entry then check if the current name
641 // is a possible short name.
642 //
643
644 if (!FoundEntry) {
645
646 ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &FinalName.FileName );
647
648 //
649 // If there is an embedded short name offset then look for the
650 // matching long name in the directory.
651 //
652
654
655 if (CleanupFileContext) {
656
657 CdCleanupFileContext( IrpContext, &FileContext );
658 }
659
660 CdInitializeFileContext( IrpContext, &FileContext );
661 CleanupFileContext = TRUE;
662
663 FoundEntry = CdFindFileByShortName( IrpContext,
665 &FinalName,
668 &FileContext );
669
670 //
671 // If we found an entry and it is a directory then look
672 // this up in the path table.
673 //
674
675 if (FoundEntry) {
676
677 ShortNameMatch = TRUE;
678
679 if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
681
684
685 FoundEntry = CdFindPathEntry( IrpContext,
687 &FileContext.InitialDirent->Dirent.CdCaseFileName,
690
691 //
692 // We better find this entry.
693 //
694
695 if (!FoundEntry) {
696
698 }
699
700 //
701 // Upcase the name with the short name if case
702 // insensitive.
703 //
704
705 if (IgnoreCase) {
706
707 CdUpcaseName( IrpContext, &FinalName, &FinalName );
708 }
709
710 //
711 // We found a matching file. If we are at the last
712 // entry then break out of the loop and open the
713 // file below. Otherwise we return an error.
714 //
715
716 } else if (RemainingName.FileName.Length == 0) {
717
718 //
719 // Break out of the loop. We will process the dirent
720 // below.
721 //
722
724 break;
725
726 } else {
727
729 }
730 }
731 }
732
733 //
734 // We didn't find the name in either the path table or as
735 // a short name in a directory. If the remaining name
736 // length is zero then break out of the loop to search
737 // the directory.
738 //
739
740 if (!FoundEntry) {
741
742 if (RemainingName.FileName.Length == 0) {
743
744 break;
745
746 //
747 // Otherwise this path could not be cracked.
748 //
749
750 } else {
751
753 }
754 }
755 }
756
757 //
758 // If this is an ignore case open then copy the exact case
759 // in the file object name. If it was a short name match then
760 // the name must be upcase already.
761 //
762
763 if (IgnoreCase && !ShortNameMatch) {
764
765 RtlCopyMemory( FinalName.FileName.Buffer,
766 CompoundPathEntry.PathEntry.CdDirName.FileName.Buffer,
767 CompoundPathEntry.PathEntry.CdDirName.FileName.Length );
768 }
769
770 //
771 // If we have found the last component then open this as a directory
772 // and return to our caller.
773 //
774
775 if (RemainingName.FileName.Length == 0) {
776
778
780 }
781
782 //
783 // The only create disposition we allow is OPEN.
784 //
785
786 if ((CreateDisposition != FILE_OPEN) &&
788
790 }
791
792 try_return( Status = CdOpenDirectoryFromPathEntry( IrpContext,
793 IrpSp,
794 Vcb,
795 &CurrentFcb,
796 &FinalName,
798 ShortNameMatch,
799 &CompoundPathEntry.PathEntry,
800 TRUE,
801 RelatedCcb ));
802 }
803
804 //
805 // Otherwise open an Fcb for this intermediate index Fcb.
806 //
807
808 CdOpenDirectoryFromPathEntry( IrpContext,
809 IrpSp,
810 Vcb,
811 &CurrentFcb,
812 &FinalName,
814 ShortNameMatch,
815 &CompoundPathEntry.PathEntry,
816 FALSE,
817 NULL );
818
820 CleanupCompoundPathEntry = FALSE;
821 }
822
823 //
824 // We need to scan the current directory for a matching file name
825 // if we don't already have one.
826 //
827
828 if (!FoundEntry) {
829
830 if (CleanupFileContext) {
831
832 CdCleanupFileContext( IrpContext, &FileContext );
833 }
834
835 CdInitializeFileContext( IrpContext, &FileContext );
836 CleanupFileContext = TRUE;
837
838 //
839 // Split our search name into separate components.
840 //
841
842 CdConvertNameToCdName( IrpContext, &FinalName );
843
844 FoundEntry = CdFindFile( IrpContext,
846 &FinalName,
849 &MatchingName );
850 }
851
852 //
853 // If we didn't find a match then check if the name is invalid to
854 // determine which error code to return.
855 //
856
857 if (!FoundEntry) {
858
859 if ((CreateDisposition == FILE_OPEN) ||
861
863 }
864
865 //
866 // Any other operation return STATUS_ACCESS_DENIED.
867 //
868
870 }
871
872 //
873 // If this is a directory then the disk is corrupt because it wasn't
874 // in the Path Table.
875 //
876
877 if (FlagOn( FileContext.InitialDirent->Dirent.Flags, CD_ATTRIBUTE_DIRECTORY )) {
878
880 }
881
882 //
883 // Make sure our opener didn't want a directory.
884 //
885
886 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
888
890 }
891
892 //
893 // The only create disposition we allow is OPEN.
894 //
895
896 if ((CreateDisposition != FILE_OPEN) &&
898
900 }
901
902 //
903 // If this is an ignore case open then copy the exact case
904 // in the file object name. Any version portion should
905 // already be upcased.
906 //
907
908 if (IgnoreCase) {
909
910 RtlCopyMemory( FinalName.FileName.Buffer,
911 MatchingName->FileName.Buffer,
912 MatchingName->FileName.Length );
913 }
914
915 //
916 // Open the file using the file context. We already have the
917 // first and last dirents.
918 //
919
920 try_return( Status = CdOpenFileFromFileContext( IrpContext,
921 IrpSp,
922 Vcb,
923 &CurrentFcb,
924 &FinalName,
928 RelatedCcb ));
929
930 try_exit: NOTHING;
931 } _SEH2_FINALLY {
932
933 //
934 // Cleanup the PathEntry if initialized.
935 //
936
937 if (CleanupCompoundPathEntry) {
938
940 }
941
942 //
943 // Cleanup the FileContext if initialized.
944 //
945
946 if (CleanupFileContext) {
947
948 CdCleanupFileContext( IrpContext, &FileContext );
949 }
950
951 //
952 // The result of this open could be success, pending or some error
953 // condition.
954 //
955
957
958
959 //
960 // In the error path we start by calling our teardown routine if we
961 // have a CurrentFcb and its not the volume Dasd Fcb.
962 //
963
964 if ((CurrentFcb != NULL) &&
965 (CurrentFcb != Vcb->VolumeDasdFcb)) {
966
967 BOOLEAN RemovedFcb;
968
969 CdTeardownStructures( IrpContext, CurrentFcb, &RemovedFcb );
970
971 if (RemovedFcb) {
972
974 }
975 }
976
977 //
978 // No need to complete the request.
979 //
980
981 IrpContext = NULL;
982 Irp = NULL;
983
984 //
985 // If we posted this request through the oplock package we need
986 // to show that there is no reason to complete the request.
987 //
988
989 } else if (Status == STATUS_PENDING) {
990
991 IrpContext = NULL;
992 Irp = NULL;
993 }
994
995 //
996 // Release the Current Fcb if still acquired.
997 //
998
999 if (CurrentFcb != NULL) {
1001 CdReleaseFcb( IrpContext, CurrentFcb );
1002 }
1003
1004 //
1005 // Release the Vcb.
1006 //
1007
1008 CdReleaseVcb( IrpContext, Vcb );
1009
1010 //
1011 // Call our completion routine. It will handle the case where either
1012 // the Irp and/or IrpContext are gone.
1013 //
1014
1015 CdCompleteRequest( IrpContext, Irp, Status );
1016 } _SEH2_END;
1017
1018 return Status;
1019}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
VOID CdCompleteRequest(_Inout_opt_ PIRP_CONTEXT IrpContext, _Inout_opt_ PIRP Irp, _In_ NTSTATUS Status)
Definition: cddata.c:914
VOID CdDissectName(_In_ PIRP_CONTEXT IrpContext, _Inout_ PUNICODE_STRING RemainingName, _Out_ PUNICODE_STRING FinalName)
Definition: namesup.c:301
#define CdReleaseVcb(IC, V)
Definition: cdprocs.h:985
_In_ PFCB _In_ PCD_NAME _In_ BOOLEAN _Inout_ PFILE_ENUM_CONTEXT _Out_ PCD_NAME * MatchingName
Definition: cdprocs.h:444
VOID CdVerifyVcb(_In_ PIRP_CONTEXT IrpContext, _Inout_ PVCB Vcb)
Definition: verfysup.c:411
@ UnopenedFileObject
Definition: cdprocs.h:573
@ UserVolumeOpen
Definition: cdprocs.h:575
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:802
VOID CdUpcaseName(_In_ PIRP_CONTEXT IrpContext, _In_ PCD_NAME Name, _Inout_ PCD_NAME UpcaseName)
Definition: namesup.c:194
#define CdAcquireVcbShared(IC, V, I)
Definition: cdprocs.h:982
#define CdAcquireVcbExclusive(IC, V, I)
Definition: cdprocs.h:979
ULONG CdShortNameDirentOffset(_In_ PIRP_CONTEXT IrpContext, _In_ PUNICODE_STRING Name)
Definition: namesup.c:955
_In_ PFCB _In_ PCD_NAME _In_ BOOLEAN _In_ ULONG ShortNameDirentOffset
Definition: cdprocs.h:462
#define CdRaiseStatus(IC, S)
Definition: cdprocs.h:1859
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1215
#define VCB_STATE_AUDIO_DISK
Definition: cdstruc.h:712
#define VCB_STATE_LOCKED
Definition: cdstruc.h:709
#define IRP_CONTEXT_FLAG_TRAIL_BACKSLASH
Definition: cdstruc.h:1230
#define _Analysis_assume_lock_held_(lock)
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define IgnoreCase
Definition: cdprocs.h:461
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define SafeNodeType(Ptr)
Definition: nodetype.h:54
#define OpenByFileId
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
struct _FileName FileName
Definition: fatprocs.h:897
#define FILE_OPEN_BY_FILE_ID
Definition: from_kernel.h:41
#define FILE_OPEN
Definition: from_kernel.h:54
#define FILE_CREATE
Definition: from_kernel.h:55
#define FILE_OVERWRITE
Definition: from_kernel.h:57
#define FILE_OPEN_IF
Definition: from_kernel.h:56
#define FILE_OPEN_REQUIRING_OPLOCK
Definition: winternl.h:186
#define _Inout_
Definition: no_sal2.h:162
#define STATUS_CANT_WAIT
Definition: ntstatus.h:452
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:166
#define STATUS_SUCCESS
Definition: shellext.h:65
Definition: cdstruc.h:1067
UNICODE_STRING VersionString
Definition: cdstruc.h:250
UNICODE_STRING FileName
Definition: cdstruc.h:244
ULONG Flags
Definition: ntfs.h:536
FILE_NAME_NODE ShortName
Definition: fatstruc.h:1115
Definition: cdstruc.h:498
#define MAXULONG
Definition: typedefs.h:251
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define STATUS_DISK_CORRUPT_ERROR
Definition: udferr_usr.h:147
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_Must_inspect_result_ _In_opt_ WDFKEY _In_ PCUNICODE_STRING _In_ ACCESS_MASK _In_ ULONG _Out_opt_ PULONG CreateDisposition
Definition: wdfregistry.h:120
#define SL_OPEN_PAGING_FILE
Definition: iotypes.h:1817
* PFILE_OBJECT
Definition: iotypes.h:1998
#define SL_OPEN_TARGET_DIRECTORY
Definition: iotypes.h:1818
#define SL_CASE_SENSITIVE
Definition: iotypes.h:1820