source: trunk/Utilities/Junctions/Module.h @ 350

Last change on this file since 350 was 350, checked in by roman, 7 years ago
File size: 8.6 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2013
3// Created by Roman Ryltsov roman@alax.info
4
5#pragma once
6
7#include "reparse.h"
8#include "roinifile.h"
9
10////////////////////////////////////////////////////////////
11// CModule
12
13class CModule :
14        public CAtlExeModuleT<CModule>
15{
16public:
17
18        ////////////////////////////////////////////////////////
19        // CReparsePointData
20
21        class CReparsePointData
22        {
23        public:
24                REPARSE_GUID_DATA_BUFFER m_ReparseGuidDataBufferHeader;
25                REPARSE_DATA_BUFFER m_ReparseDataBufferHeader;
26                CStringW m_sPrintName;
27                CStringW m_sSubstituteName;
28
29                static CStringW StringFromCharacters(const WCHAR* pszCharacters, SIZE_T nLength)
30                {
31                        CStringW sString;
32                        if(nLength)
33                        {
34                                _A(pszCharacters);
35                                memcpy(sString.GetBufferSetLength((INT) nLength), pszCharacters, nLength * sizeof *pszCharacters);
36                        }
37                        return sString;
38                }
39                VOID Clear()
40                {
41                        ZeroMemory(&m_ReparseGuidDataBufferHeader, sizeof m_ReparseGuidDataBufferHeader);
42                        ZeroMemory(&m_ReparseDataBufferHeader, sizeof m_ReparseDataBufferHeader);
43                        m_sPrintName.Empty();
44                        m_sSubstituteName.Empty();
45                }
46
47        public:
48        // CReparsePointData
49                CReparsePointData()
50                {
51                        Clear();
52                }
53                CReparsePointData(const CPath& sPath)
54                {
55                        Initialize(sPath);
56                }
57                VOID Initialize(const CPath& sPath)
58                {
59                        Clear();
60                        _ATLTRY
61                        {
62                                CAtlFile Directory;
63                                HRESULT nCreateResult = Directory.Create(sPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
64                                if(FAILED(nCreateResult))
65                                {
66                                        _Z4(atlTraceGeneral, 4, _T("nCreateResult 0x%08x\n"), nCreateResult);
67                                        return;
68                                }
69                                BYTE pnReparseBuffer[MAX_REPARSE_SIZE];
70                                REPARSE_GUID_DATA_BUFFER* pReparseGuidDataBuffer = (REPARSE_GUID_DATA_BUFFER*) pnReparseBuffer;
71                                DWORD nReturnedLength;
72                                if(!DeviceIoControl(Directory, FSCTL_GET_REPARSE_POINT, NULL, 0, pReparseGuidDataBuffer, sizeof pnReparseBuffer, &nReturnedLength, NULL))
73                                {
74                                        HRESULT nResult = HRESULT_FROM_WIN32(GetLastError());
75                                        _Z4(atlTraceGeneral, 4, _T("nCreateResult 0x%08x\n"), nResult);
76                                        return;
77                                }
78                                m_ReparseGuidDataBufferHeader = *pReparseGuidDataBuffer;
79                                _Z4(atlTraceGeneral, 4, _T("ReparseTag 0x%08x\n"), pReparseGuidDataBuffer->ReparseTag);
80                                if(IsReparseTagMicrosoft(pReparseGuidDataBuffer->ReparseTag))
81                                {
82                                        switch(pReparseGuidDataBuffer->ReparseTag & 0xFFFFFFFF)
83                                        {
84                                        case IO_REPARSE_TAG_SYMBOLIC_LINK:
85                                                {
86                                                        REPARSE_DATA_BUFFER* pReparseDataBuffer = (REPARSE_DATA_BUFFER*) pReparseGuidDataBuffer;
87                                                        m_ReparseDataBufferHeader = *pReparseDataBuffer;
88                                                        CStringW sPrintName = StringFromCharacters((PWCHAR) ((BYTE*) pReparseDataBuffer->SymbolicLinkReparseBuffer.PathBuffer + pReparseDataBuffer->SymbolicLinkReparseBuffer.PrintNameOffset), pReparseDataBuffer->SymbolicLinkReparseBuffer.PrintNameLength);
89                                                        CStringW sSubstituteName = StringFromCharacters((PWCHAR) ((BYTE*) pReparseDataBuffer->SymbolicLinkReparseBuffer.PathBuffer + pReparseDataBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset), pReparseDataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength);
90                                                        _Z4(atlTraceGeneral, 4, _T("sPrintName \"%ls\", sSubstituteName \"%ls\"\n"), sPrintName, sSubstituteName);
91                                                        m_sPrintName = sPrintName;
92                                                        m_sSubstituteName = sSubstituteName;
93                                                }
94                                                break;
95                                        case IO_REPARSE_TAG_MOUNT_POINT:
96                                                {
97                                                        REPARSE_DATA_BUFFER* pReparseDataBuffer = (REPARSE_DATA_BUFFER*) pReparseGuidDataBuffer;
98                                                        m_ReparseDataBufferHeader = *pReparseDataBuffer;
99                                                        CStringW sPrintName = StringFromCharacters((PWCHAR) ((BYTE*) pReparseDataBuffer->SymbolicLinkReparseBuffer.PathBuffer + pReparseDataBuffer->SymbolicLinkReparseBuffer.PrintNameOffset), pReparseDataBuffer->SymbolicLinkReparseBuffer.PrintNameLength);
100                                                        CStringW sSubstituteName = StringFromCharacters((PWCHAR) ((BYTE*) pReparseDataBuffer->SymbolicLinkReparseBuffer.PathBuffer + pReparseDataBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset), pReparseDataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength);
101                                                        _Z4(atlTraceGeneral, 4, _T("sPrintName \"%ls\", sSubstituteName \"%ls\"\n"), sPrintName, sSubstituteName);
102                                                        // NOTE: According to Mark, junctions contain ':' unlike mount points
103                                                        m_sPrintName = sPrintName;
104                                                        m_sSubstituteName = sSubstituteName;
105                                                }
106                                                break;
107                                        //case IO_REPARSE_TAG_HSM:
108                                        //case IO_REPARSE_TAG_SIS:
109                                        //case IO_REPARSE_TAG_DFS:
110                                        }
111                                }
112                        }
113                        _ATLCATCHALL()
114                        {
115                                _Z1(atlTraceGeneral, 1, _T("An exception has been caught\n"));
116                        }
117                }
118                CStringW GetFriendlySubstituteName() const
119                {
120                        CStringW sSubstituteName = m_sSubstituteName;
121                        if(sSubstituteName.Left(4) == L"\\??\\")
122                                sSubstituteName.Delete(0, 4);
123                        return sSubstituteName;
124                }
125        };
126
127public:
128        //CPath m_sIniFilePath;
129        //CObjectPtr<CIniFile::CSection> m_pSection;
130        CPath m_sPath;
131        UINT m_nDirectoryCount;
132        UINT m_nReparsePointCount;
133
134public:
135// CModule
136        CModule()
137        {
138                AtlTraceSetDefaultSettings();
139                _Z4_THIS();
140                _W(CExceptionFilter::Initialize());
141        }
142        ~CModule()
143        {
144                _Z4_THIS();
145                CExceptionFilter::Terminate();
146        }
147        HRESULT PreMessageLoop(INT nShowCommand)
148        {
149                const HRESULT nResult = __super::PreMessageLoop(nShowCommand);
150                return SUCCEEDED(nResult) ? S_OK : nResult;
151        }
152        BOOL Syntax()
153        {
154                _tprintf(_T("Syntax: Junctions <path>\n"));
155                return FALSE;
156        }
157        BOOL ParseCommandLineEx(SIZE_T argc, TCHAR* argv[])
158        {
159                for(SIZE_T nIndex = 1; nIndex < argc; nIndex++)
160                {
161                        CString sArgument = argv[nIndex];
162                        _A(!sArgument.IsEmpty());
163                        #pragma region Switches
164                        if(_tcschr(_T("-/"), sArgument[0]))
165                        {
166                                sArgument.Delete(0);
167                                #pragma region Switch Value/Specification
168                                const INT nSeparatorPosition = sArgument.Find(_T(':'));
169                                CString sArgumentValue;
170                                BOOL bIntegerArgumentValueValid = FALSE;
171                                INT nIntegerArgumentValue = 0;
172                                if(nSeparatorPosition > 0)
173                                {
174                                        sArgumentValue = sArgument.Mid(nSeparatorPosition + 1);
175                                        sArgument = sArgument.Left(nSeparatorPosition);
176                                        if(!sArgumentValue.IsEmpty())
177                                                bIntegerArgumentValueValid =  AtlStringToInteger(sArgumentValue, nIntegerArgumentValue);
178                                }
179                                #pragma endregion
180/*
181                                if(sArgument.CompareNoCase(_T("f")) == 0) // Flavor
182                                {
183                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
184                                        m_nFlavor = (UINT) nIntegerArgumentValue;
185                                        m_bFlavorAvailable = TRUE;
186                                        continue;
187                                }
188                                if(sArgument.CompareNoCase(_T("fl")) == 0) // Flavor List
189                                {
190                                        m_bListFlavors = TRUE;
191                                        continue;
192                                }
193*/
194                        }
195                        #pragma endregion
196                        #pragma region Non-switch
197                        if(sArgument.GetLength() >= 2 && sArgument[0] == _T('"') && sArgument[sArgument.GetLength() - 1] == _T('"'))
198                                sArgument = sArgument.Mid(1, sArgument.GetLength() - 2);
199                        if(_tcslen(m_sPath))
200                                return Syntax();
201                        m_sPath = (LPCTSTR) sArgument;
202                        #pragma endregion
203                }
204                #pragma region Validation
205                if(!_tcslen(m_sPath))
206                        return Syntax();
207                #pragma endregion
208                return TRUE;
209        }
210        VOID ProcessDirectory(const CPath& sDirectory)
211        {
212                _Y1(AtlFormatString(_T("sDirectory \"%s\""), sDirectory));
213                CFindFiles FindFiles;
214                for(BOOL bFound = FindFiles.FindFirstFile(sDirectory, _T("*.*")); bFound; bFound = FindFiles.FindNextFile())
215                {
216                        if(!(FindFiles.GetFindData().dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
217                                continue; // Not a Directory
218                        if(_tcscmp(FindFiles.GetFindData().cFileName, _T(".")) == 0 || _tcscmp(FindFiles.GetFindData().cFileName, _T("..")) == 0)
219                                continue; // Not a Real Directory
220                        m_nDirectoryCount++;
221                        CPath sPath;
222                        sPath.Combine(sDirectory, FindFiles.GetFindData().cFileName);
223                        if(FindFiles.GetFindData().dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
224                                _ATLTRY
225                                {
226                                        CReparsePointData ReparsePointData(sPath);
227                                        _tprintf(_T("%s -> %ls\n"), sPath, ReparsePointData.GetFriendlySubstituteName());
228                                        m_nReparsePointCount++;
229                                }
230                                _ATLCATCH(Exception)
231                                {
232                                        _Z_ATLEXCEPTION(Exception);
233                                }
234                        else
235                                ProcessDirectory(sPath);
236                }
237        }
238        VOID RunMessageLoop()
239        {
240                #pragma region .INI File
241                //CPath sIniFilePath = CIniFile::GetDefaultPath();
242                //CIniFile::LookupParentDirectoryPath(sIniFilePath, 2);
243                //const CObjectPtr<CIniFile::CSection> pSection = CIniFile::Open(sIniFilePath, CIniFile::GetDefaultSection());
244                //m_sIniFilePath = sIniFilePath;
245                //m_pSection = pSection;
246                #pragma endregion
247                _tprintf(_T("Base path: %s\n"), m_sPath);
248                m_nDirectoryCount = 0;
249                m_nReparsePointCount = 0;
250                ProcessDirectory(m_sPath);
251                _tprintf(_T("Found directories: %d\n"), m_nDirectoryCount);
252                _tprintf(_T("Found reparse points: %d\n"), m_nReparsePointCount);
253        }
254};
255
Note: See TracBrowser for help on using the repository browser.