- Update address of Free Software Foundation.
[reactos.git] / reactos / base / shell / explorer / shell / winfs.cpp
1 /*
2 * Copyright 2003, 2004, 2005 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // winfs.cpp
24 //
25 // Martin Fuchs, 23.07.2003
26 //
27
28
29 #include <precomp.h>
30
31 #ifndef _NO_WIN_FS
32
33 //#include "winfs.h"
34
35
36 int ScanNTFSStreams(Entry* entry, HANDLE hFile)
37 {
38 PVOID ctx = 0;
39 DWORD read, seek_high;
40 Entry** pnext = &entry->_down;
41 int cnt = 0;
42
43 for(;;) {
44 struct NTFS_StreamHdr : public WIN32_STREAM_ID {
45 WCHAR name_padding[_MAX_FNAME]; // room for reading stream name
46 } hdr;
47
48 if (!BackupRead(hFile, (LPBYTE)&hdr, (LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr, &read, FALSE, FALSE, &ctx) ||
49 (long)read!=(LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr)
50 break;
51
52 if (hdr.dwStreamId == BACKUP_ALTERNATE_DATA) {
53 if (hdr.dwStreamNameSize &&
54 BackupRead(hFile, (LPBYTE)hdr.cStreamName, hdr.dwStreamNameSize, &read, FALSE, FALSE, &ctx) &&
55 read==hdr.dwStreamNameSize)
56 {
57 ++cnt;
58
59 int l = hdr.dwStreamNameSize / sizeof(WCHAR);
60 LPCWSTR p = hdr.cStreamName;
61 LPCWSTR e = hdr.cStreamName + l;
62
63 if (l>0 && *p==':') {
64 ++p, --l;
65
66 e = p;
67
68 while(l>0 && *e!=':')
69 ++e, --l;
70
71 l = e - p;
72 }
73
74 Entry* stream_entry = new WinEntry(entry);
75
76 memcpy(&stream_entry->_data, &entry->_data, sizeof(WIN32_FIND_DATA));
77 lstrcpy(stream_entry->_data.cFileName, String(p, l));
78
79 stream_entry->_down = NULL;
80 stream_entry->_expanded = false;
81 stream_entry->_scanned = false;
82 stream_entry->_level = entry->_level + 1;
83
84 *pnext = stream_entry;
85 pnext = &stream_entry->_next;
86 }
87 }
88
89 // jump to the next stream header
90 if (!BackupSeek(hFile, ~0, ~0, &read, &seek_high, &ctx)) {
91 DWORD error = GetLastError();
92
93 if (error != ERROR_SEEK) {
94 BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx); // terminate BackupRead() loop
95 THROW_EXCEPTION(error);
96 //break;
97 }
98
99 hdr.Size.QuadPart -= read;
100 hdr.Size.HighPart -= seek_high;
101
102 BYTE buffer[4096];
103
104 while(hdr.Size.QuadPart > 0) {
105 if (!BackupRead(hFile, buffer, sizeof(buffer), &read, FALSE, FALSE, &ctx) || read!=sizeof(buffer))
106 break;
107
108 hdr.Size.QuadPart -= read;
109 }
110 }
111 }
112
113 if (ctx)
114 if (!BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx)) // terminate BackupRead() loop
115 THROW_EXCEPTION(GetLastError());
116
117 return cnt;
118 }
119
120
121 void WinDirectory::read_directory(int scan_flags)
122 {
123 CONTEXT("WinDirectory::read_directory()");
124
125 int level = _level + 1;
126
127 Entry* first_entry = NULL;
128 Entry* last = NULL;
129 Entry* entry;
130
131 LPCTSTR path = (LPCTSTR)_path;
132 TCHAR buffer[MAX_PATH], *pname;
133 for(pname=buffer; *path; )
134 *pname++ = *path++;
135
136 lstrcpy(pname, TEXT("\\*"));
137
138 WIN32_FIND_DATA w32fd;
139 HANDLE hFind = FindFirstFile(buffer, &w32fd);
140
141 if (hFind != INVALID_HANDLE_VALUE) {
142 do {
143 lstrcpy(pname+1, w32fd.cFileName);
144
145 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
146 entry = new WinDirectory(this, buffer);
147 else
148 entry = new WinEntry(this);
149
150 if (!first_entry)
151 first_entry = entry;
152
153 if (last)
154 last->_next = entry;
155
156 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
157 entry->_level = level;
158
159 // display file type names, but don't hide file extensions
160 g_Globals._ftype_mgr.set_type(entry, true);
161
162 if (!(scan_flags & SCAN_DONT_ACCESS)) {
163 HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
164 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
165
166 if (hFile != INVALID_HANDLE_VALUE) {
167 if (GetFileInformationByHandle(hFile, &entry->_bhfi))
168 entry->_bhfi_valid = true;
169
170 if (ScanNTFSStreams(entry, hFile))
171 entry->_scanned = true; // There exist named NTFS sub-streams in this file.
172
173 CloseHandle(hFile);
174 }
175 }
176
177 last = entry; // There is always at least one entry, because FindFirstFile() succeeded and we don't filter the file entries.
178 } while(FindNextFile(hFind, &w32fd));
179
180 if (last)
181 last->_next = NULL;
182
183 FindClose(hFind);
184 }
185
186 _down = first_entry;
187 _scanned = true;
188 }
189
190
191 const void* WinDirectory::get_next_path_component(const void* p) const
192 {
193 LPCTSTR s = (LPCTSTR) p;
194
195 while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
196 ++s;
197
198 while(*s==TEXT('\\') || *s==TEXT('/'))
199 ++s;
200
201 if (!*s)
202 return NULL;
203
204 return s;
205 }
206
207
208 Entry* WinDirectory::find_entry(const void* p)
209 {
210 LPCTSTR name = (LPCTSTR)p;
211
212 for(Entry*entry=_down; entry; entry=entry->_next) {
213 LPCTSTR p = name;
214 LPCTSTR q = entry->_data.cFileName;
215
216 do {
217 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
218 return entry;
219 } while(tolower(*p++) == tolower(*q++));
220
221 p = name;
222 q = entry->_data.cAlternateFileName;
223
224 do {
225 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
226 return entry;
227 } while(tolower(*p++) == tolower(*q++));
228 }
229
230 return NULL;
231 }
232
233
234 // get full path of specified directory entry
235 bool WinEntry::get_path(PTSTR path, size_t path_count) const
236 {
237 return get_path_base(path, path_count, ET_WINDOWS);
238 }
239
240 ShellPath WinEntry::create_absolute_pidl() const
241 {
242 CONTEXT("WinEntry::create_absolute_pidl()");
243
244 TCHAR path[MAX_PATH];
245
246 if (get_path(path, COUNTOF(path)))
247 return ShellPath(path);
248
249 return ShellPath();
250 }
251
252 #endif // _NO_WIN_FS