diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /fs/umsdos | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'fs/umsdos')
-rw-r--r-- | fs/umsdos/README-WIP.txt | 31 | ||||
-rw-r--r-- | fs/umsdos/check.c | 31 | ||||
-rw-r--r-- | fs/umsdos/dir.c | 1734 | ||||
-rw-r--r-- | fs/umsdos/emd.c | 964 | ||||
-rw-r--r-- | fs/umsdos/file.c | 136 | ||||
-rw-r--r-- | fs/umsdos/inode.c | 1247 | ||||
-rw-r--r-- | fs/umsdos/ioctl.c | 628 | ||||
-rw-r--r-- | fs/umsdos/mangle.c | 899 | ||||
-rw-r--r-- | fs/umsdos/namei.c | 2156 | ||||
-rw-r--r-- | fs/umsdos/rdir.c | 488 | ||||
-rw-r--r-- | fs/umsdos/symlink.c | 143 |
11 files changed, 4412 insertions, 4045 deletions
diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt index 1357fdd69..05d3001c5 100644 --- a/fs/umsdos/README-WIP.txt +++ b/fs/umsdos/README-WIP.txt @@ -8,7 +8,7 @@ UMSDOS FILESYSTEM, AND MAYBE EVEN OTHER FILESYSTEMS IN USE. YOU'VE BEEN WARNED. --------- WARNING --------- WARNING --------- WARNING ----------- -Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-3: +Current status (980428) - UMSDOS dentry-WIP-Beta 0.82-4: (1) pure MSDOS (no --linux-.--- EMD file): @@ -32,14 +32,13 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver - long file names - works - read file - works - switching MSDOS/UMSDOS - works? -- switching UMSDOS/MSDOS - UNTESTED -- pseudo root things - COMMENTED OUT mostly currently. To be fixed when - dentries stuff is straightened out. +- switching UMSDOS/MSDOS - works? +- pseudo root things - COMPLETELY UNTESTED - resolve symlink - seems to work fully now! - dereference symlink - seems to work fully now! - hard links - seems to work now - special files (block/char device, fifos, sockets...) - seems to work ok. -- other ioctls - MOSTLY UNTESTED +- other ioctls - some UNTESTED - dangling symlink - UNTESTED ! - create symlink - seems to work both on short & long names now ! @@ -47,16 +46,16 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver - create file - seems to work both on short & long names now ! - create special file - seems to work both on short & long names now ! - write to file - seems to work both on short & long names now ! -- rename file (same dir) - WARNING: NOT FIXED YET! -- rename file (dif. dir) - WARNING: NOT FIXED YET! -- rename dir (same dir) - WARNING: NOT FIXED YET! -- rename dir (dif. dir) - WARNING: NOT FIXED YET! +- rename file (same dir) - seems to work, but with i_count PROBLEMS +- rename file (dif. dir) - seems to work, but with i_count PROBLEMS +- rename dir (same dir) - seems to work, but with i_count PROBLEMS +- rename dir (dif. dir) - seems to work, but with i_count PROBLEMS - delete file - seems to work fully now! - notify_change (chown,perms) - seems to work! - delete hardlink - WARNING: NOT FIXED YET! - mkdir - seems to work both on short & long names now ! -- rmdir - WARNING: NOT FIXED YET! -- umssyncing - seems to work, but NEEDS EXTENSIVE TESTING +- rmdir - may work, but readdir blocks linux afterwards. to be FIXED! +- umssyncing - seems to work, but NEEDS MORE TESTING - CVF-FAT stuff (compressed DOS filesystem) - there is some support from Frank Gockel <gockel@sent13.uni-duisburg.de> to use it even under @@ -130,6 +129,8 @@ some of my notes for myself /mn/: - what about .dotfiles ? working ? multiple dots ? etc.... - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular? +- chase down all "FIXME", "DELME", "CNT", check_dentry, check_inode, kill_dentry + and fix it properly. - umsdos_create_any - calling msdos_create will create dentry for shor name. Hmmmm..? - kill_dentry - put it where is needed. Also dput() at needed places. @@ -144,6 +145,14 @@ something ? - SECURITY WARNING: short dentries should be invalidated, or they could be accessed instead of proper long names. +- I've put many check_dentry() calls to trace down problems. those should be + removed in final version. + +- iput()s with "FIXME?" comment are uncomented and probably ok. Those with + "FIXME??" should be tested but prolly work. Commented iput()s with + any "FIXME" comments should probably be uncommented and tested. At some + places we may need dput() instead of iput(), but that should be checked. + - as for iput() : (my only pointer so far. anyone else ?) >development I only know about iput. All functions that get an inode as diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c index 67846925a..717a0df39 100644 --- a/fs/umsdos/check.c +++ b/fs/umsdos/check.c @@ -17,11 +17,11 @@ #include <asm/system.h> -static int check_one_table(struct pde * page_dir) +static int check_one_table (struct pde *page_dir) { - if (pgd_none(*page_dir)) + if (pgd_none (*page_dir)) return 0; - if (pgd_bad(*page_dir)) + if (pgd_bad (*page_dir)) return 1; return 0; } @@ -29,23 +29,28 @@ static int check_one_table(struct pde * page_dir) /* * This function checks all page tables of "current" */ -void check_page_tables(void) +void check_page_tables (void) { - struct pgd * pg_dir; + struct pgd *pg_dir; static int err = 0; - int stack_level = (long)(&pg_dir)-current->kernel_stack_page; - if (stack_level < 1500) printk ("** %d ** ",stack_level); - pg_dir = PAGE_DIR_OFFSET(current, 0); + int stack_level = (long) (&pg_dir) - current->kernel_stack_page; + + if (stack_level < 1500) + printk ("** %d ** ", stack_level); + pg_dir = PAGE_DIR_OFFSET (current, 0); if (err == 0) { int i; - for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){ - int notok = check_one_table(page_dir); - if (notok){ + + for (i = 0; i < PTRS_PER_PAGE; i++, page_dir++) { + int notok = check_one_table (page_dir); + + if (notok) { err++; - printk ("|%d:%08lx| ",i, page_dir->pgd); + printk ("|%d:%08lx| ", i, page_dir->pgd); } } - if (err) printk ("\nErreur MM %d\n",err); + if (err) + printk ("\nErreur MM %d\n", err); } } diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 288c77d45..3f49d0c2e 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -2,7 +2,7 @@ * linux/fs/umsdos/dir.c * * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... : Werner Almesberger + * Inspired from linux/fs/msdos/... : Werner Almesberger * * Extended MS-DOS directory handling functions */ @@ -27,48 +27,76 @@ extern struct inode *pseudo_root; /* P.T.Waltenberg - I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS - uses. It's easier to do once than hack all the other instances. Probably safer as well -*/ + * I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS + * uses. It's easier to do once than hack all the other instances. Probably safer as well + */ + +/* FIXME: it returns inode with i_count of 0. this should be redesigned to return dentry instead, + and correct dentry (with correct d_parent) */ -int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struct inode **inode) +int compat_umsdos_real_lookup (struct inode *dir, const char *name, int len, struct inode **inode) { - int rv; - struct dentry *dentry; + int rv; + struct dentry *dentry; + unsigned long ino; - dentry = creat_dentry (name, len, NULL, NULL); - rv = umsdos_real_lookup(dir,dentry); - if (inode) *inode = dentry->d_inode; - kill_dentry (dentry); - - return rv; -} + Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: start\n")); + check_inode (dir); + dentry = creat_dentry (name, len, NULL, NULL); + rv = umsdos_real_lookup (dir, dentry); + iput (dir); /* should be here, because umsdos_real_lookup does inc_count(dir) */ + if (rv) { + Printk ((KERN_WARNING "compat_umsdos_real_lookup failed with %d\n", rv)); + return rv; + } -int compat_msdos_create(struct inode *dir,const char *name,int len, int mode, struct inode **inode) + if (!inode) { + Printk ((KERN_ERR "inode should be set here. Arrgh! segfaulting...\n")); + } + + ino = dentry->d_inode->i_ino; + *inode = dentry->d_inode; + + dput (dentry); /* we are done with it: FIXME: does this work /mn/ ? */ + + check_dentry (dentry); + check_inode (dir); + + Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: end\n")); + + return rv; +} + + +int compat_msdos_create (struct inode *dir, const char *name, int len, int mode, struct inode **inode) { - int rv; - struct dentry *dentry; + int rv; + struct dentry *dentry; + + check_inode (dir); + dentry = creat_dentry (name, len, NULL, NULL); + check_dentry (dentry); + rv = msdos_create (dir, dentry, mode); + check_dentry (dentry); + if (inode != NULL) + *inode = dentry->d_inode; - dentry = creat_dentry (name, len, NULL, NULL); - rv = msdos_create(dir,dentry,mode); - if(inode != NULL) *inode = dentry->d_inode; - - return rv; -} + check_inode (dir); + return rv; +} /* - So grep * doesn't complain in the presence of directories. -*/ -int UMSDOS_dir_read(struct file *filp, - char *buff, - size_t size, - loff_t * count) + * So grep * doesn't complain in the presence of directories. + */ + +int UMSDOS_dir_read (struct file *filp, char *buff, size_t size, loff_t *count) { return -EISDIR; } + struct UMSDOS_DIR_ONCE { void *dirbuf; filldir_t filldir; @@ -77,873 +105,929 @@ struct UMSDOS_DIR_ONCE { }; /* - Record a single entry the first call. - Return -EINVAL the next one. - NOTE: filldir DOES NOT use a dentry -*/ -static int umsdos_dir_once( - void * buf, - const char *name, - int len, - off_t offset, - ino_t ino) + * Record a single entry the first call. + * Return -EINVAL the next one. + * NOTE: filldir DOES NOT use a dentry + */ + +static int umsdos_dir_once ( void *buf, + const char *name, + int len, + off_t offset, + ino_t ino) { - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; - if (d->count == 0){ - PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset)); - ret = d->filldir (d->dirbuf,name,len,offset,ino); - d->stop = ret < 0; - d->count = 1; - } - return ret; + int ret = -EINVAL; + struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; + + if (d->count == 0) { + PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset)); + ret = d->filldir (d->dirbuf, name, len, offset, ino); + d->stop = ret < 0; + d->count = 1; + } + return ret; } + /* - Read count directory entries from directory filp - Return a negative value from linux/errno.h. - Return > 0 if success (The amount of byte written by filldir). - - This function is used by the normal readdir VFS entry point and by - some function who try to find out info on a file from a pure MSDOS - inode. See umsdos_locate_ancestor() below. -*/ -static int umsdos_readdir_x( - struct inode *dir, /* Point to a description of the super block */ - struct file *filp, /* Point to a directory which is read */ - void *dirbuf, /* Will hold count directory entry */ - /* but filled by the filldir function */ - int internal_read, /* Called for internal purpose */ - struct umsdos_dirent *u_entry, /* Optional umsdos entry */ - int follow_hlink, - filldir_t filldir) + * Read count directory entries from directory filp + * Return a negative value from linux/errno.h. + * Return > 0 if success (The amount of byte written by filldir). + * + * This function is used by the normal readdir VFS entry point and by + * some function who try to find out info on a file from a pure MSDOS + * inode. See umsdos_locate_ancestor() below. + */ + +static int umsdos_readdir_x ( + struct inode *dir, /* Point to a description of the super block */ + struct file *filp, /* Point to a directory which is read */ + void *dirbuf, /* Will hold count directory entry */ + /* but filled by the filldir function */ + int internal_read, /* Called for internal purpose */ + struct umsdos_dirent *u_entry, /* Optional umsdos entry */ + int follow_hlink, + filldir_t filldir) { - int ret = 0; - struct inode *root_inode; - - root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO); - umsdos_startlookup(dir); - if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS - && pseudo_root - && dir == pseudo_root - && !internal_read){ - - Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); - /* - We don't need to simulate this pseudo directory - when umsdos_readdir_x is called for internal operation - of umsdos. This is why dirent_in_fs is tested - */ - /* #Specification: pseudo root / directory /DOS - When umsdos operates in pseudo root mode (C:\linux is the - linux root), it simulate a directory /DOS which points to - the real root of the file system. - */ - if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS - ,UMSDOS_ROOT_INO) == 0){ - filp->f_pos++; - } - }else if (filp->f_pos < 2 - || (dir != root_inode && filp->f_pos == 32)){ - /* #Specification: readdir / . and .. - The msdos filesystem manage the . and .. entry properly - so the EMD file won't hold any info about it. - - In readdir, we assume that for the root directory - the read position will be 0 for ".", 1 for "..". For - a non root directory, the read position will be 0 for "." - and 32 for "..". - */ - /* - This is a trick used by the msdos file system (fs/msdos/dir.c) - to manage . and .. for the root directory of a file system. - Since there is no such entry in the root, fs/msdos/dir.c - use the following: - - if f_pos == 0, return ".". - if f_pos == 1, return "..". - - So let msdos handle it - - Since umsdos entries are much larger, we share the same f_pos. - if f_pos is 0 or 1 or 32, we are clearly looking at . and - .. - - As soon as we get f_pos == 2 or f_pos == 64, then back to - 0, but this time we are reading the EMD file. - - Well, not so true. The problem, is that UMSDOS_REC_SIZE is - also 64, so as soon as we read the first record in the - EMD, we are back at offset 64. So we set the offset - to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the - .. entry from msdos. - - Now (linux 1.3), umsdos_readdir can read more than one - entry even if we limit (umsdos_dir_once) to only one: - It skips over hidden file. So we switch to - UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully - the .. entry. - */ - int last_f_pos = filp->f_pos; - struct UMSDOS_DIR_ONCE bufk; - - Printk (("umsdos_readdir_x: . or .. /mn/?\n")); - - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.count = 0; - - ret = fat_readdir(filp,&bufk,umsdos_dir_once); - if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; - if (u_entry != NULL) u_entry->flags = 0; - }else{ - struct inode *emd_dir; - Printk (("umsdos_readdir_x: normal file /mn/?\n")); - emd_dir = umsdos_emd_dir_lookup(dir,0); - if (emd_dir != NULL){ - off_t start_fpos = filp->f_pos; - Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n",emd_dir->i_ino)); - if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0; - Printk (("f_pos %Ld i_size %ld\n",filp->f_pos,emd_dir->i_size)); - ret = 0; - while (filp->f_pos < emd_dir->i_size){ - struct umsdos_dirent entry; - off_t cur_f_pos = filp->f_pos; - if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){ - ret = -EIO; - break; - }else if (entry.name_len != 0){ - /* #Specification: umsdos / readdir - umsdos_readdir() should fill a struct dirent with - an inode number. The cheap way to get it is to - do a lookup in the MSDOS directory for each - entry processed by the readdir() function. - This is not very efficient, but very simple. The - other way around is to maintain a copy of the inode - number in the EMD file. This is a problem because - this has to be maintained in sync using tricks. - Remember that MSDOS (the OS) does not update the - modification time (mtime) of a directory. There is - no easy way to tell that a directory was modified - during a DOS session and synchronise the EMD file. - - Suggestion welcome. - - So the easy way is used! - */ - struct umsdos_info info; - struct inode *inode; - - int lret; - umsdos_parse (entry.name,entry.name_len,&info); - info.f_pos = cur_f_pos; - umsdos_manglename (&info); - /* FIXME, fake a dentry --> /mn/ fixed ? */ - lret = compat_umsdos_real_lookup (dir,info.fake.fname, - info.fake.len,&inode); - Printk (("Cherche inode de %s lret %d flags %d\n" - ,info.fake.fname,lret,entry.flags)); - if (lret == 0 - && (entry.flags & UMSDOS_HLINK) - && follow_hlink){ - struct inode *rinode; - lret = umsdos_hlink2inode (inode,&rinode); - inode = rinode; - } - if (lret == 0){ - /* #Specification: pseudo root / reading real root - The pseudo root (/linux) is logically - erased from the real root. This mean that - ls /DOS, won't show "linux". This avoids - infinite recursion /DOS/linux/DOS/linux while - walking the file system. - */ - if (inode != pseudo_root - && (internal_read - || !(entry.flags & UMSDOS_HIDDEN))){ - if (filldir (dirbuf, - entry.name, - entry.name_len, - cur_f_pos, - inode->i_ino) < 0){ - filp->f_pos = cur_f_pos; - } - Printk (("Trouve ino %ld ",inode->i_ino)); - if (u_entry != NULL) *u_entry = entry; - /* iput (inode); FIXME */ - break; - } - /* iput (inode); FIXME */ - }else{ - /* #Specification: umsdos / readdir / not in MSDOS - During a readdir operation, if the file is not - in the MSDOS directory anymore, the entry is - removed from the EMD file silently. - */ - Printk (("'Silently' removing EMD for file\n")); - ret = umsdos_writeentry (dir,emd_dir,&info,1); - if (ret != 0){ - break; - } - } + int ret = 0; + + umsdos_startlookup (dir); + if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS + && pseudo_root + && dir == pseudo_root + && !internal_read) { + + Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); + /* + * We don't need to simulate this pseudo directory + * when umsdos_readdir_x is called for internal operation + * of umsdos. This is why dirent_in_fs is tested + */ + /* #Specification: pseudo root / directory /DOS + * When umsdos operates in pseudo root mode (C:\linux is the + * linux root), it simulate a directory /DOS which points to + * the real root of the file system. + */ + if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) { + filp->f_pos++; + } + } else if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) { + + /* FIXME: that was in 2.0.x: else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)) + * I'm probably screwing up pseudo-root and stuff with this. It needs proper fix. + */ + + + /* #Specification: readdir / . and .. + * The msdos filesystem manage the . and .. entry properly + * so the EMD file won't hold any info about it. + * + * In readdir, we assume that for the root directory + * the read position will be 0 for ".", 1 for "..". For + * a non root directory, the read position will be 0 for "." + * and 32 for "..". + */ + /* + * This is a trick used by the msdos file system (fs/msdos/dir.c) + * to manage . and .. for the root directory of a file system. + * Since there is no such entry in the root, fs/msdos/dir.c + * use the following: + * + * if f_pos == 0, return ".". + * if f_pos == 1, return "..". + * + * So let msdos handle it + * + * Since umsdos entries are much larger, we share the same f_pos. + * if f_pos is 0 or 1 or 32, we are clearly looking at . and + * .. + * + * As soon as we get f_pos == 2 or f_pos == 64, then back to + * 0, but this time we are reading the EMD file. + * + * Well, not so true. The problem, is that UMSDOS_REC_SIZE is + * also 64, so as soon as we read the first record in the + * EMD, we are back at offset 64. So we set the offset + * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the + * .. entry from msdos. + * + * Now (linux 1.3), umsdos_readdir can read more than one + * entry even if we limit (umsdos_dir_once) to only one: + * It skips over hidden file. So we switch to + * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully + * the .. entry. + */ + int last_f_pos = filp->f_pos; + struct UMSDOS_DIR_ONCE bufk; + + Printk (("umsdos_readdir_x: . or .. /mn/?\n")); + + bufk.dirbuf = dirbuf; + bufk.filldir = filldir; + bufk.count = 0; + + ret = fat_readdir (filp, &bufk, umsdos_dir_once); + if (last_f_pos > 0 && filp->f_pos > last_f_pos) + filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; + if (u_entry != NULL) + u_entry->flags = 0; + } else { + struct inode *emd_dir; + + Printk (("umsdos_readdir_x: normal file /mn/?\n")); + emd_dir = umsdos_emd_dir_lookup (dir, 0); + if (emd_dir != NULL) { + off_t start_fpos = filp->f_pos; + + Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n", emd_dir->i_ino)); + if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1) + filp->f_pos = 0; + Printk (("f_pos %Ld i_size %ld\n", filp->f_pos, emd_dir->i_size)); + ret = 0; + while (filp->f_pos < emd_dir->i_size) { + struct umsdos_dirent entry; + off_t cur_f_pos = filp->f_pos; + + if (umsdos_emd_dir_readentry (emd_dir, filp, &entry) != 0) { + ret = -EIO; + break; + } else if (entry.name_len != 0) { + /* #Specification: umsdos / readdir + * umsdos_readdir() should fill a struct dirent with + * an inode number. The cheap way to get it is to + * do a lookup in the MSDOS directory for each + * entry processed by the readdir() function. + * This is not very efficient, but very simple. The + * other way around is to maintain a copy of the inode + * number in the EMD file. This is a problem because + * this has to be maintained in sync using tricks. + * Remember that MSDOS (the OS) does not update the + * modification time (mtime) of a directory. There is + * no easy way to tell that a directory was modified + * during a DOS session and synchronise the EMD file. + * + * Suggestion welcome. + * + * So the easy way is used! + */ + struct umsdos_info info; + struct inode *inode; + + int lret; + + umsdos_parse (entry.name, entry.name_len, &info); + info.f_pos = cur_f_pos; + umsdos_manglename (&info); + lret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode); + Printk (("Cherche inode de %s lret %d flags %d\n", info.fake.fname, lret, entry.flags)); + if (lret == 0 + && (entry.flags & UMSDOS_HLINK) + && follow_hlink) { + struct inode *rinode; + + Printk ((KERN_DEBUG "umsdos_hlink2inode now\n")); + lret = umsdos_hlink2inode (inode, &rinode); + inode = rinode; + } + if (lret == 0) { + /* #Specification: pseudo root / reading real root + * The pseudo root (/linux) is logically + * erased from the real root. This mean that + * ls /DOS, won't show "linux". This avoids + * infinite recursion /DOS/linux/DOS/linux while + * walking the file system. + */ + if (inode != pseudo_root + && (internal_read + || !(entry.flags & UMSDOS_HIDDEN))) { + Printk ((KERN_DEBUG "filldir now\n")); + if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, inode->i_ino) < 0) { + filp->f_pos = cur_f_pos; + } + Printk (("Trouve ino %ld ", inode->i_ino)); + if (u_entry != NULL) + *u_entry = entry; + iput (inode); /* FIXME? */ + break; + } + Printk ((KERN_DEBUG " dir.c:Putting inode %lu with i_count=%d\n", inode->i_ino, inode->i_count)); + iput (inode); /* FIXME? */ + } else { + /* #Specification: umsdos / readdir / not in MSDOS + * During a readdir operation, if the file is not + * in the MSDOS directory anymore, the entry is + * removed from the EMD file silently. + */ + Printk (("'Silently' removing EMD for file\n")); + ret = umsdos_writeentry (dir, emd_dir, &info, 1); + if (ret != 0) { + break; + } + } + } + } + /* + * If the fillbuf has failed, f_pos is back to 0. + * To avoid getting back into the . and .. state + * (see comments at the beginning), we put back + * the special offset. + */ + if (filp->f_pos == 0) + filp->f_pos = start_fpos; + Printk ((KERN_DEBUG " dir.c:Putting emd_dir %lu with i_count=%d\n", emd_dir->i_ino, emd_dir->i_count)); + iput (emd_dir); /* FIXME? */ + } } - } - /* - If the fillbuf has failed, f_pos is back to 0. - To avoid getting back into the . and .. state - (see comments at the beginning), we put back - the special offset. - */ - if (filp->f_pos == 0) filp->f_pos = start_fpos; - /* iput(emd_dir); FIXME */ - } - } - umsdos_endlookup(dir); - Printk (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret)); - return ret; + umsdos_endlookup (dir); + + Printk (("read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret)); + return ret; } /* - Read count directory entries from directory filp - Return a negative value from linux/errno.h. - Return 0 or positive if successful -*/ -static int UMSDOS_readdir( - struct file *filp, /* Point to a directory which is read */ - void *dirbuf, /* Will hold directory entries */ - filldir_t filldir) + * Read count directory entries from directory filp + * Return a negative value from linux/errno.h. + * Return 0 or positive if successful + */ + +static int UMSDOS_readdir ( + struct file *filp, /* Point to a directory which is read */ + void *dirbuf, /* Will hold directory entries */ + filldir_t filldir) { - struct inode *dir = filp->f_dentry->d_inode; - int ret = 0; - int count = 0; - struct UMSDOS_DIR_ONCE bufk; - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.stop = 0; - - Printk (("UMSDOS_readdir in\n")); - while (ret == 0 && bufk.stop == 0){ - struct umsdos_dirent entry; - bufk.count = 0; - Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once)); - ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once); - if (bufk.count == 0) break; - count += bufk.count; - } - Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count - ,filp->f_pos)); - return count?:ret; + struct inode *dir = filp->f_dentry->d_inode; + int ret = 0; + int count = 0; + struct UMSDOS_DIR_ONCE bufk; + + bufk.dirbuf = dirbuf; + bufk.filldir = filldir; + bufk.stop = 0; + + Printk (("UMSDOS_readdir in\n")); + while (ret == 0 && bufk.stop == 0) { + struct umsdos_dirent entry; + + bufk.count = 0; + Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once)); + ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once); + if (bufk.count == 0) + break; + count += bufk.count; + } + Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", ret, count, filp->f_pos)); + return count ? : ret; } + /* - Complete the inode content with info from the EMD file -*/ + * Complete the inode content with info from the EMD file + */ + void umsdos_lookup_patch ( - struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry, - off_t emd_pos) + struct inode *dir, + struct inode *inode, + struct umsdos_dirent *entry, + off_t emd_pos) { - /* - This function modify the state of a dir inode. It decides - if the dir is a umsdos dir or a dos dir. This is done - deeper in umsdos_patch_inode() called at the end of this function. - - umsdos_patch_inode() may block because it is doing disk access. - At the same time, another process may get here to initialise - the same dir inode. There is 3 cases. - - 1-The inode is already initialised. We do nothing. - 2-The inode is not initialised. We lock access and do it. - 3-Like 2 but another process has lock the inode, so we try - to lock it and right after check if initialisation is still - needed. - - - Thanks to the mem option of the kernel command line, it was - possible to consistently reproduce this problem by limiting - my mem to 4 meg and running X. - */ - /* - Do this only if the inode is freshly read, because we will lose - the current (updated) content. - */ - /* - A lookup of a mount point directory yield the inode into - the other fs, so we don't care about initialising it. iget() - does this automatically. - */ - if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){ - if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode); - if (!umsdos_isinit(inode)){ - /* #Specification: umsdos / lookup / inode info - After successfully reading an inode from the MSDOS - filesystem, we use the EMD file to complete it. - We update the following field. - - uid, gid, atime, ctime, mtime, mode. - - We rely on MSDOS for mtime. If the file - was modified during an MSDOS session, at least - mtime will be meaningful. We do this only for regular - file. - - We don't rely on MSDOS for mtime for directory because - the MSDOS directory date is creation time (strange - MSDOS behavior) which fit nowhere in the three UNIX - time stamp. - */ - if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime; - inode->i_mode = entry->mode; - inode->i_rdev = to_kdev_t(entry->rdev); - inode->i_atime = entry->atime; - inode->i_ctime = entry->ctime; - inode->i_mtime = entry->mtime; - inode->i_uid = entry->uid; - inode->i_gid = entry->gid; - /* #Specification: umsdos / conversion mode - The msdos fs can do some inline conversion - of the data of a file. It can translate - silently from MsDOS text file format to Unix - one (crlf -> lf) while reading, and the reverse - while writing. This is activated using the mount - option conv=.... - - This is not useful for Linux file in promoted - directory. It can even be harmful. For this - reason, the binary (no conversion) mode is - always activated. - */ - /* #Specification: umsdos / conversion mode / todo - A flag could be added to file and directories - forcing an automatic conversion mode (as - done with the msdos fs). - - This flag could be setup on a directory basis - (instead of file) and all file in it would - logically inherited. If the conversion mode - is active (conv=) then the i_binary flag would - be left untouched in those directories. - - It was proposed that the sticky bit was used - to set this. The problem is that new file would - be written incorrectly. The other problem is that - the sticky bit has a meaning for directories. So - another bit should be used (there is some space - in the EMD file for it) and a special utilities - would be used to assign the flag to a directory). - I don't think it is useful to assign this flag - on a single file. - */ - - MSDOS_I(inode)->i_binary = 1; - /* #Specification: umsdos / i_nlink - The nlink field of an inode is maintain by the MSDOS file system - for directory and by UMSDOS for other file. The logic is that - MSDOS is already figuring out what to do for directories and - does nothing for other files. For MSDOS, there are no hard link - so all file carry nlink==1. UMSDOS use some info in the - EMD file to plug the correct value. - */ - if (!S_ISDIR(entry->mode)){ - if (entry->nlink > 0){ - inode->i_nlink = entry->nlink; - }else{ - printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n"); + /* + * This function modify the state of a dir inode. It decides + * if the dir is a umsdos dir or a dos dir. This is done + * deeper in umsdos_patch_inode() called at the end of this function. + * + * umsdos_patch_inode() may block because it is doing disk access. + * At the same time, another process may get here to initialise + * the same dir inode. There is 3 cases. + * + * 1-The inode is already initialised. We do nothing. + * 2-The inode is not initialised. We lock access and do it. + * 3-Like 2 but another process has lock the inode, so we try + * to lock it and right after check if initialisation is still + * needed. + * + * + * Thanks to the mem option of the kernel command line, it was + * possible to consistently reproduce this problem by limiting + * my mem to 4 meg and running X. + */ + /* + * Do this only if the inode is freshly read, because we will lose + * the current (updated) content. + */ + /* + * A lookup of a mount point directory yield the inode into + * the other fs, so we don't care about initialising it. iget() + * does this automatically. + */ + + if (inode->i_sb == dir->i_sb && !umsdos_isinit (inode)) { + if (S_ISDIR (inode->i_mode)) + umsdos_lockcreate (inode); + if (!umsdos_isinit (inode)) { + /* #Specification: umsdos / lookup / inode info + * After successfully reading an inode from the MSDOS + * filesystem, we use the EMD file to complete it. + * We update the following field. + * + * uid, gid, atime, ctime, mtime, mode. + * + * We rely on MSDOS for mtime. If the file + * was modified during an MSDOS session, at least + * mtime will be meaningful. We do this only for regular + * file. + * + * We don't rely on MSDOS for mtime for directory because + * the MSDOS directory date is creation time (strange + * MSDOS behavior) which fit nowhere in the three UNIX + * time stamp. + */ + if (S_ISREG (entry->mode)) + entry->mtime = inode->i_mtime; + inode->i_mode = entry->mode; + inode->i_rdev = to_kdev_t (entry->rdev); + inode->i_atime = entry->atime; + inode->i_ctime = entry->ctime; + inode->i_mtime = entry->mtime; + inode->i_uid = entry->uid; + inode->i_gid = entry->gid; + /* #Specification: umsdos / conversion mode + * The msdos fs can do some inline conversion + * of the data of a file. It can translate + * silently from MsDOS text file format to Unix + * one (crlf -> lf) while reading, and the reverse + * while writing. This is activated using the mount + * option conv=.... + * + * This is not useful for Linux file in promoted + * directory. It can even be harmful. For this + * reason, the binary (no conversion) mode is + * always activated. + */ + /* #Specification: umsdos / conversion mode / todo + * A flag could be added to file and directories + * forcing an automatic conversion mode (as + * done with the msdos fs). + * + * This flag could be setup on a directory basis + * (instead of file) and all file in it would + * logically inherited. If the conversion mode + * is active (conv=) then the i_binary flag would + * be left untouched in those directories. + * + * It was proposed that the sticky bit was used + * to set this. The problem is that new file would + * be written incorrectly. The other problem is that + * the sticky bit has a meaning for directories. So + * another bit should be used (there is some space + * in the EMD file for it) and a special utilities + * would be used to assign the flag to a directory). + * I don't think it is useful to assign this flag + * on a single file. + */ + + MSDOS_I (inode)->i_binary = 1; + /* #Specification: umsdos / i_nlink + * The nlink field of an inode is maintain by the MSDOS file system + * for directory and by UMSDOS for other file. The logic is that + * MSDOS is already figuring out what to do for directories and + * does nothing for other files. For MSDOS, there are no hard link + * so all file carry nlink==1. UMSDOS use some info in the + * EMD file to plug the correct value. + */ + if (!S_ISDIR (entry->mode)) { + if (entry->nlink > 0) { + inode->i_nlink = entry->nlink; + } else { + printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n"); + } + } + umsdos_patch_inode (inode, dir, emd_pos); + } + if (S_ISDIR (inode->i_mode)) + umsdos_unlockcreate (inode); + if (inode->u.umsdos_i.i_emd_owner == 0) + printk (KERN_WARNING "emd_owner still 0 ???\n"); } - } - umsdos_patch_inode(inode,dir,emd_pos); - } - if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode); - if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n"); - } } -struct UMSDOS_DIRENT_K{ - off_t f_pos; /* will hold the offset of the entry in EMD */ - ino_t ino; + + +struct UMSDOS_DIRENT_K { + off_t f_pos; /* will hold the offset of the entry in EMD */ + ino_t ino; }; + /* - Just to record the offset of one entry. -*/ -static int umsdos_filldir_k( - void * buf, - const char *name, - int len, - off_t offset, - ino_t ino) + * Just to record the offset of one entry. + */ + +static int umsdos_filldir_k ( + void *buf, + const char *name, + int len, + off_t offset, + ino_t ino) { - struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf; - d->f_pos = offset; - d->ino = ino; - return 0; + struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *) buf; + + d->f_pos = offset; + d->ino = ino; + return 0; } -struct UMSDOS_DIR_SEARCH{ - struct umsdos_dirent *entry; - int found; - ino_t search_ino; +struct UMSDOS_DIR_SEARCH { + struct umsdos_dirent *entry; + int found; + ino_t search_ino; }; static int umsdos_dir_search ( - void * buf, - const char *name, - int len, - off_t offset, - ino_t ino) + void *buf, + const char *name, + int len, + off_t offset, + ino_t ino) { - int ret = 0; - struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf; - if (d->search_ino == ino){ - d->found = 1; - memcpy (d->entry->name,name,len); - d->entry->name[len] = '\0'; - d->entry->name_len = len; - ret = 1; /* So fat_readdir will terminate */ - } - return ret; + int ret = 0; + struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *) buf; + + if (d->search_ino == ino) { + d->found = 1; + memcpy (d->entry->name, name, len); + d->entry->name[len] = '\0'; + d->entry->name_len = len; + ret = 1; /* So fat_readdir will terminate */ + } + return ret; } + /* - Locate entry of an inode in a directory. - Return 0 or a negative error code. - - Normally, this function must succeed. It means a strange corruption - in the file system if not. -*/ + * Locate entry of an inode in a directory. + * Return 0 or a negative error code. + * + * Normally, this function must succeed. It means a strange corruption + * in the file system if not. + */ + int umsdos_inode2entry ( - struct inode *dir, - struct inode *inode, - struct umsdos_dirent *entry) /* Will hold the entry */ -{ - int ret = -ENOENT; - if (pseudo_root && inode == pseudo_root){ - /* - Quick way to find the name. - Also umsdos_readdir_x won't show /linux anyway - */ - memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1); - entry->name_len = UMSDOS_PSDROOT_LEN; - ret = 0; - }else{ - struct inode *emddir = umsdos_emd_dir_lookup(dir,0); - /* iput (emddir); FIXME */ - if (emddir == NULL){ - /* This is a DOS directory */ - struct UMSDOS_DIR_SEARCH bufk; - struct file filp; - - fill_new_filp (&filp, NULL); - - Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n")); - filp.f_reada = 1; - filp.f_pos = 0; - bufk.entry = entry; - bufk.search_ino = inode->i_ino; - fat_readdir (&filp,&bufk,umsdos_dir_search); - if (bufk.found){ - ret = 0; - inode->u.umsdos_i.i_dir_owner = dir->i_ino; - inode->u.umsdos_i.i_emd_owner = 0; - umsdos_setup_dir_inode(inode); - } - }else{ - /* skip . and .. see umsdos_readdir_x() */ - struct file filp; - fill_new_filp (&filp, NULL); - - filp.f_reada = 1; - filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; - Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n")); - while (1){ - struct UMSDOS_DIRENT_K bufk; - if (umsdos_readdir_x(dir,&filp,&bufk - ,1,entry,0,umsdos_filldir_k) < 0){ - printk ("UMSDOS: can't locate inode %ld in EMD file???\n" - ,inode->i_ino); - break; - }else if (bufk.ino == inode->i_ino){ - ret = 0; - umsdos_lookup_patch (dir,inode,entry,bufk.f_pos); - break; + struct inode *dir, + struct inode *inode, + struct umsdos_dirent *entry) +{ /* Will hold the entry */ + int ret = -ENOENT; + + if (pseudo_root && inode == pseudo_root) { + /* + * Quick way to find the name. + * Also umsdos_readdir_x won't show /linux anyway + */ + memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1); + entry->name_len = UMSDOS_PSDROOT_LEN; + ret = 0; + } else { + struct inode *emddir = umsdos_emd_dir_lookup (dir, 0); + + iput (emddir); /* FIXME? */ + if (emddir == NULL) { + /* This is a DOS directory */ + struct UMSDOS_DIR_SEARCH bufk; + struct file filp; + struct dentry *i2e; + + i2e = creat_dentry ("i2e.nul", 7, dir, NULL); + + fill_new_filp (&filp, i2e); + + Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n")); + filp.f_reada = 1; + filp.f_pos = 0; + bufk.entry = entry; + bufk.search_ino = inode->i_ino; + fat_readdir (&filp, &bufk, umsdos_dir_search); + if (bufk.found) { + ret = 0; + inode->u.umsdos_i.i_dir_owner = dir->i_ino; + inode->u.umsdos_i.i_emd_owner = 0; + umsdos_setup_dir_inode (inode); + } + } else { + /* skip . and .. see umsdos_readdir_x() */ + struct file filp; + struct dentry *i2e; + + i2e = creat_dentry ("i2e.nn", 6, dir, NULL); + fill_new_filp (&filp, i2e); + + filp.f_reada = 1; + filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; + Printk ((KERN_ERR "umsdos_inode2entry skip...: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n")); + while (1) { + struct UMSDOS_DIRENT_K bufk; + + if (umsdos_readdir_x (dir, &filp, &bufk + ,1, entry, 0, umsdos_filldir_k) < 0) { + printk ("UMSDOS: can't locate inode %ld in EMD file???\n" + ,inode->i_ino); + break; + } else if (bufk.ino == inode->i_ino) { + ret = 0; + umsdos_lookup_patch (dir, inode, entry, bufk.f_pos); + break; + } + } + } } - } - } - } - return ret; + return ret; } /* - Locate the parent of a directory and the info on that directory - Return 0 or a negative error code. -*/ + * Locate the parent of a directory and the info on that directory + * Return 0 or a negative error code. + */ + static int umsdos_locate_ancestor ( - struct inode *dir, - struct inode **result, - struct umsdos_dirent *entry) + struct inode *dir, + struct inode **result, + struct umsdos_dirent *entry) { - int ret; - - umsdos_patch_inode (dir,NULL,0); - /* FIXME */ - ret = compat_umsdos_real_lookup (dir,"..",2,result); - Printk (("result %d %p ",ret,*result)); - if (ret == 0){ - struct inode *adir = *result; - ret = umsdos_inode2entry (adir,dir,entry); - } - Printk (("\n")); - return ret; + int ret; + + umsdos_patch_inode (dir, NULL, 0); + /* FIXME */ + ret = compat_umsdos_real_lookup (dir, "..", 2, result); + Printk (("result %d %p ", ret, *result)); + if (ret == 0) { + struct inode *adir = *result; + + ret = umsdos_inode2entry (adir, dir, entry); + } + Printk (("\n")); + return ret; } + + /* - Build the path name of an inode (relative to the file system. - This function is need to set (pseudo) hard link. - - It uses the same strategy as the standard getcwd(). -*/ + * Build the path name of an inode (relative to the file system. + * This function is need to set (pseudo) hard link. + * + * It uses the same strategy as the standard getcwd(). + */ + int umsdos_locate_path ( - struct inode *inode, - char *path) + struct inode *inode, + char *path) { - int ret = 0; - struct inode *dir = inode; - struct inode *root_inode; - char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - root_inode = iget(inode->i_sb,UMSDOS_ROOT_INO); - if (bpath == NULL){ - ret = -ENOMEM; - }else{ - struct umsdos_dirent entry; - char *ptbpath = bpath+PATH_MAX-1; - *ptbpath = '\0'; - Printk (("locate_path mode %x ",inode->i_mode)); - if (!S_ISDIR(inode->i_mode)){ - ret = umsdos_get_dirowner (inode,&dir); - Printk (("locate_path ret %d ",ret)); - if (ret == 0){ - ret = umsdos_inode2entry (dir,inode,&entry); - if (ret == 0){ - ptbpath -= entry.name_len; - memcpy (ptbpath,entry.name,entry.name_len); - Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath)); - } - } - }else{ - dir->i_count++; - } - if (ret == 0){ - while (dir != root_inode){ - struct inode *adir; - ret = umsdos_locate_ancestor (dir,&adir,&entry); - /* iput (dir); FIXME */ - dir = NULL; - Printk (("ancestor %d ",ret)); - if (ret == 0){ - *--ptbpath = '/'; - ptbpath -= entry.name_len; - memcpy (ptbpath,entry.name,entry.name_len); - dir = adir; - Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath)); - }else{ - break; + int ret = 0; + struct inode *dir = inode; + struct inode *root_inode; + char *bpath = (char *) kmalloc (PATH_MAX, GFP_KERNEL); + + root_inode = iget (inode->i_sb, UMSDOS_ROOT_INO); + if (bpath == NULL) { + ret = -ENOMEM; + } else { + struct umsdos_dirent entry; + char *ptbpath = bpath + PATH_MAX - 1; + + *ptbpath = '\0'; + Printk (("locate_path mode %x ", inode->i_mode)); + if (!S_ISDIR (inode->i_mode)) { + ret = umsdos_get_dirowner (inode, &dir); + Printk (("locate_path ret %d ", ret)); + if (ret == 0) { + ret = umsdos_inode2entry (dir, inode, &entry); + if (ret == 0) { + ptbpath -= entry.name_len; + memcpy (ptbpath, entry.name, entry.name_len); + Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath)); + } + } + } else { + inc_count (dir); + } + if (ret == 0) { + while (dir != root_inode) { + struct inode *adir; + + ret = umsdos_locate_ancestor (dir, &adir, &entry); + /* iput (dir); FIXME */ + dir = NULL; + Printk (("ancestor %d ", ret)); + if (ret == 0) { + *--ptbpath = '/'; + ptbpath -= entry.name_len; + memcpy (ptbpath, entry.name, entry.name_len); + dir = adir; + Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath)); + } else { + break; + } + } + } + strcpy (path, ptbpath); + kfree (bpath); } - } - } - strcpy (path,ptbpath); - kfree (bpath); - } - Printk (("\n")); - /* iput (dir); FIXME */ - return ret; + Printk (("\n")); + iput (dir); /* FIXME?? */ + return ret; } + /* - Return != 0 if an entry is the pseudo DOS entry in the pseudo root. -*/ + * Return != 0 if an entry is the pseudo DOS entry in the pseudo root. + */ + int umsdos_is_pseudodos ( - struct inode *dir, - struct dentry *dentry) + struct inode *dir, + struct dentry *dentry) { - /* #Specification: pseudo root / DOS hard coded - The pseudo sub-directory DOS in the pseudo root is hard coded. - The name is DOS. This is done this way to help standardised - the umsdos layout. The idea is that from now on /DOS is - a reserved path and nobody will think of using such a path - for a package. - */ - return pseudo_root - && dir == pseudo_root - && dentry->d_name.len == 3 - && dentry->d_name.name[0] == 'D' - && dentry->d_name.name[1] == 'O' - && dentry->d_name.name[2] == 'S'; + /* #Specification: pseudo root / DOS hard coded + * The pseudo sub-directory DOS in the pseudo root is hard coded. + * The name is DOS. This is done this way to help standardised + * the umsdos layout. The idea is that from now on /DOS is + * a reserved path and nobody will think of using such a path + * for a package. + */ + return pseudo_root + && dir == pseudo_root + && dentry->d_name.len == 3 + && dentry->d_name.name[0] == 'D' + && dentry->d_name.name[1] == 'O' + && dentry->d_name.name[2] == 'S'; } + /* - Check if a file exist in the current directory. - Return 0 if ok, negative error code if not (ex: -ENOENT). -*/ + * Check if a file exist in the current directory. + * Return 0 if ok, negative error code if not (ex: -ENOENT). + */ + int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, - int nopseudo)/* Don't care about pseudo root mode */ -{ - int ret = -ENOENT; - struct inode *root_inode; - struct inode *pseudo_root_inode=NULL; - int len = dentry->d_name.len; - const char *name = dentry->d_name.name; - - Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu, d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dentry->d_parent)); /* FIXME /mn/ debug only */ - if (dentry->d_parent) Printk ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */ - - root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO); - /* pseudo_root_inode = iget( ... ) ? */ - dentry->d_inode = NULL; - umsdos_startlookup(dir); - if (len == 1 && name[0] == '.'){ - d_add (dentry, dir); - dir->i_count++; - ret = 0; - }else if (len == 2 && name[0] == '.' && name[1] == '.'){ - if (pseudo_root && dir == pseudo_root_inode){ - /* #Specification: pseudo root / .. in real root - Whenever a lookup is those in the real root for - the directory .., and pseudo root is active, the - pseudo root is returned. - */ - ret = 0; - d_add (dentry, pseudo_root); - pseudo_root->i_count++; - }else{ - /* #Specification: locating .. / strategy - We use the msdos filesystem to locate the parent directory. - But it is more complicated than that. - - We have to step back even further to - get the parent of the parent, so we can get the EMD - of the parent of the parent. Using the EMD file, we can - locate all the info on the parent, such a permissions - and owner. - */ - - ret = compat_umsdos_real_lookup (dir,"..",2,&dentry->d_inode); - Printk (("ancestor ret %d dir %p *result %p ",ret,dir,dentry->d_inode)); - if (ret == 0 - && dentry->d_inode != root_inode - && dentry->d_inode != pseudo_root){ - struct inode *aadir; - struct umsdos_dirent entry; - ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry); - /* iput (aadir); FIXME */ - } - } - }else if (umsdos_is_pseudodos(dir,dentry)){ - /* #Specification: pseudo root / lookup(DOS) - A lookup of DOS in the pseudo root will always succeed - and return the inode of the real root. - */ - d_add (dentry, root_inode); - (dentry->d_inode)->i_count++; - ret = 0; - }else{ - struct umsdos_info info; - ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); - if (ret == 0) ret = umsdos_findentry (dir,&info,0); - Printk (("lookup %.*s pos %lu ret %d len %d ",info.fake.len,info.fake.fname,info.f_pos,ret - ,info.fake.len)); - if (ret == 0){ - /* #Specification: umsdos / lookup - A lookup for a file is done in two step. First, we locate - the file in the EMD file. If not present, we return - an error code (-ENOENT). If it is there, we repeat the - operation on the msdos file system. If this fails, it means - that the file system is not in sync with the emd file. - We silently remove this entry from the emd file, - and return ENOENT. - */ - struct inode *inode; - - ret = compat_umsdos_real_lookup (dir,info.fake.fname,info.fake.len,&inode); - - Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode)); - - if (inode == NULL){ - printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n" - ,info.fake.len, info.fake.fname); - umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode)); - }else{ - Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino)); - - /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */ - d_add (dentry, iget(dir->i_sb, inode->i_ino)); - - umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - Printk (("lookup ino %ld flags %d\n",inode->i_ino - ,info.entry.flags)); - if (info.entry.flags & UMSDOS_HLINK){ - Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n")); - ret = umsdos_hlink2inode (inode,&dentry->d_inode); - } - if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo){ - /* #Specification: pseudo root / dir lookup - For the same reason as readdir, a lookup in /DOS for - the pseudo root directory (linux) will fail. - */ - /* - This has to be allowed for resolving hard link - which are recorded independently of the pseudo-root - mode. - */ - Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n")); - /* iput (pseudo_root); FIXME */ - dentry->d_inode = NULL; - ret = -ENOENT; + int nopseudo) +{ /* Don't care about pseudo root mode */ + int ret = -ENOENT; + struct inode *root_inode; + int len = dentry->d_name.len; + const char *name = dentry->d_name.name; + + PRINTK ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu (i_count=%d), d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dir->i_count, dentry->d_parent)); /* FIXME /mn/ debug only */ + if (dentry->d_parent) + PRINTK ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */ + + root_inode = iget (dir->i_sb, UMSDOS_ROOT_INO); + Printk ((KERN_ERR "umsdos_lookup_x (CNT!): entering root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count)); /* FIXME: DEBUG, DELME */ + + d_instantiate (dentry, NULL); + umsdos_startlookup (dir); + if (len == 1 && name[0] == '.') { + d_add (dentry, dir); + inc_count (dir); + ret = 0; + } else if (len == 2 && name[0] == '.' && name[1] == '.') { + if (pseudo_root && dir == pseudo_root) { + /* #Specification: pseudo root / .. in real root + * Whenever a lookup is those in the real root for + * the directory .., and pseudo root is active, the + * pseudo root is returned. + */ + ret = 0; + d_add (dentry, pseudo_root); + inc_count (pseudo_root); + } else { + /* #Specification: locating .. / strategy + * We use the msdos filesystem to locate the parent directory. + * But it is more complicated than that. + * + * We have to step back even further to + * get the parent of the parent, so we can get the EMD + * of the parent of the parent. Using the EMD file, we can + * locate all the info on the parent, such a permissions + * and owner. + */ + + ret = compat_umsdos_real_lookup (dir, "..", 2, &dentry->d_inode); + Printk (("ancestor ret %d dir %p *result %p ", ret, dir, dentry->d_inode)); + if (ret == 0 + && dentry->d_inode != root_inode + && dentry->d_inode != pseudo_root) { + struct inode *aadir; + struct umsdos_dirent entry; + + ret = umsdos_locate_ancestor (dentry->d_inode, &aadir, &entry); + iput (aadir); /* FIXME */ + } + } + } else if (umsdos_is_pseudodos (dir, dentry)) { + /* #Specification: pseudo root / lookup(DOS) + * A lookup of DOS in the pseudo root will always succeed + * and return the inode of the real root. + */ + d_add (dentry, root_inode); + inc_count (dentry->d_inode); + ret = 0; + } else { + struct umsdos_info info; + + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); + if (ret == 0) + ret = umsdos_findentry (dir, &info, 0); + Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret + ,info.fake.len)); + if (ret == 0) { + /* #Specification: umsdos / lookup + * A lookup for a file is done in two step. First, we locate + * the file in the EMD file. If not present, we return + * an error code (-ENOENT). If it is there, we repeat the + * operation on the msdos file system. If this fails, it means + * that the file system is not in sync with the emd file. + * We silently remove this entry from the emd file, + * and return ENOENT. + */ + struct inode *inode; + + ret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode); + + Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode)); + + if (inode == NULL) { + printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n" + ,info.fake.len, info.fake.fname); + umsdos_delentry (dir, &info, S_ISDIR (info.entry.mode)); + } else { + Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino)); + + /* we've found it. now put inode in dentry */ + d_add (dentry, inode); + + umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos); + Printk (("lookup ino %ld flags %d\n", inode->i_ino, info.entry.flags)); + if (info.entry.flags & UMSDOS_HLINK) { + Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n")); + ret = umsdos_hlink2inode (inode, &dentry->d_inode); + } + if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo) { + /* #Specification: pseudo root / dir lookup + * For the same reason as readdir, a lookup in /DOS for + * the pseudo root directory (linux) will fail. + */ + /* + * This has to be allowed for resolving hard link + * which are recorded independently of the pseudo-root + * mode. + */ + Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n")); + iput (pseudo_root); /* FIXME?? */ + d_instantiate (dentry, NULL); /* FIXME: should be dput(dentry) ? */ + ret = -ENOENT; + } + } + } } - } - } - } - umsdos_endlookup(dir); - /* iput (dir); FIXME */ - Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret)); - return ret; + umsdos_endlookup (dir); + PRINTK ((KERN_DEBUG "umsdos_lookup_x: returning %d : name=%.*s (i_count=%d), dir=%lu (i_count=%d)\n", ret, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_count, dir->i_ino, dir->i_count)); + Printk ((KERN_ERR "umsdos_lookup_x (CNT!): exiting root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count)); /* FIXME: DEBUG, DELME */ + return ret; } /* - Check if a file exist in the current directory. - Return 0 if ok, negative error code if not (ex: -ENOENT). - - -*/ + * Check if a file exist in the current directory. + * Return 0 if ok, negative error code if not (ex: -ENOENT). + * + * + */ + int UMSDOS_lookup ( - struct inode *dir, - struct dentry *dentry) + struct inode *dir, + struct dentry *dentry) { - int ret; - ret = umsdos_lookup_x(dir,dentry,0); - + int ret; + + check_dentry (dentry); + ret = umsdos_lookup_x (dir, dentry, 0); + check_dentry (dentry); + #if 1 - if (ret == -ENOENT) { - Printk ((KERN_INFO "UMSDOS_lookup: converting -ENOENT to negative dentry !\n")); - d_add (dentry, NULL); /* create negative dentry if not found */ - ret = 0; - } + if (ret == -ENOENT) { + Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative dentry !\n")); + d_add (dentry, NULL); /* create negative dentry if not found */ + ret = 0; + } #endif - - return ret; + + return ret; } /* - Locate the inode pointed by a (pseudo) hard link - Return 0 if ok, a negative error code if not. -*/ + * Locate the inode pointed by a (pseudo) hard link + * Return 0 if ok, a negative error code if not. + */ + int umsdos_hlink2inode (struct inode *hlink, struct inode **result) { - struct inode *root_inode; - int ret = -EIO; - struct dentry *dentry_src, *dentry_dst; - char *path; - -#if 0 /* FIXME: DELME */ - Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n")); - return -ENOENT; /* /mn/ FIXME just for test */ + struct inode *root_inode; + int ret = -EIO; + struct dentry *dentry_src, *dentry_dst; + char *path; + +#if 0 /* FIXME: DELME */ + Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n")); + return -ENOENT; /* /mn/ FIXME just for test */ #endif - - path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - - root_inode = iget(hlink->i_sb,UMSDOS_ROOT_INO); - *result = NULL; - if (path == NULL){ - ret = -ENOMEM; - /* iput (hlink); FIXME */ - }else{ - struct file filp; - loff_t offs = 0; - - fill_new_filp (&filp, NULL); - - - dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL); - - memset (&filp, 0, sizeof (filp)); - - filp.f_pos = 0; - filp.f_reada = 1; - filp.f_flags = O_RDONLY; - filp.f_dentry = dentry_src; - filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ - - Printk (("hlink2inode ")); - if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size) - { - struct inode *dir; - char *pt = path; - dir = root_inode; - path[hlink->i_size] = '\0'; -/* iput (hlink); / * FIXME! /mn/ */ - dir->i_count++; - while (1) - { - char *start = pt; - int len; - while (*pt != '\0' && *pt != '/') pt++; - len = (int)(pt - start); - if (*pt == '/') *pt++ = '\0'; - /* FIXME. /mn/ fixed ? */ - - dentry_dst = creat_dentry (start, len, NULL, NULL); - - if (dir->u.umsdos_i.i_emd_dir == 0){ - /* This is a DOS directory */ - - Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); - ret = umsdos_rlookup_x(dir,dentry_dst,1); - }else{ - Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); - ret = umsdos_lookup_x(dir,dentry_dst,1); - } - Printk ((" returned %d\n", ret)); - *result = dentry_dst->d_inode; /* /mn/ ok ? */ - - Printk (("h2n lookup :%s: -> %d ",start,ret)); - if (ret == 0 && *pt != '\0'){ - dir = *result; - }else{ - break; - } - } - }else{ - Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n")); - /* iput (hlink); / * FIXME */ - } - Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result)); - kfree (path); - } - return ret; + + path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); + + root_inode = iget (hlink->i_sb, UMSDOS_ROOT_INO); + *result = NULL; + if (path == NULL) { + ret = -ENOMEM; + iput (hlink); /* FIXME? */ + } else { + struct file filp; + loff_t offs = 0; + + dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL); + + fill_new_filp (&filp, dentry_src); + filp.f_flags = O_RDONLY; + + Printk (("hlink2inode ")); + if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size) { + struct inode *dir; + char *pt = path; + + dir = root_inode; + path[hlink->i_size] = '\0'; + iput (hlink); /* FIXME? */ + inc_count (dir); + while (1) { + char *start = pt; + int len; + + while (*pt != '\0' && *pt != '/') + pt++; + len = (int) (pt - start); + if (*pt == '/') + *pt++ = '\0'; + /* FIXME. /mn/ fixed ? */ + + dentry_dst = creat_dentry (start, len, NULL, NULL); + + if (dir->u.umsdos_i.i_emd_dir == 0) { + /* This is a DOS directory */ + + Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); + ret = umsdos_rlookup_x (dir, dentry_dst, 1); + } else { + Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); + ret = umsdos_lookup_x (dir, dentry_dst, 1); + } + Printk ((" returned %d\n", ret)); + *result = dentry_dst->d_inode; /* /mn/ ok ? */ + + Printk (("h2n lookup :%s: -> %d ", start, ret)); + if (ret == 0 && *pt != '\0') { + dir = *result; + } else { + break; + } + } + } else { + Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n")); + iput (hlink); /* FIXME? */ + } + Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result)); + kfree (path); + } + return ret; } -static struct file_operations umsdos_dir_operations = { - NULL, /* lseek - default */ - UMSDOS_dir_read, /* read */ - NULL, /* write - bad */ - UMSDOS_readdir, /* readdir */ - NULL, /* poll - default */ - UMSDOS_ioctl_dir, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* fsync */ /* in original NULL. changed to file_fsync. FIXME? /mn/ */ +static struct file_operations umsdos_dir_operations = +{ + NULL, /* lseek - default */ + UMSDOS_dir_read, /* read */ + NULL, /* write - bad */ + UMSDOS_readdir, /* readdir */ + NULL, /* poll - default */ + UMSDOS_ioctl_dir, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync *//* in original NULL. changed to file_fsync. FIXME? /mn/ */ }; -struct inode_operations umsdos_dir_inode_operations = { +struct inode_operations umsdos_dir_inode_operations = +{ &umsdos_dir_operations, /* default directory file-ops */ UMSDOS_create, /* create */ UMSDOS_lookup, /* lookup */ @@ -955,22 +1039,14 @@ struct inode_operations umsdos_dir_inode_operations = { UMSDOS_mknod, /* mknod */ UMSDOS_rename, /* rename */ NULL, /* readlink */ - NULL, /* followlink */ - generic_readpage, /* readpage */ /* in original NULL. changed to generic_readpage. FIXME? /mn/ */ + NULL, /* followlink */ + generic_readpage, /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */ NULL, /* writepage */ - fat_bmap, /* bmap */ /* in original NULL. changed to fat_bmap. FIXME? /mn/ */ + fat_bmap, /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* updatepage */ NULL, /* revalidate */ - -}; - - - - - - - +}; diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 6cb630b1c..bf52a4d96 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -24,200 +24,118 @@ #define Printk(x) printk x /* - * makes empty filp - * + * Read a file into kernel space memory + * returns how many bytes read (from fat_file_read) */ - -void fill_new_filp (struct file *filp, struct dentry *dentry) -{ - Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp)); - if (dentry) - Printk ((" dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); - else - Printk ((" dentry is NULL ! you must fill it later...\n")); - - memset (filp, 0, sizeof (struct file)); - - filp->f_pos = 0; - filp->f_reada = 1; - filp->f_flags = O_RDWR; - filp->f_dentry = dentry; - filp->f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with SOMETHING */ -} - -/* - * 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, struct dentry *parent) +ssize_t umsdos_file_read_kmem ( struct inode *emd_dir, + struct file *filp, + char *buf, + size_t count, + loff_t *offs) { -/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */ - - struct dentry *ret; - struct qstr qname; - - if (inode) - Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); - else - Printk ((KERN_DEBUG "/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 = NULL; - - if (inode) d_add (ret, inode); - - return ret; -} - + int ret; -/* - * removes temporary dentry created by creat_dentry - * - */ - -void kill_dentry (struct dentry *dentry) -{ - if (dentry) { - Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name)); - if (dentry->d_inode) - Printk (("inode=%lu\n", dentry->d_inode->i_ino)); - else - Printk (("inode is NULL\n")); - - /* FIXME: is this ok ?! /mn/ */ - /* d_invalidate (dentry); */ - /*dput (dentry);*/ - } else { - Printk (("/mn/ kill_dentry: dentry is NULL ?!\n")); - } - - - Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n")); - return; -} + 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, NULL); + *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)); + + MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2; + 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/ */ + + d_drop (filp->f_dentry); /* FIXME: hmmmm... we should not dispose of it in this way ? */ + 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 original 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)); -/* - * Read a file into kernel space memory - * returns how many bytes read (from fat_file_read) - */ +#if 0 + { + struct umsdos_dirent *mydirent = buf; -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, NULL); - *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)); - - MSDOS_I(filp->f_dentry->d_inode)->i_binary=2; - 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)); + 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 -#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; + set_fs (old_fs); + return ret; } /* - * Write to file from kernel space. - * Does the real job, assumes all structures are initialized ! + * Write to file from kernel space. + * Does the real job, assumes all structures are initialized ! */ - -ssize_t umsdos_file_write_kmem_real (struct file *filp, - const char *buf, - size_t count, - loff_t *offs) + +ssize_t umsdos_file_write_kmem_real (struct file * filp, + const char *buf, + size_t count, + loff_t * offs) { ssize_t ret; - mm_segment_t old_fs = get_fs(); - + mm_segment_t old_fs = get_fs (); + set_fs (KERNEL_DS); - Printk ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); - Printk ((KERN_DEBUG " struct dentry=%p\n", filp->f_dentry)); - Printk ((KERN_DEBUG " struct inode=%p\n", filp->f_dentry->d_inode)); - 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)); + PRINTK ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + PRINTK ((KERN_DEBUG " struct dentry=%p\n", filp->f_dentry)); + PRINTK ((KERN_DEBUG " struct inode=%p\n", filp->f_dentry->d_inode)); + 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)); /* note: i_binary=2 is for CVF-FAT. We put it here, instead of - umsdos_file_write_kmem, since it is also wise not to compress symlinks - (in unlikely event that they are > 512 bytes and can be compressed - FIXME: should we set it when reading symlink too ? */ + * umsdos_file_write_kmem, since it is also wise not to compress symlinks + * (in unlikely event that they are > 512 bytes and can be compressed + * FIXME: should we set it when reading symlink too ? */ + + MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2; - MSDOS_I(filp->f_dentry->d_inode)->i_binary=2; - ret = fat_file_write (filp, buf, count, offs); PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret)); @@ -227,32 +145,32 @@ ssize_t umsdos_file_write_kmem_real (struct file *filp, /* - * Write to a file from kernel space + * Write to a file from kernel space */ - -ssize_t umsdos_file_write_kmem (struct inode *emd_dir, - struct file *filp, + +ssize_t umsdos_file_write_kmem (struct inode * emd_dir, + struct file * filp, const char *buf, - size_t count, - loff_t *offs - ) + size_t count, + loff_t * offs) { int ret; struct dentry *old_dentry; - + Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n")); - Printk ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino)); - old_dentry=filp->f_dentry; /* save it */ + old_dentry = filp->f_dentry; /* save it */ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL); *offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */ - ret=umsdos_file_write_kmem_real (filp, buf, count, offs); + ret = umsdos_file_write_kmem_real (filp, buf, count, offs); + d_drop (filp->f_dentry); filp->f_pos = *offs; - filp->f_dentry=old_dentry; + filp->f_dentry = old_dentry; return ret; } @@ -261,26 +179,27 @@ ssize_t umsdos_file_write_kmem (struct inode *emd_dir, /* - Write a block of bytes into one EMD file. - The block of data is NOT in user space. - - Return 0 if ok, a negative error code if not. -*/ -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 - ) + * Write a block of bytes into one EMD file. + * The block of data is NOT in user space. + * + * Return 0 if ok, a negative error code if not. + */ + +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; - + loff_t myofs = 0; + #ifdef __BIG_ENDIAN - struct umsdos_dirent *d = (struct umsdos_dirent *)buf; + struct umsdos_dirent *d = (struct umsdos_dirent *) buf; + #endif filp->f_flags = 0; -#ifdef __BIG_ENDIAN +#ifdef __BIG_ENDIAN d->nlink = cpu_to_le16 (d->nlink); d->uid = cpu_to_le16 (d->uid); d->gid = cpu_to_le16 (d->gid); @@ -289,15 +208,17 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, d->ctime = cpu_to_le32 (d->ctime); d->rdev = cpu_to_le16 (d->rdev); d->mode = cpu_to_le16 (d->mode); -#endif - - if (offs) myofs=*offs; /* if offs is not NULL, read it */ +#endif + + if (offs) + myofs = *offs; /* if offs is not NULL, read it */ Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %d, %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 + 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); d->gid = le16_to_cpu (d->gid); @@ -306,12 +227,12 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, d->ctime = le32_to_cpu (d->ctime); d->rdev = le16_to_cpu (d->rdev); d->mode = le16_to_cpu (d->mode); -#endif - -#ifdef 1 - if (written != count) Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count)); #endif +#if 1 + if (written != count) + Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count)); +#endif return written != count ? -EIO : 0; } @@ -319,36 +240,36 @@ ssize_t umsdos_emd_dir_write (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. + * 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 */ - size_t count, - loff_t *offs - ) + +ssize_t umsdos_emd_dir_read (struct inode * emd_dir, + struct file * filp, + char *buf, /* buffer in kernel memory, not in user space */ + size_t count, + loff_t * offs) { - loff_t myofs=0; + loff_t myofs = 0; long int ret = 0; int sizeread; - - + + #ifdef __BIG_ENDIAN - struct umsdos_dirent *d = (struct umsdos_dirent *)buf; + struct umsdos_dirent *d = (struct umsdos_dirent *) buf; + #endif - if (offs) myofs=*offs; /* if offs is not NULL, read it */ + 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, &myofs); - if (sizeread != count){ - printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n" - ,filp->f_pos,sizeread,count); + if (sizeread != count) { + printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n", filp->f_pos, sizeread, count); ret = -EIO; } -#ifdef __BIG_ENDIAN +#ifdef __BIG_ENDIAN d->nlink = le16_to_cpu (d->nlink); d->uid = le16_to_cpu (d->uid); d->gid = le16_to_cpu (d->gid); @@ -357,8 +278,9 @@ ssize_t umsdos_emd_dir_read (struct inode *emd_dir, d->ctime = le32_to_cpu (d->ctime); 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 */ +#endif + if (offs) + *offs = myofs; /* if offs is not NULL, store myofs there */ return ret; } @@ -367,92 +289,95 @@ ssize_t umsdos_emd_dir_read (struct inode *emd_dir, /* - Locate the EMD file in a directory . + * Locate the EMD file in a directory . + * + * Return NULL if error. If ok, dir->u.umsdos_i.emd_inode + */ - 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; + 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? not fixed? ")); + Printk (("avant create ")); + inc_count (dir); + + check_inode (ret); + code = compat_msdos_create (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_IFREG | 0777, &ret); + check_inode (ret); + Printk (("Creat EMD code %d ret %p ", code, ret)); + if (ret != NULL) { + Printk ((" ino=%lu", ret->i_ino)); + 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; +#if 1 + Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); + if (ret != NULL) + Printk ((KERN_DEBUG " returning ino=%lu\n", ret->i_ino)); +#endif + return ret; } -/* - creates an EMD file - Return NULL if error. If ok, dir->u.umsdos_i.emd_inode -*/ -struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int mode) +/* + * creates an EMD file + * + * Return NULL if error. If ok, dir->u.umsdos_i.emd_inode + */ + +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); + + if (dir->u.umsdos_i.i_emd_dir != 0) { + ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir); Printk (("deja trouve %lu %p", dir->u.umsdos_i.i_emd_dir, ret)); - }else{ - - 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"); - } + } else { + + int code; + + Printk (("avant create ")); + inc_count (dir); + 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; + if (ret != NULL) { + /* Disable UMSDOS_notify_change() for EMD file */ + ret->u.umsdos_i.i_emd_owner = 0xffffffff; } return ret; } @@ -460,28 +385,29 @@ struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int /* - Read an entry from the EMD file. - Support variable length record. - Return -EIO if error, 0 if ok. -*/ + * Read an entry from the EMD file. + * Support variable length record. + * Return -EIO if error, 0 if ok. + */ + int umsdos_emd_dir_readentry ( - struct inode *emd_dir, - struct file *filp, - struct umsdos_dirent *entry) + struct inode *emd_dir, + struct file *filp, + struct umsdos_dirent *entry) { 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... */ + + ret = umsdos_emd_dir_read (emd_dir, filp, (char *) entry, UMSDOS_REC_SIZE, NULL); + if (ret == 0) { /* note /mn/: is this wrong? ret is always 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,NULL); - + + 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, NULL); } } Printk (("umsdos_emd_dir_readentry /mn/: returning %d.\n", ret)); @@ -492,61 +418,62 @@ int umsdos_emd_dir_readentry ( /* - Write an entry in the EMD file. - Return 0 if ok, -EIO if some error. -*/ + * Write an entry in the EMD file. + * Return 0 if ok, -EIO if some error. + */ + int umsdos_writeentry ( - struct inode *dir, - struct inode *emd_dir, - struct umsdos_info *info, - int free_entry) /* This entry is deleted, so Write all 0's */ -{ + struct inode *dir, + struct inode *emd_dir, + struct umsdos_info *info, + 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; - fill_new_filp (&filp, NULL); + fill_new_filp (&filp, NULL); Printk (("umsdos_writeentry /mn/: entering...\n")); - emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir, NULL); - - if (free_entry){ + emd_dentry = creat_dentry ("wremd_mn", 8, emd_dir, NULL); + + if (free_entry) { /* #Specification: EMD file / empty entries - Unused entry in the EMD file are identify - by the name_len field equal to 0. However to - help future extension (or bug correction :-( ), - empty entries are filled with 0. - */ - memset (&entry0,0,sizeof(entry0)); + * Unused entry in the EMD file are identify + * by the name_len field equal to 0. However to + * help future extension (or bug correction :-( ), + * empty entries are filled with 0. + */ + memset (&entry0, 0, sizeof (entry0)); entry = &entry0; - }else if (entry->name_len > 0){ - memset (entry->name+entry->name_len,'\0' - ,sizeof(entry->name)-entry->name_len); + } else if (entry->name_len > 0) { + memset (entry->name + entry->name_len, '\0', sizeof (entry->name) - entry->name_len); /* #Specification: EMD file / spare bytes - 10 bytes are unused in each record of the EMD. They - are set to 0 all the time. So it will be possible - to do new stuff and rely on the state of those - bytes in old EMD file around. - */ - memset (entry->spare,0,sizeof(entry->spare)); + * 10 bytes are unused in each record of the EMD. They + * are set to 0 all the time. So it will be possible + * to do new stuff and rely on the state of those + * bytes in old EMD file around. + */ + 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"); + if (!info) + printk (KERN_ERR "umsdosfs: /mn/ info is empty ! ooops...\n"); filp.f_pos = info->f_pos; filp.f_reada = 0; 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); + 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 with %d!\n", ret)); - if (ret != 0){ + if (ret != 0) { printk ("UMSDOS: problem with EMD file. Can't write\n"); - }else{ + } else { dir->i_ctime = dir->i_mtime = CURRENT_TIME; /* dir->i_dirt = 1; FIXME iput/dput ??? */ } @@ -558,10 +485,10 @@ int umsdos_writeentry ( #define CHUNK_SIZE (8*UMSDOS_REC_SIZE) -struct find_buffer{ +struct find_buffer { char buffer[CHUNK_SIZE]; - int pos; /* read offset in buffer */ - int size; /* Current size of buffer */ + int pos; /* read offset in buffer */ + int size; /* Current size of buffer */ struct file filp; }; @@ -570,34 +497,36 @@ struct find_buffer{ /* - Fill the read buffer and take care of the byte remaining inside. - Unread bytes are simply move to the beginning. + * Fill the read buffer and take care of the byte remaining inside. + * Unread bytes are simply move to the beginning. + * + * Return -ENOENT if EOF, 0 if ok, a negative error code if any problem. + */ - Return -ENOENT if EOF, 0 if ok, a negative error code if any problem. -*/ static int umsdos_fillbuf ( - struct inode *inode, - struct find_buffer *buf) + struct inode *inode, + struct find_buffer *buf) { int ret = -ENOENT; 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); + + if (mustmove > 0) { + memcpy (buf->buffer, buf->buffer + buf->pos, mustmove); } buf->pos = 0; mustread = CHUNK_SIZE - mustmove; 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,NULL); - if (ret == 0) buf->size = mustmove + mustread; - }else if (mustmove){ + if (remain < mustread) + mustread = remain; + if (mustread > 0) { + 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; ret = 0; } @@ -607,61 +536,61 @@ static int umsdos_fillbuf ( /* - 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 - slot (of the proper size). - - Caller must do iput on *pt_emd_dir. - - Return 0 if found, -ENOENT if not found, another error code if - other problem. - - So this routine is used to either find an existing entry or to - create a new one, while making sure it is a new one. After you - get -ENOENT, you make sure the entry is stuffed correctly and - call umsdos_writeentry(). - - To delete an entry, you find it, zero out the entry (memset) - and call umsdos_writeentry(). + * 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 + * slot (of the proper size). + * + * Caller must do iput on *pt_emd_dir. + * + * Return 0 if found, -ENOENT if not found, another error code if + * other problem. + * + * So this routine is used to either find an existing entry or to + * create a new one, while making sure it is a new one. After you + * get -ENOENT, you make sure the entry is stuffed correctly and + * call umsdos_writeentry(). + * + * To delete an entry, you find it, zero out the entry (memset) + * and call umsdos_writeentry(). + * + * All this to say that umsdos_writeentry must be call after this + * function since it rely on the f_pos field of info. + */ - All this to say that umsdos_writeentry must be call after this - function since it rely on the f_pos field of info. -*/ static int umsdos_find ( - struct inode *dir, - struct umsdos_info *info, /* Hold name and name_len */ - /* Will hold the entry found */ - struct inode **pt_emd_dir) /* Will hold the emd_dir inode */ - /* or NULL if not found */ + struct inode *dir, + struct umsdos_info *info, /* Hold name and name_len */ + /* Will hold the entry found */ + struct inode **pt_emd_dir) /* Will hold the emd_dir inode or NULL if not found */ + { /* #Specification: EMD file structure - The EMD file uses a fairly simple layout. It is made of records - (UMSDOS_REC_SIZE == 64). When a name can't be written is a single - record, multiple contiguous record are allocated. - */ + * The EMD file uses a fairly simple layout. It is made of records + * (UMSDOS_REC_SIZE == 64). When a name can't be written is a single + * record, multiple contiguous record are allocated. + */ int ret = -ENOENT; struct inode *emd_dir; struct umsdos_dirent *entry = &info->entry; - + Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino)); - + emd_dir = umsdos_emd_dir_lookup (dir, 1); - if (emd_dir != NULL){ + if (emd_dir != NULL) { int recsize = info->recsize; struct { off_t posok; /* Position available to store the entry */ - int found; /* A valid empty position has been found */ - off_t one; /* One empty position -> maybe <- large enough */ + int found; /* A valid empty position has been found */ + off_t one; /* One empty position -> maybe <- large enough */ int onesize; /* size of empty region starting at one */ - }empty; + } empty; + /* Read several entries at a time to speed up the search */ struct find_buffer buf; struct dentry *dentry; - memset (&buf.filp, 0, sizeof (buf.filp)); - dentry = creat_dentry ("umsfind-mn", 10, emd_dir, NULL); - + fill_new_filp (&buf.filp, dentry); buf.pos = 0; @@ -670,218 +599,225 @@ static int umsdos_find ( empty.found = 0; empty.posok = emd_dir->i_size; empty.onesize = 0; - while (1){ - struct umsdos_dirent *rentry = (struct umsdos_dirent*) - (buf.buffer + buf.pos); + while (1) { + struct umsdos_dirent *rentry = (struct umsdos_dirent *) + (buf.buffer + buf.pos); int file_pos = buf.filp.f_pos - buf.size + buf.pos; - if (buf.pos == buf.size){ - ret = umsdos_fillbuf (emd_dir,&buf); - if (ret < 0){ + + if (buf.pos == buf.size) { + ret = umsdos_fillbuf (emd_dir, &buf); + if (ret < 0) { /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } - }else if (rentry->name_len == 0){ + } else if (rentry->name_len == 0) { /* We are looking for an empty section at least */ /* recsize large */ - if (entry->name_len == 0){ + if (entry->name_len == 0) { info->f_pos = file_pos; ret = 0; break; - }else if (!empty.found){ - if (empty.onesize == 0){ + } else if (!empty.found) { + if (empty.onesize == 0) { /* This is the first empty record of a section */ empty.one = file_pos; } /* grow the empty section */ empty.onesize += UMSDOS_REC_SIZE; - if (empty.onesize == recsize){ + if (empty.onesize == recsize) { /* here is a large enough section */ empty.posok = empty.one; empty.found = 1; } } buf.pos += UMSDOS_REC_SIZE; - }else{ - int entry_size = umsdos_evalrecsize(rentry->name_len); - if (buf.pos+entry_size > buf.size){ - ret = umsdos_fillbuf (emd_dir,&buf); - if (ret < 0){ + } else { + int entry_size = umsdos_evalrecsize (rentry->name_len); + + if (buf.pos + entry_size > buf.size) { + ret = umsdos_fillbuf (emd_dir, &buf); + if (ret < 0) { /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } - }else{ + } else { empty.onesize = 0; /* Reset the free slot search */ if (entry->name_len == rentry->name_len - && memcmp(entry->name,rentry->name,rentry->name_len) - ==0){ + && memcmp (entry->name, rentry->name, rentry->name_len) + == 0) { info->f_pos = file_pos; *entry = *rentry; ret = 0; break; - }else{ + } else { buf.pos += entry_size; } } - } + } } - umsdos_manglename(info); + umsdos_manglename (info); } *pt_emd_dir = emd_dir; - + Printk (("umsdos_find: returning %d\n", ret)); return ret; } + /* - Add a new entry in the emd file - Return 0 if ok or a negative error code. - Return -EEXIST if the entry already exist. + * Add a new entry in the emd file + * Return 0 if ok or a negative error code. + * Return -EEXIST if the entry already exist. + * + * Complete the information missing in info. + */ - Complete the information missing in info. -*/ int umsdos_newentry ( - struct inode *dir, - struct umsdos_info *info) + struct inode *dir, + struct umsdos_info *info) { struct inode *emd_dir; - int ret = umsdos_find (dir,info,&emd_dir); - if (ret == 0){ + int ret = umsdos_find (dir, info, &emd_dir); + + if (ret == 0) { ret = -EEXIST; - }else if (ret == -ENOENT){ - ret = umsdos_writeentry(dir,emd_dir,info,0); - Printk (("umsdos_newentry EMD ret = %d\n",ret)); + } else if (ret == -ENOENT) { + ret = umsdos_writeentry (dir, emd_dir, info, 0); + Printk (("umsdos_writeentry EMD ret = %d\n", ret)); } - /* iput (emd_dir); FIXME */ + iput (emd_dir); /* FIXME? */ return ret; } + /* - Create a new hidden link. - Return 0 if ok, an error code if not. -*/ + * Create a new hidden link. + * Return 0 if ok, an error code if not. + */ + int umsdos_newhidden ( - struct inode *dir, - struct umsdos_info *info) + struct inode *dir, + struct umsdos_info *info) { struct inode *emd_dir; int ret; - umsdos_parse ("..LINK",6,info); + + umsdos_parse ("..LINK", 6, info); info->entry.name_len = 0; - ret = umsdos_find (dir,info,&emd_dir); - /* iput (emd_dir); FIXME */ - if (ret == -ENOENT || ret == 0){ + ret = umsdos_find (dir, info, &emd_dir); + iput (emd_dir); /* FIXME? */ + if (ret == -ENOENT || ret == 0) { /* #Specification: hard link / hidden name - When a hard link is created, the original file is renamed - to a hidden name. The name is "..LINKNNN" where NNN is a - number define from the entry offset in the EMD file. - */ - info->entry.name_len = sprintf (info->entry.name,"..LINK%ld" - ,info->f_pos); + * When a hard link is created, the original file is renamed + * to a hidden name. The name is "..LINKNNN" where NNN is a + * number define from the entry offset in the EMD file. + */ + info->entry.name_len = sprintf (info->entry.name, "..LINK%ld" + ,info->f_pos); ret = 0; } return ret; } /* - Remove an entry from the emd file - Return 0 if ok, a negative error code otherwise. + * Remove an entry from the emd file + * Return 0 if ok, a negative error code otherwise. + * + * Complete the information missing in info. + */ - Complete the information missing in info. -*/ int umsdos_delentry ( - struct inode *dir, - struct umsdos_info *info, - int isdir) + struct inode *dir, + struct umsdos_info *info, + int isdir) { struct inode *emd_dir; - int ret = umsdos_find (dir,info,&emd_dir); - if (ret == 0){ - if (info->entry.name_len != 0){ - if ((isdir != 0) != (S_ISDIR(info->entry.mode) != 0)){ - if (S_ISDIR(info->entry.mode)){ + int ret = umsdos_find (dir, info, &emd_dir); + + if (ret == 0) { + if (info->entry.name_len != 0) { + if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) { + if (S_ISDIR (info->entry.mode)) { ret = -EISDIR; - }else{ + } else { ret = -ENOTDIR; } - }else{ - ret = umsdos_writeentry(dir,emd_dir,info,1); + } else { + ret = umsdos_writeentry (dir, emd_dir, info, 1); } } } - /* iput(emd_dir); FIXME */ + iput(emd_dir); /* FIXME? */ return ret; } /* - Verify is a EMD directory is empty. - Return 0 if not empty - 1 if empty - 2 if empty, no EMD file. -*/ + * Verify is a EMD directory is empty. + * Return 0 if not empty + * 1 if empty + * 2 if empty, no EMD file. + */ + int umsdos_isempty (struct inode *dir) { struct dentry *dentry; - + int ret = 2; - struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0); + 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){ + if (emd_dir != NULL) { struct file filp; - fill_new_filp (&filp, NULL); - - /* Find an empty slot */ - memset (&filp, 0, sizeof (filp)); dentry = creat_dentry ("isempty-mn", 10, dir, NULL); - - filp.f_pos = 0; - filp.f_reada = 1; + fill_new_filp (&filp, dentry); 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){ + while (filp.f_pos < emd_dir->i_size) { struct umsdos_dirent entry; - if (umsdos_emd_dir_readentry(emd_dir,&filp,&entry)!=0){ + + if (umsdos_emd_dir_readentry (emd_dir, &filp, &entry) != 0) { ret = 0; break; - }else if (entry.name_len != 0){ + } else if (entry.name_len != 0) { ret = 0; break; - } + } } - /* iput (emd_dir); FIXME */ + iput (emd_dir); /* FIXME? */ } return ret; } /* - Locate an entry in a EMD directory. - Return 0 if ok, errcod if not, generally -ENOENT. -*/ + * Locate an entry in a EMD directory. + * Return 0 if ok, errcod if not, generally -ENOENT. + */ + int umsdos_findentry ( - struct inode *dir, - struct umsdos_info *info, - int expect) /* 0: anything */ - /* 1: file */ - /* 2: directory */ -{ + struct inode *dir, + struct umsdos_info *info, + int expect) +{ /* 0: anything */ + /* 1: file */ + /* 2: directory */ struct inode *emd_dir; - int ret = umsdos_find (dir,info,&emd_dir); - if (ret == 0){ - if (expect != 0){ - if (S_ISDIR(info->entry.mode)){ - if (expect != 2) ret = -EISDIR; - }else if (expect == 2){ + int ret = umsdos_find (dir, info, &emd_dir); + + if (ret == 0) { + if (expect != 0) { + if (S_ISDIR (info->entry.mode)) { + if (expect != 2) + ret = -EISDIR; + } else if (expect == 2) { ret = -ENOTDIR; } } } - /* iput (emd_dir); FIXME */ + iput (emd_dir); /* FIXME? */ Printk (("umsdos_findentry: returning %d\n", ret)); return ret; } - diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c index b7f58a2b9..a9267e122 100644 --- a/fs/umsdos/file.c +++ b/fs/umsdos/file.c @@ -2,7 +2,7 @@ * linux/fs/umsdos/file.c * * Written 1993 by Jacques Gelinas - * inspired from linux/fs/msdos/file.c Werner Almesberger + * inspired from linux/fs/msdos/file.c Werner Almesberger * * Extended MS-DOS regular file handling primitives */ @@ -24,71 +24,74 @@ /* - Read a file into user space memory -*/ -static ssize_t UMSDOS_file_read( - struct file *filp, - char *buf, - size_t count, - loff_t *ppos - ) + * Read a file into user space memory + */ +static ssize_t UMSDOS_file_read ( + struct file *filp, + char *buf, + size_t count, + loff_t * ppos +) { - struct dentry * dentry = filp->f_dentry; + struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - + /* We have to set the access time because msdos don't care */ /* FIXME */ - int ret = fat_file_read(filp,buf,count,ppos); - if (!IS_RDONLY(inode)){ + int ret = fat_file_read (filp, buf, count, ppos); + + if (!IS_RDONLY (inode)) { inode->i_atime = CURRENT_TIME; /* FIXME - inode->i_dirt = 1; - */ + * inode->i_dirt = 1; + */ } return ret; } /* - Write a file from user space memory -*/ -static ssize_t UMSDOS_file_write( - struct file *filp, - const char *buf, - size_t count, - loff_t *ppos) + * Write a file from user space memory + */ +static ssize_t UMSDOS_file_write ( + struct file *filp, + const char *buf, + size_t count, + loff_t * ppos) { - return fat_file_write(filp,buf,count,ppos); + return fat_file_write (filp, buf, count, ppos); } /* - Truncate a file to 0 length. -*/ -static void UMSDOS_truncate(struct inode *inode) + * Truncate a file to 0 length. + */ +static void UMSDOS_truncate (struct inode *inode) { Printk (("UMSDOS_truncate\n")); fat_truncate (inode); inode->i_ctime = inode->i_mtime = CURRENT_TIME; - - /*FIXME inode->i_dirt = 1; */ + + /*FIXME inode->i_dirt = 1; */ } /* Function for normal file system (512 bytes hardware sector size) */ -struct file_operations umsdos_file_operations = { - NULL, /* lseek - default */ +struct file_operations umsdos_file_operations = +{ + NULL, /* lseek - default */ UMSDOS_file_read, /* read */ UMSDOS_file_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll - default */ - NULL, /* ioctl - default */ - generic_file_mmap, /* mmap */ - NULL, /* no special open is needed */ - NULL, /* release */ - file_fsync /* fsync */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ }; -struct inode_operations umsdos_file_inode_operations = { +struct inode_operations umsdos_file_inode_operations = +{ &umsdos_file_operations, /* default file operations */ NULL, /* create */ NULL, /* lookup */ @@ -110,20 +113,22 @@ struct inode_operations umsdos_file_inode_operations = { }; /* For other with larger and unaligned file system */ -struct file_operations umsdos_file_operations_no_bmap = { - NULL, /* lseek - default */ - UMSDOS_file_read, /* read */ - UMSDOS_file_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll - default */ - NULL, /* ioctl - default */ - fat_mmap, /* mmap */ - NULL, /* no special open is needed */ - NULL, /* release */ - file_fsync /* fsync */ +struct file_operations umsdos_file_operations_no_bmap = +{ + NULL, /* lseek - default */ + UMSDOS_file_read, /* read */ + UMSDOS_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + fat_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ }; -struct inode_operations umsdos_file_inode_operations_no_bmap = { +struct inode_operations umsdos_file_inode_operations_no_bmap = +{ &umsdos_file_operations_no_bmap, /* default file operations */ NULL, /* create */ NULL, /* lookup */ @@ -135,7 +140,7 @@ struct inode_operations umsdos_file_inode_operations_no_bmap = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow link */ + NULL, /* follow link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -145,20 +150,22 @@ struct inode_operations umsdos_file_inode_operations_no_bmap = { }; /* For other with larger and unaligned file system with readpage */ -struct file_operations umsdos_file_operations_readpage = { - NULL, /* lseek - default */ - UMSDOS_file_read, /* read */ - UMSDOS_file_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll - default */ - NULL, /* ioctl - default */ - generic_file_mmap, /* mmap */ - NULL, /* no special open is needed */ - NULL, /* release */ - file_fsync /* fsync */ +struct file_operations umsdos_file_operations_readpage = +{ + NULL, /* lseek - default */ + UMSDOS_file_read, /* read */ + UMSDOS_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ }; -struct inode_operations umsdos_file_inode_operations_readpage = { +struct inode_operations umsdos_file_inode_operations_readpage = +{ &umsdos_file_operations_readpage, /* default file operations */ NULL, /* create */ NULL, /* lookup */ @@ -170,7 +177,7 @@ struct inode_operations umsdos_file_inode_operations_readpage = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow link */ + NULL, /* follow link */ fat_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -178,4 +185,3 @@ struct inode_operations umsdos_file_inode_operations_readpage = { NULL, /* permission */ NULL, /* smap */ }; - diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 0238a5bd1..4bf2a65ce 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -1,8 +1,8 @@ /* * linux/fs/umsdos/inode.c * - * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... by Werner Almesberger + * Written 1993 by Jacques Gelinas + * Inspired from linux/fs/msdos/... by Werner Almesberger * */ @@ -18,122 +18,348 @@ #include <linux/string.h> #include <linux/stat.h> #include <linux/umsdos_fs.h> +#include <linux/list.h> -struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */ - /* directory. See UMSDOS_readdir_x() */ +extern struct inode_operations umsdos_rdir_inode_operations; + + +struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */ + + /* directory. See UMSDOS_readdir_x() */ /* #Specification: convention / PRINTK Printk and printk - Here is the convention for the use of printk inside fs/umsdos - - printk carry important message (error or status). - Printk is for debugging (it is a macro defined at the beginning of - most source. - PRINTK is a nulled Printk macro. - - This convention makes the source easier to read, and Printk easier - to shut off. -*/ + * Here is the convention for the use of printk inside fs/umsdos + * + * printk carry important message (error or status). + * Printk is for debugging (it is a macro defined at the beginning of + * most source. + * PRINTK is a nulled Printk macro. + * + * This convention makes the source easier to read, and Printk easier + * to shut off. + */ #define PRINTK(x) #define Printk(x) printk x -void UMSDOS_put_inode(struct inode *inode) + + + +/* + * makes return inode->i_dentry + * + */ + +inline struct dentry *geti_dentry (struct inode *inode) { - PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu\n", inode, inode->i_ino - ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos - ,inode->u.umsdos_i.i_emd_dir)); - if (inode && pseudo_root && inode == pseudo_root){ - printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n"); - } - -#if 1 - fat_put_inode(inode); -#else - Printk ((KERN_WARNING "UMSDOS_put_inode: skipping ! FIXME /mn/\n")); -#endif + struct dentry *ret; + if (!inode) { + printk (KERN_ERR "geti_dentry: inode is NULL!\n"); + return NULL; + } + ret = list_entry (inode->i_dentry.next, struct dentry, d_alias); /* FIXME: does this really work ? :) */ + Printk ((KERN_DEBUG "geti_dentry : inode %lu: i_dentry is %p\n", inode->i_ino, ret)); + return ret; } +/* + * makes inode->i_count++ + * + */ -void UMSDOS_put_super(struct super_block *sb) +inline void inc_count (struct inode *inode) { - Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); - msdos_put_super(sb); - MOD_DEC_USE_COUNT; + inode->i_count++; + Printk ((KERN_DEBUG "inc_count: inode %lu incremented count to %d\n", inode->i_ino, inode->i_count)); } +/* + * makes empty filp + * + */ + +void fill_new_filp (struct file *filp, struct dentry *dentry) +{ + Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp)); + if (dentry) + Printk ((" dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); + else + Printk ((" dentry is NULL ! you must fill it later...\n")); + + memset (filp, 0, sizeof (struct file)); + + filp->f_pos = 0; + filp->f_reada = 1; + filp->f_flags = O_RDWR; + filp->f_dentry = dentry; + filp->f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with SOMETHING */ +} /* - Call msdos_lookup, but set back the original msdos function table. - Return 0 if ok, or a negative error code if not. -*/ -int umsdos_real_lookup ( - struct inode *dir, - struct dentry *dentry - ) /* Will hold inode of the file, if successful */ + * check a superblock + */ + +void check_sb (struct super_block *sb, const char c) +{ + if (sb) { + Printk ((" (has %c_sb=%d, %d)", c, MAJOR (sb->s_dev), MINOR (sb->s_dev))); + } else { + Printk ((" (%c_sb is NULL)", c)); + } +} + +/* + * check an inode + */ + +void check_inode (struct inode *inode) +{ + if (inode) { + Printk ((KERN_DEBUG "* inode is %lu (i_count=%d)", inode->i_ino, inode->i_count)); + check_sb (inode->i_sb, 'i'); + + if (inode->i_dentry.next) { /* FIXME: does this work ? */ + Printk ((" (has i_dentry)")); + } else { + Printk ((" (NO i_dentry)")); + } + + if (inode->i_op == NULL) { + Printk ((" (i_op is NULL)\n")); + } else if (inode->i_op == &umsdos_dir_inode_operations) { + Printk ((" (i_op is umsdos_dir_inode_operations)\n")); + } else if (inode->i_op == &umsdos_file_inode_operations) { + Printk ((" (i_op is umsdos_file_inode_operations)\n")); + } else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) { + Printk ((" (i_op is umsdos_file_inode_operations_no_bmap)\n")); + } else if (inode->i_op == &umsdos_file_inode_operations_readpage) { + Printk ((" (i_op is umsdos_file_inode_operations_readpage)\n")); + } else if (inode->i_op == &umsdos_rdir_inode_operations) { + Printk ((" (i_op is umsdos_rdir_inode_operations)\n")); + } else if (inode->i_op == &umsdos_symlink_inode_operations) { + Printk ((" (i_op is umsdos_symlink_inode_operations)\n")); + } else { + Printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op)); + } + } else { + Printk ((KERN_DEBUG "* inode is NULL\n")); + } +} + + +/* + * internal part of check_dentry. does the real job. + * + */ + +void check_dent_int (struct dentry *dentry, int parent) +{ + if (parent) { + Printk ((KERN_DEBUG "* parent dentry: %.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); + } else { + Printk ((KERN_DEBUG "\n*** checking dentry: %.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); + } + check_inode (dentry->d_inode); + Printk ((KERN_DEBUG "* d_count=%d", dentry->d_count)); + check_sb (dentry->d_sb, 'd'); + if (dentry->d_op == NULL) { + Printk ((" (d_op is NULL)\n")); + } else { + Printk ((" (d_op is UNKNOWN: %p)\n", dentry->d_op)); + } +} + +/* + * checks dentry and prints info + * + */ + +void check_dentry (struct dentry *dentry) { - int ret; - - PRINTK ((KERN_DEBUG "umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name)); - dir->i_count++; /* /mn/ what is this and why ? locking? */ - ret = msdos_lookup (dir,dentry); - PRINTK (("/ returned %d\n", ret)); - - return ret; + if (!dentry) { + Printk ((KERN_DEBUG "\n*** checking dentry... it is NULL !\n")); + return; + } + check_dent_int (dentry, 0); + + if (dentry->d_parent) { + check_dent_int (dentry->d_parent, 1); + } else { + Printk ((KERN_DEBUG "* has no parent.\n")); + } + + Printk ((KERN_DEBUG "*** end checking dentry\n")); } + /* - Complete the setup of an directory inode. - First, it completes the function pointers, then - it locates the EMD file. If the EMD is there, then plug the - umsdos function table. If not, use the msdos one. -*/ + * 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, struct dentry *parent) +{ +/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */ + + struct dentry *ret; + struct qstr qname; + + if (inode) + Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); + else + Printk ((KERN_DEBUG "/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 = NULL; + + if (!parent) { + ret->d_parent = ret; + Printk ((KERN_WARNING "creat_dentry: WARNING: NO parent! faking! beware !\n")); + } + + + if (inode) { + ret->d_sb = inode->i_sb; /* try to fill it in if avalaible. If avalaible in parent->d_sb, d_alloc will add it automatically */ + d_add (ret, inode); + } + + return ret; +} + + +/* + * removes temporary dentry created by creat_dentry + * + */ + +void kill_dentry (struct dentry *dentry) +{ + if (dentry) { + Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name)); + if (dentry->d_inode) + Printk (("inode=%lu (i_count=%d)\n", dentry->d_inode->i_ino, dentry->d_inode->i_count)); + else + Printk (("inode is NULL\n")); + + /* FIXME: is this ok ?! /mn/ */ + /* d_drop (dentry); */ + /* d_invalidate (dentry); */ + /*dput (dentry); */ + /*d_delete (dentry) */ + } else { + Printk (("/mn/ kill_dentry: dentry is NULL ?!\n")); + } + + + Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n")); + return; +} + + + + + + +void UMSDOS_put_inode (struct inode *inode) +{ + PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n", inode, inode->i_ino + ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos + ,inode->u.umsdos_i.i_emd_dir, inode->i_count)); + + if (inode && pseudo_root && inode == pseudo_root) { + printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n"); + } + + fat_put_inode (inode); +} + + +void UMSDOS_put_super (struct super_block *sb) +{ + Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); + msdos_put_super (sb); + MOD_DEC_USE_COUNT; +} + + + +/* + * Call msdos_lookup, but set back the original msdos function table. + * Return 0 if ok, or a negative error code if not. + */ +int umsdos_real_lookup ( + struct inode *dir, + struct dentry *dentry +) +{ /* Will hold inode of the file, if successful */ + int ret; + + PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %s /", dentry->d_name.name)); + inc_count (dir); /* should be here ? Causes all kind of missing iput()'s all around, but panics w/o it /mn/ */ + ret = msdos_lookup (dir, dentry); + PRINTK (("/ returned %d\n", ret)); + + return ret; +} + +/* + * Complete the setup of an directory inode. + * First, it completes the function pointers, then + * it locates the EMD file. If the EMD is there, then plug the + * umsdos function table. If not, use the msdos one. + */ void umsdos_setup_dir_inode (struct inode *inode) { - inode->u.umsdos_i.i_emd_dir = 0; - { - struct inode *emd_dir = NULL; - extern struct inode_operations umsdos_rdir_inode_operations; - - emd_dir = umsdos_emd_dir_lookup (inode,0); - Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir)); - - if (emd_dir == NULL) { - Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n")); - inode->i_op = &umsdos_rdir_inode_operations; - } else { - Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n")); - inode->i_op = &umsdos_dir_inode_operations; - } - -/* iput (emd_dir); FIXME /mn/ ! */ - } + inode->u.umsdos_i.i_emd_dir = 0; + { + struct inode *emd_dir; + + emd_dir = umsdos_emd_dir_lookup (inode, 0); + Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n", inode, emd_dir)); + + if (emd_dir == NULL) { + Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. NOT using EMD.\n")); + inode->i_op = &umsdos_rdir_inode_operations; + } else { + Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. using EMD.\n")); + inode->i_op = &umsdos_dir_inode_operations; + } + + iput (emd_dir); /* FIXME? OK? */ + } } /* - Add some info into an inode so it can find its owner quickly -*/ -void umsdos_set_dirinfo( - struct inode *inode, - struct inode *dir, - off_t f_pos) + * Add some info into an inode so it can find its owner quickly + */ +void umsdos_set_dirinfo ( + struct inode *inode, + struct inode *dir, + off_t f_pos) { - struct inode *emd_owner; - /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */ -/* Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino));*/ - emd_owner = umsdos_emd_dir_lookup(dir,1); - Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino)); - inode->u.umsdos_i.i_dir_owner = dir->i_ino; - inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; - /* iput (emd_owner); FIXME */ - inode->u.umsdos_i.pos = f_pos; + struct inode *emd_owner; + + /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */ +/* Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino)); */ + emd_owner = umsdos_emd_dir_lookup (dir, 1); + Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino)); + inode->u.umsdos_i.i_dir_owner = dir->i_ino; + inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; + iput (emd_owner); /* FIXME? */ + inode->u.umsdos_i.pos = f_pos; } /* - Tells if an Umsdos inode has been "patched" once. - Return != 0 if so. -*/ + * Tells if an Umsdos inode has been "patched" once. + * Return != 0 if so. + */ int umsdos_isinit (struct inode *inode) { #if 1 @@ -141,125 +367,129 @@ int umsdos_isinit (struct inode *inode) #elif 0 return inode->i_atime != 0; #else - return atomic_read(&inode->i_count) > 1; + return atomic_read (&inode->i_count) > 1; #endif } /* - Connect the proper tables in the inode and add some info. -*/ + * Connect the proper tables in the inode and add some info. + */ void umsdos_patch_inode ( - struct inode *inode, - struct inode *dir, /* May be NULL */ - off_t f_pos) + struct inode *inode, + struct inode *dir, /* May be NULL */ + off_t f_pos) { - /* - This function is called very early to setup the inode, somewhat - too early (called by UMSDOS_read_inode). At this point, we can't - do to much, such as lookup up EMD files and so on. This causes - confusion in the kernel. This is why some initialisation - will be done when dir != NULL only. - - UMSDOS do run piggy back on top of msdos fs. It looks like something - is missing in the VFS to accommodate stacked fs. Still unclear what - (quite honestly). - - Well, maybe one! A new entry "may_unmount" which would allow - the stacked fs to allocate some inode permanently and release - them at the end. Doing that now introduce a problem. unmount - always fail because some inodes are in use. - */ - - Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino)); - - if (!umsdos_isinit(inode)){ - inode->u.umsdos_i.i_emd_dir = 0; - if (S_ISREG(inode->i_mode)){ - if (MSDOS_SB(inode->i_sb)->cvf_format){ - if (MSDOS_SB(inode->i_sb)->cvf_format->flags&CVF_USE_READPAGE){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n")); - inode->i_op = &umsdos_file_inode_operations_readpage; - }else{ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); - inode->i_op = &umsdos_file_inode_operations_no_bmap; - } - }else{ - if (inode->i_op->bmap != NULL){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); - inode->i_op = &umsdos_file_inode_operations; - }else{ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); - inode->i_op = &umsdos_file_inode_operations_no_bmap; - } - } - }else if (S_ISDIR(inode->i_mode)){ - if (dir != NULL){ - umsdos_setup_dir_inode(inode); - } - }else if (S_ISLNK(inode->i_mode)){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n")); - inode->i_op = &umsdos_symlink_inode_operations; - }else if (S_ISCHR(inode->i_mode)){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n")); - inode->i_op = &chrdev_inode_operations; - }else if (S_ISBLK(inode->i_mode)){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n")); - inode->i_op = &blkdev_inode_operations; - }else if (S_ISFIFO(inode->i_mode)){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n")); - init_fifo(inode); - } - if (dir != NULL){ - /* #Specification: inode / umsdos info - The first time an inode is seen (inode->i_count == 1), - the inode number of the EMD file which control this inode - is tagged to this inode. It allows operation such - as notify_change to be handled. - */ - /* - This is done last because it also control the - status of umsdos_isinit() - */ - PRINTK ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos)); - umsdos_set_dirinfo (inode,dir,f_pos); - } - }else if (dir != NULL){ - /* - Test to see if the info is maintained. - This should be removed when the file system will be proven. - */ - /* FIXME, again, not a clue */ - struct inode *emd_owner; - Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); - emd_owner = umsdos_emd_dir_lookup(dir,1); - /* iput (emd_owner); FIXME */ - if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){ - printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld " - ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner); - } - } + /* + * This function is called very early to setup the inode, somewhat + * too early (called by UMSDOS_read_inode). At this point, we can't + * do to much, such as lookup up EMD files and so on. This causes + * confusion in the kernel. This is why some initialisation + * will be done when dir != NULL only. + * + * UMSDOS do run piggy back on top of msdos fs. It looks like something + * is missing in the VFS to accommodate stacked fs. Still unclear what + * (quite honestly). + * + * Well, maybe one! A new entry "may_unmount" which would allow + * the stacked fs to allocate some inode permanently and release + * them at the end. Doing that now introduce a problem. unmount + * always fail because some inodes are in use. + */ + + Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino)); + + if (!umsdos_isinit (inode)) { + inode->u.umsdos_i.i_emd_dir = 0; + if (S_ISREG (inode->i_mode)) { + if (MSDOS_SB (inode->i_sb)->cvf_format) { + if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n")); + inode->i_op = &umsdos_file_inode_operations_readpage; + } else { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + inode->i_op = &umsdos_file_inode_operations_no_bmap; + } + } else { + if (inode->i_op->bmap != NULL) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); + inode->i_op = &umsdos_file_inode_operations; + } else { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + inode->i_op = &umsdos_file_inode_operations_no_bmap; + } + } + } else if (S_ISDIR (inode->i_mode)) { + if (dir != NULL) { + umsdos_setup_dir_inode (inode); + } + } else if (S_ISLNK (inode->i_mode)) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n")); + inode->i_op = &umsdos_symlink_inode_operations; + } else if (S_ISCHR (inode->i_mode)) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n")); + inode->i_op = &chrdev_inode_operations; + } else if (S_ISBLK (inode->i_mode)) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n")); + inode->i_op = &blkdev_inode_operations; + } else if (S_ISFIFO (inode->i_mode)) { + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n")); + init_fifo (inode); + } + if (dir != NULL) { + /* #Specification: inode / umsdos info + * The first time an inode is seen (inode->i_count == 1), + * the inode number of the EMD file which control this inode + * is tagged to this inode. It allows operation such + * as notify_change to be handled. + */ + /* + * This is done last because it also control the + * status of umsdos_isinit() + */ + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos)); + umsdos_set_dirinfo (inode, dir, f_pos); + } + } else if (dir != NULL) { + /* + * Test to see if the info is maintained. + * This should be removed when the file system will be proven. + */ + /* FIXME, again, not a clue */ + struct inode *emd_owner; + + Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); + emd_owner = umsdos_emd_dir_lookup (dir, 1); + iput (emd_owner); /* FIXME? */ + if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner) { + printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld " + ,inode->i_ino, emd_owner->i_ino, inode->u.umsdos_i.i_emd_owner); + } + } } /* - Get the inode of the directory which owns this inode. - Return 0 if ok, -EIO if error. -*/ -int umsdos_get_dirowner( - struct inode *inode, - struct inode **result) /* Hold NULL if any error */ - /* else, the inode of the directory */ -{ + * Get the inode of the directory which owns this inode. + * Return 0 if ok, -EIO if error. + */ +int umsdos_get_dirowner ( + struct inode *inode, + struct inode **result) +{ /* Hold NULL if any error */ + /* else, the inode of the directory */ int ret = -EIO; unsigned long ino = inode->u.umsdos_i.i_dir_owner; + *result = NULL; - if (ino == 0){ + if (ino == 0) { printk ("UMSDOS: umsdos_get_dirowner ino == 0\n"); - }else{ - struct inode *dir = *result = iget(inode->i_sb,ino); - if (dir != NULL){ - umsdos_patch_inode (dir,NULL,0); + } else { + struct inode *dir = *result = iget (inode->i_sb, ino); + + if (dir != NULL) { + umsdos_patch_inode (dir, NULL, 0); + /* iput (dir); / * FIXME: /mn/ added this. Is it ok ? */ ret = 0; } } @@ -269,366 +499,369 @@ int umsdos_get_dirowner( /* - Load an inode from disk. -*/ -void UMSDOS_read_inode(struct inode *inode) + * Load an inode from disk. + */ +void UMSDOS_read_inode (struct inode *inode) { - PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",inode,inode->i_ino)); - msdos_read_inode(inode); - PRINTK (("ino after msdos_read_inode= %lu\n",inode->i_ino)); - if (S_ISDIR(inode->i_mode) - && (inode->u.umsdos_i.u.dir_info.creating != 0 - || inode->u.umsdos_i.u.dir_info.looking != 0 - || waitqueue_active(&inode->u.umsdos_i.u.dir_info.p))){ - PRINTK (("read inode %d %d %p\n" - ,inode->u.umsdos_i.u.dir_info.creating - ,inode->u.umsdos_i.u.dir_info.looking - ,inode->u.umsdos_i.u.dir_info.p)); + Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", inode, inode->i_ino)); + msdos_read_inode (inode); + Printk (("ino after msdos_read_inode= %lu i_count=%d\n", inode->i_ino, inode->i_count)); + if (S_ISDIR (inode->i_mode) + && (inode->u.umsdos_i.u.dir_info.creating != 0 + || inode->u.umsdos_i.u.dir_info.looking != 0 + || waitqueue_active (&inode->u.umsdos_i.u.dir_info.p))) { + Printk (("read inode %d %d %p\n" + ,inode->u.umsdos_i.u.dir_info.creating + ,inode->u.umsdos_i.u.dir_info.looking + ,inode->u.umsdos_i.u.dir_info.p)); } /* #Specification: Inode / post initialisation - To completely initialise an inode, we need access to the owner - directory, so we can locate more info in the EMD file. This is - not available the first time the inode is access, we use - a value in the inode to tell if it has been finally initialised. - - At first, we have tried testing i_count but it was causing - problem. It is possible that two or more process use the - newly accessed inode. While the first one block during - the initialisation (probably while reading the EMD file), the - others believe all is well because i_count > 1. They go banana - with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode. - */ - umsdos_patch_inode(inode,NULL,0); + * To completely initialise an inode, we need access to the owner + * directory, so we can locate more info in the EMD file. This is + * not available the first time the inode is access, we use + * a value in the inode to tell if it has been finally initialised. + * + * At first, we have tried testing i_count but it was causing + * problem. It is possible that two or more process use the + * newly accessed inode. While the first one block during + * the initialisation (probably while reading the EMD file), the + * others believe all is well because i_count > 1. They go banana + * with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode. + */ + umsdos_patch_inode (inode, NULL, 0); +} + + +int internal_notify_change (struct inode *inode, struct iattr *attr) +{ + int ret = 0; + struct inode *root; + + PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n")); + + if ((ret = inode_change_ok (inode, attr)) != 0) + return ret; + + if (inode->i_nlink > 0) { + /* #Specification: notify_change / i_nlink > 0 + * notify change is only done for inode with nlink > 0. An inode + * with nlink == 0 is no longer associated with any entry in + * the EMD file, so there is nothing to update. + */ + unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; + + root = iget (inode->i_sb, UMSDOS_ROOT_INO); + if (inode == root) { + /* #Specification: root inode / attributes + * I don't know yet how this should work. Normally + * the attributes (permissions bits, owner, times) of + * a directory are stored in the EMD file of its parent. + * + * One thing we could do is store the attributes of the root + * inode in its own EMD file. A simple entry named "." could + * be used for this special case. It would be read once + * when the file system is mounted and update in + * UMSDOS_notify_change() (right here). + * + * I am not sure of the behavior of the root inode for + * a real UNIX file system. For now, this is a nop. + */ + } else if (i_emd_owner != 0xffffffff && i_emd_owner != 0) { + /* This inode is not a EMD file nor an inode used internally + * by MSDOS, so we can update its status. + * See emd.c + */ + struct inode *emd_owner; + + emd_owner = iget (inode->i_sb, i_emd_owner); + Printk (("notify change %p ", inode)); + if (emd_owner == NULL) { + printk ("UMSDOS: emd_owner = NULL ???"); + ret = -EPERM; + } else { + struct file filp; + struct umsdos_dirent entry; + struct dentry *emd_dentry; + loff_t offs; + + emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL); + fill_new_filp (&filp, emd_dentry); + + filp.f_pos = inode->u.umsdos_i.pos; + filp.f_reada = 0; + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ + Printk (("pos = %Lu ", filp.f_pos)); + /* Read only the start of the entry since we don't touch */ + /* the name */ + ret = umsdos_emd_dir_read (emd_owner, &filp, (char *) &entry, UMSDOS_REC_SIZE, &offs); + if (ret == 0) { + if (attr->ia_valid & ATTR_UID) + entry.uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + entry.gid = attr->ia_gid; + if (attr->ia_valid & ATTR_MODE) + entry.mode = attr->ia_mode; + if (attr->ia_valid & ATTR_ATIME) + entry.atime = attr->ia_atime; + if (attr->ia_valid & ATTR_MTIME) + entry.mtime = attr->ia_mtime; + if (attr->ia_valid & ATTR_CTIME) + entry.ctime = attr->ia_ctime; + + entry.nlink = inode->i_nlink; + filp.f_pos = inode->u.umsdos_i.pos; + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ + ret = umsdos_emd_dir_write (emd_owner, &filp, (char *) &entry, UMSDOS_REC_SIZE, &offs); + + Printk (("notify pos %lu ret %d nlink %d " + ,inode->u.umsdos_i.pos + ,ret, entry.nlink)); + /* #Specification: notify_change / msdos fs + * notify_change operation are done only on the + * EMD file. The msdos fs is not even called. + */ + } + iput (emd_owner); /* FIXME? /mn/ */ + } + Printk (("\n")); + } + iput (root); /* FIXME - /mn/ this is hopefully ok */ + } + if (ret == 0) + inode_setattr (inode, attr); + + return ret; } +int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) +{ + return internal_notify_change (dentry->d_inode, attr); +} + /* - Update the disk with the inode content -*/ -void UMSDOS_write_inode(struct inode *inode) + * Update the disk with the inode content + */ +void UMSDOS_write_inode (struct inode *inode) { struct iattr newattrs; - PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",inode->u.umsdos_i.i_emd_owner)); - fat_write_inode(inode); + PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n", inode->u.umsdos_i.i_emd_owner)); + fat_write_inode (inode); newattrs.ia_mtime = inode->i_mtime; newattrs.ia_atime = inode->i_atime; newattrs.ia_ctime = inode->i_ctime; newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME; /* - UMSDOS_notify_change is convenient to call here - to update the EMD entry associated with this inode. - But it has the side effect to re"dirt" the inode. - */ - /* FIXME, notify_change now takes a dentry, not an - inode so, the emd update needs to be done here - UMSDOS_notify_change (inode, &newattrs); - */ - - /* FIXME inode->i_dirt = 0; */ + * UMSDOS_notify_change is convenient to call here + * to update the EMD entry associated with this inode. + * But it has the side effect to re"dirt" the inode. + */ + +/* + * internal_notify_change (inode, &newattrs); + * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work... we need to remove ourselfs from list on dirty inodes /mn/ */ } -int internal_notify_change(struct inode *inode, struct iattr *attr) -{ - int ret = 0; - - PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n")); - - if ((ret = inode_change_ok(inode, attr)) != 0) - return ret; - - if (inode->i_nlink > 0){ - /* #Specification: notify_change / i_nlink > 0 - notify change is only done for inode with nlink > 0. An inode - with nlink == 0 is no longer associated with any entry in - the EMD file, so there is nothing to update. - */ - unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; - if (inode == iget(inode->i_sb,UMSDOS_ROOT_INO)){ - /* #Specification: root inode / attributes - I don't know yet how this should work. Normally - the attributes (permissions bits, owner, times) of - a directory are stored in the EMD file of its parent. - - One thing we could do is store the attributes of the root - inode in its own EMD file. A simple entry named "." could - be used for this special case. It would be read once - when the file system is mounted and update in - UMSDOS_notify_change() (right here). - - I am not sure of the behavior of the root inode for - a real UNIX file system. For now, this is a nop. - */ - }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){ - /* This inode is not a EMD file nor an inode used internally - by MSDOS, so we can update its status. - See emd.c - */ - struct inode *emd_owner = iget (inode->i_sb,i_emd_owner); - Printk (("notify change %p ",inode)); - if (emd_owner == NULL){ - printk ("UMSDOS: emd_owner = NULL ???"); - ret = -EPERM; - }else{ - struct file filp; - struct umsdos_dirent entry; - struct dentry *emd_dentry; - loff_t offs; - - emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL); - fill_new_filp (&filp, emd_dentry); - - filp.f_pos = inode->u.umsdos_i.pos; - filp.f_reada = 0; - offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ - Printk (("pos = %Lu ", filp.f_pos)); - /* Read only the start of the entry since we don't touch */ - /* the name */ - ret = umsdos_emd_dir_read (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); - if (ret == 0){ - if (attr->ia_valid & ATTR_UID) - entry.uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - entry.gid = attr->ia_gid; - if (attr->ia_valid & ATTR_MODE) - entry.mode = attr->ia_mode; - if (attr->ia_valid & ATTR_ATIME) - entry.atime = attr->ia_atime; - if (attr->ia_valid & ATTR_MTIME) - entry.mtime = attr->ia_mtime; - if (attr->ia_valid & ATTR_CTIME) - entry.ctime = attr->ia_ctime; - - entry.nlink = inode->i_nlink; - filp.f_pos = inode->u.umsdos_i.pos; - offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ - ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); - - Printk (("notify pos %lu ret %d nlink %d " - ,inode->u.umsdos_i.pos - ,ret, entry.nlink)); - /* #Specification: notify_change / msdos fs - notify_change operation are done only on the - EMD file. The msdos fs is not even called. - */ - } - /* iput (emd_owner); FIXME */ - } - Printk (("\n")); - } - } - if (ret == 0) - inode_setattr(inode, attr); - return ret; -} - - -int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) -{ - return internal_notify_change (dentry->d_inode, attr); -} - /* #Specification: function name / convention - A simple convention for function name has been used in - the UMSDOS file system. First all function use the prefix - umsdos_ to avoid name clash with other part of the kernel. - - And standard VFS entry point use the prefix UMSDOS (upper case) - so it's easier to tell them apart. - N.B. (FIXME) PTW, the order and contents of this struct changed -*/ - -static struct super_operations umsdos_sops = { - UMSDOS_read_inode, /* read_inode */ - UMSDOS_write_inode, /* write_inode */ - UMSDOS_put_inode, /* put_inode */ - NULL, /* delete_inode */ - UMSDOS_notify_change, /* notify_change */ - UMSDOS_put_super, /* put_super */ - NULL, /* write_super */ - fat_statfs, /* statfs */ - NULL /* remount_fs*/ + * A simple convention for function name has been used in + * the UMSDOS file system. First all function use the prefix + * umsdos_ to avoid name clash with other part of the kernel. + * + * And standard VFS entry point use the prefix UMSDOS (upper case) + * so it's easier to tell them apart. + * N.B. (FIXME) PTW, the order and contents of this struct changed + */ + +static struct super_operations umsdos_sops = +{ + UMSDOS_read_inode, /* read_inode */ + UMSDOS_write_inode, /* write_inode */ + UMSDOS_put_inode, /* put_inode */ + fat_delete_inode, /* delete_inode */ + UMSDOS_notify_change, /* notify_change */ + UMSDOS_put_super, /* put_super */ + NULL, /* write_super */ + fat_statfs, /* statfs */ + NULL /* remount_fs */ }; /* - Read the super block of an Extended MS-DOS FS. -*/ -struct super_block *UMSDOS_read_super( - struct super_block *sb, - void *data, - int silent) + * Read the super block of an Extended MS-DOS FS. + */ +struct super_block *UMSDOS_read_super ( + struct super_block *sb, + void *data, + int silent) { - /* #Specification: mount / options - Umsdos run on top of msdos. Currently, it supports no - mount option, but happily pass all option received to - the msdos driver. I am not sure if all msdos mount option - make sense with Umsdos. Here are at least those who - are useful. - uid= - gid= - - These options affect the operation of umsdos in directories - which do not have an EMD file. They behave like normal - msdos directory, with all limitation of msdos. - */ - struct super_block *res; - struct inode *pseudo=NULL; - Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n")); - MOD_INC_USE_COUNT; - PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb)); - res = msdos_read_super(sb,data,silent); - PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res)); - printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-3 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); - - if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } - - MSDOS_SB(res)->options.dotsOK = 0; /* disable hidden==dotfile */ - res->s_op = &umsdos_sops; - Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n")); - - pseudo = iget(res,UMSDOS_ROOT_INO); - Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo)); - - umsdos_setup_dir_inode (pseudo); - -#if 0 /* disabled /mn/ test FIXME */ - - /* if (s == super_blocks){ FIXME, super_blocks no longer exported */ - if(pseudo) { - /* #Specification: pseudo root / mount - When a umsdos fs is mounted, a special handling is done - if it is the root partition. We check for the presence - of the file /linux/etc/init or /linux/etc/rc or - /linux/sbin/init. If one is there, we do a chroot("/linux"). - - We check both because (see init/main.c) the kernel - try to exec init at different place and if it fails - it tries /bin/sh /etc/rc. To be consistent with - init/main.c, many more test would have to be done - to locate init. Any complain ? - - The chroot is done manually in init/main.c but the - info (the inode) is located at mount time and store - in a global variable (pseudo_root) which is used at - different place in the umsdos driver. There is no - need to store this variable elsewhere because it - will always be one, not one per mount. - - This feature allows the installation - of a linux system within a DOS system in a subdirectory. - - A user may install its linux stuff in c:\linux - avoiding any clash with existing DOS file and subdirectory. - When linux boots, it hides this fact, showing a normal - root directory with /etc /bin /tmp ... - - The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h - in the macro UMSDOS_PSDROOT_NAME. - */ - struct dentry *root, *etc, *etc_rc, *init, *sbin; - - root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL, NULL); - sbin = creat_dentry ("sbin", 4, NULL, NULL); - - Printk ((KERN_DEBUG "Mounting root\n")); - if (umsdos_real_lookup (pseudo,root)==0 - && (root->d_inode != NULL) - && S_ISDIR(root->d_inode->i_mode)){ - - int pseudo_ok = 0; - Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME)); - etc = creat_dentry ("etc", 3, NULL, NULL); - - - /* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */ - if(umsdos_real_lookup(pseudo, etc) == 0 - && S_ISDIR(etc->d_inode->i_mode)){ - - Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); - - init = creat_dentry ("init", 4, NULL, NULL); - etc_rc = creat_dentry ("rc", 2, NULL, NULL); - - /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/ - if((umsdos_real_lookup(pseudo, init) == 0 - && S_ISREG(init->d_inode->i_mode)) - /* || (umsdos_real_lookup (etc,"rc",2,&rc)==0*/ - || (umsdos_real_lookup(pseudo, etc_rc) == 0 - && S_ISREG(etc_rc->d_inode->i_mode))){ - pseudo_ok = 1; - } - /* FIXME !!!!!! */ - /* iput(init); */ - /* iput(rc); */ - } - if (!pseudo_ok - /* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0*/ - && umsdos_real_lookup(pseudo, sbin) == 0 - && S_ISDIR(sbin->d_inode->i_mode)){ - - Printk ((KERN_DEBUG "/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); - /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */ - if(umsdos_real_lookup(pseudo, init) == 0 - && S_ISREG(init->d_inode->i_mode)){ - pseudo_ok = 1; - } - /* FIXME !!! - iput (init); */ + /* #Specification: mount / options + * Umsdos run on top of msdos. Currently, it supports no + * mount option, but happily pass all option received to + * the msdos driver. I am not sure if all msdos mount option + * make sense with Umsdos. Here are at least those who + * are useful. + * uid= + * gid= + * + * These options affect the operation of umsdos in directories + * which do not have an EMD file. They behave like normal + * msdos directory, with all limitation of msdos. + */ + struct super_block *res; + struct inode *pseudo = NULL; + + Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n")); + MOD_INC_USE_COUNT; + PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n", sb)); + res = msdos_read_super (sb, data, silent); + PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n", res)); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-4 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + + if (res == NULL) { + MOD_DEC_USE_COUNT; + return NULL; } - if (pseudo_ok){ - umsdos_setup_dir_inode (pseudo); - Printk ((KERN_INFO "Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); - pseudo_root = pseudo; - pseudo->i_count++; - pseudo = NULL; + MSDOS_SB (res)->options.dotsOK = 0; /* disable hidden==dotfile */ + res->s_op = &umsdos_sops; + Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n")); + + pseudo = iget (res, UMSDOS_ROOT_INO); + Printk ((KERN_DEBUG "umsdos_read_super %p\n", pseudo)); + + umsdos_setup_dir_inode (pseudo); + Printk ((KERN_DEBUG "umsdos_setup_dir_inode passed. pseudo i_count=%d\n", pseudo->i_count)); + + /* if (s == super_blocks){ FIXME, super_blocks no longer exported */ + if (pseudo) { + /* #Specification: pseudo root / mount + * When a umsdos fs is mounted, a special handling is done + * if it is the root partition. We check for the presence + * of the file /linux/etc/init or /linux/etc/rc or + * /linux/sbin/init. If one is there, we do a chroot("/linux"). + * + * We check both because (see init/main.c) the kernel + * try to exec init at different place and if it fails + * it tries /bin/sh /etc/rc. To be consistent with + * init/main.c, many more test would have to be done + * to locate init. Any complain ? + * + * The chroot is done manually in init/main.c but the + * info (the inode) is located at mount time and store + * in a global variable (pseudo_root) which is used at + * different place in the umsdos driver. There is no + * need to store this variable elsewhere because it + * will always be one, not one per mount. + * + * This feature allows the installation + * of a linux system within a DOS system in a subdirectory. + * + * A user may install its linux stuff in c:\linux + * avoiding any clash with existing DOS file and subdirectory. + * When linux boots, it hides this fact, showing a normal + * root directory with /etc /bin /tmp ... + * + * The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h + * in the macro UMSDOS_PSDROOT_NAME. + */ + struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL; + + root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen (UMSDOS_PSDROOT_NAME), NULL, NULL); + sbin = creat_dentry ("sbin", 4, NULL, NULL); + + Printk ((KERN_DEBUG "Mounting root\n")); + if (umsdos_real_lookup (pseudo, root) == 0 + && (root->d_inode != NULL) + && S_ISDIR (root->d_inode->i_mode)) { + + int pseudo_ok = 0; + + Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME)); + etc = creat_dentry ("etc", 3, NULL, root); + + + if (umsdos_real_lookup (pseudo, etc) == 0 + && S_ISDIR (etc->d_inode->i_mode)) { + + Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME)); + + init = creat_dentry ("init", 4, NULL, etc); + etc_rc = creat_dentry ("rc", 2, NULL, etc); + + /* if ((umsdos_real_lookup (etc,"init",4,init)==0 */ + if ((umsdos_real_lookup (pseudo, init) == 0 + && S_ISREG (init->d_inode->i_mode)) + /* || (umsdos_real_lookup (etc,"rc",2,&rc)==0 */ + || (umsdos_real_lookup (pseudo, etc_rc) == 0 + && S_ISREG (etc_rc->d_inode->i_mode))) { + pseudo_ok = 1; + } + /* FIXME !!!!!! */ + /* iput(init); */ + /* iput(rc); */ + } + if (!pseudo_ok + /* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */ + && umsdos_real_lookup (pseudo, sbin) == 0 + && S_ISDIR (sbin->d_inode->i_mode)) { + + Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME)); + /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */ + if (umsdos_real_lookup (pseudo, init) == 0 + && S_ISREG (init->d_inode->i_mode)) { + pseudo_ok = 1; + } + /* FIXME !!! + * iput (init); */ + } + if (pseudo_ok) { + umsdos_setup_dir_inode (pseudo); + Printk ((KERN_INFO "Activating pseudo root /%s\n", UMSDOS_PSDROOT_NAME)); + pseudo_root = pseudo; + inc_count (pseudo); + pseudo = NULL; + } + /* FIXME + * + * iput (sbin); + * iput (etc); + */ + } + iput (pseudo); } - /* FIXME - - iput (sbin); - iput (etc); - */ - } - - Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n")); - - /* iput (pseudo); / * FIXME */ - } - -#endif /* disabled */ - - PRINTK ((KERN_DEBUG "umsdos_read_super /mn/: returning %p\n",res)); - return res; + Printk ((KERN_DEBUG "umsdos_read_super /mn/: (pseudo=%lu, i_count=%d) returning %p\n", pseudo->i_ino, pseudo->i_count, res)); + return res; } -static struct file_system_type umsdos_fs_type = { - "umsdos", - FS_REQUIRES_DEV, - UMSDOS_read_super, - NULL +static struct file_system_type umsdos_fs_type = +{ + "umsdos", + FS_REQUIRES_DEV, + UMSDOS_read_super, + NULL }; -__initfunc(int init_umsdos_fs(void)) +__initfunc (int init_umsdos_fs (void)) { - return register_filesystem(&umsdos_fs_type); + return register_filesystem (&umsdos_fs_type); } #ifdef MODULE EXPORT_NO_SYMBOLS; -int init_module(void) +int init_module (void) { - return init_umsdos_fs(); + return init_umsdos_fs (); } -void cleanup_module(void) +void cleanup_module (void) { - unregister_filesystem(&umsdos_fs_type); + unregister_filesystem (&umsdos_fs_type); } #endif diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c index b3f11ee32..a379ba368 100644 --- a/fs/umsdos/ioctl.c +++ b/fs/umsdos/ioctl.c @@ -24,326 +24,336 @@ struct UMSDOS_DIR_ONCE { }; /* - Record a single entry the first call. - Return -EINVAL the next one. -*/ -static int umsdos_ioctl_fill( - void * buf, - const char * name, - int name_len, - off_t offset, - ino_t ino) + * Record a single entry the first call. + * Return -EINVAL the next one. + */ +static int umsdos_ioctl_fill ( + void *buf, + const char *name, + int name_len, + off_t offset, + ino_t ino) { - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; - if (d->count == 0){ - copy_to_user (d->ent->d_name,name,name_len); - put_user ('\0',d->ent->d_name+name_len); - put_user (name_len,&d->ent->d_reclen); - put_user (ino,&d->ent->d_ino); - put_user (offset,&d->ent->d_off); - d->count = 1; - ret = 0; - } - return ret; + int ret = -EINVAL; + struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; + + if (d->count == 0) { + copy_to_user (d->ent->d_name, name, name_len); + put_user ('\0', d->ent->d_name + name_len); + put_user (name_len, &d->ent->d_reclen); + put_user (ino, &d->ent->d_ino); + put_user (offset, &d->ent->d_off); + d->count = 1; + ret = 0; + } + return ret; } /* - Perform special function on a directory -*/ + * Perform special function on a directory + */ int UMSDOS_ioctl_dir ( - struct inode *dir, - struct file *filp, - unsigned int cmd, - unsigned long data) + struct inode *dir, + struct file *filp, + unsigned int cmd, + unsigned long data) { - int ret = -EPERM; - int err; + int ret = -EPERM; + int err; - /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */ - if(cmd!=UMSDOS_GETVERSION - &&cmd!=UMSDOS_READDIR_DOS - &&cmd!=UMSDOS_READDIR_EMD - &&cmd!=UMSDOS_INIT_EMD - &&cmd!=UMSDOS_CREAT_EMD - &&cmd!=UMSDOS_RENAME_DOS - &&cmd!=UMSDOS_UNLINK_EMD - &&cmd!=UMSDOS_UNLINK_DOS - &&cmd!=UMSDOS_RMDIR_DOS - &&cmd!=UMSDOS_STAT_DOS - &&cmd!=UMSDOS_DOS_SETUP) - return fat_dir_ioctl(dir,filp,cmd,data); + /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */ + if (cmd != UMSDOS_GETVERSION + && cmd != UMSDOS_READDIR_DOS + && cmd != UMSDOS_READDIR_EMD + && cmd != UMSDOS_INIT_EMD + && cmd != UMSDOS_CREAT_EMD + && cmd != UMSDOS_RENAME_DOS + && cmd != UMSDOS_UNLINK_EMD + && cmd != UMSDOS_UNLINK_DOS + && cmd != UMSDOS_RMDIR_DOS + && cmd != UMSDOS_STAT_DOS + && cmd != UMSDOS_DOS_SETUP) + return fat_dir_ioctl (dir, filp, cmd, data); - /* #Specification: ioctl / acces - Only root (effective id) is allowed to do IOCTL on directory - in UMSDOS. EPERM is returned for other user. - */ - /* - Well, not all cases require write access, but it simplifies - the code, and let's face it, there is only one client (umssync) - for all this. - */ - if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) { - ret = err; - }else if (current->euid == 0 - || cmd == UMSDOS_GETVERSION){ - struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data; - ret = -EINVAL; - /* #Specification: ioctl / prototypes - The official prototype for the umsdos ioctl on directory - is: - - int ioctl ( - int fd, // File handle of the directory - int cmd, // command - struct umsdos_ioctl *data) - - The struct and the commands are defined in linux/umsdos_fs.h. - - umsdos_progs/umsdosio.c provide an interface in C++ to all - these ioctl. umsdos_progs/udosctl is a small utility showing - all this. - - These ioctl generally allow one to work on the EMD or the - DOS directory independently. These are essential to implement - the synchronise. - */ - Printk (("ioctl %d ",cmd)); - if (cmd == UMSDOS_GETVERSION){ - /* #Specification: ioctl / UMSDOS_GETVERSION - The field version and release of the structure - umsdos_ioctl are filled with the version and release - number of the fs code in the kernel. This will allow - some form of checking. Users won't be able to run - incompatible utility such as the synchroniser (umssync). - umsdos_progs/umsdosio.c enforce this checking. - - Return always 0. - */ - put_user(UMSDOS_VERSION,&idata->version); - put_user(UMSDOS_RELEASE,&idata->release); - ret = 0; - }else if (cmd == UMSDOS_READDIR_DOS){ - /* #Specification: ioctl / UMSDOS_READDIR_DOS - One entry is read from the DOS directory at the current - file position. The entry is put as is in the dos_dirent - field of struct umsdos_ioctl. - - Return > 0 if success. - */ - struct UMSDOS_DIR_ONCE bufk; - bufk.count = 0; - bufk.ent = &idata->dos_dirent; - - fat_readdir(filp,&bufk,umsdos_ioctl_fill); - - ret = bufk.count == 1 ? 1 : 0; - }else if (cmd == UMSDOS_READDIR_EMD){ - /* #Specification: ioctl / UMSDOS_READDIR_EMD - One entry is read from the EMD at the current - file position. The entry is put as is in the umsdos_dirent - field of struct umsdos_ioctl. The corresponding mangled - DOS entry name is put in the dos_dirent field. - - All entries are read including hidden links. Blank - entries are skipped. - - Return > 0 if success. - */ - struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0); - if (emd_dir != NULL){ - while (1){ - if (filp->f_pos >= emd_dir->i_size){ - ret = 0; - break; - }else{ - struct umsdos_dirent entry; - off_t f_pos = filp->f_pos; - ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry); - if (ret < 0){ - break; - }else if (entry.name_len > 0){ - struct umsdos_info info; - ret = entry.name_len; - umsdos_parse (entry.name,entry.name_len,&info); - info.f_pos = f_pos; - umsdos_manglename(&info); - copy_to_user(&idata->umsdos_dirent,&entry - ,sizeof(entry)); - copy_to_user(&idata->dos_dirent.d_name - ,info.fake.fname,info.fake.len+1); - break; - } - } - } - /* iput (emd_dir); FIXME */ - }else{ - /* The absence of the EMD is simply seen as an EOF */ - ret = 0; - } - }else if (cmd == UMSDOS_INIT_EMD){ - /* #Specification: ioctl / UMSDOS_INIT_EMD - The UMSDOS_INIT_EMD command make sure the EMD - exist for a directory. If it does not, it is - created. Also, it makes sure the directory functions - table (struct inode_operations) is set to the UMSDOS - semantic. This mean that umssync may be applied to - an "opened" msdos directory, and it will change behavior - on the fly. - - Return 0 if success. - */ - extern struct inode_operations umsdos_rdir_inode_operations; - struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1); - ret = emd_dir != NULL; - /* iput (emd_dir); FIXME */ - - dir->i_op = ret - ? &umsdos_dir_inode_operations - : &umsdos_rdir_inode_operations; - }else{ - struct umsdos_ioctl data; - copy_from_user (&data,idata,sizeof(data)); - if (cmd == UMSDOS_CREAT_EMD){ - /* #Specification: ioctl / UMSDOS_CREAT_EMD - The umsdos_dirent field of the struct umsdos_ioctl is used - as is to create a new entry in the EMD of the directory. - The DOS directory is not modified. - No validation is done (yet). - - Return 0 if success. - */ - struct umsdos_info info; - /* This makes sure info.entry and info in general is correctly */ - /* initialised */ - memcpy (&info.entry,&data.umsdos_dirent - ,sizeof(data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name - ,data.umsdos_dirent.name_len,&info); - ret = umsdos_newentry (dir,&info); - }else if (cmd == UMSDOS_RENAME_DOS){ - struct dentry *old_dentry,*new_dentry; /* FIXME */ - /* #Specification: ioctl / UMSDOS_RENAME_DOS - A file or directory is rename in a DOS directory - (not moved across directory). The source name - is in the dos_dirent.name field and the destination - is in umsdos_dirent.name field. - - This ioctl allows umssync to rename a mangle file - name before syncing it back in the EMD. - */ - dir->i_count+=2; - /* - ret = msdos_rename (dir - ,data.dos_dirent.d_name,data.dos_dirent.d_reclen - ,dir - ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); - */ - old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, NULL); /* FIXME: prolly should fill inode part */ - new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL); - ret = msdos_rename(dir,old_dentry,dir,new_dentry); - }else if (cmd == UMSDOS_UNLINK_EMD){ - /* #Specification: ioctl / UMSDOS_UNLINK_EMD - The umsdos_dirent field of the struct umsdos_ioctl is used - as is to remove an entry from the EMD of the directory. - No validation is done (yet). The mode field is used - to validate S_ISDIR or S_ISREG. - - Return 0 if success. - */ - struct umsdos_info info; - /* This makes sure info.entry and info in general is correctly */ - /* initialised */ - memcpy (&info.entry,&data.umsdos_dirent - ,sizeof(data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name - ,data.umsdos_dirent.name_len,&info); - ret = umsdos_delentry (dir,&info - ,S_ISDIR(data.umsdos_dirent.mode)); - }else if (cmd == UMSDOS_UNLINK_DOS){ - struct dentry *dentry; /* FIXME */ - /* #Specification: ioctl / UMSDOS_UNLINK_DOS - The dos_dirent field of the struct umsdos_ioctl is used to - execute a msdos_unlink operation. The d_name and d_reclen - fields are used. - - Return 0 if success. - */ - dir->i_count++; + /* #Specification: ioctl / acces + * Only root (effective id) is allowed to do IOCTL on directory + * in UMSDOS. EPERM is returned for other user. + */ /* - ret = msdos_unlink (dir,data.dos_dirent.d_name,data.dos_dirent.d_reclen); - */ - ret = msdos_unlink(dir,dentry); - }else if (cmd == UMSDOS_RMDIR_DOS){ - struct dentry *dentry; /* FIXME */ - /* #Specification: ioctl / UMSDOS_RMDIR_DOS - The dos_dirent field of the struct umsdos_ioctl is used to - execute a msdos_unlink operation. The d_name and d_reclen - fields are used. - - Return 0 if success. - */ - dir->i_count++; - /* - ret = msdos_rmdir (dir,data.dos_dirent.d_name - ,data.dos_dirent.d_reclen); - */ - ret = msdos_rmdir(dir,dentry); - }else if (cmd == UMSDOS_STAT_DOS){ - /* #Specification: ioctl / UMSDOS_STAT_DOS - The dos_dirent field of the struct umsdos_ioctl is - used to execute a stat operation in the DOS directory. - The d_name and d_reclen fields are used. - - The following field of umsdos_ioctl.stat are filled. - - st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, - Return 0 if success. - */ - struct inode *inode; + * Well, not all cases require write access, but it simplifies + * the code, and let's face it, there is only one client (umssync) + * for all this. + */ + if ((err = verify_area (VERIFY_WRITE, (void *) data, sizeof (struct umsdos_ioctl))) < 0) { + ret = err; + } else if (current->euid == 0 + || cmd == UMSDOS_GETVERSION) { + struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data; - ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode); - if (ret == 0){ - data.stat.st_ino = inode->i_ino; - data.stat.st_mode = inode->i_mode; - data.stat.st_size = inode->i_size; - data.stat.st_atime = inode->i_atime; - data.stat.st_ctime = inode->i_ctime; - data.stat.st_mtime = inode->i_mtime; - copy_to_user (&idata->stat,&data.stat,sizeof(data.stat)); - /* iput (inode); FIXME */ - } - }else if (cmd == UMSDOS_DOS_SETUP){ - /* #Specification: ioctl / UMSDOS_DOS_SETUP - The UMSDOS_DOS_SETUP ioctl allow changing the - default permission of the MsDOS file system driver - on the fly. The MsDOS driver apply global permission - to every file and directory. Normally these permissions - are controlled by a mount option. This is not - available for root partition, so a special utility - (umssetup) is provided to do this, normally in - /etc/rc.local. - - Be aware that this apply ONLY to MsDOS directory - (those without EMD --linux-.---). Umsdos directory - have independent (standard) permission for each - and every file. - - The field umsdos_dirent provide the information needed. - umsdos_dirent.uid and gid sets the owner and group. - umsdos_dirent.mode set the permissions flags. - */ - dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; - dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; - dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode; - ret = 0; - } - } - } - Printk (("ioctl return %d\n",ret)); - return ret; -} + ret = -EINVAL; + /* #Specification: ioctl / prototypes + * The official prototype for the umsdos ioctl on directory + * is: + * + * int ioctl ( + * int fd, // File handle of the directory + * int cmd, // command + * struct umsdos_ioctl *data) + * + * The struct and the commands are defined in linux/umsdos_fs.h. + * + * umsdos_progs/umsdosio.c provide an interface in C++ to all + * these ioctl. umsdos_progs/udosctl is a small utility showing + * all this. + * + * These ioctl generally allow one to work on the EMD or the + * DOS directory independently. These are essential to implement + * the synchronise. + */ + Printk (("ioctl %d ", cmd)); + if (cmd == UMSDOS_GETVERSION) { + /* #Specification: ioctl / UMSDOS_GETVERSION + * The field version and release of the structure + * umsdos_ioctl are filled with the version and release + * number of the fs code in the kernel. This will allow + * some form of checking. Users won't be able to run + * incompatible utility such as the synchroniser (umssync). + * umsdos_progs/umsdosio.c enforce this checking. + * + * Return always 0. + */ + put_user (UMSDOS_VERSION, &idata->version); + put_user (UMSDOS_RELEASE, &idata->release); + ret = 0; + } else if (cmd == UMSDOS_READDIR_DOS) { + /* #Specification: ioctl / UMSDOS_READDIR_DOS + * One entry is read from the DOS directory at the current + * file position. The entry is put as is in the dos_dirent + * field of struct umsdos_ioctl. + * + * Return > 0 if success. + */ + struct UMSDOS_DIR_ONCE bufk; + + bufk.count = 0; + bufk.ent = &idata->dos_dirent; + fat_readdir (filp, &bufk, umsdos_ioctl_fill); + ret = bufk.count == 1 ? 1 : 0; + } else if (cmd == UMSDOS_READDIR_EMD) { + /* #Specification: ioctl / UMSDOS_READDIR_EMD + * One entry is read from the EMD at the current + * file position. The entry is put as is in the umsdos_dirent + * field of struct umsdos_ioctl. The corresponding mangled + * DOS entry name is put in the dos_dirent field. + * + * All entries are read including hidden links. Blank + * entries are skipped. + * + * Return > 0 if success. + */ + struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 0); + if (emd_dir != NULL) { + while (1) { + if (filp->f_pos >= emd_dir->i_size) { + ret = 0; + break; + } else { + struct umsdos_dirent entry; + off_t f_pos = filp->f_pos; + + ret = umsdos_emd_dir_readentry (emd_dir, filp, &entry); + if (ret < 0) { + break; + } else if (entry.name_len > 0) { + struct umsdos_info info; + + ret = entry.name_len; + umsdos_parse (entry.name, entry.name_len, &info); + info.f_pos = f_pos; + umsdos_manglename (&info); + copy_to_user (&idata->umsdos_dirent, &entry + ,sizeof (entry)); + copy_to_user (&idata->dos_dirent.d_name + ,info.fake.fname, info.fake.len + 1); + break; + } + } + } + iput (emd_dir); /* FIXME? */ + } else { + /* The absence of the EMD is simply seen as an EOF */ + ret = 0; + } + } else if (cmd == UMSDOS_INIT_EMD) { + /* #Specification: ioctl / UMSDOS_INIT_EMD + * The UMSDOS_INIT_EMD command make sure the EMD + * exist for a directory. If it does not, it is + * created. Also, it makes sure the directory functions + * table (struct inode_operations) is set to the UMSDOS + * semantic. This mean that umssync may be applied to + * an "opened" msdos directory, and it will change behavior + * on the fly. + * + * Return 0 if success. + */ + extern struct inode_operations umsdos_rdir_inode_operations; + struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1); + + ret = emd_dir != NULL; + iput (emd_dir); /* FIXME?? */ + + dir->i_op = ret + ? &umsdos_dir_inode_operations + : &umsdos_rdir_inode_operations; + } else { + struct umsdos_ioctl data; + + copy_from_user (&data, idata, sizeof (data)); + if (cmd == UMSDOS_CREAT_EMD) { + /* #Specification: ioctl / UMSDOS_CREAT_EMD + * The umsdos_dirent field of the struct umsdos_ioctl is used + * as is to create a new entry in the EMD of the directory. + * The DOS directory is not modified. + * No validation is done (yet). + * + * Return 0 if success. + */ + struct umsdos_info info; + + /* This makes sure info.entry and info in general is correctly */ + /* initialised */ + memcpy (&info.entry, &data.umsdos_dirent + ,sizeof (data.umsdos_dirent)); + umsdos_parse (data.umsdos_dirent.name + ,data.umsdos_dirent.name_len, &info); + ret = umsdos_newentry (dir, &info); + } else if (cmd == UMSDOS_RENAME_DOS) { + struct dentry *old_dentry, *new_dentry; /* FIXME */ + + /* #Specification: ioctl / UMSDOS_RENAME_DOS + * A file or directory is rename in a DOS directory + * (not moved across directory). The source name + * is in the dos_dirent.name field and the destination + * is in umsdos_dirent.name field. + * + * This ioctl allows umssync to rename a mangle file + * name before syncing it back in the EMD. + */ + inc_count (dir); + inc_count (dir); + /* + * ret = msdos_rename (dir + * ,data.dos_dirent.d_name,data.dos_dirent.d_reclen + * ,dir + * ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); + */ + old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, geti_dentry (dir)); /* FIXME: prolly should fill inode part */ + new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, geti_dentry (dir)); + ret = msdos_rename (dir, old_dentry, dir, new_dentry); + } else if (cmd == UMSDOS_UNLINK_EMD) { + /* #Specification: ioctl / UMSDOS_UNLINK_EMD + * The umsdos_dirent field of the struct umsdos_ioctl is used + * as is to remove an entry from the EMD of the directory. + * No validation is done (yet). The mode field is used + * to validate S_ISDIR or S_ISREG. + * + * Return 0 if success. + */ + struct umsdos_info info; + + /* This makes sure info.entry and info in general is correctly */ + /* initialised */ + memcpy (&info.entry, &data.umsdos_dirent + ,sizeof (data.umsdos_dirent)); + umsdos_parse (data.umsdos_dirent.name + ,data.umsdos_dirent.name_len, &info); + ret = umsdos_delentry (dir, &info + ,S_ISDIR (data.umsdos_dirent.mode)); + } else if (cmd == UMSDOS_UNLINK_DOS) { + struct dentry *dentry, *dp; + + /* #Specification: ioctl / UMSDOS_UNLINK_DOS + * The dos_dirent field of the struct umsdos_ioctl is used to + * execute a msdos_unlink operation. The d_name and d_reclen + * fields are used. + * + * Return 0 if success. + */ + inc_count (dir); + dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL); + dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp); + ret = msdos_unlink (dir, dentry); + + } else if (cmd == UMSDOS_RMDIR_DOS) { + struct dentry *dentry, *dp; + + /* #Specification: ioctl / UMSDOS_RMDIR_DOS + * The dos_dirent field of the struct umsdos_ioctl is used to + * execute a msdos_unlink operation. The d_name and d_reclen + * fields are used. + * + * Return 0 if success. + */ + inc_count (dir); + dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL); + dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp); + ret = msdos_rmdir (dir, dentry); + + } else if (cmd == UMSDOS_STAT_DOS) { + /* #Specification: ioctl / UMSDOS_STAT_DOS + * The dos_dirent field of the struct umsdos_ioctl is + * used to execute a stat operation in the DOS directory. + * The d_name and d_reclen fields are used. + * + * The following field of umsdos_ioctl.stat are filled. + * + * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, + * Return 0 if success. + */ + struct inode *inode; + + ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode); + if (ret == 0) { + data.stat.st_ino = inode->i_ino; + data.stat.st_mode = inode->i_mode; + data.stat.st_size = inode->i_size; + data.stat.st_atime = inode->i_atime; + data.stat.st_ctime = inode->i_ctime; + data.stat.st_mtime = inode->i_mtime; + copy_to_user (&idata->stat, &data.stat, sizeof (data.stat)); + /* iput (inode); FIXME */ + } + } else if (cmd == UMSDOS_DOS_SETUP) { + /* #Specification: ioctl / UMSDOS_DOS_SETUP + * The UMSDOS_DOS_SETUP ioctl allow changing the + * default permission of the MsDOS file system driver + * on the fly. The MsDOS driver apply global permission + * to every file and directory. Normally these permissions + * are controlled by a mount option. This is not + * available for root partition, so a special utility + * (umssetup) is provided to do this, normally in + * /etc/rc.local. + * + * Be aware that this apply ONLY to MsDOS directory + * (those without EMD --linux-.---). Umsdos directory + * have independent (standard) permission for each + * and every file. + * + * The field umsdos_dirent provide the information needed. + * umsdos_dirent.uid and gid sets the owner and group. + * umsdos_dirent.mode set the permissions flags. + */ + dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; + dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; + dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode; + ret = 0; + } + } + } + Printk (("ioctl return %d\n", ret)); + return ret; +} diff --git a/fs/umsdos/mangle.c b/fs/umsdos/mangle.c index e94ff12d5..ecd62f4c3 100644 --- a/fs/umsdos/mangle.c +++ b/fs/umsdos/mangle.c @@ -1,7 +1,7 @@ /* * linux/fs/umsdos/mangle.c * - * Written 1993 by Jacques Gelinas + * Written 1993 by Jacques Gelinas * * Control the mangling of file name to fit msdos name space. * Many optimisation by GLU == dglaude@is1.vub.ac.be (GLAUDE DAVID) @@ -13,474 +13,507 @@ #include <linux/umsdos_fs.h> /* - Complete the mangling of the MSDOS fake name - based on the position of the entry in the EMD file. - - Simply complete the job of umsdos_parse; fill the extension. - - Beware that info->f_pos must be set. -*/ + * Complete the mangling of the MSDOS fake name + * based on the position of the entry in the EMD file. + * + * Simply complete the job of umsdos_parse; fill the extension. + * + * Beware that info->f_pos must be set. + */ void umsdos_manglename (struct umsdos_info *info) { - if (info->msdos_reject){ - /* #Specification: file name / non MSDOS conforming / mangling - Each non MSDOS conforming file has a special extension - build from the entry position in the EMD file. - - This number is then transform in a base 32 number, where - each digit is expressed like hexadecimal number, using - digit and letter, except it uses 22 letters from 'a' to 'v'. - The number 32 comes from 2**5. It is faster to split a binary - number using a base which is a power of two. And I was 32 - when I started this project. Pick your answer :-) . - - If the result is '0', it is replace with '_', simply - to make it odd. - - This is true for the first two character of the extension. - The last one is taken from a list of odd character, which - are: - - { } ( ) ! ` ^ & @ - - With this scheme, we can produce 9216 ( 9* 32 * 32) - different extensions which should not clash with any useful - extension already popular or meaningful. Since most directory - have much less than 32 * 32 files in it, the first character - of the extension of any mangle name will be {. - - Here are the reason to do this (this kind of mangling). - - -The mangling is deterministic. Just by the extension, we - are able to locate the entry in the EMD file. - - -By keeping to beginning of the file name almost unchanged, - we are helping the MSDOS user. - - -The mangling produces names not too ugly, so an msdos user - may live with it (remember it, type it, etc...). - - -The mangling produces names ugly enough so no one will - ever think of using such a name in real life. This is not - fool proof. I don't think there is a total solution to this. - */ - union { - int entry_num; - struct { - unsigned num1:5,num2:5,num3:5; - }num; - } u; - char *pt = info->fake.fname + info->fake.len; - /* lookup for encoding the last character of the extension */ - /* It contain valid character after the ugly one to make sure */ - /* even if someone overflow the 32 * 32 * 9 limit, it still do */ - /* something */ + if (info->msdos_reject) { + /* #Specification: file name / non MSDOS conforming / mangling + * Each non MSDOS conforming file has a special extension + * build from the entry position in the EMD file. + * + * This number is then transform in a base 32 number, where + * each digit is expressed like hexadecimal number, using + * digit and letter, except it uses 22 letters from 'a' to 'v'. + * The number 32 comes from 2**5. It is faster to split a binary + * number using a base which is a power of two. And I was 32 + * when I started this project. Pick your answer :-) . + * + * If the result is '0', it is replace with '_', simply + * to make it odd. + * + * This is true for the first two character of the extension. + * The last one is taken from a list of odd character, which + * are: + * + * { } ( ) ! ` ^ & @ + * + * With this scheme, we can produce 9216 ( 9* 32 * 32) + * different extensions which should not clash with any useful + * extension already popular or meaningful. Since most directory + * have much less than 32 * 32 files in it, the first character + * of the extension of any mangle name will be {. + * + * Here are the reason to do this (this kind of mangling). + * + * -The mangling is deterministic. Just by the extension, we + * are able to locate the entry in the EMD file. + * + * -By keeping to beginning of the file name almost unchanged, + * we are helping the MSDOS user. + * + * -The mangling produces names not too ugly, so an msdos user + * may live with it (remember it, type it, etc...). + * + * -The mangling produces names ugly enough so no one will + * ever think of using such a name in real life. This is not + * fool proof. I don't think there is a total solution to this. + */ + union { + int entry_num; + struct { + unsigned num1:5, num2:5, num3:5; + } num; + } u; + char *pt = info->fake.fname + info->fake.len; + + /* lookup for encoding the last character of the extension */ + /* It contain valid character after the ugly one to make sure */ + /* even if someone overflow the 32 * 32 * 9 limit, it still do */ + /* something */ #define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@' - static char lookup3[]={ - SPECIAL_MANGLING, - /* This is the start of lookup12 */ - '_','1','2','3','4','5','6','7','8','9', - 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', - 'p','q','r','s','t','u','v' - }; + static char lookup3[] = + { + SPECIAL_MANGLING, + /* This is the start of lookup12 */ + '_', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v' + }; + #define lookup12 (lookup3+9) - u.entry_num = info->f_pos / UMSDOS_REC_SIZE; - if (u.entry_num > (9* 32 * 32)){ - printk ("UMSDOS: More than 9216 file in a directory.\n" - "This may break the mangling strategy.\n" - "Not a killer problem. See doc.\n"); - } - *pt++ = '.'; - *pt++ = lookup3 [u.num.num3]; - *pt++ = lookup12[u.num.num2]; - *pt++ = lookup12[u.num.num1]; - *pt = '\0'; /* help doing printk */ - info->fake.len += 4; - info->msdos_reject = 0; /* Avoid mangling twice */ - } + u.entry_num = info->f_pos / UMSDOS_REC_SIZE; + if (u.entry_num > (9 * 32 * 32)) { + printk ("UMSDOS: More than 9216 file in a directory.\n" + "This may break the mangling strategy.\n" + "Not a killer problem. See doc.\n"); + } + *pt++ = '.'; + *pt++ = lookup3[u.num.num3]; + *pt++ = lookup12[u.num.num2]; + *pt++ = lookup12[u.num.num1]; + *pt = '\0'; /* help doing printk */ + info->fake.len += 4; + info->msdos_reject = 0; /* Avoid mangling twice */ + } } /* - Evaluate the record size needed to store of name of len character. - The value returned is a multiple of UMSDOS_REC_SIZE. -*/ + * Evaluate the record size needed to store of name of len character. + * The value returned is a multiple of UMSDOS_REC_SIZE. + */ int umsdos_evalrecsize (int len) { - struct umsdos_dirent dirent; - int nbrec = 1+((len-1+(dirent.name-(char*)&dirent)) - / UMSDOS_REC_SIZE); - return nbrec * UMSDOS_REC_SIZE; - /* - GLU This should be inlined or something to speed it up to the max. - GLU nbrec is absolutely not needed to return the value. - */ + struct umsdos_dirent dirent; + int nbrec = 1 + ((len - 1 + (dirent.name - (char *) &dirent)) + / UMSDOS_REC_SIZE); + + return nbrec * UMSDOS_REC_SIZE; + /* + * GLU This should be inlined or something to speed it up to the max. + * GLU nbrec is absolutely not needed to return the value. + */ } #ifdef TEST int umsdos_evalrecsize_old (int len) { - struct umsdos_dirent dirent; - int size = len + (dirent.name-(char*)&dirent); - int nbrec = size / UMSDOS_REC_SIZE; - int extra = size % UMSDOS_REC_SIZE; - if (extra > 0) nbrec++; - return nbrec * UMSDOS_REC_SIZE; + struct umsdos_dirent dirent; + int size = len + (dirent.name - (char *) &dirent); + int nbrec = size / UMSDOS_REC_SIZE; + int extra = size % UMSDOS_REC_SIZE; + + if (extra > 0) + nbrec++; + return nbrec * UMSDOS_REC_SIZE; } #endif /* - Fill the struct info with the full and msdos name of a file - Return 0 if all is ok, a negative error code otherwise. -*/ + * Fill the struct info with the full and msdos name of a file + * Return 0 if all is ok, a negative error code otherwise. + */ int umsdos_parse ( - const char *fname, - int len, - struct umsdos_info *info) + const char *fname, + int len, + struct umsdos_info *info) { - int ret = -ENAMETOOLONG; - /* #Specification: file name / too long - If a file name exceed UMSDOS maxima, the file name is silently - truncated. This makes it conformant with the other file system - of Linux (minix and ext2 at least). - */ - if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME; - { - const char *firstpt=NULL; /* First place we saw a . in fname */ - /* #Specification: file name / non MSDOS conforming / base length 0 - file name beginning with a period '.' are invalid for MsDOS. - It needs absolutely a base name. So the file name is mangled - */ - int ivldchar = fname[0] == '.';/* At least one invalid character */ - int msdos_len = len; - int base_len; - /* - cardinal_per_size tells if there exist at least one - DOS pseudo devices on length n. See the test below. - */ - static const char cardinal_per_size[9]={ - 0, 0, 0, 1, 1, 0, 1, 0, 1 - }; - /* - lkp translate all character to acceptable character (for DOS). - When lkp[n] == n, it means also it is an acceptable one. - So it serve both as a flag and as a translator. - */ - static char lkp[256]; - static char is_init=0; - if (!is_init){ - /* - Initialisation of the array is easier and less error prone - like this. - */ - int i; - static const char *spc = "\"*+,/:;<=>?[\\]|~"; - is_init = 1; - for (i=0; i<=32; i++) lkp[i] = '#'; - for (i=33; i<'A'; i++) lkp[i] = (char)i; - for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A')); - for (i='Z'+1; i<127; i++) lkp[i] = (char)i; - for (i=128; i<256; i++) lkp[i] = '#'; - - lkp['.'] = '_'; - while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#'; - } - /* GLU - file name which are longer than 8+'.'+3 are invalid for MsDOS. - So the file name is to be mangled no more test needed. - This Speed Up for long and very long name. - The position of the last point is no more necessary anyway. - */ - if (len<=(8+1+3)){ - const char *pt = fname; - const char *endpt = fname + len; - while (pt < endpt){ - if (*pt == '.'){ - if (firstpt != NULL){ - /* 2 . in a file name. Reject */ - ivldchar = 1; - break; - }else{ - int extlen = (int)(endpt - pt); - firstpt = pt; - if (firstpt - fname > 8){ - /* base name longer than 8: reject */ - ivldchar = 1; - break; - }else if (extlen > 4){ - /* Extension longer than 4 (including .): reject */ - ivldchar = 1; - break; - }else if (extlen == 1){ - /* #Specification: file name / non MSDOS conforming / last char == . - If the last character of a file name is - a period, mangling is applied. MsDOS do - not support those file name. - */ - ivldchar = 1; - break; - }else if (extlen == 4){ - /* #Specification: file name / non MSDOS conforming / mangling clash - To avoid clash with the umsdos mangling, any file - with a special character as the first character - of the extension will be mangled. This solve the - following problem: - - # - touch FILE - # FILE is invalid for DOS, so mangling is applied - # file.{_1 is created in the DOS directory - touch file.{_1 - # To UMSDOS file point to a single DOS entry. - # So file.{_1 has to be mangled. - # - */ - static char special[]={ - SPECIAL_MANGLING,'\0' - }; - if (strchr(special,firstpt[1])!= NULL){ - ivldchar = 1; - break; - } - } - } - }else if (lkp[(unsigned char)(*pt)] != *pt){ - ivldchar = 1; - break; - } - pt++; - } - }else{ - ivldchar = 1; - } - if (ivldchar - || (firstpt == NULL && len > 8) - || (len == UMSDOS_EMD_NAMELEN - && memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){ - /* #Specification: file name / --linux-.--- - The name of the EMD file --linux-.--- is map to a mangled - name. So UMSDOS does not restrict its use. - */ - /* #Specification: file name / non MSDOS conforming / mangling - Non MSDOS conforming file name must use some alias to fit - in the MSDOS name space. - - The strategy is simple. The name is simply truncated to - 8 char. points are replace with underscore and a - number is given as an extension. This number correspond - to the entry number in the EMD file. The EMD file - only need to carry the real name. - - Upper case is also convert to lower case. - Control character are converted to #. - Space are converted to #. - The following character are also converted to #. - # - " * + , / : ; < = > ? [ \ ] | ~ - # - - Sometime, the problem is not in MsDOS itself but in - command.com. - */ - int i; - char *pt = info->fake.fname; - base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len; - /* - There is no '.' any more so we know for a fact that - the base length is the length. - */ - memcpy (info->fake.fname,fname,msdos_len); - for (i=0; i<msdos_len; i++, pt++) *pt = lkp[(unsigned char)(*pt)]; - *pt = '\0'; /* GLU C'est sur on a un 0 a la fin */ - info->msdos_reject = 1; - /* - The numeric extension is added only when we know - the position in the EMD file, in umsdos_newentry(), - umsdos_delentry(), and umsdos_findentry(). - See umsdos_manglename(). - */ - }else{ - /* Conforming MSDOS file name */ - strncpy (info->fake.fname,fname,len); - info->msdos_reject = 0; - base_len = firstpt != NULL ? (int)(firstpt - fname) : len; - } - if (cardinal_per_size[base_len]){ - /* #Specification: file name / MSDOS devices / mangling - To avoid unreachable file from MsDOS, any MsDOS conforming - file with a basename equal to one of the MsDOS pseudo - devices will be mangled. - - If a file such as "prn" was created, it would be unreachable - under MsDOS because prn is assumed to be the printer, even - if the file does have an extension. - - Since the extension is unimportant to MsDOS, we must patch - the basename also. We simply insert a minus '-'. To avoid - conflict with valid file with a minus in front (such as - "-prn"), we add an mangled extension like any other - mangled file name. - - Here is the list of DOS pseudo devices: - - # - "prn","con","aux","nul", - "lpt1","lpt2","lpt3","lpt4", - "com1","com2","com3","com4", - "clock$" - # - - and some standard ones for common DOS programs - - "emmxxxx0","xmsxxxx0","setverxx" - - (Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK> - for pointing these to me). - - Is there one missing ? - */ - /* This table must be ordered by length */ - static const char *tbdev[]={ - "prn","con","aux","nul", - "lpt1","lpt2","lpt3","lpt4", - "com1","com2","com3","com4", - "clock$", - "emmxxxx0","xmsxxxx0","setverxx" - }; - /* Tell where to find in tbdev[], the first name of */ - /* a certain length */ - static const char start_ind_dev[9]={ - 0, 0, 0, 4, 12, 12, 13, 13, 16 - }; - char basen[9]; - int i; - for (i=start_ind_dev[base_len-1]; i<start_ind_dev[base_len]; i++){ - if (memcmp(info->fake.fname,tbdev[i],base_len)==0){ - memcpy (basen,info->fake.fname,base_len); - basen[base_len] = '\0'; /* GLU C'est sur on a un 0 a la fin */ - /* - GLU On ne fait cela que si necessaire, on essaye d'etre le - GLU simple dans le cas general (le plus frequent). - */ - info->fake.fname[0] = '-'; - strcpy (info->fake.fname+1,basen); /* GLU C'est sur on a un 0 a la fin */ - msdos_len = (base_len==8) ? 8 : base_len + 1; - info->msdos_reject = 1; - break; + int ret = -ENAMETOOLONG; + + /* #Specification: file name / too long + * If a file name exceed UMSDOS maxima, the file name is silently + * truncated. This makes it conformant with the other file system + * of Linux (minix and ext2 at least). + */ + if (len > UMSDOS_MAXNAME) + len = UMSDOS_MAXNAME; + { + const char *firstpt = NULL; /* First place we saw a . in fname */ + + /* #Specification: file name / non MSDOS conforming / base length 0 + * file name beginning with a period '.' are invalid for MsDOS. + * It needs absolutely a base name. So the file name is mangled + */ + int ivldchar = fname[0] == '.'; /* At least one invalid character */ + int msdos_len = len; + int base_len; + + /* + * cardinal_per_size tells if there exist at least one + * DOS pseudo devices on length n. See the test below. + */ + static const char cardinal_per_size[9] = + { + 0, 0, 0, 1, 1, 0, 1, 0, 1 + }; + + /* + * lkp translate all character to acceptable character (for DOS). + * When lkp[n] == n, it means also it is an acceptable one. + * So it serve both as a flag and as a translator. + */ + static char lkp[256]; + static char is_init = 0; + + if (!is_init) { + /* + * Initialisation of the array is easier and less error prone + * like this. + */ + int i; + static const char *spc = "\"*+,/:;<=>?[\\]|~"; + + is_init = 1; + for (i = 0; i <= 32; i++) + lkp[i] = '#'; + for (i = 33; i < 'A'; i++) + lkp[i] = (char) i; + for (i = 'A'; i <= 'Z'; i++) + lkp[i] = (char) (i + ('a' - 'A')); + for (i = 'Z' + 1; i < 127; i++) + lkp[i] = (char) i; + for (i = 128; i < 256; i++) + lkp[i] = '#'; + + lkp['.'] = '_'; + while (*spc != '\0') + lkp[(unsigned char) (*spc++)] = '#'; + } + /* GLU + * file name which are longer than 8+'.'+3 are invalid for MsDOS. + * So the file name is to be mangled no more test needed. + * This Speed Up for long and very long name. + * The position of the last point is no more necessary anyway. + */ + if (len <= (8 + 1 + 3)) { + const char *pt = fname; + const char *endpt = fname + len; + + while (pt < endpt) { + if (*pt == '.') { + if (firstpt != NULL) { + /* 2 . in a file name. Reject */ + ivldchar = 1; + break; + } else { + int extlen = (int) (endpt - pt); + + firstpt = pt; + if (firstpt - fname > 8) { + /* base name longer than 8: reject */ + ivldchar = 1; + break; + } else if (extlen > 4) { + /* Extension longer than 4 (including .): reject */ + ivldchar = 1; + break; + } else if (extlen == 1) { + /* #Specification: file name / non MSDOS conforming / last char == . + * If the last character of a file name is + * a period, mangling is applied. MsDOS do + * not support those file name. + */ + ivldchar = 1; + break; + } else if (extlen == 4) { + /* #Specification: file name / non MSDOS conforming / mangling clash + * To avoid clash with the umsdos mangling, any file + * with a special character as the first character + * of the extension will be mangled. This solve the + * following problem: + * + * # + * touch FILE + * # FILE is invalid for DOS, so mangling is applied + * # file.{_1 is created in the DOS directory + * touch file.{_1 + * # To UMSDOS file point to a single DOS entry. + * # So file.{_1 has to be mangled. + * # + */ + static char special[] = + { + SPECIAL_MANGLING, '\0' + }; + + if (strchr (special, firstpt[1]) != NULL) { + ivldchar = 1; + break; + } + } + } + } else if (lkp[(unsigned char) (*pt)] != *pt) { + ivldchar = 1; + break; + } + pt++; + } + } else { + ivldchar = 1; + } + if (ivldchar + || (firstpt == NULL && len > 8) + || (len == UMSDOS_EMD_NAMELEN + && memcmp (fname, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN) == 0)) { + /* #Specification: file name / --linux-.--- + * The name of the EMD file --linux-.--- is map to a mangled + * name. So UMSDOS does not restrict its use. + */ + /* #Specification: file name / non MSDOS conforming / mangling + * Non MSDOS conforming file name must use some alias to fit + * in the MSDOS name space. + * + * The strategy is simple. The name is simply truncated to + * 8 char. points are replace with underscore and a + * number is given as an extension. This number correspond + * to the entry number in the EMD file. The EMD file + * only need to carry the real name. + * + * Upper case is also convert to lower case. + * Control character are converted to #. + * Space are converted to #. + * The following character are also converted to #. + * # + * " * + , / : ; < = > ? [ \ ] | ~ + * # + * + * Sometime, the problem is not in MsDOS itself but in + * command.com. + */ + int i; + char *pt = info->fake.fname; + + base_len = msdos_len = (msdos_len > 8) ? 8 : msdos_len; + /* + * There is no '.' any more so we know for a fact that + * the base length is the length. + */ + memcpy (info->fake.fname, fname, msdos_len); + for (i = 0; i < msdos_len; i++, pt++) + *pt = lkp[(unsigned char) (*pt)]; + *pt = '\0'; /* GLU C'est sur on a un 0 a la fin */ + info->msdos_reject = 1; + /* + * The numeric extension is added only when we know + * the position in the EMD file, in umsdos_newentry(), + * umsdos_delentry(), and umsdos_findentry(). + * See umsdos_manglename(). + */ + } else { + /* Conforming MSDOS file name */ + strncpy (info->fake.fname, fname, len); + info->msdos_reject = 0; + base_len = firstpt != NULL ? (int) (firstpt - fname) : len; + } + if (cardinal_per_size[base_len]) { + /* #Specification: file name / MSDOS devices / mangling + * To avoid unreachable file from MsDOS, any MsDOS conforming + * file with a basename equal to one of the MsDOS pseudo + * devices will be mangled. + * + * If a file such as "prn" was created, it would be unreachable + * under MsDOS because prn is assumed to be the printer, even + * if the file does have an extension. + * + * Since the extension is unimportant to MsDOS, we must patch + * the basename also. We simply insert a minus '-'. To avoid + * conflict with valid file with a minus in front (such as + * "-prn"), we add an mangled extension like any other + * mangled file name. + * + * Here is the list of DOS pseudo devices: + * + * # + * "prn","con","aux","nul", + * "lpt1","lpt2","lpt3","lpt4", + * "com1","com2","com3","com4", + * "clock$" + * # + * + * and some standard ones for common DOS programs + * + * "emmxxxx0","xmsxxxx0","setverxx" + * + * (Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK> + * for pointing these to me). + * + * Is there one missing ? + */ + /* This table must be ordered by length */ + static const char *tbdev[] = + { + "prn", "con", "aux", "nul", + "lpt1", "lpt2", "lpt3", "lpt4", + "com1", "com2", "com3", "com4", + "clock$", + "emmxxxx0", "xmsxxxx0", "setverxx" + }; + + /* Tell where to find in tbdev[], the first name of */ + /* a certain length */ + static const char start_ind_dev[9] = + { + 0, 0, 0, 4, 12, 12, 13, 13, 16 + }; + char basen[9]; + int i; + + for (i = start_ind_dev[base_len - 1]; i < start_ind_dev[base_len]; i++) { + if (memcmp (info->fake.fname, tbdev[i], base_len) == 0) { + memcpy (basen, info->fake.fname, base_len); + basen[base_len] = '\0'; /* GLU C'est sur on a un 0 a la fin */ + /* + * GLU On ne fait cela que si necessaire, on essaye d'etre le + * GLU simple dans le cas general (le plus frequent). + */ + info->fake.fname[0] = '-'; + strcpy (info->fake.fname + 1, basen); /* GLU C'est sur on a un 0 a la fin */ + msdos_len = (base_len == 8) ? 8 : base_len + 1; + info->msdos_reject = 1; + break; + } + } + } + info->fake.fname[msdos_len] = '\0'; /* Help doing printk */ + /* GLU Ce zero devrais deja y etre ! (invariant ?) */ + info->fake.len = msdos_len; + /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ? */ + memcpy (info->entry.name, fname, len); + info->entry.name_len = len; + ret = 0; } - } - } - info->fake.fname[msdos_len] = '\0'; /* Help doing printk */ - /* GLU Ce zero devrais deja y etre ! (invariant ?) */ - info->fake.len = msdos_len; - /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/ - memcpy (info->entry.name,fname,len); - info->entry.name_len = len; - ret = 0; - } - /* - Evaluate how many record are needed to store this entry. - */ - info->recsize = umsdos_evalrecsize (len); - return ret; + /* + * Evaluate how many record are needed to store this entry. + */ + info->recsize = umsdos_evalrecsize (len); + return ret; } #ifdef TEST -struct MANG_TEST{ - char *fname; /* Name to validate */ - int msdos_reject; /* Expected msdos_reject flag */ - char *msname; /* Expected msdos name */ +struct MANG_TEST { + char *fname; /* Name to validate */ + int msdos_reject; /* Expected msdos_reject flag */ + char *msname; /* Expected msdos name */ }; -struct MANG_TEST tb[]={ - "hello", 0, "hello", - "hello.1", 0, "hello.1", - "hello.1_", 0, "hello.1_", - "prm", 0, "prm", - +struct MANG_TEST tb[] = +{ + "hello", 0, "hello", + "hello.1", 0, "hello.1", + "hello.1_", 0, "hello.1_", + "prm", 0, "prm", + #ifdef PROPOSITION - "HELLO", 1, "hello", - "Hello.1", 1, "hello.1", - "Hello.c", 1, "hello.c", + "HELLO", 1, "hello", + "Hello.1", 1, "hello.1", + "Hello.c", 1, "hello.c", #elseif /* - Je trouve les trois exemples ci-dessous tres "malheureux". - Je propose de mettre en minuscule dans un passe preliminaire, - et de tester apres si il y a d'autres caracters "mechants". - Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement - modifiable que ca. Mais c'est pour le principe. - Evidemment cela augmente les chances de "Collision", - par exemple: entre "HELLO" et "Hello", mais ces problemes - peuvent etre traiter ailleur avec les autres collisions. -*/ - "HELLO", 1, "hello", - "Hello.1", 1, "hello_1", - "Hello.c", 1, "hello_c", + * Je trouve les trois exemples ci-dessous tres "malheureux". + * Je propose de mettre en minuscule dans un passe preliminaire, + * et de tester apres si il y a d'autres caracters "mechants". + * Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement + * modifiable que ca. Mais c'est pour le principe. + * Evidemment cela augmente les chances de "Collision", + * par exemple: entre "HELLO" et "Hello", mais ces problemes + * peuvent etre traiter ailleur avec les autres collisions. + */ + "HELLO", 1, "hello", + "Hello.1", 1, "hello_1", + "Hello.c", 1, "hello_c", #endif - - "hello.{_1", 1, "hello_{_", - "hello\t", 1, "hello#", - "hello.1.1", 1, "hello_1_", - "hel,lo", 1, "hel#lo", - "Salut.Tu.vas.bien?", 1, "salut_tu", - ".profile", 1, "_profile", - ".xv", 1, "_xv", - "toto.", 1, "toto_", - "clock$.x", 1, "-clock$", - "emmxxxx0", 1, "-emmxxxx", - "emmxxxx0.abcd", 1, "-emmxxxx", - "aux", 1, "-aux", - "prn", 1, "-prn", - "prn.abc", 1, "-prn", - "PRN", 1, "-prn", + + "hello.{_1", 1, "hello_{_", + "hello\t", 1, "hello#", + "hello.1.1", 1, "hello_1_", + "hel,lo", 1, "hel#lo", + "Salut.Tu.vas.bien?", 1, "salut_tu", + ".profile", 1, "_profile", + ".xv", 1, "_xv", + "toto.", 1, "toto_", + "clock$.x", 1, "-clock$", + "emmxxxx0", 1, "-emmxxxx", + "emmxxxx0.abcd", 1, "-emmxxxx", + "aux", 1, "-aux", + "prn", 1, "-prn", + "prn.abc", 1, "-prn", + "PRN", 1, "-prn", /* - GLU ATTENTION : Le resultat de ceux-ci sont differents avec ma version - GLU du mangle par rapport au mangle originale. - GLU CAUSE: La maniere de calculer la variable baselen. - GLU Pour toi c'est toujours 3 - GLU Pour moi c'est respectivement 7, 8 et 8 - */ - "PRN.abc", 1, "prn_abc", - "Prn.abcd", 1, "prn_abcd", - "prn.abcd", 1, "prn_abcd", - "Prn.abcdefghij", 1, "prn_abcd" + * GLU ATTENTION : Le resultat de ceux-ci sont differents avec ma version + * GLU du mangle par rapport au mangle originale. + * GLU CAUSE: La maniere de calculer la variable baselen. + * GLU Pour toi c'est toujours 3 + * GLU Pour moi c'est respectivement 7, 8 et 8 + */ + "PRN.abc", 1, "prn_abc", + "Prn.abcd", 1, "prn_abcd", + "prn.abcd", 1, "prn_abcd", + "Prn.abcdefghij", 1, "prn_abcd" }; int main (int argc, char *argv[]) { - int i,rold,rnew; - printf ("Testing the umsdos_parse.\n"); - for (i=0; i<sizeof(tb)/sizeof(tb[0]); i++){ - struct MANG_TEST *pttb = tb+i; - struct umsdos_info info; - int ok = umsdos_parse (pttb->fname,strlen(pttb->fname),&info); - if (strcmp(info.fake.fname,pttb->msname)!=0){ - printf ("**** %s -> ",pttb->fname); - printf ("%s <> %s\n",info.fake.fname,pttb->msname); - }else if (info.msdos_reject != pttb->msdos_reject){ - printf ("**** %s -> %s ",pttb->fname,pttb->msname); - printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject); - }else{ - printf (" %s -> %s %d\n",pttb->fname,pttb->msname - ,pttb->msdos_reject); - } - } - printf ("Testing the new umsdos_evalrecsize."); - for (i=0; i<UMSDOS_MAXNAME ; i++){ - rnew=umsdos_evalrecsize (i); - rold=umsdos_evalrecsize_old (i); - if (!(i%UMSDOS_REC_SIZE)){ - printf ("\n%d:\t",i); - } - if (rnew!=rold){ - printf ("**** %d newres: %d != %d \n", i, rnew, rold); - }else{ - printf("."); - } - } - printf ("\nEnd of Testing.\n"); - - return 0; + int i, rold, rnew; + + printf ("Testing the umsdos_parse.\n"); + for (i = 0; i < sizeof (tb) / sizeof (tb[0]); i++) { + struct MANG_TEST *pttb = tb + i; + struct umsdos_info info; + int ok = umsdos_parse (pttb->fname, strlen (pttb->fname), &info); + + if (strcmp (info.fake.fname, pttb->msname) != 0) { + printf ("**** %s -> ", pttb->fname); + printf ("%s <> %s\n", info.fake.fname, pttb->msname); + } else if (info.msdos_reject != pttb->msdos_reject) { + printf ("**** %s -> %s ", pttb->fname, pttb->msname); + printf ("%d <> %d\n", info.msdos_reject, pttb->msdos_reject); + } else { + printf (" %s -> %s %d\n", pttb->fname, pttb->msname + ,pttb->msdos_reject); + } + } + printf ("Testing the new umsdos_evalrecsize."); + for (i = 0; i < UMSDOS_MAXNAME; i++) { + rnew = umsdos_evalrecsize (i); + rold = umsdos_evalrecsize_old (i); + if (!(i % UMSDOS_REC_SIZE)) { + printf ("\n%d:\t", i); + } + if (rnew != rold) { + printf ("**** %d newres: %d != %d \n", i, rnew, rold); + } else { + printf ("."); + } + } + printf ("\nEnd of Testing.\n"); + + return 0; } #endif diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 7b549fd96..387ed4fe3 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -1,8 +1,8 @@ /* * linux/fs/umsdos/namei.c * - * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... by Werner Almesberger + * Written 1993 by Jacques Gelinas + * Inspired from linux/fs/msdos/... by Werner Almesberger * * Maintain and access the --linux alternate directory file. */ @@ -23,291 +23,306 @@ #if 1 /* - Wait for creation exclusivity. - Return 0 if the dir was already available. - Return 1 if a wait was necessary. - When 1 is return, it means a wait was done. It does not - mean the directory is available. -*/ -static int umsdos_waitcreate(struct inode *dir) + * Wait for creation exclusivity. + * Return 0 if the dir was already available. + * Return 1 if a wait was necessary. + * When 1 is return, it means a wait was done. It does not + * mean the directory is available. + */ +static int umsdos_waitcreate (struct inode *dir) { - int ret = 0; - if (dir->u.umsdos_i.u.dir_info.creating - && dir->u.umsdos_i.u.dir_info.pid != current->pid){ - sleep_on(&dir->u.umsdos_i.u.dir_info.p); - ret = 1; - } - return ret; + int ret = 0; + + if (dir->u.umsdos_i.u.dir_info.creating + && dir->u.umsdos_i.u.dir_info.pid != current->pid) { + sleep_on (&dir->u.umsdos_i.u.dir_info.p); + ret = 1; + } + return ret; } /* - Wait for any lookup process to finish -*/ + * Wait for any lookup process to finish + */ static void umsdos_waitlookup (struct inode *dir) { - while (dir->u.umsdos_i.u.dir_info.looking){ - sleep_on(&dir->u.umsdos_i.u.dir_info.p); - } + while (dir->u.umsdos_i.u.dir_info.looking) { + sleep_on (&dir->u.umsdos_i.u.dir_info.p); + } } /* - Lock all other process out of this directory. -*/ + * Lock all other process out of this directory. + */ void umsdos_lockcreate (struct inode *dir) { - /* #Specification: file creation / not atomic - File creation is a two step process. First we create (allocate) - an entry in the EMD file and then (using the entry offset) we - build a unique name for MSDOS. We create this name in the msdos - space. - - We have to use semaphore (sleep_on/wake_up) to prevent lookup - into a directory when we create a file or directory and to - prevent creation while a lookup is going on. Since many lookup - may happen at the same time, the semaphore is a counter. - - Only one creation is allowed at the same time. This protection - may not be necessary. The problem arise mainly when a lookup - or a readdir is done while a file is partially created. The - lookup process see that as a "normal" problem and silently - erase the file from the EMD file. Normal because a file - may be erased during a MSDOS session, but not removed from - the EMD file. - - The locking is done on a directory per directory basis. Each - directory inode has its wait_queue. - - For some operation like hard link, things even get worse. Many - creation must occur at once (atomic). To simplify the design - a process is allowed to recursively lock the directory for - creation. The pid of the locking process is kept along with - a counter so a second level of locking is granted or not. - */ - /* - Wait for any creation process to finish except - if we (the process) own the lock - */ - while (umsdos_waitcreate(dir)!=0); - dir->u.umsdos_i.u.dir_info.creating++; - dir->u.umsdos_i.u.dir_info.pid = current->pid; - umsdos_waitlookup (dir); + /* #Specification: file creation / not atomic + * File creation is a two step process. First we create (allocate) + * an entry in the EMD file and then (using the entry offset) we + * build a unique name for MSDOS. We create this name in the msdos + * space. + * + * We have to use semaphore (sleep_on/wake_up) to prevent lookup + * into a directory when we create a file or directory and to + * prevent creation while a lookup is going on. Since many lookup + * may happen at the same time, the semaphore is a counter. + * + * Only one creation is allowed at the same time. This protection + * may not be necessary. The problem arise mainly when a lookup + * or a readdir is done while a file is partially created. The + * lookup process see that as a "normal" problem and silently + * erase the file from the EMD file. Normal because a file + * may be erased during a MSDOS session, but not removed from + * the EMD file. + * + * The locking is done on a directory per directory basis. Each + * directory inode has its wait_queue. + * + * For some operation like hard link, things even get worse. Many + * creation must occur at once (atomic). To simplify the design + * a process is allowed to recursively lock the directory for + * creation. The pid of the locking process is kept along with + * a counter so a second level of locking is granted or not. + */ + /* + * Wait for any creation process to finish except + * if we (the process) own the lock + */ + while (umsdos_waitcreate (dir) != 0); + dir->u.umsdos_i.u.dir_info.creating++; + dir->u.umsdos_i.u.dir_info.pid = current->pid; + umsdos_waitlookup (dir); } /* - Lock all other process out of those two directories. -*/ + * Lock all other process out of those two directories. + */ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) { - /* - We must check that both directory are available before - locking anyone of them. This is to avoid some deadlock. - Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing - this to me. - */ - while (1){ - if (umsdos_waitcreate(dir1)==0 - && umsdos_waitcreate(dir2)==0){ - /* We own both now */ - dir1->u.umsdos_i.u.dir_info.creating++; - dir1->u.umsdos_i.u.dir_info.pid = current->pid; - dir2->u.umsdos_i.u.dir_info.creating++; - dir2->u.umsdos_i.u.dir_info.pid = current->pid; - break; - } - } - umsdos_waitlookup(dir1); - umsdos_waitlookup(dir2); + /* + * We must check that both directory are available before + * locking anyone of them. This is to avoid some deadlock. + * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing + * this to me. + */ + while (1) { + if (umsdos_waitcreate (dir1) == 0 + && umsdos_waitcreate (dir2) == 0) { + /* We own both now */ + dir1->u.umsdos_i.u.dir_info.creating++; + dir1->u.umsdos_i.u.dir_info.pid = current->pid; + dir2->u.umsdos_i.u.dir_info.creating++; + dir2->u.umsdos_i.u.dir_info.pid = current->pid; + break; + } + } + umsdos_waitlookup (dir1); + umsdos_waitlookup (dir2); } /* - Wait until creation is finish in this directory. -*/ + * Wait until creation is finish in this directory. + */ void umsdos_startlookup (struct inode *dir) { - while (umsdos_waitcreate (dir) != 0); - dir->u.umsdos_i.u.dir_info.looking++; + while (umsdos_waitcreate (dir) != 0); + dir->u.umsdos_i.u.dir_info.looking++; } /* - Unlock the directory. -*/ + * Unlock the directory. + */ void umsdos_unlockcreate (struct inode *dir) { - dir->u.umsdos_i.u.dir_info.creating--; - if (dir->u.umsdos_i.u.dir_info.creating < 0){ - printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d" - ,dir->u.umsdos_i.u.dir_info.creating); - } - wake_up (&dir->u.umsdos_i.u.dir_info.p); + dir->u.umsdos_i.u.dir_info.creating--; + if (dir->u.umsdos_i.u.dir_info.creating < 0) { + printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d" + ,dir->u.umsdos_i.u.dir_info.creating); + } + wake_up (&dir->u.umsdos_i.u.dir_info.p); } /* - Tell directory lookup is over. -*/ + * Tell directory lookup is over. + */ void umsdos_endlookup (struct inode *dir) { - dir->u.umsdos_i.u.dir_info.looking--; - if (dir->u.umsdos_i.u.dir_info.looking < 0){ - printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d" - ,dir->u.umsdos_i.u.dir_info.looking); - } - wake_up (&dir->u.umsdos_i.u.dir_info.p); + dir->u.umsdos_i.u.dir_info.looking--; + if (dir->u.umsdos_i.u.dir_info.looking < 0) { + printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d" + ,dir->u.umsdos_i.u.dir_info.looking); + } + wake_up (&dir->u.umsdos_i.u.dir_info.p); } #else -static void umsdos_lockcreate (struct inode *dir){} -static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){} -void umsdos_startlookup (struct inode *dir){} -static void umsdos_unlockcreate (struct inode *dir){} -void umsdos_endlookup (struct inode *dir){} +static void umsdos_lockcreate (struct inode *dir) +{ +} +static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) +{ +} +void umsdos_startlookup (struct inode *dir) +{ +} +static void umsdos_unlockcreate (struct inode *dir) +{ +} +void umsdos_endlookup (struct inode *dir) +{ +} + #endif -static int umsdos_nevercreat( - struct inode *dir, - struct dentry *dentry, - int errcod) /* Length of the name */ -{ - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; - int ret = 0; - if (umsdos_is_pseudodos(dir,dentry)){ - /* #Specification: pseudo root / any file creation /DOS - The pseudo sub-directory /DOS can't be created! - EEXIST is returned. - - The pseudo sub-directory /DOS can't be removed! - EPERM is returned. - */ - ret = -EPERM; - ret = errcod; - }else if (name[0] == '.' - && (len == 1 || (len == 2 && name[1] == '.'))){ - /* #Specification: create / . and .. - If one try to creates . or .., it always fail and return - EEXIST. - - If one try to delete . or .., it always fail and return - EPERM. - - This should be test at the VFS layer level to avoid - duplicating this in all file systems. Any comments ? - */ - ret = errcod; - } - return ret; +static int umsdos_nevercreat ( + struct inode *dir, + struct dentry *dentry, + int errcod) +{ /* Length of the name */ + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; + int ret = 0; + + if (umsdos_is_pseudodos (dir, dentry)) { + /* #Specification: pseudo root / any file creation /DOS + * The pseudo sub-directory /DOS can't be created! + * EEXIST is returned. + * + * The pseudo sub-directory /DOS can't be removed! + * EPERM is returned. + */ + ret = -EPERM; + ret = errcod; + } else if (name[0] == '.' + && (len == 1 || (len == 2 && name[1] == '.'))) { + /* #Specification: create / . and .. + * If one try to creates . or .., it always fail and return + * EEXIST. + * + * If one try to delete . or .., it always fail and return + * EPERM. + * + * This should be test at the VFS layer level to avoid + * duplicating this in all file systems. Any comments ? + */ + ret = errcod; + } + return ret; } - + /* - Add a new file (ordinary or special) into the alternate directory. - The file is added to the real MSDOS directory. If successful, it - is then added to the EDM file. - - Return the status of the operation. 0 mean success. -*/ + * Add a new file (ordinary or special) into the alternate directory. + * The file is added to the real MSDOS directory. If successful, it + * is then added to the EDM file. + * + * Return the status of the operation. 0 mean success. + */ static int umsdos_create_any ( - struct inode *dir, - struct dentry *dentry, /* name/length etc*/ - int mode, /* Permission bit + file type ??? */ - int rdev, /* major, minor or 0 for ordinary file */ - /* and symlinks */ - char flags - ) /* Will hold the inode of the newly created */ - /* file */ -{ - - int ret; - struct dentry *fake; - - Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); - ret = umsdos_nevercreat(dir,dentry,-EEXIST); - Printk (("%d/\n", ret)); - if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info); - - if (ret == 0){ - info.entry.mode = mode; - info.entry.rdev = rdev; - info.entry.flags = flags; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) - ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime - = CURRENT_TIME; - info.entry.nlink = 1; - umsdos_lockcreate(dir); - ret = umsdos_newentry (dir,&info); - if (ret == 0){ - dir->i_count++; - fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent); /* create short name dentry */ - ret = msdos_create (dir, fake, S_IFREG|0777); - if (ret == 0){ - struct inode *inode = fake->d_inode; - umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count)); - Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino, - info.fake.len, info.fake.fname, current->pid, info.f_pos)); - - d_instantiate(dentry, inode); /* long name also gets inode info */ - }else{ - /* #Specification: create / file exist in DOS - Here is a situation. Trying to create a file with - UMSDOS. The file is unknown to UMSDOS but already - exist in the DOS directory. - - Here is what we are NOT doing: - - We could silently assume that everything is fine - and allows the creation to succeed. - - It is possible not all files in the partition - are mean to be visible from linux. By trying to create - those file in some directory, one user may get access - to those file without proper permissions. Looks like - a security hole to me. Off course sharing a file system - with DOS is some kind of security hole :-) - - So ? - - We return EEXIST in this case. - The same is true for directory creation. - */ - if (ret == -EEXIST){ - printk ("UMSDOS: out of sync, Creation error [%ld], " - "deleting %.*s %d %d pos %ld\n",dir->i_ino - ,info.fake.len,info.fake.fname,-ret,current->pid,info.f_pos); - } - umsdos_delentry (dir,&info,0); + struct inode *dir, + struct dentry *dentry, /* name/length etc */ + int mode, /* Permission bit + file type ??? */ + int rdev, /* major, minor or 0 for ordinary file and symlinks */ + char flags +) +{ /* Will hold the inode of the newly created file */ + + int ret; + struct dentry *fake; + + Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); + check_dentry (dentry); + ret = umsdos_nevercreat (dir, dentry, -EEXIST); + Printk (("%d/\n", ret)); + if (ret == 0) { + struct umsdos_info info; + + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); + + if (ret == 0) { + info.entry.mode = mode; + info.entry.rdev = rdev; + info.entry.flags = flags; + info.entry.uid = current->fsuid; + info.entry.gid = (dir->i_mode & S_ISGID) + ? dir->i_gid : current->fsgid; + info.entry.ctime = info.entry.atime = info.entry.mtime + = CURRENT_TIME; + info.entry.nlink = 1; + umsdos_lockcreate (dir); + ret = umsdos_newentry (dir, &info); + if (ret == 0) { + inc_count (dir); + fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent); /* create short name dentry */ + ret = msdos_create (dir, fake, S_IFREG | 0777); + if (ret == 0) { + struct inode *inode = fake->d_inode; + + umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos); + Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count)); + Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino, + info.fake.len, info.fake.fname, current->pid, info.f_pos)); + + d_instantiate (dentry, inode); /* long name also gets inode info */ + dput (fake); /* FIXME: is this ok ? we try to kill short name dentry that we don't need */ + } else { + /* #Specification: create / file exist in DOS + * Here is a situation. Trying to create a file with + * UMSDOS. The file is unknown to UMSDOS but already + * exist in the DOS directory. + * + * Here is what we are NOT doing: + * + * We could silently assume that everything is fine + * and allows the creation to succeed. + * + * It is possible not all files in the partition + * are mean to be visible from linux. By trying to create + * those file in some directory, one user may get access + * to those file without proper permissions. Looks like + * a security hole to me. Off course sharing a file system + * with DOS is some kind of security hole :-) + * + * So ? + * + * We return EEXIST in this case. + * The same is true for directory creation. + */ + if (ret == -EEXIST) { + printk ("UMSDOS: out of sync, Creation error [%ld], " + "deleting %.*s %d %d pos %ld\n", dir->i_ino + ,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos); + } + umsdos_delentry (dir, &info, 0); + } + Printk (("umsdos_create %.*s ret = %d pos %ld\n", + info.fake.len, info.fake.fname, ret, info.f_pos)); + } + umsdos_unlockcreate (dir); + } } - Printk (("umsdos_create %.*s ret = %d pos %ld\n", - info.fake.len, info.fake.fname, ret, info.f_pos)); - } - umsdos_unlockcreate(dir); - } - } - /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */ - return ret; + /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */ + return ret; } /* - Initialise the new_entry from the old for a rename operation. - (Only useful for umsdos_rename_f() below). -*/ -static void umsdos_ren_init( - struct umsdos_info *new_info, - struct umsdos_info *old_info, - int flags) /* 0 == copy flags from old_name */ - /* != 0, this is the value of flags */ -{ - new_info->entry.mode = old_info->entry.mode; - new_info->entry.rdev = old_info->entry.rdev; - new_info->entry.uid = old_info->entry.uid; - new_info->entry.gid = old_info->entry.gid; - new_info->entry.ctime = old_info->entry.ctime; - new_info->entry.atime = old_info->entry.atime; - new_info->entry.mtime = old_info->entry.mtime; - new_info->entry.flags = flags ? flags : old_info->entry.flags; - new_info->entry.nlink = old_info->entry.nlink; + * Initialise the new_entry from the old for a rename operation. + * (Only useful for umsdos_rename_f() below). + */ +static void umsdos_ren_init ( + struct umsdos_info *new_info, + struct umsdos_info *old_info, + int flags) +{ /* 0 == copy flags from old_name */ + /* != 0, this is the value of flags */ + new_info->entry.mode = old_info->entry.mode; + new_info->entry.rdev = old_info->entry.rdev; + new_info->entry.uid = old_info->entry.uid; + new_info->entry.gid = old_info->entry.gid; + new_info->entry.ctime = old_info->entry.ctime; + new_info->entry.atime = old_info->entry.atime; + new_info->entry.mtime = old_info->entry.mtime; + new_info->entry.flags = flags ? flags : old_info->entry.flags; + new_info->entry.nlink = old_info->entry.nlink; } #define chkstk() \ @@ -319,870 +334,909 @@ if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\ } #undef chkstk -#define chkstk() do { } while (0) - +#define chkstk() do { } while (0); + /* - Rename a file (move) in the file system. -*/ -static int umsdos_rename_f( - struct inode * old_dir, - struct dentry *old_dentry, - struct inode * new_dir, - struct dentry *new_dentry, - int flags) /* 0 == copy flags from old_name */ - /* != 0, this is the value of flags */ -{ - int ret = -EPERM; - struct umsdos_info old_info; - int old_ret = umsdos_parse (old_dentry->d_name.name, - old_dentry->d_name.len,&old_info); - struct umsdos_info new_info; - int new_ret = umsdos_parse (new_dentry->d_name.name, - new_dentry->d_name.len,&new_info); - chkstk(); - Printk (("umsdos_rename %d %d ",old_ret,new_ret)); - if (old_ret == 0 && new_ret == 0){ - umsdos_lockcreate2(old_dir,new_dir); - chkstk(); - Printk (("old findentry ")); - ret = umsdos_findentry(old_dir,&old_info,0); - chkstk(); - Printk (("ret %d ",ret)); - if (ret == 0){ - /* check sticky bit on old_dir */ - if ( !(old_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || - current->fsuid == old_info.entry.uid || - current->fsuid == old_dir->i_uid ) { - /* Does new_name already exist? */ - PRINTK(("new findentry ")); - ret = umsdos_findentry(new_dir,&new_info,0); - if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ - !(new_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || - current->fsuid == new_info.entry.uid || - current->fsuid == new_dir->i_uid ) { - PRINTK (("new newentry ")); - umsdos_ren_init(&new_info,&old_info,flags); - ret = umsdos_newentry (new_dir,&new_info); - chkstk(); - PRINTK (("ret %d %d ",ret,new_info.fake.len)); - if (ret == 0){ - struct dentry *old, *new; - old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL, NULL); - new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, NULL); - - PRINTK (("msdos_rename ")); - old_dir->i_count++; - new_dir->i_count++; /* Both inode are needed later */ - ret = msdos_rename (old_dir, - old, - new_dir, - new); - chkstk(); - PRINTK (("after m_rename ret %d ",ret)); - if (ret != 0){ - umsdos_delentry (new_dir,&new_info - ,S_ISDIR(new_info.entry.mode)); - chkstk(); - }else{ - ret = umsdos_delentry (old_dir,&old_info - ,S_ISDIR(old_info.entry.mode)); - chkstk(); - if (ret == 0){ - /* - This umsdos_lookup_x does not look very useful. - It makes sure that the inode of the file will - be correctly setup (umsdos_patch_inode()) in - case it is already in use. - - Not very efficient ... - */ - struct inode *inode; - new_dir->i_count++; - PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ",new_len,new_info.entry.flags)); - ret = umsdos_lookup_x (new_dir, new_dentry, 0); - inode = new_dentry->d_inode; - chkstk(); - if (ret != 0){ - printk ("UMSDOS: partial rename for file %.*s\n" - ,new_info.entry.name_len,new_info.entry.name); - }else{ - /* - Update f_pos so notify_change will succeed - if the file was already in use. - */ - umsdos_set_dirinfo (inode,new_dir,new_info.f_pos); - chkstk(); - /* iput (inode); FIXME */ + * Rename a file (move) in the file system. + */ + +static int umsdos_rename_f ( + struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry, + int flags) +{ /* 0 == copy flags from old_name */ + /* != 0, this is the value of flags */ + int ret = -EPERM; + struct umsdos_info old_info; + int old_ret = umsdos_parse (old_dentry->d_name.name, + old_dentry->d_name.len, &old_info); + struct umsdos_info new_info; + int new_ret = umsdos_parse (new_dentry->d_name.name, + new_dentry->d_name.len, &new_info); + + check_dentry (old_dentry); + check_dentry (new_dentry); + + chkstk (); + Printk (("umsdos_rename %d %d ", old_ret, new_ret)); + if (old_ret == 0 && new_ret == 0) { + umsdos_lockcreate2 (old_dir, new_dir); + chkstk (); + Printk (("old findentry ")); + ret = umsdos_findentry (old_dir, &old_info, 0); + chkstk (); + Printk (("ret %d ", ret)); + if (ret == 0) { + /* check sticky bit on old_dir */ + if (!(old_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) || + current->fsuid == old_info.entry.uid || + current->fsuid == old_dir->i_uid) { + /* Does new_name already exist? */ + Printk (("new findentry ")); + ret = umsdos_findentry (new_dir, &new_info, 0); + if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ + !(new_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) || + current->fsuid == new_info.entry.uid || + current->fsuid == new_dir->i_uid) { + Printk (("new newentry ")); + umsdos_ren_init (&new_info, &old_info, flags); + ret = umsdos_newentry (new_dir, &new_info); + chkstk (); + Printk (("ret %d %d ", ret, new_info.fake.len)); + if (ret == 0) { + struct dentry *old, *new; + struct inode *oldid = NULL; + + ret = compat_umsdos_real_lookup (old_dir, old_info.fake.fname, old_info.fake.len, &oldid); + old = creat_dentry (old_info.fake.fname, old_info.fake.len, oldid, old_dentry->d_parent); + + new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, new_dentry->d_parent); + + Printk (("msdos_rename ")); + inc_count (old_dir); + inc_count (new_dir); /* Both inode are needed later */ + + check_dentry (old); check_dentry (new); /* FIXME: debug only */ + ret = msdos_rename (old_dir, old, new_dir, new); + chkstk (); + Printk (("after m_rename ret %d ", ret)); + kill_dentry (old); + kill_dentry (new); + + if (ret != 0) { + umsdos_delentry (new_dir, &new_info, S_ISDIR (new_info.entry.mode)); + chkstk (); + } else { + ret = umsdos_delentry (old_dir, &old_info, S_ISDIR (old_info.entry.mode)); + chkstk (); + if (ret == 0) { + /* + * This umsdos_lookup_x does not look very useful. + * It makes sure that the inode of the file will + * be correctly setup (umsdos_patch_inode()) in + * case it is already in use. + * + * Not very efficient ... + */ + struct inode *inode; + + inc_count (new_dir); + PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ", new_len, new_info.entry.flags)); + ret = umsdos_lookup_x (new_dir, new_dentry, 0); + inode = new_dentry->d_inode; + chkstk (); + if (ret != 0) { + printk ("UMSDOS: partial rename for file %.*s\n" + ,new_info.entry.name_len, new_info.entry.name); + } else { + /* + * Update f_pos so notify_change will succeed + * if the file was already in use. + */ + umsdos_set_dirinfo (inode, new_dir, new_info.f_pos); + d_move (old_dentry, new_dentry); + chkstk (); + /* iput (inode); FIXME */ + } + } + } + } + } else { + /* sticky bit set on new_dir */ + Printk (("sticky set on new ")); + ret = -EPERM; + } + } else { + /* sticky bit set on old_dir */ + Printk (("sticky set on old ")); + ret = -EPERM; + } } - } - } - } - }else{ - /* sticky bit set on new_dir */ - Printk(("sticky set on new ")); - ret = -EPERM; + Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n")); + umsdos_unlockcreate (old_dir); + umsdos_unlockcreate (new_dir); } - }else{ - /* sticky bit set on old_dir */ - Printk(("sticky set on old ")); - ret = -EPERM; - } - } - umsdos_unlockcreate(old_dir); - umsdos_unlockcreate(new_dir); - } - d_move(old_dentry,new_dentry); - Printk (("\n")); - return ret; + check_dentry (old_dentry); + check_dentry (new_dentry); + + Printk ((" _ret=%d\n", ret)); + return ret; } /* - Setup un Symbolic link or a (pseudo) hard link - Return a negative error code or 0 if ok. -*/ -static int umsdos_symlink_x( - struct inode * dir, - struct dentry *dentry, - const char * symname, /* name will point to this path */ - int mode, - char flags) + * Setup un Symbolic link or a (pseudo) hard link + * Return a negative error code or 0 if ok. + */ +static int umsdos_symlink_x ( + struct inode *dir, + struct dentry *dentry, + const char *symname, /* name will point to this path */ + int mode, + char flags) { - /* #Specification: symbolic links / strategy - A symbolic link is simply a file which hold a path. It is - implemented as a normal MSDOS file (not very space efficient :-() - - I see 2 different way to do it. One is to place the link data - in unused entry of the EMD file. The other is to have a separate - file dedicated to hold all symbolic links data. - - Let's go for simplicity... - */ - - - int ret; - dir->i_count++;/* We keep the inode in case we need it */ - /* later */ - ret = umsdos_create_any (dir,dentry,mode,0,flags); - Printk (("umsdos_symlink ret %d ",ret)); - if (ret == 0){ - int len = strlen(symname); - struct file filp; - loff_t myofs=0; - fill_new_filp (&filp, dentry); - - /* Make the inode acceptable to MSDOS FIXME */ - Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n")); - Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); - ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs); - /* dput(dentry); ?? where did this come from FIXME */ - if (ret >= 0){ - if (ret != len){ - ret = -EIO; - printk ("UMSDOS: " - "Can't write symbolic link data\n"); - }else{ - ret = 0; - } - } - if (ret != 0){ - UMSDOS_unlink (dir,dentry); - dir = NULL; - } - } - /* d_instantiate(dentry,dir); //already done in umsdos_create_any */ - Printk (("\n")); - return ret; + /* #Specification: symbolic links / strategy + * A symbolic link is simply a file which hold a path. It is + * implemented as a normal MSDOS file (not very space efficient :-() + * + * I see 2 different way to do it. One is to place the link data + * in unused entry of the EMD file. The other is to have a separate + * file dedicated to hold all symbolic links data. + * + * Let's go for simplicity... + */ + + + int ret; + + inc_count (dir); /* We keep the inode in case we need it */ + /* later */ + ret = umsdos_create_any (dir, dentry, mode, 0, flags); + Printk (("umsdos_symlink ret %d ", ret)); + if (ret == 0) { + int len = strlen (symname); + struct file filp; + loff_t myofs = 0; + + fill_new_filp (&filp, dentry); + + /* Make the inode acceptable to MSDOS FIXME */ + Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n")); + Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); + ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs); + /* dput(dentry); ?? where did this come from FIXME */ + + if (ret >= 0) { + if (ret != len) { + ret = -EIO; + printk ("UMSDOS: " + "Can't write symbolic link data\n"); + } else { + ret = 0; + } + } + if (ret != 0) { + UMSDOS_unlink (dir, dentry); + dir = NULL; + } + } + /* d_instantiate(dentry,dir); //already done in umsdos_create_any. */ + Printk (("\n")); + return ret; } /* - Setup un Symbolic link. - Return a negative error code or 0 if ok. -*/ -int UMSDOS_symlink( - struct inode * dir, - struct dentry *dentry, - const char * symname - ) + * Setup un Symbolic link. + * Return a negative error code or 0 if ok. + */ +int UMSDOS_symlink ( + struct inode *dir, + struct dentry *dentry, + const char *symname +) { - return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0); + return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0); } /* - Add a link to an inode in a directory -*/ + * Add a link to an inode in a directory + */ int UMSDOS_link ( - struct dentry * olddentry, - struct inode * dir, - struct dentry *dentry) + struct dentry *olddentry, + struct inode *dir, + struct dentry *dentry) { - struct inode *oldinode = olddentry->d_inode; - /* #Specification: hard link / strategy - Well ... hard link are difficult to implement on top of an - MsDOS fat file system. Unlike UNIX file systems, there are no - inode. A directory entry hold the functionality of the inode - and the entry. - - We will used the same strategy as a normal Unix file system - (with inode) except we will do it symbolically (using paths). - - Because anything can happen during a DOS session (defragment, - directory sorting, etc...), we can't rely on MsDOS pseudo - inode number to record the link. For this reason, the link - will be done using hidden symbolic links. The following - scenario illustrate how it work. - - Given a file /foo/file - - # - ln /foo/file /tmp/file2 - - become internally - - mv /foo/file /foo/-LINK1 - ln -s /foo/-LINK1 /foo/file - ln -s /foo/-LINK1 /tmp/file2 - # - - Using this strategy, we can operate on /foo/file or /foo/file2. - We can remove one and keep the other, like a normal Unix hard link. - We can rename /foo/file or /tmp/file2 independently. - - The entry -LINK1 will be hidden. It will hold a link count. - When all link are erased, the hidden file is erased too. - */ - /* #Specification: weakness / hard link - The strategy for hard link introduces a side effect that - may or may not be acceptable. Here is the sequence - - # - mkdir subdir1 - touch subdir1/file - mkdir subdir2 - ln subdir1/file subdir2/file - rm subdir1/file - rmdir subdir1 - rmdir: subdir1: Directory not empty - # - - This happen because there is an invisible file (--link) in - subdir1 which is referenced by subdir2/file. - - Any idea ? - */ - /* #Specification: weakness / hard link / rename directory - Another weakness of hard link come from the fact that - it is based on hidden symbolic links. Here is an example. - - # - mkdir /subdir1 - touch /subdir1/file - mkdir /subdir2 - ln /subdir1/file subdir2/file - mv /subdir1 subdir3 - ls -l /subdir2/file - # - - Since /subdir2/file is a hidden symbolic link - to /subdir1/..hlinkNNN, accessing it will fail since - /subdir1 does not exist anymore (has been renamed). - */ - int ret = 0; - if (S_ISDIR(oldinode->i_mode)){ - /* #Specification: hard link / directory - A hard link can't be made on a directory. EPERM is returned - in this case. - */ - ret = -EPERM; - }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){ - struct inode *olddir; - ret = umsdos_get_dirowner(oldinode,&olddir); - Printk (("umsdos_link dir_owner = %lu -> %p [%d] ", - oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count)); - if (ret == 0){ - struct umsdos_dirent entry; - umsdos_lockcreate2(dir,olddir); - ret = umsdos_inode2entry (olddir,oldinode,&entry); - if (ret == 0){ - Printk (("umsdos_link :%.*s: ino %lu flags %d " - ,entry.name_len, entry.name - ,oldinode->i_ino, entry.flags)); - if (!(entry.flags & UMSDOS_HIDDEN)){ - /* #Specification: hard link / first hard link - The first time a hard link is done on a file, this - file must be renamed and hidden. Then an internal - symbolic link must be done on the hidden file. - - The second link is done after on this hidden file. - - It is expected that the Linux MSDOS file system - keeps the same pseudo inode when a rename operation - is done on a file in the same directory. - */ - struct umsdos_info info; - ret = umsdos_newhidden (olddir,&info); - if (ret == 0){ - Printk (("olddir[%d] ",olddir->i_count)); - ret = umsdos_rename_f( - olddentry->d_inode, - olddentry, - dir, - dentry, - UMSDOS_HIDDEN); - if (ret == 0){ - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (path == NULL){ - ret = -ENOMEM; - }else{ - struct dentry *temp; - temp = creat_dentry (entry.name, entry.name_len, NULL, NULL); - Printk (("olddir[%d] ",olddir->i_count)); - ret = umsdos_locate_path (oldinode,path); - Printk (("olddir[%d] ",olddir->i_count)); - if (ret == 0){ - olddir->i_count++; - ret = umsdos_symlink_x (olddir - ,temp - ,path - ,S_IFREG|0777,UMSDOS_HLINK); - if (ret == 0){ - dir->i_count++; - ret = umsdos_symlink_x (dir,dentry, - path, - S_IFREG|0777,UMSDOS_HLINK); - } + struct inode *oldinode = olddentry->d_inode; + + /* #Specification: hard link / strategy + * Well ... hard link are difficult to implement on top of an + * MsDOS fat file system. Unlike UNIX file systems, there are no + * inode. A directory entry hold the functionality of the inode + * and the entry. + * + * We will used the same strategy as a normal Unix file system + * (with inode) except we will do it symbolically (using paths). + * + * Because anything can happen during a DOS session (defragment, + * directory sorting, etc...), we can't rely on MsDOS pseudo + * inode number to record the link. For this reason, the link + * will be done using hidden symbolic links. The following + * scenario illustrate how it work. + * + * Given a file /foo/file + * + * # + * ln /foo/file /tmp/file2 + * + * become internally + * + * mv /foo/file /foo/-LINK1 + * ln -s /foo/-LINK1 /foo/file + * ln -s /foo/-LINK1 /tmp/file2 + * # + * + * Using this strategy, we can operate on /foo/file or /foo/file2. + * We can remove one and keep the other, like a normal Unix hard link. + * We can rename /foo/file or /tmp/file2 independently. + * + * The entry -LINK1 will be hidden. It will hold a link count. + * When all link are erased, the hidden file is erased too. + */ + /* #Specification: weakness / hard link + * The strategy for hard link introduces a side effect that + * may or may not be acceptable. Here is the sequence + * + * # + * mkdir subdir1 + * touch subdir1/file + * mkdir subdir2 + * ln subdir1/file subdir2/file + * rm subdir1/file + * rmdir subdir1 + * rmdir: subdir1: Directory not empty + * # + * + * This happen because there is an invisible file (--link) in + * subdir1 which is referenced by subdir2/file. + * + * Any idea ? + */ + /* #Specification: weakness / hard link / rename directory + * Another weakness of hard link come from the fact that + * it is based on hidden symbolic links. Here is an example. + * + * # + * mkdir /subdir1 + * touch /subdir1/file + * mkdir /subdir2 + * ln /subdir1/file subdir2/file + * mv /subdir1 subdir3 + * ls -l /subdir2/file + * # + * + * Since /subdir2/file is a hidden symbolic link + * to /subdir1/..hlinkNNN, accessing it will fail since + * /subdir1 does not exist anymore (has been renamed). + */ + int ret = 0; + + if (S_ISDIR (oldinode->i_mode)) { + /* #Specification: hard link / directory + * A hard link can't be made on a directory. EPERM is returned + * in this case. + */ + ret = -EPERM; + } else if ((ret = umsdos_nevercreat (dir, dentry, -EPERM)) == 0) { + struct inode *olddir; + + ret = umsdos_get_dirowner (oldinode, &olddir); + Printk (("umsdos_link dir_owner = %lu -> %p [%d] ", + oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count)); + if (ret == 0) { + struct umsdos_dirent entry; + + umsdos_lockcreate2 (dir, olddir); + ret = umsdos_inode2entry (olddir, oldinode, &entry); + if (ret == 0) { + Printk (("umsdos_link :%.*s: ino %lu flags %d " + ,entry.name_len, entry.name + ,oldinode->i_ino, entry.flags)); + if (!(entry.flags & UMSDOS_HIDDEN)) { + /* #Specification: hard link / first hard link + * The first time a hard link is done on a file, this + * file must be renamed and hidden. Then an internal + * symbolic link must be done on the hidden file. + * + * The second link is done after on this hidden file. + * + * It is expected that the Linux MSDOS file system + * keeps the same pseudo inode when a rename operation + * is done on a file in the same directory. + */ + struct umsdos_info info; + + ret = umsdos_newhidden (olddir, &info); + if (ret == 0) { + Printk (("olddir[%d] ", olddir->i_count)); + ret = umsdos_rename_f (olddentry->d_inode, olddentry, dir, dentry, UMSDOS_HIDDEN); + if (ret == 0) { + char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); + + if (path == NULL) { + ret = -ENOMEM; + } else { + struct dentry *temp; + + temp = creat_dentry (entry.name, entry.name_len, NULL, NULL); + Printk (("olddir[%d] ", olddir->i_count)); + ret = umsdos_locate_path (oldinode, path); + Printk (("olddir[%d] ", olddir->i_count)); + if (ret == 0) { + inc_count (olddir); + ret = umsdos_symlink_x (olddir, temp, path, S_IFREG | 0777, UMSDOS_HLINK); + if (ret == 0) { + inc_count (dir); + ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK); + } + } + kfree (path); + } + } + } + } else { + char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); + + if (path == NULL) { + ret = -ENOMEM; + } else { + ret = umsdos_locate_path (oldinode, path); + if (ret == 0) { + inc_count (dir); + ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK); + } + kfree (path); + } + } + } + umsdos_unlockcreate (olddir); + umsdos_unlockcreate (dir); } - kfree (path); - } - } - } - }else{ - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (path == NULL){ - ret = -ENOMEM; - }else{ - ret = umsdos_locate_path (oldinode,path); - if (ret == 0){ - dir->i_count++; - ret = umsdos_symlink_x (dir,dentry,path - ,S_IFREG|0777,UMSDOS_HLINK); - } - kfree (path); - } + /* iput (olddir); FIXME */ } - } - umsdos_unlockcreate(olddir); - umsdos_unlockcreate(dir); - } - /* iput (olddir); FIXME */ - } - if (ret == 0){ - struct iattr newattrs; - oldinode->i_nlink++; - newattrs.ia_valid = 0; - ret = UMSDOS_notify_change(olddentry, &newattrs); - } + if (ret == 0) { + struct iattr newattrs; + oldinode->i_nlink++; + newattrs.ia_valid = 0; + ret = UMSDOS_notify_change (olddentry, &newattrs); + } /* dput (olddentry); - dput (dentry); FIXME.... */ - - Printk (("umsdos_link %d\n",ret)); - return ret; + * dput (dentry); FIXME.... */ + + Printk (("umsdos_link %d\n", ret)); + return ret; } /* - Add a new file into the alternate directory. - The file is added to the real MSDOS directory. If successful, it - is then added to the EDM file. - - Return the status of the operation. 0 mean success. -*/ + * Add a new file into the alternate directory. + * The file is added to the real MSDOS directory. If successful, it + * is then added to the EDM file. + * + * Return the status of the operation. 0 mean success. + */ int UMSDOS_create ( - struct inode *dir, - struct dentry *dentry, - int mode /* Permission bit + file type ??? */ - ) /* Will hold the inode of the newly created */ - /* file */ -{ - return umsdos_create_any (dir,dentry,mode,0,0); + struct inode *dir, + struct dentry *dentry, + int mode /* Permission bit + file type ??? */ +) +{ /* Will hold the inode of the newly created file */ + Printk ((KERN_ERR "UMSDOS_create: entering\n")); + check_dentry (dentry); + return umsdos_create_any (dir, dentry, mode, 0, 0); } /* - Add a sub-directory in a directory -*/ -int UMSDOS_mkdir( - struct inode * dir, - struct dentry *dentry, - int mode) + * Add a sub-directory in a directory + */ +int UMSDOS_mkdir ( + struct inode *dir, + struct dentry *dentry, + int mode) { - int ret = umsdos_nevercreat(dir,dentry,-EEXIST); - if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); - Printk (("umsdos_mkdir %d\n",ret)); - if (ret == 0){ - info.entry.mode = mode | S_IFDIR; - info.entry.rdev = 0; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) - ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime - = CURRENT_TIME; - info.entry.flags = 0; - umsdos_lockcreate(dir); - info.entry.nlink = 1; - ret = umsdos_newentry (dir,&info); - Printk (("newentry %d ",ret)); - if (ret == 0){ - struct dentry *temp, *tdir; - tdir = creat_dentry ("mkd-dir", 7, dir, NULL); - temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); - dir->i_count++; - ret = msdos_mkdir (dir, temp, mode); - - if (ret != 0){ - umsdos_delentry (dir,&info,1); - /* #Specification: mkdir / Directory already exist in DOS - We do the same thing as for file creation. - For all user it is an error. - */ - }else{ - /* #Specification: mkdir / umsdos directory / create EMD - When we created a new sub-directory in a UMSDOS - directory (one with full UMSDOS semantic), we - create immediately an EMD file in the new - sub-directory so it inherit UMSDOS semantic. - */ - struct inode *subdir; - ret = compat_umsdos_real_lookup (dir,info.fake.fname, - info.fake.len,&subdir); - if (ret == 0){ - struct dentry *tdentry, *tdsub; - tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL); - tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub); - ret = msdos_create (subdir, tdentry, S_IFREG|0777); - kill_dentry (tdentry); /* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-) FIXME */ - kill_dentry (tdsub); - umsdos_setup_dir_inode (subdir); /* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */ - subdir = NULL; - d_instantiate(dentry, temp->d_inode); - /* iput (result); FIXME */ - } - if (ret < 0){ - printk ("UMSDOS: Can't create empty --linux-.---\n"); - } - - - /* iput (subdir); FIXME */ + int ret = umsdos_nevercreat (dir, dentry, -EEXIST); + + if (ret == 0) { + struct umsdos_info info; + + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); + Printk (("umsdos_mkdir %d\n", ret)); + if (ret == 0) { + info.entry.mode = mode | S_IFDIR; + info.entry.rdev = 0; + info.entry.uid = current->fsuid; + info.entry.gid = (dir->i_mode & S_ISGID) + ? dir->i_gid : current->fsgid; + info.entry.ctime = info.entry.atime = info.entry.mtime + = CURRENT_TIME; + info.entry.flags = 0; + umsdos_lockcreate (dir); + info.entry.nlink = 1; + ret = umsdos_newentry (dir, &info); + Printk (("newentry %d ", ret)); + if (ret == 0) { + struct dentry *temp, *tdir; + + tdir = creat_dentry ("mkd-dir", 7, dir, NULL); + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); + inc_count (dir); + ret = msdos_mkdir (dir, temp, mode); + + if (ret != 0) { + umsdos_delentry (dir, &info, 1); + /* #Specification: mkdir / Directory already exist in DOS + * We do the same thing as for file creation. + * For all user it is an error. + */ + } else { + /* #Specification: mkdir / umsdos directory / create EMD + * When we created a new sub-directory in a UMSDOS + * directory (one with full UMSDOS semantic), we + * create immediately an EMD file in the new + * sub-directory so it inherit UMSDOS semantic. + */ + struct inode *subdir; + + ret = compat_umsdos_real_lookup (dir, info.fake.fname, + info.fake.len, &subdir); + if (ret == 0) { + struct dentry *tdentry, + *tdsub; + + tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL); + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub); + ret = msdos_create (subdir, tdentry, S_IFREG | 0777); + kill_dentry (tdentry); /* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-) FIXME */ + kill_dentry (tdsub); + umsdos_setup_dir_inode (subdir); /* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */ + subdir = NULL; + d_instantiate (dentry, temp->d_inode); + /* iput (result); FIXME */ + } + if (ret < 0) { + printk ("UMSDOS: Can't create empty --linux-.---\n"); + } + /* iput (subdir); FIXME */ + } + } + umsdos_unlockcreate (dir); + } } - } - umsdos_unlockcreate(dir); - } - } - Printk (("umsdos_mkdir %d\n",ret)); - /* dput (dentry); / * FIXME /mn/ */ - return ret; + Printk (("umsdos_mkdir %d\n", ret)); + /* dput (dentry); / * FIXME /mn/ */ + return ret; } /* - Add a new device special file into a directory. -*/ -int UMSDOS_mknod( - struct inode * dir, - struct dentry *dentry, - int mode, - int rdev) + * Add a new device special file into a directory. + */ +int UMSDOS_mknod ( + struct inode *dir, + struct dentry *dentry, + int mode, + int rdev) { - /* #Specification: Special files / strategy - Device special file, pipes, etc ... are created like normal - file in the msdos file system. Of course they remain empty. - - One strategy was to create those files only in the EMD file - since they were not important for MSDOS. The problem with - that, is that there were not getting inode number allocated. - The MSDOS filesystems is playing a nice game to fake inode - number, so why not use it. - - The absence of inode number compatible with those allocated - for ordinary files was causing major trouble with hard link - in particular and other parts of the kernel I guess. - */ - - int ret = umsdos_create_any (dir,dentry,mode,rdev,0); - /* dput(dentry); / * /mn/ FIXME! */ - return ret; + /* #Specification: Special files / strategy + * Device special file, pipes, etc ... are created like normal + * file in the msdos file system. Of course they remain empty. + * + * One strategy was to create those files only in the EMD file + * since they were not important for MSDOS. The problem with + * that, is that there were not getting inode number allocated. + * The MSDOS filesystems is playing a nice game to fake inode + * number, so why not use it. + * + * The absence of inode number compatible with those allocated + * for ordinary files was causing major trouble with hard link + * in particular and other parts of the kernel I guess. + */ + + int ret; + + check_dentry (dentry); + ret = umsdos_create_any (dir, dentry, mode, rdev, 0); + check_dentry (dentry); + + /* dput(dentry); / * /mn/ FIXME! */ + return ret; } /* - Remove a sub-directory. -*/ -int UMSDOS_rmdir( - struct inode * dir, - struct dentry *dentry) + * Remove a sub-directory. + */ +int UMSDOS_rmdir ( + struct inode *dir, + struct dentry *dentry) { - /* #Specification: style / iput strategy - In the UMSDOS project, I am trying to apply a single - programming style regarding inode management. Many - entry point are receiving an inode to act on, and must - do an iput() as soon as they are finished with - the inode. - - For simple case, there is no problem. When you introduce - error checking, you end up with many iput placed around the - code. - - The coding style I use all around is one where I am trying - to provide independent flow logic (I don't know how to - name this). With this style, code is easier to understand - but you rapidly get iput() all around. Here is an exemple - of what I am trying to avoid. - - # - if (a){ - ... - if(b){ - ... - } - ... - if (c){ - // Complex state. Was b true ? - ... - } - ... - } - // Weird state - if (d){ - // ... - } - // Was iput finally done ? - return status; - # - - Here is the style I am using. Still sometime I do the - first when things are very simple (or very complicated :-( ) - - # - if (a){ - if (b){ - ... - }else if (c){ - // A single state gets here - } - }else if (d){ - ... - } - return status; - # - - Again, while this help clarifying the code, I often get a lot - of iput(), unlike the first style, where I can place few - "strategic" iput(). "strategic" also mean, more difficult - to place. - - So here is the style I will be using from now on in this project. - There is always an iput() at the end of a function (which has - to do an iput()). One iput by inode. There is also one iput() - at the places where a successful operation is achieved. This - iput() is often done by a sub-function (often from the msdos - file system). So I get one too many iput() ? At the place - where an iput() is done, the inode is simply nulled, disabling - the last one. - - # - if (a){ - if (b){ - ... - }else if (c){ - msdos_rmdir(dir,...); - dir = NULL; - } - }else if (d){ - ... - } - iput (dir); - return status; - # - - Note that the umsdos_lockcreate() and umsdos_unlockcreate() function - pair goes against this practice of "forgetting" the inode as soon - as possible. - */ - - int ret; - - ret = umsdos_nevercreat(dir,dentry,-EPERM); - if (ret == 0){ - volatile struct inode *sdir; - dir->i_count++; - ret = umsdos_lookup_x (dir, dentry, 0); - sdir = dentry->d_inode; - Printk (("rmdir lookup %d ",ret)); - if (ret == 0){ - int empty; - umsdos_lockcreate(dir); - if (sdir->i_count > 1){ - Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1\n", sdir->i_count)); - ret = -EBUSY; - }else if ((empty = umsdos_isempty (sdir)) != 0){ - struct dentry *tdentry, *tedir; - tedir = creat_dentry ("emd-rmd", 7, dir, NULL); - tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir); - umsdos_real_lookup (dir, tdentry); /* fill inode part */ - Printk (("isempty %d i_count %d ",empty,sdir->i_count)); + /* #Specification: style / iput strategy + * In the UMSDOS project, I am trying to apply a single + * programming style regarding inode management. Many + * entry point are receiving an inode to act on, and must + * do an iput() as soon as they are finished with + * the inode. + * + * For simple case, there is no problem. When you introduce + * error checking, you end up with many iput placed around the + * code. + * + * The coding style I use all around is one where I am trying + * to provide independent flow logic (I don't know how to + * name this). With this style, code is easier to understand + * but you rapidly get iput() all around. Here is an exemple + * of what I am trying to avoid. + * + * # + * if (a){ + * ... + * if(b){ + * ... + * } + * ... + * if (c){ + * // Complex state. Was b true ? + * ... + * } + * ... + * } + * // Weird state + * if (d){ + * // ... + * } + * // Was iput finally done ? + * return status; + * # + * + * Here is the style I am using. Still sometime I do the + * first when things are very simple (or very complicated :-( ) + * + * # + * if (a){ + * if (b){ + * ... + * }else if (c){ + * // A single state gets here + * } + * }else if (d){ + * ... + * } + * return status; + * # + * + * Again, while this help clarifying the code, I often get a lot + * of iput(), unlike the first style, where I can place few + * "strategic" iput(). "strategic" also mean, more difficult + * to place. + * + * So here is the style I will be using from now on in this project. + * There is always an iput() at the end of a function (which has + * to do an iput()). One iput by inode. There is also one iput() + * at the places where a successful operation is achieved. This + * iput() is often done by a sub-function (often from the msdos + * file system). So I get one too many iput() ? At the place + * where an iput() is done, the inode is simply nulled, disabling + * the last one. + * + * # + * if (a){ + * if (b){ + * ... + * }else if (c){ + * msdos_rmdir(dir,...); + * dir = NULL; + * } + * }else if (d){ + * ... + * } + * iput (dir); + * return status; + * # + * + * Note that the umsdos_lockcreate() and umsdos_unlockcreate() function + * pair goes against this practice of "forgetting" the inode as soon + * as possible. + */ + + int ret; + + ret = umsdos_nevercreat (dir, dentry, -EPERM); + if (ret == 0) { + volatile struct inode *sdir; + + inc_count (dir); + ret = umsdos_lookup_x (dir, dentry, 0); + sdir = dentry->d_inode; + Printk (("rmdir lookup %d ", ret)); + if (ret == 0) { + int empty; + + umsdos_lockcreate (dir); + + Printk ((" /mn/ rmdir: FIXME EBUSY TEST: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count)); + sdir->i_count = 1; /* /mn/ FIXME! DELME! FOR TEST ONLY ! */ + + if (sdir->i_count > 1) { + Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count)); + ret = -EBUSY; + } else if ((empty = umsdos_isempty (sdir)) != 0) { + struct dentry *tdentry, *tedir; + + tedir = creat_dentry ("emd-rmd", 7, dir, NULL); + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir); + umsdos_real_lookup (dir, tdentry); /* fill inode part */ + Printk (("isempty %d i_count %d ", empty, sdir->i_count)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || - current->fsuid == sdir->i_uid || - current->fsuid == dir->i_uid ) { - if (empty == 1){ - /* We have to remove the EMD file */ - ret = msdos_unlink (sdir, tdentry); - Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret)); - sdir = NULL; - } - /* sdir must be free before msdos_rmdir() */ - /* iput (sdir); FIXME */ - sdir = NULL; - Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink)); - if (ret == 0){ - struct umsdos_info info; - struct dentry *temp, *tdir; - dir->i_count++; - umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); - /* The findentry is there only to complete */ - /* the mangling */ - umsdos_findentry (dir,&info,2); - - tdir = creat_dentry ("dir-rmd", 7, dir, NULL); - temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); - umsdos_real_lookup (dir, temp); /* fill inode part */ - - Printk ((KERN_ERR " rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */ - Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino)); - Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); - - ret = msdos_rmdir (dir, temp); - - Printk ((KERN_ERR " rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */ - Printk ((KERN_ERR " rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); - Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode)); - Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); - - kill_dentry (tdir); - kill_dentry (temp); - - if (ret == 0){ - ret = umsdos_delentry (dir,&info,1); - d_delete (dentry); - } - } - }else{ - /* sticky bit set and we don't have permission */ - Printk(("sticky set ")); - ret = -EPERM; + if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) || + current->fsuid == sdir->i_uid || + current->fsuid == dir->i_uid) { + if (empty == 1) { + /* We have to remove the EMD file */ + ret = msdos_unlink (sdir, tdentry); + Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret)); + sdir = NULL; + } + /* sdir must be free before msdos_rmdir() */ + /* iput (sdir); FIXME */ + sdir = NULL; + Printk (("isempty ret %d nlink %d ", ret, dir->i_nlink)); + if (ret == 0) { + struct umsdos_info info; + struct dentry *temp, *tdir; + + inc_count (dir); + umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); + /* The findentry is there only to complete */ + /* the mangling */ + umsdos_findentry (dir, &info, 2); + + tdir = creat_dentry ("dir-rmd", 7, dir, NULL); + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); + umsdos_real_lookup (dir, temp); /* fill inode part */ + + Printk ((KERN_ERR " rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */ + Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino)); + Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); + + ret = msdos_rmdir (dir, temp); + + Printk ((KERN_ERR " rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */ + Printk ((KERN_ERR " rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); + Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode)); + Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); + + kill_dentry (tdir); + kill_dentry (temp); + + if (ret == 0) { + ret = umsdos_delentry (dir, &info, 1); + d_delete (dentry); + } + } + } else { + /* sticky bit set and we don't have permission */ + Printk (("sticky set ")); + ret = -EPERM; + } + } else { + /* + * The subdirectory is not empty, so leave it there + */ + ret = -ENOTEMPTY; + } + /* iput(sdir); FIXME */ + umsdos_unlockcreate (dir); + } } - }else{ - /* - The subdirectory is not empty, so leave it there - */ - ret = -ENOTEMPTY; - } - /* iput(sdir); FIXME */ - umsdos_unlockcreate(dir); - } - } - /* dput(dentry); FIXME /mn/ */ - Printk (("umsdos_rmdir %d\n",ret)); - return ret; + /* dput(dentry); FIXME /mn/ */ + Printk (("umsdos_rmdir %d\n", ret)); + return ret; } /* - Remove a file from the directory. -*/ + * Remove a file from the directory. + */ int UMSDOS_unlink ( - struct inode * dir, - struct dentry *dentry) + struct inode *dir, + struct dentry *dentry) { - int ret; - Printk ((" *** UMSDOS_unlink entering /mn/ *** \n")); - - ret = umsdos_nevercreat(dir,dentry,-EPERM); - - Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret)); - - if (ret == 0){ - struct umsdos_info info; - ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); - if (ret == 0){ - umsdos_lockcreate(dir); - ret = umsdos_findentry(dir,&info,1); - Printk (("UMSDOS_unlink: findentry returned %d\n", ret)); - if (ret == 0){ - Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname)); + int ret; + + Printk ((" *** UMSDOS_unlink entering /mn/ *** \n")); + + ret = umsdos_nevercreat (dir, dentry, -EPERM); + + Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret)); + + if (ret == 0) { + struct umsdos_info info; + + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); + if (ret == 0) { + umsdos_lockcreate (dir); + ret = umsdos_findentry (dir, &info, 1); + Printk (("UMSDOS_unlink: findentry returned %d\n", ret)); + if (ret == 0) { + Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || - current->fsuid == info.entry.uid || - current->fsuid == dir->i_uid ) { - if (info.entry.flags & UMSDOS_HLINK){ - /* #Specification: hard link / deleting a link - When we deletes a file, and this file is a link - we must subtract 1 to the nlink field of the - hidden link. - - If the count goes to 0, we delete this hidden - link too. - */ - /* - First, get the inode of the hidden link - using the standard lookup function. - */ - struct inode *inode; - dir->i_count++; - ret = umsdos_lookup_x (dir, dentry, 0); - inode = dentry->d_inode; - if (ret == 0){ - Printk (("unlink nlink = %d ",inode->i_nlink)); - inode->i_nlink--; - if (inode->i_nlink == 0){ - struct inode *hdir = iget(inode->i_sb - ,inode->u.umsdos_i.i_dir_owner); - struct umsdos_dirent entry; - ret = umsdos_inode2entry (hdir,inode,&entry); - if (ret == 0){ - ret = UMSDOS_unlink (hdir,dentry); - }else{ - /* iput (hdir); FIXME */ + if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) || + current->fsuid == info.entry.uid || + current->fsuid == dir->i_uid) { + if (info.entry.flags & UMSDOS_HLINK) { + /* #Specification: hard link / deleting a link + * When we deletes a file, and this file is a link + * we must subtract 1 to the nlink field of the + * hidden link. + * + * If the count goes to 0, we delete this hidden + * link too. + */ + /* + * First, get the inode of the hidden link + * using the standard lookup function. + */ + struct inode *inode; + + inc_count (dir); + ret = umsdos_lookup_x (dir, dentry, 0); + inode = dentry->d_inode; + if (ret == 0) { + Printk (("unlink nlink = %d ", inode->i_nlink)); + inode->i_nlink--; + if (inode->i_nlink == 0) { + struct inode *hdir = iget (inode->i_sb + ,inode->u.umsdos_i.i_dir_owner); + struct umsdos_dirent entry; + + ret = umsdos_inode2entry (hdir, inode, &entry); + if (ret == 0) { + ret = UMSDOS_unlink (hdir, dentry); + } else { + /* iput (hdir); FIXME */ + } + } else { + struct iattr newattrs; + + newattrs.ia_valid = 0; + ret = UMSDOS_notify_change (dentry, &newattrs); + } + /* iput (inode); FIXME */ + } + } + if (ret == 0) { + ret = umsdos_delentry (dir, &info, 0); + if (ret == 0) { + struct dentry *temp, + *tdir; + + Printk (("Avant msdos_unlink %.*s ", info.fake.len, info.fake.fname)); + inc_count (dir); /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */ + tdir = creat_dentry ("dir-del", 7, dir, NULL); /* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */ + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); + umsdos_real_lookup (dir, temp); /* fill inode part */ + + ret = msdos_unlink_umsdos (dir, temp); + Printk (("msdos_unlink %.*s %o ret %d ", info.fake.len, info.fake.fname + ,info.entry.mode, ret)); + + d_delete (dentry); + + kill_dentry (tdir); + kill_dentry (temp); + } + } + } else { + /* sticky bit set and we've not got permission */ + Printk (("sticky set ")); + ret = -EPERM; + } + } + umsdos_unlockcreate (dir); } - }else{ - struct iattr newattrs; - newattrs.ia_valid = 0; - ret = UMSDOS_notify_change (dentry, &newattrs); - } - /* iput (inode); FIXME */ - } - } - if (ret == 0){ - ret = umsdos_delentry (dir,&info,0); - if (ret == 0){ - struct dentry *temp, *tdir; - Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname)); - dir->i_count++; /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */ - tdir = creat_dentry ("dir-del", 7, dir, NULL); /* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */ - temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); - umsdos_real_lookup (dir, temp); /* fill inode part */ - - ret = msdos_unlink_umsdos (dir, temp); - Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname - ,info.entry.mode,ret)); - - d_delete (dentry); - - kill_dentry (tdir); - kill_dentry (temp); - } - } - }else{ - /* sticky bit set and we've not got permission */ - Printk(("sticky set ")); - ret = -EPERM; } - } - umsdos_unlockcreate(dir); - } - } - /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */ - Printk (("umsdos_unlink %d\n",ret)); - return ret; + /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */ + Printk (("umsdos_unlink %d\n", ret)); + return ret; } /* - Rename a file (move) in the file system. -*/ -int UMSDOS_rename( - struct inode * old_dir, - struct dentry * old_dentry, - struct inode * new_dir, - struct dentry * new_dentry) + * Rename a file (move) in the file system. + */ +int UMSDOS_rename ( + struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry) { - /* #Specification: weakness / rename - There is a case where UMSDOS rename has a different behavior - than normal UNIX file system. Renaming an open file across - directory boundary does not work. Renaming an open file within - a directory does work however. - - The problem (not sure) is in the linux VFS msdos driver. - I believe this is not a bug but a design feature, because - an inode number represent some sort of directory address - in the MSDOS directory structure. So moving the file into - another directory does not preserve the inode number. - */ - int ret = umsdos_nevercreat(new_dir,new_dentry,-EEXIST); - if (ret == 0){ - /* umsdos_rename_f eat the inode and we may need those later */ - old_dir->i_count++; - new_dir->i_count++; - ret = umsdos_rename_f (old_dir,old_dentry,new_dir,new_dentry,0); - if (ret == -EEXIST){ - /* #Specification: rename / new name exist - If the destination name already exist, it will - silently be removed. EXT2 does it this way - and this is the spec of SUNOS. So does UMSDOS. - - If the destination is an empty directory it will - also be removed. - */ - /* #Specification: rename / new name exist / possible flaw - The code to handle the deletion of the target (file - and directory) use to be in umsdos_rename_f, surrounded - by proper directory locking. This was insuring that only - one process could achieve a rename (modification) operation - in the source and destination directory. This was also - insuring the operation was "atomic". - - This has been changed because this was creating a kernel - stack overflow (stack is only 4k in the kernel). To avoid - the code doing the deletion of the target (if exist) has - been moved to a upper layer. umsdos_rename_f is tried - once and if it fails with EEXIST, the target is removed - and umsdos_rename_f is done again. - - This makes the code cleaner and (not sure) solve a - deadlock problem one tester was experiencing. - - The point is to mention that possibly, the semantic of - "rename" may be wrong. Anyone dare to check that :-) - Be aware that IF it is wrong, to produce the problem you - will need two process trying to rename a file to the - same target at the same time. Again, I am not sure it - is a problem at all. - */ - /* This is not super efficient but should work */ - new_dir->i_count++; - ret = UMSDOS_unlink (new_dir,new_dentry); - chkstk(); - Printk (("rename unlink ret %d -- ",ret)); - if (ret == -EISDIR){ - new_dir->i_count++; - ret = UMSDOS_rmdir (new_dir,new_dentry); - chkstk(); - Printk (("rename rmdir ret %d -- ",ret)); - } - if (ret == 0){ - ret = umsdos_rename_f(old_dir,old_dentry, - new_dir,new_dentry,0); - new_dir = old_dir = NULL; - } - } - } - /* - dput (new_dentry); - dput (old_dentry); FIXME /mn/ */ - return ret; -} + /* #Specification: weakness / rename + * There is a case where UMSDOS rename has a different behavior + * than normal UNIX file system. Renaming an open file across + * directory boundary does not work. Renaming an open file within + * a directory does work however. + * + * The problem (not sure) is in the linux VFS msdos driver. + * I believe this is not a bug but a design feature, because + * an inode number represent some sort of directory address + * in the MSDOS directory structure. So moving the file into + * another directory does not preserve the inode number. + */ + int ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST); + if (ret == 0) { + /* umsdos_rename_f eat the inode and we may need those later */ + inc_count (old_dir); + inc_count (new_dir); + ret = umsdos_rename_f (old_dir, old_dentry, new_dir, new_dentry, 0); + if (ret == -EEXIST) { + /* #Specification: rename / new name exist + * If the destination name already exist, it will + * silently be removed. EXT2 does it this way + * and this is the spec of SUNOS. So does UMSDOS. + * + * If the destination is an empty directory it will + * also be removed. + */ + /* #Specification: rename / new name exist / possible flaw + * The code to handle the deletion of the target (file + * and directory) use to be in umsdos_rename_f, surrounded + * by proper directory locking. This was insuring that only + * one process could achieve a rename (modification) operation + * in the source and destination directory. This was also + * insuring the operation was "atomic". + * + * This has been changed because this was creating a kernel + * stack overflow (stack is only 4k in the kernel). To avoid + * the code doing the deletion of the target (if exist) has + * been moved to a upper layer. umsdos_rename_f is tried + * once and if it fails with EEXIST, the target is removed + * and umsdos_rename_f is done again. + * + * This makes the code cleaner and (not sure) solve a + * deadlock problem one tester was experiencing. + * + * The point is to mention that possibly, the semantic of + * "rename" may be wrong. Anyone dare to check that :-) + * Be aware that IF it is wrong, to produce the problem you + * will need two process trying to rename a file to the + * same target at the same time. Again, I am not sure it + * is a problem at all. + */ + /* This is not super efficient but should work */ + inc_count (new_dir); + ret = UMSDOS_unlink (new_dir, new_dentry); + chkstk (); + Printk (("rename unlink ret %d -- ", ret)); + if (ret == -EISDIR) { + inc_count (new_dir); + ret = UMSDOS_rmdir (new_dir, new_dentry); + chkstk (); + Printk (("rename rmdir ret %d -- ", ret)); + } + if (ret == 0) { + ret = umsdos_rename_f (old_dir, old_dentry, + new_dir, new_dentry, 0); + new_dir = old_dir = NULL; + } + } + } + /* + * dput (new_dentry); + * dput (old_dentry); FIXME /mn/ */ + return ret; +} diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index 612002c3b..f0252254a 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -30,276 +30,284 @@ struct RDIR_FILLDIR { int real_root; }; -static int rdir_filldir( - void * buf, - const char *name, - int name_len, - off_t offset, - ino_t ino) +static int rdir_filldir ( + void *buf, + const char *name, + int name_len, + off_t offset, + ino_t ino) { - int ret = 0; - struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf; - PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n")); - if (d->real_root){ - PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); - /* real root of a pseudo_rooted partition */ - if (name_len != UMSDOS_PSDROOT_LEN - || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){ - /* So it is not the /linux directory */ - if (name_len == 2 - && name[0] == '.' - && name[1] == '.'){ + int ret = 0; + struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf; + + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n")); + if (d->real_root) { + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); + /* real root of a pseudo_rooted partition */ + if (name_len != UMSDOS_PSDROOT_LEN + || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) { + /* So it is not the /linux directory */ + if (name_len == 2 + && name[0] == '.' + && name[1] == '.') { /* Make sure the .. entry points back to the pseudo_root */ - ino = pseudo_root->i_ino; - } - ret = d->filldir (d->dirbuf,name,name_len,offset,ino); - } - }else{ - /* Any DOS directory */ - PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino)); - ret = d->filldir (d->dirbuf, name, name_len, offset, ino); - } - return ret; + ino = pseudo_root->i_ino; + } + ret = d->filldir (d->dirbuf, name, name_len, offset, ino); + } + } else { + /* Any DOS directory */ + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino)); + ret = d->filldir (d->dirbuf, name, name_len, offset, ino); + } + return ret; } static int UMSDOS_rreaddir ( - struct file *filp, - void *dirbuf, - filldir_t filldir) + struct file *filp, + void *dirbuf, + filldir_t filldir) { - struct RDIR_FILLDIR bufk; - struct inode *dir = filp->f_dentry->d_inode; - - PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf)); + struct RDIR_FILLDIR bufk; + struct inode *dir = filp->f_dentry->d_inode; + + PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf)); - - bufk.filldir = filldir; - bufk.dirbuf = dirbuf; - bufk.real_root = pseudo_root - && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) - && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO); - PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir)); - return fat_readdir(filp, &bufk, rdir_filldir); + + bufk.filldir = filldir; + bufk.dirbuf = dirbuf; + bufk.real_root = pseudo_root + && dir == iget (dir->i_sb, UMSDOS_ROOT_INO) + && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO); + PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n", filldir)); + return fat_readdir (filp, &bufk, rdir_filldir); } /* - Lookup into a non promoted directory. - If the result is a directory, make sure we find out if it is - a promoted one or not (calling umsdos_setup_dir_inode(inode)). -*/ -int umsdos_rlookup_x( - struct inode *dir, - struct dentry *dentry, - int nopseudo) /* Don't care about pseudo root mode */ - /* so locating "linux" will work */ -{ - int len = dentry->d_name.len; - const char *name = dentry->d_name.name; - struct inode *inode; - int ret; - if (pseudo_root - && len == 2 - && name[0] == '.' - && name[1] == '.' - && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) - && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO) ){ - /* *result = pseudo_root;*/ - Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n")); - pseudo_root->i_count++; - ret = 0; - /* #Specification: pseudo root / DOS/.. - In the real root directory (c:\), the directory .. - is the pseudo root (c:\linux). - */ - }else{ - ret = umsdos_real_lookup (dir, dentry); inode=dentry->d_inode; + * Lookup into a non promoted directory. + * If the result is a directory, make sure we find out if it is + * a promoted one or not (calling umsdos_setup_dir_inode(inode)). + */ +int umsdos_rlookup_x ( + struct inode *dir, + struct dentry *dentry, + int nopseudo) +{ /* Don't care about pseudo root mode */ + /* so locating "linux" will work */ + int len = dentry->d_name.len; + const char *name = dentry->d_name.name; + struct inode *inode; + int ret; + + if (pseudo_root + && len == 2 + && name[0] == '.' + && name[1] == '.' + && dir == iget (dir->i_sb, UMSDOS_ROOT_INO) + && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO)) { + /* *result = pseudo_root; */ + Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n")); + inc_count (pseudo_root); + ret = 0; + /* #Specification: pseudo root / DOS/.. + * In the real root directory (c:\), the directory .. + * is the pseudo root (c:\linux). + */ + } else { + ret = umsdos_real_lookup (dir, dentry); + inode = dentry->d_inode; #if 0 - Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret)); - Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode)); - if (inode) { /* /mn/ FIXME: DEL_ME */ - Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino)); - } else { - Printk ((KERN_DEBUG "NONE!\n")); - } + Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret)); + Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode)); + if (inode) { /* /mn/ FIXME: DEL_ME */ + Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino)); + } else { + Printk ((KERN_DEBUG "NONE!\n")); + } #endif - - if ((ret == 0) && inode){ - - if (pseudo_root && inode == pseudo_root && !nopseudo){ - /* #Specification: pseudo root / DOS/linux - Even in the real root directory (c:\), the directory - /linux won't show - */ - Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n")); - ret = -ENOENT; - /* iput (pseudo_root); FIXME */ - - }else if (S_ISDIR(inode->i_mode)){ - /* We must place the proper function table */ - /* depending if this is a MsDOS directory or an UMSDOS directory */ - Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino)); - umsdos_setup_dir_inode (inode); - } - } - } - /* iput (dir); FIXME */ - PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); - return ret; + + if ((ret == 0) && inode) { + + if (pseudo_root && inode == pseudo_root && !nopseudo) { + /* #Specification: pseudo root / DOS/linux + * Even in the real root directory (c:\), the directory + * /linux won't show + */ + Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n")); + ret = -ENOENT; + iput (pseudo_root); /* FIXME? */ + + } else if (S_ISDIR (inode->i_mode)) { + /* We must place the proper function table */ + /* depending if this is a MsDOS directory or an UMSDOS directory */ + Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino)); + umsdos_setup_dir_inode (inode); + } + } + } + iput (dir); /* FIXME? */ + PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); + return ret; } -int UMSDOS_rlookup( - struct inode *dir, - struct dentry *dentry - ) +int UMSDOS_rlookup ( + struct inode *dir, + struct dentry *dentry +) { - PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name)); - return umsdos_rlookup_x(dir,dentry,0); + PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name)); + return umsdos_rlookup_x (dir, dentry, 0); } static int UMSDOS_rrmdir ( - struct inode *dir, - struct dentry *dentry) + struct inode *dir, + struct dentry *dentry) { - /* #Specification: dual mode / rmdir in a DOS directory - In a DOS (not EMD in it) directory, we use a reverse strategy - compared with an Umsdos directory. We assume that a subdirectory - of a DOS directory is also a DOS directory. This is not always - true (umssync may be used anywhere), but make sense. - - So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY - then we check if it is a Umsdos directory. We check if it is - really empty (only . .. and --linux-.--- in it). If it is true - we remove the EMD and do a msdos_rmdir() again. + /* #Specification: dual mode / rmdir in a DOS directory + * In a DOS (not EMD in it) directory, we use a reverse strategy + * compared with an Umsdos directory. We assume that a subdirectory + * of a DOS directory is also a DOS directory. This is not always + * true (umssync may be used anywhere), but make sense. + * + * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY + * then we check if it is a Umsdos directory. We check if it is + * really empty (only . .. and --linux-.--- in it). If it is true + * we remove the EMD and do a msdos_rmdir() again. + * + * In a Umsdos directory, we assume all subdirectory are also + * Umsdos directory, so we check the EMD file first. + */ + int ret; - In a Umsdos directory, we assume all subdirectory are also - Umsdos directory, so we check the EMD file first. - */ - int ret; - if (umsdos_is_pseudodos(dir,dentry)){ - /* #Specification: pseudo root / rmdir /DOS - The pseudo sub-directory /DOS can't be removed! - This is done even if the pseudo root is not a Umsdos - directory anymore (very unlikely), but an accident (under - MsDOS) is always possible. - - EPERM is returned. - */ - ret = -EPERM; - }else{ - umsdos_lockcreate (dir); - dir->i_count++; - ret = msdos_rmdir (dir,dentry); - if (ret == -ENOTEMPTY){ - struct inode *sdir; - dir->i_count++; - - ret = UMSDOS_rlookup (dir,dentry); - sdir = dentry->d_inode; - PRINTK (("rrmdir lookup %d ",ret)); - if (ret == 0){ - int empty; - if ((empty = umsdos_isempty (sdir)) != 0){ - PRINTK (("isempty %d i_count %d ",empty, - atomic_read(&sdir->i_count))); - if (empty == 2){ - /* - Not a Umsdos directory, so the previous msdos_rmdir - was not lying :-) - */ - ret = -ENOTEMPTY; - }else if (empty == 1){ - /* We have to removed the EMD file */ - struct dentry *temp; - temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */ - ret = msdos_unlink(sdir, temp); - sdir = NULL; - if (ret == 0){ - dir->i_count++; - ret = msdos_rmdir (dir,dentry); - } - } - }else{ - ret = -ENOTEMPTY; - } - /* iput (sdir); FIXME */ - } - } - umsdos_unlockcreate (dir); - } - /* iput (dir); FIXME */ - return ret; -} - -/* #Specification: dual mode / introduction - One goal of UMSDOS is to allow a practical and simple coexistence - between MsDOS and Linux in a single partition. Using the EMD file - in each directory, UMSDOS add Unix semantics and capabilities to - normal DOS file system. To help and simplify coexistence, here is - the logic related to the EMD file. - - If it is missing, then the directory is managed by the MsDOS driver. - The names are limited to DOS limits (8.3). No links, no device special - and pipe and so on. + if (umsdos_is_pseudodos (dir, dentry)) { + /* #Specification: pseudo root / rmdir /DOS + * The pseudo sub-directory /DOS can't be removed! + * This is done even if the pseudo root is not a Umsdos + * directory anymore (very unlikely), but an accident (under + * MsDOS) is always possible. + * + * EPERM is returned. + */ + ret = -EPERM; + } else { + umsdos_lockcreate (dir); + inc_count (dir); + ret = msdos_rmdir (dir, dentry); + if (ret == -ENOTEMPTY) { + struct inode *sdir; - If it is there, it is the directory. If it is there but empty, then - the directory looks empty. The utility umssync allows synchronisation - of the real DOS directory and the EMD. + inc_count (dir); - Whenever umssync is applied to a directory without EMD, one is - created on the fly. The directory is promoted to full unix semantic. - Of course, the ls command will show exactly the same content as before - the umssync session. + ret = UMSDOS_rlookup (dir, dentry); + sdir = dentry->d_inode; + PRINTK (("rrmdir lookup %d ", ret)); + if (ret == 0) { + int empty; - It is believed that the user/admin will promote directories to unix - semantic as needed. + if ((empty = umsdos_isempty (sdir)) != 0) { + PRINTK (("isempty %d i_count %d ", empty, + atomic_read (&sdir->i_count))); + if (empty == 2) { + /* + * Not a Umsdos directory, so the previous msdos_rmdir + * was not lying :-) + */ + ret = -ENOTEMPTY; + } else if (empty == 1) { + /* We have to removed the EMD file */ + struct dentry *temp; - The strategy to implement this is to use two function table (struct - inode_operations). One for true UMSDOS directory and one for directory - with missing EMD. + Printk ((KERN_WARNING "UMSDOS_rmdir: hmmm... whatabout inode ? FIXME\n")); + temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */ + ret = msdos_unlink (sdir, temp); + sdir = NULL; + if (ret == 0) { + inc_count (dir); + ret = msdos_rmdir (dir, dentry); + } + } + } else { + ret = -ENOTEMPTY; + } + /* iput (sdir); FIXME */ + } + } + umsdos_unlockcreate (dir); + } + /* iput (dir); FIXME */ + return ret; +} - Functions related to the DOS semantic (but aware of UMSDOS) generally - have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate - from the one with full UMSDOS semantic. -*/ -static struct file_operations umsdos_rdir_operations = { - NULL, /* lseek - default */ - UMSDOS_dir_read, /* read */ - NULL, /* write - bad */ - UMSDOS_rreaddir, /* readdir */ - NULL, /* poll - default */ - UMSDOS_ioctl_dir, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* fsync */ +/* #Specification: dual mode / introduction + * One goal of UMSDOS is to allow a practical and simple coexistence + * between MsDOS and Linux in a single partition. Using the EMD file + * in each directory, UMSDOS add Unix semantics and capabilities to + * normal DOS file system. To help and simplify coexistence, here is + * the logic related to the EMD file. + * + * If it is missing, then the directory is managed by the MsDOS driver. + * The names are limited to DOS limits (8.3). No links, no device special + * and pipe and so on. + * + * If it is there, it is the directory. If it is there but empty, then + * the directory looks empty. The utility umssync allows synchronisation + * of the real DOS directory and the EMD. + * + * Whenever umssync is applied to a directory without EMD, one is + * created on the fly. The directory is promoted to full unix semantic. + * Of course, the ls command will show exactly the same content as before + * the umssync session. + * + * It is believed that the user/admin will promote directories to unix + * semantic as needed. + * + * The strategy to implement this is to use two function table (struct + * inode_operations). One for true UMSDOS directory and one for directory + * with missing EMD. + * + * Functions related to the DOS semantic (but aware of UMSDOS) generally + * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate + * from the one with full UMSDOS semantic. + */ +static struct file_operations umsdos_rdir_operations = +{ + NULL, /* lseek - default */ + UMSDOS_dir_read, /* read */ + NULL, /* write - bad */ + UMSDOS_rreaddir, /* readdir */ + NULL, /* poll - default */ + UMSDOS_ioctl_dir, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ }; -struct inode_operations umsdos_rdir_inode_operations = { - &umsdos_rdir_operations, /* default directory file-ops */ - msdos_create, /* create */ - UMSDOS_rlookup, /* lookup */ - NULL, /* link */ - msdos_unlink, /* unlink */ - NULL, /* symlink */ - msdos_mkdir, /* mkdir */ - UMSDOS_rrmdir, /* rmdir */ - NULL, /* mknod */ - msdos_rename, /* rename */ - NULL, /* readlink */ - NULL, /* followlink */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL, /* updatepage */ - NULL, /* revalidate */ +struct inode_operations umsdos_rdir_inode_operations = +{ + &umsdos_rdir_operations, /* default directory file-ops */ + msdos_create, /* create */ + UMSDOS_rlookup, /* lookup */ + NULL, /* link */ + msdos_unlink, /* unlink */ + NULL, /* symlink */ + msdos_mkdir, /* mkdir */ + UMSDOS_rrmdir, /* rmdir */ + NULL, /* mknod */ + msdos_rename, /* rename */ + NULL, /* readlink */ + NULL, /* followlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL, /* revalidate */ }; - - diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index 3ed550742..32510a46b 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -2,7 +2,7 @@ * linux/fs/umsdos/file.c * * Written 1992 by Jacques Gelinas - * inspired from linux/fs/msdos/file.c Werner Almesberger + * inspired from linux/fs/msdos/file.c Werner Almesberger * * Extended MS-DOS regular file handling primitives */ @@ -26,59 +26,57 @@ static struct file_operations umsdos_symlink_operations; /* - Read the data associate with the symlink. - Return length read in buffer or a negative error code. - -*/ + * Read the data associate with the symlink. + * Return length read in buffer or a negative error code. + * + */ static int umsdos_readlink_x ( - struct dentry *dentry, - char *buffer, - int bufsiz) + struct dentry *dentry, + char *buffer, + int bufsiz) { int ret; loff_t loffs = 0; struct file filp; - fill_new_filp (&filp, NULL); - ret = dentry->d_inode->i_size; - - memset (&filp, 0, sizeof (filp)); - - filp.f_pos = 0; + + check_dentry (dentry); + fill_new_filp (&filp, dentry); + filp.f_reada = 0; filp.f_flags = O_RDONLY; - filp.f_dentry = dentry; - filp.f_op = &umsdos_symlink_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + filp.f_op = &umsdos_symlink_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ - if (ret > bufsiz) ret = bufsiz; + if (ret > bufsiz) + ret = bufsiz; - PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs)); - PRINTK ((KERN_DEBUG " f_op=%p\n", filp.f_op)); - 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 " 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)); + PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs)); + PRINTK ((KERN_DEBUG " f_op=%p\n", filp.f_op)); + 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 " 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)); - PRINTK ((KERN_DEBUG"umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs)); - if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret){ + PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs)); + if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret) { ret = -EIO; } -#if 0 /* DEBUG */ - { - struct umsdos_dirent *mydirent=buffer; +#if 0 /* DEBUG */ + { + struct umsdos_dirent *mydirent = buffer; - 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 + 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 PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%Lu ret=%d\n", loffs, ret)); return ret; @@ -86,7 +84,7 @@ static int umsdos_readlink_x ( -static int UMSDOS_readlink(struct dentry *dentry, char *buffer, int buflen) +static int UMSDOS_readlink (struct dentry *dentry, char *buffer, int buflen) { int ret; @@ -96,67 +94,69 @@ static int UMSDOS_readlink(struct dentry *dentry, char *buffer, int buflen) /* dput(dentry); / * FIXME /mn/ */ Printk ((KERN_WARNING "UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret)); return ret; - + } /* this one mostly stolen from romfs :) */ -static struct dentry *UMSDOS_followlink(struct dentry *dentry, struct dentry *base) +static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *base) { struct inode *inode = dentry->d_inode; - char *symname=NULL; + char *symname = NULL; int len, cnt; - mm_segment_t old_fs = get_fs(); + mm_segment_t old_fs = get_fs (); + Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: (%.*s/%.*s)\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, (int) dentry->d_name.len, dentry->d_name.name)); len = inode->i_size; - if (!(symname = kmalloc(len+1, GFP_KERNEL))) { - dentry = ERR_PTR(-EAGAIN); /* correct? */ + if (!(symname = kmalloc (len + 1, GFP_KERNEL))) { + dentry = ERR_PTR (-EAGAIN); /* correct? */ goto outnobuf; } - set_fs (KERNEL_DS); /* we read into kernel space this time */ PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: Here goes umsdos_readlink_x %p, %p, %d\n", dentry, symname, len)); cnt = umsdos_readlink_x (dentry, symname, len); PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: back from umsdos_readlink_x %p, %p, %d!\n", dentry, symname, len)); set_fs (old_fs); Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: link name is %.*s with len %d\n", cnt, symname, cnt)); - + if (len != cnt) { - dentry = ERR_PTR(-EIO); + dentry = ERR_PTR (-EIO); goto out; } else symname[len] = 0; - dentry = lookup_dentry(symname, base, 1); - kfree(symname); + dentry = lookup_dentry (symname, base, 1); + kfree (symname); if (0) { -out: - kfree(symname); -outnobuf: - dput(base); + out: + kfree (symname); + outnobuf: + dput (base); } return dentry; } -static struct file_operations umsdos_symlink_operations = { - NULL, /* lseek - default */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll - default */ - NULL, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* no special open is needed */ - NULL, /* release */ - NULL /* fsync */ +static struct file_operations umsdos_symlink_operations = +{ + NULL, /* lseek - default */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + NULL /* fsync */ }; -struct inode_operations umsdos_symlink_inode_operations = { - NULL, /* default file operations */ +struct inode_operations umsdos_symlink_inode_operations = +{ + NULL, /* default file operations */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -167,17 +167,14 @@ struct inode_operations umsdos_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - UMSDOS_followlink, /* followlink */ /* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ - generic_readpage, /* readpage */ /* in original NULL. changed to generic_readpage. FIXME? /mn/ */ + UMSDOS_followlink, /* followlink *//* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ + generic_readpage, /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */ NULL, /* writepage */ - fat_bmap, /* bmap */ /* in original NULL. changed to fat_bmap. FIXME? /mn/ */ + fat_bmap, /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* updatepage */ NULL /* revalidate */ - -}; - - +}; |