Esempio n. 1
0
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
	struct buffer_head *bh;
	struct msdos_dir_entry *de;
	struct inode *inode,*dot;
	char msdos_name[MSDOS_NAME];
	int ino,res;

	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
	    msdos_name)) < 0) {
		iput(dir);
		return res;
	}
	lock_creation();
	if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
		unlock_creation();
		brelse(bh);
		iput(dir);
		return -EEXIST;
 	}
	if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
		unlock_creation();
		iput(dir);
		return res;
	}
	dir->i_nlink++;
	inode->i_nlink = 2; /* no need to mark them dirty */
	MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
	if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
	if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
		goto mkdir_error;
	dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
	MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
	dot->i_nlink = inode->i_nlink;
	dot->i_dirt = 1;
	iput(dot);
	if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
		goto mkdir_error;
	unlock_creation();
	dot->i_size = dir->i_size;
	MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
	dot->i_nlink = dir->i_nlink;
	dot->i_dirt = 1;
	MSDOS_I(inode)->i_busy = 0;
	iput(dot);
	iput(inode);
	iput(dir);
	return 0;
mkdir_error:
	iput(inode);
	if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
	unlock_creation();
	return res;
}
Esempio n. 2
0
/* #Specification: pseudo root / rmdir /DOS
 * The pseudo sub-directory /DOS can't be removed!
 * This is done even if the pseudo root is not a Umsdos
 * directory anymore (very unlikely), but an accident (under
 * MS-DOS) is always possible.
 * 
 * EPERM is returned.
 */
static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
{
	int ret, empty;

	ret = -EPERM;
	if (umsdos_is_pseudodos (dir, dentry))
		goto out;

	ret = -EBUSY;
	if (!d_unhashed(dentry))
		goto out;

	ret = msdos_rmdir (dir, dentry);
	if (ret != -ENOTEMPTY)
		goto out;

	empty = umsdos_isempty (dentry);
	if (empty == 1) {
		struct dentry *demd;
		/* We have to remove the EMD file. */
		demd = umsdos_get_emd_dentry(dentry);
		ret = PTR_ERR(demd);
		if (!IS_ERR(demd)) {
			ret = 0;
			if (demd->d_inode)
				ret = msdos_unlink (dentry->d_inode, demd);
			if (!ret)
				d_delete(demd);
			dput(demd);
		}
	}
	if (ret)
		goto out;

	/* now retry the original ... */
	ret = msdos_rmdir (dir, dentry);

out:
	return ret;
}
Esempio n. 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;
}
Esempio n. 4
0
/* #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.
 */
int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd,
			unsigned long data_ptr)
{
	struct dentry *dentry = filp->f_dentry;
	struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr;
	int ret;
	struct file new_filp;
	struct umsdos_ioctl data;

Printk(("UMSDOS_ioctl_dir: %s/%s, cmd=%d, data=%08lx\n",
dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr));

	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
	if (cmd != UMSDOS_GETVERSION
	    && cmd != UMSDOS_READDIR_DOS
	    && cmd != UMSDOS_READDIR_EMD
	    && cmd != UMSDOS_INIT_EMD
	    && cmd != UMSDOS_CREAT_EMD
	    && cmd != UMSDOS_RENAME_DOS
	    && cmd != UMSDOS_UNLINK_EMD
	    && cmd != UMSDOS_UNLINK_DOS
	    && cmd != UMSDOS_RMDIR_DOS
	    && cmd != UMSDOS_STAT_DOS
	    && cmd != UMSDOS_DOS_SETUP)
		return fat_dir_ioctl (dir, filp, cmd, data_ptr);

	/* #Specification: ioctl / acces
	 * Only root (effective id) is allowed to do IOCTL on directory
	 * in UMSDOS. EPERM is returned for other user.
	 */
	/*
	 * Well, not all cases require write access, but it simplifies
	 * the code, and let's face it, there is only one client (umssync)
	 * for all this.
	 */
	ret = verify_area (VERIFY_WRITE, (void *) data_ptr, 
				sizeof (struct umsdos_ioctl));
	if (ret < 0)
		goto out;

	ret = -EPERM;
	if (current->euid != 0 && cmd != UMSDOS_GETVERSION)
		goto out;

	ret = -EINVAL;
	if (cmd == UMSDOS_GETVERSION) {
		/* #Specification: ioctl / UMSDOS_GETVERSION
		 * The field version and release of the structure
		 * umsdos_ioctl are filled with the version and release
		 * number of the fs code in the kernel. This will allow
		 * some form of checking. Users won't be able to run
		 * incompatible utility such as the synchroniser (umssync).
		 * umsdos_progs/umsdosio.c enforce this checking.
		 * 
		 * Return always 0.
		 */
		put_user (UMSDOS_VERSION, &idata->version);
		put_user (UMSDOS_RELEASE, &idata->release);
		ret = 0;
		goto out;
	}
	if (cmd == UMSDOS_READDIR_DOS) {
		/* #Specification: ioctl / UMSDOS_READDIR_DOS
		 * One entry is read from the DOS directory at the current
		 * file position. The entry is put as is in the dos_dirent
		 * field of struct umsdos_ioctl.
		 * 
		 * Return > 0 if success.
		 */
		struct UMSDOS_DIR_ONCE bufk;

		bufk.count = 0;
		bufk.ent = &idata->dos_dirent;

		fat_readdir (filp, &bufk, umsdos_ioctl_fill);

		ret = bufk.count == 1 ? 1 : 0;
		goto out;
	}
	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 dentry *demd;

		/* The absence of the EMD is simply seen as an EOF */
		demd = umsdos_get_emd_dentry(dentry);
		ret = PTR_ERR(demd);
		if (IS_ERR(demd))
			goto out;
		ret = 0;
		if (!demd->d_inode)
			goto read_dput;

		fill_new_filp(&new_filp, demd);
		new_filp.f_pos = filp->f_pos;
		while (new_filp.f_pos < demd->d_inode->i_size) {
			off_t f_pos = new_filp.f_pos;
			struct umsdos_dirent entry;
			struct umsdos_info info;

			ret = umsdos_emd_dir_readentry (&new_filp, &entry);
			if (ret)
				break;
			if (entry.name_len <= 0)
				continue;

			umsdos_parse (entry.name, entry.name_len, &info);
			info.f_pos = f_pos;
			umsdos_manglename (&info);
			ret = -EFAULT;
			if (copy_to_user (&idata->umsdos_dirent, &entry,
							sizeof (entry)))
				break;
			if (copy_to_user (&idata->dos_dirent.d_name,
							info.fake.fname,
				 			info.fake.len + 1))
				break;
			ret = entry.name_len;
			break;
		}
		/* update the original f_pos */
		filp->f_pos = new_filp.f_pos;
	read_dput:
		d_drop(demd);
		dput(demd);
		goto out;
	}
	if (cmd == UMSDOS_INIT_EMD) {
		/* #Specification: ioctl / UMSDOS_INIT_EMD
		 * The UMSDOS_INIT_EMD command makes sure the EMD
		 * exists for a directory. If it does not, it is
		 * created. Also, it makes sure the directory function
		 * 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;

		ret = umsdos_make_emd(dentry);
Printk(("UMSDOS_ioctl_dir: INIT_EMD %s/%s, ret=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, ret));
		dir->i_op = (ret == 0)
		    ? &umsdos_dir_inode_operations
		    : &umsdos_rdir_inode_operations;
		goto out;
	}

	ret = -EFAULT;
	if (copy_from_user (&data, idata, sizeof (data)))
		goto out;

	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 (dentry, &info);
		goto out;
	}
	else if (cmd == UMSDOS_RENAME_DOS) {
		struct dentry *old_dentry, *new_dentry;		/* FIXME */

		/* #Specification: ioctl / UMSDOS_RENAME_DOS
		 * A file or directory is renamed 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 mangled file
		 * name before syncing it back in the EMD.
		 */
		old_dentry = umsdos_lookup_dentry (dentry, 
						data.dos_dirent.d_name,
						data.dos_dirent.d_reclen ,1);
		ret = PTR_ERR(old_dentry);
		if (IS_ERR(old_dentry))
			goto out;
		new_dentry = umsdos_lookup_dentry (dentry,
						data.umsdos_dirent.name,
						data.umsdos_dirent.name_len, 1);
		ret = PTR_ERR(new_dentry);
		if (!IS_ERR(new_dentry)) {
printk("umsdos_ioctl: renaming %s/%s to %s/%s\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
			ret = msdos_rename (dir, old_dentry, dir, new_dentry);
			dput(new_dentry);
		}
		dput(old_dentry);
		goto out;
	}
	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 (dentry, &info,
				S_ISDIR (data.umsdos_dirent.mode));
		if (ret) {
			printk(KERN_WARNING
				"umsdos_ioctl: delentry %s/%s failed, ret=%d\n",
				dentry->d_name.name, info.entry.name, ret);
		}
		goto out;
	}
	else if (cmd == UMSDOS_UNLINK_DOS) {
		struct dentry *temp;

		/* #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.
		 */
		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
						data.dos_dirent.d_reclen, 1);
		ret = PTR_ERR(temp);
		if (IS_ERR(temp))
			goto out;
		ret = -ENOENT;
		if (temp->d_inode) {
			ret = -EISDIR;
			if (!S_ISDIR(temp->d_inode->i_mode))
				ret = msdos_unlink (dir, temp);
		}
		dput (temp);
		goto out;
	}
	else if (cmd == UMSDOS_RMDIR_DOS) {
		struct dentry *temp;

		/* #Specification: ioctl / UMSDOS_RMDIR_DOS
		 * The dos_dirent field of the struct umsdos_ioctl is used to
		 * execute a msdos_rmdir operation. The d_name and d_reclen
		 * fields are used.
		 * 
		 * Return 0 if success.
		 */
		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
					    data.dos_dirent.d_reclen, 1);
		ret = PTR_ERR(temp);
		if (IS_ERR(temp))
			goto out;
		ret = -ENOENT;
		if (temp->d_inode) {
			ret = -ENOTDIR;
			if (S_ISDIR(temp->d_inode->i_mode))
				ret = msdos_rmdir (dir, temp);
		}
		dput (temp);
		goto out;

	} 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 dentry *dret;
		struct inode *inode;

		dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
					    data.dos_dirent.d_reclen, 1);
		ret = PTR_ERR(dret);
		if (IS_ERR(dret))
			goto out;
		ret = -ENOENT;
		inode = dret->d_inode;
		if (inode) {
			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;
			ret = -EFAULT;
			if (!copy_to_user (&idata->stat, &data.stat, 
						sizeof (data.stat)))
				ret = 0;
		}
		dput(dret);
		goto out;
	}
	else if (cmd == UMSDOS_DOS_SETUP) {
		/* #Specification: ioctl / UMSDOS_DOS_SETUP
		 * The UMSDOS_DOS_SETUP ioctl allow changing the
		 * default permission of the MS-DOS filesystem driver
		 * on the fly.  The MS-DOS driver applies global permissions
		 * 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 applies ONLY to MS-DOS directories
		 * (those without EMD --linux-.---). Umsdos directory
		 * have independent (standard) permission for each
		 * and every file.
		 * 
		 * The field umsdos_dirent provide the information needed.
		 * umsdos_dirent.uid and gid sets the owner and group.
		 * umsdos_dirent.mode set the permissions flags.
		 */
		dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
		dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
		dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
		ret = 0;
	}
out:
	Printk (("ioctl %d, returning %d\n", cmd, ret));
	return ret;
}
Esempio n. 5
0
static int UMSDOS_rrmdir (
	struct inode *dir,
	const char *name,
	int len)
{
	/* #Specification: dual mode / rmdir in a DOS directory
		In a DOS (not EMD in it) directory, we use a reverse strategy
		compared with an Umsdos directory. We assume that a subdirectory
		of a DOS directory is also a DOS directory. This is not always
		true (umssync may be used anywhere), but make sense.

		So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
		then we check if it is a Umsdos directory. We check if it is
		really empty (only . .. and --linux-.--- in it). If it is true
		we remove the EMD and do a msdos_rmdir() again.

		In a Umsdos directory, we assume all subdirectory are also
		Umsdos directory, so we check the EMD file first.
	*/
	int ret;
	if (umsdos_is_pseudodos(dir,name,len)){
		/* #Specification: pseudo root / rmdir /DOS
			The pseudo sub-directory /DOS can't be removed!
			This is done even if the pseudo root is not a Umsdos
			directory anymore (very unlikely), but an accident (under
			MsDOS) is always possible.

			EPERM is returned.
		*/
		ret = -EPERM;
	}else{
		umsdos_lockcreate (dir);
		dir->i_count++;
		ret = msdos_rmdir (dir,name,len);
		if (ret == -ENOTEMPTY){
			struct inode *sdir;
			dir->i_count++;
			ret = UMSDOS_rlookup (dir,name,len,&sdir);
			PRINTK (("rrmdir lookup %d ",ret));
			if (ret == 0){
				int empty;
				if ((empty = umsdos_isempty (sdir)) != 0){
					PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
					if (empty == 2){
						/*
							Not a Umsdos directory, so the previous msdos_rmdir
							was not lying :-)
						*/
						ret = -ENOTEMPTY;
					}else if (empty == 1){
						/* We have to removed the EMD file */
						ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
							,UMSDOS_EMD_NAMELEN);
						sdir = NULL;
						if (ret == 0){
							dir->i_count++;
							ret = msdos_rmdir (dir,name,len);
						}
					}
				}else{
					ret = -ENOTEMPTY;
				}
				iput (sdir);
			}
		}
		umsdos_unlockcreate (dir);
	}
	iput (dir);
	return ret;
}