http://linux-ntfs.sourceforge.net/snapshots/ntfsprogs-200307311516.tar.bz2
[ntfsprogs.git] / include / logfile.h
1 /*
2  * logfile.h - Exports for $LogFile handling. Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2000-2002 Anton Altaparmakov
5  *
6  * This program/include file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program/include file is distributed in the hope that it will be
12  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program (in the main directory of the Linux-NTFS
18  * distribution in the file COPYING); if not, write to the Free Software
19  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #ifndef _NTFS_LOGFILE_H
23 #define _NTFS_LOGFILE_H
24
25 #include "types.h"
26
27 typedef enum {
28         magic_RSTR = const_cpu_to_le32(0x52545352), /* "RSTR", restart area */
29         magic_RCRD = const_cpu_to_le32(0x44524352), /* "RCRD", log record */
30 } LOG_FILE_RECORD_TYPES;
31
32 /*
33  * Specialised magic comparison macros.
34  */
35 #define ntfs_is_rstr_record(x)          ( ntfs_is_magic (x, RSTR) )
36 #define ntfs_is_rstr_recordp(p)         ( ntfs_is_magicp(p, RSTR) )
37 #define ntfs_is_rcrd_record(x)          ( ntfs_is_magic (x, RCRD) )
38 #define ntfs_is_rcrd_recordp(p)         ( ntfs_is_magicp(p, RCRD) )
39
40 /*
41  * Log file organization:
42  *      Two restart areas present in the first two pages (restart pages). When
43  * the volume is unmounted they should be identical.
44  *      These are followed by log records organized in pages headed by a record
45  * header going up to log file size. Not all pages contain log records when a
46  * volume is first formatted, but as the volume ages, all records will be used.
47  * When the log file fills up, the records at the beginning are purged (by
48  * modifying the oldest_lsn to a higher value presumably) and writing begins
49  * at the beginning of the file. Effectively, the log file is viewed as a
50  * circular entity.
51  */
52
53 /*
54  * Log file restart page header (begins the restart area).
55  */
56 typedef struct {
57         NTFS_RECORD;            /* The magic is "RSTR". */
58         u64 chkdsk_lsn;         /* The check disk log file sequence number for
59                                    this restart page. Only used when the
60                                    magic is changed to "CHKD". = 0 */
61         u32 system_page_size;   /* Byte size of system pages, has to be >= 512
62                                    and a power of 2. Use this to calculate the
63                                    required size of the usa and add this to the
64                                    ntfs.usa_offset value. Then verify that the
65                                    result is less than the value of the
66                                    restart_offset. = 0x1000 */
67         u32 log_page_size;      /* Byte size of log file records, has to be
68                                    >= 512 and a power of 2. = 0x1000 */
69         u16 restart_offset;     /* Byte offset from the start of the record to
70                                    the restart record. Value has to be aligned
71                                    to 8-byte boundary. = 0x30 */
72         s16 minor_ver;          /* Log file minor version. Only check if major
73                                    version is 1. (=1 but >=1 is treated the
74                                    same and <=0 is also ok) */
75         u16 major_ver;          /* Log file major version (=1 but =0 is ok) */
76 } __attribute__ ((__packed__)) RESTART_PAGE_HEADER;
77
78 /*
79  * Log file restart area record. The offset of this record is found by adding
80  * the offset of the RESTART_PAGE_HEADER to the restart_offset value found in
81  * it.
82  */
83 typedef struct {
84         u64 current_lsn;        /* Log file record. = 0x700000, 0x700808 */
85         u16 log_clients;        /* Number of log client records following
86                                    the restart_area. = 1 */
87         s16 client_free_list;   /* How many clients are free(?). If != 0xffff,
88                                    check that log_clients > client_free_list.
89                                    = 0xffff */
90         s16 client_in_use_list;/* How many clients are in use(?). If != 0xffff
91                                    check that log_clients > client_in_use_list.
92                                    = 0 */
93         u16 flags;              /* ??? = 0 */
94         u32 seq_number_bits;    /* ??? = 0x2c or 0x2d */
95         u16 restart_area_length;/* Length of the restart area. Following
96                                    checks required if version matches.
97                                    Otherwise, skip them. restart_offset +
98                                    restart_area_length has to be <=
99                                    system_page_size. Also, restart_area_length
100                                    has to be >= client_array_offset +
101                                    (log_clients * 0xa0). = 0xd0 */
102         u16 client_array_offset;/* Offset from the start of this record to
103                                    the first client record if versions are
104                                    matched. The offset is otherwise assumed to
105                                    be (sizeof(RESTART_AREA) + 7) & ~7, i.e.
106                                    rounded up to first 8-byte boundary. Either
107                                    way, the offset to the client array has to be
108                                    aligned to an 8-byte boundary. Also,
109                                    restart_offset + offset to the client array
110                                    have to be <= 510. Also, the offset to the
111                                    client array + (log_clients * 0xa0) have to
112                                    be <= SystemPageSize. = 0x30 */
113         u64 file_size;          /* Byte size of the log file. If the
114                                    restart_offset + the offset of the file_size
115                                    are > 510 then corruption has occured. This
116                                    is the very first check when starting with
117                                    the restart_area as if it fails it means
118                                    that some of the above values will be
119                                    corrupted by the multi sector transfer
120                                    protection! If the structure is deprotected
121                                    then these checks are futile of course.
122                                    Calculate the file_size bits and check that
123                                    seq_number_bits == 0x43 - file_size bits.
124                                    = 0x400000 */
125         u32 last_lsn_data_length;/* ??? = 0, 0x40 */
126         u16 record_length;      /* Byte size of this record. If the version
127                                    matches then check that the value of
128                                    record_length is a multiple of 8, i.e.
129                                    (record_length + 7) & ~7 == record_length.
130                                    = 0x30 */
131         u16 log_page_data_offset;/* ??? = 0x40 */
132         /*
133          * There are eight bytes here at offset 0x58, which contain a value,
134          * which we don't know what it means. It looks like it could be a
135          * 64-bit number or a 32-bit plus something else (the second 32-bits
136          * are zero so can't tell). Have to try to zero it and see if Windows
137          * copes with this.
138          */
139 } __attribute__ ((__packed__)) RESTART_AREA;
140
141 /*
142  * Log file restart client. The offset of this record is found by adding
143  * the offset of the RESTART_AREA to the client_array_offset value found in it.
144  */
145 typedef struct {
146         u64 oldest_lsn;         /* Oldest log file sequence number for this
147                                    client record. */
148         u64 client_restart_lsn; /* Log file sequence number at which to
149                                     restart the volume, i.e. the current
150                                     position within the logfile. */
151         s16 prev_client;        /* ??? = 0xffff */
152         s16 next_client;        /* ??? = 0xffff */
153         u64 seq_number;         /* ??? = 1, size uncertain, Regis calls this
154                                    "volume clear flag" and gives a size of one
155                                    byte. */
156         u32 client_name_length; /* ??? length of client name in bytes. = 8,
157                                      size uncertain, offset uncertain */
158         uchar_t client_name[0]; /* ??? Name of the client in unicode. = NTFS */
159         /*
160          * Or it could be the client name is fixed size like in attr def struct
161          * and the 8 means something else. Favouring this is that the
162          * RESTART_CLIENT struct is assumed to be fixed size of 0xa0 bytes,
163          * just like the attr def struct! There might be parallels to be drawn
164          * between the two.
165          */
166 } __attribute__ ((__packed__)) RESTART_CLIENT;
167
168 /*
169  * Log page record page header. Each log page begins with this header and is
170  * followed by several LOG_RECORD structures, starting at offset 0x40 (the
171  * size of this structure and the following update sequence array and then
172  * aligned to 8 byte boundary, but is this specified anywhere?).
173  */
174 typedef struct {
175         NTFS_RECORD;                    /* The magic is "RCRD". */
176         union {
177                 u64 last_lsn;
178                 u32 file_offset;
179         } __attribute__ ((__packed__)) copy;
180         u32 flags;
181         u16 page_count;
182         u16 page_position;
183         union {
184                 struct {
185                         u64 next_record_offset;
186                         u64 last_end_lsn;
187                 } __attribute__ ((__packed__)) packed;
188         } __attribute__ ((__packed__)) header;
189 } __attribute__ ((__packed__)) RECORD_PAGE_HEADER;
190
191 /*
192  * Possible flags for log records.
193  */
194 typedef enum {
195         LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001),      /* ??? */
196         LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
197                 /* This has nothing to do with the log record. It is only so
198                    gcc knows to make the flags 16-bit. */
199 } __attribute__ ((__packed__)) LOG_RECORD_FLAGS;
200
201 /*
202  * Log record header. Each log record seems to have a constant size of 0x70
203  * bytes.
204  */
205 typedef struct {
206         u64 this_lsn;
207         u64 client_previous_lsn;
208         u64 client_undo_next_lsn;
209         u32 client_data_length;
210         struct {
211                 u16 seq_number;
212                 u16 client_index;
213         } __attribute__ ((__packed__)) client_id;
214         u32 record_type;
215         u32 transaction_id;
216         LOG_RECORD_FLAGS flags;
217         u16 reserved_or_alignment[3];
218 /* Now are at ofs 0x30 into struct. */
219         u16 redo_operation;
220         u16 undo_operation;
221         u16 redo_offset;
222         u16 redo_length;
223         u16 undo_offset;
224         u16 undo_length;
225         u16 target_attribute;
226         u16 lcns_to_follow;                /* Number of lcn_list entries
227                                               following this entry. */
228 /* Now at ofs 0x40. */
229         u16 record_offset;
230         u16 attribute_offset;
231         u32 alignment_or_reserved;
232         s64 target_vcn;
233 /* Now at ofs 0x50. */
234         struct {                           /* Only present if lcns_to_follow
235                                               is not 0. */
236                 s64 lcn;
237         } __attribute__((__packed__)) lcn_list[0];
238 } __attribute__ ((__packed__)) LOG_RECORD;
239
240 #endif /* defined _NTFS_LOGFILE_H */
241