This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.
[samba.git] / source / libsmb / libsmbclient.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client library implementation
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Richard Sharpe 2000
6    Copyright (C) John Terpstra 2000
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libsmbclient.h"
25
26 /* Structure for servers ... Held here so we don't need an include ...
27  * May be better to put in an include file
28  */
29
30 struct smbc_server {
31         struct smbc_server *next, *prev;
32         struct cli_state cli;
33         dev_t dev;
34         char *server_name;
35         char *share_name;
36         char *workgroup;
37         char *username;
38         BOOL no_pathinfo2;
39 };
40
41 /* Keep directory entries in a list */
42 struct smbc_dir_list {
43         struct smbc_dir_list *next;
44         struct smbc_dirent *dirent;
45 };
46
47 struct smbc_file {
48         int cli_fd; 
49         int smbc_fd;
50         char *fname;
51         off_t offset;
52         struct smbc_server *srv;
53         BOOL file;
54         struct smbc_dir_list *dir_list, *dir_end, *dir_next;
55         int dir_type, dir_error;
56 };
57
58 int smbc_fstatdir(int fd, struct stat *st); /* Forward decl */
59 BOOL smbc_getatr(struct smbc_server *srv, char *path, 
60                  uint16 *mode, size_t *size, 
61                  time_t *c_time, time_t *a_time, time_t *m_time,
62                  SMB_INO_T *ino);
63
64 extern BOOL in_client;
65 extern pstring global_myname;
66 static int smbc_initialized = 0;
67 static smbc_get_auth_data_fn smbc_auth_fn = NULL;
68 /*static int smbc_debug;*/
69 static int smbc_start_fd;
70 static struct smbc_file **smbc_file_table;
71 static struct smbc_server *smbc_srvs;
72 static pstring  my_netbios_name;
73 static pstring smbc_user;
74
75 /*
76  * Function to parse a path and turn it into components
77  *
78  * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
79  * 
80  * smb://       means show all the workgroups
81  * smb://name/  means, if name<1D> exists, list servers in workgroup,
82  *              else, if name<20> exists, list all shares for server ...
83  */
84
85 static const char *smbc_prefix = "smb:";
86
87 static int
88 smbc_parse_path(const char *fname, char *server, char *share, char *path,
89                 char *user, char *password) /* FIXME, lengths of strings */
90 {
91         static pstring s;
92         pstring userinfo;
93         char *p;
94         char *q, *r;
95         int len;
96
97         server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
98         pstrcpy(s, fname);
99
100         /*  clean_fname(s);  causing problems ... */
101
102         /* see if it has the right prefix */
103         len = strlen(smbc_prefix);
104         if (strncmp(s,smbc_prefix,len) || 
105             (s[len] != '/' && s[len] != 0)) return -1; /* What about no smb: ? */
106
107         p = s + len;
108
109         /* Watch the test below, we are testing to see if we should exit */
110
111         if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
112
113                 return -1;
114
115         }
116
117         p += 2;  /* Skip the // or \\  */
118
119         if (*p == (char)0)
120                 return 0;
121
122         if (*p == '/') {
123
124                 strncpy(server, (char *)lp_workgroup(), 16); /* FIXME: Danger here */
125                 return 0;
126                 
127         }
128
129         /*
130          * ok, its for us. Now parse out the server, share etc. 
131          *
132          * However, we want to parse out [[domain;]user[:password]@] if it
133          * exists ...
134          */
135
136         /* check that '@' occurs before '/', if '/' exists at all */
137         q = strchr_m(p, '@');
138         r = strchr_m(p, '/');
139         if (q && (!r || q < r)) {
140                 pstring username, passwd, domain;
141                 char *u = userinfo;
142
143                 next_token(&p, userinfo, "@", sizeof(fstring));
144
145                 username[0] = passwd[0] = domain[0] = 0;
146
147                 if (strchr_m(u, ';')) {
148       
149                         next_token(&u, domain, ";", sizeof(fstring));
150                         
151                 }
152
153                 if (strchr_m(u, ':')) {
154
155                         next_token(&u, username, ":", sizeof(fstring));
156
157                         pstrcpy(passwd, u);
158
159                 }
160                 else {
161
162                         pstrcpy(username, u);
163
164                 }
165
166                 if (username[0])
167                         strncpy(user, username, sizeof(fstring));  /* FIXME, size and domain */
168
169                 if (passwd[0])
170                         strncpy(password, passwd, sizeof(fstring)); /* FIXME, size */
171
172         }
173
174         if (!next_token(&p, server, "/", sizeof(fstring))) {
175                 
176                 return -1;
177                 
178         }
179
180         if (*p == (char)0) return 0;  /* That's it ... */
181   
182         if (!next_token(&p, share, "/", sizeof(fstring))) {
183
184                 return -1;
185
186         }
187
188         pstrcpy(path, p);
189   
190         all_string_sub(path, "/", "\\", 0);
191
192         return 0;
193 }
194
195 /*
196  * Convert an SMB error into a UNIX error ...
197  */
198
199 int smbc_errno(struct cli_state *c)
200 {
201         int ret;
202
203         if (cli_is_dos_error(c)) {
204                 uint8 eclass;
205                 uint32 ecode;
206
207                 cli_dos_error(c, &eclass, &ecode);
208                 ret = cli_errno_from_dos(eclass, ecode);
209                 
210                 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 
211                          (int)eclass, (int)ecode, (int)ecode, ret));
212         } else {
213                 NTSTATUS status;
214
215                 status = cli_nt_error(c);
216                 ret = cli_errno_from_nt(status);
217
218                 DEBUG(3,("smbc errno %s -> %d\n",
219                          nt_errstr(status), ret));
220         }
221
222         return ret;
223 }
224
225 /*
226  * Connect to a server, possibly on an existing connection
227  *
228  * Here, what we want to do is: If the server and username
229  * match an existing connection, reuse that, otherwise, establish a 
230  * new connection.
231  *
232  * If we have to create a new connection, call the auth_fn to get the
233  * info we need, unless the username and password were passed in.
234  */
235
236 struct smbc_server *smbc_server(char *server, char *share, 
237                                 char *workgroup, char *username, 
238                                 char *password)
239 {
240         struct smbc_server *srv=NULL;
241         struct cli_state c;
242         struct nmb_name called, calling;
243         char *p, *server_n = server;
244         fstring group;
245         pstring ipenv;
246         struct in_addr ip;
247   
248         zero_ip(&ip);
249         ZERO_STRUCT(c);
250
251         /* try to use an existing connection */
252         for (srv=smbc_srvs;srv;srv=srv->next) {
253                 if (strcmp(server,srv->server_name)==0 &&
254                     strcmp(share,srv->share_name)==0 &&
255                     strcmp(workgroup,srv->workgroup)==0 &&
256                     strcmp(username, srv->username) == 0) 
257                         return srv;
258         }
259
260         if (server[0] == 0) {
261                 errno = EPERM;
262                 return NULL;
263         }
264
265         /* 
266          * Pick up the auth info here, once we know we need to connect
267          * But only if we do not have a username and password ...
268          */
269
270         if (!username[0] || !password[0])
271                 smbc_auth_fn(server, share, workgroup, sizeof(fstring),
272                              username, sizeof(fstring), password, sizeof(fstring));
273
274         /* 
275          * However, smbc_auth_fn may have picked up info relating to an 
276          * existing connection, so try for an existing connection again ...
277          */
278
279         for (srv=smbc_srvs;srv;srv=srv->next) {
280                 if (strcmp(server,srv->server_name)==0 &&
281                     strcmp(share,srv->share_name)==0 &&
282                     strcmp(workgroup,srv->workgroup)==0 &&
283                     strcmp(username, srv->username) == 0) 
284                         return srv;
285         }
286
287         make_nmb_name(&calling, my_netbios_name, 0x0);
288         make_nmb_name(&called , server, 0x20);
289
290         DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
291   
292         if ((p=strchr_m(server_n,'#')) && 
293             (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
294     
295                 fstrcpy(group, server_n);
296                 p = strchr_m(group,'#');
297                 *p = 0;
298                 
299         }
300
301         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
302
303  again:
304         slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
305
306         zero_ip(&ip);
307
308         /* have to open a new connection */
309         if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
310                 if (c.initialised) cli_shutdown(&c);
311                 errno = ENOENT;
312                 return NULL;
313         }
314
315         if (!cli_session_request(&c, &calling, &called)) {
316                 cli_shutdown(&c);
317                 if (strcmp(called.name, "*SMBSERVER")) {
318                         make_nmb_name(&called , "*SMBSERVER", 0x20);
319                         goto again;
320                 }
321                 errno = ENOENT;
322                 return NULL;
323         }
324   
325         DEBUG(4,(" session request ok\n"));
326   
327         if (!cli_negprot(&c)) {
328                 cli_shutdown(&c);
329                 errno = ENOENT;
330                 return NULL;
331         }
332
333         if (!cli_session_setup(&c, username, 
334                                password, strlen(password),
335                                password, strlen(password),
336                                workgroup) &&
337             /* try an anonymous login if it failed */
338             !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
339                 cli_shutdown(&c);
340                 errno = EPERM;
341                 return NULL;
342         }
343
344         DEBUG(4,(" session setup ok\n"));
345
346         if (!cli_send_tconX(&c, share, "?????",
347                             password, strlen(password)+1)) {
348                 errno = smbc_errno(&c);
349                 cli_shutdown(&c);
350                 return NULL;
351         }
352   
353         DEBUG(4,(" tconx ok\n"));
354   
355         srv = (struct smbc_server *)malloc(sizeof(*srv));
356         if (!srv) {
357                 errno = ENOMEM;
358                 goto failed;
359         }
360
361         ZERO_STRUCTP(srv);
362
363         srv->cli = c;
364
365         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
366
367         srv->server_name = strdup(server);
368         if (!srv->server_name) {
369                 errno = ENOMEM;
370                 goto failed;
371         }
372
373         srv->share_name = strdup(share);
374         if (!srv->share_name) {
375                 errno = ENOMEM;
376                 goto failed;
377         }
378
379         srv->workgroup = strdup(workgroup);
380         if (!srv->workgroup) {
381                 errno = ENOMEM;
382                 goto failed;
383         }
384
385         srv->username = strdup(username);
386         if (!srv->username) {
387                 errno = ENOMEM;
388                 goto failed;
389         }
390
391         DLIST_ADD(smbc_srvs, srv);
392
393         return srv;
394
395  failed:
396         cli_shutdown(&c);
397         if (!srv) return NULL;
398   
399         SAFE_FREE(srv->server_name);
400         SAFE_FREE(srv->share_name);
401         SAFE_FREE(srv->workgroup);
402         SAFE_FREE(srv->username);
403         SAFE_FREE(srv);
404         return NULL;
405 }
406
407 /* 
408  *Remove a server from the list smbc_srvs if it's unused -- Tom (tom@ninja.nl)
409  *
410  * We accept a *srv 
411  */
412 BOOL smbc_remove_unused_server(struct smbc_server * s)
413 {
414         int p;
415
416         /* are we being fooled ? */
417         if (!s) return False;
418
419         /* close all open files/directories on this server */
420         for (p = 0; p < SMBC_MAX_FD; p++) {
421                 if (smbc_file_table[p] &&
422                     smbc_file_table[p]->srv == s) {
423                         /* Still used .. DARN */
424                         DEBUG(3, ("smbc_remove_usused_server: %x still used by %s (%d).\n", (int) s, 
425                                   smbc_file_table[p]->fname, smbc_file_table[p]->smbc_fd));
426                         return False;
427                 }
428         }
429
430         cli_shutdown(&s->cli);
431         
432         SAFE_FREE(s->username);
433         SAFE_FREE(s->workgroup);
434         SAFE_FREE(s->server_name);
435         SAFE_FREE(s->share_name);
436         DLIST_REMOVE(smbc_srvs, s);
437         DEBUG(3, ("smbc_remove_usused_server: %x removed.\n", (int) s));
438         SAFE_FREE(s);
439         return True;
440 }
441
442 /*
443  *Initialise the library etc 
444  *
445  * We accept valid values for debug from 0 to 100,
446  * and insist that fn must be non-null.
447  */
448
449 int smbc_init(smbc_get_auth_data_fn fn, int debug)
450 {
451         pstring conf;
452         int p, pid;
453         char *user = NULL, *home = NULL, *pname="libsmbclient";
454
455         if (!fn || debug < 0 || debug > 100) {
456
457                 errno = EINVAL;
458                 return -1;
459
460         }
461
462         if (smbc_initialized) { /* Don't go through this if we have already done it */
463
464                 return 0;
465
466         }
467
468         smbc_initialized = 1;
469         smbc_auth_fn = fn;
470         /*  smbc_debug = debug; */
471
472         DEBUGLEVEL = -1;
473
474         setup_logging(pname, False);
475
476         /* Here we would open the smb.conf file if needed ... */
477
478         home = getenv("HOME");
479
480         slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
481
482         load_interfaces();  /* Load the list of interfaces ... */
483
484         in_client = True; /* FIXME, make a param */
485
486         if (!lp_load(conf, True, False, False)) {
487
488                 /*
489                  * Hmmm, what the hell do we do here ... we could not parse the
490                  * config file ... We must return an error ... and keep info around
491                  * about why we failed
492                  */
493     
494                 errno = ENOENT; /* FIXME: Figure out the correct error response */
495                 return -1;
496
497         }
498
499         reopen_logs();  /* Get logging working ... */
500
501         /*
502          * FIXME: Is this the best way to get the user info? 
503          */
504
505         user = getenv("USER");
506         /* walk around as "guest" if no username can be found */
507         if (!user) user = strdup("guest");
508         pstrcpy(smbc_user, user); /* Save for use elsewhere */
509         
510         /*
511          * We try to get our netbios name from the config. If that fails we fall
512          * back on constructing our netbios name from our hostname etc
513          */
514         if (global_myname) {
515                 pstrcpy(my_netbios_name, global_myname);
516         }
517         else {
518                 /*
519                  * Hmmm, I want to get hostname as well, but I am too lazy for the moment
520                  */
521                 pid = sys_getpid();
522                 slprintf(my_netbios_name, 16, "smbc%s%d", user, pid);
523         }
524         DEBUG(0,("Using netbios name %s.\n", my_netbios_name));
525
526         name_register_wins(my_netbios_name, 0);
527
528         /* 
529          * Now initialize the file descriptor array and figure out what the
530          * max open files is, so we can return FD's that are above the max
531          * open file, and separated by a guard band
532          */
533
534 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
535         do {
536                 struct rlimit rlp;
537
538                 if (getrlimit(RLIMIT_NOFILE, &rlp)) {
539
540                         DEBUG(0, ("smbc_init: getrlimit(1) for RLIMIT_NOFILE failed with error %s\n", strerror(errno)));
541
542                         smbc_start_fd = 1000000;
543
544                 }
545                 else {
546       
547                         smbc_start_fd = rlp.rlim_max + 10000; /* Leave a guard space of 10,000 */
548
549                 }
550         } while ( 0 );
551 #else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
552
553         smbc_start_fd = 1000000;
554
555 #endif
556
557         smbc_file_table = malloc(SMBC_MAX_FD * sizeof(struct smbc_file *));
558
559         for (p = 0; p < SMBC_MAX_FD; p++)
560                 smbc_file_table[p] = NULL;
561
562         if (!smbc_file_table)
563                 return ENOMEM;
564
565         return 0;  /* Success */
566
567 }
568
569 /*
570  * Routine to open() a file ...
571  */
572
573 int smbc_open(const char *fname, int flags, mode_t mode)
574 {
575         fstring server, share, user, password, workgroup;
576         pstring path;
577         struct smbc_server *srv = NULL;
578         int fd;
579
580         if (!smbc_initialized) {
581
582                 errno = EINVAL;  /* Best I can think of ... */
583                 return -1;
584
585         }
586
587         if (!fname) {
588
589                 errno = EINVAL;
590                 return -1;
591
592         }
593
594         smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
595
596         if (user[0] == (char)0) pstrcpy(user, smbc_user);
597
598         pstrcpy(workgroup, lp_workgroup());
599
600         srv = smbc_server(server, share, workgroup, user, password);
601
602         if (!srv) {
603
604                 if (errno == EPERM) errno = EACCES;
605                 return -1;  /* smbc_server sets errno */
606
607         }
608
609         /* Hmmm, the test for a directory is suspect here ... FIXME */
610
611         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
612     
613                 fd = -1;
614
615         }
616         else {
617
618                 int slot = 0;
619
620                 /* Find a free slot first */
621
622                 while (smbc_file_table[slot])
623                         slot++;
624
625                 if (slot > SMBC_MAX_FD) {
626
627                         errno = ENOMEM; /* FIXME, is this best? */
628                         return -1;
629
630                 }
631
632                 smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
633
634                 if (!smbc_file_table[slot]) {
635
636                         errno = ENOMEM;
637                         return -1;
638
639                 }
640
641                 if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) {
642
643                         /* Handle the error ... */
644
645                         SAFE_FREE(smbc_file_table[slot]);
646                         errno = smbc_errno(&srv->cli);
647                         return -1;
648
649                 }
650
651                 /* Fill in file struct */
652
653                 smbc_file_table[slot]->cli_fd  = fd;
654                 smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
655                 smbc_file_table[slot]->fname   = strdup(fname);
656                 smbc_file_table[slot]->srv     = srv;
657                 smbc_file_table[slot]->offset  = 0;
658                 smbc_file_table[slot]->file    = True;
659
660                 return smbc_file_table[slot]->smbc_fd;
661
662         }
663
664         /* Check if opendir needed ... */
665
666         if (fd == -1) {
667                 int eno = 0;
668
669                 eno = smbc_errno(&srv->cli);
670                 fd = smbc_opendir(fname);
671                 if (fd < 0) errno = eno;
672                 return fd;
673
674         }
675
676         return 1;  /* Success, with fd ... */
677
678 }
679
680 /*
681  * Routine to create a file 
682  */
683
684 static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
685
686 int smbc_creat(const char *path, mode_t mode)
687 {
688
689         if (!smbc_initialized) {
690
691                 errno = EINVAL;
692                 return -1;
693
694         }
695
696         return smbc_open(path, creat_bits, mode);
697 }
698
699 /*
700  * Routine to read() a file ...
701  */
702
703 ssize_t smbc_read(int fd, void *buf, size_t count)
704 {
705         struct smbc_file *fe;
706         int ret;
707
708         if (!smbc_initialized) {
709
710                 errno = EINVAL;
711                 return -1;
712
713         }
714
715         DEBUG(4, ("smbc_read(%d, %d)\n", fd, (int)count));
716
717         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
718
719                 errno = EBADF;
720                 return -1;
721
722         }
723
724         /* Check that the buffer exists ... */
725
726         if (buf == NULL) {
727
728                 errno = EINVAL;
729                 return -1;
730
731         }
732
733         fe = smbc_file_table[fd - smbc_start_fd];
734
735         if (!fe || !fe->file) {
736
737                 errno = EBADF;
738                 return -1;
739
740         }
741
742         ret = cli_read(&fe->srv->cli, fe->cli_fd, buf, fe->offset, count);
743
744         if (ret < 0) {
745
746                 errno = smbc_errno(&fe->srv->cli);
747                 return -1;
748
749         }
750
751         fe->offset += ret;
752
753         DEBUG(4, ("  --> %d\n", ret));
754
755         return ret;  /* Success, ret bytes of data ... */
756
757 }
758
759 /*
760  * Routine to write() a file ...
761  */
762
763 ssize_t smbc_write(int fd, void *buf, size_t count)
764 {
765         int ret;
766         struct smbc_file *fe;
767
768         if (!smbc_initialized) {
769
770                 errno = EINVAL;
771                 return -1;
772
773         }
774
775         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
776
777                 errno = EBADF;
778                 return -1;
779     
780         }
781
782         /* Check that the buffer exists ... */
783
784         if (buf == NULL) {
785
786                 errno = EINVAL;
787                 return -1;
788
789         }
790
791         fe = smbc_file_table[fd - smbc_start_fd];
792
793         if (!fe || !fe->file) {
794
795                 errno = EBADF;
796                 return -1;
797
798         }
799
800         ret = cli_write(&fe->srv->cli, fe->cli_fd, 0, buf, fe->offset, count);
801
802         if (ret <= 0) {
803
804                 errno = smbc_errno(&fe->srv->cli);
805                 return -1;
806
807         }
808
809         fe->offset += ret;
810
811         return ret;  /* Success, 0 bytes of data ... */
812 }
813  
814 /*
815  * Routine to close() a file ...
816  */
817
818 int smbc_close(int fd)
819 {
820         struct smbc_file *fe;
821         struct smbc_server *srv;
822
823         if (!smbc_initialized) {
824
825                 errno = EINVAL;
826                 return -1;
827
828         }
829
830         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
831    
832                 errno = EBADF;
833                 return -1;
834
835         }
836
837         fe = smbc_file_table[fd - smbc_start_fd];
838
839         if (!fe) {
840
841                 errno = EBADF;
842                 return -1;
843
844         }
845
846         if (!fe->file) {
847
848                 return smbc_closedir(fd);
849
850         }
851
852         if (!cli_close(&fe->srv->cli, fe->cli_fd)) {
853
854                 DEBUG(3, ("cli_close failed on %s (%d). purging server.\n", 
855                           fe->fname, fe->smbc_fd));
856                 /* Deallocate slot and remove the server 
857                  * from the server cache if unused */
858                 errno = smbc_errno(&fe->srv->cli);  
859                 srv = fe->srv;
860                 SAFE_FREE(fe->fname);
861                 SAFE_FREE(fe);
862                 smbc_file_table[fd - smbc_start_fd] = NULL;
863                 smbc_remove_unused_server(srv);
864
865                 return -1;
866
867         }
868
869         SAFE_FREE(fe->fname);
870         SAFE_FREE(fe);
871         smbc_file_table[fd - smbc_start_fd] = NULL;
872
873         return 0;
874 }
875
876 /*
877  * Routine to unlink() a file
878  */
879
880 int smbc_unlink(const char *fname)
881 {
882         fstring server, share, user, password, workgroup;
883         pstring path;
884         struct smbc_server *srv = NULL;
885
886         if (!smbc_initialized) {
887
888                 errno = EINVAL;  /* Best I can think of ... */
889                 return -1;
890
891         }
892
893         if (!fname) {
894
895                 errno = EINVAL;
896                 return -1;
897
898         }
899
900         smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
901
902         if (user[0] == (char)0) pstrcpy(user, smbc_user);
903
904         pstrcpy(workgroup, lp_workgroup());
905
906         srv = smbc_server(server, share, workgroup, user, password);
907
908         if (!srv) {
909
910                 return -1;  /* smbc_server sets errno */
911
912         }
913
914         /*  if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
915
916             int job = smbc_stat_printjob(srv, path, NULL, NULL);
917             if (job == -1) {
918
919             return -1;
920
921             }
922             if ((err = cli_printjob_del(&srv->cli, job)) != 0) {
923
924     
925             return -1;
926
927             }
928             } else */
929
930         if (!cli_unlink(&srv->cli, path)) {
931
932                 errno = smbc_errno(&srv->cli);
933
934                 if (errno == EACCES) { /* Check if the file is a directory */
935
936                         int saverr = errno;
937                         size_t size = 0;
938                         uint16 mode = 0;
939                         time_t m_time = 0, a_time = 0, c_time = 0;
940                         SMB_INO_T ino = 0;
941
942                         if (!smbc_getatr(srv, path, &mode, &size,
943                                          &c_time, &a_time, &m_time, &ino)) {
944
945                                 /* Hmmm, bad error ... What? */
946
947                                 errno = smbc_errno(&srv->cli);
948                                 return -1;
949
950                         }
951                         else {
952
953                                 if (IS_DOS_DIR(mode))
954                                         errno = EISDIR;
955                                 else
956                                         errno = saverr;  /* Restore this */
957
958                         }
959                 }
960
961                 return -1;
962
963         }
964
965         return 0;  /* Success ... */
966
967 }
968
969 /*
970  * Routine to rename() a file
971  */
972
973 int smbc_rename(const char *oname, const char *nname)
974 {
975         fstring server1, share1, server2, share2, user1, user2, password1, password2, workgroup;
976         pstring path1, path2;
977         struct smbc_server *srv = NULL;
978
979         if (!smbc_initialized) {
980
981                 errno = EINVAL;  /* Best I can think of ... */
982                 return -1;
983
984         }
985
986         if (!oname || !nname) {
987
988                 errno = EINVAL;
989                 return -1;
990
991         }
992   
993         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
994
995         smbc_parse_path(oname, server1, share1, path1, user1, password1);
996
997         if (user1[0] == (char)0) pstrcpy(user1, smbc_user);
998
999         smbc_parse_path(nname, server2, share2, path2, user2, password2);
1000
1001         if (user2[0] == (char)0) pstrcpy(user2, smbc_user);
1002
1003         if (strcmp(server1, server2) || strcmp(share1, share2) ||
1004             strcmp(user1, user2)) {
1005
1006                 /* Can't rename across file systems, or users?? */
1007
1008                 errno = EXDEV;
1009                 return -1;
1010
1011         }
1012
1013         pstrcpy(workgroup, lp_workgroup());
1014
1015         srv = smbc_server(server1, share1, workgroup, user1, password1);
1016         if (!srv) {
1017
1018                 return -1;
1019
1020         }
1021
1022         if (!cli_rename(&srv->cli, path1, path2)) {
1023                 int eno = smbc_errno(&srv->cli);
1024
1025                 if (eno != EEXIST ||
1026                     !cli_unlink(&srv->cli, path2) ||
1027                     !cli_rename(&srv->cli, path1, path2)) {
1028
1029                         errno = eno;
1030                         return -1;
1031
1032                 }
1033         }
1034
1035         return 0; /* Success */
1036
1037 }
1038
1039 /*
1040  * A routine to lseek() a file
1041  */
1042
1043 off_t smbc_lseek(int fd, off_t offset, int whence)
1044 {
1045         struct smbc_file *fe;
1046         size_t size;
1047
1048         if (!smbc_initialized) {
1049
1050                 errno = EINVAL;
1051                 return -1;
1052
1053         }
1054
1055         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
1056
1057                 errno = EBADF;
1058                 return -1;
1059
1060         }
1061
1062         fe = smbc_file_table[fd - smbc_start_fd];
1063
1064         if (!fe) {
1065
1066                 errno = EBADF;
1067                 return -1;
1068
1069         }
1070
1071         if (!fe->file) {
1072
1073                 errno = EINVAL;
1074                 return -1;      /* Can't lseek a dir ... */
1075
1076         }
1077
1078         switch (whence) {
1079         case SEEK_SET:
1080                 fe->offset = offset;
1081                 break;
1082
1083         case SEEK_CUR:
1084                 fe->offset += offset;
1085                 break;
1086
1087         case SEEK_END:
1088                 if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
1089                                    NULL, NULL, NULL) &&
1090                     !cli_getattrE(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
1091                                   NULL)) {
1092
1093                         errno = EINVAL;
1094                         return -1;
1095                 }
1096                 fe->offset = size + offset;
1097                 break;
1098
1099         default:
1100                 errno = EINVAL;
1101                 break;
1102
1103         }
1104
1105         return fe->offset;
1106
1107 }
1108
1109 /* 
1110  * Generate an inode number from file name for those things that need it
1111  */
1112
1113 static
1114 ino_t smbc_inode(const char *name)
1115 {
1116
1117         if (!*name) return 2; /* FIXME, why 2 ??? */
1118         return (ino_t)str_checksum(name);
1119
1120 }
1121
1122 /*
1123  * Routine to put basic stat info into a stat structure ... Used by stat and
1124  * fstat below.
1125  */
1126
1127 static
1128 int smbc_setup_stat(struct stat *st, char *fname, size_t size, int mode)
1129 {
1130
1131         st->st_mode = 0;
1132
1133         if (IS_DOS_DIR(mode)) {
1134                 st->st_mode = SMBC_DIR_MODE;
1135         } else {
1136                 st->st_mode = SMBC_FILE_MODE;
1137         }
1138
1139         if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
1140         if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
1141         if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
1142         if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
1143
1144         st->st_size = size;
1145         st->st_blksize = 512;
1146         st->st_blocks = (size+511)/512;
1147         st->st_uid = getuid();
1148         st->st_gid = getgid();
1149
1150         if (IS_DOS_DIR(mode)) {
1151                 st->st_nlink = 2;
1152         } else {
1153                 st->st_nlink = 1;
1154         }
1155
1156         if (st->st_ino == 0) {
1157                 st->st_ino = smbc_inode(fname);
1158         }
1159
1160         return True;  /* FIXME: Is this needed ? */
1161
1162 }
1163
1164 /*
1165  * Get info from an SMB server on a file. Use a qpathinfo call first
1166  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
1167  */
1168
1169 BOOL smbc_getatr(struct smbc_server *srv, char *path, 
1170                  uint16 *mode, size_t *size, 
1171                  time_t *c_time, time_t *a_time, time_t *m_time,
1172                  SMB_INO_T *ino)
1173 {
1174
1175         if (!smbc_initialized) {
1176
1177                 errno = EINVAL;
1178                 return -1;
1179
1180         }
1181
1182         DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
1183   
1184         if (!srv->no_pathinfo2 &&
1185             cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
1186                            size, mode, ino)) return True;
1187
1188         /* if this is NT then don't bother with the getatr */
1189         if (srv->cli.capabilities & CAP_NT_SMBS) return False;
1190
1191         if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
1192                 a_time = c_time = m_time;
1193                 srv->no_pathinfo2 = True;
1194                 return True;
1195         }
1196         return False;
1197 }
1198
1199 /*
1200  * Routine to stat a file given a name
1201  */
1202
1203 int smbc_stat(const char *fname, struct stat *st)
1204 {
1205         struct smbc_server *srv;
1206         fstring server, share, user, password, workgroup;
1207         pstring path;
1208         time_t m_time = 0, a_time = 0, c_time = 0;
1209         size_t size = 0;
1210         uint16 mode = 0;
1211         SMB_INO_T ino = 0;
1212
1213         if (!smbc_initialized) {
1214
1215                 errno = EINVAL;  /* Best I can think of ... */
1216                 return -1;
1217
1218         }
1219
1220         if (!fname) {
1221
1222                 errno = EINVAL;
1223                 return -1;
1224
1225         }
1226   
1227         DEBUG(4, ("smbc_stat(%s)\n", fname));
1228
1229         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
1230
1231         if (user[0] == (char)0) pstrcpy(user, smbc_user);
1232
1233         pstrcpy(workgroup, lp_workgroup());
1234
1235         srv = smbc_server(server, share, workgroup, user, password);
1236
1237         if (!srv) {
1238
1239                 return -1;  /* errno set by smbc_server */
1240
1241         }
1242
1243         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1244
1245            mode = aDIR | aRONLY;
1246
1247            }
1248            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1249
1250            if (strcmp(path, "\\") == 0) {
1251
1252            mode = aDIR | aRONLY;
1253
1254            }
1255            else {
1256
1257            mode = aRONLY;
1258            smbc_stat_printjob(srv, path, &size, &m_time);
1259            c_time = a_time = m_time;
1260
1261            }
1262            else { */
1263
1264         if (!smbc_getatr(srv, path, &mode, &size, 
1265                          &c_time, &a_time, &m_time, &ino)) {
1266
1267                 errno = smbc_errno(&srv->cli);
1268                 return -1;
1269
1270         }
1271
1272         /* } */
1273
1274         st->st_ino = ino;
1275
1276         smbc_setup_stat(st, path, size, mode);
1277
1278         st->st_atime = a_time;
1279         st->st_ctime = c_time;
1280         st->st_mtime = m_time;
1281         st->st_dev   = srv->dev;
1282
1283         return 0;
1284
1285 }
1286
1287 /*
1288  * Routine to stat a file given an fd
1289  */
1290
1291 int smbc_fstat(int fd, struct stat *st)
1292 {
1293         struct smbc_file *fe;
1294         time_t c_time, a_time, m_time;
1295         size_t size;
1296         uint16 mode;
1297         SMB_INO_T ino = 0;
1298
1299         if (!smbc_initialized) {
1300
1301                 errno = EINVAL;
1302                 return -1;
1303
1304         }
1305
1306         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
1307
1308                 errno = EBADF;
1309                 return -1;
1310
1311         }
1312
1313         fe = smbc_file_table[fd - smbc_start_fd];
1314
1315         if (!fe) {
1316
1317                 errno = EBADF;
1318                 return -1;
1319
1320         }
1321
1322         if (!fe->file) {
1323
1324                 return smbc_fstatdir(fd, st);
1325
1326         }
1327
1328         if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd,
1329                            &mode, &size, &c_time, &a_time, &m_time, NULL, &ino) &&
1330             !cli_getattrE(&fe->srv->cli, fe->cli_fd,
1331                           &mode, &size, &c_time, &a_time, &m_time)) {
1332
1333                 errno = EINVAL;
1334                 return -1;
1335
1336         }
1337
1338         st->st_ino = ino;
1339
1340         smbc_setup_stat(st, fe->fname, size, mode);
1341
1342         st->st_atime = a_time;
1343         st->st_ctime = c_time;
1344         st->st_mtime = m_time;
1345         st->st_dev = fe->srv->dev;
1346
1347         return 0;
1348
1349 }
1350
1351 /*
1352  * Routine to open a directory
1353  *
1354  * We want to allow:
1355  *
1356  * smb: which should list all the workgroups available
1357  * smb:workgroup
1358  * smb:workgroup//server
1359  * smb://server
1360  * smb://server/share
1361  * smb://<IP-addr> which should list shares on server
1362  * smb://<IP-addr>/share which should list files on share
1363  */
1364
1365 static void smbc_remove_dir(struct smbc_file *dir)
1366 {
1367         struct smbc_dir_list *d,*f;
1368
1369         d = dir->dir_list;
1370         while (d) {
1371
1372                 f = d; d = d->next;
1373
1374                 SAFE_FREE(f->dirent);
1375                 SAFE_FREE(f);
1376
1377         }
1378
1379         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
1380
1381 }
1382
1383 static int add_dirent(struct smbc_file *dir, const char *name, const char *comment, uint32 type)
1384 {
1385         struct smbc_dirent *dirent;
1386         int size;
1387
1388         /*
1389          * Allocate space for the dirent, which must be increased by the 
1390          * size of the name and the comment and 1 for the null on the comment.
1391          * The null on the name is already accounted for.
1392          */
1393
1394         size = sizeof(struct smbc_dirent) + (name?strlen(name):0) +
1395                 (comment?strlen(comment):0) + 1; 
1396     
1397         dirent = malloc(size);
1398
1399         if (!dirent) {
1400
1401                 dir->dir_error = ENOMEM;
1402                 return -1;
1403
1404         }
1405
1406         if (dir->dir_list == NULL) {
1407
1408                 dir->dir_list = malloc(sizeof(struct smbc_dir_list));
1409                 if (!dir->dir_list) {
1410
1411                         SAFE_FREE(dirent);
1412                         dir->dir_error = ENOMEM;
1413                         return -1;
1414
1415                 }
1416
1417                 dir->dir_end = dir->dir_next = dir->dir_list;
1418   
1419         }
1420         else {
1421
1422                 dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
1423
1424                 if (!dir->dir_end) {
1425
1426                         SAFE_FREE(dirent);
1427                         dir->dir_error = ENOMEM;
1428                         return -1;
1429
1430                 }
1431
1432                 dir->dir_end = dir->dir_end->next;
1433
1434         }
1435
1436         dir->dir_end->next = NULL;
1437         dir->dir_end->dirent = dirent;
1438
1439         dirent->smbc_type = type;
1440         dirent->namelen = (name?strlen(name):0);
1441         dirent->commentlen = (comment?strlen(comment):0);
1442         dirent->dirlen = size;
1443   
1444         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
1445
1446         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
1447         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
1448
1449         return 0;
1450
1451 }
1452
1453 static void
1454 list_fn(const char *name, uint32 type, const char *comment, void *state)
1455 {
1456         struct smbc_file *dir = (struct smbc_file *)state;
1457         int dirent_type;
1458
1459         /* We need to process the type a little ... */
1460
1461         if (dir->dir_type == SMBC_FILE_SHARE) {
1462
1463                 switch (type) {
1464                 case 0: /* Directory tree */
1465                         dirent_type = SMBC_FILE_SHARE;
1466                         break;
1467
1468                 case 1:
1469                         dirent_type = SMBC_PRINTER_SHARE;
1470                         break;
1471
1472                 case 2:
1473                         dirent_type = SMBC_COMMS_SHARE;
1474                         break;
1475
1476                 case 3:
1477                         dirent_type = SMBC_IPC_SHARE;
1478                         break;
1479
1480                 default:
1481                         dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
1482                         break;
1483                 }
1484
1485         }
1486         else dirent_type = dir->dir_type;
1487
1488         if (add_dirent(dir, name, comment, dirent_type) < 0) {
1489
1490                 /* An error occurred, what do we do? */
1491                 /* FIXME: Add some code here */
1492
1493         }
1494
1495 }
1496
1497 static void
1498 dir_list_fn(file_info *finfo, const char *mask, void *state)
1499 {
1500
1501         if (add_dirent((struct smbc_file *)state, finfo->name, "", 
1502                        (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
1503
1504                 /* Handle an error ... */
1505                 /* FIXME: Add some code ... */
1506
1507         } 
1508
1509 }
1510
1511 int smbc_opendir(const char *fname)
1512 {
1513         fstring server, share, user, password, workgroup;
1514         pstring path;
1515         struct smbc_server *srv = NULL;
1516         struct in_addr rem_ip;
1517         int slot = 0;
1518
1519         if (!smbc_initialized) {
1520
1521                 errno = EINVAL;
1522                 return -1;
1523
1524         }
1525
1526         if (!fname) {
1527     
1528                 errno = EINVAL;
1529                 return -1;
1530
1531         }
1532
1533         if (smbc_parse_path(fname, server, share, path, user, password)) {
1534
1535                 errno = EINVAL;
1536                 return -1;
1537
1538         }
1539
1540         if (user[0] == (char)0) pstrcpy(user, smbc_user);
1541
1542         pstrcpy(workgroup, lp_workgroup());
1543
1544         /* Get a file entry ... */
1545
1546         slot = 0;
1547
1548         while (smbc_file_table[slot])
1549                 slot++;
1550
1551         if (slot > SMBC_MAX_FD) {
1552
1553                 errno = ENOMEM;
1554                 return -1; /* FIXME, ... move into a func */
1555       
1556         }
1557
1558         smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
1559
1560         if (!smbc_file_table[slot]) {
1561
1562                 errno = ENOMEM;
1563                 return -1;
1564
1565         }
1566
1567         smbc_file_table[slot]->cli_fd   = 0;
1568         smbc_file_table[slot]->smbc_fd  = slot + smbc_start_fd;
1569         smbc_file_table[slot]->fname    = strdup(fname);
1570         smbc_file_table[slot]->srv      = NULL;
1571         smbc_file_table[slot]->offset   = 0;
1572         smbc_file_table[slot]->file     = False;
1573         smbc_file_table[slot]->dir_list = 
1574                 smbc_file_table[slot]->dir_next =
1575                 smbc_file_table[slot]->dir_end = NULL;
1576
1577         if (server[0] == (char)0) {
1578
1579                 if (share[0] != (char)0 || path[0] != (char)0) {
1580     
1581                         errno = EINVAL;
1582                         if (smbc_file_table[slot]) {
1583                                 SAFE_FREE(smbc_file_table[slot]->fname);
1584                                 SAFE_FREE(smbc_file_table[slot]);
1585                         }
1586                         return -1;
1587
1588                 }
1589
1590                 /* We have server and share and path empty ... so list the workgroups */
1591
1592                 if (!resolve_name(lp_workgroup(), &rem_ip, 0x1d)) {
1593       
1594                         errno = EINVAL;  /* Something wrong with smb.conf? */
1595                         return -1;
1596
1597                 }
1598
1599                 smbc_file_table[slot]->dir_type = SMBC_WORKGROUP;
1600
1601                 /* find the name of the server ... */
1602
1603                 if (!name_status_find("*", 0, 0, rem_ip, server)) {
1604
1605                         DEBUG(0, ("Could not get the name of local master browser for server %s\n", server));
1606                         errno = EINVAL;
1607                         return -1;
1608
1609                 }
1610
1611                 /*
1612                  * Get a connection to IPC$ on the server if we do not already have one
1613                  */
1614
1615                 srv = smbc_server(server, "IPC$", workgroup, user, password);
1616
1617                 if (!srv) {
1618
1619                         if (smbc_file_table[slot]) {
1620                                 SAFE_FREE(smbc_file_table[slot]->fname);
1621                                 SAFE_FREE(smbc_file_table[slot]);
1622                         }
1623                         return -1;
1624
1625                 }
1626
1627                 smbc_file_table[slot]->srv = srv;
1628
1629                 /* Now, list the stuff ... */
1630
1631                 if (!cli_NetServerEnum(&srv->cli, workgroup, 0x80000000, list_fn,
1632                                        (void *)smbc_file_table[slot])) {
1633
1634                         if (smbc_file_table[slot]) {
1635                                 SAFE_FREE(smbc_file_table[slot]->fname);
1636                                 SAFE_FREE(smbc_file_table[slot]);
1637                         }
1638                         errno = cli_errno(&srv->cli);
1639                         return -1;
1640
1641                 }
1642         }
1643         else { /* Server not an empty string ... Check the rest and see what gives */
1644
1645                 if (share[0] == (char)0) {
1646
1647                         if (path[0] != (char)0) { /* Should not have empty share with path */
1648
1649                                 errno = EINVAL;
1650                                 if (smbc_file_table[slot]) {
1651                                         SAFE_FREE(smbc_file_table[slot]->fname);
1652                                         SAFE_FREE(smbc_file_table[slot]);
1653                                 }
1654                                 return -1;
1655         
1656                         }
1657
1658                         /* Check to see if <server><1D> translates, or <server><20> translates */
1659                         /* However, we check to see if <server> is an IP address first */
1660
1661                         if (!is_ipaddress(server) &&  /* Not an IP addr so check next */
1662                             resolve_name(server, &rem_ip, 0x1d)) { /* Found LMB */
1663                                 pstring buserver;
1664
1665                                 smbc_file_table[slot]->dir_type = SMBC_SERVER;
1666
1667                                 /*
1668                                  * Get the backup list ...
1669                                  */
1670
1671
1672                                 if (!name_status_find("*", 0, 0, rem_ip, buserver)) {
1673
1674                                         DEBUG(0, ("Could not get name of local master browser %s\n", server));
1675                                         errno = EPERM;  /* FIXME, is this correct */
1676                                         return -1;
1677
1678                                 }
1679
1680                                 /*
1681                                  * Get a connection to IPC$ on the server if we do not already have one
1682                                  */
1683
1684                                 srv = smbc_server(buserver, "IPC$", workgroup, user, password);
1685
1686                                 if (!srv) {
1687
1688                                         if (smbc_file_table[slot]) {
1689                                                 SAFE_FREE(smbc_file_table[slot]->fname);
1690                                                 SAFE_FREE(smbc_file_table[slot]);
1691                                         }
1692                                         return -1;
1693
1694                                 }
1695
1696                                 smbc_file_table[slot]->srv = srv;
1697
1698                                 /* Now, list the servers ... */
1699
1700                                 if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn,
1701                                                        (void *)smbc_file_table[slot])) {
1702
1703                                         if (smbc_file_table[slot]) {
1704                                                 SAFE_FREE(smbc_file_table[slot]->fname);
1705                                                 SAFE_FREE(smbc_file_table[slot]);
1706                                         }
1707                                         errno = cli_errno(&srv->cli);
1708                                         return -1;
1709
1710                                 }
1711
1712                         }
1713                         else {
1714
1715                                 if (resolve_name(server, &rem_ip, 0x20)) {
1716
1717                                         /* Now, list the shares ... */
1718
1719                                         smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
1720
1721                                         srv = smbc_server(server, "IPC$", workgroup, user, password);
1722
1723                                         if (!srv) {
1724
1725                                                 if (smbc_file_table[slot]) {
1726                                                         SAFE_FREE(smbc_file_table[slot]->fname);
1727                                                         SAFE_FREE(smbc_file_table[slot]);
1728                                                 }
1729                                                 return -1;
1730
1731                                         }
1732
1733                                         smbc_file_table[slot]->srv = srv;
1734
1735                                         /* Now, list the servers ... */
1736
1737                                         if (cli_RNetShareEnum(&srv->cli, list_fn, 
1738                                                               (void *)smbc_file_table[slot]) < 0) {
1739
1740                                                 errno = cli_errno(&srv->cli);
1741                                                 if (smbc_file_table[slot]) {
1742                                                         SAFE_FREE(smbc_file_table[slot]->fname);
1743                                                         SAFE_FREE(smbc_file_table[slot]);
1744                                                 }
1745                                                 return -1;
1746
1747                                         }
1748
1749                                 }
1750                                 else {
1751
1752                                         errno = ENODEV;   /* Neither the workgroup nor server exists */
1753                                         if (smbc_file_table[slot]) {
1754                                                 SAFE_FREE(smbc_file_table[slot]->fname);
1755                                                 SAFE_FREE(smbc_file_table[slot]);
1756                                         }
1757                                         return -1;
1758
1759                                 }
1760
1761                         }
1762
1763                 }
1764                 else { /* The server and share are specified ... work from there ... */
1765
1766                         /* Well, we connect to the server and list the directory */
1767
1768                         smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
1769
1770                         srv = smbc_server(server, share, workgroup, user, password);
1771
1772                         if (!srv) {
1773
1774                                 if (smbc_file_table[slot]) {
1775                                         SAFE_FREE(smbc_file_table[slot]->fname);
1776                                         SAFE_FREE(smbc_file_table[slot]);
1777                                 }
1778                                 return -1;
1779
1780                         }
1781
1782                         smbc_file_table[slot]->srv = srv;
1783
1784                         /* Now, list the files ... */
1785
1786                         pstrcat(path, "\\*");
1787
1788                         if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn, 
1789                                      (void *)smbc_file_table[slot]) < 0) {
1790
1791                                 if (smbc_file_table[slot]) {
1792                                         SAFE_FREE(smbc_file_table[slot]->fname);
1793                                         SAFE_FREE(smbc_file_table[slot]);
1794                                 }
1795                                 errno = smbc_errno(&srv->cli);
1796                                 return -1;
1797
1798                         }
1799                 }
1800
1801         }
1802
1803         return smbc_file_table[slot]->smbc_fd;
1804
1805 }
1806
1807 /*
1808  * Routine to close a directory
1809  */
1810
1811 int smbc_closedir(int fd)
1812 {
1813         struct smbc_file *fe;
1814
1815         if (!smbc_initialized) {
1816
1817                 errno = EINVAL;
1818                 return -1;
1819
1820         }
1821
1822         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
1823
1824                 errno = EBADF;
1825                 return -1;
1826
1827         }
1828
1829         fe = smbc_file_table[fd - smbc_start_fd];
1830
1831         if (!fe) {
1832
1833                 errno = EBADF;  
1834                 return -1;
1835
1836         }
1837
1838         smbc_remove_dir(fe); /* Clean it up */
1839
1840         if (fe) {
1841
1842                 SAFE_FREE(fe->fname);
1843                 SAFE_FREE(fe);    /* Free the space too */
1844
1845         }
1846
1847         smbc_file_table[fd - smbc_start_fd] = NULL;
1848
1849         return 0;
1850
1851 }
1852
1853 /*
1854  * Routine to get a directory entry
1855  */
1856
1857 static char smbc_local_dirent[512];  /* Make big enough */
1858
1859 struct smbc_dirent *smbc_readdir(unsigned int fd)
1860 {
1861         struct smbc_file *fe;
1862         struct smbc_dirent *dirp, *dirent;
1863
1864         /* Check that all is ok first ... */
1865
1866         if (!smbc_initialized) {
1867
1868                 errno = EINVAL;
1869                 return NULL;
1870
1871         }
1872
1873         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
1874
1875                 errno = EBADF;
1876                 return NULL;
1877
1878         }
1879
1880         fe = smbc_file_table[fd - smbc_start_fd];
1881
1882         if (!fe) {
1883
1884                 errno = EBADF;
1885                 return NULL;
1886
1887         }
1888
1889         if (fe->file != False) { /* FIXME, should be dir, perhaps */
1890
1891                 errno = ENOTDIR;
1892                 return NULL;
1893
1894         }
1895
1896         if (!fe->dir_next)
1897                 return NULL;
1898         else {
1899
1900                 dirent = fe->dir_next->dirent;
1901
1902                 if (!dirent) {
1903
1904                         errno = ENOENT;
1905                         return NULL;
1906
1907                 }
1908
1909                 /* Hmmm, do I even need to copy it? */
1910
1911                 memcpy(smbc_local_dirent, dirent, dirent->dirlen); /* Copy the dirent */
1912
1913                 dirp = (struct smbc_dirent *)smbc_local_dirent;
1914
1915                 dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
1916     
1917                 fe->dir_next = fe->dir_next->next;
1918
1919                 return (struct smbc_dirent *)smbc_local_dirent;
1920         }
1921
1922 }
1923
1924 /*
1925  * Routine to get directory entries
1926  */
1927
1928 int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count)
1929 {
1930         struct smbc_file *fe;
1931         struct smbc_dir_list *dir;
1932         int rem = count, reqd;
1933         char *ndir = (char *)dirp;
1934
1935         /* Check that all is ok first ... */
1936
1937         if (!smbc_initialized) {
1938
1939                 errno = EINVAL;
1940                 return -1;
1941
1942         }
1943
1944         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
1945
1946                 errno = EBADF;
1947                 return -1;
1948
1949         }
1950
1951         fe = smbc_file_table[fd - smbc_start_fd];
1952
1953         if (!fe) {
1954
1955                 errno = EBADF;
1956                 return -1;
1957
1958         }
1959
1960         if (fe->file != False) { /* FIXME, should be dir, perhaps */
1961
1962                 errno = ENOTDIR;
1963                 return -1;
1964
1965         }
1966
1967         /* 
1968          * Now, retrieve the number of entries that will fit in what was passed
1969          * We have to figure out if the info is in the list, or we need to 
1970          * send a request to the server to get the info.
1971          */
1972
1973         while ((dir = fe->dir_next)) {
1974                 struct smbc_dirent *dirent;
1975
1976                 if (!dir->dirent) {
1977
1978                         errno = ENOENT;  /* Bad error */
1979                         return -1;
1980
1981                 }
1982
1983                 if (rem < (reqd = (sizeof(struct smbc_dirent) + dir->dirent->namelen + 
1984                                    dir->dirent->commentlen + 1))) {
1985
1986                         if (rem < count) { /* We managed to copy something */
1987
1988                                 errno = 0;
1989                                 return count - rem;
1990
1991                         }
1992                         else { /* Nothing copied ... */
1993
1994                                 errno = EINVAL;  /* Not enough space ... */
1995                                 return -1;
1996
1997                         }
1998
1999                 }
2000
2001                 dirent = dir->dirent;
2002
2003                 memcpy(ndir, dirent, reqd); /* Copy the data in ... */
2004     
2005                 ((struct smbc_dirent *)ndir)->comment = 
2006                         (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1);
2007
2008                 ndir += reqd;
2009
2010                 rem -= reqd;
2011
2012                 fe->dir_next = dir = dir -> next;
2013         }
2014
2015         if (rem == count)
2016                 return 0;
2017         else 
2018                 return count - rem;
2019
2020 }
2021
2022 /*
2023  * Routine to create a directory ...
2024  */
2025
2026 int smbc_mkdir(const char *fname, mode_t mode)
2027 {
2028         struct smbc_server *srv;
2029         fstring server, share, user, password, workgroup;
2030         pstring path;
2031
2032         if (!smbc_initialized) {
2033
2034                 errno = EINVAL;
2035                 return -1;
2036
2037         }
2038
2039         if (!fname) {
2040
2041                 errno = EINVAL;
2042                 return -1;
2043
2044         }
2045   
2046         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
2047
2048         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
2049
2050         if (user[0] == (char)0) pstrcpy(user, smbc_user);
2051
2052         pstrcpy(workgroup, lp_workgroup());
2053
2054         srv = smbc_server(server, share, workgroup, user, password);
2055
2056         if (!srv) {
2057
2058                 return -1;  /* errno set by smbc_server */
2059
2060         }
2061
2062         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
2063
2064            mode = aDIR | aRONLY;
2065
2066            }
2067            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
2068
2069            if (strcmp(path, "\\") == 0) {
2070
2071            mode = aDIR | aRONLY;
2072
2073            }
2074            else {
2075
2076            mode = aRONLY;
2077            smbc_stat_printjob(srv, path, &size, &m_time);
2078            c_time = a_time = m_time;
2079
2080            }
2081            else { */
2082
2083         if (!cli_mkdir(&srv->cli, path)) {
2084
2085                 errno = smbc_errno(&srv->cli);
2086                 return -1;
2087
2088         } 
2089
2090         return 0;
2091
2092 }
2093
2094 /*
2095  * Our list function simply checks to see if a directory is not empty
2096  */
2097
2098 static int smbc_rmdir_dirempty = True;
2099
2100 static void rmdir_list_fn(file_info *finfo, const char *mask, void *state)
2101 {
2102
2103         if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0)
2104                 smbc_rmdir_dirempty = False;
2105
2106 }
2107
2108 /*
2109  * Routine to remove a directory
2110  */
2111
2112 int smbc_rmdir(const char *fname)
2113 {
2114         struct smbc_server *srv;
2115         fstring server, share, user, password, workgroup;
2116         pstring path;
2117
2118         if (!smbc_initialized) {
2119
2120                 errno = EINVAL;
2121                 return -1;
2122
2123         }
2124
2125         if (!fname) {
2126
2127                 errno = EINVAL;
2128                 return -1;
2129
2130         }
2131   
2132         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
2133
2134         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
2135
2136         if (user[0] == (char)0) pstrcpy(user, smbc_user);
2137
2138         pstrcpy(workgroup, lp_workgroup());
2139
2140         srv = smbc_server(server, share, workgroup, user, password);
2141
2142         if (!srv) {
2143
2144                 return -1;  /* errno set by smbc_server */
2145
2146         }
2147
2148         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
2149
2150            mode = aDIR | aRONLY;
2151
2152            }
2153            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
2154
2155            if (strcmp(path, "\\") == 0) {
2156
2157            mode = aDIR | aRONLY;
2158
2159            }
2160            else {
2161
2162            mode = aRONLY;
2163            smbc_stat_printjob(srv, path, &size, &m_time);
2164            c_time = a_time = m_time;
2165
2166            }
2167            else { */
2168
2169         if (!cli_rmdir(&srv->cli, path)) {
2170
2171                 errno = smbc_errno(&srv->cli);
2172
2173                 if (errno == EACCES) {  /* Check if the dir empty or not */
2174
2175                         pstring lpath; /* Local storage to avoid buffer overflows */
2176
2177                         smbc_rmdir_dirempty = True;  /* Make this so ... */
2178
2179                         pstrcpy(lpath, path);
2180                         pstrcat(lpath, "\\*");
2181
2182                         if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn,
2183                                      NULL) < 0) {
2184
2185                                 /* Fix errno to ignore latest error ... */
2186
2187                                 DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n", 
2188                                           smbc_errno(&srv->cli)));
2189                                 errno = EACCES;
2190
2191                         }
2192
2193                         if (smbc_rmdir_dirempty)
2194                                 errno = EACCES;
2195                         else
2196                                 errno = ENOTEMPTY;
2197
2198                 }
2199
2200                 return -1;
2201
2202         } 
2203
2204         return 0;
2205
2206 }
2207
2208 /*
2209  * Routine to return the current directory position
2210  */
2211
2212 off_t smbc_telldir(int fd)
2213 {
2214         struct smbc_file *fe;
2215
2216         if (!smbc_initialized) {
2217
2218                 errno = EINVAL;
2219                 return -1;
2220
2221         }
2222
2223         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
2224
2225                 errno = EBADF;
2226                 return -1;
2227
2228         }
2229
2230         fe = smbc_file_table[fd - smbc_start_fd];
2231
2232         if (!fe) {
2233
2234                 errno = EBADF;
2235                 return -1;
2236
2237         }
2238
2239         if (fe->file != False) { /* FIXME, should be dir, perhaps */
2240
2241                 errno = ENOTDIR;
2242                 return -1;
2243
2244         }
2245
2246         return (off_t) fe->dir_next;
2247
2248 }
2249
2250 /*
2251  * A routine to run down the list and see if the entry is OK
2252  */
2253
2254 struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 
2255                                          struct smbc_dirent *dirent)
2256 {
2257
2258         /* Run down the list looking for what we want */
2259
2260         if (dirent) {
2261
2262                 struct smbc_dir_list *tmp = list;
2263
2264                 while (tmp) {
2265
2266                         if (tmp->dirent == dirent)
2267                                 return tmp;
2268
2269                         tmp = tmp->next;
2270
2271                 }
2272
2273         }
2274
2275         return NULL;  /* Not found, or an error */
2276
2277 }
2278
2279
2280 /*
2281  * Routine to seek on a directory
2282  */
2283
2284 int smbc_lseekdir(int fd, off_t offset)
2285 {
2286         struct smbc_file *fe;
2287         struct smbc_dirent *dirent = (struct smbc_dirent *)offset;
2288         struct smbc_dir_list *list_ent = NULL;
2289
2290         if (!smbc_initialized) {
2291
2292                 errno = EINVAL;
2293                 return -1;
2294
2295         }
2296
2297         if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
2298
2299                 errno = EBADF;
2300                 return -1;
2301
2302         }
2303
2304         fe = smbc_file_table[fd - smbc_start_fd];
2305
2306         if (!fe) {
2307
2308                 errno = EBADF;
2309                 return -1;
2310
2311         }
2312
2313         if (fe->file != False) { /* FIXME, should be dir, perhaps */
2314
2315                 errno = ENOTDIR;
2316                 return -1;
2317
2318         }
2319
2320         /* Now, check what we were passed and see if it is OK ... */
2321
2322         if (dirent == NULL) {  /* Seek to the begining of the list */
2323
2324                 fe->dir_next = fe->dir_list;
2325                 return 0;
2326
2327         }
2328
2329         /* Now, run down the list and make sure that the entry is OK       */
2330         /* This may need to be changed if we change the format of the list */
2331
2332         if ((list_ent = smbc_check_dir_ent(fe->dir_list, dirent)) == NULL) {
2333
2334                 errno = EINVAL;   /* Bad entry */
2335                 return -1;
2336
2337         }
2338
2339         fe->dir_next = list_ent;
2340
2341         return 0; 
2342
2343 }
2344
2345 /*
2346  * Routine to fstat a dir
2347  */
2348
2349 int smbc_fstatdir(int fd, struct stat *st)
2350 {
2351
2352         if (!smbc_initialized) {
2353
2354                 errno = EINVAL;
2355                 return -1;
2356
2357         }
2358
2359         /* No code yet ... */
2360
2361         return 0;
2362
2363 }
2364
2365 /*
2366  * Routine to print a file on a remote server ...
2367  *
2368  * We open the file, which we assume to be on a remote server, and then
2369  * copy it to a print file on the share specified by printq.
2370  */
2371
2372 int smbc_print_file(const char *fname, const char *printq)
2373 {
2374         int fid1, fid2, bytes, saverr, tot_bytes = 0;
2375         char buf[4096];
2376
2377         if (!smbc_initialized) {
2378
2379                 errno = EINVAL;
2380                 return -1;
2381
2382         }
2383
2384         if (!fname && !printq) {
2385
2386                 errno = EINVAL;
2387                 return -1;
2388
2389         }
2390
2391         /* Try to open the file for reading ... */
2392
2393         if ((fid1 = smbc_open(fname, O_RDONLY, 0666)) < 0) {
2394
2395                 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
2396                 return -1;  /* smbc_open sets errno */
2397
2398         }
2399
2400         /* Now, try to open the printer file for writing */
2401
2402         if ((fid2 = smbc_open_print_job(printq)) < 0) {
2403
2404                 saverr = errno;  /* Save errno */
2405                 smbc_close(fid1);
2406                 errno = saverr;
2407                 return -1;
2408
2409         }
2410
2411         while ((bytes = smbc_read(fid1, buf, sizeof(buf))) > 0) {
2412
2413                 tot_bytes += bytes;
2414
2415                 if ((smbc_write(fid2, buf, bytes)) < 0) {
2416
2417                         saverr = errno;
2418                         smbc_close(fid1);
2419                         smbc_close(fid2);
2420                         errno = saverr;
2421
2422                 }
2423
2424         }
2425
2426         saverr = errno;
2427
2428         smbc_close(fid1);  /* We have to close these anyway */
2429         smbc_close(fid2);
2430
2431         if (bytes < 0) {
2432
2433                 errno = saverr;
2434                 return -1;
2435
2436         }
2437
2438         return tot_bytes;
2439
2440 }
2441
2442 /*
2443  * Open a print file to be written to by other calls
2444  */
2445
2446 int smbc_open_print_job(const char *fname)
2447 {
2448         fstring server, share, user, password;
2449         pstring path;
2450
2451         if (!smbc_initialized) {
2452
2453                 errno = EINVAL;
2454                 return -1;
2455
2456         }
2457
2458         if (!fname) {
2459
2460                 errno = EINVAL;
2461                 return -1;
2462
2463         }
2464   
2465         DEBUG(4, ("smbc_open_print_job(%s)\n", fname));
2466
2467         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
2468
2469         /* What if the path is empty, or the file exists? */
2470
2471         return smbc_open(fname, O_WRONLY, 666);
2472
2473 }
2474
2475 /*
2476  * Routine to list print jobs on a printer share ...
2477  */
2478
2479 int smbc_list_print_jobs(const char *fname, void (*fn)(struct print_job_info *))
2480 {
2481         struct smbc_server *srv;
2482         fstring server, share, user, password, workgroup;
2483         pstring path;
2484
2485         if (!smbc_initialized) {
2486
2487                 errno = EINVAL;
2488                 return -1;
2489
2490         }
2491
2492         if (!fname) {
2493
2494                 errno = EINVAL;
2495                 return -1;
2496
2497         }
2498   
2499         DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
2500
2501         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
2502
2503         if (user[0] == (char)0) pstrcpy(user, smbc_user);
2504
2505         pstrcpy(workgroup, lp_workgroup());
2506
2507         srv = smbc_server(server, share, workgroup, user, password);
2508
2509         if (!srv) {
2510
2511                 return -1;  /* errno set by smbc_server */
2512
2513         }
2514
2515         if (cli_print_queue(&srv->cli, fn) < 0) {
2516
2517                 errno = smbc_errno(&srv->cli);
2518                 return -1;
2519
2520         }
2521
2522         return 0;
2523
2524 }
2525
2526 /*
2527  * Delete a print job from a remote printer share
2528  */
2529
2530 int smbc_unlink_print_job(const char *fname, int id)
2531 {
2532         struct smbc_server *srv;
2533         fstring server, share, user, password, workgroup;
2534         pstring path;
2535         int err;
2536
2537         if (!smbc_initialized) {
2538
2539                 errno = EINVAL;
2540                 return -1;
2541
2542         }
2543
2544         if (!fname) {
2545
2546                 errno = EINVAL;
2547                 return -1;
2548
2549         }
2550   
2551         DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
2552
2553         smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
2554
2555         if (user[0] == (char)0) pstrcpy(user, smbc_user);
2556
2557         pstrcpy(workgroup, lp_workgroup());
2558
2559         srv = smbc_server(server, share, workgroup, user, password);
2560
2561         if (!srv) {
2562
2563                 return -1;  /* errno set by smbc_server */
2564
2565         }
2566
2567         if ((err = cli_printjob_del(&srv->cli, id)) != 0) {
2568
2569                 if (err < 0)
2570                         errno = smbc_errno(&srv->cli);
2571                 else if (err == ERRnosuchprintjob)
2572                         errno = EINVAL;
2573                 return -1;
2574
2575
2576         }
2577
2578         return 0;
2579
2580 }
2581