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