summaryrefslogtreecommitdiffstats
path: root/fs/umsdos
diff options
context:
space:
mode:
Diffstat (limited to 'fs/umsdos')
-rw-r--r--fs/umsdos/Makefile7
-rw-r--r--fs/umsdos/README20
-rw-r--r--fs/umsdos/check.c31
-rw-r--r--fs/umsdos/dir.c18
-rw-r--r--fs/umsdos/emd.c4
-rw-r--r--fs/umsdos/file.c53
-rw-r--r--fs/umsdos/inode.c91
-rw-r--r--fs/umsdos/ioctl.c19
-rw-r--r--fs/umsdos/mangle.c14
-rw-r--r--fs/umsdos/namei.c269
-rw-r--r--fs/umsdos/rdir.c31
-rw-r--r--fs/umsdos/symlink.c3
12 files changed, 362 insertions, 198 deletions
diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile
index cfba11e63..8bdf98f97 100644
--- a/fs/umsdos/Makefile
+++ b/fs/umsdos/Makefile
@@ -7,10 +7,6 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-ifndef CONFIG_UMSDOS_FS
-CFLAGS := $(CFLAGS) -DMODULE
-endif
-
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
@@ -24,6 +20,9 @@ OBJS= dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o\
umsdos.o: $(OBJS)
$(LD) -r -o umsdos.o $(OBJS)
+modules: umsdos.o
+ ln -sf ../fs/umsdos/umsdos.o $(TOPDIR)/modules
+
clean:
rm -f core *.o *.a *.s
diff --git a/fs/umsdos/README b/fs/umsdos/README
index 4ce8b4148..320dac6ca 100644
--- a/fs/umsdos/README
+++ b/fs/umsdos/README
@@ -16,7 +16,7 @@ It gives you:
There is plenty of documentation on it in the source. A formated document
made from those comments is available from
-sunsite.unc.edu:/pub/Linux/ALPHA/umsdos
+sunsite.unc.edu:/pub/Linux/system/Filesystems/umsdos.
Mostly...
@@ -53,9 +53,9 @@ Now, how to get those --linux-.---.
$5 per directory. Add any applicable taxes.
\end joke_section
-A utility umssync creates those and maintain them. It is available
-from the same directory above (sunsite) in the file umsdos_progs-0.3.tar.gz.
-A compiled version is available in umsdos-0.3a.bin.tar.gz.
+A utility umssync creates those. The kernel maintain them. It is available
+from the same directory above (sunsite) in the file umsdos_progs-0.7.tar.gz.
+A compiled version is available in umsdos_progs-0.7.bin.tar.gz.
So in our example, after mounting mnt, we do
@@ -80,5 +80,17 @@ Umsdos won't notice new files, but will signal removed file (it won't crash).
Using umssync in /etc/rc will make sure the DOS directory is in sync with
the --linux-.---.
+It is a good idea to put the following command in your RC file just
+after the "mount -a":
+
+ mount -a
+ /sbin/umssync -i+ -c+ -r99 /umsdos_mount_point
+
+ (You put one for each umsdos mount point in the fstab)
+
+This will insure nice operation. A umsdos.fsck is in the making,
+so you will be allowed to managed umsdos partition in the same way
+other filesystem are, using the generic fsck front end.
+
Hope this helps!
diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c
index d1102b4ce..7fb060c7a 100644
--- a/fs/umsdos/check.c
+++ b/fs/umsdos/check.c
@@ -1,3 +1,7 @@
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/system.h>
#include <linux/signal.h>
@@ -12,44 +16,35 @@
extern unsigned long high_memory;
-static int check_one_table(unsigned long * page_dir)
+static int check_one_table(struct pde * page_dir)
{
- unsigned long pg_table = *page_dir;
-
- if (!pg_table)
+ if (pgd_none(*page_dir))
return 0;
- if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
+ if (pgd_bad(*page_dir))
return 1;
- }
return 0;
}
/*
- * This function frees up all page tables of a process when it exits.
+ * This function checks all page tables of "current"
*/
void check_page_tables(void)
{
- unsigned long pg_dir;
+ struct pgd * pg_dir;
static int err = 0;
int stack_level = (long)(&pg_dir)-current->kernel_stack_page;
if (stack_level < 1500) printk ("** %d ** ",stack_level);
- pg_dir = current->tss.cr3;
- if (mem_map[MAP_NR(pg_dir)] > 1) {
- return;
- }
- if (err == 0){
- unsigned long *page_dir = (unsigned long *) pg_dir;
- unsigned long *base = page_dir;
+ pg_dir = PAGE_DIR_OFFSET(current, 0);
+ if (err == 0) {
int i;
for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){
int notok = check_one_table(page_dir);
if (notok){
err++;
- printk ("|%d| ",page_dir-base);
+ printk ("|%d:%08lx| ",i, page_dir->pgd);
}
}
- if (err) printk ("Erreur MM %d\n",err);
+ if (err) printk ("\nErreur MM %d\n",err);
}
}
-
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 2a668d102..990260a92 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -7,6 +7,10 @@
* Extended MS-DOS directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
@@ -32,10 +36,14 @@ int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
{
return -EISDIR;
}
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
/*
Read count directory entries from directory filp
Return a negative value from linux/errno.h.
- Return > 0 if success (the length of the file name).
+ Return > 0 if success (The amount of byte written in
+ dirent round_up to a word size (32 bits).
This function is used by the normal readdir VFS entry point and by
some function who try to find out info on a file from a pure MSDOS
@@ -72,7 +80,7 @@ static int umsdos_readdir_x(
put_fs_byte(0,dirent->d_name+3);
put_fs_word (3,&dirent->d_reclen);
if (u_entry != NULL) u_entry->flags = 0;
- ret = 3;
+ ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1);
filp->f_pos++;
}else if (filp->f_pos < 2
|| (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
@@ -191,7 +199,7 @@ static int umsdos_readdir_x(
dirent->d_reclen = entry.name_len;
if (u_entry != NULL) *u_entry = entry;
}
- ret = entry.name_len;
+ ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1);
iput (inode);
break;
}
@@ -219,7 +227,7 @@ static int umsdos_readdir_x(
/*
Read count directory entries from directory filp
Return a negative value from linux/errno.h.
- Return > 0 if success (the length of the file name).
+ Return > 0 if success (the amount of byte written to dirent)
*/
static int UMSDOS_readdir(
struct inode *dir, /* Point to a description of the super block */
@@ -644,7 +652,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
if (*pt == '/') *pt++ = '\0';
if (dir->u.umsdos_i.i_emd_dir == 0){
/* This is a DOS directory */
- ret = msdos_lookup(dir,start,len,result);
+ ret = umsdos_rlookup_x(dir,start,len,result,1);
}else{
ret = umsdos_lookup_x(dir,start,len,result,1);
}
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index e4d6a9470..b1ec47bf6 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -5,6 +5,10 @@
*
* Extended MS-DOS directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/kernel.h>
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index d292ea3c2..61eacaac6 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -7,6 +7,10 @@
* Extended MS-DOS regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
@@ -33,8 +37,10 @@ static int UMSDOS_file_read(
{
/* We have to set the access time because msdos don't care */
int ret = msdos_file_read(inode,filp,buf,count);
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ if (!IS_RDONLY(inode)){
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return ret;
}
/*
@@ -58,16 +64,8 @@ static void UMSDOS_truncate(struct inode *inode)
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
}
-/*
- See inode.c
-
- Some entry point are filled dynamically with function pointers
- from the msdos file_operations and file_inode_operations.
-
- The idea is to have the code as independent as possible from
- the msdos file system.
-*/
+/* Function for normal file system (512 bytes hardware sector size) */
struct file_operations umsdos_file_operations = {
NULL, /* lseek - default */
UMSDOS_file_read, /* read */
@@ -94,10 +92,41 @@ struct inode_operations umsdos_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ msdos_bmap, /* bmap */
UMSDOS_truncate,/* truncate */
NULL, /* permission */
msdos_smap /* smap */
};
+/* For other with larger and unaligned file system */
+struct file_operations umsdos_file_operations_no_bmap = {
+ NULL, /* lseek - default */
+ UMSDOS_file_read, /* read */
+ UMSDOS_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ msdos_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+struct inode_operations umsdos_file_inode_operations_no_bmap = {
+ &umsdos_file_operations_no_bmap, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ UMSDOS_truncate,/* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+};
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 40f7feb68..22be740cc 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -6,6 +6,14 @@
*
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
@@ -13,15 +21,9 @@
#include <linux/errno.h>
#include <asm/segment.h>
#include <linux/string.h>
-#include <linux/ctype.h>
#include <linux/stat.h>
#include <linux/umsdos_fs.h>
-#ifdef MODULE
- #include <linux/module.h>
- #include "../../tools/version.h"
-#endif
-
struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */
/* directory. See UMSDOS_readdir_x() */
@@ -45,6 +47,9 @@ void UMSDOS_put_inode(struct inode *inode)
PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
,inode->u.umsdos_i.i_emd_dir));
+ if (inode != NULL && inode == pseudo_root){
+ printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+ }
msdos_put_inode(inode);
}
@@ -52,15 +57,13 @@ void UMSDOS_put_inode(struct inode *inode)
void UMSDOS_put_super(struct super_block *sb)
{
msdos_put_super(sb);
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif
+ MOD_DEC_USE_COUNT;
}
-void UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
+void UMSDOS_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
{
- msdos_statfs(sb,buf);
+ msdos_statfs(sb,buf,bufsiz);
}
@@ -152,18 +155,11 @@ void umsdos_patch_inode (
if (!umsdos_isinit(inode)){
inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG(inode->i_mode)){
- static char is_init = 0;
- if (!is_init){
- /*
- I don't want to change the msdos file system code
- so I get the address of some subroutine dynamically
- once.
- */
- umsdos_file_inode_operations.bmap = inode->i_op->bmap;
+ if (inode->i_op->bmap != NULL){
inode->i_op = &umsdos_file_inode_operations;
- is_init = 1;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
}
- inode->i_op = &umsdos_file_inode_operations;
}else if (S_ISDIR(inode->i_mode)){
if (dir != NULL){
umsdos_setup_dir_inode(inode);
@@ -408,8 +404,10 @@ struct super_block *UMSDOS_read_super(
which do not have an EMD file. They behave like normal
msdos directory, with all limitation of msdos.
*/
- struct super_block *sb = msdos_read_super(s,data,silent);
- printk ("UMSDOS Alpha 0.5a (compatibility level %d.%d, fast msdos)\n"
+ struct super_block *sb;
+ MOD_INC_USE_COUNT;
+ sb = msdos_read_super(s,data,silent);
+ printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
,UMSDOS_VERSION,UMSDOS_RELEASE);
if (sb != NULL){
sb->s_op = &umsdos_sops;
@@ -420,8 +418,8 @@ struct super_block *UMSDOS_read_super(
/* #Specification: pseudo root / mount
When a umsdos fs is mounted, a special handling is done
if it is the root partition. We check for the presence
- of the file /linux/etc/init or /linux/etc/rc.
- If one is there, we do a chroot("/linux").
+ of the file /linux/etc/init or /linux/etc/rc or
+ /linux/sbin/init. If one is there, we do a chroot("/linux").
We check both because (see init/main.c) the kernel
try to exec init at different place and if it fails
@@ -454,32 +452,48 @@ struct super_block *UMSDOS_read_super(
,UMSDOS_PSDROOT_LEN,&pseudo)==0
&& S_ISDIR(pseudo->i_mode)){
struct inode *etc = NULL;
- struct inode *rc = NULL;
+ struct inode *sbin = NULL;
+ int pseudo_ok = 0;
Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
&& S_ISDIR(etc->i_mode)){
- struct inode *init;
+ struct inode *init = NULL;
+ struct inode *rc = NULL;
Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
if ((umsdos_real_lookup (etc,"init",4,&init)==0
&& S_ISREG(init->i_mode))
|| (umsdos_real_lookup (etc,"rc",2,&rc)==0
&& S_ISREG(rc->i_mode))){
- umsdos_setup_dir_inode (pseudo);
- Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
- pseudo_root = pseudo;
- pseudo->i_count++;
- pseudo = NULL;
+ pseudo_ok = 1;
}
iput (init);
iput (rc);
}
+ if (!pseudo_ok
+ && umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0
+ && S_ISDIR(sbin->i_mode)){
+ struct inode *init = NULL;
+ Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
+ if (umsdos_real_lookup (sbin,"init",4,&init)==0
+ && S_ISREG(init->i_mode)){
+ pseudo_ok = 1;
+ }
+ iput (init);
+ }
+ if (pseudo_ok){
+ umsdos_setup_dir_inode (pseudo);
+ Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
+ pseudo_root = pseudo;
+ pseudo->i_count++;
+ pseudo = NULL;
+ }
+ iput (sbin);
iput (etc);
}
iput (pseudo);
}
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif
+ } else {
+ MOD_DEC_USE_COUNT;
}
return sb;
}
@@ -501,12 +515,7 @@ int init_module(void)
void cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("Umsdos: file system in use, remove delayed\n");
- else
- {
- unregister_filesystem(&umsdos_fs_type);
- }
+ unregister_filesystem(&umsdos_fs_type);
}
#endif
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 972571796..d766ef939 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -5,6 +5,10 @@
*
* Extended MS-DOS ioctl directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -160,6 +164,21 @@ int UMSDOS_ioctl_dir (
umsdos_parse (data.umsdos_dirent.name
,data.umsdos_dirent.name_len,&info);
ret = umsdos_newentry (dir,&info);
+ }else if (cmd == UMSDOS_RENAME_DOS){
+ /* #Specification: ioctl / UMSDOS_RENAME_DOS
+ A file or directory is rename in a DOS directory
+ (not moved across directory). The source name
+ is in the dos_dirent.name field and the destination
+ is in umsdos_dirent.name field.
+
+ This ioctl allows umssync to rename a mangle file
+ name before syncing it back in the EMD.
+ */
+ dir->i_count += 2;
+ ret = msdos_rename (dir
+ ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
+ ,dir
+ ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
}else if (cmd == UMSDOS_UNLINK_EMD){
/* #Specification: ioctl / UMSDOS_UNLINK_EMD
The umsdos_dirent field of the struct umsdos_ioctl is used
diff --git a/fs/umsdos/mangle.c b/fs/umsdos/mangle.c
index 1f59447e9..a7649a39a 100644
--- a/fs/umsdos/mangle.c
+++ b/fs/umsdos/mangle.c
@@ -6,6 +6,10 @@
* Control the mangling of file name to fit msdos name space.
* Many optimisation by GLU == dglaude@is1.vub.ac.be (GLAUDE DAVID)
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/ctype.h>
#include <linux/string.h>
@@ -222,13 +226,15 @@ int umsdos_parse (
with a special character as the first character
of the extension will be mangled. This solve the
following problem:
-
+
+ #
touch FILE
# FILE is invalid for DOS, so mangling is applied
# file.{_1 is created in the DOS directory
touch file.{_1
# To UMSDOS file point to a single DOS entry.
# So file.{_1 has to be mangled.
+ #
*/
static char special[]={
SPECIAL_MANGLING,'\0'
@@ -270,7 +276,9 @@ int umsdos_parse (
Control character are converted to #.
Space are converted to #.
The following character are also converted to #.
+ #
" * + , / : ; < = > ? [ \ ] | ~
+ #
Sometime, the problem is not in MsDOS itself but in
command.com.
@@ -294,7 +302,7 @@ int umsdos_parse (
*/
}else{
/* Conforming MSDOS file name */
- strcpy (info->fake.fname,fname); /* GLU C'est sur on a un 0 a la fin */
+ strncpy (info->fake.fname,fname,len);
info->msdos_reject = 0;
base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
}
@@ -316,10 +324,12 @@ int umsdos_parse (
Here is the list of DOS pseudo devices:
+ #
"prn","con","aux","nul",
"lpt1","lpt2","lpt3","lpt4",
"com1","com2","com3","com4",
"clock$"
+ #
and some standard ones for common DOS programs
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 567039e14..42820bb98 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -6,6 +6,10 @@
*
* Maintain and access the --linux alternate directory file.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -315,7 +319,7 @@ static int umsdos_rename_f(
int flags) /* 0 == copy flags from old_name */
/* != 0, this is the value of flags */
{
- int ret = EPERM;
+ int ret = -EPERM;
struct umsdos_info old_info;
int old_ret = umsdos_parse (old_name,old_len,&old_info);
struct umsdos_info new_info;
@@ -330,58 +334,79 @@ chkstk();
chkstk();
PRINTK (("ret %d ",ret));
if (ret == 0){
- 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 "));
- old_dir->i_count++;
- 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));
+ /* 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){
- /*
- 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;
- 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);
+ PRINTK (("msdos_rename "));
+ old_dir->i_count++;
+ 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){
- printk ("UMSDOS: partial rename for file %s\n"
- ,new_info.entry.name);
+ umsdos_delentry (new_dir,&new_info
+ ,S_ISDIR(new_info.entry.mode));
+chkstk();
}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);
+ ret = umsdos_delentry (old_dir,&old_info
+ ,S_ISDIR(old_info.entry.mode));
chkstk();
- iput (inode);
+ 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;
+ 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;
}
}
umsdos_unlockcreate(old_dir);
@@ -483,6 +508,7 @@ int UMSDOS_link (
Given a file /foo/file
+ #
ln /foo/file /tmp/file2
become internally
@@ -490,6 +516,7 @@ int UMSDOS_link (
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.
@@ -502,6 +529,7 @@ int UMSDOS_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
@@ -509,6 +537,7 @@ int UMSDOS_link (
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.
@@ -519,12 +548,14 @@ int UMSDOS_link (
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
@@ -765,6 +796,7 @@ int UMSDOS_rmdir(
but you rapidly get iput() all around. Here is an exemple
of what I am trying to avoid.
+ #
if (a){
...
if(b){
@@ -783,10 +815,12 @@ int UMSDOS_rmdir(
}
// 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){
...
@@ -797,6 +831,7 @@ int UMSDOS_rmdir(
...
}
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
@@ -812,6 +847,7 @@ int UMSDOS_rmdir(
where an iput() is done, the inode is simply nulled, disabling
the last one.
+ #
if (a){
if (b){
...
@@ -824,6 +860,7 @@ int UMSDOS_rmdir(
}
iput (dir);
return status;
+ #
Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
pair goes against this practice of "forgetting" the inode as soon
@@ -842,28 +879,37 @@ int UMSDOS_rmdir(
ret = -EBUSY;
}else if ((empty = umsdos_isempty (sdir)) != 0){
PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
- if (empty == 1){
- /* We have to removed the EMD file */
- ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
- ,UMSDOS_EMD_NAMELEN);
+ /* 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;
- }
- /* 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;
- 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);
+ PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
if (ret == 0){
- ret = umsdos_delentry (dir,&info,1);
+ struct umsdos_info info;
+ 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{
/*
@@ -887,63 +933,72 @@ int UMSDOS_unlink (
const char * name,
int len)
{
- struct umsdos_info info;
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));
- 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 (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);
+ /* 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;
+ 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{
- iput (hdir);
+ struct iattr newattrs;
+ newattrs.ia_valid = 0;
+ ret = UMSDOS_notify_change (inode, &newattrs);
}
- }else{
- struct iattr newattrs;
- newattrs.ia_valid = 0;
- ret = UMSDOS_notify_change (inode, &newattrs);
+ iput (inode);
}
- iput (inode);
}
- }
- if (ret == 0){
- ret = umsdos_delentry (dir,&info,0);
if (ret == 0){
- PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
- 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));
+ ret = umsdos_delentry (dir,&info,0);
+ if (ret == 0){
+ PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
+ 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);
@@ -986,7 +1041,7 @@ int UMSDOS_rename(
,new_len,0);
if (ret == -EEXIST){
/* #Specification: rename / new name exist
- If the destination name already exist, it will
+ 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.
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index d7272ed96..d708709bd 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -7,6 +7,10 @@
* (For directory without EMD file).
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
@@ -32,8 +36,10 @@ static int UMSDOS_rreaddir (
{
int ret = 0;
while (1){
+ int len = -1;
ret = msdos_readdir(dir,filp,dirent,count);
- if (ret == 5
+ if (ret > 0) len = get_fs_word(&dirent->d_reclen);
+ if (len == 5
&& pseudo_root != NULL
&& dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
/*
@@ -45,7 +51,7 @@ static int UMSDOS_rreaddir (
if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
}else{
if (pseudo_root != NULL
- && ret == 2
+ && len == 2
&& dir == dir->i_sb->s_mounted
&& dir == pseudo_root->i_sb->s_mounted){
char name[2];
@@ -60,11 +66,18 @@ static int UMSDOS_rreaddir (
return ret;
}
-int UMSDOS_rlookup(
+/*
+ Lookup into a non promoted directory.
+ If the result is a directory, make sure we find out if it is
+ a promoted one or not (calling umsdos_setup_dir_inode(inode)).
+*/
+int umsdos_rlookup_x(
struct inode *dir,
const char *name,
int len,
- struct inode **result) /* Will hold inode of the file, if successful */
+ struct inode **result, /* Will hold inode of the file, if successful */
+ int nopseudo) /* Don't care about pseudo root mode */
+ /* so locating "linux" will work */
{
int ret;
if (pseudo_root != NULL
@@ -84,7 +97,7 @@ int UMSDOS_rlookup(
ret = umsdos_real_lookup (dir,name,len,result);
if (ret == 0){
struct inode *inode = *result;
- if (inode == pseudo_root){
+ if (inode == pseudo_root && !nopseudo){
/* #Specification: pseudo root / DOS/linux
Even in the real root directory (c:\), the directory
/linux won't show
@@ -102,6 +115,14 @@ int UMSDOS_rlookup(
iput (dir);
return ret;
}
+int UMSDOS_rlookup(
+ struct inode *dir,
+ const char *name,
+ int len,
+ struct inode **result) /* Will hold inode of the file, if successful */
+{
+ return umsdos_rlookup_x(dir,name,len,result,0);
+}
static int UMSDOS_rrmdir (
struct inode *dir,
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 1b1e561c2..6ab27c5dd 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -6,6 +6,9 @@
*
* Extended MS-DOS regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
#include <asm/segment.h>
#include <asm/system.h>