add usb mouse support, move usb defines to usb.h
[libogc.git] / libtinysmb / smb_devoptab.c
blob44620ab5e9e7cbf6cdb39b29d053dfb5f50a6efc
1 /****************************************************************************
2 * TinySMB
3 * Nintendo Wii/GameCube SMB implementation
5 * SMB devoptab
6 ****************************************************************************/
8 #include <malloc.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <sys/iosupport.h>
14 #include <network.h>
15 #include <ogcsys.h>
16 #include <ogc/lwp_watchdog.h>
17 #include <ogc/mutex.h>
19 #include "smb.h"
21 static mutex_t _SMB_mutex=LWP_MUTEX_NULL;
23 static inline void _SMB_lock()
25 if(_SMB_mutex!=LWP_MUTEX_NULL) LWP_MutexLock(_SMB_mutex);
28 static inline void _SMB_unlock()
30 if(_SMB_mutex!=LWP_MUTEX_NULL) LWP_MutexUnlock(_SMB_mutex);
33 typedef struct
35 SMBFILE handle;
36 off_t offset;
37 off_t len;
38 char filename[SMB_MAXPATH];
39 unsigned short access;
40 int env;
41 } SMBFILESTRUCT;
43 typedef struct
45 SMBDIRENTRY smbdir;
46 int env;
47 } SMBDIRSTATESTRUCT;
49 static bool FirstInit=true;
50 #define MAX_SMB_MOUNTED 5
52 ///////////////////////////////////////////
53 // CACHE FUNCTION DEFINITIONS //
54 ///////////////////////////////////////////
55 #define SMB_CACHE_FREE 0xFFFFFFFF
56 #define SMB_READ_BUFFERSIZE 7236
57 #define SMB_WRITE_BUFFERSIZE 7236
59 typedef struct
61 off_t offset;
62 u32 last_used;
63 SMBFILESTRUCT *file;
64 void *ptr;
65 } smb_cache_page;
67 typedef struct
69 off_t used;
70 off_t len;
71 SMBFILESTRUCT *file;
72 void *ptr;
73 } smb_write_cache;
75 void DestroySMBReadAheadCache(char *name);
76 void SMBEnableReadAhead(char *name, u32 pages);
77 int ReadSMBFromCache(void *buf, int len, SMBFILESTRUCT *file);
79 static lwp_t main_thread;
80 static bool end_cache_thread = true;
81 ///////////////////////////////////////////
82 // END CACHE FUNCTION DEFINITIONS //
83 ///////////////////////////////////////////
85 // SMB Enviroment
86 typedef struct
88 char *name;
89 int pos;
90 devoptab_t *devoptab;
92 SMBCONN smbconn;
93 u8 SMBCONNECTED ;
95 char currentpath[SMB_MAXPATH];
96 bool first_item_dir ;
97 bool diropen_root;
99 smb_write_cache SMBWriteCache;
100 smb_cache_page *SMBReadAheadCache;
101 u32 SMB_RA_pages;
103 } smb_env;
105 static smb_env SMBEnv[MAX_SMB_MOUNTED];
108 ///////////////////////////////////////////
109 // CACHE FUNCTIONS //
110 ///////////////////////////////////////////
112 smb_env* FindSMBEnv(const char *name)
114 int i;
116 for(i=0;i<MAX_SMB_MOUNTED ;i++)
118 if(SMBEnv[i].SMBCONNECTED && strcmp(name,SMBEnv[i].name)==0)
120 return &SMBEnv[i];
123 return NULL;
126 int FlushWriteSMBCache(char *name)
128 smb_env *env;
129 env=FindSMBEnv(name);
130 if(env==NULL) return -1;
131 _SMB_lock();
132 if (env->SMBWriteCache.file == NULL || env->SMBWriteCache.len == 0)
134 _SMB_unlock();
135 return 0;
138 int written = 0;
140 written = SMB_WriteFile(env->SMBWriteCache.ptr, env->SMBWriteCache.len,
141 env->SMBWriteCache.file->offset, env->SMBWriteCache.file->handle);
143 if (written <= 0)
145 env->SMBWriteCache.used = 0;
146 env->SMBWriteCache.len = 0;
147 env->SMBWriteCache.file = NULL;
148 _SMB_unlock();
149 return -1;
151 env->SMBWriteCache.file->offset += written;
152 if (env->SMBWriteCache.file->offset > env->SMBWriteCache.file->len)
153 env->SMBWriteCache.file->len = env->SMBWriteCache.file->offset;
154 env->SMBWriteCache.used = 0;
155 env->SMBWriteCache.len = 0;
156 env->SMBWriteCache.file = NULL;
157 _SMB_unlock();
158 return 0;
161 void DestroySMBReadAheadCache(char *name)
163 smb_env *env;
164 env=FindSMBEnv(name);
165 if(env==NULL) return ;
167 int i;
168 if (env->SMBReadAheadCache != NULL)
170 for (i = 0; i < env->SMB_RA_pages; i++)
172 if(env->SMBReadAheadCache[i].ptr)
173 free(env->SMBReadAheadCache[i].ptr);
175 free(env->SMBReadAheadCache);
176 env->SMBReadAheadCache = NULL;
177 env->SMB_RA_pages = 0;
179 //end_cache_thread = true;
181 FlushWriteSMBCache(env->name);
183 if(env->SMBWriteCache.ptr)
184 free(env->SMBWriteCache.ptr);
186 env->SMBWriteCache.used = 0;
187 env->SMBWriteCache.len = 0;
188 env->SMBWriteCache.file = NULL;
189 env->SMBWriteCache.ptr = NULL;
192 static void *process_cache_thread(void *ptr)
194 int i;
195 while (1)
197 //_SMB_lock();
198 for(i=0;i<MAX_SMB_MOUNTED ;i++)
200 if(SMBEnv[i].SMBCONNECTED)
202 if (SMBEnv[i].SMBWriteCache.used > 0)
204 if (ticks_to_millisecs(gettime())-ticks_to_millisecs(SMBEnv[i].SMBWriteCache.used) > 500)
206 FlushWriteSMBCache(SMBEnv[i].name);
211 //_SMB_unlock();
212 usleep(10000);
213 if (end_cache_thread) break;
216 LWP_JoinThread(main_thread, NULL);
217 return NULL;
220 void SMBEnableReadAhead(char *name, u32 pages)
222 int i, j;
224 smb_env *env;
225 env=FindSMBEnv(name);
226 if(env==NULL) return;
228 DestroySMBReadAheadCache(name);
230 if (pages == 0)
231 return;
233 //only 1 page for write
234 env->SMBWriteCache.ptr = memalign(32, SMB_WRITE_BUFFERSIZE);
235 env->SMBWriteCache.used = 0;
236 env->SMBWriteCache.len = 0;
237 env->SMBWriteCache.file = NULL;
239 env->SMB_RA_pages = pages;
240 env->SMBReadAheadCache = (smb_cache_page *) malloc(sizeof(smb_cache_page) * env->SMB_RA_pages);
241 if (env->SMBReadAheadCache == NULL)
242 return;
243 for (i = 0; i < env->SMB_RA_pages; i++)
245 env->SMBReadAheadCache[i].offset = SMB_CACHE_FREE;
246 env->SMBReadAheadCache[i].last_used = 0;
247 env->SMBReadAheadCache[i].file = NULL;
248 env->SMBReadAheadCache[i].ptr = memalign(32, SMB_READ_BUFFERSIZE);
249 if (env->SMBReadAheadCache[i].ptr == NULL)
251 for (j = i - 1; j >= 0; j--)
252 if (env->SMBReadAheadCache[j].ptr)
253 free(env->SMBReadAheadCache[j].ptr);
254 free(env->SMBReadAheadCache);
255 env->SMBReadAheadCache = NULL;
256 free(env->SMBWriteCache.ptr);
257 return;
259 memset(env->SMBReadAheadCache[i].ptr, 0, SMB_READ_BUFFERSIZE);
264 // clear cache from file (clear if you write to the file)
265 void ClearSMBFileCache(SMBFILESTRUCT *file)
267 int i,j;
268 j=file->env;
269 for (i = 0; i < SMBEnv[j].SMB_RA_pages; i++)
271 if (SMBEnv[j].SMBReadAheadCache[i].offset != SMB_CACHE_FREE)
273 if (strcmp(SMBEnv[j].SMBReadAheadCache[i].file->filename, file->filename)==0)
275 SMBEnv[j].SMBReadAheadCache[i].offset = SMB_CACHE_FREE;
276 SMBEnv[j].SMBReadAheadCache[i].last_used = 0;
277 SMBEnv[j].SMBReadAheadCache[i].file = NULL;
279 memset(SMBEnv[j].SMBReadAheadCache[i].ptr, 0, SMB_READ_BUFFERSIZE);
285 int ReadSMBFromCache(void *buf, int len, SMBFILESTRUCT *file)
287 int retval;
288 int i,j, leastUsed, rest;
289 u32 new_offset;
290 j=file->env;
291 _SMB_lock();
292 if (SMBEnv[j].SMBReadAheadCache == NULL)
294 if (SMB_ReadFile(buf, len, file->offset, file->handle) <= 0)
296 _SMB_unlock();
297 return -1;
299 _SMB_unlock();
300 return 0;
302 new_offset = file->offset;
303 rest = len;
304 leastUsed = 0;
305 for (i = 0; i < SMBEnv[j].SMB_RA_pages; i++)
307 if (SMBEnv[j].SMBReadAheadCache[i].file == file)
309 if ((file->offset >= SMBEnv[j].SMBReadAheadCache[i].offset) &&
310 (file->offset < (SMBEnv[j].SMBReadAheadCache[i].offset + SMB_READ_BUFFERSIZE)))
312 if ((file->offset + len) <= (SMBEnv[j].SMBReadAheadCache[i].offset + SMB_READ_BUFFERSIZE))
314 SMBEnv[j].SMBReadAheadCache[i].last_used = gettime();
315 memcpy(buf, SMBEnv[j].SMBReadAheadCache[i].ptr + (file->offset - SMBEnv[j].SMBReadAheadCache[i].offset), len);
316 _SMB_unlock();
317 return 0;
319 else
321 int buffer_used;
322 SMBEnv[j].SMBReadAheadCache[i].last_used = gettime();
323 buffer_used = (SMBEnv[j].SMBReadAheadCache[i].offset + SMB_READ_BUFFERSIZE) - file->offset;
324 memcpy(buf, SMBEnv[j].SMBReadAheadCache[i].ptr + (file->offset - SMBEnv[j].SMBReadAheadCache[i].offset), buffer_used);
325 buf += buffer_used;
326 rest = len - buffer_used;
327 new_offset = SMBEnv[j].SMBReadAheadCache[i].offset + SMB_READ_BUFFERSIZE;
328 i++;
329 break;
334 if ((SMBEnv[j].SMBReadAheadCache[i].last_used < SMBEnv[j].SMBReadAheadCache[leastUsed].last_used))
335 leastUsed = i;
338 for (; i < SMBEnv[j].SMB_RA_pages; i++)
340 if ((SMBEnv[j].SMBReadAheadCache[i].last_used < SMBEnv[j].SMBReadAheadCache[leastUsed].last_used))
341 leastUsed = i;
344 retval = SMB_ReadFile(SMBEnv[j].SMBReadAheadCache[leastUsed].ptr, SMB_READ_BUFFERSIZE, new_offset, file->handle);
346 if (retval <= 0)
348 SMBEnv[j].SMBReadAheadCache[leastUsed].offset = SMB_CACHE_FREE;
349 SMBEnv[j].SMBReadAheadCache[leastUsed].last_used = 0;
350 SMBEnv[j].SMBReadAheadCache[leastUsed].file = NULL;
351 _SMB_unlock();
352 return -1;
355 SMBEnv[j].SMBReadAheadCache[leastUsed].offset = new_offset;
356 SMBEnv[j].SMBReadAheadCache[leastUsed].last_used = gettime();
357 SMBEnv[j].SMBReadAheadCache[leastUsed].file = file;
358 memcpy(buf, SMBEnv[j].SMBReadAheadCache[leastUsed].ptr, rest);
359 _SMB_unlock();
360 return 0;
363 int WriteSMBUsingCache(const char *buf, int len, SMBFILESTRUCT *file)
365 if (file == NULL || buf == NULL)
366 return -1;
368 int j,ret = len;
369 _SMB_lock();
370 j=file->env;
371 if (SMBEnv[j].SMBWriteCache.file != NULL)
373 if (strcmp(SMBEnv[j].SMBWriteCache.file->filename, file->filename) != 0)
375 //Flush current buffer
376 if (FlushWriteSMBCache(SMBEnv[j].name) < 0)
378 _SMB_unlock();
379 return -1;
383 SMBEnv[j].SMBWriteCache.file = file;
385 if (SMBEnv[j].SMBWriteCache.len + len >= SMB_WRITE_BUFFERSIZE)
387 void *send_buf;
388 int rest = 0, written = 0;
389 send_buf = memalign(32, SMB_WRITE_BUFFERSIZE);
390 if (SMBEnv[j].SMBWriteCache.len > 0)
391 memcpy(send_buf, SMBEnv[j].SMBWriteCache.ptr, SMBEnv[j].SMBWriteCache.len);
392 loop:
393 rest = SMB_WRITE_BUFFERSIZE - SMBEnv[j].SMBWriteCache.len;
394 memcpy(send_buf + SMBEnv[j].SMBWriteCache.len, buf, rest);
395 written = SMB_WriteFile(send_buf, SMB_WRITE_BUFFERSIZE,
396 SMBEnv[j].SMBWriteCache.file->offset, SMBEnv[j].SMBWriteCache.file->handle);
397 free(send_buf);
398 if (written <= 0)
400 SMBEnv[j].SMBWriteCache.used = 0;
401 SMBEnv[j].SMBWriteCache.len = 0;
402 SMBEnv[j].SMBWriteCache.file = NULL;
403 _SMB_unlock();
404 return -1;
406 file->offset += written;
407 if (file->offset > file->len)
408 file->len = file->offset;
410 buf = buf + rest;
411 len = SMBEnv[j].SMBWriteCache.len + len - SMB_WRITE_BUFFERSIZE;
413 SMBEnv[j].SMBWriteCache.used = gettime();
414 SMBEnv[j].SMBWriteCache.len = 0;
416 if(len>=SMB_WRITE_BUFFERSIZE) goto loop;
418 if (len > 0)
420 memcpy(SMBEnv[j].SMBWriteCache.ptr + SMBEnv[j].SMBWriteCache.len, buf, len);
421 SMBEnv[j].SMBWriteCache.len += len;
423 _SMB_unlock();
424 return ret;
427 ///////////////////////////////////////////
428 // END CACHE FUNCTIONS //
429 ///////////////////////////////////////////
431 static char *smb_absolute_path_no_device(const char *srcpath, char *destpath, int env)
433 if (strchr(srcpath, ':') != NULL)
435 srcpath = strchr(srcpath, ':') + 1;
437 if (strchr(srcpath, ':') != NULL)
439 return NULL;
442 if (srcpath[0] != '\\' && srcpath[0] != '/')
444 strcpy(destpath, SMBEnv[env].currentpath);
445 strcat(destpath, srcpath);
447 else
449 strcpy(destpath, srcpath);
451 int i, l;
452 l = strlen(destpath);
453 for (i = 0; i < l; i++)
454 if (destpath[i] == '/')
455 destpath[i] = '\\';
457 return destpath;
460 char *ExtractDevice(const char *path, char *device)
462 int i,l;
463 l=strlen(path);
465 for(i=0;i<l && path[i]!='\0' && path[i]!=':' && i < 20;i++)
466 device[i]=path[i];
467 if(path[i]!=':')device[0]='\0';
468 else device[i]='\0';
469 return device;
472 //FILE IO
473 static int __smb_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
475 SMBFILESTRUCT *file = (SMBFILESTRUCT*) fileStruct;
478 char fixedpath[SMB_MAXPATH];
480 smb_env *env;
482 ExtractDevice(path,fixedpath);
483 if(fixedpath[0]=='\0')
485 getcwd(fixedpath,SMB_MAXPATH);
486 ExtractDevice(fixedpath,fixedpath);
488 env=FindSMBEnv(fixedpath);
489 file->env=env->pos;
491 if (!env->SMBCONNECTED)
493 r->_errno = ENODEV;
494 return -1;
497 if (smb_absolute_path_no_device(path, fixedpath, file->env) == NULL)
499 r->_errno = EINVAL;
500 return -1;
503 SMBDIRENTRY dentry;
504 bool fileExists = true;
505 _SMB_lock();
506 if (SMB_PathInfo(fixedpath, &dentry, env->smbconn) != SMB_SUCCESS)
507 fileExists = false;
509 _SMB_unlock();
511 // Determine which mode the file is open for
512 u8 smb_mode;
513 unsigned short access;
514 if ((flags & 0x03) == O_RDONLY)
516 // Open the file for read-only access
517 smb_mode = SMB_OF_OPEN;
518 access = SMB_OPEN_READING;
520 else if ((flags & 0x03) == O_WRONLY)
522 // Open file for write only access
523 if (fileExists)
524 smb_mode = SMB_OF_OPEN;
525 else
526 smb_mode = SMB_OF_CREATE;
527 access = SMB_OPEN_WRITING;
529 else if ((flags & 0x03) == O_RDWR)
531 // Open file for read/write access
532 access = SMB_OPEN_READWRITE;
533 if (fileExists)
534 smb_mode = SMB_OF_OPEN;
535 else
536 smb_mode = SMB_OF_CREATE;
538 else
540 r->_errno = EACCES;
541 return -1;
544 if ((flags & O_CREAT) && !fileExists)
545 smb_mode = SMB_OF_CREATE;
546 if (!(flags & O_APPEND) && fileExists && ((flags & 0x03) != O_RDONLY))
547 smb_mode = SMB_OF_TRUNCATE;
549 _SMB_lock();
550 file->handle = SMB_OpenFile(fixedpath, access, smb_mode, env->smbconn);
551 _SMB_unlock();
552 if (!file->handle)
554 r->_errno = ENOENT;
555 return -1;
558 file->len = 0;
559 if (fileExists)
560 file->len = dentry.size;
562 if (flags & O_APPEND)
563 file->offset = file->len;
564 else
565 file->offset = 0;
567 file->access=access;
569 strcpy(file->filename, fixedpath);
570 return 0;
573 static off_t __smb_seek(struct _reent *r, int fd, off_t pos, int dir)
575 SMBFILESTRUCT *file = (SMBFILESTRUCT*) fd;
576 off_t position;
578 if (file == NULL)
580 r->_errno = EBADF;
581 return -1;
584 switch (dir)
586 case SEEK_SET:
587 position = pos;
588 break;
589 case SEEK_CUR:
590 position = file->offset + pos;
591 break;
592 case SEEK_END:
593 position = file->len + pos;
594 break;
595 default:
596 r->_errno = EINVAL;
597 return -1;
600 if (((pos > 0) && (position < 0)) || (position > file->len))
602 r->_errno = EOVERFLOW;
603 return -1;
605 if (position < 0)
607 r->_errno = EINVAL;
608 return -1;
611 // Save position
612 file->offset = position;
613 return position;
616 static ssize_t __smb_read(struct _reent *r, int fd, char *ptr, size_t len)
618 SMBFILESTRUCT *file = (SMBFILESTRUCT*) fd;
620 if (file == NULL)
622 r->_errno = EBADF;
623 return -1;
626 // Don't try to read if the read pointer is past the end of file
627 if (file->offset > file->len)
629 r->_errno = EOVERFLOW;
630 return -1;
633 // Don't read past end of file
634 if (len + file->offset > file->len)
636 len = file->len - file->offset;
637 if (len < 0)
638 len = 0;
639 r->_errno = EOVERFLOW;
641 if (len == 0)
642 return 0;
645 // Short circuit cases where len is 0 (or less)
646 if (len <= 0)
648 r->_errno = EOVERFLOW;
649 return -1;
652 int cnt_retry=2;
653 retry_read:
654 if (ReadSMBFromCache(ptr, len, file) < 0)
656 retry_reconnect:
657 cnt_retry--;
658 if(cnt_retry>=0)
660 _SMB_lock();
661 if(CheckSMBConnection(SMBEnv[file->env].name))
663 ClearSMBFileCache(file);
664 file->handle = SMB_OpenFile(file->filename, file->access, SMB_OF_OPEN, SMBEnv[file->env].smbconn);
665 if (!file->handle)
667 r->_errno = ENOENT;
668 _SMB_unlock();
669 return -1;
671 _SMB_unlock();
672 goto retry_read;
674 _SMB_unlock();
675 usleep(50000);
676 goto retry_reconnect;
678 r->_errno = EOVERFLOW;
679 return -1;
681 file->offset += len;
683 return len;
687 static ssize_t __smb_write(struct _reent *r, int fd, const char *ptr, size_t len)
689 SMBFILESTRUCT *file = (SMBFILESTRUCT*) fd;
690 int written;
691 if (file == NULL)
693 r->_errno = EBADF;
694 return -1;
697 // Don't try to write if the pointer is past the end of file
698 if (file->offset > file->len)
700 r->_errno = EOVERFLOW;
701 return -1;
704 // Short circuit cases where len is 0 (or less)
705 if (len <= 0)
707 r->_errno = EOVERFLOW;
708 return -1;
711 ClearSMBFileCache(file);
712 written = WriteSMBUsingCache(ptr, len, file);
713 if (written <= 0)
715 r->_errno = EIO;
716 return -1;
719 return written;
722 static int __smb_close(struct _reent *r, int fd)
724 SMBFILESTRUCT *file = (SMBFILESTRUCT*) fd;
725 int j;
726 j=file->env;
727 _SMB_lock();
728 if (SMBEnv[j].SMBWriteCache.file == file)
730 FlushWriteSMBCache(SMBEnv[j].name);
732 ClearSMBFileCache(file);
733 SMB_CloseFile(file->handle);
734 _SMB_unlock();
735 file->len = 0;
736 file->offset = 0;
737 file->filename[0] = '\0';
739 return 0;
742 static int __smb_chdir(struct _reent *r, const char *path)
744 char path_absolute[SMB_MAXPATH];
746 SMBDIRENTRY dentry;
747 int found;
749 ExtractDevice(path,path_absolute);
750 if(path_absolute[0]=='\0')
752 getcwd(path_absolute,SMB_MAXPATH);
753 ExtractDevice(path_absolute,path_absolute);
756 smb_env* env;
757 env=FindSMBEnv(path_absolute);
759 if (smb_absolute_path_no_device(path, path_absolute,env->pos) == NULL)
761 r->_errno = EINVAL;
762 return -1;
765 memset(&dentry, 0, sizeof(SMBDIRENTRY));
767 _SMB_lock();
768 found = SMB_PathInfo(path_absolute, &dentry, env->smbconn);
769 _SMB_unlock();
771 if (found != SMB_SUCCESS)
773 r->_errno = ENOENT;
774 return -1;
777 if (!(dentry.attributes & SMB_SRCH_DIRECTORY))
779 r->_errno = ENOTDIR;
780 return -1;
783 strcpy(env->currentpath, path_absolute);
784 if (env->currentpath[0] != 0)
786 if (env->currentpath[strlen(env->currentpath) - 1] != '\\')
787 strcat(env->currentpath, "\\");
790 return 0;
793 static int __smb_dirreset(struct _reent *r, DIR_ITER *dirState)
795 char path_abs[SMB_MAXPATH];
796 SMBDIRSTATESTRUCT* state = (SMBDIRSTATESTRUCT*) (dirState->dirStruct);
797 SMBDIRENTRY dentry;
799 memset(&dentry, 0, sizeof(SMBDIRENTRY));
801 _SMB_lock();
802 SMB_FindClose(SMBEnv[state->env].smbconn);
804 strcpy(path_abs,SMBEnv[state->env].currentpath);
805 strcat(path_abs,"*");
806 int found = SMB_FindFirst(path_abs, SMB_SRCH_DIRECTORY | SMB_SRCH_SYSTEM | SMB_SRCH_HIDDEN | SMB_SRCH_READONLY | SMB_SRCH_ARCHIVE, &dentry, SMBEnv[state->env].smbconn);
807 _SMB_unlock();
809 if (found != SMB_SUCCESS)
811 r->_errno = ENOENT;
812 return -1;
815 if (!(dentry.attributes & SMB_SRCH_DIRECTORY))
817 r->_errno = ENOTDIR;
818 return -1;
821 state->smbdir.size = dentry.size;
822 state->smbdir.ctime = dentry.ctime;
823 state->smbdir.atime = dentry.atime;
824 state->smbdir.mtime = dentry.mtime;
825 state->smbdir.attributes = dentry.attributes;
826 strcpy(state->smbdir.name, dentry.name);
828 SMBEnv[state->env].first_item_dir = true;
829 return 0;
832 static DIR_ITER* __smb_diropen(struct _reent *r, DIR_ITER *dirState, const char *path)
834 char path_absolute[SMB_MAXPATH];
835 int found;
836 SMBDIRSTATESTRUCT* state = (SMBDIRSTATESTRUCT*) (dirState->dirStruct);
837 SMBDIRENTRY dentry;
839 ExtractDevice(path,path_absolute);
840 if(path_absolute[0]=='\0')
842 getcwd(path_absolute,SMB_MAXPATH);
843 ExtractDevice(path_absolute,path_absolute);
846 smb_env* env;
847 env=FindSMBEnv(path_absolute);
848 if (smb_absolute_path_no_device(path, path_absolute, env->pos) == NULL)
850 r->_errno = EINVAL;
851 return NULL;
853 if (path_absolute[strlen(path_absolute) - 1] != '\\')
854 strcat(path_absolute, "\\");
856 if(!strcmp(path_absolute,"\\"))
857 env->diropen_root=true;
858 else
859 env->diropen_root=false;
861 strcat(path_absolute, "*");
864 memset(&dentry, 0, sizeof(SMBDIRENTRY));
865 _SMB_lock();
866 found = SMB_FindFirst(path_absolute, SMB_SRCH_DIRECTORY | SMB_SRCH_SYSTEM | SMB_SRCH_HIDDEN | SMB_SRCH_READONLY | SMB_SRCH_ARCHIVE, &dentry, env->smbconn);
867 _SMB_unlock();
869 if (found != SMB_SUCCESS)
871 r->_errno = ENOENT;
872 return NULL;
875 if (!(dentry.attributes & SMB_SRCH_DIRECTORY))
877 r->_errno = ENOTDIR;
878 return NULL;
881 state->env=env->pos;
882 state->smbdir.size = dentry.size;
883 state->smbdir.ctime = dentry.ctime;
884 state->smbdir.atime = dentry.atime;
885 state->smbdir.mtime = dentry.mtime;
886 state->smbdir.attributes = dentry.attributes;
887 strcpy(state->smbdir.name, dentry.name);
888 env->first_item_dir = true;
889 return dirState;
892 static int dentry_to_stat(SMBDIRENTRY *dentry, struct stat *st)
894 if (!st)
895 return -1;
896 if (!dentry)
897 return -1;
899 st->st_dev = 0;
900 st->st_ino = 0;
902 st->st_mode = ((dentry->attributes & SMB_SRCH_DIRECTORY) ? S_IFDIR
903 : S_IFREG);
904 st->st_nlink = 1;
905 st->st_uid = 1; // Faked
906 st->st_rdev = st->st_dev;
907 st->st_gid = 2; // Faked
908 st->st_size = dentry->size;
909 st->st_atime = dentry->atime/10000000.0 - 11644473600LL;
910 st->st_spare1 = 0;
911 st->st_mtime = dentry->mtime/10000000.0 - 11644473600LL;
912 st->st_spare2 = 0;
913 st->st_ctime = dentry->ctime/10000000.0 - 11644473600LL;
914 st->st_spare3 = 0;
915 st->st_blksize = 1024;
916 st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize; // File size in blocks
917 st->st_spare4[0] = 0;
918 st->st_spare4[1] = 0;
920 return 0;
923 static int __smb_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename,
924 struct stat *filestat)
926 int ret;
927 SMBDIRSTATESTRUCT* state = (SMBDIRSTATESTRUCT*) (dirState->dirStruct);
928 SMBDIRENTRY dentry;
930 if (SMBEnv[state->env].currentpath[0] == '\0' || filestat == NULL)
932 r->_errno = ENOENT;
933 return -1;
936 memset(&dentry, 0, sizeof(SMBDIRENTRY));
937 if (SMBEnv[state->env].first_item_dir)
939 SMBEnv[state->env].first_item_dir = false;
940 dentry.size = 0;
941 dentry.attributes = SMB_SRCH_DIRECTORY;
942 strcpy(dentry.name, ".");
944 state->smbdir.size = dentry.size;
945 state->smbdir.ctime = dentry.ctime;
946 state->smbdir.atime = dentry.atime;
947 state->smbdir.mtime = dentry.mtime;
948 state->smbdir.attributes = dentry.attributes;
949 strcpy(state->smbdir.name, dentry.name);
950 strcpy(filename, dentry.name);
951 dentry_to_stat(&dentry, filestat);
953 return 0;
956 _SMB_lock();
957 ret = SMB_FindNext(&dentry, SMBEnv[state->env].smbconn);
958 if(ret==SMB_SUCCESS && SMBEnv[state->env].diropen_root && !strcmp(dentry.name,".."))
959 ret = SMB_FindNext(&dentry, SMBEnv[state->env].smbconn);
960 _SMB_unlock();
962 if (ret == SMB_SUCCESS)
964 state->smbdir.size = dentry.size;
965 state->smbdir.ctime = dentry.ctime;
966 state->smbdir.atime = dentry.atime;
967 state->smbdir.mtime = dentry.mtime;
968 state->smbdir.attributes = dentry.attributes;
969 strcpy(state->smbdir.name, dentry.name);
971 else
973 r->_errno = ENOENT;
974 return -1;
977 strcpy(filename, dentry.name);
979 dentry_to_stat(&dentry, filestat);
981 return 0;
984 static int __smb_dirclose(struct _reent *r, DIR_ITER *dirState)
986 SMBDIRSTATESTRUCT* state = (SMBDIRSTATESTRUCT*) (dirState->dirStruct);
988 _SMB_lock();
989 SMB_FindClose(SMBEnv[state->env].smbconn);
990 _SMB_unlock();
992 memset(state, 0, sizeof(SMBDIRSTATESTRUCT));
993 return 0;
996 static int __smb_stat(struct _reent *r, const char *path, struct stat *st)
998 char path_absolute[SMB_MAXPATH];
999 SMBDIRENTRY dentry;
1001 ExtractDevice(path,path_absolute);
1002 if(path_absolute[0]=='\0')
1004 getcwd(path_absolute,SMB_MAXPATH);
1005 ExtractDevice(path_absolute,path_absolute);
1008 smb_env* env;
1009 env=FindSMBEnv(path_absolute);
1011 if (smb_absolute_path_no_device(path, path_absolute, env->pos) == NULL)
1013 r->_errno = EINVAL;
1014 return -1;
1016 _SMB_lock();
1017 if (SMB_PathInfo(path_absolute, &dentry, env->smbconn) != SMB_SUCCESS)
1019 _SMB_unlock();
1020 r->_errno = ENOENT;
1021 return -1;
1023 _SMB_unlock();
1025 if (dentry.name[0] == '\0')
1027 r->_errno = ENOENT;
1028 return -1;
1031 dentry_to_stat(&dentry, st);
1033 return 0;
1036 static int __smb_fstat(struct _reent *r, int fd, struct stat *st)
1038 SMBFILESTRUCT *filestate = (SMBFILESTRUCT *) fd;
1040 if (!filestate)
1042 r->_errno = EBADF;
1043 return -1;
1046 st->st_size = filestate->len;
1048 return 0;
1051 void MountDevice(const char *name,SMBCONN smbconn, int env)
1053 devoptab_t *dotab_smb;
1055 dotab_smb=(devoptab_t*)malloc(sizeof(devoptab_t));
1057 dotab_smb->name=strdup(name);
1058 dotab_smb->structSize=sizeof(SMBFILESTRUCT); // size of file structure
1059 dotab_smb->open_r=__smb_open; // device open
1060 dotab_smb->close_r=__smb_close; // device close
1061 dotab_smb->write_r=__smb_write; // device write
1062 dotab_smb->read_r=__smb_read; // device read
1063 dotab_smb->seek_r=__smb_seek; // device seek
1064 dotab_smb->fstat_r=__smb_fstat; // device fstat
1065 dotab_smb->stat_r=__smb_stat; // device stat
1066 dotab_smb->link_r=NULL; // device link
1067 dotab_smb->unlink_r=NULL; // device unlink
1068 dotab_smb->chdir_r=__smb_chdir; // device chdir
1069 dotab_smb->rename_r=NULL; // device rename
1070 dotab_smb->mkdir_r=NULL; // device mkdir
1072 dotab_smb->dirStateSize=sizeof(SMBDIRSTATESTRUCT); // dirStateSize
1073 dotab_smb->diropen_r=__smb_diropen; // device diropen_r
1074 dotab_smb->dirreset_r=__smb_dirreset; // device dirreset_r
1075 dotab_smb->dirnext_r=__smb_dirnext; // device dirnext_r
1076 dotab_smb->dirclose_r=__smb_dirclose; // device dirclose_r
1077 dotab_smb->statvfs_r=NULL; // device statvfs_r
1078 dotab_smb->ftruncate_r=NULL; // device ftruncate_r
1079 dotab_smb->fsync_r=NULL; // device fsync_r
1080 dotab_smb->deviceData=NULL; /* Device data */
1082 AddDevice(dotab_smb);
1084 SMBEnv[env].pos=env;
1085 SMBEnv[env].smbconn=smbconn;
1086 SMBEnv[env].name=strdup(name);
1087 SMBEnv[env].SMBCONNECTED=true;
1088 SMBEnv[env].first_item_dir=false;
1089 SMBEnv[env].diropen_root=false;
1090 SMBEnv[env].devoptab=dotab_smb;
1092 SMBEnableReadAhead(SMBEnv[env].name,32);
1095 bool smbInitDevice(const char* name, const char *user, const char *password, const char *share, const char *ip)
1097 char myIP[16];
1098 int i;
1099 if(FirstInit)
1101 for(i=0;i<MAX_SMB_MOUNTED;i++)
1103 SMBEnv[i].SMBCONNECTED=false;
1104 SMBEnv[i].currentpath[0]='\\';
1105 SMBEnv[i].currentpath[1]='\0';
1106 SMBEnv[i].first_item_dir=false;
1107 SMBEnv[i].pos=i;
1108 SMBEnv[i].SMBReadAheadCache=NULL;
1110 FirstInit=false;
1113 for(i=0;i<MAX_SMB_MOUNTED && SMBEnv[i].SMBCONNECTED;i++);
1114 if(i==MAX_SMB_MOUNTED) return false; //all allowed samba connections reached
1116 if (if_config(myIP, NULL, NULL, true) < 0)
1117 return false;
1118 SMBCONN smbconn;
1119 if(_SMB_mutex==LWP_MUTEX_NULL)LWP_MutexInit(&_SMB_mutex, false);
1121 //root connect
1122 _SMB_lock();
1123 if (SMB_Connect(&smbconn, user, password, share, ip) != SMB_SUCCESS)
1125 _SMB_unlock();
1126 //LWP_MutexDestroy(_SMB_mutex);
1127 return false;
1129 _SMB_unlock();
1131 MountDevice(name,smbconn,i);
1133 if(end_cache_thread == true) // never close thread
1135 lwp_t client_thread;
1136 main_thread = LWP_GetSelf();
1137 end_cache_thread = false;
1138 LWP_CreateThread(&client_thread, process_cache_thread, NULL, NULL, 0, 80);
1140 return true;
1143 bool smbInit(const char *user, const char *password, const char *share, const char *ip)
1145 return smbInitDevice("smb", user, password, share, ip);
1148 void smbClose(const char* name)
1150 smb_env *env;
1151 env=FindSMBEnv(name);
1152 if(env==NULL) return;
1154 if(env->SMBCONNECTED)
1156 _SMB_lock();
1157 SMB_Close(env->smbconn);
1158 _SMB_unlock();
1160 env->SMBCONNECTED=false;
1161 RemoveDevice(env->name);
1162 //LWP_MutexDestroy(_SMB_mutex);
1165 bool CheckSMBConnection(const char* name)
1167 char device[50];
1168 int i;
1169 bool ret;
1170 smb_env *env;
1172 for(i=0;i<50 && name[i]!='\0' && name[i]!=':';i++) device[i]=name[i];
1173 device[i]='\0';
1175 env=FindSMBEnv(device);
1176 if(env==NULL) return false;
1177 _SMB_lock();
1178 ret=(SMB_Reconnect(&env->smbconn,true)==SMB_SUCCESS);
1179 _SMB_unlock();
1180 return ret;