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.

1034 lines
31 KiB

  1. //#pragma title( "EnumVols.cpp - Volume Enumeration" )
  2. /*
  3. Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved.
  4. ===============================================================================
  5. Module - enumvols.hpp
  6. System - SDResolve
  7. Author - Christy Boles
  8. Created - 97/06/27
  9. Description - Classes used to generate a list of pathnames, given a list of paths and/or
  10. machine names.
  11. Updates -
  12. ===============================================================================
  13. */
  14. #include <stdio.h>
  15. #include "stdafx.h"
  16. #include <lm.h>
  17. #include <assert.h>
  18. #include "Common.hpp"
  19. #include "Err.hpp"
  20. #include "ErrDct.hpp"
  21. #include "UString.hpp"
  22. #include "EnumVols.hpp"
  23. #include "BkupRstr.hpp"
  24. #define BUF_ENTRY_LENGTH (3)
  25. extern WCHAR * // ret -machine-name prefix of pathname if pathname is a UNC path, otherwise returns NULL
  26. GetMachineName(
  27. const LPWSTR pathname // in -pathname from which to extract machine name
  28. );
  29. extern TErrorDct err;
  30. extern bool silent;
  31. bool // ret -true if name begins with "\\" has at least 3 total chars, and no other '\'
  32. IsMachineName(
  33. const LPWSTR name // in -possible machine name to check
  34. )
  35. {
  36. assert( name );
  37. WCHAR * c = NULL; // used to traverse the name (will stay NULL if prefix check fails)
  38. if ( name[0] == L'\\' && name[1] == L'\\' ) // check for "\\" prefix
  39. {
  40. for ( c = name + 2 ; *c && *c != L'\\' ; c++ ) // check rest of string
  41. ;
  42. }
  43. return ( c && *c != L'\\' ); // <=> prefix check worked && we made it to the end of the string without hitting a '\'
  44. }
  45. bool // ret -true if name is of the form \\machine\share
  46. IsShareName(
  47. const LPWSTR name // in -string to check
  48. )
  49. {
  50. assert( name );
  51. WCHAR * c = NULL; // used to traverse the name (will stay NULL if prefix check fails)
  52. bool skip = true;
  53. if ( name[0] == L'\\' && name[1] == L'\\' ) // check for "\\" prefix
  54. {
  55. for ( c = name + 2 ; *c && (*c != L'\\' || skip) ; c++ ) // check rest of string
  56. {
  57. if ( *c == L'\\' )
  58. skip = false;
  59. }
  60. }
  61. return ( c && *c != L'\\' );
  62. }
  63. bool
  64. IsUNCName(
  65. const LPWSTR name // in - string to check
  66. )
  67. {
  68. return ( name[0] == L'\\' && name[1] == L'\\' && name[2]!=0 );
  69. }
  70. bool
  71. ContainsWildcard(
  72. WCHAR const * string
  73. )
  74. {
  75. bool wc = false;
  76. WCHAR const * curr = string;
  77. if ( string )
  78. {
  79. while ( *curr && ! wc )
  80. {
  81. if ( *curr == L'*'
  82. || *curr == L'?'
  83. || *curr == L'#'
  84. )
  85. {
  86. wc = true;
  87. }
  88. curr++;
  89. }
  90. }
  91. return wc;
  92. }
  93. /************************************************************************************
  94. TPathNode Implementation
  95. *************************************************************************************/
  96. TPathNode::TPathNode(
  97. const LPWSTR name // -in path-name for this node
  98. )
  99. {
  100. assert( name ); // name should always be a valid
  101. assert( UStrLen(name) <= MAX_PATH ); // string, shorter than MAX_PATH
  102. safecopy(path,name);
  103. iscontainer = true;
  104. FindServerName();
  105. LookForWCChars();
  106. }
  107. void
  108. TPathNode::Display() const
  109. {
  110. wprintf(L"%s\n",path);
  111. wprintf(L"%s\n",server);
  112. }
  113. void
  114. TPathNode::LookForWCChars()
  115. {
  116. ContainsWC(ContainsWildcard(path));
  117. }
  118. void
  119. TPathNode::FindServerName()
  120. {
  121. WCHAR volRoot[MAX_PATH];
  122. WCHAR tempName[MAX_PATH];
  123. UINT driveType;
  124. DWORD rc = 0;
  125. REMOTE_NAME_INFO info;
  126. DWORD sizeBuffer = (sizeof info);
  127. WCHAR * machine;
  128. if ( IsMachineName(path) )
  129. {
  130. safecopy(server,path);
  131. }
  132. else
  133. {
  134. safecopy(tempName,path);
  135. if ( path[0] != L'\\' || path[1] != L'\\' ) // get the unc name
  136. {
  137. swprintf(volRoot, L"%-3.3s", path);
  138. driveType = GetDriveType(volRoot);
  139. switch ( driveType )
  140. {
  141. case DRIVE_REMOTE:
  142. rc = WNetGetUniversalName(volRoot,
  143. REMOTE_NAME_INFO_LEVEL,
  144. (PVOID)&info,
  145. &sizeBuffer);
  146. switch ( rc )
  147. {
  148. case 0:
  149. safecopy(tempName, info.lpUniversalName);
  150. swprintf(volRoot,L"%s\\%s",tempName,path+3);
  151. safecopy(path,volRoot);
  152. break;
  153. case ERROR_NOT_CONNECTED:
  154. break;
  155. default:
  156. err.SysMsgWrite(ErrE, rc, DCT_MSG_GET_UNIVERSAL_NAME_FAILED_SD,
  157. path, rc);
  158. }
  159. break;
  160. }
  161. }
  162. machine = GetMachineName(path);
  163. if ( machine )
  164. {
  165. safecopy(server,machine);
  166. delete machine;
  167. }
  168. else
  169. {
  170. server[0] = 0;
  171. }
  172. }
  173. }
  174. DWORD // ret-0=path exists, ERROR_PATH_NOT_FOUND=path does not exist
  175. TPathNode::VerifyExists()
  176. {
  177. DWORD rc = 0;
  178. WCHAR wname[MAX_PATH];
  179. int len;
  180. HANDLE hFind;
  181. WIN32_FIND_DATAW findEntry;
  182. SERVER_INFO_100 * servInfo = NULL;
  183. SHARE_INFO_0 * shareInfo = NULL;
  184. safecopy(wname,path);
  185. if ( IsMachineName(wname) )
  186. {
  187. rc = NetServerGetInfo(wname,100,(LPBYTE *)&servInfo);
  188. switch ( rc )
  189. {
  190. case NERR_Success:
  191. break;
  192. case ERROR_BAD_NETPATH:
  193. rc = ERROR_PATH_NOT_FOUND;
  194. break;
  195. default:
  196. err.SysMsgWrite(ErrW,rc,DCT_MSG_SERVER_GETINFO_FAILED_SD,wname,rc);
  197. break;
  198. }
  199. if ( servInfo )
  200. {
  201. NetApiBufferFree(servInfo);
  202. }
  203. }
  204. else if ( IsShareName(wname) )
  205. {
  206. int ch;
  207. for ( ch = 2; wname[ch]!= L'\\' && wname[ch] ; ch++ )
  208. ;
  209. MCSVERIFY(wname[ch] == L'\\' );
  210. wname[ch] = 0;
  211. rc = NetShareGetInfo(wname,wname+ch+1,0,(LPBYTE *)&shareInfo);
  212. wname[ch] = L'\\';
  213. switch ( rc )
  214. {
  215. case NERR_NetNameNotFound:
  216. rc = ERROR_PATH_NOT_FOUND;
  217. break;
  218. case ERROR_SUCCESS:
  219. NetApiBufferFree(shareInfo);
  220. break;
  221. default:
  222. err.SysMsgWrite(ErrW,rc,DCT_MSG_SHARE_GETINFO_FAILED_SD,wname,rc);
  223. break;
  224. }
  225. }
  226. else
  227. {
  228. iscontainer = false;
  229. if ( wname[len = UStrLen(wname) - 1] == '\\' ) // len is the index of the last character (before NULL)
  230. {
  231. wname[len] = '\0'; // remove trailing backslash
  232. len--;
  233. }
  234. // do a 'find' on this file w/o wildcards, in case it is a file
  235. hFind = FindFirstFileW(wname, &findEntry);
  236. if ( hFind == INVALID_HANDLE_VALUE )
  237. { // it's not a file, lets see if it's a directory
  238. // do a find with \*.* appended
  239. validalone = false;
  240. UStrCpy(wname + len + 1,"\\*.*",DIM(wname) - len);
  241. hFind = FindFirstFileW(wname,&findEntry);
  242. if ( hFind == INVALID_HANDLE_VALUE )
  243. {
  244. rc = ERROR_PATH_NOT_FOUND;
  245. }
  246. iscontainer = true;
  247. wname[len+1] = 0;
  248. }
  249. else
  250. {
  251. validalone = true;
  252. if ( findEntry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  253. {
  254. iscontainer = true;
  255. }
  256. FindClose(hFind);
  257. }
  258. }
  259. return rc;
  260. }
  261. DWORD // ret- 0=successful, ERROR_PRIVILEGE_NOT_HELD otherwise
  262. TPathNode::VerifyBackupRestore()
  263. {
  264. DWORD rc = 0;
  265. if ( ! GetBkupRstrPriv(server) )
  266. {
  267. rc = ERROR_PRIVILEGE_NOT_HELD;
  268. }
  269. return rc;
  270. }
  271. // GetRootPath finds the root path of a volume. This is needed so we can call
  272. // GetVolumeInformation to find out things like whether this volume supports ACLs
  273. // This is fairly simplistic, and works by counting the backslashes in the path
  274. DWORD // ret- 0 or OS return code
  275. GetRootPath(
  276. WCHAR * rootpath, // out- path to root of volume
  277. WCHAR const * path // in - path within some volume
  278. )
  279. {
  280. DWORD rc = 0;
  281. DWORD i = 0;
  282. DWORD slashcount = 1;
  283. bool unc = false;
  284. WCHAR tempPath[MAX_PATH];
  285. SHARE_INFO_2 * sInfo;
  286. if ( path[0] == L'\\' && path[1] == L'\\' )
  287. {
  288. slashcount = 4;
  289. unc = true;
  290. }
  291. for (i = 0 ; path[i] && slashcount && i < DIM(tempPath) ; i++ )
  292. {
  293. tempPath[i] = path[i];
  294. if ( tempPath[i] == L'\\' )
  295. {
  296. slashcount--;
  297. }
  298. }
  299. if ( tempPath[i-1] == L'\\' )
  300. {
  301. tempPath[i] = 0;
  302. }
  303. else
  304. {
  305. tempPath[i] = L'\\' ;
  306. tempPath[i+1] = 0;
  307. i++;
  308. }
  309. // now rootpath contains either D:\ or \\machine\share\ .
  310. if ( unc )
  311. {
  312. // remove the trailing slash from the sharename
  313. if ( tempPath[i] == 0 )
  314. {
  315. i--;
  316. }
  317. if ( tempPath[i] == L'\\' )
  318. {
  319. tempPath[i] = 0;
  320. }
  321. // find the beginning of the share name
  322. while ( ( i > 0 ) && tempPath[i] != L'\\' )
  323. i--;
  324. if ( i < 3 )
  325. {
  326. MCSVERIFY(FALSE);
  327. rc = ERROR_INVALID_PARAMETER;
  328. }
  329. else
  330. {
  331. tempPath[i] = 0;
  332. }
  333. rc = NetShareGetInfo(tempPath,tempPath+i+1,2,(LPBYTE*)&sInfo);
  334. if ( ! rc )
  335. {
  336. swprintf(rootpath,L"%s\\%c$\\",tempPath,sInfo->shi2_path[0]);
  337. NetApiBufferFree(sInfo);
  338. }
  339. }
  340. else
  341. {
  342. UStrCpy(rootpath,tempPath);
  343. }
  344. return rc;
  345. }
  346. DWORD
  347. TPathNode::VerifyPersistentAcls() // ret- 0=Yes, ERROR_NO_SECURITY_ON_OBJECT or OS error code
  348. {
  349. DWORD rc = 0;
  350. DWORD maxcomponentlen; // will be used as args for GetVolumeInformation
  351. DWORD flags;
  352. UINT errmode;
  353. WCHAR rootpath[MAX_PATH];
  354. WCHAR fstype[MAX_PATH];
  355. errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // set this to prevent message box when
  356. // called on removable media drives which are empty
  357. if ( ! IsMachineName(path) )
  358. {
  359. rc = GetRootPath(rootpath,path);
  360. if ( ! rc )
  361. {
  362. if ( !GetVolumeInformation(rootpath,NULL,0,NULL,&maxcomponentlen,&flags,fstype,DIM(fstype)) )
  363. {
  364. rc = GetLastError();
  365. if ( rc != ERROR_NOT_READY )
  366. {
  367. err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_GET_VOLUME_INFO_FAILED_SD,rootpath,GetLastError());
  368. }
  369. }
  370. else
  371. {
  372. SetErrorMode(errmode); // restore error mode to its prior state
  373. if (!( FS_PERSISTENT_ACLS & flags) )
  374. {
  375. rc = ERROR_NO_SECURITY_ON_OBJECT;
  376. }
  377. }
  378. }
  379. }
  380. return rc;
  381. }
  382. // This function is used when expanding wildcards in server names. It replaces server field with the new name,
  383. // and if the path is a UNC, it changes the server component of the path.
  384. void
  385. TPathNode::SetServerName(
  386. UCHAR const * name // in - new server name
  387. )
  388. {
  389. if ( IsUNCName(path) )
  390. {
  391. WCHAR newpath[MAX_PATH];
  392. int len = UStrLen(server);
  393. swprintf(newpath,L"%S%s",name,path+len);
  394. safecopy(path,newpath);
  395. }
  396. safecopy(server,name);
  397. }
  398. /************************************************************************************
  399. TPathList Implementation
  400. *************************************************************************************/
  401. TPathList::TPathList()
  402. {
  403. numServers = 0;
  404. numPaths = 0;
  405. }
  406. TPathList::~TPathList()
  407. {
  408. TPathNode * node;
  409. for (node = (TPathNode *)Head() ; Count() ; node = (TPathNode *)Head() )
  410. {
  411. Remove(node);
  412. delete node;
  413. }
  414. }
  415. // enumerate the nodes in the list, and display the name of each - used for debugging purposes
  416. void
  417. TPathList::Display() const
  418. {
  419. TPathNode * node;
  420. TNodeListEnum displayenum;
  421. err.DbgMsgWrite(0,L"%ld servers, %ld total paths\n", numServers, numPaths);
  422. for ( node = (TPathNode *)displayenum.OpenFirst(this) ;
  423. node ;
  424. node = (TPathNode *)displayenum.Next()
  425. )
  426. {
  427. node->Display();
  428. }
  429. displayenum.Close();
  430. }
  431. void
  432. TPathList::OpenEnum()
  433. {
  434. tenum.Open(this);
  435. }
  436. // Return the name from the next node in the enumeration
  437. // Returns NULL if no more nodes in the list
  438. // OpenEnum() must be called before calling Next();
  439. WCHAR *
  440. TPathList::Next()
  441. {
  442. TPathNode * pn = (TPathNode *)tenum.Next();
  443. LPWSTR result;
  444. if ( pn )
  445. result = pn->GetPathName();
  446. else
  447. result = NULL;
  448. return result;
  449. }
  450. void
  451. TPathList::CloseEnum()
  452. {
  453. tenum.Close();
  454. }
  455. bool // ret -returns true if path added, false if path too long
  456. TPathList::AddPath(
  457. const LPWSTR path, // in -path to add to list
  458. DWORD verifyFlags // in -indicates which types of verification to perform
  459. )
  460. {
  461. TPathNode * pnode;
  462. bool error = false;
  463. bool messageshown = false;
  464. DWORD rc = 0;
  465. WCHAR fullpath[MAX_PATH];
  466. if ( UStrLen(path) >= MAX_PATH )
  467. {
  468. err.MsgWrite(ErrW,DCT_MSG_PATH_TOO_LONG_SD,path,MAX_PATH);
  469. messageshown = true;
  470. error = true;
  471. }
  472. _wfullpath(fullpath,path,DIM(fullpath));
  473. pnode = new TPathNode(fullpath);
  474. if (!pnode)
  475. return true;
  476. if ( ! ContainsWildcard(pnode->GetServerName()) )
  477. {
  478. if ( verifyFlags & VERIFY_EXISTS )
  479. {
  480. if ( rc = pnode->VerifyExists() )
  481. {
  482. error = true;
  483. }
  484. }
  485. if ( !error && ( verifyFlags & VERIFY_BACKUPRESTORE) )
  486. {
  487. if ( rc = pnode->VerifyBackupRestore() )
  488. {
  489. // WCHAR * server = pnode->GetServerName();
  490. }
  491. }
  492. if ( !error && (verifyFlags & VERIFY_PERSISTENT_ACLS ) )
  493. {
  494. rc = pnode->VerifyPersistentAcls();
  495. if ( rc == ERROR_NO_SECURITY_ON_OBJECT )
  496. {
  497. err.MsgWrite(ErrW,DCT_MSG_NO_ACLS_S,fullpath);
  498. error = true;
  499. messageshown = true;
  500. }
  501. }
  502. }
  503. if ( ! error )
  504. {
  505. AddPathToList(pnode);
  506. numPaths++; // increment count of paths
  507. }
  508. else if ( !messageshown )
  509. {
  510. // need to include an error code here.
  511. if ( ! rc )
  512. {
  513. err.MsgWrite(ErrE,DCT_MSG_PATH_NOT_FOUND_S,fullpath);
  514. }
  515. else
  516. {
  517. err.SysMsgWrite(ErrE,rc,DCT_MSG_CANNOT_READ_PATH_SD,fullpath,rc);
  518. }
  519. delete pnode;
  520. }
  521. else
  522. delete pnode;
  523. return error;
  524. }
  525. void
  526. TPathList::Clear()
  527. {
  528. TNodeListEnum tEnum;
  529. TPathNode * pNode;
  530. TPathNode * pNext;
  531. for ( pNode = (TPathNode *)tEnum.OpenFirst(this) ; pNode ; pNode = pNext )
  532. {
  533. pNext = (TPathNode *)tEnum.Next();
  534. Remove(pNode);
  535. delete pNode;
  536. }
  537. }
  538. void
  539. TPathList::AddPathToList(
  540. TPathNode * pNode // in - path to add to the list
  541. )
  542. {
  543. // set the IsFirstPathFromMachine property
  544. TNodeListEnum tEnum;
  545. TPathNode * currNode;
  546. bool machineFound = false;
  547. WCHAR * myMachine = GetMachineName(pNode->GetPathName());
  548. WCHAR * currMachine;
  549. for ( currNode = (TPathNode *)tEnum.OpenFirst(this)
  550. ; currNode && !machineFound
  551. ; currNode = (TPathNode *)tEnum.Next() )
  552. {
  553. currMachine = GetMachineName(currNode->GetPathName());
  554. if ( currMachine && myMachine )
  555. {
  556. if ( !UStrICmp(currMachine,myMachine) )
  557. {
  558. machineFound = true;
  559. }
  560. }
  561. else
  562. {
  563. if ( !currMachine && ! myMachine )
  564. {
  565. machineFound = true;
  566. }
  567. }
  568. if ( currMachine )
  569. delete [] currMachine;
  570. }
  571. if ( myMachine )
  572. delete [] myMachine;
  573. tEnum.Close();
  574. pNode->IsFirstPathFromMachine(!machineFound);
  575. InsertBottom((TNode *)pNode);
  576. }
  577. // AddVolsOnMachine generates a list of volumes on the machine mach, checks for the administrative share
  578. // for each volume, and adds NTFS shared volumes to the pathlist
  579. DWORD
  580. TVolumeEnum::Open(
  581. WCHAR const * serv, // in - server to enumerate volumes on
  582. DWORD verifyflgs, // in - flags indicating what to verify about each volume (i.e. NTFS)
  583. BOOL logmsgs // in - flag whether to print diagnostic messages
  584. )
  585. {
  586. NET_API_STATUS res;
  587. if ( isOpen )
  588. Close();
  589. if ( serv )
  590. safecopy(server,serv);
  591. else
  592. server[0] = 0;
  593. resume_handle = 0;
  594. pbuf = NULL;
  595. verbose = logmsgs;
  596. verifyFlags = verifyflgs;
  597. errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // set this to prevent message box when
  598. // called on removable media drives which are empty
  599. if ( ! bLocalOnly )
  600. {
  601. res = NetServerDiskEnum(server,0,&pbuf,MAXSIZE, &numread, &total, &resume_handle);
  602. if (NERR_Success != res )
  603. {
  604. err.SysMsgWrite(ErrW, res, DCT_MSG_DRIVE_ENUM_FAILED_SD,server, res);
  605. isOpen = FALSE;
  606. }
  607. if ( ! res )
  608. {
  609. drivelist = (WCHAR *) pbuf; // NetServerDiskEnum returns an array of
  610. isOpen = true; // WCHAR[3] elements (of the form <DriveLetter><:><NULL>)
  611. curr = 0;
  612. }
  613. }
  614. else
  615. {
  616. pbuf = new BYTE[5000];
  617. if (!pbuf)
  618. return ERROR_NOT_ENOUGH_MEMORY;
  619. res = GetLogicalDriveStrings(2500,(WCHAR *)pbuf);
  620. if (! res )
  621. {
  622. res = GetLastError();
  623. err.SysMsgWrite(ErrW, res,DCT_MSG_LOCAL_DRIVE_ENUM_FAILED_D,res);
  624. }
  625. else
  626. {
  627. if ( res < 5000 )
  628. {
  629. drivelist = (WCHAR*)pbuf;
  630. isOpen = true;
  631. curr = 0;
  632. res = 0;
  633. }
  634. else
  635. {
  636. err.MsgWrite(ErrW,DCT_MSG_DRIVE_BUFFER_TOO_SMALL);
  637. }
  638. }
  639. }
  640. return res;
  641. }
  642. WCHAR *
  643. TVolumeEnum::Next()
  644. {
  645. WCHAR * pValue = NULL;
  646. WCHAR ShareName[MAX_PATH];
  647. WCHAR rootsharename[MAX_PATH]; // this will hold "machinename\C$\"
  648. NET_API_STATUS res;
  649. bool found = false;
  650. assert(isOpen);
  651. while ( ! found )
  652. {
  653. if ( ( !bLocalOnly && curr < BUF_ENTRY_LENGTH * numread )
  654. || ( bLocalOnly && drivelist[curr] ) )
  655. {
  656. if ( verbose )
  657. err.DbgMsgWrite(0,L"%C\n",drivelist[curr]);
  658. if ( ! bLocalOnly )
  659. {
  660. swprintf(ShareName,L"%c$",drivelist[curr]);
  661. res = NetShareGetInfo(server, ShareName, 1, &shareptr); // is this really necessary?
  662. switch ( res )
  663. {
  664. case NERR_NetNameNotFound:
  665. if ( verbose )
  666. err.DbgMsgWrite(0,L"Not Shared\n");
  667. break;
  668. case NERR_Success:
  669. {
  670. if ( verbose )
  671. err.DbgMsgWrite(0,L"Shared\n");
  672. NetApiBufferFree(shareptr);
  673. shareptr = NULL;
  674. // build the complete share name
  675. DWORD mnamelen = UStrLen(server);
  676. WCHAR append[5] = L"\\C$\\";
  677. append[1] = drivelist[curr]; // change the 'C' to the actual drive letter
  678. UStrCpy(rootsharename, server, mnamelen+1);
  679. UStrCpy(&rootsharename[mnamelen], append, 5);
  680. if ( verbose )
  681. err.DbgMsgWrite(0,L"Share name: %S\n",rootsharename);
  682. }
  683. break;
  684. default:
  685. err.MsgWrite(ErrW,DCT_MSG_ADMIN_SHARES_ERROR_SSD,ShareName,server,res);
  686. break;
  687. }
  688. }
  689. else
  690. {
  691. res = GetDriveType(&drivelist[curr]);
  692. switch ( res )
  693. {
  694. case DRIVE_REMOVABLE:
  695. case DRIVE_FIXED:
  696. res = 0;
  697. break;
  698. case DRIVE_REMOTE:
  699. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_REMOTE_S, &drivelist[curr]);
  700. break;
  701. case DRIVE_CDROM:
  702. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_CDROM_S, &drivelist[curr]);
  703. break;
  704. case DRIVE_RAMDISK:
  705. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_RAMDISK_S, &drivelist[curr]);
  706. break;
  707. case DRIVE_UNKNOWN:
  708. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_UNKNOWN_S, &drivelist[curr]);
  709. break;
  710. case DRIVE_NO_ROOT_DIR:
  711. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_NO_ROOT_S, &drivelist[curr]);
  712. break;
  713. default:
  714. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_SD, &drivelist[curr],res);
  715. break;
  716. }
  717. UStrCpy(rootsharename,&drivelist[curr]);
  718. curr++;
  719. }
  720. if ( ! res )
  721. {
  722. if ( verifyFlags & VERIFY_PERSISTENT_ACLS )
  723. {
  724. TPathNode pnode(rootsharename);
  725. DWORD rc = pnode.VerifyPersistentAcls();
  726. if ( !rc )
  727. {
  728. safecopy(currEntry,rootsharename);
  729. pValue = currEntry;
  730. found = true;
  731. }
  732. else if ( rc == ERROR_NO_SECURITY_ON_OBJECT )
  733. {
  734. err.MsgWrite(0,DCT_MSG_SKIPPING_FAT_VOLUME_S,rootsharename);
  735. }
  736. else
  737. {
  738. err.SysMsgWrite(0,rc,DCT_MSG_SKIPPING_PATH_SD,rootsharename,rc);
  739. }
  740. }
  741. else
  742. {
  743. safecopy(currEntry,rootsharename);
  744. pValue = currEntry;
  745. found = true;
  746. }
  747. }
  748. curr += BUF_ENTRY_LENGTH;
  749. }
  750. else
  751. {
  752. break; // no more drives left
  753. }
  754. }
  755. return pValue;
  756. }
  757. void
  758. TVolumeEnum::Close()
  759. {
  760. if ( pbuf )
  761. {
  762. if (! bLocalOnly )
  763. {
  764. NetApiBufferFree(pbuf);
  765. }
  766. else
  767. {
  768. delete [] pbuf;
  769. }
  770. pbuf = NULL;
  771. }
  772. isOpen = FALSE;
  773. SetErrorMode(errmode); // restore error mode to its prior state
  774. }
  775. int // ret -0 if successful, nonzero otherwise
  776. TPathList::AddVolsOnMachine(
  777. const LPWSTR mach, // in - name of server
  778. bool verbose, // in - flag indicating whether to display stuff or not
  779. bool verify
  780. )
  781. {
  782. DWORD numread; // number of volnames read this time
  783. DWORD total; // total # vols
  784. DWORD resume_handle = 0;
  785. DWORD curr; // used to iterate through volumes
  786. LPBYTE pbuf;
  787. WCHAR * drivelist;
  788. WCHAR ShareName[10]; // this holds "C$"
  789. LPBYTE shareptr;
  790. int errcode = 0;
  791. NET_API_STATUS res;
  792. pbuf = NULL;
  793. res = NetServerDiskEnum(mach,0,&pbuf,MAXSIZE, &numread, &total, &resume_handle);
  794. if (NERR_Success != res )
  795. {
  796. err.MsgWrite(ErrW, DCT_MSG_DRIVE_ENUM_FAILED_SD,mach, res);
  797. errcode = 1;
  798. }
  799. if ( ! errcode )
  800. {
  801. drivelist = (WCHAR *) pbuf; // NetServerDiskEnum returns an array of
  802. // WCHAR[3] elements (of the form <DriveLetter><:><NULL>)
  803. for (curr = 0 ; curr < BUF_ENTRY_LENGTH * numread ; curr += BUF_ENTRY_LENGTH) // for each drive letter returned
  804. {
  805. if ( verbose )
  806. err.DbgMsgWrite(0,L"%c\n",drivelist[curr]);
  807. swprintf(ShareName,L"%c$",drivelist[curr]);
  808. res = NetShareGetInfo(mach, ShareName, 1, &shareptr); // is this really necessary
  809. if ( NERR_NetNameNotFound != res && NERR_Success != res )
  810. {
  811. err.MsgWrite(ErrW,DCT_MSG_ADMIN_SHARES_ERROR_SSD,ShareName,mach,res);
  812. }
  813. if ( NERR_NetNameNotFound == res )
  814. {
  815. if ( verbose )
  816. err.DbgMsgWrite(0,L"Not Shared\n");
  817. }
  818. if ( NERR_Success == res )
  819. {
  820. if ( verbose )
  821. err.DbgMsgWrite(0,L"Shared\n");
  822. NetApiBufferFree(shareptr);
  823. shareptr = NULL;
  824. // build the complete share name
  825. DWORD mnamelen = UStrLen(mach);
  826. WCHAR * rootsharename = new WCHAR[mnamelen + 5]; // this will hold "machinename\C$\"
  827. WCHAR * append = L"\\C$\\";
  828. if (!rootsharename)
  829. return 1;
  830. append[1] = drivelist[curr]; // change the 'C' to the actual drive letter
  831. UStrCpy(rootsharename, mach, mnamelen+1);
  832. UStrCpy(&rootsharename[mnamelen], append, 5);
  833. if ( verbose )
  834. err.DbgMsgWrite(0,L"Share name: %ls\n",rootsharename);
  835. // maxcomponentlen, & flags
  836. DWORD maxcomponentlen; // will be used as args for GetVolumeInformation
  837. DWORD flags;
  838. UINT errmode;
  839. errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // set this to prevent message box when
  840. // called on removable media drives which are empty
  841. if ( ! GetVolumeInformation(rootsharename,NULL,0,NULL,&maxcomponentlen,&flags,NULL,0) )
  842. {
  843. err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_SHARE_GETINFO_FAILED_SD,rootsharename,GetLastError());
  844. errcode = drivelist[curr];
  845. errcode = 0;
  846. continue;
  847. }
  848. SetErrorMode(errmode); // restore error mode to its prior state
  849. if ( FS_PERSISTENT_ACLS & flags )
  850. {
  851. if ( verbose )
  852. err.DbgMsgWrite(0,L"Adding filesystem to list\n");
  853. AddPath(rootsharename,verify);
  854. }
  855. delete rootsharename;
  856. }
  857. }
  858. NetApiBufferFree(pbuf);
  859. numServers++; // update numServers statistic
  860. }
  861. return errcode;
  862. }
  863. // for each string in argv, determine whether it is a machine name or pathname, and use
  864. // AddPath or AddVolsOnMachine as appropriate
  865. int // ret -returns 0 if successful, nonzero otherwise
  866. TPathList::BuildPathList(
  867. TCHAR ** argv, // in- list of paths/servers from command-line args
  868. int argn,
  869. bool verbose // in- flag, if true Display contents of list, along with stats
  870. )
  871. {
  872. WCHAR warg[MAX_PATH];
  873. int currentArg;
  874. int errcode = 0;
  875. if ( ! argv[0] )
  876. {
  877. err.MsgWrite(ErrE,DCT_MSG_NO_PATHS);
  878. errcode = 1;
  879. }
  880. else
  881. {
  882. for ( currentArg = 0 ; ( currentArg < argn ) && *argv[currentArg] && !errcode; currentArg++ )
  883. {
  884. if ( UStrLen(argv[currentArg]) > MAX_PATH )
  885. {
  886. err.MsgWrite(ErrW,DCT_MSG_PATH_TOO_LONG_SD,argv[currentArg],MAX_PATH);
  887. }
  888. else
  889. { // need to check for quotes -- if we read from the file, we may have something like argv[i] = "Program,
  890. // and argv[i+1] = Files"
  891. if ( *argv[currentArg] == '"' )
  892. { // scan the strings until the matching close quote is found
  893. argv[currentArg]++; // skip the open quote
  894. TCHAR * c;
  895. TCHAR p[MAX_PATH];
  896. int plen = 0;
  897. int currlen;
  898. for ( c = argv[currentArg] ; c && *c != _T('"') ; c++ )
  899. {
  900. if ( ! *c ) // we've reached the end of this string
  901. {
  902. currlen = UStrLen(argv[currentArg]);
  903. UStrCpy(&p[plen],argv[currentArg],currlen + 1); // copy the string, including the NULL
  904. plen += currlen;
  905. p[plen++] = ' '; // add the space which caused these fields to be seperated
  906. p[plen] = NULL;
  907. currentArg++;
  908. if ( currentArg < argn )
  909. c = argv[currentArg];
  910. else
  911. {
  912. c = NULL;
  913. break;
  914. }
  915. }
  916. }
  917. if ( c ) // we found the quote
  918. {
  919. // copy p to argv[currentArg]
  920. currlen = UStrLen(argv[currentArg]);
  921. UStrCpy(&p[plen],argv[currentArg],currlen);
  922. // p now contains the full path
  923. safecopy(warg,p);
  924. }
  925. else // unclosed quote -- log error and abort
  926. {
  927. err.MsgWrite(ErrE,DCT_MSG_NO_ENDING_QUOTE_S,p);
  928. errcode = 2;
  929. }
  930. }
  931. else
  932. {
  933. safecopy(warg,argv[currentArg]);
  934. }
  935. errcode = AddPath(warg, VERIFY_EXISTS | VERIFY_BACKUPRESTORE );
  936. }
  937. }
  938. }
  939. return errcode;
  940. }