few edits
[Samba.git] / source / smbwrapper / smbw.c
blob9878d3c70b66b7e3e0697de84e453df1e37f7162
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 BOOL AllowDebugChange;
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 AllowDebugChange = False;
64 setup_logging("smbsh",True);
66 dbf = stderr;
68 if ((p=smbw_getshared("LOGFILE"))) {
69 dbf = sys_fopen(p, "a");
72 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
73 if (!smbw_file_bmap) {
74 exit(1);
77 charset_initialise();
79 in_client = True;
81 load_interfaces();
83 if ((p=smbw_getshared("SERVICESF"))) {
84 pstrcpy(servicesf, p);
87 lp_load(servicesf,True,False,False);
88 codepage_initialise(lp_client_code_page());
90 get_myname(global_myname);
92 if ((p=smbw_getshared("DEBUG"))) {
93 DEBUGLEVEL = atoi(p);
96 if ((p=smbw_getshared("RESOLVE_ORDER"))) {
97 lp_set_name_resolve_order(p);
100 if ((p=smbw_getshared("PREFIX"))) {
101 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
102 all_string_sub(smbw_prefix,"//", "/", 0);
103 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
106 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
108 p = smbw_getshared(line);
109 if (!p) {
110 sys_getwd(smbw_cwd);
112 pstrcpy(smbw_cwd, p);
113 DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
115 smbw_busy--;
117 set_maxfiles(SMBW_MAX_OPEN);
119 BlockSignals(True,SIGPIPE);
121 errno = eno;
124 /*****************************************************
125 determine if a file descriptor is a smb one
126 *******************************************************/
127 int smbw_fd(int fd)
129 if (smbw_busy) return 0;
130 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
133 /*****************************************************
134 determine if a file descriptor is an internal smbw fd
135 *******************************************************/
136 int smbw_local_fd(int fd)
138 struct smbw_server *srv;
140 smbw_init();
142 if (smbw_busy) return 0;
143 if (smbw_shared_fd(fd)) return 1;
145 for (srv=smbw_srvs;srv;srv=srv->next) {
146 if (srv->cli.fd == fd) return 1;
149 return 0;
152 /*****************************************************
153 a crude inode number generator
154 *******************************************************/
155 ino_t smbw_inode(const char *name)
157 if (!*name) return 2;
158 return (ino_t)str_checksum(name);
161 /*****************************************************
162 remove redundent stuff from a filename
163 *******************************************************/
164 void clean_fname(char *name)
166 char *p, *p2;
167 int l;
168 int modified = 1;
170 if (!name) return;
172 while (modified) {
173 modified = 0;
175 DEBUG(5,("cleaning %s\n", name));
177 if ((p=strstr(name,"/./"))) {
178 modified = 1;
179 while (*p) {
180 p[0] = p[2];
181 p++;
185 if ((p=strstr(name,"//"))) {
186 modified = 1;
187 while (*p) {
188 p[0] = p[1];
189 p++;
193 if (strcmp(name,"/../")==0) {
194 modified = 1;
195 name[1] = 0;
198 if ((p=strstr(name,"/../"))) {
199 modified = 1;
200 for (p2=(p>name?p-1:p);p2>name;p2--) {
201 if (p2[0] == '/') break;
203 while (*p2) {
204 p2[0] = p2[3];
205 p2++;
209 if (strcmp(name,"/..")==0) {
210 modified = 1;
211 name[1] = 0;
214 l = strlen(name);
215 p = l>=3?(name+l-3):name;
216 if (strcmp(p,"/..")==0) {
217 modified = 1;
218 for (p2=p-1;p2>name;p2--) {
219 if (p2[0] == '/') break;
221 if (p2==name) {
222 p[0] = '/';
223 p[1] = 0;
224 } else {
225 p2[0] = 0;
229 l = strlen(name);
230 p = l>=2?(name+l-2):name;
231 if (strcmp(p,"/.")==0) {
232 if (p == name) {
233 p[1] = 0;
234 } else {
235 p[0] = 0;
239 if (strncmp(p=name,"./",2) == 0) {
240 modified = 1;
241 do {
242 p[0] = p[2];
243 } while (*p++);
246 l = strlen(p=name);
247 if (l > 1 && p[l-1] == '/') {
248 modified = 1;
249 p[l-1] = 0;
256 /*****************************************************
257 find a workgroup (any workgroup!) that has a master
258 browser on the local network
259 *******************************************************/
260 static char *smbw_find_workgroup(void)
262 fstring server;
263 char *p;
264 struct in_addr *ip_list = NULL;
265 int count = 0;
266 int i;
268 /* first off see if an existing workgroup name exists */
269 p = smbw_getshared("WORKGROUP");
270 if (!p) p = lp_workgroup();
272 slprintf(server, sizeof(server), "%s#1D", p);
273 if (smbw_server(server, "IPC$")) return p;
275 /* go looking for workgroups */
276 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
277 DEBUG(1,("No workgroups found!"));
278 return p;
281 for (i=0;i<count;i++) {
282 static fstring name;
283 if (name_status_find("*", 0, 0x1d, ip_list[i], name)) {
284 slprintf(server, sizeof(server), "%s#1D", name);
285 if (smbw_server(server, "IPC$")) {
286 smbw_setshared("WORKGROUP", name);
287 SAFE_FREE(ip_list);
288 return name;
293 SAFE_FREE(ip_list);
295 return p;
298 /*****************************************************
299 parse a smb path into its components.
300 server is one of
301 1) the name of the SMB server
302 2) WORKGROUP#1D for share listing
303 3) WORKGROUP#__ for workgroup listing
304 share is the share on the server to query
305 path is the SMB path on the server
306 return the full path (ie. add cwd if needed)
307 *******************************************************/
308 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
310 static pstring s;
311 char *p;
312 int len;
313 fstring workgroup;
315 /* add cwd if necessary */
316 if (fname[0] != '/') {
317 slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
318 } else {
319 pstrcpy(s, fname);
321 clean_fname(s);
323 /* see if it has the right prefix */
324 len = strlen(smbw_prefix)-1;
325 if (strncmp(s,smbw_prefix,len) ||
326 (s[len] != '/' && s[len] != 0)) return s;
328 /* ok, its for us. Now parse out the workgroup, share etc. */
329 p = s+len;
330 if (*p == '/') p++;
331 if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
332 /* we're in /smb - give a list of workgroups */
333 slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
334 fstrcpy(share,"IPC$");
335 pstrcpy(path,"");
336 return s;
339 if (!next_token(&p, server, "/", sizeof(fstring))) {
340 /* we are in /smb/WORKGROUP */
341 slprintf(server,sizeof(fstring), "%s#1D", workgroup);
342 fstrcpy(share,"IPC$");
343 pstrcpy(path,"");
346 if (!next_token(&p, share, "/", sizeof(fstring))) {
347 /* we are in /smb/WORKGROUP/SERVER */
348 fstrcpy(share,"IPC$");
349 pstrcpy(path,"");
352 pstrcpy(path, p);
354 all_string_sub(path, "/", "\\", 0);
356 return s;
359 /*****************************************************
360 determine if a path name (possibly relative) is in the
361 smb name space
362 *******************************************************/
363 int smbw_path(const char *path)
365 fstring server, share;
366 pstring s;
367 char *cwd;
368 int len;
370 if(!path)
371 return 0;
373 /* this is needed to prevent recursion with the BSD malloc which
374 opens /etc/malloc.conf on the first call */
375 if (strncmp(path,"/etc/", 5) == 0) {
376 return 0;
379 smbw_init();
381 len = strlen(smbw_prefix)-1;
383 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
384 return 0;
387 if (smbw_busy) return 0;
389 DEBUG(3,("smbw_path(%s)\n", path));
391 cwd = smbw_parse_path(path, server, share, s);
393 if (strncmp(cwd,smbw_prefix,len) == 0 &&
394 (cwd[len] == '/' || cwd[len] == 0)) {
395 return 1;
398 return 0;
401 /*****************************************************
402 return a unix errno from a SMB error pair
403 *******************************************************/
404 int smbw_errno(struct cli_state *c)
406 return cli_errno(c);
409 /* Return a username and password given a server and share name */
411 void get_envvar_auth_data(char *server, char *share, char **workgroup,
412 char **username, char **password)
414 /* Fall back to shared memory/environment variables */
416 *username = smbw_getshared("USER");
417 if (!*username) *username = getenv("USER");
418 if (!*username) *username = "guest";
420 *workgroup = smbw_getshared("WORKGROUP");
421 if (!*workgroup) *workgroup = lp_workgroup();
423 *password = smbw_getshared("PASSWORD");
424 if (!*password) *password = "";
427 static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
429 /*****************************************************
430 set the get auth data function
431 ******************************************************/
432 void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
434 get_auth_data_fn = fn;
437 /*****************************************************
438 return a connection to a server (existing or new)
439 *******************************************************/
440 struct smbw_server *smbw_server(char *server, char *share)
442 struct smbw_server *srv=NULL;
443 struct cli_state c;
444 char *username;
445 char *password;
446 char *workgroup;
447 struct nmb_name called, calling;
448 char *p, *server_n = server;
449 fstring group;
450 pstring ipenv;
451 struct in_addr ip;
453 zero_ip(&ip);
454 ZERO_STRUCT(c);
456 get_auth_data_fn(server, share, &workgroup, &username, &password);
458 /* try to use an existing connection */
459 for (srv=smbw_srvs;srv;srv=srv->next) {
460 if (strcmp(server,srv->server_name)==0 &&
461 strcmp(share,srv->share_name)==0 &&
462 strcmp(workgroup,srv->workgroup)==0 &&
463 strcmp(username, srv->username) == 0)
464 return srv;
467 if (server[0] == 0) {
468 errno = EPERM;
469 return NULL;
472 make_nmb_name(&calling, global_myname, 0x0);
473 make_nmb_name(&called , server, 0x20);
475 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
477 if ((p=strchr(server_n,'#')) &&
478 (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
479 struct in_addr sip;
480 pstring s;
482 fstrcpy(group, server_n);
483 p = strchr(group,'#');
484 *p = 0;
486 /* cache the workgroup master lookup */
487 slprintf(s,sizeof(s)-1,"MASTER_%s", group);
488 if (!(server_n = smbw_getshared(s))) {
489 if (!find_master_ip(group, &sip)) {
490 errno = ENOENT;
491 return NULL;
493 fstrcpy(group, inet_ntoa(sip));
494 server_n = group;
495 smbw_setshared(s,server_n);
499 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
501 again:
502 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
504 zero_ip(&ip);
505 if ((p=smbw_getshared(ipenv))) {
506 ip = *(interpret_addr2(p));
509 /* have to open a new connection */
510 if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
511 errno = ENOENT;
512 return NULL;
515 if (!cli_session_request(&c, &calling, &called)) {
516 cli_shutdown(&c);
517 if (strcmp(called.name, "*SMBSERVER")) {
518 make_nmb_name(&called , "*SMBSERVER", 0x20);
519 goto again;
521 errno = ENOENT;
522 return NULL;
525 DEBUG(4,(" session request ok\n"));
527 if (!cli_negprot(&c)) {
528 cli_shutdown(&c);
529 errno = ENOENT;
530 return NULL;
533 if (!cli_session_setup(&c, username,
534 password, strlen(password),
535 password, strlen(password),
536 workgroup) &&
537 /* try an anonymous login if it failed */
538 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
539 cli_shutdown(&c);
540 errno = EPERM;
541 return NULL;
544 DEBUG(4,(" session setup ok\n"));
546 if (!cli_send_tconX(&c, share, "?????",
547 password, strlen(password)+1)) {
548 errno = smbw_errno(&c);
549 cli_shutdown(&c);
550 return NULL;
553 smbw_setshared(ipenv,inet_ntoa(ip));
555 DEBUG(4,(" tconx ok\n"));
557 srv = (struct smbw_server *)malloc(sizeof(*srv));
558 if (!srv) {
559 errno = ENOMEM;
560 goto failed;
563 ZERO_STRUCTP(srv);
565 srv->cli = c;
567 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
569 srv->server_name = strdup(server);
570 if (!srv->server_name) {
571 errno = ENOMEM;
572 goto failed;
575 srv->share_name = strdup(share);
576 if (!srv->share_name) {
577 errno = ENOMEM;
578 goto failed;
581 srv->workgroup = strdup(workgroup);
582 if (!srv->workgroup) {
583 errno = ENOMEM;
584 goto failed;
587 srv->username = strdup(username);
588 if (!srv->username) {
589 errno = ENOMEM;
590 goto failed;
593 /* some programs play with file descriptors fairly intimately. We
594 try to get out of the way by duping to a high fd number */
595 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
596 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
597 srv->cli.fd+SMBW_CLI_FD) {
598 close(srv->cli.fd);
599 srv->cli.fd += SMBW_CLI_FD;
603 DLIST_ADD(smbw_srvs, srv);
605 return srv;
607 failed:
608 cli_shutdown(&c);
609 if (!srv) return NULL;
611 SAFE_FREE(srv->server_name);
612 SAFE_FREE(srv->share_name);
613 SAFE_FREE(srv);
614 return NULL;
618 /*****************************************************
619 map a fd to a smbw_file structure
620 *******************************************************/
621 struct smbw_file *smbw_file(int fd)
623 struct smbw_file *file;
625 for (file=smbw_files;file;file=file->next) {
626 if (file->fd == fd) return file;
628 return NULL;
631 /*****************************************************
632 a wrapper for open()
633 *******************************************************/
634 int smbw_open(const char *fname, int flags, mode_t mode)
636 fstring server, share;
637 pstring path;
638 struct smbw_server *srv=NULL;
639 int eno=0, fd = -1;
640 struct smbw_file *file=NULL;
642 smbw_init();
644 if (!fname) {
645 errno = EINVAL;
646 return -1;
649 smbw_busy++;
651 /* work out what server they are after */
652 smbw_parse_path(fname, server, share, path);
654 /* get a connection to the server */
655 srv = smbw_server(server, share);
656 if (!srv) {
657 /* smbw_server sets errno */
658 goto failed;
661 if (path[strlen(path)-1] == '\\') {
662 fd = -1;
663 } else {
664 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
666 if (fd == -1) {
667 /* it might be a directory. Maybe we should use chkpath? */
668 eno = smbw_errno(&srv->cli);
669 fd = smbw_dir_open(fname);
670 if (fd == -1) errno = eno;
671 smbw_busy--;
672 return fd;
675 file = (struct smbw_file *)malloc(sizeof(*file));
676 if (!file) {
677 errno = ENOMEM;
678 goto failed;
681 ZERO_STRUCTP(file);
683 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
684 if (!file->f) {
685 errno = ENOMEM;
686 goto failed;
689 ZERO_STRUCTP(file->f);
691 file->f->cli_fd = fd;
692 file->f->fname = strdup(path);
693 if (!file->f->fname) {
694 errno = ENOMEM;
695 goto failed;
697 file->srv = srv;
698 file->fd = open(SMBW_DUMMY, O_WRONLY);
699 if (file->fd == -1) {
700 errno = EMFILE;
701 goto failed;
704 if (bitmap_query(smbw_file_bmap, file->fd)) {
705 DEBUG(0,("ERROR: fd used in smbw_open\n"));
706 errno = EIO;
707 goto failed;
710 file->f->ref_count=1;
712 bitmap_set(smbw_file_bmap, file->fd);
714 DLIST_ADD(smbw_files, file);
716 DEBUG(4,("opened %s\n", fname));
718 smbw_busy--;
719 return file->fd;
721 failed:
722 if (fd != -1) {
723 cli_close(&srv->cli, fd);
725 if (file) {
726 if (file->f) {
727 SAFE_FREE(file->f->fname);
728 SAFE_FREE(file->f);
730 SAFE_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 SAFE_FREE(file->f->fname);
896 SAFE_FREE(file->f);
898 ZERO_STRUCTP(file);
899 SAFE_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 SAFE_FREE(srv->server_name);
1388 SAFE_FREE(srv->share_name);
1390 DLIST_REMOVE(smbw_srvs, srv);
1392 ZERO_STRUCTP(srv);
1394 SAFE_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