Fsys.cpp
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:29k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
  2. // Copyright 1996 by Jarle Aase. All rights reserved.
  3. // See the "War Software Series Licende Agreement" for details concerning 
  4. // use and distribution.
  5. // ---
  6. // This source code, executables and programs containing source code or
  7. // binaries or proprietetary technology from the War Software Series are
  8. // NOT alloed used, viewed or tested by any governmental agencies in
  9. // any countries. This includes the government, departments, police, 
  10. // military etc.
  11. // ---
  12. // This file is intended for use with Tab space = 2
  13. // Created and maintained in MSVC Developer Studio
  14. // ---
  15. // NAME : Fsys.cpp
  16. // PURPOSE : Simple file system (when not running VfSys)
  17. // PROGRAM : 
  18. // DATE : Sept. 27 1996
  19. // AUTHOR : Jarle Aase
  20. // ---
  21. // REVISION HISTORY
  22. // 
  23. #include "stdafx.h"
  24. #include <sys/stat.h>
  25. #include "WarDaemon.h"
  26. #include "FsysSecurity.h"
  27. #include "ctype.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. // Note: All functions on this level works with paths like:
  34. // <DRIVE><PATH><PATH>
  35. // where <DRIVE> is a one letter character representing the drive.
  36. // An empty path "" represents the root on the lowest level.
  37. // On the higher levels (return to user functions, the root is always  ...
  38. // No functions return trailing  .
  39. CFsys *CFsys::m_pCFsys = NULL;
  40. CLog *CFsys::m_Log = NULL;
  41. CFsys::CFsys()
  42. {
  43. m_pCFsys = this;
  44. }
  45. CFsys::~CFsys()
  46. {
  47. m_pCFsys = NULL;
  48. }
  49. LPCSTR CFsys::VisualPath(LPCSTR RootPath, LPCSTR Path, LPSTR ReturnBuf, int BufLen)
  50. {
  51. char buf[MAX_PATH * 2];
  52. LPSTR p = buf;
  53. int PathLen = 0;
  54. ASSERT(AfxIsValidString(Path));
  55. ASSERT(AfxIsValidString(RootPath));
  56. ASSERT(AfxIsValidAddress(ReturnBuf,BufLen));
  57. ASSERT(BufLen >= MAX_PATH);
  58. // See if we have to map away the root path
  59. int RootPathLen = strlen(RootPath);
  60. if (!strnicmp(RootPath,Path,RootPathLen))
  61. Path += RootPathLen;
  62. if (*Path != '\')
  63. {
  64. *p++ = '/';
  65. ++PathLen;
  66. }
  67. while(*Path)
  68. {
  69. if (++PathLen >= (sizeof(buf) - 1))
  70. {
  71. LogMsg(LOGF_WARNINGS,"VisualPath(): Internal working buffer is too small (%d bytes).", sizeof(buf));
  72. return("CFsys::VisualPath(): Error, working buffer is too small.");
  73. }
  74. if (*Path == '\')
  75. {
  76. *p++ = '/';
  77. ++Path;
  78. }
  79. else
  80. *p++ = *Path++;
  81. }
  82. *p = 0;
  83. if (PathLen > BufLen)
  84. {
  85. LogMsg(LOGF_WARNINGS,"VisualPath(): Return buffer is too small (%d bytes).", BufLen);
  86. return("CFsys::VisualPath(): Error, return buffer is too small.");
  87. }
  88. memcpy(ReturnBuf, buf, PathLen + 1);
  89. ASSERT(AfxIsValidString(ReturnBuf));
  90. return ReturnBuf;
  91. }
  92. BOOL CFsys::Create(CLog *Log)
  93. {
  94. ASSERT(this != NULL);
  95. m_Log = Log;
  96. return TRUE;
  97. }
  98. void CFsys::LogMsg(int flag, LPCSTR Format, ...)
  99. {
  100. CString cBuf;
  101. if (!ShouldLog(m_Log, flag))
  102. return;
  103. ASSERT(AfxIsValidString(Format, FALSE));
  104. ASSERT(m_Log != NULL);
  105. ASSERT(AfxIsValidAddress(m_Log,sizeof(CLog)));
  106. cBuf.Format("CFsys: %s", Format);
  107. va_list argList;
  108. va_start(argList, Format);
  109. m_Log->LogMsgV(flag, cBuf, argList);
  110. va_end(argList);
  111. }
  112. BOOL CFsys::PrepereCommandLine(CCmdArgs& Args, LPCSTR RootDir, LPCSTR CWD, int User, ...)
  113. {
  114. va_list argList;
  115. va_start(argList, User);
  116. LPCSTR LineArg;
  117. LPSTR buf, p;
  118. LPCSTR Tok;
  119. LPSTR TokBuf;
  120. char MyBuf[1024];
  121. int TokLen;
  122. for(;;)
  123. {
  124. LineArg = va_arg(argList, LPCSTR);
  125. if (!LineArg)
  126. break;
  127. ASSERT(AfxIsValidString(LineArg));
  128. // See if we can use the stack buffer...
  129. // If it is too small, allocate a buffer...
  130. TokLen = strlen(LineArg);
  131. if (TokLen > (sizeof(MyBuf) -1))
  132. p = TokBuf = buf = strdup(LineArg);
  133. else
  134. {
  135. buf = NULL;
  136. memcpy(MyBuf,LineArg,TokLen);
  137. MyBuf[TokLen] = 0;
  138. p = TokBuf = MyBuf;
  139. }
  140. for(;;)
  141. {
  142. // If a parameter begins with '-' we assume a line parameter and brak at space,
  143. // else we take the entire line...
  144. if (*p == '-')
  145. Tok = " ";
  146. else
  147. Tok = "";
  148. if ((p = strtok(TokBuf,Tok)) == NULL)
  149. break;
  150. TokBuf = NULL;
  151. // Expand file name, unless it is a line parameter
  152. if (!*Tok && strpbrk(p, "~{[*?") != NULL)
  153. {
  154. // Add file names from pattern...
  155. if (AddFromPattern(Args, RootDir, CWD, User, p));
  156. }
  157. else
  158. Args.AddArg(p);
  159. }
  160. // We will use the stack buffer in most cases
  161. if (buf)
  162. delete buf;
  163. }
  164. va_end(argList);
  165. return TRUE;
  166. }
  167. int CFsys::AddFromPattern(CCmdArgs& Args, LPCSTR RootDir, LPCSTR CWD, int User, LPCSTR p)
  168. {
  169. HANDLE h;
  170. WIN32_FIND_DATA Data;
  171. CString cPatternPath;
  172. int Rval = 0;
  173. // TODO: Check user access before adding a path
  174. // Path is relative to current dir.
  175. // TODO: Map the CWD to real path (in case of links, /, ../ etc..)
  176. cPatternPath.Format("%s\%s", CWD, p);
  177. if ((h = FindFirstFile(User, cPatternPath, &Data)) != INVALID_HANDLE_VALUE)
  178. {
  179. do
  180. {
  181. ++Rval;
  182. Args.AddArg(Data.cFileName);
  183. } while(FindNextFile(h, &Data));
  184. FindClose(h);
  185. }
  186. return Rval;
  187. }
  188. HANDLE CFsys::FindFirstFile(int User, LPCSTR Path, LPWIN32_FIND_DATA Data)
  189. {
  190. CFindFileHandle *MyHandle = (CFindFileHandle *)INVALID_HANDLE_VALUE;
  191. HANDLE h;
  192. HANDLE SecurityGrp = INVALID_HANDLE_VALUE;
  193. ASSERT(AfxIsValidString(Path));
  194. char UsePath[MAX_PATH];
  195. char MyPath[MAX_PATH];
  196. char MyPattern[MAX_PATH];
  197. // Get the pattern.
  198. strcpy(UsePath,Path);
  199. LPSTR pattern = strrchr(UsePath,'\');
  200. if (pattern && strpbrk(pattern,"*?"))
  201. {
  202. strcpy(MyPattern,pattern + 1);
  203. if (pattern == UsePath)
  204. ++pattern; // Root path, move beoind  and terminate string
  205. *pattern = 0;
  206. }
  207. else
  208. {
  209. // No pattern.
  210. *MyPattern = 0;
  211. }
  212. if (*Path == '$')
  213. *UsePath = *MyPath = *MyPattern = 0; // Special case - root node
  214. else if (!RealPath(UsePath,MyPath))
  215. return INVALID_HANDLE_VALUE;
  216. if (!*MyPattern)
  217. {
  218. // We *must* have a pattern to get the security right..
  219. if ((pattern = strrchr(MyPath,'\')) != NULL)
  220. {
  221. *pattern++ = 0;
  222. strcpy(MyPattern,pattern);
  223. }
  224. }
  225. if (User)
  226. {
  227. // We only do security lookup for users. 0 is the system. It has full access
  228. // Also, we need the security descriptor of the parent directory in order to
  229. // verify the files in this dir.
  230. if ((SecurityGrp = CFsysSecurity::GetSecurityGroupFromPath(
  231. User, CUsr::GetUserClass(User), MyPath)) == INVALID_HANDLE_VALUE)
  232. {
  233. LogMsg(LOGF_DEBUG,"FindFirstFile(%s) - failed.", Path);
  234. //free(xpath);
  235. return INVALID_HANDLE_VALUE;
  236. }
  237. }
  238. if ((strlen(MyPath) + strlen(MyPattern)) < 3)
  239. {
  240. MyHandle = new CFindFileHandle;
  241. MyHandle->m_User = User;
  242. MyHandle->m_Pattern = MyPattern;
  243. MyHandle->m_PathsQueued = new CCmdArgs;
  244. MyHandle->m_FullPath = "\";
  245. MyHandle->m_SecurityHandle = SecurityGrp;
  246. if (!*MyPattern && !*MyPath)
  247. {
  248. //Special case. Return directory . in path  ...
  249. MyHandle->m_PathsQueued->AddArg(".");
  250. PrepereLogicalFile(MyHandle->m_PathsQueued->Arg(MyHandle->m_Argc++), Data);
  251. }
  252. else
  253. {
  254. // Special case. We have to "manifacture" a list of disk drives as if they were files...
  255. char *p;
  256. if (!*MyPattern)
  257. {
  258. // Dos drives will be listed as "C:" after RealPath() is done
  259. *MyPattern = MyPath[1];
  260. MyPattern[1] = 0;
  261. }
  262. MyPath[0] = '.';
  263. MyPath[1] = 0;
  264. GetLogicalDriveStrings(MAX_PATH, MyPath + 2);
  265. if (MyPattern[1])
  266. goto failure; // Drive can only be 1 character long...
  267. // Convert to valid path
  268. for(p = MyPath;;)
  269. {
  270. if (!*p && !*(p+1))
  271. break;
  272. if (!*p && *(p+1))
  273. *p = ';';
  274. ++p;
  275. }
  276. for (p = strtok(MyPath,";:\"); p && *p; p = strtok(NULL,";:\"))
  277. {
  278. if ((*MyPattern == '*') || (*MyPattern == '?') || (toupper(*MyPattern) == toupper(*p)))
  279. MyHandle->m_PathsQueued->AddArg(p);
  280. }
  281. if (MyHandle->m_PathsQueued->m_argc)
  282. PrepereLogicalFile(MyHandle->m_PathsQueued->Arg(MyHandle->m_Argc++), Data);
  283. else
  284. {
  285. failure:
  286. delete MyHandle;
  287. MyHandle = (CFindFileHandle *)INVALID_HANDLE_VALUE;
  288. }
  289. }
  290. }
  291. else
  292. {
  293. // Default processing
  294. if (*MyPattern)
  295. sprintf(MyPath + strlen(MyPath), "\%s", MyPattern);
  296. DosPath(MyPath);
  297. if (*MyPath == '\')
  298. {
  299. SetLastError(ERROR_INVALID_PARAMETER);
  300. LogMsg(LOGF_DEBUG, "FindFirstFile() - Invalid DOS path %s", MyPath);
  301. return INVALID_HANDLE_VALUE;
  302. }
  303. if ((h = ::FindFirstFile(MyPath, Data)) != INVALID_HANDLE_VALUE)
  304. {
  305. MyHandle = new CFindFileHandle;
  306. MyHandle->m_DOShandle = h;
  307. MyHandle->m_User = User;
  308. MyHandle->m_Pattern = MyPattern;
  309. MyHandle->m_FullPath = MyPath;
  310. MyHandle->m_SecurityHandle = SecurityGrp;
  311. }
  312. }
  313. return (HANDLE) MyHandle;
  314. }
  315. BOOL CFsys::FindNextFile(HANDLE h, LPWIN32_FIND_DATA Data)
  316. {
  317. ASSERT(AfxIsValidAddress(Data, sizeof(LPWIN32_FIND_DATA)));
  318. CFindFileHandle *MyHandle = (CFindFileHandle *)h;
  319. ASSERT(AfxIsValidAddress(MyHandle, sizeof(CFindFileHandle)));
  320. if (MyHandle->m_DOShandle != INVALID_HANDLE_VALUE)
  321. return ::FindNextFile(MyHandle->m_DOShandle, Data);
  322. ASSERT(AfxIsValidAddress(MyHandle, sizeof(CFindFileHandle)));
  323. if (MyHandle->m_Argc < MyHandle->m_PathsQueued->m_argc)
  324. {
  325. PrepereLogicalFile(MyHandle->m_PathsQueued->Arg(MyHandle->m_Argc++), Data);
  326. return TRUE;
  327. }
  328. else
  329. return FALSE;
  330. }
  331. BOOL CFsys::FindClose(HANDLE h)
  332. {
  333. CFindFileHandle *MyHandle = (CFindFileHandle *)h;
  334. BOOL Rval = TRUE;
  335. ASSERT(AfxIsValidAddress(MyHandle, sizeof(CFindFileHandle)));
  336. if (MyHandle->m_DOShandle != INVALID_HANDLE_VALUE)
  337. {
  338. Rval = ::FindClose(MyHandle->m_DOShandle);
  339. MyHandle->m_DOShandle = INVALID_HANDLE_VALUE;
  340. }
  341. delete MyHandle;
  342. return Rval;
  343. }
  344.  
  345. // Put dummy data into Data
  346. void CFsys::PrepereLogicalFile(LPCSTR Name, LPWIN32_FIND_DATA Data)
  347. {
  348. ASSERT(AfxIsValidString(Name));
  349. ASSERT(AfxIsValidAddress(Data, sizeof(LPWIN32_FIND_DATA)));
  350. Data->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
  351. GetSystemTimeAsFileTime(&Data->ftCreationTime);
  352. GetSystemTimeAsFileTime(&Data->ftLastAccessTime);
  353. GetSystemTimeAsFileTime(&Data->ftLastWriteTime);
  354. Data->nFileSizeHigh = 0;
  355. Data->nFileSizeLow = 512; // Just say 512 bytes... Most likely a directory...
  356. strcpy(Data->cFileName, Name);
  357. }
  358. // Make a path. 
  359. LPCSTR CFsys::MkPath(LPCSTR Root, LPCSTR CWD, LPCSTR Path, LPSTR buf)
  360. {
  361. LPCSTR BeginPath = CWD;
  362. LPSTR p = buf;
  363. BOOL CheckSlash;
  364. int cnt = 0;
  365. ASSERT(AfxIsValidString(CWD));
  366. ASSERT(AfxIsValidString(Path));
  367. ASSERT(AfxIsValidString(Root));
  368. ASSERT(AfxIsValidAddress(buf,MAX_PATH));
  369. if (*Root && *Path == '\')
  370. {
  371. BeginPath = Root;
  372. ++Path;
  373. }
  374. CheckSlash = *BeginPath != 0;
  375. while(*BeginPath)
  376. {
  377. if (++cnt >= MAX_PATH)
  378. goto cnt_fail;
  379. *p++ = *BeginPath++;
  380. ASSERT(AfxIsValidAddress(p,1));
  381. }
  382. if (CheckSlash && (p[-1] != '\'))
  383. {
  384. if (++cnt >= MAX_PATH)
  385. goto cnt_fail;
  386. *p++ = '\';
  387. ASSERT(AfxIsValidAddress(p,1));
  388. }
  389. while(*Path)
  390. {
  391. if (++cnt >= MAX_PATH)
  392. goto cnt_fail;
  393. *p++ = *Path++;
  394. ASSERT(AfxIsValidAddress(p,1));
  395. }
  396. if (cnt && (p[-1] == '\'))
  397. --p; // Remove trailing  ...
  398. *p = 0;
  399. return buf;
  400. cnt_fail:
  401. ASSERT(cnt >= MAX_PATH);
  402. LogMsg(LOGF_WARNINGS,"MkPath() - Buffer overflow. Path must be less than %d bytes.", MAX_PATH);
  403. buf[--cnt] = 0; // Just in case...
  404. return NULL;
  405. }
  406. // Parse a path and return the actual DOS path
  407. // Resolve links (.lnk files and VfSys links)
  408. // The returned path is either C:, C:whatever or  (sytstem root)
  409. LPCSTR CFsys::RealPath(LPCSTR Path, LPSTR Buf, BOOL DotsOnly)
  410. {
  411. ASSERT(AfxIsValidString(Path));
  412. ASSERT(AfxIsValidAddress(Buf,MAX_PATH));
  413. LPCSTR PathSave = Path;
  414. int cnt = 0;
  415. struct _stat st;
  416. if (!*Path || !strcmp(Path,"\") || !strcmp(Path,"\."))
  417. {
  418. *Buf = 0;
  419. return Buf; // Special case - system root path.
  420. }
  421. if ((*Path != '\') && (*Path != '/'))
  422. return FALSE;
  423. while(*Path)
  424. {
  425. if ((*Path == '\') || (*Path == '/'))
  426. {
  427. // C:.. C:.any  C:any. C:any...any C:any..
  428. if (Path[1] == '.')
  429. {
  430. if (!Path[2] || (Path[2] == '\'))
  431. {
  432. // C:any. style. Just ignore
  433. Path += 2;
  434. continue;
  435. }
  436. if (Path[2] == '.')
  437. {
  438. if (!Path[3] || (Path[3] == '\'))
  439. {
  440. // C:any.. C:any..test style. Move back one 
  441. if (cnt == 0)
  442. {
  443. LogMsg(LOGF_DEBUG,"RealPath(%s) - invalid ..\ ", PathSave);
  444. return NULL;
  445. }
  446. while(--cnt && (Buf[cnt] != '\') && (Buf[cnt] != '/'))
  447. {
  448. ASSERT(cnt >= 0);
  449. }
  450. Path += 3;
  451. continue;
  452. }
  453. }
  454. }
  455. if (!DotsOnly && Path[1] && (cnt > 3))
  456. {
  457. // The path *must* be a directory. Check with file system.
  458. Buf[cnt] = 0;
  459. if (_stat(DosPath(Buf),&st))
  460. {
  461. LogMsg(LOGF_DEBUG,"RealPath(%s) - stat() failed on directory '%s'.", PathSave, Buf);
  462. return NULL;
  463. }
  464. if (!(st.st_mode & _S_IFDIR))
  465. {
  466. // TODO: Add link support
  467. LogMsg(LOGF_DEBUG,"RealPath(%s) - %s: not a directory", PathSave, Buf);
  468. return NULL;
  469. }
  470. UnixPath(Buf);
  471. }
  472. }
  473. // Default
  474. if (*Path == '/')
  475. {
  476. Buf[cnt] = '\';
  477. ++Path;
  478. }
  479. else
  480. Buf[cnt] = *Path++;
  481. if (++cnt >= MAX_PATH)
  482. {
  483. LogMsg(LOGF_WARNINGS,"RealPath(%s) - Real path exeeds limit of %d bytes.", PathSave, MAX_PATH);
  484. Buf[--cnt] = 0; // Just in case ...
  485. return NULL;
  486. }
  487. }
  488. Buf[cnt] = 0;
  489. return Buf;
  490. }
  491. // Convert C style paths to C: ...
  492. LPCSTR CFsys::DosPath(LPSTR Path)
  493. {
  494. ASSERT(AfxIsValidString(Path));
  495. if ((Path[0] == '\') && isalpha(Path[1]) && (!Path[2] || (Path[2] == '\')))
  496. {
  497. ASSERT((*Path == '\') || (*Path == '/') || (Path[1] == ':'));
  498. Path[0] = Path[1];
  499. Path[1] = ':';
  500. }
  501. return Path;
  502. }
  503. // Convert C: style paths to C ...
  504. LPCSTR CFsys::UnixPath(LPSTR Path)
  505. {
  506. ASSERT(AfxIsValidString(Path));
  507. if (*Path && Path[1] == ':')
  508. {
  509. Path[1] = Path[0];
  510. Path[0] = '\';
  511. }
  512. return Path;
  513. }
  514. HANDLE CFsys::CreateFile(LPCTSTR lpFileName, // pointer to name of the file 
  515.     DWORD dwDesiredAccess, // access (read-write) mode 
  516.     DWORD dwShareMode, // share mode 
  517.     LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security descriptor 
  518.     DWORD dwCreationDistribution, // how to create 
  519.     DWORD dwFlagsAndAttributes, // file attributes 
  520.     HANDLE hTemplateFile  // handle to file with attributes to copy  
  521.    )
  522. {
  523. ASSERT(AfxIsValidString(lpFileName));
  524. CString cFileName = lpFileName;
  525. DosPath(cFileName.GetBuffer(MAX_PATH));
  526. cFileName.ReleaseBuffer();
  527. ASSERT(AfxIsValidString(lpFileName));
  528. return ::CreateFile(cFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
  529. dwCreationDistribution, dwFlagsAndAttributes, hTemplateFile);
  530. }
  531. ///////////////////////////////////////////////////////////////////////////
  532. // Build a CFileInfoList
  533. BOOL CFsys::BldFileInfoList(int User, LPCSTR Root, CFileInfoList& FileList, LPCSTR Origin, LPCSTR Path, BOOL ListDir)
  534. {
  535. char buf[MAX_PATH];
  536. MkPath(Root, Origin, Path, buf);
  537. int Len = strlen(buf);
  538. if (ListDir)
  539. {
  540. // If Len == 0 we have the  root. 
  541. // MkPath will ensure that  is removed from the end of any other path.
  542. strcpy(buf + Len, Len == 1 ? "*" : "\*"); 
  543. if (!AddFileInfoListPath(User, FileList, buf))
  544. {
  545. buf[Len] = 0;
  546. AddFileInfoListPath(User, FileList, buf);
  547. }
  548. }
  549. else
  550. AddFileInfoListPath(User, FileList, buf);
  551. return TRUE;
  552. }
  553. int CFsys::AddFileInfoListPath(int User, CFileInfoList& FileList, LPCSTR Path)
  554. {
  555. /*
  556. HANDLE h;
  557. CFileInfo *Info;
  558. WIN32_FIND_DATA Data;
  559. */
  560. int Count = 0;
  561. CFsysSecurityNode *fsn = NULL;
  562. USER Class = CUsr::GetUserClass(User);
  563. /*
  564. if ((h = FindFirstFile(User, Path, &Data)) != INVALID_HANDLE_VALUE)
  565. {
  566. do
  567. {
  568. ASSERT(AfxIsValidString(((CFindFileHandle *)h)->m_FullPath));
  569. FileList.m_FullPath = ((CFindFileHandle *)h)->m_FullPath;
  570. ++Count;
  571. Info = new CFileInfo;
  572. memcpy(&Info->m_Data, &Data, sizeof(WIN32_FIND_DATA));
  573. int Mask;
  574. fsn = NULL;
  575. Info->m_Flags = CFsysSecurity::GetPermissions(
  576. User,
  577. Class, 
  578. GetSecurityHandle(h), 
  579. Data.cFileName, 
  580. ((Info->m_Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0),
  581. &Mask, // Unused here...
  582. &fsn,
  583. TRUE);
  584. Info->m_Flags |= (Info->m_Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
  585. NODE_DIR : 0;
  586. if ((Path[0] == '\') && (Path[1] == '*') && !Path[2])
  587. Info->m_Flags |= NODE_DRIVE; // Quick patch for drives...
  588. if (Info->m_Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  589. {
  590. Info->m_Flags |= NODE_READONLY;
  591. Info->m_Flags &= ~(NODE_0WRITE | NODE_AWRITE | NODE_GWRITE);
  592. }
  593. if (fsn)
  594. {
  595. Info->m_User = fsn->Owner;
  596. Info->m_Group = fsn->Class;
  597. Info->m_Comment = strdup(fsn->Comment);
  598. }
  599. else
  600. {
  601. Info->m_User = 0;
  602. Info->m_Group = 0;
  603. Info->m_Comment.Empty();
  604. }
  605. if ((Info->m_Data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
  606. || (Info->m_User && ((User == Info->m_User) && (Info->m_Flags & NODE_OHIDE)))
  607. || (Info->m_Group && ((Class == Info->m_Group) && (Info->m_Flags & NODE_GHIDE)))
  608. || (Info->m_Flags & NODE_AHIDE))
  609. {
  610. Info->Hide(TRUE);
  611. }
  612. Info->m_Inode = 0;
  613. Info->m_FileNameLen = strlen(Info->m_Data.cFileName);
  614. Info->m_Links = 1;
  615. FileList.Add(Info);
  616. } while(FindNextFile(h,&Data));
  617. FindClose(h);
  618. }
  619. */
  620. return Count;
  621. }
  622. // Get a handle to Find*File() handle and return the security handle
  623. HANDLE CFsys::GetSecurityHandle(HANDLE h)
  624. {
  625. CFindFileHandle *MyHandle = (CFindFileHandle *)h;
  626. ASSERT(AfxIsValidAddress(MyHandle, sizeof(CFindFileHandle)));
  627. ASSERT(AfxIsValidAddress((LPVOID)MyHandle->m_SecurityHandle, sizeof(CFsysSecurityGrp)));
  628. return MyHandle->m_SecurityHandle;
  629. }
  630. BOOL CFsys::IsDirectory(int User, LPCSTR Path)
  631. {
  632. HANDLE h;
  633. WIN32_FIND_DATA Data;
  634. if ((h = FindFirstFile(User, Path, &Data)) != INVALID_HANDLE_VALUE)
  635. {
  636. FindClose(h);
  637. return (Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  638. }
  639. return FALSE;
  640. }
  641. BOOL CFsys::IsPlainFile(int User, LPCSTR Path)
  642. {
  643. HANDLE h;
  644. WIN32_FIND_DATA Data;
  645. if ((h = FindFirstFile(User, Path, &Data)) != INVALID_HANDLE_VALUE)
  646. {
  647. FindClose(h);
  648. return (Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
  649. }
  650. return FALSE;
  651. }
  652. // General file security checker. 
  653. // Called prior to reading/creating files or directories
  654. BOOL CFsys::CheckPermission(int User, LPCSTR RootPath, LPCSTR Path, BOOL IsDir, int PermsWanted)
  655. {
  656. ASSERT(AfxIsValidString(Path));
  657. HANDLE h;
  658. WIN32_FIND_DATA Data;
  659. SetLastError(NO_ERROR);
  660. // EXT module
  661. CHKPRMS cp;
  662. cp.User = User;
  663. cp.RootPath = RootPath;
  664. cp.IsDir = IsDir;
  665. cp.PermsWanted = PermsWanted;
  666. int err;
  667. if (err = PrcExt(CAPIHandler::OnFsysCheckPermission,0,(WPARAM)0,(LPARAM)&cp))
  668. {
  669. if (err == CFuncList::AbortError)
  670. return FALSE;
  671. if (err == CFuncList::OkAllDone)
  672. return TRUE;
  673. }
  674. // Check against root path
  675. if (User)
  676. {
  677. CString cPath, cBuf;
  678. if (!RootPath)
  679. RootPath = CUsr::GetRecursiveParam(User, "Root", "", cBuf);
  680. if (!RootPath || !*RootPath)
  681. {
  682. LPCSTR Name = CUsr::FindUser(User,cBuf);
  683. if (!Name)
  684. Name = "**unknown**";
  685. LogMsg(LOGF_WARNINGS,"CFsys::CheckPermission(%s) - User has no root dir! Permission denied.", Name);
  686. SetLastError(ERROR_ACCESS_DENIED);
  687. return FALSE;
  688. }
  689. LPCSTR p = Path;
  690. while(*p && (*p == *RootPath))
  691. {
  692. ++p;
  693. ++RootPath;
  694. }
  695. if (*Path && *RootPath)
  696. {
  697. LPCSTR Name = CUsr::FindUser(User,cBuf);
  698. if (!Name)
  699. Name = "**unknown**";
  700. LogMsg(LOGF_DEBUG,"CFsys::CheckPermission(%s '%s') - Path is above the users root path. Permission denied.", Name, Path);
  701. SetLastError(ERROR_ACCESS_DENIED);
  702. return FALSE;
  703. }
  704. }
  705. // See if the file/dir exist. If so, we just check that objects permissions..
  706. if ((h = FindFirstFile(User, Path, &Data)) != INVALID_HANDLE_VALUE)
  707. {
  708. // The object exist. 
  709. BOOL Rval = CFsysSecurity::CheckPermission(
  710. User,
  711. CUsr::GetUserClass(User), 
  712. GetSecurityHandle(h), 
  713. Data.cFileName, 
  714. PermsWanted,
  715. IsDir);
  716. FindClose(h);
  717. if (!Rval)
  718. {
  719. LogMsg(LOGF_DEBUG,"CheckPermission(%s) - CheckPermission() - Permission denied.", Path);
  720. SetLastError(ERROR_ACCESS_DENIED);
  721. return FALSE;
  722. }
  723. // If the user want to create a new object we must also check the parent dir
  724. if (!(PermsWanted & NODE_CREATE))
  725. return TRUE;
  726. }
  727. // If the user want read access, we can give up now.
  728. if (PermsWanted & (NODE_READ | NODE_EXEC))
  729. {
  730. LogMsg(LOGF_DEBUG,"CheckPermission(%s) - File/dir not found (or access denied).", Path);
  731. SetLastError(ERROR_FILE_NOT_FOUND);
  732. return FALSE;
  733. }
  734. // The object dont exist... 
  735. // Check for appropriate permission on the parent directory level
  736. CString cMyPath = Path;
  737. LPSTR p = strrchr(cMyPath.GetBuffer(1),'\');
  738. if (!p)
  739. {
  740. LogMsg(LOGF_DEBUG,"CheckPermission(%s) - Invalid path.", Path);
  741. SetLastError(ERROR_BAD_FORMAT);
  742. return FALSE;
  743. }
  744. *p = 0;
  745. cMyPath.ReleaseBuffer();
  746. if ((h = FindFirstFile(User, cMyPath, &Data)) == INVALID_HANDLE_VALUE)
  747. {
  748. LogMsg(LOGF_DEBUG,"CheckPermission(%s) - Parent directory not found.", Path);
  749. SetLastError(ERROR_PATH_NOT_FOUND);
  750. return FALSE;
  751. }
  752. if (!CFsysSecurity::CheckPermission(
  753. User,
  754. CUsr::GetUserClass(User), 
  755. GetSecurityHandle(h), 
  756. Data.cFileName, 
  757. PermsWanted,
  758. TRUE))
  759. {
  760. FindClose(h);
  761. LogMsg(LOGF_DEBUG,"CheckPermission(%s) - CheckPermission() - Permission denied on parent level.", Path);
  762. SetLastError(ERROR_ACCESS_DENIED);
  763. return FALSE;
  764. }
  765. FindClose(h);
  766. return TRUE;
  767. }
  768. // Change directory.
  769. // Path is any valid path, including unresolved links and ..'s
  770. // Path must have / mapped to , and begin with  ...
  771. int CFsys::chdir(int User, LPCSTR Root, CString& cCWD, LPCSTR Path)
  772. {
  773. ASSERT(AfxIsValidString(Root));
  774. ASSERT(AfxIsValidString(cCWD));
  775. ASSERT(AfxIsValidString(Path));
  776. char MyPath[MAX_PATH];
  777. char ParsedPath[MAX_PATH];
  778. MkPath(Root, cCWD, Path, MyPath);
  779. ASSERT(AfxIsValidString(MyPath));
  780. // Map ../ etc for the path...
  781. if (!RealPath(MyPath, ParsedPath, TRUE))
  782. {
  783. LogMsg(LOGF_WARNINGS,"chdir(%s) - Unexpected error in RealPath(%s).", Path, MyPath);
  784. return -1;
  785. }
  786. // Check permissions
  787. if (!CheckPermission(User, Root, ParsedPath, TRUE, NODE_EXEC))
  788. {
  789. LogMsg(LOGF_DEBUG,"chdir(%s) - Not a directory (or no access).", MyPath);
  790. return -1;
  791. }
  792. UnixPath(ParsedPath);
  793. ASSERT(AfxIsValidString(ParsedPath));
  794. cCWD = ParsedPath;
  795. return 0;
  796. }
  797. LPCSTR CFsys::GetFullPath(int User, LPCSTR Root, LPCSTR CWD, LPCSTR Path, CString& cBuf, DWORD AccessFlags)
  798. {
  799. ASSERT(AfxIsValidString(Root));
  800. ASSERT(AfxIsValidString(CWD));
  801. ASSERT(AfxIsValidString(Path));
  802. char MyPath[MAX_PATH];
  803. char ParsedPath[MAX_PATH];
  804. MkPath(Root, CWD, Path, MyPath);
  805. ASSERT(AfxIsValidString(MyPath));
  806. // Map ../ etc for the path...
  807. if (!RealPath(MyPath, ParsedPath, TRUE))
  808. {
  809. LogMsg(LOGF_WARNINGS,"GetFullPath(%s) - Unexpected error in RealPath(%s).", Path, MyPath);
  810. return NULL;
  811. }
  812. UnixPath(ParsedPath);
  813. ASSERT(AfxIsValidString(ParsedPath));
  814. cBuf = ParsedPath;
  815. return cBuf;
  816. }
  817. BOOL CFsys::RenamePath(int User, LPCSTR OldPath, LPCSTR NewPath)
  818. {
  819. ASSERT(AfxIsValidString(OldPath));
  820. ASSERT(AfxIsValidString(NewPath));
  821. BOOL IsDir = IsDirectory(User, OldPath);
  822. if (!CheckPermission(User, NULL, OldPath, IsDir, NODE_WRITE))
  823. {
  824. LogMsg(LOGF_DEBUG,"RenamePath(%s --> %s) - Missing WRITE permission to old path.",
  825. OldPath, NewPath);
  826. return FALSE;
  827. }
  828. if (!CheckPermission(User, NULL, NewPath, IsDir, NODE_CREATE))
  829. {
  830. LogMsg(LOGF_DEBUG,"RenamePath(%s --> %s) - Missing CREATE permission to new path.",
  831. OldPath, NewPath);
  832. return FALSE;
  833. }
  834. // Convert filenames to DOS style names
  835. CString cOldPath = OldPath;
  836. CString cNewPath = NewPath;
  837. DosPath(cOldPath.GetBuffer(MAX_PATH));
  838. DosPath(cNewPath.GetBuffer(MAX_PATH));
  839. cNewPath.ReleaseBuffer();
  840. cOldPath.ReleaseBuffer();
  841. ASSERT(AfxIsValidString(cOldPath));
  842. ASSERT(AfxIsValidString(cNewPath));
  843. if (!::MoveFileEx(cOldPath, cNewPath, MOVEFILE_WRITE_THROUGH))
  844. {
  845. LogMsg(LOGF_DEBUG,"RenamePath() - MoveFileEx(%s, %s) failed. %s", cOldPath, cNewPath,
  846. GetLastErrorText());
  847. return FALSE;
  848. }
  849. return TRUE;
  850. }
  851. // Delete a file or directory (if the dir is empty)
  852. BOOL CFsys::DeletePath(int User, LPCSTR Path)
  853. {
  854. ASSERT(AfxIsValidString(Path));
  855. if (strpbrk(Path,"*?[]{}"))
  856. {
  857. LogMsg(LOGF_WARNINGS,"DeletePath(%s) - not allowed to delete paths containing patterns.", Path);
  858. SetLastError(ERROR_INVALID_PARAMETER);
  859. return FALSE;
  860. }
  861. CString cMyPath = Path;
  862. // Check permissions
  863. BOOL IsDir;
  864. IsDir = IsDirectory(User, Path);
  865. if (!CheckPermission(User, NULL, Path, IsDir, NODE_WRITE))
  866. {
  867. LogMsg(LOGF_WARNINGS,"DeletePath(%s) - Permission denied", Path);
  868. SetLastError(ERROR_ACCESS_DENIED);
  869. return FALSE;
  870. }
  871. // Convert filename to DOS style names
  872. DosPath(cMyPath.GetBuffer(1));
  873. cMyPath.ReleaseBuffer();
  874. ASSERT(AfxIsValidString(cMyPath));
  875. if (IsDir)
  876. {
  877. return ::RemoveDirectory(cMyPath);
  878. }
  879. return ::DeleteFile(cMyPath);
  880. }
  881. // Create a new directory
  882. BOOL CFsys::MkDir(int User, LPCSTR Path)
  883. {
  884. ASSERT(AfxIsValidString(Path));
  885. if (strpbrk(Path,"*?[]{}"))
  886. {
  887. LogMsg(LOGF_WARNINGS,"MkDir(%s) - not allowed to create paths containing patterns.", Path);
  888. SetLastError(ERROR_INVALID_PARAMETER);
  889. return FALSE;
  890. }
  891. CString cMyPath = Path;
  892. // Check permissions
  893. if (!CheckPermission(User, NULL, Path, TRUE, NODE_CREATE))
  894. {
  895. LogMsg(LOGF_WARNINGS,"MkDir(%s) - Permission denied", Path);
  896. SetLastError(ERROR_ACCESS_DENIED);
  897. return FALSE;
  898. }
  899. // Convert filename to DOS style names
  900. DosPath(cMyPath.GetBuffer(MAX_PATH));
  901. cMyPath.ReleaseBuffer();
  902. ASSERT(AfxIsValidString(cMyPath));
  903. return ::CreateDirectory(cMyPath, NULL);
  904. }
  905. // Chmod on a single file
  906. // Return 0 on success
  907. int CFsys::chmod(int User, LPCSTR Path, int SetMode, int SetOwner, 
  908. int SetClass, LPCSTR SetComment, int DefDirMode, int DefFileMode)
  909. {
  910. LPSTR fpath;
  911. LPSTR MyPath = strdup(Path);
  912. HANDLE SecurityGrp = INVALID_HANDLE_VALUE, SecurityDsc;
  913. int rval = 0;
  914. CFsysSecurityNode *fsn = NULL;
  915. DosPath(MyPath);
  916. DWORD dw = GetFileAttributes(MyPath);
  917. BOOL IsDir = ((dw != 0xFFFFFFFF) && (dw & FILE_ATTRIBUTE_DIRECTORY));
  918. // Remove any trailing  on the path..
  919. strcpy(MyPath,Path);
  920. LPSTR p = MyPath + strlen(MyPath) - 1;
  921. if (*p == '\')
  922. *p = 0;
  923. // Get the parent dir
  924. fpath = strrchr(MyPath,'\');
  925. if (!fpath)
  926. {
  927. rval = -1;
  928. goto done;
  929. }
  930. *fpath++ = 0;
  931. CFsysSecurity::Lock();
  932. if ((SecurityGrp = CFsysSecurity::GetSecurityGroupFromPath(
  933. User, CUsr::GetUserClass(User), MyPath)) == INVALID_HANDLE_VALUE)
  934. {
  935. LogMsg(LOGF_DEBUG,"chmod(%s) - GetUserClass(%d) failed.", Path, User);
  936. rval = -2;
  937. goto done;
  938. }
  939. if ((SecurityDsc = CFsysSecurity::GetSecurityDescriptor(SecurityGrp,fpath)) == INVALID_HANDLE_VALUE)
  940. {
  941. // Create a new security handle for this file
  942. if ((SecurityDsc = CFsysSecurity::CreateNode(User, SecurityGrp, IsDir, fpath)) == INVALID_HANDLE_VALUE)
  943. {
  944. LogMsg(LOGF_DEBUG,"chmod(%s) - faled to create new security handle.", Path);
  945. rval = -3;
  946. goto done;
  947. }
  948. }
  949. fsn = (CFsysSecurityNode *)SecurityDsc;
  950. ASSERT(AfxIsValidAddress(fsn, sizeof(CFsysSecurityNode)));
  951. if ((User && !CUsr::IsAdmin(User)) && (User != fsn->Owner))
  952. {
  953. LogMsg(LOGF_DEBUG,"chmod(%s) - Only root and owner can chmod. User = %d.", Path, User);
  954. rval = -4;
  955. goto done;
  956. }
  957. // Set the new permissions
  958. if (SetMode != -1)
  959. fsn->Perms = (SetMode & NODE_SETTABLE);
  960. if (SetOwner != -1)
  961. fsn->Owner = SetOwner;
  962. if (SetClass != -1)
  963. fsn->Class = SetClass;
  964. if (SetComment)
  965. fsn->Comment = SetComment;
  966. if (IsDir)
  967. fsn->Perms |= S_IFDIR;
  968. if ((dw != 0xFFFFFFFF) && (dw & FILE_ATTRIBUTE_READONLY))
  969. {
  970. fsn->Perms &= ~NODE_WRITEMSK;
  971. fsn->Perms |= NODE_READONLY;
  972. }
  973. // Save the new data.
  974. if (!CFsysSecurity::FlushGroup(SecurityGrp))
  975. rval = -1;
  976. done:
  977. CFsysSecurity::UnLock();
  978. if (SecurityGrp != INVALID_HANDLE_VALUE)
  979. CFsysSecurity::CloseSecurityGroup(SecurityGrp);
  980. free(MyPath);
  981. return rval;
  982. }
  983. ///////////////////////////////////////////////////////////////////////////
  984. // CFindFileHandle - support class for Find*File()
  985. CFindFileHandle::CFindFileHandle()
  986. {
  987. m_DOShandle = INVALID_HANDLE_VALUE;
  988. m_PathsQueued = NULL;
  989. m_User = 0;
  990. m_Pattern.Empty();
  991. m_Argc = 0;
  992. }
  993. CFindFileHandle::~CFindFileHandle()
  994. {
  995. if (m_PathsQueued)
  996. {
  997. ASSERT(AfxIsValidAddress(m_PathsQueued,sizeof(CCmdArgs)));
  998. delete m_PathsQueued;
  999. }
  1000. ASSERT(m_DOShandle == INVALID_HANDLE_VALUE);
  1001. // Delete the security group descriptor
  1002. if (m_SecurityHandle != INVALID_HANDLE_VALUE)
  1003. {
  1004. CFsysSecurityGrp *pGrp = (CFsysSecurityGrp *)m_SecurityHandle;
  1005. ASSERT(AfxIsValidAddress(pGrp,sizeof(CFsysSecurityGrp)));
  1006. delete pGrp;
  1007. }
  1008. }