linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Kernel Mode File Operations Wrappers
@ 2003-08-18 14:37 Ramit Bhalla
  2003-08-18 15:31 ` Richard B. Johnson
  0 siblings, 1 reply; 2+ messages in thread
From: Ramit Bhalla @ 2003-08-18 14:37 UTC (permalink / raw)
  To: linux-kernel; +Cc: alan

[-- Attachment #1: Type: text/plain, Size: 742 bytes --]

Hi,

I've written a file that provides wrappers for kernel mode file operations (using existing filp_xx and supporting operations).
This provides support for opening/closing/reading/writing/seeking/formatting etc operations. This should help kernel mode developers with fs operations in their kernel drivers/modules.

It helps simplify kernel mode file operations and takes care of various issues (which one can forget at times) like handling the FS registers , uid and gid. It exposes kernel mode file operations in a way that are very similar to user mode operations like fopen, fclose, fseek etc.

I have tested it on a few systems and it appears to be working great.

Hope this finds it's way into the linux kernel :)

Ramit.

[-- Attachment #2: kernel_fops.h --]
[-- Type: application/octet-stream, Size: 1123 bytes --]

#ifndef _LINUX_K_FOPS_H
#define _LINUX_K_FOPS_H

/*
 * Kernel mode file operations wrappers header file.
 * 
 * Author	:	Ramit Bhalla
 * Created	:	18th August 2003
 *
 */

#define	SEEK_SET	0	/* Set seek absolute */
#define	SEEK_CUR	1	/* Set seek relative to current */
#define SEEK_END	2	/* Set seek negative from end of file */

/*
 * File management operations
 */
struct file * kernel_fopen(const char * filename, unsigned int flags, int mode);
int kernel_fclose(struct file * file_ptr);
loff_t kernel_fseek(struct file * file_ptr, int offset, int whence);

/*
 * File Reading operations
 */
int kernel_fread(struct file * file_ptr, char * buf, int len);
int kernel_fgetc(struct file * file_ptr);
int kernel_fgets(struct file * file_ptr, char * str, int len);

/*
 * File write operations
 */
int kernel_fwrite(struct file * file_ptr, char * buf, int len);
int kernel_fputc(struct file * file_ptr, char buf);
int kernel_fputs(struct file * file_ptr, char * str);

/*
 * File write in formatted form
 */
int kernel_fprintf(struct file * file_ptr, const char * fmt, ...);

#endif

[-- Attachment #3: kernel_fops.c --]
[-- Type: application/octet-stream, Size: 14138 bytes --]

/*
 * Kernel mode file operations wrappers.
 * 
 * Author	:	Ramit Bhalla
 * Created	:	18th August 2003
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 *
 * Revision History :
 * 
 * Version 1.0
 * 	- Initial Release
 */


#ifndef __KERNEL__
#define __KERNEL__
#endif

#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/fcntl.h>
#include <linux/kernel_fops.h>



/***********************************************************************************************
 * Function Name	:	kernel_fopen
 * 
 * Details			:	This function opens/create a file in kernel mode.
 * 
 * Arguments		:	filename	- the name of the file to be opened
 * 						flags		- same flags used by fopen()
 * 						mode		- file permissions as used by fopen()
 *
 * Return Value		:	file pointer if successful
 * 						NULL if failed.
 ***********************************************************************************************/
struct file * kernel_fopen(const char * filename, unsigned int flags, int mode)
{
	int				orgfsuid, orgfsgid;
	struct file *	file_ret;

	/* 
	 * Save uid and gid used for filesystem access.
	 */
	orgfsuid = current->fsuid;
	orgfsgid = current->fsgid;

	/*
	 * Set user and group to 0 (root)
	 */
	current->fsuid = 0;
	current->fsgid = 0;
  
	/*
	 * Open the file in kernel mode
	 */
	file_ret = filp_open(filename, flags, mode);
	
	/*
	 * Restore the uid and gid
	 */
	current->fsuid = orgfsuid;
	current->fsgid = orgfsgid;

	/*
	 * Check if the file was opened successfully
	 * and return the file pointer of it was.
	 */
	return ((IS_ERR(file_ret)) ? NULL : file_ret);
}



/***********************************************************************************************
 * Function Name	:	kernel_fclose
 * 
 * Details			:	This function closes a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 *
 * Return Value		:	0 if successful
 * 						error code if failed.
 * 						-ENOENT if file pointer is not valid
 ***********************************************************************************************/
int kernel_fclose(struct file * file_ptr)
{
	int	orgfsuid, orgfsgid;
	int	file_ret;

	/*
	 * Check if the file pointer is valid
	 */
	if((NULL == file_ptr) || (IS_ERR(file_ptr)))
		return -ENOENT;
	
	/* 
	 * Save uid and gid used for filesystem access.
	 */
	orgfsuid = current->fsuid;
	orgfsgid = current->fsgid;

	/*
	 * Set user and group to 0 (root)
	 */
	current->fsuid = 0;
	current->fsgid = 0;
  
	/*
	 * Close the file in kernel mode (user_id = 0)
	 */
	file_ret = filp_close(file_ptr, 0);
	
	/*
	 * Restore the uid and gid
	 */
	current->fsuid = orgfsuid;
	current->fsgid = orgfsgid;

	/*
	 * Return the error code.
	 */
    return (file_ret);
}




/***********************************************************************************************
 * Function Name	:	kernel_fseek
 * 
 * Details			:	This function seeks the file position in a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						offset		- offset into the file
 * 						whence		- starting point (SEEK_CUR, SEEK_SET or SEEK_EMD)
 *
 * Return Value		:	new file position
 * 						-ENOENT if file pointer is not valid
 * 						-EINVAL if offset type is not valid
 ***********************************************************************************************/
loff_t kernel_fseek(struct file * file_ptr, int offset, int whence)
{
	/* 
	 * Check for a valid file pointer
	 */
	if((NULL != file_ptr) && (!(IS_ERR(file_ptr))))
	{
		/*
		 * Check the operation to be performed
		 */
		switch(whence)
		{
			case SEEK_SET:
					file_ptr->f_pos = offset;	/* Absolute offset */
					break;

			case SEEK_CUR:
					file_ptr->f_pos += offset;	/* Relative offset */
					break;

			case SEEK_END:
					file_ptr->f_pos = file_ptr->f_dentry->d_inode->i_size - offset;	/* Offset from the end of file */
					break;

			default:
					return -EINVAL;				/* Invalid offset type */
		}
		
		/*
		 * Check for boundary conditions
		 */
		if (file_ptr->f_pos < 0)
			file_ptr->f_pos = 0;

		/*
		 * Return the current file pointer
		 */
		return (file_ptr->f_pos);
	}
	else
		return -ENOENT;		/* File pointer does not exist */
}


/***********************************************************************************************
 * Function Name	:	kernel_fread
 * 
 * Details			:	This function reads data from a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						buf			- buffer to read data into
 * 						len			- length of buffer to read
 *
 * Return Value		:	number of bytes read from the file
 * 						-ENOENT if file pointer is invalid
 * 						-ENOSYS if file read function is invalid
 * 						-EACCES if file read permissions are not valid
 * 						-EINVAL if length is not valid
 ***********************************************************************************************/
int kernel_fread(struct file * file_ptr, char * buf, int len)
{
	int				orgfsuid, orgfsgid;
	int				file_ret;
	mm_segment_t	orgfs;

	/*
	 * Check if the file pointer is valid
	 */
	if((NULL == file_ptr) || (IS_ERR(file_ptr)))
		return -ENOENT;

	/*
	 * Check for a valid file read function
	 */
	if(file_ptr->f_op->read == NULL)
		return -ENOSYS;

	/*
	 * Check for access permissions
	 */
	if(((file_ptr->f_flags & O_ACCMODE) & (O_RDONLY | O_RDWR)) != 0)
		return -EACCES;

	/*
	 * Check if there is a valid length
	 */
	if(0 >= len)
		return -EINVAL;

	/* 
	 * Save uid and gid used for filesystem access.
	 */
	orgfsuid = current->fsuid;
	orgfsgid = current->fsgid;

	/*
	 * Set user and group to 0 (root)
	 */
	current->fsuid = 0;
	current->fsgid = 0;

	/* 
	 * Save FS register and set FS register to kernel
	 * space, needed for read and write to accept
	 * buffer in kernel space.
	 */
	orgfs = get_fs();

	/*
	 * Set the FS register to KERNEL mode.
	 */
	set_fs(KERNEL_DS);

	/*
	 * Read the actual data from the file
	 */
	file_ret = file_ptr->f_op->read(file_ptr, buf, len, &file_ptr->f_pos);

	/*
	 * Restore the FS register
	 */
	set_fs(orgfs);

	/*
	 * Restore the uid and gid
	 */
	current->fsuid = orgfsuid;
	current->fsgid = orgfsgid;

	/*
	 * Return the number of bytes read.
	 */
    return (file_ret);
}



/***********************************************************************************************
 * Function Name	:	kernel_fgetc
 * 
 * Details			:	This function reads a character from a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 *
 * Return Value		:	character read from file
 * 						EOF if end of file
 * 						Error code if file cannot be read
 ***********************************************************************************************/
int kernel_fgetc(struct file * file_ptr)
{
	int		read_ret;
	char	buf;

	/*
	 * Read one byte from the file
	 */
	read_ret = kernel_fread(file_ptr, &buf, 1);

	/*
	 * Check return value
	 */
	if (read_ret > 0)
		return buf;			/* Return the character read */
	else if (0 == read_ret)
		return -1;			/* End of file */
	else
		return read_ret;	/* Error code */
}


/***********************************************************************************************
 * Function Name	:	kernel_fgets
 * 
 * Details			:	This function reads a string from a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						str			- buffer to read data into
 * 						len			- length of buffer to read
 *
 * Return Value		:	number of bytes read if successful
 * 						Error code if there was an error reading from the file
 * 						-EINVAL if length is not valid
 ***********************************************************************************************/
int kernel_fgets(struct file * file_ptr, char * str, int len)
{
	int				file_ret, readlen;
	char *			cp;

	/*
	 * Check if there is a valid length
	 */
	if(0 >= len)
		return -EINVAL;

	/*
	 * Read the actual data from the file and parse it
	 */
	for(cp = str, file_ret = -1, readlen = 0; readlen < len - 1; ++cp, ++readlen)
	{
		/*
		 * Read one character from the file
		 */
		file_ret = kernel_fgetc(file_ptr);

		/*
		 * Check for error in reading
		 */
		if(0 >= file_ret)
			break;				/* End of file or error in file */
		else
			*cp = file_ret;		/* Update - actual data read */

		/*
		 * Check for a new line character
		 */
		if(*cp == '\n')
		{
			++cp;
			++readlen;
			break;
		}
	}

	/*
	 * Last character of string is NULL
	 */
	*cp = (char) NULL;

	/*
	 * Return the number of bytes read or error.
	 */
	return ((0 >= file_ret) ? file_ret : readlen);
}



/***********************************************************************************************
 * Function Name	:	kernel_fwrite
 * 
 * Details			:	This function writes data to a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						buf			- buffer to write data from
 * 						len			- length of buffer to write
 *
 * Return Value		:	number of bytes written to the file
 * 						-ENOENT if file pointer is invalid
 * 						-ENOSYS if file write function is invalid
 * 						-EACCES if file write permissions are not valid
 * 						-EINVAL if length is not valid
 ***********************************************************************************************/
int kernel_fwrite(struct file * file_ptr, char * buf, int len)
{
	int				orgfsuid, orgfsgid;
	int				file_ret;
	mm_segment_t	orgfs;

	/*
	 * Check if the file pointer is valid
	 */
	if((NULL == file_ptr) || (IS_ERR(file_ptr)))
		return -ENOENT;

	/*
	 * Check for a valid file write function
	 */
	if(file_ptr->f_op->write == NULL)
		return -ENOSYS;

	/*
	 * Check for access permissions
	 */
	if(((file_ptr->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) != 0)
		return -EACCES;

	/*
	 * Check if there is a valid length
	 */
	if(0 >= len)
		return -EINVAL;

	/* 
	 * Save uid and gid used for filesystem access.
	 */
	orgfsuid = current->fsuid;
	orgfsgid = current->fsgid;

	/*
	 * Set user and group to 0 (root)
	 */
	current->fsuid = 0;
	current->fsgid = 0;

	/* 
	 * Save FS register and set FS register to kernel
	 * space, needed for read and write to accept
	 * buffer in kernel space.
	 */
	orgfs = get_fs();

	/*
	 * Set the FS register to KERNEL mode.
	 */
	set_fs(KERNEL_DS);

	/*
	 * Read the actual data from the file
	 */
	file_ret = file_ptr->f_op->write(file_ptr, buf, len, &file_ptr->f_pos);

	/*
	 * Restore the FS register
	 */
	set_fs(orgfs);

	/*
	 * Restore the uid and gid
	 */
	current->fsuid = orgfsuid;
	current->fsgid = orgfsgid;

	/*
	 * Return the number of bytes read.
	 */
    return (file_ret);
}



/***********************************************************************************************
 * Function Name	:	kernel_fputc
 * 
 * Details			:	This function writes a character to a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						buf			- character to be written into file
 *
 * Return Value		:	character written to file
 * 						EOF if end of file
 * 						Error code if file cannot be written to
 ***********************************************************************************************/
int kernel_fputc(struct file * file_ptr, char buf)
{
	int		write_ret;

	/*
	 * Write one byte to the file
	 */
	write_ret = kernel_fwrite(file_ptr, &buf, 1);

	/*
	 * Check return value
	 */
	if (write_ret > 0)
		return buf;			/* Return the character written */
	else if (0 == write_ret)
		return -1;			/* End of file */
	else
		return write_ret;	/* Error code */
}



/***********************************************************************************************
 * Function Name	:	kernel_fputs
 * 
 * Details			:	This function writes a string to a file in kernel mode.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						str			- String to be written to file
 *
 * Return Value		:	number of characters written to file
 * 						Error code if not successful (value returned by kernel_fwrite)
 ***********************************************************************************************/
int kernel_fputs(struct file * file_ptr, char * str)
{
	/*
	 * Write to file
	 */
	return (kernel_fwrite(file_ptr, str, strlen(str)));
}



/***********************************************************************************************
 * Function Name	:	kernel_fprintf
 * 
 * Details			:	This function writes a to a file using the printf format in kernel mode.
 * 						The maximum data to be written is limited to 1024 bytes.
 * 
 * Arguments		:	file_ptr	- Pointer to the file ops structure
 * 						fmt			- String formatting
 * 						...			- variable arguments
 *
 * Return Value		:	number of characters written to file
 * 						Error code if not successful (value returned by kernel_fwrite)
 ***********************************************************************************************/
int kernel_fprintf(struct file * file_ptr, const char * fmt, ...)
{
	static char s_buf[1024];
	va_list args;

	/*
	 * Format the data to be written
	 */
	va_start(args, fmt);
	vsprintf(s_buf, fmt, args);
	va_end(args);

	/*
	 * Write to file and return the error code
	 */
	return kernel_fputs(file_ptr, s_buf);
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Kernel Mode File Operations Wrappers
  2003-08-18 14:37 Kernel Mode File Operations Wrappers Ramit Bhalla
@ 2003-08-18 15:31 ` Richard B. Johnson
  0 siblings, 0 replies; 2+ messages in thread
From: Richard B. Johnson @ 2003-08-18 15:31 UTC (permalink / raw)
  To: Ramit Bhalla; +Cc: linux-kernel, alan

On Mon, 18 Aug 2003, Ramit Bhalla wrote:

> Hi,
>
> I've written a file that provides wrappers for kernel mode file operations
> (using existing filp_xx and supporting operations).
> This provides support for opening/closing/reading/writing/seeking/formatting
> etc operations. This should help kernel mode developers with fs
> operations in their kernel drivers/modules.
>
> It helps simplify kernel mode file operations and takes care of
> various issues (which one can forget at times) like handling
> the FS  registers , uid and gid. It exposes kernel mode file
> operations in a way that are very similar to user mode
> operations like
> fopen, fclose, fseek etc.
>
> I have tested it on a few systems and it appears to be working great.
>
> Hope this finds it's way into the linux kernel :)
>
> Ramit.
>

This appears to be a cruel joke! From whom does the kernel steal
'current' when obtaining a file descriptor? And, how-come there
is a CR/LF sequence for each end-of-line? Is this some DOS program?

If there are any developers using file-access in their modules,
as stated above, that stuff should never be included in the kernel.
If those persons want to permanently damage the OS by doing same,
then they can do whatever in their own trees.


Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
            Note 96.31% of all statistics are fiction.



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-08-18 15:29 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-18 14:37 Kernel Mode File Operations Wrappers Ramit Bhalla
2003-08-18 15:31 ` Richard B. Johnson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).