winapi - mac - windows error code
¿Qué causa que CreateDirectory devuelva ERROR_ACCESS_DENIED? (2)
En otra pregunta , establecimos que sí, CreateDirectory
ocasionalmente falla con el valor GetLastError
no GetLastError
de ERROR_ACCESS_DENIED
, y que la forma correcta de manejar la situación es, probablemente, volver a intentarlo varias veces. Es fácil implementar dicho algoritmo, pero no es tan fácil probarlo cuando no se sabe cómo reproducirlo.
No necesito teorías sobre por qué sucede esto. Puede ser un error en Windows, sí. También podría ser por diseño. En última instancia, en este punto, no importa, porque Microsoft envió el comportamiento, y debo hacer frente.
Tampoco necesito una explicación de la teoría del sistema operativo multitarea y cómo Windows lo implementa en general. Escribo software de sistema para ganarme la vida. Entiendo poco más.
Lo que necesito ahora es una forma confiable de reproducir el error para que pueda escribir un caso de prueba para el código que lo resuelve. Esto es lo que he intentado hasta ahora:
- Escribí el programa de prueba P1, que enumera lenta y repetidamente el contenido del padre potencial. Además, escribí el programa de prueba P2, que no hace más que intentar reiteradamente eliminar y crear un directorio en el padre potencial. Pensé que mantener una enumeración abierta por mucho tiempo podría hacer que el problema fuera más probable. Ejecutar P2 solo produce un período ocasional de fallas (del orden de cada varios minutos durante aproximadamente 10 milisegundos). Ejecutar P1 y P2 al mismo tiempo no parece hacer que las fallas sean más frecuentes o largas.
- Ejecuté dos instancias de P2 al mismo tiempo, y eso no parece hacer que las fallas sean más frecuentes o largas.
- Modifiqué P2 para que pueda crear archivos además de directorios, y ejecutar eso al mismo tiempo que P1 no parece hacer que las fallas sean más frecuentes o más largas.
- Ejecuté P1 y varias instancias de P2 con diferentes parámetros, todo al mismo tiempo, y eso no parece hacer que las fallas sean más frecuentes o más largas.
- Escribí el programa de prueba P3, que mueve los elementos dentro y fuera del padre potencial y ejecutó P3 al mismo tiempo que P2, y eso no parece hacer que las fallas sean más frecuentes o más largas.
¿Alguna otra idea?
Permítanme comenzar comprobando dos veces que entiendo la pregunta. Si ejecuta algo como el siguiente fragmento, espera que falle eventualmente, ¿no?
while (true)
{
System.IO.Directory.CreateDirectory( ".//FooDir" );
System.IO.Directory.Delete( ".//FooDir" );
}
Si su aplicación es la única que se ejecuta en el sistema que tiene un asa abierta para ese archivo, entonces se siente como un error. Entonces, conocer la versión del sistema operativo ayudaría.
Por otro lado, si hay algo más en el sistema que mantiene el controlador abierto por un tiempo, entonces si se trata de un error o no se vuelve un poco más borroso. La cantidad de cosas que intente compilar ciegamente archivos y directorios puede sorprenderlo. Un indexador ingenuo, por ejemplo, podría entrar en ese directorio, enumerarlo, buscar archivos para indexar, etc., y si choca con él, blammo. Un filtro antivirus igualmente ingenuo, o algún otro filtro de sistema de archivos, podría estar metiéndolo también (en este caso, todavía se siente como un error).
Hay pequeñas cosas que hemos hecho en el sistema operativo para tratar de ofrecer servicios de este tipo para salir de su camino. ¿Reproduce si apaga el indexador, si apaga algún antivirus, algún anti-malware? Podemos partir de allí, y con suerte encontraremos que los bits más nuevos ya lo han arreglado (esa afirmación tenía muchas suposiciones, lo sé).
Otro dato interesante es que ERROR_ACCESS_DENIED es un error de Win32 mapeado a partir de más de un estado subyacente en el sistema (ver este artículo, por ejemplo). Entonces, si podemos profundizar un poco más, podremos descubrir qué es lo que el sistema de archivos intenta decirle a la aplicación (si es algo más que acceso denegado).
Podríamos terminar entablando una conversación sobre si puedes, en la naturaleza, asumir que tu aplicación es lo único que hurga en tus archivos y directorios. Probablemente puedas adivinar dónde irá ese.
Apostaría a suponer que su enumeración / eliminación / creación está causando algunos problemas de sincronización con los identificadores. Si CreateDirectory es algo así como CreateFile (y supongo que la lógica detrás de él sería compartida), entonces vería un comportamiento similar a CreateFile:
Si llama a CreateFile en un archivo que está pendiente de eliminación como resultado de una llamada previa a DeleteFile, la función falla. El sistema operativo demora la eliminación de archivos hasta que se cierren todos los identificadores del archivo. GetLastError devuelve ERROR_ACCESS_DENIED.