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