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