Каталог Windows Explorer в виде пакета

В течение некоторого времени я изучал способ предотвращения случайного входа моего пользователя в каталог данных моего приложения.

Мое приложение использует папку для хранения структурированного проекта. Внутренняя структура папки критична и не должна быть испорчена. Я бы хотел, чтобы мой пользователь видел эту папку целиком и не смог ее открыть (как в комплекте с Mac).

Есть ли способ сделать это на Windows?

Редактировать из текущих ответов

Конечно, я не пытаюсь предотвратить доступ моих пользователей к своим данным, просто защищаю их от случайного нарушения целостности данных. Так что шифрование или защита паролем не нужны.

Спасибо всем за ваши ответы .Net, но, к сожалению, это в основном проект C ++ без какой-либо зависимости от .Net Framework.

Данные, которые я упоминаю, не являются легкими, они получены изображения с электронного микроскопа. Эти данные могут быть огромными (от ~ 100 МБ до ~ 1 ГБ), поэтому загрузка всего в память невозможна. Это огромные изображения, поэтому хранилище должно обеспечивать возможность поэтапного чтения данных путем одновременного доступа к одному файлу без загрузки всего архива в память.

Кроме того, приложение в основном унаследовано с некоторыми компонентами, за которые мы даже не отвечаем. Решение, которое позволяет мне сохранить текущий код ввода-вывода, является предпочтительным.

Shell Extension выглядит интересно, я буду исследовать решение дальше.

LarryF, можете ли вы рассказать о драйвере фильтра или DefineDOSDevice? Я не знаком с этими понятиями.

12.12.2008 18:45:29
Можете ли вы пролить свет на то, на каком языке / в какой среде вы находитесь?
Tomalak 12.12.2008 19:31:15
Конечно, обновил ответ
Vincent Robert 13.12.2008 14:55:56
10 ОТВЕТОВ

Внутри или снаружи вашей программы?

Есть способы, но ни один из них не прост. Вы, вероятно, будете смотреть на драйвер фильтра в файловой системе.

1
25.12.2015 21:09:06

Вы можете заключить каталог вашего проекта в файл .zip и хранить там свои данные, подобно тому, как используется .jar (я знаю, что .jar в основном только для чтения, это только для примера). Создайте нестандартное расширение, чтобы двойной щелчок не оказывал немедленного эффекта. ;-)

Конечно, это означает, что вам придется обернуть все свои файловые операции ввода-вывода, чтобы использовать вместо этого .zip, в зависимости от того, как построена ваша программа, это может быть утомительно. Это уже сделано для Java: TrueZip . Может быть, вы можете использовать это как вдохновение?

Если вы испытали искушение - я бы не советовал возиться с разрешениями на папки, по понятным причинам это не поможет.

0
12.12.2008 18:59:35

Есть пара вещей, которые вы могли бы сделать:

Во-первых, вы можете создать расширение оболочки Windows для FolderView, которое будет создавать настраиваемое представление для вашей критической папки. Создав пользовательский FolderView, вы можете сделать папку просто пустой белой с одной строкой текста «Здесь нечего смотреть», или вы можете сделать что-то более сложное, например, средство просмотра GAC, использующее этот же метод. Этот метод был бы довольно сложным, но эту сложность можно уменьшить, используя в качестве основы что-то вроде библиотеки этой статьи CodeProject .

Другим решением может быть создание виртуальной файловой системы ZIP, для этого вам потребуется заменить любой код, который использует System.IO напрямую, чтобы использовать что-то другое. ASP.NET 2.0 сделал это именно по этой причине, и вы могли бы легко в этом разобраться, взгляните на эту статью MSDN о реализации VirtualPathProvider.

1
12.12.2008 19:16:52
Похоже, что это в основном для ASP.NET, но он ничего не упомянул об ASP или .NET ... Идеи, однако, хороши.
LarryF 12.12.2008 20:42:10

Вы можете использовать изолированное хранилище.

http://www.ondotnet.com/pub/a/dotnet/2003/04/21/isolatedstorage.html

Это не решает всех проблем, но делает данные приложений безопасными.

0
12.12.2008 19:18:30

Имейте в виду: если вы сохраните его в файловой системе, пользователь ВСЕГДА сможет его увидеть. Вмешайтесь в проводник, и вместо этого я использую cmd.exe. Или Total Commander. Или что-нибудь еще.

Если вы не хотите, чтобы люди связывались с вашими файлами, я бы порекомендовал

  • шифрование их, чтобы предотвратить подделку файлов
  • положить их в архив (например, ZIP), возможно защитить паролем, а затем сжать / распаковать во время выполнения (я бы посмотрел алгоритмы, которые быстро модифицируют архивы)

Это, конечно, не полная защита, но ее реализация довольно проста, не требует установки каких-либо интересных вещей внутри операционной системы и должна держать в стороне самых любопытных пользователей.

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

0
12.12.2008 19:22:24

Я видел программное обеспечение (Agilian Visual Paradigm), которое использовало предложение Томалака о zip-архиве в качестве «файла проекта». Zip-файлы хорошо понятны, а использование нестандартного расширения файла не позволяет обычному пользователю возиться с «файлом». Одним из больших преимуществ этого является то, что в случае повреждения стандартные инструменты могут быть использованы для решения проблемы, и вам не нужно беспокоиться о создании специальных инструментов для поддержки вашего основного приложения.

0
12.12.2008 19:26:12

Если вы принимаете ZIP-файл (который я рассмотрел для вас, но не упомянул об этом), я бы предложил использовать алгоритм дефляции, но использовать свою собственную файловую систему ... Посмотрите на что-то вроде формата TAR. Затем просто напишите свой код, чтобы пропустить ВСЕ ввод-вывод за алгоритмы Inflate / Deflate при их записи на диск. Я бы не использовал ZIP «FORMAT», так как слишком легко посмотреть на файл, найти PK в качестве первых двух байтов и распаковать ваш файл ....

Мне больше нравятся предложения Джошперри.

Конечно, вы также можете написать драйвер устройства, который хранит все ваши данные в одном файле, но опять же, мы смотрим на драйвер. (Я не уверен, что вы могли бы реализовать это вне драйвера. Вы, вероятно, можете, и внутри вашей программы вызовите DefineDOSDevice, дав ему имя, к которому имеет доступ только ваш код, и оно будет рассматриваться как обычная файловая система. ). Я поиграю с некоторыми идеями, и если они сработают, я застрелю вам образец. Теперь ты заинтересовал меня.

1
25.12.2015 21:10:00

Я рад слышать, что вы делаете это на C ++. Кажется, никто больше не считает C ++ «необходимым». Это все C # это и ASP.NET, что ... Даже я работаю во всем C # доме, когда я поклялся, что никогда не переключусь, так как C ++ делает все, что мне когда-либо нужно делать, а затем еще кое-что. Я достаточно взрослый, чтобы очистить свою память! хех .. В любом случае, вернемся к вопросу под рукой ...

Это DefineDOSDevice()метод, который вы используете для назначения букв дисков, имен портов (LPT1, COM1 и т. Д.). Вы передаете ему имя, некоторые флаги и «путь», который обрабатывает это устройство. Но не позволяйте этому обмануть вас. Это не путь к файловой системе, это путь к объекту NT. Я уверен, что вы видели их как «\ Device \ HardDisk0» и т. Д. Вы можете использовать WinObj.exe из sysinternals, чтобы понять, что я имею в виду. В любом случае вы можете создать драйвер устройства, а затем указать на него символическую ссылку MSDOS, и все готово. Но при условии, что это кажется большой работой для первоначальной проблемы.

Сколько из этих мегабайтовых файлов находится в типичном каталоге? Лучше всего просто прикрепить все файлы внутри одного гигантского файла и сохранить рядом с ним индексный файл (или заголовок каждого файла), который указывает на следующий «Файл» внутри вашего файла «виртуальной файловой системы».

Хорошим примером может быть просмотр формата Microsoft MSN Archive. Я перевернул этот формат архива, когда работал в AV-компании, и он на самом деле довольно креативный, но ОЧЕНЬ простой. Все это может быть сделано в одном файле, и если вы хотите стать модным, вы МОЖЕТЕ хранить данные по 3 файлам в конфигурации типа RAID 5, поэтому, если один из этих трех файлов будет подключен, вы МОЖЕТЕ перестроить остальные. Кроме того, пользователи просто увидят 3 ОЧЕНЬ больших файла в каталоге и не смогут получить доступ к отдельным (внутренним) файлам.

Я предоставил вам код, который распаковывает один из этих форматов MSN Archive. У меня нет кода, который СОЗДАЕТ его, но из исходного кода вы сможете создать / написать его без проблем. Если файлы удаляются и / или часто переименовываются, это может привести к проблеме с используемым пространством в файле, которое время от времени придется обрезать.

Этот формат даже поддерживает поля CRC, поэтому вы можете проверить, правильно ли вы получили файл. Мне никогда не удавалось полностью изменить алгоритм, который Microsoft использовал для CRC-данных, но у меня есть довольно хорошая идея.

Вы не сможете сохранить текущие подпрограммы ввода / вывода, то есть CreateFile () не просто сможет открыть какой-либо файл в архиве, однако, благодаря непревзойденной крутости C ++, вы можете переопределить вызов CreateFile для реализации Ваш формат архива.

Если вам нужна помощь с ним, и это достаточно большая проблема, возможно, мы могли бы поговорить в автономном режиме и найти решение для вас.

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

Я не уверен, что для меня кошерно давать вам свой адрес электронной почты здесь, я не уверен в политике SO по этому вопросу, так как мы могли бы говорить о потенциальной работе / привлечении, но это не мое единственное намерение. Я предпочел бы сначала помочь вам найти ваши собственные решения.

Прежде чем заглянуть в драйвер устройства, скачайте WinDDK. У него есть образцы драйверов по всему.

Если вы удивляетесь, почему я так переживаю по этому поводу, то это потому, что я уже много лет пишу на этом драйвере, который должен был быть Windows ANDСовместимость с OSX, которая позволит пользователям защищать тома дисков (USB-ключи, съемные тома) БЕЗ установки каких-либо драйверов или сложного (и громоздкого, иногда раздражающего) программного обеспечения. В последние годы многие производители оборудования делали подобные вещи, но я не думаю, что безопасность - это все, что безопасно. Я смотрю на использование RSA и AES, точно так же, как работают GPG и PGP. Первоначально со мной связались по поводу того, что (я верю, но у меня нет доказательств) собирались использовать для защиты файлов MP3. Поскольку они будут храниться в зашифрованном формате, они просто не будут работать без правильной парольной фразы. Но я видел и другие варианты использования. (Это было тогда, когда стоимость USB-ключа на 16 мегабайт (да, MEG) превышала 100 долларов или около того).

Этот проект также шел вместе с моей системой безопасности ПК для нефтяной и газовой промышленности, в которой использовалось что-то похожее на смарт-карты, гораздо проще в использовании, повторном использовании / повторном выпуске, которое невозможно (читай: ОЧЕНЬ сложно и маловероятно) взломать, и Я мог бы использовать это на своих собственных детей дома! (Так как всегда есть борьба за то, кто получает время на компьютере, и кто получил больше всего, и так далее, и так далее, и ...)

Фуф ... Я думаю, что у меня тут не по теме. В любом случае, вот пример формата архива Microsoft MSN. Посмотрите, сможете ли вы использовать что-то подобное, зная, что вы всегда можете «пропустить» право на файл, следуя смещениям в файле, когда вы анализируете / ищите запрошенный файл в мастер-файле; или в предварительно проанализированных данных, хранящихся в памяти. А поскольку вы не будете загружать необработанные данные двоичных файлов в память, единственным ограничением, вероятно, будет ограничение в 4 ГБ на 32-разрядных компьютерах.

Формат MARC (Microsoft MSN Archive) выложен (примерно) так:

  • Заголовок 12 байт (только один)
    • File Magic
    • MARC версия
    • Количество файлов (в следующей таблице)
  • Заголовки таблицы файлов размером 68 байт (от 1 до Header.NumFiles из них)
    • Имя файла
    • Размер файла
    • Контрольная сумма
    • смещение к необработанным данным файла

Теперь в 12-байтовых записях таблицы файлов 32 бита используются для длины файла и смещения. Для ваших ОЧЕНЬ больших файлов может потребоваться до 48 или 64-битных целых чисел.

Вот код, который я написал, чтобы справиться с этим.

#define MARC_FILE_MAGIC         0x4352414D // In Little Endian
#define MARC_FILENAME_LEN       56 //(You'll notice this is rather small)
#define MARC_HEADER_SIZE        12
#define MARC_FILE_ENT_SIZE      68

#define MARC_DATA_SIZE          1024 * 128 // 128k Read Buffer should be enough.

#define MARC_ERR_OK              0      // No error
#define MARC_ERR_OOD             314    // Out of data error
#define MARC_ERR_OS              315    // Error returned by the OS
#define MARC_ERR_CRC             316    // CRC error

struct marc_file_hdr
{
    ULONG            h_magic;
    ULONG            h_version;
    ULONG            h_files;
    int              h_fd;
    struct marc_dir *h_dir;
};

struct marc_file
{
    char            f_filename[MARC_FILENAME_LEN];
    long            f_filesize;
    unsigned long   f_checksum;
    long            f_offset;
};

struct marc_dir
{
    struct marc_file       *dir_file;
    ULONG                   dir_filenum;
    struct marc_dir        *dir_next;
};

Это дает вам представление о заголовках, которые я написал для них, и вот функция open. Да, он пропускает все звонки в службу поддержки, ошибки и т. Д., Но вы поняли идею. Пожалуйста, извините смесь стилей кода C и C ++. Наш сканер представлял собой кластер множества разных проблем, подобных этой ... Я использовал античные вызовы, такие как open (), fopen (), чтобы соответствовать стандартам остальной части кода.

struct marc_file_hdr *marc_open(char *filename)
{
    struct marc_file_hdr *fhdr  = (struct marc_file_hdr*)malloc(sizeof(marc_file_hdr));
    fhdr->h_dir = NULL;

#if defined(_sopen_s)
    int errno = _sopen_s(fhdr->h_fd, filename, _O_BINARY | _O_RDONLY, _SH_DENYWR, _S_IREAD | _S_IWRITE);
#else
    fhdr->h_fd = open(filename, _O_BINARY | _O_RDONLY);
#endif
    if(fhdr->h_fd < 0)
    {
        marc_close(fhdr);
        return NULL;
    }

    //Once we have the file open, read all the file headers, and populate our main headers linked list.
    if(read(fhdr->h_fd, fhdr, MARC_HEADER_SIZE) != MARC_HEADER_SIZE)
    {
        errmsg("MARC: Could not read MARC header from file %s.\n", filename);
        marc_close(fhdr);
        return NULL;
    }

    // Verify the file magic
    if(fhdr->h_magic != MARC_FILE_MAGIC)
    {
        errmsg("MARC: Incorrect file magic %x found in MARC file.", fhdr->h_magic);
        marc_close(fhdr);
        return NULL;
    }

    if(fhdr->h_files <= 0)
    {
        errmsg("MARC: No files found in archive.\n");
        marc_close(fhdr);
        return NULL;
    }

    // Get all the file headers from this archive, and link them to the main header.
    struct marc_dir *lastdir = NULL, *curdir = NULL;
    curdir = (struct marc_dir*)malloc(sizeof(marc_dir));
    fhdr->h_dir = curdir;

    for(int x = 0;x < fhdr->h_files;x++)
    {
        if(lastdir)
        {
            lastdir->dir_next = (struct marc_dir*)malloc(sizeof(marc_dir));
            lastdir->dir_next->dir_next = NULL;
            curdir = lastdir->dir_next;
        }

        curdir->dir_file = (struct marc_file*)malloc(sizeof(marc_file));
        curdir->dir_filenum = x + 1;

        if(read(fhdr->h_fd, curdir->dir_file, MARC_FILE_ENT_SIZE) != MARC_FILE_ENT_SIZE)
        {
            errmsg("MARC: Could not read file header for file %d\n", x);
            marc_close(fhdr);
            return NULL;
        }
        // LEF: Just a little extra insurance...
        curdir->dir_file->f_filename[MARC_FILENAME_LEN] = NULL;

        lastdir = curdir;
    }
    lastdir->dir_next = NULL;

    return fhdr;
}

Тогда у вас есть простой метод извлечения. Имейте в виду, что это было строго для сканирования на вирусы, так что здесь нет никаких процедур поиска и т. Д. Это было разработано, чтобы просто выгружать файл, сканировать его и двигаться дальше. Ниже приведена процедура кода CRC, которую, как я полагаю, использовала Microsoft, но я не уверен, ЧТО именно они использовали в CRC. Это может включать в себя данные заголовка + данные файла и т. Д. Я просто не достаточно, чтобы вернуться и попытаться повернуть вспять. В любом случае, как вы можете видеть, в этом формате архива нет сжатия, но его ОЧЕНЬ легко добавить. Полный источник может быть предоставлен, если вы хотите. (Я думаю, что осталось только подпрограмма close (), код, который вызывает и извлекает каждый файл и т. Д. !!)

bool marc_extract(struct marc_file_hdr *marc, struct marc_file *marcfile, char *file, int &err)
{
    // Create the file from marcfile, in *file's location, return any errors.
    int ofd = 0;
#if defined(_sopen_s)
     err = _sopen_s(ofd, filename, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
#else
    ofd = open(file, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR);
#endif

    // Seek to the offset of the file to extract
    if(lseek(marc->h_fd, marcfile->f_offset, SEEK_SET) != marcfile->f_offset)
    {
        errmsg("MARC: Could not seek to offset 0x%04x for file %s.\n", marcfile->f_offset, marcfile->f_filename);
        close(ofd);
        err = MARC_ERR_OS; // Get the last error from the OS.
        return false;
    }

    unsigned char *buffer = (unsigned char*)malloc(MARC_DATA_SIZE);

    long bytesleft = marcfile->f_filesize;
    long readsize = MARC_DATA_SIZE >= marcfile->f_filesize ? marcfile->f_filesize : MARC_DATA_SIZE;
    unsigned long crc = 0;

    while(bytesleft)
    {
        if(read(marc->h_fd, buffer, readsize) != readsize)
        {
            errmsg("MARC: Failed to extract data from MARC archive.\n");
            free(buffer);
            close(ofd);
            err = MARC_ERR_OOD;
            return false;
        }

        crc = marc_checksum(buffer, readsize, crc);

        if(write(ofd, buffer, readsize) != readsize)
        {
            errmsg("MARC: Failed to write data to file.\n");
            free(buffer);
            close(ofd);
            err = MARC_ERR_OS; // Get the last error from the OS.
            return false;
        }
        bytesleft -= readsize;
        readsize = MARC_DATA_SIZE >= bytesleft ? bytesleft : MARC_DATA_SIZE;
    }

    // LEF:  I can't quite figure out how the checksum is computed, but I think it has to do with the file header, PLUS the data in the file, or it's checked on the data in the file
    //       minus any BOM's at the start...  So, we'll just rem out this code for now, but I wrote it anyways.
    //if(crc != marcfile->f_checksum)
    //{
    //    warningmsg("MARC: File CRC does not match.  File could be corrupt, or altered.  CRC=0x%08X, expected 0x%08X\n", crc, marcfile->f_checksum);
    //    err = MARC_ERR_CRC;
    //}

    free(buffer);
    close(ofd);

    return true;
}

Вот моя предполагаемая процедура CRC (возможно, я украл ее у Стюарта Кея и libmspack , я не могу вспомнить):

static unsigned long marc_checksum(void *pv, UINT cb, unsigned long seed)
{
    int count = cb / 4;
    unsigned long csum = seed;
    BYTE *p = (BYTE*)pv;
    unsigned long ul;

    while(count-- > 0)
    {
        ul = *p++;
        ul |= (((unsigned long)(*p++)) <<  8);
        ul |= (((unsigned long)(*p++)) << 16);
        ul |= (((unsigned long)(*p++)) << 24);
        csum ^= ul;
    }

    ul = 0;
    switch(cb % 4)
    {
        case 3: ul |= (((unsigned long)(*p++)) << 16);
        case 2: ul |= (((unsigned long)(*p++)) <<  8);
        case 1: ul |= *p++;
        default: break;
    }
    csum ^= ul;

    return csum;
}                                                                                     

Ну, я думаю, что этот пост уже достаточно длинный ... Свяжитесь со мной, если вам нужна помощь или у вас есть вопросы.

0
30.12.2015 21:07:24
РЕШЕНИЕ

Похоже, некоторые порты Windows FUSE начинают появляться. Я думаю, что это было бы лучшим решением, так как оно позволило бы мне не трогать устаревший (довольно большой) код.

0
7.02.2010 23:17:52

Структурированное хранилище было разработано для сценария, который вы описываете:

Структурированное хранилище обеспечивает постоянство файлов и данных в COM, обрабатывая один файл как структурированную коллекцию объектов, известных как хранилища и потоки.

«Хранилище» аналогично папке, а «поток» аналогично файлу. По сути, у вас есть один файл, который при доступе через API-интерфейсы структурированного хранилища ведет себя и выглядит как целостная, автономная файловая система.

Обратите внимание, что:

Точное понимание технологий COM является обязательным условием для разработки структурированного хранилища.

1
8.02.2010 00:07:20
Это было бы отличной идеей, если бы у меня не было такого большого количества унаследованного кода. Я быстро посмотрел на API, и похоже, что вы должны использовать определенные COM-интерфейсы (IStream) для чтения содержимого «файлов» в вашем хранилище. Поэтому нет способа использовать существующий код с этим решением.
Vincent Robert 8.02.2010 11:33:16