r6108: Added smbsh/smbwrapper for Linux to example/libsmbclient tree; provided more...
[nivanova/samba-autobuild/.git] / examples / libsmbclient / smbwrapper / smbw.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4    SMB wrapper functions
5    Copyright (C) Andrew Tridgell 1998
6    Copyright (C) Derrell Lipman 2003-2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdarg.h>
27 #include <assert.h>
28 #include "smbw.h"
29
30 int smbw_fd_map[__FD_SETSIZE];
31 int smbw_ref_count[__FD_SETSIZE];
32 char smbw_cwd[PATH_MAX];
33 char smbw_prefix[] = SMBW_PREFIX;
34
35 /* needs to be here because of dumb include files on some systems */
36 int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
37
38 int smbw_initialized = 0;
39
40 static int debug_level = 0;
41
42 static SMBCCTX *smbw_ctx;
43
44 extern int smbw_debug;
45
46
47 int smbw_ref(int client_fd, Ref_Count_Type type, ...)
48 {
49         va_list ap;
50
51         /* client id values begin at SMBC_BASE_FC. */
52         client_fd -= SMBC_BASE_FD;
53
54         va_start(ap, type);
55         switch(type)
56         {
57         case SMBW_RCT_Increment:
58                 return ++smbw_ref_count[client_fd];
59
60         case SMBW_RCT_Decrement:
61                 return --smbw_ref_count[client_fd];
62
63         case SMBW_RCT_Get:
64                 return smbw_ref_count[client_fd];
65
66         case SMBW_RCT_Set:
67                 return (smbw_ref_count[client_fd] = va_arg(ap, int));
68         }
69         va_end(ap);
70
71         /* never gets here */
72         return -1;
73 }
74
75
76 /*
77  * Return a username and password given a server and share name
78  *
79  * Returns 0 upon success;
80  * non-zero otherwise, and errno is set to indicate the error.
81  */
82 static void get_envvar_auth_data(const char *srv, 
83                                  const char *shr,
84                                  char *wg, int wglen, 
85                                  char *un, int unlen,
86                                  char *pw, int pwlen)
87 {
88         char *u;
89         char *p;
90         char *w;
91
92         /* Fall back to environment variables */
93
94         w = getenv("WORKGROUP");
95         if (w == NULL) w = "";
96
97         u = getenv("USER");
98         if (u == NULL) u = "";
99
100         p = getenv("PASSWORD");
101         if (p == NULL) p = "";
102
103         strncpy(wg, w, wglen);
104         strncpy(un, u, unlen);
105         strncpy(pw, p, pwlen);
106 }
107
108 static smbc_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
109
110 /*****************************************************
111 set the get auth data function
112 ******************************************************/
113 void smbw_set_auth_data_fn(smbc_get_auth_data_fn fn)
114 {
115         get_auth_data_fn = fn;
116 }
117
118
119 /*****************************************************
120 ensure that all connections are terminated upon exit
121 ******************************************************/
122 static void do_shutdown(void)
123 {
124         if (smbw_ctx != NULL) {
125                 smbc_free_context(smbw_ctx, 1);
126         }
127 }
128
129
130 /***************************************************** 
131 initialise structures
132 *******************************************************/
133 static void do_init(int is_real_startup)
134 {
135         int i;
136         char *p;
137
138         smbw_initialized = 1;   /* this must be first to avoid recursion! */
139
140         smbw_ctx = NULL;        /* don't free context until it's established */
141
142         /* initially, no file descriptors are mapped */
143         for (i = 0; i < __FD_SETSIZE; i++) {
144                 smbw_fd_map[i] = -1;
145                 smbw_ref_count[i] = 0;
146         }
147
148         /* See if we've been told to start in a particular directory */
149         if ((p=getenv("SMBW_DIR")) != NULL) {
150                 strncpy(smbw_cwd, p, PATH_MAX);
151
152                 /* we don't want the old directory to be busy */
153                 (* smbw_libc.chdir)("/");
154                 
155         } else {
156                 *smbw_cwd = '\0';
157         }
158
159         if ((p=getenv("DEBUG"))) {
160                 debug_level = atoi(p);
161         }
162
163         if ((smbw_ctx = smbc_new_context()) == NULL) {
164                 exit(1);
165         }
166         
167         smbw_ctx->debug = debug_level;
168         smbw_ctx->callbacks.auth_fn = get_auth_data_fn;
169         smbw_ctx->options.browse_max_lmb_count = 0;
170         smbw_ctx->options.urlencode_readdir_entries = 1;
171         smbw_ctx->options.one_share_per_server = 1;
172 //        smbw_cache_functions(smbw_ctx);
173         
174         if (smbc_init_context(smbw_ctx) == NULL) {
175                 exit(1);
176         }
177                 
178         smbc_set_context(smbw_ctx);
179
180         /* if not real startup, exit handler has already been established */
181         if (is_real_startup) {
182             atexit(do_shutdown);
183         }
184 }
185
186 /***************************************************** 
187 initialise structures, real start up vs a fork()
188 *******************************************************/
189 void smbw_init(void)
190 {
191     do_init(1);
192 }
193
194
195 /***************************************************** 
196 determine if a file descriptor is a smb one
197 *******************************************************/
198 int smbw_fd(int smbw_fd)
199 {
200         SMBW_INIT();
201
202         return (smbw_fd >= 0 &&
203                 smbw_fd < __FD_SETSIZE &&
204                 smbw_fd_map[smbw_fd] >= SMBC_BASE_FD); /* minimum smbc_ fd */
205 }
206
207
208 /***************************************************** 
209 determine if a path is a smb one
210 *******************************************************/
211 int smbw_path(const char *name)
212 {
213         int len;
214         int ret;
215         int saved_errno;
216
217         saved_errno = errno;
218
219         SMBW_INIT();
220
221         len = strlen(smbw_prefix);
222
223         ret = ((strncmp(name, smbw_prefix, len) == 0 &&
224                 (name[len] == '\0' || name[len] == '/')) ||
225                (*name != '/' && *smbw_cwd != '\0'));
226
227         errno = saved_errno;
228         return ret;
229 }
230
231
232 /***************************************************** 
233 remove redundent stuff from a filename
234 *******************************************************/
235 void smbw_clean_fname(char *name)
236 {
237         char *p, *p2;
238         int l;
239         int modified = 1;
240
241         if (!name) return;
242
243         DEBUG(10, ("Clean [%s]...\n", name));
244
245         while (modified) {
246                 modified = 0;
247
248                 if ((p=strstr(name,"/./"))) {
249                         modified = 1;
250                         while (*p) {
251                                 p[0] = p[2];
252                                 p++;
253                         }
254                         DEBUG(10, ("\tclean 1 (/./) produced [%s]\n", name));
255                 }
256
257                 if ((p=strstr(name,"//"))) {
258                         modified = 1;
259                         while (*p) {
260                                 p[0] = p[1];
261                                 p++;
262                         }
263                         DEBUG(10, ("\tclean 2 (//) produced [%s]\n", name));
264                 }
265
266                 if (strcmp(name,"/../")==0) {
267                         modified = 1;
268                         name[1] = 0;
269                         DEBUG(10,("\tclean 3 (^/../$) produced [%s]\n", name));
270                 }
271
272                 if ((p=strstr(name,"/../"))) {
273                         modified = 1;
274                         for (p2 = (p > name ? p-1 : p); p2 > name; p2--) {
275                                 if (p2[0] == '/') break;
276                         }
277                         if (p2 > name) p2++;
278                         while (*p2) {
279                                 p2[0] = p[3];
280                                 p2++;
281                                 p++;
282                         }
283                         DEBUG(10, ("\tclean 4 (/../) produced [%s]\n", name));
284                 }
285
286                 if (strcmp(name,"/..")==0) {
287                         modified = 1;
288                         name[1] = 0;
289                         DEBUG(10, ("\tclean 5 (^/..$) produced [%s]\n", name));
290                 }
291
292                 l = strlen(name);
293                 p = l>=3?(name+l-3):name;
294                 if (strcmp(p,"/..")==0) {
295                         modified = 1;
296                         for (p2=p-1;p2>name;p2--) {
297                                 if (p2[0] == '/') break;
298                         }
299                         if (p2==name) {
300                                 p[0] = '/';
301                                 p[1] = 0;
302                         } else {
303                                 p2[0] = 0;
304                         }
305                         DEBUG(10, ("\tclean 6 (/..) produced [%s]\n", name));
306                 }
307
308                 l = strlen(name);
309                 p = l>=2?(name+l-2):name;
310                 if (strcmp(p,"/.")==0) {
311                         modified = 1;
312                         if (p == name) {
313                                 p[1] = 0;
314                         } else {
315                                 p[0] = 0;
316                         }
317                         DEBUG(10, ("\tclean 7 (/.) produced [%s]\n", name));
318                 }
319
320                 if (strncmp(p=name,"./",2) == 0) {      
321                         modified = 1;
322                         do {
323                                 p[0] = p[2];
324                         } while (*p++);
325                         DEBUG(10, ("\tclean 8 (^./) produced [%s]\n", name));
326                 }
327
328                 l = strlen(p=name);
329                 if (l > 1 && p[l-1] == '/') {
330                         modified = 1;
331                         p[l-1] = 0;
332                         DEBUG(10, ("\tclean 9 (/) produced [%s]\n", name));
333                 }
334         }
335 }
336
337 void smbw_fix_path(const char *src, char *dest)
338 {
339         const char *p;
340         int len = strlen(smbw_prefix);
341
342         if (*src == '/') {
343                 for (p = src + len; *p == '/'; p++)
344                         ;
345                 snprintf(dest, PATH_MAX, "smb://%s", p);
346         } else {
347                 snprintf(dest, PATH_MAX, "%s/%s", smbw_cwd, src);
348         }
349
350         smbw_clean_fname(dest + 5);
351
352         DEBUG(10, ("smbw_fix_path(%s) returning [%s]\n", src, dest));
353 }
354
355
356
357 /***************************************************** 
358 a wrapper for open()
359 *******************************************************/
360 int smbw_open(const char *fname, int flags, mode_t mode)
361 {
362         int client_fd;
363         int smbw_fd;
364         char path[PATH_MAX];
365
366         SMBW_INIT();
367
368         if (!fname) {
369                 errno = EINVAL;
370                 return -1;
371         }
372
373         smbw_fd = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200);
374         if (smbw_fd == -1) {
375                 errno = EMFILE;
376                 return -1;
377         }
378
379         smbw_fix_path(fname, path);
380         if (flags == creat_bits) {
381                 client_fd =  smbc_creat(path, mode);
382         } else {
383                 client_fd = smbc_open(path, flags, mode);
384         }
385
386         if (client_fd < 0) {
387                 (* smbw_libc.close)(smbw_fd);
388                 return -1;
389         }
390
391         smbw_fd_map[smbw_fd] = client_fd;
392         smbw_ref(client_fd, SMBW_RCT_Increment);
393         return smbw_fd;
394 }
395
396
397 /***************************************************** 
398 a wrapper for pread()
399
400 there should really be an smbc_pread() to avoid the two
401 lseek()s required in this kludge.
402 *******************************************************/
403 ssize_t smbw_pread(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
404 {
405         int client_fd;
406         ssize_t ret;
407         int saved_errno;
408         SMBW_OFF_T old_ofs;
409         
410         client_fd = smbw_fd_map[smbw_fd];
411
412         if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
413             smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
414                 return -1;
415         }
416
417         if ((ret = smbc_read(client_fd, buf, count)) < 0) {
418                 saved_errno = errno;
419                 (void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
420                 errno = saved_errno;
421                 return -1;
422         }
423
424         return ret;
425 }
426
427 /***************************************************** 
428 a wrapper for read()
429 *******************************************************/
430 ssize_t smbw_read(int smbw_fd, void *buf, size_t count)
431 {
432         int client_fd;
433         
434         client_fd = smbw_fd_map[smbw_fd];
435
436         return smbc_read(client_fd, buf, count);
437 }
438
439         
440
441 /***************************************************** 
442 a wrapper for write()
443 *******************************************************/
444 ssize_t smbw_write(int smbw_fd, void *buf, size_t count)
445 {
446         int client_fd;
447
448         client_fd = smbw_fd_map[smbw_fd];
449
450         return smbc_write(client_fd, buf, count);
451 }
452
453 /***************************************************** 
454 a wrapper for pwrite()
455 *******************************************************/
456 ssize_t smbw_pwrite(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
457 {
458         int saved_errno;
459         int client_fd;
460         ssize_t ret;
461         SMBW_OFF_T old_ofs;
462         
463         client_fd = smbw_fd_map[smbw_fd];
464
465         if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
466             smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
467                 return -1;
468         }
469
470         if ((ret = smbc_write(client_fd, buf, count)) < 0) {
471                 saved_errno = errno;
472                 (void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
473                 errno = saved_errno;
474                 return -1;
475         }
476
477         return ret;
478 }
479
480 /***************************************************** 
481 a wrapper for close()
482 *******************************************************/
483 int smbw_close(int smbw_fd)
484 {
485         int client_fd;
486
487         client_fd = smbw_fd_map[smbw_fd];
488
489         if (smbw_ref(client_fd, SMBW_RCT_Decrement) > 0) {
490                 return 0;
491         }
492         
493         (* smbw_libc.close)(smbw_fd);
494         smbw_fd_map[smbw_fd] = -1;
495         return smbc_close(client_fd);
496 }
497
498
499 /***************************************************** 
500 a wrapper for fcntl()
501 *******************************************************/
502 int smbw_fcntl(int smbw_fd, int cmd, long arg)
503 {
504         return 0;
505 }
506
507
508 /***************************************************** 
509 a wrapper for access()
510 *******************************************************/
511 int smbw_access(const char *name, int mode)
512 {
513         struct SMBW_stat st;
514
515         SMBW_INIT();
516
517         if (smbw_stat(name, &st)) return -1;
518
519         if (((mode & R_OK) && !(st.s_mode & S_IRUSR)) ||
520             ((mode & W_OK) && !(st.s_mode & S_IWUSR)) ||
521             ((mode & X_OK) && !(st.s_mode & S_IXUSR))) {
522                 errno = EACCES;
523                 return -1;
524         }
525         
526         return 0;
527 }
528
529 /***************************************************** 
530 a wrapper for readlink() - needed for correct errno setting
531 *******************************************************/
532 int smbw_readlink(const char *fname, char *buf, size_t bufsize)
533 {
534         struct SMBW_stat st;
535         int ret;
536
537         SMBW_INIT();
538
539         ret = smbw_stat(fname, &st);
540         if (ret != 0) {
541                 return -1;
542         }
543         
544         /* it exists - say it isn't a link */
545         errno = EINVAL;
546         return -1;
547 }
548
549
550 /***************************************************** 
551 a wrapper for unlink()
552 *******************************************************/
553 int smbw_unlink(const char *fname)
554 {
555         char path[PATH_MAX];
556         
557         SMBW_INIT();
558
559         smbw_fix_path(fname, path);
560         return smbc_unlink(path);
561 }
562
563
564 /***************************************************** 
565 a wrapper for rename()
566 *******************************************************/
567 int smbw_rename(const char *oldname, const char *newname)
568 {
569         char path_old[PATH_MAX];
570         char path_new[PATH_MAX];
571
572         SMBW_INIT();
573
574         smbw_fix_path(oldname, path_old);
575         smbw_fix_path(newname, path_new);
576         return smbc_rename(path_old, path_new);
577 }
578
579
580 /***************************************************** 
581 a wrapper for utimes
582 *******************************************************/
583 int smbw_utimes(const char *fname, void *buf)
584 {
585         char path[PATH_MAX];
586
587         smbw_fix_path(fname, path);
588         return smbc_utimes(path, buf);
589 }
590
591
592 /***************************************************** 
593 a wrapper for utime 
594 *******************************************************/
595 int smbw_utime(const char *fname, void *buf)
596 {
597         char path[PATH_MAX];
598
599         smbw_fix_path(fname, path);
600         return smbc_utime(path, buf);
601 }
602
603 /***************************************************** 
604 a wrapper for chown()
605 *******************************************************/
606 int smbw_chown(const char *fname, uid_t owner, gid_t group)
607 {
608         /* always indiciate that this is not supported. */
609         errno = ENOTSUP;
610         return -1;
611 }
612
613 /***************************************************** 
614 a wrapper for chmod()
615 *******************************************************/
616 int smbw_chmod(const char *fname, mode_t newmode)
617 {
618         char path[PATH_MAX];
619
620         smbw_fix_path(fname, path);
621         return smbc_chmod(path, newmode);
622 }
623
624
625 /***************************************************** 
626 a wrapper for lseek()
627 *******************************************************/
628 SMBW_OFF_T smbw_lseek(int smbw_fd,
629                       SMBW_OFF_T offset,
630                       int whence)
631 {
632         int client_fd;
633         SMBW_OFF_T ret;
634         
635         client_fd = smbw_fd_map[smbw_fd];
636
637         ret = smbc_lseek(client_fd, offset, whence);
638         if (smbw_debug)
639         {
640                 printf("smbw_lseek(%d/%d, 0x%llx) returned 0x%llx\n",
641                        smbw_fd, client_fd,
642                        (unsigned long long) offset,
643                        (unsigned long long) ret);
644         }
645         return ret;
646 }
647
648 /***************************************************** 
649 a wrapper for dup()
650 *******************************************************/
651 int smbw_dup(int smbw_fd)
652 {
653         int fd2;
654
655         fd2 = (smbw_libc.dup)(smbw_fd);
656         if (fd2 == -1) {
657                 return -1;
658         }
659
660         smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
661         smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
662         return fd2;
663 }
664
665
666 /***************************************************** 
667 a wrapper for dup2()
668 *******************************************************/
669 int smbw_dup2(int smbw_fd, int fd2)
670 {
671         if ((* smbw_libc.dup2)(smbw_fd, fd2) != fd2) {
672                 return -1;
673         }
674
675         smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
676         smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
677         return fd2;
678 }
679
680
681 /***************************************************** 
682 when we fork we have to close all connections and files
683 in the child
684 *******************************************************/
685 int smbw_fork(void)
686 {
687         int i;
688         pid_t child_pid;
689         int p[2];
690         char c = 0;
691
692         SMBW_INIT();
693
694         if (pipe(p)) return (* smbw_libc.fork)();
695
696         child_pid = (* smbw_libc.fork)();
697
698         if (child_pid) {
699                 /* block the parent for a moment until the sockets are
700                    closed */
701                 (* smbw_libc.close)(p[1]);
702                 (* smbw_libc.read)(p[0], &c, 1);
703                 (* smbw_libc.close)(p[0]);
704                 return child_pid;
705         }
706
707         (* smbw_libc.close)(p[0]);
708
709         /* close all server connections and locally-opened files */
710         for (i = 0; i < __FD_SETSIZE; i++) {
711                 if (smbw_fd_map[i] > 0 &&
712                     smbw_ref(smbw_fd_map[i], SMBW_RCT_Get) > 0) {
713                         
714                         smbc_close(smbw_fd_map[i]);
715                         smbw_ref(smbw_fd_map[i], SMBW_RCT_Set, 0);
716                         (* smbw_libc.close)(i);
717                 }
718
719                 smbw_fd_map[i] = -1;
720         }
721
722         /* unblock the parent */
723         write(p[1], &c, 1);
724         (* smbw_libc.close)(p[1]);
725
726         /* specify directory to start in, if it's simulated smb */
727         if (*smbw_cwd != '\0') {
728                 setenv("SMBW_DIR", smbw_cwd, 1);
729         } else {
730                 unsetenv("SMBW_DIR");
731         }
732
733         /* Re-initialize this library for the child */
734         do_init(0);
735
736         /* and continue in the child */
737         return 0;
738 }
739
740 int smbw_setxattr(const char *fname,
741                   const char *name,
742                   const void *value,
743                   size_t size,
744                   int flags)
745 {
746         char path[PATH_MAX];
747
748         if (strcmp(name, "system.posix_acl_access") == 0)
749         {
750                 name = "system.*";
751         }
752
753         smbw_fix_path(fname, path);
754         return smbc_setxattr(path, name, value, size, flags);
755 }
756
757 int smbw_lsetxattr(const char *fname,
758                    const char *name,
759                    const void *value,
760                    size_t size,
761                    int flags)
762 {
763         char path[PATH_MAX];
764
765         if (strcmp(name, "system.posix_acl_access") == 0)
766         {
767                 name = "system.*";
768         }
769
770         smbw_fix_path(fname, path);
771         return smbc_lsetxattr(path, name, value, size, flags);
772 }
773
774 int smbw_fsetxattr(int smbw_fd,
775                    const char *name,
776                    const void *value,
777                    size_t size,
778                    int flags)
779 {
780         int client_fd;
781         
782         if (strcmp(name, "system.posix_acl_access") == 0)
783         {
784                 name = "system.*";
785         }
786
787         client_fd = smbw_fd_map[smbw_fd];
788         return smbc_fsetxattr(client_fd, name, value, size, flags);
789 }
790
791 int smbw_getxattr(const char *fname,
792                   const char *name,
793                   const void *value,
794                   size_t size)
795 {
796         char path[PATH_MAX];
797
798         if (strcmp(name, "system.posix_acl_access") == 0)
799         {
800                 name = "system.*";
801         }
802
803         smbw_fix_path(fname, path);
804
805         return smbc_getxattr(path, name, value, size);
806 }
807
808 int smbw_lgetxattr(const char *fname,
809                    const char *name,
810                    const void *value,
811                    size_t size)
812 {
813         char path[PATH_MAX];
814
815         if (strcmp(name, "system.posix_acl_access") == 0)
816         {
817                 name = "system.*";
818         }
819
820         smbw_fix_path(fname, path);
821         return smbc_lgetxattr(path, name, value, size);
822 }
823
824 int smbw_fgetxattr(int smbw_fd,
825                    const char *name,
826                    const void *value,
827                    size_t size)
828 {
829         int client_fd;
830         
831         if (strcmp(name, "system.posix_acl_access") == 0)
832         {
833                 name = "system.*";
834         }
835
836         client_fd = smbw_fd_map[smbw_fd];
837         return smbc_fgetxattr(client_fd, name, value, size);
838 }
839
840 int smbw_removexattr(const char *fname,
841                      const char *name)
842 {
843         char path[PATH_MAX];
844
845         if (strcmp(name, "system.posix_acl_access") == 0)
846         {
847                 name = "system.*";
848         }
849
850         smbw_fix_path(fname, path);
851         return smbc_removexattr(path, name);
852 }
853
854 int smbw_lremovexattr(const char *fname,
855                       const char *name)
856 {
857         char path[PATH_MAX];
858
859         if (strcmp(name, "system.posix_acl_access") == 0)
860         {
861                 name = "system.*";
862         }
863
864         smbw_fix_path(fname, path);
865         return smbc_lremovexattr(path, name);
866 }
867
868 int smbw_fremovexattr(int smbw_fd,
869                       const char *name)
870 {
871         int client_fd;
872         
873         if (strcmp(name, "system.posix_acl_access") == 0)
874         {
875                 name = "system.*";
876         }
877
878         client_fd = smbw_fd_map[smbw_fd];
879         return smbc_fremovexattr(client_fd, name);
880 }
881
882 int smbw_listxattr(const char *fname,
883                    char *list,
884                    size_t size)
885 {
886         char path[PATH_MAX];
887
888         smbw_fix_path(fname, path);
889         return smbc_listxattr(path, list, size);
890 }
891
892 int smbw_llistxattr(const char *fname,
893                     char *list,
894                     size_t size)
895 {
896         char path[PATH_MAX];
897
898         smbw_fix_path(fname, path);
899         return smbc_llistxattr(path, list, size);
900 }
901
902 int smbw_flistxattr(int smbw_fd,
903                     char *list,
904                     size_t size)
905 {
906         int client_fd;
907         
908         client_fd = smbw_fd_map[smbw_fd];
909         return smbc_flistxattr(client_fd, list, size);
910 }