Attachment "generic-testTcl.c.diff-u" to
ticket [1344540fff]
added by
jfg118
2006-03-14 06:57:39.
--- ../../tcl8.4.12-src/tcl8.4.12/generic/tclTest.c 2005-10-23 16:01:30.000000000 -0700
+++ generic/tclTest.c 2006-03-13 09:45:39.481224000 -0800
@@ -4018,6 +4018,255 @@
*---------------------------------------------------------------------------
*/
+#ifdef __WIN32__
+#include <aclapi.h>
+#endif
+
+static int Testplaftorm_chmod(const char *nativePath, int pmode)
+{
+#ifdef __WIN32__
+ static const char everyoneBuf[] = "EVERYONE";
+ static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+ static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE
+ | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA
+ | FILE_WRITE_DATA | DELETE;
+
+ BYTE *secDesc = 0;
+ DWORD secDescLen;
+
+ const BOOL set_readOnly = !(pmode & 0222);
+ BOOL acl_readOnly_found = FALSE;
+
+ ACL_SIZE_INFORMATION ACLSize;
+ BOOL curAclPresent, curAclDefaulted;
+ PACL curAcl;
+ PACL newAcl = 0;
+ DWORD newAclSize;
+
+ WORD j;
+
+ DWORD userSidLen = 4096;
+ SID *userSid = 0;
+ DWORD userDomainLen = 32;
+ TCHAR *userDomain = 0;
+ SID_NAME_USE userSidUse;
+
+ DWORD attr;
+
+ int res = 0;
+
+ /*
+ * One time initialization, dynamically load Windows NT features
+ */
+ typedef DWORD (WINAPI *setNamedSecurityInfoADef)( IN LPSTR,
+ IN SE_OBJECT_TYPE, IN SECURITY_INFORMATION, IN PSID, IN PSID,
+ IN PACL, IN PACL );
+ typedef BOOL (WINAPI *getAceDef) (PACL, DWORD, LPVOID *);
+ typedef BOOL (WINAPI *addAceDef) ( PACL, DWORD, DWORD, LPVOID, DWORD );
+ typedef BOOL (WINAPI *equalSidDef) ( PSID, PSID );
+ typedef BOOL (WINAPI *addAccessDeniedAceDef) ( PACL, DWORD, DWORD, PSID );
+ typedef BOOL (WINAPI *initializeAclDef) ( PACL, DWORD, DWORD );
+ typedef DWORD (WINAPI *getLengthSidDef) ( PSID );
+ typedef BOOL (WINAPI *getAclInformationDef) (PACL, LPVOID, DWORD,
+ ACL_INFORMATION_CLASS );
+ typedef BOOL (WINAPI *getSecurityDescriptorDaclDef) (PSECURITY_DESCRIPTOR,
+ LPBOOL, PACL *, LPBOOL );
+ typedef BOOL (WINAPI *lookupAccountNameADef) ( LPCSTR, LPCSTR, PSID,
+ PDWORD, LPSTR, LPDWORD, PSID_NAME_USE );
+ typedef BOOL (WINAPI *getFileSecurityADef) ( LPCSTR, SECURITY_INFORMATION,
+ PSECURITY_DESCRIPTOR, DWORD, LPDWORD );
+
+ static setNamedSecurityInfoADef setNamedSecurityInfoProc;
+ static getAceDef getAceProc;
+ static addAceDef addAceProc;
+ static equalSidDef equalSidProc;
+ static addAccessDeniedAceDef addAccessDeniedAceProc;
+ static initializeAclDef initializeAclProc;
+ static getLengthSidDef getLengthSidProc;
+ static getAclInformationDef getAclInformationProc;
+ static getSecurityDescriptorDaclDef getSecurityDescriptorDaclProc;
+ static lookupAccountNameADef lookupAccountNameProc;
+ static getFileSecurityADef getFileSecurityProc;
+
+ static int initialized = 0;
+ if (!initialized) {
+ TCL_DECLARE_MUTEX(initialzeMutex)
+ Tcl_MutexLock(&initializeMutex);
+ if (!initialized) {
+ HINSTANCE hInstance = LoadLibrary("Advapi32");
+ if (hInstance != NULL) {
+ setNamedSecurityInfoProc = (setNamedSecurityInfoADef)
+ GetProcAddress(hInstance, "SetNamedSecurityInfoA");
+ getFileSecurityProc = (getFileSecurityADef)
+ GetProcAddress(hInstance, "GetFileSecurityA");
+ getAceProc = (getAceDef)
+ GetProcAddress(hInstance, "GetAce");
+ addAceProc = (addAceDef)
+ GetProcAddress(hInstance, "AddAce");
+ equalSidProc = (equalSidDef)
+ GetProcAddress(hInstance, "EqualSid");
+ addAccessDeniedAceProc = (addAccessDeniedAceDef)
+ GetProcAddress(hInstance, "AddAccessDeniedAce");
+ initializeAclProc = (initializeAclDef)
+ GetProcAddress(hInstance, "InitializeAcl");
+ getLengthSidProc = (getLengthSidDef)
+ GetProcAddress(hInstance, "GetLengthSid");
+ getAclInformationProc = (getAclInformationDef)
+ GetProcAddress(hInstance, "GetAclInformation");
+ getSecurityDescriptorDaclProc = (getSecurityDescriptorDaclDef)
+ GetProcAddress(hInstance, "GetSecurityDescriptorDacl");
+ lookupAccountNameProc = (lookupAccountNameADef)
+ GetProcAddress(hInstance, "LookupAccountNameA");
+ if (setNamedSecurityInfoProc && getAceProc
+ && addAceProc && equalSidProc && addAccessDeniedAceProc
+ && initializeAclProc && getLengthSidProc
+ && getAclInformationProc && getSecurityDescriptorDaclProc
+ && lookupAccountNameProc && getFileSecurityProc)
+ initialized = 1;
+ }
+ if (!initialized)
+ initialized = -1;
+ }
+ Tcl_MutexUnlock(&intializeMutex);
+ }
+
+ /* Process the chmod request */
+ attr = GetFileAttributes(nativePath);
+
+ /* nativePath not found */
+ if (attr == 0xffffffff) {
+ res = -1;
+ goto done;
+ }
+
+ /* If no ACL API is present or nativePath is not a directory,
+ * there is no special handling
+ */
+ if (initialized < 0 || !(attr & FILE_ATTRIBUTE_DIRECTORY))
+ goto done;
+
+ /* Set the result to error, if the ACL change is successful it will
+ * be reset to 0
+ */
+ res = -1;
+
+ /*
+ * Read the security descriptor for the directory. Note the
+ * first call obtains the size of the security descriptor.
+ */
+ if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ DWORD secDescLen2 = 0;
+ secDesc = (BYTE *) ckalloc(secDescLen);
+ if (!getFileSecurityProc(nativePath, infoBits, secDesc,
+ secDescLen, &secDescLen2)
+ || (secDescLen < secDescLen2)) {
+ goto done;
+ }
+ } else {
+ goto done;
+ }
+ }
+
+ /* Get the "Everyone" SID */
+ userSid = (SID *) ckalloc(userSidLen);
+ userDomain = (TCHAR *) ckalloc(userDomainLen);
+ if (!lookupAccountNameProc(NULL, everyoneBuf, userSid, &userSidLen,
+ userDomain, &userDomainLen, &userSidUse)) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ ckfree((char *)userSid);
+ userSid = (SID *) ckalloc(userSidLen);
+ ckfree(userDomain);
+ userDomain = (TCHAR *) ckalloc(userDomainLen);
+ if (!lookupAccountNameProc(NULL, everyoneBuf, userSid,
+ &userSidLen, userDomain, &userDomainLen, &userSidUse))
+ goto done;
+ } else
+ goto done;
+ }
+
+ /* If curAclPresent == false then curAcl and curAclDefaulted not valid */
+ if (!getSecurityDescriptorDaclProc(secDesc, &curAclPresent,
+ &curAcl, &curAclDefaulted))
+ goto done;
+
+ if (!curAclPresent || !curAcl) {
+ ACLSize.AclBytesInUse = 0;
+ ACLSize.AceCount = 0;
+ } else if (!getAclInformationProc(curAcl, &ACLSize, sizeof(ACLSize),
+ AclSizeInformation))
+ goto done;
+
+ /* Allocate memory for the new ACL */
+ newAclSize = ACLSize.AclBytesInUse + sizeof (ACCESS_DENIED_ACE)
+ + getLengthSidProc(userSid) - sizeof (DWORD);
+ newAcl = (ACL *) ckalloc (newAclSize);
+
+ /* Initialize the new ACL */
+ if(!initializeAclProc(newAcl, newAclSize, ACL_REVISION))
+ goto done;
+
+ /* Add denied to make readonly, this will be known as a "read-only tag" */
+ if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION,
+ readOnlyMask, userSid))
+ goto done;
+
+ acl_readOnly_found = FALSE;
+ for (j = 0; j < ACLSize.AceCount; j++) {
+ PACL *pACE2;
+ ACE_HEADER *phACE2;
+ if (! getAceProc (curAcl, j, (LPVOID*) &pACE2))
+ goto done;
+ phACE2 = ((ACE_HEADER *) pACE2);
+
+ /* Do NOT propagate inherited ACEs */
+ if (phACE2->AceFlags & INHERITED_ACE)
+ continue;
+
+ /* Skip the "read-only tag" restriction (either added above, or it
+ * is being removed)
+ */
+ if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) {
+ ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *)phACE2;
+ if (pACEd->Mask == readOnlyMask && equalSidProc(userSid,
+ (PSID)&(pACEd->SidStart))) {
+ acl_readOnly_found = TRUE;
+ continue;
+ }
+ }
+
+ /* Copy the current ACE from the old to the new ACL */
+ if(! addAceProc (newAcl, ACL_REVISION, MAXDWORD, pACE2,
+ ((PACE_HEADER) pACE2)->AceSize))
+ goto done;
+ }
+
+ /* Apply the new ACL */
+ if (set_readOnly == acl_readOnly_found
+ || setNamedSecurityInfoProc((LPSTR)nativePath, SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION, NULL, NULL, newAcl, NULL)
+ == ERROR_SUCCESS )
+ res = 0;
+
+ done:
+ if (secDesc)
+ ckfree(secDesc);
+ if (newAcl)
+ ckfree((char *)newAcl);
+ if (userSid)
+ ckfree((char *)userSid);
+ if (userDomain)
+ ckfree(userDomain);
+
+ if (res != 0)
+ return res;
+#endif
+
+ /* Run normal chmod command */
+ return chmod(nativePath, pmode);
+}
+
static int
TestchmodCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
@@ -4048,7 +4297,7 @@
if (translated == NULL) {
return TCL_ERROR;
}
- if (chmod(translated, (unsigned) mode) != 0) {
+ if (Testplaftorm_chmod(translated, (unsigned) mode) != 0) {
Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
(char *) NULL);
return TCL_ERROR;