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