patch-2.2.0-pre4 linux/fs/ntfs/dir.c
Next file: linux/fs/ntfs/dir.h
Previous file: linux/fs/ntfs/attr.h
Back to the patch index
Back to the overall index
- Lines: 485
- Date:
Sat Jan 2 10:24:46 1999
- Orig file:
v2.2.0-pre3/linux/fs/ntfs/dir.c
- Orig date:
Fri Oct 23 22:01:22 1998
diff -u --recursive --new-file v2.2.0-pre3/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c
@@ -4,9 +4,10 @@
* Copyright (C) 1995-1997 Martin von Löwis
*/
-#include "types.h"
+#include "ntfstypes.h"
#include "struct.h"
#include "dir.h"
+#include "macros.h"
#include <linux/errno.h>
#include "super.h"
@@ -26,27 +27,27 @@
ino->u.index.recordsize);
}
-static inline int ntfs_is_top(long long stack)
+static inline int ntfs_is_top(ntfs_u64 stack)
{
return stack==14;
}
-static long long ntfs_pop(long long *stack)
+static int ntfs_pop(ntfs_u64 *stack)
{
static int width[16]={1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
int res=-1;
switch(width[*stack & 15])
{
- case 1:res=(*stack&15)>>1;
+ case 1:res=(int)((*stack&15)>>1);
*stack>>=4;
break;
- case 2:res=((*stack&63)>>2)+7;
+ case 2:res=(int)(((*stack&63)>>2)+7);
*stack>>=6;
break;
- case 3:res=((*stack & 255)>>3)+23;
+ case 3:res=(int)(((*stack & 255)>>3)+23);
*stack>>=8;
break;
- case 4:res=((*stack & 1023)>>4)+55;
+ case 4:res=(int)(((*stack & 1023)>>4)+55);
*stack>>=10;
break;
default:ntfs_error("Unknown encoding\n");
@@ -59,18 +60,18 @@
return 14;
}
-static long long ntfs_push(long long stack,int i)
+static ntfs_u64 ntfs_push(ntfs_u64 stack,int i)
{
if(i<7)return (stack<<4)|(i<<1);
if(i<23)return (stack<<6)|((i-7)<<2)|1;
if(i<55)return (stack<<8)|((i-23)<<3)|3;
if(i<120)return (stack<<10)|((i-55)<<4)|7;
ntfs_error("Too many entries\n");
- return -1;
+ return 0xFFFFFFFFFFFFFFFF;
}
#if 0
-static void ntfs_display_stack(long long stack)
+static void ntfs_display_stack(ntfs_u64 stack)
{
while(!ntfs_is_top(stack))
{
@@ -162,35 +163,30 @@
if(walk->newblock * vol->clustersize >= size){
/* build index record */
int s1=walk->dir->u.index.recordsize;
+ int nr_fix = s1/vol->blocksize+1;
+ int hsize;
char *record=ntfs_malloc(s1);
- int newlen;
ntfs_bzero(record,s1);
/* magic */
ntfs_memcpy(record,"INDX",4);
/* offset to fixups */
NTFS_PUTU16(record+4,0x28);
/* number of fixups */
- NTFS_PUTU16(record+6,s1/vol->blocksize+1);
+ NTFS_PUTU16(record+6,nr_fix);
/* FIXME: log file number */
/* VCN of buffer */
NTFS_PUTU64(record+0x10,walk->newblock);
- /* header size. FIXME */
- NTFS_PUTU16(record+0x18,28);
+ /* header size. */
+ hsize = 0x10+2*nr_fix;
+ hsize = (hsize+7) & ~7; /* Align. */
+ NTFS_PUTU16(record+0x18, hsize);
/* total size of record */
NTFS_PUTU32(record+0x20,s1-0x18);
+ /* Writing the data will extend the attribute. */
io.param=record;
- newlen=walk->dir->u.index.recordsize;
- /* allocate contiguous index record */
- error=ntfs_extend_attr(walk->dir,allocation,&newlen,
- ALLOC_REQUIRE_SIZE);
- if(error){
- /* FIXME: try smaller allocations */
- ntfs_free(record);
- return ENOSPC;
- }
io.size=s1;
- error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30,
- size,&io);
+ io.do_read=0;
+ error=ntfs_readwrite_attr(walk->dir, allocation, size, &io);
if(error || io.size!=s1){
ntfs_free(record);
return error?error:EIO;
@@ -201,29 +197,38 @@
return 0;
}
+/* Write an index block (root or allocation) back to storage.
+ used is the total number of bytes in buf, including all headers. */
+
static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block,
- int used)
+ int used)
{
ntfs_io io;
int error;
+ ntfs_attribute *a;
+ ntfs_volume *vol = walk->dir->vol;
+
io.fn_put=0;
io.fn_get=ntfs_get;
io.param=buf;
- if(walk->block==-1){
+ if(block==-1){
NTFS_PUTU16(buf+0x14,used-0x10);
/* 0x18 is a copy thereof */
NTFS_PUTU16(buf+0x18,used-0x10);
io.size=used;
- error=ntfs_write_attr(walk->dir,walk->dir->vol->at_index_root,
+ error=ntfs_write_attr(walk->dir,vol->at_index_root,
I30,0,&io);
if(error)return error;
if(io.size!=used)return EIO;
+ /* shrink if necessary */
+ a = ntfs_find_attr(walk->dir, vol->at_index_root, I30);
+ ntfs_resize_attr(walk->dir, a, used);
}else{
- NTFS_PUTU16(buf+0x1C,used-0x20);
- ntfs_insert_fixups(buf,walk->dir->vol->blocksize);
+ NTFS_PUTU16(buf+0x1C,used-0x18);
+ ntfs_insert_fixups(buf,vol->blocksize);
io.size=walk->dir->u.index.recordsize;
- error=ntfs_write_attr(walk->dir,walk->dir->vol->at_index_allocation,I30,
- walk->block*walk->dir->vol->clustersize,
+ error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30,
+ block*vol->clustersize,
&io);
if(error)return error;
if(io.size!=walk->dir->u.index.recordsize)
@@ -240,13 +245,20 @@
int error,othersize,mlen;
ntfs_io io;
ntfs_volume *vol=walk->dir->vol;
+ int oldblock;
+
error=ntfs_allocate_index_block(walk);
if(error)
return error;
- for(entry=prev=start+NTFS_GETU16(start+0x18)+0x18;
- entry-start<usize/2;
- entry+=NTFS_GETU16(entry+8))
+ /* This should not happen */
+ if(walk->block == -1){
+ ntfs_error("Trying to split root");
+ return EOPNOTSUPP;
+ }
+ entry = start+NTFS_GETU16(start+0x18)+0x18;
+ for(prev=entry; entry-start<usize/2; entry += NTFS_GETU16(entry+8))
prev=entry;
+
newbuf=ntfs_malloc(vol->index_recordsize);
if(!newbuf)
return ENOMEM;
@@ -266,11 +278,19 @@
/* copy everything from entry to new block */
othersize=usize-(entry-start);
ntfs_memcpy(newbuf+NTFS_GETU16(newbuf+0x18)+0x18,entry,othersize);
- error=ntfs_index_writeback(walk,newbuf,walk->newblock,othersize);
+ /* Copy flags. */
+ NTFS_PUTU32(newbuf+0x24, NTFS_GETU32(start+0x24));
+ error=ntfs_index_writeback(walk,newbuf,walk->newblock,
+ othersize+NTFS_GETU16(newbuf+0x18)+0x18);
if(error)goto out;
/* move prev to walk */
mlen=NTFS_GETU16(prev+0x8);
+ /* Remember old child node. */
+ if(ntfs_entry_has_subnodes(prev))
+ oldblock = NTFS_GETU32(prev+mlen-8);
+ else
+ oldblock = -1;
/* allow for pointer to subnode */
middle=ntfs_malloc(ntfs_entry_has_subnodes(prev)?mlen:mlen+8);
if(!middle){
@@ -286,8 +306,21 @@
ntfs_error("entry not reset");
walk->new_entry=middle;
walk->u.flags|=ITERATE_SPLIT_DONE;
+ /* Terminate old block. */
+ othersize = usize-(prev-start);
+ NTFS_PUTU64(prev, 0);
+ if(oldblock==-1){
+ NTFS_PUTU32(prev+8, 0x10);
+ NTFS_PUTU32(prev+0xC, 2);
+ othersize += 0x10;
+ }else{
+ NTFS_PUTU32(prev+8, 0x18);
+ NTFS_PUTU32(prev+0xC, 3);
+ NTFS_PUTU64(prev+0x10, oldblock);
+ othersize += 0x18;
+ }
/* write back original block */
- error=ntfs_index_writeback(walk,start,walk->block,usize-(prev-start));
+ error=ntfs_index_writeback(walk,start,walk->block,othersize);
out:
if(newbuf)ntfs_free(newbuf);
if(middle)ntfs_free(middle);
@@ -300,12 +333,11 @@
int do_split=0;
offset=entry-start;
if(walk->block==-1){ /*index root */
- /* FIXME: adjust to maximum allowed index root value */
blocksize=walk->dir->vol->mft_recordsize;
usedsize=NTFS_GETU16(start+0x14)+0x10;
}else{
blocksize=walk->dir->u.index.recordsize;
- usedsize=NTFS_GETU16(start+0x1C)+0x20;
+ usedsize=NTFS_GETU16(start+0x1C)+0x18;
}
if(usedsize+walk->new_entry_size > blocksize){
char* s1=ntfs_malloc(blocksize+walk->new_entry_size);
@@ -321,7 +353,6 @@
usedsize+=walk->new_entry_size;
ntfs_free(walk->new_entry);
walk->new_entry=0;
- /*FIXME: split root */
if(do_split){
error=ntfs_split_record(walk,start,blocksize,usedsize);
ntfs_free(start);
@@ -330,6 +361,81 @@
return 0;
}
+/* Try to split INDEX_ROOT attributes. Return E2BIG if nothing changed. */
+
+int
+ntfs_split_indexroot(ntfs_inode *ino)
+{
+ ntfs_attribute *ra;
+ ntfs_u8 *root=0, *index=0;
+ ntfs_io io;
+ int error, off, i, bsize, isize;
+ ntfs_iterate_s walk;
+
+ ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
+ if(!ra)
+ return E2BIG;
+ bsize = ino->vol->mft_recordsize;
+ root = ntfs_malloc(bsize);
+ if(!root)
+ return E2BIG;
+ io.fn_put = ntfs_put;
+ io.param = root;
+ io.size = bsize;
+ error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io);
+ if(error)
+ goto out;
+ off = 0x20;
+ /* Count number of entries. */
+ for(i = 0; ntfs_entry_is_used(root+off); i++)
+ off += NTFS_GETU16(root+off+8);
+ if(i<=2){
+ /* We don't split small index roots. */
+ error = E2BIG;
+ goto out;
+ }
+ index = ntfs_malloc(ino->vol->index_recordsize);
+ if(!index)
+ goto out;
+ walk.dir = ino;
+ walk.block = -1;
+ walk.result = walk.new_entry = 0;
+ walk.name = 0;
+ error = ntfs_allocate_index_block(&walk);
+ if(error)
+ goto out;
+
+ /* Write old root to new index block. */
+ io.param = index;
+ io.size = ino->vol->index_recordsize;
+ error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30,
+ walk.newblock*ino->vol->clustersize, &io);
+ if(error)
+ goto out;
+ isize = NTFS_GETU16(root+0x18) - 0x10;
+ ntfs_memcpy(index+NTFS_GETU16(index+0x18)+0x18, root+0x20, isize);
+ /* Copy flags. */
+ NTFS_PUTU32(index+0x24, NTFS_GETU32(root+0x1C));
+
+ error = ntfs_index_writeback(&walk, index, walk.newblock,
+ isize+NTFS_GETU16(index+0x18)+0x18);
+ if(error)
+ goto out;
+
+ /* Mark root as split. */
+ NTFS_PUTU32(root+0x1C, 1);
+ /* Truncate index root. */
+ NTFS_PUTU64(root+0x20, 0);
+ NTFS_PUTU32(root+0x28, 0x18);
+ NTFS_PUTU32(root+0x2C, 3);
+ NTFS_PUTU64(root+0x30, walk.newblock);
+ error = ntfs_index_writeback(&walk,root,-1,0x38);
+ out:
+ ntfs_free(root);
+ ntfs_free(index);
+ return error;
+}
+
/* The entry has been found. Copy the result in the caller's buffer */
static int ntfs_copyresult(char *dest,char *source)
{
@@ -419,9 +525,9 @@
error=ntfs_getdir_record(walk,nextblock);
if(!error && walk->type==DIR_INSERT &&
(walk->u.flags & ITERATE_SPLIT_DONE)){
- /* split has occurred. adjust entry, insert new_entry */
+ /* Split has occurred. Adjust entry, insert new_entry. */
NTFS_PUTU32(entry+length-8,walk->newblock);
- /* reset flags, as the current block might be split again */
+ /* Reset flags, as the current block might be split again. */
walk->u.flags &= ~ITERATE_SPLIT_DONE;
error=ntfs_dir_insert(walk,start,entry);
}
@@ -637,6 +743,7 @@
ntfs_error("Inode %d has no volume\n",ino->i_number);
return EINVAL;
}
+ ntfs_debug(DEBUG_DIR3,"unsorted 1\n");
/* are we still in the index root */
if(*p_high==0){
buf=ntfs_malloc(length=vol->mft_recordsize);
@@ -651,6 +758,7 @@
ino->u.index.recordsize = NTFS_GETU32(buf+0x8);
ino->u.index.clusters_per_record = NTFS_GETU32(buf+0xC);
entry=buf+0x20;
+ ntfs_debug(DEBUG_DIR3,"unsorted 2\n");
}else{ /* we are in an index record */
length=ino->u.index.recordsize;
buf=ntfs_malloc(length);
@@ -673,14 +781,17 @@
return ENOTDIR;
}
entry=buf+NTFS_GETU16(buf+0x18)+0x18;
+ ntfs_debug(DEBUG_DIR3,"unsorted 3\n");
}
/* process the entries */
start=*p_low;
while(ntfs_entry_is_used(entry)){
+ ntfs_debug(DEBUG_DIR3,"unsorted 4\n");
if(start)
start--; /* skip entries that were already processed */
else{
+ ntfs_debug(DEBUG_DIR3,"unsorted 5\n");
if((error=cb(entry,param)))
/* the entry could not be processed */
break;
@@ -689,9 +800,11 @@
entry+=NTFS_GETU16(entry+8);
}
+ ntfs_debug(DEBUG_DIR3,"unsorted 6\n");
/* caller did not process all entries */
if(error){
ntfs_free(buf);
+ ntfs_debug(DEBUG_DIR3,"unsorted 7\n");
return error;
}
@@ -704,6 +817,7 @@
/* directory does not have index allocation */
*p_high=0xFFFFFFFF;
*p_low=0;
+ ntfs_debug(DEBUG_DIR3,"unsorted 8\n");
return 0;
}
buf=ntfs_malloc(length=attr->size);
@@ -713,6 +827,7 @@
if(!error && io.size!=length)error=EIO;
if(error){
ntfs_free(buf);
+ ntfs_debug(DEBUG_DIR3,"unsorted 9\n");
return EIO;
}
attr=ntfs_find_attr(ino,vol->at_index_allocation,I30);
@@ -721,6 +836,7 @@
/* no more index records */
*p_high=0xFFFFFFFF;
ntfs_free(buf);
+ ntfs_debug(DEBUG_DIR3,"unsorted 10\n");
return 0;
}
*p_high+=ino->u.index.clusters_per_record;
@@ -731,6 +847,7 @@
if(buf[byte] & bit)
break;
}
+ ntfs_debug(DEBUG_DIR3,"unsorted 11\n");
ntfs_free(buf);
return 0;
}
@@ -800,6 +917,62 @@
return error;
}
#endif
+
+/* Fills out and creates an INDEX_ROOT attribute. */
+
+static int
+add_index_root (ntfs_inode *ino, int type)
+{
+ ntfs_attribute *da;
+ ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry */
+ char name[10];
+
+ NTFS_PUTU32(data, type);
+ /* ??? */
+ NTFS_PUTU32(data+4, 1);
+ NTFS_PUTU32(data+8, ino->vol->index_recordsize);
+ NTFS_PUTU32(data+0xC, ino->vol->index_clusters_per_record);
+ /* ??? */
+ NTFS_PUTU32(data+0x10, 0x10);
+ /* Size of entries, including header. */
+ NTFS_PUTU32(data+0x14, 0x20);
+ NTFS_PUTU32(data+0x18, 0x20);
+ /* No index allocation, yet. */
+ NTFS_PUTU32(data+0x1C, 0);
+ /* add last entry. */
+ /* indexed MFT record. */
+ NTFS_PUTU64(data+0x20, 0);
+ /* size of entry */
+ NTFS_PUTU32(data+0x28, 0x10);
+ /* flags: last entry, no child nodes. */
+ NTFS_PUTU32(data+0x2C, 2);
+ /* compute name */
+ ntfs_indexname(name, type);
+ return ntfs_create_attr(ino, ino->vol->at_index_root, name,
+ data, sizeof(data), &da);
+}
+
+int
+ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *result)
+{
+ int error;
+ error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
+ if(error)
+ goto out;
+ error = add_index_root(result, 0x30);
+ if (error)
+ goto out;
+ /* Set directory bit */
+ result->attr[0x16] |= 2;
+ error = ntfs_update_inode (dir);
+ if (error)
+ goto out;
+ error = ntfs_update_inode (result);
+ if (error)
+ goto out;
+ out:
+ return error;
+}
/*
* Local variables:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov