Archivos Mensuales: agosto 2014

El extraño caso del archivo de dibujo que se duplicaba al comprimir

Un usuario de Digi3D.NET se puso en contacto conmigo porque al comprimir un archivo se le duplican las entidades.

En realidad lo que me quería decir (lo averigüé tras conectarme a su ordenador con TeamViewer) es que se le duplicaba el archivo de dibujo físicamente, se multiplicaba por dos. No que se le duplicaban las entidades en memoria, pero si cerraba el archivo y lo volvía a abrir, efectivamente sí que estaban las entidades duplicadas. Inmediatamente vino a mi cabeza la palabra Karspersky y le pregunté qué antivirus tenía. Efectivamente, el antivirus era Karspersky.

Le dije que deshabilitara unos días el antivirus porque me imaginaba que sería el culpable. Ese antivirus siempre ha molestado a Ortobatch y estaba convencido de que este era el culpable de que se duplicara el archivo. Obviamente cuando sueltas una respuesta como esta el usuario piensa que estás equivocado, pero no es así. Le expliqué lo siguiente:

Cuando ordenas a Digi3D.NET que comprima, éste realiza las siguientes tareas:

  1. Elimina de la memoria principal las entidades marcadas como borradas.
  2. Le ordena al importador/exportador que elimine físicamente del archivo de dibujo las entidades marcadas como borradas.

En el caso de ser un archivo de dibujo de Geomedia por ejemplo, el importador ordena a la base de datos que elimine los registros correspondientes. Aquí el gestor de bases de datos es el responsable de eliminar.

En el caso de ser un archivo de dibujo en con extensiones .bind o .bin se realizan los siguientes pasos y en este orden:

  1. Se cierra el archivo de dibujo.
  2. Se elimina el archivo de dibujo.
  3. Se crea un nuevo archivo de dibujo donde se almacenan las entidades no eliminadas.

El problema es que el antivirus no permitía que Digi3D.NET eliminara el archivo, porque al descubrir que Digi3D.NET lo había cerrado, lo abría para analizarlo antes de que Digi3D.NET ordenase que se elimine, haciendo que el archivo en realidad no se eliminase. En el siguiente punto, el exportador abre el archivo para escritura, pero como ya existía no se truncaba. Cuando el exportador almacenaba las entidades no eliminadas, lo hacía al final del archivo, de modo que efectivamente estas se duplicaban.

Si el problema era este, había que solucionarlo en Digi3D.NET haciendo que no fuera tan confiado a la hora de eliminar el archivo y ordenándole comprobar que el archivo ha sido eliminado en vez de confiar en que éste se ha eliminado.

Para comprobar que efectivamente era el antivirus, así que instalé éste en una máquina virtual y ejecuté el siguiente programa

while(true) {
        CFile is;
        if( !is.Open(_T("c:\\prueba.bin"), CFile::modeCreate | CFile::modeWrite) ) {
            _tprintf(_T("Error al crear el archivo"));
            return 1;
        }

        TCHAR* cadena = new TCHAR[256];
        is.Write(cadena, 256);
        delete[] cadena;

        is.Close();
        if( -1 == _tunlink(_T("c:\\prueba.bin"))) {
            _tprintf(_T("Error al eliminar el archivo"));
            return 2;
        }

        _tprintf(_T("*"));
    }

Que crea un archivo, almacena información, lo cierra y lo elimina infinitas veces.

Puedes comprobar el resultado de la prueba en el siguiente vídeo:

[youtube:http://youtu.be/Vzne7nMJMkU%5D

Como puedes comprobar, efectivamente la llamada a _tunlink devuelve -1 y porque Karspersky tiene bloqueado el archivo.

Obviamente hay que buscar una solución en Digi3D.NET que ha consistido en hacer que todas las llamadas a _tunlink estén dentro de un bucle infinito cuya manera de salir es únicamente cuando se ha podido eliminar el archivo sin ningún problema. En caso de que no se pueda eliminar el archivo, se muestra el siguiente cuadro de tareas informando al usuario del problema

TaskDialog mostrando error al comprimir (no se pudo eliminar archivo)