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