Formato de archivo FSEvents: páginas 1SLD, 2SLD y 3SLD
Estructura en disco de los logs .fseventsd de macOS: archivos gzip, cabeceras de página DLS, campos por versión y cómo tratar datos truncados o dañados.
En resumen. Cada log de .fseventsd es un archivo gzip. Una vez descomprimido, es una secuencia de páginas; cada página empieza con una cabecera de 12 bytes (1SLD, 2SLD o 3SLD, cuatro bytes desconocidos y un tamaño de página en little-endian) seguida de registros: una ruta terminada en NUL y 12, 20 o 24 bytes de campos fijos. Esta estructura coincide con lo que implementan FSEventsParser (Nicole Ibrahim, Apache-2.0) y mac_apt (ydkhatri, MIT); Apple no la documenta.
La carpeta
.fseventsd/
0000000012a44181 gzip log file; name = an event ID in hex
0000000012a4439d
fseventsd-uuid text: the stream UUID
no_log optional, empty: logging disabled
Los nombres de los logs tienen 16 dígitos hexadecimales. FSEventsParser interpreta el nombre como el último event ID del archivo; el FSEvents Parser de este sitio contrasta el nombre con los IDs que contiene y marca los archivos cuyo nombre queda fuera de su propio rango (archivos renombrados o fuera de lugar).
Capa gzip
Cada log es un flujo gzip convencional (RFC 1952). Algunos archivos contienen más de un miembro gzip, y las copias de un log que aún se estaba escribiendo terminan antes de tiempo. Un lector robusto:
- descomprime un miembro tras otro;
- conserva todos los bytes que haya podido descomprimir cuando el flujo está cortado o dañado, en lugar de rechazar el archivo;
- comprueba el CRC-32 y el tamaño del trailer, e informa de cualquier discrepancia sin descartar datos;
- acepta datos ya descomprimidos por otra herramienta (empiezan directamente con un magic de página).
Cabecera de página
| Offset | Tamaño | Campo |
|---|---|---|
| 0 | 4 | Magic, almacenado como los bytes ASCII 1SLD, 2SLD o 3SLD |
| 4 | 4 | Desconocido |
| 8 | 4 | Tamaño de página, u32 little-endian, contado desde el inicio de la cabecera |
Las páginas se suceden hasta el final de los datos descomprimidos. Algunos artículos las llaman "DLS1/DLS2" porque eso es lo que se lee al interpretar el magic como entero little-endian; los bytes en disco son 1SLD. Consulta página DLS.
Registros
Tras la cabecera, los registros se empaquetan uno detrás de otro hasta alcanzar el tamaño de página:
| Campo | 1SLD | 2SLD | 3SLD |
|---|---|---|---|
| Ruta, UTF-8, terminada en NUL | sí | sí | sí |
| Event ID, u64 LE | +0 | +0 | +0 |
| Flags, u32 LE | +8 | +8 | +8 |
| Node ID, u64 LE | +12 | +12 | |
| Extra, 4 bytes | +20 | ||
| Parte fija tras la ruta | 12 bytes | 20 bytes | 24 bytes |
- 2SLD apareció con macOS 10.13 High Sierra y 3SLD con macOS 14 Sonoma (según las notas de implementación de FSEventsParser). Un volumen que ha pasado por varias actualizaciones puede contener varias versiones.
- La ruta es relativa a la raíz del volumen, tal como era en el momento del registro:
Users/dana/Library/LaunchAgents/com.example.updater.plist, no/System/Volumes/Data/Users/…. Pueden aparecer rutas vacías. - FSEventsParser decodifica el campo adicional de 3SLD como un ID de usuario de 32 bits con signo (
fs_uid), mientras que mac_apt lo deja sin nombre. Apple no lo ha documentado; trata cualquier interpretación como una hipótesis y compruébala con datos conocidos. - Los flags se explican en la referencia de flags.
Análisis defensivo
Las adquisiciones reales contienen logs truncados, recuperados mediante carving o dañados. Estas son las reglas que sigue el parser de este sitio:
- Una página cuyo tamaño declarado sobrepasa los datos disponibles se analiza hasta el final de los datos, y se informa de ello.
- Un registro cuya ruta no tiene NUL, o cuyos campos fijos no caben, se descarta y se informa; los registros anteriores se conservan.
- Los bytes a cero tras el último registro o página son slack, no un error.
- Los bytes que no son un magic de página se omiten hasta el siguiente
1SLD/2SLD/3SLD, y se informa del número de bytes omitidos. - Los registros con combinaciones de flags imposibles (File y Folder a la vez, Symlink y Hard link a la vez) se contabilizan como indicio de daño, igual que hace FSEventsParser con los datos recuperados mediante carving.
- Las rutas que no son UTF-8 válido se muestran con caracteres de sustitución y se contabilizan.
Marcas de tiempo
El formato no incluye ninguna. Cómo fechar los registros a partir de las fechas de modificación de los archivos de log se explica en datación de registros FSEvents.
Preguntas frecuentes
¿Qué diferencia hay entre 1SLD, 2SLD y 3SLD?
El tamaño del registro. Los registros 1SLD contienen una ruta, un event ID de 8 bytes y flags de 4 bytes; 2SLD añade un node ID de 8 bytes (macOS 10.13 y posteriores); 3SLD añade 4 bytes más (macOS 14 y posteriores).
¿Los logs de FSEvents están en little-endian?
Sí. El tamaño de página, el event ID, los flags, el node ID y el campo adicional se almacenan en little-endian. Algunas herramientas leen los flags en big-endian y usan constantes con los bytes invertidos, lo que da los mismos nombres.