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