2005-09-09 13:04:21 -07:00
/*
* linux / fs / 9 p / conv . c
*
* 9 P protocol conversion functions
*
2005-09-22 21:43:48 -07:00
* Copyright ( C ) 2004 , 2005 by Latchesar Ionkov < lucho @ ionkov . net >
2005-09-09 13:04:21 -07:00
* Copyright ( C ) 2004 by Eric Van Hensbergen < ericvh @ gmail . com >
* Copyright ( C ) 2002 by Ron Minnich < rminnich @ lanl . gov >
*
* This program is free software ; you can redistribute it and / or modify
2006-03-25 03:07:28 -08:00
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
2005-09-09 13:04:21 -07:00
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to :
* Free Software Foundation
* 51 Franklin Street , Fifth Floor
* Boston , MA 02111 - 1301 USA
*
*/
# include <linux/config.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/idr.h>
2006-01-08 01:05:00 -08:00
# include <asm/uaccess.h>
2005-09-09 13:04:21 -07:00
# include "debug.h"
# include "v9fs.h"
# include "9p.h"
# include "conv.h"
/*
* Buffer to help with string parsing
*/
struct cbuf {
unsigned char * sp ;
unsigned char * p ;
unsigned char * ep ;
} ;
static inline void buf_init ( struct cbuf * buf , void * data , int datalen )
{
buf - > sp = buf - > p = data ;
buf - > ep = data + datalen ;
}
static inline int buf_check_overflow ( struct cbuf * buf )
{
return buf - > p > buf - > ep ;
}
2006-01-14 13:20:43 -08:00
static int buf_check_size ( struct cbuf * buf , int len )
2005-09-09 13:04:21 -07:00
{
2006-01-08 01:05:02 -08:00
if ( buf - > p + len > buf - > ep ) {
if ( buf - > p < buf - > ep ) {
eprintk ( KERN_ERR , " buffer overflow: want %d has %d \n " ,
len , ( int ) ( buf - > ep - buf - > p ) ) ;
dump_stack ( ) ;
buf - > p = buf - > ep + 1 ;
}
2006-01-08 01:05:00 -08:00
return 0 ;
2005-09-09 13:04:21 -07:00
}
2005-09-22 21:43:48 -07:00
return 1 ;
2005-09-09 13:04:21 -07:00
}
2006-01-14 13:20:43 -08:00
static void * buf_alloc ( struct cbuf * buf , int len )
2005-09-09 13:04:21 -07:00
{
void * ret = NULL ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , len ) ) {
ret = buf - > p ;
buf - > p + = len ;
}
2005-09-09 13:04:21 -07:00
return ret ;
}
2006-01-14 13:20:43 -08:00
static void buf_put_int8 ( struct cbuf * buf , u8 val )
2005-09-09 13:04:21 -07:00
{
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 1 ) ) {
buf - > p [ 0 ] = val ;
buf - > p + + ;
}
2005-09-09 13:04:21 -07:00
}
2006-01-14 13:20:43 -08:00
static void buf_put_int16 ( struct cbuf * buf , u16 val )
2005-09-09 13:04:21 -07:00
{
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 2 ) ) {
* ( __le16 * ) buf - > p = cpu_to_le16 ( val ) ;
buf - > p + = 2 ;
}
2005-09-09 13:04:21 -07:00
}
2006-01-14 13:20:43 -08:00
static void buf_put_int32 ( struct cbuf * buf , u32 val )
2005-09-09 13:04:21 -07:00
{
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 4 ) ) {
* ( __le32 * ) buf - > p = cpu_to_le32 ( val ) ;
buf - > p + = 4 ;
}
2005-09-09 13:04:21 -07:00
}
2006-01-14 13:20:43 -08:00
static void buf_put_int64 ( struct cbuf * buf , u64 val )
2005-09-09 13:04:21 -07:00
{
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 8 ) ) {
* ( __le64 * ) buf - > p = cpu_to_le64 ( val ) ;
buf - > p + = 8 ;
}
2005-09-09 13:04:21 -07:00
}
2006-02-03 03:04:18 -08:00
static char * buf_put_stringn ( struct cbuf * buf , const char * s , u16 slen )
2005-09-09 13:04:21 -07:00
{
2006-02-03 03:04:18 -08:00
char * ret ;
ret = NULL ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , slen + 2 ) ) {
buf_put_int16 ( buf , slen ) ;
2006-02-03 03:04:18 -08:00
ret = buf - > p ;
2005-09-22 21:43:48 -07:00
memcpy ( buf - > p , s , slen ) ;
buf - > p + = slen ;
}
2006-02-03 03:04:18 -08:00
return ret ;
2005-09-09 13:04:21 -07:00
}
static inline void buf_put_string ( struct cbuf * buf , const char * s )
{
buf_put_stringn ( buf , s , strlen ( s ) ) ;
}
2006-01-14 13:20:43 -08:00
static u8 buf_get_int8 ( struct cbuf * buf )
2005-09-09 13:04:21 -07:00
{
u8 ret = 0 ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 1 ) ) {
ret = buf - > p [ 0 ] ;
buf - > p + + ;
}
2005-09-09 13:04:21 -07:00
return ret ;
}
2006-01-14 13:20:43 -08:00
static u16 buf_get_int16 ( struct cbuf * buf )
2005-09-09 13:04:21 -07:00
{
u16 ret = 0 ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 2 ) ) {
ret = le16_to_cpu ( * ( __le16 * ) buf - > p ) ;
buf - > p + = 2 ;
}
2005-09-09 13:04:21 -07:00
return ret ;
}
2006-01-14 13:20:43 -08:00
static u32 buf_get_int32 ( struct cbuf * buf )
2005-09-09 13:04:21 -07:00
{
u32 ret = 0 ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 4 ) ) {
ret = le32_to_cpu ( * ( __le32 * ) buf - > p ) ;
buf - > p + = 4 ;
}
2005-09-09 13:04:21 -07:00
return ret ;
}
2006-01-14 13:20:43 -08:00
static u64 buf_get_int64 ( struct cbuf * buf )
2005-09-09 13:04:21 -07:00
{
u64 ret = 0 ;
2005-09-22 21:43:48 -07:00
if ( buf_check_size ( buf , 8 ) ) {
ret = le64_to_cpu ( * ( __le64 * ) buf - > p ) ;
buf - > p + = 8 ;
}
2005-09-09 13:04:21 -07:00
return ret ;
}
2006-01-14 13:20:43 -08:00
static void buf_get_str ( struct cbuf * buf , struct v9fs_str * vstr )
2005-09-09 13:04:21 -07:00
{
2006-01-08 01:05:00 -08:00
vstr - > len = buf_get_int16 ( buf ) ;
if ( ! buf_check_overflow ( buf ) & & buf_check_size ( buf , vstr - > len ) ) {
vstr - > str = buf - > p ;
buf - > p + = vstr - > len ;
} else {
vstr - > len = 0 ;
vstr - > str = NULL ;
2005-09-22 21:43:48 -07:00
}
2005-09-09 13:04:21 -07:00
}
2006-01-14 13:20:43 -08:00
static void buf_get_qid ( struct cbuf * bufp , struct v9fs_qid * qid )
2005-09-09 13:04:21 -07:00
{
2006-01-08 01:05:00 -08:00
qid - > type = buf_get_int8 ( bufp ) ;
qid - > version = buf_get_int32 ( bufp ) ;
qid - > path = buf_get_int64 ( bufp ) ;
2005-09-09 13:04:21 -07:00
}
/**
2006-01-08 01:05:00 -08:00
* v9fs_size_wstat - calculate the size of a variable length stat struct
2005-09-09 13:04:21 -07:00
* @ stat : metadata ( stat ) structure
2006-01-08 01:04:58 -08:00
* @ extended : non - zero if 9 P2000 . u
2005-09-09 13:04:21 -07:00
*
*/
2006-01-08 01:05:00 -08:00
static int v9fs_size_wstat ( struct v9fs_wstat * wstat , int extended )
2005-09-09 13:04:21 -07:00
{
int size = 0 ;
2006-01-08 01:05:00 -08:00
if ( wstat = = NULL ) {
2005-09-09 13:04:21 -07:00
eprintk ( KERN_ERR , " v9fs_size_stat: got a NULL stat pointer \n " ) ;
return 0 ;
}
size = /* 2 + */ /* size[2] */
2 + /* type[2] */
4 + /* dev[4] */
1 + /* qid.type[1] */
4 + /* qid.vers[4] */
8 + /* qid.path[8] */
4 + /* mode[4] */
4 + /* atime[4] */
4 + /* mtime[4] */
8 + /* length[8] */
8 ; /* minimum sum of string lengths */
2006-01-08 01:05:00 -08:00
if ( wstat - > name )
size + = strlen ( wstat - > name ) ;
if ( wstat - > uid )
size + = strlen ( wstat - > uid ) ;
if ( wstat - > gid )
size + = strlen ( wstat - > gid ) ;
if ( wstat - > muid )
size + = strlen ( wstat - > muid ) ;
2005-09-09 13:04:21 -07:00
2006-01-08 01:04:58 -08:00
if ( extended ) {
2005-09-09 13:04:21 -07:00
size + = 4 + /* n_uid[4] */
4 + /* n_gid[4] */
4 + /* n_muid[4] */
2 ; /* string length of extension[4] */
2006-01-08 01:05:00 -08:00
if ( wstat - > extension )
size + = strlen ( wstat - > extension ) ;
2005-09-09 13:04:21 -07:00
}
return size ;
}
/**
2006-01-08 01:05:00 -08:00
* buf_get_stat - safely decode a recieved metadata ( stat ) structure
2005-09-09 13:04:21 -07:00
* @ bufp : buffer to deserialize
* @ stat : metadata ( stat ) structure
2006-01-08 01:04:58 -08:00
* @ extended : non - zero if 9 P2000 . u
2005-09-09 13:04:21 -07:00
*
*/
2006-01-14 13:20:43 -08:00
static void
2006-01-08 01:05:00 -08:00
buf_get_stat ( struct cbuf * bufp , struct v9fs_stat * stat , int extended )
2005-09-09 13:04:21 -07:00
{
stat - > size = buf_get_int16 ( bufp ) ;
stat - > type = buf_get_int16 ( bufp ) ;
stat - > dev = buf_get_int32 ( bufp ) ;
stat - > qid . type = buf_get_int8 ( bufp ) ;
stat - > qid . version = buf_get_int32 ( bufp ) ;
stat - > qid . path = buf_get_int64 ( bufp ) ;
stat - > mode = buf_get_int32 ( bufp ) ;
stat - > atime = buf_get_int32 ( bufp ) ;
stat - > mtime = buf_get_int32 ( bufp ) ;
stat - > length = buf_get_int64 ( bufp ) ;
2006-01-08 01:05:00 -08:00
buf_get_str ( bufp , & stat - > name ) ;
buf_get_str ( bufp , & stat - > uid ) ;
buf_get_str ( bufp , & stat - > gid ) ;
buf_get_str ( bufp , & stat - > muid ) ;
2005-09-09 13:04:21 -07:00
2006-01-08 01:04:58 -08:00
if ( extended ) {
2006-01-08 01:05:00 -08:00
buf_get_str ( bufp , & stat - > extension ) ;
2005-09-09 13:04:21 -07:00
stat - > n_uid = buf_get_int32 ( bufp ) ;
stat - > n_gid = buf_get_int32 ( bufp ) ;
stat - > n_muid = buf_get_int32 ( bufp ) ;
}
}
/**
* v9fs_deserialize_stat - decode a received metadata structure
* @ buf : buffer to deserialize
* @ buflen : length of received buffer
* @ stat : metadata structure to decode into
2006-01-08 01:04:58 -08:00
* @ extended : non - zero if 9 P2000 . u
2005-09-09 13:04:21 -07:00
*
2006-01-08 01:05:00 -08:00
* Note : stat will point to the buf region .
2005-09-09 13:04:21 -07:00
*/
2006-01-08 01:05:00 -08:00
int
v9fs_deserialize_stat ( void * buf , u32 buflen , struct v9fs_stat * stat ,
int extended )
2005-09-09 13:04:21 -07:00
{
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
2006-01-08 01:05:00 -08:00
unsigned char * p ;
2005-09-09 13:04:21 -07:00
buf_init ( bufp , buf , buflen ) ;
2006-01-08 01:05:00 -08:00
p = bufp - > p ;
buf_get_stat ( bufp , stat , extended ) ;
2005-09-09 13:04:21 -07:00
2006-01-08 01:05:00 -08:00
if ( buf_check_overflow ( bufp ) )
2005-09-09 13:04:21 -07:00
return 0 ;
2006-01-08 01:05:00 -08:00
else
return bufp - > p - p ;
2005-09-09 13:04:21 -07:00
}
/**
* deserialize_fcall - unmarshal a response
* @ buf : recieved buffer
* @ buflen : length of received buffer
* @ rcall : fcall structure to populate
* @ rcalllen : length of fcall structure to populate
2006-01-08 01:04:58 -08:00
* @ extended : non - zero if 9 P2000 . u
2005-09-09 13:04:21 -07:00
*
*/
int
2006-01-08 01:04:58 -08:00
v9fs_deserialize_fcall ( void * buf , u32 buflen , struct v9fs_fcall * rcall ,
2006-01-08 01:05:00 -08:00
int extended )
2005-09-09 13:04:21 -07:00
{
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
int i = 0 ;
buf_init ( bufp , buf , buflen ) ;
2006-01-08 01:04:58 -08:00
rcall - > size = buf_get_int32 ( bufp ) ;
2005-09-09 13:04:21 -07:00
rcall - > id = buf_get_int8 ( bufp ) ;
rcall - > tag = buf_get_int16 ( bufp ) ;
dprintk ( DEBUG_CONV , " size %d id %d tag %d \n " , rcall - > size , rcall - > id ,
rcall - > tag ) ;
2006-01-08 01:05:00 -08:00
2005-09-09 13:04:21 -07:00
switch ( rcall - > id ) {
default :
eprintk ( KERN_ERR , " unknown message type: %d \n " , rcall - > id ) ;
return - EPROTO ;
case RVERSION :
rcall - > params . rversion . msize = buf_get_int32 ( bufp ) ;
2006-01-08 01:05:00 -08:00
buf_get_str ( bufp , & rcall - > params . rversion . version ) ;
2005-09-09 13:04:21 -07:00
break ;
case RFLUSH :
break ;
case RATTACH :
rcall - > params . rattach . qid . type = buf_get_int8 ( bufp ) ;
rcall - > params . rattach . qid . version = buf_get_int32 ( bufp ) ;
rcall - > params . rattach . qid . path = buf_get_int64 ( bufp ) ;
break ;
case RWALK :
rcall - > params . rwalk . nwqid = buf_get_int16 ( bufp ) ;
2006-01-08 01:05:00 -08:00
if ( rcall - > params . rwalk . nwqid > V9FS_MAXWELEM ) {
eprintk ( KERN_ERR , " Rwalk with more than %d qids: %d \n " ,
V9FS_MAXWELEM , rcall - > params . rwalk . nwqid ) ;
2006-01-08 01:04:58 -08:00
return - EPROTO ;
}
2006-01-08 01:05:00 -08:00
for ( i = 0 ; i < rcall - > params . rwalk . nwqid ; i + + )
buf_get_qid ( bufp , & rcall - > params . rwalk . wqids [ i ] ) ;
2005-09-09 13:04:21 -07:00
break ;
case ROPEN :
2006-01-08 01:05:00 -08:00
buf_get_qid ( bufp , & rcall - > params . ropen . qid ) ;
2005-09-09 13:04:21 -07:00
rcall - > params . ropen . iounit = buf_get_int32 ( bufp ) ;
break ;
case RCREATE :
2006-01-08 01:05:00 -08:00
buf_get_qid ( bufp , & rcall - > params . rcreate . qid ) ;
2005-09-09 13:04:21 -07:00
rcall - > params . rcreate . iounit = buf_get_int32 ( bufp ) ;
break ;
case RREAD :
rcall - > params . rread . count = buf_get_int32 ( bufp ) ;
2006-01-08 01:05:00 -08:00
rcall - > params . rread . data = bufp - > p ;
buf_check_size ( bufp , rcall - > params . rread . count ) ;
2005-09-09 13:04:21 -07:00
break ;
case RWRITE :
rcall - > params . rwrite . count = buf_get_int32 ( bufp ) ;
break ;
case RCLUNK :
break ;
case RREMOVE :
break ;
case RSTAT :
buf_get_int16 ( bufp ) ;
2006-01-08 01:05:00 -08:00
buf_get_stat ( bufp , & rcall - > params . rstat . stat , extended ) ;
2005-09-09 13:04:21 -07:00
break ;
case RWSTAT :
break ;
case RERROR :
2006-01-08 01:05:00 -08:00
buf_get_str ( bufp , & rcall - > params . rerror . error ) ;
2006-01-08 01:04:58 -08:00
if ( extended )
2005-09-09 13:04:21 -07:00
rcall - > params . rerror . errno = buf_get_int16 ( bufp ) ;
break ;
}
2006-01-08 01:05:00 -08:00
if ( buf_check_overflow ( bufp ) ) {
2006-01-08 01:04:58 -08:00
dprintk ( DEBUG_ERROR , " buffer overflow \n " ) ;
2005-09-09 13:04:21 -07:00
return - EIO ;
2006-01-08 01:04:58 -08:00
}
2005-09-09 13:04:21 -07:00
2006-01-08 01:05:00 -08:00
return bufp - > p - bufp - > sp ;
}
static inline void v9fs_put_int8 ( struct cbuf * bufp , u8 val , u8 * p )
{
* p = val ;
buf_put_int8 ( bufp , val ) ;
}
static inline void v9fs_put_int16 ( struct cbuf * bufp , u16 val , u16 * p )
{
* p = val ;
buf_put_int16 ( bufp , val ) ;
}
static inline void v9fs_put_int32 ( struct cbuf * bufp , u32 val , u32 * p )
{
* p = val ;
buf_put_int32 ( bufp , val ) ;
}
static inline void v9fs_put_int64 ( struct cbuf * bufp , u64 val , u64 * p )
{
* p = val ;
buf_put_int64 ( bufp , val ) ;
}
2006-01-14 13:20:43 -08:00
static void
2006-01-08 01:05:00 -08:00
v9fs_put_str ( struct cbuf * bufp , char * data , struct v9fs_str * str )
{
2006-02-03 03:04:18 -08:00
int len ;
char * s ;
if ( data )
len = strlen ( data ) ;
else
len = 0 ;
2006-01-08 01:05:00 -08:00
2006-02-03 03:04:18 -08:00
s = buf_put_stringn ( bufp , data , len ) ;
if ( str ) {
str - > len = len ;
str - > str = s ;
}
2006-01-08 01:05:00 -08:00
}
2006-01-14 13:20:43 -08:00
static int
2006-01-08 01:05:00 -08:00
v9fs_put_user_data ( struct cbuf * bufp , const char __user * data , int count ,
unsigned char * * pdata )
{
* pdata = buf_alloc ( bufp , count ) ;
return copy_from_user ( * pdata , data , count ) ;
}
static void
v9fs_put_wstat ( struct cbuf * bufp , struct v9fs_wstat * wstat ,
struct v9fs_stat * stat , int statsz , int extended )
{
v9fs_put_int16 ( bufp , statsz , & stat - > size ) ;
v9fs_put_int16 ( bufp , wstat - > type , & stat - > type ) ;
v9fs_put_int32 ( bufp , wstat - > dev , & stat - > dev ) ;
v9fs_put_int8 ( bufp , wstat - > qid . type , & stat - > qid . type ) ;
v9fs_put_int32 ( bufp , wstat - > qid . version , & stat - > qid . version ) ;
v9fs_put_int64 ( bufp , wstat - > qid . path , & stat - > qid . path ) ;
v9fs_put_int32 ( bufp , wstat - > mode , & stat - > mode ) ;
v9fs_put_int32 ( bufp , wstat - > atime , & stat - > atime ) ;
v9fs_put_int32 ( bufp , wstat - > mtime , & stat - > mtime ) ;
v9fs_put_int64 ( bufp , wstat - > length , & stat - > length ) ;
v9fs_put_str ( bufp , wstat - > name , & stat - > name ) ;
v9fs_put_str ( bufp , wstat - > uid , & stat - > uid ) ;
v9fs_put_str ( bufp , wstat - > gid , & stat - > gid ) ;
v9fs_put_str ( bufp , wstat - > muid , & stat - > muid ) ;
if ( extended ) {
v9fs_put_str ( bufp , wstat - > extension , & stat - > extension ) ;
v9fs_put_int32 ( bufp , wstat - > n_uid , & stat - > n_uid ) ;
v9fs_put_int32 ( bufp , wstat - > n_gid , & stat - > n_gid ) ;
v9fs_put_int32 ( bufp , wstat - > n_muid , & stat - > n_muid ) ;
}
}
static struct v9fs_fcall *
v9fs_create_common ( struct cbuf * bufp , u32 size , u8 id )
{
struct v9fs_fcall * fc ;
size + = 4 + 1 + 2 ; /* size[4] id[1] tag[2] */
fc = kmalloc ( sizeof ( struct v9fs_fcall ) + size , GFP_KERNEL ) ;
if ( ! fc )
return ERR_PTR ( - ENOMEM ) ;
fc - > sdata = ( char * ) fc + sizeof ( * fc ) ;
buf_init ( bufp , ( char * ) fc - > sdata , size ) ;
v9fs_put_int32 ( bufp , size , & fc - > size ) ;
v9fs_put_int8 ( bufp , id , & fc - > id ) ;
v9fs_put_int16 ( bufp , V9FS_NOTAG , & fc - > tag ) ;
return fc ;
}
void v9fs_set_tag ( struct v9fs_fcall * fc , u16 tag )
{
2006-01-08 01:05:02 -08:00
fc - > tag = tag ;
2006-01-08 01:05:00 -08:00
* ( __le16 * ) ( fc - > sdata + 5 ) = cpu_to_le16 ( tag ) ;
}
struct v9fs_fcall * v9fs_create_tversion ( u32 msize , char * version )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 2 + strlen ( version ) ; /* msize[4] version[s] */
fc = v9fs_create_common ( bufp , size , TVERSION ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , msize , & fc - > params . tversion . msize ) ;
v9fs_put_str ( bufp , version , & fc - > params . tversion . version ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
2006-03-24 03:15:52 -08:00
#if 0
2006-01-08 01:05:00 -08:00
struct v9fs_fcall * v9fs_create_tauth ( u32 afid , char * uname , char * aname )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 2 + strlen ( uname ) + 2 + strlen ( aname ) ; /* afid[4] uname[s] aname[s] */
fc = v9fs_create_common ( bufp , size , TAUTH ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , afid , & fc - > params . tauth . afid ) ;
v9fs_put_str ( bufp , uname , & fc - > params . tauth . uname ) ;
v9fs_put_str ( bufp , aname , & fc - > params . tauth . aname ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
2006-03-24 03:15:52 -08:00
# endif /* 0 */
2006-01-08 01:05:00 -08:00
struct v9fs_fcall *
v9fs_create_tattach ( u32 fid , u32 afid , char * uname , char * aname )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 4 + 2 + strlen ( uname ) + 2 + strlen ( aname ) ; /* fid[4] afid[4] uname[s] aname[s] */
fc = v9fs_create_common ( bufp , size , TATTACH ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tattach . fid ) ;
v9fs_put_int32 ( bufp , afid , & fc - > params . tattach . afid ) ;
v9fs_put_str ( bufp , uname , & fc - > params . tattach . uname ) ;
v9fs_put_str ( bufp , aname , & fc - > params . tattach . aname ) ;
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_tflush ( u16 oldtag )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 2 ; /* oldtag[2] */
fc = v9fs_create_common ( bufp , size , TFLUSH ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int16 ( bufp , oldtag , & fc - > params . tflush . oldtag ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_twalk ( u32 fid , u32 newfid , u16 nwname ,
char * * wnames )
{
int i , size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
if ( nwname > V9FS_MAXWELEM ) {
dprintk ( DEBUG_ERROR , " nwname > %d \n " , V9FS_MAXWELEM ) ;
return NULL ;
}
size = 4 + 4 + 2 ; /* fid[4] newfid[4] nwname[2] ... */
for ( i = 0 ; i < nwname ; i + + ) {
size + = 2 + strlen ( wnames [ i ] ) ; /* wname[s] */
}
fc = v9fs_create_common ( bufp , size , TWALK ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . twalk . fid ) ;
v9fs_put_int32 ( bufp , newfid , & fc - > params . twalk . newfid ) ;
v9fs_put_int16 ( bufp , nwname , & fc - > params . twalk . nwname ) ;
for ( i = 0 ; i < nwname ; i + + ) {
v9fs_put_str ( bufp , wnames [ i ] , & fc - > params . twalk . wnames [ i ] ) ;
}
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_topen ( u32 fid , u8 mode )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 1 ; /* fid[4] mode[1] */
fc = v9fs_create_common ( bufp , size , TOPEN ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . topen . fid ) ;
v9fs_put_int8 ( bufp , mode , & fc - > params . topen . mode ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
2006-03-25 03:07:26 -08:00
struct v9fs_fcall * v9fs_create_tcreate ( u32 fid , char * name , u32 perm , u8 mode ,
char * extension , int extended )
2006-01-08 01:05:00 -08:00
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 2 + strlen ( name ) + 4 + 1 ; /* fid[4] name[s] perm[4] mode[1] */
2006-03-25 03:07:26 -08:00
if ( extended & & extension ! = NULL )
size + = 2 + strlen ( extension ) ; /* extension[s] */
2006-01-08 01:05:00 -08:00
fc = v9fs_create_common ( bufp , size , TCREATE ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tcreate . fid ) ;
v9fs_put_str ( bufp , name , & fc - > params . tcreate . name ) ;
v9fs_put_int32 ( bufp , perm , & fc - > params . tcreate . perm ) ;
v9fs_put_int8 ( bufp , mode , & fc - > params . tcreate . mode ) ;
2006-03-25 03:07:26 -08:00
if ( extended )
v9fs_put_str ( bufp , extension , & fc - > params . tcreate . extension ) ;
2006-01-08 01:05:00 -08:00
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_tread ( u32 fid , u64 offset , u32 count )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 8 + 4 ; /* fid[4] offset[8] count[4] */
fc = v9fs_create_common ( bufp , size , TREAD ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tread . fid ) ;
v9fs_put_int64 ( bufp , offset , & fc - > params . tread . offset ) ;
v9fs_put_int32 ( bufp , count , & fc - > params . tread . count ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_twrite ( u32 fid , u64 offset , u32 count ,
const char __user * data )
{
int size , err ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 + 8 + 4 + count ; /* fid[4] offset[8] count[4] data[count] */
fc = v9fs_create_common ( bufp , size , TWRITE ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . twrite . fid ) ;
v9fs_put_int64 ( bufp , offset , & fc - > params . twrite . offset ) ;
v9fs_put_int32 ( bufp , count , & fc - > params . twrite . count ) ;
err = v9fs_put_user_data ( bufp , data , count , & fc - > params . twrite . data ) ;
if ( err ) {
kfree ( fc ) ;
fc = ERR_PTR ( err ) ;
}
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_tclunk ( u32 fid )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 ; /* fid[4] */
fc = v9fs_create_common ( bufp , size , TCLUNK ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tclunk . fid ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_tremove ( u32 fid )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 ; /* fid[4] */
fc = v9fs_create_common ( bufp , size , TREMOVE ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tremove . fid ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_tstat ( u32 fid )
{
int size ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
size = 4 ; /* fid[4] */
fc = v9fs_create_common ( bufp , size , TSTAT ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . tstat . fid ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
}
struct v9fs_fcall * v9fs_create_twstat ( u32 fid , struct v9fs_wstat * wstat ,
int extended )
{
int size , statsz ;
struct v9fs_fcall * fc ;
struct cbuf buffer ;
struct cbuf * bufp = & buffer ;
statsz = v9fs_size_wstat ( wstat , extended ) ;
size = 4 + 2 + 2 + statsz ; /* fid[4] stat[n] */
fc = v9fs_create_common ( bufp , size , TWSTAT ) ;
if ( IS_ERR ( fc ) )
goto error ;
v9fs_put_int32 ( bufp , fid , & fc - > params . twstat . fid ) ;
buf_put_int16 ( bufp , statsz + 2 ) ;
v9fs_put_wstat ( bufp , wstat , & fc - > params . twstat . stat , statsz , extended ) ;
if ( buf_check_overflow ( bufp ) ) {
kfree ( fc ) ;
fc = ERR_PTR ( - ENOMEM ) ;
}
error :
return fc ;
2005-09-09 13:04:21 -07:00
}