2011-12-25 19 views
8

¿Hay alguna forma de determinar si un archivo abierto se ha modificado con POSIX? Más específicamente, ¿cómo podría implementar is_modified() a continuación?Determine si se ha modificado un archivo abierto en C

FILE *f = fopen("myfile", "r+"); 

// do various things with f 

if (is_modified(f)) 
    foo(f); 

Para proporcionar algún contexto, estoy escribiendo un módulo en C que por cada archivo necesita almacenar su hash en una tabla. La interfaz proporciona contenedores para fopen() y fclose() y la función hash se puede hacer cuando el archivo está cerrado. Encontré varios enfoques para hacer esto, pero ninguno es tan eficiente, limpio o a prueba de errores como me gustaría:

  • Calcule el hash de cada archivo abierto para escribir.
  • fflush(f) y compruebe si la marca de tiempo ha cambiado.
  • Proporcionar envolturas alrededor fwrite(), fprintf(), etc.

¿Alguna sugerencia?

+1

Si eres el que abre el archivo, ¿por qué no simplemente hacer un seguimiento de si usted escribe en él o no? –

+0

Para abstracción. Se supone que esto es un módulo que proporciona manejadores de archivos en los que los clientes pueden operar de la forma que deseen. No me gustaría modificar partes grandes de otros códigos que operan en archivos abiertos que usan funciones de biblioteca estándar. – nccc

+0

Si desea evitar que otros procesos modifiquen sus archivos al mismo tiempo, eche un vistazo a [file locking] (http://en.wikipedia.org/wiki/File_locking). – jweyrich

Respuesta

6

http://rosettacode.org/wiki/File_modification_time#POSIX_utime.28.29

se puede comprobar la modificación más reciente en contra de la última modificación con la función stat().

+1

Esa es una solución muy simple, pero es susceptible a las condiciones de carrera. Después de obtener el tiempo de modificación, y antes de compararlo y realizar cualquier acción, el archivo podría haber sido cambiado por otro proceso/subproceso. +1 sin embargo. – jweyrich

+0

Estoy totalmente de acuerdo. Supongo que sleep() podría realizarse para esperar el tiempo mínimo. En mi opinión, esta es una solución subóptima a un problema arquitectónico como el anterior. – nmjohn

+2

Yo recomendaría usar 'fstat()' en lugar de 'stat()' porque ya tiene el descriptor de archivo disponible. –

3

Puesto que usted está repartiendo los mangos con fundas para fopen() y fclose(), puede grabar el resultado de fstat() cuando se abre el archivo y otra vez cuando se está a punto de cerrar el archivo y comparar los dos. Si algo ha cambiado, entonces tienes un cambio positivo y necesitas volver a calcular el hash. Si nada ha cambiado, puede estar moderadamente seguro de que tiene el mismo archivo que antes. Si necesita eliminar esa incertidumbre, necesitará volver a calcular el hash de todos modos, sabiendo que el archivo podría cambiarse por otro hilo u otro proceso mientras está computando el hash.

advertir que las modernas POSIX (POSIX 2008) proporciona struct stat con los miembros de tiempo:

  • struct timespec st_atim - Ultimo acceso a los datos de marca de tiempo.
  • struct timespec st_mtim - Última fecha y hora de modificación de datos.
  • struct timespec st_ctim - El último estado del archivo cambia la marca de tiempo.

Proporcionan una resolución de nanosegundos en los tiempos de modificación. Es probable que por razones de compatibilidad con versiones anteriores, hay macros como:

#define st_atime st_atim.tv_sec 
#define st_mtime st_mtim.tv_sec 
#define st_ctime st_ctim.tv_sec 

aunque AFAICS, el estándar POSIX no obliga a ello. Sin embargo, los nombres st_Xtime se han utilizado desde el comienzo del tiempo (Unix) - Versión 7 Unix desde 1978, y probablemente antes - por lo que los sistemas querrán mantener la compilación del código anterior y macros como los que proporcionan una forma moderadamente indolora de hacer asi que.

+0

Desafortunadamente, 'st_mtime' y los demás miembros no se actualizan mientras el archivo está abierto. Entonces, esta solución se reduce a algo como 'fclose(); stat(); 'también. – nccc

+0

Las actualizaciones se programan (siempre que los cambios, si los hay, sean 'fflush()' d) ... y si realmente está preocupado, puede aplicar una de las opciones de O_xSYNC al descriptor del archivo. Este programa (con los encabezados apropiados) demos; probado MacOS X 10.7.2, pero son los resultados esperados en cualquier máquina POSIX: 'int main (void) {struct stat s1, s2; nombre del char [] = "zzz"; ARCHIVO * fp; if ((fp = fopen (nombre, "w +"))! = 0) {fstat (fileno (fp), &s1); sleep (5); putc ('x', fp); fflush (fp); fstat (fileno (fp), &s2); printf ("t1% ld; t2% ld \ n", (largo) s1.st_mtime, (largo) s2.st_mtime); fclose (fp); unlink (name);} return (0);} ' –

+0

Sí, un' fflush() 'actualizará las marcas de tiempo, tal vez porque se refieren al inodo. Supongo que esto es todo lo que se puede, el kernel sabe con certeza si el archivo está sucio pero no parece de alguna manera exportar esta información. – nccc

3

también se puede utilizar el sistema de notificación kqueue para recibir notificaciones cuando alguien cambia el archivo, y luego invalidar/recargar sus entradas de hash

hombre 2 kqueue

http://blog.julipedia.org/2004/10/example-of-kqueue.html

+0

Eso es interesante, pero: a) significa que _cada_ escritura generará un evento; b) desde los bloques 'kevent()', necesito al menos dos hilos. ¿Correcto? – nccc

+0

a) sí, pero siempre puedes amortizarlo con eventos de cola para un período específico y luego enviarlos al otro hilo en grandes cantidades b) sí, necesitarás un segundo hilo para esperar los eventos – jackdoe

Cuestiones relacionadas