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

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).