Каталог Windows Explorer в виде пакета - PullRequest
3 голосов
/ 12 декабря 2008

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

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

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

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

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

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

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

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

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

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

Ответы [ 10 ]

1 голос
/ 08 февраля 2010

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

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

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

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

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

1 голос
/ 12 декабря 2008

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

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

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

1 голос
/ 12 декабря 2008

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

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

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

1 голос
/ 12 декабря 2008

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

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

0 голосов
/ 08 февраля 2010

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

0 голосов
/ 16 декабря 2008

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Формат MARC (Microsoft MSN Archive) выложен (приблизительно) следующим образом:

  • 12-байтовый заголовок (только один)
    • Файл 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 голосов
/ 12 декабря 2008

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

0 голосов
/ 12 декабря 2008

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

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

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

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

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

0 голосов
/ 12 декабря 2008

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

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

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

0 голосов
/ 12 декабря 2008

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

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

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

...