SMB write cache improvements. patch by dimok.
[libogc.git] / libtinysmb / smb.c
blobf8165807a1e0d5f62ed65a019de2d767e7c508a4
1 /****************************************************************************
2 * TinySMB
3 * Nintendo Wii/GameCube SMB implementation
5 * Copyright softdev
6 * Modified by Tantric to utilize NTLM authentication
7 * PathInfo added by rodries
8 * SMB devoptab by scip, rodries
10 * You will find WireShark (http://www.wireshark.org/)
11 * invaluable for debugging SAMBA implementations.
13 * Recommended Reading
14 * Implementing CIFS - Christopher R Hertel
15 * http://www.ubiqx.org/cifs/SMB.html
17 * License:
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2.1 of the License, or (at your option) any later version.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 ****************************************************************************/
34 #include <asm.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <malloc.h>
40 #include <ctype.h>
41 #include <wchar.h>
42 #include <gccore.h>
43 #include <network.h>
44 #include <processor.h>
45 #include <lwp_threads.h>
46 #include <lwp_objmgr.h>
47 #include <ogc/lwp_watchdog.h>
48 #include <sys/statvfs.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <smb.h>
53 #define IOS_O_NONBLOCK 0x04
54 #define RECV_TIMEOUT 3000 // in ms
55 #define CONN_TIMEOUT 6000
57 /**
58 * Field offsets.
60 #define SMB_OFFSET_PROTO 0
61 #define SMB_OFFSET_CMD 4
62 #define SMB_OFFSET_NTSTATUS 5
63 #define SMB_OFFSET_ECLASS 5
64 #define SMB_OFFSET_ECODE 7
65 #define SMB_OFFSET_FLAGS 9
66 #define SMB_OFFSET_FLAGS2 10
67 #define SMB_OFFSET_EXTRA 12
68 #define SMB_OFFSET_TID 24
69 #define SMB_OFFSET_PID 26
70 #define SMB_OFFSET_UID 28
71 #define SMB_OFFSET_MID 30
72 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
74 /**
75 * Message / Commands
77 #define NBT_SESSISON_MSG 0x00
79 #define SMB_NEG_PROTOCOL 0x72
80 #define SMB_SETUP_ANDX 0x73
81 #define SMB_TREEC_ANDX 0x75
84 #define NBT_KEEPALIVE_MSG 0x85
85 #define KEEPALIVE_SIZE 4
87 /**
88 * SMBTrans2
90 #define SMB_TRANS2 0x32
92 #define SMB_OPEN2 0
93 #define SMB_FIND_FIRST2 1
94 #define SMB_FIND_NEXT2 2
95 #define SMB_QUERY_FS_INFO 3
96 #define SMB_QUERY_PATH_INFO 5
97 #define SMB_SET_PATH_INFO 6
98 #define SMB_QUERY_FILE_INFO 7
99 #define SMB_SET_FILE_INFO 8
100 #define SMB_CREATE_DIR 13
101 #define SMB_FIND_CLOSE2 0x34
102 #define SMB_QUERY_FILE_ALL_INFO 0x107
105 * File I/O
107 #define SMB_OPEN_ANDX 0x2d
108 #define SMB_WRITE_ANDX 0x2f
109 #define SMB_READ_ANDX 0x2e
110 #define SMB_CLOSE 0x04
113 * SMB_COM
115 #define SMB_COM_CREATE_DIRECTORY 0x00
116 #define SMB_COM_DELETE_DIRECTORY 0x01
117 #define SMB_COM_DELETE 0x06
118 #define SMB_COM_RENAME 0x07
119 #define SMB_COM_QUERY_INFORMATION_DISK 0x80
122 * TRANS2 Offsets
124 #define T2_WORD_CNT (SMB_HEADER_SIZE)
125 #define T2_PRM_CNT (T2_WORD_CNT+1)
126 #define T2_DATA_CNT (T2_PRM_CNT+2)
127 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
128 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
129 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
130 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
131 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
132 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
133 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
134 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
135 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
136 #define T2_BYTE_CNT (T2_SUB_CMD+2)
139 #define SMB_PROTO 0x424d53ff
140 #define SMB_HANDLE_NULL 0xffffffff
141 #define SMB_MAX_NET_READ_SIZE (16*1024) // see smb_recv
142 #define SMB_MAX_NET_WRITE_SIZE 4096 // see smb_sendv
143 #define SMB_MAX_TRANSMIT_SIZE 65472
145 #define CAP_LARGE_FILES 0x00000008 // 64-bit file sizes and offsets supported
146 #define CAP_UNICODE 0x00000004 // Unicode supported
147 #define CIFS_FLAGS1 0x08 // Paths are caseless
148 #define CIFS_FLAGS2_UNICODE 0x8001 // Server may return long components in paths in the response - use 0x8001 for Unicode support
149 #define CIFS_FLAGS2 0x0001 // Server may return long components in paths in the response - use 0x0001 for ASCII support
151 #define SMB_CONNHANDLES_MAX 8
152 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
154 #define SMB_OBJTYPE_HANDLE 7
155 #define SMB_CHECK_HANDLE(hndl) \
157 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
158 return NULL; \
161 /* NBT Session Service Packet Type Codes
164 #define SESS_MSG 0x00
165 #define SESS_REQ 0x81
166 #define SESS_POS_RESP 0x82
167 #define SESS_NEG_RESP 0x83
168 #define SESS_RETARGET 0x84
169 #define SESS_KEEPALIVE 0x85
171 struct _smbfile
173 lwp_node node;
174 u16 sfid;
175 SMBCONN conn;
179 * NBT/SMB Wrapper
181 typedef struct _nbtsmb
183 u8 msg; /*** NBT Message ***/
184 u8 length_high;
185 u16 length; /*** Length, excluding NBT ***/
186 u8 smb[SMB_MAX_TRANSMIT_SIZE+128];
187 } NBTSMB;
190 * Session Information
192 typedef struct _smbsession
194 u16 TID;
195 u16 PID;
196 u16 UID;
197 u16 MID;
198 u32 sKey;
199 u32 capabilities;
200 u32 MaxBuffer;
201 u16 MaxMpx;
202 u16 MaxVCS;
203 u8 challenge[10];
204 u8 p_domain[64];
205 s64 timeOffset;
206 u16 count;
207 u16 eos;
208 bool challengeUsed;
209 u8 securityLevel;
210 } SMBSESSION;
212 typedef struct _smbhandle
214 lwp_obj object;
215 char *user;
216 char *pwd;
217 char *share_name;
218 char *server_name;
219 s32 sck_server;
220 struct sockaddr_in server_addr;
221 bool conn_valid;
222 SMBSESSION session;
223 NBTSMB message;
224 bool unicode;
225 } SMBHANDLE;
227 static u32 smb_dialectcnt = 1;
228 static bool smb_inited = false;
229 static lwp_objinfo smb_handle_objects;
230 static lwp_queue smb_filehandle_queue;
231 static struct _smbfile smb_filehandles[SMB_FILEHANDLES_MAX];
232 static const char *smb_dialects[] = {"NT LM 0.12",NULL};
234 extern void ntlm_smb_nt_encrypt(const char *passwd, const u8 * challenge, u8 * answer);
236 // UTF conversion functions
237 size_t utf16_to_utf8(char* dst, char* src, size_t len)
239 mbstate_t ps;
240 size_t count = 0;
241 int bytes;
242 char buff[MB_CUR_MAX];
243 int i;
244 unsigned short c;
245 memset(&ps, 0, sizeof(mbstate_t));
247 while (count < len && *src != '\0')
249 c = *(src + 1) << 8 | *src; // little endian
250 if (c == 0)
251 break;
252 bytes = wcrtomb(buff, c, &ps);
253 if (bytes < 0)
255 *dst = '\0';
256 return -1;
258 if (bytes > 0)
260 for (i = 0; i < bytes; i++)
262 *dst++ = buff[i];
264 src += 2;
265 count += 2;
267 else
269 break;
272 *dst = '\0';
273 return count;
276 size_t utf8_to_utf16(char* dst, char* src, size_t len)
278 mbstate_t ps;
279 wchar_t tempWChar;
280 char *tempChar;
281 int bytes;
282 size_t count = 0;
283 tempChar = (char*) &tempWChar;
284 memset(&ps, 0, sizeof(mbstate_t));
286 while (count < len - 1 && src != '\0')
288 bytes = mbrtowc(&tempWChar, src, MB_CUR_MAX, &ps);
289 if (bytes > 0)
291 *dst = tempChar[3];
292 dst++;
293 *dst = tempChar[2];
294 dst++;
295 src += bytes;
296 count += 2;
298 else if (bytes == 0)
300 break;
302 else
304 *dst = '\0';
305 dst++;
306 *dst = '\0';
307 return -1;
310 *dst = '\0';
311 dst++;
312 *dst = '\0';
313 return count;
317 * SMB Endian aware supporting functions
319 * SMB always uses Intel Little-Endian values, so htons etc are
320 * of little or no use :) ... Thanks M$
323 /*** get unsigned char ***/
324 static __inline__ u8 getUChar(u8 *buffer,u32 offset)
326 return (u8)buffer[offset];
329 /*** set unsigned char ***/
330 static __inline__ void setUChar(u8 *buffer,u32 offset,u8 value)
332 buffer[offset] = value;
335 /*** get signed short ***/
336 static __inline__ s16 getShort(u8 *buffer,u32 offset)
338 return (s16)((buffer[offset+1]<<8)|(buffer[offset]));
341 /*** get unsigned short ***/
342 static __inline__ u16 getUShort(u8 *buffer,u32 offset)
344 return (u16)((buffer[offset+1]<<8)|(buffer[offset]));
347 /*** set unsigned short ***/
348 static __inline__ void setUShort(u8 *buffer,u32 offset,u16 value)
350 buffer[offset] = (value&0xff);
351 buffer[offset+1] = ((value&0xff00)>>8);
354 /*** get unsigned int ***/
355 static __inline__ u32 getUInt(u8 *buffer,u32 offset)
357 return (u32)((buffer[offset+3]<<24)|(buffer[offset+2]<<16)|(buffer[offset+1]<<8)|buffer[offset]);
360 /*** set unsigned int ***/
361 static __inline__ void setUInt(u8 *buffer,u32 offset,u32 value)
363 buffer[offset] = (value&0xff);
364 buffer[offset+1] = ((value&0xff00)>>8);
365 buffer[offset+2] = ((value&0xff0000)>>16);
366 buffer[offset+3] = ((value&0xff000000)>>24);
369 /*** get unsigned long long ***/
370 static __inline__ u64 getULongLong(u8 *buffer,u32 offset)
372 return (u64)(getUInt(buffer, offset) | (u64)getUInt(buffer, offset+4) << 32);
375 static __inline__ SMBHANDLE* __smb_handle_open(SMBCONN smbhndl)
377 u32 level;
378 SMBHANDLE *handle;
380 SMB_CHECK_HANDLE(smbhndl);
382 _CPU_ISR_Disable(level);
383 handle = (SMBHANDLE*)__lwp_objmgr_getnoprotection(&smb_handle_objects,LWP_OBJMASKID(smbhndl));
384 _CPU_ISR_Restore(level);
385 return handle;
389 static __inline__ void __smb_handle_free(SMBHANDLE *handle)
391 u32 level;
393 _CPU_ISR_Disable(level);
394 __lwp_objmgr_close(&smb_handle_objects,&handle->object);
395 __lwp_objmgr_free(&smb_handle_objects,&handle->object);
396 _CPU_ISR_Restore(level);
399 static void __smb_init()
401 smb_inited = true;
402 __lwp_objmgr_initinfo(&smb_handle_objects,SMB_CONNHANDLES_MAX,sizeof(SMBHANDLE));
403 __lwp_queue_initialize(&smb_filehandle_queue,smb_filehandles,SMB_FILEHANDLES_MAX,sizeof(struct _smbfile));
406 static SMBHANDLE* __smb_allocate_handle()
408 u32 level;
409 SMBHANDLE *handle;
411 _CPU_ISR_Disable(level);
412 handle = (SMBHANDLE*)__lwp_objmgr_allocate(&smb_handle_objects);
413 if(handle) {
414 handle->user = NULL;
415 handle->pwd = NULL;
416 handle->server_name = NULL;
417 handle->share_name = NULL;
418 handle->sck_server = INVALID_SOCKET;
419 handle->conn_valid = false;
420 __lwp_objmgr_open(&smb_handle_objects,&handle->object);
422 _CPU_ISR_Restore(level);
423 return handle;
426 static void __smb_free_handle(SMBHANDLE *handle)
428 if(handle->user) free(handle->user);
429 if(handle->pwd) free(handle->pwd);
430 if(handle->server_name) free(handle->server_name);
431 if(handle->share_name) free(handle->share_name);
433 handle->user = NULL;
434 handle->pwd = NULL;
435 handle->server_name = NULL;
436 handle->share_name = NULL;
437 handle->sck_server = INVALID_SOCKET;
439 __smb_handle_free(handle);
442 static void MakeSMBHeader(u8 command,u8 flags,u16 flags2,SMBHANDLE *handle)
444 u8 *ptr = handle->message.smb;
445 NBTSMB *nbt = &handle->message;
446 SMBSESSION *sess = &handle->session;
448 memset(nbt,0,sizeof(NBTSMB));
450 setUInt(ptr,SMB_OFFSET_PROTO,SMB_PROTO);
451 setUChar(ptr,SMB_OFFSET_CMD,command);
452 setUChar(ptr,SMB_OFFSET_FLAGS,flags);
453 setUShort(ptr,SMB_OFFSET_FLAGS2,flags2);
454 setUShort(ptr,SMB_OFFSET_TID,sess->TID);
455 setUShort(ptr,SMB_OFFSET_PID,sess->PID);
456 setUShort(ptr,SMB_OFFSET_UID,sess->UID);
457 setUShort(ptr,SMB_OFFSET_MID,sess->MID);
459 ptr[SMB_HEADER_SIZE] = 0;
463 * MakeTRANS2Hdr
465 static void MakeTRANS2Header(u8 subcommand,SMBHANDLE *handle)
467 u8 *ptr = handle->message.smb;
469 setUChar(ptr, T2_WORD_CNT, 15);
470 setUShort(ptr, T2_MAXPRM_CNT, 10);
471 setUShort(ptr, T2_MAXBUFFER, 16384);
472 setUChar(ptr, T2_SSETUP_CNT, 1);
473 setUShort(ptr, T2_SUB_CMD, subcommand);
477 * smb_send
479 * blocking call with timeout
480 * will return when ALL data has been sent. Number of bytes sent is returned.
481 * OR timeout. Timeout will return -1
482 * OR network error. -ve value will be returned
484 static inline s32 smb_send(s32 s,const void *data,s32 size)
486 u64 t1,t2;
487 s32 ret, len = size, nextsend;
489 t1=ticks_to_millisecs(gettime());
490 while(len>0)
492 nextsend=len;
494 if(nextsend>SMB_MAX_NET_WRITE_SIZE)
495 nextsend=SMB_MAX_NET_WRITE_SIZE; //optimized value
497 ret=net_send(s,data,nextsend,0);
498 if(ret==-EAGAIN)
500 t2=ticks_to_millisecs(gettime());
501 if( (t2 - t1) > RECV_TIMEOUT)
503 return -1; // timeout
505 usleep(100); // allow system to perform work. Stabilizes system
506 continue;
508 else if(ret<0)
510 return ret; // an error occurred
512 else
514 data+=ret;
515 len-=ret;
516 if(len==0) return size;
517 t1=ticks_to_millisecs(gettime());
519 usleep(100);
521 return size;
525 * smb_recv
527 * blocking call with timeout
528 * will return when ANY data has been read from socket. Number of bytes read is returned.
529 * OR timeout. Timeout will return -1
530 * OR network error. -ve value will be returned
532 static s32 smb_recv(s32 s,void *mem,s32 len)
534 s32 ret,read,readtotal=0;
535 u64 t1,t2;
537 t1=ticks_to_millisecs(gettime());
538 while(len > 0)
540 read=len;
541 if(read>SMB_MAX_NET_READ_SIZE)
542 read=SMB_MAX_NET_READ_SIZE; // optimized value
544 ret=net_recv(s,mem+readtotal,read,0);
545 if(ret>0)
547 readtotal+=ret;
548 len-=ret;
549 if(len==0) return readtotal;
551 else
553 if(ret!=-EAGAIN) return ret;
554 t2=ticks_to_millisecs(gettime());
555 if( (t2 - t1) > RECV_TIMEOUT) return -1;
557 usleep(1000);
559 return readtotal;
562 static void clear_network(s32 s,u8 *ptr)
564 u64 t1,t2;
566 t1=ticks_to_millisecs(gettime());
567 while(true)
569 net_recv(s,ptr,SMB_MAX_NET_READ_SIZE,0);
571 t2=ticks_to_millisecs(gettime());
572 if( (t2 - t1) > 600) return;
573 usleep(100);
578 * SMBCheck
580 * Do very basic checking on the return SMB
581 * Read <readlen> bytes
582 * if <readlen>==0 then read a single SMB packet
583 * discard any non NBT_SESSISON_MSG packets along the way.
585 static s32 SMBCheck(u8 command,SMBHANDLE *handle)
587 s32 ret;
588 u8 *ptr = handle->message.smb;
589 NBTSMB *nbt = &handle->message;
590 u32 readlen;
591 u64 t1,t2;
593 if(handle->sck_server == INVALID_SOCKET) return SMB_ERROR;
595 memset(nbt,0xFF,sizeof(NBTSMB)); //NBT_SESSISON_MSG is 0x00 so fill mem with 0xFF
597 t1=ticks_to_millisecs(gettime());
599 /*keep going till we get a NBT session message*/
601 ret=smb_recv(handle->sck_server, (u8*)nbt, 4);
602 if(ret!=4) goto failed;
604 if(nbt->msg!=NBT_SESSISON_MSG)
606 readlen=(u32)((nbt->length_high<<16)|nbt->length);
607 if(readlen>0)
609 t1=ticks_to_millisecs(gettime());
610 smb_recv(handle->sck_server, ptr, readlen); //clear unexpected NBT message
613 t2=ticks_to_millisecs(gettime());
614 if( (t2 - t1) > RECV_TIMEOUT * 2) goto failed;
616 } while(nbt->msg!=NBT_SESSISON_MSG);
618 /* obtain required length from NBT header if readlen==0*/
619 readlen=(u32)((nbt->length_high<<16)|nbt->length);
621 // Get server message block
622 ret=smb_recv(handle->sck_server, ptr, readlen);
623 if(readlen!=ret) goto failed;
625 /*** Do basic SMB Header checks ***/
626 ret = getUInt(ptr,SMB_OFFSET_PROTO);
627 if(ret!=SMB_PROTO) goto failed;
629 ret = getUChar(ptr, SMB_OFFSET_CMD);
630 if(ret!=command) goto failed;
632 ret = getUInt(ptr,SMB_OFFSET_NTSTATUS);
633 if(ret) goto failed;
635 return SMB_SUCCESS;
636 failed:
637 clear_network(handle->sck_server,ptr);
638 return SMB_ERROR;
642 * SMB_SetupAndX
644 * Setup the SMB session, including authentication with the
645 * magic 'NTLM Response'
647 static s32 SMB_SetupAndX(SMBHANDLE *handle)
649 s32 pos;
650 s32 bcpos;
651 s32 i, ret;
652 u8 *ptr = handle->message.smb;
653 SMBSESSION *sess = &handle->session;
654 char pwd[30], ntRespData[24];
656 if(handle->sck_server == INVALID_SOCKET) return SMB_ERROR;
658 MakeSMBHeader(SMB_SETUP_ANDX,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
659 pos = SMB_HEADER_SIZE;
661 setUChar(ptr,pos,13);
662 pos++; /*** Word Count ***/
663 setUChar(ptr,pos,0xff);
664 pos++; /*** Next AndX ***/
665 setUChar(ptr,pos,0);
666 pos++; /*** Reserved ***/
667 pos += 2; /*** Next AndX Offset ***/
668 setUShort(ptr,pos,sess->MaxBuffer);
669 pos += 2;
670 setUShort(ptr,pos,sess->MaxMpx);
671 pos += 2;
672 setUShort(ptr,pos,sess->MaxVCS);
673 pos += 2;
674 setUInt(ptr,pos,sess->sKey);
675 pos += 4;
676 setUShort(ptr,pos,24); /*** Password length (case-insensitive) ***/
677 pos += 2;
678 setUShort(ptr,pos,24); /*** Password length (case-sensitive) ***/
679 pos += 2;
680 setUInt(ptr,pos,0);
681 pos += 4; /*** Reserved ***/
682 setUInt(ptr,pos,sess->capabilities);
683 pos += 4; /*** Capabilities ***/
684 bcpos = pos;
685 pos += 2; /*** Byte count ***/
687 /*** The magic 'NTLM Response' ***/
688 strcpy(pwd, handle->pwd);
689 if (sess->challengeUsed)
690 ntlm_smb_nt_encrypt((const char *) pwd, (const u8 *) sess->challenge, (u8*) ntRespData);
692 /*** Build information ***/
693 memset(&ptr[pos],0,24);
694 pos += 24;
695 memcpy(&ptr[pos],ntRespData,24);
696 pos += 24;
697 pos++;
698 /*** Account ***/
699 strcpy(pwd, handle->user);
700 for(i=0;i<strlen(pwd);i++)
701 pwd[i] = toupper((int)pwd[i]);
702 if(handle->unicode)
704 pos += utf8_to_utf16((char*)&ptr[pos],pwd,SMB_MAXPATH-2);
705 pos += 2;
707 else
709 memcpy(&ptr[pos],pwd,strlen(pwd));
710 pos += strlen(pwd)+1;
713 /*** Primary Domain ***/
714 if(handle->user[0]=='\0') sess->p_domain[0] = '\0';
715 if(handle->unicode)
717 pos += utf8_to_utf16((char*)&ptr[pos],(char*)sess->p_domain,SMB_MAXPATH-2);
718 pos += 2;
720 else
722 memcpy(&ptr[pos],sess->p_domain,strlen((const char*)sess->p_domain));
723 pos += strlen((const char*)sess->p_domain)+1;
726 /*** Native OS ***/
727 strcpy(pwd,"Unix (libOGC)");
728 if(handle->unicode)
730 pos += utf8_to_utf16((char*)&ptr[pos],pwd,SMB_MAXPATH-2);
731 pos += 2;
733 else
735 memcpy(&ptr[pos],pwd,strlen(pwd));
736 pos += strlen(pwd)+1;
739 /*** Native LAN Manager ***/
740 strcpy(pwd,"Nintendo Wii");
741 if(handle->unicode)
743 pos += utf8_to_utf16((char*)&ptr[pos],pwd,SMB_MAXPATH-2);
744 pos += 2;
746 else
748 memcpy(&ptr[pos],pwd,strlen(pwd));
749 pos += strlen (pwd)+1;
752 /*** Update byte count ***/
753 setUShort(ptr,bcpos,((pos-bcpos)-2));
755 handle->message.msg = NBT_SESSISON_MSG;
756 handle->message.length = htons (pos);
757 pos += 4;
759 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
760 if(ret<=0) return SMB_ERROR;
762 if((ret=SMBCheck(SMB_SETUP_ANDX,handle))==SMB_SUCCESS) {
763 /*** Collect UID ***/
764 sess->UID = getUShort(handle->message.smb,SMB_OFFSET_UID);
765 return SMB_SUCCESS;
767 return ret;
771 * SMB_TreeAndX
773 * Finally, net_connect to the remote share
775 static s32 SMB_TreeAndX(SMBHANDLE *handle)
777 s32 pos, bcpos, ret;
778 char path[512];
779 u8 *ptr = handle->message.smb;
780 SMBSESSION *sess = &handle->session;
782 if(handle->sck_server == INVALID_SOCKET) return SMB_ERROR;
784 MakeSMBHeader(SMB_TREEC_ANDX,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
785 pos = SMB_HEADER_SIZE;
787 setUChar(ptr,pos,4);
788 pos++; /*** Word Count ***/
789 setUChar(ptr,pos,0xff);
790 pos++; /*** Next AndX ***/
791 pos++; /*** Reserved ***/
792 pos += 2; /*** Next AndX Offset ***/
793 pos += 2; /*** Flags ***/
794 setUShort(ptr,pos,1);
795 pos += 2; /*** Password Length ***/
796 bcpos = pos;
797 pos += 2;
798 pos++; /*** NULL Password ***/
800 /*** Build server share path ***/
801 strcpy ((char*)path, "\\\\");
802 strcat ((char*)path, handle->server_name);
803 strcat ((char*)path, "\\");
804 strcat ((char*)path, handle->share_name);
806 for(ret=0;ret<strlen((const char*)path);ret++)
807 path[ret] = (char)toupper((int)path[ret]);
809 if(handle->unicode)
811 pos += utf8_to_utf16((char*)&ptr[pos],path,SMB_MAXPATH-2);
812 pos += 2;
814 else
816 memcpy(&ptr[pos],path,strlen((const char*)path));
817 pos += strlen((const char*)path)+1;
820 /*** Service ***/
821 strcpy((char*)path,"?????");
822 memcpy(&ptr[pos],path,strlen((const char*)path));
823 pos += strlen((const char*)path)+1;
826 /*** Update byte count ***/
827 setUShort(ptr,bcpos,(pos-bcpos)-2);
829 handle->message.msg = NBT_SESSISON_MSG;
830 handle->message.length = htons (pos);
831 pos += 4;
833 ret = smb_send(handle->sck_server,(char *)&handle->message,pos);
834 if(ret<=0) return SMB_ERROR;
836 if((ret=SMBCheck(SMB_TREEC_ANDX,handle))==SMB_SUCCESS) {
837 /*** Collect Tree ID ***/
838 sess->TID = getUShort(handle->message.smb,SMB_OFFSET_TID);
839 return SMB_SUCCESS;
841 return ret;
845 * SMB_NegotiateProtocol
847 * The only protocol we admit to is 'NT LM 0.12'
849 static s32 SMB_NegotiateProtocol(const char *dialects[],int dialectc,SMBHANDLE *handle)
851 u8 *ptr;
852 s32 pos;
853 s32 bcnt,i,j;
854 s32 ret,len;
855 u16 bytecount;
856 u32 serverMaxBuffer;
857 SMBSESSION *sess;
859 if(!handle || !dialects || dialectc<=0)
860 return SMB_ERROR;
862 if(handle->sck_server == INVALID_SOCKET) return SMB_ERROR;
864 /*** Clear session variables ***/
865 sess = &handle->session;
866 memset(sess,0,sizeof(SMBSESSION));
867 sess->PID = 0xdead;
868 sess->MID = 1;
869 sess->capabilities = 0;
871 MakeSMBHeader(SMB_NEG_PROTOCOL,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
873 pos = SMB_HEADER_SIZE+3;
874 ptr = handle->message.smb;
875 for(i=0,bcnt=0;i<dialectc;i++) {
876 len = strlen(dialects[i])+1;
877 ptr[pos++] = '\x02';
878 memcpy(&ptr[pos],dialects[i],len);
879 pos += len;
880 bcnt += len+1;
882 /*** Update byte count ***/
883 setUShort(ptr,(SMB_HEADER_SIZE+1),bcnt);
885 /*** Set NBT information ***/
886 handle->message.msg = NBT_SESSISON_MSG;
887 handle->message.length = htons(pos);
888 pos += 4;
890 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
891 if(ret<=0) return SMB_ERROR;
893 /*** Check response ***/
894 if((ret=SMBCheck(SMB_NEG_PROTOCOL,handle))==SMB_SUCCESS)
896 pos = SMB_HEADER_SIZE;
897 ptr = handle->message.smb;
899 /*** Collect information ***/
900 if(getUChar(ptr,pos)!=17) return SMB_PROTO_FAIL; // UCHAR WordCount; Count of parameter words = 17
902 pos++;
903 if(getUShort(ptr,pos)!=0) return SMB_PROTO_FAIL; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
905 pos += 2;
906 if(getUChar(ptr,pos) & 1)
908 // user level security
909 sess->securityLevel = 1;
911 else
913 // share level security - can we skip SetupAndX? If so, we would need to specify the password in TreeAndX
914 sess->securityLevel = 0;
917 pos++;
918 sess->MaxMpx = getUShort(ptr, pos); //USHORT MaxMpxCount; Max pending outstanding requests
920 pos += 2;
921 sess->MaxVCS = getUShort(ptr, pos); //USHORT MaxNumberVcs; Max VCs between client and server
923 pos += 2;
924 serverMaxBuffer = getUInt(ptr, pos); //ULONG MaxBufferSize; Max transmit buffer size
927 if(serverMaxBuffer>SMB_MAX_TRANSMIT_SIZE)
928 sess->MaxBuffer = SMB_MAX_TRANSMIT_SIZE;
929 else
930 sess->MaxBuffer = serverMaxBuffer;
931 pos += 4;
932 pos += 4; //ULONG MaxRawSize; Maximum raw buffer size
933 sess->sKey = getUInt(ptr,pos); pos += 4;
934 u32 servcap = getUInt(ptr,pos); pos += 4; //ULONG Capabilities; Server capabilities
935 pos += 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
936 pos += 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
937 sess->timeOffset = getShort(ptr,pos) * 600000000LL; pos += 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
939 //UCHAR EncryptionKeyLength - 0 or 8
940 if(getUChar(ptr,pos)!=8)
942 if (getUChar(ptr,pos)!=0)
944 return SMB_BAD_KEYLEN;
946 else
948 // Challenge key not used
949 sess->challengeUsed = false;
952 else
954 sess->challengeUsed = true;
957 pos++;
958 bytecount = getUShort(ptr,pos);
960 if (sess->challengeUsed)
962 /*** Copy challenge key ***/
963 pos += 2;
964 memcpy(&sess->challenge,&ptr[pos],8);
967 /*** Primary domain ***/
968 pos += 8;
969 i = j = 0;
970 while(ptr[pos+j]!=0) {
971 sess->p_domain[i] = ptr[pos+j];
972 j += 2;
973 i++;
975 sess->p_domain[i] = '\0';
977 // setup capabilities
978 //if(servcap & CAP_LARGE_FILES)
979 // sess->capabilities |= CAP_LARGE_FILES;
981 if(servcap & CAP_UNICODE)
983 sess->capabilities |= CAP_UNICODE;
984 handle->unicode = true;
987 return SMB_SUCCESS;
989 return ret;
992 static s32 do_netconnect(SMBHANDLE *handle)
994 u32 nodelay;
995 s32 ret;
996 s32 sock;
997 u64 t1,t2;
999 handle->sck_server = INVALID_SOCKET;
1000 /*** Create the global net_socket ***/
1001 sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
1002 if(sock==INVALID_SOCKET) return -1;
1004 // Switch off Nagle with TCP_NODELAY
1005 nodelay = 1;
1006 net_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof(nodelay));
1008 // create non blocking socket
1009 ret = net_fcntl(sock, F_GETFL, 0);
1010 if (ret < 0)
1012 net_close(sock);
1013 return ret;
1016 ret = net_fcntl(sock, F_SETFL, ret | IOS_O_NONBLOCK);
1017 if (ret < 0)
1019 net_close(sock);
1020 return ret;
1023 t1=ticks_to_millisecs(gettime());
1024 while(1)
1026 ret = net_connect(sock,(struct sockaddr*)&handle->server_addr,sizeof(handle->server_addr));
1027 if(ret==-EISCONN) break;
1028 t2=ticks_to_millisecs(gettime());
1029 usleep(1000);
1030 if((t2-t1) > CONN_TIMEOUT) break; // usually not more than 90ms
1033 if(ret!=-EISCONN)
1035 net_close(sock);
1036 return -1;
1039 handle->sck_server = sock;
1040 return 0;
1043 static s32 do_smbconnect(SMBHANDLE *handle)
1045 s32 ret;
1047 if(handle->sck_server == INVALID_SOCKET) return -1;
1049 ret = SMB_NegotiateProtocol(smb_dialects,smb_dialectcnt,handle);
1050 if(ret!=SMB_SUCCESS)
1052 net_close(handle->sck_server);
1053 handle->sck_server = INVALID_SOCKET;
1054 return -1;
1057 ret = SMB_SetupAndX(handle);
1058 if(ret!=SMB_SUCCESS)
1060 net_close(handle->sck_server);
1061 handle->sck_server = INVALID_SOCKET;
1062 return -1;
1065 ret = SMB_TreeAndX(handle);
1066 if(ret!=SMB_SUCCESS)
1068 net_close(handle->sck_server);
1069 handle->sck_server = INVALID_SOCKET;
1070 return -1;
1073 handle->conn_valid = true;
1074 return 0;
1077 /****************************************************************************
1078 * Create an NBT SESSION REQUEST message.
1079 ****************************************************************************/
1080 static int MakeSessReq(unsigned char *bufr, unsigned char *Called, unsigned char *Calling)
1082 // Write the header.
1083 bufr[0] = SESS_REQ;
1084 bufr[1] = 0;
1085 bufr[2] = 0;
1086 bufr[3] = 68; // 2x34 bytes in length.
1088 // Copy the Called and Calling names into the buffer.
1089 (void) memcpy(&bufr[4], Called, 34);
1090 (void) memcpy(&bufr[38], Calling, 34);
1092 // Return the total message length.
1093 return 72;
1096 static unsigned char *L1_Encode(unsigned char *dst, const unsigned char *name,
1097 const unsigned char pad, const unsigned char sfx)
1099 int i = 0;
1100 int j = 0;
1101 int k = 0;
1103 while (('\0' != name[i]) && (i < 15))
1105 k = toupper(name[i++]);
1106 dst[j++] = 'A' + ((k & 0xF0) >> 4);
1107 dst[j++] = 'A' + (k & 0x0F);
1110 i = 'A' + ((pad & 0xF0) >> 4);
1111 k = 'A' + (pad & 0x0F);
1112 while (j < 30)
1114 dst[j++] = i;
1115 dst[j++] = k;
1118 dst[30] = 'A' + ((sfx & 0xF0) >> 4);
1119 dst[31] = 'A' + (sfx & 0x0F);
1120 dst[32] = '\0';
1122 return (dst);
1125 static int L2_Encode(unsigned char *dst, const unsigned char *name,
1126 const unsigned char pad, const unsigned char sfx,
1127 const unsigned char *scope)
1129 int lenpos;
1130 int i;
1131 int j;
1133 if (NULL == L1_Encode(&dst[1], name, pad, sfx))
1134 return (-1);
1136 dst[0] = 0x20;
1137 lenpos = 33;
1139 if ('\0' != *scope)
1143 for (i = 0, j = (lenpos + 1); ('.' != scope[i]) && ('\0'
1144 != scope[i]); i++, j++)
1145 dst[j] = toupper(scope[i]);
1147 dst[lenpos] = (unsigned char) i;
1148 lenpos += i + 1;
1149 scope += i;
1150 } while ('.' == *(scope++));
1152 dst[lenpos] = '\0';
1155 return (lenpos + 1);
1158 /****************************************************************************
1159 * Send an NBT SESSION REQUEST over the TCP connection, then wait for a reply.
1160 ****************************************************************************/
1161 static s32 SMB_RequestNBTSession(SMBHANDLE *handle)
1163 unsigned char Called[34];
1164 unsigned char Calling[34];
1165 unsigned char bufr[128];
1166 int result;
1168 if(handle->sck_server == INVALID_SOCKET) return -1;
1170 L2_Encode(Called, (const unsigned char*) "*SMBSERVER", 0x20, 0x20,
1171 (const unsigned char*) "");
1172 L2_Encode(Calling, (const unsigned char*) "SMBCLIENT", 0x20, 0x00,
1173 (const unsigned char*) "");
1175 // Create the NBT Session Request message.
1176 result = MakeSessReq(bufr, Called, Calling);
1178 //Send the NBT Session Request message.
1179 result = smb_send(handle->sck_server, bufr, result);
1180 if (result < 0)
1182 // Error sending Session Request message
1183 return -1;
1186 // Now wait for and handle the reply (2 seconds).
1187 result = smb_recv(handle->sck_server, bufr, 128);
1188 if (result <= 0)
1190 // Timeout waiting for NBT Session Response
1191 return -1;
1194 switch (*bufr)
1196 case SESS_POS_RESP:
1197 // Positive Session Response
1198 return 0;
1200 case SESS_NEG_RESP:
1201 // Negative Session Response
1202 return -1;
1204 case SESS_RETARGET:
1205 // Retarget Session Response
1206 return -1;
1208 default:
1209 // Unexpected Session Response
1210 return -1;
1214 /****************************************************************************
1215 * Primary setup, logon and connection all in one :)
1216 ****************************************************************************/
1217 s32 SMB_Connect(SMBCONN *smbhndl, const char *user, const char *password, const char *share, const char *server)
1219 s32 ret = 0;
1220 SMBHANDLE *handle;
1221 struct in_addr val;
1223 *smbhndl = SMB_HANDLE_NULL;
1225 if(!user || !password || !share || !server ||
1226 strlen(user) > 20 || strlen(password) > 14 ||
1227 strlen(share) > 80 || strlen(server) > 80)
1229 return SMB_BAD_LOGINDATA;
1232 if(!smb_inited)
1234 u32 level;
1235 _CPU_ISR_Disable(level);
1236 __smb_init();
1237 _CPU_ISR_Restore(level);
1240 handle = __smb_allocate_handle();
1241 if(!handle) return SMB_ERROR;
1243 handle->user = strdup(user);
1244 handle->pwd = strdup(password);
1245 handle->server_name = strdup(server);
1246 handle->share_name = strdup(share);
1247 handle->server_addr.sin_family = AF_INET;
1248 handle->server_addr.sin_port = htons(445);
1249 handle->unicode = false;
1251 if(strlen(server) < 16 && inet_aton(server, &val))
1253 handle->server_addr.sin_addr.s_addr = val.s_addr;
1255 else // might be a hostname
1257 #ifdef HW_RVL
1258 struct hostent *hp = net_gethostbyname(server);
1259 if (!hp || !(hp->h_addrtype == PF_INET))
1260 ret = SMB_BAD_LOGINDATA;
1261 else
1262 memcpy((char *)&handle->server_addr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
1263 #else
1264 __smb_free_handle(handle);
1265 return SMB_ERROR;
1266 #endif
1269 *smbhndl =(SMBCONN)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE)|LWP_OBJMASKID(handle->object.id));
1271 if(ret==0)
1273 ret = do_netconnect(handle);
1274 if(ret==0) ret = do_smbconnect(handle);
1276 if(ret!=0)
1278 // try port 139
1279 handle->server_addr.sin_port = htons(139);
1280 ret = do_netconnect(handle);
1281 if(ret==0) ret = SMB_RequestNBTSession(handle);
1282 if(ret==0) ret = do_smbconnect(handle);
1285 if(ret!=0)
1287 __smb_free_handle(handle);
1288 return SMB_ERROR;
1291 return SMB_SUCCESS;
1294 /****************************************************************************
1295 * SMB_Destroy
1296 ****************************************************************************/
1297 void SMB_Close(SMBCONN smbhndl)
1299 SMBHANDLE *handle = __smb_handle_open(smbhndl);
1300 if(!handle) return;
1302 if(handle->sck_server!=INVALID_SOCKET)
1303 net_close(handle->sck_server);
1305 __smb_free_handle(handle);
1308 s32 SMB_Reconnect(SMBCONN *_smbhndl, bool test_conn)
1310 s32 ret = SMB_SUCCESS;
1311 SMBCONN smbhndl = *_smbhndl;
1312 SMBHANDLE *handle = __smb_handle_open(smbhndl);
1313 if(!handle)
1314 return SMB_ERROR; // we have no handle, so we can't reconnect
1316 if(handle->conn_valid && test_conn)
1318 SMBDIRENTRY dentry;
1319 if(SMB_PathInfo("\\", &dentry, smbhndl)==SMB_SUCCESS) return SMB_SUCCESS; // no need to reconnect
1320 handle->conn_valid = false; // else connection is invalid
1322 if(!handle->conn_valid)
1324 // shut down connection
1325 if(handle->sck_server!=INVALID_SOCKET)
1327 net_close(handle->sck_server);
1328 handle->sck_server = INVALID_SOCKET;
1331 // reconnect
1332 if(handle->server_addr.sin_port > 0)
1334 ret = do_netconnect(handle);
1335 if(ret==0 && handle->server_addr.sin_port == htons(139))
1336 ret = SMB_RequestNBTSession(handle);
1337 if(ret==0)
1338 ret = do_smbconnect(handle);
1340 else // initial connection
1342 handle->server_addr.sin_port = htons(445);
1343 ret = do_netconnect(handle);
1344 if(ret==0) ret = do_smbconnect(handle);
1346 if(ret != 0)
1348 // try port 139
1349 handle->server_addr.sin_port = htons(139);
1350 ret = do_netconnect(handle);
1351 if(ret==0) ret = SMB_RequestNBTSession(handle);
1352 if(ret==0) ret = do_smbconnect(handle);
1355 if(ret != 0)
1356 handle->server_addr.sin_port = 0;
1359 return ret;
1362 SMBFILE SMB_OpenFile(const char *filename, u16 access, u16 creation,SMBCONN smbhndl)
1364 s32 pos;
1365 s32 bpos,ret;
1366 u8 *ptr;
1367 struct _smbfile *fid = NULL;
1368 SMBHANDLE *handle;
1369 char realfile[512];
1371 if(filename == NULL)
1372 return NULL;
1374 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return NULL;
1376 handle = __smb_handle_open(smbhndl);
1377 if(!handle) return NULL;
1379 MakeSMBHeader(SMB_OPEN_ANDX,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1381 pos = SMB_HEADER_SIZE;
1382 ptr = handle->message.smb;
1383 setUChar(ptr, pos, 15);
1384 pos++; /*** Word Count ***/
1385 setUChar(ptr, pos, 0xff);
1386 pos++; /*** AndXCommand 0xFF = None ***/
1387 setUChar(ptr, pos, 0);
1388 pos++; /*** AndX Reserved must be 0 ***/
1389 pos += 2; /*** Next AndX Offset to next Command ***/
1390 pos += 2; /*** Flags ***/
1391 setUShort(ptr, pos, access);
1392 pos += 2; /*** Access mode ***/
1393 setUShort(ptr, pos, 0x6);
1394 pos += 2; /*** Type of file ***/
1395 pos += 2; /*** File Attributes ***/
1396 pos += 4; /*** File time - don't care - let server decide ***/
1397 setUShort(ptr, pos, creation);
1398 pos += 2; /*** Creation flags ***/
1399 pos += 4; /*** Allocation size ***/
1400 setUInt(ptr, pos, 0);
1401 pos += 4; /*** Reserved[0] must be 0 ***/
1402 setUInt(ptr, pos, 0);
1403 pos += 4; /*** Reserved[1] must be 0 ***/
1404 pos += 2; /*** Byte Count ***/
1405 bpos = pos;
1406 setUChar(ptr, pos, 0x04); /** Bufferformat **/
1407 pos++;
1409 realfile[0]='\0';
1410 if (filename[0] != '\\')
1411 strcpy(realfile,"\\");
1412 strcat(realfile,filename);
1414 if(handle->unicode)
1416 pos += utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
1417 pos += 2;
1419 else
1421 memcpy(&ptr[pos],realfile,strlen(realfile));
1422 pos += strlen(realfile)+1;
1425 setUShort(ptr,(bpos-2),(pos-bpos));
1427 handle->message.msg = NBT_SESSISON_MSG;
1428 handle->message.length = htons(pos);
1430 pos += 4;
1431 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1432 if(ret<0) goto failed;
1434 if(SMBCheck(SMB_OPEN_ANDX,handle)==SMB_SUCCESS) {
1435 /*** Check file handle ***/
1436 fid = (struct _smbfile*)__lwp_queue_get(&smb_filehandle_queue);
1437 if(fid) {
1438 fid->conn = smbhndl;
1439 fid->sfid = getUShort(handle->message.smb,(SMB_HEADER_SIZE+5));
1442 return (SMBFILE)fid;
1444 failed:
1445 handle->conn_valid = false;
1446 return NULL;
1450 * SMB_CloseFile
1452 void SMB_CloseFile(SMBFILE sfid)
1454 u8 *ptr;
1455 s32 pos, ret;
1456 SMBHANDLE *handle;
1457 struct _smbfile *fid = (struct _smbfile*)sfid;
1459 if(!fid) return;
1461 handle = __smb_handle_open(fid->conn);
1462 if(!handle) return;
1464 MakeSMBHeader(SMB_CLOSE,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1466 pos = SMB_HEADER_SIZE;
1467 ptr = handle->message.smb;
1468 setUChar(ptr, pos, 3);
1469 pos++; /** Word Count **/
1470 setUShort(ptr, pos, fid->sfid);
1471 pos += 2;
1472 setUInt(ptr, pos, 0xffffffff);
1473 pos += 4; /*** Last Write ***/
1474 pos += 2; /*** Byte Count ***/
1476 handle->message.msg = NBT_SESSISON_MSG;
1477 handle->message.length = htons(pos);
1479 pos += 4;
1480 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1481 if(ret<0) handle->conn_valid = false;
1482 else SMBCheck(SMB_CLOSE,handle);
1483 __lwp_queue_append(&smb_filehandle_queue,&fid->node);
1487 * SMB_CreateDirectory
1489 s32 SMB_CreateDirectory(const char *dirname, SMBCONN smbhndl)
1491 s32 pos;
1492 s32 bpos,ret;
1493 u8 *ptr;
1494 SMBHANDLE *handle;
1495 char realfile[512];
1497 if(dirname == NULL)
1498 return -1;
1500 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return -1;
1502 handle = __smb_handle_open(smbhndl);
1503 if(!handle) return -1;
1505 MakeSMBHeader(SMB_COM_CREATE_DIRECTORY,CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1507 pos = SMB_HEADER_SIZE;
1508 ptr = handle->message.smb;
1509 setUChar(ptr, pos, 0);
1510 pos++; /*** Word Count ***/
1511 pos += 2; /*** Byte Count ***/
1512 bpos = pos;
1513 setUChar(ptr, pos, 0x04); /*** Buffer format ***/
1514 pos++;
1516 realfile[0]='\0';
1517 if (dirname[0] != '\\')
1518 strcpy(realfile,"\\");
1519 strcat(realfile,dirname);
1521 if(handle->unicode)
1523 pos += utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
1524 pos += 2;
1526 else
1528 memcpy(&ptr[pos],realfile,strlen(realfile));
1529 pos += strlen(realfile)+1;
1532 setUShort(ptr,(bpos-2),(pos-bpos));
1534 handle->message.msg = NBT_SESSISON_MSG;
1535 handle->message.length = htons(pos);
1537 pos += 4;
1538 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1539 if(ret < 0) goto failed;
1541 ret = SMBCheck(SMB_COM_CREATE_DIRECTORY,handle);
1543 return ret;
1545 failed:
1546 return ret;
1550 * SMB_DeleteDirectory
1552 s32 SMB_DeleteDirectory(const char *dirname, SMBCONN smbhndl)
1554 s32 pos;
1555 s32 bpos,ret;
1556 u8 *ptr;
1557 SMBHANDLE *handle;
1558 char realfile[512];
1560 if(dirname == NULL)
1561 return -1;
1563 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return -1;
1565 handle = __smb_handle_open(smbhndl);
1566 if(!handle) return -1;
1568 MakeSMBHeader(SMB_COM_DELETE_DIRECTORY,CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1570 pos = SMB_HEADER_SIZE;
1571 ptr = handle->message.smb;
1572 setUChar(ptr, pos, 0);
1573 pos++; /*** Word Count ***/
1574 pos += 2; /*** Byte Count ***/
1575 bpos = pos;
1576 setUChar(ptr, pos, 0x04); /** Bufferformat **/
1577 pos++;
1579 realfile[0]='\0';
1580 if (dirname[0] != '\\')
1581 strcpy(realfile,"\\");
1582 strcat(realfile,dirname);
1584 if(handle->unicode)
1586 pos += utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
1587 pos += 2;
1589 else
1591 memcpy(&ptr[pos],realfile,strlen(realfile));
1592 pos += strlen(realfile)+1;
1595 setUShort(ptr,(bpos-2),(pos-bpos));
1597 handle->message.msg = NBT_SESSISON_MSG;
1598 handle->message.length = htons(pos);
1600 pos += 4;
1601 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1602 if(ret < 0) goto failed;
1604 ret = SMBCheck(SMB_COM_DELETE_DIRECTORY,handle);
1606 return ret;
1608 failed:
1609 return ret;
1613 * SMB_DeleteFile
1615 s32 SMB_DeleteFile(const char *filename, SMBCONN smbhndl)
1617 s32 pos;
1618 s32 bpos,ret;
1619 u8 *ptr;
1620 SMBHANDLE *handle;
1621 char realfile[512];
1623 if(filename == NULL)
1624 return -1;
1626 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return -1;
1628 handle = __smb_handle_open(smbhndl);
1629 if(!handle) return -1;
1631 MakeSMBHeader(SMB_COM_DELETE,CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1633 pos = SMB_HEADER_SIZE;
1634 ptr = handle->message.smb;
1635 setUChar(ptr, pos, 1);
1636 pos++; /*** Word Count ***/
1637 setUShort(ptr, pos, SMB_SRCH_HIDDEN);
1638 pos += 2; /*** SearchAttributes ***/
1639 pos += 2; /*** Byte Count ***/
1640 bpos = pos;
1641 setUChar(ptr, pos, 0x04); /** Bufferformat **/
1642 pos++;
1644 realfile[0]='\0';
1645 if (filename[0] != '\\')
1646 strcpy(realfile,"\\");
1647 strcat(realfile,filename);
1649 if(handle->unicode)
1651 pos += utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
1652 pos += 2;
1654 else
1656 memcpy(&ptr[pos],realfile,strlen(realfile));
1657 pos += strlen(realfile)+1;
1660 setUShort(ptr,(bpos-2),(pos-bpos));
1662 handle->message.msg = NBT_SESSISON_MSG;
1663 handle->message.length = htons(pos);
1665 pos += 4;
1666 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1667 if(ret < 0) goto failed;
1669 ret = SMBCheck(SMB_COM_DELETE,handle);
1671 return ret;
1673 failed:
1674 return ret;
1678 * SMB_Rename
1680 s32 SMB_Rename(const char *filename, const char * newfilename, SMBCONN smbhndl)
1682 s32 pos;
1683 s32 bpos,ret;
1684 u8 *ptr;
1685 SMBHANDLE *handle;
1686 char realfile[512];
1687 char newrealfile[512];
1689 if(filename == NULL || newfilename == NULL)
1690 return -1;
1692 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS)
1693 return -1;
1695 handle = __smb_handle_open(smbhndl);
1696 if(!handle) return -1;
1698 MakeSMBHeader(SMB_COM_RENAME,CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1700 pos = SMB_HEADER_SIZE;
1701 ptr = handle->message.smb;
1702 setUChar(ptr, pos, 1);
1703 pos++; /*** Word Count ***/
1704 setUShort(ptr, pos, SMB_SRCH_HIDDEN);
1705 pos += 2; /*** SearchAttributes ***/
1706 pos += 2; /*** Byte Count ***/
1707 bpos = pos;
1708 setUChar(ptr, pos, 0x04); /** Bufferformat **/
1709 pos++;
1711 realfile[0]='\0';
1712 if (filename[0] != '\\')
1713 strcpy(realfile,"\\");
1714 strcat(realfile,filename);
1716 if(handle->unicode)
1718 pos += utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
1719 pos += 2;
1721 else
1723 memcpy(&ptr[pos],realfile,strlen(realfile));
1724 pos += strlen(realfile)+1;
1727 pos++;
1728 setUChar(ptr, pos, 0x04); /** Bufferformat **/
1729 pos++;
1731 newrealfile[0]='\0';
1732 if (newfilename[0] != '\\')
1733 strcpy(newrealfile,"\\");
1734 strcat(newrealfile,newfilename);
1736 if(handle->unicode)
1738 pos += utf8_to_utf16((char*)&ptr[pos],newrealfile,SMB_MAXPATH-2);
1739 pos += 2;
1741 else
1743 memcpy(&ptr[pos],newrealfile,strlen(newrealfile));
1744 pos += strlen(newrealfile)+1;
1747 setUShort(ptr,(bpos-2),(pos-bpos));
1749 handle->message.msg = NBT_SESSISON_MSG;
1750 handle->message.length = htons(pos);
1752 pos += 4;
1753 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1754 if(ret < 0) goto failed;
1756 ret = SMBCheck(SMB_COM_RENAME,handle);
1758 return ret;
1760 failed:
1761 return ret;
1765 * SMB_DiskInformation
1767 s32 SMB_DiskInformation(struct statvfs *buf, SMBCONN smbhndl)
1769 s32 pos;
1770 s32 bpos,ret;
1771 u16 TotalUnits, BlocksPerUnit, BlockSize, FreeUnits;
1772 u8 *ptr;
1773 SMBHANDLE *handle;
1775 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return -1;
1777 handle = __smb_handle_open(smbhndl);
1778 if(!handle) return -1;
1780 MakeSMBHeader(SMB_COM_QUERY_INFORMATION_DISK,CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1782 pos = SMB_HEADER_SIZE;
1783 ptr = handle->message.smb;
1784 setUChar(ptr, pos, 0);
1785 pos++; /*** Word Count ***/
1786 setUShort(ptr, pos, 0);
1787 pos += 2; /*** Byte Count ***/
1788 bpos = pos;
1790 handle->message.msg = NBT_SESSISON_MSG;
1791 handle->message.length = htons(pos);
1793 pos += 4;
1794 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1795 if(ret < 0) goto failed;
1797 if((ret=SMBCheck(SMB_COM_QUERY_INFORMATION_DISK, handle))==SMB_SUCCESS)
1799 ptr = handle->message.smb;
1800 /** Read the received data ***/
1801 /** WordCount **/
1802 s32 recv_pos = 1;
1803 /** TotalUnits **/
1804 TotalUnits = getUShort(ptr,(SMB_HEADER_SIZE+recv_pos));
1805 recv_pos += 2;
1806 /** BlocksPerUnit **/
1807 BlocksPerUnit = getUShort(ptr,(SMB_HEADER_SIZE+recv_pos));
1808 recv_pos += 2;
1809 /** BlockSize **/
1810 BlockSize = getUShort(ptr,(SMB_HEADER_SIZE+recv_pos));
1811 recv_pos += 2;
1812 /** FreeUnits **/
1813 FreeUnits = getUShort(ptr,(SMB_HEADER_SIZE+recv_pos));
1814 recv_pos += 2;
1816 buf->f_bsize = (unsigned long) BlockSize; // File system block size.
1817 buf->f_frsize = (unsigned long) BlockSize; // Fundamental file system block size.
1818 buf->f_blocks = (fsblkcnt_t) (TotalUnits*BlocksPerUnit); // Total number of blocks on file system in units of f_frsize.
1819 buf->f_bfree = (fsblkcnt_t) (FreeUnits*BlocksPerUnit); // Total number of free blocks.
1820 buf->f_bavail = 0; // Number of free blocks available to non-privileged process.
1821 buf->f_files = 0; // Total number of file serial numbers.
1822 buf->f_ffree = 0; // Total number of free file serial numbers.
1823 buf->f_favail = 0; // Number of file serial numbers available to non-privileged process.
1824 buf->f_fsid = 0; // File system ID. 32bit ioType value
1825 buf->f_flag = 0; // Bit mask of f_flag values.
1826 buf->f_namemax = SMB_MAXPATH; // Maximum filename length.
1828 return SMB_SUCCESS;
1831 failed:
1832 handle->conn_valid = false;
1833 return ret;
1837 * SMB_Read
1839 s32 SMB_ReadFile(char *buffer, size_t size, off_t offset, SMBFILE sfid)
1841 u8 *ptr;
1842 u32 pos, ret, ofs;
1843 u16 length = 0;
1844 SMBHANDLE *handle;
1845 size_t totalread=0,nextread;
1846 struct _smbfile *fid = (struct _smbfile*)sfid;
1848 if(!fid) return -1;
1850 // Check for invalid size
1851 if(size == 0) return -1;
1853 handle = __smb_handle_open(fid->conn);
1854 if(!handle) return -1;
1856 while(totalread < size)
1858 if((size-totalread) > SMB_MAX_TRANSMIT_SIZE)
1859 nextread=SMB_MAX_TRANSMIT_SIZE;
1860 else
1861 nextread=size-totalread;
1863 MakeSMBHeader(SMB_READ_ANDX,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1865 pos = SMB_HEADER_SIZE;
1866 ptr = handle->message.smb;
1867 setUChar(ptr, pos, 12);
1868 pos++; /*** Word count ***/
1869 setUChar(ptr, pos, 0xff);
1870 pos++;
1871 setUChar(ptr, pos, 0);
1872 pos++; /*** Reserved must be 0 ***/
1873 pos += 2; /*** Next AndX Offset ***/
1874 setUShort(ptr, pos, fid->sfid);
1875 pos += 2; /*** FID ***/
1876 setUInt(ptr, pos, (offset+totalread) & 0xffffffff);
1877 pos += 4; /*** Offset ***/
1879 setUShort(ptr, pos, nextread & 0xffff);
1880 pos += 2;
1881 setUShort(ptr, pos, nextread & 0xffff);
1882 pos += 2;
1883 setUInt(ptr, pos, 0);
1884 pos += 4; /*** Reserved must be 0 ***/
1885 setUShort(ptr, pos, nextread & 0xffff);
1886 pos += 2; /*** Remaining ***/
1887 setUInt(ptr, pos, (offset+totalread) >> 32); // offset high
1888 pos += 4; /*** OffsetHIGH ***/
1889 pos += 2; /*** Byte count ***/
1891 handle->message.msg = NBT_SESSISON_MSG;
1892 handle->message.length = htons(pos);
1894 pos += 4;
1896 ret = smb_send(handle->sck_server,(char*)&handle->message, pos);
1897 if(ret<0) goto failed;
1899 /*** SMBCheck ***/
1900 if(SMBCheck(SMB_READ_ANDX,handle)!=SMB_SUCCESS) goto failed;
1902 ptr = handle->message.smb;
1903 // Retrieve data length for this packet
1904 length = getUShort(ptr,(SMB_HEADER_SIZE+11));
1906 if(length==0)
1907 break;
1909 // Retrieve offset to data
1910 ofs = getUShort(ptr,(SMB_HEADER_SIZE+13));
1911 memcpy(&buffer[totalread],&ptr[ofs],length);
1912 totalread+=length;
1914 return size;
1916 failed:
1917 handle->conn_valid = false;
1918 return SMB_ERROR;
1922 * SMB_Write
1924 s32 SMB_WriteFile(const char *buffer, size_t size, off_t offset, SMBFILE sfid)
1926 u8 *ptr,*src;
1927 s32 pos, ret;
1928 s32 blocks64;
1929 u32 copy_len;
1930 SMBHANDLE *handle;
1931 struct _smbfile *fid = (struct _smbfile*)sfid;
1933 if(!fid) return -1;
1935 handle = __smb_handle_open(fid->conn);
1936 if(!handle) return -1;
1938 MakeSMBHeader(SMB_WRITE_ANDX,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
1941 pos = SMB_HEADER_SIZE;
1942 ptr = handle->message.smb;
1943 setUChar(ptr, pos, 14);
1944 pos++; /*** Word Count ***/
1945 setUChar(ptr, pos, 0xff);
1946 pos += 2; /*** Next AndX ***/
1947 pos += 2; /*** Next AndX Offset ***/
1949 setUShort(ptr, pos, fid->sfid);
1950 pos += 2;
1951 setUInt(ptr, pos, offset & 0xffffffff);
1952 pos += 4;
1953 setUInt(ptr, pos, 0); /*** Reserved, must be 0 ***/
1954 pos += 4;
1955 setUShort(ptr, pos, 0); /*** Write Mode ***/
1956 pos += 2;
1957 pos += 2; /*** Remaining ***/
1959 blocks64 = size >> 16;
1961 setUShort(ptr, pos, blocks64);
1962 pos += 2; /*** Length High ***/
1963 setUShort(ptr, pos, size & 0xffff);
1964 pos += 2; /*** Length Low ***/
1965 setUShort(ptr, pos, 63);
1966 pos += 2; /*** Data Offset ***/
1967 setUInt(ptr, pos, offset >> 32); /*** OffsetHigh ***/
1968 pos += 4;
1969 setUShort(ptr, pos, size & 0xffff);
1970 pos += 2; /*** Data Byte Count ***/
1972 handle->message.msg = NBT_SESSISON_MSG;
1973 handle->message.length = htons(pos+size);
1975 src = (u8*)buffer;
1976 copy_len = size;
1978 if((copy_len+pos)>SMB_MAX_TRANSMIT_SIZE)
1979 copy_len = (SMB_MAX_TRANSMIT_SIZE-pos);
1981 memcpy(&ptr[pos],src,copy_len);
1982 size -= copy_len;
1983 src += copy_len;
1984 pos += copy_len;
1986 pos += 4;
1988 /*** Send Header Information ***/
1989 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1990 if(ret<0) goto failed;
1992 if(size>0) {
1993 /*** Send the data ***/
1994 ret = smb_send(handle->sck_server,src,size);
1995 if(ret<0) goto failed;
1998 ret = 0;
1999 if(SMBCheck(SMB_WRITE_ANDX,handle)==SMB_SUCCESS) {
2000 ptr = handle->message.smb;
2001 ret = getUShort(ptr,(SMB_HEADER_SIZE+5));
2004 return ret;
2006 failed:
2007 handle->conn_valid = false;
2008 return ret;
2012 * SMB_PathInfo
2014 s32 SMB_PathInfo(const char *filename, SMBDIRENTRY *sdir, SMBCONN smbhndl)
2016 u8 *ptr;
2017 s32 pos;
2018 s32 ret;
2019 s32 bpos;
2020 int len;
2021 SMBHANDLE *handle;
2022 char realfile[512];
2024 if(filename == NULL)
2025 return SMB_ERROR;
2027 handle = __smb_handle_open(smbhndl);
2028 if (!handle) return SMB_ERROR;
2030 MakeSMBHeader(SMB_TRANS2, CIFS_FLAGS1, handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2, handle);
2031 MakeTRANS2Header(SMB_QUERY_PATH_INFO, handle);
2033 bpos = pos = (T2_BYTE_CNT + 2);
2034 pos += 3; /*** Padding ***/
2035 ptr = handle->message.smb;
2036 setUShort(ptr, pos, SMB_QUERY_FILE_ALL_INFO);
2037 pos += 2; /*** Level of information requested ***/
2038 setUInt(ptr, pos, 0);
2039 pos += 4; /*** reserved ***/
2041 realfile[0] = '\0';
2042 if (filename[0] != '\\')
2043 strcpy(realfile,"\\");
2044 strcat(realfile,filename);
2046 if(handle->unicode)
2048 len = utf8_to_utf16((char*)&ptr[pos],realfile,SMB_MAXPATH-2);
2049 pos += len+2;
2050 len+=1;
2052 else
2054 len = strlen(realfile);
2055 memcpy(&ptr[pos],realfile,len);
2056 pos += len+1;
2059 /*** Update counts ***/
2060 setUShort(ptr, T2_PRM_CNT, (7 + len));
2061 setUShort(ptr, T2_SPRM_CNT, (7 + len));
2062 setUShort(ptr, T2_SPRM_OFS, 68);
2063 setUShort(ptr, T2_BYTE_CNT, (pos - bpos));
2065 handle->message.msg = NBT_SESSISON_MSG;
2066 handle->message.length = htons(pos);
2068 pos += 4;
2069 ret = smb_send(handle->sck_server, (char*) &handle->message, pos);
2070 if(ret<0) goto failed;
2072 ret = SMB_ERROR;
2073 if (SMBCheck(SMB_TRANS2, handle) == SMB_SUCCESS) {
2075 ptr = handle->message.smb;
2076 /*** Get parameter offset ***/
2077 pos = getUShort(ptr, (SMB_HEADER_SIZE + 9));
2078 pos += 4; // padding
2079 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
2080 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
2081 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
2082 pos += 8; // ULONGLONG - change time
2083 sdir->attributes = getUInt(ptr,pos); pos += 4; // ULONG - file attributes
2084 pos += 4; // padding
2085 pos += 8; // ULONGLONG - allocated file size
2086 sdir->size = getULongLong(ptr, pos); pos += 8; // ULONGLONG - file size
2087 pos += 4; // ULONG NumberOfLinks;
2088 pos += 2; // UCHAR DeletePending;
2089 pos += 2; // UCHAR Directory;
2090 pos += 2; // USHORT Pad2; // for alignment only
2091 pos += 4; // ULONG EaSize;
2092 pos += 4; // ULONG FileNameLength;
2094 strcpy(sdir->name,realfile);
2096 ret = SMB_SUCCESS;
2098 return ret;
2100 failed:
2101 handle->conn_valid = false;
2102 return ret;
2106 * SMB_FindFirst
2108 * Uses TRANS2 to support long filenames
2110 s32 SMB_FindFirst(const char *filename, unsigned short flags, SMBDIRENTRY *sdir, SMBCONN smbhndl)
2112 u8 *ptr;
2113 s32 pos;
2114 s32 ret;
2115 s32 bpos;
2116 unsigned int len;
2117 SMBHANDLE *handle;
2118 SMBSESSION *sess;
2120 if(filename == NULL)
2121 return SMB_ERROR;
2123 if(SMB_Reconnect(&smbhndl,true)!=SMB_SUCCESS) return SMB_ERROR;
2125 handle = __smb_handle_open(smbhndl);
2126 if(!handle) return SMB_ERROR;
2128 sess = &handle->session;
2129 MakeSMBHeader(SMB_TRANS2,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
2130 MakeTRANS2Header(SMB_FIND_FIRST2,handle);
2132 ptr = handle->message.smb;
2134 bpos = pos = (T2_BYTE_CNT+2);
2135 pos += 3; /*** Padding ***/
2136 setUShort(ptr, pos, flags);
2137 pos += 2; /*** Flags ***/
2138 setUShort(ptr, pos, 1);
2139 pos += 2; /*** Count ***/
2140 setUShort(ptr, pos, 6);
2141 pos += 2; /*** Internal Flags ***/
2142 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
2143 pos += 2; /*** Level of Interest ***/
2144 pos += 4; /*** Storage Type == 0 ***/
2146 if(handle->unicode)
2148 len = utf8_to_utf16((char*)&ptr[pos], (char*)filename,SMB_MAXPATH-2);
2149 pos += len+2;
2150 len++;
2152 else
2154 len = strlen(filename);
2155 memcpy(&ptr[pos],filename,len);
2156 pos += len+1;
2159 /*** Update counts ***/
2160 setUShort(ptr, T2_PRM_CNT, (13+len));
2161 setUShort(ptr, T2_SPRM_CNT, (13+len));
2162 setUShort(ptr, T2_SPRM_OFS, 68);
2163 setUShort(ptr, T2_BYTE_CNT,(pos-bpos));
2165 handle->message.msg = NBT_SESSISON_MSG;
2166 handle->message.length = htons(pos);
2168 pos += 4;
2169 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
2170 if(ret<0) goto failed;
2172 sess->eos = 1;
2173 sess->count = 0;
2174 ret = SMB_ERROR;
2175 if(SMBCheck(SMB_TRANS2,handle)==SMB_SUCCESS) {
2176 ptr = handle->message.smb;
2177 /*** Get parameter offset ***/
2178 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
2179 sdir->sid = getUShort(ptr, pos); pos += 2;
2180 sess->count = getUShort(ptr, pos); pos += 2;
2181 sess->eos = getUShort(ptr, pos); pos += 2;
2182 pos += 2; // USHORT EaErrorOffset;
2183 pos += 2; // USHORT LastNameOffset;
2184 pos += 2; // padding?
2186 if (sess->count)
2188 pos += 4; // ULONG NextEntryOffset;
2189 pos += 4; // ULONG FileIndex;
2190 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
2191 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
2192 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
2193 pos += 8; // ULONGLONG - change time low
2194 sdir->size = getULongLong(ptr, pos); pos += 8;
2195 pos += 8;
2196 sdir->attributes = getUInt(ptr, pos); pos += 4;
2197 len=getUInt(ptr, pos);
2198 pos += 34;
2199 if(handle->unicode)
2200 utf16_to_utf8(sdir->name,(char*)&ptr[pos],len);
2201 else
2202 strcpy(sdir->name,(const char*)&ptr[pos]);
2204 ret = SMB_SUCCESS;
2207 return ret;
2209 failed:
2210 handle->conn_valid = false;
2211 return ret;
2215 * SMB_FindNext
2217 s32 SMB_FindNext(SMBDIRENTRY *sdir,SMBCONN smbhndl)
2219 u8 *ptr;
2220 s32 pos;
2221 s32 ret;
2222 s32 bpos;
2223 SMBHANDLE *handle;
2224 SMBSESSION *sess;
2226 handle = __smb_handle_open(smbhndl);
2227 if(!handle) return SMB_ERROR;
2229 sess = &handle->session;
2230 if(sess->eos || sdir->sid==0) return SMB_ERROR;
2232 MakeSMBHeader(SMB_TRANS2,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
2233 MakeTRANS2Header(SMB_FIND_NEXT2,handle);
2235 bpos = pos = (T2_BYTE_CNT+2);
2236 pos += 3; /*** Padding ***/
2237 ptr = handle->message.smb;
2238 setUShort(ptr, pos, sdir->sid);
2239 pos += 2; /*** Search ID ***/
2240 setUShort(ptr, pos, 1);
2241 pos += 2; /*** Count ***/
2242 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
2243 pos += 2; /*** Level of Interest ***/
2244 pos += 4; /*** Storage Type == 0 ***/
2245 setUShort(ptr, pos, 12);
2246 pos+=2; /*** Search flags ***/
2247 pos++;
2249 int pad=0;
2250 if(handle->unicode)pad=1;
2251 pos+=pad;
2253 /*** Update counts ***/
2254 setUShort(ptr, T2_PRM_CNT, 13+pad);
2255 setUShort(ptr, T2_SPRM_CNT, 13+pad);
2256 setUShort(ptr, T2_SPRM_OFS, 68);
2257 setUShort(ptr, T2_BYTE_CNT, (pos-bpos));
2259 handle->message.msg = NBT_SESSISON_MSG;
2260 handle->message.length = htons(pos);
2262 pos += 4;
2263 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
2264 if(ret<0) goto failed;
2266 ret = SMB_ERROR;
2267 if (SMBCheck(SMB_TRANS2,handle)==SMB_SUCCESS) {
2268 ptr = handle->message.smb;
2269 /*** Get parameter offset ***/
2270 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
2271 sess->count = getUShort(ptr, pos); pos += 2;
2272 sess->eos = getUShort(ptr, pos); pos += 2;
2273 pos += 2; // USHORT EaErrorOffset;
2274 pos += 2; // USHORT LastNameOffset;
2276 if (sess->count)
2278 int len;
2279 pos += 4; // ULONG NextEntryOffset;
2280 pos += 4; // ULONG FileIndex;
2281 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
2282 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
2283 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
2284 pos += 8; // ULONGLONG - change time low
2285 sdir->size = getULongLong(ptr, pos); pos += 8;
2286 pos += 8;
2287 sdir->attributes = getUInt(ptr, pos); pos += 4;
2288 len=getUInt(ptr, pos);
2289 pos += 34;
2290 if(handle->unicode)
2291 utf16_to_utf8(sdir->name, (char*)&ptr[pos],len);
2292 else
2293 strcpy (sdir->name, (const char*)&ptr[pos]);
2295 ret = SMB_SUCCESS;
2298 return ret;
2300 failed:
2301 handle->conn_valid = false;
2302 return ret;
2306 * SMB_FindClose
2308 s32 SMB_FindClose(SMBDIRENTRY *sdir,SMBCONN smbhndl)
2310 u8 *ptr;
2311 s32 pos;
2312 s32 ret;
2313 SMBHANDLE *handle;
2314 SMBSESSION *sess;
2316 handle = __smb_handle_open(smbhndl);
2317 if(!handle) return SMB_ERROR;
2319 sess = &handle->session;
2320 if(sdir->sid==0) return SMB_ERROR;
2322 MakeSMBHeader(SMB_FIND_CLOSE2,CIFS_FLAGS1,handle->unicode?CIFS_FLAGS2_UNICODE:CIFS_FLAGS2,handle);
2324 pos = SMB_HEADER_SIZE;
2325 ptr = handle->message.smb;
2326 setUChar(ptr, pos, 1);
2327 pos++; /*** Word Count ***/
2328 setUShort(ptr, pos, sdir->sid);
2329 pos += 2;
2330 pos += 2; /*** Byte Count ***/
2332 handle->message.msg = NBT_SESSISON_MSG;
2333 handle->message.length = htons(pos);
2335 pos += 4;
2336 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
2337 if(ret<0) goto failed;
2339 ret = SMBCheck(SMB_FIND_CLOSE2,handle);
2340 return ret;
2342 failed:
2343 handle->conn_valid = false;
2344 return ret;