4 * Copyright (C) 1996-1997 Martin von Löwis
5 * Copyright (C) 1996-1997 Régis Duchesne
19 /* Look if an attribute already exists in the inode, and if not, create it */
21 new_attr(ntfs_inode
*ino
,int type
,void *name
,int namelen
,int *pos
, int *found
)
26 for(i
=0;i
<ino
->attr_count
;i
++)
28 int n
=min(namelen
,ino
->attrs
[i
].namelen
);
29 int s
=ntfs_uni_strncmp(ino
->attrs
[i
].name
,name
,n
);
31 * We assume that each attribute can be uniquely
33 * number, attribute type and attribute name.
35 if(ino
->attrs
[i
].type
==type
&& ino
->attrs
[i
].namelen
==namelen
&& !s
){
40 /* attributes are ordered by type, then by name */
41 if(ino
->attrs
[i
].type
>type
|| (ino
->attrs
[i
].type
==type
&& s
==1)){
47 /* re-allocate space */
48 if(ino
->attr_count
% 8 ==0)
50 ntfs_attribute
* old
=ino
->attrs
;
51 ino
->attrs
= (ntfs_attribute
*)ntfs_malloc((ino
->attr_count
+8)*
52 sizeof(ntfs_attribute
));
54 ntfs_memcpy(ino
->attrs
,old
,ino
->attr_count
*sizeof(ntfs_attribute
));
59 ntfs_memmove(ino
->attrs
+i
+1,ino
->attrs
+i
,(ino
->attr_count
-i
)*
60 sizeof(ntfs_attribute
));
62 ino
->attrs
[i
].type
=type
;
63 ino
->attrs
[i
].namelen
=namelen
;
64 ino
->attrs
[i
].name
=name
;
71 ntfs_make_attr_resident(ntfs_inode
*ino
,ntfs_attribute
*attr
)
75 /* FIXME: read data, free clusters */
82 /* Store in the inode readable information about a run */
84 ntfs_insert_run(ntfs_attribute
*attr
,int cnum
,int cluster
,int len
)
86 /* (re-)allocate space if necessary */
87 if(attr
->d
.r
.len
% 8 == 0) {
89 old
=attr
->d
.r
.runlist
;
90 attr
->d
.r
.runlist
=ntfs_malloc((attr
->d
.r
.len
+8)*sizeof(ntfs_runlist
));
92 ntfs_memcpy(attr
->d
.r
.runlist
,old
,attr
->d
.r
.len
93 *sizeof(ntfs_runlist
));
97 if(attr
->d
.r
.len
>cnum
)
98 ntfs_memmove(attr
->d
.r
.runlist
+cnum
+1,attr
->d
.r
.runlist
+cnum
,
99 (attr
->d
.r
.len
-cnum
)*sizeof(ntfs_runlist
));
100 attr
->d
.r
.runlist
[cnum
].cluster
=cluster
;
101 attr
->d
.r
.runlist
[cnum
].len
=len
;
105 int ntfs_extend_attr(ntfs_inode
*ino
, ntfs_attribute
*attr
, int *len
,
112 if(attr
->compressed
)return EOPNOTSUPP
;
113 if(attr
->resident
)return EOPNOTSUPP
;
114 if(ino
->record_count
>1)return EOPNOTSUPP
;
115 rl
=attr
->d
.r
.runlist
;
116 rlen
=attr
->d
.r
.len
-1;
118 cluster
=rl
[rlen
].cluster
+rl
[rlen
].len
;
120 /* no preference for allocation space */
122 /* round up to multiple of cluster size */
123 clen
=(*len
+ino
->vol
->clustersize
-1)/ino
->vol
->clustersize
;
124 /* FIXME: try to allocate smaller pieces */
125 error
=ntfs_allocate_clusters(ino
->vol
,&cluster
,&clen
,
126 flags
|ALLOC_REQUIRE_SIZE
);
127 if(error
)return error
;
128 attr
->allocated
+=clen
;
129 *len
=clen
*ino
->vol
->clustersize
;
130 /* contiguous chunk */
131 if(rlen
>=0 && cluster
==rl
[rlen
].cluster
+rl
[rlen
].len
){
135 ntfs_insert_run(attr
,rlen
+1,cluster
,*len
);
140 ntfs_make_attr_nonresident(ntfs_inode
*ino
, ntfs_attribute
*attr
)
142 void *data
=attr
->d
.data
;
149 attr
->allocated
=attr
->initialized
=0;
151 error
=ntfs_extend_attr(ino
,attr
,&alen
,ALLOC_REQUIRE_SIZE
);
152 if(error
)return error
;/* FIXME: On error, restore old values */
158 return ntfs_readwrite_attr(ino
,attr
,0,&io
);
161 /* Resize the attribute to a newsize */
162 int ntfs_resize_attr(ntfs_inode
*ino
, ntfs_attribute
*attr
, int newsize
)
165 int oldsize
=attr
->size
;
166 int clustersize
=ino
->vol
->clustersize
;
167 int i
,count
,newlen
,newcount
;
172 /* modifying compressed attributes not supported yet */
174 /* extending is easy: just insert sparse runs */
178 if(newsize
>ino
->vol
->clustersize
){
179 error
=ntfs_make_attr_nonresident(ino
,attr
);
180 if(error
)return error
;
181 return ntfs_resize_attr(ino
,attr
,newsize
);
185 attr
->d
.data
=ntfs_malloc(newsize
);
188 ntfs_bzero(attr
->d
.data
+oldsize
,newsize
);
189 ntfs_memcpy(attr
->d
.data
,v
,min(newsize
,oldsize
));
196 /* non-resident attribute */
197 rl
=attr
->d
.r
.runlist
;
199 for(i
=0,count
=0;i
<attr
->d
.r
.len
;i
++){
200 if((count
+rl
[i
].len
)*clustersize
>newsize
)
205 /* free unused clusters in current run, unless sparse */
207 if(rl
[i
].cluster
!=-1){
208 int rounded
=newsize
-count
*clustersize
;
209 rounded
=(rounded
+clustersize
-1)/clustersize
;
210 error
=ntfs_deallocate_clusters(ino
->vol
,rl
[i
].cluster
+rounded
,
213 return error
; /* FIXME: incomplete operation */
215 newcount
=count
+rounded
;
217 /* free all other runs */
218 for(i
++;i
<attr
->d
.r
.len
;i
++)
219 if(rl
[i
].cluster
!=-1){
220 error
=ntfs_deallocate_clusters(ino
->vol
,rl
[i
].cluster
,rl
[i
].len
);
222 return error
; /* FIXME: incomplete operation */
224 /* FIXME? free space for extra runs in memory */
225 attr
->d
.r
.len
=newlen
;
228 error
=ntfs_extend_attr(ino
,attr
,&newlen
,ALLOC_REQUIRE_SIZE
);
229 if(error
)return error
; /* FIXME: incomplete */
230 newcount
=newlen
/clustersize
;
232 /* fill in new sizes */
233 attr
->allocated
= newcount
*clustersize
;
234 attr
->size
= newsize
;
235 attr
->initialized
= newsize
;
237 error
=ntfs_make_attr_resident(ino
,attr
);
241 int ntfs_create_attr(ntfs_inode
*ino
, int anum
, char *aname
, void *data
,
242 int dsize
, ntfs_attribute
**rattr
)
248 ntfs_attribute
*attr
;
249 if(dsize
>ino
->vol
->mft_recordsize
)
250 /* FIXME: non-resident attributes */
253 namelen
=strlen(aname
);
254 name
=ntfs_malloc(2*namelen
);
255 ntfs_ascii2uni(name
,aname
,namelen
);
260 new_attr(ino
,anum
,name
,namelen
,&i
,&found
);
265 *rattr
=attr
=ino
->attrs
+i
;
266 /* allocate a new number.
267 FIXME: Should this happen on inode writeback?
268 FIXME: extensions records not supported */
269 error
=ntfs_allocate_attr_number(ino
,&i
);
275 attr
->compressed
=attr
->cengine
=0;
276 attr
->size
=attr
->allocated
=attr
->initialized
=dsize
;
278 /* FIXME: INDEXED information should come from $AttrDef
279 Currently, only file names are indexed */
280 if(anum
==ino
->vol
->at_file_name
){
284 attr
->d
.data
=ntfs_malloc(dsize
);
285 ntfs_memcpy(attr
->d
.data
,data
,dsize
);
289 /* Non-resident attributes are stored in runs (intervals of clusters).
291 * This function stores in the inode readable information about a non-resident
295 ntfs_process_runs(ntfs_inode
*ino
,ntfs_attribute
* attr
,unsigned char *data
)
299 int cluster
,len
,ctype
;
300 startvcn
= NTFS_GETU64(data
+0x10);
301 endvcn
= NTFS_GETU64(data
+0x18);
303 /* check whether this chunk really belongs to the end */
304 for(cnum
=0,vcn
=0;cnum
<attr
->d
.r
.len
;cnum
++)
305 vcn
+=attr
->d
.r
.runlist
[cnum
].len
;
308 ntfs_error("Problem with runlist in extended record\n");
313 endvcn
= NTFS_GETU64(data
+0x28)-1; /* allocated length */
314 endvcn
/= ino
->vol
->clustersize
;
316 data
=data
+NTFS_GETU16(data
+0x20);
319 for(vcn
=startvcn
; vcn
<=endvcn
; vcn
+=len
)
321 if(ntfs_decompress_run(&data
,&len
,&cluster
,&ctype
))
324 ntfs_insert_run(attr
,cnum
,-1,len
);
326 ntfs_insert_run(attr
,cnum
,cluster
,len
);
332 /* Insert the attribute starting at attr in the inode ino */
333 int ntfs_insert_attribute(ntfs_inode
*ino
, unsigned char* attrdata
)
340 ntfs_attribute
*attr
;
342 type
= NTFS_GETU32(attrdata
);
343 namelen
= NTFS_GETU8(attrdata
+9);
344 /* read the attribute's name if it has one */
349 /* 1 Unicode character fits in 2 bytes */
350 name
=ntfs_malloc(2*namelen
);
351 ntfs_memcpy(name
,attrdata
+NTFS_GETU16(attrdata
+10),2*namelen
);
353 new_attr(ino
,type
,name
,namelen
,&i
,&found
);
354 /* We can have in one inode two attributes with type 0x00000030 (File Name)
356 if(found
&& /*FIXME*/type
!=ino
->vol
->at_file_name
)
358 ntfs_process_runs(ino
,ino
->attrs
+i
,attrdata
);
362 attr
->resident
=NTFS_GETU8(attrdata
+8)==0;
363 attr
->compressed
=NTFS_GETU16(attrdata
+0xC);
364 attr
->attrno
=NTFS_GETU16(attrdata
+0xE);
367 attr
->size
=NTFS_GETU16(attrdata
+0x10);
368 data
=attrdata
+NTFS_GETU16(attrdata
+0x14);
369 attr
->d
.data
= (void*)ntfs_malloc(attr
->size
);
370 ntfs_memcpy(attr
->d
.data
,data
,attr
->size
);
371 attr
->indexed
=NTFS_GETU16(attrdata
+0x16);
373 attr
->allocated
=NTFS_GETU32(attrdata
+0x28);
374 attr
->size
=NTFS_GETU32(attrdata
+0x30);
375 attr
->initialized
=NTFS_GETU32(attrdata
+0x38);
376 attr
->cengine
=NTFS_GETU16(attrdata
+0x22);
378 attr
->compsize
=NTFS_GETU32(attrdata
+0x40);
379 ino
->attrs
[i
].d
.r
.runlist
=0;
380 ino
->attrs
[i
].d
.r
.len
=0;
381 ntfs_process_runs(ino
,attr
,attrdata
);
386 /* process compressed attributes */
387 int ntfs_read_compressed(ntfs_inode
*ino
, ntfs_attribute
*attr
, int offset
,
392 int s_vcn
,rnum
,vcn
,cluster
,len
,chunk
,got
,cl1
,l1
,offs1
,copied
;
399 clustersize
=ino
->vol
->clustersize
;
400 /* starting cluster of potential chunk
401 there are three situations:
402 a) in a large uncompressible or sparse chunk,
403 s_vcn is in the middle of a run
404 b) s_vcn is right on a run border
405 c) when several runs make a chunk, s_vcn is before the chunks
407 s_vcn
=offset
/clustersize
;
408 /* round down to multiple of 16 */
410 rl
=attr
->d
.r
.runlist
;
411 for(rnum
=vcn
=0;rnum
<attr
->d
.r
.len
&& vcn
+rl
->len
<=s_vcn
;rnum
++,rl
++)
413 if(rnum
==attr
->d
.r
.len
){
414 /* beyond end of file */
415 /* FIXME: check allocated/initialized */
429 char *sparse
=ntfs_calloc(512);
431 if(!sparse
)return ENOMEM
;
432 if((len
-(s_vcn
-vcn
)) & 15)
433 ntfs_error("unexpected sparse chunk size");
434 l1
=chunk
= min((vcn
+len
)*clustersize
-offset
,l
);
437 dest
->fn_put(dest
,sparse
,i
);
441 }else if(dest
->do_read
){
443 comp
=ntfs_malloc(16*clustersize
);
450 /* we might need to start in the middle of a run */
451 cl1
=cluster
+s_vcn
-vcn
;
455 l1
=min(len
-max(s_vcn
-vcn
,0),16-got
);
456 io
.size
=l1
*clustersize
;
457 error
=ntfs_getput_clusters(ino
->vol
,cl1
,0,&io
);
459 if(l1
+max(s_vcn
-vcn
,0)==len
){
462 cluster
=cl1
=rl
->cluster
;
466 comp1
+=l1
*clustersize
;
467 }while(cluster
!=-1 && got
<16); /* until empty run */
468 chunk
=16*clustersize
;
469 if(cluster
!=-1 || got
==16)
474 decomp
=ntfs_malloc(16*clustersize
);
480 /* make sure there are null bytes
481 after the last block */
483 ntfs_decompress(decomp
,comp
,chunk
);
486 offs1
=offset
-s_vcn
*clustersize
;
487 chunk
=min(16*clustersize
-offs1
,chunk
);
489 dest
->fn_put(dest
,comp1
+offs1
,chunk
);
494 s_vcn
=offset
/clustersize
& ~15;
495 if(l
&& offset
>=((vcn
+len
)*clustersize
)){
503 if(comp
)ntfs_free(comp
);
504 if(decomp
)ntfs_free(decomp
);
509 int ntfs_write_compressed(ntfs_inode
*ino
, ntfs_attribute
*attr
, int offset
,
517 * c-file-style: "linux"