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 <stdio.h> 11#include <stdlib.h> 12 13/* STDC check */ 14#if STDC_HEADERS 15#include <string.h> 16#else /* STDC_HEADERS */ 17#ifndef HAVE_STRCHR 18#define strchr index 19#define strrchr index 20#endif /* HAVE_STRCHR */ 21char *strchr (), *strrchr (); 22 23#ifndef HAVE_MEMCPY 24#define memcpy(d,s,n) bcopy ((s), (d), (n)) 25#define memmove(d,s,n) bcopy ((s), (d), (n)) 26#endif /* ! HAVE_MEMCPY */ 27#endif /* STDC_HEADERS */ 28 29#include <utime.h> 30#include <errno.h> 31#include <sys/param.h> 32 33#include <atalk/adouble.h> 34#include <atalk/vfs.h> 35#include <atalk/logger.h> 36#include <atalk/afp.h> 37#include <atalk/util.h> 38#include <atalk/cnid.h> 39#include <atalk/unix.h> 40#include <atalk/globals.h> 41#include <atalk/fce_api.h> 42 43#include "directory.h" 44#include "dircache.h" 45#include "desktop.h" 46#include "volume.h" 47#include "fork.h" 48#include "file.h" 49#include "filedir.h" 50#include "unix.h" 51 52/* foxconn add start, improvemennt of time machine backup rate, 53 Jonathan 2012/08/22 */ 54#define TIME_MACHINE_WA 55 56/* the format for the finderinfo fields (from IM: Toolbox Essentials): 57 * field bytes subfield bytes 58 * 59 * files: 60 * ioFlFndrInfo 16 -> type 4 type field 61 * creator 4 creator field 62 * flags 2 finder flags: 63 * alias, bundle, etc. 64 * location 4 location in window 65 * folder 2 window that contains file 66 * 67 * ioFlXFndrInfo 16 -> iconID 2 icon id 68 * unused 6 reserved 69 * script 1 script system 70 * xflags 1 reserved 71 * commentID 2 comment id 72 * putawayID 4 home directory id 73 */ 74 75const u_char ufinderi[ADEDLEN_FINDERI] = { 76 0, 0, 0, 0, 0, 0, 0, 0, 77 1, 0, 0, 0, 0, 0, 0, 0, 78 0, 0, 0, 0, 0, 0, 0, 0, 79 0, 0, 0, 0, 0, 0, 0, 0 80 }; 81 82static const u_char old_ufinderi[] = { 83 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X' 84 }; 85 86/* ---------------------- 87*/ 88static int default_type(void *finder) 89{ 90 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8)) 91 return 1; 92 return 0; 93} 94 95/* FIXME path : unix or mac name ? (for now it's unix name ) */ 96void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink) 97{ 98 struct extmap *em; 99 void *ad_finder = NULL; 100 int chk_ext = 0; 101 102 if (adp) 103 ad_finder = ad_entry(adp, ADEID_FINDERI); 104 105 if (ad_finder) { 106 memcpy(data, ad_finder, ADEDLEN_FINDERI); 107 /* default type ? */ 108 if (default_type(ad_finder)) 109 chk_ext = 1; 110 } 111 else { 112 memcpy(data, ufinderi, ADEDLEN_FINDERI); 113 chk_ext = 1; 114 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */ 115 u_int16_t ashort; 116 117 ashort = htons(FINDERINFO_INVISIBLE); 118 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); 119 } 120 } 121 122 if (islink && !vol_syml_opt(vol)) { 123 u_int16_t linkflag; 124 memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2); 125 linkflag |= htons(FINDERINFO_ISALIAS); 126 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2); 127 memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4); 128 memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4); 129 chk_ext = 0; 130 } 131 132 /** Only enter if no appledouble information and no finder information found. */ 133 if (chk_ext && (em = getextmap( upath ))) { 134 memcpy(data, em->em_type, sizeof( em->em_type )); 135 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator)); 136 } 137 return data; 138} 139 140/* --------------------- 141*/ 142char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8) 143{ 144 u_int32_t aint; 145 char *tp = NULL; 146 char *src = name; 147 aint = strlen( name ); 148 149 if (!utf8) { 150 /* want mac name */ 151 if (utf8_encoding()) { 152 /* but name is an utf8 mac name */ 153 char *u, *m; 154 155 /* global static variable... */ 156 tp = strdup(name); 157 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) { 158 aint = 0; 159 } 160 else { 161 aint = strlen(m); 162 src = m; 163 } 164 165 } 166 if (aint > MACFILELEN) 167 aint = MACFILELEN; 168 *data++ = aint; 169 } 170 else { 171 u_int16_t temp; 172 173 if (aint > UTF8FILELEN_EARLY) /* FIXME safeguard, anyway if no ascii char it's game over*/ 174 aint = UTF8FILELEN_EARLY; 175 176 utf8 = vol->v_kTextEncoding; 177 memcpy(data, &utf8, sizeof(utf8)); 178 data += sizeof(utf8); 179 180 temp = htons(aint); 181 memcpy(data, &temp, sizeof(temp)); 182 data += sizeof(temp); 183 } 184 185 memcpy( data, src, aint ); 186 data += aint; 187 if (tp) { 188 strcpy(name, tp); 189 free(tp); 190 } 191 return data; 192} 193 194/* 195 * FIXME: PDINFO is UTF8 and doesn't need adp 196*/ 197#define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\ 198 (1 << FILPBIT_CDATE) |\ 199 (1 << FILPBIT_MDATE) |\ 200 (1 << FILPBIT_BDATE) |\ 201 (1 << FILPBIT_FINFO) |\ 202 (1 << FILPBIT_RFLEN) |\ 203 (1 << FILPBIT_EXTRFLEN) |\ 204 (1 << FILPBIT_PDINFO) |\ 205 (1 << FILPBIT_FNUM) |\ 206 (1 << FILPBIT_UNIXPR))) 207 208/*! 209 * @brief Get CNID for did/upath args both from database and adouble file 210 * 211 * 1. Get the objects CNID as stored in its adouble file 212 * 2. Get the objects CNID from the database 213 * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory 214 * 4. In case 2 and 3 differ, store 3 in the adouble file 215 * 216 * @param vol (rw) volume 217 * @param adp (rw) adouble struct of object upath, might be NULL 218 * @param st (r) stat of upath, must NOT be NULL 219 * @param did (r) parent CNID of upath 220 * @param upath (r) name of object 221 * @param len (r) strlen of upath 222 */ 223uint32_t get_id(struct vol *vol, 224 struct adouble *adp, 225 const struct stat *st, 226 const cnid_t did, 227 const char *upath, 228 const int len) 229{ 230 static int first = 1; /* mark if this func is called the first time */ 231 u_int32_t adcnid; 232 u_int32_t dbcnid = CNID_INVALID; 233 234restart: 235 if (vol->v_cdb != NULL) { 236 /* prime aint with what we think is the cnid, set did to zero for 237 catching moved files */ 238 adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */ 239 240 dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */ 241 /* Throw errors if cnid_add fails. */ 242 if (dbcnid == CNID_INVALID) { 243 switch (errno) { 244 case CNID_ERR_CLOSE: /* the db is closed */ 245 break; 246 case CNID_ERR_PARAM: 247 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add"); 248 afp_errno = AFPERR_PARAM; 249 goto exit; 250 case CNID_ERR_PATH: 251 afp_errno = AFPERR_PARAM; 252 goto exit; 253 default: 254 /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */ 255 /* we have to do it here for "dbd" because it uses "lazy opening" */ 256 /* In order to not end in a loop somehow with goto restart below */ 257 /* */ 258 if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */ 259 cnid_close(vol->v_cdb); 260 free(vol->v_cnidscheme); 261 vol->v_cnidscheme = strdup("tdb"); 262 263 int flags = CNID_FLAG_MEMORY; 264 if ((vol->v_flags & AFPVOL_NODEV)) { 265 flags |= CNID_FLAG_NODEV; 266 } 267 LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", 268 vol->v_path); 269 vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL); 270 if (vol->v_cdb) { 271 vol->v_flags &= ~AFPVOL_CACHE; 272 if (!(vol->v_flags & AFPVOL_TM)) { 273 vol->v_flags |= AFPVOL_RO; 274 setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead." 275 "Check server messages for details. Switching to read-only mode."); 276 kill(getpid(), SIGUSR2); 277 } 278 goto restart; /* now try again with the temp CNID db */ 279 } else { 280 setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!" 281 "Check server messages for details, can't recover from this state!"); 282 } 283 } 284 afp_errno = AFPERR_MISC; 285 goto exit; 286 } 287 } 288 else if (adp && (adcnid != dbcnid)) { /* 4 */ 289 /* Update the ressource fork. For a folder adp is always null */ 290 LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)", 291 getcwdpath(), upath, htonl(adcnid), htonl(dbcnid)); 292 if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) { 293 ad_flush(adp); 294 } 295 } 296 } 297 298exit: 299 first = 0; 300 return dbcnid; 301} 302 303/* -------------------------- */ 304int getmetadata(struct vol *vol, 305 u_int16_t bitmap, 306 struct path *path, struct dir *dir, 307 char *buf, size_t *buflen, struct adouble *adp) 308{ 309 char *data, *l_nameoff = NULL, *upath; 310 char *utf_nameoff = NULL; 311 int bit = 0; 312 u_int32_t aint; 313 cnid_t id = 0; 314 u_int16_t ashort; 315 u_char achar, fdType[4]; 316 u_int32_t utf8 = 0; 317 struct stat *st; 318 struct maccess ma; 319 320 LOG(log_debug, logtype_afpd, "getmetadata(\"%s\")", path->u_name); 321 322 upath = path->u_name; 323 st = &path->st; 324 data = buf; 325 326 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name) 327 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */ 328 || (bitmap & (1 << FILPBIT_FNUM))) { 329 if (!path->id) { 330 bstring fullpath; 331 struct dir *cachedfile; 332 int len = strlen(upath); 333 if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != NULL) 334 id = cachedfile->d_did; 335 else { 336 id = get_id(vol, adp, st, dir->d_did, upath, len); 337 338 /* Add it to the cache */ 339 LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u", 340 ntohl(dir->d_did), upath, ntohl(id)); 341 342 /* Get macname from unixname first */ 343 if (path->m_name == NULL) { 344 if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) { 345 LOG(log_error, logtype_afpd, "getmetadata: utompath error"); 346 return AFPERR_MISC; 347 } 348 } 349 350 /* Build fullpath */ 351 if (((fullpath = bstrcpy(dir->d_fullpath)) == NULL) 352 || (bconchar(fullpath, '/') != BSTR_OK) 353 || (bcatcstr(fullpath, upath)) != BSTR_OK) { 354 LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno)); 355 return AFPERR_MISC; 356 } 357 358 if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, fullpath, st)) == NULL) { 359 LOG(log_error, logtype_afpd, "getmetadata: error from dir_new"); 360 return AFPERR_MISC; 361 } 362 363 if ((dircache_add(vol, cachedfile)) != 0) { 364 LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error"); 365 return AFPERR_MISC; 366 } 367 } 368 } else { 369 id = path->id; 370 } 371 372 if (id == CNID_INVALID) 373 return afp_errno; 374 375 if (!path->m_name) { 376 path->m_name = utompath(vol, upath, id, utf8_encoding()); 377 } 378 } 379 while ( bitmap != 0 ) { 380 while (( bitmap & 1 ) == 0 ) { 381 bitmap = bitmap>>1; 382 bit++; 383 } 384 385 switch ( bit ) { 386 case FILPBIT_ATTR : 387 if ( adp ) { 388 ad_getattr(adp, &ashort); 389 } else if (vol_inv_dots(vol) && *upath == '.') { 390 ashort = htons(ATTRBIT_INVISIBLE); 391 } else 392 ashort = 0; 393#if 0 394 /* FIXME do we want a visual clue if the file is read only 395 */ 396 struct maccess ma; 397 accessmode(vol, ".", &ma, dir , NULL); 398 if ((ma.ma_user & AR_UWRITE)) { 399 accessmode(vol, upath, &ma, dir , st); 400 if (!(ma.ma_user & AR_UWRITE)) { 401 ashort |= htons(ATTRBIT_NOWRITE); 402 } 403 } 404#endif 405 memcpy(data, &ashort, sizeof( ashort )); 406 data += sizeof( ashort ); 407 LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x", 408 path->u_name, ntohs(ashort)); 409 break; 410 411 case FILPBIT_PDID : 412 memcpy(data, &dir->d_did, sizeof( u_int32_t )); 413 data += sizeof( u_int32_t ); 414 LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u", 415 path->u_name, ntohl(dir->d_did)); 416 break; 417 418 case FILPBIT_CDATE : 419 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0)) 420 aint = AD_DATE_FROM_UNIX(st->st_mtime); 421 memcpy(data, &aint, sizeof( aint )); 422 data += sizeof( aint ); 423 break; 424 425 case FILPBIT_MDATE : 426 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) { 427 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) { 428 aint = AD_DATE_FROM_UNIX(st->st_mtime); 429 } 430 } else { 431 aint = AD_DATE_FROM_UNIX(st->st_mtime); 432 } 433 memcpy(data, &aint, sizeof( int )); 434 data += sizeof( int ); 435 break; 436 437 case FILPBIT_BDATE : 438 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0)) 439 aint = AD_DATE_START; 440 memcpy(data, &aint, sizeof( int )); 441 data += sizeof( int ); 442 break; 443 444 case FILPBIT_FINFO : 445 get_finderinfo(vol, upath, adp, (char *)data,S_ISLNK(st->st_mode)); 446 data += ADEDLEN_FINDERI; 447 break; 448 449 case FILPBIT_LNAME : 450 l_nameoff = data; 451 data += sizeof( u_int16_t ); 452 break; 453 454 case FILPBIT_SNAME : 455 memset(data, 0, sizeof(u_int16_t)); 456 data += sizeof( u_int16_t ); 457 break; 458 459 case FILPBIT_FNUM : 460 memcpy(data, &id, sizeof( id )); 461 data += sizeof( id ); 462 LOG(log_debug, logtype_afpd, "metadata('%s'): CNID: %u", 463 path->u_name, ntohl(id)); 464 break; 465 466 case FILPBIT_DFLEN : 467 if (st->st_size > 0xffffffff) 468 aint = 0xffffffff; 469 else 470 aint = htonl( st->st_size ); 471 memcpy(data, &aint, sizeof( aint )); 472 data += sizeof( aint ); 473 break; 474 475 case FILPBIT_RFLEN : 476 if ( adp ) { 477 if (adp->ad_rlen > 0xffffffff) 478 aint = 0xffffffff; 479 else 480 aint = htonl( adp->ad_rlen); 481 } else { 482 aint = 0; 483 } 484 memcpy(data, &aint, sizeof( aint )); 485 data += sizeof( aint ); 486 break; 487 488 /* Current client needs ProDOS info block for this file. 489 Use simple heuristic and let the Mac "type" string tell 490 us what the PD file code should be. Everything gets a 491 subtype of 0x0000 unless the original value was hashed 492 to "pXYZ" when we created it. See IA, Ver 2. 493 <shirsch@adelphia.net> */ 494 case FILPBIT_PDINFO : 495 if (afp_version >= 30) { /* UTF8 name */ 496 utf8 = kTextEncodingUTF8; 497 utf_nameoff = data; 498 data += sizeof( u_int16_t ); 499 aint = 0; 500 memcpy(data, &aint, sizeof( aint )); 501 data += sizeof( aint ); 502 } 503 else { 504 if ( adp ) { 505 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 ); 506 507 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) { 508 achar = '\x04'; 509 ashort = 0x0000; 510 } 511 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) { 512 achar = '\xff'; 513 ashort = 0x0000; 514 } 515 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) { 516 achar = '\xb3'; 517 ashort = 0x0000; 518 } 519 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) { 520 achar = '\x00'; 521 ashort = 0x0000; 522 } 523 else if ( fdType[0] == 'p' ) { 524 achar = fdType[1]; 525 ashort = (fdType[2] * 256) + fdType[3]; 526 } 527 else { 528 achar = '\x00'; 529 ashort = 0x0000; 530 } 531 } 532 else { 533 achar = '\x00'; 534 ashort = 0x0000; 535 } 536 537 *data++ = achar; 538 *data++ = 0; 539 memcpy(data, &ashort, sizeof( ashort )); 540 data += sizeof( ashort ); 541 memset(data, 0, sizeof( ashort )); 542 data += sizeof( ashort ); 543 } 544 break; 545 case FILPBIT_EXTDFLEN: 546 aint = htonl(st->st_size >> 32); 547 memcpy(data, &aint, sizeof( aint )); 548 data += sizeof( aint ); 549 aint = htonl(st->st_size); 550 memcpy(data, &aint, sizeof( aint )); 551 data += sizeof( aint ); 552 break; 553 case FILPBIT_EXTRFLEN: 554 aint = 0; 555 if (adp) 556 aint = htonl(adp->ad_rlen >> 32); 557 memcpy(data, &aint, sizeof( aint )); 558 data += sizeof( aint ); 559 if (adp) 560 aint = htonl(adp->ad_rlen); 561 memcpy(data, &aint, sizeof( aint )); 562 data += sizeof( aint ); 563 break; 564 case FILPBIT_UNIXPR : 565 /* accessmode may change st_mode with ACLs */ 566 accessmode(vol, upath, &ma, dir , st); 567 568 aint = htonl(st->st_uid); 569 memcpy( data, &aint, sizeof( aint )); 570 data += sizeof( aint ); 571 aint = htonl(st->st_gid); 572 memcpy( data, &aint, sizeof( aint )); 573 data += sizeof( aint ); 574 575 /* FIXME: ugly hack 576 type == slnk indicates an OSX style symlink, 577 we have to add S_IFLNK to the mode, otherwise 578 10.3 clients freak out. */ 579 580 aint = st->st_mode; 581 if (adp) { 582 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 ); 583 if ( memcmp( fdType, "slnk", 4 ) == 0 ) { 584 aint |= S_IFLNK; 585 } 586 } 587 aint = htonl(aint); 588 589 memcpy( data, &aint, sizeof( aint )); 590 data += sizeof( aint ); 591 592 *data++ = ma.ma_user; 593 *data++ = ma.ma_world; 594 *data++ = ma.ma_group; 595 *data++ = ma.ma_owner; 596 break; 597 598 default : 599 return( AFPERR_BITMAP ); 600 } 601 bitmap = bitmap>>1; 602 bit++; 603 } 604 if ( l_nameoff ) { 605 ashort = htons( data - buf ); 606 memcpy(l_nameoff, &ashort, sizeof( ashort )); 607 data = set_name(vol, data, dir->d_did, path->m_name, id, 0); 608 } 609 if ( utf_nameoff ) { 610 ashort = htons( data - buf ); 611 memcpy(utf_nameoff, &ashort, sizeof( ashort )); 612 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8); 613 } 614 *buflen = data - buf; 615 return (AFP_OK); 616} 617 618/* ----------------------- */ 619int getfilparams(struct vol *vol, 620 u_int16_t bitmap, 621 struct path *path, struct dir *dir, 622 char *buf, size_t *buflen ) 623{ 624 struct adouble ad, *adp; 625 int opened = 0; 626 int rc; 627 628 LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name); 629 630 opened = PARAM_NEED_ADP(bitmap); 631 adp = NULL; 632 633 if (opened) { 634 char *upath; 635 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0; 636 637 adp = of_ad(vol, path, &ad); 638 upath = path->u_name; 639 640 if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) { 641 switch (errno) { 642 case EACCES: 643 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?", 644 upath, strerror(errno)); 645 return AFPERR_ACCESS; 646 case EIO: 647 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath); 648 /* fall through */ 649 case ENOENT: 650 default: 651 adp = NULL; 652 break; 653 } 654 } 655 } 656 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp); 657 if ( adp ) { 658 ad_close_metadata( adp); 659 } 660 661 return( rc ); 662} 663 664/* ----------------------------- */ 665int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 666{ 667 struct adouble ad, *adp; 668 struct vol *vol; 669 struct dir *dir; 670 struct ofork *of = NULL; 671 char *path, *upath; 672 int creatf, did, openf, retvalue = AFP_OK; 673 u_int16_t vid; 674 struct path *s_path; 675 676 *rbuflen = 0; 677 ibuf++; 678 creatf = (unsigned char) *ibuf++; 679 680 memcpy(&vid, ibuf, sizeof( vid )); 681 ibuf += sizeof( vid ); 682 683 if (NULL == ( vol = getvolbyvid( vid )) ) { 684 return( AFPERR_PARAM ); 685 } 686 687 if (vol->v_flags & AFPVOL_RO) 688 return AFPERR_VLOCK; 689 690 memcpy(&did, ibuf, sizeof( did)); 691 ibuf += sizeof( did ); 692 693 if (NULL == ( dir = dirlookup( vol, did )) ) { 694 return afp_errno; 695 } 696 697 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { 698 return get_afp_errno(AFPERR_PARAM); 699 } 700 701 if ( *s_path->m_name == '\0' ) { 702 return( AFPERR_BADTYPE ); 703 } 704 705 upath = s_path->u_name; 706 707 /* if upath is deleted we already in trouble anyway */ 708 if ((of = of_findname(vol, s_path))) { 709 adp = of->of_ad; 710 } else { 711 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 712 adp = &ad; 713 } 714 if ( creatf) { 715 /* on a hard create, fail if file exists and is open */ 716 if (of) 717 return AFPERR_BUSY; 718 openf = O_RDWR|O_CREAT|O_TRUNC; 719 } else { 720 /* on a soft create, if the file is open then ad_open won't fail 721 because open syscall is not called 722 */ 723 if (of) { 724 return AFPERR_EXIST; 725 } 726 openf = O_RDWR|O_CREAT|O_EXCL; 727 } 728 729 if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE, 730 openf, 0666, adp) < 0 ) { 731 switch ( errno ) { 732 case EROFS: 733 return AFPERR_VLOCK; 734 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */ 735 return ( AFPERR_NOOBJ ); 736 case EEXIST : 737 return( AFPERR_EXIST ); 738 case EACCES : 739 return( AFPERR_ACCESS ); 740 case EDQUOT: 741 case ENOSPC : 742 LOG(log_info, logtype_afpd, "afp_createfile: DISK FULL"); 743 return( AFPERR_DFULL ); 744 default : 745 return( AFPERR_PARAM ); 746 } 747 } 748 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */ 749 /* on noadouble volumes, just creating the data fork is ok */ 750 if (vol_noadouble(vol)) { 751 ad_close( adp, ADFLAGS_DF ); 752 goto createfile_done; 753 } 754 /* FIXME with hard create on an existing file, we already 755 * corrupted the data file. 756 */ 757 netatalk_unlink( upath ); 758 ad_close( adp, ADFLAGS_DF ); 759 return AFPERR_ACCESS; 760 } 761 762 path = s_path->m_name; 763 ad_setname(adp, path); 764 765 struct stat st; 766 if (lstat(upath, &st) != 0) { 767 LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): stat: %s", 768 upath, strerror(errno)); 769 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF); 770 return AFPERR_MISC; 771 } 772 773 (void)get_id(vol, adp, &st, dir->d_did, upath, strlen(upath)); 774 775 ad_flush( adp); 776 777 fce_register_new_file(s_path); 778 779 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); 780 781createfile_done: 782 curdir->d_offcnt++; 783/* foxconn add start, Jonathan 2012/08/22 */ 784#ifdef TIME_MACHINE_WA 785 afp_bandsdid_IncreaseOffcnt(curdir->d_did); 786#endif 787 788#ifdef DROPKLUDGE 789 if (vol->v_flags & AFPVOL_DROPBOX) { 790 retvalue = matchfile2dirperms(upath, vol, did); 791 } 792#endif /* DROPKLUDGE */ 793 794 setvoltime(obj, vol ); 795 796 return (retvalue); 797} 798 799int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 800{ 801 struct vol *vol; 802 struct dir *dir; 803 struct path *s_path; 804 int did, rc; 805 u_int16_t vid, bitmap; 806 807 *rbuflen = 0; 808 ibuf += 2; 809 810 memcpy(&vid, ibuf, sizeof( vid )); 811 ibuf += sizeof( vid ); 812 if (NULL == ( vol = getvolbyvid( vid )) ) { 813 return( AFPERR_PARAM ); 814 } 815 816 if (vol->v_flags & AFPVOL_RO) 817 return AFPERR_VLOCK; 818 819 memcpy(&did, ibuf, sizeof( did )); 820 ibuf += sizeof( did ); 821 if (NULL == ( dir = dirlookup( vol, did )) ) { 822 return afp_errno; /* was AFPERR_NOOBJ */ 823 } 824 825 memcpy(&bitmap, ibuf, sizeof( bitmap )); 826 bitmap = ntohs( bitmap ); 827 ibuf += sizeof( bitmap ); 828 829 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { 830 return get_afp_errno(AFPERR_PARAM); 831 } 832 833 if (path_isadir(s_path)) { 834 return( AFPERR_BADTYPE ); /* it's a directory */ 835 } 836 837 if ( s_path->st_errno != 0 ) { 838 return( AFPERR_NOOBJ ); 839 } 840 841 if ((u_long)ibuf & 1 ) { 842 ibuf++; 843 } 844 845 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) { 846 setvoltime(obj, vol ); 847 } 848 849 return( rc ); 850} 851 852/* 853 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic 854 * 855*/ 856extern struct path Cur_Path; 857 858int setfilparams(struct vol *vol, 859 struct path *path, u_int16_t f_bitmap, char *buf ) 860{ 861 struct adouble ad, *adp; 862 struct extmap *em; 863 int bit, isad = 1, err = AFP_OK; 864 char *upath; 865 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */ 866 u_int16_t ashort, bshort, oshort; 867 u_int32_t aint; 868 u_int32_t upriv; 869 u_int16_t upriv_bit = 0; 870 871 struct utimbuf ut; 872 873 int change_mdate = 0; 874 int change_parent_mdate = 0; 875 int newdate = 0; 876 struct timeval tv; 877 uid_t f_uid; 878 gid_t f_gid; 879 u_int16_t bitmap = f_bitmap; 880 u_int32_t cdate,bdate; 881 u_char finder_buf[32]; 882 int fp; 883 ssize_t len; 884 char symbuf[MAXPATHLEN+1]; 885 886#ifdef DEBUG 887 LOG(log_debug9, logtype_afpd, "begin setfilparams:"); 888#endif /* DEBUG */ 889 890 adp = of_ad(vol, path, &ad); 891 upath = path->u_name; 892 893 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) { 894 return AFPERR_ACCESS; 895 } 896 897 /* with unix priv maybe we have to change adouble file priv first */ 898 bit = 0; 899 while ( bitmap != 0 ) { 900 while (( bitmap & 1 ) == 0 ) { 901 bitmap = bitmap>>1; 902 bit++; 903 } 904 switch( bit ) { 905 case FILPBIT_ATTR : 906 change_mdate = 1; 907 memcpy(&ashort, buf, sizeof( ashort )); 908 buf += sizeof( ashort ); 909 break; 910 case FILPBIT_CDATE : 911 change_mdate = 1; 912 memcpy(&cdate, buf, sizeof(cdate)); 913 buf += sizeof( cdate ); 914 break; 915 case FILPBIT_MDATE : 916 memcpy(&newdate, buf, sizeof( newdate )); 917 buf += sizeof( newdate ); 918 break; 919 case FILPBIT_BDATE : 920 change_mdate = 1; 921 memcpy(&bdate, buf, sizeof( bdate)); 922 buf += sizeof( bdate ); 923 break; 924 case FILPBIT_FINFO : 925 change_mdate = 1; 926 if (memcmp(buf,"slnkrhap",8) == 0 927 && !(S_ISLNK(path->st.st_mode)) 928 && !(vol->v_flags & AFPVOL_FOLLOWSYM)) { 929 /* request to turn this into a symlink */ 930 if ((fp = open(path->u_name, O_RDONLY)) == -1) { 931 err = AFPERR_MISC; 932 goto setfilparam_done; 933 } 934 len = read(fp, symbuf, MAXPATHLEN); 935 close(fp); 936 if (!(len > 0)) { 937 err = AFPERR_MISC; 938 goto setfilparam_done; 939 } 940 if (unlink(path->u_name) != 0) { 941 err = AFPERR_MISC; 942 goto setfilparam_done; 943 } 944 symbuf[len] = 0; 945 if (symlink(symbuf, path->u_name) != 0) { 946 err = AFPERR_MISC; 947 goto setfilparam_done; 948 } 949 of_stat(vol, path); 950 } 951 memcpy(finder_buf, buf, 32 ); 952 buf += 32; 953 break; 954 case FILPBIT_UNIXPR : 955 if (!vol_unix_priv(vol)) { 956 /* this volume doesn't use unix priv */ 957 err = AFPERR_BITMAP; 958 bitmap = 0; 959 break; 960 } 961 change_mdate = 1; 962 change_parent_mdate = 1; 963 964 memcpy( &aint, buf, sizeof( aint )); 965 f_uid = ntohl (aint); 966 buf += sizeof( aint ); 967 memcpy( &aint, buf, sizeof( aint )); 968 f_gid = ntohl (aint); 969 buf += sizeof( aint ); 970 setfilowner(vol, f_uid, f_gid, path); 971 972 memcpy( &upriv, buf, sizeof( upriv )); 973 buf += sizeof( upriv ); 974 upriv = ntohl (upriv); 975 if ((upriv & S_IWUSR)) { 976 setfilunixmode(vol, path, upriv); 977 } 978 else { 979 /* do it later */ 980 upriv_bit = 1; 981 } 982 break; 983 case FILPBIT_PDINFO : 984 if (afp_version < 30) { /* else it's UTF8 name */ 985 achar = *buf; 986 buf += 2; 987 /* Keep special case to support crlf translations */ 988 if ((unsigned int) achar == 0x04) { 989 fdType = (u_char *)"TEXT"; 990 buf += 2; 991 } else { 992 xyy[0] = ( u_char ) 'p'; 993 xyy[1] = achar; 994 xyy[3] = *buf++; 995 xyy[2] = *buf++; 996 fdType = xyy; 997 } 998 break; 999 } 1000 /* fallthrough */ 1001 default : 1002 err = AFPERR_BITMAP; 1003 /* break while loop */ 1004 bitmap = 0; 1005 break; 1006 } 1007 1008 bitmap = bitmap>>1; 1009 bit++; 1010 } 1011 1012 /* second try with adouble open 1013 */ 1014 if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) { 1015 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error"); 1016 /* 1017 * For some things, we don't need an adouble header: 1018 * - change of modification date 1019 * - UNIX privs (Bug-ID #2863424) 1020 */ 1021 if (!vol_noadouble(vol) && (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) { 1022 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access"); 1023 return AFPERR_ACCESS; 1024 } 1025 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR"); 1026 isad = 0; 1027 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) { 1028 ad_setname(adp, path->m_name); 1029 } 1030 1031 bit = 0; 1032 bitmap = f_bitmap; 1033 while ( bitmap != 0 ) { 1034 while (( bitmap & 1 ) == 0 ) { 1035 bitmap = bitmap>>1; 1036 bit++; 1037 } 1038 1039 switch( bit ) { 1040 case FILPBIT_ATTR : 1041 ad_getattr(adp, &bshort); 1042 oshort = bshort; 1043 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) { 1044 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR ); 1045 } else { 1046 bshort &= ~ashort; 1047 } 1048 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE))) 1049 change_parent_mdate = 1; 1050 ad_setattr(adp, bshort); 1051 break; 1052 case FILPBIT_CDATE : 1053 ad_setdate(adp, AD_DATE_CREATE, cdate); 1054 break; 1055 case FILPBIT_MDATE : 1056 break; 1057 case FILPBIT_BDATE : 1058 ad_setdate(adp, AD_DATE_BACKUP, bdate); 1059 break; 1060 case FILPBIT_FINFO : 1061 if (default_type( ad_entry( adp, ADEID_FINDERI )) 1062 && ( 1063 ((em = getextmap( path->m_name )) && 1064 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) && 1065 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator))) 1066 || ((em = getdefextmap()) && 1067 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) && 1068 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator))) 1069 )) { 1070 memcpy(finder_buf, ufinderi, 8 ); 1071 } 1072 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 ); 1073 break; 1074 case FILPBIT_UNIXPR : 1075 if (upriv_bit) { 1076 setfilunixmode(vol, path, upriv); 1077 } 1078 break; 1079 case FILPBIT_PDINFO : 1080 if (afp_version < 30) { /* else it's UTF8 name */ 1081 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 ); 1082 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 ); 1083 break; 1084 } 1085 /* fallthrough */ 1086 default : 1087 err = AFPERR_BITMAP; 1088 goto setfilparam_done; 1089 } 1090 bitmap = bitmap>>1; 1091 bit++; 1092 } 1093 1094setfilparam_done: 1095 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) { 1096 newdate = AD_DATE_FROM_UNIX(tv.tv_sec); 1097 } 1098 if (newdate) { 1099 if (isad) 1100 ad_setdate(adp, AD_DATE_MODIFY, newdate); 1101 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate); 1102 utime(upath, &ut); 1103 } 1104 1105 if (isad) { 1106 ad_flush( adp); 1107 ad_close_metadata( adp); 1108 1109 } 1110 1111 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) { 1112 newdate = AD_DATE_FROM_UNIX(tv.tv_sec); 1113 bitmap = 1<<FILPBIT_MDATE; 1114 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate); 1115 } 1116 1117#ifdef DEBUG 1118 LOG(log_debug9, logtype_afpd, "end setfilparams:"); 1119#endif /* DEBUG */ 1120 return err; 1121} 1122 1123/* 1124 * renamefile and copyfile take the old and new unix pathnames 1125 * and the new mac name. 1126 * 1127 * sdir_fd source dir fd to which src path is relative (for openat et al semantics) 1128 * passing -1 means this is not used, src path is a full path 1129 * src the source path 1130 * dst the dest filename in current dir 1131 * newname the dest mac name 1132 * adp adouble struct of src file, if open, or & zeroed one 1133 * 1134 */ 1135int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) 1136{ 1137 int rc; 1138 1139 LOG(log_debug, logtype_afpd, 1140 "renamefile: src[%d, \"%s\"] -> dst[\"%s\"]", sdir_fd, src, dst); 1141 1142 if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) { 1143 switch ( errno ) { 1144 case ENOENT : 1145 return( AFPERR_NOOBJ ); 1146 case EPERM: 1147 case EACCES : 1148 return( AFPERR_ACCESS ); 1149 case EROFS: 1150 return AFPERR_VLOCK; 1151 case EXDEV : /* Cross device move -- try copy */ 1152 /* NOTE: with open file it's an error because after the copy we will 1153 * get two files, it's fixable for our process (eg reopen the new file, get the 1154 * locks, and so on. But it doesn't solve the case with a second process 1155 */ 1156 if (adp->ad_open_forks) { 1157 /* FIXME warning in syslog so admin'd know there's a conflict ?*/ 1158 return AFPERR_OLOCK; /* little lie */ 1159 } 1160 if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) { 1161 /* on error copyfile delete dest */ 1162 return( rc ); 1163 } 1164 return deletefile(vol, sdir_fd, src, 0); 1165 default : 1166 return( AFPERR_PARAM ); 1167 } 1168 } 1169 1170 if (vol->vfs->vfs_renamefile(vol, sdir_fd, src, dst) < 0 ) { 1171 int err; 1172 1173 err = errno; 1174 /* try to undo the data fork rename, 1175 * we know we are on the same device 1176 */ 1177 if (err) { 1178 unix_rename(-1, dst, sdir_fd, src ); 1179 /* return the first error */ 1180 switch ( err) { 1181 case ENOENT : 1182 return AFPERR_NOOBJ; 1183 case EPERM: 1184 case EACCES : 1185 return AFPERR_ACCESS ; 1186 case EROFS: 1187 return AFPERR_VLOCK; 1188 default : 1189 return AFPERR_PARAM ; 1190 } 1191 } 1192 } 1193 1194 /* don't care if we can't open the newly renamed ressource fork 1195 */ 1196 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) { 1197 ad_setname(adp, newname); 1198 ad_flush( adp ); 1199 ad_close( adp, ADFLAGS_HF ); 1200 } 1201 1202 return( AFP_OK ); 1203} 1204 1205/* ---------------- 1206 convert a Mac long name to an utf8 name, 1207*/ 1208size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen) 1209{ 1210size_t outlen; 1211 1212 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) { 1213 return -1; 1214 } 1215 return outlen; 1216} 1217 1218/* ---------------- */ 1219int copy_path_name(const struct vol *vol, char *newname, char *ibuf) 1220{ 1221char type = *ibuf; 1222size_t plen = 0; 1223u_int16_t len16; 1224u_int32_t hint; 1225 1226 if ( type != 2 && !(afp_version >= 30 && type == 3) ) { 1227 return -1; 1228 } 1229 ibuf++; 1230 switch (type) { 1231 case 2: 1232 if (( plen = (unsigned char)*ibuf++ ) != 0 ) { 1233 if (afp_version >= 30) { 1234 /* convert it to UTF8 1235 */ 1236 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1) 1237 return -1; 1238 } 1239 else { 1240 strncpy( newname, ibuf, plen ); 1241 newname[ plen ] = '\0'; 1242 } 1243 if (strlen(newname) != plen) { 1244 /* there's \0 in newname, e.g. it's a pathname not 1245 * only a filename. 1246 */ 1247 return -1; 1248 } 1249 } 1250 break; 1251 case 3: 1252 memcpy(&hint, ibuf, sizeof(hint)); 1253 ibuf += sizeof(hint); 1254 1255 memcpy(&len16, ibuf, sizeof(len16)); 1256 ibuf += sizeof(len16); 1257 plen = ntohs(len16); 1258 1259 if (plen) { 1260 if (plen > AFPOBJ_TMPSIZ) { 1261 return -1; 1262 } 1263 strncpy( newname, ibuf, plen ); 1264 newname[ plen ] = '\0'; 1265 if (strlen(newname) != plen) { 1266 return -1; 1267 } 1268 } 1269 break; 1270 } 1271 return plen; 1272} 1273 1274/* ----------------------------------- 1275*/ 1276int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1277{ 1278 struct vol *s_vol, *d_vol; 1279 struct dir *dir; 1280 char *newname, *p, *upath; 1281 struct path *s_path; 1282 u_int32_t sdid, ddid; 1283 int err, retvalue = AFP_OK; 1284 u_int16_t svid, dvid; 1285 1286 struct adouble ad, *adp; 1287 int denyreadset; 1288 1289 *rbuflen = 0; 1290 ibuf += 2; 1291 1292 memcpy(&svid, ibuf, sizeof( svid )); 1293 ibuf += sizeof( svid ); 1294 if (NULL == ( s_vol = getvolbyvid( svid )) ) { 1295 return( AFPERR_PARAM ); 1296 } 1297 1298 memcpy(&sdid, ibuf, sizeof( sdid )); 1299 ibuf += sizeof( sdid ); 1300 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) { 1301 return afp_errno; 1302 } 1303 1304 memcpy(&dvid, ibuf, sizeof( dvid )); 1305 ibuf += sizeof( dvid ); 1306 memcpy(&ddid, ibuf, sizeof( ddid )); 1307 ibuf += sizeof( ddid ); 1308 1309 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) { 1310 return get_afp_errno(AFPERR_PARAM); 1311 } 1312 if ( path_isadir(s_path) ) { 1313 return( AFPERR_BADTYPE ); 1314 } 1315 1316 /* don't allow copies when the file is open. 1317 * XXX: the spec only calls for read/deny write access. 1318 * however, copyfile doesn't have any of that info, 1319 * and locks need to stay coherent. as a result, 1320 * we just balk if the file is opened already. */ 1321 1322 adp = of_ad(s_vol, s_path, &ad); 1323 1324 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) { 1325 return AFPERR_DENYCONF; 1326 } 1327 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 1328 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 ); 1329 1330 if (denyreadset) { 1331 retvalue = AFPERR_DENYCONF; 1332 goto copy_exit; 1333 } 1334 1335 newname = obj->newtmp; 1336 strcpy( newname, s_path->m_name ); 1337 1338 p = ctoupath( s_vol, curdir, newname ); 1339 if (!p) { 1340 retvalue = AFPERR_PARAM; 1341 goto copy_exit; 1342 } 1343 1344#ifdef FORCE_UIDGID 1345 /* FIXME svid != dvid && dvid's user can't read svid */ 1346#endif 1347 if (NULL == ( d_vol = getvolbyvid( dvid )) ) { 1348 retvalue = AFPERR_PARAM; 1349 goto copy_exit; 1350 } 1351 1352 if (d_vol->v_flags & AFPVOL_RO) { 1353 retvalue = AFPERR_VLOCK; 1354 goto copy_exit; 1355 } 1356 1357 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) { 1358 retvalue = afp_errno; 1359 goto copy_exit; 1360 } 1361 1362 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) { 1363 retvalue = get_afp_errno(AFPERR_NOOBJ); 1364 goto copy_exit; 1365 } 1366 1367 if ( *s_path->m_name != '\0' ) { 1368 retvalue =path_error(s_path, AFPERR_NOOBJ); 1369 goto copy_exit; 1370 } 1371 1372 /* one of the handful of places that knows about the path type */ 1373 if (copy_path_name(d_vol, newname, ibuf) < 0) { 1374 retvalue = AFPERR_PARAM; 1375 goto copy_exit; 1376 } 1377 /* newname is always only a filename so curdir *is* its 1378 * parent folder 1379 */ 1380 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) { 1381 retvalue =AFPERR_PARAM; 1382 goto copy_exit; 1383 } 1384 1385 if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) { 1386 retvalue = err; 1387 goto copy_exit; 1388 } 1389 curdir->d_offcnt++; 1390/* foxconn add start, Jonathan 2012/08/22 */ 1391#ifdef TIME_MACHINE_WA 1392 afp_bandsdid_IncreaseOffcnt(curdir->d_did); 1393#endif 1394 1395#ifdef DROPKLUDGE 1396 if (vol->v_flags & AFPVOL_DROPBOX) { 1397 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */ 1398 } 1399#endif /* DROPKLUDGE */ 1400 1401 setvoltime(obj, d_vol ); 1402 1403copy_exit: 1404 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF ); 1405 return( retvalue ); 1406} 1407 1408/* ----------------------- */ 1409static int copy_all(const int dfd, const void *buf, 1410 size_t buflen) 1411{ 1412 ssize_t cc; 1413 1414#ifdef DEBUG 1415 LOG(log_debug9, logtype_afpd, "begin copy_all:"); 1416#endif /* DEBUG */ 1417 1418 while (buflen > 0) { 1419 if ((cc = write(dfd, buf, buflen)) < 0) { 1420 switch (errno) { 1421 case EINTR: 1422 continue; 1423 default: 1424 return -1; 1425 } 1426 } 1427 buflen -= cc; 1428 } 1429 1430#ifdef DEBUG 1431 LOG(log_debug9, logtype_afpd, "end copy_all:"); 1432#endif /* DEBUG */ 1433 1434 return 0; 1435} 1436 1437/* -------------------------- 1438 * copy only the fork data stream 1439*/ 1440static int copy_fork(int eid, struct adouble *add, struct adouble *ads) 1441{ 1442 ssize_t cc; 1443 int err = 0; 1444 char filebuf[8192]; 1445 int sfd, dfd; 1446 1447 if (eid == ADEID_DFORK) { 1448 sfd = ad_data_fileno(ads); 1449 dfd = ad_data_fileno(add); 1450 } 1451 else { 1452 sfd = ad_reso_fileno(ads); 1453 dfd = ad_reso_fileno(add); 1454 } 1455 1456 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET)) 1457 return -1; 1458 1459 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET)) 1460 return -1; 1461 1462#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */ 1463 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */ 1464 off_t offset = 0; 1465 size_t size; 1466 struct stat st; 1467 #define BUF 128*1024*1024 1468 1469 if (fstat(sfd, &st) == 0) { 1470 1471 while (1) { 1472 if ( offset >= st.st_size) { 1473 return 0; 1474 } 1475 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset; 1476 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) { 1477 switch (errno) { 1478 case ENOSYS: 1479 case EINVAL: /* there's no guarantee that all fs support sendfile */ 1480 goto no_sendfile; 1481 default: 1482 return -1; 1483 } 1484 } 1485 } 1486 } 1487 no_sendfile: 1488 lseek(sfd, offset, SEEK_SET); 1489#endif 1490 1491 while (1) { 1492 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) { 1493 if (errno == EINTR) 1494 continue; 1495 err = -1; 1496 break; 1497 } 1498 1499 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) { 1500 break; 1501 } 1502 } 1503 return err; 1504} 1505 1506/* ---------------------------------- 1507 * if newname is NULL (from directory.c) we don't want to copy the resource fork. 1508 * because we are doing it elsewhere. 1509 * currently if newname is NULL then adp is NULL. 1510 */ 1511int copyfile(const struct vol *s_vol, 1512 const struct vol *d_vol, 1513 int sfd, 1514 char *src, 1515 char *dst, 1516 char *newname, 1517 struct adouble *adp) 1518{ 1519 struct adouble ads, add; 1520 int err = 0; 1521 int ret_err = 0; 1522 int adflags; 1523 int stat_result; 1524 struct stat st; 1525 1526 LOG(log_debug, logtype_afpd, "copyfile(sfd:%d,s:'%s',d:'%s',n:'%s')", 1527 sfd, src, dst, newname); 1528 1529 if (adp == NULL) { 1530 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); 1531 adp = &ads; 1532 } 1533 1534 adflags = ADFLAGS_DF; 1535 if (newname) { 1536 adflags |= ADFLAGS_HF; 1537 } 1538 1539 if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) { 1540 ret_err = errno; 1541 goto done; 1542 } 1543 1544 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */ 1545 /* no resource fork, don't create one for dst file */ 1546 adflags &= ~ADFLAGS_HF; 1547 } 1548 1549 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */ 1550 1551 if (stat_result < 0) { 1552 /* unlikely but if fstat fails, the default file mode will be 0666. */ 1553 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 1554 } 1555 1556 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options); 1557 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) { 1558 ret_err = errno; 1559 ad_close( adp, adflags ); 1560 if (EEXIST != ret_err) { 1561 deletefile(d_vol, -1, dst, 0); 1562 goto done; 1563 } 1564 return AFPERR_EXIST; 1565 } 1566 1567 /* 1568 * XXX if the source and the dest don't use the same resource type it's broken 1569 */ 1570 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){ 1571 /* copy the data fork */ 1572 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) { 1573 if (ad_meta_fileno(adp) != -1) 1574 err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst); 1575 } 1576 } 1577 1578 if (err < 0) { 1579 ret_err = errno; 1580 } 1581 1582 if (!ret_err && newname && (adflags & ADFLAGS_HF)) { 1583 /* set the new name in the resource fork */ 1584 ad_copy_header(&add, adp); 1585 ad_setname(&add, newname); 1586 ad_flush( &add ); 1587 } 1588 ad_close( adp, adflags ); 1589 1590 if (ad_close( &add, adflags ) <0) { 1591 ret_err = errno; 1592 } 1593 1594 if (ret_err) { 1595 deletefile(d_vol, -1, dst, 0); 1596 } 1597 else if (stat_result == 0) { 1598 /* set dest modification date to src date */ 1599 struct utimbuf ut; 1600 1601 ut.actime = ut.modtime = st.st_mtime; 1602 utime(dst, &ut); 1603 /* FIXME netatalk doesn't use resource fork file date 1604 * but maybe we should set its modtime too. 1605 */ 1606 } 1607 1608done: 1609 switch ( ret_err ) { 1610 case 0: 1611 return AFP_OK; 1612 case EDQUOT: 1613 case EFBIG: 1614 case ENOSPC: 1615 LOG(log_info, logtype_afpd, "copyfile: DISK FULL"); 1616 return AFPERR_DFULL; 1617 case ENOENT: 1618 return AFPERR_NOOBJ; 1619 case EACCES: 1620 return AFPERR_ACCESS; 1621 case EROFS: 1622 return AFPERR_VLOCK; 1623 } 1624 return AFPERR_PARAM; 1625} 1626 1627 1628/* ----------------------------------- 1629 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename 1630 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete) 1631 1632 when deletefile is called we don't have lock on it, file is closed (for us) 1633 untrue if called by renamefile 1634 1635 ad_open always try to open file RDWR first and ad_lock takes care of 1636 WRITE lock on read only file. 1637*/ 1638 1639static int check_attrib(struct adouble *adp) 1640{ 1641u_int16_t bshort = 0; 1642 1643 ad_getattr(adp, &bshort); 1644 /* 1645 * Does kFPDeleteInhibitBit (bit 8) set? 1646 */ 1647 if ((bshort & htons(ATTRBIT_NODELETE))) { 1648 return AFPERR_OLOCK; 1649 } 1650 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { 1651 return AFPERR_BUSY; 1652 } 1653 return 0; 1654} 1655/* 1656 * dirfd can be used for unlinkat semantics 1657 */ 1658int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) 1659{ 1660 struct adouble ad; 1661 struct adouble *adp = NULL; 1662 int adflags, err = AFP_OK; 1663 int meta = 0; 1664 1665 LOG(log_debug, logtype_afpd, "deletefile('%s')", file); 1666 1667 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 1668 if (checkAttrib) { 1669 /* was EACCESS error try to get only metadata */ 1670 /* we never want to create a resource fork here, we are going to delete it 1671 * moreover sometimes deletefile is called with a no existent file and 1672 * ad_open would create a 0 byte resource fork 1673 */ 1674 if ( ad_metadataat(dirfd, file, ADFLAGS_OPENFORKS, &ad) == 0 ) { 1675 if ((err = check_attrib(&ad))) { 1676 ad_close_metadata(&ad); 1677 return err; 1678 } 1679 meta = 1; 1680 } 1681 } 1682 1683 /* try to open both forks at once */ 1684 adflags = ADFLAGS_DF; 1685 if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) { 1686 switch (errno) { 1687 case ENOENT: 1688 err = AFPERR_NOOBJ; 1689 goto end; 1690 case EACCES: /* maybe it's a file with no write mode for us */ 1691 break; /* was return AFPERR_ACCESS;*/ 1692 case EROFS: 1693 err = AFPERR_VLOCK; 1694 goto end; 1695 default: 1696 err = AFPERR_PARAM; 1697 goto end; 1698 } 1699 } 1700 else { 1701 adp = &ad; 1702 } 1703 1704 if ( adp && ad_reso_fileno( adp ) != -1 ) { /* there's a resource fork */ 1705 adflags |= ADFLAGS_HF; 1706 /* FIXME we have a pb here because we want to know if a file is open 1707 * there's a 'priority inversion' if you can't open the ressource fork RW 1708 * you can delete it if it's open because you can't get a write lock. 1709 * 1710 * ADLOCK_FILELOCK means the whole ressource fork, not only after the 1711 * metadatas 1712 * 1713 * FIXME it doesn't work for RFORK open read only and fork open without deny mode 1714 */ 1715 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) { 1716 err = AFPERR_BUSY; 1717 goto end; 1718 } 1719 } 1720 1721 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) { 1722 err = AFPERR_BUSY; 1723 } else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) { 1724 cnid_t id; 1725 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) { 1726 cnid_delete(vol->v_cdb, id); 1727 } 1728 } 1729 1730end: 1731 if (meta) 1732 ad_close_metadata(&ad); 1733 1734 if (adp) 1735 ad_close( &ad, adflags ); /* ad_close removes locks if any */ 1736 1737 return err; 1738} 1739 1740/* ------------------------------------ */ 1741/* return a file id */ 1742int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 1743{ 1744 struct stat *st; 1745 struct vol *vol; 1746 struct dir *dir; 1747 char *upath; 1748 int len; 1749 cnid_t did, id; 1750 u_short vid; 1751 struct path *s_path; 1752 1753 *rbuflen = 0; 1754 1755 ibuf += 2; 1756 1757 memcpy(&vid, ibuf, sizeof(vid)); 1758 ibuf += sizeof(vid); 1759 1760 if (NULL == ( vol = getvolbyvid( vid )) ) { 1761 return( AFPERR_PARAM); 1762 } 1763 1764 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { 1765 return AFPERR_NOOP; 1766 } 1767 1768 if (vol->v_flags & AFPVOL_RO) 1769 return AFPERR_VLOCK; 1770 1771 memcpy(&did, ibuf, sizeof( did )); 1772 ibuf += sizeof(did); 1773 1774 if (NULL == ( dir = dirlookup( vol, did )) ) { 1775 return afp_errno; /* was AFPERR_PARAM */ 1776 } 1777 1778 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { 1779 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */ 1780 } 1781 1782 if ( path_isadir(s_path) ) { 1783 return( AFPERR_BADTYPE ); 1784 } 1785 1786 upath = s_path->u_name; 1787 switch (s_path->st_errno) { 1788 case 0: 1789 break; /* success */ 1790 case EPERM: 1791 case EACCES: 1792 return AFPERR_ACCESS; 1793 case ENOENT: 1794 return AFPERR_NOOBJ; 1795 default: 1796 return AFPERR_PARAM; 1797 } 1798 st = &s_path->st; 1799 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) { 1800 memcpy(rbuf, &id, sizeof(id)); 1801 *rbuflen = sizeof(id); 1802 return AFPERR_EXISTID; 1803 } 1804 1805 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) { 1806 memcpy(rbuf, &id, sizeof(id)); 1807 *rbuflen = sizeof(id); 1808 return AFP_OK; 1809 } 1810 1811 return afp_errno; 1812} 1813 1814/* ------------------------------- */ 1815struct reenum { 1816 struct vol *vol; 1817 cnid_t did; 1818}; 1819 1820static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data) 1821{ 1822 struct path path; 1823 struct reenum *param = data; 1824 struct vol *vol = param->vol; 1825 cnid_t did = param->did; 1826 cnid_t aint; 1827 1828 if (ostat(de->d_name, &path.st, vol_syml_opt(vol)) < 0) 1829 return 0; 1830 1831 /* update or add to cnid */ 1832 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */ 1833 1834#if AD_VERSION > AD_VERSION1 1835 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) { 1836 struct adouble ad, *adp; 1837 1838 path.st_errno = 0; 1839 path.st_valid = 1; 1840 path.u_name = de->d_name; 1841 1842 adp = of_ad(vol, &path, &ad); 1843 1844 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) { 1845 return 0; 1846 } 1847 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) { 1848 ad_flush(adp); 1849 } 1850 ad_close_metadata(adp); 1851 } 1852#endif /* AD_VERSION > AD_VERSION1 */ 1853 1854 return 0; 1855} 1856 1857/* -------------------- 1858 * Ok the db is out of synch with the dir. 1859 * but if it's a deleted file we don't want to do it again and again. 1860*/ 1861static int 1862reenumerate_id(struct vol *vol, char *name, struct dir *dir) 1863{ 1864 int ret; 1865 struct reenum data; 1866 struct stat st; 1867 1868 if (vol->v_cdb == NULL) { 1869 return -1; 1870 } 1871 1872 /* FIXME use of_statdir ? */ 1873 if (ostat(name, &st, vol_syml_opt(vol))) { 1874 return -1; 1875 } 1876 1877 if (dirreenumerate(dir, &st)) { 1878 /* we already did it once and the dir haven't been modified */ 1879/* foxconn add start, Jonathan 2012/08/22 */ 1880#ifdef TIME_MACHINE_WA 1881 if(ntohl(dir->d_did )== afp_getbandsdid()){ 1882 1883 return afp_bandsdid_GetOffcnt(); 1884 } 1885 else 1886 return dir->d_offcnt; 1887#else 1888 return dir->d_offcnt; 1889#endif 1890/* foxconn add end, Jonathan 2012/08/22 */ 1891 1892 1893 } 1894 1895 data.vol = vol; 1896 data.did = dir->d_did; 1897 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) { 1898 setdiroffcnt(curdir, &st, ret); 1899 dir->d_flags |= DIRF_CNID; 1900 } 1901 1902 return ret; 1903} 1904 1905/* ------------------------------ 1906 resolve a file id */ 1907int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 1908{ 1909 struct vol *vol; 1910 struct dir *dir; 1911 char *upath; 1912 struct path path; 1913 int err, retry=0; 1914 size_t buflen; 1915 cnid_t id, cnid; 1916 u_int16_t vid, bitmap; 1917 1918 static char buffer[12 + MAXPATHLEN + 1]; 1919 int len = 12 + MAXPATHLEN + 1; 1920 1921 *rbuflen = 0; 1922 ibuf += 2; 1923 1924 memcpy(&vid, ibuf, sizeof(vid)); 1925 ibuf += sizeof(vid); 1926 1927 if (NULL == ( vol = getvolbyvid( vid )) ) { 1928 return( AFPERR_PARAM); 1929 } 1930 1931 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { 1932 return AFPERR_NOOP; 1933 } 1934 1935 memcpy(&id, ibuf, sizeof( id )); 1936 ibuf += sizeof(id); 1937 cnid = id; 1938 1939 if (!id) { 1940 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */ 1941 return AFPERR_NOID; 1942 } 1943retry: 1944 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { 1945 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */ 1946 } 1947 1948 if (NULL == ( dir = dirlookup( vol, id )) ) { 1949 return AFPERR_NOID; /* idem AFPERR_PARAM */ 1950 } 1951 if (movecwd(vol, dir) < 0) { 1952 switch (errno) { 1953 case EACCES: 1954 case EPERM: 1955 return AFPERR_ACCESS; 1956 case ENOENT: 1957 return AFPERR_NOID; 1958 default: 1959 return AFPERR_PARAM; 1960 } 1961 } 1962 1963 memset(&path, 0, sizeof(path)); 1964 path.u_name = upath; 1965 if (of_stat(vol, &path) < 0 ) { 1966#ifdef ESTALE 1967 /* with nfs and our working directory is deleted */ 1968 if (errno == ESTALE) { 1969 errno = ENOENT; 1970 } 1971#endif 1972 if ( errno == ENOENT && !retry) { 1973 /* cnid db is out of sync, reenumerate the directory and update ids */ 1974 reenumerate_id(vol, ".", dir); 1975 id = cnid; 1976 retry = 1; 1977 goto retry; 1978 } 1979 switch (errno) { 1980 case EACCES: 1981 case EPERM: 1982 return AFPERR_ACCESS; 1983 case ENOENT: 1984 return AFPERR_NOID; 1985 default: 1986 return AFPERR_PARAM; 1987 } 1988 } 1989 1990 /* directories are bad */ 1991 if (S_ISDIR(path.st.st_mode)) { 1992 /* OS9 and OSX don't return the same error code */ 1993 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE; 1994 } 1995 1996 memcpy(&bitmap, ibuf, sizeof(bitmap)); 1997 bitmap = ntohs( bitmap ); 1998 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) { 1999 return AFPERR_NOID; 2000 } 2001 path.id = cnid; 2002 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 2003 rbuf + sizeof(bitmap), &buflen))) { 2004 return err; 2005 } 2006 *rbuflen = buflen + sizeof(bitmap); 2007 memcpy(rbuf, ibuf, sizeof(bitmap)); 2008 2009 return AFP_OK; 2010} 2011 2012/* ------------------------------ */ 2013int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 2014{ 2015 struct stat st; 2016 struct vol *vol; 2017 struct dir *dir; 2018 char *upath; 2019 int err; 2020 cnid_t id; 2021 cnid_t fileid; 2022 u_short vid; 2023 static char buffer[12 + MAXPATHLEN + 1]; 2024 int len = 12 + MAXPATHLEN + 1; 2025 2026 *rbuflen = 0; 2027 ibuf += 2; 2028 2029 memcpy(&vid, ibuf, sizeof(vid)); 2030 ibuf += sizeof(vid); 2031 2032 if (NULL == ( vol = getvolbyvid( vid )) ) { 2033 return( AFPERR_PARAM); 2034 } 2035 2036 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { 2037 return AFPERR_NOOP; 2038 } 2039 2040 if (vol->v_flags & AFPVOL_RO) 2041 return AFPERR_VLOCK; 2042 2043 memcpy(&id, ibuf, sizeof( id )); 2044 ibuf += sizeof(id); 2045 fileid = id; 2046 2047 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { 2048 return AFPERR_NOID; 2049 } 2050 2051 if (NULL == ( dir = dirlookup( vol, id )) ) { 2052 if (afp_errno == AFPERR_NOOBJ) { 2053 err = AFPERR_NOOBJ; 2054 goto delete; 2055 } 2056 return( AFPERR_PARAM ); 2057 } 2058 2059 err = AFP_OK; 2060 if ((movecwd(vol, dir) < 0) || (ostat(upath, &st, vol_syml_opt(vol)) < 0)) { 2061 switch (errno) { 2062 case EACCES: 2063 case EPERM: 2064 return AFPERR_ACCESS; 2065#ifdef ESTALE 2066 case ESTALE: 2067#endif 2068 case ENOENT: 2069 /* still try to delete the id */ 2070 err = AFPERR_NOOBJ; 2071 break; 2072 default: 2073 return AFPERR_PARAM; 2074 } 2075 } 2076 else if (S_ISDIR(st.st_mode)) /* directories are bad */ 2077 return AFPERR_BADTYPE; 2078 2079delete: 2080 if (cnid_delete(vol->v_cdb, fileid)) { 2081 switch (errno) { 2082 case EROFS: 2083 return AFPERR_VLOCK; 2084 case EPERM: 2085 case EACCES: 2086 return AFPERR_ACCESS; 2087 default: 2088 return AFPERR_PARAM; 2089 } 2090 } 2091 2092 return err; 2093} 2094 2095/* ------------------------------ */ 2096static struct adouble *find_adouble(const struct vol *vol, struct path *path, struct ofork **of, struct adouble *adp) 2097{ 2098 int ret; 2099 2100 if (path->st_errno) { 2101 switch (path->st_errno) { 2102 case ENOENT: 2103 afp_errno = AFPERR_NOID; 2104 break; 2105 case EPERM: 2106 case EACCES: 2107 afp_errno = AFPERR_ACCESS; 2108 break; 2109 default: 2110 afp_errno = AFPERR_PARAM; 2111 break; 2112 } 2113 return NULL; 2114 } 2115 /* we use file_access both for legacy Mac perm and 2116 * for unix privilege, rename will take care of folder perms 2117 */ 2118 if (file_access(path, OPENACC_WR ) < 0) { 2119 afp_errno = AFPERR_ACCESS; 2120 return NULL; 2121 } 2122 2123 if ((*of = of_findname(vol, path))) { 2124 /* reuse struct adouble so it won't break locks */ 2125 adp = (*of)->of_ad; 2126 } 2127 else { 2128 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp); 2129 /* META and HF */ 2130 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) { 2131 /* from AFP spec. 2132 * The user must have the Read & Write privilege for both files in order to use this command. 2133 */ 2134 ad_close(adp, ADFLAGS_HF); 2135 afp_errno = AFPERR_ACCESS; 2136 return NULL; 2137 } 2138 } 2139 return adp; 2140} 2141 2142#define APPLETEMP ".AppleTempXXXXXX" 2143 2144int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 2145{ 2146 struct stat srcst, destst; 2147 struct vol *vol; 2148 struct dir *dir, *sdir; 2149 char *spath, temp[17], *p; 2150 char *supath, *upath; 2151 struct path *path; 2152 int err; 2153 struct adouble ads; 2154 struct adouble add; 2155 struct adouble *adsp = NULL; 2156 struct adouble *addp = NULL; 2157 struct ofork *s_of = NULL; 2158 struct ofork *d_of = NULL; 2159 int crossdev; 2160 2161 int slen, dlen; 2162 u_int32_t sid, did; 2163 u_int16_t vid; 2164 2165 uid_t uid; 2166 gid_t gid; 2167 2168 *rbuflen = 0; 2169 ibuf += 2; 2170 2171 memcpy(&vid, ibuf, sizeof(vid)); 2172 ibuf += sizeof(vid); 2173 2174 if (NULL == ( vol = getvolbyvid( vid )) ) { 2175 return( AFPERR_PARAM); 2176 } 2177 2178 if ((vol->v_flags & AFPVOL_RO)) 2179 return AFPERR_VLOCK; 2180 2181 /* source and destination dids */ 2182 memcpy(&sid, ibuf, sizeof(sid)); 2183 ibuf += sizeof(sid); 2184 memcpy(&did, ibuf, sizeof(did)); 2185 ibuf += sizeof(did); 2186 2187 /* source file */ 2188 if (NULL == (dir = dirlookup( vol, sid )) ) { 2189 return afp_errno; /* was AFPERR_PARAM */ 2190 } 2191 2192 if (NULL == ( path = cname( vol, dir, &ibuf )) ) { 2193 return get_afp_errno(AFPERR_NOOBJ); 2194 } 2195 2196 if ( path_isadir(path) ) { 2197 return AFPERR_BADTYPE; /* it's a dir */ 2198 } 2199 2200 /* save some stuff */ 2201 srcst = path->st; 2202 sdir = curdir; 2203 spath = obj->oldtmp; 2204 supath = obj->newtmp; 2205 strcpy(spath, path->m_name); 2206 strcpy(supath, path->u_name); /* this is for the cnid changing */ 2207 p = absupath( vol, sdir, supath); 2208 if (!p) { 2209 /* pathname too long */ 2210 return AFPERR_PARAM ; 2211 } 2212 2213 ad_init(&ads, vol->v_adouble, vol->v_ad_options); 2214 if (!(adsp = find_adouble(vol, path, &s_of, &ads))) { 2215 return afp_errno; 2216 } 2217 2218 /* ***** from here we may have resource fork open **** */ 2219 2220 /* look for the source cnid. if it doesn't exist, don't worry about 2221 * it. */ 2222 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath)); 2223 2224 if (NULL == ( dir = dirlookup( vol, did )) ) { 2225 err = afp_errno; /* was AFPERR_PARAM */ 2226 goto err_exchangefile; 2227 } 2228 2229 if (NULL == ( path = cname( vol, dir, &ibuf )) ) { 2230 err = get_afp_errno(AFPERR_NOOBJ); 2231 goto err_exchangefile; 2232 } 2233 2234 if ( path_isadir(path) ) { 2235 err = AFPERR_BADTYPE; 2236 goto err_exchangefile; 2237 } 2238 2239 /* FPExchangeFiles is the only call that can return the SameObj 2240 * error */ 2241 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) { 2242 err = AFPERR_SAMEOBJ; 2243 goto err_exchangefile; 2244 } 2245 2246 ad_init(&add, vol->v_adouble, vol->v_ad_options); 2247 if (!(addp = find_adouble(vol, path, &d_of, &add))) { 2248 err = afp_errno; 2249 goto err_exchangefile; 2250 } 2251 destst = path->st; 2252 2253 /* they are not on the same device and at least one is open 2254 * FIXME broken for for crossdev and adouble v2 2255 * return an error 2256 */ 2257 crossdev = (srcst.st_dev != destst.st_dev); 2258 if (/* (d_of || s_of) && */ crossdev) { 2259 err = AFPERR_MISC; 2260 goto err_exchangefile; 2261 } 2262 2263 /* look for destination id. */ 2264 upath = path->u_name; 2265 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath)); 2266 2267 /* construct a temp name. 2268 * NOTE: the temp file will be in the dest file's directory. it 2269 * will also be inaccessible from AFP. */ 2270 memcpy(temp, APPLETEMP, sizeof(APPLETEMP)); 2271 if (!mktemp(temp)) { 2272 err = AFPERR_MISC; 2273 goto err_exchangefile; 2274 } 2275 2276 if (crossdev) { 2277 /* FIXME we need to close fork for copy, both s_of and d_of are null */ 2278 ad_close(adsp, ADFLAGS_HF); 2279 ad_close(addp, ADFLAGS_HF); 2280 } 2281 2282 /* now, quickly rename the file. we error if we can't. */ 2283 if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK) 2284 goto err_exchangefile; 2285 of_rename(vol, s_of, sdir, spath, curdir, temp); 2286 2287 /* rename destination to source */ 2288 if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK) 2289 goto err_src_to_tmp; 2290 of_rename(vol, d_of, curdir, path->m_name, sdir, spath); 2291 2292 /* rename temp to destination */ 2293 if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK) 2294 goto err_dest_to_src; 2295 of_rename(vol, s_of, curdir, temp, curdir, path->m_name); 2296 2297 /* id's need switching. src -> dest and dest -> src. 2298 * we need to re-stat() if it was a cross device copy. 2299 */ 2300 if (sid) 2301 cnid_delete(vol->v_cdb, sid); 2302 if (did) 2303 cnid_delete(vol->v_cdb, did); 2304 2305 if ((did && ( (crossdev && ostat(upath, &srcst, vol_syml_opt(vol)) < 0) || 2306 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0)) 2307 || 2308 (sid && ( (crossdev && ostat(p, &destst, vol_syml_opt(vol)) < 0) || 2309 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0)) 2310 ) { 2311 switch (errno) { 2312 case EPERM: 2313 case EACCES: 2314 err = AFPERR_ACCESS; 2315 break; 2316 default: 2317 err = AFPERR_PARAM; 2318 } 2319 goto err_temp_to_dest; 2320 } 2321 2322 /* here we need to reopen if crossdev */ 2323 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp)) 2324 { 2325 ad_flush( addp ); 2326 } 2327 2328 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp)) 2329 { 2330 ad_flush( adsp ); 2331 } 2332 2333 /* change perms, src gets dest perm and vice versa */ 2334 2335 uid = geteuid(); 2336 gid = getegid(); 2337 if (seteuid(0)) { 2338 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno)); 2339 err = AFP_OK; /* ignore error */ 2340 goto err_temp_to_dest; 2341 } 2342 2343 /* 2344 * we need to exchange ACL entries as well 2345 */ 2346 /* exchange_acls(vol, p, upath); */ 2347 2348 path->st = srcst; 2349 path->st_valid = 1; 2350 path->st_errno = 0; 2351 path->m_name = NULL; 2352 path->u_name = upath; 2353 2354 setfilunixmode(vol, path, destst.st_mode); 2355 setfilowner(vol, destst.st_uid, destst.st_gid, path); 2356 2357 path->st = destst; 2358 path->st_valid = 1; 2359 path->st_errno = 0; 2360 path->u_name = p; 2361 2362 setfilunixmode(vol, path, srcst.st_mode); 2363 setfilowner(vol, srcst.st_uid, srcst.st_gid, path); 2364 2365 if ( setegid(gid) < 0 || seteuid(uid) < 0) { 2366 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno)); 2367 exit(EXITERR_SYS); 2368 } 2369 2370 err = AFP_OK; 2371 goto err_exchangefile; 2372 2373 /* all this stuff is so that we can unwind a failed operation 2374 * properly. */ 2375err_temp_to_dest: 2376 /* rename dest to temp */ 2377 renamefile(vol, -1, upath, temp, temp, adsp); 2378 of_rename(vol, s_of, curdir, upath, curdir, temp); 2379 2380err_dest_to_src: 2381 /* rename source back to dest */ 2382 renamefile(vol, -1, p, upath, path->m_name, addp); 2383 of_rename(vol, d_of, sdir, spath, curdir, path->m_name); 2384 2385err_src_to_tmp: 2386 /* rename temp back to source */ 2387 renamefile(vol, -1, temp, p, spath, adsp); 2388 of_rename(vol, s_of, curdir, temp, sdir, spath); 2389 2390err_exchangefile: 2391 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */ 2392 ad_close(adsp, ADFLAGS_HF); 2393 } 2394 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */ 2395 ad_close(addp, ADFLAGS_HF); 2396 } 2397 2398 struct dir *cached; 2399 if ((cached = dircache_search_by_did(vol, sid)) != NULL) 2400 (void)dir_remove(vol, cached); 2401 if ((cached = dircache_search_by_did(vol, did)) != NULL) 2402 (void)dir_remove(vol, cached); 2403 2404 return err; 2405} 2406