1 /****************************************************************************
3 * Nintendo Wii/GameCube SMB implementation
6 ****************************************************************************/
14 #include <sys/iosupport.h>
17 #include <ogc/lwp_watchdog.h>
18 #include <ogc/mutex.h>
19 #include <sys/statvfs.h>
23 #define MAX_SMB_MOUNTED 10
25 static lwp_t cache_thread
= LWP_THREAD_NULL
;
32 char filename
[SMB_MAXPATH
];
33 unsigned short access
;
43 static bool smbInited
= false;
44 static unsigned short smbFlags
= SMB_SRCH_DIRECTORY
| SMB_SRCH_READONLY
;
46 ///////////////////////////////////////////
47 // CACHE FUNCTION DEFINITIONS //
48 ///////////////////////////////////////////
49 #define SMB_READ_BUFFERSIZE 65472
50 #define SMB_WRITE_BUFFERSIZE (60*1024)
68 static void DestroySMBReadAheadCache(const char *name
);
69 static void SMBEnableReadAhead(const char *name
, u32 pages
);
70 static int ReadSMBFromCache(void *buf
, size_t len
, SMBFILESTRUCT
*file
);
72 ///////////////////////////////////////////
73 // END CACHE FUNCTION DEFINITIONS //
74 ///////////////////////////////////////////
86 char currentpath
[SMB_MAXPATH
];
90 smb_write_cache SMBWriteCache
;
91 smb_cache_page
*SMBReadAheadCache
;
97 static smb_env SMBEnv
[MAX_SMB_MOUNTED
];
99 static inline void _SMB_lock(int i
)
101 if(SMBEnv
[i
]._SMB_mutex
!=LWP_MUTEX_NULL
) LWP_MutexLock(SMBEnv
[i
]._SMB_mutex
);
104 static inline void _SMB_unlock(int i
)
106 if(SMBEnv
[i
]._SMB_mutex
!=LWP_MUTEX_NULL
) LWP_MutexUnlock(SMBEnv
[i
]._SMB_mutex
);
109 ///////////////////////////////////////////
110 // CACHE FUNCTIONS //
111 ///////////////////////////////////////////
113 static smb_env
* FindSMBEnv(const char *name
)
120 if(aux
[i
-1]==':')aux
[i
-1]='\0';
121 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
123 if(SMBEnv
[i
].SMBCONNECTED
&& strcmp(aux
,SMBEnv
[i
].name
)==0)
133 static int FlushWriteSMBCache(char *name
)
136 env
=FindSMBEnv(name
);
137 if(env
==NULL
) return -1;
139 if (env
->SMBWriteCache
.file
== NULL
|| env
->SMBWriteCache
.len
== 0)
147 while(env
->SMBWriteCache
.len
> 0)
149 ret
= SMB_WriteFile(env
->SMBWriteCache
.ptr
+written
, env
->SMBWriteCache
.len
,
150 env
->SMBWriteCache
.file
->offset
, env
->SMBWriteCache
.file
->handle
);
156 env
->SMBWriteCache
.file
->offset
+= ret
;
157 if (env
->SMBWriteCache
.file
->offset
> env
->SMBWriteCache
.file
->len
)
158 env
->SMBWriteCache
.file
->len
= env
->SMBWriteCache
.file
->offset
;
160 env
->SMBWriteCache
.len
-=ret
;
161 if(env
->SMBWriteCache
.len
==0) break;
163 env
->SMBWriteCache
.used
= 0;
164 env
->SMBWriteCache
.file
= NULL
;
169 static void DestroySMBReadAheadCache(const char *name
)
172 env
=FindSMBEnv(name
);
173 if(env
==NULL
) return ;
176 if (env
->SMBReadAheadCache
!= NULL
)
178 for (i
= 0; i
< env
->SMB_RA_pages
; i
++)
180 if(env
->SMBReadAheadCache
[i
].ptr
)
181 free(env
->SMBReadAheadCache
[i
].ptr
);
183 free(env
->SMBReadAheadCache
);
184 env
->SMBReadAheadCache
= NULL
;
185 env
->SMB_RA_pages
= 0;
187 FlushWriteSMBCache(env
->name
);
189 if(env
->SMBWriteCache
.ptr
)
190 free(env
->SMBWriteCache
.ptr
);
192 env
->SMBWriteCache
.used
= 0;
193 env
->SMBWriteCache
.len
= 0;
194 env
->SMBWriteCache
.file
= NULL
;
195 env
->SMBWriteCache
.ptr
= NULL
;
198 static void *process_cache_thread(void *ptr
)
203 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
205 if(SMBEnv
[i
].SMBCONNECTED
)
207 if (SMBEnv
[i
].SMBWriteCache
.used
> 0)
209 if (ticks_to_millisecs(gettime())-ticks_to_millisecs(SMBEnv
[i
].SMBWriteCache
.used
) > 500)
212 FlushWriteSMBCache(SMBEnv
[i
].name
);
223 static void SMBEnableReadAhead(const char *name
, u32 pages
)
228 env
=FindSMBEnv(name
);
229 if(env
==NULL
) return;
231 DestroySMBReadAheadCache(name
);
236 //only 1 page for write
237 env
->SMBWriteCache
.ptr
= memalign(32, SMB_WRITE_BUFFERSIZE
);
238 env
->SMBWriteCache
.used
= 0;
239 env
->SMBWriteCache
.len
= 0;
240 env
->SMBWriteCache
.file
= NULL
;
242 env
->SMB_RA_pages
= pages
;
243 env
->SMBReadAheadCache
= (smb_cache_page
*) malloc(sizeof(smb_cache_page
) * env
->SMB_RA_pages
);
244 if (env
->SMBReadAheadCache
== NULL
)
246 for (i
= 0; i
< env
->SMB_RA_pages
; i
++)
248 env
->SMBReadAheadCache
[i
].offset
= 0;
249 env
->SMBReadAheadCache
[i
].last_used
= 0;
250 env
->SMBReadAheadCache
[i
].file
= NULL
;
251 env
->SMBReadAheadCache
[i
].ptr
= memalign(32, SMB_READ_BUFFERSIZE
);
252 if (env
->SMBReadAheadCache
[i
].ptr
== NULL
)
254 for (j
= i
- 1; j
>= 0; j
--)
255 if (env
->SMBReadAheadCache
[j
].ptr
)
256 free(env
->SMBReadAheadCache
[j
].ptr
);
257 free(env
->SMBReadAheadCache
);
258 env
->SMBReadAheadCache
= NULL
;
259 free(env
->SMBWriteCache
.ptr
);
262 memset(env
->SMBReadAheadCache
[i
].ptr
, 0, SMB_READ_BUFFERSIZE
);
266 // clear cache from file
267 // called when file is closed
268 static void ClearSMBFileCache(SMBFILESTRUCT
*file
)
273 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
275 if (SMBEnv
[j
].SMBReadAheadCache
[i
].file
== file
)
277 SMBEnv
[j
].SMBReadAheadCache
[i
].offset
= 0;
278 SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
= 0;
279 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
280 memset(SMBEnv
[j
].SMBReadAheadCache
[i
].ptr
, 0, SMB_READ_BUFFERSIZE
);
285 static int ReadSMBFromCache(void *buf
, size_t len
, SMBFILESTRUCT
*file
)
288 off_t new_offset
, rest
;
291 if ( len
== 0 ) return 0;
293 if (SMBEnv
[j
].SMBReadAheadCache
== NULL
)
295 if (SMB_ReadFile(buf
, len
, file
->offset
, file
->handle
) <= 0)
302 new_offset
= file
->offset
;
307 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
309 if (SMBEnv
[j
].SMBReadAheadCache
[i
].file
== file
)
311 if ((new_offset
>= SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) &&
312 (new_offset
< (SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
)))
315 //copy as much as we can
316 SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
= gettime();
318 off_t buffer_used
= (SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
) - new_offset
;
319 if (buffer_used
> rest
) buffer_used
= rest
;
320 memcpy(buf
, SMBEnv
[j
].SMBReadAheadCache
[i
].ptr
+ (new_offset
- SMBEnv
[j
].SMBReadAheadCache
[i
].offset
), buffer_used
);
323 new_offset
+= buffer_used
;
335 for ( i
= 1; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
337 if ((SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
< SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].last_used
))
341 //fill least used page with new data
343 off_t cache_offset
= new_offset
;
345 //do not interset with existing pages
346 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
348 if ( i
== leastUsed
) continue;
349 if ( SMBEnv
[j
].SMBReadAheadCache
[i
].file
!= file
) continue;
351 if ( (cache_offset
< SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) && (cache_offset
+ SMB_READ_BUFFERSIZE
> SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) )
353 //tail of new page intersects with some cache block, clear page
354 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
357 if ( (cache_offset
>= SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) && (cache_offset
< SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
) )
359 //head of new page intersects with some cache block, clear page
360 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
364 off_t cache_to_read
= file
->len
- cache_offset
;
365 if ( cache_to_read
> SMB_READ_BUFFERSIZE
)
367 cache_to_read
= SMB_READ_BUFFERSIZE
;
371 while(read
<cache_to_read
)
373 if ( (read
+=SMB_ReadFile(SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].ptr
+read
, cache_to_read
-read
, cache_offset
+read
, file
->handle
)) <=0 )
375 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].file
= NULL
;
379 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].last_used
= gettime();
381 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].offset
= cache_offset
;
382 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].file
= file
;
387 static int WriteSMBUsingCache(const char *buf
, size_t len
, SMBFILESTRUCT
*file
)
390 if (file
== NULL
|| buf
== NULL
)
394 if (SMBEnv
[j
].SMBWriteCache
.file
!= NULL
)
396 if (strcmp(SMBEnv
[j
].SMBWriteCache
.file
->filename
, file
->filename
) != 0)
398 //Flush current buffer
399 if (FlushWriteSMBCache(SMBEnv
[j
].name
) < 0)
403 SMBEnv
[j
].SMBWriteCache
.file
= file
;
404 SMBEnv
[j
].SMBWriteCache
.len
= 0;
409 SMBEnv
[j
].SMBWriteCache
.file
= file
;
410 SMBEnv
[j
].SMBWriteCache
.len
= 0;
416 if(SMBEnv
[j
].SMBWriteCache
.len
+len
>= SMB_WRITE_BUFFERSIZE
)
418 rest
= SMB_WRITE_BUFFERSIZE
- SMBEnv
[j
].SMBWriteCache
.len
;
419 memcpy(SMBEnv
[j
].SMBWriteCache
.ptr
+ SMBEnv
[j
].SMBWriteCache
.len
, buf
, rest
);
421 written
= SMB_WriteFile(SMBEnv
[j
].SMBWriteCache
.ptr
, SMB_WRITE_BUFFERSIZE
, file
->offset
, file
->handle
);
426 file
->offset
+= written
;
427 if (file
->offset
> file
->len
)
428 file
->len
= file
->offset
;
432 SMBEnv
[j
].SMBWriteCache
.used
= gettime();
433 SMBEnv
[j
].SMBWriteCache
.len
= 0;
437 memcpy(SMBEnv
[j
].SMBWriteCache
.ptr
+ SMBEnv
[j
].SMBWriteCache
.len
, buf
, len
);
438 SMBEnv
[j
].SMBWriteCache
.len
+= len
;
439 SMBEnv
[j
].SMBWriteCache
.used
= gettime();
449 ///////////////////////////////////////////
450 // END CACHE FUNCTIONS //
451 ///////////////////////////////////////////
453 static char *smb_absolute_path_no_device(const char *srcpath
, char *destpath
, int env
)
455 char temp
[SMB_MAXPATH
];
458 if (strchr(srcpath
, ':') != NULL
)
460 srcpath
= strchr(srcpath
, ':') + 1;
462 if (strchr(srcpath
, ':') != NULL
)
469 if (srcpath
[0] != '\\' && srcpath
[0] != '/')
471 strcpy(temp
, SMBEnv
[env
].currentpath
);
473 if(srcpath
[0]!='\0') //strlen(srcpath) > 0
475 if(srcpath
[0]=='.' && (srcpath
[1]=='\\' || srcpath
[1]=='\\' || srcpath
[1]=='\0')) // to fix opendir(".") or chdir(".")
476 strcat(temp
, &srcpath
[1]);
478 strcat(temp
, srcpath
);
486 while(temp
[i
]!='\0' && (temp
[i
]=='/' || temp
[i
]=='\\'))i
++;
488 else if(srcpath
[i
]=='\\')
490 destpath
[j
++]=temp
[i
++];
491 while(temp
[i
]!='\0' && (temp
[i
]=='/' || temp
[i
]=='\\'))i
++;
495 destpath
[j
++]=temp
[i
++];
503 static char *ExtractDevice(const char *path
, char *device
)
508 for(i
=0;i
<l
&& path
[i
]!='\0' && path
[i
]!=':' && i
< 20;i
++)
510 if(path
[i
]!=':')device
[0]='\0';
516 static int __smb_open(struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
)
518 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fileStruct
;
519 char fixedpath
[SMB_MAXPATH
];
522 ExtractDevice(path
,fixedpath
);
523 if(fixedpath
[0]=='\0')
525 getcwd(fixedpath
,SMB_MAXPATH
);
526 ExtractDevice(fixedpath
,fixedpath
);
528 env
=FindSMBEnv(fixedpath
);
536 if (!env
->SMBCONNECTED
)
542 if (smb_absolute_path_no_device(path
, fixedpath
, file
->env
) == NULL
)
548 if(!smbCheckConnection(env
->name
))
555 bool fileExists
= true;
557 if (SMB_PathInfo(fixedpath
, &dentry
, env
->smbconn
) != SMB_SUCCESS
)
560 // Determine which mode the file is open for
562 unsigned short access
;
563 if ((flags
& 0x03) == O_RDONLY
)
565 // Open the file for read-only access
566 smb_mode
= SMB_OF_OPEN
;
567 access
= SMB_OPEN_READING
;
569 else if ((flags
& 0x03) == O_WRONLY
)
571 // Open file for write only access
573 smb_mode
= SMB_OF_OPEN
;
575 smb_mode
= SMB_OF_CREATE
;
576 access
= SMB_OPEN_WRITING
;
578 else if ((flags
& 0x03) == O_RDWR
)
580 // Open file for read/write access
581 access
= SMB_OPEN_READWRITE
;
583 smb_mode
= SMB_OF_OPEN
;
585 smb_mode
= SMB_OF_CREATE
;
590 _SMB_unlock(env
->pos
);
594 if ((flags
& O_CREAT
) && !fileExists
)
595 smb_mode
= SMB_OF_CREATE
;
596 if (!(flags
& O_APPEND
) && fileExists
&& ((flags
& 0x03) != O_RDONLY
))
597 smb_mode
= SMB_OF_TRUNCATE
;
599 file
->handle
= SMB_OpenFile(fixedpath
, access
, smb_mode
, env
->smbconn
);
603 _SMB_unlock(env
->pos
);
609 file
->len
= dentry
.size
;
611 if (flags
& O_APPEND
)
612 file
->offset
= file
->len
;
618 strcpy(file
->filename
, fixedpath
);
619 _SMB_unlock(env
->pos
);
623 static off_t
__smb_seek(struct _reent
*r
, int fd
, off_t pos
, int dir
)
625 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
634 //have to flush because SMBWriteCache.file->offset holds offset of cached block not yet written
635 _SMB_lock(file
->env
);
636 if (SMBEnv
[file
->env
].SMBWriteCache
.file
== file
)
638 FlushWriteSMBCache(SMBEnv
[file
->env
].name
);
647 position
= file
->offset
+ pos
;
650 position
= file
->len
+ pos
;
654 _SMB_unlock(file
->env
);
658 if (pos
> 0 && position
< 0)
660 r
->_errno
= EOVERFLOW
;
661 _SMB_unlock(file
->env
);
667 _SMB_unlock(file
->env
);
672 file
->offset
= position
;
673 _SMB_unlock(file
->env
);
677 static ssize_t
__smb_read(struct _reent
*r
, int fd
, char *ptr
, size_t len
)
683 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
691 //have to flush because SMBWriteCache.file->offset holds offset of cached block not yet writeln
692 //and file->len also may not have been updated yet
693 _SMB_lock(file
->env
);
694 if (SMBEnv
[file
->env
].SMBWriteCache
.file
== file
)
696 FlushWriteSMBCache(SMBEnv
[file
->env
].name
);
699 // Don't try to read if the read pointer is past the end of file
700 if (file
->offset
>= file
->len
)
702 r
->_errno
= EOVERFLOW
;
703 _SMB_unlock(file
->env
);
707 // Don't read past end of file
708 if (len
+ file
->offset
> file
->len
)
710 r
->_errno
= EOVERFLOW
;
711 len
= file
->len
- file
->offset
;
714 // Short circuit cases where len is 0 (or less)
717 _SMB_unlock(file
->env
);
723 r
->_errno
= EOVERFLOW
;
724 _SMB_unlock(file
->env
);
731 readsize
= len
- offset
;
732 if(readsize
> SMB_READ_BUFFERSIZE
) readsize
= SMB_READ_BUFFERSIZE
;
733 ret
= ReadSMBFromCache(ptr
+offset
, readsize
, file
);
736 file
->offset
+= readsize
;
745 if(smbCheckConnection(SMBEnv
[file
->env
].name
))
747 ClearSMBFileCache(file
);
748 file
->handle
= SMB_OpenFile(file
->filename
, file
->access
, SMB_OF_OPEN
, SMBEnv
[file
->env
].smbconn
);
752 _SMB_unlock(file
->env
);
758 goto retry_reconnect
;
761 _SMB_unlock(file
->env
);
764 _SMB_unlock(file
->env
);
768 static ssize_t
__smb_write(struct _reent
*r
, int fd
, const char *ptr
, size_t len
)
770 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
778 // Don't try to write if the pointer is past the end of file
779 if (file
->offset
> file
->len
)
781 r
->_errno
= EOVERFLOW
;
785 // Short circuit cases where len is 0 (or less)
791 r
->_errno
= EOVERFLOW
;
795 _SMB_lock(file
->env
);
796 written
= WriteSMBUsingCache(ptr
, len
, file
);
797 _SMB_unlock(file
->env
);
808 static int __smb_close(struct _reent
*r
, int fd
)
810 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
814 if (SMBEnv
[j
].SMBWriteCache
.file
== file
)
816 FlushWriteSMBCache(SMBEnv
[j
].name
);
818 ClearSMBFileCache(file
);
819 SMB_CloseFile(file
->handle
);
822 file
->filename
[0] = '\0';
828 static int __smb_chdir(struct _reent
*r
, const char *path
)
830 char path_absolute
[SMB_MAXPATH
];
835 ExtractDevice(path
,path_absolute
);
836 if(path_absolute
[0]=='\0')
838 getcwd(path_absolute
,SMB_MAXPATH
);
839 ExtractDevice(path_absolute
,path_absolute
);
843 env
=FindSMBEnv(path_absolute
);
851 if (!env
->SMBCONNECTED
)
857 if (smb_absolute_path_no_device(path
, path_absolute
,env
->pos
) == NULL
)
863 if(!smbCheckConnection(env
->name
))
869 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
872 found
= SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
);
874 if (found
!= SMB_SUCCESS
)
877 _SMB_unlock(env
->pos
);
881 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
884 _SMB_unlock(env
->pos
);
888 strcpy(env
->currentpath
, path_absolute
);
889 if (env
->currentpath
[0] != 0)
891 if (env
->currentpath
[strlen(env
->currentpath
) - 1] != '\\')
892 strcat(env
->currentpath
, "\\");
894 _SMB_unlock(env
->pos
);
898 static int __smb_dirreset(struct _reent
*r
, DIR_ITER
*dirState
)
900 char path_abs
[SMB_MAXPATH
];
901 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
904 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
906 _SMB_lock(state
->env
);
907 SMB_FindClose(&state
->smbdir
, SMBEnv
[state
->env
].smbconn
);
909 strcpy(path_abs
,SMBEnv
[state
->env
].currentpath
);
910 strcat(path_abs
,"*");
911 int found
= SMB_FindFirst(path_abs
, smbFlags
, &dentry
, SMBEnv
[state
->env
].smbconn
);
913 if (found
!= SMB_SUCCESS
)
916 _SMB_unlock(state
->env
);
920 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
923 _SMB_unlock(state
->env
);
927 state
->smbdir
.size
= dentry
.size
;
928 state
->smbdir
.ctime
= dentry
.ctime
;
929 state
->smbdir
.atime
= dentry
.atime
;
930 state
->smbdir
.mtime
= dentry
.mtime
;
931 state
->smbdir
.attributes
= dentry
.attributes
;
932 state
->smbdir
.sid
= dentry
.sid
;
933 strcpy(state
->smbdir
.name
, dentry
.name
);
935 SMBEnv
[state
->env
].first_item_dir
= true;
936 _SMB_unlock(state
->env
);
940 static DIR_ITER
* __smb_diropen(struct _reent
*r
, DIR_ITER
*dirState
, const char *path
)
942 char path_absolute
[SMB_MAXPATH
];
944 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
947 ExtractDevice(path
,path_absolute
);
948 if(path_absolute
[0]=='\0')
950 getcwd(path_absolute
,SMB_MAXPATH
);
951 ExtractDevice(path_absolute
,path_absolute
);
955 env
=FindSMBEnv(path_absolute
);
963 if (smb_absolute_path_no_device(path
, path_absolute
, env
->pos
) == NULL
)
968 if (strlen(path_absolute
) > 0 && path_absolute
[strlen(path_absolute
) - 1] != '\\')
969 strcat(path_absolute
, "\\");
971 if(!strcmp(path_absolute
,"\\"))
972 env
->diropen_root
=true;
974 env
->diropen_root
=false;
977 if(!env
->diropen_root
) // root must be valid - we don't need check it
979 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
980 found
= SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
);
981 if (found
!= SMB_SUCCESS
)
984 _SMB_unlock(env
->pos
);
988 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
991 _SMB_unlock(env
->pos
);
996 strcat(path_absolute
, "*");
997 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
998 found
= SMB_FindFirst(path_absolute
, smbFlags
, &dentry
, env
->smbconn
);
1000 if (found
!= SMB_SUCCESS
)
1003 _SMB_unlock(env
->pos
);
1007 state
->env
=env
->pos
;
1008 state
->smbdir
.size
= dentry
.size
;
1009 state
->smbdir
.ctime
= dentry
.ctime
;
1010 state
->smbdir
.atime
= dentry
.atime
;
1011 state
->smbdir
.mtime
= dentry
.mtime
;
1012 state
->smbdir
.attributes
= dentry
.attributes
;
1013 state
->smbdir
.sid
= dentry
.sid
;
1014 strcpy(state
->smbdir
.name
, dentry
.name
);
1015 env
->first_item_dir
= true;
1016 _SMB_unlock(env
->pos
);
1020 static int dentry_to_stat(SMBDIRENTRY
*dentry
, struct stat
*st
)
1030 st
->st_mode
= ((dentry
->attributes
& SMB_SRCH_DIRECTORY
) ? S_IFDIR
1033 st
->st_uid
= 1; // Faked
1034 st
->st_rdev
= st
->st_dev
;
1035 st
->st_gid
= 2; // Faked
1036 st
->st_size
= dentry
->size
;
1037 st
->st_atime
= dentry
->atime
/10000000.0 - 11644473600LL;
1039 st
->st_mtime
= dentry
->mtime
/10000000.0 - 11644473600LL;
1041 st
->st_ctime
= dentry
->ctime
/10000000.0 - 11644473600LL;
1043 st
->st_blksize
= 1024;
1044 st
->st_blocks
= (st
->st_size
+ st
->st_blksize
- 1) / st
->st_blksize
; // File size in blocks
1045 st
->st_spare4
[0] = 0;
1046 st
->st_spare4
[1] = 0;
1051 static int __smb_dirnext(struct _reent
*r
, DIR_ITER
*dirState
, char *filename
,
1052 struct stat
*filestat
)
1055 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
1058 if (SMBEnv
[state
->env
].currentpath
[0] == '\0' || filestat
== NULL
)
1064 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
1065 _SMB_lock(state
->env
);
1066 if (SMBEnv
[state
->env
].first_item_dir
)
1068 SMBEnv
[state
->env
].first_item_dir
= false;
1069 dentry
.size
= state
->smbdir
.size
;
1070 dentry
.ctime
= state
->smbdir
.ctime
;
1071 dentry
.atime
= state
->smbdir
.atime
;
1072 dentry
.mtime
= state
->smbdir
.mtime
;
1073 dentry
.attributes
= state
->smbdir
.attributes
;
1074 strcpy(dentry
.name
, state
->smbdir
.name
);
1075 strcpy(filename
, dentry
.name
);
1076 dentry_to_stat(&dentry
, filestat
);
1077 _SMB_unlock(state
->env
);
1081 dentry
.sid
= state
->smbdir
.sid
;
1083 ret
= SMB_FindNext(&dentry
, SMBEnv
[state
->env
].smbconn
);
1084 if(ret
==SMB_SUCCESS
&& SMBEnv
[state
->env
].diropen_root
)
1086 if(strlen(dentry
.name
) == 2 && strcmp(dentry
.name
,"..") == 0)
1087 ret
= SMB_FindNext(&dentry
, SMBEnv
[state
->env
].smbconn
);
1089 if (ret
== SMB_SUCCESS
)
1091 state
->smbdir
.size
= dentry
.size
;
1092 state
->smbdir
.ctime
= dentry
.ctime
;
1093 state
->smbdir
.atime
= dentry
.atime
;
1094 state
->smbdir
.mtime
= dentry
.mtime
;
1095 state
->smbdir
.attributes
= dentry
.attributes
;
1096 strcpy(state
->smbdir
.name
, dentry
.name
);
1097 strcpy(filename
, dentry
.name
);
1102 _SMB_unlock(state
->env
);
1106 dentry_to_stat(&dentry
, filestat
);
1107 _SMB_unlock(state
->env
);
1111 static int __smb_dirclose(struct _reent
*r
, DIR_ITER
*dirState
)
1113 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
1117 SMB_FindClose(&state
->smbdir
, SMBEnv
[j
].smbconn
);
1118 memset(state
, 0, sizeof(SMBDIRSTATESTRUCT
));
1123 static int __smb_stat(struct _reent
*r
, const char *path
, struct stat
*st
)
1125 char path_absolute
[SMB_MAXPATH
];
1128 ExtractDevice(path
,path_absolute
);
1129 if(path_absolute
[0]=='\0')
1131 getcwd(path_absolute
,SMB_MAXPATH
);
1132 ExtractDevice(path_absolute
,path_absolute
);
1136 env
=FindSMBEnv(path_absolute
);
1144 if (smb_absolute_path_no_device(path
, path_absolute
, env
->pos
) == NULL
)
1149 _SMB_lock(env
->pos
);
1150 if (SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
) != SMB_SUCCESS
)
1153 _SMB_unlock(env
->pos
);
1157 if (dentry
.name
[0] == '\0')
1160 _SMB_unlock(env
->pos
);
1164 dentry_to_stat(&dentry
, st
);
1165 _SMB_unlock(env
->pos
);
1170 static int __smb_fstat(struct _reent
*r
, int fd
, struct stat
*st
)
1172 SMBFILESTRUCT
*filestate
= (SMBFILESTRUCT
*) fd
;
1180 st
->st_size
= filestate
->len
;
1185 static int __smb_mkdir(struct _reent
*r
, const char *name
, int mode
)
1187 char fixedName
[SMB_MAXPATH
];
1190 ExtractDevice(name
,fixedName
);
1191 if(fixedName
[0]=='\0')
1193 getcwd(fixedName
,SMB_MAXPATH
);
1194 ExtractDevice(fixedName
,fixedName
);
1197 env
=FindSMBEnv(fixedName
);
1204 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1211 _SMB_lock(env
->pos
);
1212 if(SMB_CreateDirectory(fixedName
, env
->smbconn
) != SMB_SUCCESS
)
1214 _SMB_unlock(env
->pos
);
1219 static int __smb_unlink(struct _reent
*r
, const char *name
)
1221 char fixedName
[SMB_MAXPATH
];
1225 DIR_ITER
*dir
= NULL
;
1226 dir
= diropen(name
);
1233 ExtractDevice(name
,fixedName
);
1234 if(fixedName
[0]=='\0')
1236 getcwd(fixedName
,SMB_MAXPATH
);
1237 ExtractDevice(fixedName
,fixedName
);
1240 env
=FindSMBEnv(fixedName
);
1247 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1254 _SMB_lock(env
->pos
);
1256 ret
= SMB_DeleteDirectory(fixedName
, env
->smbconn
);
1258 ret
= SMB_DeleteFile(fixedName
, env
->smbconn
);
1259 _SMB_unlock(env
->pos
);
1261 if(ret
!= SMB_SUCCESS
)
1267 static int __smb_rename(struct _reent
*r
, const char *oldName
, const char *newName
)
1269 char fixedOldName
[SMB_MAXPATH
];
1270 char fixedNewName
[SMB_MAXPATH
];
1273 ExtractDevice(oldName
,fixedOldName
);
1274 if(fixedOldName
[0]=='\0')
1276 getcwd(fixedOldName
,SMB_MAXPATH
);
1277 ExtractDevice(fixedOldName
,fixedOldName
);
1280 env
=FindSMBEnv(fixedOldName
);
1287 if (smb_absolute_path_no_device(oldName
, fixedOldName
, env
->pos
) == NULL
)
1293 ExtractDevice(newName
,fixedNewName
);
1294 if(fixedNewName
[0]=='\0')
1296 getcwd(fixedNewName
,SMB_MAXPATH
);
1297 ExtractDevice(fixedNewName
,fixedNewName
);
1300 if (smb_absolute_path_no_device(newName
, fixedNewName
, env
->pos
) == NULL
)
1307 _SMB_lock(env
->pos
);
1308 if (SMB_Rename(fixedOldName
, fixedNewName
, env
->smbconn
) != SMB_SUCCESS
)
1310 _SMB_unlock(env
->pos
);
1315 static int __smb_statvfs_r(struct _reent
*r
, const char *name
, struct statvfs
*buf
)
1317 char fixedName
[SMB_MAXPATH
];
1320 ExtractDevice(name
,fixedName
);
1321 if(fixedName
[0]=='\0')
1323 getcwd(fixedName
,SMB_MAXPATH
);
1324 ExtractDevice(fixedName
,fixedName
);
1327 env
=FindSMBEnv(fixedName
);
1334 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1341 _SMB_lock(env
->pos
);
1342 if(SMB_DiskInformation(buf
, env
->smbconn
) != SMB_SUCCESS
)
1344 _SMB_unlock(env
->pos
);
1349 static void MountDevice(const char *name
,SMBCONN smbconn
, int env
)
1351 devoptab_t
*dotab_smb
;
1357 if(aux
[l
-1]==':')aux
[l
-1]='\0';
1359 dotab_smb
=(devoptab_t
*)malloc(sizeof(devoptab_t
));
1361 dotab_smb
->name
=strdup(aux
);
1362 dotab_smb
->structSize
=sizeof(SMBFILESTRUCT
); // size of file structure
1363 dotab_smb
->open_r
=__smb_open
; // device open
1364 dotab_smb
->close_r
=__smb_close
; // device close
1365 dotab_smb
->write_r
=__smb_write
; // device write
1366 dotab_smb
->read_r
=__smb_read
; // device read
1367 dotab_smb
->seek_r
=__smb_seek
; // device seek
1368 dotab_smb
->fstat_r
=__smb_fstat
; // device fstat
1369 dotab_smb
->stat_r
=__smb_stat
; // device stat
1370 dotab_smb
->link_r
=NULL
; // device link
1371 dotab_smb
->unlink_r
=__smb_unlink
; // device unlink
1372 dotab_smb
->chdir_r
=__smb_chdir
; // device chdir
1373 dotab_smb
->rename_r
=__smb_rename
; // device rename
1374 dotab_smb
->mkdir_r
=__smb_mkdir
; // device mkdir
1376 dotab_smb
->dirStateSize
=sizeof(SMBDIRSTATESTRUCT
); // dirStateSize
1377 dotab_smb
->diropen_r
=__smb_diropen
; // device diropen_r
1378 dotab_smb
->dirreset_r
=__smb_dirreset
; // device dirreset_r
1379 dotab_smb
->dirnext_r
=__smb_dirnext
; // device dirnext_r
1380 dotab_smb
->dirclose_r
=__smb_dirclose
; // device dirclose_r
1381 dotab_smb
->statvfs_r
=__smb_statvfs_r
; // device statvfs_r
1382 dotab_smb
->ftruncate_r
=NULL
; // device ftruncate_r
1383 dotab_smb
->fsync_r
=NULL
; // device fsync_r
1384 dotab_smb
->deviceData
=NULL
; /* Device data */
1386 AddDevice(dotab_smb
);
1388 SMBEnv
[env
].pos
=env
;
1389 SMBEnv
[env
].smbconn
=smbconn
;
1390 SMBEnv
[env
].first_item_dir
=false;
1391 SMBEnv
[env
].diropen_root
=false;
1392 SMBEnv
[env
].devoptab
=dotab_smb
;
1393 SMBEnv
[env
].SMBCONNECTED
=true;
1394 SMBEnv
[env
].name
=strdup(aux
);
1396 SMBEnableReadAhead(aux
,8);
1401 bool smbInitDevice(const char* name
, const char *user
, const char *password
, const char *share
, const char *ip
)
1405 if(!name
|| strlen(name
) > 9)
1409 sprintf(devname
, "%s:", name
);
1410 if(FindDevice(devname
) >= 0)
1415 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
1417 SMBEnv
[i
].SMBCONNECTED
=false;
1418 SMBEnv
[i
].currentpath
[0]='\\';
1419 SMBEnv
[i
].currentpath
[1]='\0';
1420 SMBEnv
[i
].first_item_dir
=false;
1422 SMBEnv
[i
].SMBReadAheadCache
=NULL
;
1423 LWP_MutexInit(&SMBEnv
[i
]._SMB_mutex
, false);
1426 if(cache_thread
== LWP_THREAD_NULL
)
1427 if(LWP_CreateThread(&cache_thread
, process_cache_thread
, NULL
, NULL
, 0, 64) != 0)
1436 if(SMB_Connect(&smbconn
, user
, password
, share
, ip
) != SMB_SUCCESS
)
1439 for(i
=0;i
<MAX_SMB_MOUNTED
&& SMBEnv
[i
].SMBCONNECTED
;i
++);
1441 if(i
==MAX_SMB_MOUNTED
)
1444 return false; // all samba connections in use
1447 SMBEnv
[i
].SMBCONNECTED
=true; // reserved
1448 MountDevice(name
,smbconn
,i
);
1452 bool smbInit(const char *user
, const char *password
, const char *share
, const char *ip
)
1454 return smbInitDevice("smb", user
, password
, share
, ip
);
1457 void smbClose(const char* name
)
1459 smb_env
*env
= FindSMBEnv(name
);
1460 if(env
==NULL
) return;
1462 _SMB_lock(env
->pos
);
1463 if(env
->SMBCONNECTED
)
1464 SMB_Close(env
->smbconn
);
1467 sprintf(device
, "%s:", env
->name
);
1468 RemoveDevice(device
);
1469 env
->SMBCONNECTED
=false;
1470 _SMB_unlock(env
->pos
);
1473 bool smbCheckConnection(const char* name
)
1480 for(i
=0; i
< 10 && name
[i
]!='\0' && name
[i
]!=':'; i
++) device
[i
]=name
[i
];
1483 env
=FindSMBEnv(device
);
1484 if(env
==NULL
) return false;
1485 _SMB_lock(env
->pos
);
1486 ret
=(SMB_Reconnect(&env
->smbconn
,true)==SMB_SUCCESS
);
1487 _SMB_unlock(env
->pos
);
1491 void smbSetSearchFlags(unsigned short flags
)