1// BeServed.cpp : Defines the entry point for the application.
2//
3
4#include "stdafx.h"
5
6#include "beCompat.h"
7#include "betalk.h"
8#include "authentication.h"
9#include "readerWriter.h"
10#include "printing.h"
11#include "ubi_SplayTree.h"
12
13// Windows service-specific header files.
14#include "winsvc.h"
15#include "NTServApp.h"
16#include "myservice.h"
17
18#define BT_MAX_THREADS			100
19#define BT_MAX_RETRIES			3
20#define BT_MAX_FILE_SHARES		128
21#define BT_MAX_PRINTER_SHARES	16
22
23#define BT_THREAD_NAME		"BeServed Handler"
24#define BT_HOST_THREAD_NAME	"BeServed Host Publisher"
25
26#define PATH_ROOT			"/boot"
27#define PATH_DELIMITER		'/'
28
29#ifndef iswhite
30#define iswhite(c)			((c == ' ' || c == '\t'))
31#endif
32
33typedef struct
34{
35	unsigned int type;
36	unsigned int length;
37	char *data;
38} bt_arg_t;
39
40typedef struct btblock
41{
42	vnode_id vnid;
43	beos_off_t pos;
44	int32 len;
45	int32 count;
46	char *buffer;
47	struct btblock *next;
48	struct btblock *prev;
49} bt_block;
50
51typedef struct session
52{
53	int socket;
54	unsigned int client_s_addr;
55	HANDLE handlerID;
56
57	bool killed;
58
59	// The user that is connected.
60	char user[MAX_NAME_LENGTH + 1];
61
62	// What share did the client connect to?  And when?
63	int share;
64	int rights;
65	time_t logon;
66
67	// Buffered write support.
68	bt_block *rootBlock;
69	sem_id blockSem;
70
71	char ioBuffer[BT_MAX_IO_BUFFER + 1];
72	char attrBuffer[BT_MAX_ATTR_BUFFER + 1];
73	char pathBuffer[B_PATH_NAME_LENGTH];
74
75	struct session *next;
76} bt_session_t;
77
78typedef void (*bt_net_func)(bt_session_t *, unsigned int, int, bt_arg_t *);
79
80typedef struct dirCommand
81{
82	unsigned char command;
83	bt_net_func handler;
84	bool supported;
85	uint8 args;
86	uint32 argTypes[MAX_COMMAND_ARGS];
87} bt_command_t;
88
89typedef struct
90{
91	vnode_id vnid;
92	int shareId;
93	char unused[20];
94} bt_fdesc;
95
96typedef struct btnode
97{
98	ubi_trNode node;
99	vnode_id vnid;
100	char *name;
101	bool invalid;
102	struct btnode *parent;
103} bt_node;
104
105typedef struct fileShare
106{
107	char path[B_PATH_NAME_LENGTH];
108	char name[B_FILE_NAME_LENGTH];
109
110	bool used;
111	bool readOnly;
112
113	// What rights does each user have?
114	bt_user_rights *rights;
115	int security;
116
117	struct fileShare *next;
118} bt_fileShare_t;
119
120typedef struct mime_mapping
121{
122	char extension[7];
123	char *mimeType;
124	struct mime_mapping *next;
125} bt_mime_mapping;
126
127
128void BeServedStartup(CMyService *service);
129bool dateCheck();
130DWORD WINAPI btSendHost(LPVOID data);
131void getHostInfo(bt_hostinfo *info);
132int getSharedResources(char *buffer, int bufSize, bool shares, bool printers);
133int getHostUsers(char *buffer);
134void startService();
135void endService(int sig);
136void initMimeMap();
137void closeMimeMap();
138void closePrinters();
139void freeFileShares();
140void waitForThread(HANDLE threadId);
141
142void initShares();
143void initPrinters();
144void loadShares();
145void getFileShare(const char *buffer);
146void loadFolder(const char *path);
147void getShareProperty(const char *buffer);
148void getAuthenticate(const char *buffer);
149bool getAuthServerAddress(const char *name);
150void addUserRights(char *share, char *user, int rights, bool isGroup);
151void getGrant(const char *buffer);
152void getPrinter(const char *buffer);
153int getToken();
154
155int receiveRequest(bt_session_t *session);
156void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[]);
157void launchThread(int client, struct sockaddr_in *addr);
158int tooManyConnections(unsigned int _s_addr);
159void sendErrorToClient(int client, unsigned int xid, int error);
160void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command);
161DWORD WINAPI requestThread(LPVOID data);
162DWORD WINAPI printerThread(LPVOID data);
163
164void KillNode(ubi_trNodePtr node);
165int CompareVnidNodes(ubi_trItemPtr item, ubi_trNodePtr node);
166int CompareNameNodes(ubi_trItemPtr item, ubi_trNodePtr node);
167
168bt_node *btGetNodeFromVnid(vnode_id vnid);
169void btAddHandle(vnode_id dir_vnid, vnode_id file_vnid, char *name);
170void btRemoveHandle(vnode_id vnid);
171void btPurgeNodes(vnode_id vnid);
172bool btIsAncestorNode(vnode_id vnid, bt_node *node);
173char *btGetLocalFileName(char *path, vnode_id vnid);
174void btMakeHandleFromNode(bt_node *node, vnode_id vnid);
175bt_node *btFindNode(bt_node *parent, char *fileName);
176char *btGetSharePath(char *shareName);
177int btGetShareId(char *shareName);
178int btGetShareIdByPath(char *path);
179bt_printer *btFindPrinter(char *printerName);
180uint32 btGetWinInode(const char *path);
181int btGetBeosStat(char *fileName, beos_stat *st);
182void btMakePath(char *path, char *dir, char *file);
183
184int btPreMount(bt_session_t *session, char *shareName);
185int btMount(bt_session_t *session, char *shareName, char *user, char *password, vnode_id *vnid);
186int btGetFSInfo(fs_info *fsInfo, char *path);
187int btLookup(char *pathBuf, vnode_id dir_vnid, char *fileName, vnode_id *file_vnid);
188int btStat(char *pathBuf, vnode_id vnid, beos_stat *st);
189int btReadDir(char *pathBuf, vnode_id dir_vnid, long **dir, vnode_id *file_vnid, char *filename, beos_stat *st);
190int32 btRead(char *pathBuf, vnode_id vnid, beos_off_t pos, int32 len, char *buffer);
191int32 btWrite(bt_session_t *session, vnode_id vnid, beos_off_t pos, int32 len, int32 totalLen, char *buffer);
192int btCreate(char *pathBuf, vnode_id dir_vnid, char *name, int omode, int perms, vnode_id *file_vnid);
193int btTruncate(char *pathBuf, vnode_id vnid, int64 len);
194int btCreateDir(char *pathBuf, vnode_id dir_vnid, char *name, int perms, vnode_id *file_vnid, beos_stat *st);
195int btDeleteDir(char *pathBuf, vnode_id dir_vnid, char *name);
196int btRename(char *pathBuf, vnode_id old_vnid, char *oldName, vnode_id new_vnid, char *newName);
197int btUnlink(char *pathBuf, vnode_id vnid, char *name);
198int btReadLink(char *pathBuf, vnode_id vnid, char *buffer, int length);
199int btSymLink(char *pathBuf, vnode_id vnid, char *name, char *dest);
200int btWStat(char *pathBuf, vnode_id vnid, long mask, int32 mode, int32 uid, int32 gid, int64 size, int32 atime, int32 mtime);
201int btCommit(bt_session_t *session, vnode_id vnid);
202int btReadAttrib(char *pathBuf, vnode_id vnid, char *name, char *buffer);
203int btAuthenticate(char *resource, char *user, char *password);
204
205bt_block *btGetWriteBlock(bt_session_t *session, vnode_id vnid);
206void btInsertWriteBlock(bt_session_t *session, bt_block *block);
207void btRemoveWriteBlock(bt_session_t *session, bt_block *block);
208
209void netbtPreMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
210void netbtMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
211void netbtFSInfo(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
212void netbtLookup(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
213void netbtStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
214void netbtReadDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
215void netbtRead(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
216void netbtWrite(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
217void netbtCreate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
218void netbtTruncate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
219void netbtCreateDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
220void netbtDeleteDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
221void netbtRename(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
222void netbtUnlink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
223void netbtReadLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
224void netbtSymLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
225void netbtWStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
226void netbtReadAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
227void netbtWriteAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
228void netbtReadAttribDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
229void netbtRemoveAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
230void netbtStatAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
231void netbtReadIndexDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
232void netbtCreateIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
233void netbtRemoveIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
234void netbtStatIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
235void netbtReadQuery(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
236void netbtCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
237void netbtPrintJobNew(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
238void netbtPrintJobData(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
239void netbtPrintJobCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
240void netbtAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
241void netbtQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
242
243CMyService *winService;
244bt_node *rootNode = NULL;
245ubi_btRoot vnidTree;
246ubi_btRoot nameTree;
247bt_mime_mapping *mimeMap = NULL;
248bt_session_t *rootSession = NULL;
249bt_fileShare_t fileShares[BT_MAX_FILE_SHARES];
250bt_printer sharedPrinters[BT_MAX_PRINTER_SHARES];
251char tokBuffer[MAX_NAME_LENGTH + 1], *tokPtr;
252bool running = true;
253bool preload = false;
254int server;
255char authServerName[B_FILE_NAME_LENGTH];
256unsigned int authServerIP;
257bt_managed_data handleData;
258bt_managed_data sessionData;
259HANDLE hostThread;
260
261char *keywords[] =
262{
263	"share",
264	"as",
265	"set",
266	"read",
267	"write",
268	"read-write",
269	"promiscuous",
270	"on",
271	"to",
272	"authenticate",
273	"with",
274	"group",
275	"printer",
276	"print",
277	"is",
278	"spooled",
279	"device",
280	"type",
281	"preload",
282	NULL
283};
284
285bt_command_t dirCommands[] =
286{
287	{ BT_CMD_PREMOUNT,			netbtPreMount,				true,	1,	{ B_STRING_TYPE } },
288	{ BT_CMD_MOUNT,				netbtMount,					true,	3,	{ B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } },
289	{ BT_CMD_FSINFO,			netbtFSInfo,				true,	1,	{ B_INT64_TYPE } },
290	{ BT_CMD_LOOKUP,			netbtLookup,				true,	2,	{ B_INT64_TYPE, B_STRING_TYPE } },
291	{ BT_CMD_STAT,				netbtStat,					true,	1,	{ B_INT64_TYPE } },
292	{ BT_CMD_READDIR,			netbtReadDir,				true,	2,	{ B_INT64_TYPE, B_STRING_TYPE } },
293	{ BT_CMD_READ,				netbtRead,					true,	3,	{ B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
294	{ BT_CMD_WRITE,				netbtWrite,					true,	5,	{ B_INT64_TYPE, B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_STRING_TYPE } },
295	{ BT_CMD_CREATE,			netbtCreate,				true,	4,	{ B_INT64_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
296	{ BT_CMD_TRUNCATE,			netbtTruncate,				true,	2,	{ B_INT64_TYPE, B_INT64_TYPE } },
297	{ BT_CMD_MKDIR,				netbtCreateDir, 			true,	3,	{ B_INT64_TYPE, B_STRING_TYPE, B_INT32_TYPE } },
298	{ BT_CMD_RMDIR,				netbtDeleteDir,				true,	2,	{ B_INT64_TYPE, B_STRING_TYPE } },
299	{ BT_CMD_RENAME,			netbtRename,				true,	4,	{ B_INT64_TYPE, B_STRING_TYPE, B_INT64_TYPE, B_STRING_TYPE } },
300	{ BT_CMD_UNLINK,			netbtUnlink,				true,	2,	{ B_INT64_TYPE, B_STRING_TYPE } },
301	{ BT_CMD_READLINK,			netbtReadLink,				false,	1,	{ B_INT64_TYPE } },
302	{ BT_CMD_SYMLINK,			netbtSymLink,				false,	3,	{ B_INT64_TYPE, B_STRING_TYPE, B_STRING_TYPE } },
303	{ BT_CMD_WSTAT,				netbtWStat,					true,	8,	{ B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
304	{ BT_CMD_READATTRIB,		netbtReadAttrib,			true,	5,	{ B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
305	{ BT_CMD_WRITEATTRIB,		netbtWriteAttrib,			false,	6,	{ B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
306	{ BT_CMD_READATTRIBDIR,		netbtReadAttribDir,			false,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
307	{ BT_CMD_REMOVEATTRIB,		netbtRemoveAttrib,			false,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
308	{ BT_CMD_STATATTRIB,		netbtStatAttrib,			true,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
309	{ BT_CMD_READINDEXDIR,		netbtReadIndexDir,			false,	1,	{ B_STRING_TYPE } },
310	{ BT_CMD_CREATEINDEX,		netbtCreateIndex,			false,	3,	{ B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } },
311	{ BT_CMD_REMOVEINDEX,		netbtRemoveIndex,			false,	1,	{ B_STRING_TYPE } },
312	{ BT_CMD_STATINDEX,			netbtStatIndex,				false,	1,	{ B_STRING_TYPE } },
313	{ BT_CMD_READQUERY,			netbtReadQuery,				false,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
314	{ BT_CMD_COMMIT,			netbtCommit,				true,	1,	{ B_INT64_TYPE } },
315	{ BT_CMD_PRINTJOB_NEW,		netbtPrintJobNew,			true,	4,	{ B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } },
316	{ BT_CMD_PRINTJOB_DATA,		netbtPrintJobData,			true,	4,	{ B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE } },
317	{ BT_CMD_PRINTJOB_COMMIT,	netbtPrintJobCommit,		true,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
318	{ BT_CMD_AUTHENTICATE,		netbtAuthenticate,			true,	3,	{ B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } },
319	{ BT_CMD_QUIT,				netbtQuit,					true,	0,	{ 0 } },
320	{ 0,						NULL,						false,	0,	{ 0 } }
321};
322
323
324//int APIENTRY WinMain(HINSTANCE hInstance,
325//                     HINSTANCE hPrevInstance,
326//                     LPSTR     lpCmdLine,
327//                     int       nCmdShow)
328void BeServedStartup(CMyService *service)
329{
330	WSADATA wsaData;
331	DWORD threadId;
332
333	ASSERT(service);
334	winService = service;
335
336	initPrinters();
337
338	initMimeMap();
339	initShares();
340	signal(SIGINT, endService);
341	signal(SIGTERM, endService);
342
343	// Initialize the trees sorted by vnode_id and by name.
344	ubi_trInitTree(&vnidTree, CompareVnidNodes, 0);
345	ubi_trInitTree(&nameTree, CompareNameNodes, 0);
346
347	if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
348		return;
349
350	if (initManagedData(&handleData))
351		if (initManagedData(&sessionData))
352			hostThread = CreateThread(NULL, 0, btSendHost, NULL, 0, &threadId);
353}
354
355bool dateCheck()
356{
357	struct _stat st;
358	time_t curTime;
359
360	time(&curTime);
361	if (curTime > 1012537700)
362		return false;
363
364	if (_stat("/boot/home/config/servers/beserved_server", &st) == 0)
365		if (curTime < st.st_ctime || curTime > st.st_ctime + 7776000)
366			return false;
367
368	return true;
369}
370
371void restartService()
372{
373	bt_fileShare_t *oldShares;
374	int i;
375
376	// Printers are easier because the printer name is sent with each print request.
377	// If the printer is no longer available, the next transmission sent regarding
378	// that printer will result in an error, terminating the print job on the client.
379	// All we have to do is clear out the structures, and initShares will read the
380	// configuration file.
381	initPrinters();
382
383	// Delay all mounting and other file system operations.
384	beginWriting(&handleData);
385	beginWriting(&sessionData);
386
387	// Copy existing share data.
388	oldShares = (bt_fileShare_t *) malloc(sizeof(bt_fileShare_t) * BT_MAX_FILE_SHARES);
389	if (oldShares)
390	{
391		for (i = 0; i < BT_MAX_FILE_SHARES; i++)
392			memcpy(&oldShares[i], &fileShares[i], sizeof(bt_fileShare_t));
393
394		// Reload the share data.
395		initShares();
396
397		// Now loop through the old file shares.  For each one, check if the same
398		// path exists in the new shares.
399		for (i = 0; i < BT_MAX_FILE_SHARES; i++)
400			if (oldShares[i].used)
401			{
402				bt_session_t *s;
403				int share = btGetShareIdByPath(oldShares[i].path);
404				if (share == -1)
405				{
406					for (s = rootSession; s; s = s->next)
407						if (s->share == i)
408							s->killed = true;
409				}
410				else if (share != i)
411				{
412					for (s = rootSession; s; s = s->next)
413						if (s->share == i)
414							s->share = share;
415				}
416			}
417
418		free(oldShares);
419	}
420
421	// Resume normal operation.
422	endWriting(&sessionData);
423	endWriting(&handleData);
424}
425
426DWORD WINAPI btSendHost(LPVOID data)
427{
428	bt_request request;
429	bt_hostinfo info;
430	struct sockaddr_in serverAddr, clientAddr;
431	char buffer[4096];
432	int server, addrLen, bufLen, replyLen;
433
434	buffer[0] = 0;
435	bufLen = sizeof(buffer);
436
437	server = socket(AF_INET, SOCK_DGRAM, 0);
438	if (server == INVALID_SOCKET)
439		return 0;
440
441	memset(&serverAddr, 0, sizeof(serverAddr));
442	serverAddr.sin_family = AF_INET;
443	serverAddr.sin_port = htons(BT_QUERYHOST_PORT);
444	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
445
446	// Bind that socket to the address constructed above.
447	if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr)))
448		return 0;
449
450	while (running)
451	{
452		addrLen = sizeof(struct sockaddr_in);
453		replyLen = 0;
454		if (recvfrom(server, (char *) &request, sizeof(request), 0, (struct sockaddr *) &clientAddr, &addrLen) <= 0)
455			continue;
456
457		switch (request.command)
458		{
459			case BT_REQ_HOST_PROBE:
460				gethostname(buffer, bufLen);
461				break;
462
463			case BT_REQ_SHARE_PROBE:
464				replyLen = getSharedResources(buffer, sizeof(buffer), true, true);
465				break;
466
467			case BT_REQ_PRINTER_PROBE:
468				replyLen = getSharedResources(buffer, sizeof(buffer), false, true);
469				break;
470
471			case BT_REQ_HOST_INFO:
472				getHostInfo(&info);
473				memcpy(buffer, &info, sizeof(bt_hostinfo));
474				replyLen = sizeof(bt_hostinfo);
475				break;
476
477			case BT_REQ_HOST_USERS:
478				replyLen = getHostUsers(buffer);
479				break;
480		}
481
482		// If no reply length has been specified, calculate it now by taking the
483		// length of the buffer.
484		if (replyLen == 0)
485			replyLen = strlen(buffer);
486
487		sendto(server, buffer, replyLen, 0, (struct sockaddr *) &clientAddr, addrLen);
488	}
489
490	// Close the socket.  Technically, I believe we should call shutdown()
491	// first, but the BeOS header file socket.h indicates that this
492	// function is not currently working.  It is present but may not have
493	// any effect.
494	shutdown(server, 2);
495	closesocket(server);
496	return 0;
497}
498
499// getSharedResources()
500//
501int getSharedResources(char *buffer, int bufSize, bool shares, bool printers)
502{
503	bt_resource resource;
504	int i, bufPos = 0;
505
506	// If the supplied buffer can't hold at least two resource structures, one
507	// for a shared resource and one to terminate the list, then don't bother
508	// building the list.
509	if (bufSize < 2 * sizeof(bt_resource))
510		return 0;
511
512	if (shares)
513		for (i = 0; i < BT_MAX_FILE_SHARES; i++)
514			if (fileShares[i].used)
515			{
516				// If this is the last resource structure that will fit in the
517				// buffer, then don't add any more into the list.
518				if (bufPos + sizeof(bt_resource) >= bufSize)
519					break;
520
521				// Fill out the resource structure.
522				resource.type = BT_SHARED_FOLDER;
523				resource.subType = 0;
524				strcpy(resource.name, fileShares[i].name);
525
526				// Copy the resource structure into the buffer at the current offset.
527				memcpy(buffer + bufPos, &resource, sizeof(bt_resource));
528				bufPos += sizeof(bt_resource);
529			}
530
531	if (printers)
532		for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
533			if (sharedPrinters[i].used)
534			{
535				// If this is the last resource structure that will fit in the
536				// buffer, then don't add any more into the list.
537				if (bufPos + sizeof(bt_resource) >= bufSize)
538					break;
539
540				// Fill out the resource structure.
541				resource.type = BT_SHARED_PRINTER;
542				resource.subType = BT_PRINTER_PCL3;
543				strcpy(resource.name, sharedPrinters[i].printerName);
544
545				// Copy the resource structure into the buffer at the current offset.
546				memcpy(buffer + bufPos, &resource, sizeof(bt_resource));
547				bufPos += sizeof(bt_resource);
548			}
549
550	// Copy the null terminating structure.
551	resource.type = BT_SHARED_NULL;
552	resource.subType = 0;
553	resource.name[0] = 0;
554	memcpy(buffer + bufPos, &resource, sizeof(bt_resource));
555	bufPos += sizeof(bt_resource);
556
557	return bufPos;
558}
559
560// getHostInfo()
561//
562void getHostInfo(bt_hostinfo *info)
563{
564	SYSTEM_INFO systemInfo;
565	OSVERSIONINFOEX osInfo;
566	bt_session_t *s;
567
568	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
569	if (!GetVersionEx((OSVERSIONINFO *) &osInfo))
570	{
571		osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
572		GetVersionEx((OSVERSIONINFO *) &osInfo);
573	}
574
575	GetSystemInfo(&systemInfo);
576
577	switch (osInfo.dwPlatformId)
578	{
579		case VER_PLATFORM_WIN32_WINDOWS:
580			if (osInfo.dwMinorVersion == 0)
581			{
582				strcpy(info->system, "Windows 95");
583				if (osInfo.szCSDVersion[1] == 'C' || osInfo.szCSDVersion[1] == 'B')
584					strcat(info->system, " OSR2");
585			}
586			else if (osInfo.dwMinorVersion == 10)
587			{
588				strcpy(info->system, "Windows 98");
589				if (osInfo.szCSDVersion[1] == 'A')
590					strcat(info->system, " SE");
591			}
592			else if (osInfo.dwMinorVersion == 90)
593				strcpy(info->system, "Windows Me");
594			break;
595
596		case VER_PLATFORM_WIN32_NT:
597			if (osInfo.dwMajorVersion <= 4)
598				sprintf(info->system, "Windows NT %d.%d %s (Build %d)",
599					osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.szCSDVersion,
600					osInfo.dwBuildNumber);
601			else if (osInfo.dwMajorVersion == 5)
602				if (osInfo.dwMinorVersion == 0)
603					sprintf(info->system, "Windows 2000 %s (Build %d)",
604						osInfo.szCSDVersion, osInfo.dwBuildNumber & 0xffff);
605				else
606					sprintf(info->system, "Windows XP %s (Build %d)",
607						osInfo.szCSDVersion, osInfo.dwBuildNumber & 0xffff);
608
609			break;
610	}
611
612	strcpy(info->beServed, "BeServed 1.2.6");
613
614	info->cpus = systemInfo.dwNumberOfProcessors;
615	info->maxConnections = BT_MAX_THREADS;
616
617	switch (systemInfo.wProcessorArchitecture)
618	{
619		case PROCESSOR_ARCHITECTURE_MIPS:
620			strcpy(info->platform, "MIPS");
621			break;
622
623		case PROCESSOR_ARCHITECTURE_ALPHA:
624			strcpy(info->platform, "DEC Alpha");
625			break;
626
627		case PROCESSOR_ARCHITECTURE_PPC:
628			strcpy(info->platform, "PowerPC");
629			break;
630
631		case PROCESSOR_ARCHITECTURE_INTEL:
632			strcpy(info->platform, "Intel x86");
633			break;
634
635		default:
636			strcpy(info->platform, "Unknown");
637	}
638
639	// Delay all new session creation.
640	beginReading(&sessionData);
641
642	info->connections = 0;
643	for (s = rootSession; s; s = s->next)
644		if (s->socket != INVALID_SOCKET)
645			info->connections++;
646
647	info->connections = B_HOST_TO_LENDIAN_INT32(info->connections);
648	endReading(&sessionData);
649}
650
651// getHostUsers()
652//
653int getHostUsers(char *buffer)
654{
655	bt_session_t *s;
656	char addr[20];
657	int len, bufSize;
658
659	// Initialize the buffer to be empty.
660	buffer[0] = 0;
661	bufSize = 0;
662
663	// Delay all new session creation.
664	beginReading(&sessionData);
665
666	for (s = rootSession; s; s = s->next)
667		if (s->socket != INVALID_SOCKET)
668		{
669			uint8 *client_s_addr = (uint8 *) s->client_s_addr;
670			sprintf(addr, "%d.%d.%d.%d", client_s_addr[0], client_s_addr[1], client_s_addr[2], client_s_addr[3]);
671			len = strlen(buffer);
672			strcpy(&buffer[len > 0 ? len + 1 : 0], addr);
673			bufSize += len + 1;
674		}
675
676	endReading(&sessionData);
677
678	buffer[bufSize++] = 0;
679	return bufSize;
680}
681
682// initMimeMap()
683//
684void initMimeMap()
685{
686	FILE *fp;
687	bt_mime_mapping *map;
688	char mimeLine[256];
689	int i, mimeLen;
690
691	fp = fopen("BeServed-MimeMap", "r");
692	if (fp)
693	{
694		while (fgets(mimeLine, sizeof(mimeLine) - 1, fp))
695		{
696			// Strip off the carriage return.
697			mimeLine[strlen(mimeLine) - 1] = 0;
698
699			// Create a new MIME map entry.
700			map = (bt_mime_mapping *) malloc(sizeof(bt_mime_mapping));
701			if (!map)
702				continue;
703
704			map->next = mimeMap;
705			mimeMap = map;
706
707			// Grab the extension.
708			for (i = 0; mimeLine[i] != ' '; i++)
709				map->extension[i] = mimeLine[i];
710
711			map->extension[i] = 0;
712
713			// Skip to the start of the MIME type.
714			while (mimeLine[i] == ' ')
715				i++;
716
717			// Grab the MIME type.
718			mimeLen = strlen(&mimeLine[i]);
719			map->mimeType = (char *) malloc(mimeLen + 1);
720			if (map->mimeType)
721				strncpy(map->mimeType, &mimeLine[i], mimeLen + 1);
722		}
723
724		fclose(fp);
725	}
726}
727
728void closeMimeMap()
729{
730	bt_mime_mapping *map = mimeMap;
731
732	while (map)
733	{
734		map = mimeMap->next;
735		free(mimeMap->mimeType);
736		free(mimeMap);
737		mimeMap = map;
738	}
739}
740
741void initShares()
742{
743	FILE *fp;
744	char buffer[512];
745	int i, length;
746
747	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
748	{
749		fileShares[i].name[0] = 0;
750		fileShares[i].path[0] = 0;
751		fileShares[i].used = false;
752		fileShares[i].readOnly = true;
753		fileShares[i].security = BT_AUTH_NONE;
754		fileShares[i].rights = NULL;
755		fileShares[i].next = NULL;
756	}
757
758	fp = fopen("BeServed-Settings", "r");
759	if (fp)
760	{
761		while (fgets(buffer, sizeof(buffer) - 1, fp))
762		{
763			length = strlen(buffer);
764			if (length <= 1 || buffer[0] == '#')
765				continue;
766
767			if (buffer[length - 1] == '\n')
768				buffer[--length] = 0;
769
770			if (strncmp(buffer, "share ", 6) == 0)
771				getFileShare(buffer);
772			else if (strncmp(buffer, "set ", 4) == 0)
773				getShareProperty(buffer);
774			else if (strncmp(buffer, "grant ", 6) == 0)
775				getGrant(buffer);
776			else if (strncmp(buffer, "authenticate ", 13) == 0)
777				getAuthenticate(buffer);
778			else if (strncmp(buffer, "printer ", 8) == 0)
779				getPrinter(buffer);
780			else if (strcmp(buffer, "preload") == 0)
781				preload = true;
782		}
783
784		fclose(fp);
785	}
786}
787
788void initPrinters()
789{
790	int i;
791
792	for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
793	{
794		sharedPrinters[i].printerName[0] = 0;
795		sharedPrinters[i].deviceName[0] = 0;
796		sharedPrinters[i].spoolDir[0] = 0;
797		sharedPrinters[i].rights = NULL;
798		sharedPrinters[i].security = BT_AUTH_NONE;
799		sharedPrinters[i].used = false;
800		sharedPrinters[i].killed = false;
801	}
802}
803
804void loadShares()
805{
806	int i;
807
808	if (preload)
809		for (i = 0; i < BT_MAX_FILE_SHARES; i++)
810			if (fileShares[i].used)
811				loadFolder(fileShares[i].path);
812}
813
814void getFileShare(const char *buffer)
815{
816	struct _stat st;
817	char path[B_PATH_NAME_LENGTH], share[MAX_NAME_LENGTH + 1], *folder;
818	int i, tok;
819
820	// Skip over SHARE command.
821	tokPtr = (char *) buffer + (6 * sizeof(char));
822
823	tok = getToken();
824	if (tok != BT_TOKEN_STRING)
825		return;
826
827	strcpy(path, tokBuffer);
828	tok = getToken();
829	if (tok != BT_TOKEN_AS)
830		return;
831
832	tok = getToken();
833	if (tok != BT_TOKEN_STRING)
834		return;
835
836	strcpy(share, tokBuffer);
837
838	// Now verify that the share name specified has not already been
839	// used to share another path.
840	folder = btGetSharePath(share);
841	if (folder)
842	{
843		winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_DUPLICATE_SHARE, share);
844		return;
845	}
846
847	// Check the path to ensure its validity.
848	if (_stat(path, &st) != 0)
849	{
850		winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_INVALID_SHARE_PATH, path);
851		return;
852	}
853
854	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
855		if (!fileShares[i].used)
856		{
857			strcpy(fileShares[i].name, share);
858			strcpy(fileShares[i].path, path);
859			fileShares[i].used = true;
860			return;
861		}
862
863	winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_TOO_MANY_SHARES, share);
864}
865
866void getShareProperty(const char *buffer)
867{
868	char share[B_FILE_NAME_LENGTH + 1];
869	int tok, shareId;
870
871	// Skip over SET command.
872	tokPtr = (char *) buffer + (4 * sizeof(char));
873
874	tok = getToken();
875	if (tok != BT_TOKEN_STRING)
876		return;
877
878	strcpy(share, tokBuffer);
879
880	// Get the index of the share referred to.  If the named share cannot be
881	// found, then abort.
882	shareId = btGetShareId(share);
883	if (shareId < 0)
884		return;
885
886	tok = getToken();
887	if (tok == BT_TOKEN_READWRITE)
888		fileShares[shareId].readOnly = false;
889}
890
891void getGrant(const char *buffer)
892{
893	char share[MAX_NAME_LENGTH + 1];
894	int tok, rights;
895	bool isGroup = false;
896
897	// Skip over GRANT command.
898	tokPtr = (char *) buffer + (6 * sizeof(char));
899	rights = 0;
900
901	do
902	{
903		tok = getToken();
904		if (tok == BT_TOKEN_READ)
905		{
906			rights |= BT_RIGHTS_READ;
907			tok = getToken();
908		}
909		else if (tok == BT_TOKEN_WRITE)
910		{
911			rights |= BT_RIGHTS_WRITE;
912			tok = getToken();
913		}
914		else if (tok == BT_TOKEN_PRINT)
915		{
916			rights |= BT_RIGHTS_PRINT;
917			tok = getToken();
918		}
919	} while (tok == BT_TOKEN_COMMA);
920
921	if (tok != BT_TOKEN_ON)
922		return;
923
924	tok = getToken();
925	if (tok != BT_TOKEN_STRING)
926		return;
927
928	strcpy(share, tokBuffer);
929	tok = getToken();
930	if (tok != BT_TOKEN_TO)
931		return;
932
933	tok = getToken();
934	if (tok == BT_TOKEN_GROUP)
935	{
936		isGroup = true;
937		tok = getToken();
938	}
939
940	if (tok != BT_TOKEN_STRING)
941		return;
942
943	addUserRights(share, tokBuffer, rights, isGroup);
944}
945
946void getAuthenticate(const char *buffer)
947{
948	int i, tok;
949
950	// Skip over AUTHENTICATE command.
951	tokPtr = (char *) buffer + (13 * sizeof(char));
952
953	tok = getToken();
954	if (tok != BT_TOKEN_WITH)
955		return;
956
957	tok = getToken();
958	if (tok != BT_TOKEN_STRING)
959		return;
960
961	// Loop up address for given host.
962	getAuthServerAddress(tokBuffer);
963
964	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
965		fileShares[i].security = BT_AUTH_BESURE;
966
967	for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
968		sharedPrinters[i].security = BT_AUTH_BESURE;
969}
970
971bool getAuthServerAddress(const char *name)
972{
973	// Look up address for given host.
974	struct hostent *ent = gethostbyname(name);
975	if (ent == NULL)
976	{
977		unsigned long addr = inet_addr(tokBuffer);
978		authServerIP = ntohl(addr);
979	}
980	else
981		authServerIP = ntohl(*((unsigned int *) ent->h_addr));
982
983	strcpy(authServerName, name);
984	return true;
985}
986
987void addUserRights(char *share, char *user, int rights, bool isGroup)
988{
989	bt_printer *printer;
990	bt_user_rights *ur;
991	bool isPrinter = false;
992	int shareId;
993
994	// Now make sure that the rights make sense.  If we're granting the
995	// right to print, we should not have granted the right to read or write.
996	// We should also be working exclusively with a printer.
997	if (rights & BT_RIGHTS_PRINT)
998	{
999		if (rights & BT_RIGHTS_READ || rights & BT_RIGHTS_WRITE)
1000			return;
1001
1002		printer = btFindPrinter(share);
1003		if (!printer)
1004			return;
1005
1006		isPrinter = true;
1007	}
1008	else
1009	{
1010		shareId = btGetShareId(share);
1011		if (shareId < 0)
1012			return;
1013	}
1014
1015	// Allocate a new user rights structure, populate it, and attach it to
1016	// either a file share or printer.
1017	ur = (bt_user_rights *) malloc(sizeof(bt_user_rights));
1018	if (ur)
1019	{
1020		ur->user = (char *) malloc(strlen(user) + 1);
1021		if (ur->user)
1022		{
1023			strcpy(ur->user, user);
1024			ur->rights = rights;
1025			ur->isGroup = isGroup;
1026
1027			if (isPrinter)
1028			{
1029				ur->next = printer->rights;
1030				printer->rights = ur;
1031			}
1032			else
1033			{
1034				ur->next = fileShares[shareId].rights;
1035				fileShares[shareId].rights = ur;
1036			}
1037		}
1038		else
1039			free(ur);
1040	}
1041}
1042
1043void getPrinter(const char *buffer)
1044{
1045	bt_printer printer;
1046	DWORD threadId;
1047	int i, tok;
1048
1049	// Skip over PRINTER command.
1050	tokPtr = (char *) buffer + (8 * sizeof(char));
1051
1052	// Now get the name this printer will be shared as.
1053	tok = getToken();
1054	if (tok != BT_TOKEN_STRING)
1055		return;
1056
1057	strcpy(printer.printerName, tokBuffer);
1058
1059	// Bypass the IS and TYPE keywords.
1060	tok = getToken();
1061	if (tok != BT_TOKEN_IS)
1062		return;
1063
1064	tok = getToken();
1065	if (tok != BT_TOKEN_TYPE)
1066		return;
1067
1068	// Get the device type of the printer.
1069	tok = getToken();
1070	if (tok != BT_TOKEN_STRING)
1071		return;
1072
1073	strcpy(printer.deviceType, tokBuffer);
1074
1075	// Bypass the DEVICE keyword.
1076	tok = getToken();
1077	if (tok != BT_TOKEN_DEVICE)
1078		return;
1079
1080	// Get the system device name of the printer.
1081	tok = getToken();
1082	if (tok != BT_TOKEN_STRING)
1083		return;
1084
1085	strcpy(printer.deviceName, tokBuffer);
1086
1087	// Bypass the SPOOLED TO keywords.
1088	tok = getToken();
1089	if (tok != BT_TOKEN_SPOOLED)
1090		return;
1091
1092	tok = getToken();
1093	if (tok != BT_TOKEN_TO)
1094		return;
1095
1096	// Get the spooling folder, where temporary files will be stored.
1097	tok = getToken();
1098	if (tok != BT_TOKEN_STRING)
1099		return;
1100
1101	strcpy(printer.spoolDir, tokBuffer);
1102
1103	for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
1104		if (!sharedPrinters[i].used)
1105		{
1106			sharedPrinters[i].used = true;
1107			strcpy(sharedPrinters[i].printerName, printer.printerName);
1108			strcpy(sharedPrinters[i].deviceType, printer.deviceType);
1109			strcpy(sharedPrinters[i].deviceName, printer.deviceName);
1110			strcpy(sharedPrinters[i].spoolDir, printer.spoolDir);
1111			sharedPrinters[i].handlerID = CreateThread(NULL, 0, printerThread, (void *) &sharedPrinters[i], 0, &threadId);
1112			break;
1113		}
1114}
1115
1116int getToken()
1117{
1118	bool quoted = false;
1119
1120	tokBuffer[0] = 0;
1121	while (*tokPtr && iswhite(*tokPtr))
1122		tokPtr++;
1123
1124	if (*tokPtr == ',')
1125	{
1126		*tokPtr++;
1127		return BT_TOKEN_COMMA;
1128	}
1129	else if (*tokPtr == '\"')
1130	{
1131		quoted = true;
1132		tokPtr++;
1133	}
1134
1135	if (isalnum(*tokPtr) || *tokPtr == '\\')
1136	{
1137		int i = 0;
1138		while (isalnum(*tokPtr) || isValid(*tokPtr) || (quoted && *tokPtr == ' '))
1139			if (i < MAX_NAME_LENGTH)
1140				tokBuffer[i++] = *tokPtr++;
1141			else
1142				tokPtr++;
1143
1144		tokBuffer[i] = 0;
1145
1146		if (!quoted)
1147			for (i = 0; keywords[i]; i++)
1148				if (stricmp(tokBuffer, keywords[i]) == 0)
1149					return ++i;
1150
1151		if (quoted)
1152			if (*tokPtr != '\"')
1153				return BT_TOKEN_ERROR;
1154			else
1155				tokPtr++;
1156
1157		return BT_TOKEN_STRING;
1158	}
1159
1160	return BT_TOKEN_ERROR;
1161}
1162
1163void startService()
1164{
1165	struct sockaddr_in serverAddr, clientAddr;
1166	int client, addrLen;
1167	char flags;
1168
1169	// Store the length of the socket addressing structure for accept().
1170	addrLen = sizeof(struct sockaddr_in);
1171
1172	// Initialize the server address structure.
1173	memset(&serverAddr, 0, sizeof(serverAddr));
1174	serverAddr.sin_port = htons(BT_TCPIP_PORT);
1175	serverAddr.sin_family = AF_INET;
1176	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
1177
1178	// Create a new socket to receive incoming requests.
1179	server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1180	if (server == INVALID_SOCKET)
1181		return;
1182
1183	// Set the socket option to reuse the current address in case it was
1184	// in use by a prior version of the service that has not yet relinquished
1185	// the socket.
1186	flags = 1;
1187	setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
1188
1189	// Bind that socket to the address constructed above.
1190	if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr)))
1191		return;
1192
1193	// Listen for incoming connections.
1194	if (listen(server, 5))
1195		return;
1196
1197	// Continually accept incoming connections.  When one is found,
1198	// fire off a handler thread to accept commands.
1199	while (running)
1200	{
1201		client = accept(server, (struct sockaddr *) &clientAddr, &addrLen);
1202		if (client != INVALID_SOCKET)
1203			launchThread(client, &clientAddr);
1204	}
1205
1206	// Close the socket.  Technically, I believe we should call shutdown()
1207	// first, but the BeOS header file socket.h indicates that this
1208	// function is not currently working.  It is present but may not have
1209	// any effect.
1210	shutdown(server, 2);
1211	closesocket(server);
1212	server = INVALID_SOCKET;
1213}
1214
1215void endService(int sig)
1216{
1217	WSACleanup();
1218
1219	TerminateThread(hostThread, 0);
1220	closeManagedData(&sessionData);
1221	closeManagedData(&handleData);
1222
1223	closePrinters();
1224	closeMimeMap();
1225	freeFileShares();
1226
1227	ubi_trKillTree(&vnidTree, KillNode);
1228	ubi_trKillTree(&nameTree, KillNode);
1229
1230	signal(SIGINT, SIG_DFL);
1231	signal(SIGTERM, SIG_DFL);
1232}
1233
1234void closePrinters()
1235{
1236	int i;
1237
1238	// Close down shared printer spooling threads.
1239	for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
1240		if (sharedPrinters[i].used)
1241		{
1242			sharedPrinters[i].killed = true;
1243			waitForThread(sharedPrinters[i].handlerID);
1244		}
1245}
1246
1247// waitForThread()
1248//
1249void waitForThread(HANDLE threadId)
1250{
1251	DWORD exitCode;
1252
1253	while (true)
1254	{
1255		// Get the exit code of the thread.  If the function fails, the
1256		// thread is invalid and thus already gone.
1257		if (!GetExitCodeThread(threadId, &exitCode))
1258			break;
1259
1260		// If we have an exit code, the thread isn't running.
1261		if (exitCode != STILL_ACTIVE)
1262			break;
1263
1264		// Otherwise, wait and retry.
1265		Sleep(100);
1266	}
1267}
1268
1269// freeFileShares()
1270//
1271void freeFileShares()
1272{
1273	bt_user_rights *ur, *nextUr;
1274	int i;
1275
1276	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
1277		for (ur = fileShares[i].rights; ur; )
1278		{
1279			nextUr = ur->next;
1280			if (ur->user)
1281				free(ur->user);
1282
1283			free(ur);
1284			ur = nextUr;
1285		}
1286}
1287
1288// launchThread()
1289//
1290void launchThread(int client, struct sockaddr_in *addr)
1291{
1292	bt_session_t *s, *cur, *last = NULL;
1293	DWORD threadId;
1294	int count = 0;
1295
1296	// First verify that the server's not too busy by scanning the list of active
1297	// sessions.  This is also useful because we need to eliminate unused sessions
1298	// from the list, i.e., sessions that have closed.
1299	beginWriting(&sessionData);
1300
1301	s = rootSession;
1302	while (s)
1303	{
1304		if (s->socket == INVALID_SOCKET)
1305		{
1306			if (last)
1307				last->next = s->next;
1308			else
1309				rootSession = s->next;
1310
1311			cur = s->next;
1312			free(s);
1313			s = cur;
1314			continue;
1315		}
1316
1317		last = s;
1318		s = s->next;
1319		count++;
1320	}
1321
1322	// If the total number of valid sessions was less than our allowed maximum, then
1323	// we can create a new session.
1324	if (count < BT_MAX_THREADS)
1325	{
1326		// We need to create an available session for this connection.
1327		bt_session_t *session = (bt_session_t *) malloc(sizeof(bt_session_t));
1328		if (session)
1329		{
1330			session->socket = client;
1331			session->client_s_addr = addr->sin_addr.s_addr;
1332			session->rootBlock = NULL;
1333			session->killed = false;
1334			session->rights = 0;
1335			session->handlerID = CreateThread(NULL, 0, requestThread, (void *) session, 0, &threadId);
1336
1337			// Add this to the session list.
1338			session->next = rootSession;
1339			rootSession = session;
1340			endWriting(&sessionData);
1341			return;
1342		}
1343	}
1344
1345	endWriting(&sessionData);
1346
1347	// We must have too many threads active, so let the client know we're busy.
1348	sendErrorToClient(client, 0, EBUSY);
1349	shutdown(client, 2);
1350	closesocket(client);
1351}
1352
1353DWORD WINAPI requestThread(LPVOID data)
1354{
1355	bt_session_t *session = (bt_session_t *) data;
1356
1357	if (!session)
1358		return 0;
1359
1360	session->blockSem = CreateSemaphore(NULL, 1, 1, NULL);
1361	if (session->blockSem)
1362	{
1363		session->rootBlock = NULL;
1364		while (!session->killed && receiveRequest(session));
1365		CloseHandle(session->blockSem);
1366	}
1367
1368	shutdown(session->socket, 2);
1369	closesocket(session->socket);
1370	session->socket = INVALID_SOCKET;
1371	return 0;
1372}
1373
1374int receiveRequest(bt_session_t *session)
1375{
1376	bt_inPacket packet;
1377	char signature[20], *buffer;
1378	unsigned char command;
1379	int client, sigLen;
1380	int32 length;
1381
1382	client = session->socket;
1383
1384	// Read the BeTalk RPC header.
1385	sigLen = strlen(BT_RPC_SIGNATURE);
1386	if (btRecvMsg(client, signature, sigLen, 0) == -1)
1387		return 0;
1388
1389//	recv(client, &verHi, sizeof(verHi), 0);
1390//	recv(client, &verLo, sizeof(verLo), 0);
1391
1392	signature[sigLen] = 0;
1393	if (strcmp(signature, BT_RPC_SIGNATURE))
1394		return 0;
1395
1396	// Read in the rest of the packet.
1397	if (btRecvMsg(client, (char *) &length, sizeof(int32), 0) == -1)
1398		return 0;
1399
1400	length = B_LENDIAN_TO_HOST_INT32(length);
1401	if (length == 0 || length > BT_RPC_MAX_PACKET_SIZE)
1402		return 0;
1403
1404	buffer = (char *) malloc(length + 1);
1405	if (!buffer)
1406		return 0;
1407
1408	if (btRecvMsg(client, buffer, length, 0) == -1)
1409	{
1410		free(buffer);
1411		return 0;
1412	}
1413
1414	buffer[length] = 0;
1415	packet.buffer = buffer;
1416	packet.length = length;
1417	packet.offset = 0;
1418
1419	// Read the transmission ID and command.
1420	command = btRPCGetChar(&packet);
1421	getArguments(session, &packet, command);
1422	free(buffer);
1423	return (command != BT_CMD_QUIT && command != BT_CMD_PREMOUNT);
1424}
1425
1426void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command)
1427{
1428	bt_arg_t args[MAX_COMMAND_ARGS];
1429	int i, client;
1430	bool error;
1431	unsigned char argc, terminator;
1432	int32 xid;
1433
1434	error = false;
1435	client = session->socket;
1436	argc = btRPCGetChar(packet);
1437	if (argc > MAX_COMMAND_ARGS)
1438		return;
1439
1440	for (i = 0; i < argc && !error; i++)
1441	{
1442		args[i].type = btRPCGetInt32(packet);
1443		args[i].data = btRPCGetNewString(packet);
1444		if (args[i].data == NULL)
1445			error = true;
1446	}
1447
1448	if (!error)
1449	{
1450		xid = btRPCGetInt32(packet);
1451		terminator = btRPCGetChar(packet);
1452		if (terminator == BT_CMD_TERMINATOR)
1453			handleRequest(session, xid, command, argc, args);
1454	}
1455
1456	while (--i >= 0)
1457		free(args[i].data);
1458}
1459
1460void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[])
1461{
1462	bool validated = true;
1463	int i, j;
1464
1465	for (i = 0; dirCommands[i].handler; i++)
1466		if (command == dirCommands[i].command)
1467		{
1468			// We may have received a valid command, but one that is not supported by this
1469			// server.  In this case, we'll want to return an operation not supported error,
1470			// as opposed to an invalid command error.
1471			if (!dirCommands[i].supported)
1472			{
1473				sendErrorToClient(session->socket, xid, ENOTSUP);
1474				return;
1475			}
1476
1477			// Now verify that the argument count is correct, and if so, the type of all
1478			// arguments is correct.  If not, an invalid command error is returned.
1479			// Otherise, the command is executed, and the handler returns any necessary
1480			// acknowledgement.
1481			if (argc == dirCommands[i].args)
1482			{
1483				for (j = 0; j < argc; j++)
1484					if (dirCommands[i].argTypes[j] != argv[j].type)
1485					{
1486						validated = false;
1487						break;
1488					}
1489
1490				if (validated)
1491				{
1492					(*dirCommands[i].handler)(session, xid, argc, argv);
1493					return;
1494				}
1495			}
1496		}
1497
1498	sendErrorToClient(session->socket, xid, EINVAL);
1499}
1500
1501void sendErrorToClient(int client, unsigned int xid, int error)
1502{
1503	bt_outPacket packet;
1504	btRPCCreateAck(&packet, xid, error);
1505	btRPCSendAck(client, &packet);
1506}
1507
1508// btRecvMsg()
1509//
1510int btRecvMsg(int sock, void *data, int dataLen, int flags)
1511{
1512	int bytesRead = 0;
1513	do
1514	{
1515		int bytes = btRecv(sock, (char *) data + bytesRead, dataLen - bytesRead, flags);
1516		if (bytes == -1)
1517			return -1;
1518
1519		bytesRead += bytes;
1520	} while (bytesRead < dataLen);
1521
1522	return bytesRead;
1523}
1524
1525// btRecv()
1526//
1527int btRecv(int sock, void *data, int dataLen, int flags)
1528{
1529	int bytes;
1530
1531	for (;;)
1532	{
1533		bytes = recv(sock, (char *) data, dataLen, flags);
1534		if (bytes == 0)
1535			return -1;
1536		else if (bytes == -1)
1537			if (errno == EINTR)
1538				continue;
1539			else
1540				return -1;
1541		else
1542			break;
1543	}
1544
1545	return bytes;
1546}
1547
1548// btSendMsg()
1549//
1550int btSendMsg(int sock, void *data, int dataLen, int flags)
1551{
1552	int bytesSent = 0;
1553	do
1554	{
1555		int bytes = btSend(sock, (char *) data + bytesSent, dataLen - bytesSent, flags);
1556		if (bytes == -1)
1557			return -1;
1558
1559		bytesSent += bytes;
1560	} while (bytesSent < dataLen);
1561
1562	return bytesSent;
1563}
1564
1565// btSend()
1566//
1567int btSend(int sock, void *data, int dataLen, int flags)
1568{
1569	int bytes;
1570
1571	for (;;)
1572	{
1573		bytes = send(sock, (char *) data, dataLen, flags);
1574		if (bytes == -1)
1575			if (errno == EINTR)
1576				continue;
1577			else
1578				return -1;
1579		else
1580			break;
1581	}
1582
1583	return bytes;
1584}
1585
1586uint32 btSwapInt32(uint32 num)
1587{
1588	uint8 byte;
1589	union
1590	{
1591		uint32 value;
1592		uint8 bytes[4];
1593	} convert;
1594
1595	convert.value = num;
1596	byte = convert.bytes[0];
1597	convert.bytes[0] = convert.bytes[3];
1598	convert.bytes[3] = byte;
1599	byte = convert.bytes[1];
1600	convert.bytes[1] = convert.bytes[2];
1601	convert.bytes[2] = byte;
1602	return convert.value;
1603}
1604
1605uint64 btSwapInt64(uint64 num)
1606{
1607	uint8 byte;
1608	union
1609	{
1610		uint64 value;
1611		uint8 bytes[8];
1612	} convert;
1613
1614	convert.value = num;
1615	byte = convert.bytes[0];
1616	convert.bytes[0] = convert.bytes[7];
1617	convert.bytes[7] = byte;
1618	byte = convert.bytes[1];
1619	convert.bytes[1] = convert.bytes[6];
1620	convert.bytes[6] = byte;
1621	byte = convert.bytes[2];
1622	convert.bytes[2] = convert.bytes[5];
1623	convert.bytes[5] = byte;
1624	byte = convert.bytes[3];
1625	convert.bytes[3] = convert.bytes[4];
1626	convert.bytes[4] = byte;
1627	return convert.value;
1628}
1629
1630void btRPCCreateAck(bt_outPacket *packet, unsigned int xid, int error)
1631{
1632	packet->size = BT_RPC_MIN_PACKET_SIZE;
1633	packet->buffer = (char *) malloc(packet->size);
1634	packet->length = 0;
1635
1636	if (!packet->buffer)
1637		return;
1638
1639	strcpy(packet->buffer, BT_RPC_SIGNATURE);
1640	packet->length += strlen(BT_RPC_SIGNATURE);
1641	btRPCPutInt32(packet, xid);
1642	btRPCPutInt32(packet, 0);
1643	btRPCPutInt32(packet, error);
1644}
1645
1646void btRPCSendAck(int client, bt_outPacket *packet)
1647{
1648	if (packet)
1649		if (packet->buffer)
1650		{
1651			*(int32 *)(&packet->buffer[9]) = B_HOST_TO_LENDIAN_INT32(packet->length - 13);
1652			btSendMsg(client, packet->buffer, packet->length, 0);
1653			free(packet->buffer);
1654		}
1655}
1656
1657unsigned char btRPCGetChar(bt_inPacket *packet)
1658{
1659	unsigned char value;
1660
1661	if (packet->offset < packet->length)
1662		value = (unsigned char) packet->buffer[packet->offset];
1663	else
1664		value = 0;
1665
1666	packet->offset += sizeof(value);
1667	return value;
1668}
1669
1670unsigned int btRPCGetInt32(bt_inPacket *packet)
1671{
1672	int32 value;
1673
1674	if (packet->offset < packet->length)
1675		value = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
1676	else
1677		value = 0;
1678
1679	packet->offset += sizeof(value);
1680	return value;
1681}
1682
1683int64 btRPCGetInt64(bt_inPacket *packet)
1684{
1685	int64 value;
1686
1687	if (packet->offset < packet->length)
1688		value = B_LENDIAN_TO_HOST_INT64(*((int64 *) &packet->buffer[packet->offset]));
1689	else
1690		value = 0;
1691
1692	packet->offset += sizeof(value);
1693	return value;
1694}
1695
1696char *btRPCGetNewString(bt_inPacket *packet)
1697{
1698	char *str;
1699	unsigned int bytes;
1700
1701	if (packet->offset >= packet->length)
1702		return NULL;
1703
1704	bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
1705	packet->offset += sizeof(bytes);
1706	if (bytes < 0 || bytes > BT_MAX_IO_BUFFER)
1707		return NULL;
1708
1709	str = (char *) malloc(bytes + 1);
1710	if (!str)
1711		return NULL;
1712
1713	if (bytes > 0)
1714		memcpy(str, &packet->buffer[packet->offset], bytes);
1715
1716	str[bytes] = 0;
1717	packet->offset += bytes;
1718
1719	return str;
1720}
1721
1722int btRPCGetString(bt_inPacket *packet, char *buffer, int length)
1723{
1724	unsigned int bytes;
1725
1726	if (packet->offset >= packet->length)
1727		return ERANGE;
1728
1729	bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
1730	packet->offset += sizeof(bytes);
1731	if (bytes < 0 || bytes > BT_MAX_IO_BUFFER)
1732		return ERANGE;
1733
1734	if (length < bytes)
1735		return ERANGE;
1736
1737	if (bytes > 0)
1738		memcpy(buffer, &packet->buffer[packet->offset], bytes);
1739
1740	packet->offset += bytes;
1741	return bytes;
1742}
1743
1744void btRPCGrowPacket(bt_outPacket *packet, int bytes)
1745{
1746	if (packet->length + bytes > packet->size)
1747	{
1748		int growth = ((bytes / BT_RPC_MIN_PACKET_SIZE) + 1) * BT_RPC_MIN_PACKET_SIZE;
1749		packet->buffer = (char *) realloc(packet->buffer, packet->size + growth);
1750		packet->size += growth;
1751	}
1752}
1753
1754void btRPCPutChar(bt_outPacket *packet, char value)
1755{
1756	btRPCGrowPacket(packet, sizeof(value));
1757	packet->buffer[packet->length] = value;
1758	packet->length += sizeof(value);
1759}
1760
1761void btRPCPutInt32(bt_outPacket *packet, int32 value)
1762{
1763	btRPCGrowPacket(packet, sizeof(value));
1764	*(int32 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT32(value);
1765	packet->length += sizeof(value);
1766}
1767
1768void btRPCPutInt64(bt_outPacket *packet, int64 value)
1769{
1770	btRPCGrowPacket(packet, sizeof(value));
1771	*(int64 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT64(value);
1772	packet->length += sizeof(value);
1773}
1774
1775void btRPCPutString(bt_outPacket *packet, char *buffer, int length)
1776{
1777	if (packet && buffer)
1778	{
1779		btRPCGrowPacket(packet, sizeof(length) + length);
1780		btRPCPutInt32(packet, length);
1781		memcpy(&packet->buffer[packet->length], buffer, length);
1782		packet->length += length;
1783	}
1784}
1785
1786void btRPCPutBinary(bt_outPacket *packet, void *buffer, int length)
1787{
1788	if (packet && buffer)
1789	{
1790		btRPCGrowPacket(packet, length);
1791		memcpy(&packet->buffer[packet->length], buffer, length);
1792		packet->length += length;
1793	}
1794}
1795
1796void btRPCGetStat(bt_inPacket *packet, beos_stat *st)
1797{
1798	st->st_dev = 0;
1799	st->st_nlink = btRPCGetInt32(packet);
1800	st->st_uid = btRPCGetInt32(packet);
1801	st->st_gid = btRPCGetInt32(packet);
1802	st->st_size = (int32) btRPCGetInt64(packet);
1803	st->st_blksize = btRPCGetInt32(packet);
1804	st->st_rdev = btRPCGetInt32(packet);
1805	st->st_ino = (int32) btRPCGetInt64(packet);
1806	st->st_mode = btRPCGetInt32(packet);
1807	st->st_atime = btRPCGetInt32(packet);
1808	st->st_mtime = btRPCGetInt32(packet);
1809	st->st_ctime = btRPCGetInt32(packet);
1810}
1811
1812void btRPCPutStat(bt_outPacket *packet, beos_stat *st)
1813{
1814	if (packet && st)
1815	{
1816		int64 size = (int64) st->st_size;
1817		int64 inode = (int64) st->st_ino;
1818
1819		btRPCPutInt32(packet, (int) st->st_nlink);
1820		btRPCPutInt32(packet, (int) st->st_uid);
1821		btRPCPutInt32(packet, (int) st->st_gid);
1822		btRPCPutInt64(packet, size);
1823		btRPCPutInt32(packet, (int) 1024);
1824		btRPCPutInt32(packet, (int) st->st_rdev);
1825		btRPCPutInt64(packet, inode);
1826		btRPCPutInt32(packet, (int) st->st_mode);
1827		btRPCPutInt32(packet, (int) st->st_atime);
1828		btRPCPutInt32(packet, (int) st->st_mtime);
1829		btRPCPutInt32(packet, (int) st->st_ctime);
1830	}
1831}
1832
1833////////////////////////////////////////////////////////////////////
1834
1835bt_node *btGetNodeFromVnid(vnode_id vnid)
1836{
1837	return (bt_node *) ubi_trFind(&vnidTree, &vnid);
1838}
1839
1840// btAddHandle()
1841//
1842void btAddHandle(vnode_id dir_vnid, vnode_id file_vnid, char *name)
1843{
1844	bt_node *vnidNode, *nameNode, *dirNode;
1845
1846	// We don't store the references to the current and the parent directory.
1847	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
1848		return;
1849
1850	beginWriting(&handleData);
1851
1852	// Obtain the parent node.  If no parent vnid is provided, then this must be
1853	// the root node.  The parent of the root node is NULL, but it should be the
1854	// only node for which this is true.
1855	if (dir_vnid)
1856		dirNode = btGetNodeFromVnid(dir_vnid);
1857	else
1858		dirNode = NULL;
1859
1860	// If a node already exists with the given vnid, then it is either a symbolic
1861	// link or an attempt to add the same node again, such as when mounting or
1862	// walking a directory tree.  If we find a matching vnid whose parent directory
1863	// and name also match, this is a duplicate and can be ignored.
1864	if (btGetNodeFromVnid(file_vnid))
1865	{
1866		endWriting(&handleData);
1867		return;
1868	}
1869
1870	// Allocate a new node for the vnid and name-based trees.  A separate node must exist for
1871	// each tree or the tree structure will go haywire.
1872	vnidNode = (bt_node *) malloc(sizeof(bt_node));
1873	if (vnidNode == NULL)
1874	{
1875		endWriting(&handleData);
1876		return;
1877	}
1878
1879	nameNode = (bt_node *) malloc(sizeof(bt_node));
1880	if (nameNode == NULL)
1881	{
1882		free(vnidNode);
1883		endWriting(&handleData);
1884		return;
1885	}
1886
1887	// Allocate memory for the file name itself.  This prevents huge memory consumption used by
1888	// a static buffer that assumes the worst case file name length.
1889	vnidNode->name = (char *) malloc(strlen(name) + 1);
1890	if (vnidNode->name == NULL)
1891	{
1892		free(nameNode);
1893		free(vnidNode);
1894		endWriting(&handleData);
1895		return;
1896	}
1897
1898	// Copy the name into the allocated buffer.
1899	strcpy(vnidNode->name, name);
1900
1901	nameNode->name = strdup(vnidNode->name);
1902	if (nameNode->name == NULL)
1903	{
1904		free(vnidNode->name);
1905		free(nameNode);
1906		free(vnidNode);
1907		endWriting(&handleData);
1908		return;
1909	}
1910
1911	// Copy over the vnid, and parent node.
1912	vnidNode->invalid = nameNode->invalid = false;
1913	vnidNode->vnid = nameNode->vnid = file_vnid;
1914	vnidNode->parent = nameNode->parent = dirNode;
1915
1916	// Now insert the new nodes into the tree.
1917	ubi_trInsert(&vnidTree, vnidNode, &vnidNode->vnid, NULL);
1918	ubi_trInsert(&nameTree, nameNode, nameNode, NULL);
1919
1920	endWriting(&handleData);
1921}
1922
1923// btRemoveHandle()
1924//
1925void btRemoveHandle(vnode_id vnid)
1926{
1927	bt_node *deadVnidNode, *deadNameNode;
1928
1929	beginWriting(&handleData);
1930
1931	deadVnidNode = (bt_node *) ubi_trFind(&vnidTree, &vnid);
1932	if (deadVnidNode)
1933	{
1934		ubi_trRemove(&vnidTree, deadVnidNode);
1935
1936		deadNameNode = (bt_node *) ubi_trFind(&nameTree, deadVnidNode);
1937		if (deadNameNode)
1938			ubi_trRemove(&nameTree, deadNameNode);
1939	}
1940
1941	endWriting(&handleData);
1942}
1943
1944// btPurgeNodes()
1945//
1946void btPurgeNodes(vnode_id vnid)
1947{
1948	bt_node *curNode;
1949	ubi_trNodePtr cur, next;
1950	ubi_trRootPtr tree;
1951	ubi_trRootPtr trees[] = { &vnidTree, &nameTree, NULL };
1952	int i;
1953
1954	beginWriting(&handleData);
1955
1956	// First loop through, marking this node and all its children as invalid.
1957	for (i = 0, tree = trees[i]; trees[i]; i++)
1958	{
1959		cur = ubi_trFirst(tree->root);
1960		while (cur)
1961		{
1962			next = ubi_trNext(cur);
1963
1964			curNode = (bt_node *) cur;
1965			if (curNode->vnid == vnid || btIsAncestorNode(vnid, curNode))
1966				curNode->invalid = true;
1967
1968			cur = next;
1969		}
1970
1971		// Now loop through again, removing all invalid nodes.  This prevents removing
1972		// a parent node and all its children being orphaned (with invalid pointers
1973		// back to the destroyed parent).
1974		cur = ubi_trFirst(tree->root);
1975		while (cur)
1976		{
1977			next = ubi_trNext(cur);
1978
1979			curNode = (bt_node *) cur;
1980			if (curNode->invalid)
1981			{
1982				ubi_trRemove(&vnidTree, curNode);
1983				free(curNode);
1984			}
1985
1986			cur = next;
1987		}
1988	}
1989
1990	endWriting(&handleData);
1991}
1992
1993// btIsAncestorNode()
1994//
1995bool btIsAncestorNode(vnode_id vnid, bt_node *node)
1996{
1997	bt_node *curNode = node->parent;
1998
1999	while (curNode)
2000	{
2001		if (curNode->vnid == vnid)
2002			return true;
2003
2004		curNode = curNode->parent;
2005	}
2006
2007	return false;
2008}
2009
2010// btGetLocalFileName()
2011//
2012char *btGetLocalFileName(char *path, vnode_id vnid)
2013{
2014	bt_node *node, *nodeStack[100];
2015	int stackSize;
2016
2017	path[0] = 0;
2018	stackSize = 1;
2019
2020	beginReading(&handleData);
2021
2022	node = btGetNodeFromVnid(vnid);
2023	if (node == NULL)
2024	{
2025		endReading(&handleData);
2026		return NULL;
2027	}
2028
2029	nodeStack[0] = node;
2030	while ((node = node->parent) != NULL)
2031		nodeStack[stackSize++] = node;
2032
2033	while (--stackSize >= 0)
2034	{
2035		strcat(path, nodeStack[stackSize]->name);
2036		if (stackSize)
2037		{
2038			int length = strlen(path);
2039			if (length > 0 && path[length - 1] != '\\')
2040				strcat(path, "\\");
2041		}
2042	}
2043
2044	endReading(&handleData);
2045	return path;
2046}
2047
2048bt_node *btFindNode(bt_node *parent, char *fileName)
2049{
2050	bt_node search, *node;
2051
2052	// Initialize the node for tree searching purposes.
2053	search.parent = parent;
2054	search.name = strdup(fileName);
2055	if (search.name == NULL)
2056		return NULL;
2057
2058	beginReading(&handleData);
2059	node = (bt_node *) ubi_trFind(&nameTree, &search);
2060	endReading(&handleData);
2061
2062	free(search.name);
2063	return node;
2064}
2065
2066char *btGetSharePath(char *shareName)
2067{
2068	int i;
2069
2070	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
2071		if (fileShares[i].used)
2072			if (stricmp(fileShares[i].name, shareName) == 0)
2073				return fileShares[i].path;
2074
2075	return NULL;
2076}
2077
2078int btGetShareId(char *shareName)
2079{
2080	int i;
2081
2082	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
2083		if (fileShares[i].used)
2084			if (stricmp(fileShares[i].name, shareName) == 0)
2085				return i;
2086
2087	return -1;
2088}
2089
2090int btGetShareIdByPath(char *path)
2091{
2092	int i;
2093
2094	for (i = 0; i < BT_MAX_FILE_SHARES; i++)
2095		if (fileShares[i].used)
2096			if (stricmp(fileShares[i].path, path) == 0)
2097				return i;
2098
2099	return -1;
2100}
2101
2102// btFindPrinter()
2103//
2104bt_printer *btFindPrinter(char *printerName)
2105{
2106	int i;
2107
2108	for (i = 0; i < BT_MAX_PRINTER_SHARES; i++)
2109		if (sharedPrinters[i].used)
2110			if (stricmp(printerName, sharedPrinters[i].printerName) == 0)
2111				return &sharedPrinters[i];
2112
2113	return NULL;
2114}
2115
2116void btGetRootPath(vnode_id vnid, char *path)
2117{
2118	bt_node *curNode;
2119
2120	beginReading(&handleData);
2121
2122	curNode = btGetNodeFromVnid(vnid);
2123	while (curNode && curNode->parent)
2124		curNode = curNode->parent;
2125
2126	if (curNode)
2127		strcpy(path, curNode->name);
2128	else
2129		path[0] = 0;
2130
2131	endReading(&handleData);
2132}
2133
2134uint32 btGetWinInode(const char *path)
2135{
2136	const int MAX_FOLDER_NESTING = 100;
2137	char *folders[MAX_FOLDER_NESTING + 1];
2138	char newPath[B_PATH_NAME_LENGTH + 1];
2139	int i, level, len, charSum;
2140
2141	// Subdivide the path into its components.
2142	char *p, *s = strdup(path);
2143	level = 0;
2144	folders[level++] = s;
2145	for (p = s; *p; p++)
2146		if (*p == '\\')
2147		{
2148			folders[level++] = p + 1;
2149			*p = 0;
2150		}
2151
2152	folders[level] = 0;
2153
2154	// Now look through the folders, to see if any are . and .. references.
2155	for (i = 0; i < level; i++)
2156		if (*folders[i])
2157			if (strcmp(folders[i], ".") == 0)
2158				folders[i] = NULL;
2159			else if (strcmp(folders[i], "..") == 0)
2160			{
2161				int j = i;
2162				folders[i] = 0;
2163				while (j > 0 && folders[j] == NULL)
2164					j--;
2165
2166				if (j >= 0)
2167					folders[j] = 0;
2168			}
2169
2170	// Now reconstruct the path without the folders eliminated above.
2171	newPath[0] = 0;
2172	for (i = 0; i < level; i++)
2173		if (folders[i])
2174		{
2175			strcat(newPath, folders[i]);
2176			if (i < level - 1)
2177				strcat(newPath, "\\");
2178		}
2179
2180	// If we eliminated folders at the end of the path, the level will have
2181	// resulted in a trailing backslash.
2182	len = strlen(newPath);
2183	if (newPath[len - 1] == '\\')
2184		newPath[--len] = 0;
2185
2186	// Now compute the checksum, i.e., inode number, using the revised path.
2187	free(s);
2188	p = newPath;
2189	for (charSum = len = 0; *p; p++, len++)
2190		charSum += (*p * len);
2191
2192	return ((len << 24) + charSum);
2193}
2194
2195int btGetBeosStat(char *fileName, beos_stat *st)
2196{
2197	struct _stat _st;
2198
2199	if (_stat(fileName, &_st) != 0)
2200		return BEOS_ENOENT;
2201
2202	st->st_atime = _st.st_atime;
2203	st->st_blksize = 1024;
2204	st->st_ctime = _st.st_ctime;
2205	st->st_dev = 0;
2206	st->st_gid = 0;
2207	st->st_uid = 0;
2208	st->st_ino = btGetWinInode(fileName);
2209	st->st_mode = _st.st_mode;
2210	st->st_mtime = _st.st_mtime;
2211	st->st_nlink = 0;
2212	st->st_rdev = 0;
2213	st->st_size = _st.st_size;
2214
2215	return B_OK;
2216}
2217
2218void btMakePath(char *path, char *dir, char *file)
2219{
2220	int length;
2221
2222	strcpy(path, dir);
2223	length = strlen(path);
2224	if (length > 0)
2225		if (path[length - 1] != '\\')
2226			strcat(path, "\\");
2227
2228	strcat(path, file);
2229}
2230
2231////////////////////////////////////////////////////////////////////
2232
2233int btPreMount(bt_session_t *session, char *shareName)
2234{
2235	// Look for the specified share name.  If it can't be found, check to see if it's
2236	// a printer.  If not, then there is no such resource available on this host.
2237	int shareId = btGetShareId(shareName);
2238	if (shareId < 0)
2239	{
2240		bt_printer *printer = btFindPrinter(shareName);
2241		if (!printer)
2242			return BEOS_ENOENT;
2243
2244		return printer->security;
2245	}
2246
2247	return fileShares[shareId].security;
2248}
2249
2250int btMount(bt_session_t *session, char *shareName, char *user, char *password, vnode_id *vnid)
2251{
2252	bt_user_rights *ur;
2253	struct stat st;
2254	char *path, *groups[MAX_GROUPS_PER_USER];
2255	int i, shareId;
2256	bool authenticated = false;
2257
2258	// Initialize the groups array.  We may need to release the memory later.
2259	for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2260		groups[i] = NULL;
2261
2262	// Look for the specified share name.  If it can't be found, it must no longer be
2263	// shared on this host.
2264	shareId = btGetShareId(shareName);
2265	if (shareId < 0)
2266		return BEOS_ENOENT;
2267
2268	if (fileShares[shareId].security != BT_AUTH_NONE)
2269	{
2270		// Authenticate the user with name/password.
2271		authenticated = authenticateUser(user, password);
2272		if (!authenticated)
2273			return BEOS_EACCES;
2274
2275		// Does the authenticated user have any rights on this file share?
2276		session->rights = 0;
2277		for (ur = fileShares[shareId].rights; ur; ur = ur->next)
2278			if (!ur->isGroup && stricmp(ur->user, user) == 0)
2279				session->rights |= ur->rights;
2280
2281		getUserGroups(user, groups);
2282		for (ur = fileShares[shareId].rights; ur; ur = ur->next)
2283			if (ur->isGroup)
2284				for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2285					if (groups[i] && stricmp(ur->user, groups[i]) == 0)
2286					{
2287						session->rights |= ur->rights;
2288						break;
2289					}
2290
2291		// Free the memory occupied by the group list.
2292		for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2293			if (groups[i])
2294				free(groups[i]);
2295
2296		// If no rights have been granted, deny access.
2297		if (session->rights == 0)
2298			return BEOS_EACCES;
2299
2300		// If write access has been globally disabled, this user's rights must be
2301		// correspondingly synchronized.
2302		if (fileShares[shareId].readOnly)
2303			session->rights = BT_RIGHTS_READ;
2304	}
2305	else
2306		session->rights = fileShares[shareId].readOnly
2307			? BT_RIGHTS_READ
2308			: BT_RIGHTS_READ | BT_RIGHTS_WRITE;
2309
2310	// Make sure the folder we want to share still exists.
2311	path = fileShares[shareId].path;
2312	if (stat(path, &st) != 0)
2313		return BEOS_ENOENT;
2314
2315	if (!S_ISDIR(st.st_mode))
2316		return BEOS_EACCES;
2317
2318	// Mark this session as owned by this user.
2319	strcpy(session->user, user);
2320	return B_OK;
2321}
2322
2323int btGetFSInfo(fs_info *fsInfo, char *path)
2324{
2325	DWORD secsPerClstr, bytesPerSec, freeClstrs, totalClstrs;
2326	char rootDir[5];
2327
2328	// We only want the root directory specification, not the entire path.
2329	strncpy(rootDir, path, 3);
2330	rootDir[3] = 0;
2331
2332	if (GetDiskFreeSpace(rootDir, &secsPerClstr, &bytesPerSec, &freeClstrs, &totalClstrs))
2333	{
2334		fsInfo->block_size = bytesPerSec;
2335		fsInfo->total_blocks = secsPerClstr * totalClstrs;
2336		fsInfo->free_blocks = secsPerClstr * freeClstrs;
2337		return B_OK;
2338	}
2339
2340	return ENOTSUP;
2341}
2342
2343int btLookup(char *pathBuf, vnode_id dir_vnid, char *fileName, vnode_id *file_vnid)
2344{
2345	struct _stat st;
2346	if (_stat(fileName, &st) != 0)
2347		return BEOS_ENOENT;
2348
2349	return B_OK;
2350}
2351
2352int btStat(char *pathBuf, vnode_id vnid, beos_stat *st)
2353{
2354	char *fileName;
2355	int error;
2356
2357	fileName = btGetLocalFileName(pathBuf, vnid);
2358	if (fileName)
2359	{
2360		error = btGetBeosStat(fileName, st);
2361		return error;
2362	}
2363
2364	return BEOS_ENOENT;
2365}
2366
2367int btReadDir(char *pathBuf, vnode_id dir_vnid, long **dir, vnode_id *file_vnid, char *filename, beos_stat *st)
2368{
2369	struct _finddata_t fileInfo;
2370	char *folder, path[B_PATH_NAME_LENGTH];
2371	long result = -1;
2372
2373	if (dir_vnid == 0 || !file_vnid || !filename)
2374		return EINVAL;
2375
2376	if (!*dir)
2377	{
2378		folder = btGetLocalFileName(pathBuf, dir_vnid);
2379		if (folder)
2380		{
2381			char search[B_PATH_NAME_LENGTH];
2382			btMakePath(search, folder, "*.*");
2383			result = _findfirst(search, &fileInfo);
2384			*dir = (long *) malloc(sizeof(long *));
2385			memcpy(*dir, &result, sizeof(result));
2386		}
2387	}
2388	else
2389		result = _findnext((long) **dir, &fileInfo);
2390
2391	if (result != -1)
2392	{
2393		folder = btGetLocalFileName(pathBuf, dir_vnid);
2394		if (folder)
2395		{
2396			btMakePath(path, folder, fileInfo.name);
2397			if (btGetBeosStat(path, st) != 0)
2398				return BEOS_ENOENT;
2399
2400			strcpy(filename, fileInfo.name);
2401			*file_vnid = (vnode_id) st->st_ino;
2402			btAddHandle(dir_vnid, *file_vnid, filename);
2403			return B_OK;
2404		}
2405	}
2406	else if (*dir)
2407	{
2408		_findclose((long) **dir);
2409		return BEOS_ENOENT;
2410	}
2411
2412	return EINVAL;
2413}
2414
2415int32 btRead(char *pathBuf, vnode_id vnid, beos_off_t pos, int32 len, char *buffer)
2416{
2417	char *path;
2418	int bytes;
2419
2420	path = btGetLocalFileName(pathBuf, vnid);
2421	if (path)
2422	{
2423		FILE *fp = fopen(path, "rb");
2424		if (!fp)
2425			return EACCES;
2426
2427		fseek(fp, (int) pos, SEEK_SET);
2428		bytes = fread(buffer, 1, len, fp);
2429		fclose(fp);
2430
2431		buffer[bytes] = 0;
2432		return bytes;
2433	}
2434
2435	return 0;
2436}
2437
2438int32 btWrite(bt_session_t *session, vnode_id vnid, beos_off_t pos, int32 len, int32 totalLen, char *buffer)
2439{
2440	bt_block *block;
2441
2442	// If we've been given a total length, then we have a new buffered write
2443	// session coming.  A block will need to be allocated.
2444	if (totalLen > 0)
2445	{
2446		// Make sure we don't have a wildly inaccurate total length to allocate.
2447		if (totalLen > 10 * 1024 * 1024)
2448			return 0;
2449
2450		// Allocate a new buffered I/O block.
2451		block = (bt_block *) malloc(sizeof(bt_block));
2452		if (block)
2453		{
2454			block->vnid = vnid;
2455			block->pos = pos;
2456			block->len = totalLen;
2457			block->count = 0;
2458
2459			block->buffer = (char *) malloc(totalLen + 1);
2460			if (!block->buffer)
2461			{
2462				free(block);
2463				return 0;
2464			}
2465
2466			btInsertWriteBlock(session, block);
2467		}
2468		else
2469			return 0;
2470	}
2471	else
2472	{
2473		block = btGetWriteBlock(session, vnid);
2474		if (!block)
2475			return 0;
2476	}
2477
2478	memcpy(block->buffer + block->count, buffer, len);
2479	block->count += len;
2480	return len;
2481}
2482
2483// btGetWriteBlock()
2484//
2485bt_block *btGetWriteBlock(bt_session_t *session, vnode_id vnid)
2486{
2487	bt_block *block;
2488
2489	WaitForSingleObject(session->blockSem, INFINITE);
2490
2491	block = session->rootBlock;
2492	while (block && block->vnid != vnid)
2493		block = block->next;
2494
2495	ReleaseSemaphore(session->blockSem, 1, NULL);
2496	return block;
2497}
2498
2499// btInsertWriteBlock()
2500//
2501void btInsertWriteBlock(bt_session_t *session, bt_block *block)
2502{
2503	WaitForSingleObject(session->blockSem, INFINITE);
2504
2505	block->next = session->rootBlock;
2506	block->prev = NULL;
2507	if (session->rootBlock)
2508		session->rootBlock->prev = block;
2509
2510	session->rootBlock = block;
2511
2512	ReleaseSemaphore(session->blockSem, 1, NULL);
2513}
2514
2515int btCommit(bt_session_t *session, vnode_id vnid)
2516{
2517	bt_block *block;
2518	char *path;
2519	int file;
2520
2521	// Get the full path for the specified file.
2522	path = btGetLocalFileName(session->pathBuffer, vnid);
2523	if (!path)
2524		return BEOS_ENOENT;
2525
2526	// Obtain the buffered I/O block.  If one can't be found, no buffered I/O
2527	// session was started for this vnode.
2528	block = btGetWriteBlock(session, vnid);
2529	if (!block)
2530		return BEOS_ENOENT;
2531
2532	// Open the file for writing.
2533	file = _open(path, _O_WRONLY | _O_CREAT | _O_BINARY);
2534	if (file < 0)
2535		return errno;
2536
2537	WaitForSingleObject(session->blockSem, INFINITE);
2538
2539	// Write the data.
2540	_lseek(file, (int32) block->pos, SEEK_SET);
2541	_write(file, block->buffer, block->len);
2542
2543	btRemoveWriteBlock(session, block);
2544	ReleaseSemaphore(session->blockSem, 1, NULL);
2545
2546	_close(file);
2547	return B_OK;
2548}
2549
2550void btRemoveWriteBlock(bt_session_t *session, bt_block *block)
2551{
2552	// If we're removing the root, then adjust the root block pointer.
2553	if (session->rootBlock == block)
2554		session->rootBlock = block->next;
2555
2556	// If there's a previous block, it should now point beyond this block.
2557	if (block->prev)
2558		block->prev->next = block->next;
2559
2560	// If there's a next block, it hsould now point to the current predecessor.
2561	if (block->next)
2562		block->next->prev = block->prev;
2563
2564	// Release the memory used by this block.
2565	free(block->buffer);
2566	free(block);
2567}
2568
2569int btCreate(char *pathBuf, vnode_id dir_vnid, char *name, int omode, int perms, vnode_id *file_vnid)
2570{
2571	beos_stat st;
2572	char path[B_PATH_NAME_LENGTH], *folder;
2573	int fh;
2574
2575	folder = btGetLocalFileName(pathBuf, dir_vnid);
2576	if (folder)
2577	{
2578		btMakePath(path, folder, name);
2579		fh = open(path, O_WRONLY | O_CREAT | O_TRUNC, _S_IREAD | _S_IWRITE);
2580		if (fh == -1)
2581			return errno;
2582		else
2583		{
2584			close(fh);
2585			if (btGetBeosStat(path, &st) == 0)
2586			{
2587				*file_vnid = (vnode_id) st.st_ino;
2588				btAddHandle(dir_vnid, *file_vnid, name);
2589			}
2590			else
2591				return BEOS_EACCES;
2592		}
2593	}
2594
2595	return B_OK;
2596}
2597
2598int btTruncate(char *pathBuf, vnode_id vnid, int64 len)
2599{
2600	char *path;
2601
2602	path = btGetLocalFileName(pathBuf, vnid);
2603	if (path)
2604	{
2605		FILE *fp = fopen(path, "w");
2606		fclose(fp);
2607		return B_OK;
2608	}
2609
2610	return BEOS_EACCES;
2611}
2612
2613// btCreateDir()
2614//
2615int btCreateDir(char *pathBuf, vnode_id dir_vnid, char *name, int perms, vnode_id *file_vnid, beos_stat *st)
2616{
2617	char path[B_PATH_NAME_LENGTH], *folder;
2618
2619	folder = btGetLocalFileName(pathBuf, dir_vnid);
2620	if (folder)
2621	{
2622		btMakePath(path, folder, name);
2623		if (_mkdir(path) == -1)
2624			return errno;
2625
2626		if (btGetBeosStat(path, st) != 0)
2627			return BEOS_ENOENT;
2628
2629		*file_vnid = (vnode_id) st->st_ino;
2630		btAddHandle(dir_vnid, *file_vnid, name);
2631		return B_OK;
2632	}
2633
2634	return BEOS_ENOENT;
2635}
2636
2637// btDeleteDir()
2638//
2639int btDeleteDir(char *pathBuf, vnode_id vnid, char *name)
2640{
2641	struct _stat st;
2642	char path[B_PATH_NAME_LENGTH], *folder;
2643
2644	folder = btGetLocalFileName(pathBuf, vnid);
2645	if (folder)
2646	{
2647		btMakePath(path, folder, name);
2648		if (_stat(path, &st) != 0)
2649			return errno;
2650
2651		if (_rmdir(path) == -1)
2652			return errno;
2653
2654		btPurgeNodes(btGetWinInode(path));
2655		return B_OK;
2656	}
2657
2658	return BEOS_ENOENT;
2659}
2660
2661// btRename()
2662//
2663int btRename(char *pathBuf, vnode_id old_vnid, char *oldName, vnode_id new_vnid, char *newName)
2664{
2665	struct _stat st;
2666	char oldPath[B_PATH_NAME_LENGTH], newPath[B_PATH_NAME_LENGTH], *oldFolder, *newFolder;
2667
2668	oldFolder = btGetLocalFileName(pathBuf, old_vnid);
2669	if (oldFolder)
2670	{
2671		btMakePath(oldPath, oldFolder, oldName);
2672
2673		newFolder = btGetLocalFileName(pathBuf, new_vnid);
2674		if (newFolder)
2675		{
2676			btMakePath(newPath, newFolder, newName);
2677
2678			if (_stat(oldPath, &st) != 0)
2679				return errno;
2680
2681			btPurgeNodes(btGetWinInode(oldPath));
2682
2683			if (rename(oldPath, newPath) == -1)
2684				return errno;
2685
2686			return B_OK;
2687		}
2688	}
2689
2690	return BEOS_ENOENT;
2691}
2692
2693// btUnlink()
2694//
2695int btUnlink(char *pathBuf, vnode_id vnid, char *name)
2696{
2697	struct _stat st;
2698	char path[B_PATH_NAME_LENGTH], *folder;
2699	int error;
2700
2701	folder = btGetLocalFileName(pathBuf, vnid);
2702	if (folder)
2703	{
2704		btMakePath(path, folder, name);
2705
2706		// Obtain the inode (vnid) of the specified file through stat().
2707		if (_stat(path, &st) != 0)
2708			return errno;
2709
2710		// Construct a dummy file descriptor and cause it to be removed from
2711		// the list.
2712		btRemoveHandle(btGetWinInode(path));
2713
2714		error = unlink(path);
2715		return (error == -1 ? errno : B_OK);
2716	}
2717
2718	return BEOS_EACCES;
2719}
2720
2721int btReadLink(char *pathBuf, vnode_id vnid, char *buffer, int length)
2722{
2723	return BEOS_ENOENT;
2724}
2725
2726int btSymLink(char *pathBuf, vnode_id vnid, char *name, char *dest)
2727{
2728	return BEOS_ENOENT;
2729}
2730
2731int btWStat(char *pathBuf, vnode_id vnid, long mask, int32 mode, int32 uid, int32 gid, int64 size, int32 atime, int32 mtime)
2732{
2733	struct _utimbuf ftimes;
2734	struct _stat st;
2735	char *path;
2736
2737	path = btGetLocalFileName(pathBuf, vnid);
2738	if (path)
2739	{
2740//		if (mask & WSTAT_MODE)
2741//			chmod(path, mode);
2742
2743//		if (mask & WSTAT_UID)
2744//			chown(path, uid, -1);
2745
2746//		if (mask & WSTAT_GID)
2747//			chown(path, -1, gid);
2748
2749//		if (mask & WSTAT_SIZE)
2750//			truncate(path, size);
2751
2752		if (_stat(path, &st) == 0)
2753			if (mask & WSTAT_ATIME || mask & WSTAT_MTIME)
2754			{
2755				ftimes.actime = mask & WSTAT_ATIME ? atime : st.st_atime;
2756				ftimes.modtime = mask & WSTAT_MTIME ? mtime : st.st_mtime;
2757				_utime(path, &ftimes);
2758			}
2759
2760		return B_OK;
2761	}
2762
2763	return BEOS_ENOENT;
2764}
2765
2766int btReadAttrib(char *pathBuf, vnode_id vnid, char *name, char *buffer)
2767{
2768	bt_mime_mapping *map;
2769	char *path;
2770
2771	path = btGetLocalFileName(pathBuf, vnid);
2772	if (path)
2773	{
2774		char *ext = strrchr(path, '.');
2775		if (ext)
2776		{
2777			ext++;
2778			for (map = mimeMap; map; map = map->next)
2779				if (stricmp(ext, map->extension) == 0)
2780				{
2781					strcpy(buffer, map->mimeType);
2782					return (strlen(buffer));
2783				}
2784		}
2785	}
2786
2787	return 0;
2788}
2789
2790int btAuthenticate(char *resource, char *user, char *password)
2791{
2792	bt_user_rights *ur, *rootUr;
2793	bt_printer *printer;
2794	char *groups[MAX_GROUPS_PER_USER];
2795	int i, rights, share;
2796	bool authenticated = false;
2797
2798	// Determine if the resource is a file share or a printer.
2799	share = btGetShareId(resource);
2800	if (share >= 0)
2801	{
2802		if (fileShares[share].security == BT_AUTH_NONE)
2803			return B_OK;
2804
2805		rootUr = fileShares[share].rights;
2806	}
2807	else
2808	{
2809		printer = btFindPrinter(resource);
2810		if (printer)
2811			if (printer->security == BT_AUTH_NONE)
2812				return B_OK;
2813
2814		rootUr = printer->rights;
2815	}
2816
2817	// Authenticate the user with name/password.
2818	authenticated = authenticateUser(user, password);
2819	if (!authenticated)
2820		return BEOS_EACCES;
2821
2822	// Does the authenticated user have any rights on this file share?
2823	rights = 0;
2824	for (ur = rootUr; ur; ur = ur->next)
2825		if (!ur->isGroup && stricmp(ur->user, user) == 0)
2826			rights |= ur->rights;
2827
2828	// Does the authenticated user belong to any groups that have any rights on this
2829	// file share?
2830	for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2831		groups[i] = NULL;
2832
2833	getUserGroups(user, groups);
2834	for (ur = rootUr; ur; ur = ur->next)
2835		if (ur->isGroup)
2836			for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2837				if (groups[i] && stricmp(ur->user, groups[i]) == 0)
2838				{
2839					rights |= ur->rights;
2840					break;
2841				}
2842
2843	// Free the memory occupied by the group list.
2844	for (i = 0; i < MAX_GROUPS_PER_USER; i++)
2845		if (groups[i])
2846			free(groups[i]);
2847
2848	// If no rights have been granted, deny access.
2849	if (!rights)
2850		return BEOS_EACCES;
2851
2852	return B_OK;
2853}
2854
2855////////////////////////////////////////////////////////////////////
2856
2857void netbtPreMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2858{
2859	bt_outPacket packet;
2860	int client, security;
2861
2862	client = session->socket;
2863	security = btPreMount(session, argv[0].data);
2864	btRPCCreateAck(&packet, xid, security);
2865	btRPCSendAck(session->socket, &packet);
2866}
2867
2868void netbtMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2869{
2870	bt_outPacket packet;
2871	vnode_id vnid;
2872	int client, error;
2873	char *shareName = argv[0].data;
2874	char *user = argv[1].data;
2875	char *password = argv[2].data;
2876
2877	client = session->socket;
2878
2879	error = btMount(session, shareName, user, password, &vnid);
2880	if (error == B_OK)
2881	{
2882		// Record this session having logged in to a specific share.
2883		session->share = btGetShareId(shareName);
2884		session->logon = time(NULL);
2885
2886		// Now send the client a response with the root vnid;
2887		btRPCCreateAck(&packet, xid, error);
2888		btRPCPutInt64(&packet, vnid);
2889	}
2890	else
2891		btRPCCreateAck(&packet, xid, error);
2892
2893	btRPCSendAck(client, &packet);
2894}
2895
2896void netbtFSInfo(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2897{
2898	bt_outPacket packet;
2899	int client, error;
2900	fs_info info;
2901
2902	client = session->socket;
2903
2904	error = btGetFSInfo(&info, fileShares[session->share].path);
2905	if (error == B_OK)
2906	{
2907		btRPCCreateAck(&packet, xid, error);
2908		btRPCPutInt32(&packet, info.block_size);
2909		btRPCPutInt32(&packet, info.total_blocks);
2910		btRPCPutInt32(&packet, info.free_blocks);
2911	}
2912	else
2913		btRPCCreateAck(&packet, xid, error);
2914
2915	btRPCSendAck(client, &packet);
2916}
2917
2918void netbtLookup(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2919{
2920	bt_outPacket packet;
2921	beos_stat st;
2922	int client, error;
2923	vnode_id dir_vnid = *((vnode_id *) argv[0].data);
2924	vnode_id file_vnid;
2925
2926	client = session->socket;
2927
2928	error = btLookup(session->pathBuffer, dir_vnid, argv[1].data, &file_vnid);
2929	if (error == B_OK)
2930		error = btStat(session->pathBuffer, file_vnid, &st);
2931
2932	if (error == B_OK)
2933	{
2934		btRPCCreateAck(&packet, xid, B_OK);
2935		btRPCPutInt64(&packet, file_vnid);
2936		btRPCPutStat(&packet, &st);
2937	}
2938	else
2939		btRPCCreateAck(&packet, xid, error);
2940
2941	btRPCSendAck(client, &packet);
2942}
2943
2944void netbtReadDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2945{
2946	const int MAX_FOLDER_ENTRIES = 128;
2947	bt_outPacket packet;
2948	beos_stat st;
2949	int client, error;
2950	vnode_id dir_vnid = *((vnode_id *) argv[0].data);
2951	vnode_id file_vnid;
2952	long *dir;
2953	char filename[B_PATH_NAME_LENGTH];
2954	int entries = 0;
2955
2956	client = session->socket;
2957
2958	dir = (long *)(*((int32 *) argv[1].data));
2959	error = btReadDir(session->pathBuffer, dir_vnid, &dir, &file_vnid, filename, &st);
2960
2961	if (error != B_OK)
2962	{
2963		btRPCCreateAck(&packet, xid, error);
2964		btRPCSendAck(client, &packet);
2965		return;
2966	}
2967
2968	btRPCCreateAck(&packet, xid, B_OK);
2969	while (error == B_OK)
2970	{
2971		btRPCPutInt64(&packet, file_vnid);
2972		btRPCPutString(&packet, filename, strlen(filename));
2973		btRPCPutInt32(&packet, (int32) dir);
2974		btRPCPutStat(&packet, &st);
2975
2976		if (++entries >= MAX_FOLDER_ENTRIES)
2977			break;
2978
2979		error = btReadDir(session->pathBuffer, dir_vnid, &dir, &file_vnid, filename, &st);
2980		btRPCPutInt32(&packet, error);
2981	}
2982
2983	// If we exhausted the list of directory entries without filling
2984	// the buffer, add an error message that will prevent the client
2985	// from requesting further entries.
2986	if (entries < MAX_FOLDER_ENTRIES)
2987		btRPCPutInt32(&packet, BEOS_ENOENT);
2988
2989	btRPCSendAck(client, &packet);
2990}
2991
2992void netbtStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
2993{
2994	bt_outPacket packet;
2995	int client, error;
2996	beos_stat info;
2997	vnode_id vnid = *((vnode_id *) argv[0].data);
2998
2999	client = session->socket;
3000
3001	error = btStat(session->pathBuffer, vnid, &info);
3002
3003	if (error == B_OK)
3004	{
3005		btRPCCreateAck(&packet, xid, error);
3006		btRPCPutStat(&packet, &info);
3007	}
3008	else
3009		btRPCCreateAck(&packet, xid, error);
3010
3011	btRPCSendAck(client, &packet);
3012}
3013
3014void netbtRead(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3015{
3016	bt_outPacket packet;
3017	int client;
3018	vnode_id vnid = *((vnode_id *) argv[0].data);
3019	beos_off_t pos = *((beos_off_t *) argv[1].data);
3020	int32 len = *((int32 *) argv[2].data);
3021	int32 bytes = 0;
3022
3023	client = session->socket;
3024
3025	session->ioBuffer[len] = 0;
3026	bytes = btRead(session->pathBuffer, vnid, pos, len, session->ioBuffer);
3027
3028	btRPCCreateAck(&packet, xid, B_OK);
3029	btRPCPutString(&packet, session->ioBuffer, bytes);
3030	btRPCSendAck(client, &packet);
3031}
3032
3033void netbtWrite(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3034{
3035	int client;
3036	vnode_id vnid = *((vnode_id *) argv[0].data);
3037	beos_off_t pos = *((beos_off_t *) argv[1].data);
3038	int32 len = *((int32 *) argv[2].data);
3039	int32 totalLen = *((int32 *) argv[3].data);
3040
3041	client = session->socket;
3042
3043	// If the file share this user is connected to is read-only, the command
3044	// cannot be honored.
3045	if (session->rights & BT_RIGHTS_WRITE)
3046		btWrite(session, vnid, pos, len, totalLen, argv[4].data);
3047}
3048
3049void netbtCreate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3050{
3051	bt_outPacket packet;
3052	beos_stat st;
3053	int client, error;
3054	vnode_id dir_vnid = *((vnode_id *) argv[0].data);
3055	vnode_id file_vnid;
3056	int omode = *((int *) argv[2].data);
3057	int perms = *((int *) argv[3].data);
3058
3059	client = session->socket;
3060
3061	// If the file share this user is connected to is read-only, the command
3062	// cannot be honored.
3063	if (!(session->rights & BT_RIGHTS_WRITE))
3064	{
3065		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3066		btRPCSendAck(client, &packet);
3067		return;
3068	}
3069
3070	error = btCreate(session->pathBuffer, dir_vnid, argv[1].data, omode, perms, &file_vnid);
3071	if (error == B_OK)
3072		error = btStat(session->pathBuffer, file_vnid, &st);
3073
3074	if (error == B_OK)
3075	{
3076		btRPCCreateAck(&packet, xid, B_OK);
3077		btRPCPutInt64(&packet, file_vnid);
3078		btRPCPutStat(&packet, &st);
3079	}
3080	else
3081		btRPCCreateAck(&packet, xid, error);
3082
3083	btRPCSendAck(client, &packet);
3084}
3085
3086void netbtTruncate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3087{
3088	bt_outPacket packet;
3089	int client, error;
3090	vnode_id vnid = *((vnode_id *) argv[0].data);
3091
3092	client = session->socket;
3093
3094	// If the file share this user is connected to is read-only, the command
3095	// cannot be honored.
3096	if (!(session->rights & BT_RIGHTS_WRITE))
3097	{
3098		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3099		btRPCSendAck(client, &packet);
3100		return;
3101	}
3102
3103	error = btTruncate(session->pathBuffer, vnid, *((int64 *) argv[1].data));
3104	btRPCCreateAck(&packet, xid, error);
3105	btRPCSendAck(client, &packet);
3106}
3107
3108void netbtUnlink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3109{
3110	bt_outPacket packet;
3111	int client, error;
3112	vnode_id vnid = *((vnode_id *) argv[0].data);
3113
3114	client = session->socket;
3115
3116	// If the file share this user is connected to is read-only, the command
3117	// cannot be honored.
3118	if (!(session->rights & BT_RIGHTS_WRITE))
3119	{
3120		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3121		btRPCSendAck(client, &packet);
3122		return;
3123	}
3124
3125	error = btUnlink(session->pathBuffer, vnid, argv[1].data);
3126	btRPCCreateAck(&packet, xid, error);
3127	btRPCSendAck(client, &packet);
3128}
3129
3130void netbtRename(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3131{
3132	bt_outPacket packet;
3133	int client, error;
3134	vnode_id old_vnid = *((vnode_id *) argv[0].data);
3135	vnode_id new_vnid = *((vnode_id *) argv[2].data);
3136
3137	client = session->socket;
3138
3139	// If the file share this user is connected to is read-only, the command
3140	// cannot be honored.
3141	if (!(session->rights & BT_RIGHTS_WRITE))
3142	{
3143		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3144		btRPCSendAck(client, &packet);
3145		return;
3146	}
3147
3148	error = btRename(session->pathBuffer, old_vnid, argv[1].data, new_vnid, argv[3].data);
3149	btRPCCreateAck(&packet, xid, error);
3150	btRPCSendAck(client, &packet);
3151}
3152
3153void netbtCreateDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3154{
3155	bt_outPacket packet;
3156	int client, error;
3157	vnode_id dir_vnid = *((vnode_id *) argv[0].data);
3158	vnode_id file_vnid;
3159	beos_stat st;
3160
3161	client = session->socket;
3162
3163	// If the file share this user is connected to is read-only, the command
3164	// cannot be honored.
3165	if (!(session->rights & BT_RIGHTS_WRITE))
3166	{
3167		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3168		btRPCSendAck(client, &packet);
3169		return;
3170	}
3171
3172	error = btCreateDir(session->pathBuffer, dir_vnid, argv[1].data, *((int *) argv[2].data), &file_vnid, &st);
3173	if (error == B_OK)
3174	{
3175		btRPCCreateAck(&packet, xid, B_OK);
3176		btRPCPutInt64(&packet, file_vnid);
3177		btRPCPutStat(&packet, &st);
3178	}
3179	else
3180		btRPCCreateAck(&packet, xid, error);
3181
3182	btRPCSendAck(client, &packet);
3183}
3184
3185void netbtDeleteDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3186{
3187	bt_outPacket packet;
3188	int client, error;
3189	vnode_id vnid = *((vnode_id *) argv[0].data);
3190
3191	client = session->socket;
3192
3193	// If the file share this user is connected to is read-only, the command
3194	// cannot be honored.
3195	if (!(session->rights & BT_RIGHTS_WRITE))
3196	{
3197		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3198		btRPCSendAck(client, &packet);
3199		return;
3200	}
3201
3202	error = btDeleteDir(session->pathBuffer, vnid, argv[1].data);
3203	btRPCCreateAck(&packet, xid, error);
3204	btRPCSendAck(client, &packet);
3205}
3206
3207void netbtReadLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3208{
3209	bt_outPacket packet;
3210	int client;
3211
3212	client = session->socket;
3213	btRPCCreateAck(&packet, xid, ENOTSUP);
3214	btRPCSendAck(client, &packet);
3215}
3216
3217void netbtSymLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3218{
3219	bt_outPacket packet;
3220	int client;
3221
3222	client = session->socket;
3223	btRPCCreateAck(&packet, xid, ENOTSUP);
3224	btRPCSendAck(client, &packet);
3225}
3226
3227void netbtWStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3228{
3229	bt_outPacket packet;
3230	int client, error;
3231	vnode_id vnid = *((vnode_id *) argv[0].data);
3232	int32 mask = *((int32 *) argv[1].data);
3233	int32 mode = *((int32 *) argv[2].data);
3234	int32 uid = *((int32 *) argv[3].data);
3235	int32 gid = *((int32 *) argv[4].data);
3236	int64 size = (int64) *((int32 *) argv[5].data);
3237	int32 atime = *((int32 *) argv[6].data);
3238	int32 mtime = *((int32 *) argv[7].data);
3239
3240	client = session->socket;
3241
3242	// If the file share this user is connected to is read-only, the command
3243	// cannot be honored.
3244	if (!(session->rights & BT_RIGHTS_WRITE))
3245	{
3246		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3247		btRPCSendAck(client, &packet);
3248		return;
3249	}
3250
3251	error = btWStat(session->pathBuffer, vnid, mask, mode, uid, gid, size, atime, mtime);
3252	btRPCCreateAck(&packet, xid, error);
3253	btRPCSendAck(client, &packet);
3254}
3255
3256void netbtReadAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3257{
3258	bt_outPacket packet;
3259	int client, bytesRead;
3260
3261	client = session->socket;
3262
3263	if (stricmp(argv[1].data, "BEOS:TYPE") == 0)
3264	{
3265		vnode_id vnid = *((vnode_id *) argv[0].data);
3266		bytesRead = btReadAttrib(session->pathBuffer, vnid, argv[1].data, session->attrBuffer);
3267		if (bytesRead > 0)
3268		{
3269			btRPCCreateAck(&packet, xid, B_OK);
3270			btRPCPutInt32(&packet, (int32) bytesRead + 1);
3271			btRPCPutString(&packet, session->attrBuffer, bytesRead + 1);
3272			btRPCSendAck(client, &packet);
3273			return;
3274		}
3275	}
3276
3277	btRPCCreateAck(&packet, xid, ENOTSUP);
3278	btRPCSendAck(client, &packet);
3279}
3280
3281void netbtWriteAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3282{
3283	bt_outPacket packet;
3284	int client;
3285
3286	client = session->socket;
3287	btRPCCreateAck(&packet, xid, ENOTSUP);
3288	btRPCSendAck(client, &packet);
3289}
3290
3291void netbtReadAttribDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3292{
3293	bt_outPacket packet;
3294	int client;
3295
3296	client = session->socket;
3297	btRPCCreateAck(&packet, xid, ENOTSUP);
3298	btRPCSendAck(client, &packet);
3299}
3300
3301void netbtRemoveAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3302{
3303	bt_outPacket packet;
3304	int client;
3305
3306	client = session->socket;
3307	btRPCCreateAck(&packet, xid, ENOTSUP);
3308	btRPCSendAck(client, &packet);
3309}
3310
3311void netbtStatAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3312{
3313	bt_outPacket packet;
3314	int client, bytesRead;
3315
3316	client = session->socket;
3317	if (strcmp(argv[1].data, "BEOS:TYPE") == 0)
3318	{
3319		vnode_id vnid = *((vnode_id *) argv[0].data);
3320		bytesRead = btReadAttrib(session->pathBuffer, vnid, argv[1].data, session->attrBuffer);
3321		btRPCCreateAck(&packet, xid, B_OK);
3322		btRPCPutInt32(&packet, B_STRING_TYPE);
3323		btRPCPutInt64(&packet, bytesRead + 1);
3324		btRPCSendAck(client, &packet);
3325		return;
3326	}
3327
3328	btRPCCreateAck(&packet, xid, ENOTSUP);
3329	btRPCSendAck(client, &packet);
3330}
3331
3332void netbtReadIndexDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3333{
3334	bt_outPacket packet;
3335	int client;
3336
3337	client = session->socket;
3338	btRPCCreateAck(&packet, xid, ENOTSUP);
3339	btRPCSendAck(client, &packet);
3340}
3341
3342void netbtCreateIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3343{
3344	bt_outPacket packet;
3345	int client;
3346
3347	client = session->socket;
3348	btRPCCreateAck(&packet, xid, ENOTSUP);
3349	btRPCSendAck(client, &packet);
3350}
3351
3352void netbtRemoveIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3353{
3354	bt_outPacket packet;
3355	int client;
3356
3357	client = session->socket;
3358	btRPCCreateAck(&packet, xid, ENOTSUP);
3359	btRPCSendAck(client, &packet);
3360}
3361
3362void netbtStatIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3363{
3364	bt_outPacket packet;
3365	int client;
3366
3367	client = session->socket;
3368	btRPCCreateAck(&packet, xid, ENOTSUP);
3369	btRPCSendAck(client, &packet);
3370}
3371
3372void netbtReadQuery(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3373{
3374	bt_outPacket packet;
3375	int client;
3376
3377	client = session->socket;
3378	btRPCCreateAck(&packet, xid, ENOTSUP);
3379	btRPCSendAck(client, &packet);
3380}
3381
3382void netbtCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3383{
3384	bt_outPacket packet;
3385	int client, error;
3386	vnode_id vnid = *((vnode_id *) argv[0].data);
3387
3388	client = session->socket;
3389
3390	// If the file share this user is connected to is read-only, the command
3391	// cannot be honored.
3392	if (!(session->rights & BT_RIGHTS_WRITE))
3393	{
3394		btRPCCreateAck(&packet, xid, BEOS_EACCES);
3395		btRPCSendAck(client, &packet);
3396		return;
3397	}
3398
3399	error = btCommit(session, vnid);
3400	btRPCCreateAck(&packet, xid, error);
3401	btRPCSendAck(client, &packet);
3402}
3403
3404void netbtPrintJobNew(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3405{
3406	bt_outPacket packet;
3407	int client, error;
3408	char jobId[MAX_NAME_LENGTH];
3409	char *printerName = argv[0].data;
3410	char *user = argv[1].data;
3411	char *password = argv[2].data;
3412	char *jobName = argv[3].data;
3413
3414	client = session->socket;
3415
3416	error = btPrintJobNew(printerName, user, password, session->client_s_addr, jobName, jobId);
3417	btRPCCreateAck(&packet, xid, error);
3418	if (error == B_OK)
3419		btRPCPutString(&packet, jobId, strlen(jobId));
3420
3421	btRPCSendAck(client, &packet);
3422}
3423
3424void netbtPrintJobData(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3425{
3426	bt_outPacket packet;
3427	int client, error;
3428	char *printerName = argv[0].data;
3429	char *jobId = argv[1].data;
3430	char *jobData = argv[2].data;
3431	int32 dataLen = *((int32 *) argv[3].data);
3432
3433	client = session->socket;
3434
3435	error = btPrintJobData(printerName, jobId, jobData, dataLen);
3436	btRPCCreateAck(&packet, xid, error);
3437	btRPCSendAck(client, &packet);
3438}
3439
3440void netbtPrintJobCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3441{
3442	bt_outPacket packet;
3443	int client, error;
3444	char *printerName = argv[0].data;
3445	char *jobId = argv[1].data;
3446
3447	client = session->socket;
3448
3449	error = btPrintJobCommit(printerName, jobId);
3450	btRPCCreateAck(&packet, xid, error);
3451	btRPCSendAck(client, &packet);
3452}
3453
3454void netbtAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3455{
3456	bt_outPacket packet;
3457	int client, error;
3458	char *resource = argv[0].data;
3459	char *user = argv[1].data;
3460	char *password = argv[2].data;
3461
3462	client = session->socket;
3463
3464	error = btAuthenticate(resource, user, password);
3465	btRPCCreateAck(&packet, xid, error);
3466	btRPCSendAck(client, &packet);
3467}
3468
3469void netbtQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
3470{
3471	bt_outPacket packet;
3472	int client;
3473
3474	client = session->socket;
3475	btRPCCreateAck(&packet, xid, B_OK);
3476	btRPCSendAck(client, &packet);
3477}
3478
3479/*
3480bool IsValidUser(char *user, char *domain, char *password)
3481{
3482	HANDLE hUser, hTok;
3483	OSVERSIONINFO osInfo;
3484	bool authenticated;
3485
3486	authenticated = false;
3487
3488	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
3489	if (GetVersionEx(&osInfo))
3490		if (osInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
3491			return true;
3492
3493	hTok = 0;
3494	if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hTok))
3495	{
3496		TOKEN_PRIVILEGES tp;
3497		tp.PrivilegeCount = 1;
3498		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
3499		if (LookupPrivilegeValue(0, SE_TCB_NAME, &tp.Privileges[0].Luid))
3500			if (AdjustTokenPrivileges(hTok, FALSE, &tp, 0, NULL, NULL))
3501				if (LogonUser(user, domain, password, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &hUser))
3502				{
3503					CloseHandle(hUser);
3504					authenticated = true;
3505				}
3506
3507		CloseHandle(hTok);
3508	}
3509
3510	return authenticated;
3511}
3512*/
3513
3514void loadFolder(const char *path)
3515{
3516	struct _finddata_t fileInfo;
3517	struct _stat st;
3518	char *search;
3519	long dir, result;
3520	uint32 dir_vnid;
3521
3522	search = (char *) malloc(MAX_PATH);
3523	if (search == NULL)
3524		return;
3525
3526	dir_vnid = btGetWinInode(path);
3527	sprintf(search, "%s\\*.*", path);
3528
3529	dir = result = _findfirst(search, &fileInfo);
3530	while (result != -1)
3531	{
3532		btMakePath(search, (char *) path, fileInfo.name);
3533		btAddHandle(dir_vnid, btGetWinInode(search), fileInfo.name);
3534
3535		_stat(search, &st);
3536		if (st.st_mode & _S_IFDIR)
3537			if (strcmp(fileInfo.name, ".") && strcmp(fileInfo.name, ".."))
3538				loadFolder(search);
3539
3540		result = _findnext(dir, &fileInfo);
3541	}
3542
3543	_findclose(dir);
3544	free(search);
3545}
3546
3547
3548
3549////////
3550
3551void KillNode(ubi_trNodePtr node)
3552{
3553	bt_node *bn = (bt_node *) node;
3554	free(bn->name);
3555	free(node);
3556}
3557
3558int CompareVnidNodes(ubi_trItemPtr item, ubi_trNodePtr node)
3559{
3560	vnode_id vnid1 = *((vnode_id *) item);
3561	vnode_id vnid2 = ((bt_node *) node)->vnid;
3562	if (vnid1 < vnid2)
3563		return -1;
3564	else if (vnid1 > vnid2)
3565		return 1;
3566	else
3567		return 0;
3568}
3569
3570int CompareNameNodes(ubi_trItemPtr item, ubi_trNodePtr node)
3571{
3572	bt_node *node1 = (bt_node *) item;
3573	bt_node *node2 = (bt_node *) node;
3574
3575	if (node1->parent < node2->parent)
3576		return -1;
3577	else if (node1->parent > node2->parent)
3578		return 1;
3579	else
3580		return strcmp(node1->name, node2->name);
3581}
3582