merge from 2.2
[Samba/gbeck.git] / source / smbwrapper / smbw.c
blob95739bac5a1edfba58d5520a2ce6e4643673b861
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 char *p;
51 int eno;
52 pstring line;
54 if (initialised) return;
55 initialised = 1;
57 eno = errno;
59 smbw_busy++;
61 DEBUGLEVEL = 0;
62 setup_logging("smbsh",True);
64 dbf = x_stderr;
66 if ((p=smbw_getshared("LOGFILE"))) {
67 dbf = sys_fopen(p, "a");
70 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
71 if (!smbw_file_bmap) {
72 exit(1);
75 in_client = True;
77 load_interfaces();
79 if ((p=smbw_getshared("SERVICESF"))) {
80 pstrcpy(servicesf, p);
83 lp_load(servicesf,True,False,False);
85 charset_initialise();
87 get_myname(global_myname);
89 if ((p=smbw_getshared("DEBUG"))) {
90 DEBUGLEVEL = atoi(p);
93 if ((p=smbw_getshared("RESOLVE_ORDER"))) {
94 lp_set_name_resolve_order(p);
97 if ((p=smbw_getshared("PREFIX"))) {
98 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
99 all_string_sub(smbw_prefix,"//", "/", 0);
100 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
103 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
105 p = smbw_getshared(line);
106 if (!p) {
107 sys_getwd(smbw_cwd);
109 pstrcpy(smbw_cwd, p);
110 DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
112 smbw_busy--;
114 set_maxfiles(SMBW_MAX_OPEN);
116 BlockSignals(True,SIGPIPE);
118 errno = eno;
121 /*****************************************************
122 determine if a file descriptor is a smb one
123 *******************************************************/
124 int smbw_fd(int fd)
126 if (smbw_busy) return 0;
127 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
130 /*****************************************************
131 determine if a file descriptor is an internal smbw fd
132 *******************************************************/
133 int smbw_local_fd(int fd)
135 struct smbw_server *srv;
137 smbw_init();
139 if (smbw_busy) return 0;
140 if (smbw_shared_fd(fd)) return 1;
142 for (srv=smbw_srvs;srv;srv=srv->next) {
143 if (srv->cli.fd == fd) return 1;
146 return 0;
149 /*****************************************************
150 a crude inode number generator
151 *******************************************************/
152 ino_t smbw_inode(const char *name)
154 if (!*name) return 2;
155 return (ino_t)str_checksum(name);
158 /*****************************************************
159 remove redundent stuff from a filename
160 *******************************************************/
161 void clean_fname(char *name)
163 char *p, *p2;
164 int l;
165 int modified = 1;
167 if (!name) return;
169 while (modified) {
170 modified = 0;
172 DEBUG(5,("cleaning %s\n", name));
174 if ((p=strstr(name,"/./"))) {
175 modified = 1;
176 while (*p) {
177 p[0] = p[2];
178 p++;
182 if ((p=strstr(name,"//"))) {
183 modified = 1;
184 while (*p) {
185 p[0] = p[1];
186 p++;
190 if (strcmp(name,"/../")==0) {
191 modified = 1;
192 name[1] = 0;
195 if ((p=strstr(name,"/../"))) {
196 modified = 1;
197 for (p2=(p>name?p-1:p);p2>name;p2--) {
198 if (p2[0] == '/') break;
200 while (*p2) {
201 p2[0] = p2[3];
202 p2++;
206 if (strcmp(name,"/..")==0) {
207 modified = 1;
208 name[1] = 0;
211 l = strlen(name);
212 p = l>=3?(name+l-3):name;
213 if (strcmp(p,"/..")==0) {
214 modified = 1;
215 for (p2=p-1;p2>name;p2--) {
216 if (p2[0] == '/') break;
218 if (p2==name) {
219 p[0] = '/';
220 p[1] = 0;
221 } else {
222 p2[0] = 0;
226 l = strlen(name);
227 p = l>=2?(name+l-2):name;
228 if (strcmp(p,"/.")==0) {
229 if (p == name) {
230 p[1] = 0;
231 } else {
232 p[0] = 0;
236 if (strncmp(p=name,"./",2) == 0) {
237 modified = 1;
238 do {
239 p[0] = p[2];
240 } while (*p++);
243 l = strlen(p=name);
244 if (l > 1 && p[l-1] == '/') {
245 modified = 1;
246 p[l-1] = 0;
253 /*****************************************************
254 find a workgroup (any workgroup!) that has a master
255 browser on the local network
256 *******************************************************/
257 static char *smbw_find_workgroup(void)
259 fstring server;
260 char *p;
261 struct in_addr *ip_list = NULL;
262 int count = 0;
263 int i;
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;
278 for (i=0;i<count;i++) {
279 static fstring name;
280 if (name_status_find(0x1d, ip_list[i], name)) {
281 slprintf(server, sizeof(server), "%s#1D", name);
282 if (smbw_server(server, "IPC$")) {
283 smbw_setshared("WORKGROUP", name);
284 free(ip_list);
285 return name;
290 free(ip_list);
292 return p;
295 /*****************************************************
296 parse a smb path into its components.
297 server is one of
298 1) the name of the SMB server
299 2) WORKGROUP#1D for share listing
300 3) WORKGROUP#__ for workgroup listing
301 share is the share on the server to query
302 path is the SMB path on the server
303 return the full path (ie. add cwd if needed)
304 *******************************************************/
305 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
307 static pstring s;
308 char *p;
309 int len;
310 fstring workgroup;
312 /* add cwd if necessary */
313 if (fname[0] != '/') {
314 slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
315 } else {
316 pstrcpy(s, fname);
318 clean_fname(s);
320 /* see if it has the right prefix */
321 len = strlen(smbw_prefix)-1;
322 if (strncmp(s,smbw_prefix,len) ||
323 (s[len] != '/' && s[len] != 0)) return s;
325 /* ok, its for us. Now parse out the workgroup, share etc. */
326 p = s+len;
327 if (*p == '/') p++;
328 if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
329 /* we're in /smb - give a list of workgroups */
330 slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
331 fstrcpy(share,"IPC$");
332 pstrcpy(path,"");
333 return s;
336 if (!next_token(&p, server, "/", sizeof(fstring))) {
337 /* we are in /smb/WORKGROUP */
338 slprintf(server,sizeof(fstring), "%s#1D", workgroup);
339 fstrcpy(share,"IPC$");
340 pstrcpy(path,"");
343 if (!next_token(&p, share, "/", sizeof(fstring))) {
344 /* we are in /smb/WORKGROUP/SERVER */
345 fstrcpy(share,"IPC$");
346 pstrcpy(path,"");
349 pstrcpy(path, p);
351 all_string_sub(path, "/", "\\", 0);
353 return s;
356 /*****************************************************
357 determine if a path name (possibly relative) is in the
358 smb name space
359 *******************************************************/
360 int smbw_path(const char *path)
362 fstring server, share;
363 pstring s;
364 char *cwd;
365 int len;
367 if(!path)
368 return 0;
370 /* this is needed to prevent recursion with the BSD malloc which
371 opens /etc/malloc.conf on the first call */
372 if (strncmp(path,"/etc/", 5) == 0) {
373 return 0;
376 smbw_init();
378 len = strlen(smbw_prefix)-1;
380 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
381 return 0;
384 if (smbw_busy) return 0;
386 DEBUG(3,("smbw_path(%s)\n", path));
388 cwd = smbw_parse_path(path, server, share, s);
390 if (strncmp(cwd,smbw_prefix,len) == 0 &&
391 (cwd[len] == '/' || cwd[len] == 0)) {
392 return 1;
395 return 0;
398 /*****************************************************
399 return a unix errno from a SMB error pair
400 *******************************************************/
401 int smbw_errno(struct cli_state *c)
403 uint8 eclass;
404 uint32 ecode;
405 int ret;
407 ret = cli_error(c, &eclass, &ecode, NULL);
409 if (ret) {
410 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
411 (int)eclass, (int)ecode, (int)ecode, ret));
413 return ret;
416 /* Return a username and password given a server and share name */
418 void get_envvar_auth_data(char *server, char *share, char **workgroup,
419 char **username, char **password)
421 /* Fall back to shared memory/environment variables */
423 *username = smbw_getshared("USER");
424 if (!*username) *username = getenv("USER");
425 if (!*username) *username = "guest";
427 *workgroup = smbw_getshared("WORKGROUP");
428 if (!*workgroup) *workgroup = lp_workgroup();
430 *password = smbw_getshared("PASSWORD");
431 if (!*password) *password = "";
434 static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
436 /*****************************************************
437 set the get auth data function
438 ******************************************************/
439 void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
441 get_auth_data_fn = fn;
444 /*****************************************************
445 return a connection to a server (existing or new)
446 *******************************************************/
447 struct smbw_server *smbw_server(char *server, char *share)
449 struct smbw_server *srv=NULL;
450 struct cli_state c;
451 char *username;
452 char *password;
453 char *workgroup;
454 struct nmb_name called, calling;
455 char *p, *server_n = server;
456 fstring group;
457 pstring ipenv;
458 struct in_addr ip;
459 extern struct in_addr ipzero;
461 ip = ipzero;
462 ZERO_STRUCT(c);
464 get_auth_data_fn(server, share, &workgroup, &username, &password);
466 /* try to use an existing connection */
467 for (srv=smbw_srvs;srv;srv=srv->next) {
468 if (strcmp(server,srv->server_name)==0 &&
469 strcmp(share,srv->share_name)==0 &&
470 strcmp(workgroup,srv->workgroup)==0 &&
471 strcmp(username, srv->username) == 0)
472 return srv;
475 if (server[0] == 0) {
476 errno = EPERM;
477 return NULL;
480 make_nmb_name(&calling, global_myname, 0x0);
481 make_nmb_name(&called , server, 0x20);
483 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
485 if ((p=strchr_m(server_n,'#')) &&
486 (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
487 struct in_addr sip;
488 pstring s;
490 fstrcpy(group, server_n);
491 p = strchr_m(group,'#');
492 *p = 0;
494 /* cache the workgroup master lookup */
495 slprintf(s,sizeof(s)-1,"MASTER_%s", group);
496 if (!(server_n = smbw_getshared(s))) {
497 if (!find_master_ip(group, &sip)) {
498 errno = ENOENT;
499 return NULL;
501 fstrcpy(group, inet_ntoa(sip));
502 server_n = group;
503 smbw_setshared(s,server_n);
507 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
509 again:
510 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
512 ip = ipzero;
513 if ((p=smbw_getshared(ipenv))) {
514 ip = *(interpret_addr2(p));
517 /* have to open a new connection */
518 if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
519 errno = ENOENT;
520 return NULL;
523 if (!cli_session_request(&c, &calling, &called)) {
524 cli_shutdown(&c);
525 if (strcmp(called.name, "*SMBSERVER")) {
526 make_nmb_name(&called , "*SMBSERVER", 0x20);
527 goto again;
529 errno = ENOENT;
530 return NULL;
533 DEBUG(4,(" session request ok\n"));
535 if (!cli_negprot(&c)) {
536 cli_shutdown(&c);
537 errno = ENOENT;
538 return NULL;
541 if (!cli_session_setup(&c, username,
542 password, strlen(password),
543 password, strlen(password),
544 workgroup) &&
545 /* try an anonymous login if it failed */
546 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
547 cli_shutdown(&c);
548 errno = EPERM;
549 return NULL;
552 DEBUG(4,(" session setup ok\n"));
554 if (!cli_send_tconX(&c, share, "?????",
555 password, strlen(password)+1)) {
556 errno = smbw_errno(&c);
557 cli_shutdown(&c);
558 return NULL;
561 smbw_setshared(ipenv,inet_ntoa(ip));
563 DEBUG(4,(" tconx ok\n"));
565 srv = (struct smbw_server *)malloc(sizeof(*srv));
566 if (!srv) {
567 errno = ENOMEM;
568 goto failed;
571 ZERO_STRUCTP(srv);
573 srv->cli = c;
575 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
577 srv->server_name = strdup(server);
578 if (!srv->server_name) {
579 errno = ENOMEM;
580 goto failed;
583 srv->share_name = strdup(share);
584 if (!srv->share_name) {
585 errno = ENOMEM;
586 goto failed;
589 srv->workgroup = strdup(workgroup);
590 if (!srv->workgroup) {
591 errno = ENOMEM;
592 goto failed;
595 srv->username = strdup(username);
596 if (!srv->username) {
597 errno = ENOMEM;
598 goto failed;
601 /* some programs play with file descriptors fairly intimately. We
602 try to get out of the way by duping to a high fd number */
603 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
604 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
605 srv->cli.fd+SMBW_CLI_FD) {
606 close(srv->cli.fd);
607 srv->cli.fd += SMBW_CLI_FD;
611 DLIST_ADD(smbw_srvs, srv);
613 return srv;
615 failed:
616 cli_shutdown(&c);
617 if (!srv) return NULL;
619 if (srv->server_name) free(srv->server_name);
620 if (srv->share_name) free(srv->share_name);
621 free(srv);
622 return NULL;
626 /*****************************************************
627 map a fd to a smbw_file structure
628 *******************************************************/
629 struct smbw_file *smbw_file(int fd)
631 struct smbw_file *file;
633 for (file=smbw_files;file;file=file->next) {
634 if (file->fd == fd) return file;
636 return NULL;
639 /*****************************************************
640 a wrapper for open()
641 *******************************************************/
642 int smbw_open(const char *fname, int flags, mode_t mode)
644 fstring server, share;
645 pstring path;
646 struct smbw_server *srv=NULL;
647 int eno=0, fd = -1;
648 struct smbw_file *file=NULL;
650 smbw_init();
652 if (!fname) {
653 errno = EINVAL;
654 return -1;
657 smbw_busy++;
659 /* work out what server they are after */
660 smbw_parse_path(fname, server, share, path);
662 /* get a connection to the server */
663 srv = smbw_server(server, share);
664 if (!srv) {
665 /* smbw_server sets errno */
666 goto failed;
669 if (path[strlen(path)-1] == '\\') {
670 fd = -1;
671 } else {
672 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
674 if (fd == -1) {
675 /* it might be a directory. Maybe we should use chkpath? */
676 eno = smbw_errno(&srv->cli);
677 fd = smbw_dir_open(fname);
678 if (fd == -1) errno = eno;
679 smbw_busy--;
680 return fd;
683 file = (struct smbw_file *)malloc(sizeof(*file));
684 if (!file) {
685 errno = ENOMEM;
686 goto failed;
689 ZERO_STRUCTP(file);
691 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
692 if (!file->f) {
693 errno = ENOMEM;
694 goto failed;
697 ZERO_STRUCTP(file->f);
699 file->f->cli_fd = fd;
700 file->f->fname = strdup(path);
701 if (!file->f->fname) {
702 errno = ENOMEM;
703 goto failed;
705 file->srv = srv;
706 file->fd = open(SMBW_DUMMY, O_WRONLY);
707 if (file->fd == -1) {
708 errno = EMFILE;
709 goto failed;
712 if (bitmap_query(smbw_file_bmap, file->fd)) {
713 DEBUG(0,("ERROR: fd used in smbw_open\n"));
714 errno = EIO;
715 goto failed;
718 file->f->ref_count=1;
720 bitmap_set(smbw_file_bmap, file->fd);
722 DLIST_ADD(smbw_files, file);
724 DEBUG(4,("opened %s\n", fname));
726 smbw_busy--;
727 return file->fd;
729 failed:
730 if (fd != -1) {
731 cli_close(&srv->cli, fd);
733 if (file) {
734 if (file->f) {
735 if (file->f->fname) {
736 free(file->f->fname);
738 free(file->f);
740 free(file);
742 smbw_busy--;
743 return -1;
747 /*****************************************************
748 a wrapper for pread()
749 *******************************************************/
750 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
752 struct smbw_file *file;
753 int ret;
755 smbw_busy++;
757 file = smbw_file(fd);
758 if (!file) {
759 errno = EBADF;
760 smbw_busy--;
761 return -1;
764 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
766 if (ret == -1) {
767 errno = smbw_errno(&file->srv->cli);
768 smbw_busy--;
769 return -1;
772 smbw_busy--;
773 return ret;
776 /*****************************************************
777 a wrapper for read()
778 *******************************************************/
779 ssize_t smbw_read(int fd, void *buf, size_t count)
781 struct smbw_file *file;
782 int ret;
784 DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
786 smbw_busy++;
788 file = smbw_file(fd);
789 if (!file) {
790 errno = EBADF;
791 smbw_busy--;
792 return -1;
795 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
796 file->f->offset, count);
798 if (ret == -1) {
799 errno = smbw_errno(&file->srv->cli);
800 smbw_busy--;
801 return -1;
804 file->f->offset += ret;
806 DEBUG(4,(" -> %d\n", ret));
808 smbw_busy--;
809 return ret;
814 /*****************************************************
815 a wrapper for write()
816 *******************************************************/
817 ssize_t smbw_write(int fd, void *buf, size_t count)
819 struct smbw_file *file;
820 int ret;
822 smbw_busy++;
824 file = smbw_file(fd);
825 if (!file) {
826 errno = EBADF;
827 smbw_busy--;
828 return -1;
831 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
833 if (ret == -1) {
834 errno = smbw_errno(&file->srv->cli);
835 smbw_busy--;
836 return -1;
839 file->f->offset += ret;
841 smbw_busy--;
842 return ret;
845 /*****************************************************
846 a wrapper for pwrite()
847 *******************************************************/
848 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
850 struct smbw_file *file;
851 int ret;
853 smbw_busy++;
855 file = smbw_file(fd);
856 if (!file) {
857 errno = EBADF;
858 smbw_busy--;
859 return -1;
862 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
864 if (ret == -1) {
865 errno = smbw_errno(&file->srv->cli);
866 smbw_busy--;
867 return -1;
870 smbw_busy--;
871 return ret;
874 /*****************************************************
875 a wrapper for close()
876 *******************************************************/
877 int smbw_close(int fd)
879 struct smbw_file *file;
881 smbw_busy++;
883 file = smbw_file(fd);
884 if (!file) {
885 int ret = smbw_dir_close(fd);
886 smbw_busy--;
887 return ret;
890 if (file->f->ref_count == 1 &&
891 !cli_close(&file->srv->cli, file->f->cli_fd)) {
892 errno = smbw_errno(&file->srv->cli);
893 smbw_busy--;
894 return -1;
898 bitmap_clear(smbw_file_bmap, file->fd);
899 close(file->fd);
901 DLIST_REMOVE(smbw_files, file);
903 file->f->ref_count--;
904 if (file->f->ref_count == 0) {
905 free(file->f->fname);
906 free(file->f);
908 ZERO_STRUCTP(file);
909 free(file);
911 smbw_busy--;
913 return 0;
917 /*****************************************************
918 a wrapper for fcntl()
919 *******************************************************/
920 int smbw_fcntl(int fd, int cmd, long arg)
922 return 0;
926 /*****************************************************
927 a wrapper for access()
928 *******************************************************/
929 int smbw_access(const char *name, int mode)
931 struct stat st;
933 DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
935 if (smbw_stat(name, &st)) return -1;
937 if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
938 ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
939 ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
940 errno = EACCES;
941 return -1;
944 return 0;
947 /*****************************************************
948 a wrapper for realink() - needed for correct errno setting
949 *******************************************************/
950 int smbw_readlink(const char *path, char *buf, size_t bufsize)
952 struct stat st;
953 int ret;
955 ret = smbw_stat(path, &st);
956 if (ret != 0) {
957 DEBUG(4,("readlink(%s) failed\n", path));
958 return -1;
961 /* it exists - say it isn't a link */
962 DEBUG(4,("readlink(%s) not a link\n", path));
964 errno = EINVAL;
965 return -1;
969 /*****************************************************
970 a wrapper for unlink()
971 *******************************************************/
972 int smbw_unlink(const char *fname)
974 struct smbw_server *srv;
975 fstring server, share;
976 pstring path;
978 if (!fname) {
979 errno = EINVAL;
980 return -1;
983 smbw_init();
985 smbw_busy++;
987 /* work out what server they are after */
988 smbw_parse_path(fname, server, share, path);
990 /* get a connection to the server */
991 srv = smbw_server(server, share);
992 if (!srv) {
993 /* smbw_server sets errno */
994 goto failed;
997 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
998 int job = smbw_stat_printjob(srv, path, NULL, NULL);
999 if (job == -1) {
1000 goto failed;
1002 if (cli_printjob_del(&srv->cli, job) != 0) {
1003 goto failed;
1005 } else if (!cli_unlink(&srv->cli, path)) {
1006 errno = smbw_errno(&srv->cli);
1007 goto failed;
1010 smbw_busy--;
1011 return 0;
1013 failed:
1014 smbw_busy--;
1015 return -1;
1019 /*****************************************************
1020 a wrapper for rename()
1021 *******************************************************/
1022 int smbw_rename(const char *oldname, const char *newname)
1024 struct smbw_server *srv;
1025 fstring server1, share1;
1026 pstring path1;
1027 fstring server2, share2;
1028 pstring path2;
1030 if (!oldname || !newname) {
1031 errno = EINVAL;
1032 return -1;
1035 smbw_init();
1037 DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
1039 smbw_busy++;
1041 /* work out what server they are after */
1042 smbw_parse_path(oldname, server1, share1, path1);
1043 smbw_parse_path(newname, server2, share2, path2);
1045 if (strcmp(server1, server2) || strcmp(share1, share2)) {
1046 /* can't cross filesystems */
1047 errno = EXDEV;
1048 return -1;
1051 /* get a connection to the server */
1052 srv = smbw_server(server1, share1);
1053 if (!srv) {
1054 /* smbw_server sets errno */
1055 goto failed;
1058 if (!cli_rename(&srv->cli, path1, path2)) {
1059 int eno = smbw_errno(&srv->cli);
1060 if (eno != EEXIST ||
1061 !cli_unlink(&srv->cli, path2) ||
1062 !cli_rename(&srv->cli, path1, path2)) {
1063 errno = eno;
1064 goto failed;
1068 smbw_busy--;
1069 return 0;
1071 failed:
1072 smbw_busy--;
1073 return -1;
1077 /*****************************************************
1078 a wrapper for utime and utimes
1079 *******************************************************/
1080 static int smbw_settime(const char *fname, time_t t)
1082 struct smbw_server *srv;
1083 fstring server, share;
1084 pstring path;
1085 uint16 mode;
1087 if (!fname) {
1088 errno = EINVAL;
1089 return -1;
1092 smbw_init();
1094 smbw_busy++;
1096 /* work out what server they are after */
1097 smbw_parse_path(fname, server, share, path);
1099 /* get a connection to the server */
1100 srv = smbw_server(server, share);
1101 if (!srv) {
1102 /* smbw_server sets errno */
1103 goto failed;
1106 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1107 errno = smbw_errno(&srv->cli);
1108 goto failed;
1111 if (!cli_setatr(&srv->cli, path, mode, t)) {
1112 /* some servers always refuse directory changes */
1113 if (!(mode & aDIR)) {
1114 errno = smbw_errno(&srv->cli);
1115 goto failed;
1119 smbw_busy--;
1120 return 0;
1122 failed:
1123 smbw_busy--;
1124 return -1;
1127 /*****************************************************
1128 a wrapper for utime
1129 *******************************************************/
1130 int smbw_utime(const char *fname, void *buf)
1132 struct utimbuf *tbuf = (struct utimbuf *)buf;
1133 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1136 /*****************************************************
1137 a wrapper for utime
1138 *******************************************************/
1139 int smbw_utimes(const char *fname, void *buf)
1141 struct timeval *tbuf = (struct timeval *)buf;
1142 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1146 /*****************************************************
1147 a wrapper for chown()
1148 *******************************************************/
1149 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1151 struct smbw_server *srv;
1152 fstring server, share;
1153 pstring path;
1154 uint16 mode;
1156 if (!fname) {
1157 errno = EINVAL;
1158 return -1;
1161 smbw_init();
1163 smbw_busy++;
1165 /* work out what server they are after */
1166 smbw_parse_path(fname, server, share, path);
1168 /* get a connection to the server */
1169 srv = smbw_server(server, share);
1170 if (!srv) {
1171 /* smbw_server sets errno */
1172 goto failed;
1175 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1176 errno = smbw_errno(&srv->cli);
1177 goto failed;
1180 /* assume success */
1182 smbw_busy--;
1183 return 0;
1185 failed:
1186 smbw_busy--;
1187 return -1;
1190 /*****************************************************
1191 a wrapper for chmod()
1192 *******************************************************/
1193 int smbw_chmod(const char *fname, mode_t newmode)
1195 struct smbw_server *srv;
1196 fstring server, share;
1197 pstring path;
1198 uint32 mode;
1200 if (!fname) {
1201 errno = EINVAL;
1202 return -1;
1205 smbw_init();
1207 smbw_busy++;
1209 /* work out what server they are after */
1210 smbw_parse_path(fname, server, share, path);
1212 /* get a connection to the server */
1213 srv = smbw_server(server, share);
1214 if (!srv) {
1215 /* smbw_server sets errno */
1216 goto failed;
1219 mode = 0;
1221 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1222 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1223 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1224 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1226 if (!cli_setatr(&srv->cli, path, mode, 0)) {
1227 errno = smbw_errno(&srv->cli);
1228 goto failed;
1231 smbw_busy--;
1232 return 0;
1234 failed:
1235 smbw_busy--;
1236 return -1;
1239 /*****************************************************
1240 a wrapper for lseek()
1241 *******************************************************/
1242 off_t smbw_lseek(int fd, off_t offset, int whence)
1244 struct smbw_file *file;
1245 size_t size;
1247 smbw_busy++;
1249 file = smbw_file(fd);
1250 if (!file) {
1251 off_t ret = smbw_dir_lseek(fd, offset, whence);
1252 smbw_busy--;
1253 return ret;
1256 switch (whence) {
1257 case SEEK_SET:
1258 file->f->offset = offset;
1259 break;
1260 case SEEK_CUR:
1261 file->f->offset += offset;
1262 break;
1263 case SEEK_END:
1264 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1265 NULL, &size, NULL, NULL, NULL,
1266 NULL, NULL) &&
1267 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1268 NULL, &size, NULL, NULL, NULL)) {
1269 errno = EINVAL;
1270 smbw_busy--;
1271 return -1;
1273 file->f->offset = size + offset;
1274 break;
1277 smbw_busy--;
1278 return file->f->offset;
1282 /*****************************************************
1283 a wrapper for dup()
1284 *******************************************************/
1285 int smbw_dup(int fd)
1287 int fd2;
1288 struct smbw_file *file, *file2;
1290 smbw_busy++;
1292 file = smbw_file(fd);
1293 if (!file) {
1294 errno = EBADF;
1295 goto failed;
1298 fd2 = dup(file->fd);
1299 if (fd2 == -1) {
1300 goto failed;
1303 if (bitmap_query(smbw_file_bmap, fd2)) {
1304 DEBUG(0,("ERROR: fd already open in dup!\n"));
1305 errno = EIO;
1306 goto failed;
1309 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1310 if (!file2) {
1311 close(fd2);
1312 errno = ENOMEM;
1313 goto failed;
1316 ZERO_STRUCTP(file2);
1318 *file2 = *file;
1319 file2->fd = fd2;
1321 file->f->ref_count++;
1323 bitmap_set(smbw_file_bmap, fd2);
1325 DLIST_ADD(smbw_files, file2);
1327 smbw_busy--;
1328 return fd2;
1330 failed:
1331 smbw_busy--;
1332 return -1;
1336 /*****************************************************
1337 a wrapper for dup2()
1338 *******************************************************/
1339 int smbw_dup2(int fd, int fd2)
1341 struct smbw_file *file, *file2;
1343 smbw_busy++;
1345 file = smbw_file(fd);
1346 if (!file) {
1347 errno = EBADF;
1348 goto failed;
1351 if (bitmap_query(smbw_file_bmap, fd2)) {
1352 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1353 errno = EIO;
1354 goto failed;
1357 if (dup2(file->fd, fd2) != fd2) {
1358 goto failed;
1361 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1362 if (!file2) {
1363 close(fd2);
1364 errno = ENOMEM;
1365 goto failed;
1368 ZERO_STRUCTP(file2);
1370 *file2 = *file;
1371 file2->fd = fd2;
1373 file->f->ref_count++;
1375 bitmap_set(smbw_file_bmap, fd2);
1377 DLIST_ADD(smbw_files, file2);
1379 smbw_busy--;
1380 return fd2;
1382 failed:
1383 smbw_busy--;
1384 return -1;
1388 /*****************************************************
1389 close a connection to a server
1390 *******************************************************/
1391 static void smbw_srv_close(struct smbw_server *srv)
1393 smbw_busy++;
1395 cli_shutdown(&srv->cli);
1397 free(srv->server_name);
1398 free(srv->share_name);
1400 DLIST_REMOVE(smbw_srvs, srv);
1402 ZERO_STRUCTP(srv);
1404 free(srv);
1406 smbw_busy--;
1409 /*****************************************************
1410 when we fork we have to close all connections and files
1411 in the child
1412 *******************************************************/
1413 int smbw_fork(void)
1415 pid_t child;
1416 int p[2];
1417 char c=0;
1418 pstring line;
1420 struct smbw_file *file, *next_file;
1421 struct smbw_server *srv, *next_srv;
1423 if (pipe(p)) return real_fork();
1425 child = real_fork();
1427 if (child) {
1428 /* block the parent for a moment until the sockets are
1429 closed */
1430 close(p[1]);
1431 read(p[0], &c, 1);
1432 close(p[0]);
1433 return child;
1436 close(p[0]);
1438 /* close all files */
1439 for (file=smbw_files;file;file=next_file) {
1440 next_file = file->next;
1441 close(file->fd);
1444 /* close all server connections */
1445 for (srv=smbw_srvs;srv;srv=next_srv) {
1446 next_srv = srv->next;
1447 smbw_srv_close(srv);
1450 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
1451 smbw_setshared(line,smbw_cwd);
1453 /* unblock the parent */
1454 write(p[1], &c, 1);
1455 close(p[1]);
1457 /* and continue in the child */
1458 return 0;
1461 #ifndef NO_ACL_WRAPPER
1462 /*****************************************************
1463 say no to acls
1464 *******************************************************/
1465 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1467 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1468 errno = ENOSYS;
1469 return -1;
1471 #endif
1473 #ifndef NO_FACL_WRAPPER
1474 /*****************************************************
1475 say no to acls
1476 *******************************************************/
1477 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1479 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1480 errno = ENOSYS;
1481 return -1;
1483 #endif
1485 #ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
1486 #ifdef HAVE_STAT64
1487 /* this can't be in wrapped.c because of include conflicts */
1488 void stat64_convert(struct stat *st, struct stat64 *st64)
1490 st64->st_size = st->st_size;
1491 st64->st_mode = st->st_mode;
1492 st64->st_ino = st->st_ino;
1493 st64->st_dev = st->st_dev;
1494 st64->st_rdev = st->st_rdev;
1495 st64->st_nlink = st->st_nlink;
1496 st64->st_uid = st->st_uid;
1497 st64->st_gid = st->st_gid;
1498 st64->st_atime = st->st_atime;
1499 st64->st_mtime = st->st_mtime;
1500 st64->st_ctime = st->st_ctime;
1501 st64->st_blksize = st->st_blksize;
1502 st64->st_blocks = st->st_blocks;
1504 #endif
1506 #ifdef HAVE_READDIR64
1507 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1509 d64->d_ino = d->d_ino;
1510 d64->d_off = d->d_off;
1511 d64->d_reclen = d->d_reclen;
1512 pstrcpy(d64->d_name, d->d_name);
1514 #endif
1515 #endif
1518 #ifdef HAVE___XSTAT
1519 /* Definition of `struct stat' used in the linux kernel.. */
1520 struct kernel_stat {
1521 unsigned short int st_dev;
1522 unsigned short int __pad1;
1523 unsigned long int st_ino;
1524 unsigned short int st_mode;
1525 unsigned short int st_nlink;
1526 unsigned short int st_uid;
1527 unsigned short int st_gid;
1528 unsigned short int st_rdev;
1529 unsigned short int __pad2;
1530 unsigned long int st_size;
1531 unsigned long int st_blksize;
1532 unsigned long int st_blocks;
1533 unsigned long int st_atime;
1534 unsigned long int __unused1;
1535 unsigned long int st_mtime;
1536 unsigned long int __unused2;
1537 unsigned long int st_ctime;
1538 unsigned long int __unused3;
1539 unsigned long int __unused4;
1540 unsigned long int __unused5;
1544 * Prototype for gcc in 'fussy' mode.
1546 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1547 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1549 #ifdef _STAT_VER_LINUX_OLD
1550 if (vers == _STAT_VER_LINUX_OLD) {
1551 memcpy(st, kbuf, sizeof(*st));
1552 return;
1554 #endif
1556 ZERO_STRUCTP(st);
1558 st->st_dev = kbuf->st_dev;
1559 st->st_ino = kbuf->st_ino;
1560 st->st_mode = kbuf->st_mode;
1561 st->st_nlink = kbuf->st_nlink;
1562 st->st_uid = kbuf->st_uid;
1563 st->st_gid = kbuf->st_gid;
1564 st->st_rdev = kbuf->st_rdev;
1565 st->st_size = kbuf->st_size;
1566 st->st_blksize = kbuf->st_blksize;
1567 st->st_blocks = kbuf->st_blocks;
1568 st->st_atime = kbuf->st_atime;
1569 st->st_mtime = kbuf->st_mtime;
1570 st->st_ctime = kbuf->st_ctime;
1572 #endif