diff options
Diffstat (limited to 'fs/umsdos/ioctl.c')
| -rw-r--r-- | fs/umsdos/ioctl.c | 446 |
1 files changed, 0 insertions, 446 deletions
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c deleted file mode 100644 index fc300030afd1..000000000000 --- a/fs/umsdos/ioctl.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * linux/fs/umsdos/ioctl.c - * - * Written 1993 by Jacques Gelinas - * - * Extended MS-DOS ioctl directory handling functions - * - * Changes: - * 11/07/2003 Daniele Bellucci <bellucda@tiscali.it> - * - audit copy_to_user/put_user in umsdos_ioctl_fill. - */ - -#include <asm/uaccess.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/time.h> -#include <linux/fs.h> -#include <linux/msdos_fs.h> -#include <linux/umsdos_fs.h> - -struct UMSDOS_DIR_ONCE { - struct dirent *ent; - int count; -}; - -/* - * Record a single entry the first call. - * Return -EINVAL the next one. - */ -static int umsdos_ioctl_fill ( - void *buf, - const char *name, - int name_len, - loff_t offset, - ino_t ino, - unsigned type) -{ - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; - - if (d->count == 0) { - if (copy_to_user (d->ent->d_name, name, name_len) || - put_user ('\0', d->ent->d_name + name_len) || - put_user (name_len, &d->ent->d_reclen) || - put_user (ino, &d->ent->d_ino) || - put_user (offset, &d->ent->d_off)) - return -EFAULT; - d->count = 1; - ret = 0; - } - return ret; -} - - -/* - * Perform special function on a directory - */ -/* #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 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 / access - * 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; - loff_t pos = filp->f_pos; - - /* 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; - - while (pos < demd->d_inode->i_size) { - off_t f_pos = pos; - struct umsdos_dirent entry; - struct umsdos_info info; - - ret = umsdos_emd_dir_readentry (demd, &pos, &entry); - - if (ret == -ENAMETOOLONG) { - printk (KERN_INFO "Fixing EMD entry with invalid size -- zeroing out\n"); - memset (&info, 0, sizeof (info)); - info.f_pos = f_pos; - info.recsize = UMSDOS_REC_SIZE; - ret = umsdos_writeentry (dentry, &info, 1); - continue; - } - - 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 = 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. - */ - - 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)); - umsdos_setup_dir (dentry); - 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); - d_drop(new_dentry); - d_drop(old_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); - if (!ret) - d_delete(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); - if (!ret) - d_delete(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_fmask = - dir->i_sb->u.msdos_sb.options.fs_dmask = - data.umsdos_dirent.mode; - ret = 0; - } -out: - Printk (("ioctl %d, returning %d\n", cmd, ret)); - return ret; -} |
