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.

880 lines
25 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. //get needed privileges and keep them until the agent removes itself
  266. if ( ! GetBkupRstrPriv(server) )
  267. {
  268. rc = ERROR_PRIVILEGE_NOT_HELD;
  269. }
  270. return rc;
  271. }
  272. // GetRootPath finds the root path of a volume. This is needed so we can call
  273. // GetVolumeInformation to find out things like whether this volume supports ACLs
  274. // This is fairly simplistic, and works by counting the backslashes in the path
  275. DWORD // ret- 0 or OS return code
  276. GetRootPath(
  277. WCHAR * rootpath, // out- path to root of volume
  278. WCHAR const * path // in - path within some volume
  279. )
  280. {
  281. DWORD rc = 0;
  282. DWORD i = 0;
  283. DWORD slashcount = 1;
  284. bool unc = false;
  285. WCHAR tempPath[MAX_PATH];
  286. SHARE_INFO_2 * sInfo;
  287. if ( path[0] == L'\\' && path[1] == L'\\' )
  288. {
  289. slashcount = 4;
  290. unc = true;
  291. }
  292. for (i = 0 ; path[i] && slashcount && i < DIM(tempPath)-1; i++ )
  293. {
  294. tempPath[i] = path[i];
  295. if ( tempPath[i] == L'\\' )
  296. {
  297. slashcount--;
  298. }
  299. }
  300. if ( tempPath[i-1] == L'\\' )
  301. {
  302. tempPath[i] = 0;
  303. }
  304. else
  305. {
  306. if (i == DIM(tempPath) - 1)
  307. {
  308. // if i points to the end of the buffer, truncate the last character
  309. i--;
  310. }
  311. tempPath[i] = L'\\' ;
  312. tempPath[i+1] = 0;
  313. i++;
  314. }
  315. // now rootpath contains either D:\ or \\machine\share\ .
  316. if ( unc )
  317. {
  318. // remove the trailing slash from the sharename
  319. if ( tempPath[i] == 0 )
  320. {
  321. i--;
  322. }
  323. if ( tempPath[i] == L'\\' )
  324. {
  325. tempPath[i] = 0;
  326. }
  327. // find the beginning of the share name
  328. while ( ( i > 0 ) && tempPath[i] != L'\\' )
  329. i--;
  330. if ( i < 3 )
  331. {
  332. MCSVERIFY(FALSE);
  333. rc = ERROR_INVALID_PARAMETER;
  334. }
  335. else
  336. {
  337. tempPath[i] = 0;
  338. }
  339. rc = NetShareGetInfo(tempPath,tempPath+i+1,2,(LPBYTE*)&sInfo);
  340. if ( ! rc )
  341. {
  342. swprintf(rootpath,L"%s\\%c$\\",tempPath,sInfo->shi2_path[0]);
  343. NetApiBufferFree(sInfo);
  344. }
  345. }
  346. else
  347. {
  348. UStrCpy(rootpath,tempPath);
  349. }
  350. return rc;
  351. }
  352. DWORD
  353. TPathNode::VerifyPersistentAcls() // ret- 0=Yes, ERROR_NO_SECURITY_ON_OBJECT or OS error code
  354. {
  355. DWORD rc = 0;
  356. DWORD maxcomponentlen; // will be used as args for GetVolumeInformation
  357. DWORD flags;
  358. UINT errmode;
  359. WCHAR rootpath[MAX_PATH];
  360. WCHAR fstype[MAX_PATH];
  361. errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // set this to prevent message box when
  362. // called on removable media drives which are empty
  363. if ( ! IsMachineName(path) )
  364. {
  365. rc = GetRootPath(rootpath,path);
  366. if ( ! rc )
  367. {
  368. if ( !GetVolumeInformation(rootpath,NULL,0,NULL,&maxcomponentlen,&flags,fstype,DIM(fstype)) )
  369. {
  370. rc = GetLastError();
  371. if ( rc != ERROR_NOT_READY )
  372. {
  373. err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_GET_VOLUME_INFO_FAILED_SD,rootpath,GetLastError());
  374. }
  375. }
  376. else
  377. {
  378. if (!( FS_PERSISTENT_ACLS & flags) )
  379. {
  380. rc = ERROR_NO_SECURITY_ON_OBJECT;
  381. }
  382. }
  383. }
  384. }
  385. SetErrorMode(errmode); // restore error mode to its prior state
  386. return rc;
  387. }
  388. // This function is used when expanding wildcards in server names. It replaces server field with the new name,
  389. // and if the path is a UNC, it changes the server component of the path.
  390. void
  391. TPathNode::SetServerName(
  392. UCHAR const * name // in - new server name
  393. )
  394. {
  395. if ( IsUNCName(path) )
  396. {
  397. WCHAR newpath[MAX_PATH];
  398. int len = UStrLen(server);
  399. swprintf(newpath,L"%S%s",name,path+len);
  400. safecopy(path,newpath);
  401. }
  402. safecopy(server,name);
  403. }
  404. /************************************************************************************
  405. TPathList Implementation
  406. *************************************************************************************/
  407. TPathList::TPathList()
  408. {
  409. numServers = 0;
  410. numPaths = 0;
  411. }
  412. TPathList::~TPathList()
  413. {
  414. TPathNode * node;
  415. for (node = (TPathNode *)Head() ; Count() ; node = (TPathNode *)Head() )
  416. {
  417. Remove(node);
  418. delete node;
  419. }
  420. }
  421. // enumerate the nodes in the list, and display the name of each - used for debugging purposes
  422. void
  423. TPathList::Display() const
  424. {
  425. TPathNode * node;
  426. TNodeListEnum displayenum;
  427. err.DbgMsgWrite(0,L"%ld servers, %ld total paths\n", numServers, numPaths);
  428. for ( node = (TPathNode *)displayenum.OpenFirst(this) ;
  429. node ;
  430. node = (TPathNode *)displayenum.Next()
  431. )
  432. {
  433. node->Display();
  434. }
  435. displayenum.Close();
  436. }
  437. void
  438. TPathList::OpenEnum()
  439. {
  440. tenum.Open(this);
  441. }
  442. // Return the name from the next node in the enumeration
  443. // Returns NULL if no more nodes in the list
  444. // OpenEnum() must be called before calling Next();
  445. WCHAR *
  446. TPathList::Next()
  447. {
  448. TPathNode * pn = (TPathNode *)tenum.Next();
  449. LPWSTR result;
  450. if ( pn )
  451. result = pn->GetPathName();
  452. else
  453. result = NULL;
  454. return result;
  455. }
  456. void
  457. TPathList::CloseEnum()
  458. {
  459. tenum.Close();
  460. }
  461. bool // ret -returns true if path added, false if path too long
  462. TPathList::AddPath(
  463. const LPWSTR path, // in -path to add to list
  464. DWORD verifyFlags // in -indicates which types of verification to perform
  465. )
  466. {
  467. TPathNode * pnode;
  468. bool error = false;
  469. bool messageshown = false;
  470. DWORD rc = 0;
  471. WCHAR fullpath[MAX_PATH];
  472. WCHAR* pFullPathBuffer = NULL;
  473. if ( UStrLen(path) >= MAX_PATH )
  474. {
  475. err.MsgWrite(ErrW,DCT_MSG_PATH_TOO_LONG_SD,path,MAX_PATH);
  476. messageshown = true;
  477. error = true;
  478. return error;
  479. }
  480. pFullPathBuffer = _wfullpath(fullpath,path,DIM(fullpath));
  481. if(!pFullPathBuffer)
  482. {
  483. err.MsgWrite(ErrW,DCT_MSG_GET_FULL_PATH_FAILED, path);
  484. messageshown = true;
  485. error = true;
  486. return error;
  487. }
  488. pnode = new TPathNode(fullpath);
  489. if (!pnode)
  490. return true;
  491. if ( ! ContainsWildcard(pnode->GetServerName()) )
  492. {
  493. if ( verifyFlags & VERIFY_EXISTS )
  494. {
  495. if ( rc = pnode->VerifyExists() )
  496. {
  497. error = true;
  498. }
  499. }
  500. if ( !error && ( verifyFlags & VERIFY_BACKUPRESTORE) )
  501. {
  502. if ( rc = pnode->VerifyBackupRestore() )
  503. {
  504. // WCHAR * server = pnode->GetServerName();
  505. }
  506. }
  507. if ( !error && (verifyFlags & VERIFY_PERSISTENT_ACLS ) )
  508. {
  509. rc = pnode->VerifyPersistentAcls();
  510. if ( rc == ERROR_NO_SECURITY_ON_OBJECT )
  511. {
  512. err.MsgWrite(ErrW,DCT_MSG_NO_ACLS_S,fullpath);
  513. error = true;
  514. messageshown = true;
  515. }
  516. }
  517. }
  518. if ( ! error )
  519. {
  520. AddPathToList(pnode);
  521. numPaths++; // increment count of paths
  522. }
  523. else if ( !messageshown )
  524. {
  525. // need to include an error code here.
  526. if ( ! rc )
  527. {
  528. err.MsgWrite(ErrE,DCT_MSG_PATH_NOT_FOUND_S,fullpath);
  529. }
  530. else
  531. {
  532. err.SysMsgWrite(ErrE,rc,DCT_MSG_CANNOT_READ_PATH_SD,fullpath,rc);
  533. }
  534. delete pnode;
  535. }
  536. else
  537. delete pnode;
  538. return error;
  539. }
  540. void
  541. TPathList::Clear()
  542. {
  543. TNodeListEnum tEnum;
  544. TPathNode * pNode;
  545. TPathNode * pNext;
  546. for ( pNode = (TPathNode *)tEnum.OpenFirst(this) ; pNode ; pNode = pNext )
  547. {
  548. pNext = (TPathNode *)tEnum.Next();
  549. Remove(pNode);
  550. delete pNode;
  551. }
  552. }
  553. void
  554. TPathList::AddPathToList(
  555. TPathNode * pNode // in - path to add to the list
  556. )
  557. {
  558. // set the IsFirstPathFromMachine property
  559. TNodeListEnum tEnum;
  560. TPathNode * currNode;
  561. bool machineFound = false;
  562. WCHAR * myMachine = GetMachineName(pNode->GetPathName());
  563. WCHAR * currMachine;
  564. for ( currNode = (TPathNode *)tEnum.OpenFirst(this)
  565. ; currNode && !machineFound
  566. ; currNode = (TPathNode *)tEnum.Next() )
  567. {
  568. currMachine = GetMachineName(currNode->GetPathName());
  569. if ( currMachine && myMachine )
  570. {
  571. if ( !UStrICmp(currMachine,myMachine) )
  572. {
  573. machineFound = true;
  574. }
  575. }
  576. else
  577. {
  578. if ( !currMachine && ! myMachine )
  579. {
  580. machineFound = true;
  581. }
  582. }
  583. if ( currMachine )
  584. delete [] currMachine;
  585. }
  586. if ( myMachine )
  587. delete [] myMachine;
  588. tEnum.Close();
  589. pNode->IsFirstPathFromMachine(!machineFound);
  590. InsertBottom((TNode *)pNode);
  591. }
  592. // AddVolsOnMachine generates a list of volumes on the machine mach, checks for the administrative share
  593. // for each volume, and adds NTFS shared volumes to the pathlist
  594. DWORD
  595. TVolumeEnum::Open(
  596. WCHAR const * serv, // in - server to enumerate volumes on
  597. DWORD verifyflgs, // in - flags indicating what to verify about each volume (i.e. NTFS)
  598. BOOL logmsgs // in - flag whether to print diagnostic messages
  599. )
  600. {
  601. NET_API_STATUS res;
  602. if ( isOpen )
  603. Close();
  604. if ( serv )
  605. safecopy(server,serv);
  606. else
  607. server[0] = 0;
  608. resume_handle = 0;
  609. pbuf = NULL;
  610. verbose = logmsgs;
  611. verifyFlags = verifyflgs;
  612. errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // set this to prevent message box when
  613. // called on removable media drives which are empty
  614. if ( ! bLocalOnly )
  615. {
  616. res = NetServerDiskEnum(server,0,&pbuf,MAXSIZE, &numread, &total, &resume_handle);
  617. if (NERR_Success != res )
  618. {
  619. err.SysMsgWrite(ErrW, res, DCT_MSG_DRIVE_ENUM_FAILED_SD,server, res);
  620. isOpen = FALSE;
  621. }
  622. if ( ! res )
  623. {
  624. drivelist = (WCHAR *) pbuf; // NetServerDiskEnum returns an array of
  625. isOpen = true; // WCHAR[3] elements (of the form <DriveLetter><:><NULL>)
  626. curr = 0;
  627. }
  628. }
  629. else
  630. {
  631. //first call to determine the size of the buffer we need for drive strings
  632. DWORD dwSizeNeeded = GetLogicalDriveStrings(0, NULL);
  633. if (dwSizeNeeded != 0)
  634. {
  635. //add 1 character to the needed length and allocate the memory
  636. pbuf = new BYTE[(dwSizeNeeded + 1) * sizeof(TCHAR)];
  637. if (!pbuf)
  638. return ERROR_NOT_ENOUGH_MEMORY;
  639. //now get the drive strings
  640. dwSizeNeeded = GetLogicalDriveStrings(dwSizeNeeded + 1, (WCHAR *)pbuf);
  641. if (dwSizeNeeded != 0) //if success, save the drive string
  642. {
  643. drivelist = (WCHAR*)pbuf;
  644. isOpen = true;
  645. curr = 0;
  646. res = 0;
  647. }
  648. else
  649. {
  650. res = GetLastError();
  651. err.SysMsgWrite(ErrW,res,DCT_MSG_LOCAL_DRIVE_ENUM_FAILED_D,res);
  652. }
  653. }//end if got size needed
  654. else
  655. {
  656. res = GetLastError();
  657. err.SysMsgWrite(ErrW,res,DCT_MSG_LOCAL_DRIVE_ENUM_FAILED_D,res);
  658. }
  659. }
  660. return res;
  661. }
  662. WCHAR *
  663. TVolumeEnum::Next()
  664. {
  665. WCHAR * pValue = NULL;
  666. WCHAR ShareName[MAX_PATH];
  667. WCHAR rootsharename[MAX_PATH]; // this will hold "machinename\C$\"
  668. NET_API_STATUS res;
  669. bool found = false;
  670. assert(isOpen);
  671. while ( ! found )
  672. {
  673. if ( ( !bLocalOnly && curr < BUF_ENTRY_LENGTH * numread )
  674. || ( bLocalOnly && drivelist[curr] ) )
  675. {
  676. if ( verbose )
  677. err.DbgMsgWrite(0,L"%C\n",drivelist[curr]);
  678. if ( ! bLocalOnly )
  679. {
  680. swprintf(ShareName,L"%c$",drivelist[curr]);
  681. res = NetShareGetInfo(server, ShareName, 1, &shareptr); // is this really necessary?
  682. switch ( res )
  683. {
  684. case NERR_NetNameNotFound:
  685. if ( verbose )
  686. err.DbgMsgWrite(0,L"Not Shared\n");
  687. break;
  688. case NERR_Success:
  689. {
  690. if ( verbose )
  691. err.DbgMsgWrite(0,L"Shared\n");
  692. NetApiBufferFree(shareptr);
  693. shareptr = NULL;
  694. // build the complete share name
  695. DWORD mnamelen = UStrLen(server);
  696. WCHAR append[5] = L"\\C$\\";
  697. append[1] = drivelist[curr]; // change the 'C' to the actual drive letter
  698. UStrCpy(rootsharename, server, mnamelen+1);
  699. UStrCpy(&rootsharename[mnamelen], append, 5);
  700. if ( verbose )
  701. err.DbgMsgWrite(0,L"Share name: %S\n",rootsharename);
  702. }
  703. break;
  704. default:
  705. err.MsgWrite(ErrW,DCT_MSG_ADMIN_SHARES_ERROR_SSD,ShareName,server,res);
  706. break;
  707. }
  708. }
  709. else
  710. {
  711. res = GetDriveType(&drivelist[curr]);
  712. switch ( res )
  713. {
  714. case DRIVE_REMOVABLE:
  715. case DRIVE_FIXED:
  716. res = 0;
  717. break;
  718. case DRIVE_REMOTE:
  719. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_REMOTE_S, &drivelist[curr]);
  720. break;
  721. case DRIVE_CDROM:
  722. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_CDROM_S, &drivelist[curr]);
  723. break;
  724. case DRIVE_RAMDISK:
  725. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_RAMDISK_S, &drivelist[curr]);
  726. break;
  727. case DRIVE_UNKNOWN:
  728. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_UNKNOWN_S, &drivelist[curr]);
  729. break;
  730. case DRIVE_NO_ROOT_DIR:
  731. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_NO_ROOT_S, &drivelist[curr]);
  732. break;
  733. default:
  734. err.MsgWrite(0,DCT_MSG_SKIPPING_DRIVE_SD, &drivelist[curr],res);
  735. break;
  736. }
  737. UStrCpy(rootsharename,&drivelist[curr]);
  738. curr++;
  739. }
  740. if ( ! res )
  741. {
  742. if ( verifyFlags & VERIFY_PERSISTENT_ACLS )
  743. {
  744. TPathNode pnode(rootsharename);
  745. DWORD rc = pnode.VerifyPersistentAcls();
  746. if ( !rc )
  747. {
  748. safecopy(currEntry,rootsharename);
  749. pValue = currEntry;
  750. found = true;
  751. }
  752. else if ( rc == ERROR_NO_SECURITY_ON_OBJECT )
  753. {
  754. err.MsgWrite(0,DCT_MSG_SKIPPING_FAT_VOLUME_S,rootsharename);
  755. }
  756. else
  757. {
  758. err.SysMsgWrite(0,rc,DCT_MSG_SKIPPING_PATH_SD,rootsharename,rc);
  759. }
  760. }
  761. else
  762. {
  763. safecopy(currEntry,rootsharename);
  764. pValue = currEntry;
  765. found = true;
  766. }
  767. }
  768. curr += BUF_ENTRY_LENGTH;
  769. }
  770. else
  771. {
  772. break; // no more drives left
  773. }
  774. }
  775. return pValue;
  776. }
  777. void
  778. TVolumeEnum::Close()
  779. {
  780. if ( pbuf )
  781. {
  782. if (! bLocalOnly )
  783. {
  784. NetApiBufferFree(pbuf);
  785. }
  786. else
  787. {
  788. delete [] pbuf;
  789. }
  790. pbuf = NULL;
  791. }
  792. isOpen = FALSE;
  793. SetErrorMode(errmode); // restore error mode to its prior state
  794. }