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