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