r17727: Start pulling in changes for 3.0.23c
[Samba/gbeck.git] / source / smbwrapper / smbw.c
blobd4a5b51af4e27c02699984a5f5c356608fa2d762
1 /*
2 Unix SMB/CIFS implementation.
3 SMB wrapper functions
4 Copyright (C) Andrew Tridgell 1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
22 #include "realcalls.h"
24 pstring smbw_cwd;
26 static struct smbw_file *smbw_files;
27 static struct smbw_server *smbw_srvs;
29 struct bitmap *smbw_file_bmap;
31 fstring smbw_prefix = SMBW_PREFIX;
33 int smbw_busy=0;
35 /* needs to be here because of dumb include files on some systems */
36 int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
39 /*****************************************************
40 initialise structures
41 *******************************************************/
42 void smbw_init(void)
44 extern BOOL in_client;
45 static int initialised;
46 char *p;
47 int eno;
48 pstring line;
50 if (initialised) return;
51 initialised = 1;
53 eno = errno;
55 smbw_busy++;
57 DEBUGLEVEL = 0;
58 setup_logging("smbsh",True);
60 dbf = x_stderr;
62 if ((p=smbw_getshared("LOGFILE"))) {
63 dbf = sys_fopen(p, "a");
66 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
67 if (!smbw_file_bmap) {
68 exit(1);
71 in_client = True;
73 load_interfaces();
75 if ((p=smbw_getshared("SERVICESF"))) {
76 pstrcpy(dyn_CONFIGFILE, p);
79 lp_load(dyn_CONFIGFILE,True,False,False,True);
81 if (!init_names())
82 exit(1);
84 if ((p=smbw_getshared("DEBUG"))) {
85 DEBUGLEVEL = atoi(p);
88 if ((p=smbw_getshared("RESOLVE_ORDER"))) {
89 lp_set_name_resolve_order(p);
92 if ((p=smbw_getshared("PREFIX"))) {
93 slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
94 all_string_sub(smbw_prefix,"//", "/", 0);
95 DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
98 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
100 p = smbw_getshared(line);
101 if (!p) {
102 sys_getwd(smbw_cwd);
104 pstrcpy(smbw_cwd, p);
105 DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
107 smbw_busy--;
109 set_maxfiles(SMBW_MAX_OPEN);
111 BlockSignals(True,SIGPIPE);
113 errno = eno;
116 /*****************************************************
117 determine if a file descriptor is a smb one
118 *******************************************************/
119 int smbw_fd(int fd)
121 if (smbw_busy) return 0;
122 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
125 /*****************************************************
126 determine if a file descriptor is an internal smbw fd
127 *******************************************************/
128 int smbw_local_fd(int fd)
130 struct smbw_server *srv;
132 smbw_init();
134 if (smbw_busy) return 0;
135 if (smbw_shared_fd(fd)) return 1;
137 for (srv=smbw_srvs;srv;srv=srv->next) {
138 if (srv->cli.fd == fd) return 1;
141 return 0;
144 /*****************************************************
145 a crude inode number generator
146 *******************************************************/
147 ino_t smbw_inode(const char *name)
149 if (!*name) return 2;
150 return (ino_t)str_checksum(name);
153 /*****************************************************
154 remove redundent stuff from a filename
155 *******************************************************/
156 void clean_fname(char *name)
158 char *p, *p2;
159 int l;
160 int modified = 1;
162 if (!name) return;
164 while (modified) {
165 modified = 0;
167 DEBUG(5,("cleaning %s\n", name));
169 if ((p=strstr(name,"/./"))) {
170 modified = 1;
171 while (*p) {
172 p[0] = p[2];
173 p++;
177 if ((p=strstr(name,"//"))) {
178 modified = 1;
179 while (*p) {
180 p[0] = p[1];
181 p++;
185 if (strcmp(name,"/../")==0) {
186 modified = 1;
187 name[1] = 0;
190 if ((p=strstr(name,"/../"))) {
191 modified = 1;
192 for (p2=(p>name?p-1:p);p2>name;p2--) {
193 if (p2[0] == '/') break;
195 while (*p2) {
196 p2[0] = p2[3];
197 p2++;
201 if (strcmp(name,"/..")==0) {
202 modified = 1;
203 name[1] = 0;
206 l = strlen(name);
207 p = l>=3?(name+l-3):name;
208 if (strcmp(p,"/..")==0) {
209 modified = 1;
210 for (p2=p-1;p2>name;p2--) {
211 if (p2[0] == '/') break;
213 if (p2==name) {
214 p[0] = '/';
215 p[1] = 0;
216 } else {
217 p2[0] = 0;
221 l = strlen(name);
222 p = l>=2?(name+l-2):name;
223 if (strcmp(p,"/.")==0) {
224 if (p == name) {
225 p[1] = 0;
226 } else {
227 p[0] = 0;
231 if (strncmp(p=name,"./",2) == 0) {
232 modified = 1;
233 do {
234 p[0] = p[2];
235 } while (*p++);
238 l = strlen(p=name);
239 if (l > 1 && p[l-1] == '/') {
240 modified = 1;
241 p[l-1] = 0;
248 /*****************************************************
249 find a workgroup (any workgroup!) that has a master
250 browser on the local network
251 *******************************************************/
252 static char *smbw_find_workgroup(void)
254 fstring server;
255 char *p;
256 struct in_addr *ip_list = NULL;
257 int count = 0;
258 int i;
260 /* first off see if an existing workgroup name exists */
261 p = smbw_getshared("WORKGROUP");
262 if (!p) p = lp_workgroup();
264 slprintf(server, sizeof(server), "%s#1D", p);
265 if (smbw_server(server, "IPC$")) return p;
267 /* go looking for workgroups */
268 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
269 DEBUG(1,("No workgroups found!"));
270 return p;
273 for (i=0;i<count;i++) {
274 static fstring name;
275 if (name_status_find("*", 0, 0x1d, ip_list[i], name)) {
276 slprintf(server, sizeof(server), "%s#1D", name);
277 if (smbw_server(server, "IPC$")) {
278 smbw_setshared("WORKGROUP", name);
279 SAFE_FREE(ip_list);
280 return name;
285 SAFE_FREE(ip_list);
287 return p;
290 /*****************************************************
291 parse a smb path into its components.
292 server is one of
293 1) the name of the SMB server
294 2) WORKGROUP#1D for share listing
295 3) WORKGROUP#__ for workgroup listing
296 share is the share on the server to query
297 path is the SMB path on the server
298 return the full path (ie. add cwd if needed)
299 *******************************************************/
300 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
302 static pstring s;
303 char *p;
304 int len;
305 fstring workgroup;
307 /* add cwd if necessary */
308 if (fname[0] != '/') {
309 slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
310 } else {
311 pstrcpy(s, fname);
313 clean_fname(s);
315 /* see if it has the right prefix */
316 len = strlen(smbw_prefix)-1;
317 if (strncmp(s,smbw_prefix,len) ||
318 (s[len] != '/' && s[len] != 0)) return s;
320 /* ok, its for us. Now parse out the workgroup, share etc. */
321 p = s+len;
322 if (*p == '/') p++;
323 if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
324 /* we're in /smb - give a list of workgroups */
325 slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
326 fstrcpy(share,"IPC$");
327 pstrcpy(path,"");
328 return s;
331 if (!next_token(&p, server, "/", sizeof(fstring))) {
332 /* we are in /smb/WORKGROUP */
333 slprintf(server,sizeof(fstring), "%s#1D", workgroup);
334 fstrcpy(share,"IPC$");
335 pstrcpy(path,"");
338 if (!next_token(&p, share, "/", sizeof(fstring))) {
339 /* we are in /smb/WORKGROUP/SERVER */
340 fstrcpy(share,"IPC$");
341 pstrcpy(path,"");
344 pstrcpy(path, p);
346 all_string_sub(path, "/", "\\", 0);
348 return s;
351 /*****************************************************
352 determine if a path name (possibly relative) is in the
353 smb name space
354 *******************************************************/
355 int smbw_path(const char *path)
357 fstring server, share;
358 pstring s;
359 char *cwd;
360 int len;
362 if(!path)
363 return 0;
365 /* this is needed to prevent recursion with the BSD malloc which
366 opens /etc/malloc.conf on the first call */
367 if (strncmp(path,"/etc/", 5) == 0) {
368 return 0;
371 smbw_init();
373 len = strlen(smbw_prefix)-1;
375 if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
376 return 0;
379 if (smbw_busy) return 0;
381 DEBUG(3,("smbw_path(%s)\n", path));
383 cwd = smbw_parse_path(path, server, share, s);
385 if (strncmp(cwd,smbw_prefix,len) == 0 &&
386 (cwd[len] == '/' || cwd[len] == 0)) {
387 return 1;
390 return 0;
393 /*****************************************************
394 return a unix errno from a SMB error pair
395 *******************************************************/
396 int smbw_errno(struct cli_state *c)
398 return cli_errno(c);
401 /* Return a username and password given a server and share name */
403 void get_envvar_auth_data(char *server, char *share, char **workgroup,
404 char **username, char **password)
406 /* Fall back to shared memory/environment variables */
408 *username = smbw_getshared("USER");
409 if (!*username) *username = getenv("USER");
410 if (!*username) *username = "guest";
412 *workgroup = smbw_getshared("WORKGROUP");
413 if (!*workgroup) *workgroup = lp_workgroup();
415 *password = smbw_getshared("PASSWORD");
416 if (!*password) *password = "";
419 static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
421 /*****************************************************
422 set the get auth data function
423 ******************************************************/
424 void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
426 get_auth_data_fn = fn;
429 /*****************************************************
430 return a connection to a server (existing or new)
431 *******************************************************/
432 struct smbw_server *smbw_server(char *server, char *share)
434 struct smbw_server *srv=NULL;
435 struct cli_state c;
436 char *username;
437 char *password;
438 char *workgroup;
439 struct nmb_name called, calling;
440 char *p, *server_n = server;
441 fstring group;
442 pstring ipenv;
443 struct in_addr ip;
445 zero_ip(&ip);
446 ZERO_STRUCT(c);
448 get_auth_data_fn(server, share, &workgroup, &username, &password);
450 /* try to use an existing connection */
451 for (srv=smbw_srvs;srv;srv=srv->next) {
452 if (strcmp(server,srv->server_name)==0 &&
453 strcmp(share,srv->share_name)==0 &&
454 strcmp(workgroup,srv->workgroup)==0 &&
455 strcmp(username, srv->username) == 0)
456 return srv;
459 if (server[0] == 0) {
460 errno = EPERM;
461 return NULL;
464 make_nmb_name(&calling, global_myname(), 0x0);
465 make_nmb_name(&called , server, 0x20);
467 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
469 if ((p=strchr_m(server_n,'#')) &&
470 (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
471 struct in_addr sip;
472 pstring s;
474 fstrcpy(group, server_n);
475 p = strchr_m(group,'#');
476 *p = 0;
478 /* cache the workgroup master lookup */
479 slprintf(s,sizeof(s)-1,"MASTER_%s", group);
480 if (!(server_n = smbw_getshared(s))) {
481 if (!find_master_ip(group, &sip)) {
482 errno = ENOENT;
483 return NULL;
485 fstrcpy(group, inet_ntoa(sip));
486 server_n = group;
487 smbw_setshared(s,server_n);
491 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
493 again:
494 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
496 zero_ip(&ip);
497 if ((p=smbw_getshared(ipenv))) {
498 ip = *(interpret_addr2(p));
501 /* have to open a new connection */
502 if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
503 errno = ENOENT;
504 return NULL;
507 if (!cli_session_request(&c, &calling, &called)) {
508 cli_shutdown(&c);
509 if (strcmp(called.name, "*SMBSERVER")) {
510 make_nmb_name(&called , "*SMBSERVER", 0x20);
511 goto again;
513 errno = ENOENT;
514 return NULL;
517 DEBUG(4,(" session request ok\n"));
519 if (!cli_negprot(&c)) {
520 cli_shutdown(&c);
521 errno = ENOENT;
522 return NULL;
525 if (!cli_session_setup(&c, username,
526 password, strlen(password),
527 password, strlen(password),
528 workgroup) &&
529 /* try an anonymous login if it failed */
530 !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
531 cli_shutdown(&c);
532 errno = EPERM;
533 return NULL;
536 DEBUG(4,(" session setup ok\n"));
538 if (!cli_send_tconX(&c, share, "?????",
539 password, strlen(password)+1)) {
540 errno = smbw_errno(&c);
541 cli_shutdown(&c);
542 return NULL;
545 smbw_setshared(ipenv,inet_ntoa(ip));
547 DEBUG(4,(" tconx ok\n"));
549 srv = SMB_MALLOC_P(struct smbw_server);
550 if (!srv) {
551 errno = ENOMEM;
552 goto failed;
555 ZERO_STRUCTP(srv);
557 srv->cli = c;
559 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
561 srv->server_name = SMB_STRDUP(server);
562 if (!srv->server_name) {
563 errno = ENOMEM;
564 goto failed;
567 srv->share_name = SMB_STRDUP(share);
568 if (!srv->share_name) {
569 errno = ENOMEM;
570 goto failed;
573 srv->workgroup = SMB_STRDUP(workgroup);
574 if (!srv->workgroup) {
575 errno = ENOMEM;
576 goto failed;
579 srv->username = SMB_STRDUP(username);
580 if (!srv->username) {
581 errno = ENOMEM;
582 goto failed;
585 /* some programs play with file descriptors fairly intimately. We
586 try to get out of the way by duping to a high fd number */
587 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
588 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
589 srv->cli.fd+SMBW_CLI_FD) {
590 close(srv->cli.fd);
591 srv->cli.fd += SMBW_CLI_FD;
595 DLIST_ADD(smbw_srvs, srv);
597 return srv;
599 failed:
600 cli_shutdown(&c);
601 if (!srv) return NULL;
603 SAFE_FREE(srv->server_name);
604 SAFE_FREE(srv->share_name);
605 SAFE_FREE(srv);
606 return NULL;
610 /*****************************************************
611 map a fd to a smbw_file structure
612 *******************************************************/
613 struct smbw_file *smbw_file(int fd)
615 struct smbw_file *file;
617 for (file=smbw_files;file;file=file->next) {
618 if (file->fd == fd) return file;
620 return NULL;
623 /*****************************************************
624 a wrapper for open()
625 *******************************************************/
626 int smbw_open(const char *fname, int flags, mode_t mode)
628 fstring server, share;
629 pstring path;
630 struct smbw_server *srv=NULL;
631 int eno=0, fd = -1;
632 struct smbw_file *file=NULL;
634 smbw_init();
636 if (!fname) {
637 errno = EINVAL;
638 return -1;
641 smbw_busy++;
643 /* work out what server they are after */
644 smbw_parse_path(fname, server, share, path);
646 /* get a connection to the server */
647 srv = smbw_server(server, share);
648 if (!srv) {
649 /* smbw_server sets errno */
650 goto failed;
653 if (path[strlen(path)-1] == '\\') {
654 fd = -1;
655 } else {
656 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
658 if (fd == -1) {
659 /* it might be a directory. Maybe we should use chkpath? */
660 eno = smbw_errno(&srv->cli);
661 fd = smbw_dir_open(fname);
662 if (fd == -1) errno = eno;
663 smbw_busy--;
664 return fd;
667 file = SMB_MALLOC_P(struct smbw_file);
668 if (!file) {
669 errno = ENOMEM;
670 goto failed;
673 ZERO_STRUCTP(file);
675 file->f = SMB_MALLOC_P(struct smbw_filedes);
676 if (!file->f) {
677 errno = ENOMEM;
678 goto failed;
681 ZERO_STRUCTP(file->f);
683 file->f->cli_fd = fd;
684 file->f->fname = SMB_STRDUP(path);
685 if (!file->f->fname) {
686 errno = ENOMEM;
687 goto failed;
689 file->srv = srv;
690 file->fd = open(SMBW_DUMMY, O_WRONLY);
691 if (file->fd == -1) {
692 errno = EMFILE;
693 goto failed;
696 if (bitmap_query(smbw_file_bmap, file->fd)) {
697 DEBUG(0,("ERROR: fd used in smbw_open\n"));
698 errno = EIO;
699 goto failed;
702 file->f->ref_count=1;
704 bitmap_set(smbw_file_bmap, file->fd);
706 DLIST_ADD(smbw_files, file);
708 DEBUG(4,("opened %s\n", fname));
710 smbw_busy--;
711 return file->fd;
713 failed:
714 if (fd != -1) {
715 cli_close(&srv->cli, fd);
717 if (file) {
718 if (file->f) {
719 SAFE_FREE(file->f->fname);
720 SAFE_FREE(file->f);
722 SAFE_FREE(file);
724 smbw_busy--;
725 return -1;
729 /*****************************************************
730 a wrapper for pread()
731 *******************************************************/
732 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
734 struct smbw_file *file;
735 int ret;
737 smbw_busy++;
739 file = smbw_file(fd);
740 if (!file) {
741 errno = EBADF;
742 smbw_busy--;
743 return -1;
746 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
748 if (ret == -1) {
749 errno = smbw_errno(&file->srv->cli);
750 smbw_busy--;
751 return -1;
754 smbw_busy--;
755 return ret;
758 /*****************************************************
759 a wrapper for read()
760 *******************************************************/
761 ssize_t smbw_read(int fd, void *buf, size_t count)
763 struct smbw_file *file;
764 int ret;
766 DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
768 smbw_busy++;
770 file = smbw_file(fd);
771 if (!file) {
772 errno = EBADF;
773 smbw_busy--;
774 return -1;
777 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
778 file->f->offset, count);
780 if (ret == -1) {
781 errno = smbw_errno(&file->srv->cli);
782 smbw_busy--;
783 return -1;
786 file->f->offset += ret;
788 DEBUG(4,(" -> %d\n", ret));
790 smbw_busy--;
791 return ret;
796 /*****************************************************
797 a wrapper for write()
798 *******************************************************/
799 ssize_t smbw_write(int fd, void *buf, size_t count)
801 struct smbw_file *file;
802 int ret;
804 smbw_busy++;
806 file = smbw_file(fd);
807 if (!file) {
808 errno = EBADF;
809 smbw_busy--;
810 return -1;
813 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
815 if (ret == -1) {
816 errno = smbw_errno(&file->srv->cli);
817 smbw_busy--;
818 return -1;
821 file->f->offset += ret;
823 smbw_busy--;
824 return ret;
827 /*****************************************************
828 a wrapper for pwrite()
829 *******************************************************/
830 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
832 struct smbw_file *file;
833 int ret;
835 smbw_busy++;
837 file = smbw_file(fd);
838 if (!file) {
839 errno = EBADF;
840 smbw_busy--;
841 return -1;
844 ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
846 if (ret == -1) {
847 errno = smbw_errno(&file->srv->cli);
848 smbw_busy--;
849 return -1;
852 smbw_busy--;
853 return ret;
856 /*****************************************************
857 a wrapper for close()
858 *******************************************************/
859 int smbw_close(int fd)
861 struct smbw_file *file;
863 smbw_busy++;
865 file = smbw_file(fd);
866 if (!file) {
867 int ret = smbw_dir_close(fd);
868 smbw_busy--;
869 return ret;
872 if (file->f->ref_count == 1 &&
873 !cli_close(&file->srv->cli, file->f->cli_fd)) {
874 errno = smbw_errno(&file->srv->cli);
875 smbw_busy--;
876 return -1;
880 bitmap_clear(smbw_file_bmap, file->fd);
881 close(file->fd);
883 DLIST_REMOVE(smbw_files, file);
885 file->f->ref_count--;
886 if (file->f->ref_count == 0) {
887 SAFE_FREE(file->f->fname);
888 SAFE_FREE(file->f);
890 ZERO_STRUCTP(file);
891 SAFE_FREE(file);
893 smbw_busy--;
895 return 0;
899 /*****************************************************
900 a wrapper for fcntl()
901 *******************************************************/
902 int smbw_fcntl(int fd, int cmd, long arg)
904 return 0;
908 /*****************************************************
909 a wrapper for access()
910 *******************************************************/
911 int smbw_access(const char *name, int mode)
913 struct stat st;
915 DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
917 if (smbw_stat(name, &st)) return -1;
919 if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
920 ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
921 ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
922 errno = EACCES;
923 return -1;
926 return 0;
929 /*****************************************************
930 a wrapper for realink() - needed for correct errno setting
931 *******************************************************/
932 int smbw_readlink(const char *path, char *buf, size_t bufsize)
934 struct stat st;
935 int ret;
937 ret = smbw_stat(path, &st);
938 if (ret != 0) {
939 DEBUG(4,("readlink(%s) failed\n", path));
940 return -1;
943 /* it exists - say it isn't a link */
944 DEBUG(4,("readlink(%s) not a link\n", path));
946 errno = EINVAL;
947 return -1;
951 /*****************************************************
952 a wrapper for unlink()
953 *******************************************************/
954 int smbw_unlink(const char *fname)
956 struct smbw_server *srv;
957 fstring server, share;
958 pstring path;
960 if (!fname) {
961 errno = EINVAL;
962 return -1;
965 smbw_init();
967 smbw_busy++;
969 /* work out what server they are after */
970 smbw_parse_path(fname, server, share, path);
972 /* get a connection to the server */
973 srv = smbw_server(server, share);
974 if (!srv) {
975 /* smbw_server sets errno */
976 goto failed;
979 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
980 int job = smbw_stat_printjob(srv, path, NULL, NULL);
981 if (job == -1) {
982 goto failed;
984 if (cli_printjob_del(&srv->cli, job) != 0) {
985 goto failed;
987 } else if (!cli_unlink(&srv->cli, path)) {
988 errno = smbw_errno(&srv->cli);
989 goto failed;
992 smbw_busy--;
993 return 0;
995 failed:
996 smbw_busy--;
997 return -1;
1001 /*****************************************************
1002 a wrapper for rename()
1003 *******************************************************/
1004 int smbw_rename(const char *oldname, const char *newname)
1006 struct smbw_server *srv;
1007 fstring server1, share1;
1008 pstring path1;
1009 fstring server2, share2;
1010 pstring path2;
1012 if (!oldname || !newname) {
1013 errno = EINVAL;
1014 return -1;
1017 smbw_init();
1019 DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
1021 smbw_busy++;
1023 /* work out what server they are after */
1024 smbw_parse_path(oldname, server1, share1, path1);
1025 smbw_parse_path(newname, server2, share2, path2);
1027 if (strcmp(server1, server2) || strcmp(share1, share2)) {
1028 /* can't cross filesystems */
1029 errno = EXDEV;
1030 return -1;
1033 /* get a connection to the server */
1034 srv = smbw_server(server1, share1);
1035 if (!srv) {
1036 /* smbw_server sets errno */
1037 goto failed;
1040 if (!cli_rename(&srv->cli, path1, path2)) {
1041 int eno = smbw_errno(&srv->cli);
1042 if (eno != EEXIST ||
1043 !cli_unlink(&srv->cli, path2) ||
1044 !cli_rename(&srv->cli, path1, path2)) {
1045 errno = eno;
1046 goto failed;
1050 smbw_busy--;
1051 return 0;
1053 failed:
1054 smbw_busy--;
1055 return -1;
1059 /*****************************************************
1060 a wrapper for utime and utimes
1061 *******************************************************/
1062 static int smbw_settime(const char *fname, time_t t)
1064 struct smbw_server *srv;
1065 fstring server, share;
1066 pstring path;
1067 uint16 mode;
1069 if (!fname) {
1070 errno = EINVAL;
1071 return -1;
1074 smbw_init();
1076 smbw_busy++;
1078 /* work out what server they are after */
1079 smbw_parse_path(fname, server, share, path);
1081 /* get a connection to the server */
1082 srv = smbw_server(server, share);
1083 if (!srv) {
1084 /* smbw_server sets errno */
1085 goto failed;
1088 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1089 errno = smbw_errno(&srv->cli);
1090 goto failed;
1093 if (!cli_setatr(&srv->cli, path, mode, t)) {
1094 /* some servers always refuse directory changes */
1095 if (!(mode & aDIR)) {
1096 errno = smbw_errno(&srv->cli);
1097 goto failed;
1101 smbw_busy--;
1102 return 0;
1104 failed:
1105 smbw_busy--;
1106 return -1;
1109 /*****************************************************
1110 a wrapper for utime
1111 *******************************************************/
1112 int smbw_utime(const char *fname, void *buf)
1114 struct utimbuf *tbuf = (struct utimbuf *)buf;
1115 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1118 /*****************************************************
1119 a wrapper for utime
1120 *******************************************************/
1121 int smbw_utimes(const char *fname, void *buf)
1123 struct timeval *tbuf = (struct timeval *)buf;
1124 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1128 /*****************************************************
1129 a wrapper for chown()
1130 *******************************************************/
1131 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1133 struct smbw_server *srv;
1134 fstring server, share;
1135 pstring path;
1136 uint16 mode;
1138 if (!fname) {
1139 errno = EINVAL;
1140 return -1;
1143 smbw_init();
1145 smbw_busy++;
1147 /* work out what server they are after */
1148 smbw_parse_path(fname, server, share, path);
1150 /* get a connection to the server */
1151 srv = smbw_server(server, share);
1152 if (!srv) {
1153 /* smbw_server sets errno */
1154 goto failed;
1157 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1158 errno = smbw_errno(&srv->cli);
1159 goto failed;
1162 /* assume success */
1164 smbw_busy--;
1165 return 0;
1167 failed:
1168 smbw_busy--;
1169 return -1;
1172 /*****************************************************
1173 a wrapper for chmod()
1174 *******************************************************/
1175 int smbw_chmod(const char *fname, mode_t newmode)
1177 struct smbw_server *srv;
1178 fstring server, share;
1179 pstring path;
1180 uint32 mode;
1182 if (!fname) {
1183 errno = EINVAL;
1184 return -1;
1187 smbw_init();
1189 smbw_busy++;
1191 /* work out what server they are after */
1192 smbw_parse_path(fname, server, share, path);
1194 /* get a connection to the server */
1195 srv = smbw_server(server, share);
1196 if (!srv) {
1197 /* smbw_server sets errno */
1198 goto failed;
1201 mode = 0;
1203 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1204 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1205 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1206 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1208 if (!cli_setatr(&srv->cli, path, mode, 0)) {
1209 errno = smbw_errno(&srv->cli);
1210 goto failed;
1213 smbw_busy--;
1214 return 0;
1216 failed:
1217 smbw_busy--;
1218 return -1;
1221 /*****************************************************
1222 a wrapper for lseek()
1223 *******************************************************/
1224 off_t smbw_lseek(int fd, off_t offset, int whence)
1226 struct smbw_file *file;
1227 SMB_OFF_T size;
1229 smbw_busy++;
1231 file = smbw_file(fd);
1232 if (!file) {
1233 off_t ret = smbw_dir_lseek(fd, offset, whence);
1234 smbw_busy--;
1235 return ret;
1238 switch (whence) {
1239 case SEEK_SET:
1240 file->f->offset = offset;
1241 break;
1242 case SEEK_CUR:
1243 file->f->offset += offset;
1244 break;
1245 case SEEK_END:
1246 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1247 NULL, &size, NULL, NULL, NULL,
1248 NULL, NULL) &&
1249 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1250 NULL, &size, NULL, NULL, NULL)) {
1251 errno = EINVAL;
1252 smbw_busy--;
1253 return -1;
1255 file->f->offset = size + offset;
1256 break;
1259 smbw_busy--;
1260 return file->f->offset;
1264 /*****************************************************
1265 a wrapper for dup()
1266 *******************************************************/
1267 int smbw_dup(int fd)
1269 int fd2;
1270 struct smbw_file *file, *file2;
1272 smbw_busy++;
1274 file = smbw_file(fd);
1275 if (!file) {
1276 errno = EBADF;
1277 goto failed;
1280 fd2 = dup(file->fd);
1281 if (fd2 == -1) {
1282 goto failed;
1285 if (bitmap_query(smbw_file_bmap, fd2)) {
1286 DEBUG(0,("ERROR: fd already open in dup!\n"));
1287 errno = EIO;
1288 goto failed;
1291 file2 = SMB_MALLOC_P(struct smbw_file);
1292 if (!file2) {
1293 close(fd2);
1294 errno = ENOMEM;
1295 goto failed;
1298 ZERO_STRUCTP(file2);
1300 *file2 = *file;
1301 file2->fd = fd2;
1303 file->f->ref_count++;
1305 bitmap_set(smbw_file_bmap, fd2);
1307 DLIST_ADD(smbw_files, file2);
1309 smbw_busy--;
1310 return fd2;
1312 failed:
1313 smbw_busy--;
1314 return -1;
1318 /*****************************************************
1319 a wrapper for dup2()
1320 *******************************************************/
1321 int smbw_dup2(int fd, int fd2)
1323 struct smbw_file *file, *file2;
1325 smbw_busy++;
1327 file = smbw_file(fd);
1328 if (!file) {
1329 errno = EBADF;
1330 goto failed;
1333 if (bitmap_query(smbw_file_bmap, fd2)) {
1334 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1335 errno = EIO;
1336 goto failed;
1339 if (dup2(file->fd, fd2) != fd2) {
1340 goto failed;
1343 file2 = SMB_MALLOC_P(struct smbw_file);
1344 if (!file2) {
1345 close(fd2);
1346 errno = ENOMEM;
1347 goto failed;
1350 ZERO_STRUCTP(file2);
1352 *file2 = *file;
1353 file2->fd = fd2;
1355 file->f->ref_count++;
1357 bitmap_set(smbw_file_bmap, fd2);
1359 DLIST_ADD(smbw_files, file2);
1361 smbw_busy--;
1362 return fd2;
1364 failed:
1365 smbw_busy--;
1366 return -1;
1370 /*****************************************************
1371 close a connection to a server
1372 *******************************************************/
1373 static void smbw_srv_close(struct smbw_server *srv)
1375 smbw_busy++;
1377 cli_shutdown(&srv->cli);
1379 SAFE_FREE(srv->server_name);
1380 SAFE_FREE(srv->share_name);
1382 DLIST_REMOVE(smbw_srvs, srv);
1384 ZERO_STRUCTP(srv);
1386 SAFE_FREE(srv);
1388 smbw_busy--;
1391 /*****************************************************
1392 when we fork we have to close all connections and files
1393 in the child
1394 *******************************************************/
1395 int smbw_fork(void)
1397 pid_t child;
1398 int p[2];
1399 char c=0;
1400 pstring line;
1402 struct smbw_file *file, *next_file;
1403 struct smbw_server *srv, *next_srv;
1405 if (pipe(p)) return real_fork();
1407 child = real_fork();
1409 if (child) {
1410 /* block the parent for a moment until the sockets are
1411 closed */
1412 close(p[1]);
1413 read(p[0], &c, 1);
1414 close(p[0]);
1415 return child;
1418 close(p[0]);
1420 /* close all files */
1421 for (file=smbw_files;file;file=next_file) {
1422 next_file = file->next;
1423 close(file->fd);
1426 /* close all server connections */
1427 for (srv=smbw_srvs;srv;srv=next_srv) {
1428 next_srv = srv->next;
1429 smbw_srv_close(srv);
1432 slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
1433 smbw_setshared(line,smbw_cwd);
1435 /* unblock the parent */
1436 write(p[1], &c, 1);
1437 close(p[1]);
1439 /* and continue in the child */
1440 return 0;
1443 #ifndef NO_ACL_WRAPPER
1444 /*****************************************************
1445 say no to acls
1446 *******************************************************/
1447 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1449 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1450 errno = ENOSYS;
1451 return -1;
1453 #endif
1455 #ifndef NO_FACL_WRAPPER
1456 /*****************************************************
1457 say no to acls
1458 *******************************************************/
1459 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1461 if (cmd == GETACL || cmd == GETACLCNT) return 0;
1462 errno = ENOSYS;
1463 return -1;
1465 #endif
1467 #ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
1468 #ifdef HAVE_STAT64
1469 /* this can't be in wrapped.c because of include conflicts */
1470 void stat64_convert(struct stat *st, struct stat64 *st64)
1472 st64->st_size = st->st_size;
1473 st64->st_mode = st->st_mode;
1474 st64->st_ino = st->st_ino;
1475 st64->st_dev = st->st_dev;
1476 st64->st_rdev = st->st_rdev;
1477 st64->st_nlink = st->st_nlink;
1478 st64->st_uid = st->st_uid;
1479 st64->st_gid = st->st_gid;
1480 st64->st_atime = st->st_atime;
1481 st64->st_mtime = st->st_mtime;
1482 st64->st_ctime = st->st_ctime;
1483 #ifdef HAVE_STAT_ST_BLKSIZE
1484 st64->st_blksize = st->st_blksize;
1485 #endif
1486 #ifdef HAVE_STAT_ST_BLOCKS
1487 st64->st_blocks = st->st_blocks;
1488 #endif
1490 #endif
1492 #ifdef HAVE_READDIR64
1493 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1495 d64->d_ino = d->d_ino;
1496 d64->d_off = d->d_off;
1497 d64->d_reclen = d->d_reclen;
1498 pstrcpy(d64->d_name, d->d_name);
1500 #endif
1501 #endif
1504 #ifdef HAVE___XSTAT
1505 /* Definition of `struct stat' used in the linux kernel.. */
1506 struct kernel_stat {
1507 unsigned short int st_dev;
1508 unsigned short int __pad1;
1509 unsigned long int st_ino;
1510 unsigned short int st_mode;
1511 unsigned short int st_nlink;
1512 unsigned short int st_uid;
1513 unsigned short int st_gid;
1514 unsigned short int st_rdev;
1515 unsigned short int __pad2;
1516 unsigned long int st_size;
1517 unsigned long int st_blksize;
1518 unsigned long int st_blocks;
1519 unsigned long int st_atime_;
1520 unsigned long int __unused1;
1521 unsigned long int st_mtime_;
1522 unsigned long int __unused2;
1523 unsigned long int st_ctime_;
1524 unsigned long int __unused3;
1525 unsigned long int __unused4;
1526 unsigned long int __unused5;
1530 * Prototype for gcc in 'fussy' mode.
1532 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1533 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1535 #ifdef _STAT_VER_LINUX_OLD
1536 if (vers == _STAT_VER_LINUX_OLD) {
1537 memcpy(st, kbuf, sizeof(*st));
1538 return;
1540 #endif
1542 ZERO_STRUCTP(st);
1544 st->st_dev = kbuf->st_dev;
1545 st->st_ino = kbuf->st_ino;
1546 st->st_mode = kbuf->st_mode;
1547 st->st_nlink = kbuf->st_nlink;
1548 st->st_uid = kbuf->st_uid;
1549 st->st_gid = kbuf->st_gid;
1550 st->st_rdev = kbuf->st_rdev;
1551 st->st_size = kbuf->st_size;
1552 #ifdef HAVE_STAT_ST_BLKSIZE
1553 st->st_blksize = kbuf->st_blksize;
1554 #endif
1555 #ifdef HAVE_STAT_ST_BLOCKS
1556 st->st_blocks = kbuf->st_blocks;
1557 #endif
1558 st->st_atime = kbuf->st_atime_;
1559 st->st_mtime = kbuf->st_mtime_;
1560 st->st_ctime = kbuf->st_ctime_;
1562 #endif