Pregunta

He estado investigando desde hace algún tiempo una forma de evitar que mi usuario ingrese accidentalmente a un directorio de datos de mi aplicación.

Mi aplicación usa una carpeta para almacenar un proyecto estructurado.La estructura interna de la carpeta es crítica y no debe estropearse.Me gustaría que mi usuario vea esta carpeta como un todo y no pueda abrirla (como un paquete de Mac).

¿Hay alguna manera de hacer eso en Windows?

Editar de las respuestas actuales

Por supuesto, no estoy tratando de impedir que mis usuarios accedan a sus datos, solo los protejo para que no destruyan accidentalmente la integridad de los datos.Por lo tanto, no se necesita cifrado ni protección con contraseña.

Gracias a todos por sus respuestas .Net, pero desafortunadamente, este es principalmente un proyecto C++ sin ninguna dependencia del marco .Net.

Los datos que menciono no son luminosos, son imágenes adquiridas de un microscopio electrónico.Estos datos pueden ser enormes (~100 MiB a ~1 GiB), por lo que cargar todo en la memoria no es una opción.Se trata de imágenes enormes, por lo que el almacenamiento debe proporcionar una forma de leer los datos de forma incremental accediendo a un archivo a la vez sin cargar todo el archivo en la memoria.

Además, la aplicación es principalmente heredada con algunos componentes de los que ni siquiera somos responsables.Es preferible una solución que me permita mantener el código IO actual.

Shell Extension parece interesante, investigaré más a fondo la solución.

LarryF, ¿puedes darnos más detalles sobre Filter Driver o DefineDOSDevice?No estoy familiarizado con estos conceptos.

¿Fue útil?

Solución 9

Parece que algunos puertos de Windows del FUSIBLE están empezando a aparecer. Creo que esta sería la mejor solución ya que permitiría que siga el código heredado (que es bastante grande) sin tocar.

Otros consejos

Hay un par de cosas que usted puede hacer:

Una cosa es que se puede crear una extensión de shell de Windows FolderView que crearía una vista personalizada para su carpeta crítico. Mediante la creación de un FolderView personalizada que podría hacer que la carpeta sólo blanco en blanco con una línea de texto "No hay nada que ver aquí", o se podría hacer algo más complicaciones como el visor de GAC que utiliza este mismo método. Este método sería bastante complejo, pero esta complejidad puede ser mitigado mediante el uso de algo así como este CodeProject biblioteca del artículo como base.

Otra solución sería hacer postal del sistema de archivos virtual, esto requiere que se reemplace cualquier código que utiliza System.IO directamente a usar otra cosa. ASP.NET 2.0 hizo esto por esta razón exacta y le podría construir sábana de que con bastante facilidad, echar un vistazo a este MSDN artículo en la implementación de un VirtualPathProvider.

de almacenamiento estructurado fue diseñado para el escenario que usted describe:

  

almacenamiento estructurado proporciona archivo y datos de persistencia en COM por el manejo de un solo archivo como una colección estructurada de objetos conocidos como almacenes y arroyos.

A "almacenamiento" es análogo a una carpeta, y una "corriente" es análogo a un archivo. Básicamente, usted tiene un solo archivo que, cuando se accede mediante las API de almacenamiento estructurado, se comporta y se parece a un sistema de archivos completo, autónomo.

Tome nota, sin embargo, que:

  

Una comprensión sólida de las tecnologías COM es un requisito previo para el uso en el desarrollo de almacenamiento estructurado.

En el interior o exterior de su programa?

Hay maneras, pero ninguno de ellos fácil. Usted está probablemente va a estar mirando a un controlador de filtro del sistema de archivos.

Si se toma el aproach archivo ZIP, (que yo consideraba para usted, pero no menciono) se recomienda usar el algoritmo deflate, pero el uso de su propio sistema de archivos ... Mira algo así como el formato TAR. A continuación, acaba de escribir el código para pasar todas las E / S más allá del inflado / desinflado algoritmos a medida que se escriben en el disco. Yo no usaría la postal "formato", ya que es demasiado fácil ver el archivo, busque la PK ya que los dos primeros bytes, y descomprimir el archivo ....

Me gustan las sugerencias de Joshperry mejor.

Por supuesto, también se puede escribir un controlador de dispositivo que almacena todos sus datos en un solo archivo, pero de nuevo, que está buscando en un conductor. (No estoy seguro de que podría implementar fuera de un conductor .. Es probable que pueda, y dentro de su DefineDosDevice llamada del programa, lo que le da un nombre que sólo el código tiene acceso a, y se verá como un sistema de archivos normal. ). Voy a jugar con algunas ideas, y si funcionan, te disparo una muestra. Ahora usted me interesa.

Se puede envolver el directorio del proyecto en un archivo .zip y almacenar sus datos de allí, al igual que se utiliza un .jar (Conozco a un .jar es más o menos de sólo lectura, es por el bien del ejemplo). Hacer una extensión no estándar, de modo que un doble clic no tiene efecto inmediato, hecho. ; -)

Por supuesto, esto significa que tendría para envolver todo su archivo IO utilizar el .zip en su lugar, dependiendo de cómo su programa se basa esto podría ser tedioso. Se ha hecho ya para Java: TrueZIP . Tal vez se puede usar eso como una inspiración?

Si usted ha tenido la tentación -. Yo no recomendaría jugando con permisos de carpeta, por razones obvias, esto no va a ayudar

Se puede usar el almacenamiento aislado.

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

No resuelve todos los problemas, pero sí pone datos de aplicaciones bien fuera de peligro.

Tenga en cuenta: si lo guarda en el sistema de archivos, el usuario siempre será capaz de verlo. Tamper con el explorador y yo uso cmd.exe en su lugar. O Total Commander. O cualquier otra cosa.

Si no quieres que la gente a meterse con sus archivos, me gustaría recomendar

  • encriptación de ellos para evitar la manipulación de los archivos
  • ponerlos en un archivo (es decir, postal), posiblemente proteger con contraseña, y luego comprimir / descomprimir en tiempo de ejecución (i levantaba la vista algoritmos que son rápidos en la modificación de archivos)

Eso no es completa protección por supuesto, pero es bastante recta hacia adelante para implementar, no requiere que instale materia enrrollada en el interior del sistema operativo y deben mantener la distancia usuarios más curiosos.

Por supuesto, usted nunca será capaz de controlar totalmente los archivos en un ordenador del usuario sin controlar el propio ordenador.

He visto software (Agilian de Visual Paradigm) que utilizaba la sugerencia de Tomalak de un archivo zip como 'archivo de proyecto'.Los archivos zip se entienden bien y el uso de una extensión de archivo no estándar evita que el usuario ocasional juegue con el "archivo".Una gran ventaja de esto es que, en caso de corrupción, se pueden usar herramientas estándar para solucionar el problema y no tiene que preocuparse por crear herramientas especiales para respaldar su aplicación principal.

Me alegra saber que está haciendo esto en C ++. Parece que nadie ve C ++ como "necesario" más. Es todo esto C # y ASP.NET que ... Incluso yo trabajo en una casa de toda C #, cuando juré que no interruptor, como C ++ hace todo lo que jamás había que hacer y luego algunos. Estoy suficiente para limpiar mi propia memoria para adultos! je .. De todas formas, volviendo al tema que nos ocupa ...

El DefineDOSDevice() es un método que se utiliza para asignar letras de unidad, los nombres de puerto (LPT1, COM1, etc). Se le pasa un nombre, algunas banderas y un "camino" que se encarga de este dispositivo. Pero, no dejes que te engañe. No es una vía de sistema, que es una ruta de objeto NT. Estoy seguro de que los ha visto como "\ Device \ HardDisk0", etc Usted puede utilizar WinObj.exe de Sysinternals para ver a qué me refiero. De todas formas, se puede crear un controlador de dispositivo, a continuación, seleccione un enlace simbólico MSDOS a ella, y que está fuera de funcionamiento. Pero sentado que parece como un montón de trabajo por lo que el problema original es.

¿Cuántos de estos meg a gigabyte archivos se encuentran en un directorio típico? Usted puede ser el mejor fuera simplemente pegando todos los archivos dentro de un archivo gigante, y almacenar un archivo de índice al lado de ella, (o un encabezado de cada archivo) que apunta a la siguiente "Archivo" dentro de su archivo "sistema de ficheros virtual".

Un buen ejemplo podría ser la de mirar el formato de Microsoft MSN Archivo. Invertí este formato de archivo cuando estaba trabajando para una compañía de AV, y es realmente muy creativo, pero muy simple. Se puede hacer todo en un solo archivo, y si usted desea conseguir la suposición, que PODÍA almacenar los datos a través de 3 archivos en una configuración de tipo de RAID 5, por lo que si cualquiera de los 3 archivos consigue lavar con manguera, se pudo reconstruir los demás. Además, los usuarios podrían ver sólo 3 muy archivos de gran tamaño en un directorio, y no sería capaz de acceder a los archivos individuales (internos).

Te he proporcionado con el código que descomprime uno de estos formatos de MSN Archive. No tengo código que crea una, pero a partir de la fuente de extracción, que sería capaz de construir / escribir uno sin ningún problema. Si se eliminan los archivos y / o cambiar de nombre a menudo, eso podría ser un problema con el espacio utilizado en el archivo que tendría que ser recortado de vez en cuando.

Este formato admite incluso CRC, por lo que puede probar si tiene el archivo de salir bien. Nunca fue capaz de revertir por completo el algoritmo que utiliza Microsoft al CRC de los datos, pero tengo una idea bastante buena.

Usted no sería capaz de mantener las rutinas actuales de E / S, lo que significa CreateFile () no sólo sería capaz de abrir cualquier archivo en el archivo, sin embargo, con la súper-frescor de C ++, se puede anular el CreateFile llamar a aplicar el formato de archivo.

Si quieres un poco de ayuda con la suya, y es un tema lo suficientemente grande, tal vez podríamos hablar fuera de línea y encontrar una solución para usted.

No estoy en lugar de escribir que un FileSystemDriver, pero para eso, tendríamos que empezar a hablar de una compensación. Yo estaría más que feliz de darle dirección y las ideas de forma gratuita, así como yo estoy haciendo ahora.

No estoy seguro si es kosher para que le dé mi dirección de correo electrónico aquí, no estoy seguro acerca de las políticas de SO en esto, ya que podríamos estar hablando de potencial de trabajo / solicitación, pero ese no es mi única intención . Prefiero ayudaré a encontrar sus propias soluciones en primer lugar.

Antes de buscar en un controlador de dispositivo, descargue el WinDDK. Tiene muestras de controladores por todas partes.

Si usted se pregunta por qué me preocupo tanto por esto, es porque he tenido en mi pizarra durante años para escribir un controlador similar a este, que tuvo que ser Windows y OSX compatible, que permitiría a los usuarios fijar los volúmenes de disco (llaves USB, volúmenes extraíbles) sin necesidad de instalar ningún controlador, o complicada (y voluminosos, a veces molesto) de software. En los últimos años, muchos de los fabricantes de hardware han hecho cosas similares, pero no creo que la seguridad es tan seguro. Estoy buscando en el uso de RSA y AES, exactamente de la misma manera GPG, y el trabajo de PGP. Originalmente fui contactado en ello por lo que (Icreer, pero no tienen ninguna prueba) iba a ser utilizado para asegurar los archivos MP3. Desde que se habían pueden almacenar en formato cifrado, simplemente no funcionaría sin la contraseña correcta. Sin embargo, vi otros usos para él también. (Esto fue cuando un costo clave 16 meg (sí MEG) USB en exceso de $ 100 o más).

Este proyecto también fue junto con mi sistema de seguridad de la PC de la industria de petróleo y gas que utiliza algo similar a las tarjetas inteligentes, simplemente mucho más fácil de usar, reutilizar / reedición, imposible (léase: muy difícil, y es poco probable) a Hack, y pude usarlo en mis propios hijos en casa! (Dado que no siempre es pelear sobre quién obtiene tiempo en el equipo, y que recibieron la mayor parte, y sigue, y sigue, y sigue, y ...)

Uf .. Creo que tengo manera fuera de tema aquí. De todas formas, aquí es un ejemplo del formato de archivo de Microsoft MSN. Vea si usted puede ser capaz de usar algo como esto, sabiendo que siempre se puede "Skip" derecho a un archivo siguiendo los desplazamientos en el archivo como lo analizo / búsqueda para el archivo solicitado en el archivo maestro; o en los datos pre-analizada celebrada en la memoria. Y puesto que no sería la carga de los datos de los archivos binarios sin formato en la memoria, su único límite sería probablemente el límite de archivo de 4 GB en equipos de 32 bits.

El formato MARC (Microsoft MSN Archivo) se presenta (sin apretar) como esto:

  • 12 byte de cabecera (sólo uno)
    • Magic File
    • versión MARC
    • El número de archivos (en la tabla siguiente)
  • encabezados de tabla
  • 68 Byte File (1 a Header.NumFiles de éstos)
    • Nombre de archivo
    • Tamaño del archivo
    • Checksum
    • compensar a los datos del archivo RAW

Ahora, en las entradas de la tabla de archivos de 12 bytes, 32 bits se utilizan para longitudes de archivos, y las compensaciones. Para sus archivos muy grandes, puede que tenga que hasta que a 48 o de 64 bits enteros.

Aquí hay un código que escribí para manejar estos.

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

Eso te da una idea de las cabeceras que escribí para ellos, y aquí es la función abierta. Sí, le faltan todas las llamadas de soporte, errar rutinas, etc, pero se entiende la idea. Por favor, disculpe la C y la mezcla de estilo de código C ++. Nuestro escáner era un grupo de muchos problemas diferentes, como esto ... utiliza las llamadas antiguas como open (), fopen (), para mantener los estándares con el resto de la 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;
}

A continuación, usted tiene el método simple extracto. Tenga en cuenta que esto era estrictamente para detección de virus, así que no hay rutinas de búsqueda, etc. Esto fue diseñado para simplemente volcar un archivo, escanearlo, y siguió adelante. Debajo de eso es la rutina de código CRC que creo que Microsoft ha utilizado, pero no estoy seguro de ¿QUÉ es exactamente lo que CRC'ed. Podría incluir datos de cabecera + datos de archivos, etc. simplemente no han preocupado lo suficiente como para volver y tratar de revertirla. De todos modos, como se puede ver, no hay compresión en este formato de archivo, pero es muy fácil de añadir. El código fuente completo se puede proporcionar si lo desea. (Creo que todo lo que queda es la estrecha () de rutina, y el código que llama y extrae cada archivo, 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;
}

Aquí está mi rutina CRC asumido (que puede haber robó esto desde Stuart Caie y libmspack , no puedo recordar):

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

Bueno, creo que este post es el tiempo suficiente ahora ... en contacto conmigo si necesita ayuda o tiene preguntas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top