1/* 2 Copyright (c) 2004 Didier Gautheron 3 Copyright (c) 2009 Frank Lahm 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 19*/ 20#ifdef HAVE_CONFIG_H 21#include "config.h" 22#endif /* HAVE_CONFIG_H */ 23 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <unistd.h> 27#include <string.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <libgen.h> 31 32#include <atalk/afp.h> 33#include <atalk/adouble.h> 34#include <atalk/ea.h> 35#include <atalk/acl.h> 36#include <atalk/logger.h> 37#include <atalk/util.h> 38#include <atalk/volume.h> 39#include <atalk/vfs.h> 40#include <atalk/directory.h> 41#include <atalk/unix.h> 42#include <atalk/errchk.h> 43#include <atalk/bstrlib.h> 44#include <atalk/bstradd.h> 45#include <atalk/compat.h> 46 47struct perm { 48 uid_t uid; 49 gid_t gid; 50}; 51 52typedef int (*rf_loop)(const struct vol *, struct dirent *, char *, void *, int); 53 54/* ----------------------------- */ 55static int 56for_each_adouble(const char *from, const char *name, rf_loop fn, const struct vol *vol, void *data, int flag) 57{ 58 char buf[ MAXPATHLEN + 1]; 59 char *m; 60 DIR *dp; 61 struct dirent *de; 62 int ret; 63 64 65 if (NULL == ( dp = opendir( name)) ) { 66 if (!flag) { 67 LOG(log_error, logtype_afpd, "%s: opendir %s: %s", from, fullpathname(name),strerror(errno) ); 68 return -1; 69 } 70 return 0; 71 } 72 strlcpy( buf, name, sizeof(buf)); 73 strlcat( buf, "/", sizeof(buf) ); 74 m = strchr( buf, '\0' ); 75 ret = 0; 76 while ((de = readdir(dp))) { 77 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { 78 continue; 79 } 80 81 strlcat(buf, de->d_name, sizeof(buf)); 82 if (fn && (ret = fn(vol, de, buf, data, flag))) { 83 closedir(dp); 84 return ret; 85 } 86 *m = 0; 87 } 88 closedir(dp); 89 return ret; 90} 91 92static int netatalk_name(const char *name) 93{ 94 return strcmp(name,".AppleDB") && strcmp(name,".AppleDesktop"); 95} 96 97/******************************************************************************* 98 * classic adouble format 99 *******************************************************************************/ 100 101static int validupath_adouble(VFS_FUNC_ARGS_VALIDUPATH) 102{ 103 if (name[0] != '.') 104 return 1; 105 106 return netatalk_name(name) && strcmp(name,".AppleDouble") && strcasecmp(name,".Parent"); 107} 108 109/* ----------------- */ 110static int RF_chown_adouble(VFS_FUNC_ARGS_CHOWN) 111{ 112 struct stat st; 113 const char *ad_p; 114 115 ad_p = vol->ad_path(path, ADFLAGS_HF ); 116 117 if ( stat( ad_p, &st ) < 0 ) 118 return 0; /* ignore */ 119 120 return chown( ad_p, uid, gid ); 121} 122 123/* ----------------- */ 124static int RF_renamedir_adouble(VFS_FUNC_ARGS_RENAMEDIR) 125{ 126 return 0; 127} 128 129/* ----------------- */ 130static int deletecurdir_adouble_loop(const struct vol *vol, struct dirent *de, char *name, void *data _U_, int flag _U_) 131{ 132 struct stat st; 133 int err; 134 135 /* bail if the file exists in the current directory. 136 * note: this will not fail with dangling symlinks */ 137 138 if (lstat(de->d_name, &st) == 0) 139 return AFPERR_DIRNEMPT; 140 141 if ((err = netatalk_unlink(name))) 142 return err; 143 144 return 0; 145} 146 147static int RF_deletecurdir_adouble(VFS_FUNC_ARGS_DELETECURDIR) 148{ 149 int err; 150 151 /* delete stray .AppleDouble files. this happens to get .Parent files 152 as well. */ 153 if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, vol, NULL, 1))) 154 return err; 155 return netatalk_rmdir(-1, ".AppleDouble" ); 156} 157 158/* ----------------- */ 159static int adouble_setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat *st) 160{ 161 return setfilmode(vol, name, ad_hf_mode(mode), st); 162} 163 164static int RF_setfilmode_adouble(VFS_FUNC_ARGS_SETFILEMODE) 165{ 166 return adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_HF ), mode, st); 167} 168 169/* ----------------- */ 170static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE) 171{ 172 const char *adouble = vol->ad_path(name, ADFLAGS_DIR ); 173 174 if (dir_rx_set(mode)) { 175 if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 176 return -1; 177 } 178 179 if (adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_DIR ), mode, st) < 0) 180 return -1; 181 182 if (!dir_rx_set(mode)) { 183 if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 184 return -1 ; 185 } 186 return 0; 187} 188 189/* ----------------- */ 190static int setdirmode_adouble_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag) 191{ 192 mode_t hf_mode = *(mode_t *)data; 193 struct stat st; 194 195 if (ostat(name, &st, vol_syml_opt(vol)) < 0 ) { 196 if (flag) 197 return 0; 198 LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) ); 199 } 200 else if (!S_ISDIR(st.st_mode)) { 201 if (setfilmode(vol, name, hf_mode, &st) < 0) { 202 /* FIXME what do we do then? */ 203 } 204 } 205 return 0; 206} 207 208static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE) 209{ 210 mode_t hf_mode = ad_hf_mode(mode); 211 const char *adouble = vol->ad_path(name, ADFLAGS_DIR ); 212 const char *adouble_p = ad_dir(adouble); 213 214 if (dir_rx_set(mode)) { 215 if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 216 return -1; 217 } 218 219 if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, vol, &hf_mode, 0)) 220 return -1; 221 222 if (!dir_rx_set(mode)) { 223 if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 224 return -1 ; 225 } 226 return 0; 227} 228 229static int RF_setdirowner_adouble(VFS_FUNC_ARGS_SETDIROWNER) 230{ 231 if (lchown(".AppleDouble", uid, gid) < 0 && errno != EPERM ) { 232 LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", 233 uid, gid,fullpathname(".AppleDouble"), strerror(errno)); 234 } 235 return 0; 236} 237 238/* ----------------- */ 239static int RF_deletefile_adouble(VFS_FUNC_ARGS_DELETEFILE) 240{ 241 return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF)); 242} 243 244/* ----------------- */ 245static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE) 246{ 247 char adsrc[ MAXPATHLEN + 1]; 248 int err = 0; 249 250 strcpy( adsrc, vol->ad_path(src, 0 )); 251 if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) { 252 struct stat st; 253 254 err = errno; 255 if (errno == ENOENT) { 256 struct adouble ad; 257 258 if (ostatat(dirfd, adsrc, &st, vol_syml_opt(vol))) /* source has no ressource fork, */ 259 return 0; 260 261 /* We are here because : 262 * -there's no dest folder. 263 * -there's no .AppleDouble in the dest folder. 264 * if we use the struct adouble passed in parameter it will not 265 * create .AppleDouble if the file is already opened, so we 266 * use a diff one, it's not a pb,ie it's not the same file, yet. 267 */ 268 ad_init(&ad, vol); 269 if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) == 0) { 270 ad_close(&ad, ADFLAGS_HF); 271 if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) ) 272 err = 0; 273 else 274 err = errno; 275 } 276 else { /* it's something else, bail out */ 277 err = errno; 278 } 279 } 280 } 281 if (err) { 282 errno = err; 283 return -1; 284 } 285 return 0; 286} 287 288static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE) 289/* const struct vol *vol, int sfd, const char *src, const char *dst */ 290{ 291 EC_INIT; 292 bstring s = NULL, d = NULL; 293 char *dup1 = NULL; 294 char *dup2 = NULL; 295 char *dup3 = NULL; 296 char *dup4 = NULL; 297 const char *name = NULL; 298 const char *dir = NULL; 299 300 struct stat st; 301 EC_ZERO(stat(dst, &st)); 302 303 if (S_ISDIR(st.st_mode)) { 304 /* build src path to AppleDouble file*/ 305 EC_NULL(s = bfromcstr(src)); 306 EC_ZERO(bcatcstr(s, "/.AppleDouble/.Parent")); 307 308 /* build dst path to AppleDouble file*/ 309 EC_NULL(d = bfromcstr(dst)); 310 EC_ZERO(bcatcstr(d, "/.AppleDouble/.Parent")); 311 } else { 312 /* get basename */ 313 314 /* build src path to AppleDouble file*/ 315 EC_NULL(dup1 = strdup(src)); 316 EC_NULL(name = basename(strdup(dup1))); 317 318 EC_NULL(dup2 = strdup(src)); 319 EC_NULL(dir = dirname(dup2)); 320 EC_NULL(s = bfromcstr(dir)); 321 EC_ZERO(bcatcstr(s, "/.AppleDouble/")); 322 EC_ZERO(bcatcstr(s, name)); 323 324 /* build dst path to AppleDouble file*/ 325 EC_NULL(dup4 = strdup(dst)); 326 EC_NULL(name = basename(strdup(dup4))); 327 328 EC_NULL(dup3 = strdup(dst)); 329 EC_NULL(dir = dirname(dup3)); 330 EC_NULL(d = bfromcstr(dir)); 331 EC_ZERO(bcatcstr(d, "/.AppleDouble/")); 332 EC_ZERO(bcatcstr(d, name)); 333 } 334 335 /* ignore errors */ 336 if (copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666) != 0) 337 if (errno != ENOENT) 338 EC_FAIL; 339 340EC_CLEANUP: 341 bdestroy(s); 342 bdestroy(d); 343 if (dup1) free(dup1); 344 if (dup2) free(dup2); 345 if (dup3) free(dup3); 346 if (dup4) free(dup4); 347 348 EC_EXIT; 349} 350 351#ifdef HAVE_SOLARIS_ACLS 352static int RF_solaris_acl(VFS_FUNC_ARGS_ACL) 353{ 354 static char buf[ MAXPATHLEN + 1]; 355 struct stat st; 356 int len; 357 358 if ((stat(path, &st)) != 0) { 359 if (errno == ENOENT) 360 return AFP_OK; 361 return AFPERR_MISC; 362 } 363 if (!S_ISDIR(st.st_mode)) { 364 /* set ACL on ressource fork */ 365 if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0) 366 return AFPERR_MISC; 367 } 368 return AFP_OK; 369} 370 371static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) 372{ 373 int ret; 374 static char buf[ MAXPATHLEN + 1]; 375 int len; 376 377 if (dir) 378 return AFP_OK; 379 380 /* remove ACL from ressource fork */ 381 if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK) { 382 if (errno == ENOENT) 383 return AFP_OK; 384 return ret; 385 } 386 387 return AFP_OK; 388} 389#endif 390 391#ifdef HAVE_POSIX_ACLS 392static int RF_posix_acl(VFS_FUNC_ARGS_ACL) 393{ 394 EC_INIT; 395 struct stat st; 396 397 if (stat(path, &st) == -1) 398 EC_FAIL; 399 400 if (!S_ISDIR(st.st_mode)) { 401 /* set ACL on ressource fork */ 402 EC_ZERO_ERR( acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl), AFPERR_MISC ); 403 } 404 405EC_CLEANUP: 406 if (errno == ENOENT) 407 EC_STATUS(AFP_OK); 408 EC_EXIT; 409} 410 411static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) 412{ 413 EC_INIT; 414 415 if (dir) 416 EC_EXIT_STATUS(AFP_OK); 417 418 /* remove ACL from ressource fork */ 419 EC_ZERO_ERR( remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC ); 420 421EC_CLEANUP: 422 if (errno == ENOENT) 423 EC_STATUS(AFP_OK); 424 EC_EXIT; 425} 426#endif 427 428/************************************************************************* 429 * EA adouble format 430 ************************************************************************/ 431static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH) 432{ 433 if (name[0] != '.') 434 return 1; 435 436#ifndef HAVE_EAFD 437 if (name[1] == '_') 438 return ad_valid_header_osx(name); 439#endif 440 return netatalk_name(name); 441} 442 443/* ----------------- */ 444static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN) 445{ 446#ifndef HAVE_EAFD 447 return chown(vol->ad_path(path, ADFLAGS_HF ), uid, gid); 448#endif 449 return 0; 450} 451 452/* ---------------- */ 453static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR) 454{ 455 return 0; 456} 457 458/* Returns 1 if the entry is NOT an ._ file */ 459static int deletecurdir_ea_osx_chkifempty_loop(const struct vol *vol, struct dirent *de, char *name, void *data _U_, int flag _U_) 460{ 461 if (de->d_name[0] != '.' || de->d_name[0] == '_') 462 return 1; 463 464 return 0; 465} 466 467static int deletecurdir_ea_osx_loop(const struct vol *vol, struct dirent *de, char *name, void *data _U_, int flag _U_) 468{ 469 int ret; 470 struct stat sb; 471 472 if (strncmp(name, "._", strlen("._")) == 0) { 473 if (lstat(name, &sb) != 0) 474 return -1; 475 if (S_ISREG(sb.st_mode)) 476 if ((ret = netatalk_unlink(name)) != 0) 477 return ret; 478 } 479 480 return 0; 481} 482 483/* ---------------- */ 484static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR) 485{ 486#ifndef HAVE_EAFD 487 int err; 488 /* delete stray ._AppleDouble files */ 489 if ((err = for_each_adouble("deletecurdir_ea_osx", ".", 490 deletecurdir_ea_osx_loop, 491 vol, NULL, 0)) != 0) 492 return err; 493 494#endif 495 return 0; 496} 497 498/* ---------------- */ 499static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE) 500{ 501#ifndef HAVE_EAFD 502#endif 503 return 0; 504} 505 506static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE) 507{ 508#ifndef HAVE_EAFD 509 return adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_HF ), mode, st); 510#endif 511 return 0; 512} 513 514/* ---------------- */ 515static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE) 516{ 517#ifndef HAVE_EAFD 518#endif 519 return 0; 520} 521 522/* ---------------- */ 523static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER) 524{ 525#ifndef HAVE_EAFD 526#endif 527 return 0; 528} 529 530static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE) 531{ 532#ifndef HAVE_EAFD 533 return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF)); 534#endif 535 return 0; 536} 537static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE) 538{ 539#ifdef HAVE_EAFD 540 /* the EA VFS module does this all for us */ 541 return 0; 542#endif 543 544 EC_INIT; 545 bstring s = NULL, d = NULL; 546 char *dup1 = NULL; 547 char *dup2 = NULL; 548 char *dup3 = NULL; 549 char *dup4 = NULL; 550 const char *name = NULL; 551 const char *dir = NULL; 552 553 /* get basename */ 554 555 /* build src path to ._ file*/ 556 EC_NULL(dup1 = strdup(src)); 557 EC_NULL(name = basename(strdup(dup1))); 558 559 EC_NULL(dup2 = strdup(src)); 560 EC_NULL(dir = dirname(dup2)); 561 EC_NULL(s = bfromcstr(dir)); 562 EC_ZERO(bcatcstr(s, "/._")); 563 EC_ZERO(bcatcstr(s, name)); 564 565 /* build dst path to ._file*/ 566 EC_NULL(dup4 = strdup(dst)); 567 EC_NULL(name = basename(strdup(dup4))); 568 569 EC_NULL(dup3 = strdup(dst)); 570 EC_NULL(dir = dirname(dup3)); 571 EC_NULL(d = bfromcstr(dir)); 572 EC_ZERO(bcatcstr(d, "/._")); 573 EC_ZERO(bcatcstr(d, name)); 574 575 if (copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666) != 0) { 576 switch (errno) { 577 case ENOENT: 578 break; 579 default: 580 LOG(log_error, logtype_afpd, "[VFS] copyfile(\"%s\" -> \"%s\"): %s", 581 cfrombstr(s), cfrombstr(d), strerror(errno)); 582 EC_FAIL; 583 584 } 585 } 586 587EC_CLEANUP: 588 bdestroy(s); 589 bdestroy(d); 590 free(dup1); 591 free(dup2); 592 free(dup3); 593 free(dup4); 594 EC_EXIT; 595} 596 597/* ---------------- */ 598static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE) 599{ 600#ifndef HAVE_EAFD 601 char adsrc[ MAXPATHLEN + 1]; 602 int err = 0; 603 604 strcpy( adsrc, vol->ad_path(src, 0 )); 605 606 if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) { 607 struct stat st; 608 609 err = errno; 610 if (errno == ENOENT && ostatat(dirfd, adsrc, &st, vol_syml_opt(vol))) /* source has no ressource fork, */ 611 return 0; 612 errno = err; 613 return -1; 614 } 615 return 0; 616#endif 617 return 0; 618} 619 620/******************************************************************************************** 621 * VFS chaining 622 ********************************************************************************************/ 623 624/* 625 * Up until we really start stacking many VFS modules on top of one another or use 626 * dynamic module loading like we do for UAMs, up until then we just stack VFS modules 627 * via an fixed size array. 628 * All VFS funcs must return AFP_ERR codes. When a func in the chain returns an error 629 * this error code will be returned to the caller, BUT the chain in followed and all 630 * following funcs are called in order to give them a chance. 631 */ 632 633/* 634 * Define most VFS funcs with macros as they all do the same. 635 * Only "ad_path" and "validupath" will NOT do stacking and only 636 * call the func from the first module. 637 */ 638 639#define VFS_MFUNC(name, args, vars) \ 640 static int vfs_ ## name(args) \ 641 { \ 642 int i = 0, ret = AFP_OK, err; \ 643 while (vol->vfs_modules[i]) { \ 644 if (vol->vfs_modules[i]->vfs_ ## name) { \ 645 err = vol->vfs_modules[i]->vfs_ ## name (vars); \ 646 if ((ret == AFP_OK) && (err != AFP_OK)) \ 647 ret = err; \ 648 } \ 649 i ++; \ 650 } \ 651 return ret; \ 652 } 653 654VFS_MFUNC(chown, VFS_FUNC_ARGS_CHOWN, VFS_FUNC_VARS_CHOWN) 655VFS_MFUNC(renamedir, VFS_FUNC_ARGS_RENAMEDIR, VFS_FUNC_VARS_RENAMEDIR) 656VFS_MFUNC(deletecurdir, VFS_FUNC_ARGS_DELETECURDIR, VFS_FUNC_VARS_DELETECURDIR) 657VFS_MFUNC(setfilmode, VFS_FUNC_ARGS_SETFILEMODE, VFS_FUNC_VARS_SETFILEMODE) 658VFS_MFUNC(setdirmode, VFS_FUNC_ARGS_SETDIRMODE, VFS_FUNC_VARS_SETDIRMODE) 659VFS_MFUNC(setdirunixmode, VFS_FUNC_ARGS_SETDIRUNIXMODE, VFS_FUNC_VARS_SETDIRUNIXMODE) 660VFS_MFUNC(setdirowner, VFS_FUNC_ARGS_SETDIROWNER, VFS_FUNC_VARS_SETDIROWNER) 661VFS_MFUNC(deletefile, VFS_FUNC_ARGS_DELETEFILE, VFS_FUNC_VARS_DELETEFILE) 662VFS_MFUNC(renamefile, VFS_FUNC_ARGS_RENAMEFILE, VFS_FUNC_VARS_RENAMEFILE) 663VFS_MFUNC(copyfile, VFS_FUNC_ARGS_COPYFILE, VFS_FUNC_VARS_COPYFILE) 664#ifdef HAVE_ACLS 665VFS_MFUNC(acl, VFS_FUNC_ARGS_ACL, VFS_FUNC_VARS_ACL) 666VFS_MFUNC(remove_acl, VFS_FUNC_ARGS_REMOVE_ACL, VFS_FUNC_VARS_REMOVE_ACL) 667#endif 668VFS_MFUNC(ea_getsize, VFS_FUNC_ARGS_EA_GETSIZE, VFS_FUNC_VARS_EA_GETSIZE) 669VFS_MFUNC(ea_getcontent, VFS_FUNC_ARGS_EA_GETCONTENT, VFS_FUNC_VARS_EA_GETCONTENT) 670VFS_MFUNC(ea_list, VFS_FUNC_ARGS_EA_LIST, VFS_FUNC_VARS_EA_LIST) 671VFS_MFUNC(ea_set, VFS_FUNC_ARGS_EA_SET, VFS_FUNC_VARS_EA_SET) 672VFS_MFUNC(ea_remove, VFS_FUNC_ARGS_EA_REMOVE, VFS_FUNC_VARS_EA_REMOVE) 673 674static int vfs_validupath(VFS_FUNC_ARGS_VALIDUPATH) 675{ 676 return vol->vfs_modules[0]->vfs_validupath(VFS_FUNC_VARS_VALIDUPATH); 677} 678 679/* 680 * These function pointers get called from the lib users via vol->vfs->func. 681 * These funcs are defined via the macros above. 682 */ 683static struct vfs_ops vfs_master_funcs = { 684 vfs_validupath, 685 vfs_chown, 686 vfs_renamedir, 687 vfs_deletecurdir, 688 vfs_setfilmode, 689 vfs_setdirmode, 690 vfs_setdirunixmode, 691 vfs_setdirowner, 692 vfs_deletefile, 693 vfs_renamefile, 694 vfs_copyfile, 695#ifdef HAVE_ACLS 696 vfs_acl, 697 vfs_remove_acl, 698#endif 699 vfs_ea_getsize, 700 vfs_ea_getcontent, 701 vfs_ea_list, 702 vfs_ea_set, 703 vfs_ea_remove 704}; 705 706/* 707 * Primary adouble modules: v2, ea 708 */ 709 710static struct vfs_ops netatalk_adouble_v2 = { 711 /* vfs_validupath: */ validupath_adouble, 712 /* vfs_chown: */ RF_chown_adouble, 713 /* vfs_renamedir: */ RF_renamedir_adouble, 714 /* vfs_deletecurdir: */ RF_deletecurdir_adouble, 715 /* vfs_setfilmode: */ RF_setfilmode_adouble, 716 /* vfs_setdirmode: */ RF_setdirmode_adouble, 717 /* vfs_setdirunixmode:*/ RF_setdirunixmode_adouble, 718 /* vfs_setdirowner: */ RF_setdirowner_adouble, 719 /* vfs_deletefile: */ RF_deletefile_adouble, 720 /* vfs_renamefile: */ RF_renamefile_adouble, 721 /* vfs_copyfile: */ RF_copyfile_adouble, 722 NULL 723}; 724 725static struct vfs_ops netatalk_adouble_ea = { 726 /* vfs_validupath: */ validupath_ea, 727 /* vfs_chown: */ RF_chown_ea, 728 /* vfs_renamedir: */ RF_renamedir_ea, 729 /* vfs_deletecurdir: */ RF_deletecurdir_ea, 730 /* vfs_setfilmode: */ RF_setfilmode_ea, 731 /* vfs_setdirmode: */ RF_setdirmode_ea, 732 /* vfs_setdirunixmode:*/ RF_setdirunixmode_ea, 733 /* vfs_setdirowner: */ RF_setdirowner_ea, 734 /* vfs_deletefile: */ RF_deletefile_ea, 735 /* vfs_renamefile: */ RF_renamefile_ea, 736 /* vfs_copyfile: */ RF_copyfile_ea, 737 NULL 738}; 739 740/* 741 * Secondary vfs modules for Extended Attributes 742 */ 743 744static struct vfs_ops netatalk_ea_adouble = { 745 /* vfs_validupath: */ NULL, 746 /* vfs_chown: */ ea_chown, 747 /* vfs_renamedir: */ NULL, /* ok */ 748 /* vfs_deletecurdir: */ NULL, /* ok */ 749 /* vfs_setfilmode: */ ea_chmod_file, 750 /* vfs_setdirmode: */ NULL, /* ok */ 751 /* vfs_setdirunixmode:*/ ea_chmod_dir, 752 /* vfs_setdirowner: */ NULL, /* ok */ 753 /* vfs_deletefile: */ ea_deletefile, 754 /* vfs_renamefile: */ ea_renamefile, 755 /* vfs_copyfile */ ea_copyfile, 756#ifdef HAVE_ACLS 757 /* vfs_acl: */ NULL, 758 /* vfs_remove_acl */ NULL, 759#endif 760 /* vfs_getsize */ get_easize, 761 /* vfs_getcontent */ get_eacontent, 762 /* vfs_list */ list_eas, 763 /* vfs_set */ set_ea, 764 /* vfs_remove */ remove_ea 765}; 766 767static struct vfs_ops netatalk_ea_sys = { 768 /* validupath: */ NULL, 769 /* rf_chown: */ NULL, 770 /* rf_renamedir: */ NULL, 771 /* rf_deletecurdir: */ NULL, 772 /* rf_setfilmode: */ NULL, 773 /* rf_setdirmode: */ NULL, 774 /* rf_setdirunixmode: */ NULL, 775 /* rf_setdirowner: */ NULL, 776 /* rf_deletefile: */ NULL, 777 /* rf_renamefile: */ NULL, 778 /* vfs_copyfile: */ sys_ea_copyfile, 779#ifdef HAVE_ACLS 780 /* rf_acl: */ NULL, 781 /* rf_remove_acl */ NULL, 782#endif 783 /* ea_getsize */ sys_get_easize, 784 /* ea_getcontent */ sys_get_eacontent, 785 /* ea_list */ sys_list_eas, 786 /* ea_set */ sys_set_ea, 787 /* ea_remove */ sys_remove_ea 788}; 789 790/* 791 * Tertiary VFS modules for ACLs 792 */ 793 794#ifdef HAVE_SOLARIS_ACLS 795static struct vfs_ops netatalk_solaris_acl_adouble = { 796 /* validupath: */ NULL, 797 /* rf_chown: */ NULL, 798 /* rf_renamedir: */ NULL, 799 /* rf_deletecurdir: */ NULL, 800 /* rf_setfilmode: */ NULL, 801 /* rf_setdirmode: */ NULL, 802 /* rf_setdirunixmode: */ NULL, 803 /* rf_setdirowner: */ NULL, 804 /* rf_deletefile: */ NULL, 805 /* rf_renamefile: */ NULL, 806 /* vfs_copyfile */ NULL, 807 /* rf_acl: */ RF_solaris_acl, 808 /* rf_remove_acl */ RF_solaris_remove_acl, 809 NULL 810}; 811#endif 812 813#ifdef HAVE_POSIX_ACLS 814static struct vfs_ops netatalk_posix_acl_adouble = { 815 /* validupath: */ NULL, 816 /* rf_chown: */ NULL, 817 /* rf_renamedir: */ NULL, 818 /* rf_deletecurdir: */ NULL, 819 /* rf_setfilmode: */ NULL, 820 /* rf_setdirmode: */ NULL, 821 /* rf_setdirunixmode: */ NULL, 822 /* rf_setdirowner: */ NULL, 823 /* rf_deletefile: */ NULL, 824 /* rf_renamefile: */ NULL, 825 /* vfs_copyfile */ NULL, 826 /* rf_acl: */ RF_posix_acl, 827 /* rf_remove_acl */ RF_posix_remove_acl, 828 NULL 829}; 830#endif 831 832/* ---------------- */ 833void initvol_vfs(struct vol *vol) 834{ 835 vol->vfs = &vfs_master_funcs; 836 837 /* Default adouble stuff */ 838 if (vol->v_adouble == AD_VERSION2) { 839 vol->vfs_modules[0] = &netatalk_adouble_v2; 840 vol->ad_path = ad_path; 841 } else { 842 vol->vfs_modules[0] = &netatalk_adouble_ea; 843#ifdef HAVE_EAFD 844 vol->ad_path = ad_path_ea; 845#else 846 vol->ad_path = ad_path_osx; 847#endif 848 } 849 850 /* Extended Attributes */ 851 if (vol->v_vfs_ea == AFPVOL_EA_SYS) { 852 LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with native EAs"); 853 vol->vfs_modules[1] = &netatalk_ea_sys; 854 } else if (vol->v_vfs_ea == AFPVOL_EA_AD) { 855 LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with adouble files"); 856 vol->vfs_modules[1] = &netatalk_ea_adouble; 857 } else { 858 LOG(log_debug, logtype_afpd, "initvol_vfs: volume without EA support"); 859 } 860 861 /* ACLs */ 862#ifdef HAVE_SOLARIS_ACLS 863 vol->vfs_modules[2] = &netatalk_solaris_acl_adouble; 864#endif 865#ifdef HAVE_POSIX_ACLS 866 vol->vfs_modules[2] = &netatalk_posix_acl_adouble; 867#endif 868 869} 870