1 /****************************************************************************
3 * Nintendo Wii/GameCube SMB implementation
6 ****************************************************************************/
8 #include <sys/iosupport.h>
17 #include <ogc/lwp_watchdog.h>
18 #include <ogc/mutex.h>
22 #define MAX_SMB_MOUNTED 10
24 static lwp_t cache_thread
= LWP_THREAD_NULL
;
25 static SMBDIRENTRY last_dentry
;
26 static int last_env
=-1;
27 static char last_path
[SMB_MAXPATH
];
35 char filename
[SMB_MAXPATH
];
36 unsigned short access
;
45 char dir
[SMB_MAXPATH
];
48 static bool smbInited
= false;
49 static unsigned short smbFlags
= SMB_SRCH_DIRECTORY
| SMB_SRCH_READONLY
;
51 ///////////////////////////////////////////
52 // CACHE FUNCTION DEFINITIONS //
53 ///////////////////////////////////////////
54 #define SMB_READ_BUFFERSIZE 65472
55 #define SMB_WRITE_BUFFERSIZE (60*1024)
73 static void DestroySMBReadAheadCache(const char *name
);
74 static void SMBEnableReadAhead(const char *name
, u32 pages
);
75 static int ReadSMBFromCache(void *buf
, size_t len
, SMBFILESTRUCT
*file
);
77 ///////////////////////////////////////////
78 // END CACHE FUNCTION DEFINITIONS //
79 ///////////////////////////////////////////
91 char currentpath
[SMB_MAXPATH
];
95 smb_write_cache SMBWriteCache
;
96 smb_cache_page
*SMBReadAheadCache
;
102 static smb_env SMBEnv
[MAX_SMB_MOUNTED
];
104 static inline void _SMB_lock(int i
)
106 if(SMBEnv
[i
]._SMB_mutex
!=LWP_MUTEX_NULL
) LWP_MutexLock(SMBEnv
[i
]._SMB_mutex
);
109 static inline void _SMB_unlock(int i
)
111 if(SMBEnv
[i
]._SMB_mutex
!=LWP_MUTEX_NULL
) LWP_MutexUnlock(SMBEnv
[i
]._SMB_mutex
);
114 ///////////////////////////////////////////
115 // CACHE FUNCTIONS //
116 ///////////////////////////////////////////
118 static smb_env
* FindSMBEnv(const char *name
)
125 if(aux
[i
-1]==':')aux
[i
-1]='\0';
126 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
128 if(SMBEnv
[i
].SMBCONNECTED
&& strcmp(aux
,SMBEnv
[i
].name
)==0)
138 static int FlushWriteSMBCache(char *name
)
141 env
=FindSMBEnv(name
);
142 if(env
==NULL
) return -1;
144 if (env
->SMBWriteCache
.file
== NULL
|| env
->SMBWriteCache
.len
== 0)
152 while(env
->SMBWriteCache
.len
> 0)
154 ret
= SMB_WriteFile(env
->SMBWriteCache
.ptr
+written
, env
->SMBWriteCache
.len
,
155 env
->SMBWriteCache
.file
->offset
, env
->SMBWriteCache
.file
->handle
);
161 env
->SMBWriteCache
.file
->offset
+= ret
;
162 if (env
->SMBWriteCache
.file
->offset
> env
->SMBWriteCache
.file
->len
)
163 env
->SMBWriteCache
.file
->len
= env
->SMBWriteCache
.file
->offset
;
165 env
->SMBWriteCache
.len
-=ret
;
166 if(env
->SMBWriteCache
.len
==0) break;
168 env
->SMBWriteCache
.used
= 0;
169 env
->SMBWriteCache
.file
= NULL
;
174 static void DestroySMBReadAheadCache(const char *name
)
177 env
=FindSMBEnv(name
);
178 if(env
==NULL
) return ;
181 if (env
->SMBReadAheadCache
!= NULL
)
183 for (i
= 0; i
< env
->SMB_RA_pages
; i
++)
185 if(env
->SMBReadAheadCache
[i
].ptr
)
186 free(env
->SMBReadAheadCache
[i
].ptr
);
188 free(env
->SMBReadAheadCache
);
189 env
->SMBReadAheadCache
= NULL
;
190 env
->SMB_RA_pages
= 0;
192 FlushWriteSMBCache(env
->name
);
194 if(env
->SMBWriteCache
.ptr
)
195 free(env
->SMBWriteCache
.ptr
);
197 env
->SMBWriteCache
.used
= 0;
198 env
->SMBWriteCache
.len
= 0;
199 env
->SMBWriteCache
.file
= NULL
;
200 env
->SMBWriteCache
.ptr
= NULL
;
203 static void *process_cache_thread(void *ptr
)
208 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
210 if(SMBEnv
[i
].SMBCONNECTED
)
212 if (SMBEnv
[i
].SMBWriteCache
.used
> 0)
214 if (ticks_to_millisecs(gettime())-ticks_to_millisecs(SMBEnv
[i
].SMBWriteCache
.used
) > 500)
217 FlushWriteSMBCache(SMBEnv
[i
].name
);
228 static void SMBEnableReadAhead(const char *name
, u32 pages
)
233 env
=FindSMBEnv(name
);
234 if(env
==NULL
) return;
236 DestroySMBReadAheadCache(name
);
241 //only 1 page for write
242 env
->SMBWriteCache
.ptr
= memalign(32, SMB_WRITE_BUFFERSIZE
);
243 env
->SMBWriteCache
.used
= 0;
244 env
->SMBWriteCache
.len
= 0;
245 env
->SMBWriteCache
.file
= NULL
;
247 env
->SMB_RA_pages
= pages
;
248 env
->SMBReadAheadCache
= (smb_cache_page
*) malloc(sizeof(smb_cache_page
) * env
->SMB_RA_pages
);
249 if (env
->SMBReadAheadCache
== NULL
)
251 for (i
= 0; i
< env
->SMB_RA_pages
; i
++)
253 env
->SMBReadAheadCache
[i
].offset
= 0;
254 env
->SMBReadAheadCache
[i
].last_used
= 0;
255 env
->SMBReadAheadCache
[i
].file
= NULL
;
256 env
->SMBReadAheadCache
[i
].ptr
= memalign(32, SMB_READ_BUFFERSIZE
);
257 if (env
->SMBReadAheadCache
[i
].ptr
== NULL
)
259 for (j
= i
- 1; j
>= 0; j
--)
260 if (env
->SMBReadAheadCache
[j
].ptr
)
261 free(env
->SMBReadAheadCache
[j
].ptr
);
262 free(env
->SMBReadAheadCache
);
263 env
->SMBReadAheadCache
= NULL
;
264 free(env
->SMBWriteCache
.ptr
);
267 memset(env
->SMBReadAheadCache
[i
].ptr
, 0, SMB_READ_BUFFERSIZE
);
271 // clear cache from file
272 // called when file is closed
273 static void ClearSMBFileCache(SMBFILESTRUCT
*file
)
278 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
280 if (SMBEnv
[j
].SMBReadAheadCache
[i
].file
== file
)
282 SMBEnv
[j
].SMBReadAheadCache
[i
].offset
= 0;
283 SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
= 0;
284 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
285 memset(SMBEnv
[j
].SMBReadAheadCache
[i
].ptr
, 0, SMB_READ_BUFFERSIZE
);
290 static int ReadSMBFromCache(void *buf
, size_t len
, SMBFILESTRUCT
*file
)
293 off_t new_offset
, rest
;
296 if ( len
== 0 ) return 0;
298 if (SMBEnv
[j
].SMBReadAheadCache
== NULL
)
300 if (SMB_ReadFile(buf
, len
, file
->offset
, file
->handle
) <= 0)
307 new_offset
= file
->offset
;
312 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
314 if (SMBEnv
[j
].SMBReadAheadCache
[i
].file
== file
)
316 if ((new_offset
>= SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) &&
317 (new_offset
< (SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
)))
320 //copy as much as we can
321 SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
= gettime();
323 off_t buffer_used
= (SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
) - new_offset
;
324 if (buffer_used
> rest
) buffer_used
= rest
;
325 memcpy(buf
, SMBEnv
[j
].SMBReadAheadCache
[i
].ptr
+ (new_offset
- SMBEnv
[j
].SMBReadAheadCache
[i
].offset
), buffer_used
);
328 new_offset
+= buffer_used
;
340 for ( i
= 1; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
342 if ((SMBEnv
[j
].SMBReadAheadCache
[i
].last_used
< SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].last_used
))
346 //fill least used page with new data
348 off_t cache_offset
= new_offset
;
350 //do not interset with existing pages
351 for (i
= 0; i
< SMBEnv
[j
].SMB_RA_pages
; i
++)
353 if ( i
== leastUsed
) continue;
354 if ( SMBEnv
[j
].SMBReadAheadCache
[i
].file
!= file
) continue;
356 if ( (cache_offset
< SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) && (cache_offset
+ SMB_READ_BUFFERSIZE
> SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) )
358 //tail of new page intersects with some cache block, clear page
359 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
362 if ( (cache_offset
>= SMBEnv
[j
].SMBReadAheadCache
[i
].offset
) && (cache_offset
< SMBEnv
[j
].SMBReadAheadCache
[i
].offset
+ SMB_READ_BUFFERSIZE
) )
364 //head of new page intersects with some cache block, clear page
365 SMBEnv
[j
].SMBReadAheadCache
[i
].file
= NULL
;
369 off_t cache_to_read
= file
->len
- cache_offset
;
370 if ( cache_to_read
> SMB_READ_BUFFERSIZE
)
372 cache_to_read
= SMB_READ_BUFFERSIZE
;
376 while(read
<cache_to_read
)
378 readed
= SMB_ReadFile(SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].ptr
+read
, cache_to_read
-read
, cache_offset
+read
, file
->handle
);
381 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].file
= NULL
;
386 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].last_used
= gettime();
388 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].offset
= cache_offset
;
389 SMBEnv
[j
].SMBReadAheadCache
[leastUsed
].file
= file
;
394 static int WriteSMBUsingCache(const char *buf
, size_t len
, SMBFILESTRUCT
*file
)
397 if (file
== NULL
|| buf
== NULL
)
401 if (SMBEnv
[j
].SMBWriteCache
.file
!= NULL
)
403 if (strcmp(SMBEnv
[j
].SMBWriteCache
.file
->filename
, file
->filename
) != 0)
405 //Flush current buffer
406 if (FlushWriteSMBCache(SMBEnv
[j
].name
) < 0)
410 SMBEnv
[j
].SMBWriteCache
.file
= file
;
411 SMBEnv
[j
].SMBWriteCache
.len
= 0;
416 SMBEnv
[j
].SMBWriteCache
.file
= file
;
417 SMBEnv
[j
].SMBWriteCache
.len
= 0;
423 if(SMBEnv
[j
].SMBWriteCache
.len
+len
>= SMB_WRITE_BUFFERSIZE
)
425 rest
= SMB_WRITE_BUFFERSIZE
- SMBEnv
[j
].SMBWriteCache
.len
;
426 memcpy(SMBEnv
[j
].SMBWriteCache
.ptr
+ SMBEnv
[j
].SMBWriteCache
.len
, buf
, rest
);
428 written
= SMB_WriteFile(SMBEnv
[j
].SMBWriteCache
.ptr
, SMB_WRITE_BUFFERSIZE
, file
->offset
, file
->handle
);
433 file
->offset
+= written
;
434 if (file
->offset
> file
->len
)
435 file
->len
= file
->offset
;
439 SMBEnv
[j
].SMBWriteCache
.used
= gettime();
440 SMBEnv
[j
].SMBWriteCache
.len
= 0;
444 memcpy(SMBEnv
[j
].SMBWriteCache
.ptr
+ SMBEnv
[j
].SMBWriteCache
.len
, buf
, len
);
445 SMBEnv
[j
].SMBWriteCache
.len
+= len
;
446 SMBEnv
[j
].SMBWriteCache
.used
= gettime();
456 ///////////////////////////////////////////
457 // END CACHE FUNCTIONS //
458 ///////////////////////////////////////////
460 static char *smb_absolute_path_no_device(const char *srcpath
, char *destpath
, int env
)
462 char temp
[SMB_MAXPATH
];
465 if (strchr(srcpath
, ':') != NULL
)
467 srcpath
= strchr(srcpath
, ':') + 1;
469 if (strchr(srcpath
, ':') != NULL
)
474 memset(temp
,0,SMB_MAXPATH
);
476 if (srcpath
[0] != '\\' && srcpath
[0] != '/')
478 strcpy(temp
, SMBEnv
[env
].currentpath
);
480 if(srcpath
[0]!='\0') //strlen(srcpath) > 0
482 if(srcpath
[0]=='.' && (srcpath
[1]=='\\' || srcpath
[1]=='\0')) // to fix opendir(".") or chdir(".")
483 strcat(temp
, &srcpath
[1]);
485 strcat(temp
, srcpath
);
488 while(temp
[i
]!='\0' && i
< SMB_MAXPATH
)
493 while(temp
[i
]!='\0' && i
< SMB_MAXPATH
&& (temp
[i
]=='/' || temp
[i
]=='\\'))i
++;
495 else if(srcpath
[i
]=='\\')
497 destpath
[j
++]=temp
[i
++];
498 while(temp
[i
]!='\0' && i
< SMB_MAXPATH
&& (temp
[i
]=='/' || temp
[i
]=='\\'))i
++;
502 destpath
[j
++]=temp
[i
++];
510 static char *ExtractDevice(const char *path
, char *device
)
515 for(i
=0;i
<l
&& path
[i
]!='\0' && path
[i
]!=':' && i
< 20;i
++)
517 if(path
[i
]!=':')device
[0]='\0';
523 static int __smb_open(struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
)
525 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fileStruct
;
526 char fixedpath
[SMB_MAXPATH
];
529 ExtractDevice(path
,fixedpath
);
530 if(fixedpath
[0]=='\0')
532 getcwd(fixedpath
,SMB_MAXPATH
);
533 ExtractDevice(fixedpath
,fixedpath
);
535 env
=FindSMBEnv(fixedpath
);
543 if (!env
->SMBCONNECTED
)
549 if (smb_absolute_path_no_device(path
, fixedpath
, file
->env
) == NULL
)
555 if(!smbCheckConnection(env
->name
))
562 bool fileExists
= true;
564 if (SMB_PathInfo(fixedpath
, &dentry
, env
->smbconn
) != SMB_SUCCESS
)
568 // Determine which mode the file is open for
570 unsigned short access
;
571 if ((flags
& 0x03) == O_RDONLY
)
573 // Open the file for read-only access
574 smb_mode
= SMB_OF_OPEN
;
575 access
= SMB_OPEN_READING
;
577 else if ((flags
& 0x03) == O_WRONLY
)
579 // Open file for write only access
581 smb_mode
= SMB_OF_OPEN
;
583 smb_mode
= SMB_OF_CREATE
;
584 access
= SMB_OPEN_WRITING
;
586 else if ((flags
& 0x03) == O_RDWR
)
588 // Open file for read/write access
589 access
= SMB_OPEN_READWRITE
;
591 smb_mode
= SMB_OF_OPEN
;
593 smb_mode
= SMB_OF_CREATE
;
598 _SMB_unlock(env
->pos
);
602 if ((flags
& O_CREAT
) && !fileExists
)
603 smb_mode
= SMB_OF_CREATE
;
604 if (!(flags
& O_APPEND
) && fileExists
&& ((flags
& 0x03) != O_RDONLY
))
605 smb_mode
= SMB_OF_TRUNCATE
;
606 file
->handle
= SMB_OpenFile(fixedpath
, access
, smb_mode
, env
->smbconn
);
610 _SMB_unlock(env
->pos
);
615 file
->attributes
= 0;
618 file
->len
= dentry
.size
;
619 file
->attributes
= dentry
.attributes
;
622 if (flags
& O_APPEND
)
623 file
->offset
= file
->len
;
629 strcpy(file
->filename
, fixedpath
);
630 _SMB_unlock(env
->pos
);
634 static off_t
__smb_seek(struct _reent
*r
, int fd
, off_t pos
, int dir
)
636 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
645 //have to flush because SMBWriteCache.file->offset holds offset of cached block not yet written
646 _SMB_lock(file
->env
);
647 if (SMBEnv
[file
->env
].SMBWriteCache
.file
== file
)
649 FlushWriteSMBCache(SMBEnv
[file
->env
].name
);
658 position
= file
->offset
+ pos
;
661 position
= file
->len
+ pos
;
665 _SMB_unlock(file
->env
);
669 if (pos
> 0 && position
< 0)
671 r
->_errno
= EOVERFLOW
;
672 _SMB_unlock(file
->env
);
678 _SMB_unlock(file
->env
);
683 file
->offset
= position
;
684 _SMB_unlock(file
->env
);
688 static ssize_t
__smb_read(struct _reent
*r
, int fd
, char *ptr
, size_t len
)
694 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
706 //have to flush because SMBWriteCache.file->offset holds offset of cached block not yet writeln
707 //and file->len also may not have been updated yet
708 _SMB_lock(file
->env
);
709 if (SMBEnv
[file
->env
].SMBWriteCache
.file
== file
)
711 FlushWriteSMBCache(SMBEnv
[file
->env
].name
);
714 // Don't try to read if the read pointer is past the end of file
715 if (file
->offset
>= file
->len
)
717 r
->_errno
= EOVERFLOW
;
718 _SMB_unlock(file
->env
);
722 // Don't read past end of file
723 if (len
+ file
->offset
> file
->len
)
725 r
->_errno
= EOVERFLOW
;
726 len
= file
->len
- file
->offset
;
729 // Short circuit cases where len is 0 (or less)
732 _SMB_unlock(file
->env
);
738 readsize
= len
- offset
;
739 if(readsize
> SMB_READ_BUFFERSIZE
) readsize
= SMB_READ_BUFFERSIZE
;
740 ret
= ReadSMBFromCache(ptr
+offset
, readsize
, file
);
743 file
->offset
+= readsize
;
752 if(smbCheckConnection(SMBEnv
[file
->env
].name
))
754 ClearSMBFileCache(file
);
755 file
->handle
= SMB_OpenFile(file
->filename
, file
->access
, SMB_OF_OPEN
, SMBEnv
[file
->env
].smbconn
);
759 _SMB_unlock(file
->env
);
765 goto retry_reconnect
;
768 _SMB_unlock(file
->env
);
771 _SMB_unlock(file
->env
);
775 static ssize_t
__smb_write(struct _reent
*r
, int fd
, const char *ptr
, size_t len
)
777 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
785 // Don't try to write if the pointer is past the end of file
786 if (file
->offset
> file
->len
)
788 r
->_errno
= EOVERFLOW
;
792 // Short circuit cases where len is 0 (or less)
796 _SMB_lock(file
->env
);
797 written
= WriteSMBUsingCache(ptr
, len
, file
);
798 _SMB_unlock(file
->env
);
809 static int __smb_close(struct _reent
*r
, int fd
)
811 SMBFILESTRUCT
*file
= (SMBFILESTRUCT
*) fd
;
815 if (SMBEnv
[j
].SMBWriteCache
.file
== file
)
817 FlushWriteSMBCache(SMBEnv
[j
].name
);
819 ClearSMBFileCache(file
);
820 SMB_CloseFile(file
->handle
);
823 file
->filename
[0] = '\0';
829 static int __smb_chdir(struct _reent
*r
, const char *path
)
831 char path_absolute
[SMB_MAXPATH
];
836 ExtractDevice(path
,path_absolute
);
837 if(path_absolute
[0]=='\0')
839 getcwd(path_absolute
,SMB_MAXPATH
);
840 ExtractDevice(path_absolute
,path_absolute
);
844 env
=FindSMBEnv(path_absolute
);
852 if (!env
->SMBCONNECTED
)
858 if (smb_absolute_path_no_device(path
, path_absolute
,env
->pos
) == NULL
)
864 if(!smbCheckConnection(env
->name
))
870 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
873 found
= SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
);
875 if (found
!= SMB_SUCCESS
)
878 _SMB_unlock(env
->pos
);
882 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
885 _SMB_unlock(env
->pos
);
889 strcpy(env
->currentpath
, path_absolute
);
890 if (env
->currentpath
[0] != 0)
892 if (env
->currentpath
[strlen(env
->currentpath
) - 1] != '\\')
893 strcat(env
->currentpath
, "\\");
895 _SMB_unlock(env
->pos
);
899 static int __smb_dirreset(struct _reent
*r
, DIR_ITER
*dirState
)
901 char path_abs
[SMB_MAXPATH
];
902 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
905 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
907 _SMB_lock(state
->env
);
908 SMB_FindClose(&state
->smbdir
, SMBEnv
[state
->env
].smbconn
);
910 strcpy(path_abs
,SMBEnv
[state
->env
].currentpath
);
911 strcat(path_abs
,"*");
912 int found
= SMB_FindFirst(path_abs
, smbFlags
, &dentry
, SMBEnv
[state
->env
].smbconn
);
914 if (found
!= SMB_SUCCESS
)
917 _SMB_unlock(state
->env
);
921 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
924 _SMB_unlock(state
->env
);
928 state
->smbdir
.size
= dentry
.size
;
929 state
->smbdir
.ctime
= dentry
.ctime
;
930 state
->smbdir
.atime
= dentry
.atime
;
931 state
->smbdir
.mtime
= dentry
.mtime
;
932 state
->smbdir
.attributes
= dentry
.attributes
;
933 state
->smbdir
.sid
= dentry
.sid
;
934 strcpy(state
->smbdir
.name
, dentry
.name
);
936 SMBEnv
[state
->env
].first_item_dir
= true;
937 _SMB_unlock(state
->env
);
941 static DIR_ITER
* __smb_diropen(struct _reent
*r
, DIR_ITER
*dirState
, const char *path
)
943 char path_absolute
[SMB_MAXPATH
];
945 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
948 ExtractDevice(path
,path_absolute
);
949 if(path_absolute
[0]=='\0')
951 getcwd(path_absolute
,SMB_MAXPATH
);
952 ExtractDevice(path_absolute
,path_absolute
);
956 env
=FindSMBEnv(path_absolute
);
964 if (smb_absolute_path_no_device(path
, path_absolute
, env
->pos
) == NULL
)
969 if (strlen(path_absolute
) > 0 && path_absolute
[strlen(path_absolute
) - 1] != '\\')
970 strcat(path_absolute
, "\\");
972 if(!strcmp(path_absolute
,"\\"))
973 env
->diropen_root
=true;
975 env
->diropen_root
=false;
977 if(!smbCheckConnection(env
->name
))
984 if(!env
->diropen_root
) // root must be valid - we don't need check it
986 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
987 found
= SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
);
988 if (found
!= SMB_SUCCESS
)
991 _SMB_unlock(env
->pos
);
995 if (!(dentry
.attributes
& SMB_SRCH_DIRECTORY
))
998 _SMB_unlock(env
->pos
);
1003 strcpy(state
->dir
,path_absolute
);
1005 strcat(path_absolute
, "*");
1006 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
1007 found
= SMB_FindFirst(path_absolute
, smbFlags
, &dentry
, env
->smbconn
);
1009 if (found
!= SMB_SUCCESS
)
1012 _SMB_unlock(env
->pos
);
1016 state
->env
=env
->pos
;
1017 state
->smbdir
.size
= dentry
.size
;
1018 state
->smbdir
.ctime
= dentry
.ctime
;
1019 state
->smbdir
.atime
= dentry
.atime
;
1020 state
->smbdir
.mtime
= dentry
.mtime
;
1021 state
->smbdir
.attributes
= dentry
.attributes
;
1022 state
->smbdir
.sid
= dentry
.sid
;
1023 strcpy(state
->smbdir
.name
, dentry
.name
);
1024 env
->first_item_dir
= true;
1025 _SMB_unlock(env
->pos
);
1029 static int dentry_to_stat(SMBDIRENTRY
*dentry
, struct stat
*st
)
1039 st
->st_mode
= ((dentry
->attributes
& SMB_SRCH_DIRECTORY
) ? S_IFDIR
: S_IFREG
);
1041 st
->st_uid
= 1; // Faked
1042 st
->st_rdev
= st
->st_dev
;
1043 st
->st_gid
= 2; // Faked
1044 st
->st_size
= dentry
->size
;
1045 st
->st_atime
= dentry
->atime
/10000000.0 - 11644473600LL;
1047 st
->st_mtime
= dentry
->mtime
/10000000.0 - 11644473600LL;
1049 st
->st_ctime
= dentry
->ctime
/10000000.0 - 11644473600LL;
1051 st
->st_blksize
= 1024;
1052 st
->st_blocks
= (st
->st_size
+ st
->st_blksize
- 1) / st
->st_blksize
; // File size in blocks
1053 st
->st_spare4
[0] = 0;
1054 st
->st_spare4
[1] = 0;
1059 static int cpy_dentry(SMBDIRENTRY
*dest
, SMBDIRENTRY
*source
)
1061 if (!dest
|| !source
)
1064 dest
->attributes
=source
->attributes
;
1065 dest
->size
=source
->size
;
1066 dest
->atime
=source
->atime
;
1067 dest
->mtime
=source
->mtime
;
1068 dest
->ctime
=source
->ctime
;
1069 strcpy(dest
->name
,source
->name
);
1074 static int __smb_dirnext(struct _reent
*r
, DIR_ITER
*dirState
, char *filename
,
1075 struct stat
*filestat
)
1078 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
1081 if (SMBEnv
[state
->env
].currentpath
[0] == '\0' || filestat
== NULL
)
1087 memset(&dentry
, 0, sizeof(SMBDIRENTRY
));
1088 _SMB_lock(state
->env
);
1089 if (SMBEnv
[state
->env
].first_item_dir
)
1091 SMBEnv
[state
->env
].first_item_dir
= false;
1092 dentry
.size
= state
->smbdir
.size
;
1093 dentry
.ctime
= state
->smbdir
.ctime
;
1094 dentry
.atime
= state
->smbdir
.atime
;
1095 dentry
.mtime
= state
->smbdir
.mtime
;
1096 dentry
.attributes
= state
->smbdir
.attributes
;
1097 strcpy(dentry
.name
, state
->smbdir
.name
);
1098 strcpy(filename
, dentry
.name
);
1099 dentry_to_stat(&dentry
, filestat
);
1100 cpy_dentry(&last_dentry
,&dentry
);
1101 last_env
=state
->env
;
1102 strcpy(last_path
,state
->dir
);
1103 _SMB_unlock(state
->env
);
1107 dentry
.sid
= state
->smbdir
.sid
;
1109 ret
= SMB_FindNext(&dentry
, SMBEnv
[state
->env
].smbconn
);
1110 if(ret
==SMB_SUCCESS
&& SMBEnv
[state
->env
].diropen_root
)
1112 if(strlen(dentry
.name
) == 2 && strcmp(dentry
.name
,"..") == 0)
1113 ret
= SMB_FindNext(&dentry
, SMBEnv
[state
->env
].smbconn
);
1115 if (ret
== SMB_SUCCESS
)
1117 state
->smbdir
.size
= dentry
.size
;
1118 state
->smbdir
.ctime
= dentry
.ctime
;
1119 state
->smbdir
.atime
= dentry
.atime
;
1120 state
->smbdir
.mtime
= dentry
.mtime
;
1121 state
->smbdir
.attributes
= dentry
.attributes
;
1122 strcpy(state
->smbdir
.name
, dentry
.name
);
1123 strcpy(filename
, dentry
.name
);
1128 _SMB_unlock(state
->env
);
1132 dentry_to_stat(&dentry
, filestat
);
1133 cpy_dentry(&last_dentry
,&dentry
);
1134 last_env
=state
->env
;
1135 strcpy(last_path
,state
->dir
);
1136 _SMB_unlock(state
->env
);
1140 static int __smb_dirclose(struct _reent
*r
, DIR_ITER
*dirState
)
1142 SMBDIRSTATESTRUCT
* state
= (SMBDIRSTATESTRUCT
*) (dirState
->dirStruct
);
1146 SMB_FindClose(&state
->smbdir
, SMBEnv
[j
].smbconn
);
1147 memset(state
, 0, sizeof(SMBDIRSTATESTRUCT
));
1152 static int __smb_stat(struct _reent
*r
, const char *path
, struct stat
*st
)
1154 char path_absolute
[SMB_MAXPATH
];
1163 if(strcmp(path
,".")==0 || strcmp(path
,"..")==0)
1165 memset(st
,0,sizeof(struct stat
));
1166 st
->st_mode
= S_IFDIR
;
1170 ExtractDevice(path
,path_absolute
);
1171 if(path_absolute
[0]=='\0')
1173 getcwd(path_absolute
,SMB_MAXPATH
);
1174 ExtractDevice(path_absolute
,path_absolute
);
1178 env
=FindSMBEnv(path_absolute
);
1186 if (smb_absolute_path_no_device(path
, path_absolute
, env
->pos
) == NULL
)
1192 if(env
->pos
==last_env
) //optimization, usually after a dirnext we do stat
1194 char file
[SMB_MAXPATH
];
1195 strcpy(file
,last_path
);
1196 strcat(file
,last_dentry
.name
);
1197 if(strcmp(file
,path_absolute
)==0)
1199 dentry_to_stat(&last_dentry
, st
);
1204 _SMB_lock(env
->pos
);
1205 if (SMB_PathInfo(path_absolute
, &dentry
, env
->smbconn
) != SMB_SUCCESS
)
1208 _SMB_unlock(env
->pos
);
1212 if (dentry
.name
[0] == '\0')
1216 _SMB_unlock(env
->pos
);
1220 dentry_to_stat(&dentry
, st
);
1221 _SMB_unlock(env
->pos
);
1226 static int __smb_fstat(struct _reent
*r
, int fd
, struct stat
*st
)
1228 SMBFILESTRUCT
*filestate
= (SMBFILESTRUCT
*) fd
;
1236 st
->st_size
= filestate
->len
;
1237 st
->st_mode
= ((filestate
->attributes
& SMB_SRCH_DIRECTORY
) ? S_IFDIR
: S_IFREG
);
1242 static int __smb_mkdir(struct _reent
*r
, const char *name
, int mode
)
1244 char fixedName
[SMB_MAXPATH
];
1247 ExtractDevice(name
,fixedName
);
1248 if(fixedName
[0]=='\0')
1250 getcwd(fixedName
,SMB_MAXPATH
);
1251 ExtractDevice(fixedName
,fixedName
);
1254 env
=FindSMBEnv(fixedName
);
1261 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1268 _SMB_lock(env
->pos
);
1269 if(SMB_CreateDirectory(fixedName
, env
->smbconn
) != SMB_SUCCESS
)
1271 _SMB_unlock(env
->pos
);
1276 static int __smb_unlink(struct _reent
*r
, const char *name
)
1278 char fixedName
[SMB_MAXPATH
];
1283 dir
= opendir(name
);
1290 ExtractDevice(name
,fixedName
);
1291 if(fixedName
[0]=='\0')
1293 getcwd(fixedName
,SMB_MAXPATH
);
1294 ExtractDevice(fixedName
,fixedName
);
1297 env
=FindSMBEnv(fixedName
);
1304 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1311 _SMB_lock(env
->pos
);
1313 ret
= SMB_DeleteDirectory(fixedName
, env
->smbconn
);
1315 ret
= SMB_DeleteFile(fixedName
, env
->smbconn
);
1316 _SMB_unlock(env
->pos
);
1318 if(ret
!= SMB_SUCCESS
)
1324 static int __smb_rename(struct _reent
*r
, const char *oldName
, const char *newName
)
1326 char fixedOldName
[SMB_MAXPATH
];
1327 char fixedNewName
[SMB_MAXPATH
];
1330 ExtractDevice(oldName
,fixedOldName
);
1331 if(fixedOldName
[0]=='\0')
1333 getcwd(fixedOldName
,SMB_MAXPATH
);
1334 ExtractDevice(fixedOldName
,fixedOldName
);
1337 env
=FindSMBEnv(fixedOldName
);
1344 if (smb_absolute_path_no_device(oldName
, fixedOldName
, env
->pos
) == NULL
)
1350 ExtractDevice(newName
,fixedNewName
);
1351 if(fixedNewName
[0]=='\0')
1353 getcwd(fixedNewName
,SMB_MAXPATH
);
1354 ExtractDevice(fixedNewName
,fixedNewName
);
1357 if (smb_absolute_path_no_device(newName
, fixedNewName
, env
->pos
) == NULL
)
1364 _SMB_lock(env
->pos
);
1365 if (SMB_Rename(fixedOldName
, fixedNewName
, env
->smbconn
) != SMB_SUCCESS
)
1367 _SMB_unlock(env
->pos
);
1372 static int __smb_statvfs_r(struct _reent
*r
, const char *name
, struct statvfs
*buf
)
1374 char fixedName
[SMB_MAXPATH
];
1377 ExtractDevice(name
,fixedName
);
1378 if(fixedName
[0]=='\0')
1380 getcwd(fixedName
,SMB_MAXPATH
);
1381 ExtractDevice(fixedName
,fixedName
);
1384 env
=FindSMBEnv(fixedName
);
1391 if (smb_absolute_path_no_device(name
, fixedName
, env
->pos
) == NULL
)
1398 _SMB_lock(env
->pos
);
1399 if(SMB_DiskInformation(buf
, env
->smbconn
) != SMB_SUCCESS
)
1401 _SMB_unlock(env
->pos
);
1406 static void MountDevice(const char *name
,SMBCONN smbconn
, int env
)
1408 devoptab_t
*dotab_smb
;
1414 if(aux
[l
-1]==':')aux
[l
-1]='\0';
1416 dotab_smb
=(devoptab_t
*)malloc(sizeof(devoptab_t
));
1418 dotab_smb
->name
=strdup(aux
);
1419 dotab_smb
->structSize
=sizeof(SMBFILESTRUCT
); // size of file structure
1420 dotab_smb
->open_r
=__smb_open
; // device open
1421 dotab_smb
->close_r
=__smb_close
; // device close
1422 dotab_smb
->write_r
=__smb_write
; // device write
1423 dotab_smb
->read_r
=__smb_read
; // device read
1424 dotab_smb
->seek_r
=__smb_seek
; // device seek
1425 dotab_smb
->fstat_r
=__smb_fstat
; // device fstat
1426 dotab_smb
->stat_r
=__smb_stat
; // device stat
1427 dotab_smb
->link_r
=NULL
; // device link
1428 dotab_smb
->unlink_r
=__smb_unlink
; // device unlink
1429 dotab_smb
->chdir_r
=__smb_chdir
; // device chdir
1430 dotab_smb
->rename_r
=__smb_rename
; // device rename
1431 dotab_smb
->mkdir_r
=__smb_mkdir
; // device mkdir
1433 dotab_smb
->dirStateSize
=sizeof(SMBDIRSTATESTRUCT
); // dirStateSize
1434 dotab_smb
->diropen_r
=__smb_diropen
; // device diropen_r
1435 dotab_smb
->dirreset_r
=__smb_dirreset
; // device dirreset_r
1436 dotab_smb
->dirnext_r
=__smb_dirnext
; // device dirnext_r
1437 dotab_smb
->dirclose_r
=__smb_dirclose
; // device dirclose_r
1438 dotab_smb
->statvfs_r
=__smb_statvfs_r
; // device statvfs_r
1439 dotab_smb
->ftruncate_r
=NULL
; // device ftruncate_r
1440 dotab_smb
->fsync_r
=NULL
; // device fsync_r
1441 dotab_smb
->deviceData
=NULL
; /* Device data */
1443 AddDevice(dotab_smb
);
1445 SMBEnv
[env
].pos
=env
;
1446 SMBEnv
[env
].smbconn
=smbconn
;
1447 SMBEnv
[env
].first_item_dir
=false;
1448 SMBEnv
[env
].diropen_root
=false;
1449 SMBEnv
[env
].devoptab
=dotab_smb
;
1450 SMBEnv
[env
].SMBCONNECTED
=true;
1451 SMBEnv
[env
].name
=strdup(aux
);
1453 SMBEnableReadAhead(aux
,8);
1458 bool smbInitDevice(const char* name
, const char *user
, const char *password
, const char *share
, const char *ip
)
1462 if(!name
|| strlen(name
) > 9)
1466 sprintf(devname
, "%s:", name
);
1467 if(FindDevice(devname
) >= 0)
1472 for(i
=0;i
<MAX_SMB_MOUNTED
;i
++)
1474 SMBEnv
[i
].SMBCONNECTED
=false;
1475 SMBEnv
[i
].currentpath
[0]='\\';
1476 SMBEnv
[i
].currentpath
[1]='\0';
1477 SMBEnv
[i
].first_item_dir
=false;
1479 SMBEnv
[i
].SMBReadAheadCache
=NULL
;
1480 LWP_MutexInit(&SMBEnv
[i
]._SMB_mutex
, false);
1483 if(cache_thread
== LWP_THREAD_NULL
)
1484 if(LWP_CreateThread(&cache_thread
, process_cache_thread
, NULL
, NULL
, 0, 64) != 0)
1493 if(SMB_Connect(&smbconn
, user
, password
, share
, ip
) != SMB_SUCCESS
)
1496 for(i
=0;i
<MAX_SMB_MOUNTED
&& SMBEnv
[i
].SMBCONNECTED
;i
++);
1498 if(i
==MAX_SMB_MOUNTED
)
1501 return false; // all samba connections in use
1504 SMBEnv
[i
].SMBCONNECTED
=true; // reserved
1505 MountDevice(name
,smbconn
,i
);
1509 bool smbInit(const char *user
, const char *password
, const char *share
, const char *ip
)
1511 return smbInitDevice("smb", user
, password
, share
, ip
);
1514 void smbClose(const char* name
)
1516 smb_env
*env
= FindSMBEnv(name
);
1517 if(env
==NULL
) return;
1519 _SMB_lock(env
->pos
);
1520 if(env
->SMBCONNECTED
)
1521 SMB_Close(env
->smbconn
);
1524 sprintf(device
, "%s:", env
->name
);
1525 RemoveDevice(device
);
1526 env
->SMBCONNECTED
=false;
1527 _SMB_unlock(env
->pos
);
1530 bool smbCheckConnection(const char* name
)
1537 for(i
=0; i
< 10 && name
[i
]!='\0' && name
[i
]!=':'; i
++) device
[i
]=name
[i
];
1540 env
=FindSMBEnv(device
);
1541 if(env
==NULL
) return false;
1542 _SMB_lock(env
->pos
);
1543 ret
=(SMB_Reconnect(&env
->smbconn
,true)==SMB_SUCCESS
);
1544 _SMB_unlock(env
->pos
);
1548 void smbSetSearchFlags(unsigned short flags
)