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