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