Added support for SERVICESF shared variable to change configuration file
[Samba/gbeck.git] / source / smbwrapper / smbw.c
blob65a70c9178343f6e7a769afbaaa96766ba57a53a
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.0
4 SMB wrapper functions
5 Copyright (C) Andrew Tridgell 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
23 #include "realcalls.h"
25 pstring smbw_cwd;
27 static struct smbw_file *smbw_files;
28 static struct smbw_server *smbw_srvs;
30 struct bitmap *smbw_file_bmap;
31 extern pstring global_myname;
32 extern int DEBUGLEVEL;
34 fstring smbw_prefix = SMBW_PREFIX;
36 int smbw_busy=0;
38 /* needs to be here because of dumb include files on some systems */
39 int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
42 /*****************************************************
43 initialise structures
44 *******************************************************/
45 void smbw_init(void)
47 extern BOOL in_client;
48 static int initialised;
49 static pstring servicesf = CONFIGFILE;
50 extern FILE *dbf;
51 char *p;
52 int eno;
53 pstring line;
55 if (initialised) return;
56 initialised = 1;
58 eno = errno;
60 smbw_busy++;
62 DEBUGLEVEL = 0;
63 setup_logging("smbsh",True);
65 dbf = stderr;
67 if ((p=smbw_getshared("LOGFILE"))) {
68 dbf = sys_fopen(p, "a");
71 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
72 if (!smbw_file_bmap) {
73 exit(1);
76 charset_initialise();
78 in_client = True;
80 load_interfaces();
82 if ((p=smbw_getshared("SERVICESF"))) {
83 pstrcpy(servicesf, p);
86 lp_load(servicesf,True,False,False);
88 get_myname(global_myname);
90 if ((p=smbw_getshared("DEBUG"))) {
91 DEBUGLEVEL = atoi(p);
94 if ((p=smbw_getshared("RESOLVE_ORDER"))) {
95 lp_set_name_resolve_order(p);
98 if ((p=smbw_getshared("PREFIX"))) {
99 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
100 all_string_sub(smbw_prefix,"//", "/", 0);
101 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
104 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
106 p = smbw_getshared(line);
107 if (!p) {
108 sys_getwd(smbw_cwd);
110 pstrcpy(smbw_cwd, p);
111 DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
113 smbw_busy--;
115 set_maxfiles(SMBW_MAX_OPEN);
117 BlockSignals(True,SIGPIPE);
119 errno = eno;
122 /*****************************************************
123 determine if a file descriptor is a smb one
124 *******************************************************/
125 int smbw_fd(int fd)
127 if (smbw_busy) return 0;
128 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
131 /*****************************************************
132 determine if a file descriptor is an internal smbw fd
133 *******************************************************/
134 int smbw_local_fd(int fd)
136 struct smbw_server *srv;
138 smbw_init();
140 if (smbw_busy) return 0;
141 if (smbw_shared_fd(fd)) return 1;
143 for (srv=smbw_srvs;srv;srv=srv->next) {
144 if (srv->cli.fd == fd) return 1;
147 return 0;
150 /*****************************************************
151 a crude inode number generator
152 *******************************************************/
153 ino_t smbw_inode(const char *name)
155 if (!*name) return 2;
156 return (ino_t)str_checksum(name);
159 /*****************************************************
160 remove redundent stuff from a filename
161 *******************************************************/
162 void clean_fname(char *name)
164 char *p, *p2;
165 int l;
166 int modified = 1;
168 if (!name) return;
170 while (modified) {
171 modified = 0;
173 DEBUG(5,("cleaning %s\n", name));
175 if ((p=strstr(name,"/./"))) {
176 modified = 1;
177 while (*p) {
178 p[0] = p[2];
179 p++;
183 if ((p=strstr(name,"//"))) {
184 modified = 1;
185 while (*p) {
186 p[0] = p[1];
187 p++;
191 if (strcmp(name,"/../")==0) {
192 modified = 1;
193 name[1] = 0;
196 if ((p=strstr(name,"/../"))) {
197 modified = 1;
198 for (p2=(p>name?p-1:p);p2>name;p2--) {
199 if (p2[0] == '/') break;
201 while (*p2) {
202 p2[0] = p2[3];
203 p2++;
207 if (strcmp(name,"/..")==0) {
208 modified = 1;
209 name[1] = 0;
212 l = strlen(name);
213 p = l>=3?(name+l-3):name;
214 if (strcmp(p,"/..")==0) {
215 modified = 1;
216 for (p2=p-1;p2>name;p2--) {
217 if (p2[0] == '/') break;
219 if (p2==name) {
220 p[0] = '/';
221 p[1] = 0;
222 } else {
223 p2[0] = 0;
227 l = strlen(name);
228 p = l>=2?(name+l-2):name;
229 if (strcmp(p,"/.")==0) {
230 if (p == name) {
231 p[1] = 0;
232 } else {
233 p[0] = 0;
237 if (strncmp(p=name,"./",2) == 0) {
238 modified = 1;
239 do {
240 p[0] = p[2];
241 } while (*p++);
244 l = strlen(p=name);
245 if (l > 1 && p[l-1] == '/') {
246 modified = 1;
247 p[l-1] = 0;
254 /*****************************************************
255 find a workgroup (any workgroup!) that has a master
256 browser on the local network
257 *******************************************************/
258 static char *smbw_find_workgroup(void)
260 fstring server;
261 char *p;
262 struct in_addr *ip_list = NULL;
263 int count = 0;
265 /* first off see if an existing workgroup name exists */
266 p = smbw_getshared("WORKGROUP");
267 if (!p) p = lp_workgroup();
269 slprintf(server, sizeof(server), "%s#1D", p);
270 if (smbw_server(server, "IPC$")) return p;
272 /* go looking for workgroups */
273 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
274 DEBUG(1,("No workgroups found!"));
275 return p;
279 free((char *)ip_list);
281 DEBUG(0,("Need to do node status code"));
282 return p;
285 /*****************************************************
286 parse a smb path into its components.
287 server is one of
288 1) the name of the SMB server
289 2) WORKGROUP#1D for share listing
290 3) WORKGROUP#__ for workgroup listing
291 share is the share on the server to query
292 path is the SMB path on the server
293 return the full path (ie. add cwd if needed)
294 *******************************************************/
295 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
297 static pstring s;
298 char *p;
299 int len;
300 fstring workgroup;
302 /* add cwd if necessary */
303 if (fname[0] != '/') {
304 slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
305 } else {
306 pstrcpy(s, fname);
308 clean_fname(s);
310 /* see if it has the right prefix */
311 len = strlen(smbw_prefix)-1;
312 if (strncmp(s,smbw_prefix,len) ||
313 (s[len] != '/' && s[len] != 0)) return s;
315 /* ok, its for us. Now parse out the workgroup, share etc. */
316 p = s+len;
317 if (*p == '/') p++;
318 if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
319 /* we're in /smb - give a list of workgroups */
320 slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
321 fstrcpy(share,"IPC$");
322 pstrcpy(path,"");
323 return s;
326 if (!next_token(&p, server, "/", sizeof(fstring))) {
327 /* we are in /smb/WORKGROUP */
328 slprintf(server,sizeof(fstring), "%s#1D", workgroup);
329 fstrcpy(share,"IPC$");
330 pstrcpy(path,"");
333 if (!next_token(&p, share, "/", sizeof(fstring))) {
334 /* we are in /smb/WORKGROUP/SERVER */
335 fstrcpy(share,"IPC$");
336 pstrcpy(path,"");
339 pstrcpy(path, p);
341 all_string_sub(path, "/", "\\", 0);
343 return s;
346 /*****************************************************
347 determine if a path name (possibly relative) is in the
348 smb name space
349 *******************************************************/
350 int smbw_path(const char *path)
352 fstring server, share;
353 pstring s;
354 char *cwd;
355 int len;
357 if(!path)
358 return 0;
360 /* this is needed to prevent recursion with the BSD malloc which
361 opens /etc/malloc.conf on the first call */
362 if (strncmp(path,"/etc/", 5) == 0) {
363 return 0;
366 smbw_init();
368 len = strlen(smbw_prefix)-1;
370 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
371 return 0;
374 if (smbw_busy) return 0;
376 DEBUG(3,("smbw_path(%s)\n", path));
378 cwd = smbw_parse_path(path, server, share, s);
380 if (strncmp(cwd,smbw_prefix,len) == 0 &&
381 (cwd[len] == '/' || cwd[len] == 0)) {
382 return 1;
385 return 0;
388 /*****************************************************
389 return a unix errno from a SMB error pair
390 *******************************************************/
391 int smbw_errno(struct cli_state *c)
393 uint8 eclass;
394 uint32 ecode;
395 int ret;
397 ret = cli_error(c, &eclass, &ecode, NULL);
399 if (ret) {
400 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
401 (int)eclass, (int)ecode, (int)ecode, ret));
403 return ret;
406 /* Return a username and password given a server and share name */
408 void get_envvar_auth_data(char *server, char *share, char **workgroup,
409 char **username, char **password)
411 /* Fall back to shared memory/environment variables */
413 *username = smbw_getshared("USER");
414 if (!*username) *username = getenv("USER");
415 if (!*username) *username = "guest";
417 *workgroup = smbw_getshared("WORKGROUP");
418 if (!*workgroup) *workgroup = lp_workgroup();
420 *password = smbw_getshared("PASSWORD");
421 if (!*password) *password = "";
424 static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
426 /*****************************************************
427 set the get auth data function
428 ******************************************************/
429 void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
431 get_auth_data_fn = fn;
434 /*****************************************************
435 return a connection to a server (existing or new)
436 *******************************************************/
437 struct smbw_server *smbw_server(char *server, char *share)
439 struct smbw_server *srv=NULL;
440 struct cli_state c;
441 char *username;
442 char *password;
443 char *workgroup;
444 struct nmb_name called, calling;
445 char *p, *server_n = server;
446 fstring group;
447 pstring ipenv;
448 struct in_addr ip;
449 extern struct in_addr ipzero;
451 ip = ipzero;
452 ZERO_STRUCT(c);
454 get_auth_data_fn(server, share, &workgroup, &username, &password);
456 /* try to use an existing connection */
457 for (srv=smbw_srvs;srv;srv=srv->next) {
458 if (strcmp(server,srv->server_name)==0 &&
459 strcmp(share,srv->share_name)==0 &&
460 strcmp(workgroup,srv->workgroup)==0 &&
461 strcmp(username, srv->username) == 0)
462 return srv;
465 if (server[0] == 0) {
466 errno = EPERM;
467 return NULL;
470 make_nmb_name(&calling, global_myname, 0x0);
471 make_nmb_name(&called , server, 0x20);
473 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
475 if ((p=strchr(server_n,'#')) &&
476 (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
477 struct in_addr sip;
478 pstring s;
480 fstrcpy(group, server_n);
481 p = strchr(group,'#');
482 *p = 0;
484 /* cache the workgroup master lookup */
485 slprintf(s,sizeof(s)-1,"MASTER_%s", group);
486 if (!(server_n = smbw_getshared(s))) {
487 if (!find_master_ip(group, &sip)) {
488 errno = ENOENT;
489 return NULL;
491 fstrcpy(group, inet_ntoa(sip));
492 server_n = group;
493 smbw_setshared(s,server_n);
497 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
499 again:
500 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
502 ip = ipzero;
503 if ((p=smbw_getshared(ipenv))) {
504 ip = *(interpret_addr2(p));
507 /* have to open a new connection */
508 if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
509 errno = ENOENT;
510 return NULL;
513 if (!cli_session_request(&c, &calling, &called)) {
514 cli_shutdown(&c);
515 if (strcmp(called.name, "*SMBSERVER")) {
516 make_nmb_name(&called , "*SMBSERVER", 0x20);
517 goto again;
519 errno = ENOENT;
520 return NULL;
523 DEBUG(4,(" session request ok\n"));
525 if (!cli_negprot(&c)) {
526 cli_shutdown(&c);
527 errno = ENOENT;
528 return NULL;
531 if (!cli_session_setup(&c, username,
532 password, strlen(password),
533 password, strlen(password),
534 workgroup) &&
535 /* try an anonymous login if it failed */
536 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
537 cli_shutdown(&c);
538 errno = EPERM;
539 return NULL;
542 DEBUG(4,(" session setup ok\n"));
544 if (!cli_send_tconX(&c, share, "?????",
545 password, strlen(password)+1)) {
546 errno = smbw_errno(&c);
547 cli_shutdown(&c);
548 return NULL;
551 smbw_setshared(ipenv,inet_ntoa(ip));
553 DEBUG(4,(" tconx ok\n"));
555 srv = (struct smbw_server *)malloc(sizeof(*srv));
556 if (!srv) {
557 errno = ENOMEM;
558 goto failed;
561 ZERO_STRUCTP(srv);
563 srv->cli = c;
565 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
567 srv->server_name = strdup(server);
568 if (!srv->server_name) {
569 errno = ENOMEM;
570 goto failed;
573 srv->share_name = strdup(share);
574 if (!srv->share_name) {
575 errno = ENOMEM;
576 goto failed;
579 srv->workgroup = strdup(workgroup);
580 if (!srv->workgroup) {
581 errno = ENOMEM;
582 goto failed;
585 srv->username = strdup(username);
586 if (!srv->username) {
587 errno = ENOMEM;
588 goto failed;
591 /* some programs play with file descriptors fairly intimately. We
592 try to get out of the way by duping to a high fd number */
593 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
594 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
595 srv->cli.fd+SMBW_CLI_FD) {
596 close(srv->cli.fd);
597 srv->cli.fd += SMBW_CLI_FD;
601 DLIST_ADD(smbw_srvs, srv);
603 return srv;
605 failed:
606 cli_shutdown(&c);
607 if (!srv) return NULL;
609 if (srv->server_name) free(srv->server_name);
610 if (srv->share_name) free(srv->share_name);
611 free(srv);
612 return NULL;
616 /*****************************************************
617 map a fd to a smbw_file structure
618 *******************************************************/
619 struct smbw_file *smbw_file(int fd)
621 struct smbw_file *file;
623 for (file=smbw_files;file;file=file->next) {
624 if (file->fd == fd) return file;
626 return NULL;
629 /*****************************************************
630 a wrapper for open()
631 *******************************************************/
632 int smbw_open(const char *fname, int flags, mode_t mode)
634 fstring server, share;
635 pstring path;
636 struct smbw_server *srv=NULL;
637 int eno=0, fd = -1;
638 struct smbw_file *file=NULL;
640 smbw_init();
642 if (!fname) {
643 errno = EINVAL;
644 return -1;
647 smbw_busy++;
649 /* work out what server they are after */
650 smbw_parse_path(fname, server, share, path);
652 /* get a connection to the server */
653 srv = smbw_server(server, share);
654 if (!srv) {
655 /* smbw_server sets errno */
656 goto failed;
659 if (path[strlen(path)-1] == '\\') {
660 fd = -1;
661 } else {
662 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
664 if (fd == -1) {
665 /* it might be a directory. Maybe we should use chkpath? */
666 eno = smbw_errno(&srv->cli);
667 fd = smbw_dir_open(fname);
668 if (fd == -1) errno = eno;
669 smbw_busy--;
670 return fd;
673 file = (struct smbw_file *)malloc(sizeof(*file));
674 if (!file) {
675 errno = ENOMEM;
676 goto failed;
679 ZERO_STRUCTP(file);
681 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
682 if (!file->f) {
683 errno = ENOMEM;
684 goto failed;
687 ZERO_STRUCTP(file->f);
689 file->f->cli_fd = fd;
690 file->f->fname = strdup(path);
691 if (!file->f->fname) {
692 errno = ENOMEM;
693 goto failed;
695 file->srv = srv;
696 file->fd = open(SMBW_DUMMY, O_WRONLY);
697 if (file->fd == -1) {
698 errno = EMFILE;
699 goto failed;
702 if (bitmap_query(smbw_file_bmap, file->fd)) {
703 DEBUG(0,("ERROR: fd used in smbw_open\n"));
704 errno = EIO;
705 goto failed;
708 file->f->ref_count=1;
710 bitmap_set(smbw_file_bmap, file->fd);
712 DLIST_ADD(smbw_files, file);
714 DEBUG(4,("opened %s\n", fname));
716 smbw_busy--;
717 return file->fd;
719 failed:
720 if (fd != -1) {
721 cli_close(&srv->cli, fd);
723 if (file) {
724 if (file->f) {
725 if (file->f->fname) {
726 free(file->f->fname);
728 free(file->f);
730 free(file);
732 smbw_busy--;
733 return -1;
737 /*****************************************************
738 a wrapper for pread()
739 *******************************************************/
740 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
742 struct smbw_file *file;
743 int ret;
745 smbw_busy++;
747 file = smbw_file(fd);
748 if (!file) {
749 errno = EBADF;
750 smbw_busy--;
751 return -1;
754 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
756 if (ret == -1) {
757 errno = smbw_errno(&file->srv->cli);
758 smbw_busy--;
759 return -1;
762 smbw_busy--;
763 return ret;
766 /*****************************************************
767 a wrapper for read()
768 *******************************************************/
769 ssize_t smbw_read(int fd, void *buf, size_t count)
771 struct smbw_file *file;
772 int ret;
774 DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
776 smbw_busy++;
778 file = smbw_file(fd);
779 if (!file) {
780 errno = EBADF;
781 smbw_busy--;
782 return -1;
785 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
786 file->f->offset, count);
788 if (ret == -1) {
789 errno = smbw_errno(&file->srv->cli);
790 smbw_busy--;
791 return -1;
794 file->f->offset += ret;
796 DEBUG(4,(" -> %d\n", ret));
798 smbw_busy--;
799 return ret;
804 /*****************************************************
805 a wrapper for write()
806 *******************************************************/
807 ssize_t smbw_write(int fd, void *buf, size_t count)
809 struct smbw_file *file;
810 int ret;
812 smbw_busy++;
814 file = smbw_file(fd);
815 if (!file) {
816 errno = EBADF;
817 smbw_busy--;
818 return -1;
821 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
823 if (ret == -1) {
824 errno = smbw_errno(&file->srv->cli);
825 smbw_busy--;
826 return -1;
829 file->f->offset += ret;
831 smbw_busy--;
832 return ret;
835 /*****************************************************
836 a wrapper for pwrite()
837 *******************************************************/
838 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
840 struct smbw_file *file;
841 int ret;
843 smbw_busy++;
845 file = smbw_file(fd);
846 if (!file) {
847 errno = EBADF;
848 smbw_busy--;
849 return -1;
852 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
854 if (ret == -1) {
855 errno = smbw_errno(&file->srv->cli);
856 smbw_busy--;
857 return -1;
860 smbw_busy--;
861 return ret;
864 /*****************************************************
865 a wrapper for close()
866 *******************************************************/
867 int smbw_close(int fd)
869 struct smbw_file *file;
871 smbw_busy++;
873 file = smbw_file(fd);
874 if (!file) {
875 int ret = smbw_dir_close(fd);
876 smbw_busy--;
877 return ret;
880 if (file->f->ref_count == 1 &&
881 !cli_close(&file->srv->cli, file->f->cli_fd)) {
882 errno = smbw_errno(&file->srv->cli);
883 smbw_busy--;
884 return -1;
888 bitmap_clear(smbw_file_bmap, file->fd);
889 close(file->fd);
891 DLIST_REMOVE(smbw_files, file);
893 file->f->ref_count--;
894 if (file->f->ref_count == 0) {
895 free(file->f->fname);
896 free(file->f);
898 ZERO_STRUCTP(file);
899 free(file);
901 smbw_busy--;
903 return 0;
907 /*****************************************************
908 a wrapper for fcntl()
909 *******************************************************/
910 int smbw_fcntl(int fd, int cmd, long arg)
912 return 0;
916 /*****************************************************
917 a wrapper for access()
918 *******************************************************/
919 int smbw_access(const char *name, int mode)
921 struct stat st;
923 DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
925 if (smbw_stat(name, &st)) return -1;
927 if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
928 ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
929 ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
930 errno = EACCES;
931 return -1;
934 return 0;
937 /*****************************************************
938 a wrapper for realink() - needed for correct errno setting
939 *******************************************************/
940 int smbw_readlink(const char *path, char *buf, size_t bufsize)
942 struct stat st;
943 int ret;
945 ret = smbw_stat(path, &st);
946 if (ret != 0) {
947 DEBUG(4,("readlink(%s) failed\n", path));
948 return -1;
951 /* it exists - say it isn't a link */
952 DEBUG(4,("readlink(%s) not a link\n", path));
954 errno = EINVAL;
955 return -1;
959 /*****************************************************
960 a wrapper for unlink()
961 *******************************************************/
962 int smbw_unlink(const char *fname)
964 struct smbw_server *srv;
965 fstring server, share;
966 pstring path;
968 if (!fname) {
969 errno = EINVAL;
970 return -1;
973 smbw_init();
975 smbw_busy++;
977 /* work out what server they are after */
978 smbw_parse_path(fname, server, share, path);
980 /* get a connection to the server */
981 srv = smbw_server(server, share);
982 if (!srv) {
983 /* smbw_server sets errno */
984 goto failed;
987 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
988 int job = smbw_stat_printjob(srv, path, NULL, NULL);
989 if (job == -1) {
990 goto failed;
992 if (cli_printjob_del(&srv->cli, job) != 0) {
993 goto failed;
995 } else if (!cli_unlink(&srv->cli, path)) {
996 errno = smbw_errno(&srv->cli);
997 goto failed;
1000 smbw_busy--;
1001 return 0;
1003 failed:
1004 smbw_busy--;
1005 return -1;
1009 /*****************************************************
1010 a wrapper for rename()
1011 *******************************************************/
1012 int smbw_rename(const char *oldname, const char *newname)
1014 struct smbw_server *srv;
1015 fstring server1, share1;
1016 pstring path1;
1017 fstring server2, share2;
1018 pstring path2;
1020 if (!oldname || !newname) {
1021 errno = EINVAL;
1022 return -1;
1025 smbw_init();
1027 DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
1029 smbw_busy++;
1031 /* work out what server they are after */
1032 smbw_parse_path(oldname, server1, share1, path1);
1033 smbw_parse_path(newname, server2, share2, path2);
1035 if (strcmp(server1, server2) || strcmp(share1, share2)) {
1036 /* can't cross filesystems */
1037 errno = EXDEV;
1038 return -1;
1041 /* get a connection to the server */
1042 srv = smbw_server(server1, share1);
1043 if (!srv) {
1044 /* smbw_server sets errno */
1045 goto failed;
1048 if (!cli_rename(&srv->cli, path1, path2)) {
1049 int eno = smbw_errno(&srv->cli);
1050 if (eno != EEXIST ||
1051 !cli_unlink(&srv->cli, path2) ||
1052 !cli_rename(&srv->cli, path1, path2)) {
1053 errno = eno;
1054 goto failed;
1058 smbw_busy--;
1059 return 0;
1061 failed:
1062 smbw_busy--;
1063 return -1;
1067 /*****************************************************
1068 a wrapper for utime and utimes
1069 *******************************************************/
1070 static int smbw_settime(const char *fname, time_t t)
1072 struct smbw_server *srv;
1073 fstring server, share;
1074 pstring path;
1075 uint16 mode;
1077 if (!fname) {
1078 errno = EINVAL;
1079 return -1;
1082 smbw_init();
1084 smbw_busy++;
1086 /* work out what server they are after */
1087 smbw_parse_path(fname, server, share, path);
1089 /* get a connection to the server */
1090 srv = smbw_server(server, share);
1091 if (!srv) {
1092 /* smbw_server sets errno */
1093 goto failed;
1096 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1097 errno = smbw_errno(&srv->cli);
1098 goto failed;
1101 if (!cli_setatr(&srv->cli, path, mode, t)) {
1102 /* some servers always refuse directory changes */
1103 if (!(mode & aDIR)) {
1104 errno = smbw_errno(&srv->cli);
1105 goto failed;
1109 smbw_busy--;
1110 return 0;
1112 failed:
1113 smbw_busy--;
1114 return -1;
1117 /*****************************************************
1118 a wrapper for utime
1119 *******************************************************/
1120 int smbw_utime(const char *fname, void *buf)
1122 struct utimbuf *tbuf = (struct utimbuf *)buf;
1123 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1126 /*****************************************************
1127 a wrapper for utime
1128 *******************************************************/
1129 int smbw_utimes(const char *fname, void *buf)
1131 struct timeval *tbuf = (struct timeval *)buf;
1132 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1136 /*****************************************************
1137 a wrapper for chown()
1138 *******************************************************/
1139 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1141 struct smbw_server *srv;
1142 fstring server, share;
1143 pstring path;
1144 uint16 mode;
1146 if (!fname) {
1147 errno = EINVAL;
1148 return -1;
1151 smbw_init();
1153 smbw_busy++;
1155 /* work out what server they are after */
1156 smbw_parse_path(fname, server, share, path);
1158 /* get a connection to the server */
1159 srv = smbw_server(server, share);
1160 if (!srv) {
1161 /* smbw_server sets errno */
1162 goto failed;
1165 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1166 errno = smbw_errno(&srv->cli);
1167 goto failed;
1170 /* assume success */
1172 smbw_busy--;
1173 return 0;
1175 failed:
1176 smbw_busy--;
1177 return -1;
1180 /*****************************************************
1181 a wrapper for chmod()
1182 *******************************************************/
1183 int smbw_chmod(const char *fname, mode_t newmode)
1185 struct smbw_server *srv;
1186 fstring server, share;
1187 pstring path;
1188 uint32 mode;
1190 if (!fname) {
1191 errno = EINVAL;
1192 return -1;
1195 smbw_init();
1197 smbw_busy++;
1199 /* work out what server they are after */
1200 smbw_parse_path(fname, server, share, path);
1202 /* get a connection to the server */
1203 srv = smbw_server(server, share);
1204 if (!srv) {
1205 /* smbw_server sets errno */
1206 goto failed;
1209 mode = 0;
1211 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1212 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1213 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1214 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1216 if (!cli_setatr(&srv->cli, path, mode, 0)) {
1217 errno = smbw_errno(&srv->cli);
1218 goto failed;
1221 smbw_busy--;
1222 return 0;
1224 failed:
1225 smbw_busy--;
1226 return -1;
1229 /*****************************************************
1230 a wrapper for lseek()
1231 *******************************************************/
1232 off_t smbw_lseek(int fd, off_t offset, int whence)
1234 struct smbw_file *file;
1235 size_t size;
1237 smbw_busy++;
1239 file = smbw_file(fd);
1240 if (!file) {
1241 off_t ret = smbw_dir_lseek(fd, offset, whence);
1242 smbw_busy--;
1243 return ret;
1246 switch (whence) {
1247 case SEEK_SET:
1248 file->f->offset = offset;
1249 break;
1250 case SEEK_CUR:
1251 file->f->offset += offset;
1252 break;
1253 case SEEK_END:
1254 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1255 NULL, &size, NULL, NULL, NULL,
1256 NULL, NULL) &&
1257 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1258 NULL, &size, NULL, NULL, NULL)) {
1259 errno = EINVAL;
1260 smbw_busy--;
1261 return -1;
1263 file->f->offset = size + offset;
1264 break;
1267 smbw_busy--;
1268 return file->f->offset;
1272 /*****************************************************
1273 a wrapper for dup()
1274 *******************************************************/
1275 int smbw_dup(int fd)
1277 int fd2;
1278 struct smbw_file *file, *file2;
1280 smbw_busy++;
1282 file = smbw_file(fd);
1283 if (!file) {
1284 errno = EBADF;
1285 goto failed;
1288 fd2 = dup(file->fd);
1289 if (fd2 == -1) {
1290 goto failed;
1293 if (bitmap_query(smbw_file_bmap, fd2)) {
1294 DEBUG(0,("ERROR: fd already open in dup!\n"));
1295 errno = EIO;
1296 goto failed;
1299 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1300 if (!file2) {
1301 close(fd2);
1302 errno = ENOMEM;
1303 goto failed;
1306 ZERO_STRUCTP(file2);
1308 *file2 = *file;
1309 file2->fd = fd2;
1311 file->f->ref_count++;
1313 bitmap_set(smbw_file_bmap, fd2);
1315 DLIST_ADD(smbw_files, file2);
1317 smbw_busy--;
1318 return fd2;
1320 failed:
1321 smbw_busy--;
1322 return -1;
1326 /*****************************************************
1327 a wrapper for dup2()
1328 *******************************************************/
1329 int smbw_dup2(int fd, int fd2)
1331 struct smbw_file *file, *file2;
1333 smbw_busy++;
1335 file = smbw_file(fd);
1336 if (!file) {
1337 errno = EBADF;
1338 goto failed;
1341 if (bitmap_query(smbw_file_bmap, fd2)) {
1342 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1343 errno = EIO;
1344 goto failed;
1347 if (dup2(file->fd, fd2) != fd2) {
1348 goto failed;
1351 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1352 if (!file2) {
1353 close(fd2);
1354 errno = ENOMEM;
1355 goto failed;
1358 ZERO_STRUCTP(file2);
1360 *file2 = *file;
1361 file2->fd = fd2;
1363 file->f->ref_count++;
1365 bitmap_set(smbw_file_bmap, fd2);
1367 DLIST_ADD(smbw_files, file2);
1369 smbw_busy--;
1370 return fd2;
1372 failed:
1373 smbw_busy--;
1374 return -1;
1378 /*****************************************************
1379 close a connection to a server
1380 *******************************************************/
1381 static void smbw_srv_close(struct smbw_server *srv)
1383 smbw_busy++;
1385 cli_shutdown(&srv->cli);
1387 free(srv->server_name);
1388 free(srv->share_name);
1390 DLIST_REMOVE(smbw_srvs, srv);
1392 ZERO_STRUCTP(srv);
1394 free(srv);
1396 smbw_busy--;
1399 /*****************************************************
1400 when we fork we have to close all connections and files
1401 in the child
1402 *******************************************************/
1403 int smbw_fork(void)
1405 pid_t child;
1406 int p[2];
1407 char c=0;
1408 pstring line;
1410 struct smbw_file *file, *next_file;
1411 struct smbw_server *srv, *next_srv;
1413 if (pipe(p)) return real_fork();
1415 child = real_fork();
1417 if (child) {
1418 /* block the parent for a moment until the sockets are
1419 closed */
1420 close(p[1]);
1421 read(p[0], &c, 1);
1422 close(p[0]);
1423 return child;
1426 close(p[0]);
1428 /* close all files */
1429 for (file=smbw_files;file;file=next_file) {
1430 next_file = file->next;
1431 close(file->fd);
1434 /* close all server connections */
1435 for (srv=smbw_srvs;srv;srv=next_srv) {
1436 next_srv = srv->next;
1437 smbw_srv_close(srv);
1440 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
1441 smbw_setshared(line,smbw_cwd);
1443 /* unblock the parent */
1444 write(p[1], &c, 1);
1445 close(p[1]);
1447 /* and continue in the child */
1448 return 0;
1451 #ifndef NO_ACL_WRAPPER
1452 /*****************************************************
1453 say no to acls
1454 *******************************************************/
1455 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1457 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1458 errno = ENOSYS;
1459 return -1;
1461 #endif
1463 #ifndef NO_FACL_WRAPPER
1464 /*****************************************************
1465 say no to acls
1466 *******************************************************/
1467 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1469 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1470 errno = ENOSYS;
1471 return -1;
1473 #endif
1475 #ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
1476 #ifdef HAVE_STAT64
1477 /* this can't be in wrapped.c because of include conflicts */
1478 void stat64_convert(struct stat *st, struct stat64 *st64)
1480 st64->st_size = st->st_size;
1481 st64->st_mode = st->st_mode;
1482 st64->st_ino = st->st_ino;
1483 st64->st_dev = st->st_dev;
1484 st64->st_rdev = st->st_rdev;
1485 st64->st_nlink = st->st_nlink;
1486 st64->st_uid = st->st_uid;
1487 st64->st_gid = st->st_gid;
1488 st64->st_atime = st->st_atime;
1489 st64->st_mtime = st->st_mtime;
1490 st64->st_ctime = st->st_ctime;
1491 st64->st_blksize = st->st_blksize;
1492 st64->st_blocks = st->st_blocks;
1494 #endif
1496 #ifdef HAVE_READDIR64
1497 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1499 d64->d_ino = d->d_ino;
1500 d64->d_off = d->d_off;
1501 d64->d_reclen = d->d_reclen;
1502 pstrcpy(d64->d_name, d->d_name);
1504 #endif
1505 #endif
1508 #ifdef HAVE___XSTAT
1509 /* Definition of `struct stat' used in the linux kernel.. */
1510 struct kernel_stat {
1511 unsigned short int st_dev;
1512 unsigned short int __pad1;
1513 unsigned long int st_ino;
1514 unsigned short int st_mode;
1515 unsigned short int st_nlink;
1516 unsigned short int st_uid;
1517 unsigned short int st_gid;
1518 unsigned short int st_rdev;
1519 unsigned short int __pad2;
1520 unsigned long int st_size;
1521 unsigned long int st_blksize;
1522 unsigned long int st_blocks;
1523 unsigned long int st_atime;
1524 unsigned long int __unused1;
1525 unsigned long int st_mtime;
1526 unsigned long int __unused2;
1527 unsigned long int st_ctime;
1528 unsigned long int __unused3;
1529 unsigned long int __unused4;
1530 unsigned long int __unused5;
1534 * Prototype for gcc in 'fussy' mode.
1536 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1537 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1539 #ifdef _STAT_VER_LINUX_OLD
1540 if (vers == _STAT_VER_LINUX_OLD) {
1541 memcpy(st, kbuf, sizeof(*st));
1542 return;
1544 #endif
1546 ZERO_STRUCTP(st);
1548 st->st_dev = kbuf->st_dev;
1549 st->st_ino = kbuf->st_ino;
1550 st->st_mode = kbuf->st_mode;
1551 st->st_nlink = kbuf->st_nlink;
1552 st->st_uid = kbuf->st_uid;
1553 st->st_gid = kbuf->st_gid;
1554 st->st_rdev = kbuf->st_rdev;
1555 st->st_size = kbuf->st_size;
1556 st->st_blksize = kbuf->st_blksize;
1557 st->st_blocks = kbuf->st_blocks;
1558 st->st_atime = kbuf->st_atime;
1559 st->st_mtime = kbuf->st_mtime;
1560 st->st_ctime = kbuf->st_ctime;
1562 #endif