4 * Copyright (C) 1995-1997 Martin von Löwis
12 #include <linux/errno.h>
19 static char I30
[]="$I30";
21 /* An index record should start with INDX, and the last word in each
22 block should contain the check value. If it passes, the original
23 values need to be restored */
24 int ntfs_check_index_record(ntfs_inode
*ino
, char *record
)
26 return ntfs_fixup_record(ino
->vol
, record
, "INDX",
27 ino
->u
.index
.recordsize
);
30 static inline int ntfs_is_top(ntfs_u64 stack
)
35 static int ntfs_pop(ntfs_u64
*stack
)
37 static int width
[16]={1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
39 switch(width
[*stack
& 15])
41 case 1:res
=(int)((*stack
&15)>>1);
44 case 2:res
=(int)(((*stack
&63)>>2)+7);
47 case 3:res
=(int)(((*stack
& 255)>>3)+23);
50 case 4:res
=(int)(((*stack
& 1023)>>4)+55);
53 default:ntfs_error("Unknown encoding\n");
58 static inline unsigned int ntfs_top(void)
63 static ntfs_u64
ntfs_push(ntfs_u64 stack
,int i
)
65 if(i
<7)return (stack
<<4)|(i
<<1);
66 if(i
<23)return (stack
<<6)|((i
-7)<<2)|1;
67 if(i
<55)return (stack
<<8)|((i
-23)<<3)|3;
68 if(i
<120)return (stack
<<10)|((i
-55)<<4)|7;
69 ntfs_error("Too many entries\n");
70 return 0xFFFFFFFFFFFFFFFF;
74 static void ntfs_display_stack(ntfs_u64 stack
)
76 while(!ntfs_is_top(stack
))
78 printf("%d ",ntfs_pop(&stack
));
84 /* True if the entry points to another block of entries */
85 static inline int ntfs_entry_has_subnodes(char* entry
)
87 return (int)NTFS_GETU8(entry
+12)&1;
90 /* True if it is not the 'end of dir' entry */
91 static inline int ntfs_entry_is_used(char* entry
)
93 return (int)(NTFS_GETU8(entry
+12)&2)==0;
96 static int ntfs_allocate_index_block(ntfs_iterate_s
*walk
)
98 ntfs_attribute
*allocation
=0,*bitmap
=0;
102 ntfs_volume
*vol
=walk
->dir
->vol
;
104 /* check for allocation attribute */
105 allocation
=ntfs_find_attr(walk
->dir
,vol
->at_index_allocation
,I30
);
108 /* create index allocation attribute */
109 error
=ntfs_create_attr(walk
->dir
,vol
->at_index_allocation
,I30
,
111 if(error
)return error
;
112 ntfs_bzero(bmp
,sizeof(bmp
));
113 error
=ntfs_create_attr(walk
->dir
,vol
->at_bitmap
,I30
,
114 bmp
,sizeof(bmp
),&bitmap
);
115 if(error
)return error
;
117 bitmap
=ntfs_find_attr(walk
->dir
,vol
->at_bitmap
,I30
);
119 ntfs_error("Directory w/o bitmap\n");
123 bmap
=ntfs_malloc(size
);
124 if(!bmap
)return ENOMEM
;
129 error
=ntfs_read_attr(walk
->dir
,vol
->at_bitmap
,I30
,0,&io
);
140 for(i
=bit
=0;i
<size
;i
++){
141 if(bmap
[i
]==0xFF)continue;
142 for(bit
=0;bit
<8;bit
++)
143 if(((bmap
[i
]>>bit
) & 1) == 0)
148 /* FIXME: extend bitmap */
150 walk
->newblock
=(i
*8+bit
)*walk
->dir
->u
.index
.clusters_per_record
;
154 error
=ntfs_write_attr(walk
->dir
,vol
->at_bitmap
,I30
,0,&io
);
155 if(error
|| io
.size
!=size
){
157 return error
?error
:EIO
;
161 /* check whether record is out of allocated range */
162 size
=allocation
->size
;
163 if(walk
->newblock
* vol
->clustersize
>= size
){
164 /* build index record */
165 int s1
=walk
->dir
->u
.index
.recordsize
;
166 int nr_fix
= s1
/vol
->blocksize
+1;
168 char *record
=ntfs_malloc(s1
);
169 ntfs_bzero(record
,s1
);
171 ntfs_memcpy(record
,"INDX",4);
172 /* offset to fixups */
173 NTFS_PUTU16(record
+4,0x28);
174 /* number of fixups */
175 NTFS_PUTU16(record
+6,nr_fix
);
176 /* FIXME: log file number */
178 NTFS_PUTU64(record
+0x10,walk
->newblock
);
180 hsize
= 0x10+2*nr_fix
;
181 hsize
= (hsize
+7) & ~7; /* Align. */
182 NTFS_PUTU16(record
+0x18, hsize
);
183 /* total size of record */
184 NTFS_PUTU32(record
+0x20,s1
-0x18);
185 /* Writing the data will extend the attribute. */
189 error
=ntfs_readwrite_attr(walk
->dir
, allocation
, size
, &io
);
190 if(error
|| io
.size
!=s1
){
192 return error
?error
:EIO
;
200 /* Write an index block (root or allocation) back to storage.
201 used is the total number of bytes in buf, including all headers. */
203 static int ntfs_index_writeback(ntfs_iterate_s
*walk
, ntfs_u8
*buf
, int block
,
209 ntfs_volume
*vol
= walk
->dir
->vol
;
215 NTFS_PUTU16(buf
+0x14,used
-0x10);
216 /* 0x18 is a copy thereof */
217 NTFS_PUTU16(buf
+0x18,used
-0x10);
219 error
=ntfs_write_attr(walk
->dir
,vol
->at_index_root
,
221 if(error
)return error
;
222 if(io
.size
!=used
)return EIO
;
223 /* shrink if necessary */
224 a
= ntfs_find_attr(walk
->dir
, vol
->at_index_root
, I30
);
225 ntfs_resize_attr(walk
->dir
, a
, used
);
227 NTFS_PUTU16(buf
+0x1C,used
-0x18);
228 ntfs_insert_fixups(buf
,vol
->blocksize
);
229 io
.size
=walk
->dir
->u
.index
.recordsize
;
230 error
=ntfs_write_attr(walk
->dir
,vol
->at_index_allocation
,I30
,
231 block
*vol
->clustersize
,
233 if(error
)return error
;
234 if(io
.size
!=walk
->dir
->u
.index
.recordsize
)
240 static int ntfs_split_record(ntfs_iterate_s
*walk
, char *start
, int bsize
,
244 ntfs_u8
*newbuf
=0,*middle
=0;
245 int error
,othersize
,mlen
;
247 ntfs_volume
*vol
=walk
->dir
->vol
;
250 error
=ntfs_allocate_index_block(walk
);
253 /* This should not happen */
254 if(walk
->block
== -1){
255 ntfs_error("Trying to split root");
258 entry
= start
+NTFS_GETU16(start
+0x18)+0x18;
259 for(prev
=entry
; entry
-start
<usize
/2; entry
+= NTFS_GETU16(entry
+8))
262 newbuf
=ntfs_malloc(vol
->index_recordsize
);
268 io
.size
=vol
->index_recordsize
;
269 /* read in old header. FIXME: reading everything is overkill */
270 error
=ntfs_read_attr(walk
->dir
,vol
->at_index_allocation
,I30
,
271 walk
->newblock
*vol
->clustersize
,&io
);
273 if(io
.size
!=vol
->index_recordsize
){
277 /* FIXME: adjust header */
278 /* copy everything from entry to new block */
279 othersize
=usize
-(entry
-start
);
280 ntfs_memcpy(newbuf
+NTFS_GETU16(newbuf
+0x18)+0x18,entry
,othersize
);
282 NTFS_PUTU32(newbuf
+0x24, NTFS_GETU32(start
+0x24));
283 error
=ntfs_index_writeback(walk
,newbuf
,walk
->newblock
,
284 othersize
+NTFS_GETU16(newbuf
+0x18)+0x18);
287 /* move prev to walk */
288 mlen
=NTFS_GETU16(prev
+0x8);
289 /* Remember old child node. */
290 if(ntfs_entry_has_subnodes(prev
))
291 oldblock
= NTFS_GETU32(prev
+mlen
-8);
294 /* allow for pointer to subnode */
295 middle
=ntfs_malloc(ntfs_entry_has_subnodes(prev
)?mlen
:mlen
+8);
300 ntfs_memcpy(middle
,prev
,mlen
);
301 /* set has_subnodes flag */
302 NTFS_PUTU8(middle
+0xC, NTFS_GETU8(middle
+0xC) | 1);
303 /* middle entry points to block, parent entry will point to newblock */
304 NTFS_PUTU64(middle
+mlen
-8,walk
->block
);
306 ntfs_error("entry not reset");
307 walk
->new_entry
=middle
;
308 walk
->u
.flags
|=ITERATE_SPLIT_DONE
;
309 /* Terminate old block. */
310 othersize
= usize
-(prev
-start
);
311 NTFS_PUTU64(prev
, 0);
313 NTFS_PUTU32(prev
+8, 0x10);
314 NTFS_PUTU32(prev
+0xC, 2);
317 NTFS_PUTU32(prev
+8, 0x18);
318 NTFS_PUTU32(prev
+0xC, 3);
319 NTFS_PUTU64(prev
+0x10, oldblock
);
322 /* write back original block */
323 error
=ntfs_index_writeback(walk
,start
,walk
->block
,othersize
);
325 if(newbuf
)ntfs_free(newbuf
);
326 if(middle
)ntfs_free(middle
);
330 static int ntfs_dir_insert(ntfs_iterate_s
*walk
, char *start
, char* entry
)
332 int blocksize
,usedsize
,error
,offset
;
335 if(walk
->block
==-1){ /*index root */
336 blocksize
=walk
->dir
->vol
->mft_recordsize
;
337 usedsize
=NTFS_GETU16(start
+0x14)+0x10;
339 blocksize
=walk
->dir
->u
.index
.recordsize
;
340 usedsize
=NTFS_GETU16(start
+0x1C)+0x18;
342 if(usedsize
+walk
->new_entry_size
> blocksize
){
343 char* s1
=ntfs_malloc(blocksize
+walk
->new_entry_size
);
344 if(!s1
)return ENOMEM
;
345 ntfs_memcpy(s1
,start
,usedsize
);
347 /* adjust entry to s1 */
348 entry
=s1
+(entry
-start
);
351 ntfs_memmove(entry
+walk
->new_entry_size
,entry
,usedsize
-offset
);
352 ntfs_memcpy(entry
,walk
->new_entry
,walk
->new_entry_size
);
353 usedsize
+=walk
->new_entry_size
;
354 ntfs_free(walk
->new_entry
);
357 error
=ntfs_split_record(walk
,start
,blocksize
,usedsize
);
360 ntfs_index_writeback(walk
,start
,walk
->block
,usedsize
);
364 /* Try to split INDEX_ROOT attributes. Return E2BIG if nothing changed. */
367 ntfs_split_indexroot(ntfs_inode
*ino
)
370 ntfs_u8
*root
=0, *index
=0;
372 int error
, off
, i
, bsize
, isize
;
375 ra
= ntfs_find_attr(ino
, ino
->vol
->at_index_root
, I30
);
378 bsize
= ino
->vol
->mft_recordsize
;
379 root
= ntfs_malloc(bsize
);
382 io
.fn_put
= ntfs_put
;
385 error
= ntfs_read_attr(ino
, ino
->vol
->at_index_root
, I30
, 0, &io
);
389 /* Count number of entries. */
390 for(i
= 0; ntfs_entry_is_used(root
+off
); i
++)
391 off
+= NTFS_GETU16(root
+off
+8);
393 /* We don't split small index roots. */
397 index
= ntfs_malloc(ino
->vol
->index_recordsize
);
402 walk
.result
= walk
.new_entry
= 0;
404 error
= ntfs_allocate_index_block(&walk
);
408 /* Write old root to new index block. */
410 io
.size
= ino
->vol
->index_recordsize
;
411 error
= ntfs_read_attr(ino
, ino
->vol
->at_index_allocation
, I30
,
412 walk
.newblock
*ino
->vol
->clustersize
, &io
);
415 isize
= NTFS_GETU16(root
+0x18) - 0x10;
416 ntfs_memcpy(index
+NTFS_GETU16(index
+0x18)+0x18, root
+0x20, isize
);
418 NTFS_PUTU32(index
+0x24, NTFS_GETU32(root
+0x1C));
420 error
= ntfs_index_writeback(&walk
, index
, walk
.newblock
,
421 isize
+NTFS_GETU16(index
+0x18)+0x18);
425 /* Mark root as split. */
426 NTFS_PUTU32(root
+0x1C, 1);
427 /* Truncate index root. */
428 NTFS_PUTU64(root
+0x20, 0);
429 NTFS_PUTU32(root
+0x28, 0x18);
430 NTFS_PUTU32(root
+0x2C, 3);
431 NTFS_PUTU64(root
+0x30, walk
.newblock
);
432 error
= ntfs_index_writeback(&walk
,root
,-1,0x38);
439 /* The entry has been found. Copy the result in the caller's buffer */
440 static int ntfs_copyresult(char *dest
,char *source
)
442 int length
=NTFS_GETU16(source
+8);
443 ntfs_memcpy(dest
,source
,length
);
447 /* use $UpCase some day */
448 static inline unsigned short ntfs_my_toupper(ntfs_volume
*vol
, ntfs_u16 x
)
450 /* we should read any pending rest of $UpCase here */
451 if(x
>= vol
->upcase_length
)
453 return vol
->upcase
[x
];
456 /* everything passed in walk and entry */
457 static int ntfs_my_strcmp(ntfs_iterate_s
*walk
, const unsigned char *entry
)
459 int lu
=*(entry
+0x50);
462 ntfs_u16
* name
=(ntfs_u16
*)(entry
+0x52);
463 ntfs_volume
*vol
=walk
->dir
->vol
;
464 for(i
=0;i
<lu
&& i
<walk
->namelen
;i
++)
465 if(ntfs_my_toupper(vol
,name
[i
])!=ntfs_my_toupper(vol
,walk
->name
[i
]))
467 if(i
==lu
&& i
==walk
->namelen
)return 0;
469 if(i
==walk
->namelen
)return -1;
470 if(ntfs_my_toupper(vol
,name
[i
])<ntfs_my_toupper(vol
,walk
->name
[i
]))return 1;
474 /* Necessary forward declaration */
475 static int ntfs_getdir_iterate(ntfs_iterate_s
*walk
, char *start
, char *entry
);
477 /* Parse a block of entries. Load the block, fix it up, and iterate
478 over the entries. The block is given as virtual cluster number */
479 static int ntfs_getdir_record(ntfs_iterate_s
*walk
, int block
)
481 int length
=walk
->dir
->u
.index
.recordsize
;
482 char *record
=(char*)ntfs_malloc(length
);
491 /* Read the block from the index allocation attribute */
492 error
=ntfs_read_attr(walk
->dir
,walk
->dir
->vol
->at_index_allocation
,I30
,
493 block
*walk
->dir
->vol
->clustersize
,&io
);
494 if(error
|| io
.size
!=length
){
495 ntfs_error("read failed\n");
499 if(!ntfs_check_index_record(walk
->dir
,record
)){
500 ntfs_error("%x is not an index record\n",block
);
504 offset
=record
+NTFS_GETU16(record
+0x18)+0x18;
505 oldblock
=walk
->block
;
507 retval
=ntfs_getdir_iterate(walk
,record
,offset
);
508 walk
->block
=oldblock
;
513 /* go down to the next block of entries. These collate before
515 static int ntfs_descend(ntfs_iterate_s
*walk
, ntfs_u8
*start
, ntfs_u8
*entry
)
517 int length
=NTFS_GETU16(entry
+8);
518 int nextblock
=NTFS_GETU32(entry
+length
-8);
521 if(!ntfs_entry_has_subnodes(entry
)) {
522 ntfs_error("illegal ntfs_descend call\n");
525 error
=ntfs_getdir_record(walk
,nextblock
);
526 if(!error
&& walk
->type
==DIR_INSERT
&&
527 (walk
->u
.flags
& ITERATE_SPLIT_DONE
)){
528 /* Split has occurred. Adjust entry, insert new_entry. */
529 NTFS_PUTU32(entry
+length
-8,walk
->newblock
);
530 /* Reset flags, as the current block might be split again. */
531 walk
->u
.flags
&= ~ITERATE_SPLIT_DONE
;
532 error
=ntfs_dir_insert(walk
,start
,entry
);
538 ntfs_getdir_iterate_byposition(ntfs_iterate_s
*walk
,char* start
,char *entry
)
541 int curpos
=0,destpos
=0;
544 if(ntfs_is_top(walk
->u
.pos
))return 0;
545 destpos
=ntfs_pop(&walk
->u
.pos
);
550 if(ntfs_entry_has_subnodes(entry
))
551 ntfs_descend(walk
,start
,entry
);
553 walk
->u
.pos
=ntfs_top();
554 if(ntfs_is_top(walk
->u
.pos
) && !ntfs_entry_is_used(entry
))
558 walk
->u
.pos
=ntfs_push(walk
->u
.pos
,curpos
);
563 if(!ntfs_is_top(walk
->u
.pos
) && ntfs_entry_has_subnodes(entry
))
565 retval
=ntfs_descend(walk
,start
,entry
);
567 walk
->u
.pos
=ntfs_push(walk
->u
.pos
,curpos
);
570 if(!ntfs_entry_is_used(entry
))
575 if(ntfs_entry_is_used(entry
))
577 retval
=ntfs_copyresult(walk
->result
,entry
);
580 walk
->u
.pos
=ntfs_top();
585 if(!ntfs_entry_is_used(entry
))break;
586 length
=NTFS_GETU16(entry
+8);
588 ntfs_error("infinite loop\n");
596 /* Iterate over a list of entries, either from an index block, or from
598 If searching BY_POSITION, pop the top index from the position. If the
599 position stack is empty then, return the item at the index and set the
600 position to the next entry. If the position stack is not empty,
601 recursively proceed for subnodes. If the entry at the position is the
602 'end of dir' entry, return 'not found' and the empty stack.
603 If searching BY_NAME, walk through the items until found or until
604 one item is collated after the requested item. In the former case, return
605 the result. In the latter case, recursively proceed to the subnodes.
606 If 'end of dir' is reached, the name is not in the directory */
607 static int ntfs_getdir_iterate(ntfs_iterate_s
*walk
, char *start
, char *entry
)
613 if(walk
->type
==BY_POSITION
)
614 return ntfs_getdir_iterate_byposition(walk
,start
,entry
);
616 /* if the current entry is a real one, compare with the
617 requested item. If the current entry is the last item,
618 it is always larger than the requested item */
619 cmp
= ntfs_entry_is_used(entry
) ? ntfs_my_strcmp(walk
,entry
) : -1;
624 case -1:return ntfs_entry_has_subnodes(entry
)?
625 ntfs_descend(walk
,start
,entry
):0;
626 case 0:return ntfs_copyresult(walk
->result
,entry
);
632 case -1:return ntfs_entry_has_subnodes(entry
)?
633 ntfs_descend(walk
,start
,entry
):
634 ntfs_dir_insert(walk
,start
,entry
);
635 case 0:return EEXIST
;
640 ntfs_error("TODO\n");
642 if(!ntfs_entry_is_used(entry
))break;
643 length
=NTFS_GETU16(entry
+8);
645 ntfs_error("infinite loop\n");
653 /* Tree walking is done using position numbers. The following numbers have
658 All other numbers encode sequences of indices. The sequence a,b,c is
659 encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The
660 first few integers are encoded as follows:
661 0: 0000 1: 0010 2: 0100 3: 0110
662 4: 1000 5: 1010 6: 1100 stop: 1110
663 7: 000001 8: 000101 9: 001001 10: 001101
664 The least significant bits give the width of this encoding, the
665 other bits encode the value, starting from the first value of the
667 tag width first value last value
672 More values are hopefully not needed, as the file position has currently
676 /* Find an entry in the directory. Return 0 if not found, otherwise copy
677 the entry to the result buffer. */
678 int ntfs_getdir(ntfs_iterate_s
* walk
)
680 int length
=walk
->dir
->vol
->mft_recordsize
;
682 /* start at the index root.*/
683 char *root
=ntfs_malloc(length
);
689 error
=ntfs_read_attr(walk
->dir
,walk
->dir
->vol
->at_index_root
,
693 ntfs_error("Not a directory\n");
697 /* FIXME: move these to walk */
698 walk
->dir
->u
.index
.recordsize
= NTFS_GETU32(root
+0x8);
699 walk
->dir
->u
.index
.clusters_per_record
= NTFS_GETU32(root
+0xC);
700 /* FIXME: consistency check */
702 retval
= ntfs_getdir_iterate(walk
,root
,root
+0x20);
707 /* Find an entry in the directory by its position stack. Iteration starts
708 if the stack is 0, in which case the position is set to the first item
709 in the directory. If the position is nonzero, return the item at the
710 position and change the position to the next item. The position is -1
711 if there are no more items */
712 int ntfs_getdir_byposition(ntfs_iterate_s
*walk
)
714 walk
->type
=BY_POSITION
;
715 return ntfs_getdir(walk
);
718 /* Find an entry in the directory by its name. Return 0 if not found */
719 int ntfs_getdir_byname(ntfs_iterate_s
*walk
)
722 return ntfs_getdir(walk
);
725 int ntfs_getdir_unsorted(ntfs_inode
*ino
,ntfs_u32
*p_high
,ntfs_u32
* p_low
,
726 int(*cb
)(ntfs_u8
*,void*),void *param
)
728 char *buf
=0,*entry
=0;
733 ntfs_attribute
*attr
;
734 ntfs_volume
*vol
=ino
->vol
;
739 ntfs_error("No inode passed to getdir_unsorted\n");
743 ntfs_error("Inode %d has no volume\n",ino
->i_number
);
746 ntfs_debug(DEBUG_DIR3
,"unsorted 1\n");
747 /* are we still in the index root */
749 buf
=ntfs_malloc(length
=vol
->mft_recordsize
);
753 error
=ntfs_read_attr(ino
,vol
->at_index_root
,I30
,0,&io
);
758 ino
->u
.index
.recordsize
= NTFS_GETU32(buf
+0x8);
759 ino
->u
.index
.clusters_per_record
= NTFS_GETU32(buf
+0xC);
761 ntfs_debug(DEBUG_DIR3
,"unsorted 2\n");
762 }else{ /* we are in an index record */
763 length
=ino
->u
.index
.recordsize
;
764 buf
=ntfs_malloc(length
);
768 /* 0 is index root, index allocation starts with 4 */
769 block
= *p_high
- ino
->u
.index
.clusters_per_record
;
770 error
=ntfs_read_attr(ino
,vol
->at_index_allocation
,I30
,
771 block
*vol
->clustersize
,&io
);
772 if(!error
&& io
.size
!=length
)error
=EIO
;
774 ntfs_error("read failed\n");
778 if(!ntfs_check_index_record(ino
,buf
)){
779 ntfs_error("%x is not an index record\n",block
);
783 entry
=buf
+NTFS_GETU16(buf
+0x18)+0x18;
784 ntfs_debug(DEBUG_DIR3
,"unsorted 3\n");
787 /* process the entries */
789 while(ntfs_entry_is_used(entry
)){
790 ntfs_debug(DEBUG_DIR3
,"unsorted 4\n");
792 start
--; /* skip entries that were already processed */
794 ntfs_debug(DEBUG_DIR3
,"unsorted 5\n");
795 if((error
=cb(entry
,param
)))
796 /* the entry could not be processed */
800 entry
+=NTFS_GETU16(entry
+8);
803 ntfs_debug(DEBUG_DIR3
,"unsorted 6\n");
804 /* caller did not process all entries */
807 ntfs_debug(DEBUG_DIR3
,"unsorted 7\n");
811 /* we have to locate the next record */
815 attr
=ntfs_find_attr(ino
,vol
->at_bitmap
,I30
);
817 /* directory does not have index allocation */
820 ntfs_debug(DEBUG_DIR3
,"unsorted 8\n");
823 buf
=ntfs_malloc(length
=attr
->size
);
826 error
=ntfs_read_attr(ino
,vol
->at_bitmap
,I30
,0,&io
);
827 if(!error
&& io
.size
!=length
)error
=EIO
;
830 ntfs_debug(DEBUG_DIR3
,"unsorted 9\n");
833 attr
=ntfs_find_attr(ino
,vol
->at_index_allocation
,I30
);
835 if(*p_high
*vol
->clustersize
> attr
->size
){
836 /* no more index records */
839 ntfs_debug(DEBUG_DIR3
,"unsorted 10\n");
842 *p_high
+=ino
->u
.index
.clusters_per_record
;
843 byte
=*p_high
/ino
->u
.index
.clusters_per_record
-1;
844 bit
= 1 << (byte
& 7);
846 /* this record is allocated */
850 ntfs_debug(DEBUG_DIR3
,"unsorted 11\n");
855 int ntfs_dir_add(ntfs_inode
*dir
, ntfs_inode
*new, ntfs_attribute
*name
)
859 ntfs_u8
* entry
,*ndata
;
862 walk
.type
=DIR_INSERT
;
866 ndata
= name
->d
.data
;
867 walk
.name
=(ntfs_u16
*)(ndata
+0x42);
868 walk
.namelen
=NTFS_GETU8(ndata
+0x40);
869 walk
.new_entry_size
= esize
= ((nsize
+0x18)/8)*8;
870 walk
.new_entry
=entry
=ntfs_malloc(esize
);
871 if(!entry
)return ENOMEM
;
872 ntfs_bzero(entry
,esize
);
873 NTFS_PUTINUM(entry
,new);
874 NTFS_PUTU16(entry
+0x8,esize
); /* size of entry */
875 NTFS_PUTU16(entry
+0xA,nsize
); /* size of original name attribute */
876 NTFS_PUTU32(entry
+0xC,0); /* FIXME: D-F? */
877 ntfs_memcpy(entry
+0x10,ndata
,nsize
);
878 error
=ntfs_getdir(&walk
);
880 ntfs_free(walk
.new_entry
);
885 int ntfs_dir_add1(ntfs_inode
*dir
,const char* name
,int namelen
,ntfs_inode
*ino
)
891 ntfs_attribute
*name_attr
;
892 error
=ntfs_decodeuni(dir
->vol
,name
,namelen
,&walk
.name
,&walk
.namelen
);
895 /* FIXME: set flags */
896 walk
.type
=DIR_INSERT
;
899 /* prepare new entry */
900 /* round up to a multiple of 8 */
901 walk
.new_entry_size
= nsize
= ((0x52+2*walk
.namelen
+7)/8)*8;
902 walk
.new_entry
=entry
=ntfs_malloc(nsize
);
905 ntfs_bzero(entry
,nsize
);
906 NTFS_PUTINUM(entry
,ino
);
907 NTFS_PUTU16(entry
+8,nsize
);
908 NTFS_PUTU16(entry
+0xA,0x42+2*namelen
); /*FIXME: size of name attr*/
909 NTFS_PUTU32(entry
+0xC,0); /*FIXME: D-F? */
910 name_attr
=ntfs_find_attr(ino
,vol
->at_file_name
,0); /* FIXME:multiple names */
911 if(!name_attr
|| !name_attr
->resident
)
913 /* directory, file stamps, sizes, filename */
914 ntfs_memcpy(entry
+0x10,name_attr
->d
.data
,0x42+2*namelen
);
915 error
=ntfs_getdir(&walk
);
916 ntfs_free(walk
.name
);
921 /* Fills out and creates an INDEX_ROOT attribute. */
924 add_index_root (ntfs_inode
*ino
, int type
)
927 ntfs_u8 data
[0x30]; /* 0x20 header, 0x10 last entry */
930 NTFS_PUTU32(data
, type
);
932 NTFS_PUTU32(data
+4, 1);
933 NTFS_PUTU32(data
+8, ino
->vol
->index_recordsize
);
934 NTFS_PUTU32(data
+0xC, ino
->vol
->index_clusters_per_record
);
936 NTFS_PUTU32(data
+0x10, 0x10);
937 /* Size of entries, including header. */
938 NTFS_PUTU32(data
+0x14, 0x20);
939 NTFS_PUTU32(data
+0x18, 0x20);
940 /* No index allocation, yet. */
941 NTFS_PUTU32(data
+0x1C, 0);
942 /* add last entry. */
943 /* indexed MFT record. */
944 NTFS_PUTU64(data
+0x20, 0);
946 NTFS_PUTU32(data
+0x28, 0x10);
947 /* flags: last entry, no child nodes. */
948 NTFS_PUTU32(data
+0x2C, 2);
950 ntfs_indexname(name
, type
);
951 return ntfs_create_attr(ino
, ino
->vol
->at_index_root
, name
,
952 data
, sizeof(data
), &da
);
956 ntfs_mkdir(ntfs_inode
* dir
,const char* name
,int namelen
, ntfs_inode
*result
)
959 error
= ntfs_alloc_inode(dir
, result
, name
, namelen
, NTFS_AFLAG_DIR
);
962 error
= add_index_root(result
, 0x30);
965 /* Set directory bit */
966 result
->attr
[0x16] |= 2;
967 error
= ntfs_update_inode (dir
);
970 error
= ntfs_update_inode (result
);
979 * c-file-style: "linux"