summaryrefslogtreecommitdiffstats
path: root/fs/umsdos/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/umsdos/namei.c')
-rw-r--r--fs/umsdos/namei.c1862
1 files changed, 938 insertions, 924 deletions
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index b2a1e2e56..76c486405 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -31,97 +31,97 @@
*/
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
*/
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.
*/
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.
+ /* #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.
- 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);
+ 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.
*/
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.
*/
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++;
}
/*
@@ -129,25 +129,27 @@ void umsdos_startlookup (struct inode *dir)
*/
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.
*/
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){}
@@ -156,152 +158,155 @@ static void umsdos_unlockcreate (struct inode *dir){}
void umsdos_endlookup (struct inode *dir){}
#endif
static int umsdos_nevercreat(
- struct inode *dir,
- const char *name, /* Name of the file to add */
- int len,
- int errcod) /* Length of the name */
+ struct inode *dir,
+ struct dentry *dentry,
+ int errcod) /* Length of the name */
{
- int ret = 0;
- if (umsdos_is_pseudodos(dir,name,len)){
- /* #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;
+ 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,
- const char *name, /* Name of the file to add */
- int len, /* Length of the name */
- int mode, /* Permission bit + file type ??? */
- int rdev, /* major, minor or 0 for ordinary file */
- /* and symlinks */
- char flags,
- struct inode **result) /* Will hold the inode of the newly created */
- /* file */
+ 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 = umsdos_nevercreat(dir,name,len,-EEXIST);
+
+ 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);
+
+ 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++;
+ /* FIXME
+ ret = msdos_create (dir,info.fake.fname,info.fake.len
+ ,S_IFREG|0777,result);
+ */
+ ret =msdos_create(dir,dentry,S_IFREG|0777);
if (ret == 0){
- struct umsdos_info info;
- ret = umsdos_parse (name,len,&info);
- *result = NULL;
- 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){
- atomic_inc(&dir->i_count);
- ret = msdos_create (dir,info.fake.fname,info.fake.len
- ,S_IFREG|0777,result);
- if (ret == 0){
- struct inode *inode = *result;
- umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
- PRINTK (("inode %p[%d] ",inode,
- atomic_read(&inode->i_count)));
- PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
- ,info.fake.fname,current->pid,info.f_pos));
- }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.fname,-ret,current->pid,info.f_pos);
- }
- umsdos_delentry (dir,&info,0);
- }
- PRINTK (("umsdos_create %s ret = %d pos %d\n"
- ,info.fake.fname,ret,info.f_pos));
- }
- umsdos_unlockcreate(dir);
- }
+ struct inode *inode = dentry->d_inode;
+ umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+ Printk (("inode %p[%d] ",inode,inode->i_count));
+ Printk (("Creation OK: [%lu] %.*s %d pos %ld\n", dir->i_ino,
+ info.fake.len, info.fake.fname, current->pid, info.f_pos));
+ }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);
}
- iput (dir);
- return ret;
+ 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);
+ 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 */
+ 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;
+ 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() \
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
- printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
- , current->comm,STACK_MAGIC \
- ,*(unsigned long *)current->kernel_stack_page \
- ,__LINE__); \
- }
+if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
+ printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
+ , current->comm,STACK_MAGIC \
+ ,*(unsigned long *)current->kernel_stack_page \
+ ,__LINE__); \
+}
#undef chkstk
#define chkstk() do { } while (0)
@@ -310,794 +315,803 @@ static void umsdos_ren_init(
Rename a file (move) in the file system.
*/
static int umsdos_rename_f(
- struct inode * old_dir,
- const char * old_name,
- int old_len,
- struct inode * new_dir,
- const char * new_name,
- int new_len,
- int flags) /* 0 == copy flags from old_name */
- /* != 0, this is the value of flags */
+ 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_name,old_len,&old_info);
- struct umsdos_info new_info;
- int new_ret = umsdos_parse (new_name,new_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) || fsuser() ||
- 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) || fsuser() ||
- 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){
- PRINTK (("msdos_rename "));
- atomic_inc(&old_dir->i_count);
- atomic_inc(&new_dir->i_count); /* Both inode are needed later */
- ret = msdos_rename (old_dir
- ,old_info.fake.fname,old_info.fake.len
- ,new_dir
- ,new_info.fake.fname,new_info.fake.len);
-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 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;
- atomic_inc(&new_dir->i_count);
- PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
- ret = UMSDOS_lookup (new_dir,new_name,new_len
- ,&inode);
-chkstk();
- if (ret != 0){
- printk ("UMSDOS: partial rename for file %s\n"
- ,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);
- }
- }
- }
- }
- }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;
- }
+ 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) || fsuser() ||
+ 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) || fsuser() ||
+ 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);
+ new = creat_dentry (new_info.fake.fname, new_info.fake.len, 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 */
}
- umsdos_unlockcreate(old_dir);
- umsdos_unlockcreate(new_dir);
+ }
+ }
+ }
+ }else{
+ /* sticky bit set on new_dir */
+ Printk(("sticky set on new "));
+ ret = -EPERM;
}
- iput (old_dir);
- iput (new_dir);
- PRINTK (("\n"));
- return ret;
+ }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;
}
/*
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,
- const char * name,
- int len,
- const char * symname, /* name will point to this path */
- int mode,
- char flags)
+ 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...
- */
- struct inode *inode;
- int ret;
- atomic_inc(&dir->i_count);/* We keep the inode in case we need it */
- /* later */
- ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
- PRINTK (("umsdos_symlink ret %d ",ret));
- if (ret == 0){
- int len = strlen(symname);
- struct file filp;
- filp.f_pos = 0;
- /* Make the inode acceptable to MSDOS */
- ret = umsdos_file_write_kmem (inode,&filp,symname,len);
- iput (inode);
- 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,name,len);
- dir = NULL;
- }
- }
- iput (dir);
- 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;
+ 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;
+ filp.f_pos = 0;
+ /* Make the inode acceptable to MSDOS FIXME */
+ Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
+ ret = umsdos_file_write_kmem (dentry->d_inode, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast...
+ PTW dentry->d_inode is "less incorrect" */
+ /* 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);
+ Printk (("\n"));
+ return ret;
}
/*
- Setup un Symbolic link.
- Return a negative error code or 0 if ok.
+ Setup un Symbolic link.
+ Return a negative error code or 0 if ok.
*/
int UMSDOS_symlink(
- struct inode * dir,
- const char * name,
- int len,
- const char * symname) /* name will point to this path */
+ struct inode * dir,
+ struct dentry *dentry,
+ const char * symname
+ )
{
- return umsdos_symlink_x (dir,name,len,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 inode * oldinode,
- struct inode * dir,
- const char * name,
- int len)
+ struct dentry * olddentry,
+ struct inode * dir,
+ struct dentry *dentry)
{
- /* #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,name,len,-EPERM))==0){
- struct inode *olddir;
- ret = umsdos_get_dirowner(oldinode,&olddir);
- PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
- ,oldinode->u.umsdos_i.i_dir_owner,olddir,
- atomic_read(&olddir->i_count)));
+ 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);
+ Printk (("olddir[%d] ",olddir->i_count));
+ ret = umsdos_locate_path (oldinode,path);
+ Printk (("olddir[%d] ",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 %d flags %d "
- ,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){
- atomic_add(2, &olddir->i_count);
- PRINTK (("olddir[%d] ",
- atomic_read(&olddir->i_count)));
- ret = umsdos_rename_f (olddir,entry.name
- ,entry.name_len
- ,olddir,info.entry.name,info.entry.name_len
- ,UMSDOS_HIDDEN);
- if (ret == 0){
- char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
- if (path == NULL){
- ret = -ENOMEM;
- }else{
- PRINTK (("olddir[%d] ",
- atomic_read(&olddir->i_count)));
- ret = umsdos_locate_path (oldinode,path);
- PRINTK (("olddir[%d] ",
- atomic_read(&olddir->i_count)));
- if (ret == 0){
- atomic_inc(&olddir->i_count);
- ret = umsdos_symlink_x (olddir
- ,entry.name
- ,entry.name_len,path
- ,S_IFREG|0777,UMSDOS_HLINK);
- if (ret == 0){
- atomic_inc(&dir->i_count);
- ret = umsdos_symlink_x (dir,name,len
- ,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){
- atomic_inc(&dir->i_count);
- ret = umsdos_symlink_x (dir,name,len,path
- ,S_IFREG|0777,UMSDOS_HLINK);
- }
- kfree (path);
- }
- }
- }
- umsdos_unlockcreate(olddir);
- umsdos_unlockcreate(dir);
+ 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);
+ }
}
- iput (olddir);
+ 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);
+ }
}
- if (ret == 0){
- struct iattr newattrs;
- oldinode->i_nlink++;
- newattrs.ia_valid = 0;
- ret = UMSDOS_notify_change(oldinode, &newattrs);
- }
- iput (oldinode);
- iput (dir);
- PRINTK (("umsdos_link %d\n",ret));
- return ret;
+ }
+ umsdos_unlockcreate(olddir);
+ umsdos_unlockcreate(dir);
+ }
+ iput (olddir);
+ }
+ if (ret == 0){
+ struct iattr newattrs;
+ oldinode->i_nlink++;
+ newattrs.ia_valid = 0;
+ ret = UMSDOS_notify_change(olddentry, &newattrs);
+ }
+ dput (olddentry);
+ dput (dentry);
+ 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,
- const char *name, /* Name of the file to add */
- int len, /* Length of the name */
- int mode, /* Permission bit + file type ??? */
- struct inode **result) /* Will hold the inode of the newly created */
+ struct inode *dir,
+ struct dentry *dentry, /* Length of the name */
+ int mode /* Permission bit + file type ??? */
+ ) /* Will hold the inode of the newly created */
/* file */
{
- return umsdos_create_any (dir,name,len,mode,0,0,result);
+ return umsdos_create_any (dir,dentry,mode,0,0);
}
/*
Add a sub-directory in a directory
*/
int UMSDOS_mkdir(
- struct inode * dir,
- const char * name,
- int len,
- int mode)
+ struct inode * dir,
+ struct dentry *dentry,
+ int mode)
{
- int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
- if (ret == 0){
- struct umsdos_info info;
- ret = umsdos_parse (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){
- atomic_inc(&dir->i_count);
- ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,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 = umsdos_real_lookup (dir,info.fake.fname
- ,info.fake.len,&subdir);
- if (ret == 0){
- struct inode *result;
- ret = msdos_create (subdir,UMSDOS_EMD_FILE
- ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
- subdir = NULL;
- iput (result);
- }
- if (ret < 0){
- printk ("UMSDOS: Can't create empty --linux-.---\n");
- }
- iput (subdir);
- }
- }
- umsdos_unlockcreate(dir);
- }
+ 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;
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+ 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 inode *result;
+ struct dentry *tdentry;
+ tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+
+ ret = msdos_create (subdir, tdentry,S_IFREG|0777);
+ subdir = NULL;
+ /* iput (result); FIXME */
+ }
+ if (ret < 0){
+ printk ("UMSDOS: Can't create empty --linux-.---\n");
+ }
+ /* iput (subdir); FIXME */
}
- PRINTK (("umsdos_mkdir %d\n",ret));
- iput (dir);
- return ret;
+ }
+ umsdos_unlockcreate(dir);
+ }
+ }
+ Printk (("umsdos_mkdir %d\n",ret));
+ dput (dentry);
+ return ret;
}
/*
Add a new device special file into a directory.
*/
int UMSDOS_mknod(
struct inode * dir,
- const char * name,
- int len,
+ 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.
- */
- struct inode *inode;
- int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
- iput (inode);
- 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 = umsdos_create_any (dir,dentry,mode,rdev,0);
+ dput(dentry);
+ return ret;
}
/*
- Remove a sub-directory.
+ Remove a sub-directory.
*/
int UMSDOS_rmdir(
struct inode * dir,
- const char * name,
- int len)
+ 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;
- #
+ /* #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.
+ */
- Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
- pair goes against this practice of "forgetting" the inode as soon
- as possible.
- */
- int ret = umsdos_nevercreat(dir,name,len,-EPERM);
- if (ret == 0){
- struct inode *sdir;
- atomic_inc(&dir->i_count);
- ret = UMSDOS_lookup (dir,name,len,&sdir);
- PRINTK (("rmdir lookup %d ",ret));
- if (ret == 0){
- int empty;
- umsdos_lockcreate(dir);
- if (atomic_read(&sdir->i_count) > 1){
- ret = -EBUSY;
- }else if ((empty = umsdos_isempty (sdir)) != 0){
- PRINTK (("isempty %d i_count %d ",empty,
- atomic_read(&sdir->i_count)));
+ int 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){
+ ret = -EBUSY;
+ }else if ((empty = umsdos_isempty (sdir)) != 0){
+ struct dentry *tdentry;
+ tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+ Printk (("isempty %d i_count %d ",empty,sdir->i_count));
/* check sticky bit */
- if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
- current->fsuid == sdir->i_uid ||
- current->fsuid == dir->i_uid ) {
- if (empty == 1){
- /* We have to removed the EMD file */
- ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
- ,UMSDOS_EMD_NAMELEN);
- sdir = NULL;
- }
- /* sdir must be free before msdos_rmdir() */
- iput (sdir);
- sdir = NULL;
- PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
- if (ret == 0){
- struct umsdos_info info;
- atomic_inc(&dir->i_count);
- umsdos_parse (name,len,&info);
- /* The findentry is there only to complete */
- /* the mangling */
- umsdos_findentry (dir,&info,2);
- ret = msdos_rmdir (dir,info.fake.fname
- ,info.fake.len);
- if (ret == 0){
- ret = umsdos_delentry (dir,&info,1);
- }
- }
- }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);
- umsdos_unlockcreate(dir);
- }
+ if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ current->fsuid == sdir->i_uid ||
+ current->fsuid == dir->i_uid ) {
+ if (empty == 1){
+ /* We have to removed the EMD file */
+ ret = msdos_unlink (sdir, tdentry);
+ 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;
+ 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);
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+
+ ret = msdos_rmdir (dir, temp);
+ if (ret == 0){
+ ret = umsdos_delentry (dir,&info,1);
+ }
+ }
+ }else{
+ /* sticky bit set and we don't have permission */
+ Printk(("sticky set "));
+ ret = -EPERM;
}
- iput (dir);
- PRINTK (("umsdos_rmdir %d\n",ret));
- return ret;
+ }else{
+ /*
+ The subdirectory is not empty, so leave it there
+ */
+ ret = -ENOTEMPTY;
+ }
+ /* iput(sdir); FIXME */
+ umsdos_unlockcreate(dir);
+ }
+ }
+ dput(dentry);
+ 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,
- const char * name,
- int len)
+ struct dentry *dentry)
{
- int ret = umsdos_nevercreat(dir,name,len,-EPERM);
- if (ret == 0){
- struct umsdos_info info;
- ret = umsdos_parse (name,len,&info);
- if (ret == 0){
- umsdos_lockcreate(dir);
- ret = umsdos_findentry(dir,&info,1);
- if (ret == 0){
- PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
+ int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+ 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);
+ if (ret == 0){
+ Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname));
/* check sticky bit */
- if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
- 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;
- atomic_inc(&dir->i_count);
- ret = UMSDOS_lookup (dir,name,len,&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,entry.name
- ,entry.name_len);
- }else{
- iput (hdir);
- }
- }else{
- struct iattr newattrs;
- newattrs.ia_valid = 0;
- ret = UMSDOS_notify_change (inode, &newattrs);
- }
- iput (inode);
- }
- }
- if (ret == 0){
- ret = umsdos_delentry (dir,&info,0);
- if (ret == 0){
- PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
- atomic_inc(&dir->i_count);
- ret = msdos_unlink_umsdos (dir,info.fake.fname
- ,info.fake.len);
- PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
- ,info.entry.mode,ret));
- }
- }
- }else{
- /* sticky bit set and we've not got permission */
- PRINTK(("sticky set "));
- ret = -EPERM;
- }
- }
- umsdos_unlockcreate(dir);
+ if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ 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 */
}
- }
- iput (dir);
- PRINTK (("umsdos_unlink %d\n",ret));
- return ret;
+ }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;
+ Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname));
+ dir->i_count++;
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+ ret = msdos_unlink_umsdos (dir, temp);
+ Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname
+ ,info.entry.mode,ret));
+ }
+ }
+ }else{
+ /* sticky bit set and we've not got permission */
+ Printk(("sticky set "));
+ ret = -EPERM;
+ }
+ }
+ umsdos_unlockcreate(dir);
+ }
+ }
+ dput(dentry);
+ Printk (("umsdos_unlink %d\n",ret));
+ return ret;
}
+
+
/*
Rename a file (move) in the file system.
*/
int UMSDOS_rename(
- struct inode * old_dir,
- const char * old_name,
- int old_len,
- struct inode * new_dir,
- const char * new_name,
- int new_len)
+ 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_name,new_len,-EEXIST);
- if (ret == 0){
- /* umsdos_rename_f eat the inode and we may need those later */
- atomic_inc(&old_dir->i_count);
- atomic_inc(&new_dir->i_count);
- ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
- ,new_len,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 */
- atomic_inc(&new_dir->i_count);
- ret = UMSDOS_unlink (new_dir,new_name,new_len);
-chkstk();
- PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
- if (ret == -EISDIR){
- atomic_inc(&new_dir->i_count);
- ret = UMSDOS_rmdir (new_dir,new_name,new_len);
-chkstk();
- PRINTK (("rename rmdir ret %d -- ",ret));
- }
- if (ret == 0){
- ret = umsdos_rename_f (old_dir,old_name,old_len
- ,new_dir,new_name,new_len,0);
- new_dir = old_dir = NULL;
- }
- }
- }
- iput (new_dir);
- iput (old_dir);
- 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 */
+ 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);
+ return ret;
}