1/* 2 * Copyright (c) 1990,1993 Regents of The University of Michigan. 3 * All Rights Reserved. See COPYRIGHT. 4 */ 5 6#ifdef HAVE_CONFIG_H 7#include "config.h" 8#endif /* HAVE_CONFIG_H */ 9 10#include <string.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <grp.h> 14#include <pwd.h> 15#include <sys/param.h> 16#include <sys/stat.h> 17#include <errno.h> 18#include <utime.h> 19#include <assert.h> 20 21#include <atalk/adouble.h> 22#include <atalk/vfs.h> 23#include <atalk/afp.h> 24#include <atalk/util.h> 25#include <atalk/cnid.h> 26#include <atalk/logger.h> 27#include <atalk/uuid.h> 28#include <atalk/unix.h> 29#include <atalk/bstrlib.h> 30#include <atalk/bstradd.h> 31#include <atalk/errchk.h> 32#include <atalk/globals.h> 33#include <atalk/fce_api.h> 34 35#include "directory.h" 36#include "dircache.h" 37#include "desktop.h" 38#include "volume.h" 39#include "fork.h" 40#include "file.h" 41#include "filedir.h" 42#include "unix.h" 43#include "mangle.h" 44#include "hash.h" 45 46/* foxconn add start, improvemennt of time machine backup rate, 47 Jonathan 2012/08/22 */ 48#define TIME_MACHINE_WA 49/* 50 * FIXMEs, loose ends after the dircache rewrite: 51 * o merge dircache_search_by_name and dir_add ?? 52 * o case-insensitivity is gone from cname 53 */ 54 55 56/******************************************************************************************* 57 * Globals 58 ******************************************************************************************/ 59 60int afp_errno; 61/* As long as directory.c hasn't got its own init call, this get initialized in dircache_init */ 62struct dir rootParent = { 63 NULL, NULL, NULL, NULL, /* path, d_m_name, d_u_name, d_m_name_ucs2 */ 64 NULL, 0, 0, /* qidx_node, ctime, d_flags */ 65 0, 0, 0, 0 /* pdid, did, offcnt, d_vid */ 66}; 67struct dir *curdir = &rootParent; 68struct path Cur_Path = { 69 0, 70 "", /* mac name */ 71 ".", /* unix name */ 72 0, /* id */ 73 NULL,/* struct dir * */ 74 0, /* stat is not set */ 75 0, /* errno */ 76 {0} /* struct stat */ 77}; 78 79/* 80 * dir_remove queues struct dirs to be freed here. We can't just delete them immeidately 81 * eg in dircache_search_by_id, because a caller somewhere up the stack might be 82 * referencing it. 83 * So instead: 84 * - we mark it as invalid by setting d_did to CNID_INVALID (ie 0) 85 * - queue it in "invalid_dircache_entries" queue 86 * - which is finally freed at the end of every AFP func in afp_dsi.c. 87 */ 88q_t *invalid_dircache_entries; 89 90/* foxconn add start, Jonathan 2012/08/22 */ 91#ifdef TIME_MACHINE_WA 92/* Eric Kao, 2012/07/05 */ 93static int check_bands_did_flag = 0; 94static int files_num = 0; 95static int bands_did = 0; 96static int sparse_did = 0; 97static unsigned int bands_offcnt =0; /* declare as static, jon, 2012/07/31 */ 98 99void afp_bandsdid_IncreaseOffcnt(unsigned int did) 100{ 101#if 0 /* if band count > 0, store it's pid for tmd daemon, jon 2012/07/31 */ 102 if(ntohl(did )== afp_getbandsdid()) 103 { 104 bands_offcnt++; 105 p_create_pid_file(); 106 } 107#else 108 if(ntohl(did )== afp_getbandsdid()) 109 bands_offcnt++; 110#endif 111} 112 113void afp_bandsdid_decreaseOffcnt(unsigned int did) 114{ 115 if(ntohl(did )== afp_getbandsdid()) 116 bands_offcnt--; 117} 118 119unsigned int afp_bandsdid_GetOffcnt() 120{ 121 return bands_offcnt; 122} 123 124void afp_bandsdid_SetOffcnt(unsigned int Val) 125{ 126 bands_offcnt = Val; 127} 128#endif 129/* foxconn add end, Jonathan 2012/08/22 */ 130 131/******************************************************************************************* 132 * Locals 133 ******************************************************************************************/ 134 135 136/* ------------------------- 137 appledouble mkdir afp error code. 138*/ 139static int netatalk_mkdir(const struct vol *vol, const char *name) 140{ 141 int ret; 142 struct stat st; 143 144 if (vol->v_flags & AFPVOL_UNIX_PRIV) { 145 if (lstat(".", &st) < 0) 146 return AFPERR_MISC; 147 int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask); 148 LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}", 149 name, st.st_mode, vol->v_umask); 150 151 ret = mkdir(name, mode); 152 } else { 153 ret = ad_mkdir(name, DIRBITS | 0777); 154 } 155 156 if (ret < 0) { 157 switch ( errno ) { 158 case ENOENT : 159 return( AFPERR_NOOBJ ); 160 case EROFS : 161 return( AFPERR_VLOCK ); 162 case EPERM: 163 case EACCES : 164 return( AFPERR_ACCESS ); 165 case EEXIST : 166 return( AFPERR_EXIST ); 167 case ENOSPC : 168 case EDQUOT : 169 return( AFPERR_DFULL ); 170 default : 171 return( AFPERR_PARAM ); 172 } 173 } 174 return AFP_OK; 175} 176 177/* ------------------- */ 178static int deletedir(int dirfd, char *dir) 179{ 180 char path[MAXPATHLEN + 1]; 181 DIR *dp; 182 struct dirent *de; 183 struct stat st; 184 size_t len; 185 int err = AFP_OK; 186 size_t remain; 187 188 if ((len = strlen(dir)) +2 > sizeof(path)) 189 return AFPERR_PARAM; 190 191 /* already gone */ 192 if ((dp = opendirat(dirfd, dir)) == NULL) 193 return AFP_OK; 194 195 strcpy(path, dir); 196 strcat(path, "/"); 197 len++; 198 remain = sizeof(path) -len -1; 199 while ((de = readdir(dp)) && err == AFP_OK) { 200 /* skip this and previous directory */ 201 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 202 continue; 203 204 if (strlen(de->d_name) > remain) { 205 err = AFPERR_PARAM; 206 break; 207 } 208 strcpy(path + len, de->d_name); 209 if (lstatat(dirfd, path, &st)) { 210 continue; 211 } 212 if (S_ISDIR(st.st_mode)) { 213 err = deletedir(dirfd, path); 214 } else { 215 err = netatalk_unlinkat(dirfd, path); 216 } 217 } 218 closedir(dp); 219 220 /* okay. the directory is empty. delete it. note: we already got rid 221 of .AppleDouble. */ 222 if (err == AFP_OK) { 223 err = netatalk_rmdir(dirfd, dir); 224 } 225 return err; 226} 227 228/* do a recursive copy. */ 229static int copydir(const struct vol *vol, int dirfd, char *src, char *dst) 230{ 231 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1]; 232 DIR *dp; 233 struct dirent *de; 234 struct stat st; 235 struct utimbuf ut; 236 size_t slen, dlen; 237 size_t srem, drem; 238 int err; 239 240 /* doesn't exist or the path is too long. */ 241 if (((slen = strlen(src)) > sizeof(spath) - 2) || 242 ((dlen = strlen(dst)) > sizeof(dpath) - 2) || 243 ((dp = opendirat(dirfd, src)) == NULL)) 244 return AFPERR_PARAM; 245 246 /* try to create the destination directory */ 247 if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) { 248 closedir(dp); 249 return err; 250 } 251 252 /* set things up to copy */ 253 strcpy(spath, src); 254 strcat(spath, "/"); 255 slen++; 256 srem = sizeof(spath) - slen -1; 257 258 strcpy(dpath, dst); 259 strcat(dpath, "/"); 260 dlen++; 261 drem = sizeof(dpath) - dlen -1; 262 263 err = AFP_OK; 264 while ((de = readdir(dp))) { 265 /* skip this and previous directory */ 266 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 267 continue; 268 269 if (strlen(de->d_name) > srem) { 270 err = AFPERR_PARAM; 271 break; 272 } 273 strcpy(spath + slen, de->d_name); 274 275 if (lstatat(dirfd, spath, &st) == 0) { 276 if (strlen(de->d_name) > drem) { 277 err = AFPERR_PARAM; 278 break; 279 } 280 strcpy(dpath + dlen, de->d_name); 281 282 if (S_ISDIR(st.st_mode)) { 283 if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath))) 284 goto copydir_done; 285 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) { 286 goto copydir_done; 287 288 } else { 289 /* keep the same time stamp. */ 290 ut.actime = ut.modtime = st.st_mtime; 291 utime(dpath, &ut); 292 } 293 } 294 } 295 296 /* keep the same time stamp. */ 297 if (lstatat(dirfd, src, &st) == 0) { 298 ut.actime = ut.modtime = st.st_mtime; 299 utime(dst, &ut); 300 } 301 302copydir_done: 303 closedir(dp); 304 return err; 305} 306 307/* --------------------- 308 * is our cached offspring count valid? 309 */ 310static int diroffcnt(struct dir *dir, struct stat *st) 311{ 312 return st->st_ctime == dir->d_ctime; 313} 314 315/* --------------------- */ 316static int invisible_dots(const struct vol *vol, const char *name) 317{ 318 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, ".."); 319} 320 321/* ------------------ */ 322static int set_dir_errors(struct path *path, const char *where, int err) 323{ 324 switch ( err ) { 325 case EPERM : 326 case EACCES : 327 return AFPERR_ACCESS; 328 case EROFS : 329 return AFPERR_VLOCK; 330 } 331 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) ); 332 return AFPERR_PARAM; 333} 334 335/*! 336 * @brief Convert name in client encoding to server encoding 337 * 338 * Convert ret->m_name to ret->u_name from client encoding to server encoding. 339 * This only gets called from cname(). 340 * 341 * @returns 0 on success, -1 on error 342 * 343 * @note If the passed ret->m_name is mangled, we'll demangle it 344 */ 345static int cname_mtouname(const struct vol *vol, const struct dir *dir, struct path *ret, int toUTF8) 346{ 347 static char temp[ MAXPATHLEN + 1]; 348 char *t; 349 cnid_t fileid = 0; 350 351 if (afp_version >= 30) { 352 if (toUTF8) { 353 if (dir->d_did == DIRDID_ROOT_PARENT) { 354 /* 355 * With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981. 356 * So we compare it with the longname from the current volume and if they match 357 * we overwrite the requested path with the utf8 volume name so that the following 358 * strcmp can match. 359 */ 360 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1); 361 if (strcasecmp(ret->m_name, temp) == 0) 362 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, ret->m_name, AFPVOL_U8MNAMELEN); 363 } else { 364 /* toUTF8 */ 365 if (mtoUTF8(vol, ret->m_name, strlen(ret->m_name), temp, MAXPATHLEN) == (size_t)-1) { 366 afp_errno = AFPERR_PARAM; 367 return -1; 368 } 369 strcpy(ret->m_name, temp); 370 } 371 } 372 373 /* check for OS X mangled filename :( */ 374 t = demangle_osx(vol, ret->m_name, dir->d_did, &fileid); 375 LOG(log_maxdebug, logtype_afpd, "cname_mtouname('%s',did:%u) {demangled:'%s', fileid:%u}", 376 ret->m_name, ntohl(dir->d_did), t, ntohl(fileid)); 377 378 if (t != ret->m_name) { 379 ret->u_name = t; 380 /* duplicate work but we can't reuse all convert_char we did in demangle_osx 381 * flags weren't the same 382 */ 383 if ( (t = utompath(vol, ret->u_name, fileid, utf8_encoding())) ) { 384 /* at last got our view of mac name */ 385 strcpy(ret->m_name, t); 386 } 387 } 388 } /* afp_version >= 30 */ 389 390 /* If we haven't got it by now, get it */ 391 if (ret->u_name == NULL) { 392 if ((ret->u_name = mtoupath(vol, ret->m_name, dir->d_did, utf8_encoding())) == NULL) { 393 afp_errno = AFPERR_PARAM; 394 return -1; 395 } 396 } 397 398 return 0; 399} 400 401/*! 402 * @brief Build struct path from struct dir 403 * 404 * The final movecwd in cname failed, possibly with EPERM or ENOENT. We: 405 * 1. move cwd into parent dir (we're often already there, but not always) 406 * 2. set struct path to the dirname 407 * 3. in case of 408 * AFPERR_ACCESS: the dir is there, we just cant chdir into it 409 * AFPERR_NOOBJ: the dir was there when we stated it in cname, so we have a race 410 * 4. indicate there's no dir for this path 411 * 5. remove the dir 412 */ 413static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path *ret) 414{ 415 if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT) 416 return NULL; 417 418 switch (afp_errno) { 419 420 case AFPERR_ACCESS: 421 if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */ 422 return NULL; 423 424 memcpy(ret->m_name, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1); /* 3 */ 425 if (dir->d_m_name == dir->d_u_name) { 426 ret->u_name = ret->m_name; 427 } else { 428 ret->u_name = ret->m_name + blength(dir->d_m_name) + 1; 429 memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1); 430 } 431 432 ret->d_dir = dir; 433 434 LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}", 435 cfrombstr(dir->d_fullpath), 436 cfrombstr(curdir->d_fullpath), 437 ret->u_name); 438 439 return ret; 440 441 case AFPERR_NOOBJ: 442 if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */ 443 return NULL; 444 445 memcpy(ret->m_name, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1); 446 if (dir->d_m_name == dir->d_u_name) { 447 ret->u_name = ret->m_name; 448 } else { 449 ret->u_name = ret->m_name + blength(dir->d_m_name) + 1; 450 memcpy(ret->u_name, cfrombstr(dir->d_u_name), blength(dir->d_u_name) + 1); 451 } 452 453 ret->d_dir = NULL; /* 4 */ 454 dir_remove(vol, dir); /* 5 */ 455 return ret; 456 457 default: 458 return NULL; 459 } 460 461 /* DEADC0DE: never get here */ 462 return NULL; 463} 464 465 466/********************************************************************************************* 467 * Interface 468 ********************************************************************************************/ 469 470int get_afp_errno(const int param) 471{ 472 if (afp_errno != AFPERR_DID1) 473 return afp_errno; 474 return param; 475} 476 477/*! 478 * Resolve struct dir for an absolute path 479 * 480 * Given a path like "/Volumes/volume/dir/subdir" in a volume "/Volumes/volume" return 481 * a pointer to struct dir of "subdir". 482 * 1. Remove volue path from absolute path 483 * 2. start path 484 * 3. loop through all elements of the remaining path from 1. 485 * 4. we only allow dirs 486 * 5. search dircache 487 * 6. if not found in the dircache query the CNID database for the DID 488 * 7. and use dirlookup to resolve the DID to a it's struct dir * 489 * 490 * @param vol (r) volume the path is in, must be known 491 * @param path (r) absoule path 492 * 493 * @returns pointer to struct dir or NULL on error 494 */ 495struct dir *dirlookup_bypath(const struct vol *vol, const char *path) 496{ 497 EC_INIT; 498 499 struct dir *dir = NULL; 500 cnid_t cnid, did; 501 bstring rpath = NULL; 502 bstring statpath = NULL; 503 struct bstrList *l = NULL; 504 struct stat st; 505 int i; 506 507 cnid = htonl(2); 508 dir = vol->v_root; 509 510 EC_NULL(rpath = rel_path_in_vol(path, vol->v_path)); /* 1. */ 511 EC_NULL(statpath = bfromcstr(vol->v_path)); /* 2. */ 512 513 l = bsplit(rpath, '/'); 514 for (i = 0; i < l->qty ; i++) { /* 3. */ 515 did = cnid; 516 EC_ZERO(bcatcstr(statpath, "/")); 517 EC_ZERO(bconcat(statpath, l->entry[i])); 518 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), 519 "lstat(rpath: %s, elem: %s): %s: %s", 520 cfrombstr(rpath), cfrombstr(l->entry[i]), 521 cfrombstr(statpath), strerror(errno)); 522 523 if (!(S_ISDIR(st.st_mode))) /* 4. */ 524 EC_FAIL; 525 526 if ((dir = dircache_search_by_name(vol, /* 5. */ 527 dir, 528 cfrombstr(l->entry[i]), 529 blength(l->entry[i]))) == NULL) { 530 if ((cnid = cnid_add(vol->v_cdb, /* 6. */ 531 &st, 532 did, 533 cfrombstr(l->entry[i]), 534 blength(l->entry[i]), 535 0)) == CNID_INVALID) { 536 EC_FAIL; 537 } 538 539 if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */ 540 EC_FAIL; 541 } 542 } 543 544EC_CLEANUP: 545 bdestroy(rpath); 546 bstrListDestroy(l); 547 bdestroy(statpath); 548 if (ret != 0) 549 return NULL; 550 551 return dir; 552} 553 554/*! 555 * @brief Resolve a DID 556 * 557 * Resolve a DID, allocate a struct dir for it 558 * 1. Check for special CNIDs 0 (invalid), 1 and 2. 559 * 2a. Check if the DID is in the cache. 560 * 2b. Check if it's really a dir because we cache files too. 561 * 3. If it's not in the cache resolve it via the database. 562 * 4. Build complete server-side path to the dir. 563 * 5. Check if it exists and is a directory. 564 * 6. Create the struct dir and populate it. 565 * 7. Add it to the cache. 566 * 567 * @param vol (r) pointer to struct vol 568 * @param did (r) DID to resolve 569 * 570 * @returns pointer to struct dir 571 */ 572struct dir *dirlookup(const struct vol *vol, cnid_t did) 573{ 574 static char buffer[12 + MAXPATHLEN + 1]; 575 struct stat st; 576 struct dir *ret = NULL, *pdir; 577 bstring fullpath = NULL; 578 char *upath = NULL, *mpath; 579 cnid_t cnid, pdid; 580 size_t maxpath; 581 int buflen = 12 + MAXPATHLEN + 1; 582 int utf8; 583 int err = 0; 584 585 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): START", ntohl(did)); 586 587 /* check for did 0, 1 and 2 */ 588 if (did == 0 || vol == NULL) { /* 1 */ 589 afp_errno = AFPERR_PARAM; 590 ret = NULL; 591 goto exit; 592 } else if (did == DIRDID_ROOT_PARENT) { 593 rootParent.d_vid = vol->v_vid; 594 ret = &rootParent; 595 goto exit; 596 } else if (did == DIRDID_ROOT) { 597 ret = vol->v_root; 598 goto exit; 599 } 600 601 /* Search the cache */ 602 if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */ 603 if (ret->d_flags & DIRF_ISFILE) { /* 2b */ 604 afp_errno = AFPERR_BADTYPE; 605 ret = NULL; 606 goto exit; 607 } 608 if (lstat(cfrombstr(ret->d_fullpath), &st) != 0) { 609 LOG(log_debug, logtype_afpd, "dirlookup(did: %u, path: \"%s\"): lstat: %s", 610 ntohl(did), cfrombstr(ret->d_fullpath), strerror(errno)); 611 switch (errno) { 612 case ENOENT: 613 case ENOTDIR: 614 /* It's not there anymore, so remove it */ 615 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): calling dir_remove", ntohl(did)); 616 dir_remove(vol, ret); 617 afp_errno = AFPERR_NOOBJ; 618 ret = NULL; 619 goto exit; 620 default: 621 ret = ret; 622 goto exit; 623 } 624 /* DEADC0DE */ 625 ret = NULL; 626 goto exit; 627 } 628 ret = ret; 629 goto exit; 630 } 631 632 utf8 = utf8_encoding(); 633 maxpath = (utf8) ? MAXPATHLEN - 7 : 255; 634 635 /* Get it from the database */ 636 cnid = did; 637 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): querying CNID database", ntohl(did)); 638 if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) { 639 afp_errno = AFPERR_NOOBJ; 640 err = 1; 641 goto exit; 642 } 643 if ((upath = strdup(upath)) == NULL) { /* 3 */ 644 afp_errno = AFPERR_NOOBJ; 645 err = 1; 646 goto exit; 647 } 648 pdid = cnid; 649 650 /* 651 * Recurse up the tree, terminates in dirlookup when either 652 * - DIRDID_ROOT is hit 653 * - a cached entry is found 654 */ 655 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): recursion for did: %u", 656 ntohl(did), ntohl(pdid)); 657 if ((pdir = dirlookup(vol, pdid)) == NULL) { 658 err = 1; 659 goto exit; 660 } 661 662 /* build the fullpath */ 663 if ((fullpath = bstrcpy(pdir->d_fullpath)) == NULL 664 || bconchar(fullpath, '/') != BSTR_OK 665 || bcatcstr(fullpath, upath) != BSTR_OK) { 666 err = 1; 667 goto exit; 668 } 669 670 /* stat it and check if it's a dir */ 671 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): stating \"%s\"", 672 ntohl(did), cfrombstr(fullpath)); 673 674 if (lstat(cfrombstr(fullpath), &st) != 0) { /* 5a */ 675 switch (errno) { 676 case ENOENT: 677 afp_errno = AFPERR_NOOBJ; 678 err = 1; 679 goto exit; 680 case EPERM: 681 afp_errno = AFPERR_ACCESS; 682 err = 1; 683 goto exit; 684 default: 685 afp_errno = AFPERR_MISC; 686 err = 1; 687 goto exit; 688 } 689 } else { 690 if ( ! S_ISDIR(st.st_mode)) { /* 5b */ 691 afp_errno = AFPERR_BADTYPE; 692 err = 1; 693 goto exit; 694 } 695 } 696 697 /* Get macname from unix name */ 698 if ( (mpath = utompath(vol, upath, did, utf8)) == NULL ) { 699 afp_errno = AFPERR_NOOBJ; 700 err = 1; 701 goto exit; 702 } 703 704 /* Create struct dir */ 705 if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, &st)) == NULL) { /* 6 */ 706 LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno)); 707 err = 1; 708 goto exit; 709 } 710 711 /* Add it to the cache only if it's a dir */ 712 if (dircache_add(vol, ret) != 0) { /* 7 */ 713 err = 1; 714 goto exit; 715 } 716 717exit: 718 if (upath) free(upath); 719 if (err) { 720 LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {exit_error: %s}", 721 ntohl(did), AfpErr2name(afp_errno)); 722 if (fullpath) 723 bdestroy(fullpath); 724 if (ret) { 725 dir_free(ret); 726 ret = NULL; 727 } 728 } 729 if (ret) 730 LOG(log_debug, logtype_afpd, "dirlookup(did: %u): RESULT: pdid: %u, path: \"%s\"", 731 ntohl(ret->d_did), ntohl(ret->d_pdid), cfrombstr(ret->d_fullpath)); 732 733 return ret; 734} 735 736#define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/" 737 738int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir) 739{ 740 DIR *dp; 741 struct dirent *de; 742 int ret; 743 static u_int32_t did = 0; 744 static char cname[MAXPATHLEN]; 745 static char lname[MAXPATHLEN]; 746 ucs2_t u2_path[MAXPATHLEN]; 747 ucs2_t u2_dename[MAXPATHLEN]; 748 char *tmp, *savepath; 749 750 if (!(vol->v_flags & AFPVOL_CASEINSEN)) 751 return -1; 752 753 if (veto_file(ENUMVETO, path->u_name)) 754 return -1; 755 756 savepath = path->u_name; 757 758 /* very simple cache */ 759 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) { 760 path->u_name = cname; 761 path->d_dir = NULL; 762 if (of_stat( path ) == 0 ) { 763 return 0; 764 } 765 /* something changed, we cannot stat ... */ 766 did = 0; 767 } 768 769 if (NULL == ( dp = opendir( "." )) ) { 770 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name); 771 return -1; 772 } 773 774 775 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */ 776 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) ) 777 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name); 778 779 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */ 780 ret = -1; 781 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) { 782 if (NULL == check_dirent(vol, de->d_name)) 783 continue; 784 785 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) ) 786 continue; 787 788 if (strcasecmp_w( u2_path, u2_dename) == 0) { 789 tmp = path->u_name; 790 strlcpy(cname, de->d_name, sizeof(cname)); 791 path->u_name = cname; 792 path->d_dir = NULL; 793 if (of_stat( path ) == 0 ) { 794 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name); 795 strlcpy(lname, tmp, sizeof(lname)); 796 did = dir->d_did; 797 ret = 0; 798 break; 799 } 800 else 801 path->u_name = tmp; 802 } 803 804 } 805 closedir(dp); 806 807 if (ret) { 808 /* invalidate cache */ 809 cname[0] = 0; 810 did = 0; 811 path->u_name = savepath; 812 } 813 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */ 814 return ret; 815} 816 817 818/*! 819 * @brief Construct struct dir 820 * 821 * Construct struct dir from parameters. 822 * 823 * @param m_name (r) directory name in UTF8-dec 824 * @param u_name (r) directory name in server side encoding 825 * @param vol (r) pointer to struct vol 826 * @param pdid (r) Parent CNID 827 * @param did (r) CNID 828 * @param path (r) Full unix path to object 829 * @param st (r) struct stat of object 830 * 831 * @returns pointer to new struct dir or NULL on error 832 * 833 * @note Most of the time mac name and unix name are the same. 834 */ 835struct dir *dir_new(const char *m_name, 836 const char *u_name, 837 const struct vol *vol, 838 cnid_t pdid, 839 cnid_t did, 840 bstring path, 841 struct stat *st) 842{ 843 struct dir *dir; 844 845 dir = (struct dir *) calloc(1, sizeof( struct dir )); 846 if (!dir) 847 return NULL; 848 849 if ((dir->d_m_name = bfromcstr(m_name)) == NULL) { 850 free(dir); 851 return NULL; 852 } 853 854 if (convert_string_allocate( (utf8_encoding()) ? CH_UTF8_MAC : vol->v_maccharset, 855 CH_UCS2, 856 m_name, 857 -1, (char **)&dir->d_m_name_ucs2) == (size_t)-1 ) { 858 LOG(log_error, logtype_afpd, "dir_new(did: %u) {%s, %s}: couldn't set UCS2 name", ntohl(did), m_name, u_name); 859 dir->d_m_name_ucs2 = NULL; 860 } 861 862 if (m_name == u_name || !strcmp(m_name, u_name)) { 863 dir->d_u_name = dir->d_m_name; 864 } 865 else if ((dir->d_u_name = bfromcstr(u_name)) == NULL) { 866 bdestroy(dir->d_m_name); 867 free(dir); 868 return NULL; 869 } 870 871 dir->d_did = did; 872 dir->d_pdid = pdid; 873 dir->d_vid = vol->v_vid; 874 dir->d_fullpath = path; 875 dir->dcache_ctime = st->st_ctime; 876 dir->dcache_ino = st->st_ino; 877 if (!S_ISDIR(st->st_mode)) 878 dir->d_flags = DIRF_ISFILE; 879 dir->d_rights_cache = 0xffffffff; 880 return dir; 881} 882 883/*! 884 * @brief Free a struct dir and all its members 885 * 886 * @param (rw) pointer to struct dir 887 */ 888void dir_free(struct dir *dir) 889{ 890 if (dir->d_u_name != dir->d_m_name) { 891 bdestroy(dir->d_u_name); 892 } 893 if (dir->d_m_name_ucs2) 894 free(dir->d_m_name_ucs2); 895 bdestroy(dir->d_m_name); 896 bdestroy(dir->d_fullpath); 897 free(dir); 898} 899 900/*! 901 * @brief Create struct dir from struct path 902 * 903 * Create a new struct dir from struct path. Then add it to the cache. 904 * 905 * 1. Open adouble file, get CNID from it. 906 * 2. Search the database, hinting with the CNID from (1). 907 * 3. Build fullpath and create struct dir. 908 * 4. Add it to the cache. 909 * 910 * @param vol (r) pointer to struct vol, possibly modified in callee 911 * @param dir (r) pointer to parrent directory 912 * @param path (rw) pointer to struct path with valid path->u_name 913 * @param len (r) strlen of path->u_name 914 * 915 * @returns Pointer to new struct dir or NULL on error. 916 * 917 * @note Function also assigns path->m_name from path->u_name. 918 */ 919struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, int len) 920{ 921 int err = 0; 922 struct dir *cdir = NULL; 923 cnid_t id; 924 struct adouble ad; 925 struct adouble *adp = NULL; 926 bstring fullpath; 927 928 AFP_ASSERT(vol); 929 AFP_ASSERT(dir); 930 AFP_ASSERT(path); 931 AFP_ASSERT(len > 0); 932 933 if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) { 934 /* there's a stray entry in the dircache */ 935 LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}", 936 ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name, 937 ntohl(cdir->d_did), cfrombstr(dir->d_fullpath)); 938 if (dir_remove(vol, cdir) != 0) { 939 dircache_dump(); 940 AFP_PANIC("dir_add"); 941 } 942 } 943 944 /* get_id needs adp for reading CNID from adouble file */ 945 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 946 if ((ad_open_metadata(path->u_name, ADFLAGS_DIR, 0, &ad)) == 0) /* 1 */ 947 adp = &ad; 948 949 /* Get CNID */ 950 if ((id = get_id(vol, adp, &path->st, dir->d_did, path->u_name, len)) == 0) { /* 2 */ 951 err = 1; 952 goto exit; 953 } 954 955 if (adp) 956 ad_close_metadata(adp); 957 958 /* Get macname from unixname */ 959 if (path->m_name == NULL) { 960 if ((path->m_name = utompath(vol, path->u_name, id, utf8_encoding())) == NULL) { 961 LOG(log_error, logtype_afpd, "dir_add(\"%s\"): can't assign macname", path->u_name); 962 err = 2; 963 goto exit; 964 } 965 } 966 967 /* Build fullpath */ 968 if ( ((fullpath = bstrcpy(dir->d_fullpath)) == NULL) /* 3 */ 969 || (bconchar(fullpath, '/') != BSTR_OK) 970 || (bcatcstr(fullpath, path->u_name)) != BSTR_OK) { 971 LOG(log_error, logtype_afpd, "dir_add: fullpath: %s", strerror(errno) ); 972 err = 3; 973 goto exit; 974 } 975 976 /* Allocate and initialize struct dir */ 977 if ((cdir = dir_new(path->m_name, 978 path->u_name, 979 vol, 980 dir->d_did, 981 id, 982 fullpath, 983 &path->st)) == NULL) { /* 3 */ 984 err = 4; 985 goto exit; 986 } 987 988 if ((dircache_add(vol, cdir)) != 0) { /* 4 */ 989 LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath)); 990 exit(EXITERR_SYS); 991 } 992 993exit: 994 if (err != 0) { 995 LOG(log_debug, logtype_afpd, "dir_add('%s/%s'): error: %u", 996 cfrombstr(dir->d_u_name), path->u_name, err); 997 998 if (adp) 999 ad_close_metadata(adp); 1000 if (!cdir && fullpath) 1001 bdestroy(fullpath); 1002 if (cdir) 1003 dir_free(cdir); 1004 cdir = NULL; 1005 } else { 1006 /* no error */ 1007 LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {cached: %u,'%s'}", 1008 ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name, 1009 ntohl(cdir->d_did), cfrombstr(cdir->d_fullpath)); 1010 } 1011 1012 return(cdir); 1013} 1014 1015/*! 1016 * Free the queue with invalid struct dirs 1017 * 1018 * This gets called at the end of every AFP func. 1019 */ 1020void dir_free_invalid_q(void) 1021{ 1022 struct dir *dir; 1023 while (dir = (struct dir *)dequeue(invalid_dircache_entries)) 1024 dir_free(dir); 1025} 1026 1027/*! 1028 * @brief Remove a dir from a cache and queue it for freeing 1029 * 1030 * 1. Check if the dir is locked or has opened forks 1031 * 2. Remove it from the cache 1032 * 3. Queue it for removal 1033 * 4. If it's a request to remove curdir, mark curdir as invalid 1034 * 5. Mark it as invalid 1035 * 1036 * @param (r) pointer to struct vol 1037 * @param (rw) pointer to struct dir 1038 */ 1039int dir_remove(const struct vol *vol, struct dir *dir) 1040{ 1041 AFP_ASSERT(vol); 1042 AFP_ASSERT(dir); 1043 1044 if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT) 1045 return 0; 1046 1047 LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}", 1048 ntohl(dir->d_did), cfrombstr(dir->d_u_name)); 1049 1050 dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 2 */ 1051 enqueue(invalid_dircache_entries, dir); /* 3 */ 1052 1053 if (curdir == dir) /* 4 */ 1054 curdir = NULL; 1055 1056 dir->d_did = CNID_INVALID; /* 5 */ 1057 1058 return 0; 1059} 1060 1061#if 0 /* unused */ 1062/*! 1063 * @brief Modify a struct dir, adjust cache 1064 * 1065 * Any value that is 0 or NULL is not changed. If new_uname is NULL it is set to new_mname. 1066 * If given new_uname == new_mname, new_uname will point to new_mname. 1067 * 1068 * @param vol (r) pointer to struct vol 1069 * @param dir (rw) pointer to struct dir 1070 * @param pdid (r) new parent DID 1071 * @param did (r) new DID 1072 * @param new_mname (r) new mac-name 1073 * @param new_uname (r) new unix-name 1074 * @param pdir_fullpath (r) new fullpath of parent dir 1075 */ 1076int dir_modify(const struct vol *vol, 1077 struct dir *dir, 1078 cnid_t pdid, 1079 cnid_t did, 1080 const char *new_mname, 1081 const char *new_uname, 1082 bstring pdir_fullpath) 1083{ 1084 int ret = 0; 1085 1086 /* Remove it from the cache */ 1087 dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); 1088 1089 if (pdid) 1090 dir->d_pdid = pdid; 1091 if (did) 1092 dir->d_did = did; 1093 1094 if (new_mname) { 1095 /* free uname if it's not the same as mname */ 1096 if (dir->d_m_name != dir->d_u_name) 1097 bdestroy(dir->d_u_name); 1098 1099 if (new_uname == NULL) 1100 new_uname = new_mname; 1101 1102 /* assign new name */ 1103 if ((bassigncstr(dir->d_m_name, new_mname)) != BSTR_OK) { 1104 LOG(log_error, logtype_afpd, "dir_modify: bassigncstr: %s", strerror(errno) ); 1105 return -1; 1106 } 1107 1108 if (new_mname == new_uname || (strcmp(new_mname, new_uname) == 0)) { 1109 dir->d_u_name = dir->d_m_name; 1110 } else { 1111 if ((dir->d_u_name = bfromcstr(new_uname)) == NULL) { 1112 LOG(log_error, logtype_afpd, "dir_modify: bassigncstr: %s", strerror(errno) ); 1113 return -1; 1114 } 1115 } 1116 } 1117 1118 if (pdir_fullpath) { 1119 if (bassign(dir->d_fullpath, pdir_fullpath) != BSTR_OK) 1120 return -1; 1121 if (bcatcstr(dir->d_fullpath, "/") != BSTR_OK) 1122 return -1; 1123 if (bcatcstr(dir->d_fullpath, new_uname) != BSTR_OK) 1124 return -1; 1125 } 1126 1127 if (dir->d_m_name_ucs2) 1128 free(dir->d_m_name_ucs2); 1129 if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, -1, (char**)&dir->d_m_name_ucs2)) 1130 dir->d_m_name_ucs2 = NULL; 1131 1132 /* Re-add it to the cache */ 1133 if ((dircache_add(vol, dir)) != 0) { 1134 dircache_dump(); 1135 AFP_PANIC("dir_modify"); 1136 } 1137 1138 return ret; 1139} 1140#endif 1141 1142/*! 1143 * @brief Resolve a catalog node name path 1144 * 1145 * 1. Evaluate path type 1146 * 2. Move to start dir, if we cant, it might eg because of EACCES, build 1147 * path from dirname, so eg getdirparams has sth it can chew on. curdir 1148 * is dir parent then. All this is done in path_from_dir(). 1149 * 3. Parse next cnode name in path, cases: 1150 * 4. single "\0" -> do nothing 1151 * 5. two or more consecutive "\0" -> chdir("..") one or more times 1152 * 6. cnode name -> copy it to path.m_name 1153 * 7. Get unix name from mac name 1154 * 8. Special handling of request with did 1 1155 * 9. stat the cnode name 1156 * 10. If it's not there, it's probably an afp_createfile|dir, 1157 * return with curdir = dir parent, struct path = dirname 1158 * 11. If it's there and it's a file, it must should be the last element of the requested 1159 * path. Return with curdir = cnode name parent dir, struct path = filename 1160 * 12. Treat symlinks like files, dont follow them 1161 * 13. If it's a dir: 1162 * 14. Search the dircache for it 1163 * 15. If it's not in the cache, create a struct dir for it and add it to the cache 1164 * 16. chdir into the dir and 1165 * 17. set m_name to the mac equivalent of "." 1166 * 18. goto 3 1167 */ 1168struct path *cname(struct vol *vol, struct dir *dir, char **cpath) 1169{ 1170 static char path[ MAXPATHLEN + 1]; 1171 static struct path ret; 1172 1173 struct dir *cdir; 1174 char *data, *p; 1175 int len; 1176 u_int32_t hint; 1177 u_int16_t len16; 1178 int size = 0; 1179 int toUTF8 = 0; 1180 1181 LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstr(dir->d_fullpath)); 1182 1183 data = *cpath; 1184 afp_errno = AFPERR_NOOBJ; 1185 memset(&ret, 0, sizeof(ret)); 1186 1187 switch (ret.m_type = *data) { /* 1 */ 1188 case 2: 1189 data++; 1190 len = (unsigned char) *data++; 1191 size = 2; 1192 if (afp_version >= 30) { 1193 ret.m_type = 3; 1194 toUTF8 = 1; 1195 } 1196 break; 1197 case 3: 1198 if (afp_version >= 30) { 1199 data++; 1200 memcpy(&hint, data, sizeof(hint)); 1201 hint = ntohl(hint); 1202 data += sizeof(hint); 1203 1204 memcpy(&len16, data, sizeof(len16)); 1205 len = ntohs(len16); 1206 data += 2; 1207 size = 7; 1208 break; 1209 } 1210 /* else it's an error */ 1211 default: 1212 afp_errno = AFPERR_PARAM; 1213 return( NULL ); 1214 } 1215 *cpath += len + size; 1216 1217 path[0] = 0; 1218 ret.m_name = path; 1219 1220 if (movecwd(vol, dir) < 0 ) { 1221 LOG(log_debug, logtype_afpd, "cname(did:%u): failed to chdir to '%s'", 1222 ntohl(dir->d_did), cfrombstr(dir->d_fullpath)); 1223 if (len == 0) 1224 return path_from_dir(vol, dir, &ret); 1225 else 1226 return NULL; 1227 } 1228 1229 while (len) { /* 3 */ 1230 if (*data == 0) { /* 4 or 5 */ 1231 data++; 1232 len--; 1233 while (len > 0 && *data == 0) { /* 5 */ 1234 /* chdir to parrent dir */ 1235 if ((dir = dirlookup(vol, dir->d_pdid)) == NULL) 1236 return NULL; 1237 if (movecwd( vol, dir ) < 0 ) { 1238 dir_remove(vol, dir); 1239 return NULL; 1240 } 1241 data++; 1242 len--; 1243 } 1244 continue; 1245 } 1246 1247 /* 6*/ 1248 for ( p = path; *data != 0 && len > 0; len-- ) { 1249 *p++ = *data++; 1250 if (p > &path[UTF8FILELEN_EARLY]) { /* FIXME safeguard, limit of early Mac OS X */ 1251 afp_errno = AFPERR_PARAM; 1252 return NULL; 1253 } 1254 } 1255 *p = 0; /* Terminate string */ 1256 ret.u_name = NULL; 1257 1258 if (cname_mtouname(vol, dir, &ret, toUTF8) != 0) { /* 7 */ 1259 LOG(log_error, logtype_afpd, "cname('%s'): error from cname_mtouname", path); 1260 return NULL; 1261 } 1262 1263 LOG(log_maxdebug, logtype_afpd, "came('%s'): {node: '%s}", cfrombstr(dir->d_fullpath), ret.u_name); 1264 1265 /* Prevent access to our special folders like .AppleDouble */ 1266 if (check_name(vol, ret.u_name)) { 1267 /* the name is illegal */ 1268 LOG(log_info, logtype_afpd, "cname: illegal path: '%s'", ret.u_name); 1269 afp_errno = AFPERR_PARAM; 1270 return NULL; 1271 } 1272 1273 if (dir->d_did == DIRDID_ROOT_PARENT) { /* 8 */ 1274 /* 1275 * Special case: CNID 1 1276 * root parent (did 1) has one child: the volume. Requests for did=1 with 1277 * some <name> must check against the volume name. 1278 */ 1279 if ((strcmp(cfrombstr(vol->v_root->d_m_name), ret.m_name)) == 0) 1280 cdir = vol->v_root; 1281 else 1282 return NULL; 1283 } else { 1284 /* 1285 * CNID != 1, eg. most of the times we take this way. 1286 * Now check if current path-part is a file or dir: 1287 * o if it's dir we have to step into it 1288 * o if it's a file we expect it to be the last part of the requested path 1289 * and thus call continue which should terminate the while loop because 1290 * len = 0. Ok? 1291 */ 1292 if (of_stat(&ret) != 0) { /* 9 */ 1293 /* 1294 * ret.u_name doesn't exist, might be afp_createfile|dir 1295 * that means it should have been the last part 1296 */ 1297 if (len > 0) { 1298 /* it wasn't the last part, so we have a bogus path request */ 1299 afp_errno = AFPERR_NOOBJ; 1300 return NULL; 1301 } 1302 /* 1303 * this will terminate clean in while (1) because len == 0, 1304 * probably afp_createfile|dir 1305 */ 1306 LOG(log_maxdebug, logtype_afpd, "came('%s'): {leave-cnode ENOENT (possile create request): '%s'}", 1307 cfrombstr(dir->d_fullpath), ret.u_name); 1308 continue; /* 10 */ 1309 } 1310 1311 switch (ret.st.st_mode & S_IFMT) { 1312 case S_IFREG: /* 11 */ 1313 LOG(log_debug, logtype_afpd, "came('%s'): {file: '%s'}", 1314 cfrombstr(dir->d_fullpath), ret.u_name); 1315 if (len > 0) { 1316 /* it wasn't the last part, so we have a bogus path request */ 1317 afp_errno = AFPERR_PARAM; 1318 return NULL; 1319 } 1320 continue; /* continues while loop */ 1321 case S_IFLNK: /* 12 */ 1322 LOG(log_debug, logtype_afpd, "came('%s'): {link: '%s'}", 1323 cfrombstr(dir->d_fullpath), ret.u_name); 1324 if (len > 0) { 1325 LOG(log_warning, logtype_afpd, "came('%s'): {symlinked dir: '%s'}", 1326 cfrombstr(dir->d_fullpath), ret.u_name); 1327 afp_errno = AFPERR_PARAM; 1328 return NULL; 1329 } 1330 continue; /* continues while loop */ 1331 case S_IFDIR: /* 13 */ 1332 break; 1333 default: 1334 LOG(log_info, logtype_afpd, "cname: special file: '%s'", ret.u_name); 1335 afp_errno = AFPERR_NODIR; 1336 return NULL; 1337 } 1338 1339 /* Search the cache */ 1340 int unamelen = strlen(ret.u_name); 1341 cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */ 1342 if (cdir == NULL) { 1343 /* Not in cache, create one */ 1344 if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */ 1345 LOG(log_error, logtype_afpd, "cname(did:%u, name:'%s', cwd:'%s'): failed to add dir", 1346 ntohl(dir->d_did), ret.u_name, getcwdpath()); 1347 return NULL; 1348 } 1349 } 1350 } /* if/else cnid==1 */ 1351 1352 /* Now chdir to the evaluated dir */ 1353 if (movecwd( vol, cdir ) < 0 ) { /* 16 */ 1354 LOG(log_debug, logtype_afpd, "cname(cwd:'%s'): failed to chdir to new subdir '%s': %s", 1355 cfrombstr(curdir->d_fullpath), cfrombstr(cdir->d_fullpath), strerror(errno)); 1356 if (len == 0) 1357 return path_from_dir(vol, cdir, &ret); 1358 else 1359 return NULL; 1360 } 1361 dir = cdir; 1362 ret.m_name[0] = 0; /* 17, so we later know last token was a dir */ 1363 } /* while (len) */ 1364 1365 if (curdir->d_did == DIRDID_ROOT_PARENT) { 1366 afp_errno = AFPERR_DID1; 1367 return NULL; 1368 } 1369 1370 if (ret.m_name[0] == 0) { 1371 /* Last part was a dir */ 1372 ret.u_name = mtoupath(vol, ret.m_name, 0, 1); /* Force "." into a useable static buffer */ 1373 ret.d_dir = dir; 1374 } 1375 1376 LOG(log_debug, logtype_afpd, "came('%s') {end: curdir:'%s', path:'%s'}", 1377 cfrombstr(dir->d_fullpath), 1378 cfrombstr(curdir->d_fullpath), 1379 ret.u_name); 1380 1381 return &ret; 1382} 1383 1384/* 1385 * @brief chdir() to dir 1386 * 1387 * @param vol (r) pointer to struct vol 1388 * @param dir (r) pointer to struct dir 1389 * 1390 * @returns 0 on success, -1 on error with afp_errno set appropiately 1391 */ 1392int movecwd(const struct vol *vol, struct dir *dir) 1393{ 1394 int ret; 1395 1396 AFP_ASSERT(vol); 1397 AFP_ASSERT(dir); 1398 1399 LOG(log_maxdebug, logtype_afpd, "movecwd: from: curdir:\"%s\", cwd:\"%s\"", 1400 curdir ? cfrombstr(curdir->d_fullpath) : "INVALID", getcwdpath()); 1401 1402 if (dir->d_did == DIRDID_ROOT_PARENT) { 1403 curdir = &rootParent; 1404 return 0; 1405 } 1406 1407 LOG(log_debug, logtype_afpd, "movecwd(to: did: %u, \"%s\")", 1408 ntohl(dir->d_did), cfrombstr(dir->d_fullpath)); 1409 1410 if ((ret = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) { 1411 LOG(log_debug, logtype_afpd, "movecwd(\"%s\"): ret: %u, %s", 1412 cfrombstr(dir->d_fullpath), ret, strerror(errno)); 1413 if (ret == 1) { 1414 /* p is a symlink or getcwd failed */ 1415 afp_errno = AFPERR_BADTYPE; 1416 1417 if (chdir(vol->v_path ) < 0) { 1418 LOG(log_error, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno)); 1419 /* XXX what do we do here? */ 1420 } 1421 curdir = vol->v_root; 1422 return -1; 1423 } 1424 1425 switch (errno) { 1426 case EACCES: 1427 case EPERM: 1428 afp_errno = AFPERR_ACCESS; 1429 break; 1430 default: 1431 afp_errno = AFPERR_NOOBJ; 1432 } 1433 return( -1 ); 1434 } 1435 1436 curdir = dir; 1437 return( 0 ); 1438} 1439 1440/* 1441 * We can't use unix file's perm to support Apple's inherited protection modes. 1442 * If we aren't the file's owner we can't change its perms when moving it and smb 1443 * nfs,... don't even try. 1444 */ 1445#define AFP_CHECK_ACCESS 1446 1447int check_access(char *path, int mode) 1448{ 1449#ifdef AFP_CHECK_ACCESS 1450 struct maccess ma; 1451 char *p; 1452 1453 p = ad_dir(path); 1454 if (!p) 1455 return -1; 1456 1457 accessmode(p, &ma, curdir, NULL); 1458 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) 1459 return -1; 1460 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) 1461 return -1; 1462#endif 1463 return 0; 1464} 1465 1466/* --------------------- */ 1467int file_access(struct path *path, int mode) 1468{ 1469 struct maccess ma; 1470 1471 accessmode(path->u_name, &ma, curdir, &path->st); 1472 1473 LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x", 1474 path->u_name, ma.ma_user); 1475 1476 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) { 1477 LOG(log_debug, logtype_afpd, "file_access(\"%s\"): write access denied", path->u_name); 1478 return -1; 1479 } 1480 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) { 1481 LOG(log_debug, logtype_afpd, "file_access(\"%s\"): read access denied", path->u_name); 1482 return -1; 1483 } 1484 return 0; 1485 1486} 1487 1488/* --------------------- */ 1489void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count) 1490{ 1491 dir->d_offcnt = count; 1492 dir->d_ctime = st->st_ctime; 1493 dir->d_flags &= ~DIRF_CNID; 1494} 1495 1496 1497/* --------------------- 1498 * is our cached also for reenumerate id? 1499 */ 1500int dirreenumerate(struct dir *dir, struct stat *st) 1501{ 1502 return st->st_ctime == dir->d_ctime && (dir->d_flags & DIRF_CNID); 1503} 1504 1505/* ------------------------------ 1506 (".", curdir) 1507 (name, dir) with curdir:name == dir, from afp_enumerate 1508*/ 1509 1510int getdirparams(const struct vol *vol, 1511 u_int16_t bitmap, struct path *s_path, 1512 struct dir *dir, 1513 char *buf, size_t *buflen ) 1514{ 1515 struct maccess ma; 1516 struct adouble ad; 1517 char *data, *l_nameoff = NULL, *utf_nameoff = NULL; 1518 int bit = 0, isad = 0; 1519 u_int32_t aint; 1520 u_int16_t ashort; 1521 int ret; 1522 u_int32_t utf8 = 0; 1523 cnid_t pdid; 1524 struct stat *st = &s_path->st; 1525 char *upath = s_path->u_name; 1526/* foxconn add start, Jonathan 2012/08/22 */ 1527#ifdef TIME_MACHINE_WA 1528 static int recnt_times = 0; /* do 1 time before workaround */ 1529#endif 1530/* foxconn add end, Jonathan 2012/08/22 */ 1531 1532 1533 if ((bitmap & ((1 << DIRPBIT_ATTR) | 1534 (1 << DIRPBIT_CDATE) | 1535 (1 << DIRPBIT_MDATE) | 1536 (1 << DIRPBIT_BDATE) | 1537 (1 << DIRPBIT_FINFO)))) { 1538 1539 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 1540 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) { 1541 isad = 1; 1542 if (ad.ad_md->adf_flags & O_CREAT) { 1543 /* We just created it */ 1544 if (s_path->m_name == NULL) { 1545 if ((s_path->m_name = utompath(vol, 1546 upath, 1547 dir->d_did, 1548 utf8_encoding())) == NULL) { 1549 LOG(log_error, logtype_afpd, 1550 "getdirparams(\"%s\"): can't assign macname", 1551 cfrombstr(dir->d_fullpath)); 1552 return AFPERR_MISC; 1553 } 1554 } 1555 ad_setname(&ad, s_path->m_name); 1556 ad_setid( &ad, 1557 s_path->st.st_dev, 1558 s_path->st.st_ino, 1559 dir->d_did, 1560 dir->d_pdid, 1561 vol->v_stamp); 1562 ad_flush( &ad); 1563 } 1564 } 1565 } 1566 1567 pdid = dir->d_pdid; 1568 1569 data = buf; 1570 while ( bitmap != 0 ) { 1571 while (( bitmap & 1 ) == 0 ) { 1572 bitmap = bitmap>>1; 1573 bit++; 1574 } 1575 1576 switch ( bit ) { 1577 case DIRPBIT_ATTR : 1578 if ( isad ) { 1579 ad_getattr(&ad, &ashort); 1580 } else if (invisible_dots(vol, cfrombstr(dir->d_u_name))) { 1581 ashort = htons(ATTRBIT_INVISIBLE); 1582 } else 1583 ashort = 0; 1584 ashort |= htons(ATTRBIT_SHARED); 1585 memcpy( data, &ashort, sizeof( ashort )); 1586 data += sizeof( ashort ); 1587 break; 1588 1589 case DIRPBIT_PDID : 1590 memcpy( data, &pdid, sizeof( pdid )); 1591 data += sizeof( pdid ); 1592 LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u", 1593 s_path->u_name, ntohl(pdid)); 1594 break; 1595 1596 case DIRPBIT_CDATE : 1597 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0)) 1598 aint = AD_DATE_FROM_UNIX(st->st_mtime); 1599 memcpy( data, &aint, sizeof( aint )); 1600 data += sizeof( aint ); 1601 break; 1602 1603 case DIRPBIT_MDATE : 1604 aint = AD_DATE_FROM_UNIX(st->st_mtime); 1605 memcpy( data, &aint, sizeof( aint )); 1606 data += sizeof( aint ); 1607 break; 1608 1609 case DIRPBIT_BDATE : 1610 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0)) 1611 aint = AD_DATE_START; 1612 memcpy( data, &aint, sizeof( aint )); 1613 data += sizeof( aint ); 1614 break; 1615 1616 case DIRPBIT_FINFO : 1617 if ( isad ) { 1618 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 ); 1619 } else { /* no appledouble */ 1620 memset( data, 0, 32 ); 1621 /* set default view -- this also gets done in ad_open() */ 1622 ashort = htons(FINDERINFO_CLOSEDVIEW); 1623 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort)); 1624 1625 /* dot files are by default visible */ 1626 if (invisible_dots(vol, cfrombstr(dir->d_u_name))) { 1627 ashort = htons(FINDERINFO_INVISIBLE); 1628 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); 1629 } 1630 } 1631 data += 32; 1632 break; 1633 1634 case DIRPBIT_LNAME : 1635 if (dir->d_m_name) /* root of parent can have a null name */ 1636 l_nameoff = data; 1637 else 1638 memset(data, 0, sizeof(u_int16_t)); 1639 data += sizeof( u_int16_t ); 1640 break; 1641 1642 case DIRPBIT_SNAME : 1643 memset(data, 0, sizeof(u_int16_t)); 1644 data += sizeof( u_int16_t ); 1645 break; 1646 1647 case DIRPBIT_DID : 1648 memcpy( data, &dir->d_did, sizeof( aint )); 1649 data += sizeof( aint ); 1650 LOG(log_debug, logtype_afpd, "metadata('%s'): DID: %u", 1651 s_path->u_name, ntohl(dir->d_did)); 1652 break; 1653 1654 case DIRPBIT_OFFCNT : 1655 ashort = 0; 1656 /* this needs to handle current directory access rights */ 1657/* foxconn add start, Jonathan 2012/08/22 */ 1658#ifdef TIME_MACHINE_WA 1659 //if(recnt_times >= 2 && (ntohl(dir->d_did) == afp_getbandsdid()) ) 1660 if(recnt_times >= 1 && (ntohl(dir->d_did) == afp_getbandsdid()) ) /* set recount time >= 1, jon 2012/07/31 */ 1661 { 1662 ashort = (afp_bandsdid_GetOffcnt() > 0xffff)?0xffff:afp_bandsdid_GetOffcnt(); 1663 } 1664 else if (diroffcnt(dir, st)) { 1665 1666 ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt; 1667 } 1668 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) { 1669 if(ntohl(dir->d_did) == afp_getbandsdid()){ 1670 recnt_times++; 1671 afp_bandsdid_SetOffcnt((unsigned int)ret); 1672 } 1673 setdiroffcnt(dir, st, ret); 1674 ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt; 1675 } 1676#else 1677 if (diroffcnt(dir, st)) { 1678 ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt; 1679 } 1680 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) { 1681 setdiroffcnt(dir, st, ret); 1682 ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt; 1683 } 1684#endif 1685/* foxconn add end, Jonathan 2012/08/22 */ 1686 1687 ashort = htons( ashort ); 1688 memcpy( data, &ashort, sizeof( ashort )); 1689 data += sizeof( ashort ); 1690 break; 1691 1692 case DIRPBIT_UID : 1693 aint = htonl(st->st_uid); 1694 memcpy( data, &aint, sizeof( aint )); 1695 data += sizeof( aint ); 1696 break; 1697 1698 case DIRPBIT_GID : 1699 aint = htonl(st->st_gid); 1700 memcpy( data, &aint, sizeof( aint )); 1701 data += sizeof( aint ); 1702 break; 1703 1704 case DIRPBIT_ACCESS : 1705 accessmode( upath, &ma, dir , st); 1706 1707 *data++ = ma.ma_user; 1708 *data++ = ma.ma_world; 1709 *data++ = ma.ma_group; 1710 *data++ = ma.ma_owner; 1711 break; 1712 1713 /* Client has requested the ProDOS information block. 1714 Just pass back the same basic block for all 1715 directories. <shirsch@ibm.net> */ 1716 case DIRPBIT_PDINFO : 1717 if (afp_version >= 30) { /* UTF8 name */ 1718 utf8 = kTextEncodingUTF8; 1719 if (dir->d_m_name) /* root of parent can have a null name */ 1720 utf_nameoff = data; 1721 else 1722 memset(data, 0, sizeof(u_int16_t)); 1723 data += sizeof( u_int16_t ); 1724 aint = 0; 1725 memcpy(data, &aint, sizeof( aint )); 1726 data += sizeof( aint ); 1727 } 1728 else { /* ProDOS Info Block */ 1729 *data++ = 0x0f; 1730 *data++ = 0; 1731 ashort = htons( 0x0200 ); 1732 memcpy( data, &ashort, sizeof( ashort )); 1733 data += sizeof( ashort ); 1734 memset( data, 0, sizeof( ashort )); 1735 data += sizeof( ashort ); 1736 } 1737 break; 1738 1739 case DIRPBIT_UNIXPR : 1740 aint = htonl(st->st_uid); 1741 memcpy( data, &aint, sizeof( aint )); 1742 data += sizeof( aint ); 1743 aint = htonl(st->st_gid); 1744 memcpy( data, &aint, sizeof( aint )); 1745 data += sizeof( aint ); 1746 1747 aint = st->st_mode; 1748 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */ 1749 memcpy( data, &aint, sizeof( aint )); 1750 data += sizeof( aint ); 1751 1752 accessmode( upath, &ma, dir , st); 1753 1754 *data++ = ma.ma_user; 1755 *data++ = ma.ma_world; 1756 *data++ = ma.ma_group; 1757 *data++ = ma.ma_owner; 1758 break; 1759 1760 default : 1761 if ( isad ) { 1762 ad_close_metadata( &ad ); 1763 } 1764 return( AFPERR_BITMAP ); 1765 } 1766 bitmap = bitmap>>1; 1767 bit++; 1768 } 1769 if ( l_nameoff ) { 1770 ashort = htons( data - buf ); 1771 memcpy( l_nameoff, &ashort, sizeof( ashort )); 1772 data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, 0); 1773 } 1774 if ( utf_nameoff ) { 1775 ashort = htons( data - buf ); 1776 memcpy( utf_nameoff, &ashort, sizeof( ashort )); 1777 data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, utf8); 1778 } 1779 if ( isad ) { 1780 ad_close_metadata( &ad ); 1781 } 1782 *buflen = data - buf; 1783 return( AFP_OK ); 1784} 1785 1786/* ----------------------------- */ 1787int path_error(struct path *path, int error) 1788{ 1789/* - a dir with access error 1790 * - no error it's a file 1791 * - file not found 1792 */ 1793 if (path_isadir(path)) 1794 return afp_errno; 1795 if (path->st_valid && path->st_errno) 1796 return error; 1797 return AFPERR_BADTYPE ; 1798} 1799 1800/* ----------------------------- */ 1801int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1802{ 1803 struct vol *vol; 1804 struct dir *dir; 1805 struct path *path; 1806 u_int16_t vid, bitmap; 1807 u_int32_t did; 1808 int rc; 1809 1810 *rbuflen = 0; 1811 ibuf += 2; 1812 memcpy( &vid, ibuf, sizeof( vid )); 1813 ibuf += sizeof( vid ); 1814 1815 if (NULL == ( vol = getvolbyvid( vid )) ) { 1816 return( AFPERR_PARAM ); 1817 } 1818 1819 if (vol->v_flags & AFPVOL_RO) 1820 return AFPERR_VLOCK; 1821 1822 memcpy( &did, ibuf, sizeof( did )); 1823 ibuf += sizeof( int ); 1824 1825 if (NULL == ( dir = dirlookup( vol, did )) ) { 1826 return afp_errno; 1827 } 1828 1829 memcpy( &bitmap, ibuf, sizeof( bitmap )); 1830 bitmap = ntohs( bitmap ); 1831 ibuf += sizeof( bitmap ); 1832 1833 if (NULL == ( path = cname( vol, dir, &ibuf )) ) { 1834 return get_afp_errno(AFPERR_NOOBJ); 1835 } 1836 1837 if ( *path->m_name != '\0' ) { 1838 rc = path_error(path, AFPERR_NOOBJ); 1839 /* maybe we are trying to set perms back */ 1840 if (rc != AFPERR_ACCESS) 1841 return rc; 1842 } 1843 1844 /* 1845 * If ibuf is odd, make it even. 1846 */ 1847 if ((u_long)ibuf & 1 ) { 1848 ibuf++; 1849 } 1850 1851 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) { 1852 setvoltime(obj, vol ); 1853 } 1854 return( rc ); 1855} 1856 1857/* 1858 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic 1859 * 1860 * assume path == '\0' eg. it's a directory in canonical form 1861 */ 1862int setdirparams(struct vol *vol, struct path *path, u_int16_t d_bitmap, char *buf ) 1863{ 1864 struct maccess ma; 1865 struct adouble ad; 1866 struct utimbuf ut; 1867 struct timeval tv; 1868 1869 char *upath; 1870 struct dir *dir; 1871 int bit, isad = 1; 1872 int cdate, bdate; 1873 int owner, group; 1874 u_int16_t ashort, bshort, oshort; 1875 int err = AFP_OK; 1876 int change_mdate = 0; 1877 int change_parent_mdate = 0; 1878 int newdate = 0; 1879 u_int16_t bitmap = d_bitmap; 1880 u_char finder_buf[32]; 1881 u_int32_t upriv; 1882 mode_t mpriv = 0; 1883 u_int16_t upriv_bit = 0; 1884 1885 bit = 0; 1886 upath = path->u_name; 1887 dir = path->d_dir; 1888 while ( bitmap != 0 ) { 1889 while (( bitmap & 1 ) == 0 ) { 1890 bitmap = bitmap>>1; 1891 bit++; 1892 } 1893 1894 switch( bit ) { 1895 case DIRPBIT_ATTR : 1896 change_mdate = 1; 1897 memcpy( &ashort, buf, sizeof( ashort )); 1898 buf += sizeof( ashort ); 1899 break; 1900 case DIRPBIT_CDATE : 1901 change_mdate = 1; 1902 memcpy(&cdate, buf, sizeof(cdate)); 1903 buf += sizeof( cdate ); 1904 break; 1905 case DIRPBIT_MDATE : 1906 memcpy(&newdate, buf, sizeof(newdate)); 1907 buf += sizeof( newdate ); 1908 break; 1909 case DIRPBIT_BDATE : 1910 change_mdate = 1; 1911 memcpy(&bdate, buf, sizeof(bdate)); 1912 buf += sizeof( bdate ); 1913 break; 1914 case DIRPBIT_FINFO : 1915 change_mdate = 1; 1916 memcpy( finder_buf, buf, 32 ); 1917 buf += 32; 1918 break; 1919 case DIRPBIT_UID : /* What kind of loser mounts as root? */ 1920 change_parent_mdate = 1; 1921 memcpy( &owner, buf, sizeof(owner)); 1922 buf += sizeof( owner ); 1923 break; 1924 case DIRPBIT_GID : 1925 change_parent_mdate = 1; 1926 memcpy( &group, buf, sizeof( group )); 1927 buf += sizeof( group ); 1928 break; 1929 case DIRPBIT_ACCESS : 1930 change_mdate = 1; 1931 change_parent_mdate = 1; 1932 ma.ma_user = *buf++; 1933 ma.ma_world = *buf++; 1934 ma.ma_group = *buf++; 1935 ma.ma_owner = *buf++; 1936 mpriv = mtoumode( &ma ) | vol->v_dperm; 1937 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) { 1938 err = set_dir_errors(path, "setdirmode", errno); 1939 bitmap = 0; 1940 } 1941 break; 1942 /* Ignore what the client thinks we should do to the 1943 ProDOS information block. Skip over the data and 1944 report nothing amiss. <shirsch@ibm.net> */ 1945 case DIRPBIT_PDINFO : 1946 if (afp_version < 30) { 1947 buf += 6; 1948 } 1949 else { 1950 err = AFPERR_BITMAP; 1951 bitmap = 0; 1952 } 1953 break; 1954 case DIRPBIT_UNIXPR : 1955 if (vol_unix_priv(vol)) { 1956 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */ 1957 buf += sizeof( owner ); 1958 memcpy( &group, buf, sizeof( group )); 1959 buf += sizeof( group ); 1960 1961 change_mdate = 1; 1962 change_parent_mdate = 1; 1963 memcpy( &upriv, buf, sizeof( upriv )); 1964 buf += sizeof( upriv ); 1965 upriv = ntohl (upriv) | vol->v_dperm; 1966 if (dir_rx_set(upriv)) { 1967 /* maybe we are trying to set perms back */ 1968 if ( setdirunixmode(vol, upath, upriv) < 0 ) { 1969 bitmap = 0; 1970 err = set_dir_errors(path, "setdirunixmode", errno); 1971 } 1972 } 1973 else { 1974 /* do it later */ 1975 upriv_bit = 1; 1976 } 1977 break; 1978 } 1979 /* fall through */ 1980 default : 1981 err = AFPERR_BITMAP; 1982 bitmap = 0; 1983 break; 1984 } 1985 1986 bitmap = bitmap>>1; 1987 bit++; 1988 } 1989 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 1990 1991 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) { 1992 /* 1993 * Check to see what we're trying to set. If it's anything 1994 * but ACCESS, UID, or GID, give an error. If it's any of those 1995 * three, we don't need the ad to be open, so just continue. 1996 * 1997 * note: we also don't need to worry about mdate. also, be quiet 1998 * if we're using the noadouble option. 1999 */ 2000 if (!vol_noadouble(vol) && (d_bitmap & 2001 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)| 2002 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)| 2003 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) { 2004 return AFPERR_ACCESS; 2005 } 2006 2007 isad = 0; 2008 } else { 2009 /* 2010 * Check to see if a create was necessary. If it was, we'll want 2011 * to set our name, etc. 2012 */ 2013 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) { 2014 ad_setname(&ad, cfrombstr(curdir->d_m_name)); 2015 } 2016 } 2017 2018 bit = 0; 2019 bitmap = d_bitmap; 2020 while ( bitmap != 0 ) { 2021 while (( bitmap & 1 ) == 0 ) { 2022 bitmap = bitmap>>1; 2023 bit++; 2024 } 2025 2026 switch( bit ) { 2027 case DIRPBIT_ATTR : 2028 if (isad) { 2029 ad_getattr(&ad, &bshort); 2030 oshort = bshort; 2031 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) { 2032 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR ); 2033 } else { 2034 bshort &= ~ashort; 2035 } 2036 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE))) 2037 change_parent_mdate = 1; 2038 ad_setattr(&ad, bshort); 2039 } 2040 break; 2041 case DIRPBIT_CDATE : 2042 if (isad) { 2043 ad_setdate(&ad, AD_DATE_CREATE, cdate); 2044 } 2045 break; 2046 case DIRPBIT_MDATE : 2047 break; 2048 case DIRPBIT_BDATE : 2049 if (isad) { 2050 ad_setdate(&ad, AD_DATE_BACKUP, bdate); 2051 } 2052 break; 2053 case DIRPBIT_FINFO : 2054 if (isad) { 2055 /* Fixes #2802236 */ 2056 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF); 2057 *fflags &= htons(~FINDERINFO_ISHARED); 2058 /* #2802236 end */ 2059 if ( dir->d_did == DIRDID_ROOT ) { 2060 /* 2061 * Alright, we admit it, this is *really* sick! 2062 * The 4 bytes that we don't copy, when we're dealing 2063 * with the root of a volume, are the directory's 2064 * location information. This eliminates that annoying 2065 * behavior one sees when mounting above another mount 2066 * point. 2067 */ 2068 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 ); 2069 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 ); 2070 } else { 2071 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 ); 2072 } 2073 } 2074 break; 2075 case DIRPBIT_UID : /* What kind of loser mounts as root? */ 2076 if ( (dir->d_did == DIRDID_ROOT) && 2077 (setdeskowner( ntohl(owner), -1 ) < 0)) { 2078 err = set_dir_errors(path, "setdeskowner", errno); 2079 if (isad && err == AFPERR_PARAM) { 2080 err = AFP_OK; /* ???*/ 2081 } 2082 else { 2083 goto setdirparam_done; 2084 } 2085 } 2086 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) { 2087 err = set_dir_errors(path, "setdirowner", errno); 2088 goto setdirparam_done; 2089 } 2090 break; 2091 case DIRPBIT_GID : 2092 if (dir->d_did == DIRDID_ROOT) 2093 setdeskowner( -1, ntohl(group) ); 2094 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) { 2095 err = set_dir_errors(path, "setdirowner", errno); 2096 goto setdirparam_done; 2097 } 2098 break; 2099 case DIRPBIT_ACCESS : 2100 if (dir->d_did == DIRDID_ROOT) { 2101 setdeskmode(mpriv); 2102 if (!dir_rx_set(mpriv)) { 2103 /* we can't remove read and search for owner on volume root */ 2104 err = AFPERR_ACCESS; 2105 goto setdirparam_done; 2106 } 2107 } 2108 2109 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) { 2110 err = set_dir_errors(path, "setdirmode", errno); 2111 goto setdirparam_done; 2112 } 2113 break; 2114 case DIRPBIT_PDINFO : 2115 if (afp_version >= 30) { 2116 err = AFPERR_BITMAP; 2117 goto setdirparam_done; 2118 } 2119 break; 2120 case DIRPBIT_UNIXPR : 2121 if (vol_unix_priv(vol)) { 2122 if (dir->d_did == DIRDID_ROOT) { 2123 if (!dir_rx_set(upriv)) { 2124 /* we can't remove read and search for owner on volume root */ 2125 err = AFPERR_ACCESS; 2126 goto setdirparam_done; 2127 } 2128 setdeskowner( -1, ntohl(group) ); 2129 setdeskmode( upriv ); 2130 } 2131 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) { 2132 err = set_dir_errors(path, "setdirowner", errno); 2133 goto setdirparam_done; 2134 } 2135 2136 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) { 2137 err = set_dir_errors(path, "setdirunixmode", errno); 2138 goto setdirparam_done; 2139 } 2140 } 2141 else { 2142 err = AFPERR_BITMAP; 2143 goto setdirparam_done; 2144 } 2145 break; 2146 default : 2147 err = AFPERR_BITMAP; 2148 goto setdirparam_done; 2149 break; 2150 } 2151 2152 bitmap = bitmap>>1; 2153 bit++; 2154 } 2155 2156setdirparam_done: 2157 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) { 2158 newdate = AD_DATE_FROM_UNIX(tv.tv_sec); 2159 } 2160 if (newdate) { 2161 if (isad) 2162 ad_setdate(&ad, AD_DATE_MODIFY, newdate); 2163 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate); 2164 utime(upath, &ut); 2165 } 2166 2167 if ( isad ) { 2168 if (path->st_valid && !path->st_errno) { 2169 struct stat *st = &path->st; 2170 2171 if (dir && dir->d_pdid) { 2172 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_pdid, vol->v_stamp); 2173 } 2174 } 2175 ad_flush( &ad); 2176 ad_close_metadata( &ad); 2177 } 2178 2179 if (change_parent_mdate && dir->d_did != DIRDID_ROOT 2180 && gettimeofday(&tv, NULL) == 0) { 2181 if (movecwd(vol, dirlookup(vol, dir->d_pdid)) == 0) { 2182 newdate = AD_DATE_FROM_UNIX(tv.tv_sec); 2183 /* be careful with bitmap because now dir is null */ 2184 bitmap = 1<<DIRPBIT_MDATE; 2185 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate); 2186 /* should we reset curdir ?*/ 2187 } 2188 } 2189 2190 return err; 2191} 2192 2193int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 2194{ 2195#ifdef HAVE_DIRFD 2196 DIR *dp; 2197#endif 2198 int dfd; 2199 struct vol *vol; 2200 struct dir *dir; 2201 u_int32_t did; 2202 u_int16_t vid; 2203 2204 *rbuflen = 0; 2205 ibuf += 2; 2206 2207 memcpy( &vid, ibuf, sizeof( vid )); 2208 ibuf += sizeof( vid ); 2209 if (NULL == (vol = getvolbyvid( vid )) ) { 2210 return( AFPERR_PARAM ); 2211 } 2212 2213 memcpy( &did, ibuf, sizeof( did )); 2214 ibuf += sizeof( did ); 2215 2216 /* 2217 * Here's the deal: 2218 * if it's CNID 2 our only choice to meet the specs is call sync. 2219 * For any other CNID just sync that dir. To my knowledge the 2220 * intended use of FPSyncDir is to sync the volume so all we're 2221 * ever going to see here is probably CNID 2. Anyway, we' prepared. 2222 */ 2223 2224 if ( ntohl(did) == 2 ) { 2225 sync(); 2226 } else { 2227 if (NULL == ( dir = dirlookup( vol, did )) ) { 2228 return afp_errno; /* was AFPERR_NOOBJ */ 2229 } 2230 2231 if (movecwd( vol, dir ) < 0 ) 2232 return ( AFPERR_NOOBJ ); 2233 2234 /* 2235 * Assuming only OSens that have dirfd also may require fsyncing directories 2236 * in order to flush metadata e.g. Linux. 2237 */ 2238 2239#ifdef HAVE_DIRFD 2240 if (NULL == ( dp = opendir( "." )) ) { 2241 switch( errno ) { 2242 case ENOENT : 2243 return( AFPERR_NOOBJ ); 2244 case EACCES : 2245 return( AFPERR_ACCESS ); 2246 default : 2247 return( AFPERR_PARAM ); 2248 } 2249 } 2250 2251 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name); 2252 2253 dfd = dirfd( dp ); 2254 if ( fsync ( dfd ) < 0 ) 2255 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s", 2256 dir->d_u_name, strerror(errno) ); 2257 closedir(dp); /* closes dfd too */ 2258#endif 2259 2260 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) { 2261 switch( errno ) { 2262 case ENOENT: 2263 return( AFPERR_NOOBJ ); 2264 case EACCES: 2265 return( AFPERR_ACCESS ); 2266 default: 2267 return( AFPERR_PARAM ); 2268 } 2269 } 2270 2271 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'", 2272 vol->ad_path(".", ADFLAGS_DIR) ); 2273 2274 if ( fsync(dfd) < 0 ) 2275 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s", 2276 vol->ad_path(cfrombstr(dir->d_u_name), ADFLAGS_DIR), strerror(errno) ); 2277 close(dfd); 2278 } 2279 2280 return ( AFP_OK ); 2281} 2282 2283/* foxconn add start, Jonathan 2012/08/22 */ 2284#ifdef TIME_MACHINE_WA 2285/* Eric Kao, 2012/07/05 */ 2286void afp_enablechk(void) 2287{ 2288 check_bands_did_flag = 1; 2289} 2290 2291void afp_disablechk(void) 2292{ 2293 check_bands_did_flag = 0; 2294} 2295 2296int afp_checkflag(void) 2297{ 2298 return check_bands_did_flag; 2299} 2300 2301void afp_recbandsdid(int did) 2302{ 2303 bands_did = did; 2304} 2305 2306void afp_recSparsedid(int did) 2307{ 2308 sparse_did = did; 2309} 2310int afp_getSparsedid() 2311{ 2312 return sparse_did; 2313} 2314 2315int afp_getbandsdid() 2316{ 2317 return bands_did; 2318} 2319/* Eric Kao, 2012/07/05 */ 2320#endif 2321/* foxconn add start, Jonathan 2012/08/22 */ 2322 2323 2324int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 2325{ 2326 struct adouble ad; 2327 struct vol *vol; 2328 struct dir *dir; 2329 char *upath; 2330 struct path *s_path; 2331 u_int32_t did; 2332 u_int16_t vid; 2333 int err; 2334 2335 *rbuflen = 0; 2336 ibuf += 2; 2337 2338 memcpy( &vid, ibuf, sizeof( vid )); 2339 ibuf += sizeof( vid ); 2340 if (NULL == ( vol = getvolbyvid( vid )) ) { 2341 return( AFPERR_PARAM ); 2342 } 2343 2344 if (vol->v_flags & AFPVOL_RO) 2345 return AFPERR_VLOCK; 2346/* foxconn add start, Jonathan 2012/08/22 */ 2347#ifdef TIME_MACHINE_WA 2348 afp_enablechk(); // Eric Kao, 2012/07/05 2349#endif 2350 2351 memcpy( &did, ibuf, sizeof( did )); 2352 ibuf += sizeof( did ); 2353 if (NULL == ( dir = dirlookup( vol, did )) ) { 2354/* foxconn add start, Jonathan 2012/08/22 */ 2355#ifdef TIME_MACHINE_WA 2356 afp_disablechk(); // Eric Kao, 2012/07/05 2357#endif 2358 return afp_errno; /* was AFPERR_NOOBJ */ 2359 } 2360 /* for concurrent access we need to be sure we are not in the 2361 * folder we want to create... 2362 */ 2363 movecwd(vol, dir); 2364 2365 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { 2366/* foxconn add start, Jonathan 2012/08/22 */ 2367#ifdef TIME_MACHINE_WA 2368 afp_disablechk(); // Eric Kao, 2012/07/05 2369#endif 2370 return get_afp_errno(AFPERR_PARAM); 2371 } 2372 /* cname was able to move curdir to it! */ 2373 if (*s_path->m_name == '\0') 2374 return AFPERR_EXIST; 2375 2376 upath = s_path->u_name; 2377 2378 if (AFP_OK != (err = netatalk_mkdir(vol, upath))) { 2379 return err; 2380 } 2381 2382 if (of_stat(s_path) < 0) { 2383 return AFPERR_MISC; 2384 } 2385 2386 curdir->d_offcnt++; 2387/* foxconn add start, Jonathan 2012/08/22 */ 2388#ifdef TIME_MACHINE_WA 2389 afp_bandsdid_IncreaseOffcnt(curdir->d_did); 2390#endif 2391 2392 if ((dir = dir_add(vol, curdir, s_path, strlen(s_path->u_name))) == NULL) { 2393 return AFPERR_MISC; 2394 } 2395 2396 if ( movecwd( vol, dir ) < 0 ) { 2397 return( AFPERR_PARAM ); 2398 } 2399 2400 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 2401 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) { 2402 if (vol_noadouble(vol)) 2403 goto createdir_done; 2404 return( AFPERR_ACCESS ); 2405 } 2406 ad_setname(&ad, s_path->m_name); 2407 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp); 2408 2409 fce_register_new_dir(s_path); 2410 2411 ad_flush( &ad); 2412 ad_close_metadata( &ad); 2413 2414createdir_done: 2415 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t )); 2416 *rbuflen = sizeof( u_int32_t ); 2417 setvoltime(obj, vol ); 2418/* foxconn add start, Jonathan 2012/08/22 */ 2419#ifdef TIME_MACHINE_WA 2420 afp_disablechk(); // Eric Kao, 2012/07/05 2421#endif 2422 return( AFP_OK ); 2423} 2424 2425/* 2426 * dst new unix filename (not a pathname) 2427 * newname new mac name 2428 * newparent curdir 2429 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd 2430 */ 2431int renamedir(const struct vol *vol, 2432 int dirfd, 2433 char *src, 2434 char *dst, 2435 struct dir *dir, 2436 struct dir *newparent, 2437 char *newname) 2438{ 2439 struct adouble ad; 2440 int err; 2441 2442 /* existence check moved to afp_moveandrename */ 2443 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) { 2444 switch ( errno ) { 2445 case ENOENT : 2446 return( AFPERR_NOOBJ ); 2447 case EACCES : 2448 return( AFPERR_ACCESS ); 2449 case EROFS: 2450 return AFPERR_VLOCK; 2451 case EINVAL: 2452 /* tried to move directory into a subdirectory of itself */ 2453 return AFPERR_CANTMOVE; 2454 case EXDEV: 2455 /* this needs to copy and delete. bleah. that means we have 2456 * to deal with entire directory hierarchies. */ 2457 if ((err = copydir(vol, dirfd, src, dst)) < 0) { 2458 deletedir(-1, dst); 2459 return err; 2460 } 2461 if ((err = deletedir(dirfd, src)) < 0) 2462 return err; 2463 break; 2464 default : 2465 return( AFPERR_PARAM ); 2466 } 2467 } 2468 2469 vol->vfs->vfs_renamedir(vol, dirfd, src, dst); 2470 2471 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 2472 2473 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) { 2474 ad_setname(&ad, newname); 2475 ad_flush( &ad); 2476 ad_close_metadata( &ad); 2477 } 2478 2479 return( AFP_OK ); 2480} 2481 2482/* delete an empty directory */ 2483int deletecurdir(struct vol *vol) 2484{ 2485 struct dirent *de; 2486 struct stat st; 2487 struct dir *fdir, *pdir; 2488 DIR *dp; 2489 struct adouble ad; 2490 u_int16_t ashort; 2491 int err; 2492 2493 if ((pdir = dirlookup(vol, curdir->d_pdid)) == NULL) { 2494 return( AFPERR_ACCESS ); 2495 } 2496 2497 fdir = curdir; 2498 2499 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 2500 /* we never want to create a resource fork here, we are going to delete it */ 2501 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) { 2502 2503 ad_getattr(&ad, &ashort); 2504 ad_close_metadata(&ad); 2505 if ((ashort & htons(ATTRBIT_NODELETE))) { 2506 return AFPERR_OLOCK; 2507 } 2508 } 2509 err = vol->vfs->vfs_deletecurdir(vol); 2510 if (err) { 2511 LOG(log_error, logtype_afpd, "deletecurdir: error deleting .AppleDouble in \"%s\"", 2512 curdir->d_fullpath); 2513 return err; 2514 } 2515 2516 /* now get rid of dangling symlinks */ 2517 if ((dp = opendir("."))) { 2518 while ((de = readdir(dp))) { 2519 /* skip this and previous directory */ 2520 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 2521 continue; 2522 2523 /* bail if it's not a symlink */ 2524 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) { 2525 LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): not empty", 2526 curdir->d_fullpath); 2527 closedir(dp); 2528 return AFPERR_DIRNEMPT; 2529 } 2530 2531 if ((err = netatalk_unlink(de->d_name))) { 2532 closedir(dp); 2533 return err; 2534 } 2535 } 2536 } 2537 2538 if (movecwd(vol, pdir) < 0) { 2539 err = afp_errno; 2540 goto delete_done; 2541 } 2542 2543 LOG(log_debug, logtype_afpd, "deletecurdir: moved to \"%s\"", 2544 cfrombstr(curdir->d_fullpath)); 2545 2546 err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name)); 2547 if ( err == AFP_OK || err == AFPERR_NOOBJ) { 2548 cnid_delete(vol->v_cdb, fdir->d_did); 2549 dir_remove( vol, fdir ); 2550 } else { 2551 LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error", 2552 curdir->d_fullpath); 2553 } 2554 2555delete_done: 2556 if (dp) { 2557 /* inode is used as key for cnid. 2558 * Close the descriptor only after cnid_delete 2559 * has been called. 2560 */ 2561 closedir(dp); 2562 } 2563 return err; 2564} 2565 2566int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 2567{ 2568 struct passwd *pw; 2569 struct group *gr; 2570 char *name; 2571 u_int32_t id; 2572 int len, sfunc; 2573 int utf8 = 0; 2574 2575 ibuf++; 2576 sfunc = (unsigned char) *ibuf++; 2577 *rbuflen = 0; 2578 2579 if (sfunc >= 3 && sfunc <= 6) { 2580 if (afp_version < 30) { 2581 return( AFPERR_PARAM ); 2582 } 2583 utf8 = 1; 2584 } 2585 2586 switch ( sfunc ) { 2587 case 1 : 2588 case 3 :/* unicode */ 2589 memcpy( &id, ibuf, sizeof( id )); 2590 id = ntohl(id); 2591 if ( id != 0 ) { 2592 if (( pw = getpwuid( id )) == NULL ) { 2593 return( AFPERR_NOITEM ); 2594 } 2595 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC), 2596 pw->pw_name, -1, &name); 2597 } else { 2598 len = 0; 2599 name = NULL; 2600 } 2601 break; 2602 case 2 : 2603 case 4 : /* unicode */ 2604 memcpy( &id, ibuf, sizeof( id )); 2605 id = ntohl(id); 2606 if ( id != 0 ) { 2607 if (NULL == ( gr = (struct group *)getgrgid( id ))) { 2608 return( AFPERR_NOITEM ); 2609 } 2610 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC, 2611 gr->gr_name, -1, &name); 2612 } else { 2613 len = 0; 2614 name = NULL; 2615 } 2616 break; 2617 2618 case 5 : /* UUID -> username */ 2619 case 6 : /* UUID -> groupname */ 2620 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) 2621 return AFPERR_PARAM; 2622 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request"); 2623 uuidtype_t type; 2624 len = getnamefromuuid((unsigned char*) ibuf, &name, &type); 2625 if (len != 0) /* its a error code, not len */ 2626 return AFPERR_NOITEM; 2627 switch (type) { 2628 case UUID_USER: 2629 if (( pw = getpwnam( name )) == NULL ) 2630 return( AFPERR_NOITEM ); 2631 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid); 2632 id = htonl(UUID_USER); 2633 memcpy( rbuf, &id, sizeof( id )); 2634 id = htonl( pw->pw_uid); 2635 rbuf += sizeof( id ); 2636 memcpy( rbuf, &id, sizeof( id )); 2637 rbuf += sizeof( id ); 2638 *rbuflen = 2 * sizeof( id ); 2639 break; 2640 case UUID_GROUP: 2641 if (( gr = getgrnam( name )) == NULL ) 2642 return( AFPERR_NOITEM ); 2643 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid); 2644 id = htonl(UUID_GROUP); 2645 memcpy( rbuf, &id, sizeof( id )); 2646 rbuf += sizeof( id ); 2647 id = htonl( gr->gr_gid); 2648 memcpy( rbuf, &id, sizeof( id )); 2649 rbuf += sizeof( id ); 2650 *rbuflen = 2 * sizeof( id ); 2651 break; 2652 default: 2653 return AFPERR_MISC; 2654 } 2655 break; 2656 2657 default : 2658 return( AFPERR_PARAM ); 2659 } 2660 2661 if (name) 2662 len = strlen( name ); 2663 2664 if (utf8) { 2665 u_int16_t tp = htons(len); 2666 memcpy(rbuf, &tp, sizeof(tp)); 2667 rbuf += sizeof(tp); 2668 *rbuflen += 2; 2669 } 2670 else { 2671 *rbuf++ = len; 2672 *rbuflen += 1; 2673 } 2674 if ( len > 0 ) { 2675 memcpy( rbuf, name, len ); 2676 } 2677 *rbuflen += len; 2678 if (name) 2679 free(name); 2680 return( AFP_OK ); 2681} 2682 2683int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 2684{ 2685 struct passwd *pw; 2686 struct group *gr; 2687 int len, sfunc; 2688 u_int32_t id; 2689 u_int16_t ulen; 2690 2691 ibuf++; 2692 sfunc = (unsigned char) *ibuf++; 2693 *rbuflen = 0; 2694 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version); 2695 switch ( sfunc ) { 2696 case 1 : 2697 case 2 : /* unicode */ 2698 if (afp_version < 30) { 2699 return( AFPERR_PARAM ); 2700 } 2701 memcpy(&ulen, ibuf, sizeof(ulen)); 2702 len = ntohs(ulen); 2703 ibuf += 2; 2704 LOG(log_debug, logtype_afpd, "afp_mapname: alive"); 2705 break; 2706 case 3 : 2707 case 4 : 2708 len = (unsigned char) *ibuf++; 2709 break; 2710 case 5 : /* username -> UUID */ 2711 case 6 : /* groupname -> UUID */ 2712 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) 2713 return AFPERR_PARAM; 2714 memcpy(&ulen, ibuf, sizeof(ulen)); 2715 len = ntohs(ulen); 2716 ibuf += 2; 2717 break; 2718 default : 2719 return( AFPERR_PARAM ); 2720 } 2721 2722 ibuf[ len ] = '\0'; 2723 2724 if ( len == 0 ) 2725 return AFPERR_PARAM; 2726 else { 2727 switch ( sfunc ) { 2728 case 1 : /* unicode */ 2729 case 3 : 2730 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) { 2731 return( AFPERR_NOITEM ); 2732 } 2733 id = pw->pw_uid; 2734 id = htonl(id); 2735 memcpy( rbuf, &id, sizeof( id )); 2736 *rbuflen = sizeof( id ); 2737 break; 2738 2739 case 2 : /* unicode */ 2740 case 4 : 2741 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf); 2742 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) { 2743 return( AFPERR_NOITEM ); 2744 } 2745 id = gr->gr_gid; 2746 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id); 2747 id = htonl(id); 2748 memcpy( rbuf, &id, sizeof( id )); 2749 *rbuflen = sizeof( id ); 2750 break; 2751 case 5 : /* username -> UUID */ 2752 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); 2753 if (0 != getuuidfromname(ibuf, UUID_USER, (unsigned char *)rbuf)) 2754 return AFPERR_NOITEM; 2755 *rbuflen = UUID_BINSIZE; 2756 break; 2757 case 6 : /* groupname -> UUID */ 2758 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); 2759 if (0 != getuuidfromname(ibuf, UUID_GROUP, (unsigned char *)rbuf)) 2760 return AFPERR_NOITEM; 2761 *rbuflen = UUID_BINSIZE; 2762 break; 2763 } 2764 } 2765 return( AFP_OK ); 2766} 2767 2768/* ------------------------------------ 2769 variable DID support 2770*/ 2771int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 2772{ 2773#if 0 2774 struct vol *vol; 2775 struct dir *dir; 2776 u_int16_t vid; 2777 u_int32_t did; 2778#endif /* 0 */ 2779 2780 *rbuflen = 0; 2781 2782 /* do nothing as dids are static for the life of the process. */ 2783#if 0 2784 ibuf += 2; 2785 2786 memcpy(&vid, ibuf, sizeof( vid )); 2787 ibuf += sizeof( vid ); 2788 if (( vol = getvolbyvid( vid )) == NULL ) { 2789 return( AFPERR_PARAM ); 2790 } 2791 2792 memcpy( &did, ibuf, sizeof( did )); 2793 ibuf += sizeof( did ); 2794 if (( dir = dirlookup( vol, did )) == NULL ) { 2795 return( AFPERR_PARAM ); 2796 } 2797 2798 /* dir_remove -- deletedid */ 2799#endif /* 0 */ 2800 2801 return AFP_OK; 2802} 2803 2804/* did creation gets done automatically 2805 * there's a pb again with case but move it to cname 2806 */ 2807int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 2808{ 2809 struct vol *vol; 2810 struct dir *parentdir; 2811 struct path *path; 2812 u_int32_t did; 2813 u_int16_t vid; 2814 2815 *rbuflen = 0; 2816 ibuf += 2; 2817 2818 memcpy(&vid, ibuf, sizeof(vid)); 2819 ibuf += sizeof( vid ); 2820 2821 if (NULL == ( vol = getvolbyvid( vid )) ) { 2822 return( AFPERR_PARAM ); 2823 } 2824 2825 memcpy(&did, ibuf, sizeof(did)); 2826 ibuf += sizeof(did); 2827 2828 if (NULL == ( parentdir = dirlookup( vol, did )) ) { 2829 return afp_errno; 2830 } 2831 2832 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) { 2833 return get_afp_errno(AFPERR_PARAM); 2834 } 2835 2836 if ( *path->m_name != '\0' ) { 2837 return path_error(path, AFPERR_NOOBJ); 2838 } 2839 2840 if ( !path->st_valid && of_stat(path ) < 0 ) { 2841 return( AFPERR_NOOBJ ); 2842 } 2843 if ( path->st_errno ) { 2844 return( AFPERR_NOOBJ ); 2845 } 2846 2847 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did)); 2848 *rbuflen = sizeof(curdir->d_did); 2849 return AFP_OK; 2850} 2851