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
10 #include "ntfstypes.h"
14 #include <linux/errno.h>
24 /* Look if an attribute already exists in the inode, and if not, create it */
26 ntfs_new_attr(ntfs_inode
*ino
,int type
,void *name
,int namelen
,int *pos
,
27 int *found
, int do_search
)
32 for(i
=0;i
<ino
->attr_count
;i
++)
34 int n
=min(namelen
,ino
->attrs
[i
].namelen
);
35 int s
=ntfs_uni_strncmp(ino
->attrs
[i
].name
,name
,n
);
38 * We assume that each attribute can be uniquely
40 * number, attribute type and attribute name.
42 if(ino
->attrs
[i
].type
==type
&& ino
->attrs
[i
].namelen
==namelen
&& !s
){
48 /* attributes are ordered by type, then by name */
49 if(ino
->attrs
[i
].type
>type
|| (ino
->attrs
[i
].type
==type
&& s
==1)){
55 /* re-allocate space */
56 if(ino
->attr_count
% 8 ==0)
59 new = (ntfs_attribute
*)ntfs_malloc((ino
->attr_count
+8)*
60 sizeof(ntfs_attribute
));
64 ntfs_memcpy( new, ino
->attrs
, ino
->attr_count
*sizeof(ntfs_attribute
) );
65 ntfs_free( ino
->attrs
);
70 ntfs_memmove(ino
->attrs
+i
+1,ino
->attrs
+i
,(ino
->attr_count
-i
)*
71 sizeof(ntfs_attribute
));
74 ino
->attrs
[i
].type
=type
;
75 ino
->attrs
[i
].namelen
=namelen
;
76 ino
->attrs
[i
].name
=name
;
83 ntfs_make_attr_resident(ntfs_inode
*ino
,ntfs_attribute
*attr
)
87 /* FIXME: read data, free clusters */
94 /* Store in the inode readable information about a run */
96 ntfs_insert_run(ntfs_attribute
*attr
,int cnum
,ntfs_cluster_t cluster
,int len
)
98 /* (re-)allocate space if necessary */
99 if(attr
->d
.r
.len
% 8 == 0) {
101 new = ntfs_malloc((attr
->d
.r
.len
+8)*sizeof(ntfs_runlist
));
104 if( attr
->d
.r
.runlist
) {
105 ntfs_memcpy(new, attr
->d
.r
.runlist
, attr
->d
.r
.len
106 *sizeof(ntfs_runlist
));
107 ntfs_free( attr
->d
.r
.runlist
);
109 attr
->d
.r
.runlist
= new;
111 if(attr
->d
.r
.len
>cnum
)
112 ntfs_memmove(attr
->d
.r
.runlist
+cnum
+1,attr
->d
.r
.runlist
+cnum
,
113 (attr
->d
.r
.len
-cnum
)*sizeof(ntfs_runlist
));
114 attr
->d
.r
.runlist
[cnum
].cluster
=cluster
;
115 attr
->d
.r
.runlist
[cnum
].len
=len
;
119 /* Extends an attribute. Another run will be added if necessary,
120 * but we try to extend the last run in the runlist first.
121 * FIXME: what if there isn't enough contiguous space, we don't create
124 * *len: the desired new length of the attr (_not_ the amount to extend by)
126 int ntfs_extend_attr(ntfs_inode
*ino
, ntfs_attribute
*attr
, int *len
,
132 ntfs_cluster_t cluster
;
135 if(attr
->compressed
)return EOPNOTSUPP
;
136 if(ino
->record_count
>1)return EOPNOTSUPP
;
139 error
= ntfs_make_attr_nonresident(ino
,attr
);
144 if( *len
<= attr
->allocated
)
145 return 0; /* truely stupid things do sometimes happen */
147 rl
=attr
->d
.r
.runlist
;
148 rlen
=attr
->d
.r
.len
-1;
151 cluster
=rl
[rlen
].cluster
+rl
[rlen
].len
;
153 /* no preference for allocation space */
156 /* calculate the extra space we need, and round up to multiple of cluster
157 * size to get number of new clusters needed */
159 clen
=( (*len
- attr
->allocated
) + ino
->vol
->clustersize
- 1 ) /
160 ino
->vol
->clustersize
;
164 /* FIXME: try to allocate smaller pieces */
165 error
=ntfs_allocate_clusters(ino
->vol
,&cluster
,&clen
,
166 flags
|ALLOC_REQUIRE_SIZE
);
167 if(error
)return error
;
168 attr
->allocated
+= clen
*ino
->vol
->clustersize
;
169 *len
= attr
->allocated
;
171 /* contiguous chunk */
172 if(rlen
>=0 && cluster
==rl
[rlen
].cluster
+rl
[rlen
].len
){
173 rl
[rlen
].len
+= clen
;
176 ntfs_insert_run(attr
,rlen
+1,cluster
,clen
);
181 ntfs_make_attr_nonresident(ntfs_inode
*ino
, ntfs_attribute
*attr
)
183 void *data
=attr
->d
.data
;
190 attr
->allocated
=attr
->initialized
=0;
192 error
=ntfs_extend_attr(ino
,attr
,&alen
,ALLOC_REQUIRE_SIZE
);
193 if(error
)return error
;/* FIXME: On error, restore old values */
199 return ntfs_readwrite_attr(ino
,attr
,0,&io
);
203 ntfs_attr_allnonresident(ntfs_inode
*ino
)
206 ntfs_volume
*vol
= ino
->vol
;
208 for (i
=0; !error
&& i
<ino
->attr_count
; i
++)
210 if (ino
->attrs
[i
].type
!= vol
->at_security_descriptor
211 && ino
->attrs
[i
].type
!= vol
->at_data
)
213 error
= ntfs_make_attr_nonresident (ino
, ino
->attrs
+i
);
218 /* Resize the attribute to a newsize */
219 int ntfs_resize_attr(ntfs_inode
*ino
, ntfs_attribute
*attr
, int newsize
)
222 int oldsize
=attr
->size
;
223 int clustersize
=ino
->vol
->clustersize
;
224 int i
,count
,newlen
,newcount
;
229 /* modifying compressed attributes not supported yet */
231 /* extending is easy: just insert sparse runs */
235 if(newsize
>ino
->vol
->mft_recordsize
){
236 error
=ntfs_make_attr_nonresident(ino
,attr
);
237 if(error
)return error
;
238 return ntfs_resize_attr(ino
,attr
,newsize
);
242 attr
->d
.data
=ntfs_malloc(newsize
);
248 ntfs_bzero((char*)attr
->d
.data
+oldsize
,
250 ntfs_memcpy((char*)attr
->d
.data
,v
,min(newsize
,oldsize
));
257 /* non-resident attribute */
258 rl
=attr
->d
.r
.runlist
;
260 for(i
=0,count
=0;i
<attr
->d
.r
.len
;i
++){
261 if((count
+rl
[i
].len
)*clustersize
>newsize
)
263 count
+=(int)rl
[i
].len
;
266 /* free unused clusters in current run, unless sparse */
268 if(rl
[i
].cluster
!=MAX_CLUSTER_T
){
269 int rounded
=newsize
-count
*clustersize
;
270 rounded
=(rounded
+clustersize
-1)/clustersize
;
271 error
=ntfs_deallocate_clusters(ino
->vol
,rl
[i
].cluster
+rounded
,
272 (int)rl
[i
].len
-rounded
);
274 return error
; /* FIXME: incomplete operation */
276 newcount
=count
+rounded
;
278 /* free all other runs */
279 for(i
++;i
<attr
->d
.r
.len
;i
++)
280 if(rl
[i
].cluster
!=MAX_CLUSTER_T
){
281 error
=ntfs_deallocate_clusters(ino
->vol
,rl
[i
].cluster
,(int)rl
[i
].len
);
283 return error
; /* FIXME: incomplete operation */
285 /* FIXME? free space for extra runs in memory */
286 attr
->d
.r
.len
=newlen
;
289 error
=ntfs_extend_attr(ino
,attr
,&newlen
,ALLOC_REQUIRE_SIZE
);
290 if(error
)return error
; /* FIXME: incomplete */
291 newcount
=newlen
/clustersize
;
293 /* fill in new sizes */
294 attr
->allocated
= newcount
*clustersize
;
295 attr
->size
= newsize
;
296 /* attr->initialized does not change. */
298 error
=ntfs_make_attr_resident(ino
,attr
);
302 int ntfs_create_attr(ntfs_inode
*ino
, int anum
, char *aname
, void *data
,
303 int dsize
, ntfs_attribute
**rattr
)
309 ntfs_attribute
*attr
;
310 if(dsize
>ino
->vol
->mft_recordsize
)
311 /* FIXME: non-resident attributes */
314 namelen
=strlen(aname
);
315 name
=ntfs_malloc(2*namelen
);
318 ntfs_ascii2uni(name
,aname
,namelen
);
324 error
= ntfs_new_attr(ino
,anum
,name
,namelen
,&i
,&found
,1);
334 *rattr
=attr
=ino
->attrs
+i
;
335 /* allocate a new number.
336 FIXME: Should this happen on inode writeback?
337 FIXME: extensions records not supported */
338 error
=ntfs_allocate_attr_number(ino
,&i
);
344 attr
->compressed
=attr
->cengine
=0;
345 attr
->size
=attr
->allocated
=attr
->initialized
=dsize
;
347 /* FIXME: INDEXED information should come from $AttrDef
348 Currently, only file names are indexed */
349 if(anum
==ino
->vol
->at_file_name
){
353 attr
->d
.data
=ntfs_malloc(dsize
);
358 ntfs_memcpy(attr
->d
.data
,data
,dsize
);
362 /* Non-resident attributes are stored in runs (intervals of clusters).
364 * This function stores in the inode readable information about a non-resident
368 ntfs_process_runs(ntfs_inode
*ino
,ntfs_attribute
* attr
,unsigned char *data
)
372 ntfs_cluster_t cluster
;
374 startvcn
= NTFS_GETU64(data
+0x10);
375 endvcn
= NTFS_GETU64(data
+0x18);
377 /* check whether this chunk really belongs to the end */
378 for(cnum
=0,vcn
=0;cnum
<attr
->d
.r
.len
;cnum
++)
379 vcn
+=attr
->d
.r
.runlist
[cnum
].len
;
382 ntfs_error("Problem with runlist in extended record\n");
387 endvcn
= NTFS_GETU64(data
+0x28)-1; /* allocated length */
388 endvcn
/= ino
->vol
->clustersize
;
390 data
=data
+NTFS_GETU16(data
+0x20);
393 for(vcn
=startvcn
; vcn
<=endvcn
; vcn
+=len
)
395 if(ntfs_decompress_run(&data
,&len
,&cluster
,&ctype
))
398 ntfs_insert_run(attr
,cnum
,-1,len
);
400 ntfs_insert_run(attr
,cnum
,cluster
,len
);
406 /* Insert the attribute starting at attr in the inode ino */
407 int ntfs_insert_attribute(ntfs_inode
*ino
, unsigned char* attrdata
)
414 ntfs_attribute
*attr
;
417 type
= NTFS_GETU32(attrdata
);
418 namelen
= NTFS_GETU8(attrdata
+9);
419 /* read the attribute's name if it has one */
424 /* 1 Unicode character fits in 2 bytes */
425 name
=ntfs_malloc(2*namelen
);
429 ntfs_memcpy(name
,attrdata
+NTFS_GETU16(attrdata
+10),2*namelen
);
432 error
= ntfs_new_attr(ino
,type
,name
,namelen
,&i
,&found
,1);
434 if( name
) ntfs_free( name
);
438 /* We can have in one inode two attributes with type 0x00000030 (File Name)
440 if(found
&& /*FIXME*/type
!=ino
->vol
->at_file_name
)
442 ntfs_process_runs(ino
,ino
->attrs
+i
,attrdata
);
445 /* Don't understand the above, but I know it leaks memory below
446 as it overwrites a found entry without freeing it. So here we
447 call ntfs_new_attr again but this time ask it to always allocate a
449 ntfs_new_attr(ino
,type
,name
,namelen
,&i
,&found
,0);
452 attr
->resident
=NTFS_GETU8(attrdata
+8)==0;
453 attr
->compressed
=NTFS_GETU16(attrdata
+0xC);
454 attr
->attrno
=NTFS_GETU16(attrdata
+0xE);
457 attr
->size
=NTFS_GETU16(attrdata
+0x10);
458 data
=attrdata
+NTFS_GETU16(attrdata
+0x14);
459 attr
->d
.data
= (void*)ntfs_malloc(attr
->size
);
462 ntfs_memcpy(attr
->d
.data
,data
,attr
->size
);
463 attr
->indexed
=NTFS_GETU16(attrdata
+0x16);
465 attr
->allocated
=NTFS_GETU32(attrdata
+0x28);
466 attr
->size
=NTFS_GETU32(attrdata
+0x30);
467 attr
->initialized
=NTFS_GETU32(attrdata
+0x38);
468 attr
->cengine
=NTFS_GETU16(attrdata
+0x22);
470 attr
->compsize
=NTFS_GETU32(attrdata
+0x40);
471 ino
->attrs
[i
].d
.r
.runlist
=0;
472 ino
->attrs
[i
].d
.r
.len
=0;
473 ntfs_process_runs(ino
,attr
,attrdata
);
479 ntfs_read_zero(ntfs_io
*dest
,int size
)
481 char *sparse
=ntfs_calloc(512);
486 dest
->fn_put(dest
,sparse
,i
);
493 /* process compressed attributes */
494 int ntfs_read_compressed(ntfs_inode
*ino
, ntfs_attribute
*attr
, int offset
,
499 int s_vcn
,rnum
,vcn
,len
,chunk
,got
,l1
,offs1
,copied
;
500 ntfs_cluster_t cluster
,cl1
;
507 clustersize
=ino
->vol
->clustersize
;
508 /* starting cluster of potential chunk
509 there are three situations:
510 a) in a large uncompressible or sparse chunk,
511 s_vcn is in the middle of a run
512 b) s_vcn is right on a run border
513 c) when several runs make a chunk, s_vcn is before the chunks
515 s_vcn
=offset
/clustersize
;
516 /* round down to multiple of 16 */
518 rl
=attr
->d
.r
.runlist
;
519 for(rnum
=vcn
=0;rnum
<attr
->d
.r
.len
&& vcn
+rl
->len
<=s_vcn
;rnum
++,rl
++)
521 if(rnum
==attr
->d
.r
.len
){
522 /* beyond end of file */
523 /* FIXME: check allocated/initialized */
535 if(cluster
==MAX_CLUSTER_T
){
538 if((len
-(s_vcn
-vcn
)) & 15)
539 ntfs_error("unexpected sparse chunk size");
540 l1
=chunk
= min((vcn
+len
)*clustersize
-offset
,l
);
541 error
= ntfs_read_zero(dest
,l1
);
544 }else if(dest
->do_read
){
546 comp
=ntfs_malloc(16*clustersize
);
553 /* we might need to start in the middle of a run */
554 cl1
=cluster
+s_vcn
-vcn
;
558 l1
=min(len
-max(s_vcn
-vcn
,0),16-got
);
559 io
.size
=l1
*clustersize
;
560 error
=ntfs_getput_clusters(ino
->vol
,cl1
,0,&io
);
562 if(l1
+max(s_vcn
-vcn
,0)==len
){
565 cluster
=cl1
=rl
->cluster
;
569 comp1
+=l1
*clustersize
;
570 }while(cluster
!=MAX_CLUSTER_T
&& got
<16); /* until empty run */
571 chunk
=16*clustersize
;
572 if(cluster
!=MAX_CLUSTER_T
|| got
==16)
577 decomp
=ntfs_malloc(16*clustersize
);
583 /* make sure there are null bytes
584 after the last block */
586 ntfs_decompress(decomp
,comp
,chunk
);
589 offs1
=offset
-s_vcn
*clustersize
;
590 chunk
=min(16*clustersize
-offs1
,chunk
);
592 dest
->fn_put(dest
,comp1
+offs1
,chunk
);
597 s_vcn
=offset
/clustersize
& ~15;
598 if(l
&& offset
>=((vcn
+len
)*clustersize
)){
606 if(comp
)ntfs_free(comp
);
607 if(decomp
)ntfs_free(decomp
);
612 int ntfs_write_compressed(ntfs_inode
*ino
, ntfs_attribute
*attr
, int offset
,
620 * c-file-style: "linux"