Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / network / smbfs / source_code / smb_abstraction.c
blobfbfec861a39b299d2c4a412f5f66a171314d699d
1 /*
2 * $Id$
4 * :ts=4
6 * Name: smb_abstraction.c
7 * Description: Smb abstraction layer.
8 * Author: Christian Starkjohann <cs -at- hal -dot- kph -dot- tuwien -dot- ac -dot- at>
9 * Date: 1996-12-31
10 * Copyright: GNU-GPL
12 * Modified for use with AmigaOS by Olaf Barthel <obarthel -at- gmx -dot- net>
15 #include "smbfs.h"
17 /*****************************************************************************/
19 #include <smb/smb_fs.h>
20 #include <smb/smb.h>
21 #include <smb/smbno.h>
23 #ifndef MAXHOSTNAMELEN
24 #define MAXHOSTNAMELEN 256
25 #endif
27 /*****************************************************************************/
29 #define ATTR_CACHE_TIME 5 /* cache attributes for this time */
30 #define DIR_CACHE_TIME 5 /* cache directories for this time */
31 #define DIRCACHE_SIZE 170
32 #define DOS_PATHSEP '\\'
34 /*****************************************************************************/
36 typedef struct dircache
38 int base;
39 int len;
40 int eof; /* cache end is eof */
41 long created_at; /* for invalidation */
42 struct smba_file *cache_for; /* owner of this cache */
43 int cache_size;
44 struct smb_dirent cache[1];
45 } dircache_t;
47 /* opaque structures for server and files: */
48 struct smba_server
50 struct smb_server server;
51 struct MinList open_files;
52 dircache_t * dircache;
53 unsigned supports_E:1;
54 unsigned supports_E_known:1;
57 struct smba_file
59 struct MinNode node;
60 struct smba_server *server;
61 struct smb_dirent dirent;
62 long attr_time; /* time when dirent was read */
63 dircache_t *dircache; /* content cache for directories */
64 unsigned attr_dirty:1; /* attribute cache is dirty */
65 unsigned is_valid:1; /* server was down, entry removed, ... */
68 /*****************************************************************************/
70 #include "smb_abstraction.h"
72 /*****************************************************************************/
74 static int smba_connect(smba_connect_parameters_t *p, unsigned int ip_addr, int use_E, char *workgroup_name,
75 int cache_size, int max_transmit, int opt_raw_smb, smba_server_t **result);
76 static INLINE int make_open(smba_file_t *f, int need_fid);
77 static int write_attr(smba_file_t *f);
78 static void invalidate_dircache(struct smba_server *server, char *path);
79 static void close_path(smba_server_t *s, char *path);
80 static void smba_cleanup_dircache(struct smba_server *server);
81 static int smba_setup_dircache(struct smba_server *server, int cache_size);
82 static int extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size);
84 /*****************************************************************************/
86 static int
87 smba_connect (smba_connect_parameters_t * p, unsigned int ip_addr, int use_E, char * workgroup_name,
88 int cache_size, int max_transmit, int opt_raw_smb, smba_server_t ** result)
90 smba_server_t *res;
91 struct smb_mount_data data;
92 int errnum;
93 char hostname[MAXHOSTNAMELEN], *s;
94 struct servent * servent;
96 (*result) = NULL;
98 res = malloc (sizeof(*res));
99 if(res == NULL)
101 ReportError("Not enough memory.");
102 errnum = -ENOMEM;
103 goto error_occured;
106 memset (res, 0, sizeof(*res));
107 memset (&data, 0, sizeof (data));
108 memset (hostname, 0, sizeof (hostname));
110 /* Olaf (2012-12-10): force raw SMB over TCP rather than NetBIOS. */
111 if(opt_raw_smb)
112 res->server.raw_smb = 1;
114 errnum = smba_setup_dircache (res,cache_size);
115 if(errnum < 0)
117 ReportError("Directory cache initialization failed (%ld, %s).",-errnum,amitcp_strerror(-errnum));
118 goto error_occured;
121 strlcpy(data.workgroup_name,workgroup_name,sizeof(data.workgroup_name));
123 res->server.abstraction = res;
125 gethostname (hostname, MAXHOSTNAMELEN);
127 if ((s = strchr (hostname, '.')) != NULL)
128 (*s) = '\0';
130 data.addr.sin_family = AF_INET;
131 data.addr.sin_addr.s_addr = ip_addr;
133 if(res->server.raw_smb)
135 servent = getservbyname("microsoft-ds","tcp");
136 if(servent != NULL)
137 data.addr.sin_port = servent->s_port;
138 else
139 data.addr.sin_port = htons (445);
141 else
143 servent = getservbyname("netbios-ssn","tcp");
144 if(servent != NULL)
145 data.addr.sin_port = servent->s_port;
146 else
147 data.addr.sin_port = htons (139);
150 data.fd = socket (AF_INET, SOCK_STREAM, 0);
151 if (data.fd < 0)
153 errnum = (-errno);
154 ReportError("socket() call failed (%ld, %s).", errno, amitcp_strerror (errno));
155 goto error_occured;
158 strlcpy (data.service, p->service, sizeof(data.service));
159 StringToUpper (data.service);
160 strlcpy (data.username, p->username, sizeof(data.username));
161 strlcpy (data.password, p->password, sizeof(data.password));
163 /* Minimum receive buffer size is 8000 bytes, and the
164 * maximum transmit buffer size should be of the same
165 * order.
167 if (0 < max_transmit && max_transmit < 8000)
168 max_transmit = 8000;
170 if (0 < max_transmit && max_transmit < 65535)
171 data.given_max_xmit = max_transmit;
172 else
173 data.given_max_xmit = 65534; /* 2014/10/4 fm: use 65534 since some NASs report -1 but return max of 65534 bytes */
175 strlcpy (data.server_name, p->server_name, sizeof(data.server_name));
176 strlcpy (data.client_name, p->client_name, sizeof(data.client_name));
178 if (data.server_name[0] == '\0')
180 if (strlen (p->server_ipname) > 16)
182 errnum = -ENAMETOOLONG;
183 ReportError("Server name '%s' is too long for NetBIOS (max %ld characters).",p->server_ipname,16);
184 goto error_occured;
187 strlcpy (data.server_name, p->server_ipname, sizeof(data.server_name));
190 StringToUpper (data.server_name);
192 if (data.client_name[0] == '\0')
194 if (strlen (hostname) > 16)
196 errnum = -ENAMETOOLONG;
197 ReportError("Local host name '%s' is too long for NetBIOS (max %ld characters).", hostname, 16);
198 goto error_occured;
201 strlcpy (data.client_name, hostname, sizeof(data.client_name));
202 StringToUpper (data.client_name);
205 res->server.mount_data = data;
207 NewList((struct List *)&res->open_files);
209 if ((errnum = smb_proc_connect (&res->server)) < 0)
211 ReportError("Cannot connect to server (%ld, %s).", -errnum,amitcp_strerror(-errnum));
212 goto error_occured;
215 if (!use_E)
216 res->supports_E_known = 1;
218 (*result) = res;
219 res = NULL;
221 errnum = 0;
223 error_occured:
225 if(res != NULL)
227 smba_cleanup_dircache (res);
228 free (res);
231 return errnum;
234 /*****************************************************************************/
236 void
237 smba_disconnect (smba_server_t * server)
239 CloseSocket (server->server.mount_data.fd);
241 smba_cleanup_dircache(server);
243 free (server);
246 /*****************************************************************************/
248 static INLINE int
249 make_open (smba_file_t * f, int need_fid)
251 smba_server_t *s;
252 int errnum;
254 if (!f->is_valid || (need_fid && !f->dirent.opened))
256 s = f->server;
258 if (!f->is_valid || f->attr_time == -1 || GetCurrentTime() - f->attr_time > ATTR_CACHE_TIME)
260 errnum = smb_proc_getattr_core (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
261 if (errnum < 0)
262 goto out;
265 if ((f->dirent.attr & aDIR) == 0) /* a regular file */
267 if (need_fid || !s->supports_E_known || s->supports_E)
269 LOG (("opening file %s\n", f->dirent.complete_path));
270 errnum = smb_proc_open (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
271 if (errnum < 0)
272 goto out;
274 if (s->supports_E || !s->supports_E_known)
276 if (smb_proc_getattrE (&s->server, &f->dirent) < 0)
278 if (!s->supports_E_known)
280 s->supports_E_known = 1;
281 s->supports_E = 0;
282 } /* ignore errors here */
284 else
286 s->supports_E_known = 1;
287 s->supports_E = 1;
292 else
294 /* don't open directory, initialize directory cache */
295 if (f->dircache != NULL)
297 f->dircache->cache_for = NULL;
298 f->dircache->len = 0;
299 f->dircache = NULL;
303 f->attr_time = GetCurrentTime();
304 f->is_valid = 1;
307 errnum = 0;
309 out:
311 return errnum;
314 /*****************************************************************************/
317 smba_open (smba_server_t * s, char *name, size_t name_size, smba_file_t ** file)
319 smba_file_t *f;
320 int errnum;
322 (*file) = NULL;
324 f = malloc (sizeof(*f));
325 if(f == NULL)
327 errnum = -ENOMEM;
328 goto out;
331 memset(f,0,sizeof(*f));
333 f->dirent.complete_path = name;
334 f->dirent.complete_path_size = name_size;
335 f->dirent.len = strlen (name);
336 f->server = s;
338 errnum = make_open (f, 0);
339 if (errnum < 0)
340 goto out;
342 AddTail ((struct List *)&s->open_files, (struct Node *)f);
344 (*file) = f;
345 f = NULL;
347 errnum = 0;
349 out:
351 if (f != NULL)
352 free (f);
354 return errnum;
357 /*****************************************************************************/
359 static int
360 write_attr (smba_file_t * f)
362 int errnum;
364 LOG (("file %s\n", f->dirent.complete_path));
366 errnum = make_open (f, 0);
367 if (errnum < 0)
368 goto out;
370 if (f->dirent.opened && f->server->supports_E)
371 errnum = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent);
372 else
373 errnum = smb_proc_setattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
375 if (errnum < 0)
377 f->attr_time = -1;
378 goto out;
381 f->attr_dirty = 0;
383 errnum = 0;
385 out:
387 return errnum;
390 /*****************************************************************************/
392 void
393 smba_close (smba_file_t * f)
395 if(f != NULL)
397 if(f->node.mln_Succ != NULL || f->node.mln_Pred != NULL)
398 Remove((struct Node *)f);
400 if(f->attr_dirty)
401 write_attr(f);
403 if (f->dirent.opened)
405 LOG (("closing file %s\n", f->dirent.complete_path));
406 smb_proc_close (&f->server->server, f->dirent.fileid, f->dirent.mtime);
409 if (f->dircache != NULL)
411 f->dircache->cache_for = NULL;
412 f->dircache->len = 0;
413 f->dircache = NULL;
416 free (f);
420 /*****************************************************************************/
423 smba_read (smba_file_t * f, char *data, long len, long offset)
425 int num_bytes_read = 0;
426 int maxsize, count, result;
427 int errnum;
429 errnum = make_open (f, 1);
430 if (errnum < 0)
432 result = errnum;
433 goto out;
436 D(("read %ld bytes from offset %ld",len,offset));
438 /* SMB_COM_READ_RAW and SMB_COM_WRITE_RAW supported? */
439 if (f->server->server.capabilities & CAP_RAW_MODE)
441 SHOWVALUE(f->server->server.max_buffer_size);
443 if(len <= f->server->server.max_raw_size)
445 result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, len, data);
446 if(result > 0)
448 num_bytes_read += result;
449 offset += result;
452 LOG (("smb_proc_read_raw(%s)->%ld\n", f->dirent.complete_path, result));
454 else
456 int n;
460 n = min(len,f->server->server.max_raw_size);
462 result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, n, data);
463 if(result <= 0)
465 D(("!!! wanted to read %ld bytes, got %ld",n,result));
466 break;
469 num_bytes_read += result;
470 len -= result;
471 offset += result;
472 data += result;
474 if(result < n)
476 D(("read returned fewer characters than expected (%ld < %ld)",result,n));
477 break;
480 while(len > 0);
483 else
485 /* Nothing read so far. */
486 result = 0;
489 /* Raw read not supported and no data read yet?
490 * Fall back onto SMB_COM_READ.
492 if (result <= 0 && num_bytes_read == 0)
494 maxsize = f->server->server.max_buffer_size - SMB_HEADER_LEN - 5 * 2 - 5;
498 count = min(len,maxsize);
500 result = smb_proc_read (&f->server->server, &f->dirent, offset, count, data, 0);
501 if (result < 0)
502 goto out;
504 num_bytes_read += result;
505 len -= result;
506 offset += result;
507 data += result;
509 if(result < count)
511 D(("read returned fewer characters than expected (%ld < %ld)",result,count));
512 break;
515 while (len > 0);
518 /* Still no luck? */
519 if(result < 0)
520 goto out;
522 result = num_bytes_read;
524 out:
526 return result;
529 /*****************************************************************************/
532 smba_write (smba_file_t * f, char *data, long len, long offset)
534 int maxsize, count, result;
535 long num_bytes_written = 0;
536 int errnum;
538 errnum = make_open (f, 1);
539 if (errnum < 0)
541 result = errnum;
542 goto out;
545 /* Calculate maximum number of bytes that could be transferred with
546 a single SMBwrite packet... */
547 maxsize = f->server->server.max_buffer_size - (SMB_HEADER_LEN + 5 * sizeof (word) + 5) - 4;
549 if (len <= maxsize)
551 /* Use a single SMBwrite packet whenever possible instead of a SMBwritebraw
552 because that requires two packets to be sent. */
553 result = smb_proc_write (&f->server->server, &f->dirent, offset, len, data);
554 if(result < 0)
555 goto out;
557 num_bytes_written += result;
558 offset += result;
560 else
562 /* Nothing was written yet. */
563 result = 0;
565 if (f->server->server.capabilities & CAP_RAW_MODE)
567 long max_xmit;
568 int n;
570 /* Try to send the maximum number of bytes with the two SMBwritebraw packets. */
571 max_xmit = 2 * f->server->server.max_buffer_size - (SMB_HEADER_LEN + 12 * sizeof (word) + 4) - 8;
573 /* If the number of bytes that should be transferred exceed the number of
574 bytes that could be transferred by a single call to smb_proc_write_raw,
575 the data is transfered as before: Only by the second packet. This
576 prevents the CPU from copying the data into the transferbuffer. */
577 if (max_xmit < len)
578 max_xmit = f->server->server.max_buffer_size - 4;
582 n = min(len,max_xmit);
584 if (n <= maxsize)
586 /* Use a single SMBwrite packet whenever possible instead of a
587 * SMBwritebraw because that requires two packets to be sent.
589 result = smb_proc_write (&f->server->server, &f->dirent, offset, n, data);
591 else
593 result = smb_proc_write_raw (&f->server->server, &f->dirent, offset, n, data);
596 /* Stop if the write operation failed. We'll try again with
597 * SMB_COM_WRITE if possible.
599 if(result <= 0)
600 break;
602 data += result;
603 offset += result;
604 len -= result;
605 num_bytes_written += result;
607 /* Fewer data written than intended? Could be out of disk space. */
608 if(result < n)
609 break;
611 while(len > 0);
614 /* Raw write failed and no data has been written yet?
615 * Fall back onto SMB_COM_WRITE.
617 if (result <= 0 && num_bytes_written == 0)
621 count = min(len,maxsize);
623 result = smb_proc_write (&f->server->server, &f->dirent, offset, count, data);
624 if (result < 0)
625 goto out;
627 len -= result;
628 offset += result;
629 data += result;
630 num_bytes_written += result;
632 /* Fewer data written than intended? Could be out of disk space. */
633 if(result < count)
634 break;
636 while (len > 0);
639 /* Still no luck? */
640 if(result < 0)
641 goto out;
644 result = num_bytes_written;
646 out:
648 if (result < 0)
649 f->attr_time = -1;
650 else if (result > 0)
651 f->dirent.mtime = GetCurrentTime();
653 /* Even if one write access failed, we may have succeeded
654 * at writing some data. Hence we update the cached file
655 * size here.
657 if (offset + num_bytes_written > f->dirent.size)
658 f->dirent.size = offset + num_bytes_written;
660 return result;
663 /*****************************************************************************/
665 long
666 smba_seek (smba_file_t *f, long offset, long mode, off_t * new_position_ptr)
668 long result;
669 int errnum;
671 D(("seek %ld bytes from position %s",offset,mode > 0 ? (mode == 2 ? "SEEK_END" : "SEEK_CUR") : "SEEK_SET"));
673 errnum = make_open (f, 1);
674 if(errnum < 0)
676 result = errnum;
677 goto out;
680 errnum = smb_proc_lseek (&f->server->server, &f->dirent, offset, mode, new_position_ptr);
681 if(errnum < 0)
683 result = errnum;
684 goto out;
687 result = 0;
689 out:
691 return result;
694 /*****************************************************************************/
696 /* perform a single record-lock */
698 smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, long timeout)
700 struct smb_lkrng *rec_lock = NULL;
701 int errnum;
702 int result;
704 errnum = make_open (f, 1);
705 if(errnum < 0)
707 result = errnum;
708 goto out;
711 if (unlocked)
712 mode |= 2;
714 rec_lock = malloc (sizeof (*rec_lock));
715 if (rec_lock == NULL)
717 result = -ENOMEM;
718 goto out;
721 rec_lock->offset = offset,
722 rec_lock->len = len;
724 errnum = smb_proc_lockingX (&f->server->server, &f->dirent, rec_lock, 1, mode, timeout);
725 if(errnum < 0)
727 result = errnum;
728 goto out;
731 result = 0;
733 out:
735 if(rec_lock != NULL)
736 free (rec_lock);
738 return(result);
741 /*****************************************************************************/
744 smba_getattr (smba_file_t * f, smba_stat_t * data)
746 long now = GetCurrentTime();
747 int errnum;
748 int result;
750 errnum = make_open (f, 0);
751 if (errnum < 0)
753 result = errnum;
754 goto out;
757 if (f->attr_time == -1 || (now - f->attr_time) > ATTR_CACHE_TIME)
759 LOG (("file %s\n", f->dirent.complete_path));
761 if (f->dirent.opened && f->server->supports_E)
762 errnum = smb_proc_getattrE (&f->server->server, &f->dirent);
763 else
764 errnum = smb_proc_getattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
766 if (errnum < 0)
768 result = errnum;
769 goto out;
772 f->attr_time = now;
775 data->is_dir = (f->dirent.attr & aDIR) != 0;
776 data->is_wp = (f->dirent.attr & aRONLY) != 0;
777 data->is_hidden = (f->dirent.attr & aHIDDEN) != 0;
778 data->is_system = (f->dirent.attr & aSYSTEM) != 0;
779 data->is_archive = (f->dirent.attr & aARCH) != 0;
781 data->size = f->dirent.size;
782 data->atime = f->dirent.atime;
783 data->ctime = f->dirent.ctime;
784 data->mtime = f->dirent.mtime;
786 result = 0;
788 out:
790 return(result);
793 /*****************************************************************************/
796 smba_setattr (smba_file_t * f, smba_stat_t * data)
798 int errnum;
799 int result;
801 if (data->atime != -1)
802 f->dirent.atime = data->atime;
804 if (data->ctime != -1)
805 f->dirent.ctime = data->ctime;
807 if (data->mtime != -1)
808 f->dirent.mtime = data->mtime;
810 if (data->is_wp)
811 f->dirent.attr |= aRONLY;
812 else
813 f->dirent.attr &= ~aRONLY;
815 if (data->is_archive)
816 f->dirent.attr |= aARCH;
817 else
818 f->dirent.attr &= ~aARCH;
820 if (data->is_system)
821 f->dirent.attr |= aSYSTEM;
822 else
823 f->dirent.attr &= ~aSYSTEM;
825 f->attr_dirty = 1;
827 errnum = write_attr (f);
828 if (errnum < 0)
830 result = errnum;
831 goto out;
834 if (data->size != -1 && data->size != (int)f->dirent.size)
836 errnum = make_open (f, 1);
837 if(errnum < 0)
839 result = errnum;
840 goto out;
843 errnum = smb_proc_trunc (&f->server->server, f->dirent.fileid, data->size);
844 if(errnum < 0)
846 result = errnum;
847 goto out;
850 f->dirent.size = data->size;
853 result = 0;
855 out:
857 return(result);
860 /*****************************************************************************/
863 smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback)
865 int cache_index, o, eof, count = 0;
866 long now = GetCurrentTime();
867 int num_entries;
868 smba_stat_t data;
869 int result;
870 int errnum;
872 errnum = make_open (f, 0);
873 if (errnum < 0)
875 result = errnum;
876 goto out;
879 if (f->dircache == NULL) /* get a cache */
881 dircache_t * dircache = f->server->dircache;
883 if (dircache->cache_for != NULL)
884 dircache->cache_for->dircache = NULL; /* steal it */
886 dircache->eof = dircache->len = dircache->base = 0;
887 dircache->cache_for = f;
889 f->dircache = dircache;
891 LOG (("stealing cache\n"));
893 else
895 if ((now - f->dircache->created_at) >= DIR_CACHE_TIME)
897 f->dircache->eof = f->dircache->len = f->dircache->base = 0;
899 LOG (("cache outdated\n"));
903 for (cache_index = offs ; ; cache_index++)
905 if (cache_index < f->dircache->base /* fill cache if necessary */
906 || cache_index >= f->dircache->base + f->dircache->len)
908 if (cache_index >= f->dircache->base + f->dircache->len && f->dircache->eof)
909 break; /* nothing more to read */
911 LOG (("cachefill for %s\n", f->dirent.complete_path));
912 LOG (("\tbase was: %ld, len was: %ld, newbase=%ld\n", f->dircache->base, f->dircache->len, cache_index));
914 f->dircache->len = 0;
915 f->dircache->base = cache_index;
917 num_entries = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, f->dircache->cache);
918 if (num_entries < 0)
920 result = num_entries;
921 goto out;
924 /* Avoid some hits if restart/retry occured. Should fix the real root
925 of this problem really, but I am not bored enough atm. -Piru
926 ZZZ this needs further investigation. */
927 if (f->dircache == NULL)
929 LOG (("lost dircache due to an error, bailing out!\n"));
930 result = -ENOSPC;
931 goto out;
934 f->dircache->len = num_entries;
935 f->dircache->eof = (num_entries < f->dircache->cache_size);
936 f->dircache->created_at = now;
938 LOG (("cachefill with %ld entries\n", num_entries));
941 o = cache_index - f->dircache->base;
942 eof = (o >= (f->dircache->len - 1) && f->dircache->eof);
943 count++;
945 LOG (("delivering '%s', cache_index=%ld, eof=%ld\n", f->dircache->cache[o].complete_path, cache_index, eof));
947 data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0;
948 data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0;
949 data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0;
950 data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0;
951 data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0;
952 data.size = f->dircache->cache[o].size;
953 data.atime = f->dircache->cache[o].atime;
954 data.ctime = f->dircache->cache[o].ctime;
955 data.mtime = f->dircache->cache[o].mtime;
957 if ((*callback) (d, cache_index, cache_index + 1, f->dircache->cache[o].complete_path, eof, &data))
958 break;
961 result = count;
963 out:
965 return result;
968 /*****************************************************************************/
970 static void
971 invalidate_dircache (struct smba_server * server, char * path)
973 dircache_t * dircache = server->dircache;
974 char other_path[SMB_MAXNAMELEN + 1];
976 ENTER();
978 if(path != NULL)
980 int len,i;
982 strlcpy(other_path,path,sizeof(other_path));
984 len = strlen(other_path);
985 for(i = len-1 ; i >= 0 ; i--)
987 if(i == 0)
989 other_path[0] = DOS_PATHSEP;
990 other_path[1] = '\0';
992 else if (other_path[i] == DOS_PATHSEP)
994 other_path[i] = '\0';
995 break;
999 else
1001 other_path[0] = '\0';
1004 SHOWSTRING(other_path);
1006 if(dircache->cache_for != NULL)
1007 SHOWSTRING(dircache->cache_for->dirent.complete_path);
1008 else
1009 SHOWMSG("-- directory cache is empty --");
1011 if(path == NULL || (dircache->cache_for != NULL && CompareNames(other_path,dircache->cache_for->dirent.complete_path) == SAME))
1013 SHOWMSG("clearing directory cache");
1015 dircache->eof = dircache->len = dircache->base = 0;
1016 if(dircache->cache_for != NULL)
1018 dircache->cache_for->dircache = NULL;
1019 dircache->cache_for = NULL;
1023 LEAVE();
1026 /*****************************************************************************/
1029 smba_create (smba_file_t * dir, const char *name, smba_stat_t * attr)
1031 struct smb_dirent entry;
1032 char *path = NULL;
1033 int result;
1034 int errnum;
1036 errnum = make_open (dir, 0);
1037 if (errnum < 0)
1039 result = errnum;
1040 goto out;
1043 memset (&entry, 0, sizeof (entry));
1045 if (attr->is_wp)
1046 entry.attr |= aRONLY;
1048 if (attr->is_archive)
1049 entry.attr |= aARCH;
1051 if (attr->is_system)
1052 entry.attr |= aSYSTEM;
1054 entry.atime = entry.mtime = entry.ctime = GetCurrentTime();
1056 path = malloc (strlen (name) + dir->dirent.len + 2);
1057 if(path == NULL)
1059 result = -ENOMEM;
1060 goto out;
1063 memcpy (path, dir->dirent.complete_path, dir->dirent.len);
1064 path[dir->dirent.len] = DOS_PATHSEP;
1065 strcpy (&path[dir->dirent.len + 1], name);
1067 errnum = smb_proc_create (&dir->server->server, path, strlen (path), &entry);
1068 if(errnum < 0)
1070 result = errnum;
1071 goto out;
1074 invalidate_dircache (dir->server, path);
1076 result = 0;
1078 out:
1080 if(path != NULL)
1081 free (path);
1083 return(result);
1086 /*****************************************************************************/
1089 smba_mkdir (smba_file_t * dir, const char *name)
1091 char *path = NULL;
1092 int errnum;
1093 int result;
1095 errnum = make_open (dir, 0);
1096 if (errnum < 0)
1098 result = errnum;
1099 goto out;
1102 path = malloc (strlen (name) + dir->dirent.len + 2);
1103 if(path == NULL)
1105 result = -ENOMEM;
1106 goto out;
1109 memcpy (path, dir->dirent.complete_path, dir->dirent.len);
1110 path[dir->dirent.len] = DOS_PATHSEP;
1111 strcpy (&path[dir->dirent.len + 1], name);
1113 errnum = smb_proc_mkdir (&dir->server->server, path, strlen (path));
1114 if(errnum < 0)
1116 result = errnum;
1117 goto out;
1120 invalidate_dircache (dir->server, path);
1122 result = 0;
1124 out:
1126 if(path != NULL)
1127 free (path);
1129 return(result);
1132 /*****************************************************************************/
1134 static void
1135 close_path (smba_server_t * s, char *path)
1137 smba_file_t *p;
1139 for (p = (smba_file_t *)s->open_files.mlh_Head;
1140 p->node.mln_Succ != NULL;
1141 p = (smba_file_t *)p->node.mln_Succ)
1143 if (p->is_valid && CompareNames(p->dirent.complete_path, path) == SAME)
1145 if (p->dirent.opened)
1146 smb_proc_close (&s->server, p->dirent.fileid, p->dirent.mtime);
1148 p->dirent.opened = 0;
1149 p->is_valid = 0;
1154 /*****************************************************************************/
1157 smba_remove (smba_server_t * s, char *path)
1159 int errnum;
1160 int result;
1162 close_path (s, path);
1164 errnum = smb_proc_unlink (&s->server, path, strlen (path));
1165 if(errnum < 0)
1167 result = errnum;
1168 goto out;
1171 invalidate_dircache (s, path);
1173 result = 0;
1175 out:
1177 return result;
1180 /*****************************************************************************/
1183 smba_rmdir (smba_server_t * s, char *path)
1185 int result;
1186 int errnum;
1188 close_path (s, path);
1190 errnum = smb_proc_rmdir (&s->server, path, strlen (path));
1191 if(errnum < 0)
1193 result = errnum;
1194 goto out;
1197 invalidate_dircache (s, path);
1199 result = 0;
1201 out:
1203 return result;
1206 /*****************************************************************************/
1209 smba_rename (smba_server_t * s, char *from, char *to)
1211 int result;
1212 int errnum;
1214 close_path (s, from);
1216 errnum = smb_proc_mv (&s->server, from, strlen (from), to, strlen (to));
1217 if(errnum < 0)
1219 result = errnum;
1220 goto out;
1223 invalidate_dircache (s, from);
1225 result = 0;
1227 out:
1229 return(result);
1232 /*****************************************************************************/
1235 smba_statfs (smba_server_t * s, long *bsize, long *blocks, long *bfree)
1237 struct smb_dskattr dskattr;
1238 int errnum;
1239 int result;
1241 errnum = smb_proc_dskattr (&s->server, &dskattr);
1242 if (errnum < 0)
1244 result = errnum;
1245 goto out;
1248 (*bsize) = dskattr.blocksize * dskattr.allocblocks;
1249 (*blocks) = dskattr.total;
1250 (*bfree) = dskattr.free;
1252 result = 0;
1254 out:
1256 return(result);
1259 /*****************************************************************************/
1261 void
1262 smb_invalidate_all_inodes (struct smb_server *server)
1264 smba_file_t *f;
1266 invalidate_dircache (server->abstraction, NULL);
1268 for (f = (smba_file_t *)server->abstraction->open_files.mlh_Head;
1269 f->node.mln_Succ != NULL;
1270 f = (smba_file_t *)f->node.mln_Succ)
1272 f->dirent.opened = 0;
1273 f->is_valid = 0;
1277 /*****************************************************************************/
1279 static void
1280 free_dircache(dircache_t * the_dircache)
1282 int i;
1284 for (i = 0; i < the_dircache->cache_size; i++)
1286 if(the_dircache->cache[i].complete_path != NULL)
1287 free(the_dircache->cache[i].complete_path);
1290 free(the_dircache);
1293 static void
1294 smba_cleanup_dircache(struct smba_server * server)
1296 dircache_t * the_dircache;
1298 the_dircache = server->dircache;
1299 if(the_dircache != NULL)
1301 free_dircache(the_dircache);
1302 server->dircache = NULL;
1306 static int
1307 smba_setup_dircache (struct smba_server * server,int cache_size)
1309 dircache_t * the_dircache;
1310 int error = -ENOMEM;
1311 int i;
1313 the_dircache = malloc(sizeof(*the_dircache) + (cache_size-1) * sizeof(the_dircache->cache));
1314 if(the_dircache == NULL)
1315 goto out;
1317 memset(the_dircache,0,sizeof(*the_dircache));
1318 the_dircache->cache_size = cache_size;
1320 for (i = 0; i < the_dircache->cache_size; i++)
1322 the_dircache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
1323 if(the_dircache->cache[i].complete_path == NULL)
1324 goto out;
1326 the_dircache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
1329 server->dircache = the_dircache;
1330 the_dircache = NULL;
1332 error = 0;
1334 out:
1336 if(the_dircache != NULL)
1337 free_dircache(the_dircache);
1339 return(error);
1342 /*****************************************************************************/
1344 static int
1345 extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size)
1347 char * share_start;
1348 char * root_start;
1349 char * complete_service;
1350 char * service_copy;
1351 int result = 0;
1353 service_copy = malloc(strlen(service)+1);
1354 if(service_copy == NULL)
1356 result = -ENOMEM;
1357 ReportError("Not enough memory.");
1358 goto out;
1361 strcpy (service_copy, service);
1362 complete_service = service_copy;
1364 if (strlen (complete_service) < 4 || complete_service[0] != '/')
1366 result = -EINVAL;
1367 ReportError("Invalid service name '%s'.",complete_service);
1368 goto out;
1371 while (complete_service[0] == '/')
1372 complete_service += 1;
1374 share_start = strchr (complete_service, '/');
1375 if (share_start == NULL)
1377 result = -EINVAL;
1378 ReportError("Invalid share name '%s'.",complete_service);
1379 goto out;
1382 (*share_start++) = '\0';
1383 root_start = strchr (share_start, '/');
1385 if (root_start != NULL)
1386 (*root_start) = '\0';
1388 if ((strlen (complete_service) > 63) || (strlen (share_start) > 63))
1390 result = -ENAMETOOLONG;
1391 ReportError("Server or share name is too long in '%s' (max %ld characters).",service,63);
1392 goto out;
1395 strlcpy (server, complete_service, server_size);
1396 strlcpy (share, share_start, share_size);
1398 out:
1400 if(service_copy != NULL)
1401 free(service_copy);
1403 return(result);
1407 smba_start(char * service,char *opt_workgroup,char *opt_username,char *opt_password,char *opt_clientname,
1408 char *opt_servername,int opt_cachesize,int opt_max_transmit,int opt_raw_smb,smba_server_t ** result)
1410 smba_connect_parameters_t par;
1411 smba_server_t *the_server = NULL;
1412 int i;
1413 struct hostent *h;
1414 int use_extended = 0;
1415 char server_name[17], client_name[17];
1416 char username[64], password[64];
1417 char workgroup[20];
1418 char server[64], share[64];
1419 unsigned int ipAddr;
1420 int error;
1422 (*result) = NULL;
1423 (*username) = (*password) = (*server_name) = (*client_name) = '\0';
1425 error = extract_service (service, server, sizeof(server), share, sizeof(share));
1426 if(error < 0)
1427 goto out;
1429 ipAddr = inet_addr (server);
1430 if (ipAddr == INADDR_NONE) /* name was given, not numeric */
1432 int lookup_error;
1434 h = gethostbyname (server);
1435 lookup_error = h_errno;
1437 if (h != NULL)
1439 ipAddr = ((struct in_addr *)(h->h_addr))->s_addr;
1441 else if (BroadcastNameQuery(server,"",(UBYTE *)&ipAddr) != 0)
1443 ReportError("Unknown host '%s' (%ld, %s).",server,lookup_error,host_strerror(lookup_error));
1444 error = (-ENOENT);
1445 goto out;
1448 else
1450 char hostName[MAXHOSTNAMELEN+1];
1452 h = gethostbyaddr ((char *) &ipAddr, sizeof (ipAddr), AF_INET);
1453 if (h == NULL)
1455 ReportError("Unknown host '%s' (%ld, %s).",server,h_errno,host_strerror(errno));
1456 error = (-ENOENT);
1457 goto out;
1460 /* Brian Willette: Now we will set the server name to the DNS
1461 hostname, hopefully this will be the same as the NetBIOS name for
1462 the server.
1463 We do this because the user supplied no hostname, and we
1464 need one for NetBIOS, this is the best guess choice we have
1465 NOTE: If the names are different between DNS and NetBIOS on
1466 the windows side, the user MUST use the -s option. */
1467 for (i = 0; h->h_name[i] != '.' && h->h_name[i] != '\0' && i < 255; i++)
1468 hostName[i] = h->h_name[i];
1470 hostName[i] = '\0';
1472 /* Make sure the hostname is 16 characters or less (for Netbios) */
1473 if (strlen (hostName) > 16)
1475 ReportError("Server host name '%s' is too long (max %ld characters).", hostName, 16);
1476 error = (-ENAMETOOLONG);
1477 goto out;
1480 strlcpy (server_name, hostName, sizeof(server_name));
1483 if(opt_password != NULL)
1485 if(strlen(opt_password) >= sizeof(password))
1487 ReportError("Password is too long (max %ld characters).", sizeof(password)-1);
1488 error = (-ENAMETOOLONG);
1489 goto out;
1492 strlcpy(password,opt_password,sizeof(password));
1495 if(strlen(opt_username) >= sizeof(username))
1497 ReportError("User name '%s' is too long (max %ld characters).", username,sizeof(username)-1);
1498 error = (-ENAMETOOLONG);
1499 goto out;
1502 strlcpy(username,opt_username,sizeof(username));
1503 StringToUpper(username);
1505 if (strlen(opt_workgroup) > 15)
1507 ReportError("Workgroup/domain name '%s' is too long (max %ld characters).", opt_workgroup,15);
1508 error = (-ENAMETOOLONG);
1509 goto out;
1512 strlcpy (workgroup, opt_workgroup, sizeof(workgroup));
1513 StringToUpper (workgroup);
1515 if(opt_servername != NULL)
1517 if (strlen (opt_servername) > 16)
1519 ReportError("Server name '%s' is too long (max %ld characters).", opt_servername,16);
1520 error = (-ENAMETOOLONG);
1521 goto out;
1524 strlcpy (server_name, opt_servername, sizeof(server_name));
1527 if(opt_clientname != NULL)
1529 if (strlen (opt_clientname) > 16)
1531 ReportError("Client name '%s' is too long (max %ld characters).", opt_clientname,16);
1532 error = (-ENAMETOOLONG);
1533 goto out;
1536 strlcpy (client_name, opt_clientname, sizeof(client_name));
1539 if(opt_cachesize < 1)
1540 opt_cachesize = DIRCACHE_SIZE;
1541 else if (opt_cachesize < 10)
1542 opt_cachesize = 10;
1544 strlcpy(par.server_ipname,server,sizeof(par.server_ipname));
1545 par.server_name = server_name;
1546 par.client_name = client_name;
1548 strlcpy(par.service,share,sizeof(par.service));
1549 par.username = username;
1550 par.password = password;
1552 error = smba_connect (&par, ipAddr, use_extended, workgroup, opt_cachesize, opt_max_transmit, opt_raw_smb, &the_server);
1553 if(error < 0)
1555 ReportError("Could not connect to server (%ld, %s).",-error,amitcp_strerror(-error));
1556 goto out;
1559 (*result) = the_server;
1561 error = 0;
1563 out:
1565 return(error);
1568 /*****************************************************************************/
1571 smba_get_dircache_size(struct smba_server * server)
1573 int result;
1575 result = server->dircache->cache_size;
1577 return(result);
1580 /*****************************************************************************/
1583 smba_change_dircache_size(struct smba_server * server,int cache_size)
1585 dircache_t * new_cache;
1586 dircache_t * old_dircache = server->dircache;
1587 int result;
1588 int i;
1590 result = old_dircache->cache_size;
1592 /* We have to have a minimum cache size. */
1593 if(cache_size < 10)
1594 cache_size = 10;
1596 /* Don't do anything if the cache size has not changed. */
1597 if(cache_size == old_dircache->cache_size)
1598 goto out;
1600 /* Allocate a new cache and set it up with defaults. Note that
1601 * the file name pointers in the cache are still not initialized.
1603 new_cache = malloc(sizeof(*new_cache) + (cache_size-1) * sizeof(new_cache->cache));
1604 if(new_cache == NULL)
1605 goto out;
1607 memset(new_cache,0,sizeof(*new_cache));
1608 new_cache->cache_size = cache_size;
1610 /* If the new cache is to be larger than the old one, allocate additional file name slots. */
1611 if(cache_size > old_dircache->cache_size)
1613 /* Initialize the file name pointers so that free_dircache()
1614 * can be called safely, if necessary.
1616 for(i = 0 ; i < cache_size ; i++)
1617 new_cache->cache[i].complete_path = NULL;
1619 /* Allocate memory for the file names. */
1620 for(i = old_dircache->cache_size ; i < cache_size ; i++)
1622 new_cache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
1623 if(new_cache->cache[i].complete_path == NULL)
1625 free_dircache(new_cache);
1626 goto out;
1629 new_cache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
1632 /* Reuse the file name buffers allocated for the old cache. */
1633 for(i = 0 ; i < old_dircache->cache_size ; i++)
1635 new_cache->cache[i].complete_path = old_dircache->cache[i].complete_path;
1636 new_cache->cache[i].complete_path_size = old_dircache->cache[i].complete_path_size;
1638 old_dircache->cache[i].complete_path = NULL;
1641 else
1643 /* Reuse the file name buffers allocated for the old cache. */
1644 for(i = 0 ; i < cache_size ; i++)
1646 new_cache->cache[i].complete_path = old_dircache->cache[i].complete_path;
1647 new_cache->cache[i].complete_path_size = old_dircache->cache[i].complete_path_size;
1649 old_dircache->cache[i].complete_path = NULL;
1653 invalidate_dircache(server, NULL);
1655 free_dircache(old_dircache);
1657 server->dircache = new_cache;
1658 result = cache_size;
1660 out:
1662 return(result);