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