[SYSDM] Allow deleting and copying of user profiles only for profiles that are curren...
[reactos.git] / dll / cpl / sysdm / userprofile.c
index fb49a20..0c9e1f9 100644 (file)
 
 #include "precomp.h"
 #include <sddl.h>
+#include <winnls.h>
 
 #include <debug.h>
 
 typedef struct _PROFILEDATA
 {
-    BOOL bMyProfile;
+    DWORD dwRefCount;
     DWORD dwState;
     PWSTR pszFullName;
 } PROFILEDATA, *PPROFILEDATA;
@@ -175,7 +176,7 @@ DeleteUserProfile(
         return FALSE;
 
     pProfileData = (PPROFILEDATA)Item.lParam;
-    if (pProfileData->bMyProfile)
+    if (pProfileData->dwRefCount != 0)
         return FALSE;
 
     LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE_TITLE, szTitle, ARRAYSIZE(szTitle));
@@ -322,22 +323,78 @@ SetListViewColumns(
 }
 
 
-static VOID
-AddUserProfile(
-    _In_ HWND hwndListView,
+static
+BOOL
+GetProfileSize(
+    PWSTR pszProfilePath,
+    PULONGLONG pullProfileSize)
+{
+    HANDLE hFile = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATA FindData;
+    DWORD dwProfilePathLength;
+    ULARGE_INTEGER Size;
+    BOOL bResult = TRUE;
+
+    dwProfilePathLength = wcslen(pszProfilePath);
+
+    wcscat(pszProfilePath, L"\\*.*");
+
+    hFile = FindFirstFileW(pszProfilePath, &FindData);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        if ((GetLastError() != ERROR_FILE_NOT_FOUND) &&
+            (GetLastError() != ERROR_PATH_NOT_FOUND))
+            bResult = FALSE;
+
+        goto done;
+    }
+
+    do
+    {
+        if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        {
+            if ((_wcsicmp(FindData.cFileName, L".") == 0) ||
+                (_wcsicmp(FindData.cFileName, L"..") == 0))
+                continue;
+
+            pszProfilePath[dwProfilePathLength + 1] = UNICODE_NULL;
+            wcscat(pszProfilePath, FindData.cFileName);
+
+            if (!GetProfileSize(pszProfilePath, pullProfileSize))
+            {
+                bResult = FALSE;
+                goto done;
+            }
+        }
+        else
+        {
+            Size.u.LowPart = FindData.nFileSizeLow;
+            Size.u.HighPart = FindData.nFileSizeHigh;
+            *pullProfileSize += Size.QuadPart;
+        }
+    }
+    while (FindNextFile(hFile, &FindData));
+
+done:
+    pszProfilePath[dwProfilePathLength] = UNICODE_NULL;
+
+    if (hFile != INVALID_HANDLE_VALUE)
+        FindClose(hFile);
+
+    return bResult;
+}
+
+
+static
+BOOL
+GetProfileName(
     _In_ PSID pProfileSid,
-    _In_ PSID pMySid,
-    _In_ HKEY hProfileKey)
+    _In_ DWORD dwNameBufferSize,
+    _Out_ PWSTR pszNameBuffer)
 {
-    PPROFILEDATA pProfileData = NULL;
     WCHAR szAccountName[128], szDomainName[128];
-    WCHAR szNameBuffer[256];
-    SID_NAME_USE Use;
     DWORD dwAccountNameSize, dwDomainNameSize;
-    DWORD dwProfileData, dwSize, dwType, dwState = 0;
-    PWSTR ptr;
-    INT nId, iItem;
-    LV_ITEM lvi;
+    SID_NAME_USE Use;
 
     dwAccountNameSize = ARRAYSIZE(szAccountName);
     dwDomainNameSize = ARRAYSIZE(szDomainName);
@@ -350,26 +407,120 @@ AddUserProfile(
                            &Use))
     {
         /* Unknown account */
-        LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, szNameBuffer, ARRAYSIZE(szNameBuffer));
+        LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, pszNameBuffer, dwNameBufferSize);
     }
     else
     {
         /* Show only the user accounts */
         if (Use != SidTypeUser)
-            return;
+            return FALSE;
 
         if (szAccountName[0] == UNICODE_NULL)
         {
             /* Deleted account */
-            LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, szNameBuffer, ARRAYSIZE(szNameBuffer));
+            LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, pszNameBuffer, dwNameBufferSize);
         }
         else
         {
             /* Normal account */
-            wsprintf(szNameBuffer, L"%s\\%s", szDomainName, szAccountName);
+            wsprintf(pszNameBuffer, L"%s\\%s", szDomainName, szAccountName);
         }
     }
 
+    return TRUE;
+}
+
+
+static
+VOID
+FormatProfileSize(LPWSTR Buffer, double size)
+{
+    const LPWSTR units[] = {L"MB", L"GB", L"TB"};
+    int i = 0, j;
+
+    size /= 1024;
+    size /= 1024;
+
+    while (size >= 1024 && i < 3)
+    {
+        size /= 1024;
+        i++;
+    }
+
+    if (size < 10)
+        j = 2;
+    else if (size < 100)
+        j = 1;
+    else
+        j = 0;
+
+    swprintf(Buffer, L"%.*f %s", j, size, units[i]);
+}
+
+
+static VOID
+AddUserProfile(
+    _In_ HWND hwndListView,
+    _In_ PSID pProfileSid,
+    _In_ HKEY hProfileKey)
+{
+    WCHAR szTempProfilePath[MAX_PATH], szProfilePath[MAX_PATH];
+    WCHAR szNameBuffer[256];
+    PPROFILEDATA pProfileData = NULL;
+    DWORD dwProfileData, dwSize, dwType, dwState = 0, dwRefCount = 0;
+    DWORD dwProfilePathLength;
+    PWSTR ptr;
+    INT nId, iItem;
+    LV_ITEM lvi;
+    WIN32_FIND_DATA FindData;
+    HANDLE hFile;
+    SYSTEMTIME SystemTime;
+    ULONGLONG ullProfileSize;
+    DWORD dwError;
+
+    /* Get the profile path */
+    dwSize = MAX_PATH * sizeof(WCHAR);
+    dwError = RegQueryValueExW(hProfileKey,
+                               L"ProfileImagePath",
+                               NULL,
+                               &dwType,
+                               (LPBYTE)szTempProfilePath,
+                               &dwSize);
+    if (dwError != ERROR_SUCCESS)
+        return;
+
+    /* Expand it */
+    ExpandEnvironmentStringsW(szTempProfilePath,
+                              szProfilePath,
+                              MAX_PATH);
+
+    /* Check if the profile path exists */
+    hFile = FindFirstFileW(szProfilePath, &FindData);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return;
+
+    FindClose(hFile);
+
+    /* Get the length of the profile path */
+    dwProfilePathLength = wcslen(szProfilePath);
+
+    /* Check for the ntuser.dat file */
+    wcscat(szProfilePath, L"\\ntuser.dat");
+    hFile = FindFirstFileW(szProfilePath, &FindData);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return;
+
+    FindClose(hFile);
+    szProfilePath[dwProfilePathLength] = UNICODE_NULL;
+
+    /* Get the profile size */
+    ullProfileSize = 0ULL;
+    GetProfileSize(szProfilePath, &ullProfileSize);
+
+    /* Get the profile name */
+    if (!GetProfileName(pProfileSid, ARRAYSIZE(szNameBuffer), szNameBuffer))
+        return;
+
     /* Get the profile state value */
     dwSize = sizeof(dwState);
     if (RegQueryValueExW(hProfileKey,
@@ -382,16 +533,28 @@ AddUserProfile(
         dwState = 0;
     }
 
+    /* Get the profile reference counter */
+    dwSize = sizeof(dwRefCount);
+    if (RegQueryValueExW(hProfileKey,
+                         L"RefCount",
+                         NULL,
+                         &dwType,
+                         (LPBYTE)&dwRefCount,
+                         &dwSize) != ERROR_SUCCESS)
+    {
+        dwRefCount = 0;
+    }
+
     /* Create and fill the profile data entry */
     dwProfileData = sizeof(PROFILEDATA) +
                     ((wcslen(szNameBuffer) + 1) * sizeof(WCHAR));
     pProfileData = HeapAlloc(GetProcessHeap(),
-                             0,
+                             HEAP_ZERO_MEMORY,
                              dwProfileData);
     if (pProfileData == NULL)
         return;
 
-    pProfileData->bMyProfile = EqualSid(pMySid, pProfileSid);
+    pProfileData->dwRefCount = dwRefCount;
     pProfileData->dwState = dwState;
 
     ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA));
@@ -407,7 +570,21 @@ AddUserProfile(
     lvi.lParam = (LPARAM)pProfileData;
     iItem = ListView_InsertItem(hwndListView, &lvi);
 
+    /* Set the profile size */
+    FormatProfileSize(szNameBuffer, (double)ullProfileSize);
+    ListView_SetItemText(hwndListView, iItem, 1, szNameBuffer);
+
     /* Set the profile type */
+    if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
+        nId = IDS_USERPROFILE_ROAMING;
+    else
+        nId = IDS_USERPROFILE_LOCAL;
+
+    LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
+
+    ListView_SetItemText(hwndListView, iItem, 2, szNameBuffer);
+
+    /* FIXME: Set the profile status */
     if (dwState & 0x0001) // PROFILE_MANDATORY
         nId = IDS_USERPROFILE_MANDATORY;
     else if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
@@ -415,9 +592,22 @@ AddUserProfile(
     else
         nId = IDS_USERPROFILE_LOCAL;
 
-    LoadStringW(hApplet, nId, szAccountName, ARRAYSIZE(szAccountName));
+    LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
+
+    ListView_SetItemText(hwndListView, iItem, 3, szNameBuffer);
 
-    ListView_SetItemText(hwndListView, iItem, 2, szAccountName);
+    /* Set the profile modified time */
+    FileTimeToSystemTime(&FindData.ftLastWriteTime,
+                         &SystemTime);
+
+    GetDateFormatW(LOCALE_USER_DEFAULT,
+                   DATE_SHORTDATE,
+                   &SystemTime,
+                   NULL,
+                   szNameBuffer,
+                   ARRAYSIZE(szNameBuffer));
+
+    ListView_SetItemText(hwndListView, iItem, 4, szNameBuffer);
 }
 
 
@@ -428,7 +618,9 @@ UpdateButtonState(
 {
     LVITEM Item;
     INT iSelected;
-    BOOL bMyProfile;
+    BOOL bChange = FALSE;
+    BOOL bCopy = FALSE;
+    BOOL bDelete = FALSE;
 
     iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
     if (iSelected != -1)
@@ -440,22 +632,23 @@ UpdateButtonState(
         {
             if (Item.lParam != 0)
             {
-                bMyProfile = ((PPROFILEDATA)Item.lParam)->bMyProfile;
-                if (!bMyProfile)
-                {
-                    EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), TRUE);
-                    EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), TRUE);
-                }
+                bCopy = (((PPROFILEDATA)Item.lParam)->dwRefCount == 0);
+                bDelete = (((PPROFILEDATA)Item.lParam)->dwRefCount == 0);
             }
         }
-        EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), TRUE);
+
+        bChange = TRUE;
     }
     else
     {
-        EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), FALSE);
-        EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), FALSE);
-        EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), FALSE);
+        bChange = FALSE;
+        bCopy = FALSE;
+        bDelete = FALSE;
     }
+
+    EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), bChange);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bDelete);
+    EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bCopy);
 }
 
 
@@ -521,7 +714,9 @@ AddUserProfiles(
             {
                 if (ConvertStringSidToSid(szProfileSid, &pProfileSid))
                 {
-                    AddUserProfile(hwndListView, pProfileSid, pTokenUser->User.Sid, hProfileKey);
+                    AddUserProfile(hwndListView,
+                                   pProfileSid,
+                                   hProfileKey);
                     LocalFree(pProfileSid);
                 }
 
@@ -539,7 +734,9 @@ AddUserProfiles(
                               KEY_READ,
                               &hProfileKey) == ERROR_SUCCESS)
             {
-                AddUserProfile(hwndListView, pTokenUser->User.Sid, pTokenUser->User.Sid, hProfileKey);
+                AddUserProfile(hwndListView,
+                               pTokenUser->User.Sid,
+                               hProfileKey);
                 RegCloseKey(hProfileKey);
             }