Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

stat() help

Status
Not open for further replies.

31164

Programmer
Aug 4, 2006
9
US
I have a filename with UTF-8 encoded characters, and I am trying to grab the date created from stat().

For example:
the filename is ??.txt

I manage to get the correct filename using WideCharToMultiByte(), but stat() gives the wrong value.

the correct value of date created: 8/4/2006 10:35:38, while
stat gives me 12/15/1992 04:34:08




 
I'm making a guess that you never initialised your stat buffer, and you ignored the return result from the stat() call, and just printed out whatever garbage was present.

Post some actual code, and state OS / Compiler / actual filenames tried - anything which might help to focus on the real problem.
And don't forget to use [code][/code] tags around your code.

Otherwise, expect vague hand waving along the lines of "have you tried...".

--
 
I am running it on windows.
filename: "\u0395\u03c7.txt"

I am sorry. I did not notice that the 2 characters are translated as ??.

Code:
JNIEXPORT jlong JNICALL Java_getAccessedDate
(JNIEnv * env, jclass obj, jstring filename){

	struct _stat statfile;
	char* rtn = getFilename8(filename, env);
	
        if(rtn == NULL){
            stat(rtn, &statfile);
	    free(rtn);
	    return (jlong)statfile.st_atime;
        } else {
            return 0;
        }
}

char* getFilename8(jstring filename, JNIEnv * env){

	const jchar * filename8;
	char* rtn;
	int size = 0;
	int len = (*env)->GetStringLength(env, filename);
	filename8 = (*env)->GetStringChars( env, filename, NULL );
	if ( filename8 == NULL ){
		return NULL;
	}

	rtn = (char*)malloc( len*2+1 );	
	size = WideCharToMultiByte( CP_UTF8, 0, (LPCWSTR)filename8, len, rtn,
                           (len*2+1), NULL, NULL );
	if( size <= 0 )
		return NULL;

	(*env)->ReleaseStringChars(env, filename, filename8 );
	return rtn;
}
 
I have changed the code so that it checks the return value from stat(). But still, it returns 12/15/1992 04:34:08....

When I try to detect the file using fopen(), it returns NULL.
Somehow stat() returns 724466048 not 0.

I have also printed the value of rtn, and it shows the right name.

I am not familiar with this but I have tried to play around with the data type.
I have uses wchar_t instead of char, and _wstat(), but nothing seems to work out.




 
> I have also printed the value of rtn, and it shows the right name.
But are you in the right directory?
Each process has it's own idea of what cwd() is, but something may have changed it since you last set it.

> if(rtn == NULL){
> stat(rtn, &statfile);
Surely this should be rtn != NULL ?

--
 
Oh ya that's a typo.
I believe that I am at the right directory.
the fullpath is
"c:\temporary_test\sample_test\\u0395\u03c7.txt.txt"

The issue that is still bugging me is the return value from stat.

As I mention before, I use fopen to detect the existence of the file. If it returns NULL, then stat should return 0, but it returns some other value.

The bug might be coming from getFilename8 or I am using the wrong data type and function.

I have found out that I can use
(*env)->GetStringUTFRegion(env, filename, 0, len, rtn);
The function description, it says that

"it copies the content of a string to or from a
preallocated C buffer in the UTF-8 format."

but it gives the same value.

 
sorry...
stat() does return 0.
so the bug is coming from getfilename8
 
"c:\temporary_test\sample_test\\u0395\u03c7.txt.txt"
Is that what it looks like when your print it on the screen? The two backslashes don't really look right, and is it supposed to end with two '.txt' extensions?
 
sorry, another typo.

i write "\u0395\u03c7" since the two characters are converted into ?? after i am posting it to the forum.

In the file system, it looks like
c:\temporary_test\sample_test\??.txt

the print looks like
c:\temporary_test\sample_test\Εχ.txt
 
the two letters are greek symbols.
\u0395 = GREEK CAPITAL LETTER EPSILON
\u03c7 = GREEK SMAL LETTER CHI
 
Code:
if(rtn == NULL){
Shouldn't that be:
Code:
if(rtn != NULL){
 
Mmm, works here
Code:
#include <cstdlib>
#include <iostream>
#include <cwchar>
#include <windows.h>
#include <sys/stat.h>
#include <ctime>

using namespace std;

void hexdump ( void *ptr, size_t len ) {
     unsigned char *mem = (unsigned char *)ptr;
     size_t   i;
     for ( i = 0 ; i < len ; i++ ) {
         printf( "%02x ", mem[i] );
         if ( (i+1) % 8 == 0 ) printf( "\n" );
     }
     printf( "\n" );
}

int main(int argc, char *argv[])
{
    wchar_t fn1[] = L"file\u0395\u03c7.txt";
    char    fn2[30] = { 0 };
    int result = WideCharToMultiByte (
               CP_UTF8,
               0,
               fn1,
               sizeof(fn1)/sizeof(fn1[0]),
               fn2,
               100,
               NULL,
               NULL
        );
    printf( "Conversion returns %d\n", result );
    hexdump ( fn1, sizeof fn1 );
    hexdump ( fn2, sizeof fn2 );
    FILE *fp = fopen( fn2, "w" );
    if ( fp != NULL ) {
         fprintf( fp, "hello world\n" );
         fclose( fp );
         struct stat sb = { 0 };
         int sr = stat( fn2, &sb );
         printf( "Stat returned %d\n", sr );
         struct tm now = *localtime( &sb.st_mtime );
         printf( "Mod Time=%s", asctime(&now) );
         now = *localtime( &sb.st_atime );
         printf( "Access Time=%s", asctime(&now) );
    } else {
        perror ( "Write failed\n" );
    }
    system("PAUSE");
    return EXIT_SUCCESS;
}

My results
Conversion returns 13
66 00 69 00 6c 00 65 00
95 03 c7 03 2e 00 74 00
78 00 74 00 00 00
66 69 6c 65 ce 95 cf 87
2e 74 78 74 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00
Stat returned 0
Mod Time=Sat Aug 05 14:02:57 2006
Access Time=Sat Aug 05 14:02:57 2006
Press any key to continue . . .

And yes, when I look for the file using windows explorer, I see the same filename you see, which is to be expected as a result of the way UTF-8 encodes extended characters.

--
 
Thank you, Salem.
I have tried it and it works too.
But in the code, you write

wchar_t fn1[] = L"file\u0395\u03c7.txt";

Is there any way to pass it as variable?
For example:

let
filename = "file\u0395\u03c7.txt";
and
wchar_t fn1[] = L(filename);

The problem is filename is a value pass to a function.

I have tried to use L(filename) but C wont let me do it.

Thank you




 
> The problem is filename is a value pass to a function.
So where does it come from originally?

I mean, you have a function like
[tt]getStat ( wchar_t fn[] );[/tt]

Which would get called with a wchar_t array containing a wide-string filename (which you then apply UTF-8 encoding on).

Perhaps you should hexdump() your filename8 and see what you really have. This is just basic debugging, nothing more.

I don't know what else to say except you need to start looking at the data more closely to see exactly how your wide strings are encoded. It all seems to work on a fixed example, which leads me to think that something is wrong with the data you're providing (remember, Garbage In, Garbage Out).

--
 
I have found a solution from a forum.
It seems that I need to do memcpy.

Code:
wchar_t* getFilename8(jstring filename, JNIEnv * env){
...
...
filename8 = (*env)->GetStringChars( env, filename, NULL );
_wrtn = (wchar_t*)malloc(sizeof(wchar_t)*len+1);
memcpy(_wrtn, filename8, sizeof(wchar_t)*len); 
...
...
}

Thank you, Everyone :D
 
don't forget to add the NULL terminator :

_wrtn[len] = '\0';

--------------------------------------------------
Free Java/J2EE Database Connection Pooling Software
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top