alsa.audio: build the bridge link lib only for linux architecture
[AROS.git] / workbench / network / smbfs / source_code / smb_abstraction.c
blobf48a6bf354a2b7385824b414af5eab51c87d552a
1 /*
2 * $Id$
4 * :ts=8
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 #define MAXHOSTNAMELEN 256
25 /*****************************************************************************/
27 #define ATTR_CACHE_TIME 5 /* cache attributes for this time */
28 #define DIR_CACHE_TIME 5 /* cache directories for this time */
29 #define DIRCACHE_SIZE 170
30 #define DOS_PATHSEP '\\'
32 /*****************************************************************************/
34 typedef struct dircache
36 int base;
37 int len;
38 int eof; /* cache end is eof */
39 long created_at; /* for invalidation */
40 struct smba_file *cache_for; /* owner of this cache */
41 int cache_size;
42 struct smb_dirent cache[1];
43 } dircache_t;
45 /* opaque structures for server and files: */
46 struct smba_server
48 struct smb_server server;
49 struct MinList open_files;
50 dircache_t * dircache;
51 unsigned supports_E:1;
52 unsigned supports_E_known:1;
55 struct smba_file
57 struct MinNode node;
58 struct smba_server *server;
59 struct smb_dirent dirent;
60 long attr_time; /* time when dirent was read */
61 dircache_t *dircache; /* content cache for directories */
62 unsigned attr_dirty:1; /* attribute cache is dirty */
63 unsigned is_valid:1; /* server was down, entry removed, ... */
66 /*****************************************************************************/
68 #include "smb_abstraction.h"
70 /*****************************************************************************/
72 static int smba_connect(smba_connect_parameters_t *p, unsigned int ip_addr, int use_E, char *workgroup_name, int cache_size, smba_server_t **result);
73 static INLINE int make_open(smba_file_t *f, int need_fid);
74 static int write_attr(smba_file_t *f);
75 static void invalidate_dircache(struct smba_server *server, char *path);
76 static void close_path(smba_server_t *s, char *path);
77 static void smba_cleanup_dircache(struct smba_server *server);
78 static int smba_setup_dircache(struct smba_server *server, int cache_size);
79 static int extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size);
81 /*****************************************************************************/
83 static int
84 smba_connect (smba_connect_parameters_t * p, unsigned int ip_addr, int use_E, char * workgroup_name, int cache_size, smba_server_t ** result)
86 smba_server_t *res;
87 struct smb_mount_data data;
88 int errnum;
89 char hostname[MAXHOSTNAMELEN], *s;
90 struct servent * servent;
92 (*result) = NULL;
94 res = malloc (sizeof(*res));
95 if(res == NULL)
97 ReportError("Not enough memory.");
98 errnum = -ENOMEM;
99 goto error_occured;
102 memset (res, 0, sizeof(*res));
103 memset (&data, 0, sizeof (data));
104 memset (hostname, 0, sizeof (hostname));
106 errnum = smba_setup_dircache (res,cache_size);
107 if(errnum < 0)
109 ReportError("Directory cache initialization failed (%ld, %s).",-errnum,amitcp_strerror(-errnum));
110 goto error_occured;
113 strlcpy(data.workgroup_name,workgroup_name,sizeof(data.workgroup_name));
115 res->server.abstraction = res;
117 gethostname (hostname, MAXHOSTNAMELEN);
119 if ((s = strchr (hostname, '.')) != NULL)
120 (*s) = '\0';
122 data.addr.sin_family = AF_INET;
123 data.addr.sin_addr.s_addr = ip_addr;
125 servent = getservbyname("netbios-ssn","tcp");
126 if(servent != NULL)
127 data.addr.sin_port = htons (servent->s_port);
128 else
129 data.addr.sin_port = htons (SMB_PORT);
131 data.fd = socket (AF_INET, SOCK_STREAM, 0);
132 if (data.fd < 0)
134 errnum = (-errno);
135 ReportError("socket() call failed (%ld, %s).", errno, amitcp_strerror (errno));
136 goto error_occured;
139 strlcpy (data.service, p->service, sizeof(data.service));
140 StringToUpper (data.service);
141 strlcpy (data.username, p->username, sizeof(data.username));
142 strlcpy (data.password, p->password, sizeof(data.password));
144 if (p->max_xmit > 0)
145 data.max_xmit = p->max_xmit;
146 else
147 data.max_xmit = 65530 /*8300*/;
149 strlcpy (data.server_name, p->server_name, sizeof(data.server_name));
150 strlcpy (data.client_name, p->client_name, sizeof(data.client_name));
152 if (data.server_name[0] == '\0')
154 if (strlen (p->server_ipname) > 16)
156 errnum = -ENAMETOOLONG;
157 ReportError("Server name '%s' is too long for NetBIOS (max %ld characters).",p->server_ipname,16);
158 goto error_occured;
161 strlcpy (data.server_name, p->server_ipname, sizeof(data.server_name));
164 StringToUpper (data.server_name);
166 if (data.client_name[0] == '\0')
168 if (strlen (hostname) > 16)
170 errnum = -ENAMETOOLONG;
171 ReportError("Local host name '%s' is too long for NetBIOS (max %ld characters).", hostname, 16);
172 goto error_occured;
175 strlcpy (data.client_name, hostname, sizeof(data.client_name));
176 StringToUpper (data.client_name);
179 res->server.mount_data = data;
181 NewList((struct List *)&res->open_files);
183 if ((errnum = smb_proc_connect (&res->server)) < 0)
185 ReportError("Cannot connect to server (%ld, %s).", -errnum,amitcp_strerror(-errnum));
186 goto error_occured;
189 if (!use_E)
190 res->supports_E_known = 1;
192 (*result) = res;
194 return 0;
196 error_occured:
198 if(res != NULL)
200 smba_cleanup_dircache (res);
201 free (res);
204 return errnum;
207 /*****************************************************************************/
209 void
210 smba_disconnect (smba_server_t * server)
212 CloseSocket (server->server.mount_data.fd);
214 smba_cleanup_dircache(server);
216 free (server);
219 /*****************************************************************************/
221 static INLINE int
222 make_open (smba_file_t * f, int need_fid)
224 int errnum = 0;
225 smba_server_t *s;
227 if (!f->is_valid || (need_fid && !f->dirent.opened))
229 s = f->server;
231 if (!f->is_valid || f->attr_time == -1 || GetCurrentTime() - f->attr_time > ATTR_CACHE_TIME)
233 if ((errnum = smb_proc_getattr_core (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent)) < 0)
234 goto error_occured;
237 if ((f->dirent.attr & aDIR) == 0) /* a regular file */
239 if (need_fid || !s->supports_E_known || s->supports_E)
241 LOG (("opening file %s\n", f->dirent.complete_path));
242 if ((errnum = smb_proc_open (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent)) < 0)
243 goto error_occured;
245 if (s->supports_E || !s->supports_E_known)
247 if (smb_proc_getattrE (&s->server, &f->dirent) < 0)
249 if (!s->supports_E_known)
251 s->supports_E_known = 1;
252 s->supports_E = 0;
253 } /* ignore errors here */
255 else
257 s->supports_E_known = 1;
258 s->supports_E = 1;
263 else
265 /* don't open directory, initialize directory cache */
266 if (f->dircache != NULL)
268 f->dircache->cache_for = NULL;
269 f->dircache->len = 0;
270 f->dircache = NULL;
274 f->attr_time = GetCurrentTime();
275 f->is_valid = 1;
278 error_occured:
280 return errnum;
283 /*****************************************************************************/
286 smba_open (smba_server_t * s, char *name, size_t name_size, smba_file_t ** file)
288 smba_file_t *f;
289 int errnum;
291 (*file) = NULL;
293 f = malloc (sizeof(*f));
294 if(f == NULL)
296 errnum = -ENOMEM;
297 goto error_occured;
300 memset(f,0,sizeof(*f));
302 f->dirent.complete_path = name;
303 f->dirent.complete_path_size = name_size;
304 f->dirent.len = strlen (name);
305 f->server = s;
307 errnum = make_open (f, 0);
308 if (errnum < 0)
309 goto error_occured;
311 AddTail ((struct List *)&s->open_files, (struct Node *)f);
313 (*file) = f;
315 return 0;
317 error_occured:
319 if (f != NULL)
320 free (f);
322 return errnum;
325 /*****************************************************************************/
327 static int
328 write_attr (smba_file_t * f)
330 int errnum;
332 LOG (("file %s\n", f->dirent.complete_path));
334 errnum = make_open (f, 0);
335 if (errnum < 0)
336 goto out;
338 if (f->dirent.opened && f->server->supports_E)
339 errnum = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent);
340 else
341 errnum = smb_proc_setattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
343 if (errnum < 0)
344 f->attr_time = -1;
345 else
346 f->attr_dirty = 0;
348 out:
350 return errnum;
353 /*****************************************************************************/
355 void
356 smba_close (smba_file_t * f)
358 if(f->node.mln_Succ != NULL || f->node.mln_Pred != NULL)
359 Remove((struct Node *)f);
361 if(f->attr_dirty)
362 write_attr(f);
364 if (f->dirent.opened)
366 LOG (("closing file %s\n", f->dirent.complete_path));
367 smb_proc_close (&f->server->server, f->dirent.fileid, f->dirent.mtime);
370 if (f->dircache != NULL)
372 f->dircache->cache_for = NULL;
373 f->dircache->len = 0;
374 f->dircache = NULL;
377 free (f);
380 /*****************************************************************************/
383 smba_read (smba_file_t * f, char *data, long len, long offset)
385 int maxsize, count, totalcount, result;
386 int bytes_read = 0;
387 char *rpos;
389 result = make_open (f, 1);
390 if (result < 0)
391 goto out;
393 D(("read %ld bytes from offset %ld",len,offset));
395 if (f->server->server.blkmode & 1)
397 SHOWVALUE(f->server->server.max_xmit);
399 if(len <= 65535)
401 result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, len, data);
403 LOG (("smb_proc_read_raw(%s)->%ld\n", f->dirent.complete_path, result));
405 else if (len > 0)
407 int n;
409 totalcount = 0;
413 n = min(len,65535);
415 result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, n, data);
416 if(result <= 0)
418 D(("!!! wanted to read %ld bytes, got %ld",n,result));
419 totalcount = -1;
420 break;
423 data += result;
424 offset += result;
425 len -= result;
426 totalcount += result;
428 if(result < n)
430 D(("read returned fewer characters than expected (%ld < %ld)",result,n));
431 break;
434 while(len > 0);
436 if(totalcount != -1)
438 result = totalcount;
439 goto out;
444 if (result <= 0)
446 totalcount = len;
447 rpos = data;
449 maxsize = f->server->server.max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
453 count = totalcount > maxsize ? maxsize : totalcount;
455 result = smb_proc_read (&f->server->server, &f->dirent, offset, count, rpos, 0);
456 if (result <= 0)
457 break;
459 bytes_read += result;
460 totalcount -= result;
461 offset += result;
462 rpos += result;
464 if(result < count)
466 D(("read returned fewer characters than expected (%ld < %ld)",result,count));
467 break;
470 while (totalcount > 0);
472 if(result >= 0)
473 result = bytes_read;
476 out:
478 return result;
481 /*****************************************************************************/
484 smba_write (smba_file_t * f, char *data, long len, long offset)
486 int newlen, maxsize, totalcount, count, result;
488 if ((result = make_open (f, 1)) < 0)
489 return result;
491 /* Calculate maximum number of bytes that could be tranfered with
492 a single SMBwrite packet... */
493 maxsize = f->server->server.max_xmit - (SMB_HEADER_LEN + 5 * sizeof (word) + 5) - 4;
495 if (len <= maxsize)
497 /* Use a single SMBwrite packet whenever possible instead of a SMBwritebraw
498 because that requires two packets to be send. */
499 result = smb_proc_write (&f->server->server, &f->dirent, offset, len, data);
501 else
503 /* Added by Brian Willette - We were always checking bit 2 here, but
504 according to the documentation I have, the newer versions of SMB put
505 the SMB_RAW_WRITE AND SMB_RAW_READ capability in bit 1 */
506 if ((f->server->server.protocol >= PROTOCOL_NT1
507 && f->server->server.blkmode & 1)
508 || (f->server->server.protocol < PROTOCOL_NT1
509 && f->server->server.blkmode & 2))
511 long maxxmit;
512 int n;
514 totalcount = 0;
516 /* Try to send the maximum number of bytes with the two SMBwritebraw packets. */
517 maxxmit = 2 * f->server->server.max_xmit - (SMB_HEADER_LEN + 12 * sizeof (word) + 4) - 8;
519 /* If the number of bytes that should be transfered exceed the number of
520 bytes that could be transfered by a single call to smb_proc_write_raw,
521 the data is transfered as before: Only by the second packet, this
522 prevents the CPU from copying the data into the transferbuffer. */
523 if (maxxmit < len)
524 maxxmit = f->server->server.max_xmit - 4;
528 n = min(len,maxxmit);
530 if (n <= maxsize)
532 /* Use a single SMBwrite packet whenever possible instead of a
533 SMBwritebraw because that requires two packets to be send. */
534 result = smb_proc_write (&f->server->server, &f->dirent, offset, n, data);
536 else
538 result = smb_proc_write_raw (&f->server->server, &f->dirent, offset, n, data);
541 if(result <= 0)
543 totalcount = -1;
544 break;
547 data += result;
548 offset += result;
549 len -= result;
550 totalcount += result;
552 if(result < n)
553 break;
555 while(len > 0);
557 if(totalcount != -1)
559 len = totalcount;
560 goto out;
563 if (result <= 0)
565 /* Failed to use the SMBwritebraw packet, fallback to SMBwrite... */
566 totalcount = len;
567 len = 0;
571 count = totalcount > maxsize ? maxsize : totalcount;
572 result = smb_proc_write (&f->server->server, &f->dirent, offset, count, data);
573 if (result < 0)
574 break;
576 totalcount -= result;
577 offset += result;
578 data += result;
579 len += result;
581 if(result < count)
582 break;
584 while (totalcount > 0);
588 out:
590 if (result < 0)
592 f->attr_time = -1;
593 return result;
596 f->dirent.mtime = GetCurrentTime();
598 newlen = f->dirent.size;
600 if (offset + len > newlen)
601 newlen = offset + len;
603 f->dirent.size = newlen;
604 return len;
607 /*****************************************************************************/
609 long
610 smba_seek (smba_file_t *f, long offset, long mode, off_t * new_position_ptr)
612 long result;
614 D(("seek %ld bytes from position %s",offset,mode > 0 ? (mode == 2 ? "SEEK_END" : "SEEK_CUR") : "SEEK_SET"));
616 if ((result = make_open (f, 1)) >= 0)
617 result = smb_proc_lseek (&f->server->server, &f->dirent, offset, mode, new_position_ptr);
619 return result;
622 /*****************************************************************************/
624 /* perform a single record-lock */
626 smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, long timeout)
628 int errnum;
629 struct smb_lkrng *rec_lock;
631 if ((errnum = make_open (f, 1)) >= 0)
633 if (unlocked)
634 mode |= 2;
636 rec_lock = malloc (sizeof (struct smb_lkrng));
637 if (rec_lock != NULL)
639 rec_lock->offset = offset,
640 rec_lock->len = len;
642 errnum = smb_proc_lockingX (&f->server->server, &f->dirent, rec_lock, 1, mode, timeout);
644 free (rec_lock);
646 else
648 errnum = -ENOMEM;
652 return errnum;
655 /*****************************************************************************/
658 smba_getattr (smba_file_t * f, smba_stat_t * data)
660 long now = GetCurrentTime();
661 int errnum;
663 errnum = make_open (f, 0);
664 if (errnum < 0)
665 goto out;
667 if (f->attr_time == -1 || (now - f->attr_time) > ATTR_CACHE_TIME)
669 LOG (("file %s\n", f->dirent.complete_path));
671 if (f->dirent.opened && f->server->supports_E)
672 errnum = smb_proc_getattrE (&f->server->server, &f->dirent);
673 else
674 errnum = smb_proc_getattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
676 if (errnum >= 0)
677 f->attr_time = now;
680 data->is_dir = (f->dirent.attr & aDIR) != 0;
681 data->is_wp = (f->dirent.attr & aRONLY) != 0;
682 data->is_hidden = (f->dirent.attr & aHIDDEN) != 0;
683 data->is_system = (f->dirent.attr & aSYSTEM) != 0;
684 data->is_archive = (f->dirent.attr & aARCH) != 0;
686 data->size = f->dirent.size;
687 data->atime = f->dirent.atime;
688 data->ctime = f->dirent.ctime;
689 data->mtime = f->dirent.mtime;
691 out:
693 return errnum;
696 /*****************************************************************************/
699 smba_setattr (smba_file_t * f, smba_stat_t * data)
701 int errnum;
703 if (data->atime != -1)
704 f->dirent.atime = data->atime;
706 if (data->ctime != -1)
707 f->dirent.ctime = data->ctime;
709 if (data->mtime != -1)
710 f->dirent.mtime = data->mtime;
712 if (data->is_wp)
713 f->dirent.attr |= aRONLY;
714 else
715 f->dirent.attr &= ~aRONLY;
717 if (data->is_archive)
718 f->dirent.attr |= aARCH;
719 else
720 f->dirent.attr &= ~aARCH;
722 if (data->is_system)
723 f->dirent.attr |= aSYSTEM;
724 else
725 f->dirent.attr &= ~aSYSTEM;
727 f->attr_dirty = 1;
729 if ((errnum = write_attr (f)) < 0)
730 goto error_occured;
732 if (data->size != -1 &&
733 data->size != (int)f->dirent.size)
735 if ((errnum = make_open (f, 1)) < 0)
736 goto error_occured;
738 if ((errnum = smb_proc_trunc (&f->server->server, f->dirent.fileid, data->size)) < 0)
739 goto error_occured;
741 f->dirent.size = data->size;
744 error_occured:
746 return errnum;
749 /*****************************************************************************/
752 smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback)
754 int cache_index, rval, o, eof, count = 0;
755 long now = GetCurrentTime();
756 smba_stat_t data;
758 rval = make_open (f, 0);
759 if (rval < 0)
760 goto out;
762 if (f->dircache == NULL) /* get a cache */
764 dircache_t * dircache = f->server->dircache;
766 if (dircache->cache_for != NULL)
767 dircache->cache_for->dircache = NULL; /* steal it */
769 dircache->eof = dircache->len = dircache->base = 0;
770 dircache->cache_for = f;
772 f->dircache = dircache;
774 LOG (("stealing cache\n"));
776 else
778 if ((now - f->dircache->created_at) >= DIR_CACHE_TIME)
780 f->dircache->eof = f->dircache->len = f->dircache->base = 0;
782 LOG (("cache outdated\n"));
786 for (cache_index = offs ; ; cache_index++)
788 if (cache_index < f->dircache->base /* fill cache if necessary */
789 || cache_index >= f->dircache->base + f->dircache->len)
791 if (cache_index >= f->dircache->base + f->dircache->len && f->dircache->eof)
792 break; /* nothing more to read */
794 LOG (("cachefill for %s\n", f->dirent.complete_path));
795 LOG (("\tbase was: %ld, len was: %ld, newbase=%ld\n", f->dircache->base, f->dircache->len, cache_index));
797 f->dircache->len = 0;
798 f->dircache->base = cache_index;
800 rval = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, f->dircache->cache);
801 if (rval <= 0)
802 break;
804 /* Avoid some hits if restart/retry occured. Should fix the real root
805 of this problem really, but I am not bored enough atm. -Piru
806 ZZZ this needs further investigation. */
807 if (f->dircache == NULL)
809 LOG (("lost dircache due to an error, bailing out!\n"));
810 rval = -1;
811 break;
814 f->dircache->len = rval;
815 f->dircache->eof = (rval < f->dircache->cache_size);
816 f->dircache->created_at = now;
818 LOG (("cachefill with %ld entries\n", rval));
821 o = cache_index - f->dircache->base;
822 eof = (o >= (f->dircache->len - 1) && f->dircache->eof);
823 count++;
825 LOG (("delivering '%s', cache_index=%ld, eof=%ld\n", f->dircache->cache[o].complete_path, cache_index, eof));
827 data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0;
828 data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0;
829 data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0;
830 data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0;
831 data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0;
832 data.size = f->dircache->cache[o].size;
833 data.atime = f->dircache->cache[o].atime;
834 data.ctime = f->dircache->cache[o].ctime;
835 data.mtime = f->dircache->cache[o].mtime;
837 if ((*callback) (d, cache_index, cache_index + 1, f->dircache->cache[o].complete_path, eof, &data))
838 break;
841 out:
843 if (rval < 0)
844 return rval;
845 else
846 return count;
849 /*****************************************************************************/
851 static void
852 invalidate_dircache (struct smba_server * server, char * path)
854 dircache_t * dircache = server->dircache;
855 char other_path[SMB_MAXNAMELEN + 1];
857 ENTER();
859 if(path != NULL)
861 int len,i;
863 strlcpy(other_path,path,sizeof(other_path));
865 len = strlen(other_path);
866 for(i = len-1 ; i >= 0 ; i--)
868 if(i == 0)
870 other_path[0] = DOS_PATHSEP;
871 other_path[1] = '\0';
873 else if (other_path[i] == DOS_PATHSEP)
875 other_path[i] = '\0';
876 break;
880 else
882 other_path[0] = '\0';
885 SHOWSTRING(other_path);
887 if(dircache->cache_for != NULL)
888 SHOWSTRING(dircache->cache_for->dirent.complete_path);
889 else
890 SHOWMSG("-- directory cache is empty --");
892 if(path == NULL || (dircache->cache_for != NULL && CompareNames(other_path,dircache->cache_for->dirent.complete_path) == SAME))
894 SHOWMSG("clearing directory cache");
896 dircache->eof = dircache->len = dircache->base = 0;
897 if(dircache->cache_for != NULL)
899 dircache->cache_for->dircache = NULL;
900 dircache->cache_for = NULL;
904 LEAVE();
907 /*****************************************************************************/
910 smba_create (smba_file_t * dir, const char *name, smba_stat_t * attr)
912 struct smb_dirent entry;
913 char *path;
914 int errnum;
916 errnum = make_open (dir, 0);
917 if (errnum < 0)
918 goto out;
920 memset (&entry, 0, sizeof (entry));
922 if (attr->is_wp)
923 entry.attr |= aRONLY;
925 if (attr->is_archive)
926 entry.attr |= aARCH;
928 if (attr->is_system)
929 entry.attr |= aSYSTEM;
931 entry.atime = entry.mtime = entry.ctime = GetCurrentTime();
933 path = malloc (strlen (name) + dir->dirent.len + 2);
934 if(path == NULL)
936 errnum = -ENOMEM;
937 goto out;
940 memcpy (path, dir->dirent.complete_path, dir->dirent.len);
941 path[dir->dirent.len] = DOS_PATHSEP;
942 strcpy (&path[dir->dirent.len + 1], name);
944 errnum = smb_proc_create (&dir->server->server, path, strlen (path), &entry);
945 if(errnum >= 0)
946 invalidate_dircache (dir->server, path);
948 free (path);
950 out:
952 return errnum;
955 /*****************************************************************************/
958 smba_mkdir (smba_file_t * dir, const char *name)
960 char *path;
961 int errnum;
963 errnum = make_open (dir, 0);
964 if (errnum < 0)
965 goto out;
967 path = malloc (strlen (name) + dir->dirent.len + 2);
968 if(path == NULL)
970 errnum = -ENOMEM;
971 goto out;
974 memcpy (path, dir->dirent.complete_path, dir->dirent.len);
975 path[dir->dirent.len] = DOS_PATHSEP;
976 strcpy (&path[dir->dirent.len + 1], name);
978 errnum = smb_proc_mkdir (&dir->server->server, path, strlen (path));
979 if(errnum >= 0)
980 invalidate_dircache (dir->server, path);
982 free (path);
984 out:
986 return errnum;
989 /*****************************************************************************/
991 static void
992 close_path (smba_server_t * s, char *path)
994 smba_file_t *p;
996 for (p = (smba_file_t *)s->open_files.mlh_Head;
997 p->node.mln_Succ != NULL;
998 p = (smba_file_t *)p->node.mln_Succ)
1000 if (p->is_valid && CompareNames(p->dirent.complete_path, path) == SAME)
1002 if (p->dirent.opened)
1003 smb_proc_close (&s->server, p->dirent.fileid, p->dirent.mtime);
1005 p->dirent.opened = 0;
1006 p->is_valid = 0;
1011 /*****************************************************************************/
1014 smba_remove (smba_server_t * s, char *path)
1016 int result;
1018 close_path (s, path);
1020 result = smb_proc_unlink (&s->server, path, strlen (path));
1021 if(result >= 0)
1022 invalidate_dircache (s, path);
1024 return result;
1027 /*****************************************************************************/
1030 smba_rmdir (smba_server_t * s, char *path)
1032 int result;
1034 close_path (s, path);
1036 result = smb_proc_rmdir (&s->server, path, strlen (path));
1037 if(result >= 0)
1038 invalidate_dircache (s, path);
1040 return result;
1043 /*****************************************************************************/
1046 smba_rename (smba_server_t * s, char *from, char *to)
1048 int result;
1050 close_path (s, from);
1052 result = smb_proc_mv (&s->server, from, strlen (from), to, strlen (to));
1053 if(result >= 0)
1054 invalidate_dircache (s, from);
1056 return result;
1059 /*****************************************************************************/
1062 smba_statfs (smba_server_t * s, long *bsize, long *blocks, long *bfree)
1064 struct smb_dskattr dskattr;
1065 int errnum;
1067 errnum = smb_proc_dskattr (&s->server, &dskattr);
1068 if (errnum < 0)
1069 goto out;
1071 (*bsize) = dskattr.blocksize * dskattr.allocblocks;
1072 (*blocks) = dskattr.total;
1073 (*bfree) = dskattr.free;
1075 out:
1077 return errnum;
1080 /*****************************************************************************/
1082 void
1083 smb_invalidate_all_inodes (struct smb_server *server)
1085 smba_file_t *f;
1087 invalidate_dircache (server->abstraction, NULL);
1089 for (f = (smba_file_t *)server->abstraction->open_files.mlh_Head;
1090 f->node.mln_Succ != NULL;
1091 f = (smba_file_t *)f->node.mln_Succ)
1093 f->dirent.opened = 0;
1094 f->is_valid = 0;
1098 /*****************************************************************************/
1100 static void
1101 smba_cleanup_dircache(struct smba_server * server)
1103 dircache_t * the_dircache = server->dircache;
1105 if(the_dircache != NULL)
1107 int i;
1109 for (i = 0; i < the_dircache->cache_size; i++)
1111 if(the_dircache->cache[i].complete_path != NULL)
1112 free(the_dircache->cache[i].complete_path);
1115 free(the_dircache);
1116 server->dircache = NULL;
1120 static int
1121 smba_setup_dircache (struct smba_server * server,int cache_size)
1123 dircache_t * the_dircache;
1124 int error = (-ENOMEM);
1125 int i;
1127 the_dircache = malloc(sizeof(*the_dircache) + (cache_size-1) * sizeof(the_dircache->cache));
1128 if(the_dircache == NULL)
1129 goto out;
1131 memset(the_dircache,0,sizeof(*the_dircache));
1132 the_dircache->cache_size = cache_size;
1134 for (i = 0; i < the_dircache->cache_size; i++)
1136 the_dircache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
1137 if(the_dircache->cache[i].complete_path == NULL)
1138 goto out;
1140 the_dircache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
1143 server->dircache = the_dircache;
1145 error = 0;
1147 out:
1149 if(error < 0)
1151 if(the_dircache != NULL)
1153 for (i = 0; i < the_dircache->cache_size; i++)
1155 if(the_dircache->cache[i].complete_path != NULL)
1156 free(the_dircache->cache[i].complete_path);
1159 free(the_dircache);
1163 return(error);
1166 /*****************************************************************************/
1168 static int
1169 extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size)
1171 char *share_start;
1172 char *root_start;
1173 char *complete_service;
1174 char * service_copy;
1175 int result = 0;
1177 service_copy = malloc(strlen(service)+1);
1178 if(service_copy == NULL)
1180 result = -ENOMEM;
1181 ReportError("Not enough memory.");
1182 goto out;
1185 strcpy (service_copy, service);
1186 complete_service = service_copy;
1188 if (strlen (complete_service) < 4 || complete_service[0] != '/')
1190 result = -EINVAL;
1191 ReportError("Invalid service name '%s'.",complete_service);
1192 goto out;
1195 while (complete_service[0] == '/')
1196 complete_service += 1;
1198 share_start = strchr (complete_service, '/');
1199 if (share_start == NULL)
1201 result = -EINVAL;
1202 ReportError("Invalid share name '%s'.",complete_service);
1203 goto out;
1206 (*share_start++) = '\0';
1207 root_start = strchr (share_start, '/');
1209 if (root_start != NULL)
1210 (*root_start) = '\0';
1212 if ((strlen (complete_service) > 63) || (strlen (share_start) > 63))
1214 result = -ENAMETOOLONG;
1215 ReportError("Server or share name is too long in '%s' (max %ld characters).",service,63);
1216 goto out;
1219 strlcpy (server, complete_service, server_size);
1220 strlcpy (share, share_start, share_size);
1222 out:
1224 if(service_copy != NULL)
1225 free(service_copy);
1227 return(result);
1231 smba_start(char * service,char *opt_workgroup,char *opt_username,char *opt_password,char *opt_clientname,char *opt_servername,int opt_cachesize,smba_server_t ** result)
1233 smba_connect_parameters_t par;
1234 smba_server_t *the_server = NULL;
1235 int i;
1236 struct hostent *h;
1237 int max_xmit = -1;
1238 int use_extended = 0;
1239 char server_name[17], client_name[17];
1240 char username[64], password[64];
1241 char workgroup[20];
1242 char server[64], share[64];
1243 unsigned int ipAddr;
1244 int error;
1246 (*result) = NULL;
1247 (*username) = (*password) = (*server_name) = (*client_name) = '\0';
1249 error = extract_service (service, server, sizeof(server), share, sizeof(share));
1250 if(error < 0)
1251 goto out;
1253 ipAddr = inet_addr (server);
1254 if (ipAddr == INADDR_NONE) /* name was given, not numeric */
1256 int lookup_error;
1258 h = gethostbyname (server);
1259 lookup_error = h_errno;
1261 if (h != NULL)
1263 ipAddr = ((struct in_addr *)(h->h_addr))->s_addr;
1265 else if (BroadcastNameQuery(server,"",(UBYTE *)&ipAddr) != 0)
1267 ReportError("Unknown host '%s' (%ld, %s).",server,lookup_error,host_strerror(lookup_error));
1268 error = (-ENOENT);
1269 goto out;
1272 else
1274 char hostName[MAXHOSTNAMELEN+1];
1276 h = gethostbyaddr ((char *) &ipAddr, sizeof (ipAddr), AF_INET);
1277 if (h == NULL)
1279 ReportError("Unknown host '%s' (%ld, %s).",server,h_errno,host_strerror(errno));
1280 error = (-ENOENT);
1281 goto out;
1284 /* Brian Willette: Now we will set the server name to the dns
1285 hostname, hopefully this will be the same as the netbios name for
1286 the server.
1287 We do this because the user supplied no hostname, and we
1288 need one for netbios, this is the best guess choice we have
1289 NOTE: If the names are different between DNS and netbios on
1290 the windows side, the user MUST use the -s option. */
1291 for (i = 0; h->h_name[i] != '.' && h->h_name[i] != '\0' && i < 255; i++)
1292 hostName[i] = h->h_name[i];
1294 hostName[i] = '\0';
1296 /* Make sure the hostname is 16 characters or less (for Netbios) */
1297 if (strlen (hostName) > 16)
1299 ReportError("Server host name '%s' is too long (max %ld characters).", hostName, 16);
1300 error = (-ENAMETOOLONG);
1301 goto out;
1304 strlcpy (server_name, hostName, sizeof(server_name));
1307 if(opt_password != NULL)
1309 if(strlen(opt_password) >= sizeof(password))
1311 ReportError("Password is too long (max %ld characters).", sizeof(password)-1);
1312 error = (-ENAMETOOLONG);
1313 goto out;
1316 strlcpy(password,opt_password,sizeof(password));
1319 if(strlen(opt_username) >= sizeof(username))
1321 ReportError("User name '%s' is too long (max %ld characters).", username,sizeof(username)-1);
1322 error = (-ENAMETOOLONG);
1323 goto out;
1326 strlcpy(username,opt_username,sizeof(username));
1327 StringToUpper(username);
1329 if (strlen(opt_workgroup) > 15)
1331 ReportError("Workgroup/domain name '%s' is too long (max %ld characters).", opt_workgroup,15);
1332 error = (-ENAMETOOLONG);
1333 goto out;
1336 strlcpy (workgroup, opt_workgroup, sizeof(workgroup));
1337 StringToUpper (workgroup);
1339 if(opt_servername != NULL)
1341 if (strlen (opt_servername) > 16)
1343 ReportError("Server name '%s' is too long (max %ld characters).", opt_servername,16);
1344 error = (-ENAMETOOLONG);
1345 goto out;
1348 strlcpy (server_name, opt_servername, sizeof(server_name));
1351 if(opt_clientname != NULL)
1353 if (strlen (opt_clientname) > 16)
1355 ReportError("Client name '%s' is too long (max %ld characters).", opt_clientname,16);
1356 error = (-ENAMETOOLONG);
1357 goto out;
1360 strlcpy (client_name, opt_clientname, sizeof(client_name));
1363 if(opt_cachesize < 1)
1364 opt_cachesize = DIRCACHE_SIZE;
1365 else if (opt_cachesize < 10)
1366 opt_cachesize = 10;
1368 strlcpy(par.server_ipname,server,sizeof(par.server_ipname));
1369 par.server_name = server_name;
1370 par.client_name = client_name;
1372 strlcpy(par.service,share,sizeof(par.service));
1373 par.username = username;
1374 par.password = password;
1375 par.max_xmit = max_xmit;
1377 error = smba_connect (&par, ipAddr, use_extended, workgroup, opt_cachesize, &the_server);
1378 if(error < 0)
1380 ReportError("Could not connect to server (%ld, %s).",-error,amitcp_strerror(-error));
1381 goto out;
1384 (*result) = the_server;
1386 error = 0;
1388 out:
1390 return(error);
1393 /*****************************************************************************/
1396 smba_get_dircache_size(struct smba_server * server)
1398 int result;
1400 result = server->dircache->cache_size;
1402 return(result);
1405 /*****************************************************************************/
1408 smba_change_dircache_size(struct smba_server * server,int cache_size)
1410 dircache_t * new_cache;
1411 dircache_t * the_dircache = server->dircache;
1412 int result;
1413 int i;
1415 result = the_dircache->cache_size;
1417 if(cache_size < 10)
1418 cache_size = 10;
1420 if(cache_size == the_dircache->cache_size)
1421 goto out;
1423 new_cache = malloc(sizeof(*new_cache) + (cache_size-1) * sizeof(new_cache->cache));
1424 if(new_cache == NULL)
1425 goto out;
1427 memset(new_cache,0,sizeof(*new_cache));
1428 new_cache->cache_size = cache_size;
1430 /* If the new cache is to be larger than the old one,
1431 allocate additional file name slots. */
1432 if(cache_size > the_dircache->cache_size)
1434 for(i = the_dircache->cache_size ; i < cache_size ; i++)
1436 new_cache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
1437 if(new_cache->cache[i].complete_path == NULL)
1439 int j;
1441 for(j = the_dircache->cache_size ; j < i ; j++)
1442 free(new_cache->cache[j].complete_path);
1444 free(new_cache);
1446 goto out;
1449 new_cache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
1452 /* Reuse the file name buffers allocated for
1453 the old cache. */
1454 for(i = 0 ; i < the_dircache->cache_size ; i++)
1456 new_cache->cache[i].complete_path = the_dircache->cache[i].complete_path;
1457 new_cache->cache[i].complete_path_size = the_dircache->cache[i].complete_path_size;
1459 the_dircache->cache[i].complete_path = NULL;
1462 else
1464 /* Reuse the file name buffers allocated for
1465 the old cache. */
1466 for(i = 0 ; i < cache_size ; i++)
1468 new_cache->cache[i].complete_path = the_dircache->cache[i].complete_path;
1469 new_cache->cache[i].complete_path_size = the_dircache->cache[i].complete_path_size;
1470 the_dircache->cache[i].complete_path = NULL;
1474 invalidate_dircache(server, NULL);
1476 for (i = 0; i < the_dircache->cache_size; i++)
1478 if(the_dircache->cache[i].complete_path != NULL)
1479 free(the_dircache->cache[i].complete_path);
1482 free(the_dircache);
1484 server->dircache = new_cache;
1485 result = cache_size;
1487 out:
1489 return(result);