Куда поместить общие файлы приложений с возможностью записи?

Я думал, что CSIDL_COMMON_APPDATA\company\product должно быть местом для размещения файлов, которые являются общими для всех пользователей приложения и которые приложение может изменять, однако в Vista это место только для чтения, если оно не изменено установщиком (согласно MSDN - http://msdn.microsoft.com/en-us/library/ms995853.aspx), так что ... что лучше? Изменить настройки безопасности местоположения, чтобы вместо этого можно было писать или использовать CSIDL_COMMON_DOCUMENTS\company\product? Может есть третий вариант?

Кроме того, есть ли где-нибудь «официальная» рекомендация Microsoft по этому поводу?


person dennisV    schedule 28.09.2008    source источник


Ответы (4)


Измените безопасность только в определенном подкаталоге каталога AppData (это из предоставленную вами ссылку):

CSIDL_COMMON_APPDATA Эта папка должна использоваться для данных приложения, не зависящих от пользователя. Например, приложение может хранить словарь проверки орфографии, базу данных клип-артов или файл журнала в папке CSIDL_COMMON_APPDATA. Эта информация не будет перемещаться и доступна любому, кто пользуется компьютером. По умолчанию это место доступно только для чтения для обычных (не администраторов, не обладающих полномочиями) пользователей. Если приложение требует, чтобы обычные пользователи имели доступ на запись к подкаталогу CSIDL_COMMON_APPDATA для конкретного приложения, тогда приложение должно явно изменить безопасность в этом подкаталоге во время установки приложения. Измененные параметры безопасности должны быть задокументированы в Анкета продавца.

person 1800 INFORMATION    schedule 28.09.2008
comment
Да, я тоже об этом думаю. Но похоже, что они (Microsoft) не хотят, чтобы вы помещали туда файлы, а вместо этого использовали COMMON_DOCUMENTS. Спасибо. - person dennisV; 29.09.2008
comment
Откуда вы взяли, что они не хотят, чтобы вы туда клали файлы? Похоже, они вполне довольны тем, что вы помещаете туда файлы - вы должны поместить их в свой собственный подкаталог и правильно управлять безопасностью. - person 1800 INFORMATION; 29.09.2008
comment
Я полагаю, что да, но изменение безопасности - это дополнительный шаг, который, как я полагаю (возможно, ошибочно), размещен там, чтобы отговорить людей от использования этой папки для файлов с возможностью записи. - person dennisV; 29.09.2008
comment
Нет, это дополнительный шаг к тому, чтобы файлы данных приложений оставались изолированными друг от друга. Затем вы вынуждены думать о том, какие пользователи должны иметь доступ, и соответственно предоставлять его. - person 1800 INFORMATION; 29.09.2008

Вот простой пример, показывающий, как создавать файлы и папки с разрешениями на чтение и запись для всех пользователей в папке общих данных приложения (CSIDL_COMMON_APPDATA). Любой пользователь может запустить этот код, чтобы дать всем остальным пользователям разрешение на запись в файлы и папки:

#include <windows.h>

#include <shlobj.h>
#pragma comment(lib, "shell32.lib")

// for PathAppend
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#pragma comment(lib, "advapi32.lib")    

#include <iostream>
#include <fstream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwRes, dwDisposition;
    PSID pEveryoneSID = NULL;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    SECURITY_ATTRIBUTES sa;

    // Create a well-known SID for the Everyone group.
    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                     SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0,
                     &pEveryoneSID))
    {
        _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone access to files & folders you create.
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = 0xFFFFFFFF;
    ea.grfAccessMode = SET_ACCESS;

    // both folders & files will inherit this ACE
    ea.grfInheritance= CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName  = (LPTSTR) pEveryoneSID;

    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes)
    {
        _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security descriptor.
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (NULL == pSD)
    {
        _tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
        goto Cleanup;
    }

    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
    {
        _tprintf(_T("InitializeSecurityDescriptor Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Add the ACL to the security descriptor.
    if (!SetSecurityDescriptorDacl(pSD,
            TRUE,     // bDaclPresent flag
            pACL,
            FALSE))   // not a default DACL
    {
        _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security attributes structure.
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;



    TCHAR szPath[MAX_PATH];

    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath))) 
    {
        PathAppend(szPath, TEXT("Your Shared Folder"));

        if (!CreateDirectory(szPath, &sa)
            && GetLastError() != ERROR_ALREADY_EXISTS) 
        {
            goto Cleanup;
        }

        PathAppend(szPath, TEXT("textitup.txt"));

        HANDLE hFile = CreateFile(szPath, GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, 0, 0);
        if (hFile == INVALID_HANDLE_VALUE)
            goto Cleanup;
        else
            CloseHandle(hFile);

        //TODO: do the writing
        ofstream fsOut;
        fsOut.exceptions(ios::eofbit | ios::failbit | ios::badbit);
        fsOut.open(szPath, ios::out | ios::binary | ios::trunc);

        fsOut << "Hello world!\n";
        fsOut.close();
    }

Cleanup:

    if (pEveryoneSID) 
        FreeSid(pEveryoneSID);
    if (pACL) 
        LocalFree(pACL);
    if (pSD) 
        LocalFree(pSD);

    return 0;
}
person Wyatt O'Day    schedule 21.08.2011

Я думаю, что этот пост может ответить на некоторые вопросы, но многим это кажется сложной проблемой.

По-видимому, CSIDL_COMMON_DOCUMENTS предоставляет общий обходной путь

person TheSoftwareJedi    schedule 28.09.2008
comment
Извините, я не понимаю, как это отвечает на вопрос. Я знаю, как получить путь, я спрашиваю, какой путь правильный. - person dennisV; 29.09.2008
comment
Да, спасибо. Жаль, что на эту проблему нет официального ответа. - person dennisV; 29.09.2008

Рекомендации для Vista / UAC можно найти здесь. Поищите на этой странице "CSIDL", и вы найдете несколько "официальных" ответов.

person Christoffer Lette    schedule 29.09.2008
comment
Спасибо - все указывает на каталог, который я изначально планировал использовать. Думаю, тогда это правильный ответ :) - person dennisV; 29.09.2008
comment
Приятное теплое чувство, когда узнаешь, что все время был прав, не так ли? ;-) - person Christoffer Lette; 29.09.2008