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