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

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 : Unix.cpp
  16. // PURPOSE : UNIX commands
  17. // PROGRAM : 
  18. // DATE : Sept. 27 1996
  19. // AUTHOR : Jarle Aase
  20. // ---
  21. // REVISION HISTORY
  22. // 
  23. // This module contains code from free-bsd
  24. /*
  25.  * Copyright (c) 1987 Regents of the University of California.
  26.  * All rights reserved.
  27.  *
  28.  * Redistribution and use in source and binary forms, with or without
  29.  * modification, are permitted provided that the following conditions
  30.  * are met:
  31.  * 1. Redistributions of source code must retain the above copyright
  32.  *    notice, this list of conditions and the following disclaimer.
  33.  * 2. Redistributions in binary form must reproduce the above copyright
  34.  *    notice, this list of conditions and the following disclaimer in the
  35.  *    documentation and/or other materials provided with the distribution.
  36.  * 3. All advertising materials mentioning features or use of this software
  37.  *    must display the following acknowledgement:
  38.  * This product includes software developed by the University of
  39.  * California, Berkeley and its contributors.
  40.  * 4. Neither the name of the University nor the names of its contributors
  41.  *    may be used to endorse or promote products derived from this software
  42.  *    without specific prior written permission.
  43.  *
  44.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  45.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  46.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  47.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  48.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  49.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  50.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  51.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  52.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  53.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  54.  * SUCH DAMAGE.
  55.  */
  56. #include "stdafx.h"
  57. #include "WarSoftware.h"
  58. #include "Unix.h"
  59. #ifdef _DEBUG
  60. #define new DEBUG_NEW
  61. #undef THIS_FILE
  62. static char THIS_FILE[] = __FILE__;
  63. #endif
  64. #define index(a,b) strchr(a,b)
  65. #define rindex(a,b) strrchr(a,b)
  66. #define BADCH (int)'?'
  67. #define EMSG ""
  68. CUnix::CUnix()
  69. {
  70. m_TmpName = NULL;
  71. m_stdio = NULL;
  72. place = EMSG;
  73. opterr = 0; /* if error message should be printed */
  74. optind = 0; /* index into parent argv vector */
  75. optopt = 0; /* character checked for validity */
  76. optarg = NULL;
  77. }
  78. CUnix::~CUnix()
  79. {
  80. if (m_TmpName)
  81. delete m_TmpName;
  82. if (m_stdio && (m_stdio != BUFFER_STDIO))
  83. fclose(m_stdio);
  84. }
  85. BOOL CUnix::Create(CCmdArgs *CmdArgs, CLog *Log, FILE *OutFile, CUserFsys *Fsys)
  86. {
  87. m_Fsys = Fsys;
  88. m_CmdArgs = CmdArgs;
  89. m_Log = Log;
  90. optind = 1;
  91. opterr = 1;
  92. m_stdio = OutFile;
  93. m_HavePrintedSomething = FALSE;
  94. m_ShowLinkAsFile = FALSE;
  95. m_UseBufferOutput = FALSE;
  96. return TRUE;
  97. }
  98. int CUnix::Exec()
  99. {
  100. if (!m_stdio)
  101. {
  102. // Open a temporary file
  103. LPCSTR TmpDir = getenv("TEMP");
  104. ASSERT(TmpDir ? AfxIsValidString(TmpDir) : TRUE);
  105. if ((m_TmpName = _tempnam(TmpDir, "~CUnix")) == NULL)
  106. {
  107. LogMsg(LOGF_WARNINGS,"Exec: Failed to get temporary file name.");
  108. return FALSE;
  109. }
  110. ASSERT(AfxIsValidString(m_TmpName));
  111. if ((m_stdio = fopen(m_TmpName,"w+b")) == NULL)
  112. {
  113. LogMsg(LOGF_WARNINGS,"Exec: Failed to open temporary file '%s'.", m_TmpName);
  114. return FALSE;
  115. }
  116. }
  117. else if (m_stdio == BUFFER_STDIO)
  118. {
  119. m_stdout.Empty();
  120. m_UseBufferOutput = TRUE;
  121. }
  122. // Call the main function
  123. ASSERT(AfxIsValidAddress(m_CmdArgs,sizeof(m_CmdArgs)));
  124. ASSERT(m_CmdArgs->m_argc >= 1);
  125. return main(m_CmdArgs->m_argc, m_CmdArgs->m_argv);
  126. }
  127. int CUnix::main(int argc, char **argv)
  128. {
  129. // Must be overridden
  130. ASSERT(FALSE);
  131. return -1;
  132. }
  133. void CUnix::LogMsg(int flag, LPCSTR Format, ...)
  134. {
  135. CString cBuf;
  136. if (!ShouldLog(m_Log, flag))
  137. return;
  138. ASSERT(AfxIsValidString(Format, FALSE));
  139. cBuf.Format("CUnix: %s", Format);
  140. va_list argList;
  141. va_start(argList, Format);
  142. m_Log->LogMsgV(flag, cBuf, argList);
  143. va_end(argList);
  144. }
  145. BOOL CUnix::BldFileInfoList(CFileInfoList& FileList, LPCSTR Path, BOOL ListDir)
  146. {
  147. return m_Fsys->BldFileInfoList(FileList, Path, ListDir);
  148. }
  149. int CUnix::printf(LPCSTR format,  ... )
  150. {
  151. ASSERT(AfxIsValidString(format));
  152. int Rval;
  153. va_list marker;
  154. va_start(marker,format);
  155. if (m_UseBufferOutput)
  156. {
  157. Rval = m_stdout.FormatCatV(format, marker);
  158. }
  159. else
  160. {
  161. Rval = ::vfprintf(m_stdio, format, marker); 
  162. }
  163. va_end(marker);
  164. BOOL m_HavePrintedSomething = TRUE;
  165. return Rval;
  166. }
  167. int CUnix::putchar(int ch)
  168. {
  169. BOOL m_HavePrintedSomething = TRUE;
  170. if (ch == 'n')
  171. return puts(m_CRLF);
  172. if (m_UseBufferOutput)
  173. {
  174. m_stdout += ch;
  175. return ch;
  176. }
  177. return fputc(ch, m_stdio);
  178. }
  179. int CUnix::putc(int ch)
  180. {
  181. BOOL m_HavePrintedSomething = TRUE;
  182. if (ch == 'n')
  183. return puts(m_CRLF);
  184. return fputc(ch, m_stdio);
  185. }
  186. int CUnix::puts(LPCSTR str)
  187. {
  188. ASSERT(AfxIsValidString(str));
  189. BOOL m_HavePrintedSomething = TRUE;
  190. if (m_UseBufferOutput)
  191. {
  192. m_stdout += str;
  193. return 1;
  194. }
  195. else
  196. return fputs(str, m_stdio);
  197. }
  198. /////////////////////////////////////////////////////////////////////////////////////
  199. // Misc standard UNIX lib functions
  200. int CUnix::getuid()
  201. {
  202. if (m_Fsys->m_IsAdmin)
  203. return 0; // root
  204. return m_Fsys->m_User;
  205. }
  206. int CUnix::getopt(int nargc, char * const *nargv, const char *ostr)
  207. {
  208. register char *oli; /* option letter list index */
  209. char *p;
  210. if (!*place) { /* update scanning pointer */
  211. if (optind >= nargc || *(place = nargv[optind]) != '-') {
  212. place = EMSG;
  213. return(EOF);
  214. }
  215. if (place[1] && *++place == '-') { /* found "--" */
  216. ++optind;
  217. place = EMSG;
  218. return(EOF);
  219. }
  220. } /* option letter okay? */
  221. if ((optopt = (int)*place++) == (int)':' ||
  222.     !(oli = index(ostr, optopt))) {
  223. /*
  224.  * if the user didn't specify '-' as an option,
  225.  * assume it means EOF.
  226.  */
  227. if (optopt == (int)'-')
  228. return(EOF);
  229. if (!*place)
  230. ++optind;
  231. if (opterr) {
  232. if (!(p = rindex(*nargv, '/')))
  233. p = *nargv;
  234. else
  235. ++p;
  236. LogMsg(LOGF_WARNINGS, "getopt(): %s: illegal option -- %cn", p, optopt);
  237. }
  238. return(BADCH);
  239. }
  240. if (*++oli != ':') { /* don't need argument */
  241. optarg = NULL;
  242. if (!*place)
  243. ++optind;
  244. }
  245. else { /* need an argument */
  246. if (*place) /* no white space */
  247. optarg = place;
  248. else if (nargc <= ++optind) { /* no arg */
  249. place = EMSG;
  250. if (!(p = rindex(*nargv, '/')))
  251. p = *nargv;
  252. else
  253. ++p;
  254. if (opterr)
  255. LogMsg(LOGF_WARNINGS, "getopt() %s: option requires an argument -- %cn", p, optopt);
  256. return(BADCH);
  257. }
  258.   else /* white space */
  259. optarg = nargv[optind];
  260. place = EMSG;
  261. ++optind;
  262. }
  263. return(optopt); /* dump back option letter */
  264. }
  265. LPCSTR CUnix::userfromuid(int uid, int nouser)
  266. {
  267. uid;
  268. nouser;
  269. return "ftp";
  270. }
  271. LPCSTR CUnix::groupfromgid(int gid, int nouser)
  272. {
  273. gid;
  274. nouser;
  275. return "ftp";
  276. }
  277. void CUnix::strmode(DWORD Flags, char *bp)
  278. {
  279. ASSERT(AfxIsValidAddress(bp, 16));
  280. sprintf(bp,"%c%c%c%c%c%c%c%c%c%c",
  281. (!m_ShowLinkAsFile && (Flags & NODE_LINK)) ? 'l' : (Flags & NODE_DIR) ? 'd' : '-',
  282. Flags & NODE_OREAD ? 'r' : '-',
  283. Flags & NODE_0WRITE ? 'w' : '-',
  284. Flags & NODE_OEXEC ? 'x' : '-',
  285. Flags & NODE_GREAD ? 'r' : '-',
  286. Flags & NODE_GWRITE ? 'w' : '-',
  287. Flags & NODE_GEXEC ? 'x' : '-',
  288. Flags & NODE_AREAD ? 'r' : '-',
  289. Flags & NODE_AWRITE ? 'w' : '-',
  290. Flags & NODE_AEXEC ? 'x' : '-');
  291. }
  292. int CUnix::readlink(LPCSTR path, LPSTR buf, int bufsiz)
  293. {
  294. return -1;
  295. }
  296. /*
  297.  * Get next token from string *stringp, where tokens are possibly-empty
  298.  * strings separated by characters from delim.
  299.  *
  300.  * Writes NULs into the string at *stringp to end tokens.
  301.  * delim need not remain constant from call to call.
  302.  * On return, *stringp points past the last NUL written (if there might
  303.  * be further tokens), or is NULL (if there are definitely no more tokens).
  304.  *
  305.  * If *stringp is NULL, strsep returns NULL.
  306.  */
  307. LPSTR CUnix::strsep(LPSTR *stringp, LPCSTR delim)
  308. {
  309. register char *s;
  310. register const char *spanp;
  311. register int c, sc;
  312. char *tok;
  313. if ((s = *stringp) == NULL)
  314. return (NULL);
  315. for (tok = s;;) {
  316. c = *s++;
  317. spanp = delim;
  318. do {
  319. if ((sc = *spanp++) == c) {
  320. if (c == 0)
  321. s = NULL;
  322. else
  323. s[-1] = 0;
  324. *stringp = s;
  325. return (tok);
  326. }
  327. } while (sc != 0);
  328. }
  329. /* NOTREACHED */
  330. }
  331. #define SET_LEN 6 /* initial # of bitcmd struct to malloc */
  332. #define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
  333. typedef struct bitcmd {
  334. char cmd;
  335. char cmd2;
  336. int bits;
  337. } BITCMD;
  338. #define CMD2_CLR 0x01
  339. #define CMD2_SET 0x02
  340. #define CMD2_GBITS 0x04
  341. #define CMD2_OBITS 0x08
  342. #define CMD2_UBITS 0x10
  343. static void compress_mode(BITCMD *set);
  344. static BITCMD *addcmd(BITCMD *set, int op, int who, int oparg, u_int mask);
  345. /*
  346.  * Given the old mode and an array of bitcmd structures, apply the operations
  347.  * described in the bitcmd structures to the old mode, and return the new mode.
  348.  * Note that there is no '=' command; a strict assignment is just a '-' (clear
  349.  * bits) followed by a '+' (set bits).
  350.  */
  351. int CUnix::getmode(void *bbox, int omode)
  352. {
  353. register BITCMD *set;
  354. register int clrval, newmode, value;
  355. set = (BITCMD *)bbox;
  356. newmode = omode;
  357. for (value = 0;; set++)
  358. switch(set->cmd) {
  359. /*
  360.  * When copying the user, group or other bits around, we "know"
  361.  * where the bits are in the mode so that we can do shifts to
  362.  * copy them around.  If we don't use shifts, it gets real
  363.  * grundgy with lots of single bit checks and bit sets.
  364.  */
  365. case 'u':
  366. value = (newmode & S_IRWXU) >> 6;
  367. goto common;
  368. case 'g':
  369. value = (newmode & S_IRWXG) >> 3;
  370. goto common;
  371. case 'o':
  372. value = newmode & S_IRWXO;
  373. common: if (set->cmd2 & CMD2_CLR) {
  374. clrval =
  375.     (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
  376. if (set->cmd2 & CMD2_UBITS)
  377. newmode &= ~((clrval<<6) & set->bits);
  378. if (set->cmd2 & CMD2_GBITS)
  379. newmode &= ~((clrval<<3) & set->bits);
  380. if (set->cmd2 & CMD2_OBITS)
  381. newmode &= ~(clrval & set->bits);
  382. }
  383. if (set->cmd2 & CMD2_SET) {
  384. if (set->cmd2 & CMD2_UBITS)
  385. newmode |= (value<<6) & set->bits;
  386. if (set->cmd2 & CMD2_GBITS)
  387. newmode |= (value<<3) & set->bits;
  388. if (set->cmd2 & CMD2_OBITS)
  389. newmode |= value & set->bits;
  390. }
  391. break;
  392. case '+':
  393. newmode |= set->bits;
  394. break;
  395. case '-':
  396. newmode &= ~set->bits;
  397. break;
  398. case 'X':
  399. //if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
  400. if (omode & (NODE_DIR|S_IXUSR|S_IXGRP|S_IXOTH))
  401. newmode |= set->bits;
  402. break;
  403. case '':
  404. default:
  405. #ifdef SETMODE_DEBUG
  406. (void)printf("getmode:%04o -> %04on", omode, newmode);
  407. #endif
  408. return (newmode);
  409. }
  410. }
  411. #define ADDCMD(a, b, c, d)
  412. if (set >= endset) {
  413. register BITCMD *newset;
  414. setlen += SET_LEN_INCR;
  415. newset = (BITCMD *)realloc(saveset, sizeof(BITCMD) * setlen);
  416. if (!saveset)
  417. return (NULL);
  418. set = newset + (set - saveset);
  419. saveset = newset;
  420. endset = newset + (setlen - 2);
  421. }
  422. set = addcmd(set, (a), (b), (c), (d))
  423. #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
  424. LPVOID CUnix::setmode(LPCSTR p)
  425. {
  426. register int perm, who;
  427. register char op;
  428. BITCMD *set, *saveset, *endset;
  429. int mask = 0;
  430. int equalopdone=0, permXbits, setlen;
  431. if (!*p)
  432. return (NULL);
  433. /*
  434.  * Get a copy of the mask for the permissions that are mask relative.
  435.  * Flip the bits, we want what's not set.  Since it's possible that
  436.  * the caller is opening files inside a signal handler, protect them
  437.  * as best we can.
  438.  */
  439. setlen = SET_LEN + 2;
  440. if ((set = (BITCMD *)malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
  441. return (NULL);
  442. saveset = set;
  443. endset = set + (setlen - 2);
  444. /*
  445.  * If an absolute number, get it and return; disallow non-octal digits
  446.  * or illegal bits.
  447.  */
  448. if (isdigit(*p)) {
  449. perm = (int)strtol(p, NULL, 8);
  450. if (perm & ~(STANDARD_BITS|S_ISTXT)) {
  451. free(saveset);
  452. return (NULL);
  453. }
  454. while (*++p)
  455. if (*p < '0' || *p > '7') {
  456. free(saveset);
  457. return (NULL);
  458. }
  459. ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
  460. return (saveset);
  461. }
  462. /*
  463.  * Build list of structures to set/clear/copy bits as described by
  464.  * each clause of the symbolic mode.
  465.  */
  466. for (;;) {
  467. /* First, find out which bits might be modified. */
  468. for (who = 0;; ++p) {
  469. switch (*p) {
  470. case 'a':
  471. who |= STANDARD_BITS;
  472. break;
  473. case 'u':
  474. who |= S_ISUID|S_IRWXU;
  475. break;
  476. case 'g':
  477. who |= S_ISGID|S_IRWXG;
  478. break;
  479. case 'o':
  480. who |= S_IRWXO;
  481. break;
  482. default:
  483. goto getop;
  484. }
  485. }
  486. getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
  487. free(saveset);
  488. return (NULL);
  489. }
  490. if (op == '=')
  491. equalopdone = 0;
  492. who &= ~S_ISTXT;
  493. for (perm = 0, permXbits = 0;; ++p) {
  494. switch (*p) {
  495. case 'r':
  496. perm |= S_IRUSR|S_IRGRP|S_IROTH;
  497. break;
  498. case 's':
  499. /* If only "other" bits ignore set-id. */
  500. if (who & ~S_IRWXO)
  501. perm |= S_ISUID|S_ISGID;
  502. break;
  503. case 't':
  504. /* If only "other" bits ignore sticky. */
  505. if (who & ~S_IRWXO) {
  506. who |= S_ISTXT;
  507. perm |= S_ISTXT;
  508. }
  509. break;
  510. case 'w':
  511. perm |= S_IWUSR|S_IWGRP|S_IWOTH;
  512. break;
  513. case 'X':
  514. permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
  515. break;
  516. case 'x':
  517. perm |= S_IXUSR|S_IXGRP|S_IXOTH;
  518. break;
  519. case 'u':
  520. case 'g':
  521. case 'o':
  522. /*
  523.  * When ever we hit 'u', 'g', or 'o', we have
  524.  * to flush out any partial mode that we have,
  525.  * and then do the copying of the mode bits.
  526.  */
  527. if (perm) {
  528. ADDCMD(op, who, perm, mask);
  529. perm = 0;
  530. }
  531. if (op == '=')
  532. equalopdone = 1;
  533. if (op == '+' && permXbits) {
  534. ADDCMD('X', who, permXbits, mask);
  535. permXbits = 0;
  536. }
  537. ADDCMD(*p, who, op, mask);
  538. break;
  539. default:
  540. /*
  541.  * Add any permissions that we haven't already
  542.  * done.
  543.  */
  544. if (perm || (op == '=' && !equalopdone)) {
  545. if (op == '=')
  546. equalopdone = 1;
  547. ADDCMD(op, who, perm, mask);
  548. perm = 0;
  549. }
  550. if (permXbits) {
  551. ADDCMD('X', who, permXbits, mask);
  552. permXbits = 0;
  553. }
  554. goto apply;
  555. }
  556. }
  557. apply: if (!*p)
  558. break;
  559. if (*p != ',')
  560. goto getop;
  561. ++p;
  562. }
  563. set->cmd = 0;
  564. #ifdef SETMODE_DEBUG
  565. (void)printf("Before compress_mode()n");
  566. dumpmode(saveset);
  567. #endif
  568. compress_mode(saveset);
  569. #ifdef SETMODE_DEBUG
  570. (void)printf("After compress_mode()n");
  571. dumpmode(saveset);
  572. #endif
  573. return (saveset);
  574. }
  575. static BITCMD *addcmd(BITCMD *set, int op, int who, int oparg, u_int mask)
  576. {
  577. switch (op) {
  578. case '=':
  579. set->cmd = '-';
  580. set->bits = who ? who : STANDARD_BITS;
  581. set++;
  582. op = '+';
  583. /* FALLTHROUGH */
  584. case '+':
  585. case '-':
  586. case 'X':
  587. set->cmd = op;
  588. set->bits = (who ? who : mask) & oparg;
  589. break;
  590. case 'u':
  591. case 'g':
  592. case 'o':
  593. set->cmd = op;
  594. if (who) {
  595. set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
  596.     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
  597.     ((who & S_IROTH) ? CMD2_OBITS : 0);
  598. set->bits = ~0;
  599. } else {
  600. set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
  601. set->bits = mask;
  602. }
  603. if (oparg == '+')
  604. set->cmd2 |= CMD2_SET;
  605. else if (oparg == '-')
  606. set->cmd2 |= CMD2_CLR;
  607. else if (oparg == '=')
  608. set->cmd2 |= CMD2_SET|CMD2_CLR;
  609. break;
  610. }
  611. return (set + 1);
  612. }
  613. /*
  614.  * Given an array of bitcmd structures, compress by compacting consecutive
  615.  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
  616.  * 'g' and 'o' commands continue to be separate.  They could probably be
  617.  * compacted, but it's not worth the effort.
  618.  */
  619. static void compress_mode(BITCMD *set)
  620. {
  621. register BITCMD *nset;
  622. register int setbits, clrbits, Xbits, op;
  623. for (nset = set;;) {
  624. /* Copy over any 'u', 'g' and 'o' commands. */
  625. while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
  626. *set++ = *nset++;
  627. if (!op)
  628. return;
  629. }
  630. for (setbits = clrbits = Xbits = 0;; nset++) {
  631. if ((op = nset->cmd) == '-') {
  632. clrbits |= nset->bits;
  633. setbits &= ~nset->bits;
  634. Xbits &= ~nset->bits;
  635. } else if (op == '+') {
  636. setbits |= nset->bits;
  637. clrbits &= ~nset->bits;
  638. Xbits &= ~nset->bits;
  639. } else if (op == 'X')
  640. Xbits |= nset->bits & ~setbits;
  641. else
  642. break;
  643. }
  644. if (clrbits) {
  645. set->cmd = '-';
  646. set->cmd2 = 0;
  647. set->bits = clrbits;
  648. set++;
  649. }
  650. if (setbits) {
  651. set->cmd = '+';
  652. set->cmd2 = 0;
  653. set->bits = setbits;
  654. set++;
  655. }
  656. if (Xbits) {
  657. set->cmd = 'X';
  658. set->cmd2 = 0;
  659. set->bits = Xbits;
  660. set++;
  661. }
  662. }
  663. }
  664. int CUnix::chmod(LPCSTR path, int mode,
  665. int SetOwner, int SetClass, LPCSTR SetComment,
  666. int DefDirMode, int DefFileMode)
  667. {
  668. ASSERT(FALSE);
  669. return -1;
  670. }