use smbw_errno() not smbw_error()
[sfrench/samba-autobuild/.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 "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=0, 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                 eno = smbw_errno(&srv->cli);
533                 fd = smbw_dir_open(fname);
534                 if (fd == -1) errno = eno;
535                 smbw_busy--;
536                 return fd;
537         }
538
539         file = (struct smbw_file *)malloc(sizeof(*file));
540         if (!file) {
541                 errno = ENOMEM;
542                 goto failed;
543         }
544
545         ZERO_STRUCTP(file);
546
547         file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
548         if (!file->f) {
549                 errno = ENOMEM;
550                 goto failed;
551         }
552
553         ZERO_STRUCTP(file->f);
554
555         file->f->cli_fd = fd;
556         file->f->fname = strdup(path);
557         if (!file->f->fname) {
558                 errno = ENOMEM;
559                 goto failed;
560         }
561         file->srv = srv;
562         file->fd = open(SMBW_DUMMY, O_WRONLY);
563         if (file->fd == -1) {
564                 errno = EMFILE;
565                 goto failed;
566         }
567
568         if (bitmap_query(smbw_file_bmap, file->fd)) {
569                 DEBUG(0,("ERROR: fd used in smbw_open\n"));
570                 errno = EIO;
571                 goto failed;
572         }
573
574         file->f->ref_count=1;
575
576         bitmap_set(smbw_file_bmap, file->fd);
577
578         DLIST_ADD(smbw_files, file);
579
580         DEBUG(4,("opened %s\n", fname));
581
582         smbw_busy--;
583         return file->fd;
584
585  failed:
586         if (fd != -1) {
587                 cli_close(&srv->cli, fd);
588         }
589         if (file) {
590                 if (file->f) {
591                         if (file->f->fname) {
592                                 free(file->f->fname);
593                         }
594                         free(file->f);
595                 }
596                 free(file);
597         }
598         smbw_busy--;
599         return -1;
600 }
601
602
603 /***************************************************** 
604 a wrapper for pread()
605 *******************************************************/
606 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
607 {
608         struct smbw_file *file;
609         int ret;
610
611         smbw_busy++;
612
613         file = smbw_file(fd);
614         if (!file) {
615                 errno = EBADF;
616                 smbw_busy--;
617                 return -1;
618         }
619         
620         ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
621
622         if (ret == -1) {
623                 errno = smbw_errno(&file->srv->cli);
624                 smbw_busy--;
625                 return -1;
626         }
627
628         smbw_busy--;
629         return ret;
630 }
631
632 /***************************************************** 
633 a wrapper for read()
634 *******************************************************/
635 ssize_t smbw_read(int fd, void *buf, size_t count)
636 {
637         struct smbw_file *file;
638         int ret;
639
640         smbw_busy++;
641
642         file = smbw_file(fd);
643         if (!file) {
644                 errno = EBADF;
645                 smbw_busy--;
646                 return -1;
647         }
648         
649         ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, 
650                        file->f->offset, count);
651
652         if (ret == -1) {
653                 errno = smbw_errno(&file->srv->cli);
654                 smbw_busy--;
655                 return -1;
656         }
657
658         file->f->offset += ret;
659
660         smbw_busy--;
661         return ret;
662 }
663
664         
665
666 /***************************************************** 
667 a wrapper for write()
668 *******************************************************/
669 ssize_t smbw_write(int fd, void *buf, size_t count)
670 {
671         struct smbw_file *file;
672         int ret;
673
674         smbw_busy++;
675
676         file = smbw_file(fd);
677         if (!file) {
678                 DEBUG(3,("bad fd in read\n"));
679                 errno = EBADF;
680                 smbw_busy--;
681                 return -1;
682         }
683         
684         ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, file->f->offset, count);
685
686         if (ret == -1) {
687                 errno = smbw_errno(&file->srv->cli);
688                 smbw_busy--;
689                 return -1;
690         }
691
692         file->f->offset += ret;
693
694         smbw_busy--;
695         return ret;
696 }
697
698 /***************************************************** 
699 a wrapper for pwrite()
700 *******************************************************/
701 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
702 {
703         struct smbw_file *file;
704         int ret;
705
706         smbw_busy++;
707
708         file = smbw_file(fd);
709         if (!file) {
710                 DEBUG(3,("bad fd in read\n"));
711                 errno = EBADF;
712                 smbw_busy--;
713                 return -1;
714         }
715         
716         ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
717
718         if (ret == -1) {
719                 errno = smbw_errno(&file->srv->cli);
720                 smbw_busy--;
721                 return -1;
722         }
723
724         smbw_busy--;
725         return ret;
726 }
727
728 /***************************************************** 
729 a wrapper for close()
730 *******************************************************/
731 int smbw_close(int fd)
732 {
733         struct smbw_file *file;
734
735         smbw_busy++;
736
737         file = smbw_file(fd);
738         if (!file) {
739                 int ret = smbw_dir_close(fd);
740                 smbw_busy--;
741                 return ret;
742         }
743         
744         if (file->f->ref_count == 1 &&
745             !cli_close(&file->srv->cli, file->f->cli_fd)) {
746                 errno = smbw_errno(&file->srv->cli);
747                 smbw_busy--;
748                 return -1;
749         }
750
751
752         bitmap_clear(smbw_file_bmap, file->fd);
753         close(file->fd);
754         
755         DLIST_REMOVE(smbw_files, file);
756
757         file->f->ref_count--;
758         if (file->f->ref_count == 0) {
759                 free(file->f->fname);
760                 free(file->f);
761         }
762         ZERO_STRUCTP(file);
763         free(file);
764         
765         smbw_busy--;
766
767         return 0;
768 }
769
770
771 /***************************************************** 
772 a wrapper for fcntl()
773 *******************************************************/
774 int smbw_fcntl(int fd, int cmd, long arg)
775 {
776         return 0;
777 }
778
779
780 /***************************************************** 
781 a wrapper for access()
782 *******************************************************/
783 int smbw_access(const char *name, int mode)
784 {
785         struct stat st;
786         /* how do we map this properly ?? */
787         return smbw_stat(name, &st);
788 }
789
790 /***************************************************** 
791 a wrapper for realink() - needed for correct errno setting
792 *******************************************************/
793 int smbw_readlink(const char *path, char *buf, size_t bufsize)
794 {
795         struct stat st;
796         int ret;
797
798         ret = smbw_stat(path, &st);
799         if (ret != 0) {
800                 DEBUG(4,("readlink(%s) failed\n", path));
801                 return -1;
802         }
803         
804         /* it exists - say it isn't a link */
805         DEBUG(4,("readlink(%s) not a link\n", path));
806
807         errno = EINVAL;
808         return -1;
809 }
810
811
812 /***************************************************** 
813 a wrapper for unlink()
814 *******************************************************/
815 int smbw_unlink(const char *fname)
816 {
817         struct smbw_server *srv;
818         fstring server, share;
819         pstring path;
820
821         if (!fname) {
822                 errno = EINVAL;
823                 return -1;
824         }
825
826         smbw_init();
827
828         smbw_busy++;
829
830         /* work out what server they are after */
831         smbw_parse_path(fname, server, share, path);
832
833         /* get a connection to the server */
834         srv = smbw_server(server, share);
835         if (!srv) {
836                 /* smbw_server sets errno */
837                 goto failed;
838         }
839
840         if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
841                 int job = smbw_stat_printjob(srv, path, NULL, NULL);
842                 if (job == -1) {
843                         goto failed;
844                 }
845                 if (cli_printjob_del(&srv->cli, job) != 0) {
846                         goto failed;
847                 }
848         } else if (!cli_unlink(&srv->cli, path)) {
849                 errno = smbw_errno(&srv->cli);
850                 goto failed;
851         }
852
853         smbw_busy--;
854         return 0;
855
856  failed:
857         smbw_busy--;
858         return -1;
859 }
860
861
862 /***************************************************** 
863 a wrapper for rename()
864 *******************************************************/
865 int smbw_rename(const char *oldname, const char *newname)
866 {
867         struct smbw_server *srv;
868         fstring server1, share1;
869         pstring path1;
870         fstring server2, share2;
871         pstring path2;
872
873         if (!oldname || !newname) {
874                 errno = EINVAL;
875                 return -1;
876         }
877
878         smbw_init();
879
880         smbw_busy++;
881
882         /* work out what server they are after */
883         smbw_parse_path(oldname, server1, share1, path1);
884         smbw_parse_path(newname, server2, share2, path2);
885
886         if (strcmp(server1, server2) || strcmp(share1, share2)) {
887                 /* can't cross filesystems */
888                 errno = EXDEV;
889                 return -1;
890         }
891
892         /* get a connection to the server */
893         srv = smbw_server(server1, share1);
894         if (!srv) {
895                 /* smbw_server sets errno */
896                 goto failed;
897         }
898
899         if (!cli_rename(&srv->cli, path1, path2)) {
900                 errno = smbw_errno(&srv->cli);
901                 goto failed;
902         }
903
904         smbw_busy--;
905         return 0;
906
907  failed:
908         smbw_busy--;
909         return -1;
910 }
911
912
913 /***************************************************** 
914 a wrapper for utime and utimes
915 *******************************************************/
916 static int smbw_settime(const char *fname, time_t t)
917 {
918         struct smbw_server *srv;
919         fstring server, share;
920         pstring path;
921         uint32 mode;
922
923         if (!fname) {
924                 errno = EINVAL;
925                 return -1;
926         }
927
928         smbw_init();
929
930         smbw_busy++;
931
932         /* work out what server they are after */
933         smbw_parse_path(fname, server, share, path);
934
935         /* get a connection to the server */
936         srv = smbw_server(server, share);
937         if (!srv) {
938                 /* smbw_server sets errno */
939                 goto failed;
940         }
941
942         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
943                 errno = smbw_errno(&srv->cli);
944                 goto failed;
945         }
946
947         if (!cli_setatr(&srv->cli, path, mode, t)) {
948                 errno = smbw_errno(&srv->cli);
949                 goto failed;
950         }
951
952         smbw_busy--;
953         return 0;
954
955  failed:
956         smbw_busy--;
957         return -1;
958 }
959
960 /***************************************************** 
961 a wrapper for utime 
962 *******************************************************/
963 int smbw_utime(const char *fname, void *buf)
964 {
965         struct utimbuf *tbuf = (struct utimbuf *)buf;
966         return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
967 }
968
969 /***************************************************** 
970 a wrapper for utime 
971 *******************************************************/
972 int smbw_utimes(const char *fname, void *buf)
973 {
974         struct timeval *tbuf = (struct timeval *)buf;
975         return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
976 }
977
978
979 /***************************************************** 
980 a wrapper for chown()
981 *******************************************************/
982 int smbw_chown(const char *fname, uid_t owner, gid_t group)
983 {
984         struct smbw_server *srv;
985         fstring server, share;
986         pstring path;
987         uint32 mode;
988
989         if (!fname) {
990                 errno = EINVAL;
991                 return -1;
992         }
993
994         smbw_init();
995
996         smbw_busy++;
997
998         /* work out what server they are after */
999         smbw_parse_path(fname, server, share, path);
1000
1001         /* get a connection to the server */
1002         srv = smbw_server(server, share);
1003         if (!srv) {
1004                 /* smbw_server sets errno */
1005                 goto failed;
1006         }
1007
1008         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1009                 errno = smbw_errno(&srv->cli);
1010                 goto failed;
1011         }
1012         
1013         /* assume success */
1014
1015         smbw_busy--;
1016         return 0;
1017
1018  failed:
1019         smbw_busy--;
1020         return -1;
1021 }
1022
1023 /***************************************************** 
1024 a wrapper for chmod()
1025 *******************************************************/
1026 int smbw_chmod(const char *fname, mode_t newmode)
1027 {
1028         struct smbw_server *srv;
1029         fstring server, share;
1030         pstring path;
1031         uint32 mode;
1032
1033         if (!fname) {
1034                 errno = EINVAL;
1035                 return -1;
1036         }
1037
1038         smbw_init();
1039
1040         smbw_busy++;
1041
1042         /* work out what server they are after */
1043         smbw_parse_path(fname, server, share, path);
1044
1045         /* get a connection to the server */
1046         srv = smbw_server(server, share);
1047         if (!srv) {
1048                 /* smbw_server sets errno */
1049                 goto failed;
1050         }
1051
1052         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1053                 errno = smbw_errno(&srv->cli);
1054                 goto failed;
1055         }
1056         
1057         /* assume success for the moment - need to add attribute mapping */
1058
1059         smbw_busy--;
1060         return 0;
1061
1062  failed:
1063         smbw_busy--;
1064         return -1;
1065 }
1066
1067 /***************************************************** 
1068 a wrapper for lseek()
1069 *******************************************************/
1070 off_t smbw_lseek(int fd, off_t offset, int whence)
1071 {
1072         struct smbw_file *file;
1073         size_t size;
1074
1075         smbw_busy++;
1076
1077         file = smbw_file(fd);
1078         if (!file) {
1079                 off_t ret = smbw_dir_lseek(fd, offset, whence);
1080                 smbw_busy--;
1081                 return ret;
1082         }
1083
1084         switch (whence) {
1085         case SEEK_SET:
1086                 file->f->offset = offset;
1087                 break;
1088         case SEEK_CUR:
1089                 file->f->offset += offset;
1090                 break;
1091         case SEEK_END:
1092                 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, 
1093                                    NULL, &size, NULL, NULL, NULL) &&
1094                     !cli_getattrE(&file->srv->cli, file->f->cli_fd, 
1095                                   NULL, &size, NULL, NULL, NULL)) {
1096                         errno = EINVAL;
1097                         smbw_busy--;
1098                         return -1;
1099                 }
1100                 file->f->offset = size + offset;
1101                 break;
1102         }
1103
1104         smbw_busy--;
1105         return file->f->offset;
1106 }
1107
1108
1109 /***************************************************** 
1110 a wrapper for dup()
1111 *******************************************************/
1112 int smbw_dup(int fd)
1113 {
1114         int fd2;
1115         struct smbw_file *file, *file2;
1116
1117         smbw_busy++;
1118
1119         file = smbw_file(fd);
1120         if (!file) {
1121                 errno = EBADF;
1122                 goto failed;
1123         }
1124
1125         fd2 = dup(file->fd);
1126         if (fd2 == -1) {
1127                 goto failed;
1128         }
1129
1130         if (bitmap_query(smbw_file_bmap, fd2)) {
1131                 DEBUG(0,("ERROR: fd already open in dup!\n"));
1132                 errno = EIO;
1133                 goto failed;
1134         }
1135
1136         file2 = (struct smbw_file *)malloc(sizeof(*file2));
1137         if (!file2) {
1138                 close(fd2);
1139                 errno = ENOMEM;
1140                 goto failed;
1141         }
1142
1143         ZERO_STRUCTP(file2);
1144
1145         *file2 = *file;
1146         file2->fd = fd2;
1147
1148         file->f->ref_count++;
1149
1150         bitmap_set(smbw_file_bmap, fd2);
1151         
1152         DLIST_ADD(smbw_files, file2);
1153         
1154         smbw_busy--;
1155         return fd2;
1156
1157  failed:
1158         smbw_busy--;
1159         return -1;
1160 }
1161
1162
1163 /***************************************************** 
1164 a wrapper for dup2()
1165 *******************************************************/
1166 int smbw_dup2(int fd, int fd2)
1167 {
1168         struct smbw_file *file, *file2;
1169
1170         smbw_busy++;
1171
1172         file = smbw_file(fd);
1173         if (!file) {
1174                 errno = EBADF;
1175                 goto failed;
1176         }
1177
1178         if (bitmap_query(smbw_file_bmap, fd2)) {
1179                 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1180                 errno = EIO;
1181                 goto failed;
1182         }
1183
1184         if (dup2(file->fd, fd2) != fd2) {
1185                 goto failed;
1186         }
1187
1188         file2 = (struct smbw_file *)malloc(sizeof(*file2));
1189         if (!file2) {
1190                 close(fd2);
1191                 errno = ENOMEM;
1192                 goto failed;
1193         }
1194
1195         ZERO_STRUCTP(file2);
1196
1197         *file2 = *file;
1198         file2->fd = fd2;
1199
1200         file->f->ref_count++;
1201
1202         bitmap_set(smbw_file_bmap, fd2);
1203         
1204         DLIST_ADD(smbw_files, file2);
1205         
1206         smbw_busy--;
1207         return fd2;
1208
1209  failed:
1210         smbw_busy--;
1211         return -1;
1212 }
1213