1 /* Remote Windows CE device filesystem.
3 Based on lufs "Userland filesystem" ( http://lufs.sourceforge.net/ )
4 and synce ( http://synce.sourceforge.net/ )
7 Author: Fedor Bezrukov <fedor@ms2.inr.ac.ru>
16 #include <sys/types.h>
22 #include <lufs/proto.h>
35 cefs_init(struct list_head *cfg, struct dir_cache *cache, struct credentials *cred, void **global_ctx){
36 return (void*)new CEFS(cfg, cache);
47 cefs_mount(void *ctx){
48 return ((CEFS*)ctx)->do_mount();
52 cefs_umount(void *ctx){
53 // return ((CEFS*)ctx)->do_umount();
57 cefs_readdir(void *ctx, char *dir_name, struct directory *dir){
58 return ((CEFS*)ctx)->do_readdir(dir_name, dir);
62 cefs_stat(void *ctx, char *name, struct lufs_fattr *fattr){
63 return ((CEFS*)ctx)->do_stat(name, fattr);
67 cefs_mkdir(void *ctx, char *dir, int mode){
68 return ((CEFS*)ctx)->do_mkdir(dir, mode);
72 cefs_rmdir(void *ctx, char *dir){
73 return ((CEFS*)ctx)->do_rmdir(dir);
77 cefs_create(void *ctx, char *file, int mode){
78 return ((CEFS*)ctx)->do_create(file, mode);
82 cefs_unlink(void *ctx, char *file){
83 return ((CEFS*)ctx)->do_unlink(file);
87 cefs_rename(void *ctx, char *old_name, char *new_name){
88 return ((CEFS*)ctx)->do_rename(old_name, new_name);
92 cefs_open(void *ctx, char *file, unsigned mode){
93 return ((CEFS*)ctx)->do_open(file, mode);
97 cefs_release(void *ctx, char *file){
98 return ((CEFS*)ctx)->do_release(file);
102 cefs_read(void *ctx, char *file, long long offset, unsigned long count, char *buf){
103 return ((CEFS*)ctx)->do_read(file, offset, count, buf);
107 cefs_write(void *ctx, char *file, long long offset, unsigned long count, char *buf){
108 return ((CEFS*)ctx)->do_write(file, offset, count, buf);
112 cefs_readlink(void *ctx, char *link, char *buf, int buflen){
113 return ((CEFS*)ctx)->do_readlink(link, buf, buflen);
117 cefs_link(void *ctx, char *target, char *link){
118 return ((CEFS*)ctx)->do_link(target, link);
122 cefs_symlink(void *ctx, char *target, char *link){
123 return ((CEFS*)ctx)->do_symlink(target, link);
127 cefs_setattr(void *ctx, char *file, struct lufs_fattr *fattr){
128 return ((CEFS*)ctx)->do_setattr(file, fattr);
135 * It controls whether a new Rapi connection is initialized for every
136 * function or only once per process. I am not sure at the moment,
139 #define CERAPIINIT_PER_PROCESS
141 // WinCE Send buffer size
142 //#define MYBUF_SIZE (16*1024)
143 #define MYBUF_SIZE (64*1024)
146 // Return values from main()
148 #define TEST_SUCCEEDED 0
149 #define TEST_FAILED -1
153 #define VERIFY_HRESULT(call) \
154 TRACE("CeRapiInit");\
155 if (FAILED((call))) { WARN("FAIL."); return TEST_FAILED; }
161 char* from_unicode(const WCHAR* inbuf)
163 size_t length = wcslen(inbuf);
164 size_t inbytesleft = length * 2, outbytesleft = length;
165 char* outbuf = new char[outbytesleft+1];
166 char* outbuf_iterator = outbuf;
167 char* inbuf_iterator = (char*)inbuf;
169 iconv_t cd = iconv_open("KOI8-R", "UNICODELITTLE");
170 size_t result = iconv(cd, &inbuf_iterator, &inbytesleft, &outbuf_iterator, &outbytesleft);
173 if ((size_t)-1 == result)
174 strcpy(outbuf, "(failed)");
181 WCHAR* to_unicode(const char* inbuf)
183 size_t length = strlen(inbuf);
184 size_t inbytesleft = length, outbytesleft = (length+1)* 2;
185 char * inbuf_iterator = const_cast<char*>(inbuf);
186 WCHAR* outbuf = new WCHAR[inbytesleft+1];
187 WCHAR* outbuf_iterator = outbuf;
189 iconv_t cd = iconv_open("UNICODELITTLE", "KOI8-R");
190 size_t result = iconv(cd, &inbuf_iterator, &inbytesleft, (char**)&outbuf_iterator, &outbytesleft);
193 if ((size_t)-1 == result)
201 char* ce_to_unix_name(const WCHAR* cefile)
203 char* file = from_unicode(cefile);
204 for (char* pp=file; *pp!=0; pp++)
205 if (*pp=='/') *pp = '%';
209 WCHAR* unix_to_ce_name(const char* file)
211 WCHAR* path = to_unicode(file);
212 for (WCHAR* pp=path; *pp!=0; pp++)
213 if (*pp=='/') *pp='\\';
214 else if (*pp=='\\') *pp='%';
218 //static void noalrmHandler(int sig){
219 // TRACE("False timeout...");
221 // signal(SIGALRM, noalrmHandler);
222 // siginterrupt(SIGALRM, 1);
225 CEFS::CEFS(struct list_head* cf, struct dir_cache *cache, struct credentials *cred){
236 rhnd = new RAPIHandle;
241 rhnd->lockbuffer=NULL;
242 rhnd->lockbuffersize=0;
244 TRACE("in CEFS constructor");
249 TRACE("in CEFS destructor");
254 TRACE("mounting a cefs.");
255 #ifdef CERAPIINIT_PER_PROCESS
256 VERIFY_HRESULT(CeRapiInit(rhnd));
263 TRACE("umounting a cefs.");
264 #ifdef CERAPIINIT_PER_PROCESS
270 CEFS::do_readdir(char* d, struct directory *dir){
273 TRACE("reading '"<<d<<"'");
275 WCHAR* path_tmp = unix_to_ce_name(d);
276 int dlen=wcslen(path_tmp);
278 wcscpy(path,path_tmp);
280 WCHAR* pd = path+dlen;
281 if ( *(pd-1) != '\\' ) *(pd++) = '\\';
282 *(pd++) = '*'; *(pd++) = '.'; *(pd++) = '*';
285 #ifndef CERAPIINIT_PER_PROCESS
286 VERIFY_HRESULT(CeRapiInit(rhnd));
289 CE_FIND_DATA* find_data = NULL;
290 DWORD file_count = 0;
292 /* lufsd is now using pthreads, sorry no more alarms... */
293 // signal(SIGALRM, noalrmHandler);
294 // siginterrupt(SIGALRM, 1);
296 if( !CeFindAllFiles(rhnd,path,
297 ( FAF_NAME|FAF_SIZE_LOW
298 |FAF_LASTWRITE_TIME|FAF_LASTACCESS_TIME
301 &file_count, &find_data) ) {
302 TRACE("could not open directory!");
306 struct lufs_fattr fattr;
307 fattr.f_mode = S_IFDIR;
308 // fattr.f_mode &= ~options.o_umask;
311 // fattr.f_uid = options.o_uid;
313 // fattr.f_gid = options.o_gid;
314 /* Are these lines correct? */
315 /* I mean, they are surely wrong, but does this change anything? */
317 /* F.M.: yup, they're ok, not really used. they're just placeholders */
318 /* in cache, so that each dir contains al least 2 entries... */
319 // lu_cache_add2dir(dir, ".", NULL, &fattr);
320 // lu_cache_add2dir(dir, "..", NULL, &fattr);
322 for (unsigned i = 0; i < file_count; i++) {
323 char* d_name = ce_to_unix_name(find_data[i].cFileName);
324 TRACE("adding direntry " << d_name);
327 fattr.f_mode = S_IFREG;
328 if ( FILE_ATTRIBUTE_DIRECTORY & find_data[i].dwFileAttributes ) {
329 fattr.f_mode = S_IFDIR;
330 // fattr.f_mode |= 0111;
332 // fattr.f_mode |= 0666;
333 // fattr.f_mode &= ~options.o_umask;
334 fattr.f_size = find_data[i].nFileSizeLow;
335 fattr.f_atime = DOSFS_FileTimeToUnixTime(
336 &(find_data[i].ftLastAccessTime),NULL );
337 fattr.f_mtime = DOSFS_FileTimeToUnixTime(
338 &(find_data[i].ftLastWriteTime),NULL );
339 fattr.f_ctime = DOSFS_FileTimeToUnixTime(
340 &(find_data[i].ftCreationTime),NULL );
341 lu_cache_add2dir(dir, d_name, NULL, &fattr);
345 CeRapiFreeBuffer(rhnd,find_data);
348 #ifndef CERAPIINIT_PER_PROCESS
355 CEFS::do_stat(char *nm, struct lufs_fattr *fattr){
358 TRACE("stat: " << nm);
362 if((i = s.find_last_of('/')) == string::npos){
363 WARN("couldn't isolate dir in "<<nm<<"!");
366 string dir = (i == 0) ? string("/") : s.substr(0, i+1);
367 if (dir=="//") dir="/";
368 string f = dir+s.substr(i + 1, s.length() - i - 1);
369 TRACE("stat: using " << f.c_str());
370 WCHAR* path = unix_to_ce_name(f.c_str());
371 // WCHAR* path = unix_to_ce_name(nm);
373 fattr->f_mode = S_IFREG;
374 // fattr->f_mode |= 0664;
375 // fattr->f_mode &= ~options.o_umask;
377 // fattr->f_uid = options.o_uid;
379 // fattr->f_gid = options.o_gid;
381 if ( f=="/." ) { // Artificial root directory
382 fattr->f_mode = S_IFDIR;
386 #ifndef CERAPIINIT_PER_PROCESS
387 VERIFY_HRESULT(CeRapiInit(rhnd));
390 CE_FIND_DATA find_data;
391 HANDLE hnd=CeFindFirstFile(rhnd,path, &find_data);
393 if (INVALID_HANDLE_VALUE==hnd) {
394 TRACE("CeFindFirstFile of '"<<nm<<"'failed in do_stat!");
397 if ( FAILED(CeFindClose( rhnd,hnd )) )
398 WARN("CeFindClose failed in do_stat!");
400 if ( FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes ) {
401 fattr->f_mode = S_IFDIR;
402 // fattr->f_mode |= 0111;
404 // fattr->f_mode |= 0666;
405 // fattr->f_mode &= ~options.o_umask;
407 fattr->f_size = find_data.nFileSizeLow;
408 fattr->f_atime = DOSFS_FileTimeToUnixTime(
409 &(find_data.ftLastAccessTime),NULL );
410 fattr->f_mtime = DOSFS_FileTimeToUnixTime(
411 &(find_data.ftLastWriteTime),NULL );
412 fattr->f_ctime = DOSFS_FileTimeToUnixTime(
413 &(find_data.ftCreationTime),NULL );
417 #ifndef CERAPIINIT_PER_PROCESS
424 CEFS::do_mkdir(char *dir, int mode){
425 #ifndef CERAPIINIT_PER_PROCESS
426 VERIFY_HRESULT(CeRapiInit(rhnd));
428 WCHAR* path = unix_to_ce_name(dir);
429 int res = CeCreateDirectory(rhnd,path, NULL);
431 #ifndef CERAPIINIT_PER_PROCESS
438 CEFS::do_rmdir(char *dir){
439 #ifndef CERAPIINIT_PER_PROCESS
440 VERIFY_HRESULT(CeRapiInit(rhnd));
442 WCHAR* path = unix_to_ce_name(dir);
443 int res = CeRemoveDirectory(rhnd,path);
445 #ifndef CERAPIINIT_PER_PROCESS
452 CEFS::do_create(char *file, int mode){
454 #ifndef CERAPIINIT_PER_PROCESS
455 VERIFY_HRESULT(CeRapiInit(rhnd));
457 TRACE(file<< " mode " << mode);
458 WCHAR* path = unix_to_ce_name(file);
459 HANDLE handle = CeCreateFile(rhnd,path,
464 FILE_ATTRIBUTE_NORMAL,
467 if (INVALID_HANDLE_VALUE==handle) goto out;
468 CeCloseHandle(rhnd,handle);
472 #ifndef CERAPIINIT_PER_PROCESS
479 CEFS::do_unlink(char *file){
480 #ifndef CERAPIINIT_PER_PROCESS
481 VERIFY_HRESULT(CeRapiInit(rhnd));
483 WCHAR* path =unix_to_ce_name(file);
484 int res = CeDeleteFile(rhnd,path);
486 #ifndef CERAPIINIT_PER_PROCESS
493 CEFS::do_rename(char *old, char *nnew){
494 #ifndef CERAPIINIT_PER_PROCESS
495 VERIFY_HRESULT(CeRapiInit(rhnd));
497 TRACE(old << " to " << nnew);
499 WCHAR* oldpath = unix_to_ce_name(old);
500 WCHAR* newpath = unix_to_ce_name(nnew);
502 int res=CeMoveFile(rhnd, oldpath,newpath );
507 #ifndef CERAPIINIT_PER_PROCESS
514 CEFS::do_open(char *file, unsigned mode){
516 TRACE(file <<"mode" << mode);
517 if (stored_data_len) {
518 do_release(stored_file);
520 if ( mode&O_WRONLY ) {
522 stored_file = strdup(file);
528 CEFS::do_release(char *file){
531 if (writing && stored_data_len) {
533 #ifndef CERAPIINIT_PER_PROCESS
534 VERIFY_HRESULT(CeRapiInit(rhnd));
536 WCHAR* path = unix_to_ce_name(file);
537 HANDLE handle = CeCreateFile(rhnd,path,
542 FILE_ATTRIBUTE_NORMAL,
545 if (handle == INVALID_HANDLE_VALUE) goto out;
546 for ( char* buffer=stored_data;
547 buffer<stored_data+stored_data_len;
548 buffer+=MYBUF_SIZE ) {
549 DWORD did_write = (DWORD)-1;
550 size_t bytes_read = MYBUF_SIZE;
551 if ( buffer+MYBUF_SIZE >= stored_data+stored_data_len )
552 bytes_read = stored_data+stored_data_len-buffer;
554 if ( 0==CeWriteFile(rhnd,handle, buffer, bytes_read, &did_write, NULL) )
556 if (bytes_read != did_write)
557 WARN("Only wrote %lu bytes to file of %u possible.\n"<< did_write<< bytes_read);
560 CeCloseHandle(rhnd,handle);
564 #ifndef CERAPIINIT_PER_PROCESS
569 if (stored_data_len) {
581 CEFS::do_read(char *file, long long offset, unsigned long count, char *buf){
582 TRACE("read "<<file<<", "<<offset<<", "<<count);
585 if ( stored_data_len==0 || strcmp(file,stored_file)!=0 ) {
586 // signal(SIGALRM, noalrmHandler);
587 // siginterrupt(SIGALRM, 1);
589 struct lufs_fattr fattr;
590 if ( do_stat(file, &fattr)!=0 )
592 if (stored_data_len) {
596 stored_file=strdup(file);
597 stored_data_len = fattr.f_size;
598 stored_data = (char*)malloc(stored_data_len*sizeof(char));
599 #ifndef CERAPIINIT_PER_PROCESS
600 VERIFY_HRESULT(CeRapiInit(rhnd));
602 WCHAR* path = unix_to_ce_name(file);
604 HANDLE handle = CeCreateFile(rhnd,path,
609 FILE_ATTRIBUTE_NORMAL,
612 if (INVALID_HANDLE_VALUE == handle ) goto out;
614 for ( char* point=stored_data;
615 CeReadFile(rhnd,handle,point,MYBUF_SIZE,&bytes_read,NULL);
616 point += bytes_read )
617 if (bytes_read==0) break;
618 CeCloseHandle(rhnd,handle);
622 #ifndef CERAPIINIT_PER_PROCESS
625 if (result < 0) return result;
627 if (offset+count>stored_data_len)
628 count = stored_data_len-offset;
629 memcpy(buf,stored_data+offset,count);
635 CEFS::do_write(char *file, long long offset, unsigned long count, char *buf){
637 TRACE("write "<<file<<", "<<offset<<", "<<count);
638 if ( stored_data_len!=0 && strcmp(file,stored_file)!=0 ) {
640 stored_file=strdup(file);
644 if (offset+count>stored_data_len) {
645 stored_data_len = offset+count;
646 stored_data = (char*)realloc(stored_data,stored_data_len);
648 memcpy(stored_data+offset,buf,count);
654 CEFS::do_setattr(char* file, struct lufs_fattr*)