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 #ifdef BACKUP_READ_IMPLEMENTED
37 int ScanNTFSStreams(Entry* entry, HANDLE hFile)
38 {
39 	PVOID ctx = 0;
40 	DWORD read, seek_high;
41 	Entry** pnext = &entry->_down;
42 	int cnt = 0;
43 
44 	for(;;) {
45 		struct NTFS_StreamHdr : public WIN32_STREAM_ID {
46 			WCHAR name_padding[_MAX_FNAME];	// room for reading stream name
47 		} hdr;
48 
49 		if (!BackupRead(hFile, (LPBYTE)&hdr, (LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr, &read, FALSE, FALSE, &ctx) ||
50 			(long)read!=(LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr)
51 			break;
52 
53 		if (hdr.dwStreamId == BACKUP_ALTERNATE_DATA) {
54 			if (hdr.dwStreamNameSize &&
55 				BackupRead(hFile, (LPBYTE)hdr.cStreamName, hdr.dwStreamNameSize, &read, FALSE, FALSE, &ctx) &&
56 				read==hdr.dwStreamNameSize)
57 			{
58 				++cnt;
59 
60 				int l = hdr.dwStreamNameSize / sizeof(WCHAR);
61 				LPCWSTR p = hdr.cStreamName;
62 				LPCWSTR e = hdr.cStreamName + l;
63 
64 				if (l>0 && *p==':') {
65 					++p, --l;
66 
67 					e = p;
68 
69 					while(l>0 && *e!=':')
70 						++e, --l;
71 
72 					l = e - p;
73 				}
74 
75 				Entry* stream_entry = new WinEntry(entry);
76 
77 				memcpy(&stream_entry->_data, &entry->_data, sizeof(WIN32_FIND_DATA));
78 				lstrcpy(stream_entry->_data.cFileName, String(p, l));
79 
80 				stream_entry->_down = NULL;
81 				stream_entry->_expanded = false;
82 				stream_entry->_scanned = false;
83 				stream_entry->_level = entry->_level + 1;
84 
85 				*pnext = stream_entry;
86 				pnext = &stream_entry->_next;
87 			}
88 		}
89 
90 		 // jump to the next stream header
91 		if (!BackupSeek(hFile, ~0, ~0, &read, &seek_high, &ctx)) {
92 			DWORD error = GetLastError();
93 
94 			if (error != ERROR_SEEK) {
95 				BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx);	// terminate BackupRead() loop
96 				THROW_EXCEPTION(error);
97 				//break;
98 			}
99 
100 			hdr.Size.QuadPart -= read;
101 			hdr.Size.HighPart -= seek_high;
102 
103 			BYTE buffer[4096];
104 
105 			while(hdr.Size.QuadPart > 0) {
106 				if (!BackupRead(hFile, buffer, sizeof(buffer), &read, FALSE, FALSE, &ctx) || read!=sizeof(buffer))
107 					break;
108 
109 				hdr.Size.QuadPart -= read;
110 			}
111 		}
112 	}
113 
114 	if (ctx)
115 		if (!BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx))	// terminate BackupRead() loop
116 			THROW_EXCEPTION(GetLastError());
117 
118 	return cnt;
119 }
120 #endif
121 
122 
123 void WinDirectory::read_directory(int scan_flags)
124 {
125 	CONTEXT("WinDirectory::read_directory()");
126 
127 	int level = _level + 1;
128 
129 	Entry* first_entry = NULL;
130 	Entry* last = NULL;
131 	Entry* entry;
132 
133 	LPCTSTR path = (LPCTSTR)_path;
134 	TCHAR buffer[MAX_PATH], *pname;
135 	for(pname=buffer; *path; )
136 		*pname++ = *path++;
137 
138 	lstrcpy(pname, TEXT("\\*"));
139 
140 	WIN32_FIND_DATA w32fd;
141 	HANDLE hFind = FindFirstFile(buffer, &w32fd);
142 
143 	if (hFind != INVALID_HANDLE_VALUE) {
144 		do {
145 			lstrcpy(pname+1, w32fd.cFileName);
146 
147 			if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
148 				entry = new WinDirectory(this, buffer);
149 			else
150 				entry = new WinEntry(this);
151 
152 			if (!first_entry)
153 				first_entry = entry;
154 
155 			if (last)
156 				last->_next = entry;
157 
158 			memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
159 			entry->_level = level;
160 
161 			 // display file type names, but don't hide file extensions
162 			g_Globals._ftype_mgr.set_type(entry, true);
163 
164 			if (!(scan_flags & SCAN_DONT_ACCESS)) {
165 				HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
166 											0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
167 
168 				if (hFile != INVALID_HANDLE_VALUE) {
169 					if (GetFileInformationByHandle(hFile, &entry->_bhfi))
170 						entry->_bhfi_valid = true;
171 
172 #ifdef BACKUP_READ_IMPLEMENTED
173 					if (ScanNTFSStreams(entry, hFile))
174 						entry->_scanned = true;	// There exist named NTFS sub-streams in this file.
175 #endif
176 
177 					CloseHandle(hFile);
178 				}
179 			}
180 
181 			last = entry;	// There is always at least one entry, because FindFirstFile() succeeded and we don't filter the file entries.
182 		} while(FindNextFile(hFind, &w32fd));
183 
184 		if (last)
185 			last->_next = NULL;
186 
187 		FindClose(hFind);
188 	}
189 
190 	_down = first_entry;
191 	_scanned = true;
192 }
193 
194 
195 const void* WinDirectory::get_next_path_component(const void* p) const
196 {
197 	LPCTSTR s = (LPCTSTR) p;
198 
199 	while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
200 		++s;
201 
202 	while(*s==TEXT('\\') || *s==TEXT('/'))
203 		++s;
204 
205 	if (!*s)
206 		return NULL;
207 
208 	return s;
209 }
210 
211 
212 Entry* WinDirectory::find_entry(const void* p)
213 {
214 	LPCTSTR name = (LPCTSTR)p;
215 
216 	for(Entry*entry=_down; entry; entry=entry->_next) {
217 		LPCTSTR p = name;
218 		LPCTSTR q = entry->_data.cFileName;
219 
220 		do {
221 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
222 				return entry;
223 		} while(tolower(*p++) == tolower(*q++));
224 
225 		p = name;
226 		q = entry->_data.cAlternateFileName;
227 
228 		do {
229 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
230 				return entry;
231 		} while(tolower(*p++) == tolower(*q++));
232 	}
233 
234 	return NULL;
235 }
236 
237 
238  // get full path of specified directory entry
239 bool WinEntry::get_path(PTSTR path, size_t path_count) const
240 {
241 	return get_path_base(path, path_count, ET_WINDOWS);
242 }
243 
244 ShellPath WinEntry::create_absolute_pidl() const
245 {
246 	CONTEXT("WinEntry::create_absolute_pidl()");
247 
248 	TCHAR path[MAX_PATH];
249 
250 	if (get_path(path, COUNTOF(path)))
251 		return ShellPath(path);
252 
253 	return ShellPath();
254 }
255 
256 #endif // _NO_WIN_FS
257