===== Entendiendo los timestamps de ficheros en Linux (Acceso / Modificación / Cambio / Creación)=====
Entender las diferentes marcas de tiempo de los ficheros en Linux es algo básico para su administración, ya que son usados por infinidad de comandos para poder filtrar y encontrar determinados archivos y carpetas.
stat fichero.pdf
File: `fichero.pdf'
Size: 921599 Blocks: 1800 IO Block: 4096 regular file
Device: 91a1h/37281d Inode: 2728917 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2009-04-03 21:40:42.767849143 +0200
Modify: 2009-04-03 21:40:14.665837796 +0200
Change: 2009-05-15 16:41:42.727736900 +0200
Birth: -
**Access** / **Acceso** (atime): Fecha del ultimo acceso, el cual puede ser realizado por las llamadas al sistema mknod(2), utimes(2) / utimensat(2) y read(2). Algunas distribuciones desactivan la actualización de esta información para evitar operaciones de entrada y salida (fstab: noatime,nodiratime,etc)
**Modify** / **Modificación** (mtime): Fecha de la última modificación, que pudo ser ocasionada por las llamadas sl sistema mknod(2), utimes(2) / utimensat(2) y write(2). Comandos como "stat" "ls -l" o "date -r" muestran la fecha de modificación de un fichero.
**Change** / **Cambio** (ctime): Fecha de la ultima modificación del inodo (metadatos), ocasionado por las llamada al sistema chmod(2), chown(2), link(2), mknod(2), rename(2), unlink(2), utimes(2) / utimensat(2) y write(2).
**Birth** / **Creación** (crtime): La fecha de creación de un fichero antiguamente no se podía visualizar con el comando stat (Birth: - ([[http://lists.gnu.org/archive/html/bug-findutils/2011-11/msg00015.html|leer]])), pero actualmente dependiendo de la versión del sistema sí es factible. Si se está usando un sistema antiguo puede utilizarse debugfs para obtener dicha fecha de creación, veamos un ejemplo usando LVM.
debugfs -R 'stat /home/maria/fichero' /dev/mapper/Volgroup00-lv_root
debugfs 0.92.13 (15-May-2008)
Inode: 269835 Type: regular Mode: 0644 Flags: 0x80000
Generation: 2264140096 Version: 0x00000000:00000001
User: 0 Group: 0 Size: 0
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 0
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x57225282:ad2d99c0 -- Thu Apr 28 20:12:18 2009
atime: 0x57225195:32e9e720 -- Thu Apr 28 20:08:21 2009
mtime: 0x57225282:ad2d99c0 -- Thu Apr 28 20:12:18 2009
crtime: 0x57225195:32e9e720 -- Thu Apr 28 10:01:21 2008
Size of extra inode fields: 32
EXTENTS:
Usando el inodo del fichero / directorio en vez de la ruta al fichero (Versiones antiguas de debugfs).
ls -i /home/maria/fichero
267850 /home/maria/fichero
debugfs -R 'stat <267850>' /dev/mapper/Volgroup00-lv_root
NOTA: Los timestamps de creación y cambio en Linux no pueden ser modificados a fecha de hoy.
**Uso del comando ls para ordenar y visualizar las fechas de acceso, modificación y cambios de ficheros / directorios**.
ls -ltu # Visualiza y ordena por la fecha del último acceso (atime).
ls -lt # Visualiza y ordena por fecha de la ultima modificación (mtime).
lt -ltc # Visualiza y ordena por fecha del último cambio (ctime).
# NOTA: Sin la "t", usando solo la opción "l", siempre se ordena por nombre. (-h es recomendable para leer el mejor el tamaño de los archivos con ls)
**Modificar las fechas de acceso / modificación de un fichero con touch** (man touch).
# Modifica los estados de acceso (-a), modificación (-m) por la fecha actual.
touch fichero
# NOTA: Se puede utilizar indistintamente -a, --time=atime, --time=access, --time=use
# Copiar las marcas de tiempo de otro fichero tomado como referencia.
# NOTA: Los timestamps de "creación" y "cambio" no pueden ser modificados a fecha de este artículo en sistemas GNU/Linux. Mirar el hack del siguiente apartado.
touch fichero -r fichero_referencia.txt # Se puede utilizar -a y -m si solo interesa copiar "atime" o "mtime".
# Si el archivo llamado "fichero" existe, actualiza los timestamp que tenga, en caso contrario no crea el fichero.
touch -c fichero
# Especificar una fecha en concreto (-t / -d).
touch -t 201408121510.59 fichero # 12-08-2014 a las 15:10:59
touch -d 11am fichero # 11 de la mañana de hoy.
touch -d "last fortnight" fichero # 15 días atrás.
touch -d "yesterday 6am" fichero # Ayer a las 6 de la mañana.
touch -d "380 days ago 12:00" fichero # Hace 380 días a las 12:00.
touch -d "tomorrow 02:00" fichero # Ayer a las 02:00.
touch -d "5 Nov" fichero # 5 de Noviembre de este año.
NOTA: El timestamp de "Change" (Cambio) es modificado a la vez que se cambia la fecha de último acceso o de la última modificación.
**Hack para falsear de manera aproximada la fecha de creación/Change de un fichero**
No es factible cambiar los timestamps de "Change" y "Birth" en sistemas Linux sin cambiar la fecha del sistema. El cambiar la fecha del sistema hace que se dependa de la velocidad de procesamiento ya que el comando stat nos muestra detalle de nanosegundo. Es decir, en ese nanosegundo deben realizarse todas las acciones para que no haya diferencias. Un nanosegundo es la duración de un ciclo de reloj de un microprocesador de 1 GHz.
En este ejemplo se clonarán los tres timestamps de un "fichero_referente" a otro denominado "fichero_hack", incluyendo la fecha Change.
Sin campo Birth.
# Fechas del fichero_hack y fichero referente.
File: 'fichero_hack'
Access: 2019-08-07 23:27:47.204914004 +0200
Modify: 2019-08-07 23:27:47.204914004 +0200
Change: 2019-08-07 23:28:08.819620381 +0200
Birth: -
File: 'fichero_referente'
Access: 2019-08-07 17:43:13.535171587 +0200
Modify: 2018-07-31 17:00:12.000000000 +0200
Change: 2020-08-30 08:23:20.682000046 +0200
Birth: -
# Se clonan los timestamps de acceso y modificación en la fecha exacta de "cambio" del fichero.
date --set="2020-08-30 08:23:20.682000046"; touch fichero_hack -r fichero_referente
File: 'fichero_hack'
Access: 2019-08-07 17:43:13.535171587 +0200
Modify: 2018-07-31 17:00:12.000000000 +0200
Change: 2020-08-30 08:23:20.682000046 +0200
Birth: -
File: 'fichero_referente'
Access: 2019-08-07 17:43:13.535171587 +0200
Modify: 2018-07-31 17:00:12.000000000 +0200
Change: 2020-08-30 08:23:20.682000046 +0200
Birth: -
Con el campo "Birth" visualizable habría que hacer un paso más en comparación con el anterior, es decir, crear el fichero en una fecha concreta.
# Se crea el fichero filehack mediante una copia de un fichero en la fecha de creación del fichero_referente.
# Si el campo Birth del fichero referencia es 2012-03-30 08:23:20.622000046:
date --set="2012-03-30 08:23:20.622000046"; cp file file_hack
# Con eso actualmente file_hack ya tendrá dicha fecha de creación. Ahora simplemente se debe proceder como en el caso anterior para cambiar "Access", "Modify" y "Change".
Si se quiere volver rápidamente al tiempo del sistema "actual", podemos guardar en una variable el tiempo justo antes de ejecutar los comandos y posteriormente establecer de nuevo la hora. En realidad la acción dura fracciones de segundo, por lo que prácticamente será inapreciable (Eso no deja de tener su posible reflejo en logs de journal, por ejemplo el cambio horario activa una limpieza de la cache de systemd-resolved).
actual=$(date +"%Y-%m-%d %H:%M:%S.%9N") date --set="2012-03-30 08:23:20.622000046"; cp file file_hack; date --set="$actual"
Algunos logs generados por el cambio de hora del sistema.
systemd-resolved[39295]: Clock change detected. Flushing caches.
systemd[1]: Starting Discard unused blocks on filesystems from /etc/fstab...
systemd[1]: Starting Rotate log files...
systemd[1]: Starting Daily man-db regeneration...
systemd[1]: Started Verify integrity of password and group files.
systemd[1]: shadow.service: Deactivated successfully.
systemd[1]: logrotate.service: Deactivated successfully.
systemd[1]: Finished Rotate log files.
systemd[1]: man-db.service: Deactivated successfully.
audit: BPF prog-id=0 op=UNLOAD
systemd[1]: Finished Daily man-db regeneration.
audit: BPF prog-id=0 op=UNLOAD
kernel: audit: type=1334 audit(1660253972.419:515): prog-id=0 op=UNLOAD
kernel: audit: type=1334 audit(1660253972.419:516): prog-id=0 op=UNLOAD
fstrim[39947]: /: 154 GiB (165362356224 bytes) recortados en /dev/sda1
systemd[1]: fstrim.service: Deactivated successfully.
systemd[1]: Finished Discard unused blocks on filesystems from /etc/fstab.
NOTA: Recordar que depende de la capacidad de procesamiento pueden encontrarse diferencias en los nanosegundos. Si se opera varias veces el mismo comando y siempre se obtiene la misma diferencia de tiempo con el fichero referencia, se puede hacer una simple resta para ir unos nanosegundos más al pasado e intentar compensar.
Al utilizar el comando date para cambiar la fecha, por debajo se hace una llamada al sistema del tipo "CLOCK_REALTIME". Esta systemcall no es compatible con el "time namespace" y por lo tanto, aunque se use un espacio de nombres de tiempo (unshare -T) con la intención de no impactar sobre todo el sistema operativo, no funcionará. Cuando se usa unshare con la opción -T, las únicas llamadas al sistema que tendrían efecto en el nuevo espacio de nombres serían CLOCK_MONOTONIC/BOOTTIME.