From: "Ramit Bhalla" <ramit.bhalla@wipro.com>
To: <linux-kernel@vger.kernel.org>
Cc: <alan@redhat.com>
Subject: Kernel Mode File Operations Wrappers
Date: Mon, 18 Aug 2003 20:07:37 +0530 [thread overview]
Message-ID: <52C85426D39B314381D76DDD480EEE0CF5FCAB@blr-m3-msg.wipro.com> (raw)
[-- 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);
}
next reply other threads:[~2003-08-18 15:05 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-08-18 14:37 Ramit Bhalla [this message]
2003-08-18 15:31 ` Richard B. Johnson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52C85426D39B314381D76DDD480EEE0CF5FCAB@blr-m3-msg.wipro.com \
--to=ramit.bhalla@wipro.com \
--cc=alan@redhat.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®