fixed vi on smbwrappper (it was a problem in cli_read())
[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 "smbw.h"
24 #include "wrapper.h"
25
26 static pstring smb_cwd;
27
28 struct smbw_server {
29         struct smbw_server *next, *prev;
30         struct cli_state cli;
31         char *server_name;
32         char *share_name;
33         dev_t dev;
34 };
35
36 struct smbw_file {
37         struct smbw_file *next, *prev;
38         int cli_fd, fd;
39         char *fname;
40         off_t offset;
41         struct smbw_server *srv;
42 };
43
44 struct smbw_dir {
45         struct smbw_dir *next, *prev;
46         int fd;
47         int offset, count, malloced;
48         struct smbw_server *srv;
49         struct file_info *list;
50 };
51
52 static struct smbw_file *smbw_files;
53 static struct smbw_dir *smbw_dirs;
54 static struct smbw_server *smbw_srvs;
55
56 static struct bitmap *file_bmap;
57 static pstring local_machine;
58 extern int DEBUGLEVEL;
59
60 static int smbw_busy;
61
62 /***************************************************** 
63 initialise structures
64 *******************************************************/
65 void smbw_init(void)
66 {
67         extern BOOL in_client;
68         static int initialised;
69         static pstring servicesf = CONFIGFILE;
70         extern FILE *dbf;
71         char *p;
72
73         if (initialised) return;
74         initialised = 1;
75
76         smbw_busy++;
77
78         DEBUGLEVEL = 0;
79         setup_logging("smbw",True);
80
81         dbf = stderr;
82
83         if ((p=getenv("SMBW_LOGFILE"))) {
84                 dbf = fopen(p, "a");
85         }
86
87         file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
88         if (!file_bmap) {
89                 exit(1);
90         }
91
92         charset_initialise();
93
94         in_client = True;
95
96         if (!lp_load(servicesf,True,False,False)) {
97                 exit(1);
98         }
99
100         get_myname(local_machine,NULL);
101
102         if ((p=getenv("SMBW_DEBUG"))) {
103                 DEBUGLEVEL = atoi(p);
104         }
105
106         if ((p=getenv(SMBW_PWD_ENV))) {
107                 pstrcpy(smb_cwd, p);
108                 DEBUG(4,("Initial cwd from smb_cwd is %s\n", smb_cwd));
109         } else {
110                 sys_getwd(smb_cwd);
111                 DEBUG(4,("Initial cwd from getwd is %s\n", smb_cwd));
112         }
113         smbw_busy--;
114 }
115
116 /***************************************************** 
117 determine if a file descriptor is a smb one
118 *******************************************************/
119 BOOL smbw_fd(int fd)
120 {
121         if (smbw_busy) return False;
122         return (fd >= SMBW_FD_OFFSET);
123 }
124
125 /***************************************************** 
126 a crude inode number generator
127 *******************************************************/
128 ino_t smbw_inode(const char *name)
129 {
130         return (ino_t)str_checksum(name);
131 }
132
133 /***************************************************** 
134 remove redundent stuff from a filename
135 *******************************************************/
136 void clean_fname(char *name)
137 {
138         char *p, *p2;
139         int l;
140         int modified = 1;
141
142         if (!name) return;
143
144         while (modified) {
145                 modified = 0;
146
147                 DEBUG(5,("cleaning %s\n", name));
148
149                 if ((p=strstr(name,"/./"))) {
150                         modified = 1;
151                         while (*p) {
152                                 p[0] = p[2];
153                                 p++;
154                         }
155                 }
156
157                 if ((p=strstr(name,"//"))) {
158                         modified = 1;
159                         while (*p) {
160                                 p[0] = p[1];
161                                 p++;
162                         }
163                 }
164
165                 if (strcmp(name,"/../")==0) {
166                         modified = 1;
167                         name[1] = 0;
168                 }
169
170                 if ((p=strstr(name,"/../"))) {
171                         modified = 1;
172                         for (p2=(p>name?p-1:p);p2>name;p2--) {
173                                 if (p2[0] == '/') break;
174                         }
175                         while (*p2) {
176                                 p2[0] = p2[3];
177                                 p2++;
178                         }
179                 }
180
181                 if (strcmp(name,"/..")==0) {
182                         modified = 1;
183                         name[1] = 0;
184                 }
185
186                 l = strlen(name);
187                 p = l>=3?(name+l-3):name;
188                 if (strcmp(p,"/..")==0) {
189                         modified = 1;
190                         for (p2=p-1;p2>name;p2--) {
191                                 if (p2[0] == '/') break;
192                         }
193                         if (p2==name) {
194                                 p[0] = '/';
195                                 p[1] = 0;
196                         } else {
197                                 p2[0] = 0;
198                         }
199                 }
200
201                 l = strlen(name);
202                 p = l>=2?(name+l-2):name;
203                 if (strcmp(p,"/.")==0) {
204                         if (p == name) {
205                                 p[1] = 0;
206                         } else {
207                                 p[0] = 0;
208                         }
209                 }
210
211                 if (strncmp(p=name,"./",2) == 0) {      
212                         modified = 1;
213                         do {
214                                 p[0] = p[2];
215                         } while (*p++);
216                 }
217
218                 l = strlen(p=name);
219                 if (l > 1 && p[l-1] == '/') {
220                         modified = 1;
221                         p[l-1] = 0;
222                 }
223         }
224 }
225
226
227 /***************************************************** 
228 parse a smb path into its components. 
229 *******************************************************/
230 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
231 {
232         static pstring s;
233         char *p, *p2;
234         int len;
235
236         *server = *share = *path = 0;
237
238         if (fname[0] == '/') {
239                 pstrcpy(s, fname);
240         } else {
241                 slprintf(s,sizeof(s)-1, "%s/%s", smb_cwd, fname);
242         }
243         clean_fname(s);
244
245         DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n", 
246                  s, fname, smb_cwd));
247
248         if (strncmp(s,SMBW_PREFIX,strlen(SMBW_PREFIX))) return s;
249
250         p = s + strlen(SMBW_PREFIX);
251         p2 = strchr(p,'/');
252
253         if (p2) {
254                 len = (int)(p2-p);
255         } else {
256                 len = strlen(p);
257         }
258
259         len = MIN(len,sizeof(fstring)-1);
260
261         strncpy(server, p, len);
262         server[len] = 0;                
263
264         p = p2;
265         if (!p) {
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, smb_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 BOOL smbw_path(const char *path)
308 {
309         fstring server, share;
310         pstring s;
311         char *cwd;
312         int l=strlen(SMBW_PREFIX)-1;
313
314         if (path[0] == '/' && strncmp(path,SMBW_PREFIX,l)) {
315                 return False;
316         }
317
318         if (smbw_busy) return False;
319
320         smbw_init();
321
322         DEBUG(3,("smbw_path(%s)\n", path));
323
324         cwd = smbw_parse_path(path, server, share, s);
325
326         if (strncmp(cwd,SMBW_PREFIX,l) == 0 &&
327             (cwd[l] == '/' || cwd[l] == 0)) {
328                 return True;
329         }
330
331         return False;
332 }
333
334 /***************************************************** 
335 return a unix errno from a SMB error pair
336 *******************************************************/
337 int smbw_errno(struct cli_state *c)
338 {
339         uint8 eclass;
340         uint32 ecode;
341         int ret;
342
343         ret = cli_error(c, &eclass, &ecode);
344
345         if (ret) {
346                 DEBUG(3,("smbw_error %d %d (0x%x)\n", 
347                          (int)eclass, (int)ecode, (int)ecode));
348         }
349         return ret;
350 }
351
352 /***************************************************** 
353 return a connection to a server (existing or new)
354 *******************************************************/
355 struct smbw_server *smbw_server(char *server, char *share)
356 {
357         struct smbw_server *srv=NULL;
358         static struct cli_state c;
359         char *username;
360         char *password;
361         char *workgroup;
362         struct nmb_name called, calling;
363
364         username = getenv("SMBW_USER");
365         if (!username) username = getenv("USER");
366         if (!username) username = "guest";
367
368         workgroup = getenv("SMBW_WORKGROUP");
369         if (!workgroup) workgroup = lp_workgroup();
370
371         password = getenv("SMBW_PASSWORD");
372         if (!password) password = "";
373
374         /* try to use an existing connection */
375         for (srv=smbw_srvs;srv;srv=srv->next) {
376                 if (strcmp(server,srv->server_name)==0 &&
377                     strcmp(share,srv->share_name)==0) return srv;
378         }
379
380         if (server[0] == 0) {
381                 errno = EPERM;
382                 return NULL;
383         }
384
385         /* have to open a new connection */
386         if (!cli_initialise(&c) || !cli_connect(&c, server, NULL)) {
387                 errno = ENOENT;
388                 return NULL;
389         }
390
391         make_nmb_name(&calling, local_machine, 0x0, "");
392         make_nmb_name(&called , server, 0x20, "");
393
394         if (!cli_session_request(&c, &calling, &called)) {
395                 cli_shutdown(&c);
396                 errno = ENOENT;
397                 return NULL;
398         }
399
400         if (!cli_negprot(&c)) {
401                 cli_shutdown(&c);
402                 errno = ENOENT;
403                 return NULL;
404         }
405
406         if (!cli_session_setup(&c, username, 
407                                password, strlen(password),
408                                password, strlen(password),
409                                workgroup)) {
410                 cli_shutdown(&c);
411                 errno = EPERM;
412                 return NULL;
413         }
414
415         if (!cli_send_tconX(&c, share, 
416                             strstr(share,"IPC$")?"IPC":"A:", 
417                             password, strlen(password)+1)) {
418                 errno = smbw_errno(&c);
419                 cli_shutdown(&c);
420                 return NULL;
421         }
422
423         srv = (struct smbw_server *)malloc(sizeof(*srv));
424         if (!srv) {
425                 errno = ENOMEM;
426                 goto failed;
427         }
428
429         ZERO_STRUCTP(srv);
430
431         srv->cli = c;
432
433         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
434
435         srv->server_name = strdup(server);
436         if (!srv->server_name) {
437                 errno = ENOMEM;
438                 goto failed;
439         }
440
441         srv->share_name = strdup(share);
442         if (!srv->share_name) {
443                 errno = ENOMEM;
444                 goto failed;
445         }
446
447         /* some programs play with file descriptors fairly intimately. We
448            try to get out of the way by duping to a high fd number */
449         if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
450                 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == 
451                     srv->cli.fd+SMBW_CLI_FD) {
452                         close(srv->cli.fd);
453                         srv->cli.fd += SMBW_CLI_FD;
454                 }
455         }
456
457         DLIST_ADD(smbw_srvs, srv);
458
459         return srv;
460
461  failed:
462         cli_shutdown(&c);
463         if (!srv) return NULL;
464
465         if (srv->server_name) free(srv->server_name);
466         if (srv->share_name) free(srv->share_name);
467         free(srv);
468         return NULL;
469 }
470
471
472 /***************************************************** 
473 map a fd to a smbw_file structure
474 *******************************************************/
475 struct smbw_file *smbw_file(int fd)
476 {
477         struct smbw_file *file;
478
479         for (file=smbw_files;file;file=file->next) {
480                 if (file->fd == fd) return file;
481         }
482         return NULL;
483 }
484
485 /***************************************************** 
486 map a fd to a smbw_dir structure
487 *******************************************************/
488 struct smbw_dir *smbw_dir(int fd)
489 {
490         struct smbw_dir *dir;
491
492         for (dir=smbw_dirs;dir;dir=dir->next) {
493                 if (dir->fd == fd) return dir;
494         }
495         return NULL;
496 }
497
498 /***************************************************** 
499 setup basic info in a stat structure
500 *******************************************************/
501 void smbw_setup_stat(struct stat *st, char *fname, size_t size, int mode)
502 {
503         ZERO_STRUCTP(st);
504
505         if (IS_DOS_DIR(mode)) {
506                 st->st_mode = SMBW_DIR_MODE;
507         } else {
508                 st->st_mode = SMBW_FILE_MODE;
509         }
510
511         st->st_size = size;
512         st->st_blksize = 512;
513         st->st_blocks = (size+511)/512;
514         st->st_uid = getuid();
515         st->st_gid = getgid();
516         st->st_ino = smbw_inode(fname);
517 }
518
519
520 /***************************************************** 
521 try to do a QPATHINFO and if that fails then do a getatr
522 this is needed because win95 sometimes refuses the qpathinfo
523 *******************************************************/
524 static BOOL smbw_getatr(struct smbw_server *srv, char *path, 
525                         uint32 *mode, size_t *size, 
526                         time_t *c_time, time_t *a_time, time_t *m_time)
527 {
528         if (cli_qpathinfo(&srv->cli, path, c_time, a_time, m_time,
529                           size, mode)) return True;
530
531         /* if this is NT then don't bother with the getatr */
532         if (srv->cli.capabilities & CAP_NT_SMBS) return False;
533
534         if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
535                 a_time = c_time = m_time;
536                 return True;
537         }
538         return False;
539 }
540
541 /***************************************************** 
542 free a smbw_dir structure and all entries
543 *******************************************************/
544 static void free_dir(struct smbw_dir *dir)
545 {
546         if (dir->list) {
547                 free(dir->list);
548         }
549         ZERO_STRUCTP(dir);
550         free(dir);
551 }
552
553
554 static struct smbw_dir *cur_dir;
555
556 /***************************************************** 
557 add a entry to a directory listing
558 *******************************************************/
559 void smbw_dir_add(struct file_info *finfo)
560 {
561         DEBUG(5,("%s\n", finfo->name));
562
563         if (cur_dir->malloced == cur_dir->count) {
564                 cur_dir->list = (struct file_info *)Realloc(cur_dir->list, 
565                                                             sizeof(cur_dir->list[0])*
566                                                             (cur_dir->count+100));
567                 if (!cur_dir->list) {
568                         /* oops */
569                         return;
570                 }
571                 cur_dir->malloced += 100;
572         }
573
574         cur_dir->list[cur_dir->count] = *finfo;
575         cur_dir->count++;
576 }
577
578 /***************************************************** 
579 add a entry to a directory listing
580 *******************************************************/
581 void smbw_share_add(const char *share, uint32 type, const char *comment)
582 {
583         struct file_info finfo;
584
585         ZERO_STRUCT(finfo);
586
587         pstrcpy(finfo.name, share);
588         finfo.mode = aRONLY | aDIR;     
589
590         smbw_dir_add(&finfo);
591 }
592
593
594 /***************************************************** 
595 open a directory on the server
596 *******************************************************/
597 int smbw_dir_open(const char *fname, int flags)
598 {
599         fstring server, share;
600         pstring path;
601         struct smbw_server *srv=NULL;
602         struct smbw_dir *dir=NULL;
603         pstring mask;
604         int fd;
605
606         DEBUG(4,("%s\n", __FUNCTION__));
607
608         if (!fname) {
609                 errno = EINVAL;
610                 return -1;
611         }
612
613         smbw_init();
614
615         /* work out what server they are after */
616         smbw_parse_path(fname, server, share, path);
617
618         DEBUG(4,("dir_open share=%s\n", share));
619
620         /* get a connection to the server */
621         srv = smbw_server(server, share);
622         if (!srv) {
623                 /* smbw_server sets errno */
624                 goto failed;
625         }
626
627         dir = (struct smbw_dir *)malloc(sizeof(*dir));
628         if (!dir) {
629                 errno = ENOMEM;
630                 goto failed;
631         }
632
633         ZERO_STRUCTP(dir);
634
635         cur_dir = dir;
636
637         slprintf(mask, sizeof(mask)-1, "%s\\*", path);
638         string_sub(mask,"\\\\","\\");
639
640         if (strcmp(share,"IPC$") == 0) {
641                 DEBUG(4,("doing NetShareEnum\n"));
642                 if (cli_RNetShareEnum(&srv->cli, smbw_share_add) <= 0) {
643                         errno = smbw_errno(&srv->cli);
644                         goto failed;
645                 }
646         } else {
647                 if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, 
648                              smbw_dir_add) <= 0) {
649                         errno = smbw_errno(&srv->cli);
650                         goto failed;
651                 }
652         }
653
654         cur_dir = NULL;
655         
656         fd = bitmap_find(file_bmap, 0);
657         if (fd == -1) {
658                 errno = EMFILE;
659                 goto failed;
660         }
661
662         DLIST_ADD(smbw_dirs, dir);
663         
664         bitmap_set(file_bmap, fd);
665
666         dir->fd = fd + SMBW_FD_OFFSET;
667         dir->srv = srv;
668
669         DEBUG(4,("  -> %d\n", dir->count));
670
671         return dir->fd;
672
673  failed:
674         if (dir) {
675                 free_dir(dir);
676         }
677
678         return -1;
679 }
680
681
682 /***************************************************** 
683 a wrapper for open()
684 *******************************************************/
685 int smbw_open(const char *fname, int flags, mode_t mode)
686 {
687         fstring server, share;
688         pstring path;
689         struct smbw_server *srv=NULL;
690         int eno, fd = -1;
691         struct smbw_file *file=NULL;
692
693         DEBUG(4,("%s\n", __FUNCTION__));
694
695         smbw_init();
696
697         if (!fname) {
698                 errno = EINVAL;
699                 return -1;
700         }
701
702         smbw_busy++;    
703
704         /* work out what server they are after */
705         smbw_parse_path(fname, server, share, path);
706
707         /* get a connection to the server */
708         srv = smbw_server(server, share);
709         if (!srv) {
710                 /* smbw_server sets errno */
711                 goto failed;
712         }
713
714         if (path[strlen(path)-1] == '\\') {
715                 fd = -1;
716         } else {
717                 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
718         }
719         if (fd == -1) {
720                 /* it might be a directory. Maybe we should use chkpath? */
721                 fd = smbw_dir_open(fname, flags);
722                 smbw_busy--;
723                 return fd;
724         }
725         if (fd == -1) {
726                 errno = eno;
727                 goto failed;
728         }
729
730         file = (struct smbw_file *)malloc(sizeof(*file));
731         if (!file) {
732                 errno = ENOMEM;
733                 goto failed;
734         }
735
736         ZERO_STRUCTP(file);
737
738         file->cli_fd = fd;
739         file->fname = strdup(path);
740         if (!file->fname) {
741                 errno = ENOMEM;
742                 goto failed;
743         }
744         file->srv = srv;
745         file->fd = bitmap_find(file_bmap, 0);
746
747         if (file->fd == -1) {
748                 errno = EMFILE;
749                 goto failed;
750         }
751
752         bitmap_set(file_bmap, file->fd);
753
754         file->fd += SMBW_FD_OFFSET;
755
756         DLIST_ADD(smbw_files, file);
757
758         DEBUG(4,("opened %s\n", fname));
759
760         smbw_busy--;
761         return file->fd;
762
763  failed:
764         if (fd != -1) {
765                 cli_close(&srv->cli, fd);
766         }
767         if (file) {
768                 if (file->fname) {
769                         free(file->fname);
770                 }
771                 free(file);
772         }
773         smbw_busy--;
774         return -1;
775 }
776
777
778 /***************************************************** 
779 a wrapper for fstat() on a directory
780 *******************************************************/
781 int smbw_dir_fstat(int fd, struct stat *st)
782 {
783         struct smbw_dir *dir;
784
785         DEBUG(4,("%s\n", __FUNCTION__));
786
787         dir = smbw_dir(fd);
788         if (!dir) {
789                 errno = EBADF;
790                 return -1;
791         }
792
793         ZERO_STRUCTP(st);
794
795         smbw_setup_stat(st, "", dir->count*sizeof(struct dirent), aDIR);
796
797         st->st_dev = dir->srv->dev;
798
799         return 0;
800 }
801
802 /***************************************************** 
803 a wrapper for fstat()
804 *******************************************************/
805 int smbw_fstat(int fd, struct stat *st)
806 {
807         struct smbw_file *file;
808         time_t c_time, a_time, m_time;
809         uint32 size;
810         int mode;
811
812         DEBUG(4,("%s\n", __FUNCTION__));
813
814         smbw_busy++;
815
816         file = smbw_file(fd);
817         if (!file) {
818                 int ret = smbw_dir_fstat(fd, st);
819                 smbw_busy--;
820                 return ret;
821         }
822
823         if (!cli_qfileinfo(&file->srv->cli, file->cli_fd, 
824                           &mode, &size, &c_time, &a_time, &m_time) &&
825             !cli_getattrE(&file->srv->cli, file->cli_fd, 
826                           &mode, &size, &c_time, &a_time, &m_time)) {
827                 errno = EINVAL;
828                 smbw_busy--;
829                 return -1;
830         }
831
832         smbw_setup_stat(st, file->fname, size, mode);
833
834         st->st_atime = a_time;
835         st->st_ctime = c_time;
836         st->st_mtime = m_time;
837         st->st_dev = file->srv->dev;
838
839         DEBUG(4,("%s - OK\n", __FUNCTION__));
840
841         smbw_busy--;
842         return 0;
843 }
844
845
846 /***************************************************** 
847 a wrapper for stat()
848 *******************************************************/
849 int smbw_stat(const char *fname, struct stat *st)
850 {
851         struct smbw_server *srv;
852         fstring server, share;
853         pstring path;
854         time_t m_time=0, a_time=0, c_time=0;
855         size_t size=0;
856         uint32 mode=0;
857
858         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
859
860         if (!fname) {
861                 errno = EINVAL;
862                 return -1;
863         }
864
865         smbw_init();
866
867         smbw_busy++;
868
869         /* work out what server they are after */
870         smbw_parse_path(fname, server, share, path);
871
872         /* get a connection to the server */
873         srv = smbw_server(server, share);
874         if (!srv) {
875                 /* smbw_server sets errno */
876                 goto failed;
877         }
878
879         if (strcmp(share,"IPC$") == 0) {
880                 mode = aDIR | aRONLY;
881         } else {
882                 if (!smbw_getatr(srv, path, 
883                                  &mode, &size, &c_time, &a_time, &m_time)) {
884                         errno = smbw_errno(&srv->cli);
885                         goto failed;
886                 }
887         }
888
889         smbw_setup_stat(st, path, size, mode);
890
891         st->st_atime = time(NULL);
892         st->st_ctime = m_time;
893         st->st_mtime = m_time;
894         st->st_dev = srv->dev;
895
896         smbw_busy--;
897         return 0;
898
899  failed:
900         smbw_busy--;
901         return -1;
902 }
903
904 /***************************************************** 
905 a wrapper for read()
906 *******************************************************/
907 ssize_t smbw_read(int fd, void *buf, size_t count)
908 {
909         struct smbw_file *file;
910         int ret;
911
912         DEBUG(4,("%s %d\n", __FUNCTION__, (int)count));
913
914         smbw_busy++;
915
916         file = smbw_file(fd);
917         if (!file) {
918                 errno = EBADF;
919                 smbw_busy--;
920                 return -1;
921         }
922         
923         ret = cli_read(&file->srv->cli, file->cli_fd, buf, file->offset, count);
924
925         if (ret == -1) {
926                 errno = smbw_errno(&file->srv->cli);
927                 smbw_busy--;
928                 return -1;
929         }
930
931         file->offset += ret;
932
933         smbw_busy--;
934         return ret;
935 }
936
937 /***************************************************** 
938 a wrapper for write()
939 *******************************************************/
940 ssize_t smbw_write(int fd, void *buf, size_t count)
941 {
942         struct smbw_file *file;
943         int ret;
944
945         DEBUG(4,("%s\n", __FUNCTION__));
946
947         smbw_busy++;
948
949         file = smbw_file(fd);
950         if (!file) {
951                 DEBUG(3,("bad fd in read\n"));
952                 errno = EBADF;
953                 smbw_busy--;
954                 return -1;
955         }
956         
957         ret = cli_write(&file->srv->cli, file->cli_fd, buf, file->offset, count);
958
959         if (ret == -1) {
960                 errno = smbw_errno(&file->srv->cli);
961                 smbw_busy--;
962                 return -1;
963         }
964
965         file->offset += ret;
966
967         smbw_busy--;
968         return ret;
969 }
970
971 /***************************************************** 
972 close a directory handle
973 *******************************************************/
974 int smbw_dir_close(int fd)
975 {
976         struct smbw_dir *dir;
977
978         DEBUG(4,("%s\n", __FUNCTION__));
979
980         dir = smbw_dir(fd);
981         if (!dir) {
982                 DEBUG(4,("%s(%d)\n", __FUNCTION__, __LINE__));
983                 errno = EBADF;
984                 return -1;
985         }
986
987         bitmap_clear(file_bmap, dir->fd - SMBW_FD_OFFSET);
988         
989         DLIST_REMOVE(smbw_dirs, dir);
990         
991         free_dir(dir);
992
993         return 0;
994 }
995
996 /***************************************************** 
997 a wrapper for close()
998 *******************************************************/
999 int smbw_close(int fd)
1000 {
1001         struct smbw_file *file;
1002
1003         DEBUG(4,("%s\n", __FUNCTION__));
1004
1005         smbw_busy++;
1006
1007         file = smbw_file(fd);
1008         if (!file) {
1009                 int ret = smbw_dir_close(fd);
1010                 smbw_busy--;
1011                 return ret;
1012         }
1013         
1014         if (!cli_close(&file->srv->cli, file->cli_fd)) {
1015                 errno = smbw_errno(&file->srv->cli);
1016                 smbw_busy--;
1017                 return -1;
1018         }
1019
1020
1021         bitmap_clear(file_bmap, file->fd - SMBW_FD_OFFSET);
1022         
1023         DLIST_REMOVE(smbw_files, file);
1024
1025         free(file->fname);
1026         ZERO_STRUCTP(file);
1027         free(file);
1028         
1029         smbw_busy--;
1030
1031         return 0;
1032 }
1033
1034
1035 /***************************************************** 
1036 a wrapper for fcntl()
1037 *******************************************************/
1038 int smbw_fcntl(int fd, int cmd, long arg)
1039 {
1040         DEBUG(4,("%s\n", __FUNCTION__));
1041         return 0;
1042 }
1043
1044
1045 /***************************************************** 
1046 a wrapper for getdents()
1047 *******************************************************/
1048 int smbw_getdents(unsigned int fd, struct dirent *dirp, int count)
1049 {
1050         struct smbw_dir *dir;
1051         int n=0;
1052
1053         DEBUG(4,("%s\n", __FUNCTION__));
1054
1055         smbw_busy++;
1056
1057         dir = smbw_dir(fd);
1058         if (!dir) {
1059                 errno = EBADF;
1060                 smbw_busy--;
1061                 return -1;
1062         }
1063         
1064         while (count>=sizeof(*dirp) && (dir->offset < dir->count)) {
1065                 dirp->d_off = (dir->offset+1)*sizeof(*dirp);
1066                 dirp->d_reclen = sizeof(*dirp);
1067                 /* what's going on with the -1 here? maybe d_type
1068                    isn't really there? */
1069                 safe_strcpy(&dirp->d_name[-1], dir->list[dir->offset].name, 
1070                             sizeof(dirp->d_name)-1);
1071                 dirp->d_ino = smbw_inode(dir->list[dir->offset].name);
1072                 dir->offset++;
1073                 count -= dirp->d_reclen;
1074                 if (dir->offset == dir->count) {
1075                         dirp->d_off = -1;
1076                 }
1077                 dirp++;
1078                 n++;
1079         }
1080
1081         smbw_busy--;
1082         return n*sizeof(*dirp);
1083 }
1084
1085
1086 /***************************************************** 
1087 a wrapper for access()
1088 *******************************************************/
1089 int smbw_access(const char *name, int mode)
1090 {
1091         struct stat st;
1092         /* how do we map this properly ?? */
1093         return smbw_stat(name, &st);
1094 }
1095
1096 /***************************************************** 
1097 a wrapper for realink() - needed for correct errno setting
1098 *******************************************************/
1099 int smbw_readlink(const char *path, char *buf, size_t bufsize)
1100 {
1101         struct stat st;
1102         int ret;
1103
1104         ret = smbw_stat(path, &st);
1105         if (ret != 0) {
1106                 DEBUG(4,("readlink(%s) failed\n", path));
1107                 return -1;
1108         }
1109         
1110         /* it exists - say it isn't a link */
1111         DEBUG(4,("readlink(%s) not a link\n", path));
1112
1113         errno = EINVAL;
1114         return -1;
1115 }
1116
1117
1118 /***************************************************** 
1119 a wrapper for chdir()
1120 *******************************************************/
1121 int smbw_chdir(const char *name)
1122 {
1123         struct smbw_server *srv;
1124         fstring server, share;
1125         pstring path;
1126         uint32 mode = aDIR;
1127         char *cwd;
1128
1129         smbw_init();
1130
1131         if (smbw_busy) return real_chdir(cwd);
1132
1133         smbw_busy++;
1134
1135         if (!name) {
1136                 errno = EINVAL;
1137                 goto failed;
1138         }
1139
1140         DEBUG(4,("%s (%s)\n", __FUNCTION__, name));
1141
1142         /* work out what server they are after */
1143         cwd = smbw_parse_path(name, server, share, path);
1144
1145         if (strncmp(cwd,SMBW_PREFIX,strlen(SMBW_PREFIX))) {
1146                 if (real_chdir(cwd) == 0) {
1147                         DEBUG(4,("set SMBW_CWD to %s\n", cwd));
1148                         pstrcpy(smb_cwd, cwd);
1149                         if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) {
1150                                 DEBUG(4,("setenv failed\n"));
1151                         }
1152                         goto success;
1153                 }
1154                 errno = ENOENT;
1155                 goto failed;
1156         }
1157
1158         /* get a connection to the server */
1159         srv = smbw_server(server, share);
1160         if (!srv) {
1161                 /* smbw_server sets errno */
1162                 goto failed;
1163         }
1164
1165         if (strcmp(share,"IPC$") &&
1166             !smbw_getatr(srv, path, 
1167                          &mode, NULL, NULL, NULL, NULL)) {
1168                 errno = smbw_errno(&srv->cli);
1169                 goto failed;
1170         }
1171
1172         if (!(mode & aDIR)) {
1173                 errno = ENOTDIR;
1174                 goto failed;
1175         }
1176
1177         DEBUG(4,("set SMBW_CWD2 to %s\n", cwd));
1178         pstrcpy(smb_cwd, cwd);
1179         if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) {
1180                 DEBUG(4,("setenv failed\n"));
1181         }
1182
1183         /* we don't want the old directory to be busy */
1184         real_chdir("/");
1185
1186  success:
1187         smbw_busy--;
1188         return 0;
1189
1190  failed:
1191         smbw_busy--;
1192         return -1;
1193 }
1194
1195
1196 /***************************************************** 
1197 a wrapper for unlink()
1198 *******************************************************/
1199 int smbw_unlink(const char *fname)
1200 {
1201         struct smbw_server *srv;
1202         fstring server, share;
1203         pstring path;
1204
1205         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1206
1207         if (!fname) {
1208                 errno = EINVAL;
1209                 return -1;
1210         }
1211
1212         smbw_init();
1213
1214         smbw_busy++;
1215
1216         /* work out what server they are after */
1217         smbw_parse_path(fname, server, share, path);
1218
1219         /* get a connection to the server */
1220         srv = smbw_server(server, share);
1221         if (!srv) {
1222                 /* smbw_server sets errno */
1223                 goto failed;
1224         }
1225
1226         if (!cli_unlink(&srv->cli, path)) {
1227                 errno = smbw_errno(&srv->cli);
1228                 goto failed;
1229         }
1230
1231         smbw_busy--;
1232         return 0;
1233
1234  failed:
1235         smbw_busy--;
1236         return -1;
1237 }
1238
1239
1240 /***************************************************** 
1241 a wrapper for rename()
1242 *******************************************************/
1243 int smbw_rename(const char *oldname, const char *newname)
1244 {
1245         struct smbw_server *srv;
1246         fstring server1, share1;
1247         pstring path1;
1248         fstring server2, share2;
1249         pstring path2;
1250
1251         DEBUG(4,("%s (%s, %s)\n", __FUNCTION__, oldname, newname));
1252
1253         if (!oldname || !newname) {
1254                 errno = EINVAL;
1255                 return -1;
1256         }
1257
1258         smbw_init();
1259
1260         smbw_busy++;
1261
1262         /* work out what server they are after */
1263         smbw_parse_path(oldname, server1, share1, path1);
1264         smbw_parse_path(newname, server2, share2, path2);
1265
1266         if (strcmp(server1, server2) || strcmp(share1, share2)) {
1267                 /* can't cross filesystems */
1268                 errno = EXDEV;
1269                 return -1;
1270         }
1271
1272         /* get a connection to the server */
1273         srv = smbw_server(server1, share1);
1274         if (!srv) {
1275                 /* smbw_server sets errno */
1276                 goto failed;
1277         }
1278
1279         if (!cli_rename(&srv->cli, path1, path2)) {
1280                 errno = smbw_errno(&srv->cli);
1281                 goto failed;
1282         }
1283
1284         smbw_busy--;
1285         return 0;
1286
1287  failed:
1288         smbw_busy--;
1289         return -1;
1290 }
1291
1292
1293 /***************************************************** 
1294 a wrapper for utime()
1295 *******************************************************/
1296 int smbw_utime(const char *fname, struct utimbuf *buf)
1297 {
1298         struct smbw_server *srv;
1299         fstring server, share;
1300         pstring path;
1301         uint32 mode;
1302
1303         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1304
1305         if (!fname) {
1306                 errno = EINVAL;
1307                 return -1;
1308         }
1309
1310         smbw_init();
1311
1312         smbw_busy++;
1313
1314         /* work out what server they are after */
1315         smbw_parse_path(fname, server, share, path);
1316
1317         /* get a connection to the server */
1318         srv = smbw_server(server, share);
1319         if (!srv) {
1320                 /* smbw_server sets errno */
1321                 goto failed;
1322         }
1323
1324         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1325                 errno = smbw_errno(&srv->cli);
1326                 goto failed;
1327         }
1328
1329         if (!cli_setatr(&srv->cli, path, mode, buf->modtime)) {
1330                 errno = smbw_errno(&srv->cli);
1331                 goto failed;
1332         }
1333
1334         smbw_busy--;
1335         return 0;
1336
1337  failed:
1338         smbw_busy--;
1339         return -1;
1340 }
1341
1342 /***************************************************** 
1343 a wrapper for chown()
1344 *******************************************************/
1345 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1346 {
1347         struct smbw_server *srv;
1348         fstring server, share;
1349         pstring path;
1350         uint32 mode;
1351
1352         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1353
1354         if (!fname) {
1355                 errno = EINVAL;
1356                 return -1;
1357         }
1358
1359         smbw_init();
1360
1361         smbw_busy++;
1362
1363         /* work out what server they are after */
1364         smbw_parse_path(fname, server, share, path);
1365
1366         /* get a connection to the server */
1367         srv = smbw_server(server, share);
1368         if (!srv) {
1369                 /* smbw_server sets errno */
1370                 goto failed;
1371         }
1372
1373         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1374                 errno = smbw_errno(&srv->cli);
1375                 goto failed;
1376         }
1377         
1378         /* assume success */
1379
1380         smbw_busy--;
1381         return 0;
1382
1383  failed:
1384         smbw_busy--;
1385         return -1;
1386 }
1387
1388 /***************************************************** 
1389 a wrapper for chmod()
1390 *******************************************************/
1391 int smbw_chmod(const char *fname, mode_t newmode)
1392 {
1393         struct smbw_server *srv;
1394         fstring server, share;
1395         pstring path;
1396         uint32 mode;
1397
1398         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1399
1400         if (!fname) {
1401                 errno = EINVAL;
1402                 return -1;
1403         }
1404
1405         smbw_init();
1406
1407         smbw_busy++;
1408
1409         /* work out what server they are after */
1410         smbw_parse_path(fname, server, share, path);
1411
1412         /* get a connection to the server */
1413         srv = smbw_server(server, share);
1414         if (!srv) {
1415                 /* smbw_server sets errno */
1416                 goto failed;
1417         }
1418
1419         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1420                 errno = smbw_errno(&srv->cli);
1421                 goto failed;
1422         }
1423         
1424         /* assume success for the moment - need to add attribute mapping */
1425
1426         smbw_busy--;
1427         return 0;
1428
1429  failed:
1430         smbw_busy--;
1431         return -1;
1432 }
1433
1434
1435 /***************************************************** 
1436 a wrapper for lseek() on directories
1437 *******************************************************/
1438 off_t smbw_dir_lseek(int fd, off_t offset, int whence)
1439 {
1440         struct smbw_dir *dir;
1441         off_t ret;
1442
1443         DEBUG(4,("%s offset=%d whence=%d\n", __FUNCTION__, 
1444                  (int)offset, whence));
1445
1446         dir = smbw_dir(fd);
1447         if (!dir) {
1448                 errno = EBADF;
1449                 return -1;
1450         }
1451
1452         switch (whence) {
1453         case SEEK_SET:
1454                 dir->offset = offset/sizeof(struct dirent);
1455                 break;
1456         case SEEK_CUR:
1457                 dir->offset += offset/sizeof(struct dirent);
1458                 break;
1459         case SEEK_END:
1460                 dir->offset = (dir->count * sizeof(struct dirent)) + offset;
1461                 dir->offset /= sizeof(struct dirent);
1462                 break;
1463         }
1464
1465         ret = dir->offset * sizeof(struct dirent);
1466
1467         DEBUG(4,("   -> %d\n", (int)ret));
1468
1469         return ret;
1470 }
1471
1472 /***************************************************** 
1473 a wrapper for lseek()
1474 *******************************************************/
1475 off_t smbw_lseek(int fd, off_t offset, int whence)
1476 {
1477         struct smbw_file *file;
1478         uint32 size;
1479
1480         DEBUG(4,("%s\n", __FUNCTION__));
1481
1482         smbw_busy++;
1483
1484         file = smbw_file(fd);
1485         if (!file) {
1486                 off_t ret = smbw_dir_lseek(fd, offset, whence);
1487                 smbw_busy--;
1488                 return ret;
1489         }
1490
1491         switch (whence) {
1492         case SEEK_SET:
1493                 file->offset = offset;
1494                 break;
1495         case SEEK_CUR:
1496                 file->offset += offset;
1497                 break;
1498         case SEEK_END:
1499                 if (!cli_qfileinfo(&file->srv->cli, file->cli_fd, 
1500                                    NULL, &size, NULL, NULL, NULL) &&
1501                     !cli_getattrE(&file->srv->cli, file->cli_fd, 
1502                                   NULL, &size, NULL, NULL, NULL)) {
1503                         errno = EINVAL;
1504                         smbw_busy--;
1505                         return -1;
1506                 }
1507                 file->offset = size + offset;
1508                 break;
1509         }
1510
1511         smbw_busy--;
1512         return file->offset;
1513 }
1514
1515
1516 /***************************************************** 
1517 a wrapper for mkdir()
1518 *******************************************************/
1519 int smbw_mkdir(const char *fname, mode_t mode)
1520 {
1521         struct smbw_server *srv;
1522         fstring server, share;
1523         pstring path;
1524
1525         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1526
1527         if (!fname) {
1528                 errno = EINVAL;
1529                 return -1;
1530         }
1531
1532         smbw_init();
1533
1534         smbw_busy++;
1535
1536         /* work out what server they are after */
1537         smbw_parse_path(fname, server, share, path);
1538
1539         /* get a connection to the server */
1540         srv = smbw_server(server, share);
1541         if (!srv) {
1542                 /* smbw_server sets errno */
1543                 goto failed;
1544         }
1545
1546         if (!cli_mkdir(&srv->cli, path)) {
1547                 errno = smbw_errno(&srv->cli);
1548                 goto failed;
1549         }
1550
1551         smbw_busy--;
1552         return 0;
1553
1554  failed:
1555         smbw_busy--;
1556         return -1;
1557 }
1558
1559 /***************************************************** 
1560 a wrapper for rmdir()
1561 *******************************************************/
1562 int smbw_rmdir(const char *fname)
1563 {
1564         struct smbw_server *srv;
1565         fstring server, share;
1566         pstring path;
1567
1568         DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
1569
1570         if (!fname) {
1571                 errno = EINVAL;
1572                 return -1;
1573         }
1574
1575         smbw_init();
1576
1577         smbw_busy++;
1578
1579         /* work out what server they are after */
1580         smbw_parse_path(fname, server, share, path);
1581
1582         /* get a connection to the server */
1583         srv = smbw_server(server, share);
1584         if (!srv) {
1585                 /* smbw_server sets errno */
1586                 goto failed;
1587         }
1588
1589         if (!cli_rmdir(&srv->cli, path)) {
1590                 errno = smbw_errno(&srv->cli);
1591                 goto failed;
1592         }
1593
1594         smbw_busy--;
1595         return 0;
1596
1597  failed:
1598         smbw_busy--;
1599         return -1;
1600 }
1601
1602
1603 /***************************************************** 
1604 a wrapper for getcwd()
1605 *******************************************************/
1606 char *smbw_getcwd(char *buf, size_t size)
1607 {
1608         smbw_init();
1609
1610         if (smbw_busy) {
1611                 return __getcwd(buf, size);
1612         }
1613
1614         smbw_busy++;
1615
1616         if (!buf) {
1617                 if (size <= 0) size = strlen(smb_cwd)+1;
1618                 buf = (char *)malloc(size);
1619                 if (!buf) {
1620                         errno = ENOMEM;
1621                         smbw_busy--;
1622                         return NULL;
1623                 }
1624         }
1625
1626         if (strlen(smb_cwd) > size-1) {
1627                 errno = ERANGE;
1628                 smbw_busy--;
1629                 return NULL;
1630         }
1631
1632         safe_strcpy(buf, smb_cwd, size);
1633
1634         smbw_busy--;
1635         return buf;
1636 }