Pergunta

Eu têm vindo a investigar há já algum tempo uma maneira de evitar que o meu usuário de entrar acidentalmente um diretório de dados da minha aplicação.

Meu aplicativo usa uma pasta para armazenar um projeto estruturado. A estrutura interna da pasta é crítico e não deve ser confuso. Gostaria que o meu usuário para ver esta pasta como um todo e não ser capaz de abri-lo (como um pacote Mac).

Existe uma maneira de fazer isso no Windows?

Editar a partir de respostas atuais

É claro que eu não estou tentando impedir que meus usuários acessem seus dados, apenas protegendo-os de destruir acidentalmente a integridade dos dados. criptografia para proteção de senha ou não são necessários.

Obrigado a todos por suas respostas NET, mas, infelizmente, este é principalmente um projeto C ++ sem qualquer dependência para o framework .Net.

Os dados que eu estou mencionando não são leves, eles são adquiridas imagens de um microscópio eletrônico. Estes dados podem ser enorme (~ 100 MiB para ~ 1 GiB) para o carregamento tudo na memória não é uma opção. Estas são imagens enormes modo que o armazenamento deve fornecer uma maneira para ler os dados de forma incremental, acessando um arquivo de cada vez sem carregar o arquivo inteiro na memória.

Além disso, a aplicação é principalmente legado com alguns componentes que não são ainda responsáveis ??de. Uma solução que me permite manter o código IO atual é preferível.

Shell Extension parece interessante, eu vou investigar mais a solução.

LarryF, você pode elaborar sobre driver de filtro ou DefineDosDevice? Eu não estou familiarizado com estes conceitos.

Foi útil?

Solução 9

Parece um Windows do FUSE estão começando a aparecer. Eu acho que esta seria a melhor solução, uma vez que me permita manter o código legado (que é bastante grande) intocado.

Outras dicas

Existem algumas coisas que você pode fazer:

Uma coisa é que você pode criar um FolderView do Windows Shell Extension que iria criar uma exibição personalizada para a pasta crítica. Ao criar um costume FolderView você poderia tornar a pasta apenas em branco com uma linha de texto "Nada para ver aqui", ou você poderia fazer algo mais complicação como o espectador GAC que utiliza este mesmo método. Este método seria bastante complexo, mas essa complexidade pode ser atenuado pelo uso de algo como este CodeProject biblioteca de artigo como base.

Outra solução seria fazer ZIP Virtual Filesystem, isso exigiria que você substitua qualquer código que usa System.IO diretamente para usar outra coisa. ASP.NET 2.0 fez isso por esta razão exata e você poderia construir ontop de que muito facilmente, dê uma olhada nesta MSDN artigo na implementação de um VirtualPathProvider.

Estruturado armazenamento foi projetado para o cenário que você descreve:

estruturado armazenamento fornece arquivo e persistência de dados em COM por manipulação de um único arquivo como um conjunto estruturado de objetos conhecidos como estoques e fluxos.

A "armazenamento" é análogo a uma pasta, e um "stream" é análogo a um arquivo. Basicamente, você tem um único arquivo que, quando acessado usando os estruturado armazenamento APIs, se comporta e se parece com um sistema de arquivos completo, auto-suficiente.

Tome nota, porém, que:

Uma sólida compreensão das tecnologias COM é pré-requisito para o uso do desenvolvimento de armazenamento estruturado.

Dentro ou fora do seu programa?

Existem maneiras, mas nenhum deles fácil. Você provavelmente vai estar a olhar para um driver de filtro no sistema de arquivos.

Se você tomar o aproach arquivo ZIP, (que eu considerada por você, mas não mencionou), sugiro usar o algoritmo deflate, mas usar o seu próprio sistema de arquivos ... Olhe para algo como o formato TAR. Em seguida, basta escrever o código para passar todos os I / O passado os algoritmos Inflate / Deflate como eles são gravados no disco. Eu não usaria o ZIP "Format", como é olhar demasiado fácil para o arquivo, encontrar o PK como os dois primeiros bytes, e descompacte o arquivo ....

Eu como sugestões de Joshperry melhor.

É claro, você também pode escrever um driver de dispositivo que armazena todos os dados dentro de um único arquivo, mas, novamente, nós estamos olhando para um motorista. (Não tenho certeza de que você poderia implementá-lo fora de um motorista .. Você provavelmente pode, e dentro de sua DefineDosDevice chamada do programa, dando-lhe um nome que apenas o seu código tem acesso a, e ele vai ser visto como um sistema de arquivos normal. ). Eu vou jogar com algumas idéias, e se eles funcionam, eu vou atirar em você um exemplo. Agora você me interessou.

Você poderia envolver o diretório do projeto em um arquivo .zip e armazene seus dados lá, muito parecido com um .jar é usado (eu sei um .jar é praticamente apenas de leitura, é por causa do exemplo). Faça uma extensão não-padrão para que um duplo-clique tem nenhum efeito imediato, feito. ; -)

É claro que isso significa que você teria de envolver todo o seu arquivo IO usar o .zip em vez disso, dependendo de como o programa é construído este poderia ser tedioso. Tem sido feito para Java: TrueZip . Talvez você possa usar isso como uma inspiração?

Se você tem sido tentado -. Eu não recomendo mexer com permissões de pasta, por razões óbvias isto não vai ajudar

Você pode usar o armazenamento isolado.

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

Ele não resolve todos os problemas, mas não colocar dados de aplicativos bem fora do caminho do mal.

Lembre-se: se você armazená-lo no sistema de arquivos, o usuário sempre será capaz de vê-lo. Mexer com explorador e eu uso cmd.exe vez. Ou Total Commander. Ou qualquer outra coisa.

Se você não quer que as pessoas para mexer com seus arquivos, eu recomendo

  • criptografando-os para evitar adulteração dos arquivos
  • colocá-los em um arquivo (ZIP ou seja), possivelmente por senha protegê-la, e em seguida comprimir / descomprimir em tempo de execução (i iria olhar para cima algoritmos que são rápidos a modificar arquivos)

Isso não é uma protecção completa, é claro, mas é bastante simples e direta de implementar, não requer a instalação de material funky dentro do sistema operacional e deve manter-se longe utilizadores mais curiosos.

Claro, você nunca vai ser capaz de controlar totalmente arquivos em um computador usuários sem controlar o computador em si.

software

Eu vi (Visual Paradigm Agilian) que usou sugestão de um arquivo zip do Tomalak como o 'arquivo de projeto'. Arquivos zip são bem compreendidos, e o uso de uma extensão de arquivo não-padrão impede o usuário casual de mexer com o 'arquivo'. Uma grande vantagem disso é que em caso de corrupção, ferramentas padrão pode ser usado para corrigir o problema, e você não precisa se preocupar em criar ferramentas especiais para apoiar a sua aplicação principal.

Eu estou contente de ouvir que você está fazendo isso em C ++. Parece que ninguém vê C ++ como "necessário" mais. É tudo C # isso, e ASP.NET que ... Mesmo trabalho eu em um C # casa tudo, quando eu jurei que faria não switch, como C ++ faz tudo o que eu já tinha precisa fazer e, em seguida, alguns. Estou bastante adulto para limpar a minha própria memória! heh .. De qualquer forma, de volta para o assunto em questão ...

O DefineDOSDevice() é um método que você usa para letras de unidade ceder, nomes de portas (LPT1, COM1, etc). Você passa-lhe um nome, algumas bandeiras e um "caminho" que lida com este dispositivo. Mas, não se deixe enganar. Não é um arquivo do caminho de sistema, é um caminho de objeto NT. Eu estou certo que você viu-los como "\ Device \ HardDisk0", etc. Você pode usar Winobj.exe da Sysinternals para ver o que quero dizer. De qualquer forma, você pode criar um driver de dispositivo, e em seguida, apontar um MSDOS link simbólico para ele, e você está fora e correndo. Mas certo que parece ser um monte de trabalho para que o problema original é.

Como muitos destes meg a arquivos gigabytes estão em um diretório típico? Você pode ser melhor fora apenas furando todos os arquivos dentro de um arquivo gigante, e armazenar um arquivo de índice bem próximo a ela, (ou um cabeçalho para cada arquivo) que aponta para a próxima "Arquivo" dentro do seu arquivo "sistema de arquivos virtual".

Um bom exemplo pode ser a olhar para o formato Microsoft MSN Archive. I revertida este formato de arquivo quando eu estava trabalhando para uma companhia de AV, e é realmente muito criativo, mas muito simples. Isso pode ser feito tudo em um arquivo, e se você quiser começar a fantasia, você PODERIA armazenar os dados por 3 arquivos em uma configuração do tipo RAID 5, por isso, se qualquer um dos 3 arquivos fica metralhado, você poderia reconstruir os outros. Além disso, os usuários só iria ver 3 muito grandes arquivos em um diretório, e não seria capaz de acessar os arquivos individuais (internos).

Eu tenho desde que com o código que descompacta um desses formatos MSN Arquivo. Eu não tenho código que cria um, mas a partir da fonte extrato, você seria capaz de construir / uma gravação sem nenhum problema. Se os arquivos são apagados, e / ou renomeado, muitas vezes, isso pode representar um problema com o espaço utilizado no arquivo que teria que ser cortado de vez em quando.

Este formato suporta até mesmo campos de CRC, assim você pode testar se você tem o arquivo para fora OK. Eu nunca foi capaz de reverter completamente o algoritmo que Microsoft usado para CRC dos dados, mas eu tenho uma boa idéia bastante.

Você não seria capaz de manter rotinas de E / S atuais, ou seja, CreateFile () não seria apenas capaz de abrir qualquer arquivo no arquivo, no entanto, com o uber-frieza de C ++, você poderia substituir o CreateFile chamar para implementar o seu formato de arquivo.

Se você quer alguma ajuda com a sua, e é um problema grande o suficiente, talvez pudéssemos falar off-line e encontrar uma solução para você.

Eu não me oponho a escrever-lhe uma FileSystemDriver, mas para isso, teríamos que começar a falar sobre remuneração. Eu ficaria mais que feliz em dar-lhe direção e idéias para livre, assim como eu estou fazendo agora.

Eu não tenho certeza se é kosher para mim para dar-lhe o meu endereço de e-mail aqui, eu não tenho certeza sobre as políticas do assim por diante isso, já que poderíamos estar falando de potencial de trabalho / solicitação, mas isso não é a minha única intenção . Eu prefiro ajudar a encontrar suas próprias soluções em primeiro lugar.

Antes de olhar para um driver de dispositivo, baixar o WinDDK. Tem amostras motorista tudo sobre ele.

Se você quer saber porque eu me importo muito sobre isso, é porque eu tive na minha ardósia por anos para escrever um driver semelhante a este, que tinha que ser o Windows e OSX compatível, que permitiria que os usuários para garantir os volumes da unidade (chaves USB, volumes removíveis) sem instalar qualquer driver ou complicado (e volumosos, às vezes irritante) software. Nos últimos anos, muitos dos fabricantes de hardware têm feito coisas semelhantes, mas eu não acho que a segurança é tudo o que seguro. Eu estou olhando para usar RSA e AES, exatamente da mesma maneira GPG, e trabalhar PGP. Originalmente I foi contactado sobre-lo para o que (eu acredito, mas não tenho nenhuma prova) ia ser usado para arquivos MP3 seguras. Desde que eles sejam armazenados em formato criptografado, eles simplesmente não funcionaria sem a senha correta. Mas, eu vi outros usos para ele também. (Isso foi quando um 16 meg (sim MEG) custo Key USB em excesso de $ 100 ou mais).

Este projeto também foi junto com meu sistema de segurança PC indústria de petróleo e gás que algo usado semelhante ao Smart Cards, apenas muito mais fácil utilização, reutilização / re-edição, impossível (leia-se: muito difícil e improvável) para cortar, e eu poderia usá-lo em meus próprios filhos em casa! (Uma vez que não está sempre lutando sobre quem fica com o tempo no computador, e quem tem a maioria, e, e, e, e ...)

Ufa .. Eu acho que eu tenho maneira fora de tópico aqui. De qualquer forma, aqui está um exemplo do formato de arquivo Microsoft MSN. Veja se você pode ser capaz de usar algo como isto, sabendo que você pode sempre "Skip" direito de um arquivo seguindo os deslocamentos no arquivo como você analisar / procurar o arquivo solicitado no arquivo mestre; ou nos dados pré-analisado retido na memória. E desde que você não estaria carregando os dados de arquivos binários na memória, o seu único limite seria provavelmente o limite de arquivo de 4GB em máquinas de 32 bits.

O formato MARC (Microsoft MSN Archive) é colocado para fora (vagamente) como este:

  • 12 Byte Header (apenas um)
    • Mágica Arquivo
    • versão MARC
    • O número de arquivos (na tabela a seguir)
  • 68 Byte cabeçalhos de tabela de ficheiros (1 a Header.NumFiles destes)
    • O nome do arquivo
    • Tamanho do Arquivo
    • checksum
    • compensados ??com os dados do arquivo raw

Agora, as entradas de tabela de arquivo de 12 bytes, 32 bits são usados ??para comprimentos de arquivo e deslocamentos. Para seus arquivos muito grandes, você pode ter que se que a 48 ou 64 bit inteiros.

Aqui está um código que escrevi para lidar com estes.

#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;
};

Isso lhe dá uma idéia dos cabeçalhos que escrevi para eles, e aqui é a função de abertura. Sim, está faltando todas as chamadas de suporte, rotinas err, etc, mas você começa a idéia. Por favor, desculpe o C e mistura de estilo de código C ++. Nosso scanner era um aglomerado de muitos problemas diferentes como este ... Eu usei as chamadas antigos como open (), fopen (), para manter padrões com o resto da base de código.

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;
}

Então, você tem o método extrato simples. Tenha em mente este foi estritamente para a verificação de vírus, portanto, não há rotinas de pesquisa, etc. Isto foi projetado para simplesmente despejar um arquivo, digitalizá-lo e segui em frente. Abaixo disso é o código de rotina CRC que eu acredito que Microsoft usado, mas não tenho certeza O exatamente eles CRC'ed. Pode incluir dados arquivo de dados + cabeçalho, etc. Eu só não se importava o suficiente para voltar e tentar revertê-la. De qualquer forma, como você pode ver, não há compressão sobre este formato de arquivo, mas é muito fácil de adicionar. fonte completo pode ser fornecido, se quiser. (Eu acho que tudo o que resta é a close () de rotina, e o código que chama e extratos cada arquivo, etc. !!)

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;
}

Aqui está o meu assumiu rotina CRC (I pode ter roubou isto de Stuart Caie e libmspack , não me lembro):

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;
}                                                                                     

Bem, eu acho que este post é longo o suficiente agora ... Contacte-me se você precisar de ajuda, ou tem dúvidas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top