Leaked source code of windows server 2003
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.

483 lines
11 KiB

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