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