diff options
Diffstat (limited to 'fs/umsdos/emd.c')
-rw-r--r-- | fs/umsdos/emd.c | 390 |
1 files changed, 323 insertions, 67 deletions
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 86002ddeb..169a75a45 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -17,36 +17,153 @@ #include <asm/uaccess.h> +#include <asm/delay.h> + #define PRINTK(x) #define Printk(x) printk x /* - Read a file into kernel space memory -*/ -long umsdos_file_read_kmem (struct inode *inode, - struct file *filp, - char *buf, - unsigned long count) + * makes dentry. for name name with length len. /mn/ + * if inode is not NULL, puts it also. + * + */ + +struct dentry *creat_dentry (const char *name, const int len, struct inode *inode) { - int ret; - mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = fat_file_read(inode,filp,buf,count); - set_fs (old_fs); - return ret; + struct dentry *ret, *parent=NULL; /* FIXME /mn/: whatis parent ?? */ + struct qstr qname; + + if (inode) + Printk (("/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); + else + Printk (("/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); + + qname.name = name; + qname.len = len; + qname.hash = 0; + + ret = d_alloc (parent,&qname); /* create new dentry */ + ret->d_inode = inode; + return ret; +} + + + +/* + * Read a file into kernel space memory + * returns how many bytes read (from fat_file_read) + */ + +ssize_t umsdos_file_read_kmem (struct inode *emd_dir, + struct file *filp, + char *buf, + size_t count, + loff_t *offs + ) +{ + int ret; + + struct dentry *old_dentry; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + + old_dentry=filp->f_dentry; /* save it */ + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + *offs = filp->f_pos; + + PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + PRINTK ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino)); + PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + PRINTK ((KERN_DEBUG " ofs=%ld\n",(unsigned long) *offs)); + PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos)); + PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + PRINTK ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid)); + PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); + PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + ret = fat_file_read(filp,buf,count,offs); + PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret)); + + filp->f_pos = *offs; /* we needed *filp only for this? grrrr... /mn/ */ + /* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced. + this probably needs fixing /mn/ */ + + filp->f_dentry=old_dentry; /* restore orig. dentry (it is dentry of file we need info about. Dunno why it gets passed to us + since we have no use for it, expect to store totally unrelated data of offset of EMD_FILE + end not directory in it. But what the hell now... fat_file_read requires it also, but prolly expects + it to be file* of EMD not file we want to read EMD entry about... ugh. complicated to explain :) /mn/ */ + + /* FIXME: we probably need to destroy originl filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */ + /* Also FIXME: all the same problems in umsdos_file_write_kmem */ + + PRINTK ((KERN_DEBUG " (ret) using emd=%lu\n", emd_dir->i_ino)); + PRINTK ((KERN_DEBUG " (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + PRINTK ((KERN_DEBUG " (ret) ofs=%Lu\n", *offs)); + PRINTK ((KERN_DEBUG " (ret) f_pos=%Lu\n", filp->f_pos)); + PRINTK ((KERN_DEBUG " (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + PRINTK ((KERN_DEBUG " (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + PRINTK ((KERN_DEBUG " (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + PRINTK ((KERN_DEBUG " (ret) f_owner=%d\n", filp->f_owner.uid)); + PRINTK ((KERN_DEBUG " (ret) f_version=%ld\n", filp->f_version)); + PRINTK ((KERN_DEBUG " (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + +#if 0 + { + struct umsdos_dirent *mydirent=buf; + + PRINTK ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); + PRINTK ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); + PRINTK ((KERN_DEBUG " (DDD) name=>%.20s<\n",mydirent->name)); + } +#endif + + set_fs (old_fs); + return ret; } + + /* Write to a file from kernel space */ -long umsdos_file_write_kmem (struct inode *inode, - struct file *filp, - const char *buf, - unsigned long count) +ssize_t umsdos_file_write_kmem (struct inode *emd_dir, + struct file *filp, + const char *buf, + size_t count, + loff_t *offs + ) { int ret; mm_segment_t old_fs = get_fs(); + struct dentry *old_dentry; + + Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + + Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs)); + Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos)); + Printk ((KERN_ERR " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + Printk ((KERN_ERR " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + Printk ((KERN_ERR " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid)); + Printk ((KERN_ERR " f_version=%ld\n", filp->f_version)); + Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + set_fs (KERNEL_DS); - ret = fat_file_write(inode,filp,buf,count); + old_dentry=filp->f_dentry; /* save it */ + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + *offs = filp->f_pos; + + ret = fat_file_write (filp, buf, count, offs); + PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + + filp->f_pos = *offs; + filp->f_dentry=old_dentry; + set_fs (old_fs); return ret; } @@ -58,12 +175,16 @@ long umsdos_file_write_kmem (struct inode *inode, Return 0 if ok, a negative error code if not. */ -long umsdos_emd_dir_write (struct inode *emd_dir, - struct file *filp, - char *buf, /* buffer in kernel memory, not in user space */ - unsigned long count) +ssize_t umsdos_emd_dir_write (struct inode *emd_dir, + struct file *filp, + char *buf, /* buffer in kernel memory, not in user space */ + size_t count, + loff_t *offs + ) { int written; + loff_t myofs=0; + #ifdef __BIG_ENDIAN struct umsdos_dirent *d = (struct umsdos_dirent *)buf; #endif @@ -78,7 +199,13 @@ long umsdos_emd_dir_write (struct inode *emd_dir, d->rdev = cpu_to_le16 (d->rdev); d->mode = cpu_to_le16 (d->mode); #endif - written = umsdos_file_write_kmem (emd_dir,filp,buf,count); + + if (offs) myofs=*offs; /* if offs is not NULL, read it */ + Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %ld, %Ld\n", emd_dir, filp, buf, count, myofs)); + written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs); + Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n")); + if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ + #ifdef __BIG_ENDIAN d->nlink = le16_to_cpu (d->nlink); d->uid = le16_to_cpu (d->uid); @@ -91,25 +218,36 @@ long umsdos_emd_dir_write (struct inode *emd_dir, #endif return written != count ? -EIO : 0; } + + + /* - Read a block of bytes from one EMD file. - The block of data is NOT in user space. - Return 0 if ok, -EIO if any error. -*/ -long umsdos_emd_dir_read (struct inode *emd_dir, + * Read a block of bytes from one EMD file. + * The block of data is NOT in user space. + * Return 0 if ok, -EIO if any error. + */ + +ssize_t umsdos_emd_dir_read (struct inode *emd_dir, struct file *filp, char *buf, /* buffer in kernel memory, not in user space */ - unsigned long count) + size_t count, + loff_t *offs + ) { + loff_t myofs=0; long int ret = 0; int sizeread; + + #ifdef __BIG_ENDIAN struct umsdos_dirent *d = (struct umsdos_dirent *)buf; #endif + + if (offs) myofs=*offs; /* if offs is not NULL, read it */ filp->f_flags = 0; - sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count); + sizeread = umsdos_file_read_kmem (emd_dir, filp, buf, count, &myofs); if (sizeread != count){ - printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %ld)\n" + printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n" ,filp->f_pos,sizeread,count); ret = -EIO; } @@ -123,49 +261,107 @@ long umsdos_emd_dir_read (struct inode *emd_dir, d->rdev = le16_to_cpu (d->rdev); d->mode = le16_to_cpu (d->mode); #endif + if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ return ret; } + + + + +/* + Locate the EMD file in a directory . + + Return NULL if error. If ok, dir->u.umsdos_i.emd_inode +*/ +struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat) +{ + struct inode *ret = NULL; + int res; + PRINTK ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n")); + if (dir->u.umsdos_i.i_emd_dir != 0){ + ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); + Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n" + ,dir->u.umsdos_i.i_emd_dir,ret)); + } else { + PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE)); + res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret); + PRINTK ((KERN_DEBUG "-returned %d\n", res)); + Printk ((KERN_INFO "emd_dir_lookup ")); + if (ret != NULL){ + Printk (("Found --linux ")); + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + } else if (creat) { + int code; + Printk ((" * ERROR * /mn/: creat not yet implemented!!!!" )); + Printk ((KERN_DEBUG "avant create ")); + dir->i_count++; + + code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN + ,S_IFREG|0777,&ret); + Printk ((KERN_WARNING "Creat EMD code %d ret %p ", code, ret)); + if (ret != NULL){ + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + }else{ + printk (KERN_WARNING "UMSDOS: Can't create EMD file\n"); + } + } + + if (ret != NULL){ + /* Disable UMSDOS_notify_change() for EMD file */ + ret->u.umsdos_i.i_emd_owner = 0xffffffff; + } + + } + +#if 0 + PRINTK ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); + if (ret != NULL) PRINTK ((KERN_DEBUG " debug : returning ino=%lu\n", ret->i_ino)); +#endif + return ret; +} + /* - Locate the EMD file in a directory and optionally, creates it. + creates an EMD file Return NULL if error. If ok, dir->u.umsdos_i.emd_inode */ -struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat) + +struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int mode) { struct inode *ret = NULL; if (dir->u.umsdos_i.i_emd_dir != 0){ ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); - PRINTK (("deja trouve %d %x [%d] " - ,dir->u.umsdos_i.i_emd_dir,ret, - atomic_read(&ret->i_count))); + Printk (("deja trouve %lu %p", dir->u.umsdos_i.i_emd_dir, ret)); }else{ - umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret); - PRINTK (("emd_dir_lookup ")); - if (ret != NULL){ - PRINTK (("Find --linux ")); - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - }else if (creat){ - int code; - PRINTK (("avant create ")); - atomic_inc(&dir->i_count); - code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN - ,S_IFREG|0777,&ret); - PRINTK (("Creat EMD code %d ret %x ",code,ret)); - if (ret != NULL){ - dir->u.umsdos_i.i_emd_dir = ret->i_ino; - }else{ - printk ("UMSDOS: Can't create EMD file\n"); - } - } + + int code; + Printk (("avant create ")); + dir->i_count++; + /* + code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN + ,S_IFREG|0777,&ret); + + FIXME, I think I need a new dentry here + */ + code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN, S_IFREG|0777, &ret); + Printk (("Creat EMD code %d ret %p ", code, ret)); + if (ret != NULL){ + dir->u.umsdos_i.i_emd_dir = ret->i_ino; + }else{ + printk ("UMSDOS: Can't create EMD file\n"); + } } + if (ret != NULL){ - /* Disable UMSDOS_notify_change() for EMD file */ - ret->u.umsdos_i.i_emd_owner = 0xffffffff; + /* Disable UMSDOS_notify_change() for EMD file */ + ret->u.umsdos_i.i_emd_owner = 0xffffffff; } return ret; } + + /* Read an entry from the EMD file. Support variable length record. @@ -176,18 +372,28 @@ int umsdos_emd_dir_readentry ( struct file *filp, struct umsdos_dirent *entry) { - int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE); - if (ret == 0){ + int ret; + Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n")); + Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %.*s (ino=%lu) using EMD %lu\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino)); + + ret = umsdos_emd_dir_read(emd_dir, filp, (char*)entry, UMSDOS_REC_SIZE, NULL); + if (ret == 0){ /* note /mn/: is this wrong? ret is allways 0 or -EIO. but who knows. It used to work this way... */ /* Variable size record. Maybe, we have to read some more */ int recsize = umsdos_evalrecsize (entry->name_len); + Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: FIXME if %d > %d?\n",recsize, UMSDOS_REC_SIZE)); if (recsize > UMSDOS_REC_SIZE){ - ret = umsdos_emd_dir_read(emd_dir,filp - ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE); + ret = umsdos_emd_dir_read(emd_dir, filp + ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE,NULL); } } + Printk (("umsdos_emd_dir_readentry /mn/: returning %d.\n", ret)); return ret; } + + + + /* Write an entry in the EMD file. Return 0 if ok, -EIO if some error. @@ -199,9 +405,14 @@ int umsdos_writeentry ( int free_entry) /* This entry is deleted, so Write all 0's */ { int ret = 0; + struct dentry *emd_dentry; struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; + + Printk (("umsdos_writeentry /mn/: entering...\n")); + emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir); + if (free_entry){ /* #Specification: EMD file / empty entries Unused entry in the EMD file are identify @@ -222,18 +433,31 @@ int umsdos_writeentry ( */ memset (entry->spare,0,sizeof(entry->spare)); } + + Printk (("umsdos_writeentry /mn/: if passed...\n")); + + if (!info) printk (KERN_ERR "umsdosfs: /mn/ info is empty ! ooops...\n"); filp.f_pos = info->f_pos; filp.f_reada = 0; - ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize); + filp.f_flags = O_RDWR; + filp.f_dentry = emd_dentry; + filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + + ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL); + Printk (("emd_dir_write returned !\n")); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; + /* dir->i_dirt = 1; FIXME iput/dput ??? */ } + + Printk (("umsdos_writeentry /mn/: returning...\n")); return ret; } + + #define CHUNK_SIZE (8*UMSDOS_REC_SIZE) struct find_buffer{ char buffer[CHUNK_SIZE]; @@ -242,6 +466,10 @@ struct find_buffer{ struct file filp; }; + + + + /* Fill the read buffer and take care of the byte remaining inside. Unread bytes are simply move to the beginning. @@ -256,6 +484,9 @@ static int umsdos_fillbuf ( int mustmove = buf->size - buf->pos; int mustread; int remain; + + PRINTK ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %lu, buf=%p\n", inode->i_ino, buf)); + if (mustmove > 0){ memcpy (buf->buffer,buf->buffer+buf->pos,mustmove); } @@ -264,8 +495,8 @@ static int umsdos_fillbuf ( remain = inode->i_size - buf->filp.f_pos; if (remain < mustread) mustread = remain; if (mustread > 0){ - ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove - ,mustread); + ret = umsdos_emd_dir_read (inode, &buf->filp,buf->buffer+mustmove + ,mustread,NULL); if (ret == 0) buf->size = mustmove + mustread; }else if (mustmove){ buf->size = mustmove; @@ -274,6 +505,8 @@ static int umsdos_fillbuf ( return ret; } + + /* General search, locate a name in the EMD file or an empty slot to store it. if info->entry.name_len == 0, search the first empty @@ -308,7 +541,8 @@ static int umsdos_find ( record, multiple contiguous record are allocated. */ int ret = -ENOENT; - struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1); + /* FIXME -- /mn/ fixed ? */ + struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1); if (emd_dir != NULL){ struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; @@ -320,10 +554,21 @@ static int umsdos_find ( }empty; /* Read several entries at a time to speed up the search */ struct find_buffer buf; - buf.pos = 0; - buf.size = 0; + struct dentry *dentry; + + memset (&buf.filp, 0, sizeof (buf.filp)); + + dentry = creat_dentry ("umsfind-mn", 10, emd_dir); + buf.filp.f_pos = 0; buf.filp.f_reada = 1; + buf.filp.f_flags = O_RDONLY; + buf.filp.f_dentry = dentry; + buf.filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + + buf.pos = 0; + buf.size = 0; + empty.found = 0; empty.posok = emd_dir->i_size; empty.onesize = 0; @@ -388,6 +633,7 @@ static int umsdos_find ( *pt_emd_dir = emd_dir; return ret; } + /* Add a new entry in the emd file Return 0 if ok or a negative error code. @@ -405,11 +651,12 @@ int umsdos_newentry ( ret = -EEXIST; }else if (ret == -ENOENT){ ret = umsdos_writeentry(dir,emd_dir,info,0); - PRINTK (("umsdos_newentry EDM ret = %d\n",ret)); + Printk (("umsdos_newentry EDM ret = %d\n",ret)); } iput (emd_dir); return ret; } + /* Create a new hidden link. Return 0 if ok, an error code if not. @@ -475,15 +722,24 @@ int umsdos_delentry ( */ int umsdos_isempty (struct inode *dir) { + struct dentry *dentry; + int ret = 2; struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0); /* If the EMD file does not exist, it is certainly empty :-) */ if (emd_dir != NULL){ struct file filp; /* Find an empty slot */ + memset (&filp, 0, sizeof (filp)); + + dentry = creat_dentry ("isempty-mn", 10, dir); + filp.f_pos = 0; filp.f_reada = 1; filp.f_flags = O_RDONLY; + filp.f_dentry = dentry; + filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + ret = 1; while (filp.f_pos < emd_dir->i_size){ struct umsdos_dirent entry; |