--- linux-2.6.9/fs/cifs/cifs_unicode.h 2004-10-19 06:55:28.000000000 +0900 +++ linux-2.6.9-1.681_FC3/fs/cifs/cifs_unicode.h 2004-12-21 15:36:24.034446688 +0900 @@ -29,6 +29,8 @@ * The upper/lower functions are based on a table created by mkupr. * This is a compressed table of upper and lower case conversion. * + * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 + * */ #include @@ -61,6 +63,7 @@ extern struct UniCaseRange UniLowerRange #ifdef __KERNEL__ int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +int cifs_strfromUCS_le_fitBufLen(char *, int, const wchar_t *, int, const struct nls_table *); #endif /* --- linux-2.6.9/fs/cifs/cifs_unicode.c 2004-12-19 02:55:01.000000000 +0900 +++ linux-2.6.9-1.681_FC3/fs/cifs/cifs_unicode.c 2004-12-21 15:36:05.561255040 +0900 @@ -17,6 +17,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 */ #include #include "cifs_unicode.h" @@ -37,25 +39,24 @@ cifs_strfromUCS_le(char *to, const wchar int i; int outlen = 0; -printk( KERN_ERR "cifs_strfromUCS_le : ." ); + printk(KERN_ERR "cifs_strfromUCS_le() : begins : to 0x%08x, from 0x%08x, len %d\n", to, from, len); + for (i = 0; (i < len) && from[i]; i++) { int charlen; /* 2.4.0 kernel or greater */ -printk( KERN_ERR "1" ); charlen = codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], NLS_MAX_CHARSET_SIZE); -printk( KERN_ERR "2" ); if (charlen > 0) { outlen += charlen; -printk( KERN_ERR "3" ); } else { to[outlen++] = '?'; -printk( KERN_ERR "4" ); } } to[outlen] = 0; -printk( KERN_ERR "..%d chars converted\n", outlen ); + + printk(KERN_ERR "cifs_strfromUCS_le() : ends : outlen %d\n", outlen); + return outlen; } @@ -91,3 +92,53 @@ cifs_strtoUCS(wchar_t * to, const char * return i; } +/* + * NAME: cifs_strfromUCS() + * + * FUNCTION: Convert little-endian unicode string to character string + * Converted multibyte string never exceeds to buffer length + * if exceeds, remainder will be represented as '~' + */ +int cifs_strfromUCS_le_fitBufLen( char * to, int to_len, const wchar_t * from, int from_len, const struct nls_table *codepage ) +{ + int i,j; + int outlen = 0; + + to_len--; // reserved for null termination + + for ( i=0; (iuni2char(le16_to_cpu(from[i]), conv_buffer, + NLS_MAX_CHARSET_SIZE); + if ( charlen > 0 ) { + /* test if converted mbChar fits in to buffer */ + if ( ( charlen < to_len - outlen ) || + ((charlen == to_len - outlen) + && ((i+1>=from_len) || from[i+1]==0)) ) { + for(j=0; j=from_len) || from[i+1]==0)) ) { + to[outlen++]='?'; + } else { + to[outlen++]='~'; + break; + } + } + } + to[outlen] = 0; + + return outlen; +} + + --- linux-2.6.9/fs/cifs/file.c 2004-12-19 03:51:56.000000000 +0900 +++ linux-2.6.9-1.681_FC3/fs/cifs/file.c 2004-12-21 15:36:28.574756456 +0900 @@ -19,6 +19,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 */ #include #include @@ -35,8 +38,7 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" -int -cifs_open(struct inode *inode, struct file *file) +int cifs_open(struct inode *inode, struct file *file) { int rc = -EACCES; int xid, oplock; @@ -1564,7 +1566,8 @@ construct_dentry(struct qstr *qstring, s static void reset_resume_key(struct file * dir_file, unsigned char * filename, - unsigned int len,int Unicode,struct nls_table * nls_tab) { + unsigned int len) +{ struct cifsFileInfo *cifsFile; cifsFile = (struct cifsFileInfo *)dir_file->private_data; @@ -1574,24 +1577,24 @@ static void reset_resume_key(struct file kfree(cifsFile->search_resume_name); } - if(Unicode) - len *= 2; + /* for safe null termination */ cifsFile->resume_name_length = len; cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + kmalloc(cifsFile->resume_name_length + 2, GFP_KERNEL); if(cifsFile->search_resume_name == NULL) { cERROR(1,("failed new resume key allocate, length %d", cifsFile->resume_name_length)); return; } - if(Unicode) - cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, - filename, len, nls_tab); - else - memcpy(cifsFile->search_resume_name, filename, - cifsFile->resume_name_length); + + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + + /* for safe null termination */ + cifsFile->search_resume_name[len] = 0; + cifsFile->search_resume_name[len+1] = 0; cFYI(1,("Reset resume key to: %s with len %d",filename,len)); return; } @@ -1600,13 +1603,16 @@ static void reset_resume_key(struct file static int cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, - struct file *file, filldir_t filldir, void *direntry) + struct file *file, filldir_t filldir, void *direntry, char * mbFileName ) { struct inode *tmp_inode; struct dentry *tmp_dentry; int object_type,rc; - pqstring->name = pfindData->FileName; + if ( mbFileName == NULL ) + mbFileName = pfindData->FileName; + + pqstring->name = mbFileName; /* pqstring->len is already set by caller */ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); @@ -1614,12 +1620,12 @@ cifs_filldir(struct qstr *pqstring, FILE return -ENOMEM; } fill_in_inode(tmp_inode, pfindData, &object_type); - rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, + rc = filldir(direntry, mbFileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { /* due to readdir error we need to recalculate resume key so next readdir will restart on right entry */ - cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); + cFYI(1,("Error %d on filldir of %s",rc , mbFileName)); } dput(tmp_dentry); return rc; @@ -1628,14 +1634,17 @@ cifs_filldir(struct qstr *pqstring, FILE static int cifs_filldir_unix(struct qstr *pqstring, FILE_UNIX_INFO * pUnixFindData, struct file *file, - filldir_t filldir, void *direntry) + filldir_t filldir, void *direntry, char * mbFileName ) { struct inode *tmp_inode; struct dentry *tmp_dentry; int object_type, rc; - pqstring->name = pUnixFindData->FileName; - pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); + if ( mbFileName == NULL ) + mbFileName = pUnixFindData->FileName; + + pqstring->name = mbFileName; + pqstring->len = strnlen(mbFileName, MAX_PATHCONF); construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { @@ -1643,12 +1652,12 @@ cifs_filldir_unix(struct qstr *pqstring, } unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); - rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, + rc = filldir(direntry, mbFileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { /* due to readdir error we need to recalculate resume key so next readdir will restart on right entry */ - cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + cFYI(1,("Error %d on filldir of %s",rc , mbFileName)); } dput(tmp_dentry); return rc; @@ -1661,8 +1670,6 @@ cifs_readdir(struct file *file, void *di int xid; int Unicode = FALSE; int UnixSearch = FALSE; - int FindDataLength = 0; - unsigned int bufsize, i; __u16 searchHandle; struct cifs_sb_info *cifs_sb; @@ -1680,9 +1687,6 @@ cifs_readdir(struct file *file, void *di xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); -/* */ - printk( KERN_ERR "cifs_readdir : local nls -> %s\n", cifs_sb->local_nls->charset ); -/* */ pTcon = cifs_sb->tcon; bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; if(bufsize > CIFS_MAX_MSGSIZE) { @@ -1749,7 +1753,7 @@ cifs_readdir(struct file *file, void *di } rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, &findParms, cifs_sb->local_nls, - &Unicode, &UnixSearch, &FindDataLength ); + &Unicode, &UnixSearch); cFYI(1, ("Count: %d End: %d ", le16_to_cpu(findParms.SearchCount), le16_to_cpu(findParms.EndofSearch))); @@ -1840,83 +1844,89 @@ cifs_readdir(struct file *file, void *di cifsFile->resume_name_length); } for (i = 2; i < count + 2; i++) { + /* unicode conversion buffer */ + char convBuf[MAX_PATHCONF]; + char *pmbFileName = NULL; + if (UnixSearch == FALSE) { __u32 len = le32_to_cpu(pfindData->FileNameLength); - if (Unicode == TRUE) { + pmbFileName = pfindData->FileName; + if (Unicode == TRUE) + { + pmbFileName = convBuf; len = - cifs_strfromUCS_le - (pfindData->FileName, - (wchar_t *) - pfindData->FileName, - len / 2, - cifs_sb->local_nls); -/* */ - printk( KERN_ERR "cifs_readdir : 1.filename -> %s\n", pfindData->FileName ); -/* */ + cifs_strfromUCS_le_fitBufLen( + pmbFileName, MAX_PATHCONF, + (wchar_t *) pfindData->FileName, len / 2, + cifs_sb->local_nls); } qstring.len = len; if (((len != 1) - || (pfindData->FileName[0] != '.')) + || (pmbFileName[0] != '.')) && ((len != 2) - || (pfindData-> - FileName[0] != '.') - || (pfindData-> - FileName[1] != '.'))) { + || (pmbFileName[0] != '.') + || (pmbFileName[1] != '.'))) { if(cifs_filldir(&qstring, pfindData, file, filldir, - direntry)) { + direntry, pmbFileName)) { /* do not end search if kernel not ready to take remaining entries yet */ - reset_resume_key(file, pfindData->FileName,qstring.len, - Unicode, cifs_sb->local_nls); + reset_resume_key(file, pfindData->FileName, + le32_to_cpu(pfindData->FileNameLength)); findParms.EndofSearch = 0; break; } file->f_pos++; } } else { /* UnixSearch */ - pfindDataUnix = - (FILE_UNIX_INFO *) pfindData; + __u32 len = 0; + pfindDataUnix = (FILE_UNIX_INFO *) pfindData; + pmbFileName = pfindDataUnix->FileName; + /* calculate safe length */ + len = le32_to_cpu(pfindDataUnix->NextEntryOffset) + - (__u32)(sizeof(FILE_UNIX_INFO)-1); + /* trim extra null chars */ + if (Unicode == TRUE) { + __u32 lenTmp = len/2-1; + wchar_t * pwc = (wchar_t*)pfindDataUnix->FileName; + while ( lenTmp>1 && pwc[lenTmp-1] == 0 && pwc[lenTmp] == 0 ) + lenTmp--; + len=lenTmp*2; + } else { + __u32 lenTmp = len-1; + char * pmb = pfindDataUnix->FileName; + while ( lenTmp>1 && pmb[lenTmp-1] == 0 && pmb[lenTmp] == 0 ) + lenTmp--; + len = lenTmp; + } if (Unicode == TRUE) { - __u32 len = FindDataLength + 1 - sizeof(FILE_UNIX_INFO); + pmbFileName = convBuf; qstring.len = - cifs_strfromUCS_le - (pfindDataUnix->FileName, - (wchar_t *) - pfindDataUnix->FileName, - /* MAX_PATHCONF, */ len, - cifs_sb->local_nls); -/* */ - printk( KERN_ERR "cifs_readdir : 2.filename -> %s\n", pfindDataUnix->FileName ); -/* */ - } - else + cifs_strfromUCS_le_fitBufLen( + pmbFileName, MAX_PATHCONF, + (wchar_t *) pfindDataUnix->FileName, len / 2, + cifs_sb->local_nls); + } else qstring.len = - strnlen(pfindDataUnix-> - FileName, - MAX_PATHCONF); - if (((qstring.len != 1) - || (pfindDataUnix-> - FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindDataUnix-> - FileName[0] != '.') - || (pfindDataUnix-> - FileName[1] != '.'))) { + strnlen(pmbFileName, len); + + if (((qstring.len != 1) || (pmbFileName[0] != '.')) + && ((qstring.len != 2) || (pmbFileName[0] != '.') + || (pmbFileName[1] != '.'))) { if(cifs_filldir_unix(&qstring, pfindDataUnix, file, filldir, - direntry)) { + direntry, + pmbFileName)) { /* do not end search if kernel not ready to take remaining entries yet */ findParms.EndofSearch = 0; - reset_resume_key(file, pfindDataUnix->FileName, - qstring.len,Unicode,cifs_sb->local_nls); + reset_resume_key(file, pfindDataUnix->FileName, len ); break; } file->f_pos++; @@ -1960,7 +1970,7 @@ cifs_readdir(struct file *file, void *di cifsFile->search_resume_name, cifsFile->resume_name_length, cifsFile->resume_key, - &Unicode, &UnixSearch, &FindDataLength); + &Unicode, &UnixSearch); cFYI(1,("Count: %d End: %d ", le16_to_cpu(findNextParms.SearchCount), le16_to_cpu(findNextParms.EndofSearch))); @@ -2047,86 +2057,88 @@ cifs_readdir(struct file *file, void *di } for (i = 0; i < count; i++) { - __u32 len = le32_to_cpu(pfindData-> - FileNameLength); + /* unicode conversion buffer */ + char convBuf[MAX_PATHCONF]; + char *pmbFileName = NULL; + if (UnixSearch == FALSE) { - if (Unicode == TRUE) { + __u32 len = le32_to_cpu(pfindData->FileNameLength); + pmbFileName = pfindData->FileName; + if (Unicode == TRUE) + { + pmbFileName = convBuf; len = - cifs_strfromUCS_le - (pfindData->FileName, - (wchar_t *) - pfindData->FileName, - len / 2, - cifs_sb->local_nls); -/* */ - printk( KERN_ERR "cifs_readdir : 3.filename -> %s\n", pfindData->FileName ); -/* */ + cifs_strfromUCS_le_fitBufLen( + pmbFileName, MAX_PATHCONF, + (wchar_t *)pfindData->FileName, len / 2, + cifs_sb->local_nls); } qstring.len = len; - if (((len != 1) - || (pfindData->FileName[0] != '.')) + if (((len != 1) || (pmbFileName[0] != '.')) && ((len != 2) - || (pfindData->FileName[0] != '.') - || (pfindData->FileName[1] != - '.'))) { + || (pmbFileName[0] != '.') + || (pmbFileName[1] != '.'))) { if(cifs_filldir (&qstring, pfindData, file, filldir, - direntry)) { + direntry, pmbFileName)) { /* do not end search if kernel not ready to take remaining entries yet */ findNextParms.EndofSearch = 0; - reset_resume_key(file, pfindData->FileName,qstring.len, - Unicode,cifs_sb->local_nls); + reset_resume_key(file, pfindData->FileName, + le32_to_cpu(pfindData->FileNameLength)); break; } file->f_pos++; } } else { /* UnixSearch */ - pfindDataUnix = - (FILE_UNIX_INFO *) - pfindData; + __u32 len = 0; + pfindDataUnix = (FILE_UNIX_INFO *) pfindData; + pmbFileName = pfindDataUnix->FileName; + /* calculate safe length */ + len = le32_to_cpu(pfindDataUnix->NextEntryOffset) + - (__u32)(sizeof(FILE_UNIX_INFO)-1); + /* trim extra null chars */ if (Unicode == TRUE) { - __u32 len = FindDataLength + 1 - sizeof(FILE_UNIX_INFO); - qstring.len = - cifs_strfromUCS_le - (pfindDataUnix->FileName, - (wchar_t *) - pfindDataUnix->FileName, - /*MAX_PATHCONF,*/ len, - cifs_sb->local_nls); -/* */ - printk( KERN_ERR "cifs_readdir : 4.filename -> %s\n", pfindData->FileName ); -/* */ + __u32 lenTmp = len/2-1; + wchar_t * pwc = (wchar_t*)pfindDataUnix->FileName; + while ( lenTmp>1 && pwc[lenTmp-1] == 0 && pwc[lenTmp] == 0 ) + lenTmp--; + len=lenTmp*2; + } else { + __u32 lenTmp = len-1; + char * pmb = pfindDataUnix->FileName; + while ( lenTmp>1 && pmb[lenTmp-1] == 0 && pmb[lenTmp] == 0 ) + lenTmp--; + len = lenTmp; } - else + + if (Unicode == TRUE) { + pmbFileName = convBuf; + qstring.len = + cifs_strfromUCS_le_fitBufLen( + pmbFileName, MAX_PATHCONF, + (wchar_t *)pfindDataUnix->FileName, len / 2, + cifs_sb->local_nls); + } else qstring.len = - strnlen - (pfindDataUnix-> - FileName, - MAX_PATHCONF); - if (((qstring.len != 1) - || (pfindDataUnix-> - FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindDataUnix-> - FileName[0] != '.') - || (pfindDataUnix-> - FileName[1] != - '.'))) { + strnlen(pmbFileName, len); + + if (((qstring.len != 1) || (pmbFileName[0] != '.')) + && ((qstring.len != 2) || (pmbFileName[0] != '.') + || (pmbFileName[1] != '.'))) { if(cifs_filldir_unix (&qstring, pfindDataUnix, file, filldir, - direntry)) { + direntry, pmbFileName)) { /* do not end search if kernel not ready to take remaining entries yet */ findNextParms.EndofSearch = 0; - reset_resume_key(file, pfindDataUnix->FileName,qstring.len, - Unicode,cifs_sb->local_nls); + reset_resume_key(file, pfindDataUnix->FileName, len ); break; } file->f_pos++;