1/*
2   Unix SMB/Netbios implementation.
3   Version 2.0
4   SMB wrapper functions
5   Copyright (C) Andrew Tridgell 1998
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23#include "realcalls.h"
24
25pstring smbw_cwd;
26
27static struct smbw_file *smbw_files;
28static struct smbw_server *smbw_srvs;
29
30struct bitmap *smbw_file_bmap;
31extern pstring global_myname;
32extern int DEBUGLEVEL;
33
34fstring smbw_prefix = SMBW_PREFIX;
35
36int smbw_busy=0;
37
38/* needs to be here because of dumb include files on some systems */
39int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
40
41
42/*****************************************************
43initialise structures
44*******************************************************/
45void smbw_init(void)
46{
47	extern BOOL in_client;
48	static int initialised;
49	static pstring servicesf = CONFIGFILE;
50	extern FILE *dbf;
51	char *p;
52	int eno;
53	pstring line;
54
55	if (initialised) return;
56	initialised = 1;
57
58	eno = errno;
59
60	smbw_busy++;
61
62	DEBUGLEVEL = 0;
63	setup_logging("smbsh",True);
64
65	dbf = stderr;
66
67	if ((p=smbw_getshared("LOGFILE"))) {
68		dbf = sys_fopen(p, "a");
69	}
70
71	smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
72	if (!smbw_file_bmap) {
73		exit(1);
74	}
75
76	charset_initialise();
77
78	in_client = True;
79
80	load_interfaces();
81
82	lp_load(servicesf,True,False,False);
83
84	get_myname(global_myname);
85
86	if ((p=smbw_getshared("DEBUG"))) {
87		DEBUGLEVEL = atoi(p);
88	}
89
90	if ((p=smbw_getshared("RESOLVE_ORDER"))) {
91		lp_set_name_resolve_order(p);
92	}
93
94	if ((p=smbw_getshared("PREFIX"))) {
95		slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
96		all_string_sub(smbw_prefix,"//", "/", 0);
97		DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
98	}
99
100	slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
101
102	p = smbw_getshared(line);
103	if (!p) {
104		sys_getwd(smbw_cwd);
105	}
106	pstrcpy(smbw_cwd, p);
107	DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
108
109	smbw_busy--;
110
111	set_maxfiles(SMBW_MAX_OPEN);
112
113	BlockSignals(True,SIGPIPE);
114
115	errno = eno;
116}
117
118/*****************************************************
119determine if a file descriptor is a smb one
120*******************************************************/
121int smbw_fd(int fd)
122{
123	if (smbw_busy) return 0;
124	return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
125}
126
127/*****************************************************
128determine if a file descriptor is an internal smbw fd
129*******************************************************/
130int smbw_local_fd(int fd)
131{
132	struct smbw_server *srv;
133
134	smbw_init();
135
136	if (smbw_busy) return 0;
137	if (smbw_shared_fd(fd)) return 1;
138
139	for (srv=smbw_srvs;srv;srv=srv->next) {
140		if (srv->cli.fd == fd) return 1;
141	}
142
143	return 0;
144}
145
146/*****************************************************
147a crude inode number generator
148*******************************************************/
149ino_t smbw_inode(const char *name)
150{
151	if (!*name) return 2;
152	return (ino_t)str_checksum(name);
153}
154
155/*****************************************************
156remove redundent stuff from a filename
157*******************************************************/
158void clean_fname(char *name)
159{
160	char *p, *p2;
161	int l;
162	int modified = 1;
163
164	if (!name) return;
165
166	while (modified) {
167		modified = 0;
168
169		DEBUG(5,("cleaning %s\n", name));
170
171		if ((p=strstr(name,"/./"))) {
172			modified = 1;
173			while (*p) {
174				p[0] = p[2];
175				p++;
176			}
177		}
178
179		if ((p=strstr(name,"//"))) {
180			modified = 1;
181			while (*p) {
182				p[0] = p[1];
183				p++;
184			}
185		}
186
187		if (strcmp(name,"/../")==0) {
188			modified = 1;
189			name[1] = 0;
190		}
191
192		if ((p=strstr(name,"/../"))) {
193			modified = 1;
194			for (p2=(p>name?p-1:p);p2>name;p2--) {
195				if (p2[0] == '/') break;
196			}
197			while (*p2) {
198				p2[0] = p2[3];
199				p2++;
200			}
201		}
202
203		if (strcmp(name,"/..")==0) {
204			modified = 1;
205			name[1] = 0;
206		}
207
208		l = strlen(name);
209		p = l>=3?(name+l-3):name;
210		if (strcmp(p,"/..")==0) {
211			modified = 1;
212			for (p2=p-1;p2>name;p2--) {
213				if (p2[0] == '/') break;
214			}
215			if (p2==name) {
216				p[0] = '/';
217				p[1] = 0;
218			} else {
219				p2[0] = 0;
220			}
221		}
222
223		l = strlen(name);
224		p = l>=2?(name+l-2):name;
225		if (strcmp(p,"/.")==0) {
226			if (p == name) {
227				p[1] = 0;
228			} else {
229				p[0] = 0;
230			}
231		}
232
233		if (strncmp(p=name,"./",2) == 0) {
234			modified = 1;
235			do {
236				p[0] = p[2];
237			} while (*p++);
238		}
239
240		l = strlen(p=name);
241		if (l > 1 && p[l-1] == '/') {
242			modified = 1;
243			p[l-1] = 0;
244		}
245	}
246}
247
248
249/*****************************************************
250parse a smb path into its components.
251*******************************************************/
252char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
253{
254	static pstring s;
255	char *p, *p2;
256	int len = strlen(smbw_prefix)-1;
257
258	*server = *share = *path = 0;
259
260	if (fname[0] == '/') {
261		pstrcpy(s, fname);
262	} else {
263		slprintf(s,sizeof(s)-1, "%s/%s", smbw_cwd, fname);
264	}
265	clean_fname(s);
266
267	DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n",
268		 s, fname, smbw_cwd));
269
270	if (strncmp(s,smbw_prefix,len) ||
271	    (s[len] != '/' && s[len] != 0)) return s;
272
273	p = s + len;
274	if (*p == '/') p++;
275
276	p2 = strchr(p,'/');
277
278	if (p2) {
279		len = (int)(p2-p);
280	} else {
281		len = strlen(p);
282	}
283
284	len = MIN(len,sizeof(fstring)-1);
285
286	strncpy(server, p, len);
287	server[len] = 0;
288
289	p = p2;
290	if (!p) {
291		if (len == 0) {
292			char *workgroup = smbw_getshared("WORKGROUP");
293			if (!workgroup) workgroup = lp_workgroup();
294			slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup);
295		}
296		fstrcpy(share,"IPC$");
297		pstrcpy(path,"");
298		goto ok;
299	}
300
301	p++;
302	p2 = strchr(p,'/');
303
304	if (p2) {
305		len = (int)(p2-p);
306	} else {
307		len = strlen(p);
308	}
309
310	len = MIN(len,sizeof(fstring)-1);
311
312	strncpy(share, p, len);
313	share[len] = 0;
314
315	p = p2;
316	if (!p) {
317		pstrcpy(path,"\\");
318		goto ok;
319	}
320
321	pstrcpy(path,p);
322
323	all_string_sub(path, "/", "\\", 0);
324
325 ok:
326	DEBUG(4,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n",
327		 fname, smbw_cwd,
328		 server, share, path));
329
330	return s;
331}
332
333/*****************************************************
334determine if a path name (possibly relative) is in the
335smb name space
336*******************************************************/
337int smbw_path(const char *path)
338{
339	fstring server, share;
340	pstring s;
341	char *cwd;
342	int len;
343
344	if(!path)
345		return 0;
346
347	/* this is needed to prevent recursion with the BSD malloc which
348	   opens /etc/malloc.conf on the first call */
349	if (strncmp(path,"/etc/", 5) == 0) {
350		return 0;
351	}
352
353	smbw_init();
354
355	len = strlen(smbw_prefix)-1;
356
357	if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
358		return 0;
359	}
360
361	if (smbw_busy) return 0;
362
363	DEBUG(3,("smbw_path(%s)\n", path));
364
365	cwd = smbw_parse_path(path, server, share, s);
366
367	if (strncmp(cwd,smbw_prefix,len) == 0 &&
368	    (cwd[len] == '/' || cwd[len] == 0)) {
369		return 1;
370	}
371
372	return 0;
373}
374
375/*****************************************************
376return a unix errno from a SMB error pair
377*******************************************************/
378int smbw_errno(struct cli_state *c)
379{
380	uint8 eclass;
381	uint32 ecode;
382	int ret;
383
384	ret = cli_error(c, &eclass, &ecode, NULL);
385
386	if (ret) {
387		DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
388			 (int)eclass, (int)ecode, (int)ecode, ret));
389	}
390	return ret;
391}
392
393/*****************************************************
394return a connection to a server (existing or new)
395*******************************************************/
396struct smbw_server *smbw_server(char *server, char *share)
397{
398	struct smbw_server *srv=NULL;
399	struct cli_state c;
400	char *username;
401	char *password;
402	char *workgroup;
403	struct nmb_name called, calling;
404	char *p, *server_n = server;
405	fstring group;
406	pstring ipenv;
407	struct in_addr ip;
408	extern struct in_addr ipzero;
409
410	ip = ipzero;
411	ZERO_STRUCT(c);
412
413	username = smbw_getshared("USER");
414	if (!username) username = getenv("USER");
415	if (!username) username = "guest";
416
417	workgroup = smbw_getshared("WORKGROUP");
418	if (!workgroup) workgroup = lp_workgroup();
419
420	password = smbw_getshared("PASSWORD");
421	if (!password) password = "";
422
423	/* try to use an existing connection */
424	for (srv=smbw_srvs;srv;srv=srv->next) {
425		if (strcmp(server,srv->server_name)==0 &&
426		    strcmp(share,srv->share_name)==0) return srv;
427	}
428
429	if (server[0] == 0) {
430		errno = EPERM;
431		return NULL;
432	}
433
434	make_nmb_name(&calling, global_myname, 0x0);
435	make_nmb_name(&called , server, 0x20);
436
437	DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
438
439	if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) {
440		struct in_addr sip;
441		pstring s;
442
443		fstrcpy(group, server_n);
444		p = strchr(group,'#');
445		*p = 0;
446
447		/* cache the workgroup master lookup */
448		slprintf(s,sizeof(s)-1,"MASTER_%s", group);
449		if (!(server_n = smbw_getshared(s))) {
450			if (!find_master_ip(group, &sip)) {
451				errno = ENOENT;
452				return NULL;
453			}
454			fstrcpy(group, inet_ntoa(sip));
455			server_n = group;
456			smbw_setshared(s,server_n);
457		}
458	}
459
460	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
461
462 again:
463	slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
464
465	ip = ipzero;
466	if ((p=smbw_getshared(ipenv))) {
467		ip = *(interpret_addr2(p));
468	}
469
470	/* have to open a new connection */
471	if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
472		errno = ENOENT;
473		return NULL;
474	}
475
476	if (!cli_session_request(&c, &calling, &called)) {
477		cli_shutdown(&c);
478		if (strcmp(called.name, "*SMBSERVER")) {
479			make_nmb_name(&called , "*SMBSERVER", 0x20);
480			goto again;
481		}
482		errno = ENOENT;
483		return NULL;
484	}
485
486	DEBUG(4,(" session request ok\n"));
487
488	if (!cli_negprot(&c)) {
489		cli_shutdown(&c);
490		errno = ENOENT;
491		return NULL;
492	}
493
494	if (!cli_session_setup(&c, username,
495			       password, strlen(password),
496			       password, strlen(password),
497			       workgroup) &&
498	    /* try an anonymous login if it failed */
499	    !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
500		cli_shutdown(&c);
501		errno = EPERM;
502		return NULL;
503	}
504
505	DEBUG(4,(" session setup ok\n"));
506
507	if (!cli_send_tconX(&c, share, "?????",
508			    password, strlen(password)+1)) {
509		errno = smbw_errno(&c);
510		cli_shutdown(&c);
511		return NULL;
512	}
513
514	smbw_setshared(ipenv,inet_ntoa(ip));
515
516	DEBUG(4,(" tconx ok\n"));
517
518	srv = (struct smbw_server *)malloc(sizeof(*srv));
519	if (!srv) {
520		errno = ENOMEM;
521		goto failed;
522	}
523
524	ZERO_STRUCTP(srv);
525
526	srv->cli = c;
527
528	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
529
530	srv->server_name = strdup(server);
531	if (!srv->server_name) {
532		errno = ENOMEM;
533		goto failed;
534	}
535
536	srv->share_name = strdup(share);
537	if (!srv->share_name) {
538		errno = ENOMEM;
539		goto failed;
540	}
541
542	/* some programs play with file descriptors fairly intimately. We
543	   try to get out of the way by duping to a high fd number */
544	if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
545		if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
546		    srv->cli.fd+SMBW_CLI_FD) {
547			close(srv->cli.fd);
548			srv->cli.fd += SMBW_CLI_FD;
549		}
550	}
551
552	DLIST_ADD(smbw_srvs, srv);
553
554	return srv;
555
556 failed:
557	cli_shutdown(&c);
558	if (!srv) return NULL;
559
560	if (srv->server_name) free(srv->server_name);
561	if (srv->share_name) free(srv->share_name);
562	free(srv);
563	return NULL;
564}
565
566
567/*****************************************************
568map a fd to a smbw_file structure
569*******************************************************/
570struct smbw_file *smbw_file(int fd)
571{
572	struct smbw_file *file;
573
574	for (file=smbw_files;file;file=file->next) {
575		if (file->fd == fd) return file;
576	}
577	return NULL;
578}
579
580/*****************************************************
581a wrapper for open()
582*******************************************************/
583int smbw_open(const char *fname, int flags, mode_t mode)
584{
585	fstring server, share;
586	pstring path;
587	struct smbw_server *srv=NULL;
588	int eno=0, fd = -1;
589	struct smbw_file *file=NULL;
590
591	smbw_init();
592
593	if (!fname) {
594		errno = EINVAL;
595		return -1;
596	}
597
598	smbw_busy++;
599
600	/* work out what server they are after */
601	smbw_parse_path(fname, server, share, path);
602
603	/* get a connection to the server */
604	srv = smbw_server(server, share);
605	if (!srv) {
606		/* smbw_server sets errno */
607		goto failed;
608	}
609
610	if (path[strlen(path)-1] == '\\') {
611		fd = -1;
612	} else {
613		fd = cli_open(&srv->cli, path, flags, DENY_NONE);
614	}
615	if (fd == -1) {
616		/* it might be a directory. Maybe we should use chkpath? */
617		eno = smbw_errno(&srv->cli);
618		fd = smbw_dir_open(fname);
619		if (fd == -1) errno = eno;
620		smbw_busy--;
621		return fd;
622	}
623
624	file = (struct smbw_file *)malloc(sizeof(*file));
625	if (!file) {
626		errno = ENOMEM;
627		goto failed;
628	}
629
630	ZERO_STRUCTP(file);
631
632	file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
633	if (!file->f) {
634		errno = ENOMEM;
635		goto failed;
636	}
637
638	ZERO_STRUCTP(file->f);
639
640	file->f->cli_fd = fd;
641	file->f->fname = strdup(path);
642	if (!file->f->fname) {
643		errno = ENOMEM;
644		goto failed;
645	}
646	file->srv = srv;
647	file->fd = open(SMBW_DUMMY, O_WRONLY);
648	if (file->fd == -1) {
649		errno = EMFILE;
650		goto failed;
651	}
652
653	if (bitmap_query(smbw_file_bmap, file->fd)) {
654		DEBUG(0,("ERROR: fd used in smbw_open\n"));
655		errno = EIO;
656		goto failed;
657	}
658
659	file->f->ref_count=1;
660
661	bitmap_set(smbw_file_bmap, file->fd);
662
663	DLIST_ADD(smbw_files, file);
664
665	DEBUG(4,("opened %s\n", fname));
666
667	smbw_busy--;
668	return file->fd;
669
670 failed:
671	if (fd != -1) {
672		cli_close(&srv->cli, fd);
673	}
674	if (file) {
675		if (file->f) {
676			if (file->f->fname) {
677				free(file->f->fname);
678			}
679			free(file->f);
680		}
681		free(file);
682	}
683	smbw_busy--;
684	return -1;
685}
686
687
688/*****************************************************
689a wrapper for pread()
690*******************************************************/
691ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
692{
693	struct smbw_file *file;
694	int ret;
695
696	smbw_busy++;
697
698	file = smbw_file(fd);
699	if (!file) {
700		errno = EBADF;
701		smbw_busy--;
702		return -1;
703	}
704
705	ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
706
707	if (ret == -1) {
708		errno = smbw_errno(&file->srv->cli);
709		smbw_busy--;
710		return -1;
711	}
712
713	smbw_busy--;
714	return ret;
715}
716
717/*****************************************************
718a wrapper for read()
719*******************************************************/
720ssize_t smbw_read(int fd, void *buf, size_t count)
721{
722	struct smbw_file *file;
723	int ret;
724
725	DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
726
727	smbw_busy++;
728
729	file = smbw_file(fd);
730	if (!file) {
731		errno = EBADF;
732		smbw_busy--;
733		return -1;
734	}
735
736	ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
737		       file->f->offset, count);
738
739	if (ret == -1) {
740		errno = smbw_errno(&file->srv->cli);
741		smbw_busy--;
742		return -1;
743	}
744
745	file->f->offset += ret;
746
747	DEBUG(4,(" -> %d\n", ret));
748
749	smbw_busy--;
750	return ret;
751}
752
753
754
755/*****************************************************
756a wrapper for write()
757*******************************************************/
758ssize_t smbw_write(int fd, void *buf, size_t count)
759{
760	struct smbw_file *file;
761	int ret;
762
763	smbw_busy++;
764
765	file = smbw_file(fd);
766	if (!file) {
767		errno = EBADF;
768		smbw_busy--;
769		return -1;
770	}
771
772	ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
773
774	if (ret == -1) {
775		errno = smbw_errno(&file->srv->cli);
776		smbw_busy--;
777		return -1;
778	}
779
780	file->f->offset += ret;
781
782	smbw_busy--;
783	return ret;
784}
785
786/*****************************************************
787a wrapper for pwrite()
788*******************************************************/
789ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
790{
791	struct smbw_file *file;
792	int ret;
793
794	smbw_busy++;
795
796	file = smbw_file(fd);
797	if (!file) {
798		errno = EBADF;
799		smbw_busy--;
800		return -1;
801	}
802
803	ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
804
805	if (ret == -1) {
806		errno = smbw_errno(&file->srv->cli);
807		smbw_busy--;
808		return -1;
809	}
810
811	smbw_busy--;
812	return ret;
813}
814
815/*****************************************************
816a wrapper for close()
817*******************************************************/
818int smbw_close(int fd)
819{
820	struct smbw_file *file;
821
822	smbw_busy++;
823
824	file = smbw_file(fd);
825	if (!file) {
826		int ret = smbw_dir_close(fd);
827		smbw_busy--;
828		return ret;
829	}
830
831	if (file->f->ref_count == 1 &&
832	    !cli_close(&file->srv->cli, file->f->cli_fd)) {
833		errno = smbw_errno(&file->srv->cli);
834		smbw_busy--;
835		return -1;
836	}
837
838
839	bitmap_clear(smbw_file_bmap, file->fd);
840	close(file->fd);
841
842	DLIST_REMOVE(smbw_files, file);
843
844	file->f->ref_count--;
845	if (file->f->ref_count == 0) {
846		free(file->f->fname);
847		free(file->f);
848	}
849	ZERO_STRUCTP(file);
850	free(file);
851
852	smbw_busy--;
853
854	return 0;
855}
856
857
858/*****************************************************
859a wrapper for fcntl()
860*******************************************************/
861int smbw_fcntl(int fd, int cmd, long arg)
862{
863	return 0;
864}
865
866
867/*****************************************************
868a wrapper for access()
869*******************************************************/
870int smbw_access(const char *name, int mode)
871{
872	struct stat st;
873
874	DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
875
876	if (smbw_stat(name, &st)) return -1;
877
878	if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
879	    ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
880	    ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
881		errno = EACCES;
882		return -1;
883	}
884
885	return 0;
886}
887
888/*****************************************************
889a wrapper for realink() - needed for correct errno setting
890*******************************************************/
891int smbw_readlink(const char *path, char *buf, size_t bufsize)
892{
893	struct stat st;
894	int ret;
895
896	ret = smbw_stat(path, &st);
897	if (ret != 0) {
898		DEBUG(4,("readlink(%s) failed\n", path));
899		return -1;
900	}
901
902	/* it exists - say it isn't a link */
903	DEBUG(4,("readlink(%s) not a link\n", path));
904
905	errno = EINVAL;
906	return -1;
907}
908
909
910/*****************************************************
911a wrapper for unlink()
912*******************************************************/
913int smbw_unlink(const char *fname)
914{
915	struct smbw_server *srv;
916	fstring server, share;
917	pstring path;
918
919	if (!fname) {
920		errno = EINVAL;
921		return -1;
922	}
923
924	smbw_init();
925
926	smbw_busy++;
927
928	/* work out what server they are after */
929	smbw_parse_path(fname, server, share, path);
930
931	/* get a connection to the server */
932	srv = smbw_server(server, share);
933	if (!srv) {
934		/* smbw_server sets errno */
935		goto failed;
936	}
937
938	if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
939		int job = smbw_stat_printjob(srv, path, NULL, NULL);
940		if (job == -1) {
941			goto failed;
942		}
943		if (cli_printjob_del(&srv->cli, job) != 0) {
944			goto failed;
945		}
946	} else if (!cli_unlink(&srv->cli, path)) {
947		errno = smbw_errno(&srv->cli);
948		goto failed;
949	}
950
951	smbw_busy--;
952	return 0;
953
954 failed:
955	smbw_busy--;
956	return -1;
957}
958
959
960/*****************************************************
961a wrapper for rename()
962*******************************************************/
963int smbw_rename(const char *oldname, const char *newname)
964{
965	struct smbw_server *srv;
966	fstring server1, share1;
967	pstring path1;
968	fstring server2, share2;
969	pstring path2;
970
971	if (!oldname || !newname) {
972		errno = EINVAL;
973		return -1;
974	}
975
976	smbw_init();
977
978	DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
979
980	smbw_busy++;
981
982	/* work out what server they are after */
983	smbw_parse_path(oldname, server1, share1, path1);
984	smbw_parse_path(newname, server2, share2, path2);
985
986	if (strcmp(server1, server2) || strcmp(share1, share2)) {
987		/* can't cross filesystems */
988		errno = EXDEV;
989		return -1;
990	}
991
992	/* get a connection to the server */
993	srv = smbw_server(server1, share1);
994	if (!srv) {
995		/* smbw_server sets errno */
996		goto failed;
997	}
998
999	if (!cli_rename(&srv->cli, path1, path2)) {
1000		int eno = smbw_errno(&srv->cli);
1001		if (eno != EEXIST ||
1002		    !cli_unlink(&srv->cli, path2) ||
1003		    !cli_rename(&srv->cli, path1, path2)) {
1004			errno = eno;
1005			goto failed;
1006		}
1007	}
1008
1009	smbw_busy--;
1010	return 0;
1011
1012 failed:
1013	smbw_busy--;
1014	return -1;
1015}
1016
1017
1018/*****************************************************
1019a wrapper for utime and utimes
1020*******************************************************/
1021static int smbw_settime(const char *fname, time_t t)
1022{
1023	struct smbw_server *srv;
1024	fstring server, share;
1025	pstring path;
1026	uint16 mode;
1027
1028	if (!fname) {
1029		errno = EINVAL;
1030		return -1;
1031	}
1032
1033	smbw_init();
1034
1035	smbw_busy++;
1036
1037	/* work out what server they are after */
1038	smbw_parse_path(fname, server, share, path);
1039
1040	/* get a connection to the server */
1041	srv = smbw_server(server, share);
1042	if (!srv) {
1043		/* smbw_server sets errno */
1044		goto failed;
1045	}
1046
1047	if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1048		errno = smbw_errno(&srv->cli);
1049		goto failed;
1050	}
1051
1052	if (!cli_setatr(&srv->cli, path, mode, t)) {
1053		/* some servers always refuse directory changes */
1054		if (!(mode & aDIR)) {
1055			errno = smbw_errno(&srv->cli);
1056			goto failed;
1057		}
1058	}
1059
1060	smbw_busy--;
1061	return 0;
1062
1063 failed:
1064	smbw_busy--;
1065	return -1;
1066}
1067
1068/*****************************************************
1069a wrapper for utime
1070*******************************************************/
1071int smbw_utime(const char *fname, void *buf)
1072{
1073	struct utimbuf *tbuf = (struct utimbuf *)buf;
1074	return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1075}
1076
1077/*****************************************************
1078a wrapper for utime
1079*******************************************************/
1080int smbw_utimes(const char *fname, void *buf)
1081{
1082	struct timeval *tbuf = (struct timeval *)buf;
1083	return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1084}
1085
1086
1087/*****************************************************
1088a wrapper for chown()
1089*******************************************************/
1090int smbw_chown(const char *fname, uid_t owner, gid_t group)
1091{
1092	struct smbw_server *srv;
1093	fstring server, share;
1094	pstring path;
1095	uint16 mode;
1096
1097	if (!fname) {
1098		errno = EINVAL;
1099		return -1;
1100	}
1101
1102	smbw_init();
1103
1104	smbw_busy++;
1105
1106	/* work out what server they are after */
1107	smbw_parse_path(fname, server, share, path);
1108
1109	/* get a connection to the server */
1110	srv = smbw_server(server, share);
1111	if (!srv) {
1112		/* smbw_server sets errno */
1113		goto failed;
1114	}
1115
1116	if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1117		errno = smbw_errno(&srv->cli);
1118		goto failed;
1119	}
1120
1121	/* assume success */
1122
1123	smbw_busy--;
1124	return 0;
1125
1126 failed:
1127	smbw_busy--;
1128	return -1;
1129}
1130
1131/*****************************************************
1132a wrapper for chmod()
1133*******************************************************/
1134int smbw_chmod(const char *fname, mode_t newmode)
1135{
1136	struct smbw_server *srv;
1137	fstring server, share;
1138	pstring path;
1139	uint32 mode;
1140
1141	if (!fname) {
1142		errno = EINVAL;
1143		return -1;
1144	}
1145
1146	smbw_init();
1147
1148	smbw_busy++;
1149
1150	/* work out what server they are after */
1151	smbw_parse_path(fname, server, share, path);
1152
1153	/* get a connection to the server */
1154	srv = smbw_server(server, share);
1155	if (!srv) {
1156		/* smbw_server sets errno */
1157		goto failed;
1158	}
1159
1160	mode = 0;
1161
1162	if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1163	if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1164	if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1165	if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1166
1167	if (!cli_setatr(&srv->cli, path, mode, 0)) {
1168		errno = smbw_errno(&srv->cli);
1169		goto failed;
1170	}
1171
1172	smbw_busy--;
1173	return 0;
1174
1175 failed:
1176	smbw_busy--;
1177	return -1;
1178}
1179
1180/*****************************************************
1181a wrapper for lseek()
1182*******************************************************/
1183off_t smbw_lseek(int fd, off_t offset, int whence)
1184{
1185	struct smbw_file *file;
1186	size_t size;
1187
1188	smbw_busy++;
1189
1190	file = smbw_file(fd);
1191	if (!file) {
1192		off_t ret = smbw_dir_lseek(fd, offset, whence);
1193		smbw_busy--;
1194		return ret;
1195	}
1196
1197	switch (whence) {
1198	case SEEK_SET:
1199		file->f->offset = offset;
1200		break;
1201	case SEEK_CUR:
1202		file->f->offset += offset;
1203		break;
1204	case SEEK_END:
1205		if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1206				   NULL, &size, NULL, NULL, NULL,
1207				   NULL, NULL) &&
1208		    !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1209				  NULL, &size, NULL, NULL, NULL)) {
1210			errno = EINVAL;
1211			smbw_busy--;
1212			return -1;
1213		}
1214		file->f->offset = size + offset;
1215		break;
1216	}
1217
1218	smbw_busy--;
1219	return file->f->offset;
1220}
1221
1222
1223/*****************************************************
1224a wrapper for dup()
1225*******************************************************/
1226int smbw_dup(int fd)
1227{
1228	int fd2;
1229	struct smbw_file *file, *file2;
1230
1231	smbw_busy++;
1232
1233	file = smbw_file(fd);
1234	if (!file) {
1235		errno = EBADF;
1236		goto failed;
1237	}
1238
1239	fd2 = dup(file->fd);
1240	if (fd2 == -1) {
1241		goto failed;
1242	}
1243
1244	if (bitmap_query(smbw_file_bmap, fd2)) {
1245		DEBUG(0,("ERROR: fd already open in dup!\n"));
1246		errno = EIO;
1247		goto failed;
1248	}
1249
1250	file2 = (struct smbw_file *)malloc(sizeof(*file2));
1251	if (!file2) {
1252		close(fd2);
1253		errno = ENOMEM;
1254		goto failed;
1255	}
1256
1257	ZERO_STRUCTP(file2);
1258
1259	*file2 = *file;
1260	file2->fd = fd2;
1261
1262	file->f->ref_count++;
1263
1264	bitmap_set(smbw_file_bmap, fd2);
1265
1266	DLIST_ADD(smbw_files, file2);
1267
1268	smbw_busy--;
1269	return fd2;
1270
1271 failed:
1272	smbw_busy--;
1273	return -1;
1274}
1275
1276
1277/*****************************************************
1278a wrapper for dup2()
1279*******************************************************/
1280int smbw_dup2(int fd, int fd2)
1281{
1282	struct smbw_file *file, *file2;
1283
1284	smbw_busy++;
1285
1286	file = smbw_file(fd);
1287	if (!file) {
1288		errno = EBADF;
1289		goto failed;
1290	}
1291
1292	if (bitmap_query(smbw_file_bmap, fd2)) {
1293		DEBUG(0,("ERROR: fd already open in dup2!\n"));
1294		errno = EIO;
1295		goto failed;
1296	}
1297
1298	if (dup2(file->fd, fd2) != fd2) {
1299		goto failed;
1300	}
1301
1302	file2 = (struct smbw_file *)malloc(sizeof(*file2));
1303	if (!file2) {
1304		close(fd2);
1305		errno = ENOMEM;
1306		goto failed;
1307	}
1308
1309	ZERO_STRUCTP(file2);
1310
1311	*file2 = *file;
1312	file2->fd = fd2;
1313
1314	file->f->ref_count++;
1315
1316	bitmap_set(smbw_file_bmap, fd2);
1317
1318	DLIST_ADD(smbw_files, file2);
1319
1320	smbw_busy--;
1321	return fd2;
1322
1323 failed:
1324	smbw_busy--;
1325	return -1;
1326}
1327
1328
1329/*****************************************************
1330close a connection to a server
1331*******************************************************/
1332static void smbw_srv_close(struct smbw_server *srv)
1333{
1334	smbw_busy++;
1335
1336	cli_shutdown(&srv->cli);
1337
1338	free(srv->server_name);
1339	free(srv->share_name);
1340
1341	DLIST_REMOVE(smbw_srvs, srv);
1342
1343	ZERO_STRUCTP(srv);
1344
1345	free(srv);
1346
1347	smbw_busy--;
1348}
1349
1350/*****************************************************
1351when we fork we have to close all connections and files
1352in the child
1353*******************************************************/
1354int smbw_fork(void)
1355{
1356	pid_t child;
1357	int p[2];
1358	char c=0;
1359	pstring line;
1360
1361	struct smbw_file *file, *next_file;
1362	struct smbw_server *srv, *next_srv;
1363
1364	if (pipe(p)) return real_fork();
1365
1366	child = real_fork();
1367
1368	if (child) {
1369		/* block the parent for a moment until the sockets are
1370                   closed */
1371		close(p[1]);
1372		read(p[0], &c, 1);
1373		close(p[0]);
1374		return child;
1375	}
1376
1377	close(p[0]);
1378
1379	/* close all files */
1380	for (file=smbw_files;file;file=next_file) {
1381		next_file = file->next;
1382		close(file->fd);
1383	}
1384
1385	/* close all server connections */
1386	for (srv=smbw_srvs;srv;srv=next_srv) {
1387		next_srv = srv->next;
1388		smbw_srv_close(srv);
1389	}
1390
1391	slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
1392	smbw_setshared(line,smbw_cwd);
1393
1394	/* unblock the parent */
1395	write(p[1], &c, 1);
1396	close(p[1]);
1397
1398	/* and continue in the child */
1399	return 0;
1400}
1401
1402#ifndef NO_ACL_WRAPPER
1403/*****************************************************
1404say no to acls
1405*******************************************************/
1406 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1407{
1408	if (cmd == GETACL || cmd == GETACLCNT) return 0;
1409	errno = ENOSYS;
1410	return -1;
1411}
1412#endif
1413
1414#ifndef NO_FACL_WRAPPER
1415/*****************************************************
1416say no to acls
1417*******************************************************/
1418 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1419{
1420	if (cmd == GETACL || cmd == GETACLCNT) return 0;
1421	errno = ENOSYS;
1422	return -1;
1423}
1424#endif
1425
1426
1427#ifdef HAVE_STAT64
1428/* this can't be in wrapped.c because of include conflicts */
1429 void stat64_convert(struct stat *st, struct stat64 *st64)
1430{
1431	st64->st_size = st->st_size;
1432	st64->st_mode = st->st_mode;
1433	st64->st_ino = st->st_ino;
1434	st64->st_dev = st->st_dev;
1435	st64->st_rdev = st->st_rdev;
1436	st64->st_nlink = st->st_nlink;
1437	st64->st_uid = st->st_uid;
1438	st64->st_gid = st->st_gid;
1439	st64->st_atime = st->st_atime;
1440	st64->st_mtime = st->st_mtime;
1441	st64->st_ctime = st->st_ctime;
1442	st64->st_blksize = st->st_blksize;
1443	st64->st_blocks = st->st_blocks;
1444}
1445#endif
1446
1447#ifdef HAVE_READDIR64
1448 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1449{
1450	d64->d_ino = d->d_ino;
1451	d64->d_off = d->d_off;
1452	d64->d_reclen = d->d_reclen;
1453	pstrcpy(d64->d_name, d->d_name);
1454}
1455#endif
1456
1457
1458#ifdef HAVE___XSTAT
1459/* Definition of `struct stat' used in the linux kernel..  */
1460struct kernel_stat {
1461	unsigned short int st_dev;
1462	unsigned short int __pad1;
1463	unsigned long int st_ino;
1464	unsigned short int st_mode;
1465	unsigned short int st_nlink;
1466	unsigned short int st_uid;
1467	unsigned short int st_gid;
1468	unsigned short int st_rdev;
1469	unsigned short int __pad2;
1470	unsigned long int st_size;
1471	unsigned long int st_blksize;
1472	unsigned long int st_blocks;
1473	unsigned long int st_atime;
1474	unsigned long int __unused1;
1475	unsigned long int st_mtime;
1476	unsigned long int __unused2;
1477	unsigned long int st_ctime;
1478	unsigned long int __unused3;
1479	unsigned long int __unused4;
1480	unsigned long int __unused5;
1481};
1482
1483/*
1484 * Prototype for gcc in 'fussy' mode.
1485 */
1486 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1487 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1488{
1489#ifdef _STAT_VER_LINUX_OLD
1490	if (vers == _STAT_VER_LINUX_OLD) {
1491		memcpy(st, kbuf, sizeof(*st));
1492		return;
1493	}
1494#endif
1495
1496	ZERO_STRUCTP(st);
1497
1498	st->st_dev = kbuf->st_dev;
1499	st->st_ino = kbuf->st_ino;
1500	st->st_mode = kbuf->st_mode;
1501	st->st_nlink = kbuf->st_nlink;
1502	st->st_uid = kbuf->st_uid;
1503	st->st_gid = kbuf->st_gid;
1504	st->st_rdev = kbuf->st_rdev;
1505	st->st_size = kbuf->st_size;
1506	st->st_blksize = kbuf->st_blksize;
1507	st->st_blocks = kbuf->st_blocks;
1508	st->st_atime = kbuf->st_atime;
1509	st->st_mtime = kbuf->st_mtime;
1510	st->st_ctime = kbuf->st_ctime;
1511}
1512#endif
1513