Пример #1
0
/*
	Locate the EMD file in a directory and optionally, creates it.

	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
*/
struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
{
	struct inode *ret = NULL;
	if (dir->u.umsdos_i.i_emd_dir != 0){
		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
		PRINTK (("deja trouve %d %x [%d] "
			,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
	}else{
		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
		PRINTK (("emd_dir_lookup "));
		if (ret != NULL){
			PRINTK (("Find --linux "));
			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
		}else if (creat){
			int code;
			PRINTK (("avant create "));
			dir->i_count++;
			code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
				,S_IFREG|0777,&ret);
			PRINTK (("Creat EMD code %d ret %x ",code,ret));
			if (ret != NULL){
				dir->u.umsdos_i.i_emd_dir = ret->i_ino;
			}else{
				printk ("UMSDOS: Can't create EMD file\n");
			}
		}
	}
	if (ret != NULL){
		/* Disable UMSDOS_notify_change() for EMD file */
		ret->u.umsdos_i.i_emd_owner = 0xffffffff;
	}
	return ret;
}
Пример #2
0
/*
	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 */
	int nopseudo)			/* Don't care about pseudo root mode */
							/* so locating "linux" will work */
{
	int ret;
	if (pseudo_root != NULL
		&& len == 2
		&& name[0] == '.'
		&& name[1] == '.'
		&& dir == dir->i_sb->s_mounted
		&& dir == pseudo_root->i_sb->s_mounted){
		*result = pseudo_root;
		pseudo_root->i_count++;
		ret = 0;
		/* #Specification: pseudo root / DOS/..
			In the real root directory (c:\), the directory ..
			is the pseudo root (c:\linux).
		*/
	}else{
		ret = umsdos_real_lookup (dir,name,len,result);
		if (ret == 0){
			struct inode *inode = *result;
			if (inode == pseudo_root && !nopseudo){
				/* #Specification: pseudo root / DOS/linux
					Even in the real root directory (c:\), the directory
					/linux won't show
				*/
				ret = -ENOENT;
				iput (pseudo_root);
				*result = NULL;
			}else if (S_ISDIR(inode->i_mode)){
				/* We must place the proper function table */
				/* depending if this is a MsDOS directory or an UMSDOS directory */
				umsdos_setup_dir_inode(inode);
			}
		}
	}
	iput (dir);
	return ret;
}
Пример #3
0
/*
	Perform special function on a directory
*/
int UMSDOS_ioctl_dir (
	struct inode *dir,
	struct file *filp,
	unsigned int cmd,
	unsigned long data)
{
	int ret = -EPERM;
	/* #Specification: ioctl / acces
		Only root (effective id) is allowed to do IOCTL on directory
		in UMSDOS. EPERM is returned for other user.
	*/
	if (current->euid == 0
		|| cmd == UMSDOS_GETVERSION){
		struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
		ret = -EINVAL;
		/* #Specification: ioctl / prototypes
			The official prototype for the umsdos ioctl on directory
			is:

			int ioctl (
				int fd,		// File handle of the directory
				int cmd,	// command
				struct umsdos_ioctl *data)

			The struct and the commands are defined in linux/umsdos_fs.h.

			umsdos_progs/umsdosio.c provide an interface in C++ to all
			these ioctl. umsdos_progs/udosctl is a small utility showing
			all this.

			These ioctl generally allow one to work on the EMD or the
			DOS directory independently. These are essential to implement
			the synchronise.
		*/
		PRINTK (("ioctl %d ",cmd));
		if (cmd == UMSDOS_GETVERSION){
			/* #Specification: ioctl / UMSDOS_GETVERSION
				The field version and release of the structure
				umsdos_ioctl are filled with the version and release
				number of the fs code in the kernel. This will allow
				some form of checking. Users won't be able to run
				incompatible utility such as the synchroniser (umssync).
				umsdos_progs/umsdosio.c enforce this checking.

				Return always 0.
			*/
			put_fs_byte (UMSDOS_VERSION,&idata->version);
			put_fs_byte (UMSDOS_RELEASE,&idata->release);
			ret = 0;
		}else if (cmd == UMSDOS_READDIR_DOS){
			/* #Specification: ioctl / UMSDOS_READDIR_DOS
				One entry is read from the DOS directory at the current
				file position. The entry is put as is in the dos_dirent
				field of struct umsdos_ioctl.

				Return > 0 if success.
			*/
			ret = msdos_readdir(dir,filp,&idata->dos_dirent,1);
		}else if (cmd == UMSDOS_READDIR_EMD){
			/* #Specification: ioctl / UMSDOS_READDIR_EMD
				One entry is read from the EMD at the current
				file position. The entry is put as is in the umsdos_dirent
				field of struct umsdos_ioctl. The corresponding mangled
				DOS entry name is put in the dos_dirent field.

				All entries are read including hidden links. Blank
				entries are skipped.

				Return > 0 if success.
			*/
			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
			if (emd_dir != NULL){
				while (1){
					if (filp->f_pos >= emd_dir->i_size){
						ret = 0;
						break;
					}else{
						struct umsdos_dirent entry;
						off_t f_pos = filp->f_pos;
						ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
						if (ret < 0){
							break;
						}else if (entry.name_len > 0){
							struct umsdos_info info;
							ret = entry.name_len;
							umsdos_parse (entry.name,entry.name_len,&info);
							info.f_pos = f_pos;
							umsdos_manglename(&info);
							memcpy_tofs(&idata->umsdos_dirent,&entry
								,sizeof(entry));
							memcpy_tofs(&idata->dos_dirent.d_name
								,info.fake.fname,info.fake.len+1);
							break;
						}
					}
				}
				iput (emd_dir);
			}else{
				/* The absence of the EMD is simply seen as an EOF */
				ret = 0;
			}
		}else if (cmd == UMSDOS_INIT_EMD){
			/* #Specification: ioctl / UMSDOS_INIT_EMD
				The UMSDOS_INIT_EMD command make sure the EMD
				exist for a directory. If it does not, it is
				created. Also, it makes sure the directory functions
				table (struct inode_operations) is set to the UMSDOS
				semantic. This mean that umssync may be applied to
				an "opened" msdos directory, and it will change behavior
				on the fly.

				Return 0 if success.
			*/
			extern struct inode_operations umsdos_rdir_inode_operations;
			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
			ret = emd_dir != NULL;
			iput (emd_dir);
					
			dir->i_op = ret
				? &umsdos_dir_inode_operations
				: &umsdos_rdir_inode_operations;
		}else{
			struct umsdos_ioctl data;
			memcpy_fromfs (&data,idata,sizeof(data));
			if (cmd == UMSDOS_CREAT_EMD){
				/* #Specification: ioctl / UMSDOS_CREAT_EMD
					The umsdos_dirent field of the struct umsdos_ioctl is used
					as is to create a new entry in the EMD of the directory.
					The DOS directory is not modified.
					No validation is done (yet).

					Return 0 if success.
				*/
				struct umsdos_info info;
				/* This makes sure info.entry and info in general is correctly */
				/* initialised */
				memcpy (&info.entry,&data.umsdos_dirent
					,sizeof(data.umsdos_dirent));
				umsdos_parse (data.umsdos_dirent.name
					,data.umsdos_dirent.name_len,&info);
				ret = umsdos_newentry (dir,&info);
			}else if (cmd == UMSDOS_RENAME_DOS){
				/* #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
					as is to remove an entry from the EMD of the directory.
					No validation is done (yet). The mode field is used
					to validate S_ISDIR or S_ISREG.

					Return 0 if success.
				*/
				struct umsdos_info info;
				/* This makes sure info.entry and info in general is correctly */
				/* initialised */
				memcpy (&info.entry,&data.umsdos_dirent
					,sizeof(data.umsdos_dirent));
				umsdos_parse (data.umsdos_dirent.name
					,data.umsdos_dirent.name_len,&info);
				ret = umsdos_delentry (dir,&info
					,S_ISDIR(data.umsdos_dirent.mode));
			}else if (cmd == UMSDOS_UNLINK_DOS){
				/* #Specification: ioctl / UMSDOS_UNLINK_DOS
					The dos_dirent field of the struct umsdos_ioctl is used to
					execute a msdos_unlink operation. The d_name and d_reclen
					fields are used.

					Return 0 if success.
				*/
				dir->i_count++;
				ret = msdos_unlink (dir,data.dos_dirent.d_name
					,data.dos_dirent.d_reclen);
			}else if (cmd == UMSDOS_RMDIR_DOS){
				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
					The dos_dirent field of the struct umsdos_ioctl is used to
					execute a msdos_unlink operation. The d_name and d_reclen
					fields are used.

					Return 0 if success.
				*/
				dir->i_count++;
				ret = msdos_rmdir (dir,data.dos_dirent.d_name
					,data.dos_dirent.d_reclen);
			}else if (cmd == UMSDOS_STAT_DOS){
				/* #Specification: ioctl / UMSDOS_STAT_DOS
					The dos_dirent field of the struct umsdos_ioctl is
					used to execute a stat operation in the DOS directory.
					The d_name and d_reclen fields are used.

					The following field of umsdos_ioctl.stat are filled.

					st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
					Return 0 if success.
				*/
				struct inode *inode;
				ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
					,data.dos_dirent.d_reclen,&inode);
				if (ret == 0){
					data.stat.st_ino = inode->i_ino;
					data.stat.st_mode = inode->i_mode;
					data.stat.st_size = inode->i_size;
					data.stat.st_atime = inode->i_atime;
					data.stat.st_ctime = inode->i_ctime;
					data.stat.st_mtime = inode->i_mtime;
					memcpy_tofs (&idata->stat,&data.stat,sizeof(data.stat));
					iput (inode);
				}
			}else if (cmd == UMSDOS_DOS_SETUP){
				/* #Specification: ioctl / UMSDOS_DOS_SETUP
					The UMSDOS_DOS_SETUP ioctl allow changing the
					default permission of the MsDOS file system driver
					on the fly. The MsDOS driver apply global permission
					to every file and directory. Normally these permissions
					are controlled by a mount option. This is not
					available for root partition, so a special utility
					(umssetup) is provided to do this, normally in
					/etc/rc.local.

					Be aware that this apply ONLY to MsDOS directory
					(those without EMD --linux-.---). Umsdos directory
					have independent (standard) permission for each
					and every file.

					The field umsdos_dirent provide the information needed.
					umsdos_dirent.uid and gid sets the owner and group.
					umsdos_dirent.mode set the permissions flags.
				*/
				dir->i_sb->u.msdos_sb.fs_uid = data.umsdos_dirent.uid;
				dir->i_sb->u.msdos_sb.fs_gid = data.umsdos_dirent.gid;
				dir->i_sb->u.msdos_sb.fs_umask = data.umsdos_dirent.mode;
				ret = 0;
			}
		}
	}
	PRINTK (("ioctl return %d\n",ret));
	return ret;
}
Пример #4
0
/*
	Read the super block of an Extended MS-DOS FS.
*/
struct super_block *UMSDOS_read_super(
	struct super_block *s,
	void *data,
	int silent)
{
	/* #Specification: mount / options
		Umsdos run on top of msdos. Currently, it supports no
		mount option, but happily pass all option received to
		the msdos driver. I am not sure if all msdos mount option
		make sense with Umsdos. Here are at least those who
		are useful.
			uid=
			gid=

		These options affect the operation of umsdos in directories
		which do not have an EMD file. They behave like normal
		msdos directory, with all limitation of msdos.
	*/
	struct super_block *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){
		MSDOS_SB(sb)->options.dotsOK = 0;  /* disable hidden==dotfile */
		sb->s_op = &umsdos_sops;
		PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
		umsdos_setup_dir_inode (sb->s_mounted);
		PRINTK (("End umsdos_read_super\n"));
		if (s == super_blocks){
			/* #Specification: pseudo root / mount
				When a umsdos fs is mounted, a special handling is done
				if it is the root partition. We check for the presence
				of the file /linux/etc/init or /linux/etc/rc or
				/linux/sbin/init. If one is there, we do a chroot("/linux").

				We check both because (see init/main.c) the kernel
				try to exec init at different place and if it fails
				it tries /bin/sh /etc/rc. To be consistent with
				init/main.c, many more test would have to be done
				to locate init. Any complain ?

				The chroot is done manually in init/main.c but the
				info (the inode) is located at mount time and store
				in a global variable (pseudo_root) which is used at
				different place in the umsdos driver. There is no
				need to store this variable elsewhere because it
				will always be one, not one per mount.

				This feature allows the installation
				of a linux system within a DOS system in a subdirectory.
	
				A user may install its linux stuff in c:\linux
				avoiding any clash with existing DOS file and subdirectory.
				When linux boots, it hides this fact, showing a normal
				root directory with /etc /bin /tmp ...

				The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
				in the macro UMSDOS_PSDROOT_NAME.
			*/

			struct inode *pseudo;
			Printk (("Mounting root\n"));
			if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
					,UMSDOS_PSDROOT_LEN,&pseudo)==0
				&& S_ISDIR(pseudo->i_mode)){
				struct inode *etc = 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 = 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))){
						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);
		}
	} else {
		MOD_DEC_USE_COUNT;
	}
	return sb;
}