1 /****************************************************************************
3 * Nintendo Wii/GameCube SMB implementation
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.
14 * Implementing CIFS - Christopher R Hertel
15 * http://www.ubiqx.org/cifs/SMB.html
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 ****************************************************************************/
43 #include <processor.h>
44 #include <lwp_threads.h>
45 #include <lwp_objmgr.h>
46 #include <ogc/lwp_watchdog.h>
51 #define IOS_O_NONBLOCK 0x04
52 #define RECV_TIMEOUT 5000 // in ms
57 #define SMB_OFFSET_PROTO 0
58 #define SMB_OFFSET_CMD 4
59 #define SMB_OFFSET_NTSTATUS 5
60 #define SMB_OFFSET_ECLASS 5
61 #define SMB_OFFSET_ECODE 7
62 #define SMB_OFFSET_FLAGS 9
63 #define SMB_OFFSET_FLAGS2 10
64 #define SMB_OFFSET_EXTRA 12
65 #define SMB_OFFSET_TID 24
66 #define SMB_OFFSET_PID 26
67 #define SMB_OFFSET_UID 28
68 #define SMB_OFFSET_MID 30
69 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
74 #define NBT_SESSISON_MSG 0x00
76 #define SMB_NEG_PROTOCOL 0x72
77 #define SMB_SETUP_ANDX 0x73
78 #define SMB_TREEC_ANDX 0x75
81 #define NBT_KEEPALIVE_MSG 0x85
82 #define KEEPALIVE_SIZE 4
87 #define SMB_TRANS2 0x32
90 #define SMB_FIND_FIRST2 1
91 #define SMB_FIND_NEXT2 2
92 #define SMB_QUERY_FS_INFO 3
93 #define SMB_QUERY_PATH_INFO 5
94 #define SMB_SET_PATH_INFO 6
95 #define SMB_QUERY_FILE_INFO 7
96 #define SMB_SET_FILE_INFO 8
97 #define SMB_CREATE_DIR 13
98 #define SMB_FIND_CLOSE2 0x34
99 #define SMB_QUERY_FILE_ALL_INFO 0x107
104 #define SMB_OPEN_ANDX 0x2d
105 #define SMB_WRITE_ANDX 0x2f
106 #define SMB_READ_ANDX 0x2e
107 #define SMB_CLOSE 0x04
113 #define T2_WORD_CNT (SMB_HEADER_SIZE)
114 #define T2_PRM_CNT (T2_WORD_CNT+1)
115 #define T2_DATA_CNT (T2_PRM_CNT+2)
116 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
117 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
118 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
119 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
120 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
121 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
122 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
123 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
124 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
125 #define T2_BYTE_CNT (T2_SUB_CMD+2)
128 #define SMB_PROTO 0x424d53ff
129 #define SMB_HANDLE_NULL 0xffffffff
130 #define SMB_MAX_BUFFERSIZE (62*1024) // cannot be larger than u16 (65536)
131 #define SMB_MAX_TRANSMIT_SIZE 7236
132 #define SMB_DEF_READOFFSET 59
134 #define SMB_CONNHANDLES_MAX 8
135 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
137 #define SMB_OBJTYPE_HANDLE 7
138 #define SMB_CHECK_HANDLE(hndl) \
140 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
144 /* NBT Session Service Packet Type Codes
147 #define SESS_MSG 0x00
148 #define SESS_REQ 0x81
149 #define SESS_POS_RESP 0x82
150 #define SESS_NEG_RESP 0x83
151 #define SESS_RETARGET 0x84
152 #define SESS_KEEPALIVE 0x85
164 typedef struct _nbtsmb
166 u8 msg
; /*** NBT Message ***/
167 u8 flags
; /*** Not much here really ***/
168 u16 length
; /*** Length, excluding NBT ***/
169 u8 smb
[SMB_MAX_TRANSMIT_SIZE
]; /*** Wii Actual is 7240 bytes ***/
173 * Session Information
175 typedef struct _smbsession
194 typedef struct _smbhandle
202 struct sockaddr_in server_addr
;
208 static u32 smb_dialectcnt
= 1;
209 static BOOL smb_inited
= FALSE
;
210 static lwp_objinfo smb_handle_objects
;
211 static lwp_queue smb_filehandle_queue
;
212 static struct _smbfile smb_filehandles
[SMB_FILEHANDLES_MAX
];
213 static const char *smb_dialects
[] = {"NT LM 0.12",NULL
};
215 extern void ntlm_smb_nt_encrypt(const char *passwd
, const u8
* challenge
, u8
* answer
);
218 * SMB Endian aware supporting functions
220 * SMB always uses Intel Little-Endian values, so htons etc are
221 * of little or no use :) ... Thanks M$
224 /*** get unsigned char ***/
225 static __inline__ u8
getUChar(u8
*buffer
,u32 offset
)
227 return (u8
)buffer
[offset
];
230 /*** set unsigned char ***/
231 static __inline__
void setUChar(u8
*buffer
,u32 offset
,u8 value
)
233 buffer
[offset
] = value
;
236 /*** get signed short ***/
237 static __inline__ s16
getShort(u8
*buffer
,u32 offset
)
239 return (s16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
242 /*** get unsigned short ***/
243 static __inline__ u16
getUShort(u8
*buffer
,u32 offset
)
245 return (u16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
248 /*** set unsigned short ***/
249 static __inline__
void setUShort(u8
*buffer
,u32 offset
,u16 value
)
251 buffer
[offset
] = (value
&0xff);
252 buffer
[offset
+1] = ((value
&0xff00)>>8);
255 /*** get unsigned int ***/
256 static __inline__ u32
getUInt(u8
*buffer
,u32 offset
)
258 return (u32
)((buffer
[offset
+3]<<24)|(buffer
[offset
+2]<<16)|(buffer
[offset
+1]<<8)|buffer
[offset
]);
261 /*** set unsigned int ***/
262 static __inline__
void setUInt(u8
*buffer
,u32 offset
,u32 value
)
264 buffer
[offset
] = (value
&0xff);
265 buffer
[offset
+1] = ((value
&0xff00)>>8);
266 buffer
[offset
+2] = ((value
&0xff0000)>>16);
267 buffer
[offset
+3] = ((value
&0xff000000)>>24);
270 /*** get unsigned long long ***/
271 static __inline__ u64
getULongLong(u8
*buffer
,u32 offset
)
273 return (u64
)(getUInt(buffer
, offset
) | (u64
)getUInt(buffer
, offset
+4) << 32);
276 static __inline__ SMBHANDLE
* __smb_handle_open(SMBCONN smbhndl
)
281 SMB_CHECK_HANDLE(smbhndl
);
283 _CPU_ISR_Disable(level
);
284 handle
= (SMBHANDLE
*)__lwp_objmgr_getnoprotection(&smb_handle_objects
,LWP_OBJMASKID(smbhndl
));
285 _CPU_ISR_Restore(level
);
290 static __inline__
void __smb_handle_free(SMBHANDLE
*handle
)
294 _CPU_ISR_Disable(level
);
295 __lwp_objmgr_close(&smb_handle_objects
,&handle
->object
);
296 __lwp_objmgr_free(&smb_handle_objects
,&handle
->object
);
297 _CPU_ISR_Restore(level
);
300 static void __smb_init()
303 __lwp_objmgr_initinfo(&smb_handle_objects
,SMB_CONNHANDLES_MAX
,sizeof(SMBHANDLE
));
304 __lwp_queue_initialize(&smb_filehandle_queue
,smb_filehandles
,SMB_FILEHANDLES_MAX
,sizeof(struct _smbfile
));
307 static SMBHANDLE
* __smb_allocate_handle()
312 _CPU_ISR_Disable(level
);
313 handle
= (SMBHANDLE
*)__lwp_objmgr_allocate(&smb_handle_objects
);
317 handle
->server_name
= NULL
;
318 handle
->share_name
= NULL
;
319 handle
->sck_server
= INVALID_SOCKET
;
320 handle
->conn_valid
= FALSE
;
321 __lwp_objmgr_open(&smb_handle_objects
,&handle
->object
);
323 _CPU_ISR_Restore(level
);
327 static void __smb_free_handle(SMBHANDLE
*handle
)
329 if(handle
->user
) free(handle
->user
);
330 if(handle
->pwd
) free(handle
->pwd
);
331 if(handle
->server_name
) free(handle
->server_name
);
332 if(handle
->share_name
) free(handle
->share_name
);
336 handle
->server_name
= NULL
;
337 handle
->share_name
= NULL
;
338 handle
->sck_server
= INVALID_SOCKET
;
340 __smb_handle_free(handle
);
343 static void MakeSMBHeader(u8 command
,u8 flags
,u16 flags2
,SMBHANDLE
*handle
)
345 u8
*ptr
= handle
->message
.smb
;
346 NBTSMB
*nbt
= &handle
->message
;
347 SMBSESSION
*sess
= &handle
->session
;
349 memset(nbt
,0,sizeof(NBTSMB
));
351 setUInt(ptr
,SMB_OFFSET_PROTO
,SMB_PROTO
);
352 setUChar(ptr
,SMB_OFFSET_CMD
,command
);
353 setUChar(ptr
,SMB_OFFSET_FLAGS
,flags
);
354 setUShort(ptr
,SMB_OFFSET_FLAGS2
,flags2
);
355 setUShort(ptr
,SMB_OFFSET_TID
,sess
->TID
);
356 setUShort(ptr
,SMB_OFFSET_PID
,sess
->PID
);
357 setUShort(ptr
,SMB_OFFSET_UID
,sess
->UID
);
358 setUShort(ptr
,SMB_OFFSET_MID
,sess
->MID
);
360 ptr
[SMB_HEADER_SIZE
] = 0;
366 static void MakeTRANS2Header(u8 subcommand
,SMBHANDLE
*handle
)
368 u8
*ptr
= handle
->message
.smb
;
369 SMBSESSION
*sess
= &handle
->session
;
371 setUChar(ptr
, T2_WORD_CNT
, 15);
372 setUShort(ptr
, T2_MAXPRM_CNT
, 10);
373 setUShort(ptr
, T2_MAXBUFFER
, sess
->MaxBuffer
);
374 setUChar(ptr
, T2_SSETUP_CNT
, 1);
375 setUShort(ptr
, T2_SUB_CMD
, subcommand
);
381 * blocking call with timeout
382 * will return when ALL data has been sent. Number of bytes sent is returned.
383 * OR timeout. Timeout will return -1
384 * OR network error. -ve value will be returned
386 static inline s32
smb_send(s32 s
,const void *data
,s32 size
)
391 t1
=ticks_to_millisecs(gettime());
394 ret
=net_send(s
,data
,len
,0);
397 t2
=ticks_to_millisecs(gettime());
398 if( (t2
- t1
) > RECV_TIMEOUT
)
400 return -1; /* timeout */
402 usleep(100); /* allow system to perform work. Stabilizes system */
407 return ret
; /* some error happened */
413 if(len
==0) return size
;
414 t1
=ticks_to_millisecs(gettime());
423 * blocking call with timeout
424 * will return when ANY data has been read from socket. Number of bytes read is returned.
425 * OR timeout. Timeout will return -1
426 * OR network error. -ve value will be returned
428 static s32
smb_recv(s32 s
,void *mem
,s32 len
)
433 t1
=ticks_to_millisecs(gettime());
436 ret
=net_recv(s
,mem
,len
,0);
437 if(ret
>=0) return ret
;
438 if(ret
!=-EAGAIN
) break;
439 t2
=ticks_to_millisecs(gettime());
440 if( (t2
- t1
) > RECV_TIMEOUT
)
445 usleep(100); /* allow system to perform work. Stabilizes system */
453 * Do very basic checking on the return SMB
454 * Read <readlen> bytes
455 * if <readlen>==0 then read a single SMB packet
456 * discard any NBT_KEEPALIVE_MSG packets along the way.
458 static s32
SMBCheck(u8 command
, s32 readlen
,SMBHANDLE
*handle
)
461 u8
*ptr
= handle
->message
.smb
;
462 NBTSMB
*nbt
= &handle
->message
;
464 u8 tempLength
= (readlen
==0);
466 /* if length is not specified,*/
469 /* read entire header if available. if not, just get whatever available.*/
470 readlen
= SMB_HEADER_SIZE
+4;
473 memset(nbt
,0,sizeof(NBTSMB
));
476 /*keep going till we get all the data we wanted*/
479 ret
=smb_recv(handle
->sck_server
, ptr2
+recvd
, readlen
-recvd
);
485 /* discard any and all keepalive packets */
486 while( (nbt
->msg
==NBT_KEEPALIVE_MSG
) && (recvd
>=KEEPALIVE_SIZE
) )
488 recvd
-=KEEPALIVE_SIZE
;
489 memmove(ptr2
, ptr2
+KEEPALIVE_SIZE
, recvd
);
491 /* obtain required length from NBT header if readlen==0*/
492 if(tempLength
&& recvd
>=KEEPALIVE_SIZE
)
494 /* get the length header */
495 if(nbt
->flags
!=0 || nbt
->length
>SMB_MAX_TRANSMIT_SIZE
)
497 /*length too big to be supported*/
498 return SMB_BAD_DATALEN
;
502 readlen
= nbt
->length
+KEEPALIVE_SIZE
;
508 /*** Do basic SMB Header checks ***/
509 ret
= getUInt(ptr
,SMB_OFFSET_PROTO
);
510 if(ret
!=SMB_PROTO
) return SMB_BAD_PROTOCOL
;
512 ret
= getUChar(ptr
, SMB_OFFSET_CMD
);
513 if(ret
!=command
) return SMB_BAD_COMMAND
;
515 ret
= getUInt(ptr
,SMB_OFFSET_NTSTATUS
);
516 if(ret
) return SMB_ERROR
;
524 * Setup the SMB session, including authentication with the
525 * magic 'NTLM Response'
527 static s32
SMB_SetupAndX(SMBHANDLE
*handle
)
532 u8
*ptr
= handle
->message
.smb
;
533 SMBSESSION
*sess
= &handle
->session
;
534 char pwd
[200], ntRespData
[24];
536 MakeSMBHeader(SMB_SETUP_ANDX
,0x08,0x01,handle
);
537 pos
= SMB_HEADER_SIZE
;
539 setUChar(ptr
,pos
,13);
540 pos
++; /*** Word Count ***/
541 setUChar(ptr
,pos
,0xff);
542 pos
++; /*** Next AndX ***/
543 pos
++; /*** Reserved ***/
544 pos
+= 2; /*** Next AndX Offset ***/
545 setUShort(ptr
,pos
,sess
->MaxBuffer
);
547 setUShort(ptr
,pos
,sess
->MaxMpx
);
549 setUShort(ptr
,pos
,sess
->MaxVCS
);
551 setUInt(ptr
,pos
,sess
->sKey
);
553 setUShort(ptr
,pos
,0); /*** Password length (case-insensitive) ***/
555 setUShort(ptr
,pos
,24); /*** Password length (case-sensitive) ***/
557 pos
+= 4; /*** Reserved ***/
558 pos
+= 4; /*** Capabilities ***/
560 pos
+= 2; /*** Byte count ***/
562 /*** The magic 'NTLM Response' ***/
563 strcpy(pwd
, handle
->pwd
);
564 if (sess
->challengeUsed
)
565 ntlm_smb_nt_encrypt((const char *) pwd
, (const u8
*) sess
->challenge
, (u8
*) ntRespData
);
567 /*** Build information ***/
568 memcpy(&ptr
[pos
],ntRespData
,24);
572 strcpy(pwd
, handle
->user
);
573 for(i
=0;i
<strlen(pwd
);i
++) pwd
[i
] = toupper(pwd
[i
]);
574 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
575 pos
+= strlen(pwd
)+1;
577 /*** Primary Domain ***/
578 if(handle
->user
[0]=='\0') sess
->p_domain
[0] = '\0';
579 memcpy(&ptr
[pos
],sess
->p_domain
,strlen((const char*)sess
->p_domain
));
580 pos
+= strlen((const char*)sess
->p_domain
)+1;
583 strcpy(pwd
,"Unix (libOGC)");
584 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
585 pos
+= strlen(pwd
)+1;
587 /*** Native LAN Manager ***/
588 strcpy(pwd
,"Nintendo Wii");
589 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
590 pos
+= strlen (pwd
)+1;
592 /*** Update byte count ***/
593 setUShort(ptr
,bcpos
,((pos
-bcpos
)-2));
595 handle
->message
.msg
= NBT_SESSISON_MSG
;
596 handle
->message
.length
= htons (pos
);
599 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
600 if(ret
<=0) return SMB_ERROR
;
602 if((ret
=SMBCheck(SMB_SETUP_ANDX
,0,handle
))==SMB_SUCCESS
) {
603 /*** Collect UID ***/
604 sess
->UID
= getUShort(handle
->message
.smb
,SMB_OFFSET_UID
);
613 * Finally, net_connect to the remote share
615 static s32
SMB_TreeAndX(SMBHANDLE
*handle
)
619 u8
*ptr
= handle
->message
.smb
;
620 SMBSESSION
*sess
= &handle
->session
;
622 MakeSMBHeader(SMB_TREEC_ANDX
,0x08,0x01,handle
);
623 pos
= SMB_HEADER_SIZE
;
626 pos
++; /*** Word Count ***/
627 setUChar(ptr
,pos
,0xff);
628 pos
++; /*** Next AndX ***/
629 pos
++; /*** Reserved ***/
630 pos
+= 2; /*** Next AndX Offset ***/
631 pos
+= 2; /*** Flags ***/
632 setUShort(ptr
,pos
,1);
633 pos
+= 2; /*** Password Length ***/
636 pos
++; /*** NULL Password ***/
638 /*** Build server share path ***/
639 strcpy ((char*)path
, "\\\\");
640 strcat ((char*)path
, handle
->server_name
);
641 strcat ((char*)path
, "\\");
642 strcat ((char*)path
, handle
->share_name
);
643 for(ret
=0;ret
<strlen((const char*)path
);ret
++) path
[ret
] = toupper(path
[ret
]);
645 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
646 pos
+= strlen((const char*)path
)+1;
649 strcpy((char*)path
,"?????");
650 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
651 pos
+= strlen((const char*)path
)+1;
653 /*** Update byte count ***/
654 setUShort(ptr
,bcpos
,(pos
-bcpos
)-2);
656 handle
->message
.msg
= NBT_SESSISON_MSG
;
657 handle
->message
.length
= htons (pos
);
660 ret
= smb_send(handle
->sck_server
,(char *)&handle
->message
,pos
);
661 if(ret
<=0) return SMB_ERROR
;
663 if((ret
=SMBCheck(SMB_TREEC_ANDX
,0,handle
))==SMB_SUCCESS
) {
664 /*** Collect Tree ID ***/
665 sess
->TID
= getUShort(handle
->message
.smb
,SMB_OFFSET_TID
);
672 * SMB_NegotiateProtocol
674 * The only protocol we admit to is 'NT LM 0.12'
676 static s32
SMB_NegotiateProtocol(const char *dialects
[],int dialectc
,SMBHANDLE
*handle
)
686 if(!handle
|| !dialects
|| dialectc
<=0)
689 /*** Clear session variables ***/
690 sess
= &handle
->session
;
691 memset(sess
,0,sizeof(SMBSESSION
));
695 MakeSMBHeader(SMB_NEG_PROTOCOL
,0x08,0x01,handle
);
697 pos
= SMB_HEADER_SIZE
+3;
698 ptr
= handle
->message
.smb
;
699 for(i
=0,bcnt
=0;i
<dialectc
;i
++) {
700 len
= strlen(dialects
[i
])+1;
702 memcpy(&ptr
[pos
],dialects
[i
],len
);
706 /*** Update byte count ***/
707 setUShort(ptr
,(SMB_HEADER_SIZE
+1),bcnt
);
709 /*** Set NBT information ***/
710 handle
->message
.msg
= NBT_SESSISON_MSG
;
711 handle
->message
.length
= htons(pos
);
714 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
715 if(ret
<=0) return SMB_ERROR
;
717 /*** Check response ***/
718 if((ret
=SMBCheck(SMB_NEG_PROTOCOL
,0,handle
))==SMB_SUCCESS
)
720 pos
= SMB_HEADER_SIZE
;
721 ptr
= handle
->message
.smb
;
723 /*** Collect information ***/
724 if(getUChar(ptr
,pos
)!=17) return SMB_PROTO_FAIL
; // UCHAR WordCount; Count of parameter words = 17
727 if(getUShort(ptr
,pos
)!=0) return SMB_PROTO_FAIL
; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
730 if(getUChar(ptr
,pos
)!=3)
732 // user level security
736 // share level security
740 sess
->MaxMpx
= getUShort(ptr
, pos
); //USHORT MaxMpxCount; Max pending outstanding requests
743 sess
->MaxVCS
= getUShort(ptr
, pos
); //USHORT MaxNumberVcs; Max VCs between client and server
746 serverMaxBuffer
= getUInt(ptr
, pos
); //ULONG MaxBufferSize; Max transmit buffer size
747 if(serverMaxBuffer
>SMB_MAX_TRANSMIT_SIZE
)
748 sess
->MaxBuffer
= SMB_MAX_TRANSMIT_SIZE
;
750 sess
->MaxBuffer
= serverMaxBuffer
;
753 pos
+= 4; //ULONG MaxRawSize; Maximum raw buffer size
754 sess
->sKey
= getUInt(ptr
,pos
); pos
+= 4;
755 pos
+= 4; //ULONG Capabilities; Server capabilities
756 pos
+= 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
757 pos
+= 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
758 sess
->timeOffset
= getShort(ptr
,pos
) * 600000000LL; pos
+= 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
760 //UCHAR EncryptionKeyLength - 0 or 8
761 if(getUChar(ptr
,pos
)!=8)
763 if (getUChar(ptr
,pos
)!=0)
765 return SMB_BAD_KEYLEN
;
769 // Challenge key not used
770 sess
->challengeUsed
= false;
775 sess
->challengeUsed
= true;
779 bytecount
= getUShort(ptr
,pos
);
781 if (sess
->challengeUsed
)
783 /*** Copy challenge key ***/
785 memcpy(&sess
->challenge
,&ptr
[pos
],8);
788 /*** Primary domain ***/
791 while(ptr
[pos
+j
]!=0) {
792 sess
->p_domain
[i
] = ptr
[pos
+j
];
796 sess
->p_domain
[i
] = '\0';
804 static s32
do_netconnect(SMBHANDLE
*handle
)
812 /*** Create the global net_socket ***/
813 sock
= net_socket(AF_INET
, SOCK_STREAM
, IPPROTO_IP
);
814 if(sock
==INVALID_SOCKET
) return -1;
816 /*** Switch off Nagle, ON TCP_NODELAY ***/
818 ret
= net_setsockopt(sock
,IPPROTO_TCP
,TCP_NODELAY
,&nodelay
,sizeof(nodelay
));
820 //create non blocking socket
821 flags
= net_fcntl(sock
, F_GETFL
, 0);
822 flags
|= IOS_O_NONBLOCK
;
823 ret
=net_fcntl(sock
, F_SETFL
, flags
);
825 t1
=ticks_to_millisecs(gettime());
828 ret
= net_connect(sock
,(struct sockaddr
*)&handle
->server_addr
,sizeof(handle
->server_addr
));
829 t2
=ticks_to_millisecs(gettime());
831 if(t2
-t1
> 6000) break; // 6 secs to try to connect to handle->server_addr
840 handle
->sck_server
= sock
;
844 static s32
do_smbconnect(SMBHANDLE
*handle
)
848 ret
= SMB_NegotiateProtocol(smb_dialects
,smb_dialectcnt
,handle
);
851 net_close(handle
->sck_server
);
855 ret
= SMB_SetupAndX(handle
);
858 net_close(handle
->sck_server
);
862 ret
= SMB_TreeAndX(handle
);
865 net_close(handle
->sck_server
);
869 handle
->conn_valid
= TRUE
;
873 /****************************************************************************
874 * Create an NBT SESSION REQUEST message.
875 ****************************************************************************/
876 static int MakeSessReq(unsigned char *bufr
, unsigned char *Called
, unsigned char *Calling
)
882 bufr
[3] = 68; // 2x34 bytes in length.
884 // Copy the Called and Calling names into the buffer.
885 (void) memcpy(&bufr
[4], Called
, 34);
886 (void) memcpy(&bufr
[38], Calling
, 34);
888 // Return the total message length.
892 static unsigned char *L1_Encode(unsigned char *dst
, const unsigned char *name
,
893 const unsigned char pad
, const unsigned char sfx
)
899 while (('\0' != name
[i
]) && (i
< 15))
901 k
= toupper(name
[i
++]);
902 dst
[j
++] = 'A' + ((k
& 0xF0) >> 4);
903 dst
[j
++] = 'A' + (k
& 0x0F);
906 i
= 'A' + ((pad
& 0xF0) >> 4);
907 k
= 'A' + (pad
& 0x0F);
914 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
915 dst
[31] = 'A' + (sfx
& 0x0F);
921 static int L2_Encode(unsigned char *dst
, const unsigned char *name
,
922 const unsigned char pad
, const unsigned char sfx
,
923 const unsigned char *scope
)
929 if (NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
939 for (i
= 0, j
= (lenpos
+ 1); ('.' != scope
[i
]) && ('\0'
940 != scope
[i
]); i
++, j
++)
941 dst
[j
] = toupper(scope
[i
]);
943 dst
[lenpos
] = (unsigned char) i
;
946 } while ('.' == *(scope
++));
954 /****************************************************************************
955 * Send an NBT SESSION REQUEST over the TCP connection, then wait for a reply.
956 ****************************************************************************/
957 static s32
SMB_RequestNBTSession(SMBHANDLE
*handle
)
959 unsigned char Called
[34];
960 unsigned char Calling
[34];
961 unsigned char bufr
[128];
964 L2_Encode(Called
, (const unsigned char*) "*SMBSERVER", 0x20, 0x20,
965 (const unsigned char*) "");
966 L2_Encode(Calling
, (const unsigned char*) "SMBCLIENT", 0x20, 0x00,
967 (const unsigned char*) "");
969 // Create the NBT Session Request message.
970 result
= MakeSessReq(bufr
, Called
, Calling
);
972 //Send the NBT Session Request message.
973 result
= smb_send(handle
->sck_server
, bufr
, result
);
976 // Error sending Session Request message
980 // Now wait for and handle the reply (2 seconds).
981 result
= smb_recv(handle
->sck_server
, bufr
, 128);
984 // Timeout waiting for NBT Session Response
991 // Positive Session Response
995 // Negative Session Response
999 // Retarget Session Response
1003 // Unexpected Session Response
1008 /****************************************************************************
1009 * Primary setup, logon and connection all in one :)
1010 ****************************************************************************/
1011 s32
SMB_Connect(SMBCONN
*smbhndl
, const char *user
, const char *password
, const char *share
, const char *server
)
1018 if(!user
|| !password
|| !share
|| !server
||
1019 strlen(user
) > 20 || strlen(password
) > 14 ||
1020 strlen(share
) > 80 || strlen(server
) > 80)
1022 return SMB_BAD_LOGINDATA
;
1025 *smbhndl
= SMB_HANDLE_NULL
;
1027 if(smb_inited
==FALSE
)
1030 _CPU_ISR_Disable(level
);
1032 _CPU_ISR_Restore(level
);
1035 handle
= __smb_allocate_handle();
1036 if(!handle
) return SMB_ERROR
;
1038 handle
->user
= strdup(user
);
1039 handle
->pwd
= strdup(password
);
1040 handle
->server_name
= strdup(server
);
1041 handle
->share_name
= strdup(share
);
1042 handle
->server_addr
.sin_family
= AF_INET
;
1043 handle
->server_addr
.sin_port
= htons(445);
1045 if(strlen(server
) < 16 && inet_aton(server
, &val
))
1047 handle
->server_addr
.sin_addr
.s_addr
= val
.s_addr
;
1049 else // might be a hostname
1051 hp
= net_gethostbyname(server
);
1052 if (!hp
|| !(hp
->h_addrtype
== PF_INET
))
1053 ret
= SMB_BAD_LOGINDATA
;
1055 memcpy((char *)&handle
->server_addr
.sin_addr
.s_addr
, hp
->h_addr_list
[0], hp
->h_length
);
1060 ret
= do_netconnect(handle
);
1061 if(ret
==0) ret
= do_smbconnect(handle
);
1066 handle
->server_addr
.sin_port
= htons(139);
1067 ret
= do_netconnect(handle
);
1068 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1069 if(ret
==0) ret
= do_smbconnect(handle
);
1074 __smb_free_handle(handle
);
1079 *smbhndl
=(SMBCONN
)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE
)|LWP_OBJMASKID(handle
->object
.id
));
1084 /****************************************************************************
1087 * Probably NEVER called on GameCube, but here for completeness
1088 ****************************************************************************/
1089 void SMB_Close(SMBCONN smbhndl
)
1093 handle
= __smb_handle_open(smbhndl
);
1096 if(handle
->sck_server
!=INVALID_SOCKET
) net_close(handle
->sck_server
);
1097 __smb_free_handle(handle
);
1100 s32
SMB_Reconnect(SMBCONN
*_smbhndl
, BOOL test_conn
)
1102 s32 ret
= SMB_SUCCESS
;
1103 SMBCONN smbhndl
= *_smbhndl
;
1104 SMBHANDLE
*handle
= __smb_handle_open(smbhndl
);
1106 return SMB_ERROR
; // we have no handle, so we can't reconnect
1108 if(handle
->conn_valid
&& test_conn
)
1111 if(SMB_PathInfo("\\", &dentry
, smbhndl
)==SMB_SUCCESS
) return SMB_SUCCESS
; // no need to reconnect
1112 handle
->conn_valid
= FALSE
; // else connection is invalid
1115 if(!handle
->conn_valid
)
1117 // shut down connection
1118 if(handle
->sck_server
!=INVALID_SOCKET
)
1119 net_close(handle
->sck_server
);
1122 ret
= do_netconnect(handle
);
1123 if(handle
->server_addr
.sin_port
== htons(139))
1124 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1125 if(ret
==0) ret
= do_smbconnect(handle
);
1130 SMBFILE
SMB_OpenFile(const char *filename
, u16 access
, u16 creation
,SMBCONN smbhndl
)
1135 struct _smbfile
*fid
= NULL
;
1139 if(filename
== NULL
)
1142 if(SMB_Reconnect(&smbhndl
,TRUE
)!=SMB_SUCCESS
) return NULL
;
1144 handle
= __smb_handle_open(smbhndl
);
1145 if(!handle
) return NULL
;
1147 MakeSMBHeader(SMB_OPEN_ANDX
,0x08,0x01,handle
);
1149 pos
= SMB_HEADER_SIZE
;
1150 ptr
= handle
->message
.smb
;
1151 setUChar(ptr
, pos
, 15);
1152 pos
++; /*** Word Count ***/
1153 setUChar(ptr
, pos
, 0xff);
1154 pos
++; /*** Next AndX ***/
1155 pos
+= 3; /*** Next AndX Offset ***/
1157 pos
+= 2; /*** Flags ***/
1158 setUShort(ptr
, pos
, access
);
1159 pos
+= 2; /*** Access mode ***/
1160 setUShort(ptr
, pos
, 0x6);
1161 pos
+= 2; /*** Type of file ***/
1162 pos
+= 2; /*** Attributes ***/
1163 pos
+= 4; /*** File time - don't care - let server decide ***/
1164 setUShort(ptr
, pos
, creation
);
1165 pos
+= 2; /*** Creation flags ***/
1166 pos
+= 4; /*** Allocation size ***/
1167 pos
+= 8; /*** Reserved ***/
1168 pos
+= 2; /*** Byte Count ***/
1171 if (filename
[0] != '\\') {
1172 strcpy(realfile
, "\\");
1173 strcat(realfile
,filename
);
1175 strcpy(realfile
,filename
);
1177 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1178 pos
+= strlen(realfile
)+1;
1180 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1182 handle
->message
.msg
= NBT_SESSISON_MSG
;
1183 handle
->message
.length
= htons(pos
);
1186 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1187 if(ret
<0) goto failed
;
1189 if(SMBCheck(SMB_OPEN_ANDX
,0,handle
)==SMB_SUCCESS
) {
1190 /*** Check file handle ***/
1191 fid
= (struct _smbfile
*)__lwp_queue_get(&smb_filehandle_queue
);
1193 fid
->conn
= smbhndl
;
1194 fid
->sfid
= getUShort(handle
->message
.smb
,(SMB_HEADER_SIZE
+5));
1197 return (SMBFILE
)fid
;
1200 handle
->conn_valid
= FALSE
;
1207 void SMB_CloseFile(SMBFILE sfid
)
1212 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1216 handle
= __smb_handle_open(fid
->conn
);
1219 MakeSMBHeader(SMB_CLOSE
,0x08,0x01,handle
);
1221 pos
= SMB_HEADER_SIZE
;
1222 ptr
= handle
->message
.smb
;
1223 setUChar(ptr
, pos
, 3);
1224 pos
++; /** Word Count **/
1225 setUShort(ptr
, pos
, fid
->sfid
);
1227 setUInt(ptr
, pos
, 0xffffffff);
1228 pos
+= 4; /*** Last Write ***/
1229 pos
+= 2; /*** Byte Count ***/
1231 handle
->message
.msg
= NBT_SESSISON_MSG
;
1232 handle
->message
.length
= htons(pos
);
1235 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1236 if(ret
<0) handle
->conn_valid
= FALSE
;
1237 else SMBCheck(SMB_CLOSE
,0,handle
);
1238 __lwp_queue_append(&smb_filehandle_queue
,&fid
->node
);
1244 s32
SMB_ReadFile(char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1250 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1254 // Check for invalid size
1255 if(size
== 0 || size
> SMB_MAX_BUFFERSIZE
) return 0;
1257 handle
= __smb_handle_open(fid
->conn
);
1258 if(!handle
) return 0;
1260 MakeSMBHeader(SMB_READ_ANDX
,0x08,0x01,handle
);
1262 pos
= SMB_HEADER_SIZE
;
1263 ptr
= handle
->message
.smb
;
1264 setUChar(ptr
, pos
, 10);
1265 pos
++; /*** Word count ***/
1266 setUChar(ptr
, pos
, 0xff);
1268 pos
+= 3; /*** Reserved, Next AndX Offset ***/
1269 setUShort(ptr
, pos
, fid
->sfid
);
1270 pos
+= 2; /*** FID ***/
1271 setUInt(ptr
, pos
, offset
);
1272 pos
+= 4; /*** Offset ***/
1274 setUShort(ptr
, pos
, size
& 0xffff);
1276 setUShort(ptr
, pos
, size
& 0xffff);
1278 setUInt(ptr
, pos
, 0);
1280 pos
+= 2; /*** Remaining ***/
1281 pos
+= 2; /*** Byte count ***/
1283 handle
->message
.msg
= NBT_SESSISON_MSG
;
1284 handle
->message
.length
= htons(pos
);
1287 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
, pos
);
1288 if(ret
<0) goto failed
;
1290 /*** SMBCheck should now only read up to the end of a standard header ***/
1291 if((ret
=SMBCheck(SMB_READ_ANDX
,(SMB_HEADER_SIZE
+27+4),handle
))==SMB_SUCCESS
) {
1292 ptr
= handle
->message
.smb
;
1293 /*** Retrieve data length for this packet ***/
1294 length
= getUShort(ptr
,(SMB_HEADER_SIZE
+11));
1295 /*** Retrieve offset to data ***/
1296 ofs
= getUShort(ptr
,(SMB_HEADER_SIZE
+13));
1298 /*** Default offset, with no padding is 59, so grab any outstanding padding ***/
1299 while(ofs
>SMB_DEF_READOFFSET
) {
1301 ret
= smb_recv(handle
->sck_server
,pad
,(ofs
-SMB_DEF_READOFFSET
));
1302 if(ret
<0) return ret
;
1306 /*** Finally, go grab the data ***/
1310 while ((ret
=smb_recv(handle
->sck_server
,&dest
[ofs
],length
-ofs
))!=0) {
1311 if(ret
<0) return ret
;
1314 if (ofs
>=length
) break;
1322 handle
->conn_valid
= FALSE
;
1329 s32
SMB_WriteFile(const char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1336 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1340 handle
= __smb_handle_open(fid
->conn
);
1341 if(!handle
) return SMB_ERROR
;
1343 MakeSMBHeader(SMB_WRITE_ANDX
,0x08,0x01,handle
);
1345 pos
= SMB_HEADER_SIZE
;
1346 ptr
= handle
->message
.smb
;
1347 setUChar(ptr
, pos
, 12);
1348 pos
++; /*** Word Count ***/
1349 setUChar(ptr
, pos
, 0xff);
1350 pos
+= 2; /*** Next AndX ***/
1351 pos
+= 2; /*** Next AndX Offset ***/
1353 setUShort(ptr
, pos
, fid
->sfid
);
1355 setUInt(ptr
, pos
, offset
);
1357 pos
+= 4; /*** Reserved ***/
1358 pos
+= 2; /*** Write Mode ***/
1359 pos
+= 2; /*** Remaining ***/
1361 blocks64
= size
>> 16;
1363 setUShort(ptr
, pos
, blocks64
);
1364 pos
+= 2; /*** Length High ***/
1365 setUShort(ptr
, pos
, size
& 0xffff);
1366 pos
+= 2; /*** Length Low ***/
1367 setUShort(ptr
, pos
, 59);
1368 pos
+= 2; /*** Data Offset ***/
1369 setUShort(ptr
, pos
, size
& 0xffff);
1370 pos
+= 2; /*** Data Byte Count ***/
1372 handle
->message
.msg
= NBT_SESSISON_MSG
;
1373 handle
->message
.length
= htons(pos
+size
);
1377 if((copy_len
+pos
)>SMB_MAX_TRANSMIT_SIZE
) copy_len
= (SMB_MAX_TRANSMIT_SIZE
-pos
);
1379 memcpy(&ptr
[pos
],src
,copy_len
);
1386 /*** Send Header Information ***/
1387 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1388 if(ret
<0) goto failed
;
1391 /*** Send the data ***/
1392 ret
= smb_send(handle
->sck_server
,src
,size
);
1393 if(ret
<0) goto failed
;
1397 if(SMBCheck(SMB_WRITE_ANDX
,0,handle
)==SMB_SUCCESS
) {
1398 ptr
= handle
->message
.smb
;
1399 ret
= getUShort(ptr
,(SMB_HEADER_SIZE
+5));
1405 handle
->conn_valid
= FALSE
;
1412 s32
SMB_PathInfo(const char *filename
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1421 if(filename
== NULL
)
1424 handle
= __smb_handle_open(smbhndl
);
1425 if (!handle
) return SMB_ERROR
;
1427 MakeSMBHeader(SMB_TRANS2
, 0x08, 0x01, handle
);
1428 MakeTRANS2Header(SMB_QUERY_PATH_INFO
, handle
);
1430 bpos
= pos
= (T2_BYTE_CNT
+ 2);
1431 pos
+= 3; /*** Padding ***/
1432 ptr
= handle
->message
.smb
;
1433 setUShort(ptr
, pos
, SMB_QUERY_FILE_ALL_INFO
);
1436 setUInt(ptr
, pos
, 0);
1437 pos
+= 4; /*** reserved ***/
1439 if (filename
[0] != '\\') {
1440 strcpy(realfile
, "\\");
1441 strcat(realfile
, filename
);
1443 strcpy(realfile
, filename
);
1445 memcpy(&ptr
[pos
], realfile
, strlen(realfile
));
1446 pos
+= strlen(realfile
) + 1; /*** Include padding ***/
1448 /*** Update counts ***/
1449 setUShort(ptr
, T2_PRM_CNT
, (7 + strlen(realfile
)));
1450 setUShort(ptr
, T2_SPRM_CNT
, (7 + strlen(realfile
)));
1451 setUShort(ptr
, T2_SPRM_OFS
, 68);
1452 setUShort(ptr
, T2_SDATA_OFS
, (75 + strlen(realfile
)));
1453 setUShort(ptr
, T2_BYTE_CNT
, (pos
- bpos
));
1455 handle
->message
.msg
= NBT_SESSISON_MSG
;
1456 handle
->message
.length
= htons(pos
);
1459 ret
= smb_send(handle
->sck_server
, (char*) &handle
->message
, pos
);
1460 if(ret
<0) goto failed
;
1463 if (SMBCheck(SMB_TRANS2
, 0, handle
) == SMB_SUCCESS
) {
1465 ptr
= handle
->message
.smb
;
1466 /*** Get parameter offset ***/
1467 pos
= getUShort(ptr
, (SMB_HEADER_SIZE
+ 9));
1468 pos
+= 4; // padding
1469 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1470 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1471 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1472 pos
+= 8; // ULONGLONG - change time
1473 sdir
->attributes
= getUInt(ptr
,pos
); pos
+= 4; // ULONG - file attributes
1474 pos
+= 4; // padding
1475 pos
+= 8; // ULONGLONG - allocated file size
1476 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8; // ULONGLONG - file size
1477 pos
+= 4; // ULONG NumberOfLinks;
1478 pos
+= 2; // UCHAR DeletePending;
1479 pos
+= 2; // UCHAR Directory;
1480 pos
+= 2; // USHORT Pad2; // for alignment only
1481 pos
+= 4; // ULONG EaSize;
1482 pos
+= 4; // ULONG FileNameLength;
1484 strcpy(sdir
->name
,realfile
);
1491 handle
->conn_valid
= FALSE
;
1498 * Uses TRANS2 to support long filenames
1500 s32
SMB_FindFirst(const char *filename
, unsigned short flags
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1509 if(filename
== NULL
)
1512 if(SMB_Reconnect(&smbhndl
,TRUE
)!=SMB_SUCCESS
) return SMB_ERROR
;
1514 handle
= __smb_handle_open(smbhndl
);
1515 if(!handle
) return SMB_ERROR
;
1517 sess
= &handle
->session
;
1518 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1519 MakeTRANS2Header(SMB_FIND_FIRST2
,handle
);
1521 bpos
= pos
= (T2_BYTE_CNT
+2);
1522 pos
+= 3; /*** Padding ***/
1523 ptr
= handle
->message
.smb
;
1524 setUShort(ptr
, pos
, flags
);
1525 pos
+= 2; /*** Flags ***/
1526 setUShort(ptr
, pos
, 1);
1527 pos
+= 2; /*** Count ***/
1528 setUShort(ptr
, pos
, 6);
1529 pos
+= 2; /*** Internal Flags ***/
1530 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1531 pos
+= 2; /*** Level of Interest ***/
1532 pos
+= 4; /*** Storage Type == 0 ***/
1533 memcpy(&ptr
[pos
], filename
, strlen(filename
));
1534 pos
+= strlen(filename
)+1; /*** Include padding ***/
1536 /*** Update counts ***/
1537 setUShort(ptr
, T2_PRM_CNT
, (13+strlen(filename
)));
1538 setUShort(ptr
, T2_SPRM_CNT
, (13+strlen(filename
)));
1539 setUShort(ptr
, T2_SPRM_OFS
, 68);
1540 setUShort(ptr
, T2_SDATA_OFS
,(81+strlen(filename
)));
1541 setUShort(ptr
, T2_BYTE_CNT
,(pos
-bpos
));
1543 handle
->message
.msg
= NBT_SESSISON_MSG
;
1544 handle
->message
.length
= htons(pos
);
1547 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1548 if(ret
<0) goto failed
;
1554 if(SMBCheck(SMB_TRANS2
,0,handle
)==SMB_SUCCESS
) {
1555 ptr
= handle
->message
.smb
;
1556 /*** Get parameter offset ***/
1557 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1558 sess
->sid
= getUShort(ptr
, pos
); pos
+= 2;
1559 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
1560 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
1561 pos
+= 2; // USHORT EaErrorOffset;
1562 pos
+= 2; // USHORT LastNameOffset;
1563 pos
+= 2; // padding?
1567 pos
+= 4; // ULONG NextEntryOffset;
1568 pos
+= 4; // ULONG FileIndex;
1569 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1570 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1571 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1572 pos
+= 8; // ULONGLONG - change time low
1573 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
1575 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
1577 strcpy(sdir
->name
, (const char*)&ptr
[pos
]);
1585 handle
->conn_valid
= FALSE
;
1592 s32
SMB_FindNext(SMBDIRENTRY
*sdir
,SMBCONN smbhndl
)
1601 handle
= __smb_handle_open(smbhndl
);
1602 if(!handle
) return SMB_ERROR
;
1604 sess
= &handle
->session
;
1605 if(sess
->eos
|| sess
->sid
==0) return SMB_ERROR
;
1607 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1608 MakeTRANS2Header(SMB_FIND_NEXT2
,handle
);
1610 bpos
= pos
= (T2_BYTE_CNT
+2);
1611 pos
+= 3; /*** Padding ***/
1612 ptr
= handle
->message
.smb
;
1613 setUShort(ptr
, pos
, sess
->sid
);
1614 pos
+= 2; /*** Search ID ***/
1615 setUShort(ptr
, pos
, 1);
1616 pos
+= 2; /*** Count ***/
1617 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1618 pos
+= 2; /*** Level of Interest ***/
1619 pos
+= 4; /*** Storage Type == 0 ***/
1620 setUShort(ptr
, pos
, 12);
1621 pos
+=2; /*** Search flags ***/
1624 /*** Update counts ***/
1625 setUShort(ptr
, T2_PRM_CNT
, 13);
1626 setUShort(ptr
, T2_SPRM_CNT
, 13);
1627 setUShort(ptr
, T2_SPRM_OFS
, 68);
1628 setUShort(ptr
, T2_SDATA_OFS
, 81);
1629 setUShort(ptr
, T2_BYTE_CNT
, (pos
-bpos
));
1631 handle
->message
.msg
= NBT_SESSISON_MSG
;
1632 handle
->message
.length
= htons(pos
);
1635 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1636 if(ret
<0) goto failed
;
1639 if (SMBCheck(SMB_TRANS2
,0,handle
)==SMB_SUCCESS
) {
1640 ptr
= handle
->message
.smb
;
1641 /*** Get parameter offset ***/
1642 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1643 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
1644 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
1645 pos
+= 2; // USHORT EaErrorOffset;
1646 pos
+= 2; // USHORT LastNameOffset;
1650 pos
+= 4; // ULONG NextEntryOffset;
1651 pos
+= 4; // ULONG FileIndex;
1652 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1653 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1654 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1655 pos
+= 8; // ULONGLONG - change time low
1656 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
1658 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
1660 strcpy (sdir
->name
, (const char*)&ptr
[pos
]);
1668 handle
->conn_valid
= FALSE
;
1675 s32
SMB_FindClose(SMBCONN smbhndl
)
1683 handle
= __smb_handle_open(smbhndl
);
1684 if(!handle
) return SMB_ERROR
;
1686 sess
= &handle
->session
;
1687 if(sess
->sid
==0) return SMB_ERROR
;
1689 MakeSMBHeader(SMB_FIND_CLOSE2
,0x08,0x01,handle
);
1691 pos
= SMB_HEADER_SIZE
;
1692 ptr
= handle
->message
.smb
;
1693 setUChar(ptr
, pos
, 1);
1694 pos
++; /*** Word Count ***/
1695 setUShort(ptr
, pos
, sess
->sid
);
1697 pos
+= 2; /*** Byte Count ***/
1699 handle
->message
.msg
= NBT_SESSISON_MSG
;
1700 handle
->message
.length
= htons(pos
);
1703 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1704 if(ret
<0) goto failed
;
1706 ret
= SMBCheck(SMB_FIND_CLOSE2
,0,handle
);
1710 handle
->conn_valid
= FALSE
;