s3: Plumb smb_filename through SMB_VFS_NTIMES
[sfrench/samba-autobuild/.git] / source3 / modules / vfs_cap.c
1 /*
2  * CAP VFS module for Samba 3.x Version 0.3
3  *
4  * Copyright (C) Tim Potter, 1999-2000
5  * Copyright (C) Alexander Bokovoy, 2002-2003
6  * Copyright (C) Stefan (metze) Metzmacher, 2003
7  * Copyright (C) TAKAHASHI Motonobu (monyo), 2003
8  * Copyright (C) Jeremy Allison, 2007
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "includes.h"
26
27 /* cap functions */
28 static char *capencode(TALLOC_CTX *ctx, const char *from);
29 static char *capdecode(TALLOC_CTX *ctx, const char *from);
30
31 static uint64_t cap_disk_free(vfs_handle_struct *handle, const char *path,
32         bool small_query, uint64_t *bsize,
33         uint64_t *dfree, uint64_t *dsize)
34 {
35         char *cappath = capencode(talloc_tos(), path);
36
37         if (!cappath) {
38                 errno = ENOMEM;
39                 return (uint64_t)-1;
40         }
41         return SMB_VFS_NEXT_DISK_FREE(handle, cappath, small_query, bsize,
42                                         dfree, dsize);
43 }
44
45 static SMB_STRUCT_DIR *cap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
46 {
47         char *capname = capencode(talloc_tos(), fname);
48
49         if (!capname) {
50                 errno = ENOMEM;
51                 return NULL;
52         }
53         return SMB_VFS_NEXT_OPENDIR(handle, capname, mask, attr);
54 }
55
56 static SMB_STRUCT_DIRENT *cap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
57 {
58         SMB_STRUCT_DIRENT *result;
59         SMB_STRUCT_DIRENT *newdirent;
60         char *newname;
61         size_t newnamelen;
62         DEBUG(3,("cap: cap_readdir\n"));
63
64         result = SMB_VFS_NEXT_READDIR(handle, dirp, NULL);
65         if (!result) {
66                 return NULL;
67         }
68
69         newname = capdecode(talloc_tos(), result->d_name);
70         if (!newname) {
71                 return NULL;
72         }
73         DEBUG(3,("cap: cap_readdir: %s\n", newname));
74         newnamelen = strlen(newname)+1;
75         newdirent = (SMB_STRUCT_DIRENT *)TALLOC_ARRAY(talloc_tos(),
76                         char,
77                         sizeof(SMB_STRUCT_DIRENT)+
78                                 newnamelen);
79         if (!newdirent) {
80                 return NULL;
81         }
82         memcpy(newdirent, result, sizeof(SMB_STRUCT_DIRENT));
83         memcpy(&newdirent->d_name, newname, newnamelen);
84         return newdirent;
85 }
86
87 static int cap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
88 {
89         char *cappath = capencode(talloc_tos(), path);
90
91         if (!cappath) {
92                 errno = ENOMEM;
93                 return -1;
94         }
95         return SMB_VFS_NEXT_MKDIR(handle, cappath, mode);
96 }
97
98 static int cap_rmdir(vfs_handle_struct *handle, const char *path)
99 {
100         char *cappath = capencode(talloc_tos(), path);
101
102         if (!cappath) {
103                 errno = ENOMEM;
104                 return -1;
105         }
106         return SMB_VFS_NEXT_RMDIR(handle, cappath);
107 }
108
109 static int cap_open(vfs_handle_struct *handle, struct smb_filename *smb_fname,
110                     files_struct *fsp, int flags, mode_t mode)
111 {
112         char *cappath;
113         char *tmp_base_name = NULL;
114         int ret;
115
116         cappath = capencode(talloc_tos(), smb_fname->base_name);
117
118         if (!cappath) {
119                 errno = ENOMEM;
120                 return -1;
121         }
122
123         tmp_base_name = smb_fname->base_name;
124         smb_fname->base_name = cappath;
125
126         DEBUG(3,("cap: cap_open for %s\n", smb_fname_str_dbg(smb_fname)));
127         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
128
129         smb_fname->base_name = tmp_base_name;
130         TALLOC_FREE(cappath);
131
132         return ret;
133 }
134
135 static int cap_rename(vfs_handle_struct *handle,
136                       const struct smb_filename *smb_fname_src,
137                       const struct smb_filename *smb_fname_dst)
138 {
139         char *capold = NULL;
140         char *capnew = NULL;
141         struct smb_filename *smb_fname_src_tmp = NULL;
142         struct smb_filename *smb_fname_dst_tmp = NULL;
143         NTSTATUS status;
144         int ret = -1;
145
146         capold = capencode(talloc_tos(), smb_fname_src->base_name);
147         capnew = capencode(talloc_tos(), smb_fname_dst->base_name);
148         if (!capold || !capnew) {
149                 errno = ENOMEM;
150                 goto out;
151         }
152
153         /* Setup temporary smb_filename structs. */
154         status = copy_smb_filename(talloc_tos(), smb_fname_src,
155                                    &smb_fname_src_tmp);
156         if (!NT_STATUS_IS_OK(status)) {
157                 errno = map_errno_from_nt_status(status);
158                 goto out;
159         }
160         status = copy_smb_filename(talloc_tos(), smb_fname_dst,
161                                    &smb_fname_dst_tmp);
162         if (!NT_STATUS_IS_OK(status)) {
163                 errno = map_errno_from_nt_status(status);
164                 goto out;
165         }
166
167         smb_fname_src_tmp->base_name = capold;
168         smb_fname_dst_tmp->base_name = capnew;
169
170         ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp,
171                                   smb_fname_dst_tmp);
172  out:
173         TALLOC_FREE(capold);
174         TALLOC_FREE(capnew);
175         TALLOC_FREE(smb_fname_src_tmp);
176         TALLOC_FREE(smb_fname_dst_tmp);
177
178         return ret;
179 }
180
181 static int cap_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
182 {
183         char *cappath;
184         char *tmp_base_name = NULL;
185         int ret;
186
187         cappath = capencode(talloc_tos(), smb_fname->base_name);
188
189         if (!cappath) {
190                 errno = ENOMEM;
191                 return -1;
192         }
193
194         tmp_base_name = smb_fname->base_name;
195         smb_fname->base_name = cappath;
196
197         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
198
199         smb_fname->base_name = tmp_base_name;
200         TALLOC_FREE(cappath);
201
202         return ret;
203 }
204
205 static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
206 {
207         char *cappath;
208         char *tmp_base_name = NULL;
209         int ret;
210
211         cappath = capencode(talloc_tos(), smb_fname->base_name);
212
213         if (!cappath) {
214                 errno = ENOMEM;
215                 return -1;
216         }
217
218         tmp_base_name = smb_fname->base_name;
219         smb_fname->base_name = cappath;
220
221         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
222
223         smb_fname->base_name = tmp_base_name;
224         TALLOC_FREE(cappath);
225
226         return ret;
227 }
228
229 static int cap_unlink(vfs_handle_struct *handle,
230                       const struct smb_filename *smb_fname)
231 {
232         struct smb_filename *smb_fname_tmp = NULL;
233         char *cappath = NULL;
234         NTSTATUS status;
235         int ret;
236
237         cappath = capencode(talloc_tos(), smb_fname->base_name);
238         if (!cappath) {
239                 errno = ENOMEM;
240                 return -1;
241         }
242
243         /* Setup temporary smb_filename structs. */
244         status = copy_smb_filename(talloc_tos(), smb_fname,
245                                    &smb_fname_tmp);
246         if (!NT_STATUS_IS_OK(status)) {
247                 errno = map_errno_from_nt_status(status);
248                 return -1;
249         }
250
251         smb_fname_tmp->base_name = cappath;
252
253         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
254
255         TALLOC_FREE(smb_fname_tmp);
256         return ret;
257 }
258
259 static int cap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
260 {
261         char *cappath = capencode(talloc_tos(), path);
262
263         if (!cappath) {
264                 errno = ENOMEM;
265                 return -1;
266         }
267         return SMB_VFS_NEXT_CHMOD(handle, cappath, mode);
268 }
269
270 static int cap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
271 {
272         char *cappath = capencode(talloc_tos(), path);
273
274         if (!cappath) {
275                 errno = ENOMEM;
276                 return -1;
277         }
278         return SMB_VFS_NEXT_CHOWN(handle, cappath, uid, gid);
279 }
280
281 static int cap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
282 {
283         char *cappath = capencode(talloc_tos(), path);
284
285         if (!cappath) {
286                 errno = ENOMEM;
287                 return -1;
288         }
289         return SMB_VFS_NEXT_LCHOWN(handle, cappath, uid, gid);
290 }
291
292 static int cap_chdir(vfs_handle_struct *handle, const char *path)
293 {
294         char *cappath = capencode(talloc_tos(), path);
295
296         if (!cappath) {
297                 errno = ENOMEM;
298                 return -1;
299         }
300         DEBUG(3,("cap: cap_chdir for %s\n", path));
301         return SMB_VFS_NEXT_CHDIR(handle, cappath);
302 }
303
304 static int cap_ntimes(vfs_handle_struct *handle,
305                       const struct smb_filename *smb_fname,
306                       struct smb_file_time *ft)
307 {
308         struct smb_filename *smb_fname_tmp = NULL;
309         char *cappath = NULL;
310         NTSTATUS status;
311         int ret;
312
313         cappath = capencode(talloc_tos(), smb_fname->base_name);
314
315         if (!cappath) {
316                 errno = ENOMEM;
317                 return -1;
318         }
319
320         /* Setup temporary smb_filename structs. */
321         status = copy_smb_filename(talloc_tos(), smb_fname,
322                                    &smb_fname_tmp);
323         if (!NT_STATUS_IS_OK(status)) {
324                 errno = map_errno_from_nt_status(status);
325                 return -1;
326         }
327
328         smb_fname_tmp->base_name = cappath;
329
330         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
331
332         TALLOC_FREE(smb_fname_tmp);
333         return ret;
334 }
335
336
337 static bool cap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
338 {
339         char *capold = capencode(talloc_tos(), oldpath);
340         char *capnew = capencode(talloc_tos(), newpath);
341
342         if (!capold || !capnew) {
343                 errno = ENOMEM;
344                 return -1;
345         }
346         return SMB_VFS_NEXT_SYMLINK(handle, capold, capnew);
347 }
348
349 static bool cap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
350 {
351         char *cappath = capencode(talloc_tos(), path);
352
353         if (!cappath) {
354                 errno = ENOMEM;
355                 return -1;
356         }
357         return SMB_VFS_NEXT_READLINK(handle, cappath, buf, bufsiz);
358 }
359
360 static int cap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
361 {
362         char *capold = capencode(talloc_tos(), oldpath);
363         char *capnew = capencode(talloc_tos(), newpath);
364
365         if (!capold || !capnew) {
366                 errno = ENOMEM;
367                 return -1;
368         }
369         return SMB_VFS_NEXT_LINK(handle, capold, capnew);
370 }
371
372 static int cap_mknod(vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev)
373 {
374         char *cappath = capencode(talloc_tos(), path);
375
376         if (!cappath) {
377                 errno = ENOMEM;
378                 return -1;
379         }
380         return SMB_VFS_NEXT_MKNOD(handle, cappath, mode, dev);
381 }
382
383 static char *cap_realpath(vfs_handle_struct *handle, const char *path, char *resolved_path)
384 {
385         /* monyo need capencode'ed and capdecode'ed? */
386         char *cappath = capencode(talloc_tos(), path);
387
388         if (!cappath) {
389                 errno = ENOMEM;
390                 return NULL;
391         }
392         return SMB_VFS_NEXT_REALPATH(handle, path, resolved_path);
393 }
394
395 static int cap_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
396 {
397         char *cappath = capencode(talloc_tos(), path);
398
399         /* If the underlying VFS doesn't have ACL support... */
400         if (!handle->vfs_next.ops.chmod_acl) {
401                 errno = ENOSYS;
402                 return -1;
403         }
404         if (!cappath) {
405                 errno = ENOMEM;
406                 return -1;
407         }
408         return SMB_VFS_NEXT_CHMOD_ACL(handle, cappath, mode);
409 }
410
411 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
412 {
413         char *cappath = capencode(talloc_tos(), path);
414
415         if (!cappath) {
416                 errno = ENOMEM;
417                 return (SMB_ACL_T)NULL;
418         }
419         return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cappath, type);
420 }
421
422 static int cap_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
423 {
424         char *cappath = capencode(talloc_tos(), path);
425
426         if (!cappath) {
427                 errno = ENOMEM;
428                 return -1;
429         }
430         return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cappath, acltype, theacl);
431 }
432
433 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
434 {
435         char *cappath = capencode(talloc_tos(), path);
436
437         if (!cappath) {
438                 errno = ENOMEM;
439                 return -1;
440         }
441         return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cappath);
442 }
443
444 static ssize_t cap_getxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size)
445 {
446         char *cappath = capencode(talloc_tos(), path);
447         char *capname = capencode(talloc_tos(), name);
448
449         if (!cappath || !capname) {
450                 errno = ENOMEM;
451                 return -1;
452         }
453         return SMB_VFS_NEXT_GETXATTR(handle, cappath, capname, value, size);
454 }
455
456 static ssize_t cap_lgetxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t
457 size)
458 {
459         char *cappath = capencode(talloc_tos(), path);
460         char *capname = capencode(talloc_tos(), name);
461
462         if (!cappath || !capname) {
463                 errno = ENOMEM;
464                 return -1;
465         }
466         return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size);
467 }
468
469 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
470 {
471         char *cappath = capencode(talloc_tos(), path);
472
473         if (!cappath) {
474                 errno = ENOMEM;
475                 return -1;
476         }
477         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
478 }
479
480 static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
481 {
482         char *cappath = capencode(talloc_tos(), path);
483
484         if (!cappath) {
485                 errno = ENOMEM;
486                 return -1;
487         }
488         return SMB_VFS_NEXT_LISTXATTR(handle, cappath, list, size);
489 }
490
491 static ssize_t cap_llistxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
492 {
493         char *cappath = capencode(talloc_tos(), path);
494
495         if (!cappath) {
496                 errno = ENOMEM;
497                 return -1;
498         }
499         return SMB_VFS_NEXT_LLISTXATTR(handle, cappath, list, size);
500 }
501
502 static int cap_removexattr(vfs_handle_struct *handle, const char *path, const char *name)
503 {
504         char *cappath = capencode(talloc_tos(), path);
505         char *capname = capencode(talloc_tos(), name);
506
507         if (!cappath || !capname) {
508                 errno = ENOMEM;
509                 return -1;
510         }
511         return SMB_VFS_NEXT_REMOVEXATTR(handle, cappath, capname);
512 }
513
514 static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const char *name)
515 {
516         char *cappath = capencode(talloc_tos(), path);
517         char *capname = capencode(talloc_tos(), name);
518
519         if (!cappath || !capname) {
520                 errno = ENOMEM;
521                 return -1;
522         }
523         return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname);
524 }
525
526 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
527 {
528         char *cappath = capencode(talloc_tos(), path);
529
530         if (!cappath) {
531                 errno = ENOMEM;
532                 return -1;
533         }
534         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
535 }
536
537 static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
538 {
539         char *cappath = capencode(talloc_tos(), path);
540         char *capname = capencode(talloc_tos(), name);
541
542         if (!cappath || !capname) {
543                 errno = ENOMEM;
544                 return -1;
545         }
546         return SMB_VFS_NEXT_SETXATTR(handle, cappath, capname, value, size, flags);
547 }
548
549 static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
550 {
551         char *cappath = capencode(talloc_tos(), path);
552         char *capname = capencode(talloc_tos(), name);
553
554         if (!cappath || !capname) {
555                 errno = ENOMEM;
556                 return -1;
557         }
558         return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags);
559 }
560
561 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
562 {
563         char *cappath = capencode(talloc_tos(), path);
564
565         if (!cappath) {
566                 errno = ENOMEM;
567                 return -1;
568         }
569         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
570 }
571
572 /* VFS operations structure */
573
574 static vfs_op_tuple cap_op_tuples[] = {
575
576         /* Disk operations */
577
578         {SMB_VFS_OP(cap_disk_free),                     SMB_VFS_OP_DISK_FREE,           SMB_VFS_LAYER_TRANSPARENT},
579
580         /* Directory operations */
581
582         {SMB_VFS_OP(cap_opendir),                       SMB_VFS_OP_OPENDIR,             SMB_VFS_LAYER_TRANSPARENT},
583         {SMB_VFS_OP(cap_readdir),                       SMB_VFS_OP_READDIR,             SMB_VFS_LAYER_TRANSPARENT},
584         {SMB_VFS_OP(cap_mkdir),                 SMB_VFS_OP_MKDIR,               SMB_VFS_LAYER_TRANSPARENT},
585         {SMB_VFS_OP(cap_rmdir),                 SMB_VFS_OP_RMDIR,               SMB_VFS_LAYER_TRANSPARENT},
586
587         /* File operations */
588
589         {SMB_VFS_OP(cap_open),                          SMB_VFS_OP_OPEN,                SMB_VFS_LAYER_TRANSPARENT},
590         {SMB_VFS_OP(cap_rename),                        SMB_VFS_OP_RENAME,              SMB_VFS_LAYER_TRANSPARENT},
591         {SMB_VFS_OP(cap_stat),                          SMB_VFS_OP_STAT,                SMB_VFS_LAYER_TRANSPARENT},
592         {SMB_VFS_OP(cap_lstat),                 SMB_VFS_OP_LSTAT,               SMB_VFS_LAYER_TRANSPARENT},
593         {SMB_VFS_OP(cap_unlink),                        SMB_VFS_OP_UNLINK,              SMB_VFS_LAYER_TRANSPARENT},
594         {SMB_VFS_OP(cap_chmod),                 SMB_VFS_OP_CHMOD,               SMB_VFS_LAYER_TRANSPARENT},
595         {SMB_VFS_OP(cap_chown),                 SMB_VFS_OP_CHOWN,               SMB_VFS_LAYER_TRANSPARENT},
596         {SMB_VFS_OP(cap_lchown),                SMB_VFS_OP_LCHOWN,              SMB_VFS_LAYER_TRANSPARENT},
597         {SMB_VFS_OP(cap_chdir),                 SMB_VFS_OP_CHDIR,               SMB_VFS_LAYER_TRANSPARENT},
598         {SMB_VFS_OP(cap_ntimes),                        SMB_VFS_OP_NTIMES,              SMB_VFS_LAYER_TRANSPARENT},
599         {SMB_VFS_OP(cap_symlink),                       SMB_VFS_OP_SYMLINK,             SMB_VFS_LAYER_TRANSPARENT},
600         {SMB_VFS_OP(cap_readlink),                      SMB_VFS_OP_READLINK,            SMB_VFS_LAYER_TRANSPARENT},
601         {SMB_VFS_OP(cap_link),                          SMB_VFS_OP_LINK,                SMB_VFS_LAYER_TRANSPARENT},
602         {SMB_VFS_OP(cap_mknod),                 SMB_VFS_OP_MKNOD,               SMB_VFS_LAYER_TRANSPARENT},
603         {SMB_VFS_OP(cap_realpath),                      SMB_VFS_OP_REALPATH,            SMB_VFS_LAYER_TRANSPARENT},
604
605         /* POSIX ACL operations */
606
607         {SMB_VFS_OP(cap_chmod_acl),                     SMB_VFS_OP_CHMOD_ACL,           SMB_VFS_LAYER_TRANSPARENT},
608
609         {SMB_VFS_OP(cap_sys_acl_get_file),              SMB_VFS_OP_SYS_ACL_GET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
610         {SMB_VFS_OP(cap_sys_acl_set_file),              SMB_VFS_OP_SYS_ACL_SET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
611         {SMB_VFS_OP(cap_sys_acl_delete_def_file),       SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,     SMB_VFS_LAYER_TRANSPARENT},
612
613         /* EA operations. */
614         {SMB_VFS_OP(cap_getxattr),                      SMB_VFS_OP_GETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
615         {SMB_VFS_OP(cap_lgetxattr),                     SMB_VFS_OP_LGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
616         {SMB_VFS_OP(cap_fgetxattr),                     SMB_VFS_OP_FGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
617         {SMB_VFS_OP(cap_listxattr),                     SMB_VFS_OP_LISTXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
618         {SMB_VFS_OP(cap_llistxattr),                    SMB_VFS_OP_LLISTXATTR,                  SMB_VFS_LAYER_TRANSPARENT},
619         {SMB_VFS_OP(cap_removexattr),                   SMB_VFS_OP_REMOVEXATTR,                 SMB_VFS_LAYER_TRANSPARENT},
620         {SMB_VFS_OP(cap_lremovexattr),                  SMB_VFS_OP_LREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
621         {SMB_VFS_OP(cap_fremovexattr),                  SMB_VFS_OP_FREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
622         {SMB_VFS_OP(cap_setxattr),                      SMB_VFS_OP_SETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
623         {SMB_VFS_OP(cap_lsetxattr),                     SMB_VFS_OP_LSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
624         {SMB_VFS_OP(cap_fsetxattr),                     SMB_VFS_OP_FSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
625
626         {NULL,                                          SMB_VFS_OP_NOOP,                        SMB_VFS_LAYER_NOOP}
627 };
628
629 NTSTATUS vfs_cap_init(void);
630 NTSTATUS vfs_cap_init(void)
631 {
632         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap", cap_op_tuples);
633 }
634
635 /* For CAP functions */
636 #define hex_tag ':'
637 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
638 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
639 #define is_hex(s)               ((s)[0] == hex_tag)
640
641 static unsigned char hex2bin_table[256] = {
642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
645 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
646 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
647 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
649 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
650 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
653 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
660 };
661 static unsigned char bin2hex_table[256] = "0123456789abcdef";
662
663 /*******************************************************************
664   original code -> ":xx"  - CAP format
665 ********************************************************************/
666
667 static char *capencode(TALLOC_CTX *ctx, const char *from)
668 {
669         char *out = NULL;
670         const char *p1;
671         char *to = NULL;
672         size_t len = 0;
673
674         for (p1 = from; *p1; p1++) {
675                 if ((unsigned char)*p1 >= 0x80) {
676                         len += 3;
677                 } else {
678                         len++;
679                 }
680         }
681         len++;
682
683         to = TALLOC_ARRAY(ctx, char, len);
684         if (!to) {
685                 return NULL;
686         }
687
688         for (out = to; *from;) {
689                 /* buffer husoku error */
690                 if ((unsigned char)*from >= 0x80) {
691                         *out++ = hex_tag;
692                         *out++ = bin2hex (((*from)>>4)&0x0f);
693                         *out++ = bin2hex ((*from)&0x0f);
694                         from++;
695                 } else {
696                         *out++ = *from++;
697                 }
698         }
699         *out = '\0';
700         return to;
701 }
702
703 /*******************************************************************
704   CAP -> original code
705 ********************************************************************/
706 /* ":xx" -> a byte */
707
708 static char *capdecode(TALLOC_CTX *ctx, const char *from)
709 {
710         const char *p1;
711         char *out = NULL;
712         char *to = NULL;
713         size_t len = 0;
714
715         for (p1 = from; *p1; len++) {
716                 if (is_hex(from)) {
717                         p1 += 3;
718                 } else {
719                         p1++;
720                 }
721         }
722
723         to = TALLOC_ARRAY(ctx, char, len);
724         if (!to) {
725                 return NULL;
726         }
727
728         for (out = to; *from;) {
729                 if (is_hex(from)) {
730                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
731                         from += 3;
732                 } else {
733                         *out++ = *from++;
734                 }
735         }
736         *out = '\0';
737         return to;
738 }