Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
11 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. fileutil.c
  5. Abstract:
  6. File-related functions for SPUTILS
  7. Author:
  8. Ted Miller (tedm) 11-Jan-1995
  9. Revision History:
  10. Jamie Hunter (JamieHun) Jun-27-2000
  11. Moved various functions out of setupapi
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. DWORD
  16. pSetupOpenAndMapFileForRead(
  17. IN PCTSTR FileName,
  18. OUT PDWORD FileSize,
  19. OUT PHANDLE FileHandle,
  20. OUT PHANDLE MappingHandle,
  21. OUT PVOID *BaseAddress
  22. )
  23. /*++
  24. Routine Description:
  25. Open and map an existing file for read access.
  26. Arguments:
  27. FileName - supplies pathname to file to be mapped.
  28. FileSize - receives the size in bytes of the file.
  29. FileHandle - receives the win32 file handle for the open file.
  30. The file will be opened for generic read access.
  31. MappingHandle - receives the win32 handle for the file mapping
  32. object. This object will be for read access.
  33. BaseAddress - receives the address where the file is mapped.
  34. Return Value:
  35. NO_ERROR if the file was opened and mapped successfully.
  36. The caller must unmap the file with pSetupUnmapAndCloseFile when
  37. access to the file is no longer desired.
  38. Win32 error code if the file was not successfully mapped.
  39. --*/
  40. {
  41. DWORD rc;
  42. //
  43. // Open the file -- fail if it does not exist.
  44. //
  45. *FileHandle = CreateFile(
  46. FileName,
  47. GENERIC_READ,
  48. FILE_SHARE_READ,
  49. NULL,
  50. OPEN_EXISTING,
  51. 0,
  52. NULL
  53. );
  54. if(*FileHandle == INVALID_HANDLE_VALUE) {
  55. rc = GetLastError();
  56. } else if((rc = pSetupMapFileForRead(*FileHandle,
  57. FileSize,
  58. MappingHandle,
  59. BaseAddress)) != NO_ERROR) {
  60. CloseHandle(*FileHandle);
  61. }
  62. return(rc);
  63. }
  64. #ifndef SPUTILSW
  65. DWORD
  66. pSetupMapFileForRead(
  67. IN HANDLE FileHandle,
  68. OUT PDWORD FileSize,
  69. OUT PHANDLE MappingHandle,
  70. OUT PVOID *BaseAddress
  71. )
  72. /*++
  73. Routine Description:
  74. Map an opened file for read access.
  75. Arguments:
  76. FileHandle - supplies the handle of the opened file to be mapped.
  77. This handle must have been opened with at least read access.
  78. FileSize - receives the size in bytes of the file.
  79. MappingHandle - receives the win32 handle for the file mapping
  80. object. This object will be for read access.
  81. BaseAddress - receives the address where the file is mapped.
  82. Return Value:
  83. NO_ERROR if the file was mapped successfully. The caller must
  84. unmap the file with pSetupUnmapAndCloseFile when access to the file
  85. is no longer desired.
  86. Win32 error code if the file was not successfully mapped.
  87. --*/
  88. {
  89. DWORD rc;
  90. //
  91. // Get the size of the file.
  92. //
  93. *FileSize = GetFileSize(FileHandle, NULL);
  94. if(*FileSize != (DWORD)(-1)) {
  95. //
  96. // Create file mapping for the whole file.
  97. //
  98. *MappingHandle = CreateFileMapping(
  99. FileHandle,
  100. NULL,
  101. PAGE_READONLY,
  102. 0,
  103. *FileSize,
  104. NULL
  105. );
  106. if(*MappingHandle) {
  107. //
  108. // Map the whole file.
  109. //
  110. *BaseAddress = MapViewOfFile(
  111. *MappingHandle,
  112. FILE_MAP_READ,
  113. 0,
  114. 0,
  115. *FileSize
  116. );
  117. if(*BaseAddress) {
  118. return(NO_ERROR);
  119. }
  120. rc = GetLastError();
  121. CloseHandle(*MappingHandle);
  122. } else {
  123. rc = GetLastError();
  124. }
  125. } else {
  126. rc = GetLastError();
  127. }
  128. return(rc);
  129. }
  130. BOOL
  131. pSetupUnmapAndCloseFile(
  132. IN HANDLE FileHandle,
  133. IN HANDLE MappingHandle,
  134. IN PVOID BaseAddress
  135. )
  136. /*++
  137. Routine Description:
  138. Unmap and close a file.
  139. Arguments:
  140. FileHandle - supplies win32 handle to open file.
  141. MappingHandle - supplies the win32 handle for the open file mapping
  142. object.
  143. BaseAddress - supplies the address where the file is mapped.
  144. Return Value:
  145. BOOLean value indicating success or failure.
  146. --*/
  147. {
  148. BOOL b;
  149. b = UnmapViewOfFile(BaseAddress);
  150. b = b && CloseHandle(MappingHandle);
  151. b = b && CloseHandle(FileHandle);
  152. return(b);
  153. }
  154. #endif //!SPUTILSW
  155. BOOL
  156. pSetupFileExists(
  157. IN PCTSTR FileName,
  158. OUT PWIN32_FIND_DATA FindData OPTIONAL
  159. )
  160. /*++
  161. Routine Description:
  162. Determine if a file exists and is accessible.
  163. Errormode is set (and then restored) so the user will not see
  164. any pop-ups.
  165. Arguments:
  166. FileName - supplies full path of file to check for existance.
  167. FindData - if specified, receives find data for the file.
  168. Return Value:
  169. TRUE if the file exists and is accessible.
  170. FALSE if not. GetLastError() returns extended error info.
  171. --*/
  172. {
  173. WIN32_FIND_DATA findData;
  174. HANDLE FindHandle;
  175. UINT OldMode;
  176. DWORD Error;
  177. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  178. FindHandle = FindFirstFile(FileName,&findData);
  179. if(FindHandle == INVALID_HANDLE_VALUE) {
  180. Error = GetLastError();
  181. } else {
  182. FindClose(FindHandle);
  183. if(FindData) {
  184. *FindData = findData;
  185. }
  186. Error = NO_ERROR;
  187. }
  188. SetErrorMode(OldMode);
  189. SetLastError(Error);
  190. return (Error == NO_ERROR);
  191. }
  192. DWORD
  193. pSetupMakeSurePathExists(
  194. IN PCTSTR FullFilespec
  195. )
  196. /*++
  197. Routine Description:
  198. This routine ensures that a multi-level path exists by creating individual
  199. levels one at a time. It is assumed that the caller will pass in a *filename*
  200. whose path needs to exist. Some examples:
  201. c:\x - C:\ is assumes to always exist.
  202. c:\x\y\z - Ensure that c:\x\y exists.
  203. \x\y\z - \x\y on current drive
  204. x\y - x in current directory
  205. d:x\y - d:x
  206. \\server\share\p\file - \\server\share\p
  207. \\?\GLOBALROOT\a\b\c - other more weird scenarios
  208. \\?\C:\a\b\c
  209. Arguments:
  210. FullFilespec - supplies the *filename* of a file that the caller wants to
  211. create. This routine creates the *path* to that file, in other words,
  212. the final component is assumed to be a filename, and is not a
  213. directory name. (This routine doesn't actually create this file.)
  214. If this is invalid, then the results are undefined (for example,
  215. passing \\server\share, C:\, or C:).
  216. Return Value:
  217. Win32 error code indicating outcome. If FullFilespec is invalid,
  218. *may* return ERROR_INVALID_NAME.
  219. --*/
  220. {
  221. TCHAR Buffer[MAX_PATH+2];
  222. TCHAR c;
  223. PTSTR filename;
  224. PTSTR root;
  225. PTSTR last;
  226. PTSTR backtrack;
  227. DWORD len;
  228. DWORD attrib;
  229. //
  230. // normalize path
  231. //
  232. len = GetFullPathName(FullFilespec,MAX_PATH,Buffer,&filename);
  233. if(len >= MAX_PATH) {
  234. //
  235. // directory name is longer than we can handle
  236. //
  237. return ERROR_INVALID_NAME;
  238. }
  239. if(!len) {
  240. //
  241. // other error
  242. //
  243. return GetLastError();
  244. }
  245. if(filename == NULL || filename == Buffer) {
  246. //
  247. // looks like no path specified
  248. //
  249. return ERROR_INVALID_NAME;
  250. }
  251. //
  252. // chop off filename part
  253. //
  254. filename[0] = TEXT('\0');
  255. //
  256. // now do some other sanity checks
  257. // to determine 'root' - a point we wont try to create
  258. //
  259. if(Buffer[0] && Buffer[1] == TEXT(':')) {
  260. //
  261. // looks like "d:" format
  262. //
  263. if(Buffer[2] != TEXT('\\')) {
  264. return ERROR_INVALID_NAME;
  265. }
  266. root = Buffer+2;
  267. }
  268. if(Buffer[0] == TEXT('\\') &&
  269. Buffer[1] == TEXT('\\')) {
  270. //
  271. // UNC style (\\machine\share\path \\?\d\path \\?\GLOBALROOT\path \\.\GLOBALROOT\path etc)
  272. // root is 2nd slash after \\
  273. //
  274. root = _tcschr(Buffer+2,TEXT('\\')); // find first slash
  275. if(root) {
  276. root = _tcschr(root+1,TEXT('\\')); // find 2nd slash
  277. }
  278. if(!root) {
  279. return ERROR_INVALID_NAME;
  280. }
  281. }
  282. //
  283. // see if the directory specified exists
  284. // include the slash, since that helps scenarios like \\?\GLOBALROOT\Device\HarddiskVolume1\
  285. // and works for all the other scenarios
  286. // can't use findfirst/findnext though
  287. //
  288. attrib = GetFileAttributes(Buffer);
  289. if(attrib != (DWORD)(-1)) {
  290. if(attrib & FILE_ATTRIBUTE_DIRECTORY) {
  291. //
  292. // requested directory already exists
  293. //
  294. return NO_ERROR;
  295. }
  296. //
  297. // directory was expected
  298. //
  299. return ERROR_DIRECTORY;
  300. }
  301. //
  302. // now we have to step backwards until we find an existing directory
  303. // change all '\' to nulls as we do so
  304. // this will give us something like (c esc form) c:\\a\\b\\c\0d\0e\0f\0\0
  305. // we know the last \0 is there from when we chopped filename
  306. // first directory to be created is c:\\a\\b\\c
  307. //
  308. last = CharPrev(Buffer,filename); // to last slash
  309. if(last == root) {
  310. return ERROR_INVALID_NAME;
  311. }
  312. if(*last != TEXT('\\')) {
  313. //
  314. // should never be the case
  315. //
  316. return ERROR_INVALID_NAME;
  317. }
  318. while(last > root) {
  319. *last = TEXT('\0');
  320. backtrack = _tcsrchr(Buffer,TEXT('\\'));
  321. if(!backtrack) {
  322. return ERROR_INVALID_NAME;
  323. }
  324. c = backtrack[1];
  325. backtrack[1] = TEXT('\0');
  326. attrib = GetFileAttributes(Buffer); // does this part exist?
  327. backtrack[1] = c; // but character back
  328. if(attrib != (DWORD)(-1)) {
  329. if(attrib & FILE_ATTRIBUTE_DIRECTORY) {
  330. //
  331. // requested directory already exists
  332. // 'last' points to first NULL to replace to slash
  333. // Buffer contains first directory to create
  334. //
  335. break;
  336. }
  337. //
  338. // directory was expected
  339. //
  340. return ERROR_DIRECTORY;
  341. }
  342. //
  343. // keep going
  344. //
  345. last = backtrack;
  346. }
  347. if(last <= root) {
  348. return ERROR_INVALID_NAME;
  349. }
  350. //
  351. // now begin create loop
  352. //
  353. while(CreateDirectory(Buffer,NULL)) {
  354. if(!last[1]) {
  355. //
  356. // path created
  357. //
  358. return NO_ERROR;
  359. }
  360. last[0] = TEXT('\\');
  361. last += lstrlen(last);
  362. }
  363. //
  364. // failed for some other reason
  365. //
  366. return GetLastError();
  367. }