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