/************************************************************************* * * allusrsm.c * * Move items from a user's start menu to the All Users start menu * * copyright notice: Copyright 1998 Micrsoft * * When entering install mode, if the start menu snapshot file already * exists, don't overwrite it. Otherwise, some shortcuts may not get moved * over. This fixes a problem where an App reboots the machine when it * finishes installing, without giving the user a chance to switch back to * execute mode. Now, when the user logs in again, the menu shortcuts will * be moved because winlogon always does a "change user /install" and then * "change user /execute". (That's to support RunOnce programs.) * MS 1057 * * *************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #include #include #include #include // This program takes a snapshot of the Current User's start menu and // saves it to a file. When run with the /c option, it compares the // snapshot to the present contents of the Current User's start menu. // Each new or changed file/directory is then moved to the All Users // start menu. Additionally, Read permission is granted to the Everyone // group for each moved file or directory. typedef struct File_Struct { struct File_Struct *Next; // Only used in Memory WCHAR FileName[MAX_PATH]; BOOL TimeValid; SYSTEMTIME Time; } FILENODE, *PFILENODE; typedef struct Path_Struct { DWORD FilesInDir; struct Path_Struct *Next; // Only used in Memory PFILENODE FileHead; // Only used in Memory PFILENODE FileTail; // Only used in Memory WCHAR PathStr[MAX_PATH]; } PATHNODE, *PPATHNODE; typedef struct Tree_Struct { DWORD NumPaths; PPATHNODE PathHead; PPATHNODE PathTail; } TREENODE, *PTREENODE; typedef struct RemoveDir_Struct { WCHAR PathStr[MAX_PATH]; struct RemoveDir_Struct *Next; } REMOVEDIRLIST, *PPREMOVEDIRLIST; int RunMode; WCHAR SaveName[MAX_PATH]; WCHAR CurUserDir[MAX_PATH]; WCHAR AllUserDir[MAX_PATH]; int CurUserDirLen; WCHAR StartMenu[MAX_PATH]=L""; void ReadTree(PTREENODE Tree, WCHAR *Dir); #define SD_SIZE (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH) //////////////////////////////////////////////////////////////////////////// BOOLEAN FileExists( WCHAR *path ) { return( GetFileAttributes(path) == -1 ? FALSE : TRUE ); } //////////////////////////////////////////////////////////////////////////// NTSTATUS CreateNewSecurityDescriptor( PSECURITY_DESCRIPTOR *ppNewSD, PSECURITY_DESCRIPTOR pSD, PACL pAcl ) /*++ Routine Description: From a SD and a Dacl, create a new SD. The new SD will be fully self contained (it is self relative) and does not have pointers to other structures. Arguments: ppNewSD - used to return the new SD. Caller should free with LocalFree pSD - the self relative SD we use to build the new SD pAcl - the new DACL that will be used for the new SD Return Value: NTSTATUS code --*/ { PACL pSacl; PSID psidGroup, psidOwner; BOOLEAN fSaclPres; BOOLEAN fSaclDef, fGroupDef, fOwnerDef; ULONG NewSDSize; SECURITY_DESCRIPTOR NewSD; PSECURITY_DESCRIPTOR pNewSD; NTSTATUS Status; // extract the originals from the security descriptor Status = RtlGetSaclSecurityDescriptor(pSD, &fSaclPres, &pSacl, &fSaclDef); if (!NT_SUCCESS(Status)) return(Status); Status = RtlGetOwnerSecurityDescriptor(pSD, &psidOwner, &fOwnerDef); if (!NT_SUCCESS(Status)) return(Status); Status = RtlGetGroupSecurityDescriptor(pSD, &psidGroup, &fGroupDef); if (!NT_SUCCESS(Status)) return(Status); // now create a new SD and set the info in it. we cannot return this one // since it has pointers to old SD. Status = RtlCreateSecurityDescriptor(&NewSD, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) return(Status); Status = RtlSetDaclSecurityDescriptor(&NewSD, TRUE, pAcl, FALSE); if (!NT_SUCCESS(Status)) return(Status); Status = RtlSetSaclSecurityDescriptor(&NewSD, fSaclPres, pSacl, fSaclDef); if (!NT_SUCCESS(Status)) return(Status); Status = RtlSetOwnerSecurityDescriptor(&NewSD, psidOwner, fOwnerDef); if (!NT_SUCCESS(Status)) return(Status); Status = RtlSetGroupSecurityDescriptor(&NewSD, psidGroup, fGroupDef); if (!NT_SUCCESS(Status)) return(Status); // calculate size needed for the returned SD and allocated it NewSDSize = RtlLengthSecurityDescriptor(&NewSD); pNewSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, NewSDSize); if (pNewSD == NULL) return(STATUS_INSUFFICIENT_RESOURCES); // convert the absolute to self relative Status = RtlAbsoluteToSelfRelativeSD(&NewSD, pNewSD, &NewSDSize); if (NT_SUCCESS(Status)) *ppNewSD = pNewSD; else LocalFree(pNewSD); return(Status); } // CreateNewSecurityDescriptor ///////////////////////////////////////////////////////////////////////// // Add Read and Execute permissions for built in "Everyone" Group to // the indicated file. BOOLEAN APIENTRY AddEveryoneRXPermissionW( LPCWSTR lpFileName) { NTSTATUS Status; BOOLEAN ExitVal = FALSE; HANDLE FileHandle=NULL; OBJECT_ATTRIBUTES Obja; UNICODE_STRING FileName; RTL_RELATIVE_NAME_U RelativeName; BOOLEAN TranslationStatus; IO_STATUS_BLOCK IoStatusBlock; PVOID FreeBuffer; PSECURITY_DESCRIPTOR pSD = NULL; PSECURITY_DESCRIPTOR pNewSD = NULL; DWORD LengthNeeded = 0; static PACCESS_ALLOWED_ACE pNewAce = NULL; static USHORT NewAceSize; ACL Acl; PACL pAcl, pNewAcl = NULL; BOOLEAN fDaclPresent, fDaclDef; USHORT NewAclSize; //////////////////////////////////////////////////////////////////////// // First time through this routine, create an ACE for the built-in // "Everyone" group. //////////////////////////////////////////////////////////////////////// if (pNewAce == NULL) { PSID psidEveryone = NULL; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; // Get the SID of the built-in Everyone group Status = RtlAllocateAndInitializeSid( &WorldSidAuthority, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &psidEveryone); if (!NT_SUCCESS(Status)) goto ErrorExit; // allocate and initialize new ACE NewAceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + RtlLengthSid(psidEveryone)); pNewAce = (PACCESS_ALLOWED_ACE) LocalAlloc(LMEM_FIXED, NewAceSize); if (pNewAce == NULL) goto ErrorExit; pNewAce->Header.AceFlags = (UCHAR) CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE ; pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; pNewAce->Header.AceSize = NewAceSize; pNewAce->Mask = FILE_GENERIC_READ | FILE_EXECUTE; RtlCopySid(RtlLengthSid(psidEveryone), (PSID)(&pNewAce->SidStart), psidEveryone); } //////////////////////////////////////////////////////////////////////// // Open the indicated file. //////////////////////////////////////////////////////////////////////// TranslationStatus = RtlDosPathNameToRelativeNtPathName_U( lpFileName, &FileName, NULL, &RelativeName ); if ( !TranslationStatus ) { goto ErrorExit; } FreeBuffer = FileName.Buffer; if ( RelativeName.RelativeName.Length ) FileName = RelativeName.RelativeName; else RelativeName.ContainingDirectory = NULL; InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE, RelativeName.ContainingDirectory, NULL ); Status = NtOpenFile( &FileHandle, READ_CONTROL | WRITE_DAC, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 ); RtlReleaseRelativeName(&RelativeName); RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer); if (!NT_SUCCESS(Status)) goto ErrorExit; //////////////////////////////////////////////////////////////////////// // Retrieve the security descriptor for the file and then get the // file's DACL from it. //////////////////////////////////////////////////////////////////////// pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, SD_SIZE); if (pSD == NULL) goto ErrorExit; Status = NtQuerySecurityObject( FileHandle, DACL_SECURITY_INFORMATION, pSD, SD_SIZE, &LengthNeeded ); if (!NT_SUCCESS(Status)) goto ErrorExit; // extract the originals from the security descriptor Status = RtlGetDaclSecurityDescriptor(pSD, &fDaclPresent, &pAcl, &fDaclDef); if (!NT_SUCCESS(Status)) goto ErrorExit; //////////////////////////////////////////////////////////////////////// // Create a new DACL by copying the existing DACL and appending the // "Everyone" ACE. //////////////////////////////////////////////////////////////////////// // if no DACL present, we create one if ((fDaclPresent == FALSE) || (pAcl == NULL)) { Status = RtlCreateAcl(&Acl, sizeof(Acl), ACL_REVISION) ; if (!NT_SUCCESS(Status)) goto ErrorExit; pAcl = &Acl; } // Copy the DACL into a larger buffer and add the new ACE to the end. NewAclSize = pAcl->AclSize + NewAceSize; pNewAcl = (PACL) LocalAlloc(LMEM_FIXED, NewAclSize); if (!pNewAcl) goto ErrorExit; RtlCopyMemory(pNewAcl, pAcl, pAcl->AclSize); pNewAcl->AclSize = NewAclSize; Status = RtlAddAce(pNewAcl, ACL_REVISION, pNewAcl->AceCount, pNewAce, NewAceSize); if (!NT_SUCCESS(Status)) goto ErrorExit; //////////////////////////////////////////////////////////////////////// // Create self-relative security descriptor with new DACL. Then // save the security descriptor back to the file. //////////////////////////////////////////////////////////////////////// Status = CreateNewSecurityDescriptor(&pNewSD, pSD, pNewAcl); if (!NT_SUCCESS(Status)) goto ErrorExit; Status = NtSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, pNewSD); if (!NT_SUCCESS(Status)) goto ErrorExit; ExitVal = TRUE; ErrorExit: if (FileHandle != NULL) NtClose(FileHandle); if (pNewAcl != NULL) LocalFree(pNewAcl); if (pNewSD != NULL) LocalFree(pNewSD); if (pSD != NULL) LocalFree(pSD); return(ExitVal); } //////////////////////////////////////////////////////////////////////////// #if 0 BOOLEAN APIENTRY AddEveryoneRXPermissionA( WCHAR * lpFileName) { PUNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; Unicode = &NtCurrentTeb()->StaticUnicodeString; RtlInitAnsiString(&AnsiString,lpFileName); Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE); if ( !NT_SUCCESS(Status) ) { ULONG dwErrorCode; dwErrorCode = RtlNtStatusToDosError( Status ); SetLastError( dwErrorCode ); return FALSE; } return ( AddEveryoneRXPermissionW((LPCWSTR)Unicode->Buffer) ); } #endif //////////////////////////////////////////////////////////////////////////// // return -1 for dates invalid, 0 for equal, 1 for f1 newer, 2 for f2 newer int CheckDates(PFILENODE FN1, PFILENODE FN2) { SYSTEMTIME f1s = FN1->Time; SYSTEMTIME f2s = FN2->Time; if (FN1->TimeValid == FALSE || FN2->TimeValid == FALSE) return -1; if (f1s.wYear > f2s.wYear) return 1; if (f1s.wYear < f2s.wYear) return 2; if (f1s.wMonth > f2s.wMonth) return 1; if (f1s.wMonth < f2s.wMonth) return 2; if (f1s.wDay > f2s.wDay) return 1; if (f1s.wDay < f2s.wDay) return 2; if (f1s.wHour > f2s.wHour) return 1; if (f1s.wHour < f2s.wHour) return 2; if (f1s.wMinute > f2s.wMinute) return 1; if (f1s.wMinute < f2s.wMinute) return 2; if (f1s.wSecond > f2s.wSecond) return 1; if (f1s.wSecond < f2s.wSecond) return 2; return 0; } //////////////////////////////////////////////////////////////////////////// PPATHNODE GetPathNode(PTREENODE Tree, WCHAR *Dir) { PPATHNODE p; // Handle Empty List if (Tree->PathTail == NULL) { p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE)); if (p == NULL) return NULL; Tree->PathHead = p; Tree->PathTail = p; Tree->NumPaths++; p->Next = NULL; p->FileHead = NULL; p->FileTail = NULL; p->FilesInDir = 0; wcscpy(p->PathStr,Dir); return p; } // Last Node Matches if (wcscmp(Tree->PathTail->PathStr,Dir) == 0) return Tree->PathTail; // Need to add a node p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE)); if (p == NULL) return NULL; Tree->PathTail->Next = p; Tree->PathTail = p; Tree->NumPaths++; p->Next = NULL; p->FileHead = NULL; p->FileTail = NULL; p->FilesInDir = 0; wcscpy(p->PathStr,Dir); return p; } //////////////////////////////////////////////////////////////////////////// void AddFileNode(PTREENODE Tree, WCHAR *Dir, PFILENODE FileNode) { PPATHNODE PathNode = GetPathNode(Tree, Dir); if (FileNode == NULL) return; if (PathNode == NULL) { LocalFree(FileNode); return; } // New node is always the last. FileNode->Next = NULL; // If list isn't empty, link to last node in list // Otherwise, set head pointer. if (PathNode->FileTail != NULL) PathNode->FileTail->Next = FileNode; else PathNode->FileHead = FileNode; // Put new node on end of list. PathNode->FileTail = FileNode; PathNode->FilesInDir++; } //////////////////////////////////////////////////////////////////////////// void ProcessFile(PTREENODE Tree, LPWIN32_FIND_DATA LocalData, WCHAR *LocalDir) { PFILENODE FileNode; // Don't handle directories if ((LocalData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) return; // Allocate a file node FileNode = (PFILENODE) LocalAlloc(0,sizeof(FILENODE)); if (FileNode == NULL) return; // Fill in the Local Fields wcscpy(FileNode->FileName, LocalData->cFileName); FileNode->TimeValid = FileTimeToSystemTime(&LocalData->ftLastWriteTime, &FileNode->Time); // Add to the list AddFileNode(Tree, LocalDir, FileNode); } //////////////////////////////////////////////////////////////////////////// void ProcessDir(PTREENODE Tree, LPWIN32_FIND_DATA FindData, WCHAR *Dir) { WCHAR NewDir[MAX_PATH]; PPATHNODE PathNode; // Only Handle Directories if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) return; // Don't recurse into these directories if (wcscmp(FindData->cFileName, L".") == 0) return; if (wcscmp(FindData->cFileName, L"..") == 0) return; wcscpy(NewDir,Dir); wcscat(NewDir,L"\\"); wcscat(NewDir,FindData->cFileName); // This creates a node for the directory. Nodes get automatically // created when adding files, but that doesn't handle empty // directories. This does. PathNode = GetPathNode(Tree, NewDir); ReadTree(Tree, NewDir); } //////////////////////////////////////////////////////////////////////////// // Creates an in-memory representation of the Current User's start menu. void ReadTree(PTREENODE Tree, WCHAR *Dir) { HANDLE FindHandle; WIN32_FIND_DATA FindData; int retval; // First compare all files in current directory. retval = SetCurrentDirectory(Dir); if (retval == 0) { // printf("Unable to find directory %s\n",Dir); return; } FindHandle = FindFirstFile(L"*.*", &FindData); if (FindHandle != INVALID_HANDLE_VALUE) { ProcessFile(Tree, &FindData, Dir); while (FindNextFile(FindHandle, &FindData) != FALSE) ProcessFile(Tree, &FindData, Dir); FindClose(FindHandle); } // Next, handle subdirectories. retval = SetCurrentDirectory(Dir); if (retval == 0) { // printf("Unable to find directory %s\n",Dir); return; } FindHandle = FindFirstFile(L"*.*", &FindData); if (FindHandle != INVALID_HANDLE_VALUE) { ProcessDir(Tree, &FindData, Dir); while (FindNextFile(FindHandle, &FindData) != FALSE) ProcessDir(Tree, &FindData, Dir); FindClose(FindHandle); } } //////////////////////////////////////////////////////////////////////////// int WriteTreeToDisk(PTREENODE Tree) { PPATHNODE PN; PFILENODE FN; HANDLE hFile; DWORD BytesWritten; DWORD i; hFile = CreateFile(SaveName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return(-1); // error // DbgPrint("Tree->NumPaths is %d\n",Tree->NumPaths); if (WriteFile(hFile,&Tree->NumPaths,sizeof(DWORD),&BytesWritten, NULL) == 0) { CloseHandle(hFile); return(-1); // error } for (PN = Tree->PathHead; PN != NULL; PN = PN->Next) { if (WriteFile(hFile,PN,sizeof(PATHNODE),&BytesWritten, NULL) == 0) { CloseHandle(hFile); return(-1); // error } // DbgPrint("\n%s (%d)\n",PN->PathStr, PN->FilesInDir); FN = PN->FileHead; for (i = 0; i < PN->FilesInDir; i++) { if (WriteFile(hFile,FN,sizeof(FILENODE),&BytesWritten, NULL) == 0) { CloseHandle(hFile); return(-1); // error } // DbgPrint(" %s \n", FN->FileName); FN = FN->Next; } } CloseHandle(hFile); return(0); } //////////////////////////////////////////////////////////////////////////// int ReadTreeFromDisk(PTREENODE Tree) { PATHNODE LocalPath; PPATHNODE PN; PFILENODE FN; HANDLE hFile; DWORD BytesRead; DWORD i,j; DWORD NumFiles, NumTrees; hFile = CreateFile(SaveName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return(-1); if (ReadFile(hFile,&NumTrees,sizeof(DWORD),&BytesRead, NULL) == 0) { CloseHandle(hFile); return(-1); // error } for (i = 0; i < NumTrees; i++) { if (ReadFile(hFile,&LocalPath,sizeof(PATHNODE),&BytesRead, NULL) == 0) { CloseHandle(hFile); return(-1); // error } PN = GetPathNode(Tree, LocalPath.PathStr); if (PN == NULL) { CloseHandle(hFile); return(-1); // error } NumFiles = LocalPath.FilesInDir; // DbgPrint("\n<<%s (%d)\n",PN->PathStr, NumFiles); for (j = 0; j < NumFiles; j++) { // Allocate a file node FN = (PFILENODE) LocalAlloc(0,sizeof(FILENODE)); if (FN == NULL) { CloseHandle(hFile); return(-1); // error } if (ReadFile(hFile,FN,sizeof(FILENODE),&BytesRead, NULL) == 0) { CloseHandle(hFile); LocalFree(FN); return(-1); // error } AddFileNode(Tree, PN->PathStr, FN); // DbgPrint(" %d: %s >>\n", j, FN->FileName); } } CloseHandle(hFile); return(0); } //////////////////////////////////////////////////////////////////////////// // Finds a path in a menu tree. If not found, NULL is returned. PPATHNODE FindPath(PTREENODE Tree, PPATHNODE PN) { PPATHNODE FoundPN; for (FoundPN = Tree->PathHead; FoundPN != NULL; FoundPN = FoundPN->Next) { if (_wcsicmp(FoundPN->PathStr,PN->PathStr) == 0) return FoundPN; } return NULL; } //////////////////////////////////////////////////////////////////////////// // Finds a file in a directory node. If not found, NULL is returned. PFILENODE FindFile(PPATHNODE PN, PFILENODE FN) { PFILENODE FoundFN; for (FoundFN = PN->FileHead; FoundFN != NULL; FoundFN = FoundFN->Next) { if (_wcsicmp(FoundFN->FileName,FN->FileName) == 0) return FoundFN; } return NULL; } //////////////////////////////////////////////////////////////////////////// /* ============================================================== Function Name : wcsrevchr Description : Reverse wcschr Finds a character in a string starting from the end Arguments : Return Value : PWCHAR ============================================================== */ PWCHAR wcsrevchr( PWCHAR string, WCHAR ch ) { int cLen, iCount; cLen = wcslen(string); string += cLen; for (iCount = cLen; iCount && *string != ch ; iCount--, string--) ; if (*string == ch) return string; else return NULL; } //////////////////////////////////////////////////////////////////////////// // Create the indicated directory. This function creates any parent // directories that are needed too. // // Return: TRUE = directory now exists // FALSE = directory couldn't be created BOOLEAN TsCreateDirectory( WCHAR *DirName ) { BOOL RetVal; WCHAR *LastSlash; // // Try to create the specified directory. If the create works or // the directory already exists, return TRUE. If the called failed // because the path wasn't found, continue. This occurs if the // parent directory doesn't exist. // RetVal = CreateDirectory(DirName, NULL); if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS)) return(TRUE); if (GetLastError() != ERROR_PATH_NOT_FOUND) return(FALSE); // // Remove the last component of the path and try creating the // parent directory. Upon return, add the last component back // in and try to create the specified directory again. // // Desc : BUG 267014 - replaced // LastSlash = wcschr(DirName, L'\\'); // Given a full pathname, previous always returns the drive letter. // Next line returns path components LastSlash = wcsrevchr(DirName, L'\\'); if (LastSlash == NULL) // Can't reduce path any more return(FALSE); *LastSlash = L'\0'; RetVal = TsCreateDirectory(DirName); *LastSlash = L'\\'; if (RetVal == FALSE) // Couldn't create parent directory return(FALSE); RetVal = CreateDirectory(DirName, NULL); if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS)) return(TRUE); return(FALSE); } //////////////////////////////////////////////////////////////////////////// // Moves a file from the current start menu to the All Users start menu. // Creates any directories that may be needed in the All Users menu. void TsMoveFile(PPATHNODE PN, PFILENODE FN) { WCHAR Src[MAX_PATH]; WCHAR Dest[MAX_PATH]; // Normalize Source Path wcscpy(Src,PN->PathStr); if (Src[wcslen(Src)-1] != L'\\') wcscat(Src,L"\\"); // Create Destination Path. wcscpy(Dest,AllUserDir); wcscat(Dest,&Src[CurUserDirLen]); // If directory doesn't exist, make it. The default permission is fine. if (TsCreateDirectory(Dest) != TRUE) return; wcscat(Src,FN->FileName); wcscat(Dest,FN->FileName); // Move Fails if the target already exists. This could happen // if we're copying a file that has a newer timestamp. if ( GetFileAttributes(Dest) != -1 ) DeleteFile(Dest); // DbgPrint("Moving File %s \n to %s\n",Src,Dest); if (MoveFile(Src, Dest) == FALSE) return; AddEveryoneRXPermissionW(Dest); } //////////////////////////////////////////////////////////////////////////// // Compare the current start menu with the original. Copy any new or // changed files to the All Users menu. void ProcessChanges(PTREENODE OrigTree, PTREENODE NewTree) { PPATHNODE NewPN, OrigPN; PFILENODE NewFN, OrigFN; BOOL fRet; PPREMOVEDIRLIST pRemDirList = NULL, pTemp; for (NewPN = NewTree->PathHead; NewPN != NULL; NewPN = NewPN->Next) { // DbgPrint("PC: Dir is %s\n",NewPN->PathStr); // If directory not found in original tree, move it over OrigPN = FindPath(OrigTree, NewPN); if (OrigPN == NULL) { for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next) { // DbgPrint(" Move File is %s\n",NewFN->FileName); TsMoveFile(NewPN,NewFN); } // Desc : BUG 267014 - replaced // RemoveDirectory(NewPN->PathStr); // We have a problem if NewPN doesn't contain file items but subfolders. // In this case, we do not enter the above loop, as there is nothing to move // But the folder can't be removed because it contains a tree that haven't been moved yet. // To remove it, we store its name in a LIFO stack. Stack items are removed when the loop exits fRet = RemoveDirectory(NewPN->PathStr); if (!fRet && GetLastError() == ERROR_DIR_NOT_EMPTY) { #if DBG DbgPrint("Adding to List--%S\n", NewPN->PathStr); #endif if (pRemDirList) { pTemp = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED,sizeof(REMOVEDIRLIST)); wcscpy(pTemp->PathStr, NewPN->PathStr); pTemp->Next = pRemDirList; pRemDirList = pTemp; } else { pRemDirList = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED, sizeof(REMOVEDIRLIST)); wcscpy(pRemDirList->PathStr, NewPN->PathStr); pRemDirList->Next = NULL; } } continue; } // Directory was found, check the files for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next) { // DbgPrint(" File is %s\n",NewFN->FileName); // File wasn't found, move it OrigFN = FindFile(OrigPN,NewFN); if (OrigFN == NULL) { TsMoveFile(NewPN,NewFN); continue; } // Check TimeStamp, if New Scan is more recent, move it. if (CheckDates(NewFN,OrigFN) == 1) { TsMoveFile(NewPN,NewFN); continue; } } } // Desc : BUG 267014 - added // Directories stack removal if (pRemDirList) { while (pRemDirList) { pTemp = pRemDirList; pRemDirList = pRemDirList->Next; RemoveDirectory(pTemp->PathStr); LocalFree(pTemp); } } } //////////////////////////////////////////////////////////////////////////// // Frees the in-memory representation of a start menu void FreeTree(PTREENODE Tree) { PPATHNODE PN,NextPN; PFILENODE FN,NextFN; for (PN = Tree->PathHead; PN != NULL; PN = NextPN) { for (FN = PN->FileHead; FN != NULL; FN = NextFN) { NextFN = FN->Next; LocalFree(FN); } NextPN = PN->Next; LocalFree(PN); } Tree->PathHead = NULL; Tree->PathTail = NULL; Tree->NumPaths = 0; } //////////////////////////////////////////////////////////////////////////// // Updates the "All User" menu by moving new items from the Current User's // start menu. In RunMode 0, a snapshot of the Current User's start menu // is taken. After modifications to the Current User's start menu are done, // this function is called again with RunMode 1. Then, it compares the // current state of the start menu with the saved snapshot. Any new or // modified files are copied over to the corresponding location in the // "All User" start menu. // // RunMode 0 is invoked when the system is changed into install mode and // mode 1 is called when the system returns to execute mode. int TermsrvUpdateAllUserMenu(int RunMode) { TREENODE OrigTree; TREENODE NewTree; WCHAR p[MAX_PATH]; int retval; PMESSAGE_RESOURCE_ENTRY MessageEntry; PVOID DllHandle; NTSTATUS Status; DWORD dwlen; OrigTree.PathHead = NULL; OrigTree.PathTail = NULL; OrigTree.NumPaths = 0; NewTree.PathHead = NULL; NewTree.PathTail = NULL; NewTree.NumPaths = 0; retval = GetEnvironmentVariable(L"UserProfile", p, MAX_PATH); if (retval == 0) return(-1); if (!StartMenu[0]) { HINSTANCE hInst; typedef HRESULT (* LPFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPWSTR); LPFNSHGETFOLDERPATH lpfnSHGetFolderPath; WCHAR ssPath[MAX_PATH]; WCHAR *LastSlash; wcscpy( StartMenu, L"\\Start Menu"); hInst = LoadLibrary(L"SHELL32.DLL"); if (hInst) { lpfnSHGetFolderPath = (LPFNSHGETFOLDERPATH)GetProcAddress(hInst,"SHGetFolderPathW"); if (lpfnSHGetFolderPath) { if (S_OK == lpfnSHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, ssPath)) { LastSlash = wcsrevchr(ssPath, L'\\'); if (LastSlash) { wcscpy(StartMenu, LastSlash); } } } FreeLibrary(hInst); } } wcscpy(SaveName,p); wcscat(SaveName,L"\\TsAllUsr.Dat"); wcscpy(CurUserDir,p); wcscat(CurUserDir,StartMenu); CurUserDirLen = wcslen(CurUserDir); dwlen = sizeof(AllUserDir)/sizeof(WCHAR); if (GetAllUsersProfileDirectory(AllUserDir, &dwlen)) { wcscat(AllUserDir,StartMenu); #if DBG DbgPrint("SaveName is '%S'\n",SaveName); DbgPrint("CurUserDir is '%S'\n",CurUserDir); DbgPrint("AllUserDir is '%S'\n",AllUserDir); #endif if (RunMode == 0) { // If the start menu snapshot already exists, don't overwrite it. // The user may enter "change user /install" twice, or an app may // force a reboot without changing back to execute mode. The // existing file is older. If we overwrite it, then some shortcuts // won't get moved. if (FileExists(SaveName) != TRUE) { ReadTree(&OrigTree, CurUserDir); if (WriteTreeToDisk(&OrigTree) == -1) DeleteFile(SaveName); FreeTree(&OrigTree); } } else if (RunMode == 1) { if (ReadTreeFromDisk(&OrigTree) == -1) { FreeTree(&OrigTree); DeleteFile(SaveName); // Could be a bad file. If it doesn't // exist, this won't hurt anything. return(-1); } ReadTree(&NewTree, CurUserDir); ProcessChanges(&OrigTree,&NewTree); DeleteFile(SaveName); FreeTree(&OrigTree); FreeTree(&NewTree); } } return(0); }