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