tclWinTest.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:23k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclWinTest.c --
  3.  *
  4.  * Contains commands for platform specific tests on Windows.
  5.  *
  6.  * Copyright (c) 1996 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * RCS: @(#) $Id: tclWinTest.c,v 1.8.2.6 2006/03/27 23:30:54 patthoyts Exp $
  12.  */
  13. #define USE_COMPAT_CONST
  14. #include "tclWinInt.h"
  15. /*
  16.  * For TestplatformChmod on Windows
  17.  */
  18. #ifdef __WIN32__
  19. #include <aclapi.h>
  20. #endif
  21. /*
  22.  * MinGW 3.4.2 does not define this.
  23.  */
  24. #ifndef INHERITED_ACE
  25. #define INHERITED_ACE (0x10)
  26. #endif
  27. /*
  28.  * Forward declarations of procedures defined later in this file:
  29.  */
  30. int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp));
  31. static int TesteventloopCmd _ANSI_ARGS_((ClientData dummy,
  32. Tcl_Interp *interp, int argc, CONST84 char **argv));
  33. static int TestvolumetypeCmd _ANSI_ARGS_((ClientData dummy,
  34. Tcl_Interp *interp, int objc,
  35. Tcl_Obj *CONST objv[]));
  36. static int      TestwinclockCmd _ANSI_ARGS_(( ClientData dummy,
  37.       Tcl_Interp* interp,
  38.       int objc,
  39.       Tcl_Obj *CONST objv[] ));
  40. static int      TestwinsleepCmd _ANSI_ARGS_(( ClientData dummy,
  41.       Tcl_Interp* interp,
  42.       int objc,
  43.       Tcl_Obj *CONST objv[] ));
  44. static Tcl_ObjCmdProc TestExceptionCmd;
  45. static int TestwincpuidCmd _ANSI_ARGS_(( ClientData dummy,
  46.       Tcl_Interp* interp,
  47.       int objc,
  48.       Tcl_Obj *CONST objv[] ));
  49. static int TestplatformChmod _ANSI_ARGS_((CONST char *nativePath, 
  50.  int pmode));
  51. static int TestchmodCmd _ANSI_ARGS_((ClientData dummy,
  52.   Tcl_Interp *interp, int argc, CONST84 char **argv));
  53. /*
  54.  *----------------------------------------------------------------------
  55.  *
  56.  * TclplatformtestInit --
  57.  *
  58.  * Defines commands that test platform specific functionality for
  59.  * Windows platforms.
  60.  *
  61.  * Results:
  62.  * A standard Tcl result.
  63.  *
  64.  * Side effects:
  65.  * Defines new commands.
  66.  *
  67.  *----------------------------------------------------------------------
  68.  */
  69. int
  70. TclplatformtestInit(interp)
  71.     Tcl_Interp *interp; /* Interpreter to add commands to. */
  72. {
  73.     /*
  74.      * Add commands for platform specific tests for Windows here.
  75.      */
  76.     Tcl_CreateCommand(interp, "testchmod", TestchmodCmd,
  77.       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  78.     Tcl_CreateCommand(interp, "testeventloop", TesteventloopCmd,
  79.       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  80.     Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
  81.  (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  82.     Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd,
  83.  (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  84.     Tcl_CreateObjCommand(interp, "testwincpuid", TestwincpuidCmd,
  85.  (ClientData) 0, (Tcl_CmdDeleteProc*) NULL );
  86.     Tcl_CreateObjCommand(interp, "testwinsleep", TestwinsleepCmd,
  87.  (ClientData) 0, (Tcl_CmdDeleteProc *) NULL );
  88.     Tcl_CreateObjCommand(interp, "testexcept", TestExceptionCmd,
  89.  (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  90.     return TCL_OK;
  91. }
  92. /*
  93.  *----------------------------------------------------------------------
  94.  *
  95.  * TesteventloopCmd --
  96.  *
  97.  * This procedure implements the "testeventloop" command. It is
  98.  * used to test the Tcl notifier from an "external" event loop
  99.  * (i.e. not Tcl_DoOneEvent()).
  100.  *
  101.  * Results:
  102.  * A standard Tcl result.
  103.  *
  104.  * Side effects:
  105.  * None.
  106.  *
  107.  *----------------------------------------------------------------------
  108.  */
  109. static int
  110. TesteventloopCmd(clientData, interp, argc, argv)
  111.     ClientData clientData; /* Not used. */
  112.     Tcl_Interp *interp; /* Current interpreter. */
  113.     int argc; /* Number of arguments. */
  114.     CONST84 char **argv; /* Argument strings. */
  115. {
  116.     static int *framePtr = NULL; /* Pointer to integer on stack frame of
  117.   * innermost invocation of the "wait"
  118.   * subcommand. */
  119.    if (argc < 2) {
  120. Tcl_AppendResult(interp, "wrong # arguments: should be "", argv[0],
  121.                 " option ... "", (char *) NULL);
  122.         return TCL_ERROR;
  123.     }
  124.     if (strcmp(argv[1], "done") == 0) {
  125. *framePtr = 1;
  126.     } else if (strcmp(argv[1], "wait") == 0) {
  127. int *oldFramePtr;
  128. int done;
  129. MSG msg;
  130. int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  131. /*
  132.  * Save the old stack frame pointer and set up the current frame.
  133.  */
  134. oldFramePtr = framePtr;
  135. framePtr = &done;
  136. /*
  137.  * Enter a standard Windows event loop until the flag changes.
  138.  * Note that we do not explicitly call Tcl_ServiceEvent().
  139.  */
  140. done = 0;
  141. while (!done) {
  142.     if (!GetMessage(&msg, NULL, 0, 0)) {
  143. /*
  144.  * The application is exiting, so repost the quit message
  145.  * and start unwinding.
  146.  */
  147. PostQuitMessage((int)msg.wParam);
  148. break;
  149.     }
  150.     TranslateMessage(&msg);
  151.     DispatchMessage(&msg);
  152. }
  153. (void) Tcl_SetServiceMode(oldMode);
  154. framePtr = oldFramePtr;
  155.     } else {
  156. Tcl_AppendResult(interp, "bad option "", argv[1],
  157. "": must be done or wait", (char *) NULL);
  158. return TCL_ERROR;
  159.     }
  160.     return TCL_OK;
  161. }
  162. /*
  163.  *----------------------------------------------------------------------
  164.  *
  165.  * Testvolumetype --
  166.  *
  167.  * This procedure implements the "testvolumetype" command. It is
  168.  * used to check the volume type (FAT, NTFS) of a volume.
  169.  *
  170.  * Results:
  171.  * A standard Tcl result.
  172.  *
  173.  * Side effects:
  174.  * None.
  175.  *
  176.  *----------------------------------------------------------------------
  177.  */
  178. static int
  179. TestvolumetypeCmd(clientData, interp, objc, objv)
  180.     ClientData clientData; /* Not used. */
  181.     Tcl_Interp *interp; /* Current interpreter. */
  182.     int objc; /* Number of arguments. */
  183.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  184. {
  185. #define VOL_BUF_SIZE 32
  186.     int found;
  187.     char volType[VOL_BUF_SIZE];
  188.     char *path;
  189.     if (objc > 2) {
  190. Tcl_WrongNumArgs(interp, 1, objv, "?name?");
  191.         return TCL_ERROR;
  192.     }
  193.     if (objc == 2) {
  194. /*
  195.  * path has to be really a proper volume, but we don't
  196.  * get query APIs for that until NT5
  197.  */
  198. path = Tcl_GetString(objv[1]);
  199.     } else {
  200. path = NULL;
  201.     }
  202.     found = GetVolumeInformationA(path, NULL, 0, NULL, NULL, 
  203.     NULL, volType, VOL_BUF_SIZE);
  204.     if (found == 0) {
  205. Tcl_AppendResult(interp, "could not get volume type for "",
  206. (path?path:""), """, (char *) NULL);
  207. TclWinConvertError(GetLastError());
  208. return TCL_ERROR;
  209.     }
  210.     Tcl_SetResult(interp, volType, TCL_VOLATILE);
  211.     return TCL_OK;
  212. #undef VOL_BUF_SIZE
  213. }
  214. /*
  215.  *----------------------------------------------------------------------
  216.  *
  217.  * TestwinclockCmd --
  218.  *
  219.  * Command that returns the seconds and microseconds portions of
  220.  * the system clock and of the Tcl clock so that they can be
  221.  * compared to validate that the Tcl clock is staying in sync.
  222.  *
  223.  * Usage:
  224.  * testclock
  225.  *
  226.  * Parameters:
  227.  * None.
  228.  *
  229.  * Results:
  230.  * Returns a standard Tcl result comprising a four-element list:
  231.  * the seconds and microseconds portions of the system clock,
  232.  * and the seconds and microseconds portions of the Tcl clock.
  233.  *
  234.  * Side effects:
  235.  * None.
  236.  *
  237.  *----------------------------------------------------------------------
  238.  */
  239. static int
  240. TestwinclockCmd( ClientData dummy,
  241. /* Unused */
  242.  Tcl_Interp* interp,
  243. /* Tcl interpreter */
  244.  int objc,
  245. /* Argument count */
  246.  Tcl_Obj *CONST objv[] )
  247. /* Argument vector */
  248. {
  249.     CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
  250. /* The Posix epoch, expressed as a
  251.  * Windows FILETIME */
  252.     Tcl_Time tclTime; /* Tcl clock */
  253.     FILETIME sysTime; /* System clock */
  254.     Tcl_Obj* result; /* Result of the command */
  255.     LARGE_INTEGER t1, t2;
  256.     LARGE_INTEGER p1, p2;
  257.     if ( objc != 1 ) {
  258. Tcl_WrongNumArgs( interp, 1, objv, "" );
  259. return TCL_ERROR;
  260.     }
  261.     QueryPerformanceCounter( &p1 );
  262.     Tcl_GetTime( &tclTime );
  263.     GetSystemTimeAsFileTime( &sysTime );
  264.     t1.LowPart = posixEpoch.dwLowDateTime;
  265.     t1.HighPart = posixEpoch.dwHighDateTime;
  266.     t2.LowPart = sysTime.dwLowDateTime;
  267.     t2.HighPart = sysTime.dwHighDateTime;
  268.     t2.QuadPart -= t1.QuadPart;
  269.     QueryPerformanceCounter( &p2 );
  270.     result = Tcl_NewObj();
  271.     Tcl_ListObjAppendElement
  272. ( interp, result, Tcl_NewIntObj( (int) (t2.QuadPart / 10000000 ) ) );
  273.     Tcl_ListObjAppendElement
  274. ( interp, result,
  275.   Tcl_NewIntObj( (int) ( (t2.QuadPart / 10 ) % 1000000 ) ) );
  276.     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.sec ) );
  277.     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.usec ) );
  278.     Tcl_ListObjAppendElement( interp, result, Tcl_NewWideIntObj( p1.QuadPart ) );
  279.     Tcl_ListObjAppendElement( interp, result, Tcl_NewWideIntObj( p2.QuadPart ) );
  280.     Tcl_SetObjResult( interp, result );
  281.     return TCL_OK;
  282. }
  283. /*
  284.  *----------------------------------------------------------------------
  285.  *
  286.  * TestwincpuidCmd --
  287.  *
  288.  * Retrieves CPU ID information.
  289.  *
  290.  * Usage:
  291.  * testwincpuid <eax>
  292.  *
  293.  * Parameters:
  294.  * eax - The value to pass in the EAX register to a CPUID instruction.
  295.  *
  296.  * Results:
  297.  * Returns a four-element list containing the values from the
  298.  * EAX, EBX, ECX and EDX registers returned from the CPUID instruction.
  299.  *
  300.  * Side effects:
  301.  * None.
  302.  *
  303.  *----------------------------------------------------------------------
  304.  */
  305. static int
  306. TestwincpuidCmd( ClientData dummy,
  307.  Tcl_Interp* interp, /* Tcl interpreter */
  308.  int objc, /* Parameter count */
  309.  Tcl_Obj *CONST * objv ) /* Parameter vector */
  310. {
  311.     int status;
  312.     int index;
  313.     unsigned int regs[4];
  314.     Tcl_Obj * regsObjs[4];
  315.     int i;
  316.     if ( objc != 2 ) {
  317. Tcl_WrongNumArgs( interp, 1, objv, "eax" );
  318. return TCL_ERROR;
  319.     }
  320.     if ( Tcl_GetIntFromObj( interp, objv[1], &index ) != TCL_OK ) {
  321. return TCL_ERROR;
  322.     }
  323.     status = TclWinCPUID( (unsigned int) index, regs );
  324.     if ( status != TCL_OK ) {
  325. Tcl_SetObjResult( interp, Tcl_NewStringObj( "operation not available", 
  326.     -1 ) );
  327. return status;
  328.     }
  329.     for ( i = 0; i < 4; ++i ) {
  330. regsObjs[i] = Tcl_NewIntObj( (int) regs[i] );
  331.     }
  332.     Tcl_SetObjResult( interp, Tcl_NewListObj( 4, regsObjs ) );
  333.     return TCL_OK;
  334.        
  335. }
  336. /*
  337.  *----------------------------------------------------------------------
  338.  *
  339.  * TestwinsleepCmd --
  340.  *
  341.  * Causes this process to wait for the given number of milliseconds
  342.  * by means of a direct call to Sleep.
  343.  *
  344.  * Usage:
  345.  * testwinsleep <n>
  346.  *
  347.  * Parameters:
  348.  * n - the number of milliseconds to sleep
  349.  *
  350.  * Results:
  351.  * None.
  352.  *
  353.  * Side effects:
  354.  * Sleeps for the requisite number of milliseconds.
  355.  *
  356.  *----------------------------------------------------------------------
  357.  */
  358. static int
  359. TestwinsleepCmd( ClientData clientData,
  360. /* Unused */
  361.  Tcl_Interp* interp,
  362. /* Tcl interpreter */
  363.  int objc,
  364. /* Parameter count */
  365.  Tcl_Obj * CONST * objv )
  366. /* Parameter vector */
  367. {
  368.     int ms;
  369.     if ( objc != 2 ) {
  370. Tcl_WrongNumArgs( interp, 1, objv, "ms" );
  371. return TCL_ERROR;
  372.     }
  373.     if ( Tcl_GetIntFromObj( interp, objv[1], &ms ) != TCL_OK ) {
  374. return TCL_ERROR;
  375.     }
  376.     Sleep( (DWORD) ms );
  377.     return TCL_OK;
  378. }
  379. /*
  380.  *----------------------------------------------------------------------
  381.  *
  382.  * TestExceptionCmd --
  383.  *
  384.  * Causes this process to end with the named exception. Used for
  385.  * testing Tcl_WaitPid().
  386.  *
  387.  * Usage:
  388.  * testexcept <type>
  389.  *
  390.  * Parameters:
  391.  * Type of exception.
  392.  *
  393.  * Results:
  394.  * None, this process closes now and doesn't return.
  395.  *
  396.  * Side effects:
  397.  * This Tcl process closes, hard... Bang!
  398.  *
  399.  *----------------------------------------------------------------------
  400.  */
  401. static int
  402. TestExceptionCmd(
  403.     ClientData dummy, /* Unused */
  404.     Tcl_Interp* interp, /* Tcl interpreter */
  405.     int objc, /* Argument count */
  406.     Tcl_Obj *CONST objv[]) /* Argument vector */
  407. {
  408.     static char *cmds[] = {
  409.     "access_violation",
  410.     "datatype_misalignment",
  411.     "array_bounds",
  412.     "float_denormal",
  413.     "float_divbyzero",
  414.     "float_inexact",
  415.     "float_invalidop",
  416.     "float_overflow",
  417.     "float_stack",
  418.     "float_underflow",
  419.     "int_divbyzero",
  420.     "int_overflow",
  421.     "private_instruction",
  422.     "inpageerror",
  423.     "illegal_instruction",
  424.     "noncontinue",
  425.     "stack_overflow",
  426.     "invalid_disp",
  427.     "guard_page",
  428.     "invalid_handle",
  429.     "ctrl+c",
  430.     NULL
  431.     };
  432.     static DWORD exceptions[] = {
  433.     EXCEPTION_ACCESS_VIOLATION,
  434.     EXCEPTION_DATATYPE_MISALIGNMENT,
  435.     EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
  436.     EXCEPTION_FLT_DENORMAL_OPERAND,
  437.     EXCEPTION_FLT_DIVIDE_BY_ZERO,
  438.     EXCEPTION_FLT_INEXACT_RESULT,
  439.     EXCEPTION_FLT_INVALID_OPERATION,
  440.     EXCEPTION_FLT_OVERFLOW,
  441.     EXCEPTION_FLT_STACK_CHECK,
  442.     EXCEPTION_FLT_UNDERFLOW,
  443.     EXCEPTION_INT_DIVIDE_BY_ZERO,
  444.     EXCEPTION_INT_OVERFLOW,
  445.     EXCEPTION_PRIV_INSTRUCTION,
  446.     EXCEPTION_IN_PAGE_ERROR,
  447.     EXCEPTION_ILLEGAL_INSTRUCTION,
  448.     EXCEPTION_NONCONTINUABLE_EXCEPTION,
  449.     EXCEPTION_STACK_OVERFLOW,
  450.     EXCEPTION_INVALID_DISPOSITION,
  451.     EXCEPTION_GUARD_PAGE,
  452.     EXCEPTION_INVALID_HANDLE,
  453.     CONTROL_C_EXIT
  454.     };
  455.     int cmd;
  456.     if ( objc != 2 ) {
  457. Tcl_WrongNumArgs(interp, 0, objv, "<type-of-exception>");
  458. return TCL_ERROR;
  459.     }
  460.     if (Tcl_GetIndexFromObj(interp, objv[1], cmds, "command", 0,
  461.     &cmd) != TCL_OK) {
  462. return TCL_ERROR;
  463.     }
  464.     /*
  465.      * Make sure the GPF dialog doesn't popup.
  466.      */
  467.     SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  468.     /*
  469.      * As Tcl does not handle structured exceptions, this falls all the way
  470.      * back up the instruction stack to the C run-time portion that called
  471.      * main() where the process will now be terminated with this exception
  472.      * code by the default handler the C run-time provides.
  473.      */
  474.     /* SMASH! */
  475.     RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL);
  476.     /* NOTREACHED */
  477.     return TCL_OK;
  478. }
  479. static int 
  480. TestplatformChmod(CONST char *nativePath, int pmode)
  481. {
  482.     SID_IDENTIFIER_AUTHORITY userSidAuthority =
  483.     { SECURITY_WORLD_SID_AUTHORITY };
  484.     typedef DWORD (WINAPI *getSidLengthRequiredDef) ( UCHAR );
  485.     typedef BOOL (WINAPI *initializeSidDef) ( PSID,
  486.     PSID_IDENTIFIER_AUTHORITY, BYTE );
  487.     typedef PDWORD (WINAPI *getSidSubAuthorityDef) ( PSID, DWORD );
  488.     static getSidLengthRequiredDef getSidLengthRequiredProc;
  489.     static initializeSidDef initializeSidProc;
  490.     static getSidSubAuthorityDef getSidSubAuthorityProc;
  491.     static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION 
  492.       | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  493.     static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE 
  494.       | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA |  FILE_APPEND_DATA 
  495.       | FILE_WRITE_DATA | DELETE;
  496.     BYTE *secDesc = 0;
  497.     DWORD secDescLen;
  498.     const BOOL set_readOnly = !(pmode & 0222);
  499.     BOOL acl_readOnly_found = FALSE;
  500.     ACL_SIZE_INFORMATION ACLSize;
  501.     BOOL curAclPresent, curAclDefaulted;
  502.     PACL curAcl; 
  503.     PACL newAcl = 0;
  504.     DWORD newAclSize;
  505.     WORD j;
  506.   
  507.     SID *userSid = 0;
  508.     TCHAR *userDomain = NULL;
  509.     DWORD attr;
  510.     int res = 0;
  511.     /*
  512.      * One time initialization, dynamically load Windows NT features
  513.      */
  514.     typedef DWORD (WINAPI *setNamedSecurityInfoADef)( IN LPSTR,
  515.       IN SE_OBJECT_TYPE, IN SECURITY_INFORMATION, IN PSID, IN PSID,
  516.       IN PACL, IN PACL );
  517.     typedef BOOL (WINAPI *getAceDef) (PACL, DWORD, LPVOID *);
  518.     typedef BOOL (WINAPI *addAceDef) ( PACL, DWORD, DWORD, LPVOID, DWORD );
  519.     typedef BOOL (WINAPI *equalSidDef) ( PSID, PSID );
  520.     typedef BOOL (WINAPI *addAccessDeniedAceDef) ( PACL, DWORD, DWORD, PSID );
  521.     typedef BOOL (WINAPI *initializeAclDef) ( PACL, DWORD, DWORD );
  522.     typedef DWORD (WINAPI *getLengthSidDef) ( PSID );
  523.     typedef BOOL (WINAPI *getAclInformationDef) (PACL, LPVOID, DWORD, 
  524.       ACL_INFORMATION_CLASS );
  525.     typedef BOOL (WINAPI *getSecurityDescriptorDaclDef) (PSECURITY_DESCRIPTOR,
  526.       LPBOOL, PACL *, LPBOOL );
  527.     typedef BOOL (WINAPI *lookupAccountNameADef) ( LPCSTR, LPCSTR, PSID, 
  528.       PDWORD, LPSTR, LPDWORD, PSID_NAME_USE );
  529.     typedef BOOL (WINAPI *getFileSecurityADef) ( LPCSTR, SECURITY_INFORMATION,
  530.       PSECURITY_DESCRIPTOR, DWORD, LPDWORD );
  531.     static setNamedSecurityInfoADef setNamedSecurityInfoProc;
  532.     static getAceDef getAceProc;
  533.     static addAceDef addAceProc;
  534.     static equalSidDef equalSidProc;
  535.     static addAccessDeniedAceDef addAccessDeniedAceProc;
  536.     static initializeAclDef initializeAclProc;
  537.     static getLengthSidDef getLengthSidProc;
  538.     static getAclInformationDef getAclInformationProc;
  539.     static getSecurityDescriptorDaclDef getSecurityDescriptorDaclProc;
  540.     static lookupAccountNameADef lookupAccountNameProc; 
  541.     static getFileSecurityADef getFileSecurityProc;
  542.     static int initialized = 0;
  543.     if (!initialized) {
  544. TCL_DECLARE_MUTEX(initializeMutex)
  545. Tcl_MutexLock(&initializeMutex);
  546. if (!initialized) {
  547.     HINSTANCE hInstance = LoadLibrary("Advapi32");
  548.     if (hInstance != NULL) {
  549. setNamedSecurityInfoProc = (setNamedSecurityInfoADef)
  550.   GetProcAddress(hInstance, "SetNamedSecurityInfoA");
  551. getFileSecurityProc = (getFileSecurityADef)
  552.   GetProcAddress(hInstance, "GetFileSecurityA");
  553. getAceProc = (getAceDef)
  554.   GetProcAddress(hInstance, "GetAce");
  555. addAceProc = (addAceDef)
  556.   GetProcAddress(hInstance, "AddAce");
  557. equalSidProc = (equalSidDef)
  558.   GetProcAddress(hInstance, "EqualSid");
  559. addAccessDeniedAceProc = (addAccessDeniedAceDef)
  560.   GetProcAddress(hInstance, "AddAccessDeniedAce");
  561. initializeAclProc = (initializeAclDef)
  562.   GetProcAddress(hInstance, "InitializeAcl");
  563. getLengthSidProc = (getLengthSidDef)
  564.   GetProcAddress(hInstance, "GetLengthSid");
  565. getAclInformationProc = (getAclInformationDef)
  566.   GetProcAddress(hInstance, "GetAclInformation");
  567. getSecurityDescriptorDaclProc = (getSecurityDescriptorDaclDef)
  568.   GetProcAddress(hInstance, "GetSecurityDescriptorDacl");
  569. lookupAccountNameProc = (lookupAccountNameADef)
  570.   GetProcAddress(hInstance, "LookupAccountNameA");
  571. getSidLengthRequiredProc = (getSidLengthRequiredDef)
  572.   GetProcAddress(hInstance, "GetSidLengthRequired");
  573. initializeSidProc = (initializeSidDef)
  574.   GetProcAddress(hInstance, "InitializeSid");
  575. getSidSubAuthorityProc = (getSidSubAuthorityDef)
  576.   GetProcAddress(hInstance, "GetSidSubAuthority");
  577. if (setNamedSecurityInfoProc && getAceProc
  578.   && addAceProc && equalSidProc && addAccessDeniedAceProc
  579.   && initializeAclProc && getLengthSidProc
  580.   && getAclInformationProc && getSecurityDescriptorDaclProc
  581.   && lookupAccountNameProc && getFileSecurityProc
  582.   && getSidLengthRequiredProc && initializeSidProc
  583.   && getSidSubAuthorityProc)
  584.     initialized = 1;
  585.     }
  586.     if (!initialized)
  587. initialized = -1;
  588. }
  589. Tcl_MutexUnlock(&initializeMutex);
  590.     }
  591.     /* Process the chmod request */
  592.     attr = GetFileAttributes(nativePath);
  593.     /* nativePath not found */
  594.     if (attr == 0xffffffff) {
  595. res = -1;
  596. goto done;
  597.     }
  598.     /* If no ACL API is present or nativePath is not a directory, 
  599.      * there is no special handling 
  600.      */
  601.     if (initialized < 0 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  602. goto done;
  603.     }
  604.     
  605.     /* Set the result to error, if the ACL change is successful it will 
  606.      *  be reset to 0 
  607.      */
  608.     res = -1;
  609.     /*
  610.      * Read the security descriptor for the directory. Note the
  611.      * first call obtains the size of the security descriptor.
  612.      */
  613.     if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) {
  614. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  615.     DWORD secDescLen2 = 0;
  616.     secDesc = (BYTE *) ckalloc(secDescLen);
  617.     if (!getFileSecurityProc(nativePath, infoBits,
  618.      (PSECURITY_DESCRIPTOR)secDesc, 
  619.      secDescLen, &secDescLen2) 
  620. || (secDescLen < secDescLen2)) {
  621. goto done;
  622.     }
  623. } else {
  624.     goto done;
  625. }
  626.     }
  627.     /* Get the World SID */
  628.     userSid = (SID*) ckalloc(getSidLengthRequiredProc((UCHAR)1));
  629.     initializeSidProc( userSid, &userSidAuthority, (BYTE)1);
  630.     *(getSidSubAuthorityProc( userSid, 0)) = SECURITY_WORLD_RID;
  631.     /* If curAclPresent == false then curAcl and curAclDefaulted not valid */
  632.     if (!getSecurityDescriptorDaclProc(secDesc, &curAclPresent, 
  633.        &curAcl, &curAclDefaulted))
  634. goto done;
  635.     if (!curAclPresent || !curAcl) {
  636. ACLSize.AclBytesInUse = 0;
  637. ACLSize.AceCount = 0;
  638.     } else if (!getAclInformationProc(curAcl, &ACLSize, sizeof(ACLSize), 
  639.       AclSizeInformation))
  640. goto done;
  641.     /* Allocate memory for the new ACL */
  642.     newAclSize = ACLSize.AclBytesInUse + sizeof (ACCESS_DENIED_ACE) 
  643.       + getLengthSidProc(userSid) - sizeof (DWORD);
  644.     newAcl = (ACL *) ckalloc (newAclSize);
  645.   
  646.     /* Initialize the new ACL */
  647.     if(!initializeAclProc(newAcl, newAclSize, ACL_REVISION)) {
  648. goto done;
  649.     }
  650.     
  651.     /* Add denied to make readonly, this will be known as a "read-only tag" */
  652.     if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION, 
  653.       readOnlyMask, userSid)) {
  654. goto done;
  655.     }
  656.       
  657.     acl_readOnly_found = FALSE;
  658.     for (j = 0; j < ACLSize.AceCount; j++) {
  659. PACL *pACE2;
  660. ACE_HEADER *phACE2;
  661. if (! getAceProc (curAcl, j, (LPVOID*) &pACE2)) {
  662.     goto done;
  663. }
  664. phACE2 = ((ACE_HEADER *) pACE2);
  665. /* Do NOT propagate inherited ACEs */
  666. if (phACE2->AceFlags & INHERITED_ACE) {
  667.     continue;
  668. }
  669. /* Skip the "read-only tag" restriction (either added above, or it
  670.  * is being removed) 
  671.  */
  672. if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) {
  673.     ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *)phACE2;
  674.     if (pACEd->Mask == readOnlyMask && equalSidProc(userSid, 
  675.       (PSID)&(pACEd->SidStart))) {
  676. acl_readOnly_found = TRUE;
  677. continue;
  678.     }
  679. }
  680. /* Copy the current ACE from the old to the new ACL */
  681. if(! addAceProc (newAcl, ACL_REVISION, MAXDWORD, pACE2, 
  682.   ((PACE_HEADER) pACE2)->AceSize)) {
  683.     goto done;
  684. }
  685.     }
  686.     /* Apply the new ACL */
  687.     if (set_readOnly == acl_readOnly_found
  688. || setNamedSecurityInfoProc((LPSTR)nativePath, SE_FILE_OBJECT, 
  689.      DACL_SECURITY_INFORMATION, NULL, NULL, newAcl, NULL)
  690.    == ERROR_SUCCESS ) {
  691. res = 0;
  692.     }
  693.  done:
  694.     if (secDesc) ckfree(secDesc);
  695.     if (newAcl) ckfree((char *)newAcl);
  696.     if (userSid) ckfree((char *)userSid);
  697.     if (userDomain) ckfree(userDomain);
  698.     if (res != 0)
  699. return res;
  700.     
  701.     /* Run normal chmod command */
  702.     return chmod(nativePath, pmode);
  703. }
  704. /*
  705.  *---------------------------------------------------------------------------
  706.  *
  707.  * TestchmodCmd --
  708.  *
  709.  * Implements the "testchmod" cmd.  Used when testing "file" command.
  710.  * The only attribute used by the Windows platform is the user write
  711.  * flag; if this is not set, the file is made read-only.  Otehrwise, the
  712.  * file is made read-write.
  713.  *
  714.  * Results:
  715.  * A standard Tcl result.
  716.  *
  717.  * Side effects:
  718.  * Changes permissions of specified files.
  719.  *
  720.  *---------------------------------------------------------------------------
  721.  */
  722. static int
  723. TestchmodCmd(dummy, interp, argc, argv)
  724.     ClientData dummy; /* Not used. */
  725.     Tcl_Interp *interp; /* Current interpreter. */
  726.     int argc; /* Number of arguments. */
  727.     CONST84 char **argv; /* Argument strings. */
  728. {
  729.     int i, mode;
  730.     char *rest;
  731.     if (argc < 2) {
  732. usage:
  733. Tcl_AppendResult(interp, "wrong # args: should be "", argv[0],
  734. " mode file ?file ...?", NULL);
  735. return TCL_ERROR;
  736.     }
  737.     mode = (int) strtol(argv[1], &rest, 8);
  738.     if ((rest == argv[1]) || (*rest != '')) {
  739. goto usage;
  740.     }
  741.     for (i = 2; i < argc; i++) {
  742. Tcl_DString buffer;
  743. CONST char *translated;
  744. translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
  745. if (translated == NULL) {
  746.     return TCL_ERROR;
  747. }
  748. if (TestplatformChmod(translated, mode) != 0) {
  749.     Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
  750.     NULL);
  751.     return TCL_ERROR;
  752. }
  753. Tcl_DStringFree(&buffer);
  754.     }
  755.     return TCL_OK;
  756. }