Begin to make wine an SMB client.
diff --git a/files/Makefile.in b/files/Makefile.in
index 92127b7..483914c 100644
--- a/files/Makefile.in
+++ b/files/Makefile.in
@@ -12,6 +12,7 @@
drive.c \
file.c \
profile.c \
+ smb.c \
tape.c
all: $(MODULE).o
diff --git a/files/file.c b/files/file.c
index fb28a9a..0bc85ac 100644
--- a/files/file.c
+++ b/files/file.c
@@ -56,6 +56,8 @@
#include "heap.h"
#include "msdos.h"
#include "wincon.h"
+
+#include "smb.h"
#include "wine/debug.h"
#include "wine/server.h"
@@ -74,6 +76,7 @@
static HANDLE dos_handles[DOS_TABLE_SIZE];
+extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name);
/***********************************************************************
* FILE_ConvertOFMode
@@ -480,9 +483,8 @@
/* If the name still starts with '\\', it's a UNC name. */
if (!strncmp(filename, "\\\\", 2))
{
- FIXME("UNC name (%s) not supported.\n", filename );
- SetLastError( ERROR_PATH_NOT_FOUND );
- return INVALID_HANDLE_VALUE;
+ ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
+ goto done;
}
/* If the name contains a DOS wild card (* or ?), do no create a file */
@@ -1531,6 +1533,8 @@
}
switch(type)
{
+ case FD_TYPE_SMB:
+ return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
case FD_TYPE_CONSOLE:
return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
diff --git a/files/smb.c b/files/smb.c
new file mode 100644
index 0000000..2264d35
--- /dev/null
+++ b/files/smb.c
@@ -0,0 +1,1069 @@
+/*
+ * Copyright (C) 2002 Mike McCormack
+ *
+ * CIFS implementation for WINE
+ *
+ * This is a WINE's implementation of the Common Internet File System
+ *
+ * for specification see:
+ *
+ * http://www.codefx.com/CIFS_Explained.htm
+ * http://www.ubiqx.org/cifs/rfc-draft/rfc1002.html
+ * http://www.ubiqx.org/cifs/rfc-draft/draft-leach-cifs-v1-spec-02.html
+ * http://ubiqx.org/cifs/
+ * http://www.samba.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "winerror.h"
+#include "windef.h"
+#include "winbase.h"
+#include "file.h"
+#include "heap.h"
+
+#include "smb.h"
+
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(file);
+
+#define MAX_HOST_NAME 15
+#define NB_TIMEOUT 10000
+
+USHORT SMB_MultiplexId = 0;
+
+static int netbios_name(const char *p, unsigned char *buffer)
+{
+ char ch;
+ int i,len=0;
+
+ buffer[len++]=' ';
+ for(i=0; i<=MAX_HOST_NAME; i++)
+ {
+ if(i<MAX_HOST_NAME)
+ {
+ if(*p)
+ ch = *p++&0xdf; /* add character from hostname */
+ else
+ ch = ' '; /* add padding */
+ }
+ else
+ ch = 0; /* add terminator */
+ buffer[len++] = ((ch&0xf0) >> 4) + 'A';
+ buffer[len++] = (ch&0x0f) + 'A';
+ }
+ buffer[len++] = 0; /* add second terminator */
+ return len;
+}
+
+static DWORD NB_NameReq(LPCSTR host, unsigned char *buffer, int len)
+{
+ int trn = 1234,i=0;
+
+ NBR_ADDWORD(&buffer[i],trn); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0110); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0001); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0000); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0000); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0000); i+=2;
+
+ i += netbios_name(host,&buffer[i]);
+
+ NBR_ADDWORD(&buffer[i],0x0020); i+=2;
+ NBR_ADDWORD(&buffer[i],0x0001); i+=2;
+
+ ERR("packet is %d bytes in length\n",i);
+
+ {
+ int j;
+ for(j=0; j<i; j++)
+ printf("%02x%c",buffer[j],(((j+1)%16)&&((j+1)!=j))?' ':'\n');
+ }
+
+ return i;
+}
+
+/* unc = \\hostname\share\file... */
+static BOOL UNC_SplitName(LPSTR unc, LPSTR *hostname, LPSTR *share, LPSTR *file)
+{
+ char *p;
+
+ ERR("%s\n",unc);
+
+ p = strchr(unc,'\\');
+ if(!p)
+ return FALSE;
+ p = strchr(p+1,'\\');
+ if(!p)
+ return FALSE;
+ *hostname=++p;
+
+ p = strchr(p,'\\');
+ if(!p)
+ return FALSE;
+ *p=0;
+ *share = ++p;
+
+ p = strchr(p,'\\');
+ if(!p)
+ return FALSE;
+ *p=0;
+ *file = ++p;
+
+ return TRUE;
+}
+
+static BOOL NB_Lookup(LPCSTR host, struct sockaddr_in *addr)
+{
+ int fd,on=1,r,len;
+ struct pollfd fds;
+ struct sockaddr_in sin;
+ unsigned char buffer[256];
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(fd<0)
+ return FALSE;
+
+ r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof on);
+ if(r<0)
+ return FALSE;
+
+ if(0==inet_aton("255.255.255.255", (struct in_addr *)&sin.sin_addr.s_addr))
+ {
+ FIXME("Error getting bcast address\n");
+ return FALSE;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(137);
+
+ len = NB_NameReq(host,buffer,sizeof buffer);
+ if(len<=0)
+ return FALSE;
+
+ r = sendto(fd, buffer, len, 0, &sin, sizeof sin);
+ if(r<0)
+ {
+ FIXME("Error sending packet\n");
+ return FALSE;
+ }
+
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+
+ r = poll(&fds,1,NB_TIMEOUT);
+ if(r!=1)
+ return FALSE;
+
+ close(fd);
+ TRACE("Got response!\n");
+ return TRUE;
+}
+
+#define NB_FIRST 0x40
+
+#define NB_HDRSIZE 4
+
+#define NB_SESSION_MSG 0x00
+#define NB_SESSION_REQ 0x81
+
+/* RFC 1002, section 4.3.2 */
+static BOOL NB_SessionReq(int fd, char *called, char *calling)
+{
+ unsigned char buffer[0x100];
+ int len = 0,r;
+ struct pollfd fds;
+
+ ERR("called %s, calling %s\n",called,calling);
+
+ buffer[0] = NB_SESSION_REQ;
+ buffer[1] = NB_FIRST;
+
+ netbios_name(called, &buffer[NB_HDRSIZE]);
+ len += 34;
+ netbios_name(calling, &buffer[NB_HDRSIZE+len]);
+ len += 34;
+
+ NBR_ADDWORD(&buffer[2],len);
+
+ /* for(i=0; i<(len+NB_HDRSIZE); i++)
+ DPRINTF("%02X%c",buffer[i],(((i+1)!=(len+4))&&((i+1)%16))?' ':'\n'); */
+
+ r = write(fd,buffer,len+4);
+ if(r<0)
+ {
+ ERR("Write failed\n");
+ return FALSE;
+ }
+
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+
+ r = poll(&fds,1,NB_TIMEOUT);
+ if(r!=1)
+ {
+ ERR("Poll failed\n");
+ return FALSE;
+ }
+
+ r = read(fd, buffer, NB_HDRSIZE);
+ if((r!=NB_HDRSIZE) || (buffer[0]!=0x82))
+ {
+ ERR("Received %d bytes\n",r);
+ ERR("%02x %02x %02x %02x\n", buffer[0],buffer[1],buffer[2],buffer[3]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL NB_SendData(int fd, unsigned char *data, int size)
+{
+ unsigned char buffer[NB_HDRSIZE];
+ int r;
+
+ /* CHECK: is it always OK to do this in two writes? */
+ /* perhaps use scatter gather sendmsg instead? */
+
+ buffer[0] = NB_SESSION_MSG;
+ buffer[1] = NB_FIRST;
+ NBR_ADDWORD(&buffer[2],size);
+
+ r = write(fd, buffer, NB_HDRSIZE);
+ if(r!=NB_HDRSIZE)
+ return FALSE;
+
+ r = write(fd, data, size);
+ if(r!=size)
+ {
+ ERR("write failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL NB_RecvData(int fd, unsigned char *data, int *outlen)
+{
+ int r,len;
+ unsigned char buffer[NB_HDRSIZE];
+
+ r = read(fd, buffer, NB_HDRSIZE);
+ if((r!=NB_HDRSIZE) || (buffer[0]!=NB_SESSION_MSG))
+ {
+ ERR("Received %d bytes\n",r);
+ return FALSE;
+ }
+
+ len = NBR_GETWORD(&buffer[2]);
+ r = read(fd, data, len);
+ if(len!=r)
+ {
+ ERR("Received %d bytes\n",r);
+ return FALSE;
+ }
+ *outlen = len;
+
+ return TRUE;
+}
+
+static BOOL NB_Transaction(int fd, unsigned char *buffer, int len, int *outlen)
+{
+ int r,i;
+ struct pollfd fds;
+
+ DPRINTF("Sending request:\n");
+ for(i=0; i<len; i++)
+ DPRINTF("%02X%c",buffer[i],(((i+1)!=len)&&((i+1)%16))?' ':'\n');
+
+ if(!NB_SendData(fd,buffer,len))
+ return FALSE;
+
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+
+ r = poll(&fds,1,NB_TIMEOUT);
+ if(r!=1)
+ {
+ ERR("Poll failed\n");
+ return FALSE;
+ }
+
+ if(!NB_RecvData(fd, buffer, outlen))
+ return FALSE;
+
+ len = *outlen;
+ DPRINTF("Got response:\n");
+ for(i=0; i<len; i++)
+ DPRINTF("%02X%c",buffer[i],(((i+1)!=len)&&((i+1)%16))?' ':'\n');
+
+ return TRUE;
+}
+
+#define SMB_ADDHEADER(b,l) { b[(l)++]=0xff; b[(l)++]='S'; b[(l)++]='M'; b[(l)++]='B'; }
+#define SMB_ADDERRINFO(b,l) { b[(l)++]=0; b[(l)++]=0; b[(l)++]=0; b[(l)++]=0; }
+#define SMB_ADDPADSIG(b,l) { memset(&b[l],0,12); l+=12; }
+
+#define SMB_ERRCLASS 5
+#define SMB_ERRCODE 7
+#define SMB_TREEID 24
+#define SMB_PROCID 26
+#define SMB_USERID 28
+#define SMB_PLEXID 30
+#define SMB_PCOUNT 32
+#define SMB_HDRSIZE 33
+
+static DWORD SMB_GetError(unsigned char *buffer)
+{
+ if(buffer[SMB_ERRCLASS]==0)
+ return STATUS_SUCCESS;
+ /* FIXME: return propper error codes */
+ return STATUS_INVALID_PARAMETER;
+}
+
+static int SMB_Header(unsigned char *buffer, unsigned char command, USHORT tree_id, USHORT user_id)
+{
+ int len = 0;
+ DWORD id;
+
+ /* 0 */
+ SMB_ADDHEADER(buffer,len);
+
+ /* 4 */
+ buffer[len++] = command;
+
+ /* 5 */
+ SMB_ADDERRINFO(buffer,len)
+
+ /* 9 */
+ buffer[len++] = 0x00; /* flags */
+ SMB_ADDWORD(&buffer[len],1); len += 2; /* flags2 */
+
+ /* 12 */
+ SMB_ADDPADSIG(buffer,len)
+
+ /* 24 */
+ SMB_ADDWORD(&buffer[len],tree_id); len += 2; /* treeid */
+ id = GetCurrentThreadId();
+ SMB_ADDWORD(&buffer[len],id); len += 2; /* process id */
+ SMB_ADDWORD(&buffer[len],user_id); len += 2; /* user id */
+ SMB_ADDWORD(&buffer[len],SMB_MultiplexId); len += 2; /* multiplex id */
+ SMB_MultiplexId++;
+
+ return len;
+}
+
+static const char *SMB_ProtocolDialect = "NT LM 0.12";
+/* = "Windows for Workgroups 3.1a"; */
+
+/* FIXME: support multiple SMB dialects */
+static BOOL SMB_NegotiateProtocol(int fd, USHORT *dialect)
+{
+ unsigned char buffer[0x100];
+ int buflen,len = 0;
+
+ ERR("\n");
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_NEGOTIATE, 0, 0);
+
+ /* parameters */
+ buffer[len++] = 0; /* no parameters */
+
+ /* command buffer */
+ buflen = strlen(SMB_ProtocolDialect)+2; /* include type and nul byte */
+ SMB_ADDWORD(&buffer[len],buflen); len += 2;
+
+ buffer[len] = 0x02;
+ strcpy(&buffer[len+1],SMB_ProtocolDialect);
+ len += buflen;
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ {
+ ERR("Failed\n");
+ return FALSE;
+ }
+
+ /* FIXME: check response */
+ if(SMB_GetError(buffer))
+ {
+ ERR("returned error\n");
+ return FALSE;
+ }
+
+ *dialect = 0;
+
+ return TRUE;
+}
+
+#define SMB_PARAM_COUNT(buffer) ((buffer)[SMB_PCOUNT])
+#define SMB_PARAM(buffer,n) SMB_GETWORD(&(buffer)[SMB_HDRSIZE+2*(n)])
+#define SMB_BUFFER_COUNT(buffer) SMB_GETWORD(buffer+SMB_HDRSIZE+2*SMB_PARAM_COUNT(buffer))
+#define SMB_BUFFER(buffer,n) ((buffer)[SMB_HDRSIZE + 2*SMB_PARAM_COUNT(buffer) + 2 + (n) ])
+
+static BOOL SMB_SessionSetup(int fd, USHORT *userid)
+{
+ unsigned char buffer[0x100];
+ int len = 0;
+ int i,pcount,bcount;
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_SESSION_SETUP_ANDX, 0, 0);
+
+ buffer[len++] = 0; /* no parameters? */
+
+ buffer[len++] = 0xff; /* AndXCommand: secondary request */
+ buffer[len++] = 0x00; /* AndXReserved */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */
+ SMB_ADDWORD(&buffer[len],0x400); len += 2; /* MaxBufferSize */
+ SMB_ADDWORD(&buffer[len],1); len += 2; /* MaxMpxCount */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* VcNumber */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* SessionKey */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* SessionKey */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* Password length */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* Reserved */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* Reserved */
+
+ /* FIXME: add name and password here */
+ buffer[len++] = 0; /* number of bytes in password */
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ return FALSE;
+
+ if(SMB_GetError(buffer))
+ return FALSE;
+
+ pcount = SMB_PARAM_COUNT(buffer);
+
+ if( (SMB_HDRSIZE+pcount*2) > len )
+ {
+ ERR("Bad parameter count %d\n",pcount);
+ return FALSE;
+ }
+
+ DPRINTF("SMB_COM_SESSION_SETUP response, %d args: ",pcount);
+ for(i=0; i<pcount; i++)
+ DPRINTF("%04x ",SMB_PARAM(buffer,i));
+ DPRINTF("\n");
+
+ bcount = SMB_BUFFER_COUNT(buffer);
+ if( (SMB_HDRSIZE+pcount*2+2+bcount) > len )
+ {
+ ERR("parameter count %x, buffer count %x, len %x\n",pcount,bcount,len);
+ return FALSE;
+ }
+
+ DPRINTF("response buffer %d bytes: ",bcount);
+ for(i=0; i<bcount; i++)
+ {
+ unsigned char ch = SMB_BUFFER(buffer,i);
+ DPRINTF("%c", isprint(ch)?ch:' ');
+ }
+ DPRINTF("\n");
+
+ *userid = SMB_GETWORD(&buffer[SMB_USERID]);
+
+ return TRUE;
+}
+
+static BOOL SMB_TreeConnect(int fd, USHORT user_id, LPCSTR share_name, USHORT *treeid)
+{
+ unsigned char buffer[0x100];
+ int len = 0,slen;
+
+ ERR("%s\n",share_name);
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_TREE_CONNECT, 0, user_id);
+
+ buffer[len++] = 4; /* parameters */
+
+ buffer[len++] = 0xff; /* AndXCommand: secondary request */
+ buffer[len++] = 0x00; /* AndXReserved */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* Flags */
+ SMB_ADDWORD(&buffer[len],1); len += 2; /* Password length */
+
+ /* SMB command buffer */
+ SMB_ADDWORD(&buffer[len],3); len += 2; /* command buffer len */
+ buffer[len++] = 0; /* null terminated password */
+
+ slen = strlen(share_name);
+ if(slen<(sizeof buffer-len))
+ strcpy(&buffer[len], share_name);
+ else
+ return FALSE;
+ len += slen+1;
+
+ /* name of the service */
+ buffer[len++] = 0;
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ return FALSE;
+
+ if(SMB_GetError(buffer))
+ return FALSE;
+
+ *treeid = SMB_GETWORD(&buffer[SMB_TREEID]);
+
+ ERR("OK, treeid = %04x\n", *treeid);
+
+ return TRUE;
+}
+
+static BOOL SMB_NtCreateOpen(int fd, USHORT tree_id, USHORT user_id, USHORT dialect,
+ LPCSTR filename, DWORD access, DWORD sharing,
+ LPSECURITY_ATTRIBUTES sa, DWORD creation,
+ DWORD attributes, HANDLE template, USHORT *file_id )
+{
+ unsigned char buffer[0x100];
+ int len = 0,slen;
+
+ ERR("%s\n",filename);
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_NT_CREATE_ANDX, tree_id, user_id);
+
+ /* 0 */
+ buffer[len++] = 24; /* parameters */
+
+ buffer[len++] = 0xff; /* AndXCommand: secondary request */
+ buffer[len++] = 0x00; /* AndXReserved */
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */
+
+ buffer[len++] = 0; /* reserved */
+ slen = strlen(filename);
+ SMB_ADDWORD(&buffer[len],slen); len += 2; /* name length */
+
+ /* 0x08 */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* flags */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* root directory fid */
+ /* 0x10 */
+ SMB_ADDDWORD(&buffer[len],access); len += 4; /* access */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* allocation size */
+ /* 0x18 */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* root directory fid */
+
+ /* 0x1c */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* initial allocation */
+ SMB_ADDDWORD(&buffer[len],0); len += 4;
+
+ /* 0x24 */
+ SMB_ADDDWORD(&buffer[len],attributes); len += 4; /* ExtFileAttributes*/
+
+ /* 0x28 */
+ SMB_ADDDWORD(&buffer[len],sharing); len += 4; /* ShareAccess */
+
+ /* 0x2c */
+ ERR("creation = %08lx\n",creation);
+ SMB_ADDDWORD(&buffer[len],creation); len += 4; /* CreateDisposition */
+
+ /* 0x30 */
+ SMB_ADDDWORD(&buffer[len],creation); len += 4; /* CreateOptions */
+
+ /* 0x34 */
+ SMB_ADDDWORD(&buffer[len],0); len += 4; /* Impersonation */
+
+ /* 0x38 */
+ buffer[len++] = 0; /* security flags */
+
+ /* 0x39 */
+ SMB_ADDWORD(&buffer[len],slen); len += 2; /* size of buffer */
+
+ if(slen<(sizeof buffer-len))
+ strcpy(&buffer[len], filename);
+ else
+ return FALSE;
+ len += slen+1;
+
+ /* name of the file */
+ buffer[len++] = 0;
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ return FALSE;
+
+ if(SMB_GetError(buffer))
+ return FALSE;
+
+ ERR("OK\n");
+
+ /* FIXME */
+ /* *file_id = SMB_GETWORD(&buffer[xxx]); */
+ *file_id = 0;
+ return FALSE;
+
+ return TRUE;
+}
+
+static USHORT SMB_GetMode(DWORD access, DWORD sharing)
+{
+ USHORT mode=0;
+
+ switch(access&(GENERIC_READ|GENERIC_WRITE))
+ {
+ case GENERIC_READ:
+ mode |= OF_READ;
+ break;
+ case GENERIC_WRITE:
+ mode |= OF_WRITE;
+ break;
+ case (GENERIC_READ|GENERIC_WRITE):
+ mode |= OF_READWRITE;
+ break;
+ }
+
+ switch(sharing&(FILE_SHARE_READ|FILE_SHARE_WRITE))
+ {
+ case (FILE_SHARE_READ|FILE_SHARE_WRITE):
+ mode |= OF_SHARE_DENY_NONE;
+ break;
+ case FILE_SHARE_READ:
+ mode |= OF_SHARE_DENY_WRITE;
+ break;
+ case FILE_SHARE_WRITE:
+ mode |= OF_SHARE_DENY_READ;
+ break;
+ default:
+ mode |= OF_SHARE_EXCLUSIVE;
+ break;
+ }
+
+ return mode;
+}
+
+/* inverse of FILE_ConvertOFMode */
+static BOOL SMB_OpenAndX(int fd, USHORT tree_id, USHORT user_id, USHORT dialect,
+ LPCSTR filename, DWORD access, DWORD sharing,
+ DWORD creation, DWORD attributes, USHORT *file_id )
+{
+ unsigned char buffer[0x100];
+ int len = 0;
+ USHORT mode;
+
+ ERR("%s\n",filename);
+
+ mode = SMB_GetMode(access,sharing);
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_OPEN_ANDX, tree_id, user_id);
+
+ /* 0 */
+ buffer[len++] = 15; /* parameters */
+ buffer[len++] = 0xff; /* AndXCommand: secondary request */
+ buffer[len++] = 0x00; /* AndXReserved */
+ SMB_ADDWORD(buffer+len,0); len+=2; /* AndXOffset */
+ SMB_ADDWORD(buffer+len,0); len+=2; /* Flags */
+ SMB_ADDWORD(buffer+len,mode); len+=2; /* desired access */
+ SMB_ADDWORD(buffer+len,0); len+=2; /* search attributes */
+ SMB_ADDWORD(buffer+len,0); len+=2;
+
+ /*FIXME: complete */
+ return FALSE;
+}
+
+static BOOL SMB_Open(int fd, USHORT tree_id, USHORT user_id, USHORT dialect,
+ LPCSTR filename, DWORD access, DWORD sharing,
+ DWORD creation, DWORD attributes, USHORT *file_id )
+{
+ unsigned char buffer[0x100];
+ int len = 0,slen,pcount,i;
+ USHORT mode = SMB_GetMode(access,sharing);
+
+ ERR("%s\n",filename);
+
+ memset(buffer,0,sizeof buffer);
+
+ len = SMB_Header(buffer, SMB_COM_OPEN, tree_id, user_id);
+
+ /* 0 */
+ buffer[len++] = 2; /* parameters */
+ SMB_ADDWORD(buffer+len,mode); len+=2;
+ SMB_ADDWORD(buffer+len,0); len+=2; /* search attributes */
+
+ slen = strlen(filename)+2; /* inc. nul and BufferFormat */
+ SMB_ADDWORD(buffer+len,slen); len+=2;
+
+ buffer[len] = 0x04; /* BufferFormat */
+ strcpy(&buffer[len+1],filename);
+ len += slen;
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ return FALSE;
+
+ if(SMB_GetError(buffer))
+ return FALSE;
+
+ pcount = SMB_PARAM_COUNT(buffer);
+
+ if( (SMB_HDRSIZE+pcount*2) > len )
+ {
+ ERR("Bad parameter count %d\n",pcount);
+ return FALSE;
+ }
+
+ ERR("response, %d args: ",pcount);
+ for(i=0; i<pcount; i++)
+ DPRINTF("%04x ",SMB_PARAM(buffer,i));
+ DPRINTF("\n");
+
+ *file_id = SMB_PARAM(buffer,0);
+
+ ERR("file_id = %04x\n",*file_id);
+
+ return TRUE;
+}
+
+static BOOL SMB_Read(int fd, USHORT tree_id, USHORT user_id, USHORT dialect, USHORT file_id, DWORD offset, LPVOID out, USHORT count, LPUSHORT read)
+{
+ unsigned char *buffer;
+ int len,buf_size,n,i;
+
+ ERR("user %04x tree %04x file %04x count %04x offset %08lx\n",
+ user_id, tree_id, file_id, count, offset);
+
+ buf_size = count+0x100;
+ buffer = (unsigned char *) HeapAlloc(GetProcessHeap(),0,buf_size);
+
+ memset(buffer,0,buf_size);
+
+ len = SMB_Header(buffer, SMB_COM_READ, tree_id, user_id);
+
+ buffer[len++] = 5;
+ SMB_ADDWORD(&buffer[len],file_id); len += 2;
+ SMB_ADDWORD(&buffer[len],count); len += 2;
+ SMB_ADDDWORD(&buffer[len],offset); len += 4;
+ SMB_ADDWORD(&buffer[len],0); len += 2; /* how many more bytes will be read */
+
+ buffer[len++] = 0;
+
+ if(!NB_Transaction(fd, buffer, len, &len))
+ {
+ HeapFree(GetProcessHeap(),0,buffer);
+ return FALSE;
+ }
+
+ if(SMB_GetError(buffer))
+ {
+ HeapFree(GetProcessHeap(),0,buffer);
+ return FALSE;
+ }
+
+ n = SMB_PARAM_COUNT(buffer);
+
+ if( (SMB_HDRSIZE+n*2) > len )
+ {
+ HeapFree(GetProcessHeap(),0,buffer);
+ ERR("Bad parameter count %d\n",n);
+ return FALSE;
+ }
+
+ ERR("response, %d args: ",n);
+ for(i=0; i<n; i++)
+ DPRINTF("%04x ",SMB_PARAM(buffer,i));
+ DPRINTF("\n");
+
+ n = SMB_PARAM(buffer,5) - 3;
+ if(n>count)
+ n=count;
+
+ memcpy( out, &SMB_BUFFER(buffer,3), n);
+
+ ERR("Read %d bytes\n",n);
+ *read = n;
+
+ HeapFree(GetProcessHeap(),0,buffer);
+
+ return TRUE;
+}
+
+static int SMB_LoginAndConnect(LPCSTR host, LPCSTR share, USHORT *tree_id, USHORT *user_id, USHORT *dialect)
+{
+ int fd=-1,r;
+ struct sockaddr_in sin;
+ LPSTR name=NULL;
+
+ ERR("host %s share %s\n",host,share);
+
+ /* FIXME: use various lookup methods */
+ if(0)
+ NB_Lookup(host,&sin);
+ else
+ {
+ if(0==inet_aton("127.0.0.1", (struct in_addr *)&sin.sin_addr.s_addr))
+ {
+ FIXME("Error getting localhost address\n");
+ SetLastError( ERROR_PATH_NOT_FOUND );
+ return INVALID_HANDLE_VALUE;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(139); /* netbios session */
+ }
+
+ fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(fd<0)
+ goto fail;
+
+ ERR("Connecting...\n");
+ r = connect(fd, &sin, sizeof sin);
+ if(r<0)
+ goto fail;
+
+ if(!NB_SessionReq(fd, "*SMBSERVER", "WINE"))
+ goto fail;
+
+ if(!SMB_NegotiateProtocol(fd, dialect))
+ goto fail;
+
+ if(!SMB_SessionSetup(fd, user_id))
+ goto fail;
+
+ name = HeapAlloc(GetProcessHeap(),0,strlen(host)+strlen(share)+5);
+ if(!name)
+ goto fail;
+ sprintf(name,"\\\\%s\\%s",host,share);
+ if(!SMB_TreeConnect(fd,*user_id,name,tree_id))
+ goto fail;
+ HeapFree(GetProcessHeap(),0,name);
+
+ return fd;
+
+fail:
+ if(name)
+ HeapFree(GetProcessHeap(),0,name);
+ ERR("Failed\n");
+ if(fd>=0)
+ close(fd);
+ return -1;
+}
+
+static HANDLE SMB_RegisterFile( int fd, USHORT tree_id, USHORT user_id, USHORT dialect, USHORT file_id)
+{
+ int r;
+ HANDLE ret;
+
+ wine_server_send_fd( fd );
+
+ SERVER_START_REQ( create_smb )
+ {
+ req->tree_id = tree_id;
+ req->user_id = user_id;
+ req->file_id = file_id;
+ req->dialect = 0;
+ req->fd = fd;
+ SetLastError(0);
+ r = wine_server_call_err( req );
+ ret = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ if(!r)
+ ERR("created wineserver smb object, handle = %04x\n",ret);
+ else
+ SetLastError( ERROR_PATH_NOT_FOUND );
+
+ return ret;
+}
+
+HANDLE WINAPI SMB_CreateFileA( LPCSTR uncname, DWORD access, DWORD sharing,
+ LPSECURITY_ATTRIBUTES sa, DWORD creation,
+ DWORD attributes, HANDLE template )
+{
+ int fd;
+ USHORT tree_id=0, user_id=0, dialect=0, file_id=0;
+ LPSTR name,host,share,file;
+ HANDLE handle = 0;
+
+ name = HeapAlloc(GetProcessHeap(),0,lstrlenA(uncname));
+ if(!name)
+ return -1;
+
+ lstrcpyA(name,uncname);
+
+ if( !UNC_SplitName(name, &host, &share, &file) )
+ {
+ HeapFree(GetProcessHeap(),0,name);
+ return handle;
+ }
+
+ ERR("server is %s, share is %s, file is %s\n", host, share, file);
+ fd = SMB_LoginAndConnect(host, share, &tree_id, &user_id, &dialect);
+ if(fd < 0)
+ {
+ HeapFree(GetProcessHeap(),0,name);
+ return handle;
+ }
+
+#if 0
+ if(!SMB_NtCreateOpen(fd, tree_id, user_id, dialect, file,
+ access, sharing, sa, creation, attributes, template, &file_id ))
+ {
+ close(fd);
+ HeapFree(GetProcessHeap(),0,name);
+ ERR("CreateOpen failed\n");
+ return handle;
+ }
+#endif
+ if(!SMB_Open(fd, tree_id, user_id, dialect, file,
+ access, sharing, creation, attributes, &file_id ))
+ {
+ close(fd);
+ HeapFree(GetProcessHeap(),0,name);
+ ERR("CreateOpen failed\n");
+ return handle;
+ }
+
+ HeapFree(GetProcessHeap(),0,name);
+
+ handle = SMB_RegisterFile(fd, tree_id, user_id, dialect, file_id);
+ if(!handle)
+ {
+ ERR("register failed\n");
+ close(fd);
+ }
+
+ return handle;
+}
+
+static BOOL SMB_GetSmbInfo(HANDLE hFile, USHORT *tree_id, USHORT *user_id, USHORT *dialect, USHORT *file_id, LPDWORD offset)
+{
+ int r;
+
+ SERVER_START_REQ( get_smb_info )
+ {
+ req->handle = hFile;
+ req->flags = 0;
+ SetLastError(0);
+ r = wine_server_call_err( req );
+ if(tree_id)
+ *tree_id = reply->tree_id;
+ if(user_id)
+ *user_id = reply->user_id;
+ if(file_id)
+ *file_id = reply->file_id;
+ if(dialect)
+ *dialect = reply->dialect;
+ if(offset)
+ *offset = reply->offset;
+ }
+ SERVER_END_REQ;
+
+ return !r;
+}
+
+static BOOL SMB_SetOffset(HANDLE hFile, DWORD offset)
+{
+ int r;
+
+ ERR("offset = %08lx\n",offset);
+
+ SERVER_START_REQ( get_smb_info )
+ {
+ req->handle = hFile;
+ req->flags = SMBINFO_SET_OFFSET;
+ req->offset = offset;
+ SetLastError(0);
+ r = wine_server_call_err( req );
+ /* if(offset)
+ *offset = reply->offset; */
+ }
+ SERVER_END_REQ;
+
+ return !r;
+}
+
+WINAPI BOOL SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped)
+{
+ int fd;
+ DWORD total, count, offset;
+ USHORT user_id, tree_id, dialect, file_id, read;
+ BOOL r=TRUE;
+
+ ERR("%04x %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead);
+
+ if(!SMB_GetSmbInfo(hFile, &tree_id, &user_id, &dialect, &file_id, &offset))
+ return FALSE;
+
+ fd = FILE_GetUnixHandle(hFile, GENERIC_READ);
+ if(fd<0)
+ return FALSE;
+
+ total = 0;
+ while(1)
+ {
+ count = bytesToRead - total;
+ if(count>0x400)
+ count = 0x400;
+ if(count==0)
+ break;
+ read = 0;
+ r = SMB_Read(fd, tree_id, user_id, dialect, file_id, offset, buffer, count, &read);
+ if(!r)
+ break;
+ if(!read)
+ break;
+ total += read;
+ buffer += read;
+ offset += read;
+ if(total>=bytesToRead)
+ break;
+ }
+ close(fd);
+
+ if(bytesRead)
+ *bytesRead = total;
+
+ if(!SMB_SetOffset(hFile, offset))
+ return FALSE;
+
+ return r;
+}
+
diff --git a/files/smb.h b/files/smb.h
new file mode 100644
index 0000000..268261f
--- /dev/null
+++ b/files/smb.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2002 Mike McCormack
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __INC_SMB__
+#define __INC_SMB__
+
+#define NBR_ADDWORD(p,word) { (p)[1] = (word & 0xff); (p)[0] = ((word)>>8)&0xff; }
+#define NBR_GETWORD(p) ( (((p)[0])<<8) | ((p)[1]) )
+
+#define SMB_ADDWORD(p,word) { (p)[0] = (word & 0xff); (p)[1] = ((word)>>8)&0xff; }
+#define SMB_GETWORD(p) ( (((p)[1])<<8) | ((p)[0]) )
+#define SMB_ADDDWORD(p,w) { (p)[3]=((w)>>24)&0xff; (p)[2]=((w)>>16)&0xff; (p)[1]=((w)>>8)&0xff; (p)[0]=(w)&0xff; }
+
+#define SMB_COM_CREATE_DIRECTORY 0x00
+#define SMB_COM_DELETE_DIRECTORY 0x01
+#define SMB_COM_OPEN 0x02
+#define SMB_COM_CREATE 0x03
+#define SMB_COM_CLOSE 0x04
+#define SMB_COM_FLUSH 0x05
+#define SMB_COM_DELETE 0x06
+#define SMB_COM_RENAME 0x07
+#define SMB_COM_QUERY_INFORMATION 0x08
+#define SMB_COM_SET_INFORMATION 0x09
+#define SMB_COM_READ 0x0A
+#define SMB_COM_WRITE 0x0B
+#define SMB_COM_LOCK_BYTE_RANGE 0x0C
+#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D
+#define SMB_COM_CREATE_TEMPORARY 0x0E
+#define SMB_COM_CREATE_NEW 0x0F
+#define SMB_COM_CHECK_DIRECTORY 0x10
+#define SMB_COM_PROCESS_EXIT 0x11
+#define SMB_COM_SEEK 0x12
+#define SMB_COM_LOCK_AND_READ 0x13
+#define SMB_COM_WRITE_AND_UNLOCK 0x14
+#define SMB_COM_READ_RAW 0x1A
+#define SMB_COM_READ_MPX 0x1B
+#define SMB_COM_READ_MPX_SECONDARY 0x1C
+#define SMB_COM_WRITE_RAW 0x1D
+#define SMB_COM_WRITE_MPX 0x1E
+#define SMB_COM_WRITE_COMPLETE 0x20
+#define SMB_COM_SET_INFORMATION2 0x22
+#define SMB_COM_QUERY_INFORMATION2 0x23
+#define SMB_COM_LOCKING_ANDX 0x24
+#define SMB_COM_TRANSACTION 0x25
+#define SMB_COM_TRANSACTION_SECONDARY 0x26
+#define SMB_COM_IOCTL 0x27
+#define SMB_COM_IOCTL_SECONDARY 0x28
+#define SMB_COM_COPY 0x29
+#define SMB_COM_MOVE 0x2A
+#define SMB_COM_ECHO 0x2B
+#define SMB_COM_WRITE_AND_CLOSE 0x2C
+#define SMB_COM_OPEN_ANDX 0x2D
+#define SMB_COM_READ_ANDX 0x2E
+#define SMB_COM_WRITE_ANDX 0x2F
+#define SMB_COM_CLOSE_AND_TREE_DISC 0x31
+#define SMB_COM_TRANSACTION2 0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_FIND_CLOSE2 0x34
+#define SMB_COM_FIND_NOTIFY_CLOSE 0x35
+#define SMB_COM_TREE_CONNECT 0x70
+#define SMB_COM_TREE_DISCONNECT 0x71
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SESSION_SETUP_ANDX 0x73
+#define SMB_COM_LOGOFF_ANDX 0x74
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+#define SMB_COM_QUERY_INFORMATION_DISK 0x80
+#define SMB_COM_SEARCH 0x81
+#define SMB_COM_FIND 0x82
+#define SMB_COM_FIND_UNIQUE 0x83
+#define SMB_COM_NT_TRANSACT 0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX 0xA2
+#define SMB_COM_NT_CANCEL 0xA4
+#define SMB_COM_OPEN_PRINT_FILE 0xC0
+#define SMB_COM_WRITE_PRINT_FILE 0xC1
+#define SMB_COM_CLOSE_PRINT_FILE 0xC2
+#define SMB_COM_GET_PRINT_QUEUE 0xC3
+
+extern WINAPI BOOL SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped);
+extern HANDLE WINAPI SMB_CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
+ LPSECURITY_ATTRIBUTES sa, DWORD creation,
+ DWORD attributes, HANDLE template );
+
+#endif /* __INC_SMB__ */
+
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 086de66..eb54534 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -736,7 +736,8 @@
{
FD_TYPE_INVALID,
FD_TYPE_DEFAULT,
- FD_TYPE_CONSOLE
+ FD_TYPE_CONSOLE,
+ FD_TYPE_SMB
};
#define FD_FLAG_OVERLAPPED 0x01
#define FD_FLAG_TIMEOUT 0x02
@@ -2321,6 +2322,41 @@
};
+struct create_smb_request
+{
+ struct request_header __header;
+ int fd;
+ unsigned int tree_id;
+ unsigned int user_id;
+ unsigned int file_id;
+ unsigned int dialect;
+};
+struct create_smb_reply
+{
+ struct reply_header __header;
+ handle_t handle;
+};
+
+
+struct get_smb_info_request
+{
+ struct request_header __header;
+ handle_t handle;
+ unsigned int flags;
+ unsigned int offset;
+};
+struct get_smb_info_reply
+{
+ struct reply_header __header;
+ unsigned int tree_id;
+ unsigned int user_id;
+ unsigned int dialect;
+ unsigned int file_id;
+ unsigned int offset;
+};
+#define SMBINFO_SET_OFFSET 0x01
+
+
struct create_window_request
{
@@ -2742,6 +2778,8 @@
REQ_wait_named_pipe,
REQ_disconnect_named_pipe,
REQ_get_named_pipe_info,
+ REQ_create_smb,
+ REQ_get_smb_info,
REQ_create_window,
REQ_link_window,
REQ_destroy_window,
@@ -2899,6 +2937,8 @@
struct wait_named_pipe_request wait_named_pipe_request;
struct disconnect_named_pipe_request disconnect_named_pipe_request;
struct get_named_pipe_info_request get_named_pipe_info_request;
+ struct create_smb_request create_smb_request;
+ struct get_smb_info_request get_smb_info_request;
struct create_window_request create_window_request;
struct link_window_request link_window_request;
struct destroy_window_request destroy_window_request;
@@ -3054,6 +3094,8 @@
struct wait_named_pipe_reply wait_named_pipe_reply;
struct disconnect_named_pipe_reply disconnect_named_pipe_reply;
struct get_named_pipe_info_reply get_named_pipe_info_reply;
+ struct create_smb_reply create_smb_reply;
+ struct get_smb_info_reply get_smb_info_reply;
struct create_window_reply create_window_reply;
struct link_window_reply link_window_reply;
struct destroy_window_reply destroy_window_reply;
@@ -3075,6 +3117,6 @@
struct get_window_properties_reply get_window_properties_reply;
};
-#define SERVER_PROTOCOL_VERSION 72
+#define SERVER_PROTOCOL_VERSION 73
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/Makefile.in b/server/Makefile.in
index 1bcfaaa..d62c3d9 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -31,6 +31,7 @@
select.c \
semaphore.c \
serial.c \
+ smb.c \
snapshot.c \
sock.c \
thread.c \
diff --git a/server/protocol.def b/server/protocol.def
index ad8292e..6cc06b5 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -563,7 +563,8 @@
{
FD_TYPE_INVALID,
FD_TYPE_DEFAULT,
- FD_TYPE_CONSOLE
+ FD_TYPE_CONSOLE,
+ FD_TYPE_SMB
};
#define FD_FLAG_OVERLAPPED 0x01
#define FD_FLAG_TIMEOUT 0x02
@@ -1634,6 +1635,31 @@
@END
+@REQ(create_smb)
+ int fd;
+ unsigned int tree_id;
+ unsigned int user_id;
+ unsigned int file_id;
+ unsigned int dialect;
+@REPLY
+ handle_t handle;
+@END
+
+
+@REQ(get_smb_info)
+ handle_t handle;
+ unsigned int flags;
+ unsigned int offset;
+@REPLY
+ unsigned int tree_id;
+ unsigned int user_id;
+ unsigned int dialect;
+ unsigned int file_id;
+ unsigned int offset;
+@END
+#define SMBINFO_SET_OFFSET 0x01
+
+
/* Create a window */
@REQ(create_window)
user_handle_t parent; /* parent window */
diff --git a/server/request.h b/server/request.h
index 07aed40..9a1350e 100644
--- a/server/request.h
+++ b/server/request.h
@@ -232,6 +232,8 @@
DECL_HANDLER(wait_named_pipe);
DECL_HANDLER(disconnect_named_pipe);
DECL_HANDLER(get_named_pipe_info);
+DECL_HANDLER(create_smb);
+DECL_HANDLER(get_smb_info);
DECL_HANDLER(create_window);
DECL_HANDLER(link_window);
DECL_HANDLER(destroy_window);
@@ -388,6 +390,8 @@
(req_handler)req_wait_named_pipe,
(req_handler)req_disconnect_named_pipe,
(req_handler)req_get_named_pipe_info,
+ (req_handler)req_create_smb,
+ (req_handler)req_get_smb_info,
(req_handler)req_create_window,
(req_handler)req_link_window,
(req_handler)req_destroy_window,
diff --git a/server/smb.c b/server/smb.c
new file mode 100644
index 0000000..ab0e84d
--- /dev/null
+++ b/server/smb.c
@@ -0,0 +1,192 @@
+/*
+ * Server-side smb network file management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2000, 2001, 2002 Mike McCormack
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FIXME: if you can't find something to fix,
+ * you're not looking hard enough
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#include "winerror.h"
+#include "winbase.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+
+static void smb_dump( struct object *obj, int verbose );
+static int smb_get_fd( struct object *obj );
+static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
+static int smb_get_poll_events( struct object *obj );
+static void destroy_smb(struct object *obj);
+
+struct smb
+{
+ struct object obj;
+ unsigned int tree_id;
+ unsigned int user_id;
+ unsigned int dialect;
+ unsigned int file_id;
+ unsigned int offset;
+};
+
+static const struct object_ops smb_ops =
+{
+ sizeof(struct smb), /* size */
+ smb_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ smb_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ smb_get_fd, /* get_fd */
+ no_flush, /* flush */
+ smb_get_info, /* get_file_info */
+ NULL, /* queue_async */
+ destroy_smb /* destroy */
+};
+
+static void destroy_smb( struct object *obj)
+{
+ /* struct smb *smb = (struct smb *)obj; */
+ assert( obj->ops == &smb_ops );
+}
+
+static void smb_dump( struct object *obj, int verbose )
+{
+ struct smb *smb = (struct smb *)obj;
+ assert( obj->ops == &smb_ops );
+ fprintf( stderr, "smb file with socket fd=%d \n", smb->obj.fd );
+}
+
+struct smb *get_smb_obj( struct process *process, handle_t handle, unsigned int access )
+{
+ return (struct smb *)get_handle_obj( process, handle, access, &smb_ops );
+}
+
+static int smb_get_poll_events( struct object *obj )
+{
+ /* struct smb *smb = (struct smb *)obj; */
+ int events = 0;
+ assert( obj->ops == &smb_ops );
+
+ events |= POLLIN;
+
+ /* fprintf(stderr,"poll events are %04x\n",events); */
+
+ return events;
+}
+
+static int smb_get_fd( struct object *obj )
+{
+ struct smb *smb = (struct smb *)obj;
+ assert( obj->ops == &smb_ops );
+ return smb->obj.fd;
+}
+
+static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
+{
+ /* struct smb *smb = (struct smb *) obj; */
+ assert( obj->ops == &smb_ops );
+
+ if (reply)
+ {
+ reply->type = FILE_TYPE_CHAR;
+ reply->attr = 0;
+ reply->access_time = 0;
+ reply->write_time = 0;
+ reply->size_high = 0;
+ reply->size_low = 0;
+ reply->links = 0;
+ reply->index_high = 0;
+ reply->index_low = 0;
+ reply->serial = 0;
+ }
+
+ *flags = 0;
+
+ return FD_TYPE_SMB;
+}
+
+/* create a smb */
+DECL_HANDLER(create_smb)
+{
+ struct smb *smb;
+ int fd;
+
+ reply->handle = 0;
+
+ fd = thread_get_inflight_fd( current, req->fd );
+ if (fd == -1)
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ return;
+ }
+
+ smb = alloc_object( &smb_ops, fd );
+ if (smb)
+ {
+ smb->tree_id = req->tree_id;
+ smb->user_id = req->user_id;
+ smb->dialect = req->dialect;
+ smb->file_id = req->file_id;
+ smb->offset = 0;
+ reply->handle = alloc_handle( current->process, smb, GENERIC_READ, 0);
+ release_object( smb );
+ }
+}
+
+DECL_HANDLER(get_smb_info)
+{
+ struct smb *smb;
+
+ if ((smb = get_smb_obj( current->process, req->handle, 0 )))
+ {
+ if(req->flags & SMBINFO_SET_OFFSET)
+ smb->offset = req->offset;
+
+ reply->tree_id = smb->tree_id;
+ reply->user_id = smb->user_id;
+ reply->dialect = smb->dialect;
+ reply->file_id = smb->file_id;
+ reply->offset = smb->offset;
+
+ release_object( smb );
+ }
+}
+
diff --git a/server/trace.c b/server/trace.c
index c4c2879..2e36fe4 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1843,6 +1843,36 @@
fprintf( stderr, " insize=%08x", req->insize );
}
+static void dump_create_smb_request( const struct create_smb_request *req )
+{
+ fprintf( stderr, " fd=%d,", req->fd );
+ fprintf( stderr, " tree_id=%08x,", req->tree_id );
+ fprintf( stderr, " user_id=%08x,", req->user_id );
+ fprintf( stderr, " file_id=%08x,", req->file_id );
+ fprintf( stderr, " dialect=%08x", req->dialect );
+}
+
+static void dump_create_smb_reply( const struct create_smb_reply *req )
+{
+ fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_smb_info_request( const struct get_smb_info_request *req )
+{
+ fprintf( stderr, " handle=%d,", req->handle );
+ fprintf( stderr, " flags=%08x,", req->flags );
+ fprintf( stderr, " offset=%08x", req->offset );
+}
+
+static void dump_get_smb_info_reply( const struct get_smb_info_reply *req )
+{
+ fprintf( stderr, " tree_id=%08x,", req->tree_id );
+ fprintf( stderr, " user_id=%08x,", req->user_id );
+ fprintf( stderr, " dialect=%08x,", req->dialect );
+ fprintf( stderr, " file_id=%08x,", req->file_id );
+ fprintf( stderr, " offset=%08x", req->offset );
+}
+
static void dump_create_window_request( const struct create_window_request *req )
{
fprintf( stderr, " parent=%08x,", req->parent );
@@ -2193,6 +2223,8 @@
(dump_func)dump_wait_named_pipe_request,
(dump_func)dump_disconnect_named_pipe_request,
(dump_func)dump_get_named_pipe_info_request,
+ (dump_func)dump_create_smb_request,
+ (dump_func)dump_get_smb_info_request,
(dump_func)dump_create_window_request,
(dump_func)dump_link_window_request,
(dump_func)dump_destroy_window_request,
@@ -2346,6 +2378,8 @@
(dump_func)0,
(dump_func)0,
(dump_func)dump_get_named_pipe_info_reply,
+ (dump_func)dump_create_smb_reply,
+ (dump_func)dump_get_smb_info_reply,
(dump_func)dump_create_window_reply,
(dump_func)dump_link_window_reply,
(dump_func)0,
@@ -2499,6 +2533,8 @@
"wait_named_pipe",
"disconnect_named_pipe",
"get_named_pipe_info",
+ "create_smb",
+ "get_smb_info",
"create_window",
"link_window",
"destroy_window",