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.

1886 lines
53 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. DirUtils.C
  5. Abstract:
  6. directory, file, filename and network utility functions.
  7. Author:
  8. Bob Watson (a-robw)
  9. Revision History:
  10. 24 Jun 94 Written
  11. --*/
  12. //
  13. // Windows Include Files
  14. //
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <malloc.h>
  18. #include <tchar.h> // unicode macros
  19. #include <stdlib.h> // string to number conversions
  20. #include <lmcons.h> // lanman API constants
  21. #include <lmerr.h> // lanman error returns
  22. #include <lmshare.h> // sharing API prototypes
  23. #include <lmapibuf.h> // lanman buffer API prototypes
  24. #include <commdlg.h> // common dialog include
  25. //
  26. // app include files
  27. //
  28. #include "otnboot.h"
  29. #include "otnbtdlg.h"
  30. LPCTSTR
  31. GetRootFromPath (
  32. IN LPCTSTR szPath
  33. )
  34. {
  35. static TCHAR szReturnBuffer[MAX_PATH];
  36. LPTSTR szNextChar;
  37. LONG lIndex;
  38. if (IsUncPath(szPath)) {
  39. // return server & share
  40. lstrcpy (szReturnBuffer, cszDoubleBackslash);
  41. szNextChar = &szReturnBuffer[2];
  42. if (GetServerFromUnc (szPath, szNextChar)) {
  43. lstrcat (szReturnBuffer, cszBackslash);
  44. szNextChar = &szReturnBuffer[lstrlen(szReturnBuffer)];
  45. if (GetShareFromUnc(szPath, szNextChar)) {
  46. // append trailing backslash
  47. lstrcat (szReturnBuffer, cszBackslash);
  48. } else {
  49. szReturnBuffer[0] = 0;
  50. }
  51. } else {
  52. szReturnBuffer[0] = 0;
  53. }
  54. } else {
  55. // dos path name
  56. for (lIndex = 0; lIndex < 3; lIndex++) {
  57. if (szPath[lIndex] > cSpace) {
  58. szReturnBuffer[lIndex] = szPath[lIndex];
  59. } else {
  60. break;
  61. }
  62. }
  63. szReturnBuffer[lIndex] = 0;
  64. }
  65. return (LPCTSTR)&szReturnBuffer[0];
  66. }
  67. BOOL
  68. GetShareFromUnc (
  69. IN LPCTSTR szPath,
  70. OUT LPTSTR szShare
  71. )
  72. /*++
  73. Routine Description:
  74. Parses a UNC path name and returns the Sharepoint name in the buffer
  75. supplied by the caller. The buffer size is not checked and is
  76. assumed to be at least (MAX_SHARENAME+1) characters
  77. long.
  78. Arguments:
  79. IN LPCTSTR szPath UNC path name to parse
  80. OUT LPTSTR szShare buffer supplied by caller to receive the server
  81. Return Value:
  82. TRUE if a sharename is returned, otherwise...
  83. FALSE if unable to parse out a share name
  84. --*/
  85. {
  86. int nSlashCount = 0; // count of backslashes found in string
  87. LPTSTR szPathPtr; // pointer to char in szPath
  88. LPTSTR szSharePtr; // pointer to char in szShare
  89. szPathPtr = (LPTSTR)szPath;
  90. szSharePtr = szShare;
  91. if (IsUncPath(szPath)) {
  92. while (*szPathPtr != 0) {
  93. if (nSlashCount < 3) {
  94. if (*szPathPtr++ == cBackslash) nSlashCount++;
  95. } else {
  96. if (*szPathPtr == cBackslash) {
  97. szPathPtr++;
  98. break;
  99. } else {
  100. *szSharePtr++ = *szPathPtr++;
  101. }
  102. }
  103. }
  104. }
  105. *szSharePtr = 0; // terminate share name
  106. if (szSharePtr == szShare) {
  107. return FALSE;
  108. } else {
  109. return TRUE;
  110. }
  111. }
  112. BOOL
  113. GetNetPathInfo (
  114. IN LPCTSTR szPath,
  115. OUT LPTSTR szServer,
  116. OUT LPTSTR szRemotePath
  117. )
  118. /*++
  119. Routine Description:
  120. Processes a path and returns the machine the files are on and the
  121. local path on that machine. UNC, Redirected and local paths may
  122. be processed by this routine. On remote machine paths (e.g.
  123. redir'd dos paths and UNC paths on another machine) the shared
  124. path on the remote machine is returned if there user has sufficient
  125. permission to access that information. On local paths, the
  126. local computer name and root path is returned.
  127. Arguments:
  128. IN LPCTSTR szPath
  129. the input path to analyze.
  130. OUT LPTSTR szServer
  131. the server/computername that the path references. The buffer size
  132. is NOT checked and must be at least MAX_COMPUTERNAME_LENGTH+1 char's
  133. long.
  134. OUT LPTSTR szRemotePath
  135. the path on the "szServer" machine that corresponds to the
  136. input path. The buffer size is NOT checked and must be at least
  137. MAX_PATH + 1 characters long.
  138. Return Value:
  139. TRUE if a path was processed and data returned
  140. FALSE if an error occurred or unable to process the path
  141. --*/
  142. {
  143. DWORD dwBufLen; // buffer length value used in fn. calls
  144. DWORD dwStatus; // status value returned by fn. calls
  145. TCHAR szShareName[NNLEN+1]; // net share name from path
  146. LPTSTR szUncPath; // buffer to get path from redir'd drive
  147. TCHAR szDrive[4]; // buffer to build drive string in
  148. LPTSTR szSubDirs; // pointer to start of dirs not in share
  149. LONG lBsCount; // count of backslashes found parsing UNC
  150. BOOL bReturn = FALSE; // return valie
  151. PSHARE_INFO_2 psi2Data; // pointer to Net data buffer
  152. // check args
  153. if ((szServer == NULL) || (szRemotePath == NULL)) {
  154. // an invalid argument was passed
  155. return FALSE;
  156. }
  157. szUncPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  158. if (szUncPath == NULL) {
  159. *szServer = 0;
  160. *szRemotePath = 0;
  161. return FALSE;
  162. }
  163. // args ok, so take a look at the path passed in to process
  164. if (IsUncPath(szPath)) {
  165. // extract the server from the path string
  166. if (GetServerFromUnc(szPath, szServer)) {
  167. // that worked, so extract the share name.
  168. if (GetShareFromUnc(szPath, szShareName)) {
  169. // find end of UNC so sub dirs may be appended to final path
  170. for (szSubDirs = (LPTSTR)szPath, lBsCount = 0;
  171. (lBsCount < 4) && (*szSubDirs != 0);
  172. szSubDirs++) {
  173. if (*szSubDirs == cBackslash) lBsCount++;
  174. }
  175. // now look up the share on the server to get the
  176. // source path on the server machine
  177. if (NetShareGetInfo (szServer, (LPWSTR)szShareName, 2L, (LPBYTE *)&psi2Data) == NERR_Success) {
  178. // successful call so copy the data to the user's buffer
  179. lstrcpy (szRemotePath, psi2Data->shi2_path);
  180. NetApiBufferFree (psi2Data);
  181. // add this only if there's a subdir to append
  182. if (*szSubDirs != 0) {
  183. if (szRemotePath[lstrlen(szRemotePath)-1] != cBackslash)
  184. lstrcat(szRemotePath, cszBackslash);
  185. lstrcat (szRemotePath, szSubDirs);
  186. }
  187. bReturn = TRUE;
  188. } else {
  189. // unable to get path on server
  190. *szRemotePath = 0;
  191. bReturn = FALSE;
  192. }
  193. } else {
  194. // unable to get parse share name
  195. *szRemotePath = 0;
  196. bReturn = FALSE;
  197. }
  198. } else {
  199. // unable to parse server name
  200. *szServer = 0;
  201. *szRemotePath = 0;
  202. bReturn = FALSE;
  203. }
  204. } else {
  205. // it's a dos pathname so see if it's a redirected drive
  206. if (OnRemoteDrive(szPath)) {
  207. // yes it's been redirected so look up the information
  208. // get drive letter of redirected drive
  209. szDrive[0] = szPath[0];
  210. szDrive[1] = szPath[1];
  211. szDrive[2] = 0;
  212. szSubDirs = (LPTSTR)&szPath[3];
  213. dwBufLen = MAX_PATH;
  214. dwStatus = WNetGetConnection (
  215. szDrive,
  216. szUncPath,
  217. &dwBufLen);
  218. if (dwStatus == NO_ERROR) {
  219. // UNC of shared dir looked up ok, now proccess that to
  220. // find the server and path on the server
  221. if (GetServerFromUnc(szUncPath, szServer)) {
  222. if (GetShareFromUnc(szUncPath, szShareName)) {
  223. // now look up the share on the server
  224. if (NetShareGetInfo (szServer, (LPWSTR)szShareName, 2L, (LPBYTE *)&psi2Data) == NERR_Success) {
  225. // successful call so return pointer to path string
  226. lstrcpy (szRemotePath, psi2Data->shi2_path);
  227. NetApiBufferFree (psi2Data);
  228. if (*szSubDirs != 0) {
  229. if (szRemotePath[lstrlen(szRemotePath)-1] != cBackslash)
  230. lstrcat(szRemotePath, cszBackslash);
  231. lstrcat (szRemotePath, szSubDirs);
  232. }
  233. bReturn = TRUE;
  234. } else {
  235. // unable to get path on server
  236. *szRemotePath = 0;
  237. bReturn = FALSE;
  238. }
  239. } else {
  240. // unable to get parse share name
  241. *szRemotePath = 0;
  242. bReturn = FALSE;
  243. }
  244. } else {
  245. // unable to parse server name
  246. *szServer = 0;
  247. *szRemotePath = 0;
  248. bReturn = FALSE;
  249. }
  250. }
  251. } else {
  252. // this is a local path so return the local machine name
  253. // and the path passed in
  254. dwBufLen = MAX_COMPUTERNAME_LENGTH+1;
  255. GetComputerName (szServer, &dwBufLen);
  256. lstrcpy (szRemotePath, szPath);
  257. bReturn = TRUE;
  258. }
  259. }
  260. FREE_IF_ALLOC (szUncPath);
  261. return bReturn;
  262. }
  263. BOOL
  264. ComputerPresent (
  265. IN LPCTSTR szMachine
  266. )
  267. /*++
  268. Routine Description:
  269. Try to connect to the registry on the machine name in order to
  270. determine if the machine is available on the network.
  271. Arguments:
  272. IN LPCTSTR szMachine
  273. computer name to try (must be in the form of \\machine)
  274. Return Value:
  275. TRUE "szMachine" is present
  276. FALSE unable to connect to machine
  277. --*/
  278. {
  279. LONG lStatus; // status of function call
  280. HKEY hKey; // handle to registry key opened
  281. lStatus = RegConnectRegistry (
  282. (LPTSTR)szMachine,
  283. HKEY_LOCAL_MACHINE,
  284. &hKey);
  285. if (lStatus == ERROR_SUCCESS) {
  286. RegCloseKey (hKey);
  287. return TRUE;
  288. } else {
  289. return FALSE;
  290. }
  291. }
  292. BOOL
  293. GetServerFromUnc (
  294. IN LPCTSTR szPath,
  295. OUT LPTSTR szServer
  296. )
  297. /*++
  298. Routine Description:
  299. reads a UNC path and returns the name of the server referenced in
  300. the buffer provided by the caller
  301. Arguments:
  302. IN LPCTSTR szPath
  303. UNC path to parse
  304. OUT LPTSTR szServer
  305. buffer to receive name of server (must be large enough!)
  306. Return Value:
  307. TRUE if successful,
  308. FALSE if not
  309. --*/
  310. {
  311. LPTSTR szPathPtr; // pointer to char in szPath
  312. LPTSTR szServPtr; // pointer to char in szServer
  313. int nSlashCount = 0; // count of backslash chars found
  314. szPathPtr = (LPTSTR)szPath;
  315. szServPtr = szServer;
  316. if (IsUncPath(szPath)) {
  317. while (szPathPtr != 0) {
  318. if (*szPathPtr == cBackslash) nSlashCount++;
  319. if ((nSlashCount == 2) && (*szPathPtr != cBackslash)) {
  320. *szServPtr++ = *szPathPtr;
  321. } else {
  322. if (nSlashCount == 3) break; // exit loop
  323. }
  324. szPathPtr++;
  325. }
  326. }
  327. *szServPtr = 0; // terminate server name
  328. if (szServPtr == szServer) {
  329. return FALSE;
  330. } else {
  331. return TRUE;
  332. }
  333. }
  334. BOOL
  335. LookupLocalShare (
  336. IN LPCTSTR szDrivePath,
  337. IN BOOL bExactMatch,
  338. OUT LPTSTR szLocalPath,
  339. IN PDWORD pdwBuffLen
  340. )
  341. /*++
  342. Routine Description:
  343. Searches registry to see if a file is already shared and returns
  344. the UNC name of the path if it is. (note this function is
  345. satisfied by the first match it finds, it doesn't try to
  346. find the "Best" match, just "A" match.
  347. Arguments:
  348. IN LPCTSTR szDrivePath
  349. DOS file path to look up
  350. IN BOOL bExactMatch
  351. TRUE find a share that matches the szDrivePath EXACTLY
  352. FALSE find a share that has any higher path in szDrivePath
  353. (e.g. if c:\dir is shared as XXX, then XXX would satisfy
  354. the lookup if the path was c:\dir\subdir\etc)
  355. OUT LPTSTR szLocalPath
  356. buffer to receive UNC version of path if a share exists
  357. IN PDWORD pdwBuffLen
  358. length of buffer referenced by szLocalPath
  359. Return Value:
  360. TRUE if a match is found,
  361. FALSE if not
  362. --*/
  363. {
  364. HKEY hkeyShareList; // handle to registry listing shares
  365. LONG lStatus; // called function status return value
  366. BOOL bReturn = FALSE; // routine status to return to caller
  367. BOOL bMatch; // true when strings match
  368. DWORD dwIndex; // index used to increment through search
  369. LPTSTR szValueBuffer; // value name string to examine
  370. LPTSTR szValueName; // value value string
  371. DWORD dwBufferSize; // buffer length variable
  372. DWORD dwNameSize; // Name Buffer size
  373. DWORD dwDataType; // data type read from registry
  374. LPTSTR szThisItem; // pointer to value in enumerated list of values
  375. LPTSTR szThisItemChar; // char in name value to compare to path
  376. LPTSTR szThisMatchChar; // matching character found
  377. LPTSTR szFilePath; // pointer into path buffer where filename is
  378. TCHAR szLocalMachine[MAX_COMPUTERNAME_LENGTH + 1];
  379. szValueName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  380. szValueBuffer = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
  381. if ((szValueName != NULL) && (szValueBuffer != NULL)) {
  382. // read the registry on the machine the user is
  383. // running the app on, not the server
  384. lStatus = RegOpenKeyEx (
  385. HKEY_LOCAL_MACHINE,
  386. cszLanmanServerShares,
  387. 0L,
  388. KEY_READ,
  389. &hkeyShareList);
  390. if (lStatus == ERROR_SUCCESS) {
  391. // loop through all values under this key until
  392. // a match is found or all have been examined
  393. dwIndex = 0;
  394. dwIndex = 0;
  395. dwNameSize = MAX_PATH;
  396. dwBufferSize = SMALL_BUFFER_SIZE;
  397. dwNameSize = MAX_PATH;
  398. dwBufferSize = SMALL_BUFFER_SIZE;
  399. while ((RegEnumValue(hkeyShareList, dwIndex,
  400. szValueName, &dwNameSize,
  401. 0L, &dwDataType,
  402. (LPBYTE)szValueBuffer, &dwBufferSize) == ERROR_SUCCESS) && !bReturn) {
  403. // value read in so scan multi-sz returned to find path entry
  404. for (szThisItem = szValueBuffer;
  405. *szThisItem != 0;
  406. szThisItem += (lstrlen(szThisItem)+1)) {
  407. // compare the current entry to the "Path" string.
  408. // if the characters don't match then exit the loop
  409. // after the loop, if the match char == 0 then all
  410. // characters in the "item" matched so this is the
  411. // Path entry. otherwise, it's not the path so go to the
  412. // the next item.
  413. for (szThisItemChar = szThisItem, szThisMatchChar = (LPTSTR)cszPath;
  414. (*szThisMatchChar != 0) && (*szThisItemChar != 0);
  415. szThisItemChar++, szThisMatchChar++) {
  416. if (*szThisMatchChar != *szThisItemChar) break;
  417. }
  418. if (*szThisMatchChar == 0) {
  419. // this is a match so see what the path that is
  420. // shared.
  421. while (*szThisItemChar != cEqual) szThisItemChar++;
  422. szThisItemChar++;
  423. // szThisItemChar now points to the path that is shared
  424. // compare it to the path that was passed in. if it matches,
  425. // then return the local machine and share name in a UNC
  426. // format
  427. if (bExactMatch) {
  428. if (lstrcmpi(szThisItemChar, szDrivePath) == 0) {
  429. bMatch = TRUE;
  430. } else {
  431. bMatch = FALSE;
  432. }
  433. } else {
  434. bMatch = MatchFirst(szThisItemChar, szDrivePath);
  435. }
  436. if (bMatch) {
  437. // it's a match so format return value
  438. dwBufferSize = MAX_COMPUTERNAME_LENGTH + 1;
  439. GetComputerName(
  440. szLocalMachine,
  441. &dwBufferSize);
  442. if (szLocalPath != NULL) {
  443. //
  444. // format name by replacing drive letter and colon
  445. // with UNC format \\server\path
  446. //
  447. lstrcpy (szLocalPath, cszDoubleBackslash);
  448. lstrcat (szLocalPath, szLocalMachine);
  449. lstrcat (szLocalPath, cszBackslash);
  450. lstrcat (szLocalPath, szValueName);
  451. szFilePath = (LPTSTR)&szDrivePath[lstrlen(szThisItemChar)];
  452. if (*szFilePath != cBackslash) lstrcat (szLocalPath, cszBackslash);
  453. lstrcat (szLocalPath, szFilePath);
  454. }
  455. bReturn = TRUE;
  456. }
  457. } else {
  458. // this is not the path entry so break and go to the
  459. // next one.
  460. }
  461. }
  462. // read next value
  463. dwIndex++;
  464. dwNameSize = MAX_PATH;
  465. dwBufferSize = SMALL_BUFFER_SIZE;
  466. }
  467. RegCloseKey (hkeyShareList);
  468. } else {
  469. // unable to open registry key
  470. bReturn = FALSE;
  471. }
  472. } else {
  473. // unable to allocate memory
  474. bReturn = FALSE;
  475. }
  476. FREE_IF_ALLOC (szValueName);
  477. FREE_IF_ALLOC (szValueBuffer);
  478. return bReturn;
  479. }
  480. BOOL
  481. LookupRemotePath (
  482. IN LPCTSTR szDrivePath,
  483. OUT LPTSTR szRemotePath,
  484. IN PDWORD pdwBuffLen
  485. )
  486. /*++
  487. Routine Description:
  488. Looks up a path on a remote server to see if a Dos file path is really
  489. on a remote drive and returns the UNC path if it is.
  490. Arguments:
  491. IN LPCTSTR szDrivePath
  492. DOS file path to examine
  493. OUT LPTSTR szRemotePath
  494. buffer to get UNC version of path if one exists
  495. IN PDWORD pdwBuffLen
  496. length of szRemotePath buffer in bytes
  497. Return Value:
  498. TRUE if match found
  499. FALSE if no match
  500. --*/
  501. {
  502. HKEY hkeyNetDrive; // handle to registry describing remote drive
  503. LONG lStatus; // function status returned by called fn's
  504. LPTSTR szKeyName; // buffer to build name string in
  505. TCHAR szLocalDrive[4]; // buffer to build local drive string in
  506. LPTSTR szFilePath; // pointer into buffer where file path goes
  507. DWORD dwValueType; // buffer for registry query
  508. BOOL bReturn; // return value of this function
  509. szKeyName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  510. if (szKeyName == NULL) return FALSE;
  511. lstrcpy (szKeyName, cszNetDriveListKeyName);
  512. szLocalDrive[0] = szDrivePath[0];
  513. szLocalDrive[1] = 0;
  514. lstrcat (szKeyName, szLocalDrive);
  515. szFilePath = (LPTSTR)&szDrivePath[2];
  516. lStatus = RegOpenKeyEx (
  517. HKEY_CURRENT_USER,
  518. szKeyName,
  519. 0L,
  520. KEY_READ,
  521. &hkeyNetDrive);
  522. if (lStatus == ERROR_SUCCESS) {
  523. lStatus = RegQueryValueEx (
  524. hkeyNetDrive,
  525. (LPTSTR)cszRemotePathValue,
  526. 0L,
  527. &dwValueType,
  528. (LPBYTE)szRemotePath,
  529. pdwBuffLen);
  530. RegCloseKey (hkeyNetDrive);
  531. if (lStatus == ERROR_SUCCESS) {
  532. //append the rest of the path and exit
  533. lstrcat (szRemotePath, szFilePath);
  534. bReturn = TRUE;
  535. } else {
  536. bReturn = FALSE;
  537. }
  538. } else {
  539. // unable to find drive or open key
  540. bReturn = FALSE;
  541. }
  542. FREE_IF_ALLOC (szKeyName);
  543. return bReturn;
  544. }
  545. BOOL
  546. OnRemoteDrive (
  547. IN LPCTSTR szPath
  548. )
  549. /*++
  550. Routine Description:
  551. Returns TRUE if drive referenced is a network drive as opposed to
  552. on on the local machine
  553. Arguments:
  554. IN LPCTSTR szPath
  555. path to look up
  556. Return Value:
  557. TRUE if szPath references a remote drive
  558. FALSE if szPath references a local drive
  559. --*/
  560. {
  561. TCHAR szRootDir[4]; // drive string
  562. TCHAR szServerName[MAX_COMPUTERNAME_LENGTH*2]; // server name buffer
  563. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1]; // local machine name
  564. DWORD dwBufLen; // buffer len. var.
  565. if (IsUncPath(szPath)) {
  566. if (GetServerFromUnc(szPath, szServerName)) {
  567. dwBufLen = MAX_COMPUTERNAME_LENGTH+1;
  568. GetComputerName (szComputerName, &dwBufLen);
  569. if (lstrcmpi(szServerName, szComputerName) == 0) {
  570. // shared on this machine so not remote
  571. return FALSE;
  572. } else {
  573. // not on this machine so it must be remote
  574. return TRUE;
  575. }
  576. }
  577. } else {
  578. // check the DOS path
  579. // see if this is a network or local drive
  580. szRootDir[0] = szPath[0]; // letter
  581. szRootDir[1] = szPath[1]; // colon
  582. szRootDir[2] = cBackslash;
  583. szRootDir[3] = 0;
  584. if (GetDriveType(szRootDir) == DRIVE_REMOTE) {
  585. return TRUE;
  586. } else {
  587. return FALSE;
  588. }
  589. }
  590. return FALSE;
  591. }
  592. DWORD
  593. ComputeFreeSpace (
  594. IN LPCTSTR szPath
  595. )
  596. /*++
  597. Routine Description:
  598. Function to return free space on drive referenced in path
  599. (NOTE: assumes DOS file path specification)
  600. Arguments:
  601. IN LPCTSTR szPath
  602. Path including Drive to check free space of. (MUST BE A DOS
  603. FILE Path)
  604. Return Value:
  605. Free space found in BYTES
  606. --*/
  607. {
  608. DWORD dwSectorsPerCluster;
  609. DWORD dwBytesPerSector;
  610. DWORD dwFreeClusters;
  611. DWORD dwClusters;
  612. TCHAR szRoot[MAX_PATH]; // root dir of path
  613. DWORD dwFreeBytes = 0;
  614. UINT nErrorMode;
  615. // disable windows error message popup
  616. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  617. lstrcpy (szRoot, GetRootFromPath(szPath));
  618. if (lstrlen(szRoot) > 0) {
  619. // we have a path to process so get info from the root
  620. if (GetDiskFreeSpace(szRoot, &dwSectorsPerCluster,
  621. &dwBytesPerSector, &dwFreeClusters, &dwClusters)) {
  622. ULONGLONG ullFreeBytes;
  623. ullFreeBytes =
  624. (ULONGLONG)dwFreeClusters *
  625. dwSectorsPerCluster * dwBytesPerSector;
  626. dwFreeBytes = (DWORD) ullFreeBytes;
  627. if( (ULONGLONG)dwFreeBytes != ullFreeBytes ) {
  628. //
  629. // Overflow has occured.
  630. //
  631. dwFreeBytes = 0xFFFFFFFF;
  632. }
  633. }
  634. } else {
  635. dwFreeBytes = 0xFFFFFFFF;
  636. }
  637. SetErrorMode (nErrorMode); // restore old error mode
  638. return dwFreeBytes;
  639. }
  640. BOOL
  641. IsShareNameUsed (
  642. IN LPCTSTR szServerName,
  643. IN LPCTSTR szShareName,
  644. IN OUT PDWORD pdwType,
  645. IN OUT LPTSTR pszPath
  646. )
  647. /*++
  648. Routine Description:
  649. Looks up a share name on a sever to determine if the name is in use
  650. and if so, what type of directory is shared.
  651. Arguments:
  652. IN LPCTSTR szServerName
  653. server name to look up share name on (NULL == the local machine)
  654. IN LPCTSTR szShareName
  655. share name to look up
  656. IN OUT PDWORD pdwType
  657. buffer to return share type in options are:
  658. NCDU_SHARE_IS_NOT_USED: name not found on server
  659. NCDU_SHARE_IS_CLIENT_TREE: name is a client distribution tree
  660. NCDU_SHARE_IS_SERVER_TOOLS: name is a server tool tree
  661. NCDU_SHARE_IS_OTHER_DIR: name is shared to some other dir.
  662. IN OUT LPTSTR pszPath
  663. if path is shared, then this is the path on the server that
  664. is shared
  665. Return Value:
  666. TRUE if share name is in use
  667. FALSE if the share name is not found on the server.
  668. --*/
  669. {
  670. LPTSTR szLocalPath; // local buffer to build path string in
  671. LPTSTR szLocalName; // pointer into path where sharename starts
  672. DWORD dwShareAttrib; // file attributes of share point
  673. DWORD dwBufLen; // buffer length variable
  674. BOOL bReturn = FALSE; // function return value
  675. DWORD dwLocalType; // share dir type
  676. PSHARE_INFO_2 psi2Data = NULL; // net info buffer pointer
  677. LPTSTR szReturnPath
  678. = (LPTSTR)cszEmptyString; // pointer to path string to return
  679. szLocalPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  680. if (szLocalPath != NULL) {
  681. // make share name into a UNC name using the appropriate machine
  682. lstrcpy (szLocalPath, cszDoubleBackslash);
  683. if (szServerName == NULL) {
  684. dwBufLen = MAX_COMPUTERNAME_LENGTH + 1;
  685. GetComputerName (&szLocalPath[2], &dwBufLen);
  686. } else {
  687. lstrcat (szLocalPath, szServerName);
  688. }
  689. lstrcat (szLocalPath, cszBackslash);
  690. szLocalName = &szLocalPath[lstrlen(szLocalPath)];
  691. lstrcpy (szLocalName, szShareName);
  692. TrimSpaces (szLocalName);
  693. // see if it's a valid path
  694. dwShareAttrib = QuietGetFileAttributes (szLocalPath);
  695. if (dwShareAttrib == 0xFFFFFFFF) {
  696. // it's not a valid file or dir, so
  697. bReturn = FALSE; // share name is not used
  698. szReturnPath = (LPTSTR)cszEmptyString;
  699. dwLocalType = NCDU_SHARE_IS_NOT_USED;
  700. } else {
  701. // it's a valid path so see if it's anything we want
  702. bReturn = TRUE;
  703. // terminate local path after server name for use in net API Call
  704. *(szLocalName - 1) = 0;
  705. // get share info
  706. if (NetShareGetInfo ((LPWSTR)szLocalPath, (LPWSTR)szShareName,
  707. 2L, (LPBYTE *)&psi2Data) == NERR_Success) {
  708. // successful call so return pointer to path string
  709. szReturnPath = psi2Data->shi2_path;
  710. } else {
  711. // function failed so return empty path
  712. szReturnPath = (LPTSTR)cszEmptyString;
  713. }
  714. // restore local path string
  715. *(szLocalName - 1) = cBackslash;
  716. // share is used, so see if it's a clients path
  717. if (*szReturnPath != 0) {
  718. if (ValidSharePath (szLocalPath) == 0) {
  719. dwLocalType = NCDU_SHARE_IS_CLIENT_TREE;
  720. } else if (ValidSrvToolsPath (szLocalPath) == 0) {
  721. dwLocalType = NCDU_SHARE_IS_SERVER_TOOLS;
  722. } else {
  723. dwLocalType = NCDU_SHARE_IS_OTHER_DIR;
  724. }
  725. } else {
  726. // no path name
  727. bReturn = FALSE;
  728. dwLocalType = NCDU_SHARE_IS_NOT_USED;
  729. }
  730. }
  731. FREE_IF_ALLOC (szLocalPath);
  732. } else {
  733. // unable to allocate memory
  734. bReturn = FALSE;
  735. dwLocalType = 0;
  736. }
  737. if (pdwType != NULL) {
  738. *pdwType = dwLocalType;
  739. }
  740. if (pszPath != NULL) {
  741. lstrcpy (pszPath, szReturnPath);
  742. }
  743. // free buffer created by net call
  744. if (psi2Data != NULL) NetApiBufferFree (psi2Data);
  745. return bReturn;
  746. }
  747. DWORD
  748. QuietGetFileAttributes (
  749. IN LPCTSTR lpszFileName
  750. )
  751. /*++
  752. Routine Description:
  753. Reads the attributes of the path in lpzsFileName without triggering
  754. any Windows error dialog if there's an OS error (e.g. drive not
  755. ready)
  756. Arguments:
  757. IN LPCTSTR lpszFileName
  758. path to retrieve attributes from
  759. Return Value:
  760. file attributes DWORD returned from GetFileAttributes or
  761. 0xFFFFFFFF if unable to open path.
  762. --*/
  763. {
  764. DWORD dwReturn;
  765. UINT nErrorMode;
  766. // disable windows error message popup
  767. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  768. dwReturn = GetFileAttributes (lpszFileName);
  769. SetErrorMode (nErrorMode); // restore old error mode
  770. return dwReturn;
  771. }
  772. BOOL
  773. GetSizeOfDirs (
  774. IN LPCTSTR szPath,
  775. IN BOOL bFlags,
  776. IN OUT PDWORD pdwSize
  777. )
  778. /*++
  779. Routine Description:
  780. Scans a directory and optionally a subdirectory to total the sizes
  781. of the files found.
  782. NOTE: This function will only process files that are < 4GB in size
  783. and dir paths that total less then 4GB total.
  784. Arguments:
  785. IN LPCTSTR szPath
  786. top dir or dir tree to scan.
  787. IN BOOL bFlags
  788. operation modification flags:
  789. 0 : specified path only.
  790. GSOD_INCLUDE_SUBDIRS: include sub dirs
  791. IN OUT PDWORD pdwSize
  792. buffer to return size in.
  793. Return Value:
  794. TRUE size returned in pdwSize
  795. FALSE error occurred
  796. --*/
  797. {
  798. HANDLE hSearch;
  799. HANDLE hFile;
  800. WIN32_FIND_DATA fdSearch;
  801. PDWORD pdwSizeBuffer;
  802. DWORD dwLocalSize = 0;
  803. DWORD dwPathAttrib;
  804. BOOL bSearching;
  805. LPTSTR szLocalPath;
  806. LPTSTR szSearchPath;
  807. LPTSTR szLocalFileName;
  808. DWORD dwFileSizeLow;
  809. DWORD dwFileSizeHigh;
  810. LPTSTR szThisFileName;
  811. BOOL bReturn;
  812. //
  813. // check path to see if it's a directory
  814. //
  815. dwPathAttrib = QuietGetFileAttributes (szPath);
  816. // if an invalid attribute or it's not a directory then return FALSE and set error
  817. if ((dwPathAttrib == 0xFFFFFFFF) ||
  818. ((dwPathAttrib & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)) {
  819. SetLastError (ERROR_BAD_PATHNAME);
  820. return FALSE;
  821. }
  822. //
  823. // Initialize size buffer
  824. //
  825. if (pdwSize == NULL) {
  826. pdwSizeBuffer = &dwLocalSize;
  827. } else {
  828. pdwSizeBuffer = pdwSize;
  829. }
  830. // get a local buffer for the path
  831. szSearchPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  832. szLocalPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  833. if ((szLocalPath != NULL) && (szSearchPath != NULL)) {
  834. // make a local copy of the input path
  835. lstrcpy (szLocalPath, szPath);
  836. lstrcpy (szSearchPath, szLocalPath);
  837. // make full path prefix for sub dir searches & filenames
  838. if (szLocalPath[lstrlen(szLocalPath)-1] != cBackslash) lstrcat (szLocalPath, cszBackslash);
  839. szLocalFileName = &szLocalPath[lstrlen(szLocalPath)];
  840. // make wildcard path for searching this directory
  841. lstrcat (szSearchPath, cszWildcardFile);
  842. //
  843. // start search of files in this path
  844. //
  845. hSearch = FindFirstFile (szSearchPath, &fdSearch);
  846. if (hSearch != INVALID_HANDLE_VALUE) {
  847. bSearching = TRUE;
  848. while (bSearching) {
  849. // if an alternate filename is defined, then use it, otherwise
  850. // use the regular name
  851. szThisFileName = ((fdSearch.cAlternateFileName[0] == 0) ?
  852. fdSearch.cFileName : fdSearch.cAlternateFileName);
  853. // if it's a dot or a dot dot (. or ..) dir, then skip
  854. if (!DotOrDotDotDir(szThisFileName)) {
  855. lstrcpy (szLocalFileName, szThisFileName);
  856. // if it's a dir and the SUB DIR flag is set, then
  857. // recurse through the next directory, otherwise
  858. // get the file size of this file and continue
  859. dwPathAttrib = QuietGetFileAttributes (szLocalPath);
  860. if ((dwPathAttrib & FILE_ATTRIBUTE_DIRECTORY) ==
  861. FILE_ATTRIBUTE_DIRECTORY) {
  862. // this is a directory, so call this routine again
  863. // if the sub-dir flag is set.
  864. if ((bFlags & GSOD_INCLUDE_SUBDIRS) == GSOD_INCLUDE_SUBDIRS) {
  865. if (!GetSizeOfDirs (szLocalPath, bFlags, pdwSizeBuffer)) {
  866. // this call returned an errror so propogate it
  867. // up the call stack and exit the loop here
  868. bSearching = FALSE;
  869. continue;
  870. }
  871. } else {
  872. // the caller doesn't want sub dirs so ignore it
  873. }
  874. } else {
  875. // this is a file so get the size of it and add
  876. // it to the total
  877. hFile = CreateFile (
  878. szLocalPath,
  879. GENERIC_READ,
  880. FILE_SHARE_READ | FILE_SHARE_WRITE,
  881. NULL,
  882. OPEN_EXISTING,
  883. FILE_ATTRIBUTE_NORMAL,
  884. NULL);
  885. if (hFile != INVALID_HANDLE_VALUE) {
  886. // then the file was opened successfully
  887. // go get it's size and add it to the total
  888. dwFileSizeLow = GetFileSize (hFile, &dwFileSizeHigh);
  889. if (dwFileSizeLow != 0xFFFFFFFF) {
  890. *pdwSizeBuffer += dwFileSizeLow;
  891. }
  892. // now close the file handle
  893. CloseHandle (hFile);
  894. } else {
  895. // unable to open file so skip it
  896. }
  897. }
  898. }
  899. bSearching = FindNextFile (hSearch, &fdSearch);
  900. }
  901. FindClose (hSearch);
  902. } else {
  903. // unable to start search so return 0 size
  904. }
  905. bReturn = TRUE;
  906. } else {
  907. // unable to allocate memory
  908. SetLastError (ERROR_OUTOFMEMORY);
  909. bReturn = FALSE;
  910. }
  911. FREE_IF_ALLOC (szLocalPath);
  912. FREE_IF_ALLOC (szSearchPath);
  913. return bReturn;
  914. }
  915. BOOL
  916. MediaPresent (
  917. IN LPCTSTR szPath,
  918. IN BOOL bPresentAndValid
  919. )
  920. /*++
  921. Routine Description:
  922. determines if the specified path is present and available
  923. Arguments:
  924. IN LPCTSTR szPath
  925. path to examine (Must be a DOS path)
  926. Return Value:
  927. TRUE: path is available
  928. FALSE: unable to find/open path
  929. --*/
  930. {
  931. TCHAR szDev[8];
  932. DWORD dwBytes = 0;
  933. DWORD dwAttrib;
  934. DWORD dwLastError = ERROR_SUCCESS;
  935. BOOL bMediaPresent = FALSE;
  936. UINT nErrorMode;
  937. if (!IsUncPath(szPath)) {
  938. // build device name string
  939. szDev[0] = szPath[0];
  940. szDev[1] = cColon;
  941. szDev[2] = cBackslash;
  942. szDev[3] = 0;
  943. // disable windows error message popup
  944. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  945. dwAttrib = QuietGetFileAttributes (szDev);
  946. if ((dwAttrib != 0xFFFFFFFF) && ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
  947. // if the root dir is a dir, then it must be present and formatted
  948. bMediaPresent = TRUE;
  949. } else {
  950. // otherwise see if it's present and not formatted or not present
  951. dwLastError = GetLastError();
  952. if (dwLastError == ERROR_NOT_READY) {
  953. // then no disk in drive
  954. bMediaPresent = FALSE;
  955. } else if ((dwLastError == ERROR_FILE_NOT_FOUND) ||
  956. #ifdef TERMSRV
  957. (dwLastError == ERROR_UNRECOGNIZED_MEDIA) ||
  958. (dwLastError == ERROR_SECTOR_NOT_FOUND)) {
  959. #else // TERMSRV
  960. (dwLastError == ERROR_UNRECOGNIZED_MEDIA)) {
  961. #endif // TERMSRV
  962. // then and UNFORMATTED disk is in drive
  963. if (bPresentAndValid) {
  964. // this isn't good enough if it's supposed to be formatted
  965. bMediaPresent = FALSE;
  966. } else {
  967. // we're just looking for a disk so this is OK
  968. bMediaPresent = TRUE;
  969. }
  970. }
  971. }
  972. SetErrorMode (nErrorMode); // restore old error mode
  973. } else {
  974. // assume UNC path devices are present
  975. bMediaPresent = TRUE;
  976. }
  977. return bMediaPresent;
  978. }
  979. BOOL
  980. FileExists (
  981. IN LPCTSTR szFileName
  982. )
  983. /*++
  984. Routine Description:
  985. Opens the file to test for it's presences and returns TRUE if the
  986. open was successful and FALSE if not.
  987. Arguments:
  988. file name to open
  989. ReturnValue:
  990. TRUE if file found
  991. FALSE if not.
  992. --*/
  993. {
  994. BOOL bMediaPresent;
  995. UINT nDriveType;
  996. DWORD dwAttr;
  997. nDriveType = GetDriveType((LPTSTR)szFileName);
  998. if ((nDriveType == DRIVE_REMOVABLE) || (nDriveType == DRIVE_CDROM)) {
  999. // see if a formatted drive is really there
  1000. bMediaPresent = MediaPresent(szFileName, TRUE);
  1001. } else {
  1002. // if drive is not removable, then assume it's there
  1003. bMediaPresent = TRUE;
  1004. }
  1005. // try to get inforation on the file
  1006. dwAttr = QuietGetFileAttributes ((LPTSTR)szFileName);
  1007. if (dwAttr == 0xFFFFFFFF) {
  1008. // unable to obtain attributes, so assume it's not there
  1009. // or we can't access it
  1010. return FALSE;
  1011. } else {
  1012. // found, so close it and return TRUE
  1013. return TRUE;
  1014. }
  1015. }
  1016. BOOL
  1017. IsBootDisk (
  1018. IN LPCTSTR szPath
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. examines the path (which should be the root dir of a floppy drive)
  1023. and looks for the "signature" files that indicate it's a bootable
  1024. (i.e. system) disk.
  1025. Arguments:
  1026. IN LPCTSTR szPath
  1027. drive path to look at
  1028. Return Value:
  1029. TRUE if one of the signature files was found
  1030. FALSE if not.
  1031. --*/
  1032. {
  1033. TCHAR szDrive[16];
  1034. LPTSTR szTestFile;
  1035. LPTSTR *szTryFile;
  1036. szTestFile = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  1037. if (szTestFile == NULL) {
  1038. SetLastError (ERROR_OUTOFMEMORY);
  1039. return FALSE; // unable to continue
  1040. }
  1041. if (!IsUncPath(szPath)) {
  1042. szDrive[0] = szPath[0]; // drive letter
  1043. szDrive[1] = szPath[1]; // colon
  1044. szDrive[2] = cBackslash;
  1045. szDrive[3] = 0; // terminator
  1046. for (szTryFile = (LPTSTR *)szBootIdFiles;
  1047. *szTryFile != NULL;
  1048. szTryFile++) {
  1049. lstrcpy (szTestFile, szDrive);
  1050. lstrcat (szTestFile, *szTryFile);
  1051. if (FileExists(szTestFile)) return TRUE;
  1052. }
  1053. // if we didn't bail out already, it must not be a bootable disk
  1054. return FALSE;
  1055. } else {
  1056. // unc path name automatically is not a bootable drive
  1057. return FALSE;
  1058. }
  1059. FREE_IF_ALLOC (szTestFile);
  1060. }
  1061. MEDIA_TYPE
  1062. GetDriveTypeFromPath (
  1063. IN LPCTSTR szPath
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. returns the drive type of the drive specified in the path argument
  1068. Arguments:
  1069. IN LPCTSTR szPath
  1070. path on drive to examine
  1071. Return Value:
  1072. MEDIA_TYPE value identifying drive type
  1073. --*/
  1074. {
  1075. HANDLE hFloppy;
  1076. DWORD dwRetSize;
  1077. DISK_GEOMETRY dgFloppy;
  1078. TCHAR szDevicePath[16];
  1079. UINT nDriveType;
  1080. UINT nErrorMode;
  1081. nDriveType = GetDriveType((LPTSTR)szPath);
  1082. // see if this is a remote disk and exit if it is.
  1083. if (nDriveType == DRIVE_REMOTE) return Unknown;
  1084. if ((nDriveType == DRIVE_REMOVABLE) || (nDriveType == DRIVE_CDROM)) {
  1085. // see if it's a UNC path and return unknown if so
  1086. if (IsUncPath(szPath)) return Unknown;
  1087. // it should be local and a DOS pathname so
  1088. // make device name from path
  1089. szDevicePath[0] = cBackslash;
  1090. szDevicePath[1] = cBackslash;
  1091. szDevicePath[2] = cPeriod;
  1092. szDevicePath[3] = cBackslash;
  1093. szDevicePath[4] = szPath[0]; // drive letter
  1094. szDevicePath[5] = szPath[1]; // colon
  1095. szDevicePath[6] = 0; // null terminator
  1096. // disable windows error message popup
  1097. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  1098. // open device to get type
  1099. hFloppy = CreateFile (
  1100. szDevicePath,
  1101. GENERIC_READ,
  1102. (FILE_SHARE_READ | FILE_SHARE_WRITE),
  1103. NULL,
  1104. OPEN_EXISTING,
  1105. FILE_ATTRIBUTE_NORMAL,
  1106. NULL);
  1107. if (hFloppy != INVALID_HANDLE_VALUE) {
  1108. // get drive information
  1109. if (!DeviceIoControl (hFloppy,
  1110. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1111. NULL, 0,
  1112. &dgFloppy,
  1113. sizeof(DISK_GEOMETRY),
  1114. &dwRetSize,
  1115. NULL) ){
  1116. // unable to get data so set to unknown
  1117. dgFloppy.MediaType = Unknown;
  1118. } // else return data from returned structure
  1119. CloseHandle (hFloppy);
  1120. } else {
  1121. // unable to open handle to device
  1122. dgFloppy.MediaType = Unknown;
  1123. }
  1124. SetErrorMode (nErrorMode); // reset error mode
  1125. }
  1126. return dgFloppy.MediaType;
  1127. }
  1128. BOOL
  1129. DotOrDotDotDir (
  1130. IN LPCTSTR szFileName
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. examines the filename in the parameter list to see if it is one
  1135. of the default subdirectories (e.g. the . or the .. dirs). This
  1136. routine assumes that the argument is a filename only. (i.e. NO
  1137. PATH!)
  1138. Arguments:
  1139. Filename to compare
  1140. Return Value:
  1141. TRUE if filename is either the . or the .. dir
  1142. FALSE if it is any other string
  1143. --*/
  1144. {
  1145. if (szFileName != NULL) { // check for null parameter
  1146. if (lstrcmp(szFileName, cszDot) == 0) {
  1147. return TRUE; // it's the . dir
  1148. } else if (lstrcmp(szFileName, cszDotDot) == 0) {
  1149. return TRUE; // it's the .. dir
  1150. } else {
  1151. return FALSE; // it's neither
  1152. }
  1153. } else {
  1154. return FALSE; // null filename, so not a . or .. dir
  1155. }
  1156. }
  1157. UINT
  1158. ValidSharePath (
  1159. IN LPCTSTR szPath
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. examines the path to see if it contains the "signature" file
  1164. that identifies the path as as that of a valid client
  1165. distribution directory tree.
  1166. Arguments:
  1167. IN LPCTSTR szPath
  1168. path to examine
  1169. Return Value:
  1170. ERROR_SUCCESS if it is
  1171. otherwise the ID of a string resource that describes
  1172. what was found and why it isn't a distribution tree
  1173. --*/
  1174. {
  1175. DWORD dwPathAttr;
  1176. UINT nReturn = 0;
  1177. LPTSTR szInfName;
  1178. szInfName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  1179. if (szInfName == NULL) {
  1180. SetLastError (ERROR_OUTOFMEMORY);
  1181. return NCDU_ERROR_NOMEMORY;
  1182. }
  1183. // validate share path by looking for INF file, display
  1184. // error box if necessary.
  1185. // Return 0 if valid
  1186. // return message string ID if not valid, for what ever reason.
  1187. //
  1188. dwPathAttr = QuietGetFileAttributes((LPTSTR)szPath);
  1189. if (dwPathAttr == 0xFFFFFFFF) {
  1190. // an error occured...
  1191. nReturn = NCDU_UNABLE_READ_DIR;
  1192. } else {
  1193. if ((dwPathAttr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
  1194. // so far so good!
  1195. lstrcpy (szInfName, szPath);
  1196. if (szInfName[lstrlen(szInfName)-1] != cBackslash) lstrcat(szInfName, cszBackslash);
  1197. lstrcat (szInfName, cszAppInfName);
  1198. dwPathAttr = QuietGetFileAttributes(szInfName);
  1199. if (dwPathAttr != 0xFFFFFFFF) {
  1200. nReturn = 0;
  1201. } else {
  1202. nReturn = NCDU_NOT_DIST_TREE;
  1203. }
  1204. } else {
  1205. nReturn = NCDU_PATH_NOT_DIR;
  1206. }
  1207. }
  1208. FREE_IF_ALLOC (szInfName);
  1209. return (nReturn);
  1210. }
  1211. UINT
  1212. ValidSrvToolsPath (
  1213. IN LPCTSTR szPath
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. examines the path to see if it contains the "signature" file
  1218. that identifies the path as as that of a valid server tools
  1219. distribution directory tree.
  1220. Arguments:
  1221. IN LPCTSTR szPath
  1222. path to examine
  1223. Return Value:
  1224. ERROR_SUCCESS if it is
  1225. otherwise the ID of a string resource that describes
  1226. what was found and why it isn't a server tools tree
  1227. --*/
  1228. {
  1229. UINT nReturn = 0;
  1230. DWORD dwAttrib;
  1231. LPTSTR szClientPath;
  1232. szClientPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  1233. if (szClientPath == NULL) {
  1234. SetLastError (ERROR_OUTOFMEMORY);
  1235. return NCDU_ERROR_NOMEMORY;
  1236. }
  1237. // make local copy of the path
  1238. lstrcpy (szClientPath, szPath);
  1239. // get file attributes of dir path to make sure it's really a dir
  1240. dwAttrib = QuietGetFileAttributes (szClientPath);
  1241. if ((dwAttrib != 0xFFFFFFFF) && ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
  1242. if (szClientPath[lstrlen(szClientPath)-1] != cBackslash) lstrcat(szClientPath, cszBackslash);
  1243. lstrcat (szClientPath, cszSrvToolSigFile);
  1244. // now get the file attributes of the signature file to see if this is a valid path
  1245. dwAttrib = QuietGetFileAttributes (szClientPath);
  1246. if (dwAttrib != 0xFFFFFFFF) {
  1247. nReturn = 0;
  1248. } else {
  1249. nReturn = NCDU_NOT_TOOL_TREE;
  1250. }
  1251. } else {
  1252. nReturn = NCDU_PATH_NOT_DIR;
  1253. }
  1254. FREE_IF_ALLOC (szClientPath);
  1255. return (nReturn);
  1256. }
  1257. BOOL
  1258. IsPathADir (
  1259. IN LPCTSTR szPath
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. Checks the path passed in to see if it's a directory or not
  1264. Arguments:
  1265. IN LPCTSTR szPath
  1266. path to check
  1267. Return Value:
  1268. TRUE if path is a valid directory
  1269. FALSE if unable to find path or if path is not a directory
  1270. --*/
  1271. {
  1272. DWORD dwAttrib;
  1273. dwAttrib = QuietGetFileAttributes (szPath);
  1274. if ((dwAttrib != 0xffffffff) &&
  1275. ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
  1276. return TRUE;
  1277. } else {
  1278. return FALSE;
  1279. }
  1280. }
  1281. static
  1282. DWORD
  1283. GetSectorSize (
  1284. IN LPTSTR szDriveName
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. Returns the sector size in bytes of the disk drive specified in the
  1289. argument list.
  1290. Arguments:
  1291. IN LPTSTR szDriveName ASCIZ of drive to return data for (e.g. "C:")
  1292. Return Value:
  1293. size of disk sector in bytes,
  1294. 0xFFFFFFFF ((DWORD)-1) if error, error retrieved using GetLastError()
  1295. --*/
  1296. {
  1297. BOOL bStatus;
  1298. LONG lReturn = 0xFFFFFFFF;
  1299. DWORD dwBytesReturned;
  1300. HANDLE hDrive;
  1301. DISK_GEOMETRY dgBuffer;
  1302. // open existing file (root drive)
  1303. hDrive = CreateFile (
  1304. szDriveName,
  1305. GENERIC_READ,
  1306. (FILE_SHARE_READ | FILE_SHARE_WRITE),
  1307. NULL,
  1308. OPEN_EXISTING,
  1309. 0L,
  1310. NULL);
  1311. if (hDrive != INVALID_HANDLE_VALUE) {
  1312. // get disk inoformation
  1313. bStatus = DeviceIoControl(
  1314. hDrive,
  1315. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1316. NULL,
  1317. 0L,
  1318. &dgBuffer,
  1319. sizeof(dgBuffer),
  1320. &dwBytesReturned,
  1321. NULL);
  1322. // if data was returned by IOCTL, then return
  1323. // sector size other wise return error value
  1324. if (bStatus) {
  1325. lReturn = dgBuffer.BytesPerSector;
  1326. } else {
  1327. lReturn = 0xFFFFFFFF;
  1328. }
  1329. CloseHandle (hDrive); // don't forget to close the handle
  1330. } else {
  1331. // unable to open device
  1332. lReturn = 0xFFFFFFFF;
  1333. }
  1334. return lReturn;
  1335. }
  1336. static
  1337. LONG
  1338. CopyFatBootSectorToBuffer (
  1339. IN LPTSTR szBootDrive,
  1340. IN LPBYTE *pOutputBuffer
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. Copies the first sector of the volume to the specified file
  1345. Arguments:
  1346. IN LPTSTR szBootDrive volume to locate boot sector on
  1347. IN LPBYTE *pOutputBuffer address of pointer to buffer created
  1348. Return Value:
  1349. Win 32 Status Value:
  1350. ERROR_SUCCESS The routine complete all operations normally
  1351. --*/
  1352. {
  1353. LONG lStatus = ERROR_SUCCESS;
  1354. BOOL bStatus = FALSE;
  1355. DWORD dwByteCount;
  1356. DWORD dwBytesRead;
  1357. HANDLE hDrive;
  1358. LPBYTE pBootSector;
  1359. dwByteCount = GetSectorSize (szBootDrive);
  1360. if (dwByteCount != 0xFFFFFFFF) {
  1361. // allocate buffer to read data into
  1362. pBootSector = (LPBYTE)GlobalAlloc(GPTR, dwByteCount);
  1363. } else {
  1364. pBootSector = NULL;
  1365. lStatus = GetLastError();
  1366. }
  1367. if (pBootSector != NULL) {
  1368. // if memory allocated successfully, then open drive
  1369. hDrive = CreateFile (
  1370. szBootDrive,
  1371. GENERIC_READ,
  1372. (FILE_SHARE_READ | FILE_SHARE_WRITE),
  1373. NULL,
  1374. OPEN_EXISTING,
  1375. FILE_ATTRIBUTE_NORMAL,
  1376. NULL);
  1377. if (hDrive != INVALID_HANDLE_VALUE) {
  1378. SetFilePointer (hDrive, 0, NULL, FILE_BEGIN); // go to beginning
  1379. bStatus = ReadFile (
  1380. hDrive,
  1381. pBootSector,
  1382. dwByteCount,
  1383. &dwBytesRead,
  1384. NULL);
  1385. if (bStatus) {
  1386. *pOutputBuffer = pBootSector;
  1387. lStatus = ERROR_SUCCESS;
  1388. } else {
  1389. // unable to read the file (drive) so return error
  1390. *pOutputBuffer = NULL;
  1391. lStatus = GetLastError();
  1392. }
  1393. // close handle now that we're done with it.
  1394. CloseHandle (hDrive);
  1395. } else {
  1396. // unable to open drive
  1397. *pOutputBuffer = NULL;
  1398. lStatus = GetLastError();
  1399. }
  1400. } else {
  1401. lStatus = ERROR_OUTOFMEMORY;
  1402. }
  1403. return lStatus;
  1404. }
  1405. DWORD
  1406. GetBootDiskDosVersion (
  1407. IN LPCTSTR szPath
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. examines the boot sector of the disk in the drive described in the
  1412. path variable and returns the MAJOR version of the OS that
  1413. formatted the disk.
  1414. Arguments:
  1415. IN LPCTSTR szPath
  1416. path containing drive to examine
  1417. Return Value:
  1418. Major version of MS-DOS that formatted the disk.
  1419. Zero is returned when:
  1420. -- the boot sector on the drive cannot be read
  1421. -- the drive is not a bootable drive
  1422. --*/
  1423. {
  1424. PDOS_BOOT_SECTOR pBootSector = NULL;
  1425. TCHAR szDrive[8];
  1426. DWORD dwReturn;
  1427. if (IsBootDisk(szPath)) {
  1428. szDrive[0] = cBackslash;
  1429. szDrive[1] = cBackslash;
  1430. szDrive[2] = cPeriod;
  1431. szDrive[3] = cBackslash;
  1432. szDrive[4] = szPath[0];
  1433. szDrive[5] = szPath[1];
  1434. szDrive[6] = 0;
  1435. szDrive[7] = 0;
  1436. if (CopyFatBootSectorToBuffer (
  1437. szDrive, (LPBYTE *)&pBootSector) == ERROR_SUCCESS) {
  1438. dwReturn = (pBootSector->bsOemName[5] - '0');
  1439. } else {
  1440. dwReturn = 0;
  1441. }
  1442. // free buffer allocated in CopyFatBootSectorToBuffer call.
  1443. FREE_IF_ALLOC (pBootSector);
  1444. } else {
  1445. dwReturn = 0;
  1446. }
  1447. return dwReturn;
  1448. }
  1449. DWORD
  1450. GetClusterSizeOfDisk (
  1451. IN LPCTSTR szPath
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. returns the cluster size (in bytes) of the disk in the path
  1456. Arguments:
  1457. Path containing disk drive to examine
  1458. Return Value:
  1459. cluster size (allocation unit size) of disk in bytes.
  1460. if the function cannot determine the cluster size, then
  1461. a value of 512 for floppy disk or 4096 for hard disks will
  1462. be returned.
  1463. --*/
  1464. {
  1465. DWORD dwSectorsPerCluster;
  1466. DWORD dwBytesPerSector;
  1467. DWORD dwFreeClusters;
  1468. DWORD dwClusters;
  1469. TCHAR szRoot[4]; // root dir of path
  1470. DWORD dwClusterSize = 0;
  1471. UINT nErrorMode;
  1472. // disable windows error message popup
  1473. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  1474. if (!IsUncPath(szPath)) {
  1475. szRoot[0] = szPath[0]; // drive letter
  1476. szRoot[1] = szPath[1]; // colon
  1477. szRoot[2] = cBackslash; // backslash
  1478. szRoot[3] = 0; // null terminator
  1479. if (GetDiskFreeSpace(szRoot, &dwSectorsPerCluster,
  1480. &dwBytesPerSector, &dwFreeClusters, &dwClusters)) {
  1481. dwClusterSize = dwSectorsPerCluster * dwBytesPerSector;
  1482. } else {
  1483. if (GetDriveType (szRoot) == DRIVE_FIXED) {
  1484. dwClusterSize = 4096;
  1485. } else {
  1486. dwClusterSize = 512;
  1487. }
  1488. }
  1489. } else {
  1490. dwClusterSize = 4096;
  1491. }
  1492. SetErrorMode (nErrorMode); // restore old error mode
  1493. return dwClusterSize;
  1494. }
  1495. DWORD
  1496. QuietGetFileSize (
  1497. IN LPCTSTR szPath
  1498. )
  1499. /*++
  1500. Routine Description:
  1501. Returns the size of the file passed in the arg list ( file sizz < 4GB)
  1502. while supressing any windows system error messages.
  1503. Arguments:
  1504. path to file to size
  1505. Return Value:
  1506. size of the file (if less then 4GB) or 0xFFFFFFFF if error
  1507. --*/
  1508. {
  1509. HANDLE hFile;
  1510. DWORD dwFileSizeLow, dwFileSizeHigh;
  1511. DWORD dwReturn;
  1512. UINT nErrorMode;
  1513. // disable windows error message popup
  1514. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  1515. // get the size of the file and add it to the total
  1516. hFile = CreateFile (
  1517. szPath,
  1518. GENERIC_READ,
  1519. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1520. NULL,
  1521. OPEN_EXISTING,
  1522. FILE_ATTRIBUTE_NORMAL,
  1523. NULL);
  1524. if (hFile != INVALID_HANDLE_VALUE) {
  1525. // then the file was opened successfully
  1526. // go get it's size
  1527. dwFileSizeLow = GetFileSize (hFile, &dwFileSizeHigh);
  1528. dwReturn = dwFileSizeLow;
  1529. // now close the file handle
  1530. CloseHandle (hFile);
  1531. } else {
  1532. // unable to open file so return error
  1533. dwReturn = 0xFFFFFFFF;
  1534. }
  1535. SetErrorMode (nErrorMode); // restore old error mode
  1536. return dwReturn;
  1537. }
  1538.