patch-2.1.103 linux/fs/umsdos/namei.c
Next file: linux/fs/umsdos/rdir.c
Previous file: linux/fs/umsdos/mangle.c
Back to the patch index
Back to the overall index
- Lines: 2276
- Date:
Tue May 19 15:06:50 1998
- Orig file:
v2.1.102/linux/fs/umsdos/namei.c
- Orig date:
Thu May 7 22:51:54 1998
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/namei.c linux/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 @@
}
#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"));
+ 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));
+ 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;
}
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov