* add p cc
[mascara-docs.git] / i386 / linux / linux-2.3.21 / fs / ntfs / attr.c
blob3b8277643ba03f7962c41799aeda9efcb11c3753
1 /*
2 * attr.c
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 */
10 #include "ntfstypes.h"
11 #include "struct.h"
12 #include "attr.h"
14 #include <linux/errno.h>
15 #ifdef HAVE_STRING_H
16 #include <string.h>
17 #endif
18 #include "macros.h"
19 #include "support.h"
20 #include "util.h"
21 #include "super.h"
22 #include "inode.h"
24 /* Look if an attribute already exists in the inode, and if not, create it */
25 int
26 ntfs_new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos,
27 int *found, int do_search )
29 int do_insert=0;
30 int i;
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);
36 if( do_search ) {
38 * We assume that each attribute can be uniquely
39 * identified by inode
40 * number, attribute type and attribute name.
42 if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
43 *found=1;
44 *pos=i;
45 return 0;
48 /* attributes are ordered by type, then by name */
49 if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){
50 do_insert=1;
51 break;
55 /* re-allocate space */
56 if(ino->attr_count % 8 ==0)
58 ntfs_attribute* new;
59 new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
60 sizeof(ntfs_attribute));
61 if( !new )
62 return ENOMEM;
63 if( ino->attrs ) {
64 ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) );
65 ntfs_free( ino->attrs );
67 ino->attrs = new;
69 if(do_insert)
70 ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)*
71 sizeof(ntfs_attribute));
73 ino->attr_count++;
74 ino->attrs[i].type=type;
75 ino->attrs[i].namelen=namelen;
76 ino->attrs[i].name=name;
77 *pos=i;
78 *found=0;
79 return 0;
82 int
83 ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr)
85 int size=attr->size;
86 if(size>0){
87 /* FIXME: read data, free clusters */
88 return EOPNOTSUPP;
90 attr->resident=1;
91 return 0;
94 /* Store in the inode readable information about a run */
95 void
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) {
100 ntfs_runlist* new;
101 new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
102 if( !new )
103 return;
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;
116 attr->d.r.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
122 * multiple runs?
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,
127 int flags)
129 int error=0;
130 ntfs_runlist *rl;
131 int rlen;
132 ntfs_cluster_t cluster;
133 int clen;
135 if(attr->compressed)return EOPNOTSUPP;
136 if(ino->record_count>1)return EOPNOTSUPP;
138 if(attr->resident) {
139 error = ntfs_make_attr_nonresident(ino,attr);
140 if(error)
141 return error;
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;
150 if(rlen>=0)
151 cluster=rl[rlen].cluster+rl[rlen].len;
152 else
153 /* no preference for allocation space */
154 cluster=0;
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;
161 if(clen==0)
162 return 0;
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;
174 return 0;
176 ntfs_insert_run(attr,rlen+1,cluster,clen);
177 return 0;
181 ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
183 void *data=attr->d.data;
184 int len=attr->size;
185 int error,alen;
186 ntfs_io io;
187 attr->d.r.len=0;
188 attr->d.r.runlist=0;
189 attr->resident=0;
190 attr->allocated=attr->initialized=0;
191 alen=len;
192 error=ntfs_extend_attr(ino,attr,&alen,ALLOC_REQUIRE_SIZE);
193 if(error)return error;/* FIXME: On error, restore old values */
194 io.fn_put=ntfs_put;
195 io.fn_get=ntfs_get;
196 io.param=data;
197 io.size=len;
198 io.do_read=0;
199 return ntfs_readwrite_attr(ino,attr,0,&io);
203 ntfs_attr_allnonresident(ntfs_inode *ino)
205 int i, error=0;
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)
212 continue;
213 error = ntfs_make_attr_nonresident (ino, ino->attrs+i);
215 return error;
218 /* Resize the attribute to a newsize */
219 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
221 int error=0;
222 int oldsize=attr->size;
223 int clustersize=ino->vol->clustersize;
224 int i,count,newlen,newcount;
225 ntfs_runlist *rl;
227 if(newsize==oldsize)
228 return 0;
229 /* modifying compressed attributes not supported yet */
230 if(attr->compressed)
231 /* extending is easy: just insert sparse runs */
232 return EOPNOTSUPP;
233 if(attr->resident){
234 void *v;
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);
240 v=attr->d.data;
241 if(newsize){
242 attr->d.data=ntfs_malloc(newsize);
243 if(!attr->d.data) {
244 ntfs_free(v);
245 return ENOMEM;
247 if(newsize>oldsize)
248 ntfs_bzero((char*)attr->d.data+oldsize,
249 newsize-oldsize);
250 ntfs_memcpy((char*)attr->d.data,v,min(newsize,oldsize));
251 }else
252 attr->d.data=0;
253 ntfs_free(v);
254 attr->size=newsize;
255 return 0;
257 /* non-resident attribute */
258 rl=attr->d.r.runlist;
259 if(newsize<oldsize){
260 for(i=0,count=0;i<attr->d.r.len;i++){
261 if((count+rl[i].len)*clustersize>newsize)
262 break;
263 count+=(int)rl[i].len;
265 newlen=i+1;
266 /* free unused clusters in current run, unless sparse */
267 newcount=count;
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);
273 if(error)
274 return error; /* FIXME: incomplete operation */
275 rl[i].len=rounded;
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);
282 if(error)
283 return error; /* FIXME: incomplete operation */
285 /* FIXME? free space for extra runs in memory */
286 attr->d.r.len=newlen;
287 }else{
288 newlen=newsize;
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. */
297 if(!newsize)
298 error=ntfs_make_attr_resident(ino,attr);
299 return error;
302 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
303 int dsize, ntfs_attribute **rattr)
305 void *name;
306 int namelen;
307 int found,i;
308 int error;
309 ntfs_attribute *attr;
310 if(dsize>ino->vol->mft_recordsize)
311 /* FIXME: non-resident attributes */
312 return EOPNOTSUPP;
313 if(aname){
314 namelen=strlen(aname);
315 name=ntfs_malloc(2*namelen);
316 if( !name )
317 return ENOMEM;
318 ntfs_ascii2uni(name,aname,namelen);
319 }else{
320 name=0;
321 namelen=0;
324 error = ntfs_new_attr(ino,anum,name,namelen,&i,&found,1);
325 if( error ) {
326 ntfs_free( name );
327 return error;
330 if(found){
331 ntfs_free(name);
332 return EEXIST;
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);
339 if(error)
340 return error;
341 attr->attrno=i;
343 attr->resident=1;
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){
350 attr->indexed=1;
351 }else
352 attr->indexed=0;
353 attr->d.data=ntfs_malloc(dsize);
355 if( !attr->d.data )
356 return ENOMEM;
358 ntfs_memcpy(attr->d.data,data,dsize);
359 return 0;
362 /* Non-resident attributes are stored in runs (intervals of clusters).
364 * This function stores in the inode readable information about a non-resident
365 * attribute.
367 static int
368 ntfs_process_runs(ntfs_inode *ino,ntfs_attribute* attr,unsigned char *data)
370 int startvcn,endvcn;
371 int vcn,cnum;
372 ntfs_cluster_t cluster;
373 int len,ctype;
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;
380 if(vcn!=startvcn)
382 ntfs_error("Problem with runlist in extended record\n");
383 return -1;
385 if(!endvcn)
387 endvcn = NTFS_GETU64(data+0x28)-1; /* allocated length */
388 endvcn /= ino->vol->clustersize;
390 data=data+NTFS_GETU16(data+0x20);
391 cnum=attr->d.r.len;
392 cluster=0;
393 for(vcn=startvcn; vcn<=endvcn; vcn+=len)
395 if(ntfs_decompress_run(&data,&len,&cluster,&ctype))
396 return -1;
397 if(ctype)
398 ntfs_insert_run(attr,cnum,-1,len);
399 else
400 ntfs_insert_run(attr,cnum,cluster,len);
401 cnum++;
403 return 0;
406 /* Insert the attribute starting at attr in the inode ino */
407 int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
409 int i,found;
410 int type;
411 short int *name;
412 int namelen;
413 void *data;
414 ntfs_attribute *attr;
415 int error;
417 type = NTFS_GETU32(attrdata);
418 namelen = NTFS_GETU8(attrdata+9);
419 /* read the attribute's name if it has one */
420 if(!namelen)
421 name=0;
422 else
424 /* 1 Unicode character fits in 2 bytes */
425 name=ntfs_malloc(2*namelen);
426 if( !name )
427 return ENOMEM;
429 ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen);
432 error = ntfs_new_attr(ino,type,name,namelen,&i,&found,1);
433 if( error ) {
434 if( name ) ntfs_free( name );
435 return error;
438 /* We can have in one inode two attributes with type 0x00000030 (File Name)
439 and without name */
440 if(found && /*FIXME*/type!=ino->vol->at_file_name)
442 ntfs_process_runs(ino,ino->attrs+i,attrdata);
443 return 0;
444 } else if( found ) {
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
448 new entry */
449 ntfs_new_attr(ino,type,name,namelen,&i,&found,0);
451 attr=ino->attrs+i;
452 attr->resident=NTFS_GETU8(attrdata+8)==0;
453 attr->compressed=NTFS_GETU16(attrdata+0xC);
454 attr->attrno=NTFS_GETU16(attrdata+0xE);
456 if(attr->resident) {
457 attr->size=NTFS_GETU16(attrdata+0x10);
458 data=attrdata+NTFS_GETU16(attrdata+0x14);
459 attr->d.data = (void*)ntfs_malloc(attr->size);
460 if( !attr->d.data )
461 return ENOMEM;
462 ntfs_memcpy(attr->d.data,data,attr->size);
463 attr->indexed=NTFS_GETU16(attrdata+0x16);
464 }else{
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);
469 if(attr->compressed)
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);
475 return 0;
479 ntfs_read_zero(ntfs_io *dest,int size)
481 char *sparse=ntfs_calloc(512);
482 if(!sparse)
483 return ENOMEM;
484 while(size){
485 int i=min(size,512);
486 dest->fn_put(dest,sparse,i);
487 size-=i;
489 ntfs_free(sparse);
490 return 0;
493 /* process compressed attributes */
494 int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
495 ntfs_io *dest)
497 int error=0;
498 int clustersize,l;
499 int s_vcn,rnum,vcn,len,chunk,got,l1,offs1,copied;
500 ntfs_cluster_t cluster,cl1;
501 char *comp=0,*comp1;
502 char *decomp=0;
503 ntfs_io io;
504 ntfs_runlist *rl;
506 l=dest->size;
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 */
517 s_vcn &= ~15;
518 rl=attr->d.r.runlist;
519 for(rnum=vcn=0;rnum<attr->d.r.len && vcn+rl->len<=s_vcn;rnum++,rl++)
520 vcn+=rl->len;
521 if(rnum==attr->d.r.len){
522 /* beyond end of file */
523 /* FIXME: check allocated/initialized */
524 dest->size=0;
525 return 0;
527 io.do_read=1;
528 io.fn_put=ntfs_put;
529 io.fn_get=0;
530 cluster=rl->cluster;
531 len=rl->len;
532 copied=0;
533 while(l){
534 chunk=0;
535 if(cluster==MAX_CLUSTER_T){
536 /* sparse cluster */
537 int l1;
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);
542 if(error)
543 goto out;
544 }else if(dest->do_read){
545 if(!comp){
546 comp=ntfs_malloc(16*clustersize);
547 if(!comp){
548 error=ENOMEM;
549 goto out;
552 got=0;
553 /* we might need to start in the middle of a run */
554 cl1=cluster+s_vcn-vcn;
555 comp1=comp;
557 io.param=comp1;
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);
561 if(error)goto out;
562 if(l1+max(s_vcn-vcn,0)==len){
563 rnum++;rl++;
564 vcn+=len;
565 cluster=cl1=rl->cluster;
566 len=rl->len;
568 got+=l1;
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)
573 /* uncompressible */
574 comp1=comp;
575 else{
576 if(!decomp){
577 decomp=ntfs_malloc(16*clustersize);
578 if(!decomp){
579 error=ENOMEM;
580 goto out;
583 /* make sure there are null bytes
584 after the last block */
585 *(ntfs_u32*)comp1=0;
586 ntfs_decompress(decomp,comp,chunk);
587 comp1=decomp;
589 offs1=offset-s_vcn*clustersize;
590 chunk=min(16*clustersize-offs1,chunk);
591 chunk=min(l,chunk);
592 dest->fn_put(dest,comp1+offs1,chunk);
594 l-=chunk;
595 copied+=chunk;
596 offset+=chunk;
597 s_vcn=offset/clustersize & ~15;
598 if(l && offset>=((vcn+len)*clustersize)){
599 rnum++;rl++;
600 vcn+=len;
601 cluster=rl->cluster;
602 len=rl->len;
605 out:
606 if(comp)ntfs_free(comp);
607 if(decomp)ntfs_free(decomp);
608 dest->size=copied;
609 return error;
612 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
613 ntfs_io *dest)
615 return EOPNOTSUPP;
619 * Local variables:
620 * c-file-style: "linux"
621 * End: