1 /*
2  * attr.c
3  *
4  * Copyright (C) 1996-1999 Martin von L�wis
5  * Copyright (C) 1996-1997 R�gis Duchesne
6  * Copyright (C) 1998 Joseph Malicki
7  * Copyright (C) 1999 Steve Dodd
8  * Copyright (C) 2001 Anton Altaparmakov (AIA)
9  */
10 
11 #include "ntfstypes.h"
12 #include "struct.h"
13 #include "attr.h"
14 
15 #include <linux/errno.h>
16 #include <linux/ntfs_fs.h>
17 #include "macros.h"
18 #include "support.h"
19 #include "util.h"
20 #include "super.h"
21 #include "inode.h"
22 #include "unistr.h"
23 
24 /**
25  * ntfs_find_attr_in_mft_rec - find attribute in mft record
26  * @vol:	volume on which attr resides
27  * @m:		mft record to search
28  * @type:	attribute type to find
29  * @name:	attribute name to find (optional, i.e. NULL means don't care)
30  * @name_len:	attribute name length (only needed if @name present)
31  * @ic:		ignore case if 1 or case sensitive if 0 (ignored if @name NULL)
32  * @instance:	instance number to find
33  *
34  * Only search the specified mft record and it ignores the presence of an
35  * attribute list attribute (unless it is the one being searched for,
36  * obviously, in which case it is returned).
37  */
ntfs_find_attr_in_mft_rec(ntfs_volume * vol,ntfs_u8 * m,__u32 type,wchar_t * name,__u32 name_len,int ic,__u16 instance)38 ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type,
39 		wchar_t *name, __u32 name_len, int ic, __u16 instance)
40 {
41 	ntfs_u8 *a;
42 
43 	/* Iterate over attributes in mft record @m. */
44 	a = m + NTFS_GETU16(m + 20);	/* attrs_offset */
45 	for (; a >= m && a <= m + vol->mft_record_size;
46 				a += NTFS_GETU32(a + 4 /* length */)) {
47 		/* We catch $END with this more general check, too... */
48 		if (NTFS_GETU32(a + 0 /* type */) > type)
49 			return NULL;
50 		if (!NTFS_GETU32(a + 4 /* length */))
51 			break;
52 		if (NTFS_GETU32(a + 0 /* type */) != type)
53 			continue;
54 		/* If @name is present, compare the two names. */
55 		if (name && !ntfs_are_names_equal(name, name_len, (wchar_t*)
56 				(a + NTFS_GETU16(a + 10 /* name_offset */)),
57 				a[9] /* name_length */, ic, vol->upcase,
58 				vol->upcase_length)) {
59 			register int rc;
60 
61 			rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
62 					name, name_len, (wchar_t*)(a +
63 					NTFS_GETU16(a + 10 /* name_offset */)),
64 					a[9] /* name_length */, 1, 1);
65 			/*
66 			 * If @name collates before a->name, there is no
67 			 * matching attribute.
68 			 */
69 			if (rc == -1)
70 				return NULL;
71 			/* If the strings are not equal, continue search. */
72 			if (rc)
73 	 			continue;
74 			rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
75 					name, name_len, (wchar_t*)(a +
76 					NTFS_GETU16(a + 10 /* name_offset */)),
77 					a[9] /* name_length */, 0, 1);
78 			if (rc == -1)
79 				return NULL;
80 			if (rc)
81 				continue;
82 		}
83 		/*
84 		 * The names match or @name not present. Check instance number.
85 		 * and if it matches we have found the attribute and are done.
86 		 */
87 		if (instance != NTFS_GETU16(a + 14 /* instance */))
88 			continue;
89 		ntfs_debug(DEBUG_FILE3, "ntfs_find_attr_in_mft_record: found: "
90 			"attr type 0x%x, instance number = 0x%x.\n",
91 			NTFS_GETU32(a + 0), instance);
92 		return a;
93 	}
94 	ntfs_error("ntfs_find_attr_in_mft_record: mft record 0x%x is corrupt"
95 			". Run chkdsk.\n", m);
96 	return NULL;
97 }
98 
99 /* Look if an attribute already exists in the inode, and if not, create it. */
ntfs_new_attr(ntfs_inode * ino,int type,void * name,int namelen,void * value,int value_len,int * pos,int * found)100 int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
101 		  void *value, int value_len, int *pos, int *found)
102 {
103 	int do_insert = 0;
104 	int i, m;
105 	ntfs_attribute *a;
106 
107 	for (i = 0; i < ino->attr_count; i++)
108 	{
109 		a = ino->attrs + i;
110 		if (a->type < type)
111 			continue;
112 		if (a->type > type) {
113 			do_insert = 1;
114 			break;
115 		}
116 		/* If @name is present, compare the two names. */
117 		if (namelen && !ntfs_are_names_equal((wchar_t*)name, namelen,
118 				a->name, a->namelen /* name_length */,
119 				1 /* ignore case*/, ino->vol->upcase,
120 				ino->vol->upcase_length)) {
121 			register int rc;
122 
123 			rc = ntfs_collate_names(ino->vol->upcase,
124 					ino->vol->upcase_length, a->name,
125 					a->namelen, (wchar_t*)name, namelen,
126 					1 /* ignore case */, 1);
127 			if (rc == -1)
128 				continue;
129 			if (rc == 1) {
130 	 			do_insert = 1;
131 				break;
132 			}
133 			rc = ntfs_collate_names(ino->vol->upcase,
134 					ino->vol->upcase_length, a->name,
135 					a->namelen, (wchar_t*)name, namelen,
136 					0 /* case sensitive */, 1);
137 			if (rc == -1)
138 				continue;
139 			if (rc == 1) {
140 				do_insert = 1;
141 				break;
142 			}
143 		}
144 		/* Names are equal or no name was asked for. */
145 		/* If a value was specified compare the values. */
146 		if (value_len && a->resident) {
147 			if (!a->resident) {
148 				ntfs_error("ntfs_new_attr: Value specified but "
149 					"attribute non-resident. Bug!\n");
150 				return -EINVAL;
151 			}
152 			m = value_len;
153 			if (m > a->size)
154 				m = a->size;
155 			m = memcmp(value, a->d.data, m);
156 			if (m > 0)
157 				continue;
158 			if (m < 0) {
159 				do_insert = 1;
160 				break;
161 			}
162 			/* Values match until min of value lengths. */
163 			if (value_len > a->size)
164 				continue;
165 			if (value_len < a->size) {
166 				do_insert = 1;
167 				break;
168 			}
169 		}
170 		/* Full match! */
171 		*found = 1;
172 		*pos = i;
173 		return 0;
174 	}
175 	/* Re-allocate space. */
176 	if (ino->attr_count % 8 == 0)
177 	{
178 		ntfs_attribute* new;
179 		new = (ntfs_attribute*)ntfs_malloc((ino->attr_count + 8) *
180 							sizeof(ntfs_attribute));
181 		if (!new)
182 			return -ENOMEM;
183 		if (ino->attrs) {
184 			ntfs_memcpy(new, ino->attrs, ino->attr_count *
185 							sizeof(ntfs_attribute));
186 			ntfs_free(ino->attrs);
187 		}
188 		ino->attrs = new;
189 	}
190 	if (do_insert)
191 		ntfs_memmove(ino->attrs + i + 1, ino->attrs + i,
192 			     (ino->attr_count - i) * sizeof(ntfs_attribute));
193 	ino->attr_count++;
194 	ino->attrs[i].type = type;
195 	ino->attrs[i].namelen = namelen;
196 	ino->attrs[i].name = name;
197 	*pos = i;
198 	*found = 0;
199 	return 0;
200 }
201 
ntfs_make_attr_resident(ntfs_inode * ino,ntfs_attribute * attr)202 int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr)
203 {
204 	__s64 size = attr->size;
205 	if (size > 0) {
206 		/* FIXME: read data, free clusters */
207 		return -EOPNOTSUPP;
208 	}
209 	attr->resident = 1;
210 	return 0;
211 }
212 
213 /* Store in the inode readable information about a run. */
ntfs_insert_run(ntfs_attribute * attr,int cnum,ntfs_cluster_t cluster,int len)214 int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
215 		     int len)
216 {
217 	/* (re-)allocate space if necessary. */
218 	if ((attr->d.r.len * sizeof(ntfs_runlist)) % PAGE_SIZE == 0) {
219 		ntfs_runlist* new;
220 		unsigned long new_size;
221 
222 		ntfs_debug(DEBUG_MALLOC, "ntfs_insert_run: re-allocating "
223 				"space: old attr->d.r.len = 0x%x\n",
224 				attr->d.r.len);
225 		new_size = attr->d.r.len * sizeof(ntfs_runlist) + PAGE_SIZE;
226 		if ((new_size >> PAGE_SHIFT) > num_physpages) {
227 			ntfs_error("ntfs_insert_run: attempted to allocate "
228 					"more pages than num_physpages."
229 					"This might be a bug or a corrupt"
230 					"file system.\n");
231 			return -1;
232 		}
233 		new = ntfs_vmalloc(new_size);
234 		if (!new) {
235 			ntfs_error("ntfs_insert_run: ntfs_vmalloc(new_size = "
236 					"0x%x) failed\n", new_size);
237 			return -1;
238 		}
239 		if (attr->d.r.runlist) {
240 			ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
241 					* sizeof(ntfs_runlist));
242 			ntfs_vfree(attr->d.r.runlist);
243 		}
244 		attr->d.r.runlist = new;
245 	}
246 	if (attr->d.r.len > cnum)
247 		ntfs_memmove(attr->d.r.runlist + cnum + 1,
248 			     attr->d.r.runlist + cnum,
249 			     (attr->d.r.len - cnum) * sizeof(ntfs_runlist));
250 	attr->d.r.runlist[cnum].lcn = cluster;
251 	attr->d.r.runlist[cnum].len = len;
252 	attr->d.r.len++;
253 	return 0;
254 }
255 
256 /**
257  * ntfs_extend_attr - extend allocated size of an attribute
258  * @ino:	ntfs inode containing the attribute to extend
259  * @attr:	attribute which to extend
260  * @len:	desired new length for @attr (_not_ the amount to extend by)
261  *
262  * Extends an attribute. Allocate clusters on the volume which @ino belongs to.
263  * Extends the run list accordingly, preferably by extending the last run of
264  * the existing run list, first.
265  *
266  * Only modifies attr->allocated, i.e. doesn't touch attr->size, nor
267  * attr->initialized.
268  */
ntfs_extend_attr(ntfs_inode * ino,ntfs_attribute * attr,const __s64 len)269 int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len)
270 {
271 	int rlen, rl2_len, err = 0;
272 	ntfs_cluster_t cluster, clen;
273 	ntfs_runlist *rl, *rl2;
274 
275 	if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
276 			ino->record_count > 1)
277 		return -EOPNOTSUPP;
278 	/*
279 	 * FIXME: Don't make non-resident if the attribute type is not right.
280 	 * For example cannot make index attribute non-resident! (AIA)
281 	 */
282 	if (attr->resident) {
283 		err = ntfs_make_attr_nonresident(ino, attr);
284 		if (err)
285 			return err;
286 	}
287 	if (len <= attr->allocated)
288 		return 0;	/* Truly stupid things do sometimes happen. */
289 	rl = attr->d.r.runlist;
290 	rlen = attr->d.r.len;
291 	if (rlen > 0)
292 		cluster = rl[rlen - 1].lcn + rl[rlen - 1].len;
293 	else
294 		/* No preference for allocation space. */
295 		cluster = (ntfs_cluster_t)-1;
296 	/*
297 	 * Calculate the extra space we need, and round up to multiple of
298 	 * cluster size to get number of new clusters needed.
299 	 */
300 	clen = (len - attr->allocated + ino->vol->cluster_size - 1) >>
301 			ino->vol->cluster_size_bits;
302 	if (!clen)
303 		return 0;
304 	err = ntfs_allocate_clusters(ino->vol, &cluster, &clen, &rl2,
305 			&rl2_len, DATA_ZONE);
306 	if (err)
307 		return err;
308 	attr->allocated += (__s64)clen << ino->vol->cluster_size_bits;
309 	if (rlen > 0) {
310 		err = splice_runlists(&rl, &rlen, rl2, rl2_len);
311 		ntfs_vfree(rl2);
312 		if (err)
313 			return err;
314 	} else {
315 		if (rl)
316 			ntfs_vfree(rl);
317 		rl = rl2;
318 		rlen = rl2_len;
319 	}
320 	attr->d.r.runlist = rl;
321 	attr->d.r.len = rlen;
322 	return 0;
323 }
324 
ntfs_make_attr_nonresident(ntfs_inode * ino,ntfs_attribute * attr)325 int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
326 {
327 	int error;
328 	ntfs_io io;
329 	void *data = attr->d.data;
330 	__s64 len = attr->size;
331 
332 	attr->d.r.len = 0;
333 	attr->d.r.runlist = NULL;
334 	attr->resident = 0;
335 	/*
336 	 * ->allocated is updated by ntfs_extend_attr(), while ->initialized
337 	 * and ->size are updated by ntfs_readwrite_attr(). (AIA)
338 	 */
339 	attr->allocated = attr->initialized = 0;
340 	error = ntfs_extend_attr(ino, attr, len);
341 	if (error)
342 		return error; /* FIXME: On error, restore old values. */
343 	io.fn_put = ntfs_put;
344 	io.fn_get = ntfs_get;
345 	io.param = data;
346 	io.size = len;
347 	io.do_read = 0;
348 	return ntfs_readwrite_attr(ino, attr, 0, &io);
349 }
350 
ntfs_attr_allnonresident(ntfs_inode * ino)351 int ntfs_attr_allnonresident(ntfs_inode *ino)
352 {
353 	int i, error = 0;
354         ntfs_volume *vol = ino->vol;
355 
356 	for (i = 0; !error && i < ino->attr_count; i++)
357 	{
358 		if (ino->attrs[i].type != vol->at_security_descriptor &&
359 		    ino->attrs[i].type != vol->at_data)
360 			continue;
361 		error = ntfs_make_attr_nonresident(ino, ino->attrs + i);
362 	}
363 	return error;
364 }
365 
366 /*
367  * Resize the attribute to a newsize. attr->allocated and attr->size are
368  * updated, but attr->initialized is not changed unless it becomes bigger than
369  * attr->size, in which case it is set to attr->size.
370  */
ntfs_resize_attr(ntfs_inode * ino,ntfs_attribute * attr,__s64 newsize)371 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
372 {
373 	int error = 0;
374 	__s64 oldsize = attr->size;
375 	int clustersizebits = ino->vol->cluster_size_bits;
376 	int i, count, newcount;
377 	ntfs_runlist *rl, *rlt;
378 
379 	if (newsize == oldsize)
380 		return 0;
381 	if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
382 		return -EOPNOTSUPP;
383 	if (attr->resident) {
384 		void *v;
385 		if (newsize > ino->vol->mft_record_size) {
386 			error = ntfs_make_attr_nonresident(ino, attr);
387 			if (error)
388 				return error;
389 			return ntfs_resize_attr(ino, attr, newsize);
390 		}
391 		v = attr->d.data;
392 		if (newsize) {
393 			__s64 minsize = newsize;
394 			attr->d.data = ntfs_malloc(newsize);
395 			if (!attr->d.data) {
396 				ntfs_free(v);
397 				return -ENOMEM;
398 			}
399 			if (newsize > oldsize) {
400 				minsize = oldsize;
401 				ntfs_bzero((char*)attr->d.data + oldsize,
402 					   newsize - oldsize);
403 			}
404 			ntfs_memcpy((char*)attr->d.data, v, minsize);
405 		} else
406 			attr->d.data = 0;
407 		ntfs_free(v);
408 		attr->size = newsize;
409 		return 0;
410 	}
411 	/* Non-resident attribute. */
412 	rl = attr->d.r.runlist;
413 	if (newsize < oldsize) {
414 		int rl_size;
415 		/*
416 		 * FIXME: We might be going awfully wrong for newsize = 0,
417 		 * possibly even leaking memory really badly. But considering
418 		 * in that case there is more breakage due to -EOPNOTSUPP stuff
419 		 * further down the code path, who cares for the moment... (AIA)
420 		 */
421 		for (i = 0, count = 0; i < attr->d.r.len; i++) {
422 			if ((__s64)(count + rl[i].len) << clustersizebits >
423 					newsize) {
424 				i++;
425 				break;
426 			}
427 			count += (int)rl[i].len;
428 		}
429 		newcount = count;
430 		/* Free unused clusters in current run, unless sparse. */
431 		if (rl[--i].lcn != (ntfs_cluster_t)-1) {
432 			ntfs_cluster_t rounded = newsize - ((__s64)count <<
433 					clustersizebits);
434 			rounded = (rounded + ino->vol->cluster_size - 1) >>
435 					clustersizebits;
436 			error = ntfs_deallocate_cluster_run(ino->vol,
437 					rl[i].lcn + rounded,
438 					rl[i].len - rounded);
439 			if (error)
440 				return error; /* FIXME: Incomplete operation. */
441 			rl[i].len = rounded;
442 			newcount = count + rounded;
443 		}
444 		/* Free all other runs. */
445 		i++;
446 		error = ntfs_deallocate_clusters(ino->vol, rl + i,
447 				attr->d.r.len - i);
448 		if (error)
449 			return error; /* FIXME: Incomplete operation. */
450 		/*
451 		 * Free space for extra runs in memory if enough memory left
452 		 * to do so. FIXME: Only do it if it would free memory. (AIA)
453 		 */
454 		rl_size = ((i + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
455 				PAGE_MASK;
456 		if (rl_size < ((attr->d.r.len * sizeof(ntfs_runlist) +
457 				PAGE_SIZE - 1) & PAGE_MASK)) {
458 			rlt = ntfs_vmalloc(rl_size);
459 			if (rlt) {
460 				ntfs_memcpy(rlt, rl, i * sizeof(ntfs_runlist));
461 				ntfs_vfree(rl);
462 				attr->d.r.runlist = rl = rlt;
463 			}
464 		}
465 		rl[i].lcn = (ntfs_cluster_t)-1;
466 		rl[i].len = (ntfs_cluster_t)0;
467 		attr->d.r.len = i;
468 	} else {
469 		error = ntfs_extend_attr(ino, attr, newsize);
470 		if (error)
471 			return error; /* FIXME: Incomplete operation. */
472 		newcount = (newsize + ino->vol->cluster_size - 1) >>
473 				clustersizebits;
474 	}
475 	/* Fill in new sizes. */
476 	attr->allocated = (__s64)newcount << clustersizebits;
477 	attr->size = newsize;
478 	if (attr->initialized > newsize)
479 		attr->initialized = newsize;
480 	if (!newsize)
481 		error = ntfs_make_attr_resident(ino, attr);
482 	return error;
483 }
484 
ntfs_create_attr(ntfs_inode * ino,int anum,char * aname,void * data,int dsize,ntfs_attribute ** rattr)485 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
486 		int dsize, ntfs_attribute **rattr)
487 {
488 	void *name;
489 	int namelen;
490 	int found, i;
491 	int error;
492 	ntfs_attribute *attr;
493 
494 	if (dsize > ino->vol->mft_record_size)
495 		/* FIXME: Non-resident attributes. */
496 		return -EOPNOTSUPP;
497 	if (aname) {
498 		namelen = strlen(aname);
499 		name = ntfs_malloc(2 * namelen);
500 		if (!name)
501 			return -ENOMEM;
502 		ntfs_ascii2uni(name, aname, namelen);
503 	} else {
504 		name = 0;
505 		namelen = 0;
506 	}
507 	error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
508 			&found);
509 	if (error || found) {
510 		ntfs_free(name);
511 		return error ? error : -EEXIST;
512 	}
513 	*rattr = attr = ino->attrs + i;
514 	/* Allocate a new number.
515 	 * FIXME: Should this happen on inode writeback?
516 	 * FIXME: Extension records not supported. */
517 	error = ntfs_allocate_attr_number(ino, &i);
518 	if (error)
519 		return error;
520 	attr->attrno = i;
521 	if (attr->attrno + 1 != NTFS_GETU16(ino->attr + 0x28))
522 		ntfs_error("UH OH! attr->attrno (%i) != NTFS_GETU16(ino->attr "
523 				"+ 0x28) (%i)\n", attr->attrno,
524 				NTFS_GETU16(ino->attr + 0x28));
525 	attr->resident = 1;
526 	attr->flags = 0;
527 	attr->cengine = 0;
528 	attr->size = attr->allocated = attr->initialized = dsize;
529 
530 	/* FIXME: INDEXED information should come from $AttrDef
531 	 * Currently, only file names are indexed. As of NTFS v3.0 (Win2k),
532 	 * this is no longer true. Different attributes can be indexed now. */
533 	if (anum == ino->vol->at_file_name)
534 		attr->indexed = 1;
535 	else
536 		attr->indexed = 0;
537 	attr->d.data = ntfs_malloc(dsize);
538 	if (!attr->d.data)
539 		return -ENOMEM;
540 	ntfs_memcpy(attr->d.data, data, dsize);
541 	return 0;
542 }
543 
544 /*
545  * Non-resident attributes are stored in runs (intervals of clusters).
546  *
547  * This function stores in the inode readable information about a non-resident
548  * attribute.
549  */
ntfs_process_runs(ntfs_inode * ino,ntfs_attribute * attr,unsigned char * data)550 static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr,
551 		unsigned char *data)
552 {
553 	int startvcn, endvcn;
554 	int vcn, cnum;
555 	ntfs_cluster_t cluster;
556 	int len, ctype;
557 	int er = 0;
558 	startvcn = NTFS_GETS64(data + 0x10);
559 	endvcn = NTFS_GETS64(data + 0x18);
560 
561 	/* Check whether this chunk really belongs to the end. Problem with
562 	 * this: this functions can get called on the last extent first, before
563 	 * it is called on the other extents in sequence. This happens when the
564 	 * base mft record contains the last extent instead of the first one
565 	 * and the first extent is stored, like any intermediate extents in
566 	 * extension mft records. This would be difficult to allow the way the
567 	 * runlist is stored in memory. Thus we fix elsewhere by causing the
568 	 * attribute list attribute to be processed immediately when found. The
569 	 * extents will then be processed starting with the first one. */
570 	for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
571 		vcn += attr->d.r.runlist[cnum].len;
572 	if (vcn != startvcn) {
573 		ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: ino = 0x%x, "
574 			"attr->type = 0x%x, startvcn = 0x%x, endvcn = 0x%x, "
575 			"vcn = 0x%x, cnum = 0x%x\n", ino->i_number, attr->type,
576 			startvcn, endvcn, vcn, cnum);
577 		if (vcn < startvcn) {
578 			ntfs_error("Problem with runlist in extended record\n");
579 			return -1;
580 		}
581 		/* Tried to insert an already inserted runlist. */
582 		return 0;
583 	}
584 	if (!endvcn) {
585 		if (!startvcn) {
586 			/* Allocated length. */
587 			endvcn = NTFS_GETS64(data + 0x28) - 1;
588 			endvcn >>= ino->vol->cluster_size_bits;
589 		} else {
590 			/* This is an extent. Allocated length is not defined!
591 			 * Extents must have an endvcn though so this is an
592 			 * error. */
593 			ntfs_error("Corrupt attribute extent. (endvcn is "
594 				"missing)\n");
595 			return -1;
596 		}
597 	}
598 	data = data + NTFS_GETU16(data + 0x20);
599 	cnum = attr->d.r.len;
600 	cluster = 0;
601 	for (vcn = startvcn; vcn <= endvcn; vcn += len)	{
602 		if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) {
603 			ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: "
604 				"ntfs_decompress_run failed. i_number = 0x%x\n",
605 				ino->i_number);
606 			return -1;
607 		}
608 		if (ctype)
609 			er = ntfs_insert_run(attr, cnum, -1, len);
610 		else
611 			er = ntfs_insert_run(attr, cnum, cluster, len);
612 		if (er)
613 			break;
614 		cnum++;
615 	}
616 	if (er)
617 		ntfs_error("ntfs_process_runs: ntfs_insert_run failed\n");
618 	ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: startvcn = 0x%x, vcn = 0x%x"
619 				", endvcn = 0x%x, cnum = %i\n", startvcn, vcn,
620 				endvcn, cnum);
621 	return er;
622 }
623 
624 /* Insert the attribute starting at attr in the inode ino. */
ntfs_insert_attribute(ntfs_inode * ino,unsigned char * attrdata)625 int ntfs_insert_attribute(ntfs_inode *ino, unsigned char *attrdata)
626 {
627 	int i, found;
628 	int type;
629 	short int *name;
630 	int namelen;
631 	void *data;
632 	ntfs_attribute *attr;
633 	int error;
634 
635 	type = NTFS_GETU32(attrdata);
636 	namelen = NTFS_GETU8(attrdata + 9);
637 	ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ino->i_number 0x%x, "
638 			"attr type 0x%x\n", ino->i_number, type);
639 	/* Read the attribute's name if it has one. */
640 	if (!namelen)
641 		name = 0;
642 	else {
643 		/* 1 Unicode character fits in 2 bytes. */
644 		name = ntfs_malloc(2 * namelen);
645 		if (!name)
646 			return -ENOMEM;
647 		ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10),
648 			    2 * namelen);
649 	}
650 	/* If resident look for value, too. */
651 	if (NTFS_GETU8(attrdata + 8) == 0)
652 		error = ntfs_new_attr(ino, type, name, namelen,
653 				attrdata + NTFS_GETU16(attrdata + 0x14),
654 				NTFS_GETU16(attrdata + 0x10), &i, &found);
655 	else
656 		error = ntfs_new_attr(ino, type, name, namelen, NULL, 0, &i,
657 				&found);
658 	if (error) {
659 		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ntfs_new_attr "
660 				"failed.\n");
661 		if (name)
662 			ntfs_free(name);
663 		return error;
664 	}
665 	if (found) {
666 		/* It's already there, if not resident just process the runs. */
667 		if (!ino->attrs[i].resident) {
668 			ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute:"
669 						" processing runs 1.\n");
670 			/* FIXME: Check error code! (AIA) */
671 			ntfs_process_runs(ino, ino->attrs + i, attrdata);
672 		}
673 		return 0;
674 	}
675 	attr = ino->attrs + i;
676 	attr->resident = NTFS_GETU8(attrdata + 8) == 0;
677 	attr->flags = *(__u16*)(attrdata + 0xC);
678 	attr->attrno = NTFS_GETU16(attrdata + 0xE);
679 
680 	if (attr->resident) {
681 		attr->size = NTFS_GETU16(attrdata + 0x10);
682 		data = attrdata + NTFS_GETU16(attrdata + 0x14);
683 		attr->d.data = (void*)ntfs_malloc(attr->size);
684 		if (!attr->d.data)
685 			return -ENOMEM;
686 		ntfs_memcpy(attr->d.data, data, attr->size);
687 		attr->indexed = NTFS_GETU8(attrdata + 0x16);
688 	} else {
689 		attr->allocated = NTFS_GETS64(attrdata + 0x28);
690 		attr->size = NTFS_GETS64(attrdata + 0x30);
691 		attr->initialized = NTFS_GETS64(attrdata + 0x38);
692 		attr->cengine = NTFS_GETU16(attrdata + 0x22);
693 		if (attr->flags & ATTR_IS_COMPRESSED)
694 			attr->compsize = NTFS_GETS64(attrdata + 0x40);
695 		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
696 			"attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
697 			"attr->initialized = 0x%Lx\n", attr->allocated,
698 			attr->size, attr->initialized);
699 		ino->attrs[i].d.r.runlist = 0;
700 		ino->attrs[i].d.r.len = 0;
701 		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: processing "
702 				"runs 2.\n");
703 		/* FIXME: Check error code! (AIA) */
704 		ntfs_process_runs(ino, attr, attrdata);
705 	}
706 	return 0;
707 }
708 
ntfs_read_zero(ntfs_io * dest,int size)709 int ntfs_read_zero(ntfs_io *dest, int size)
710 {
711 	int i;
712 	char *sparse = ntfs_calloc(512);
713 	if (!sparse)
714 		return -ENOMEM;
715 	i = 512;
716 	while (size) {
717 		if (i > size)
718 			i = size;
719 		dest->fn_put(dest, sparse, i);
720 		size -= i;
721 	}
722 	ntfs_free(sparse);
723 	return 0;
724 }
725 
726 /* Process compressed attributes. */
ntfs_read_compressed(ntfs_inode * ino,ntfs_attribute * attr,__s64 offset,ntfs_io * dest)727 int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
728 			 ntfs_io *dest)
729 {
730 	int error = 0;
731 	int clustersizebits;
732 	int s_vcn, rnum, vcn, got, l1;
733 	__s64 copied, len, chunk, offs1, l, chunk2;
734 	ntfs_cluster_t cluster, cl1;
735 	char *comp = 0, *comp1;
736 	char *decomp = 0;
737 	ntfs_io io;
738 	ntfs_runlist *rl;
739 
740 	l = dest->size;
741 	clustersizebits = ino->vol->cluster_size_bits;
742 	/* Starting cluster of potential chunk. There are three situations:
743 	   a) In a large uncompressible or sparse chunk, s_vcn is in the middle
744 	      of a run.
745 	   b) s_vcn is right on a run border.
746 	   c) When several runs make a chunk, s_vcn is before the chunks. */
747 	s_vcn = offset >> clustersizebits;
748 	/* Round down to multiple of 16. */
749 	s_vcn &= ~15;
750 	rl = attr->d.r.runlist;
751 	for (rnum = vcn = 0; rnum < attr->d.r.len && vcn + rl->len <= s_vcn;
752 								rnum++, rl++)
753 		vcn += rl->len;
754 	if (rnum == attr->d.r.len) {
755 		/* Beyond end of file. */
756 		/* FIXME: Check allocated / initialized. */
757 		dest->size = 0;
758 		return 0;
759 	}
760 	io.do_read = 1;
761 	io.fn_put = ntfs_put;
762 	io.fn_get = 0;
763 	cluster = rl->lcn;
764 	len = rl->len;
765 	copied = 0;
766 	while (l) {
767 		chunk = 0;
768 		if (cluster == (ntfs_cluster_t)-1) {
769 			/* Sparse cluster. */
770 			__s64 ll;
771 
772 			if ((len - (s_vcn - vcn)) & 15)
773 				ntfs_error("Unexpected sparse chunk size.");
774 			ll = ((__s64)(vcn + len) << clustersizebits) - offset;
775 			if (ll > l)
776 				ll = l;
777 			chunk = ll;
778 			error = ntfs_read_zero(dest, ll);
779 			if (error)
780 				goto out;
781 		} else if (dest->do_read) {
782 			if (!comp) {
783 				comp = ntfs_malloc(16 << clustersizebits);
784 				if (!comp) {
785 					error = -ENOMEM;
786 					goto out;
787 				}
788 			}
789 			got = 0;
790 			/* We might need to start in the middle of a run. */
791 			cl1 = cluster + s_vcn - vcn;
792 			comp1 = comp;
793 			do {
794 				int delta;
795 
796 				io.param = comp1;
797 				delta = s_vcn - vcn;
798 				if (delta < 0)
799 					delta = 0;
800 				l1 = len - delta;
801 				if (l1 > 16 - got)
802 					l1 = 16 - got;
803 				io.size = (__s64)l1 << clustersizebits;
804 				error = ntfs_getput_clusters(ino->vol, cl1, 0,
805 					       		     &io);
806 				if (error)
807 					goto out;
808 				if (l1 + delta == len) {
809 					rnum++;
810 					rl++;
811 					vcn += len;
812 					cluster = cl1 = rl->lcn;
813 					len = rl->len;
814 				}
815 				got += l1;
816 				comp1 += (__s64)l1 << clustersizebits;
817 			} while (cluster != (ntfs_cluster_t)-1 && got < 16);
818 							/* Until empty run. */
819 			chunk = 16 << clustersizebits;
820 			if (cluster != (ntfs_cluster_t)-1 || got == 16)
821 				/* Uncompressible */
822 				comp1 = comp;
823 			else {
824 				if (!decomp) {
825 					decomp = ntfs_malloc(16 <<
826 							clustersizebits);
827 					if (!decomp) {
828 						error = -ENOMEM;
829 						goto out;
830 					}
831 				}
832 				/* Make sure there are null bytes after the
833 				 * last block. */
834 				*(ntfs_u32*)comp1 = 0;
835 				ntfs_decompress(decomp, comp, chunk);
836 				comp1 = decomp;
837 			}
838 			offs1 = offset - ((__s64)s_vcn << clustersizebits);
839 			chunk2 = (16 << clustersizebits) - offs1;
840 			if (chunk2 > l)
841 				chunk2 = l;
842 			if (chunk > chunk2)
843 				chunk = chunk2;
844 			dest->fn_put(dest, comp1 + offs1, chunk);
845 		}
846 		l -= chunk;
847 		copied += chunk;
848 		offset += chunk;
849 		s_vcn = (offset >> clustersizebits) & ~15;
850 		if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
851 			rnum++;
852 			rl++;
853 			vcn += len;
854 			cluster = rl->lcn;
855 			len = rl->len;
856 		}
857 	}
858 out:
859 	if (comp)
860 		ntfs_free(comp);
861 	if (decomp)
862 		ntfs_free(decomp);
863 	dest->size = copied;
864 	return error;
865 }
866 
ntfs_write_compressed(ntfs_inode * ino,ntfs_attribute * attr,__s64 offset,ntfs_io * dest)867 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
868 		ntfs_io *dest)
869 {
870 	return -EOPNOTSUPP;
871 }
872 
873