1 |
1275 |
phoenix |
/*
|
2 |
|
|
* inode.c
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1995-1999 Martin von Löwis
|
5 |
|
|
* Copyright (C) 1996 Albert D. Cahalan
|
6 |
|
|
* Copyright (C) 1996-1997 Régis Duchesne
|
7 |
|
|
* Copyright (C) 1998 Joseph Malicki
|
8 |
|
|
* Copyright (C) 1999 Steve Dodd
|
9 |
|
|
* Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
|
10 |
|
|
*/
|
11 |
|
|
#include "ntfstypes.h"
|
12 |
|
|
#include "ntfsendian.h"
|
13 |
|
|
#include "struct.h"
|
14 |
|
|
#include "inode.h"
|
15 |
|
|
#include <linux/errno.h>
|
16 |
|
|
#include "macros.h"
|
17 |
|
|
#include "attr.h"
|
18 |
|
|
#include "super.h"
|
19 |
|
|
#include "dir.h"
|
20 |
|
|
#include "support.h"
|
21 |
|
|
#include "util.h"
|
22 |
|
|
#include <linux/ntfs_fs.h>
|
23 |
|
|
#include <linux/smp_lock.h>
|
24 |
|
|
|
25 |
|
|
typedef struct {
|
26 |
|
|
int recno;
|
27 |
|
|
unsigned char *record;
|
28 |
|
|
} ntfs_mft_record;
|
29 |
|
|
|
30 |
|
|
typedef struct {
|
31 |
|
|
int size;
|
32 |
|
|
int count;
|
33 |
|
|
ntfs_mft_record *records;
|
34 |
|
|
} ntfs_disk_inode;
|
35 |
|
|
|
36 |
|
|
static void ntfs_fill_mft_header(ntfs_u8 *mft, int rec_size, int seq_no,
|
37 |
|
|
int links, int flags)
|
38 |
|
|
{
|
39 |
|
|
int fixup_ofs = 0x2a;
|
40 |
|
|
int fixup_cnt = rec_size / NTFS_SECTOR_SIZE + 1;
|
41 |
|
|
int attr_ofs = (fixup_ofs + 2 * fixup_cnt + 7) & ~7;
|
42 |
|
|
|
43 |
|
|
NTFS_PUTU32(mft + 0x00, 0x454c4946); /* FILE */
|
44 |
|
|
NTFS_PUTU16(mft + 0x04, fixup_ofs); /* Offset to fixup. */
|
45 |
|
|
NTFS_PUTU16(mft + 0x06, fixup_cnt); /* Number of fixups. */
|
46 |
|
|
NTFS_PUTU64(mft + 0x08, 0); /* Logical sequence number. */
|
47 |
|
|
NTFS_PUTU16(mft + 0x10, seq_no); /* Sequence number. */
|
48 |
|
|
NTFS_PUTU16(mft + 0x12, links); /* Hard link count. */
|
49 |
|
|
NTFS_PUTU16(mft + 0x14, attr_ofs); /* Offset to attributes. */
|
50 |
|
|
NTFS_PUTU16(mft + 0x16, flags); /* Flags: 1 = In use,
|
51 |
|
|
2 = Directory. */
|
52 |
|
|
NTFS_PUTU32(mft + 0x18, attr_ofs + 8); /* Bytes in use. */
|
53 |
|
|
NTFS_PUTU32(mft + 0x1c, rec_size); /* Total allocated size. */
|
54 |
|
|
NTFS_PUTU64(mft + 0x20, 0); /* Base mft record. */
|
55 |
|
|
NTFS_PUTU16(mft + 0x28, 0); /* Next attr instance. */
|
56 |
|
|
NTFS_PUTU16(mft + fixup_ofs, 1); /* Fixup word. */
|
57 |
|
|
NTFS_PUTU32(mft + attr_ofs, (__u32)-1); /* End of attributes marker. */
|
58 |
|
|
}
|
59 |
|
|
|
60 |
|
|
/*
|
61 |
|
|
* Search in an inode an attribute by type and name.
|
62 |
|
|
* FIXME: Check that when attributes are inserted all attribute list
|
63 |
|
|
* attributes are expanded otherwise need to modify this function to deal
|
64 |
|
|
* with attribute lists. (AIA)
|
65 |
|
|
*/
|
66 |
|
|
ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name)
|
67 |
|
|
{
|
68 |
|
|
int i;
|
69 |
|
|
|
70 |
|
|
if (!ino) {
|
71 |
|
|
ntfs_error("ntfs_find_attr: NO INODE!\n");
|
72 |
|
|
return 0;
|
73 |
|
|
}
|
74 |
|
|
for (i = 0; i < ino->attr_count; i++) {
|
75 |
|
|
if (type < ino->attrs[i].type)
|
76 |
|
|
return 0;
|
77 |
|
|
if (type == ino->attrs[i].type) {
|
78 |
|
|
if (!name) {
|
79 |
|
|
if (!ino->attrs[i].name)
|
80 |
|
|
return ino->attrs + i;
|
81 |
|
|
} else if (ino->attrs[i].name &&
|
82 |
|
|
!ntfs_ua_strncmp(ino->attrs[i].name, name,
|
83 |
|
|
strlen(name)))
|
84 |
|
|
return ino->attrs + i;
|
85 |
|
|
}
|
86 |
|
|
}
|
87 |
|
|
return 0;
|
88 |
|
|
}
|
89 |
|
|
|
90 |
|
|
/*
|
91 |
|
|
* Insert all attributes from the record mftno of the MFT in the inode ino.
|
92 |
|
|
* If mftno is a base mft record we abort as soon as we find the attribute
|
93 |
|
|
* list, but only on the first pass. We will get called later when the attribute
|
94 |
|
|
* list attribute is being parsed so we need to distinguish the two cases.
|
95 |
|
|
* FIXME: We should be performing structural consistency checks. (AIA)
|
96 |
|
|
* Return 0 on success or -errno on error.
|
97 |
|
|
*/
|
98 |
|
|
static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno)
|
99 |
|
|
{
|
100 |
|
|
int i, error, type, len, present = 0;
|
101 |
|
|
char *it;
|
102 |
|
|
|
103 |
|
|
/* Check for duplicate extension record. */
|
104 |
|
|
for(i = 0; i < ino->record_count; i++)
|
105 |
|
|
if (ino->records[i] == mftno) {
|
106 |
|
|
if (i)
|
107 |
|
|
return 0;
|
108 |
|
|
present = 1;
|
109 |
|
|
break;
|
110 |
|
|
}
|
111 |
|
|
if (!present) {
|
112 |
|
|
/* (re-)allocate space if necessary. */
|
113 |
|
|
if (ino->record_count % 8 == 0) {
|
114 |
|
|
int *new;
|
115 |
|
|
|
116 |
|
|
new = ntfs_malloc((ino->record_count + 8) *
|
117 |
|
|
sizeof(int));
|
118 |
|
|
if (!new)
|
119 |
|
|
return -ENOMEM;
|
120 |
|
|
if (ino->records) {
|
121 |
|
|
for (i = 0; i < ino->record_count; i++)
|
122 |
|
|
new[i] = ino->records[i];
|
123 |
|
|
ntfs_free(ino->records);
|
124 |
|
|
}
|
125 |
|
|
ino->records = new;
|
126 |
|
|
}
|
127 |
|
|
ino->records[ino->record_count] = mftno;
|
128 |
|
|
ino->record_count++;
|
129 |
|
|
}
|
130 |
|
|
it = mft + NTFS_GETU16(mft + 0x14); /* mft->attrs_offset */
|
131 |
|
|
do {
|
132 |
|
|
type = NTFS_GETU32(it);
|
133 |
|
|
len = NTFS_GETU32(it + 4);
|
134 |
|
|
if (type != -1) {
|
135 |
|
|
error = ntfs_insert_attribute(ino, it);
|
136 |
|
|
if (error)
|
137 |
|
|
return error;
|
138 |
|
|
}
|
139 |
|
|
/* If we have just processed the attribute list and this is
|
140 |
|
|
* the first time we are parsing this (base) mft record then we
|
141 |
|
|
* are done so that the attribute list gets parsed before the
|
142 |
|
|
* entries in the base mft record. Otherwise we run into
|
143 |
|
|
* problems with encountering attributes out of order and when
|
144 |
|
|
* this happens with different attribute extents we die. )-:
|
145 |
|
|
* This way we are ok as the attribute list is always sorted
|
146 |
|
|
* fully and correctly. (-: */
|
147 |
|
|
if (type == 0x20 && !present)
|
148 |
|
|
return 0;
|
149 |
|
|
it += len;
|
150 |
|
|
} while (type != -1); /* Attribute listing ends with type -1. */
|
151 |
|
|
return 0;
|
152 |
|
|
}
|
153 |
|
|
|
154 |
|
|
/*
|
155 |
|
|
* Insert a single specific attribute from the record mftno of the MFT in the
|
156 |
|
|
* inode ino. We disregard the attribute list assuming we have already parsed
|
157 |
|
|
* it.
|
158 |
|
|
* FIXME: We should be performing structural consistency checks. (AIA)
|
159 |
|
|
* Return 0 on success or -errno on error.
|
160 |
|
|
*/
|
161 |
|
|
static int ntfs_insert_mft_attribute(ntfs_inode* ino, int mftno,
|
162 |
|
|
ntfs_u8 *attr)
|
163 |
|
|
{
|
164 |
|
|
int i, error, present = 0;
|
165 |
|
|
|
166 |
|
|
/* Check for duplicate extension record. */
|
167 |
|
|
for(i = 0; i < ino->record_count; i++)
|
168 |
|
|
if (ino->records[i] == mftno) {
|
169 |
|
|
present = 1;
|
170 |
|
|
break;
|
171 |
|
|
}
|
172 |
|
|
if (!present) {
|
173 |
|
|
/* (re-)allocate space if necessary. */
|
174 |
|
|
if (ino->record_count % 8 == 0) {
|
175 |
|
|
int *new;
|
176 |
|
|
|
177 |
|
|
new = ntfs_malloc((ino->record_count + 8) *
|
178 |
|
|
sizeof(int));
|
179 |
|
|
if (!new)
|
180 |
|
|
return -ENOMEM;
|
181 |
|
|
if (ino->records) {
|
182 |
|
|
for (i = 0; i < ino->record_count; i++)
|
183 |
|
|
new[i] = ino->records[i];
|
184 |
|
|
ntfs_free(ino->records);
|
185 |
|
|
}
|
186 |
|
|
ino->records = new;
|
187 |
|
|
}
|
188 |
|
|
ino->records[ino->record_count] = mftno;
|
189 |
|
|
ino->record_count++;
|
190 |
|
|
}
|
191 |
|
|
if (NTFS_GETU32(attr) == -1) {
|
192 |
|
|
ntfs_debug(DEBUG_FILE3, "ntfs_insert_mft_attribute: attribute "
|
193 |
|
|
"type is -1.\n");
|
194 |
|
|
return 0;
|
195 |
|
|
}
|
196 |
|
|
error = ntfs_insert_attribute(ino, attr);
|
197 |
|
|
if (error)
|
198 |
|
|
return error;
|
199 |
|
|
return 0;
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
/* Read and insert all the attributes of an 'attribute list' attribute.
|
203 |
|
|
* Return the number of remaining bytes in *plen. */
|
204 |
|
|
static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen)
|
205 |
|
|
{
|
206 |
|
|
ntfs_u8 *mft, *attr;
|
207 |
|
|
int mftno, l, error;
|
208 |
|
|
int last_mft = -1;
|
209 |
|
|
int len = *plen;
|
210 |
|
|
int tries = 0;
|
211 |
|
|
|
212 |
|
|
if (!ino->attr) {
|
213 |
|
|
ntfs_error("parse_attributes: called on inode 0x%x without a "
|
214 |
|
|
"loaded base mft record.\n", ino->i_number);
|
215 |
|
|
return -EINVAL;
|
216 |
|
|
}
|
217 |
|
|
mft = ntfs_malloc(ino->vol->mft_record_size);
|
218 |
|
|
if (!mft)
|
219 |
|
|
return -ENOMEM;
|
220 |
|
|
while (len > 8) {
|
221 |
|
|
l = NTFS_GETU16(alist + 4);
|
222 |
|
|
if (l > len)
|
223 |
|
|
break;
|
224 |
|
|
/* Process an attribute description. */
|
225 |
|
|
mftno = NTFS_GETU32(alist + 0x10);
|
226 |
|
|
/* FIXME: The mft reference (alist + 0x10) is __s64.
|
227 |
|
|
* - Not a problem unless we encounter a huge partition.
|
228 |
|
|
* - Should be consistency checking the sequence numbers
|
229 |
|
|
* though! This should maybe happen in
|
230 |
|
|
* ntfs_read_mft_record() itself and a hotfix could
|
231 |
|
|
* then occur there or the user notified to run
|
232 |
|
|
* ntfsck. (AIA) */
|
233 |
|
|
if (mftno != ino->i_number && mftno != last_mft) {
|
234 |
|
|
continue_after_loading_mft_data:
|
235 |
|
|
last_mft = mftno;
|
236 |
|
|
error = ntfs_read_mft_record(ino->vol, mftno, mft);
|
237 |
|
|
if (error) {
|
238 |
|
|
if (error == -EINVAL && !tries)
|
239 |
|
|
goto force_load_mft_data;
|
240 |
|
|
failed_reading_mft_data:
|
241 |
|
|
ntfs_debug(DEBUG_FILE3, "parse_attributes: "
|
242 |
|
|
"ntfs_read_mft_record(mftno = 0x%x) "
|
243 |
|
|
"failed\n", mftno);
|
244 |
|
|
ntfs_free(mft);
|
245 |
|
|
return error;
|
246 |
|
|
}
|
247 |
|
|
}
|
248 |
|
|
attr = ntfs_find_attr_in_mft_rec(
|
249 |
|
|
ino->vol, /* ntfs volume */
|
250 |
|
|
mftno == ino->i_number ?/* mft record is: */
|
251 |
|
|
ino->attr: /* base record */
|
252 |
|
|
mft, /* extension record */
|
253 |
|
|
NTFS_GETU32(alist + 0), /* type */
|
254 |
|
|
(wchar_t*)(alist + alist[7]), /* name */
|
255 |
|
|
alist[6], /* name length */
|
256 |
|
|
1, /* ignore case */
|
257 |
|
|
NTFS_GETU16(alist + 24) /* instance number */
|
258 |
|
|
);
|
259 |
|
|
if (!attr) {
|
260 |
|
|
ntfs_error("parse_attributes: mft records 0x%x and/or "
|
261 |
|
|
"0x%x corrupt!\n", ino->i_number, mftno);
|
262 |
|
|
ntfs_free(mft);
|
263 |
|
|
return -EINVAL; /* FIXME: Better error code? (AIA) */
|
264 |
|
|
}
|
265 |
|
|
error = ntfs_insert_mft_attribute(ino, mftno, attr);
|
266 |
|
|
if (error) {
|
267 |
|
|
ntfs_debug(DEBUG_FILE3, "parse_attributes: "
|
268 |
|
|
"ntfs_insert_mft_attribute(mftno 0x%x, "
|
269 |
|
|
"attribute type 0x%x) failed\n", mftno,
|
270 |
|
|
NTFS_GETU32(alist + 0));
|
271 |
|
|
ntfs_free(mft);
|
272 |
|
|
return error;
|
273 |
|
|
}
|
274 |
|
|
len -= l;
|
275 |
|
|
alist += l;
|
276 |
|
|
}
|
277 |
|
|
ntfs_free(mft);
|
278 |
|
|
*plen = len;
|
279 |
|
|
return 0;
|
280 |
|
|
force_load_mft_data:
|
281 |
|
|
{
|
282 |
|
|
ntfs_u8 *mft2, *attr2;
|
283 |
|
|
int mftno2;
|
284 |
|
|
int last_mft2 = last_mft;
|
285 |
|
|
int len2 = len;
|
286 |
|
|
int error2;
|
287 |
|
|
int found2 = 0;
|
288 |
|
|
ntfs_u8 *alist2 = alist;
|
289 |
|
|
/*
|
290 |
|
|
* We only get here if $DATA wasn't found in $MFT which only happens
|
291 |
|
|
* on volume mount when $MFT has an attribute list and there are
|
292 |
|
|
* attributes before $DATA which are inside extent mft records. So
|
293 |
|
|
* we just skip forward to the $DATA attribute and read that. Then we
|
294 |
|
|
* restart which is safe as an attribute will not be inserted twice.
|
295 |
|
|
*
|
296 |
|
|
* This still will not fix the case where the attribute list is non-
|
297 |
|
|
* resident, larger than 1024 bytes, and the $DATA attribute list entry
|
298 |
|
|
* is not in the first 1024 bytes. FIXME: This should be implemented
|
299 |
|
|
* somehow! Perhaps by passing special error code up to
|
300 |
|
|
* ntfs_load_attributes() so it keeps going trying to get to $DATA
|
301 |
|
|
* regardless. Then it would have to restart just like we do here.
|
302 |
|
|
*/
|
303 |
|
|
mft2 = ntfs_malloc(ino->vol->mft_record_size);
|
304 |
|
|
if (!mft2) {
|
305 |
|
|
ntfs_free(mft);
|
306 |
|
|
return -ENOMEM;
|
307 |
|
|
}
|
308 |
|
|
ntfs_memcpy(mft2, mft, ino->vol->mft_record_size);
|
309 |
|
|
while (len2 > 8) {
|
310 |
|
|
l = NTFS_GETU16(alist2 + 4);
|
311 |
|
|
if (l > len2)
|
312 |
|
|
break;
|
313 |
|
|
if (NTFS_GETU32(alist2 + 0x0) < ino->vol->at_data) {
|
314 |
|
|
len2 -= l;
|
315 |
|
|
alist2 += l;
|
316 |
|
|
continue;
|
317 |
|
|
}
|
318 |
|
|
if (NTFS_GETU32(alist2 + 0x0) > ino->vol->at_data) {
|
319 |
|
|
if (found2)
|
320 |
|
|
break;
|
321 |
|
|
/* Uh-oh! It really isn't there! */
|
322 |
|
|
ntfs_error("Either the $MFT is corrupt or, equally "
|
323 |
|
|
"likely, the $MFT is too complex for "
|
324 |
|
|
"the current driver to handle. Please "
|
325 |
|
|
"email the ntfs maintainer that you "
|
326 |
|
|
"saw this message. Thank you.\n");
|
327 |
|
|
goto failed_reading_mft_data;
|
328 |
|
|
}
|
329 |
|
|
/* Process attribute description. */
|
330 |
|
|
mftno2 = NTFS_GETU32(alist2 + 0x10);
|
331 |
|
|
if (mftno2 != ino->i_number && mftno2 != last_mft2) {
|
332 |
|
|
last_mft2 = mftno2;
|
333 |
|
|
error2 = ntfs_read_mft_record(ino->vol, mftno2, mft2);
|
334 |
|
|
if (error2) {
|
335 |
|
|
ntfs_debug(DEBUG_FILE3, "parse_attributes: "
|
336 |
|
|
"ntfs_read_mft_record(mftno2 = 0x%x) "
|
337 |
|
|
"failed\n", mftno2);
|
338 |
|
|
ntfs_free(mft2);
|
339 |
|
|
goto failed_reading_mft_data;
|
340 |
|
|
}
|
341 |
|
|
}
|
342 |
|
|
attr2 = ntfs_find_attr_in_mft_rec(
|
343 |
|
|
ino->vol, /* ntfs volume */
|
344 |
|
|
mftno2 == ino->i_number ?/* mft record is: */
|
345 |
|
|
ino->attr: /* base record */
|
346 |
|
|
mft2, /* extension record */
|
347 |
|
|
NTFS_GETU32(alist2 + 0), /* type */
|
348 |
|
|
(wchar_t*)(alist2 + alist2[7]), /* name */
|
349 |
|
|
alist2[6], /* name length */
|
350 |
|
|
1, /* ignore case */
|
351 |
|
|
NTFS_GETU16(alist2 + 24) /* instance number */
|
352 |
|
|
);
|
353 |
|
|
if (!attr2) {
|
354 |
|
|
ntfs_error("parse_attributes: mft records 0x%x and/or "
|
355 |
|
|
"0x%x corrupt!\n", ino->i_number,
|
356 |
|
|
mftno2);
|
357 |
|
|
ntfs_free(mft2);
|
358 |
|
|
goto failed_reading_mft_data;
|
359 |
|
|
}
|
360 |
|
|
error2 = ntfs_insert_mft_attribute(ino, mftno2, attr2);
|
361 |
|
|
if (error2) {
|
362 |
|
|
ntfs_debug(DEBUG_FILE3, "parse_attributes: "
|
363 |
|
|
"ntfs_insert_mft_attribute(mftno2 0x%x, "
|
364 |
|
|
"attribute2 type 0x%x) failed\n", mftno2,
|
365 |
|
|
NTFS_GETU32(alist2 + 0));
|
366 |
|
|
ntfs_free(mft2);
|
367 |
|
|
goto failed_reading_mft_data;
|
368 |
|
|
}
|
369 |
|
|
len2 -= l;
|
370 |
|
|
alist2 += l;
|
371 |
|
|
found2 = 1;
|
372 |
|
|
}
|
373 |
|
|
ntfs_free(mft2);
|
374 |
|
|
tries = 1;
|
375 |
|
|
goto continue_after_loading_mft_data;
|
376 |
|
|
}
|
377 |
|
|
}
|
378 |
|
|
|
379 |
|
|
static void ntfs_load_attributes(ntfs_inode *ino)
|
380 |
|
|
{
|
381 |
|
|
ntfs_attribute *alist;
|
382 |
|
|
int datasize;
|
383 |
|
|
int offset, len, delta;
|
384 |
|
|
char *buf;
|
385 |
|
|
ntfs_volume *vol = ino->vol;
|
386 |
|
|
|
387 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 1\n", ino->i_number);
|
388 |
|
|
if (ntfs_insert_mft_attributes(ino, ino->attr, ino->i_number))
|
389 |
|
|
return;
|
390 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 2\n", ino->i_number);
|
391 |
|
|
alist = ntfs_find_attr(ino, vol->at_attribute_list, 0);
|
392 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 3\n", ino->i_number);
|
393 |
|
|
if (!alist)
|
394 |
|
|
return;
|
395 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 4\n", ino->i_number);
|
396 |
|
|
datasize = alist->size;
|
397 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: alist->size = 0x%x\n",
|
398 |
|
|
ino->i_number, alist->size);
|
399 |
|
|
if (alist->resident) {
|
400 |
|
|
parse_attributes(ino, alist->d.data, &datasize);
|
401 |
|
|
return;
|
402 |
|
|
}
|
403 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 5\n", ino->i_number);
|
404 |
|
|
buf = ntfs_malloc(1024);
|
405 |
|
|
if (!buf) /* FIXME: Should be passing error code to caller. (AIA) */
|
406 |
|
|
return;
|
407 |
|
|
delta = 0;
|
408 |
|
|
for (offset = 0; datasize; datasize -= len, offset += len) {
|
409 |
|
|
ntfs_io io;
|
410 |
|
|
|
411 |
|
|
io.fn_put = ntfs_put;
|
412 |
|
|
io.fn_get = 0;
|
413 |
|
|
io.param = buf + delta;
|
414 |
|
|
len = 1024 - delta;
|
415 |
|
|
if (len > datasize)
|
416 |
|
|
len = datasize;
|
417 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: len = %i\n",
|
418 |
|
|
ino->i_number, len);
|
419 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: delta = %i\n",
|
420 |
|
|
ino->i_number, delta);
|
421 |
|
|
io.size = len;
|
422 |
|
|
if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset,
|
423 |
|
|
&io))
|
424 |
|
|
ntfs_error("error in load_attributes\n");
|
425 |
|
|
delta += len;
|
426 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after += len, "
|
427 |
|
|
"delta = %i\n", ino->i_number, delta);
|
428 |
|
|
parse_attributes(ino, buf, &delta);
|
429 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after "
|
430 |
|
|
"parse_attr, delta = %i\n", ino->i_number,
|
431 |
|
|
delta);
|
432 |
|
|
if (delta)
|
433 |
|
|
/* Move remaining bytes to buffer start. */
|
434 |
|
|
ntfs_memmove(buf, buf + len - delta, delta);
|
435 |
|
|
}
|
436 |
|
|
ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 6\n", ino->i_number);
|
437 |
|
|
ntfs_free(buf);
|
438 |
|
|
}
|
439 |
|
|
|
440 |
|
|
int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum)
|
441 |
|
|
{
|
442 |
|
|
char *buf;
|
443 |
|
|
int error;
|
444 |
|
|
|
445 |
|
|
ntfs_debug(DEBUG_FILE1, "Initializing inode 0x%x\n", inum);
|
446 |
|
|
ino->i_number = inum;
|
447 |
|
|
ino->vol = vol;
|
448 |
|
|
ino->attr = buf = ntfs_malloc(vol->mft_record_size);
|
449 |
|
|
if (!buf)
|
450 |
|
|
return -ENOMEM;
|
451 |
|
|
error = ntfs_read_mft_record(vol, inum, ino->attr);
|
452 |
|
|
if (error) {
|
453 |
|
|
ntfs_debug(DEBUG_OTHER, "Init inode: 0x%x failed\n", inum);
|
454 |
|
|
return error;
|
455 |
|
|
}
|
456 |
|
|
ntfs_debug(DEBUG_FILE2, "Init inode: got mft 0x%x\n", inum);
|
457 |
|
|
ino->sequence_number = NTFS_GETU16(buf + 0x10);
|
458 |
|
|
ino->attr_count = 0;
|
459 |
|
|
ino->record_count = 0;
|
460 |
|
|
ino->records = 0;
|
461 |
|
|
ino->attrs = 0;
|
462 |
|
|
ntfs_load_attributes(ino);
|
463 |
|
|
ntfs_debug(DEBUG_FILE2, "Init inode: done 0x%x\n", inum);
|
464 |
|
|
return 0;
|
465 |
|
|
}
|
466 |
|
|
|
467 |
|
|
void ntfs_clear_inode(ntfs_inode *ino)
|
468 |
|
|
{
|
469 |
|
|
int i;
|
470 |
|
|
if (!ino->attr) {
|
471 |
|
|
ntfs_error("ntfs_clear_inode: double free\n");
|
472 |
|
|
return;
|
473 |
|
|
}
|
474 |
|
|
ntfs_free(ino->attr);
|
475 |
|
|
ino->attr = 0;
|
476 |
|
|
ntfs_free(ino->records);
|
477 |
|
|
ino->records = 0;
|
478 |
|
|
for (i = 0; i < ino->attr_count; i++) {
|
479 |
|
|
if (ino->attrs[i].name)
|
480 |
|
|
ntfs_free(ino->attrs[i].name);
|
481 |
|
|
if (ino->attrs[i].resident) {
|
482 |
|
|
if (ino->attrs[i].d.data)
|
483 |
|
|
ntfs_free(ino->attrs[i].d.data);
|
484 |
|
|
} else {
|
485 |
|
|
if (ino->attrs[i].d.r.runlist)
|
486 |
|
|
ntfs_vfree(ino->attrs[i].d.r.runlist);
|
487 |
|
|
}
|
488 |
|
|
}
|
489 |
|
|
ntfs_free(ino->attrs);
|
490 |
|
|
ino->attrs = 0;
|
491 |
|
|
}
|
492 |
|
|
|
493 |
|
|
/* Check and fixup a MFT record. */
|
494 |
|
|
int ntfs_check_mft_record(ntfs_volume *vol, char *record)
|
495 |
|
|
{
|
496 |
|
|
return ntfs_fixup_record(record, "FILE", vol->mft_record_size);
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
/* Return (in result) the value indicating the next available attribute
|
500 |
|
|
* chunk number. Works for inodes w/o extension records only. */
|
501 |
|
|
int ntfs_allocate_attr_number(ntfs_inode *ino, int *result)
|
502 |
|
|
{
|
503 |
|
|
if (ino->record_count != 1)
|
504 |
|
|
return -EOPNOTSUPP;
|
505 |
|
|
*result = NTFS_GETU16(ino->attr + 0x28);
|
506 |
|
|
NTFS_PUTU16(ino->attr + 0x28, (*result) + 1);
|
507 |
|
|
return 0;
|
508 |
|
|
}
|
509 |
|
|
|
510 |
|
|
/* Find the location of an attribute in the inode. A name of NULL indicates
|
511 |
|
|
* unnamed attributes. Return pointer to attribute or NULL if not found. */
|
512 |
|
|
char *ntfs_get_attr(ntfs_inode *ino, int attr, char *name)
|
513 |
|
|
{
|
514 |
|
|
/* Location of first attribute. */
|
515 |
|
|
char *it = ino->attr + NTFS_GETU16(ino->attr + 0x14);
|
516 |
|
|
int type;
|
517 |
|
|
int len;
|
518 |
|
|
|
519 |
|
|
/* Only check for magic DWORD here, fixup should have happened before.*/
|
520 |
|
|
if (!IS_MFT_RECORD(ino->attr))
|
521 |
|
|
return 0;
|
522 |
|
|
do {
|
523 |
|
|
type = NTFS_GETU32(it);
|
524 |
|
|
len = NTFS_GETU16(it + 4);
|
525 |
|
|
/* We found the attribute type. Is the name correct, too? */
|
526 |
|
|
if (type == attr) {
|
527 |
|
|
int namelen = NTFS_GETU8(it + 9);
|
528 |
|
|
char *name_it, *n = name;
|
529 |
|
|
/* Match given name and attribute name if present.
|
530 |
|
|
Make sure attribute name is Unicode. */
|
531 |
|
|
if (!name) {
|
532 |
|
|
goto check_namelen;
|
533 |
|
|
} else if (namelen) {
|
534 |
|
|
for (name_it = it + NTFS_GETU16(it + 10);
|
535 |
|
|
namelen; n++, name_it += 2, namelen--)
|
536 |
|
|
if (*name_it != *n || name_it[1])
|
537 |
|
|
break;
|
538 |
|
|
check_namelen:
|
539 |
|
|
if (!namelen)
|
540 |
|
|
break;
|
541 |
|
|
}
|
542 |
|
|
}
|
543 |
|
|
it += len;
|
544 |
|
|
} while (type != -1); /* List of attributes ends with type -1. */
|
545 |
|
|
if (type == -1)
|
546 |
|
|
return 0;
|
547 |
|
|
return it;
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
__s64 ntfs_get_attr_size(ntfs_inode *ino, int type, char *name)
|
551 |
|
|
{
|
552 |
|
|
ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
|
553 |
|
|
if (!attr)
|
554 |
|
|
return 0;
|
555 |
|
|
return
|
556 |
|
|
attr->size;
|
557 |
|
|
}
|
558 |
|
|
|
559 |
|
|
int ntfs_attr_is_resident(ntfs_inode *ino, int type, char *name)
|
560 |
|
|
{
|
561 |
|
|
ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
|
562 |
|
|
if (!attr)
|
563 |
|
|
return 0;
|
564 |
|
|
return attr->resident;
|
565 |
|
|
}
|
566 |
|
|
|
567 |
|
|
/*
|
568 |
|
|
* A run is coded as a type indicator, an unsigned length, and a signed cluster
|
569 |
|
|
* offset.
|
570 |
|
|
* . To save space, length and offset are fields of variable length. The low
|
571 |
|
|
* nibble of the type indicates the width of the length :), the high nibble
|
572 |
|
|
* the width of the offset.
|
573 |
|
|
* . The first offset is relative to cluster 0, later offsets are relative to
|
574 |
|
|
* the previous cluster.
|
575 |
|
|
*
|
576 |
|
|
* This function decodes a run. Length is an output parameter, data and cluster
|
577 |
|
|
* are in/out parameters.
|
578 |
|
|
*/
|
579 |
|
|
int ntfs_decompress_run(unsigned char **data, int *length,
|
580 |
|
|
ntfs_cluster_t *cluster, int *ctype)
|
581 |
|
|
{
|
582 |
|
|
unsigned char type = *(*data)++;
|
583 |
|
|
*ctype = 0;
|
584 |
|
|
switch (type & 0xF) {
|
585 |
|
|
case 1:
|
586 |
|
|
*length = NTFS_GETS8(*data);
|
587 |
|
|
break;
|
588 |
|
|
case 2:
|
589 |
|
|
*length = NTFS_GETS16(*data);
|
590 |
|
|
break;
|
591 |
|
|
case 3:
|
592 |
|
|
*length = NTFS_GETS24(*data);
|
593 |
|
|
break;
|
594 |
|
|
case 4:
|
595 |
|
|
*length = NTFS_GETS32(*data);
|
596 |
|
|
break;
|
597 |
|
|
/* Note: cases 5-8 are probably pointless to code, since how
|
598 |
|
|
* many runs > 4GB of length are there? At the most, cases 5
|
599 |
|
|
* and 6 are probably necessary, and would also require making
|
600 |
|
|
* length 64-bit throughout. */
|
601 |
|
|
default:
|
602 |
|
|
ntfs_error("Can't decode run type field 0x%x\n", type);
|
603 |
|
|
return -1;
|
604 |
|
|
}
|
605 |
|
|
// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: length = 0x%x\n",*length);
|
606 |
|
|
if (*length < 0)
|
607 |
|
|
{
|
608 |
|
|
ntfs_error("Negative run length decoded\n");
|
609 |
|
|
return -1;
|
610 |
|
|
}
|
611 |
|
|
*data += (type & 0xF);
|
612 |
|
|
switch (type & 0xF0) {
|
613 |
|
|
case 0:
|
614 |
|
|
*ctype = 2;
|
615 |
|
|
break;
|
616 |
|
|
case 0x10:
|
617 |
|
|
*cluster += NTFS_GETS8(*data);
|
618 |
|
|
break;
|
619 |
|
|
case 0x20:
|
620 |
|
|
*cluster += NTFS_GETS16(*data);
|
621 |
|
|
break;
|
622 |
|
|
case 0x30:
|
623 |
|
|
*cluster += NTFS_GETS24(*data);
|
624 |
|
|
break;
|
625 |
|
|
case 0x40:
|
626 |
|
|
*cluster += NTFS_GETS32(*data);
|
627 |
|
|
break;
|
628 |
|
|
#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit. */
|
629 |
|
|
case 0x50:
|
630 |
|
|
*cluster += NTFS_GETS40(*data);
|
631 |
|
|
break;
|
632 |
|
|
case 0x60:
|
633 |
|
|
*cluster += NTFS_GETS48(*data);
|
634 |
|
|
break;
|
635 |
|
|
case 0x70:
|
636 |
|
|
*cluster += NTFS_GETS56(*data);
|
637 |
|
|
break;
|
638 |
|
|
case 0x80:
|
639 |
|
|
*cluster += NTFS_GETS64(*data);
|
640 |
|
|
break;
|
641 |
|
|
#endif
|
642 |
|
|
default:
|
643 |
|
|
ntfs_error("Can't decode run type field 0x%x\n", type);
|
644 |
|
|
return -1;
|
645 |
|
|
}
|
646 |
|
|
// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: cluster = 0x%x\n",
|
647 |
|
|
// *cluster);
|
648 |
|
|
*data += (type >> 4);
|
649 |
|
|
return 0;
|
650 |
|
|
}
|
651 |
|
|
|
652 |
|
|
static void dump_runlist(const ntfs_runlist *rl, const int rlen);
|
653 |
|
|
|
654 |
|
|
/*
|
655 |
|
|
* FIXME: ntfs_readwrite_attr() has the effect of writing @dest to @offset of
|
656 |
|
|
* the attribute value of the attribute @attr in the in memory inode @ino.
|
657 |
|
|
* If the attribute value of @attr is non-resident the value's contents at
|
658 |
|
|
* @offset are actually written to disk (from @dest). The on disk mft record
|
659 |
|
|
* describing the non-resident attribute value is not updated!
|
660 |
|
|
* If the attribute value is resident then the value is written only in
|
661 |
|
|
* memory. The on disk mft record containing the value is not written to disk.
|
662 |
|
|
* A possible fix would be to call ntfs_update_inode() before returning. (AIA)
|
663 |
|
|
*/
|
664 |
|
|
/* Reads l bytes of the attribute (attr, name) of ino starting at offset on
|
665 |
|
|
* vol into buf. Returns the number of bytes read in the ntfs_io struct.
|
666 |
|
|
* Returns 0 on success, errno on failure */
|
667 |
|
|
int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
|
668 |
|
|
ntfs_io *dest)
|
669 |
|
|
{
|
670 |
|
|
int rnum, s_vcn, error, clustersizebits;
|
671 |
|
|
ntfs_cluster_t cluster, s_cluster, vcn, len;
|
672 |
|
|
__s64 l, chunk, copied;
|
673 |
|
|
|
674 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): %s 0x%x bytes at offset "
|
675 |
|
|
"0x%Lx %s inode 0x%x, attr type 0x%x.\n", __FUNCTION__,
|
676 |
|
|
dest->do_read ? "Read" : "Write", dest->size, offset,
|
677 |
|
|
dest->do_read ? "from" : "to", ino->i_number,
|
678 |
|
|
attr->type);
|
679 |
|
|
l = dest->size;
|
680 |
|
|
if (l == 0)
|
681 |
|
|
return 0;
|
682 |
|
|
if (dest->do_read) {
|
683 |
|
|
/* If read _starts_ beyond end of stream, return nothing. */
|
684 |
|
|
if (offset >= attr->size) {
|
685 |
|
|
dest->size = 0;
|
686 |
|
|
return 0;
|
687 |
|
|
}
|
688 |
|
|
/* If read _extends_ beyond end of stream, return as much
|
689 |
|
|
* initialised data as we have. */
|
690 |
|
|
if (offset + l >= attr->size)
|
691 |
|
|
l = dest->size = attr->size - offset;
|
692 |
|
|
} else {
|
693 |
|
|
/*
|
694 |
|
|
* If write extends beyond _allocated_ size, extend attribute,
|
695 |
|
|
* updating attr->allocated and attr->size in the process. (AIA)
|
696 |
|
|
*/
|
697 |
|
|
if ((!attr->resident && offset + l > attr->allocated) ||
|
698 |
|
|
(attr->resident && offset + l > attr->size)) {
|
699 |
|
|
error = ntfs_resize_attr(ino, attr, offset + l);
|
700 |
|
|
if (error)
|
701 |
|
|
return error;
|
702 |
|
|
}
|
703 |
|
|
if (!attr->resident) {
|
704 |
|
|
/* Has amount of data increased? */
|
705 |
|
|
if (offset + l > attr->size)
|
706 |
|
|
attr->size = offset + l;
|
707 |
|
|
/* Has amount of initialised data increased? */
|
708 |
|
|
if (offset + l > attr->initialized) {
|
709 |
|
|
/* FIXME: Clear the section between the old
|
710 |
|
|
* initialised length and the write start.
|
711 |
|
|
* (AIA) */
|
712 |
|
|
attr->initialized = offset + l;
|
713 |
|
|
}
|
714 |
|
|
}
|
715 |
|
|
}
|
716 |
|
|
if (attr->resident) {
|
717 |
|
|
if (dest->do_read)
|
718 |
|
|
dest->fn_put(dest, (ntfs_u8*)attr->d.data + offset, l);
|
719 |
|
|
else
|
720 |
|
|
dest->fn_get((ntfs_u8*)attr->d.data + offset, dest, l);
|
721 |
|
|
dest->size = l;
|
722 |
|
|
return 0;
|
723 |
|
|
}
|
724 |
|
|
if (dest->do_read) {
|
725 |
|
|
/* Read uninitialized data. */
|
726 |
|
|
if (offset >= attr->initialized)
|
727 |
|
|
return ntfs_read_zero(dest, l);
|
728 |
|
|
if (offset + l > attr->initialized) {
|
729 |
|
|
dest->size = chunk = attr->initialized - offset;
|
730 |
|
|
error = ntfs_readwrite_attr(ino, attr, offset, dest);
|
731 |
|
|
if (error || (dest->size != chunk && (error = -EIO, 1)))
|
732 |
|
|
return error;
|
733 |
|
|
dest->size += l - chunk;
|
734 |
|
|
return ntfs_read_zero(dest, l - chunk);
|
735 |
|
|
}
|
736 |
|
|
if (attr->flags & ATTR_IS_COMPRESSED)
|
737 |
|
|
return ntfs_read_compressed(ino, attr, offset, dest);
|
738 |
|
|
} else {
|
739 |
|
|
if (attr->flags & ATTR_IS_COMPRESSED)
|
740 |
|
|
return ntfs_write_compressed(ino, attr, offset, dest);
|
741 |
|
|
}
|
742 |
|
|
vcn = 0;
|
743 |
|
|
clustersizebits = ino->vol->cluster_size_bits;
|
744 |
|
|
s_vcn = offset >> clustersizebits;
|
745 |
|
|
for (rnum = 0; rnum < attr->d.r.len &&
|
746 |
|
|
vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++)
|
747 |
|
|
vcn += attr->d.r.runlist[rnum].len;
|
748 |
|
|
if (rnum == attr->d.r.len) {
|
749 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): EOPNOTSUPP: "
|
750 |
|
|
"inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = 0x%x, "
|
751 |
|
|
"s_vcn = 0x%x.\n", __FUNCTION__, ino->i_number, rnum,
|
752 |
|
|
offset, vcn, s_vcn);
|
753 |
|
|
dump_runlist(attr->d.r.runlist, attr->d.r.len);
|
754 |
|
|
/*FIXME: Should extend runlist. */
|
755 |
|
|
return -EOPNOTSUPP;
|
756 |
|
|
}
|
757 |
|
|
copied = 0;
|
758 |
|
|
while (l) {
|
759 |
|
|
s_vcn = offset >> clustersizebits;
|
760 |
|
|
cluster = attr->d.r.runlist[rnum].lcn;
|
761 |
|
|
len = attr->d.r.runlist[rnum].len;
|
762 |
|
|
s_cluster = cluster + s_vcn - vcn;
|
763 |
|
|
chunk = ((__s64)(vcn + len) << clustersizebits) - offset;
|
764 |
|
|
if (chunk > l)
|
765 |
|
|
chunk = l;
|
766 |
|
|
dest->size = chunk;
|
767 |
|
|
error = ntfs_getput_clusters(ino->vol, s_cluster, offset -
|
768 |
|
|
((__s64)s_vcn << clustersizebits), dest);
|
769 |
|
|
if (error) {
|
770 |
|
|
ntfs_error("Read/write error.\n");
|
771 |
|
|
dest->size = copied;
|
772 |
|
|
return error;
|
773 |
|
|
}
|
774 |
|
|
l -= chunk;
|
775 |
|
|
copied += chunk;
|
776 |
|
|
offset += chunk;
|
777 |
|
|
if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
|
778 |
|
|
rnum++;
|
779 |
|
|
vcn += len;
|
780 |
|
|
cluster = attr->d.r.runlist[rnum].lcn;
|
781 |
|
|
len = attr->d.r.runlist[rnum].len;
|
782 |
|
|
}
|
783 |
|
|
}
|
784 |
|
|
dest->size = copied;
|
785 |
|
|
return 0;
|
786 |
|
|
}
|
787 |
|
|
|
788 |
|
|
int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
|
789 |
|
|
ntfs_io *buf)
|
790 |
|
|
{
|
791 |
|
|
ntfs_attribute *attr;
|
792 |
|
|
|
793 |
|
|
buf->do_read = 1;
|
794 |
|
|
attr = ntfs_find_attr(ino, type, name);
|
795 |
|
|
if (!attr) {
|
796 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode "
|
797 |
|
|
"0x%x\n", __FUNCTION__, type, ino->i_number);
|
798 |
|
|
return -EINVAL;
|
799 |
|
|
}
|
800 |
|
|
return ntfs_readwrite_attr(ino, attr, offset, buf);
|
801 |
|
|
}
|
802 |
|
|
|
803 |
|
|
int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
|
804 |
|
|
ntfs_io *buf)
|
805 |
|
|
{
|
806 |
|
|
ntfs_attribute *attr;
|
807 |
|
|
|
808 |
|
|
buf->do_read = 0;
|
809 |
|
|
attr = ntfs_find_attr(ino, type, name);
|
810 |
|
|
if (!attr) {
|
811 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode "
|
812 |
|
|
"0x%x\n", __FUNCTION__, type, ino->i_number);
|
813 |
|
|
return -EINVAL;
|
814 |
|
|
}
|
815 |
|
|
return ntfs_readwrite_attr(ino, attr, offset, buf);
|
816 |
|
|
}
|
817 |
|
|
|
818 |
|
|
/* -2 = error, -1 = hole, >= 0 means real disk cluster (lcn). */
|
819 |
|
|
int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn)
|
820 |
|
|
{
|
821 |
|
|
int rnum;
|
822 |
|
|
ntfs_attribute *data;
|
823 |
|
|
|
824 |
|
|
data = ntfs_find_attr(ino, ino->vol->at_data, 0);
|
825 |
|
|
if (!data || data->resident || data->flags & (ATTR_IS_COMPRESSED |
|
826 |
|
|
ATTR_IS_ENCRYPTED))
|
827 |
|
|
return -2;
|
828 |
|
|
if (data->size <= (__s64)vcn << ino->vol->cluster_size_bits)
|
829 |
|
|
return -2;
|
830 |
|
|
if (data->initialized <= (__s64)vcn << ino->vol->cluster_size_bits)
|
831 |
|
|
return -1;
|
832 |
|
|
for (rnum = 0; rnum < data->d.r.len &&
|
833 |
|
|
vcn >= data->d.r.runlist[rnum].len; rnum++)
|
834 |
|
|
vcn -= data->d.r.runlist[rnum].len;
|
835 |
|
|
if (data->d.r.runlist[rnum].lcn >= 0)
|
836 |
|
|
return data->d.r.runlist[rnum].lcn + vcn;
|
837 |
|
|
return data->d.r.runlist[rnum].lcn + vcn;
|
838 |
|
|
}
|
839 |
|
|
|
840 |
|
|
static int allocate_store(ntfs_volume *vol, ntfs_disk_inode *store, int count)
|
841 |
|
|
{
|
842 |
|
|
int i;
|
843 |
|
|
|
844 |
|
|
if (store->count > count)
|
845 |
|
|
return 0;
|
846 |
|
|
if (store->size < count) {
|
847 |
|
|
ntfs_mft_record *n = ntfs_malloc((count + 4) *
|
848 |
|
|
sizeof(ntfs_mft_record));
|
849 |
|
|
if (!n)
|
850 |
|
|
return -ENOMEM;
|
851 |
|
|
if (store->size) {
|
852 |
|
|
for (i = 0; i < store->size; i++)
|
853 |
|
|
n[i] = store->records[i];
|
854 |
|
|
ntfs_free(store->records);
|
855 |
|
|
}
|
856 |
|
|
store->size = count + 4;
|
857 |
|
|
store->records = n;
|
858 |
|
|
}
|
859 |
|
|
for (i = store->count; i < count; i++) {
|
860 |
|
|
store->records[i].record = ntfs_malloc(vol->mft_record_size);
|
861 |
|
|
if (!store->records[i].record)
|
862 |
|
|
return -ENOMEM;
|
863 |
|
|
store->count++;
|
864 |
|
|
}
|
865 |
|
|
return 0;
|
866 |
|
|
}
|
867 |
|
|
|
868 |
|
|
static void deallocate_store(ntfs_disk_inode* store)
|
869 |
|
|
{
|
870 |
|
|
int i;
|
871 |
|
|
|
872 |
|
|
for (i = 0; i < store->count; i++)
|
873 |
|
|
ntfs_free(store->records[i].record);
|
874 |
|
|
ntfs_free(store->records);
|
875 |
|
|
store->count = store->size = 0;
|
876 |
|
|
store->records = 0;
|
877 |
|
|
}
|
878 |
|
|
|
879 |
|
|
/**
|
880 |
|
|
* layout_runs - compress runlist into mapping pairs array
|
881 |
|
|
* @attr: attribute containing the runlist to compress
|
882 |
|
|
* @rec: destination buffer to hold the mapping pairs array
|
883 |
|
|
* @offs: current position in @rec (in/out variable)
|
884 |
|
|
* @size: size of the buffer @rec
|
885 |
|
|
*
|
886 |
|
|
* layout_runs walks the runlist in @attr, compresses it and writes it out the
|
887 |
|
|
* resulting mapping pairs array into @rec (up to a maximum of @size bytes are
|
888 |
|
|
* written). On entry @offs is the offset in @rec at which to begin writing the
|
889 |
|
|
* mapping pairs array. On exit, it contains the offset in @rec of the first
|
890 |
|
|
* byte after the end of the mapping pairs array.
|
891 |
|
|
*/
|
892 |
|
|
static int layout_runs(ntfs_attribute *attr, char *rec, int *offs, int size)
|
893 |
|
|
{
|
894 |
|
|
int i, len, offset, coffs;
|
895 |
|
|
/* ntfs_cluster_t MUST be signed! (AIA) */
|
896 |
|
|
ntfs_cluster_t cluster, rclus;
|
897 |
|
|
ntfs_runlist *rl = attr->d.r.runlist;
|
898 |
|
|
cluster = 0;
|
899 |
|
|
offset = *offs;
|
900 |
|
|
for (i = 0; i < attr->d.r.len; i++) {
|
901 |
|
|
/*
|
902 |
|
|
* We cheat with this check on the basis that lcn will never
|
903 |
|
|
* be less than -1 and the lcn delta will fit in signed
|
904 |
|
|
* 32-bits (ntfs_cluster_t). (AIA)
|
905 |
|
|
*/
|
906 |
|
|
if (rl[i].lcn < (ntfs_cluster_t)-1) {
|
907 |
|
|
ntfs_error("layout_runs() encountered an out of bounds "
|
908 |
|
|
"cluster delta, lcn = %i.\n",
|
909 |
|
|
rl[i].lcn);
|
910 |
|
|
return -ERANGE;
|
911 |
|
|
}
|
912 |
|
|
rclus = rl[i].lcn - cluster;
|
913 |
|
|
len = rl[i].len;
|
914 |
|
|
rec[offset] = 0;
|
915 |
|
|
if (offset + 9 > size)
|
916 |
|
|
return -E2BIG; /* It might still fit, but this
|
917 |
|
|
* simplifies testing. */
|
918 |
|
|
/*
|
919 |
|
|
* Run length is stored as signed number, so deal with it
|
920 |
|
|
* properly, i.e. observe that a negative number will have all
|
921 |
|
|
* its most significant bits set to 1 but we don't store that
|
922 |
|
|
* in the mapping pairs array. We store the smallest type of
|
923 |
|
|
* negative number required, thus in the first if we check
|
924 |
|
|
* whether len fits inside a signed byte and if so we store it
|
925 |
|
|
* as such, the next ifs check for a signed short, then a signed
|
926 |
|
|
* 24-bit and finally the full blown signed 32-bit. Same goes
|
927 |
|
|
* for rlus below. (AIA)
|
928 |
|
|
*/
|
929 |
|
|
if (len >= -0x80 && len <= 0x7f) {
|
930 |
|
|
NTFS_PUTU8(rec + offset + 1, len & 0xff);
|
931 |
|
|
coffs = 1;
|
932 |
|
|
} else if (len >= -0x8000 && len <= 0x7fff) {
|
933 |
|
|
NTFS_PUTU16(rec + offset + 1, len & 0xffff);
|
934 |
|
|
coffs = 2;
|
935 |
|
|
} else if (len >= -0x800000 && len <= 0x7fffff) {
|
936 |
|
|
NTFS_PUTU24(rec + offset + 1, len & 0xffffff);
|
937 |
|
|
coffs = 3;
|
938 |
|
|
} else /* if (len >= -0x80000000LL && len <= 0x7fffffff */ {
|
939 |
|
|
NTFS_PUTU32(rec + offset + 1, len);
|
940 |
|
|
coffs = 4;
|
941 |
|
|
} /* else ... FIXME: When len becomes 64-bit we need to extend
|
942 |
|
|
* the else if () statements. (AIA) */
|
943 |
|
|
*(rec + offset) |= coffs++;
|
944 |
|
|
if (rl[i].lcn == (ntfs_cluster_t)-1) /* Compressed run. */
|
945 |
|
|
/* Nothing */;
|
946 |
|
|
else if (rclus >= -0x80 && rclus <= 0x7f) {
|
947 |
|
|
*(rec + offset) |= 0x10;
|
948 |
|
|
NTFS_PUTS8(rec + offset + coffs, rclus & 0xff);
|
949 |
|
|
coffs += 1;
|
950 |
|
|
} else if (rclus >= -0x8000 && rclus <= 0x7fff) {
|
951 |
|
|
*(rec + offset) |= 0x20;
|
952 |
|
|
NTFS_PUTS16(rec + offset + coffs, rclus & 0xffff);
|
953 |
|
|
coffs += 2;
|
954 |
|
|
} else if (rclus >= -0x800000 && rclus <= 0x7fffff) {
|
955 |
|
|
*(rec + offset) |= 0x30;
|
956 |
|
|
NTFS_PUTS24(rec + offset + coffs, rclus & 0xffffff);
|
957 |
|
|
coffs += 3;
|
958 |
|
|
} else /* if (rclus >= -0x80000000LL && rclus <= 0x7fffffff)*/ {
|
959 |
|
|
*(rec + offset) |= 0x40;
|
960 |
|
|
NTFS_PUTS32(rec + offset + coffs, rclus
|
961 |
|
|
/* & 0xffffffffLL */);
|
962 |
|
|
coffs += 4;
|
963 |
|
|
} /* FIXME: When rclus becomes 64-bit.
|
964 |
|
|
else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) {
|
965 |
|
|
*(rec + offset) |= 0x50;
|
966 |
|
|
NTFS_PUTS40(rec + offset + coffs, rclus &
|
967 |
|
|
0xffffffffffLL);
|
968 |
|
|
coffs += 5;
|
969 |
|
|
} else if (rclus >= -0x800000000000 &&
|
970 |
|
|
rclus <= 0x7FFFFFFFFFFF) {
|
971 |
|
|
*(rec + offset) |= 0x60;
|
972 |
|
|
NTFS_PUTS48(rec + offset + coffs, rclus &
|
973 |
|
|
0xffffffffffffLL);
|
974 |
|
|
coffs += 6;
|
975 |
|
|
} else if (rclus >= -0x80000000000000 &&
|
976 |
|
|
rclus <= 0x7FFFFFFFFFFFFF) {
|
977 |
|
|
*(rec + offset) |= 0x70;
|
978 |
|
|
NTFS_PUTS56(rec + offset + coffs, rclus &
|
979 |
|
|
0xffffffffffffffLL);
|
980 |
|
|
coffs += 7;
|
981 |
|
|
} else {
|
982 |
|
|
*(rec + offset) |= 0x80;
|
983 |
|
|
NTFS_PUTS64(rec + offset + coffs, rclus);
|
984 |
|
|
coffs += 8;
|
985 |
|
|
} */
|
986 |
|
|
offset += coffs;
|
987 |
|
|
if (rl[i].lcn)
|
988 |
|
|
cluster = rl[i].lcn;
|
989 |
|
|
}
|
990 |
|
|
if (offset >= size)
|
991 |
|
|
return -E2BIG;
|
992 |
|
|
/* Terminating null. */
|
993 |
|
|
*(rec + offset++) = 0;
|
994 |
|
|
*offs = offset;
|
995 |
|
|
return 0;
|
996 |
|
|
}
|
997 |
|
|
|
998 |
|
|
static void count_runs(ntfs_attribute *attr, char *buf)
|
999 |
|
|
{
|
1000 |
|
|
ntfs_u32 first, count, last, i;
|
1001 |
|
|
|
1002 |
|
|
first = 0;
|
1003 |
|
|
for (i = 0, count = 0; i < attr->d.r.len; i++)
|
1004 |
|
|
count += attr->d.r.runlist[i].len;
|
1005 |
|
|
last = first + count - 1;
|
1006 |
|
|
NTFS_PUTU64(buf + 0x10, first);
|
1007 |
|
|
NTFS_PUTU64(buf + 0x18, last);
|
1008 |
|
|
}
|
1009 |
|
|
|
1010 |
|
|
/**
|
1011 |
|
|
* layout_attr - convert in memory attribute to on disk attribute record
|
1012 |
|
|
* @attr: in memory attribute to convert
|
1013 |
|
|
* @buf: destination buffer for on disk attribute record
|
1014 |
|
|
* @size: size of the destination buffer
|
1015 |
|
|
* @psize: size of converted on disk attribute record (out variable)
|
1016 |
|
|
*
|
1017 |
|
|
* layout_attr() takes the attribute @attr and converts it into the appropriate
|
1018 |
|
|
* on disk structure, writing it into @buf (up to @size bytes are written).
|
1019 |
|
|
*
|
1020 |
|
|
* On success we return 0 and set @*psize to the actual byte size of the on-
|
1021 |
|
|
* disk attribute that was written into @buf.
|
1022 |
|
|
*/
|
1023 |
|
|
static int layout_attr(ntfs_attribute *attr, char *buf, int size, int *psize)
|
1024 |
|
|
{
|
1025 |
|
|
int nameoff, hdrsize, asize;
|
1026 |
|
|
|
1027 |
|
|
if (attr->resident) {
|
1028 |
|
|
nameoff = 0x18;
|
1029 |
|
|
hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7;
|
1030 |
|
|
asize = (hdrsize + attr->size + 7) & ~7;
|
1031 |
|
|
if (size < asize)
|
1032 |
|
|
return -E2BIG;
|
1033 |
|
|
NTFS_PUTU32(buf + 0x10, attr->size);
|
1034 |
|
|
NTFS_PUTU8(buf + 0x16, attr->indexed);
|
1035 |
|
|
NTFS_PUTU16(buf + 0x14, hdrsize);
|
1036 |
|
|
if (attr->size)
|
1037 |
|
|
ntfs_memcpy(buf + hdrsize, attr->d.data, attr->size);
|
1038 |
|
|
} else {
|
1039 |
|
|
int error;
|
1040 |
|
|
|
1041 |
|
|
if (attr->flags & ATTR_IS_COMPRESSED)
|
1042 |
|
|
nameoff = 0x48;
|
1043 |
|
|
else
|
1044 |
|
|
nameoff = 0x40;
|
1045 |
|
|
hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7;
|
1046 |
|
|
if (size < hdrsize)
|
1047 |
|
|
return -E2BIG;
|
1048 |
|
|
/* Make asize point at the end of the attribute record header,
|
1049 |
|
|
i.e. at the beginning of the mapping pairs array. */
|
1050 |
|
|
asize = hdrsize;
|
1051 |
|
|
error = layout_runs(attr, buf, &asize, size);
|
1052 |
|
|
/* Now, asize points one byte beyond the end of the mapping
|
1053 |
|
|
pairs array. */
|
1054 |
|
|
if (error)
|
1055 |
|
|
return error;
|
1056 |
|
|
/* The next attribute has to begin on 8-byte boundary. */
|
1057 |
|
|
asize = (asize + 7) & ~7;
|
1058 |
|
|
/* FIXME: fragments */
|
1059 |
|
|
count_runs(attr, buf);
|
1060 |
|
|
NTFS_PUTU16(buf + 0x20, hdrsize);
|
1061 |
|
|
NTFS_PUTU16(buf + 0x22, attr->cengine);
|
1062 |
|
|
NTFS_PUTU32(buf + 0x24, 0);
|
1063 |
|
|
NTFS_PUTS64(buf + 0x28, attr->allocated);
|
1064 |
|
|
NTFS_PUTS64(buf + 0x30, attr->size);
|
1065 |
|
|
NTFS_PUTS64(buf + 0x38, attr->initialized);
|
1066 |
|
|
if (attr->flags & ATTR_IS_COMPRESSED)
|
1067 |
|
|
NTFS_PUTS64(buf + 0x40, attr->compsize);
|
1068 |
|
|
}
|
1069 |
|
|
NTFS_PUTU32(buf, attr->type);
|
1070 |
|
|
NTFS_PUTU32(buf + 4, asize);
|
1071 |
|
|
NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1);
|
1072 |
|
|
NTFS_PUTU8(buf + 9, attr->namelen);
|
1073 |
|
|
NTFS_PUTU16(buf + 0xa, nameoff);
|
1074 |
|
|
NTFS_PUTU16(buf + 0xc, attr->flags);
|
1075 |
|
|
NTFS_PUTU16(buf + 0xe, attr->attrno);
|
1076 |
|
|
if (attr->namelen)
|
1077 |
|
|
ntfs_memcpy(buf + nameoff, attr->name, 2 * attr->namelen);
|
1078 |
|
|
*psize = asize;
|
1079 |
|
|
return 0;
|
1080 |
|
|
}
|
1081 |
|
|
|
1082 |
|
|
/**
|
1083 |
|
|
* layout_inode - convert an in-memory inode into on disk mft record(s)
|
1084 |
|
|
* @ino: in memory inode to convert
|
1085 |
|
|
* @store: on disk inode, contain buffers for the on disk mft record(s)
|
1086 |
|
|
*
|
1087 |
|
|
* layout_inode takes the in memory inode @ino, converts it into a (sequence of)
|
1088 |
|
|
* mft record(s) and writes them to the appropriate buffers in the @store.
|
1089 |
|
|
*
|
1090 |
|
|
* Return 0 on success,
|
1091 |
|
|
* the required mft record count (>0) if the inode does not fit,
|
1092 |
|
|
* -ENOMEM if memory allocation problem, or
|
1093 |
|
|
* -EOPNOTSUP if beyond our capabilities.
|
1094 |
|
|
*
|
1095 |
|
|
* TODO: We at the moment do not support extension mft records. (AIA)
|
1096 |
|
|
*/
|
1097 |
|
|
int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store)
|
1098 |
|
|
{
|
1099 |
|
|
int offset, i, size, psize, error, count, recno;
|
1100 |
|
|
ntfs_attribute *attr;
|
1101 |
|
|
unsigned char *rec;
|
1102 |
|
|
|
1103 |
|
|
error = allocate_store(ino->vol, store, ino->record_count);
|
1104 |
|
|
if (error)
|
1105 |
|
|
return error;
|
1106 |
|
|
size = ino->vol->mft_record_size;
|
1107 |
|
|
count = i = 0;
|
1108 |
|
|
do {
|
1109 |
|
|
if (count < ino->record_count) {
|
1110 |
|
|
recno = ino->records[count];
|
1111 |
|
|
} else {
|
1112 |
|
|
error = allocate_store(ino->vol, store, count + 1);
|
1113 |
|
|
if (error)
|
1114 |
|
|
return error;
|
1115 |
|
|
recno = -1;
|
1116 |
|
|
}
|
1117 |
|
|
/*
|
1118 |
|
|
* FIXME: We need to support extension records properly.
|
1119 |
|
|
* At the moment they wouldn't work. Probably would "just" get
|
1120 |
|
|
* corrupted if we write to them... (AIA)
|
1121 |
|
|
*/
|
1122 |
|
|
store->records[count].recno = recno;
|
1123 |
|
|
rec = store->records[count].record;
|
1124 |
|
|
count++;
|
1125 |
|
|
/* Copy mft record header. */
|
1126 |
|
|
offset = NTFS_GETU16(ino->attr + 0x14); /* attrs_offset */
|
1127 |
|
|
ntfs_memcpy(rec, ino->attr, offset);
|
1128 |
|
|
/* Copy attributes. */
|
1129 |
|
|
while (i < ino->attr_count) {
|
1130 |
|
|
attr = ino->attrs + i;
|
1131 |
|
|
error = layout_attr(attr, rec + offset,
|
1132 |
|
|
size - offset - 8, &psize);
|
1133 |
|
|
if (error == -E2BIG && offset != NTFS_GETU16(ino->attr
|
1134 |
|
|
+ 0x14))
|
1135 |
|
|
break;
|
1136 |
|
|
if (error)
|
1137 |
|
|
return error;
|
1138 |
|
|
offset += psize;
|
1139 |
|
|
i++;
|
1140 |
|
|
}
|
1141 |
|
|
/* Terminating attribute. */
|
1142 |
|
|
NTFS_PUTU32(rec + offset, 0xFFFFFFFF);
|
1143 |
|
|
offset += 4;
|
1144 |
|
|
NTFS_PUTU32(rec + offset, 0);
|
1145 |
|
|
offset += 4;
|
1146 |
|
|
NTFS_PUTU32(rec + 0x18, offset);
|
1147 |
|
|
} while (i < ino->attr_count || count < ino->record_count);
|
1148 |
|
|
return count - ino->record_count;
|
1149 |
|
|
}
|
1150 |
|
|
|
1151 |
|
|
/*
|
1152 |
|
|
* FIXME: ntfs_update_inode() calls layout_inode() to create the mft record on
|
1153 |
|
|
* disk structure corresponding to the inode @ino. After that, ntfs_write_attr()
|
1154 |
|
|
* is called to write out the created mft record to disk.
|
1155 |
|
|
* We shouldn't need to re-layout every single time we are updating an mft
|
1156 |
|
|
* record. No wonder the ntfs driver is slow like hell. (AIA)
|
1157 |
|
|
*/
|
1158 |
|
|
int ntfs_update_inode(ntfs_inode *ino)
|
1159 |
|
|
{
|
1160 |
|
|
int error, i;
|
1161 |
|
|
ntfs_disk_inode store;
|
1162 |
|
|
ntfs_io io;
|
1163 |
|
|
|
1164 |
|
|
ntfs_bzero(&store, sizeof(store));
|
1165 |
|
|
error = layout_inode(ino, &store);
|
1166 |
|
|
if (error == -E2BIG) {
|
1167 |
|
|
i = ntfs_split_indexroot(ino);
|
1168 |
|
|
if (i != -ENOTDIR) {
|
1169 |
|
|
if (!i)
|
1170 |
|
|
i = layout_inode(ino, &store);
|
1171 |
|
|
error = i;
|
1172 |
|
|
}
|
1173 |
|
|
}
|
1174 |
|
|
if (error == -E2BIG) {
|
1175 |
|
|
error = ntfs_attr_allnonresident(ino);
|
1176 |
|
|
if (!error)
|
1177 |
|
|
error = layout_inode(ino, &store);
|
1178 |
|
|
}
|
1179 |
|
|
if (error > 0) {
|
1180 |
|
|
/* FIXME: Introduce extension records. */
|
1181 |
|
|
error = -E2BIG;
|
1182 |
|
|
}
|
1183 |
|
|
if (error) {
|
1184 |
|
|
if (error == -E2BIG)
|
1185 |
|
|
ntfs_error("Cannot handle saving inode 0x%x.\n",
|
1186 |
|
|
ino->i_number);
|
1187 |
|
|
deallocate_store(&store);
|
1188 |
|
|
return error;
|
1189 |
|
|
}
|
1190 |
|
|
io.fn_get = ntfs_get;
|
1191 |
|
|
io.fn_put = 0;
|
1192 |
|
|
for (i = 0; i < store.count; i++) {
|
1193 |
|
|
error = ntfs_insert_fixups(store.records[i].record,
|
1194 |
|
|
ino->vol->mft_record_size);
|
1195 |
|
|
if (error) {
|
1196 |
|
|
printk(KERN_ALERT "NTFS: ntfs_update_inode() caught "
|
1197 |
|
|
"corrupt %s mtf record ntfs record "
|
1198 |
|
|
"header. Refusing to write corrupt "
|
1199 |
|
|
"data to disk. Unmount and run chkdsk "
|
1200 |
|
|
"immediately!\n", i ? "extension":
|
1201 |
|
|
"base");
|
1202 |
|
|
deallocate_store(&store);
|
1203 |
|
|
return -EIO;
|
1204 |
|
|
}
|
1205 |
|
|
io.param = store.records[i].record;
|
1206 |
|
|
io.size = ino->vol->mft_record_size;
|
1207 |
|
|
error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data,
|
1208 |
|
|
0, (__s64)store.records[i].recno <<
|
1209 |
|
|
ino->vol->mft_record_size_bits, &io);
|
1210 |
|
|
if (error || io.size != ino->vol->mft_record_size) {
|
1211 |
|
|
/* Big trouble, partially written file. */
|
1212 |
|
|
ntfs_error("Please unmount: Write error in inode "
|
1213 |
|
|
"0x%x\n", ino->i_number);
|
1214 |
|
|
deallocate_store(&store);
|
1215 |
|
|
return error ? error : -EIO;
|
1216 |
|
|
}
|
1217 |
|
|
}
|
1218 |
|
|
deallocate_store(&store);
|
1219 |
|
|
return 0;
|
1220 |
|
|
}
|
1221 |
|
|
|
1222 |
|
|
void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l)
|
1223 |
|
|
{
|
1224 |
|
|
int head, comp;
|
1225 |
|
|
int copied = 0;
|
1226 |
|
|
unsigned char *stop;
|
1227 |
|
|
int bits;
|
1228 |
|
|
int tag = 0;
|
1229 |
|
|
int clear_pos;
|
1230 |
|
|
|
1231 |
|
|
while (1) {
|
1232 |
|
|
head = NTFS_GETU16(src) & 0xFFF;
|
1233 |
|
|
/* High bit indicates that compression was performed. */
|
1234 |
|
|
comp = NTFS_GETU16(src) & 0x8000;
|
1235 |
|
|
src += 2;
|
1236 |
|
|
stop = src + head;
|
1237 |
|
|
bits = 0;
|
1238 |
|
|
clear_pos = 0;
|
1239 |
|
|
if (head == 0)
|
1240 |
|
|
/* Block is not used. */
|
1241 |
|
|
return;/* FIXME: copied */
|
1242 |
|
|
if (!comp) { /* uncompressible */
|
1243 |
|
|
ntfs_memcpy(dest, src, 0x1000);
|
1244 |
|
|
dest += 0x1000;
|
1245 |
|
|
copied += 0x1000;
|
1246 |
|
|
src += 0x1000;
|
1247 |
|
|
if (l == copied)
|
1248 |
|
|
return;
|
1249 |
|
|
continue;
|
1250 |
|
|
}
|
1251 |
|
|
while (src <= stop) {
|
1252 |
|
|
if (clear_pos > 4096) {
|
1253 |
|
|
ntfs_error("Error 1 in decompress\n");
|
1254 |
|
|
return;
|
1255 |
|
|
}
|
1256 |
|
|
if (!bits) {
|
1257 |
|
|
tag = NTFS_GETU8(src);
|
1258 |
|
|
bits = 8;
|
1259 |
|
|
src++;
|
1260 |
|
|
if (src > stop)
|
1261 |
|
|
break;
|
1262 |
|
|
}
|
1263 |
|
|
if (tag & 1) {
|
1264 |
|
|
int i, len, delta, code, lmask, dshift;
|
1265 |
|
|
code = NTFS_GETU16(src);
|
1266 |
|
|
src += 2;
|
1267 |
|
|
if (!clear_pos) {
|
1268 |
|
|
ntfs_error("Error 2 in decompress\n");
|
1269 |
|
|
return;
|
1270 |
|
|
}
|
1271 |
|
|
for (i = clear_pos - 1, lmask = 0xFFF,
|
1272 |
|
|
dshift = 12; i >= 0x10; i >>= 1) {
|
1273 |
|
|
lmask >>= 1;
|
1274 |
|
|
dshift--;
|
1275 |
|
|
}
|
1276 |
|
|
delta = code >> dshift;
|
1277 |
|
|
len = (code & lmask) + 3;
|
1278 |
|
|
for (i = 0; i < len; i++) {
|
1279 |
|
|
dest[clear_pos] = dest[clear_pos -
|
1280 |
|
|
delta - 1];
|
1281 |
|
|
clear_pos++;
|
1282 |
|
|
copied++;
|
1283 |
|
|
if (copied==l)
|
1284 |
|
|
return;
|
1285 |
|
|
}
|
1286 |
|
|
} else {
|
1287 |
|
|
dest[clear_pos++] = NTFS_GETU8(src);
|
1288 |
|
|
src++;
|
1289 |
|
|
copied++;
|
1290 |
|
|
if (copied==l)
|
1291 |
|
|
return;
|
1292 |
|
|
}
|
1293 |
|
|
tag >>= 1;
|
1294 |
|
|
bits--;
|
1295 |
|
|
}
|
1296 |
|
|
dest += clear_pos;
|
1297 |
|
|
}
|
1298 |
|
|
}
|
1299 |
|
|
|
1300 |
|
|
/*
|
1301 |
|
|
* NOTE: Neither of the ntfs_*_bit functions are atomic! But we don't need
|
1302 |
|
|
* them atomic at present as we never operate on shared/cached bitmaps.
|
1303 |
|
|
*/
|
1304 |
|
|
static __inline__ int ntfs_test_bit(unsigned char *byte, const int bit)
|
1305 |
|
|
{
|
1306 |
|
|
return byte[bit >> 3] & (1 << (bit & 7)) ? 1 : 0;
|
1307 |
|
|
}
|
1308 |
|
|
|
1309 |
|
|
static __inline__ void ntfs_set_bit(unsigned char *byte, const int bit)
|
1310 |
|
|
{
|
1311 |
|
|
byte[bit >> 3] |= 1 << (bit & 7);
|
1312 |
|
|
}
|
1313 |
|
|
|
1314 |
|
|
static __inline__ void ntfs_clear_bit(unsigned char *byte, const int bit)
|
1315 |
|
|
{
|
1316 |
|
|
byte[bit >> 3] &= ~(1 << (bit & 7));
|
1317 |
|
|
}
|
1318 |
|
|
|
1319 |
|
|
static __inline__ int ntfs_test_and_clear_bit(unsigned char *byte,
|
1320 |
|
|
const int bit)
|
1321 |
|
|
{
|
1322 |
|
|
unsigned char *ptr = byte + (bit >> 3);
|
1323 |
|
|
int b = 1 << (bit & 7);
|
1324 |
|
|
int oldbit = *ptr & b ? 1 : 0;
|
1325 |
|
|
*ptr &= ~b;
|
1326 |
|
|
return oldbit;
|
1327 |
|
|
}
|
1328 |
|
|
|
1329 |
|
|
static void dump_runlist(const ntfs_runlist *rl, const int rlen)
|
1330 |
|
|
{
|
1331 |
|
|
#ifdef DEBUG
|
1332 |
|
|
int i;
|
1333 |
|
|
ntfs_cluster_t ct;
|
1334 |
|
|
|
1335 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): rlen = %i.\n", __FUNCTION__, rlen);
|
1336 |
|
|
ntfs_debug(DEBUG_OTHER, "VCN LCN Run length\n");
|
1337 |
|
|
for (i = 0, ct = 0; i < rlen; ct += rl[i++].len) {
|
1338 |
|
|
if (rl[i].lcn == (ntfs_cluster_t)-1)
|
1339 |
|
|
ntfs_debug(DEBUG_OTHER, "0x%-8x LCN_HOLE 0x%-8x "
|
1340 |
|
|
"(%s)\n", ct, rl[i].len, rl[i].len ?
|
1341 |
|
|
"sparse run" : "run list end");
|
1342 |
|
|
else
|
1343 |
|
|
ntfs_debug(DEBUG_OTHER, "0x%-8x 0x%-8x 0x%-8x%s\n", ct,
|
1344 |
|
|
rl[i].lcn, rl[i].len, rl[i].len &&
|
1345 |
|
|
i + 1 < rlen ? "" : " (run list end)");
|
1346 |
|
|
if (!rl[i].len)
|
1347 |
|
|
break;
|
1348 |
|
|
}
|
1349 |
|
|
#endif
|
1350 |
|
|
}
|
1351 |
|
|
|
1352 |
|
|
/**
|
1353 |
|
|
* splice_runlists - splice two run lists into one
|
1354 |
|
|
* @rl1: pointer to address of first run list
|
1355 |
|
|
* @r1len: number of elementfs in first run list
|
1356 |
|
|
* @rl2: pointer to second run list
|
1357 |
|
|
* @r2len: number of elements in second run list
|
1358 |
|
|
*
|
1359 |
|
|
* Append the run list @rl2 to the run list *@rl1 and return the result in
|
1360 |
|
|
* *@rl1 and *@r1len.
|
1361 |
|
|
*
|
1362 |
|
|
* Return 0 on success or -errno on error, in which case *@rl1 and *@r1len are
|
1363 |
|
|
* left untouched.
|
1364 |
|
|
*
|
1365 |
|
|
* The only possible error code at the moment is -ENOMEM and only happens if
|
1366 |
|
|
* there is insufficient memory to allocate the new run list (only happens
|
1367 |
|
|
* when size of (rl1 + rl2) > allocated size of rl1).
|
1368 |
|
|
*/
|
1369 |
|
|
int splice_runlists(ntfs_runlist **rl1, int *r1len, const ntfs_runlist *rl2,
|
1370 |
|
|
int r2len)
|
1371 |
|
|
{
|
1372 |
|
|
ntfs_runlist *rl;
|
1373 |
|
|
int rlen, rl_size, rl2_pos;
|
1374 |
|
|
|
1375 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Entering with *r1len = %i, "
|
1376 |
|
|
"r2len = %i.\n", __FUNCTION__, *r1len, r2len);
|
1377 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Dumping 1st runlist.\n", __FUNCTION__);
|
1378 |
|
|
if (*rl1)
|
1379 |
|
|
dump_runlist(*rl1, *r1len);
|
1380 |
|
|
else
|
1381 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Not present.\n", __FUNCTION__);
|
1382 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Dumping 2nd runlist.\n", __FUNCTION__);
|
1383 |
|
|
dump_runlist(rl2, r2len);
|
1384 |
|
|
rlen = *r1len + r2len + 1;
|
1385 |
|
|
rl_size = (rlen * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
|
1386 |
|
|
PAGE_MASK;
|
1387 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): rlen = %i, rl_size = %i.\n",
|
1388 |
|
|
__FUNCTION__, rlen, rl_size);
|
1389 |
|
|
/* Do we have enough space? */
|
1390 |
|
|
if (rl_size <= ((*r1len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
|
1391 |
|
|
PAGE_MASK)) {
|
1392 |
|
|
/* Have enough space already. */
|
1393 |
|
|
rl = *rl1;
|
1394 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Have enough space already.\n",
|
1395 |
|
|
__FUNCTION__);
|
1396 |
|
|
} else {
|
1397 |
|
|
/* Need more space. Reallocate. */
|
1398 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Need more space.\n",
|
1399 |
|
|
__FUNCTION__);
|
1400 |
|
|
rl = ntfs_vmalloc(rlen << sizeof(ntfs_runlist));
|
1401 |
|
|
if (!rl)
|
1402 |
|
|
return -ENOMEM;
|
1403 |
|
|
/* Copy over rl1. */
|
1404 |
|
|
ntfs_memcpy(rl, *rl1, *r1len * sizeof(ntfs_runlist));
|
1405 |
|
|
ntfs_vfree(*rl1);
|
1406 |
|
|
*rl1 = rl;
|
1407 |
|
|
}
|
1408 |
|
|
/* Reuse rl_size as the current position index into rl. */
|
1409 |
|
|
rl_size = *r1len - 1;
|
1410 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): rl_size = %i.\n", __FUNCTION__,rl_size);
|
1411 |
|
|
/* Coalesce neighbouring elements, if present. */
|
1412 |
|
|
rl2_pos = 0;
|
1413 |
|
|
if (rl[rl_size].lcn + rl[rl_size].len == rl2[rl2_pos].lcn) {
|
1414 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Coalescing adjacent runs.\n",
|
1415 |
|
|
__FUNCTION__);
|
1416 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before: rl[rl_size].len = %i.\n",
|
1417 |
|
|
__FUNCTION__, rl[rl_size].len);
|
1418 |
|
|
rl[rl_size].len += rl2[rl2_pos].len;
|
1419 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After: rl[rl_size].len = %i.\n",
|
1420 |
|
|
__FUNCTION__, rl[rl_size].len);
|
1421 |
|
|
rl2_pos++;
|
1422 |
|
|
r2len--;
|
1423 |
|
|
rlen--;
|
1424 |
|
|
}
|
1425 |
|
|
rl_size++;
|
1426 |
|
|
/* Copy over rl2. */
|
1427 |
|
|
ntfs_memcpy(rl + rl_size, rl2 + rl2_pos, r2len * sizeof(ntfs_runlist));
|
1428 |
|
|
rlen--;
|
1429 |
|
|
rl[rlen].lcn = (ntfs_cluster_t)-1;
|
1430 |
|
|
rl[rlen].len = (ntfs_cluster_t)0;
|
1431 |
|
|
*r1len = rlen;
|
1432 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Dumping result runlist.\n",
|
1433 |
|
|
__FUNCTION__);
|
1434 |
|
|
dump_runlist(*rl1, *r1len);
|
1435 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Returning with *r1len = %i.\n",
|
1436 |
|
|
__FUNCTION__, rlen);
|
1437 |
|
|
return 0;
|
1438 |
|
|
}
|
1439 |
|
|
|
1440 |
|
|
/**
|
1441 |
|
|
* ntfs_alloc_mft_record - allocate an mft record
|
1442 |
|
|
* @vol: volume to allocate an mft record on
|
1443 |
|
|
* @result: the mft record number allocated
|
1444 |
|
|
*
|
1445 |
|
|
* Allocate a new mft record on disk. Return 0 on success or -ERRNO on error.
|
1446 |
|
|
* On success, *@result contains the allocated mft record number. On error,
|
1447 |
|
|
* *@result is -1UL.
|
1448 |
|
|
*
|
1449 |
|
|
* Note, this function doesn't actually set the mft record to be in use. This
|
1450 |
|
|
* is done by the caller, which at the moment is only ntfs_alloc_inode().
|
1451 |
|
|
*
|
1452 |
|
|
* To find a free mft record, we scan the mft bitmap for a zero bit. To
|
1453 |
|
|
* optimize this we start scanning at the place where we last stopped and we
|
1454 |
|
|
* perform wrap around when we reach the end. Note, we do not try to allocate
|
1455 |
|
|
* mft records below number 24 because numbers 0 to 15 are the defined system
|
1456 |
|
|
* files anyway and 16 to 24 are special in that they are used for storing
|
1457 |
|
|
* extension mft records for $MFT's $DATA attribute. This is required to avoid
|
1458 |
|
|
* the possibility of creating a run list with a circular dependence which once
|
1459 |
|
|
* written to disk can never be read in again. Windows will only use records
|
1460 |
|
|
* 16 to 24 for normal files if the volume is completely out of space. We never
|
1461 |
|
|
* use them which means that when the volume is really out of space we cannot
|
1462 |
|
|
* create any more files while Windows can still create up to 8 small files. We
|
1463 |
|
|
* can start doing this at some later time, doesn't matter much for now.
|
1464 |
|
|
*
|
1465 |
|
|
* When scanning the mft bitmap, we only search up to the last allocated mft
|
1466 |
|
|
* record. If there are no free records left in the range 24 to number of
|
1467 |
|
|
* allocated mft records, then we extend the mft data in order to create free
|
1468 |
|
|
* mft records. We extend the allocated size of $MFT/$DATA by 16 records at a
|
1469 |
|
|
* time or one cluster, if cluster size is above 16kiB. If there isn't
|
1470 |
|
|
* sufficient space to do this, we try to extend by a single mft record or one
|
1471 |
|
|
* cluster, if cluster size is above mft record size, but we only do this if
|
1472 |
|
|
* there is enough free space, which we know from the values returned by the
|
1473 |
|
|
* failed cluster allocation function when we tried to do the first allocation.
|
1474 |
|
|
*
|
1475 |
|
|
* No matter how many mft records we allocate, we initialize only the first
|
1476 |
|
|
* allocated mft record (incrementing mft data size and initialized size) and
|
1477 |
|
|
* return its number to the caller in @*result, unless there are less than 24
|
1478 |
|
|
* mft records, in which case we allocate and initialize mft records until we
|
1479 |
|
|
* reach record 24 which we consider as the first free mft record for use by
|
1480 |
|
|
* normal files.
|
1481 |
|
|
*
|
1482 |
|
|
* If during any stage we overflow the initialized data in the mft bitmap, we
|
1483 |
|
|
* extend the initialized size (and data size) by 8 bytes, allocating another
|
1484 |
|
|
* cluster if required. The bitmap data size has to be at least equal to the
|
1485 |
|
|
* number of mft records in the mft, but it can be bigger, in which case the
|
1486 |
|
|
* superflous bits are padded with zeroes.
|
1487 |
|
|
*
|
1488 |
|
|
* Thus, when we return successfully (return value 0), we will have:
|
1489 |
|
|
* - initialized / extended the mft bitmap if necessary,
|
1490 |
|
|
* - initialized / extended the mft data if necessary,
|
1491 |
|
|
* - set the bit corresponding to the mft record being allocated in the
|
1492 |
|
|
* mft bitmap, and we will
|
1493 |
|
|
* - return the mft record number in @*result.
|
1494 |
|
|
*
|
1495 |
|
|
* On error (return value below zero), nothing will have changed. If we had
|
1496 |
|
|
* changed anything before the error occured, we will have reverted back to
|
1497 |
|
|
* the starting state before returning to the caller. Thus, except for bugs,
|
1498 |
|
|
* we should always leave the volume in a consitents state when returning from
|
1499 |
|
|
* this function. NOTE: Small exception to this is that we set the bit in the
|
1500 |
|
|
* mft bitmap but we do not mark the mft record in use, which is inconsistent.
|
1501 |
|
|
* However, the caller will immediately add the wanted attributes to the mft
|
1502 |
|
|
* record, set it in use and write it out to disk, so there should be no
|
1503 |
|
|
* problem.
|
1504 |
|
|
*
|
1505 |
|
|
* Note, this function cannot make use of most of the normal functions, like
|
1506 |
|
|
* for example for attribute resizing, etc, because when the run list overflows
|
1507 |
|
|
* the base mft record and an attribute list is used, it is very important
|
1508 |
|
|
* that the extension mft records used to store the $DATA attribute of $MFT
|
1509 |
|
|
* can be reached without having to read the information contained inside
|
1510 |
|
|
* them, as this would make it impossible to find them in the first place
|
1511 |
|
|
* after the volume is dismounted. $MFT/$BITMAP probably doesn't need to
|
1512 |
|
|
* follow this rule because the bitmap is not essential for finding the mft
|
1513 |
|
|
* records, but on the other hand, handling the bitmap in this special way
|
1514 |
|
|
* would make life easier because otherwise there might be circular invocations
|
1515 |
|
|
* of functions when reading the bitmap but if we are careful, we should be
|
1516 |
|
|
* able to avoid all problems.
|
1517 |
|
|
*
|
1518 |
|
|
* FIXME: Don't forget $MftMirr, though this probably belongs in
|
1519 |
|
|
* ntfs_update_inode() (or even deeper). (AIA)
|
1520 |
|
|
*
|
1521 |
|
|
* FIXME: Want finer grained locking. (AIA)
|
1522 |
|
|
*/
|
1523 |
|
|
static int ntfs_alloc_mft_record(ntfs_volume *vol, unsigned long *result)
|
1524 |
|
|
{
|
1525 |
|
|
unsigned long nr_mft_records, buf_size, buf_pos, pass_start, pass_end;
|
1526 |
|
|
unsigned long last_read_pos, mft_rec_size, bit, l;
|
1527 |
|
|
ntfs_attribute *data, *bmp;
|
1528 |
|
|
__u8 *buf, *byte, pass, b, have_allocated_mftbmp = 0;
|
1529 |
|
|
int rlen, rl_size = 0, r2len, rl2_size, old_data_rlen, err = 0;
|
1530 |
|
|
ntfs_runlist *rl, *rl2;
|
1531 |
|
|
ntfs_cluster_t lcn = 0, old_data_len;
|
1532 |
|
|
ntfs_io io;
|
1533 |
|
|
__s64 ll, old_data_allocated, old_data_initialized, old_data_size;
|
1534 |
|
|
|
1535 |
|
|
*result = -1UL;
|
1536 |
|
|
/* Allocate a buffer and setup the io structure. */
|
1537 |
|
|
buf = (__u8*)__get_free_page(GFP_NOFS);
|
1538 |
|
|
if (!buf)
|
1539 |
|
|
return -ENOMEM;
|
1540 |
|
|
lock_kernel();
|
1541 |
|
|
/* Get the $DATA and $BITMAP attributes of $MFT. */
|
1542 |
|
|
data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
|
1543 |
|
|
bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
|
1544 |
|
|
if (!data || !bmp) {
|
1545 |
|
|
err = -EINVAL;
|
1546 |
|
|
goto err_ret;
|
1547 |
|
|
}
|
1548 |
|
|
/* Determine the number of allocated mft records in the mft. */
|
1549 |
|
|
pass_end = nr_mft_records = data->allocated >>
|
1550 |
|
|
vol->mft_record_size_bits;
|
1551 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): nr_mft_records = %lu.\n", __FUNCTION__,
|
1552 |
|
|
nr_mft_records);
|
1553 |
|
|
/* Make sure we don't overflow the bitmap. */
|
1554 |
|
|
l = bmp->initialized << 3;
|
1555 |
|
|
if (l < nr_mft_records)
|
1556 |
|
|
// FIXME: It might be a good idea to extend the bitmap instead.
|
1557 |
|
|
pass_end = l;
|
1558 |
|
|
pass = 1;
|
1559 |
|
|
buf_pos = vol->mft_data_pos;
|
1560 |
|
|
if (buf_pos >= pass_end) {
|
1561 |
|
|
buf_pos = 24UL;
|
1562 |
|
|
pass = 2;
|
1563 |
|
|
}
|
1564 |
|
|
pass_start = buf_pos;
|
1565 |
|
|
rl = bmp->d.r.runlist;
|
1566 |
|
|
rlen = bmp->d.r.len - 1;
|
1567 |
|
|
lcn = rl[rlen].lcn + rl[rlen].len;
|
1568 |
|
|
io.fn_put = ntfs_put;
|
1569 |
|
|
io.fn_get = ntfs_get;
|
1570 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Starting bitmap search.\n",
|
1571 |
|
|
__FUNCTION__);
|
1572 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): pass = %i, pass_start = %lu, pass_end = "
|
1573 |
|
|
"%lu.\n", __FUNCTION__, pass, pass_start, pass_end);
|
1574 |
|
|
byte = NULL; // FIXME: For debugging only.
|
1575 |
|
|
/* Loop until a free mft record is found. */
|
1576 |
|
|
io.size = (nr_mft_records >> 3) & ~PAGE_MASK;
|
1577 |
|
|
for (;; io.size = PAGE_SIZE) {
|
1578 |
|
|
io.param = buf;
|
1579 |
|
|
io.do_read = 1;
|
1580 |
|
|
last_read_pos = buf_pos >> 3;
|
1581 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
|
1582 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1583 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1584 |
|
|
bmp->size, bmp->initialized);
|
1585 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, last_read_pos,
|
1586 |
|
|
&io);
|
1587 |
|
|
if (err)
|
1588 |
|
|
goto err_ret;
|
1589 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n", __FUNCTION__,
|
1590 |
|
|
(unsigned long)io.size);
|
1591 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
|
1592 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1593 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1594 |
|
|
bmp->size, bmp->initialized);
|
1595 |
|
|
if (!io.size)
|
1596 |
|
|
goto pass_done;
|
1597 |
|
|
buf_size = io.size << 3;
|
1598 |
|
|
bit = buf_pos & 7UL;
|
1599 |
|
|
buf_pos &= ~7UL;
|
1600 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before loop: buf_size = %lu, "
|
1601 |
|
|
"buf_pos = %lu, bit = %lu, *byte = 0x%x, b = "
|
1602 |
|
|
"%u.\n", __FUNCTION__, buf_size, buf_pos, bit,
|
1603 |
|
|
byte ? *byte : -1, b);
|
1604 |
|
|
for (; bit < buf_size && bit + buf_pos < pass_end;
|
1605 |
|
|
bit &= ~7UL, bit += 8UL) {
|
1606 |
|
|
byte = buf + (bit >> 3);
|
1607 |
|
|
if (*byte == 0xff)
|
1608 |
|
|
continue;
|
1609 |
|
|
b = ffz((unsigned long)*byte);
|
1610 |
|
|
if (b < (__u8)8 && b >= (bit & 7UL)) {
|
1611 |
|
|
bit = b + (bit & ~7UL) + buf_pos;
|
1612 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Found free rec "
|
1613 |
|
|
"in for loop. bit = %lu\n",
|
1614 |
|
|
__FUNCTION__, bit);
|
1615 |
|
|
goto found_free_rec;
|
1616 |
|
|
}
|
1617 |
|
|
}
|
1618 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After loop: buf_size = %lu, "
|
1619 |
|
|
"buf_pos = %lu, bit = %lu, *byte = 0x%x, b = "
|
1620 |
|
|
"%u.\n", __FUNCTION__, buf_size, buf_pos, bit,
|
1621 |
|
|
byte ? *byte : -1, b);
|
1622 |
|
|
buf_pos += buf_size;
|
1623 |
|
|
if (buf_pos < pass_end)
|
1624 |
|
|
continue;
|
1625 |
|
|
pass_done: /* Finished with the current pass. */
|
1626 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At pass_done.\n", __FUNCTION__);
|
1627 |
|
|
if (pass == 1) {
|
1628 |
|
|
/*
|
1629 |
|
|
* Now do pass 2, scanning the first part of the zone
|
1630 |
|
|
* we omitted in pass 1.
|
1631 |
|
|
*/
|
1632 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Done pass 1.\n",
|
1633 |
|
|
__FUNCTION__);
|
1634 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Pass = 2.\n",
|
1635 |
|
|
__FUNCTION__);
|
1636 |
|
|
pass = 2;
|
1637 |
|
|
pass_end = pass_start;
|
1638 |
|
|
buf_pos = pass_start = 24UL;
|
1639 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): pass = %i, pass_start = "
|
1640 |
|
|
"%lu, pass_end = %lu.\n", __FUNCTION__,
|
1641 |
|
|
pass, pass_start, pass_end);
|
1642 |
|
|
continue;
|
1643 |
|
|
} /* pass == 2 */
|
1644 |
|
|
/* No free records left. */
|
1645 |
|
|
if (bmp->initialized << 3 > nr_mft_records &&
|
1646 |
|
|
bmp->initialized > 3) {
|
1647 |
|
|
/*
|
1648 |
|
|
* The mft bitmap is already bigger but the space is
|
1649 |
|
|
* not covered by mft records, this implies that the
|
1650 |
|
|
* next records are all free, so we already have found
|
1651 |
|
|
* a free record.
|
1652 |
|
|
*/
|
1653 |
|
|
bit = nr_mft_records;
|
1654 |
|
|
if (bit < 24UL)
|
1655 |
|
|
bit = 24UL;
|
1656 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Found free record bit "
|
1657 |
|
|
"(#1) = 0x%lx.\n", __FUNCTION__, bit);
|
1658 |
|
|
goto found_free_rec;
|
1659 |
|
|
}
|
1660 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Done pass 2.\n", __FUNCTION__);
|
1661 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
|
1662 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1663 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1664 |
|
|
bmp->size, bmp->initialized);
|
1665 |
|
|
/* Need to extend the mft bitmap. */
|
1666 |
|
|
if (bmp->initialized + 8LL > bmp->allocated) {
|
1667 |
|
|
ntfs_io io2;
|
1668 |
|
|
|
1669 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Initialized "
|
1670 |
|
|
"> allocated.\n", __FUNCTION__);
|
1671 |
|
|
/* Need to extend bitmap by one more cluster. */
|
1672 |
|
|
rl = bmp->d.r.runlist;
|
1673 |
|
|
rlen = bmp->d.r.len - 1;
|
1674 |
|
|
lcn = rl[rlen].lcn + rl[rlen].len;
|
1675 |
|
|
io2.fn_put = ntfs_put;
|
1676 |
|
|
io2.fn_get = ntfs_get;
|
1677 |
|
|
io2.param = &b;
|
1678 |
|
|
io2.size = 1;
|
1679 |
|
|
io2.do_read = 1;
|
1680 |
|
|
err = ntfs_readwrite_attr(vol->bitmap, data, lcn >> 3,
|
1681 |
|
|
&io2);
|
1682 |
|
|
if (err)
|
1683 |
|
|
goto err_ret;
|
1684 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n",
|
1685 |
|
|
__FUNCTION__, (unsigned long)io2.size);
|
1686 |
|
|
if (io2.size == 1 && b != 0xff) {
|
1687 |
|
|
__u8 tb = 1 << (lcn & (ntfs_cluster_t)7);
|
1688 |
|
|
if (!(b & tb)) {
|
1689 |
|
|
/* Next cluster is free. Allocate it. */
|
1690 |
|
|
b |= tb;
|
1691 |
|
|
io2.param = &b;
|
1692 |
|
|
io2.do_read = 0;
|
1693 |
|
|
err = ntfs_readwrite_attr(vol->bitmap,
|
1694 |
|
|
data, lcn >> 3, &io2);
|
1695 |
|
|
if (err || io.size != 1) {
|
1696 |
|
|
if (!err)
|
1697 |
|
|
err = -EIO;
|
1698 |
|
|
goto err_ret;
|
1699 |
|
|
}
|
1700 |
|
|
append_mftbmp_simple: rl[rlen].len++;
|
1701 |
|
|
have_allocated_mftbmp |= 1;
|
1702 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): "
|
1703 |
|
|
"Appending one cluster "
|
1704 |
|
|
"to mftbmp.\n",
|
1705 |
|
|
__FUNCTION__);
|
1706 |
|
|
}
|
1707 |
|
|
}
|
1708 |
|
|
if (!have_allocated_mftbmp) {
|
1709 |
|
|
/* Allocate a cluster from the DATA_ZONE. */
|
1710 |
|
|
ntfs_cluster_t lcn2 = lcn;
|
1711 |
|
|
ntfs_cluster_t count = 1;
|
1712 |
|
|
err = ntfs_allocate_clusters(vol, &lcn2,
|
1713 |
|
|
&count, &rl2, &r2len,
|
1714 |
|
|
DATA_ZONE);
|
1715 |
|
|
if (err)
|
1716 |
|
|
goto err_ret;
|
1717 |
|
|
if (count != 1 || lcn2 <= 0) {
|
1718 |
|
|
if (count > 0) {
|
1719 |
|
|
rl2_dealloc_err_out: if (ntfs_deallocate_clusters(
|
1720 |
|
|
vol, rl2, r2len))
|
1721 |
|
|
ntfs_error("%s(): "
|
1722 |
|
|
"Cluster "
|
1723 |
|
|
"deallocation in error "
|
1724 |
|
|
"code path failed! You "
|
1725 |
|
|
"should run chkdsk.\n",
|
1726 |
|
|
__FUNCTION__);
|
1727 |
|
|
}
|
1728 |
|
|
ntfs_vfree(rl2);
|
1729 |
|
|
if (!err)
|
1730 |
|
|
err = -EINVAL;
|
1731 |
|
|
goto err_ret;
|
1732 |
|
|
}
|
1733 |
|
|
if (lcn2 == lcn) {
|
1734 |
|
|
ntfs_vfree(rl2);
|
1735 |
|
|
goto append_mftbmp_simple;
|
1736 |
|
|
}
|
1737 |
|
|
/* We need to append a new run. */
|
1738 |
|
|
rl_size = (rlen * sizeof(ntfs_runlist) +
|
1739 |
|
|
PAGE_SIZE - 1) & PAGE_MASK;
|
1740 |
|
|
/* Reallocate memory if necessary. */
|
1741 |
|
|
if ((rlen + 2) * sizeof(ntfs_runlist) >=
|
1742 |
|
|
rl_size) {
|
1743 |
|
|
ntfs_runlist *rlt;
|
1744 |
|
|
|
1745 |
|
|
rl_size += PAGE_SIZE;
|
1746 |
|
|
rlt = ntfs_vmalloc(rl_size);
|
1747 |
|
|
if (!rlt) {
|
1748 |
|
|
err = -ENOMEM;
|
1749 |
|
|
goto rl2_dealloc_err_out;
|
1750 |
|
|
}
|
1751 |
|
|
ntfs_memcpy(rlt, rl, rl_size -
|
1752 |
|
|
PAGE_SIZE);
|
1753 |
|
|
ntfs_vfree(rl);
|
1754 |
|
|
bmp->d.r.runlist = rl = rlt;
|
1755 |
|
|
}
|
1756 |
|
|
ntfs_vfree(rl2);
|
1757 |
|
|
rl[rlen].lcn = lcn = lcn2;
|
1758 |
|
|
rl[rlen].len = count;
|
1759 |
|
|
bmp->d.r.len = ++rlen;
|
1760 |
|
|
have_allocated_mftbmp |= 2;
|
1761 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Adding run to "
|
1762 |
|
|
"mftbmp. LCN = %i, len = %i\n",
|
1763 |
|
|
__FUNCTION__, lcn, count);
|
1764 |
|
|
}
|
1765 |
|
|
/*
|
1766 |
|
|
* We now have extended the mft bitmap allocated size
|
1767 |
|
|
* by one cluster. Reflect this in the attribute.
|
1768 |
|
|
*/
|
1769 |
|
|
bmp->allocated += (__s64)vol->cluster_size;
|
1770 |
|
|
}
|
1771 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
|
1772 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1773 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1774 |
|
|
bmp->size, bmp->initialized);
|
1775 |
|
|
/* We now have sufficient allocated space. */
|
1776 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Now have sufficient allocated "
|
1777 |
|
|
"space in mftbmp.\n", __FUNCTION__);
|
1778 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
|
1779 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1780 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1781 |
|
|
bmp->size, bmp->initialized);
|
1782 |
|
|
buf_pos = bmp->initialized;
|
1783 |
|
|
bmp->initialized += 8LL;
|
1784 |
|
|
if (bmp->initialized > bmp->size)
|
1785 |
|
|
bmp->size = bmp->initialized;
|
1786 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
|
1787 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = "
|
1788 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1789 |
|
|
bmp->size, bmp->initialized);
|
1790 |
|
|
have_allocated_mftbmp |= 4;
|
1791 |
|
|
/* Update the mft bitmap attribute value. */
|
1792 |
|
|
memset(buf, 0, 8);
|
1793 |
|
|
io.param = buf;
|
1794 |
|
|
io.size = 8;
|
1795 |
|
|
io.do_read = 0;
|
1796 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, buf_pos, &io);
|
1797 |
|
|
if (err || io.size != 8) {
|
1798 |
|
|
if (!err)
|
1799 |
|
|
err = -EIO;
|
1800 |
|
|
goto shrink_mftbmp_err_ret;
|
1801 |
|
|
}
|
1802 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Wrote extended mftbmp bytes "
|
1803 |
|
|
"%lu.\n", __FUNCTION__, (unsigned long)io.size);
|
1804 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After write: bmp->allocated = "
|
1805 |
|
|
"0x%Lx, bmp->size = 0x%Lx, bmp->initialized = "
|
1806 |
|
|
"0x%Lx.\n", __FUNCTION__, bmp->allocated,
|
1807 |
|
|
bmp->size, bmp->initialized);
|
1808 |
|
|
bit = buf_pos << 3;
|
1809 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Found free record bit (#2) = "
|
1810 |
|
|
"0x%lx.\n", __FUNCTION__, bit);
|
1811 |
|
|
goto found_free_rec;
|
1812 |
|
|
}
|
1813 |
|
|
found_free_rec:
|
1814 |
|
|
/* bit is the found free mft record. Allocate it in the mft bitmap. */
|
1815 |
|
|
vol->mft_data_pos = bit;
|
1816 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At found_free_rec.\n", __FUNCTION__);
|
1817 |
|
|
io.param = buf;
|
1818 |
|
|
io.size = 1;
|
1819 |
|
|
io.do_read = 1;
|
1820 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Before update: bmp->allocated = 0x%Lx, "
|
1821 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = 0x%Lx.\n",
|
1822 |
|
|
__FUNCTION__, bmp->allocated,
|
1823 |
|
|
bmp->size, bmp->initialized);
|
1824 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
|
1825 |
|
|
if (err || io.size != 1) {
|
1826 |
|
|
if (!err)
|
1827 |
|
|
err = -EIO;
|
1828 |
|
|
goto shrink_mftbmp_err_ret;
|
1829 |
|
|
}
|
1830 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n", __FUNCTION__,
|
1831 |
|
|
(unsigned long)io.size);
|
1832 |
|
|
#ifdef DEBUG
|
1833 |
|
|
/* Check our bit is really zero! */
|
1834 |
|
|
if (*buf & (1 << (bit & 7)))
|
1835 |
|
|
BUG();
|
1836 |
|
|
#endif
|
1837 |
|
|
*buf |= 1 << (bit & 7);
|
1838 |
|
|
io.param = buf;
|
1839 |
|
|
io.do_read = 0;
|
1840 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
|
1841 |
|
|
if (err || io.size != 1) {
|
1842 |
|
|
if (!err)
|
1843 |
|
|
err = -EIO;
|
1844 |
|
|
goto shrink_mftbmp_err_ret;
|
1845 |
|
|
}
|
1846 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Wrote %lu bytes.\n", __FUNCTION__,
|
1847 |
|
|
(unsigned long)io.size);
|
1848 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After update: bmp->allocated = 0x%Lx, "
|
1849 |
|
|
"bmp->size = 0x%Lx, bmp->initialized = 0x%Lx.\n",
|
1850 |
|
|
__FUNCTION__, bmp->allocated,
|
1851 |
|
|
bmp->size, bmp->initialized);
|
1852 |
|
|
/* The mft bitmap is now uptodate. Deal with mft data attribute now. */
|
1853 |
|
|
ll = (__s64)(bit + 1) << vol->mft_record_size_bits;
|
1854 |
|
|
if (ll <= data->initialized) {
|
1855 |
|
|
/* The allocated record is already initialized. We are done! */
|
1856 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Allocated mft record "
|
1857 |
|
|
"already initialized!\n", __FUNCTION__);
|
1858 |
|
|
goto done_ret;
|
1859 |
|
|
}
|
1860 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Allocated mft record needs "
|
1861 |
|
|
"to be initialized.\n", __FUNCTION__);
|
1862 |
|
|
/* The mft record is outside the initialized data. */
|
1863 |
|
|
mft_rec_size = (unsigned long)vol->mft_record_size;
|
1864 |
|
|
/* Preserve old values for undo purposes. */
|
1865 |
|
|
old_data_allocated = data->allocated;
|
1866 |
|
|
old_data_rlen = data->d.r.len - 1;
|
1867 |
|
|
old_data_len = data->d.r.runlist[old_data_rlen].len;
|
1868 |
|
|
/*
|
1869 |
|
|
* If necessary, extend the mft until it covers the allocated record.
|
1870 |
|
|
* The loop is only actually used when a freshly formatted volume is
|
1871 |
|
|
* first written to. But it optimizes away nicely in the common case.
|
1872 |
|
|
*/
|
1873 |
|
|
while (ll > data->allocated) {
|
1874 |
|
|
ntfs_cluster_t lcn2, nr_lcn2, nr, min_nr;
|
1875 |
|
|
|
1876 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Extending mft data allocation, "
|
1877 |
|
|
"data->allocated = 0x%Lx, data->size = 0x%Lx, "
|
1878 |
|
|
"data->initialized = 0x%Lx.\n", __FUNCTION__,
|
1879 |
|
|
data->allocated, data->size, data->initialized);
|
1880 |
|
|
/* Minimum allocation is one mft record worth of clusters. */
|
1881 |
|
|
if (mft_rec_size <= vol->cluster_size)
|
1882 |
|
|
min_nr = (ntfs_cluster_t)1;
|
1883 |
|
|
else
|
1884 |
|
|
min_nr = mft_rec_size >> vol->cluster_size_bits;
|
1885 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): min_nr = %i.\n", __FUNCTION__,
|
1886 |
|
|
min_nr);
|
1887 |
|
|
/* Allocate 16 mft records worth of clusters. */
|
1888 |
|
|
nr = mft_rec_size << 4 >> vol->cluster_size_bits;
|
1889 |
|
|
if (!nr)
|
1890 |
|
|
nr = (ntfs_cluster_t)1;
|
1891 |
|
|
/* Determine the preferred allocation location. */
|
1892 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): nr = %i.\n", __FUNCTION__, nr);
|
1893 |
|
|
rl2 = data->d.r.runlist;
|
1894 |
|
|
r2len = data->d.r.len;
|
1895 |
|
|
lcn2 = rl2[r2len - 1].lcn + rl2[r2len - 1].len;
|
1896 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): rl2[r2len - 1].lcn = %i, .len = "
|
1897 |
|
|
"%i.\n", __FUNCTION__, rl2[r2len - 1].lcn,
|
1898 |
|
|
rl2[r2len - 1].len);
|
1899 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): lcn2 = %i, r2len = %i.\n",
|
1900 |
|
|
__FUNCTION__, lcn2, r2len);
|
1901 |
|
|
retry_mft_data_allocation:
|
1902 |
|
|
nr_lcn2 = nr;
|
1903 |
|
|
err = ntfs_allocate_clusters(vol, &lcn2, &nr_lcn2, &rl2,
|
1904 |
|
|
&r2len, MFT_ZONE);
|
1905 |
|
|
#ifdef DEBUG
|
1906 |
|
|
if (!err && nr_lcn2 < min_nr)
|
1907 |
|
|
/* Allocated less than minimum needed. Weird! */
|
1908 |
|
|
BUG();
|
1909 |
|
|
#endif
|
1910 |
|
|
if (err) {
|
1911 |
|
|
/*
|
1912 |
|
|
* If there isn't enough space to do the wanted
|
1913 |
|
|
* allocation, but there is enough space to do a
|
1914 |
|
|
* minimal allocation, then try that, unless the wanted
|
1915 |
|
|
* allocation was already the minimal allocation.
|
1916 |
|
|
*/
|
1917 |
|
|
if (err == -ENOSPC && nr > min_nr &&
|
1918 |
|
|
nr_lcn2 >= min_nr) {
|
1919 |
|
|
nr = min_nr;
|
1920 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Retrying mft "
|
1921 |
|
|
"data allocation, nr = min_nr "
|
1922 |
|
|
"= %i.\n", __FUNCTION__, nr);
|
1923 |
|
|
goto retry_mft_data_allocation;
|
1924 |
|
|
}
|
1925 |
|
|
goto undo_mftbmp_alloc_err_ret;
|
1926 |
|
|
}
|
1927 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Allocated %i clusters starting "
|
1928 |
|
|
"at LCN %i.\n", __FUNCTION__, nr_lcn2, lcn2);
|
1929 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Allocated runlist:\n",
|
1930 |
|
|
__FUNCTION__);
|
1931 |
|
|
dump_runlist(rl2, r2len);
|
1932 |
|
|
/* Append rl2 to the mft data attribute's run list. */
|
1933 |
|
|
err = splice_runlists(&data->d.r.runlist, (int*)&data->d.r.len,
|
1934 |
|
|
rl2, r2len);
|
1935 |
|
|
if (err) {
|
1936 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): splice_runlists failed "
|
1937 |
|
|
"with error code %i.\n", __FUNCTION__,
|
1938 |
|
|
-err);
|
1939 |
|
|
goto undo_partial_data_alloc_err_ret;
|
1940 |
|
|
}
|
1941 |
|
|
/* Reflect the allocated clusters in the mft allocated data. */
|
1942 |
|
|
data->allocated += nr_lcn2 << vol->cluster_size_bits;
|
1943 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After extending mft data "
|
1944 |
|
|
"allocation, data->allocated = 0x%Lx, "
|
1945 |
|
|
"data->size = 0x%Lx, data->initialized = "
|
1946 |
|
|
"0x%Lx.\n", __FUNCTION__, data->allocated,
|
1947 |
|
|
data->size, data->initialized);
|
1948 |
|
|
}
|
1949 |
|
|
/* Prepare a formatted (empty) mft record. */
|
1950 |
|
|
memset(buf, 0, mft_rec_size);
|
1951 |
|
|
ntfs_fill_mft_header(buf, mft_rec_size, 0, 0, 0);
|
1952 |
|
|
err = ntfs_insert_fixups(buf, mft_rec_size);
|
1953 |
|
|
if (err)
|
1954 |
|
|
goto undo_data_alloc_err_ret;
|
1955 |
|
|
/*
|
1956 |
|
|
* Extend mft data initialized size to reach the allocated mft record
|
1957 |
|
|
* and write the formatted mft record buffer to each mft record being
|
1958 |
|
|
* initialized. Note, that ntfs_readwrite_attr extends both
|
1959 |
|
|
* data->initialized and data->size, so no need for us to touch them.
|
1960 |
|
|
*/
|
1961 |
|
|
old_data_initialized = data->initialized;
|
1962 |
|
|
old_data_size = data->size;
|
1963 |
|
|
while (ll > data->initialized) {
|
1964 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Initializing mft record "
|
1965 |
|
|
"0x%Lx.\n", __FUNCTION__,
|
1966 |
|
|
data->initialized >> vol->mft_record_size_bits);
|
1967 |
|
|
io.param = buf;
|
1968 |
|
|
io.size = mft_rec_size;
|
1969 |
|
|
io.do_read = 0;
|
1970 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, data,
|
1971 |
|
|
data->initialized, &io);
|
1972 |
|
|
if (err || io.size != mft_rec_size) {
|
1973 |
|
|
if (!err)
|
1974 |
|
|
err = -EIO;
|
1975 |
|
|
goto undo_data_init_err_ret;
|
1976 |
|
|
}
|
1977 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Wrote %i bytes to mft data.\n",
|
1978 |
|
|
__FUNCTION__, io.size);
|
1979 |
|
|
}
|
1980 |
|
|
/* Update the VFS inode size as well. */
|
1981 |
|
|
VFS_I(vol->mft_ino)->i_size = data->size;
|
1982 |
|
|
#ifdef DEBUG
|
1983 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): After mft record "
|
1984 |
|
|
"initialization: data->allocated = 0x%Lx, data->size "
|
1985 |
|
|
"= 0x%Lx, data->initialized = 0x%Lx.\n", __FUNCTION__,
|
1986 |
|
|
data->allocated, data->size, data->initialized);
|
1987 |
|
|
/* Sanity checks. */
|
1988 |
|
|
if (data->size > data->allocated || data->size < data->initialized ||
|
1989 |
|
|
data->initialized > data->allocated)
|
1990 |
|
|
BUG();
|
1991 |
|
|
#endif
|
1992 |
|
|
done_ret:
|
1993 |
|
|
/* Return the number of the allocated mft record. */
|
1994 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At done_ret. *result = bit = 0x%lx.\n",
|
1995 |
|
|
__FUNCTION__, bit);
|
1996 |
|
|
*result = bit;
|
1997 |
|
|
vol->mft_data_pos = bit + 1;
|
1998 |
|
|
err_ret:
|
1999 |
|
|
unlock_kernel();
|
2000 |
|
|
free_page((unsigned long)buf);
|
2001 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): Syncing inode $MFT.\n", __FUNCTION__);
|
2002 |
|
|
if (ntfs_update_inode(vol->mft_ino))
|
2003 |
|
|
ntfs_error("%s(): Failed to sync inode $MFT. "
|
2004 |
|
|
"Continuing anyway.\n",__FUNCTION__);
|
2005 |
|
|
if (!err) {
|
2006 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): Done. Allocated mft record "
|
2007 |
|
|
"number *result = 0x%lx.\n", __FUNCTION__,
|
2008 |
|
|
*result);
|
2009 |
|
|
return 0;
|
2010 |
|
|
}
|
2011 |
|
|
if (err != -ENOSPC)
|
2012 |
|
|
ntfs_error("%s(): Failed to allocate an mft record. Returning "
|
2013 |
|
|
"error code %i.\n", __FUNCTION__, -err);
|
2014 |
|
|
else
|
2015 |
|
|
ntfs_debug(DEBUG_FILE3, "%s(): Failed to allocate an mft "
|
2016 |
|
|
"record due to lack of free space.\n",
|
2017 |
|
|
__FUNCTION__);
|
2018 |
|
|
return err;
|
2019 |
|
|
undo_data_init_err_ret:
|
2020 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At undo_data_init_err_ret.\n",
|
2021 |
|
|
__FUNCTION__);
|
2022 |
|
|
data->initialized = old_data_initialized;
|
2023 |
|
|
data->size = old_data_size;
|
2024 |
|
|
undo_data_alloc_err_ret:
|
2025 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At undo_data_alloc_err_ret.\n",
|
2026 |
|
|
__FUNCTION__);
|
2027 |
|
|
data->allocated = old_data_allocated;
|
2028 |
|
|
undo_partial_data_alloc_err_ret:
|
2029 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At undo_partial_data_alloc_err_ret.\n",
|
2030 |
|
|
__FUNCTION__);
|
2031 |
|
|
/* Deallocate the clusters. */
|
2032 |
|
|
if (ntfs_deallocate_clusters(vol, rl2, r2len))
|
2033 |
|
|
ntfs_error("%s(): Error deallocating clusters in error code "
|
2034 |
|
|
"path. You should run chkdsk.\n", __FUNCTION__);
|
2035 |
|
|
ntfs_vfree(rl2);
|
2036 |
|
|
/* Revert the run list back to what it was before. */
|
2037 |
|
|
r2len = data->d.r.len;
|
2038 |
|
|
rl2 = data->d.r.runlist;
|
2039 |
|
|
rl2[old_data_rlen++].len = old_data_len;
|
2040 |
|
|
rl2[old_data_rlen].lcn = (ntfs_cluster_t)-1;
|
2041 |
|
|
rl2[old_data_rlen].len = (ntfs_cluster_t)0;
|
2042 |
|
|
data->d.r.len = old_data_rlen;
|
2043 |
|
|
rl2_size = ((old_data_rlen + 1) * sizeof(ntfs_runlist) + PAGE_SIZE -
|
2044 |
|
|
1) & PAGE_MASK;
|
2045 |
|
|
/* Reallocate memory freeing any extra memory allocated. */
|
2046 |
|
|
if (rl2_size < ((r2len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
|
2047 |
|
|
PAGE_MASK)) {
|
2048 |
|
|
rl2 = ntfs_vmalloc(rl2_size);
|
2049 |
|
|
if (rl2) {
|
2050 |
|
|
ntfs_memcpy(rl2, data->d.r.runlist, rl2_size);
|
2051 |
|
|
ntfs_vfree(data->d.r.runlist);
|
2052 |
|
|
data->d.r.runlist = rl2;
|
2053 |
|
|
} else
|
2054 |
|
|
ntfs_error("%s(): Error reallocating "
|
2055 |
|
|
"memory in error code path. This "
|
2056 |
|
|
"should be harmless.\n", __FUNCTION__);
|
2057 |
|
|
}
|
2058 |
|
|
undo_mftbmp_alloc_err_ret:
|
2059 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At undo_mftbmp_alloc_err_ret.\n",
|
2060 |
|
|
__FUNCTION__);
|
2061 |
|
|
/* Deallocate the allocated bit in the mft bitmap. */
|
2062 |
|
|
io.param = buf;
|
2063 |
|
|
io.size = 1;
|
2064 |
|
|
io.do_read = 1;
|
2065 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
|
2066 |
|
|
if (!err && io.size == 1) {
|
2067 |
|
|
*buf &= ~(1 << (bit & 7));
|
2068 |
|
|
io.param = buf;
|
2069 |
|
|
io.do_read = 0;
|
2070 |
|
|
err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
|
2071 |
|
|
}
|
2072 |
|
|
if (err || io.size != 1) {
|
2073 |
|
|
if (!err)
|
2074 |
|
|
err = -EIO;
|
2075 |
|
|
ntfs_error("%s(): Error deallocating mft record in error code "
|
2076 |
|
|
"path. You should run chkdsk.\n", __FUNCTION__);
|
2077 |
|
|
}
|
2078 |
|
|
shrink_mftbmp_err_ret:
|
2079 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): At shrink_mftbmp_err_ret.\n",
|
2080 |
|
|
__FUNCTION__);
|
2081 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): have_allocated_mftbmp = %i.\n",
|
2082 |
|
|
__FUNCTION__, have_allocated_mftbmp);
|
2083 |
|
|
if (!have_allocated_mftbmp)
|
2084 |
|
|
goto err_ret;
|
2085 |
|
|
/* Shrink the mftbmp back to previous size. */
|
2086 |
|
|
if (bmp->size == bmp->initialized)
|
2087 |
|
|
bmp->size -= 8LL;
|
2088 |
|
|
bmp->initialized -= 8LL;
|
2089 |
|
|
have_allocated_mftbmp &= ~4;
|
2090 |
|
|
/* If no allocation occured then we are done. */
|
2091 |
|
|
ntfs_debug(DEBUG_OTHER, "%s(): have_allocated_mftbmp = %i.\n",
|
2092 |
|
|
__FUNCTION__, have_allocated_mftbmp);
|
2093 |
|
|
if (!have_allocated_mftbmp)
|
2094 |
|
|
goto err_ret;
|
2095 |
|
|
/* Deallocate the allocated cluster. */
|
2096 |
|
|
bmp->allocated -= (__s64)vol->cluster_size;
|
2097 |
|
|
if (ntfs_deallocate_cluster_run(vol, lcn, (ntfs_cluster_t)1))
|
2098 |
|
|
ntfs_error("%s(): Error deallocating cluster in error code "
|
2099 |
|
|
"path. You should run chkdsk.\n", __FUNCTION__);
|
2100 |
|
|
switch (have_allocated_mftbmp & 3) {
|
2101 |
|
|
case 1:
|
2102 |
|
|
/* Delete the last lcn from the last run of mftbmp. */
|
2103 |
|
|
rl[rlen - 1].len--;
|
2104 |
|
|
break;
|
2105 |
|
|
case 2:
|
2106 |
|
|
/* Delete the last run of mftbmp. */
|
2107 |
|
|
bmp->d.r.len = --rlen;
|
2108 |
|
|
/* Reallocate memory if necessary. */
|
2109 |
|
|
if ((rlen + 1) * sizeof(ntfs_runlist) <= rl_size - PAGE_SIZE) {
|
2110 |
|
|
ntfs_runlist *rlt;
|
2111 |
|
|
|
2112 |
|
|
rl_size -= PAGE_SIZE;
|
2113 |
|
|
rlt = ntfs_vmalloc(rl_size);
|
2114 |
|
|
if (rlt) {
|
2115 |
|
|
ntfs_memcpy(rlt, rl, rl_size);
|
2116 |
|
|
ntfs_vfree(rl);
|
2117 |
|
|
bmp->d.r.runlist = rl = rlt;
|
2118 |
|
|
} else
|
2119 |
|
|
ntfs_error("%s(): Error "
|
2120 |
|
|
"reallocating memory in error "
|
2121 |
|
|
"code path. This should be "
|
2122 |
|
|
"harmless.\n", __FUNCTION__);
|
2123 |
|
|
}
|
2124 |
|
|
bmp->d.r.runlist[bmp->d.r.len].lcn = (ntfs_cluster_t)-1;
|
2125 |
|
|
bmp->d.r.runlist[bmp->d.r.len].len = (ntfs_cluster_t)0;
|
2126 |
|
|
break;
|
2127 |
|
|
default:
|
2128 |
|
|
BUG();
|
2129 |
|
|
}
|
2130 |
|
|
goto err_ret;
|
2131 |
|
|
}
|
2132 |
|
|
|
2133 |
|
|
/* We need 0x48 bytes in total. */
|
2134 |
|
|
static int add_standard_information(ntfs_inode *ino)
|
2135 |
|
|
{
|
2136 |
|
|
ntfs_time64_t now;
|
2137 |
|
|
char data[0x30];
|
2138 |
|
|
char *position = data;
|
2139 |
|
|
ntfs_attribute *si;
|
2140 |
|
|
|
2141 |
|
|
now = ntfs_now();
|
2142 |
|
|
NTFS_PUTU64(position + 0x00, now); /* File creation */
|
2143 |
|
|
NTFS_PUTU64(position + 0x08, now); /* Last modification */
|
2144 |
|
|
NTFS_PUTU64(position + 0x10, now); /* Last mod for MFT */
|
2145 |
|
|
NTFS_PUTU64(position + 0x18, now); /* Last access */
|
2146 |
|
|
NTFS_PUTU64(position + 0x20, 0); /* MSDOS file perms */
|
2147 |
|
|
NTFS_PUTU64(position + 0x28, 0); /* unknown */
|
2148 |
|
|
return ntfs_create_attr(ino, ino->vol->at_standard_information, 0,
|
2149 |
|
|
data, sizeof(data), &si);
|
2150 |
|
|
}
|
2151 |
|
|
|
2152 |
|
|
static int add_filename(ntfs_inode *ino, ntfs_inode *dir,
|
2153 |
|
|
const unsigned char *filename, int length, ntfs_u32 flags)
|
2154 |
|
|
{
|
2155 |
|
|
unsigned char *position;
|
2156 |
|
|
unsigned int size;
|
2157 |
|
|
ntfs_time64_t now;
|
2158 |
|
|
int count, error;
|
2159 |
|
|
unsigned char* data;
|
2160 |
|
|
ntfs_attribute *fn;
|
2161 |
|
|
|
2162 |
|
|
/* Work out the size. */
|
2163 |
|
|
size = 0x42 + 2 * length;
|
2164 |
|
|
data = ntfs_malloc(size);
|
2165 |
|
|
if (!data)
|
2166 |
|
|
return -ENOMEM;
|
2167 |
|
|
/* Search for a position. */
|
2168 |
|
|
position = data;
|
2169 |
|
|
NTFS_PUTINUM(position, dir); /* Inode num of dir */
|
2170 |
|
|
now = ntfs_now();
|
2171 |
|
|
NTFS_PUTU64(position + 0x08, now); /* File creation */
|
2172 |
|
|
NTFS_PUTU64(position + 0x10, now); /* Last modification */
|
2173 |
|
|
NTFS_PUTU64(position + 0x18, now); /* Last mod for MFT */
|
2174 |
|
|
NTFS_PUTU64(position + 0x20, now); /* Last access */
|
2175 |
|
|
/* FIXME: Get the following two sizes by finding the data attribute
|
2176 |
|
|
* in ino->attr and copying the corresponding fields from there.
|
2177 |
|
|
* If no data present then set to zero. In current implementation
|
2178 |
|
|
* add_data is called after add_filename so zero is correct on
|
2179 |
|
|
* creation. Need to change when we have hard links / support different
|
2180 |
|
|
* filename namespaces. (AIA) */
|
2181 |
|
|
NTFS_PUTS64(position + 0x28, 0); /* Allocated size */
|
2182 |
|
|
NTFS_PUTS64(position + 0x30, 0); /* Data size */
|
2183 |
|
|
NTFS_PUTU32(position + 0x38, flags); /* File flags */
|
2184 |
|
|
NTFS_PUTU32(position + 0x3c, 0); /* We don't use these
|
2185 |
|
|
* features yet. */
|
2186 |
|
|
NTFS_PUTU8(position + 0x40, length); /* Filename length */
|
2187 |
|
|
NTFS_PUTU8(position + 0x41, 0); /* Only long name */
|
2188 |
|
|
/* FIXME: This is madness. We are defining the POSIX namespace
|
2189 |
|
|
* for the filename here which can mean that the file will be
|
2190 |
|
|
* invisible when in Windows NT/2k! )-: (AIA) */
|
2191 |
|
|
position += 0x42;
|
2192 |
|
|
for (count = 0; count < length; count++) {
|
2193 |
|
|
NTFS_PUTU16(position + 2 * count, filename[count]);
|
2194 |
|
|
}
|
2195 |
|
|
error = ntfs_create_attr(ino, ino->vol->at_file_name, 0, data, size,
|
2196 |
|
|
&fn);
|
2197 |
|
|
if (!error)
|
2198 |
|
|
error = ntfs_dir_add(dir, ino, fn);
|
2199 |
|
|
ntfs_free(data);
|
2200 |
|
|
return error;
|
2201 |
|
|
}
|
2202 |
|
|
|
2203 |
|
|
int add_security(ntfs_inode* ino, ntfs_inode* dir)
|
2204 |
|
|
{
|
2205 |
|
|
int error;
|
2206 |
|
|
char *buf;
|
2207 |
|
|
int size;
|
2208 |
|
|
ntfs_attribute* attr;
|
2209 |
|
|
ntfs_io io;
|
2210 |
|
|
ntfs_attribute *se;
|
2211 |
|
|
|
2212 |
|
|
attr = ntfs_find_attr(dir, ino->vol->at_security_descriptor, 0);
|
2213 |
|
|
if (!attr)
|
2214 |
|
|
return -EOPNOTSUPP; /* Need security in directory. */
|
2215 |
|
|
size = attr->size;
|
2216 |
|
|
if (size > 512)
|
2217 |
|
|
return -EOPNOTSUPP;
|
2218 |
|
|
buf = ntfs_malloc(size);
|
2219 |
|
|
if (!buf)
|
2220 |
|
|
return -ENOMEM;
|
2221 |
|
|
io.fn_get = ntfs_get;
|
2222 |
|
|
io.fn_put = ntfs_put;
|
2223 |
|
|
io.param = buf;
|
2224 |
|
|
io.size = size;
|
2225 |
|
|
error = ntfs_read_attr(dir, ino->vol->at_security_descriptor, 0, 0,&io);
|
2226 |
|
|
if (!error && io.size != size)
|
2227 |
|
|
ntfs_error("wrong size in add_security\n");
|
2228 |
|
|
if (error) {
|
2229 |
|
|
ntfs_free(buf);
|
2230 |
|
|
return error;
|
2231 |
|
|
}
|
2232 |
|
|
/* FIXME: Consider ACL inheritance. */
|
2233 |
|
|
error = ntfs_create_attr(ino, ino->vol->at_security_descriptor,
|
2234 |
|
|
0, buf, size, &se);
|
2235 |
|
|
ntfs_free(buf);
|
2236 |
|
|
return error;
|
2237 |
|
|
}
|
2238 |
|
|
|
2239 |
|
|
static int add_data(ntfs_inode* ino, unsigned char *data, int length)
|
2240 |
|
|
{
|
2241 |
|
|
ntfs_attribute *da;
|
2242 |
|
|
|
2243 |
|
|
return ntfs_create_attr(ino, ino->vol->at_data, 0, data, length, &da);
|
2244 |
|
|
}
|
2245 |
|
|
|
2246 |
|
|
/*
|
2247 |
|
|
* We _could_ use 'dir' to help optimise inode allocation.
|
2248 |
|
|
*
|
2249 |
|
|
* FIXME: Need to undo what we do in ntfs_alloc_mft_record if we get an error
|
2250 |
|
|
* further on in ntfs_alloc_inode. Either fold the two functions to allow
|
2251 |
|
|
* proper undo or just deallocate the record from the mft bitmap. (AIA)
|
2252 |
|
|
*/
|
2253 |
|
|
int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename,
|
2254 |
|
|
int namelen, ntfs_u32 flags)
|
2255 |
|
|
{
|
2256 |
|
|
ntfs_volume *vol = dir->vol;
|
2257 |
|
|
int err;
|
2258 |
|
|
ntfs_u8 buffer[2];
|
2259 |
|
|
ntfs_io io;
|
2260 |
|
|
|
2261 |
|
|
err = ntfs_alloc_mft_record(vol, &(result->i_number));
|
2262 |
|
|
if (err) {
|
2263 |
|
|
if (err == -ENOSPC)
|
2264 |
|
|
ntfs_error("%s(): No free inodes.\n", __FUNCTION__);
|
2265 |
|
|
return err;
|
2266 |
|
|
}
|
2267 |
|
|
/* Get the sequence number. */
|
2268 |
|
|
io.fn_put = ntfs_put;
|
2269 |
|
|
io.fn_get = ntfs_get;
|
2270 |
|
|
io.param = buffer;
|
2271 |
|
|
io.size = 2;
|
2272 |
|
|
err = ntfs_read_attr(vol->mft_ino, vol->at_data, 0,
|
2273 |
|
|
((__s64)result->i_number << vol->mft_record_size_bits)
|
2274 |
|
|
+ 0x10, &io);
|
2275 |
|
|
// FIXME: We are leaving the MFT in inconsistent state! (AIA)
|
2276 |
|
|
if (err)
|
2277 |
|
|
return err;
|
2278 |
|
|
/* Increment the sequence number skipping zero. */
|
2279 |
|
|
result->sequence_number = (NTFS_GETU16(buffer) + 1) & 0xffff;
|
2280 |
|
|
if (!result->sequence_number)
|
2281 |
|
|
result->sequence_number++;
|
2282 |
|
|
result->vol = vol;
|
2283 |
|
|
result->attr_count = 0;
|
2284 |
|
|
result->attrs = 0;
|
2285 |
|
|
result->record_count = 1;
|
2286 |
|
|
result->records = ntfs_calloc(8 * sizeof(int));
|
2287 |
|
|
if (!result->records)
|
2288 |
|
|
goto mem_err_out;
|
2289 |
|
|
result->records[0] = result->i_number;
|
2290 |
|
|
result->attr = ntfs_calloc(vol->mft_record_size);
|
2291 |
|
|
if (!result->attr) {
|
2292 |
|
|
ntfs_free(result->records);
|
2293 |
|
|
result->records = NULL;
|
2294 |
|
|
goto mem_err_out;
|
2295 |
|
|
}
|
2296 |
|
|
ntfs_fill_mft_header(result->attr, vol->mft_record_size,
|
2297 |
|
|
result->sequence_number, 1, 1);
|
2298 |
|
|
err = add_standard_information(result);
|
2299 |
|
|
if (!err)
|
2300 |
|
|
err = add_filename(result, dir, filename, namelen, flags);
|
2301 |
|
|
if (!err)
|
2302 |
|
|
err = add_security(result, dir);
|
2303 |
|
|
// FIXME: We are leaving the MFT in inconsistent state on error! (AIA)
|
2304 |
|
|
return err;
|
2305 |
|
|
mem_err_out:
|
2306 |
|
|
// FIXME: We are leaving the MFT in inconsistent state! (AIA)
|
2307 |
|
|
result->record_count = 0;
|
2308 |
|
|
result->attr = NULL;
|
2309 |
|
|
return -ENOMEM;
|
2310 |
|
|
}
|
2311 |
|
|
|
2312 |
|
|
int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
|
2313 |
|
|
int namelen)
|
2314 |
|
|
{
|
2315 |
|
|
int err;
|
2316 |
|
|
|
2317 |
|
|
err = ntfs_alloc_inode(dir, result, filename, namelen, 0);
|
2318 |
|
|
if (!err)
|
2319 |
|
|
err = add_data(result, 0, 0);
|
2320 |
|
|
return err;
|
2321 |
|
|
}
|
2322 |
|
|
|