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