1/* 2 * $Id: fork.c,v 1.73 2010-03-30 12:55:26 franklahm Exp $ 3 * 4 * Copyright (c) 1990,1993 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <stdio.h> 13 14#include <string.h> 15#include <errno.h> 16 17#include <atalk/adouble.h> 18#include <atalk/logger.h> 19 20#include <sys/param.h> 21#include <sys/socket.h> 22 23#include <netatalk/at.h> 24 25#include <atalk/dsi.h> 26#include <atalk/atp.h> 27#include <atalk/asp.h> 28#include <atalk/afp.h> 29#include <atalk/util.h> 30#include <atalk/cnid.h> 31#include <atalk/globals.h> 32 33#include "fork.h" 34#include "file.h" 35#include "directory.h" 36#include "desktop.h" 37#include "volume.h" 38 39#ifdef DEBUG1 40#define Debug(a) ((a)->options.flags & OPTION_DEBUG) 41#else 42#define Debug(a) (0) 43#endif 44 45#ifdef AFS 46struct ofork *writtenfork; 47#endif 48 49static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen) 50{ 51 struct path path; 52 struct stat *st; 53 54 struct adouble *adp; 55 struct dir *dir; 56 struct vol *vol; 57 58 59 /* can only get the length of the opened fork */ 60 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN))) 61 && (ofork->of_flags & AFPFORK_RSRC)) 62 || 63 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN))) 64 && (ofork->of_flags & AFPFORK_DATA))) { 65 return( AFPERR_BITMAP ); 66 } 67 68 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */ 69 adp = NULL; 70 } else { 71 adp = ofork->of_ad; 72 } 73 74 vol = ofork->of_vol; 75 dir = dirlookup(vol, ofork->of_did); 76 77 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) { 78 return( AFPERR_MISC ); 79 } 80 path.m_name = of_name(ofork); 81 path.id = 0; 82 st = &path.st; 83 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) | 84 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) | 85 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) { 86 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) { 87 /* 0 is for symlink */ 88 if (movecwd(vol, dir) < 0) 89 return( AFPERR_NOOBJ ); 90 if ( lstat( path.u_name, st ) < 0 ) 91 return( AFPERR_NOOBJ ); 92 } else { 93 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) { 94 return( AFPERR_BITMAP ); 95 } 96 } 97 } 98 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp ); 99} 100 101/* ---------------------------- */ 102static off_t get_off_t(char **ibuf, int is64) 103{ 104 u_int32_t temp; 105 off_t ret; 106 107 ret = 0; 108 memcpy(&temp, *ibuf, sizeof( temp )); 109 ret = ntohl(temp); /* ntohl is unsigned */ 110 *ibuf += sizeof(temp); 111 112 if (is64) { 113 memcpy(&temp, *ibuf, sizeof( temp )); 114 *ibuf += sizeof(temp); 115 ret = ntohl(temp)| (ret << 32); 116 } 117 else { 118 ret = (int)ret; /* sign extend */ 119 } 120 return ret; 121} 122 123/* ---------------------- */ 124static int set_off_t(off_t offset, char *rbuf, int is64) 125{ 126 u_int32_t temp; 127 int ret; 128 129 ret = 0; 130 if (is64) { 131 temp = htonl(offset >> 32); 132 memcpy(rbuf, &temp, sizeof( temp )); 133 rbuf += sizeof(temp); 134 ret = sizeof( temp ); 135 offset &= 0xffffffff; 136 } 137 temp = htonl(offset); 138 memcpy(rbuf, &temp, sizeof( temp )); 139 ret += sizeof( temp ); 140 141 return ret; 142} 143 144/* ------------------------ 145*/ 146static int is_neg(int is64, off_t val) 147{ 148 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U))) 149 return 1; 150 return 0; 151} 152 153static int sum_neg(int is64, off_t offset, off_t reqcount) 154{ 155 if (is_neg(is64, offset +reqcount) ) 156 return 1; 157 return 0; 158} 159 160/* ------------------------- 161*/ 162static int setforkmode(struct adouble *adp, int eid, int ofrefnum, off_t what) 163{ 164 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum); 165} 166 167/* ------------------------- 168*/ 169int getforkmode(struct adouble *adp, int eid, off_t what) 170{ 171 return ad_testlock(adp, eid, what); 172} 173 174/* ------------------------- 175*/ 176static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) 177{ 178 int ret; 179 int readset; 180 int writeset; 181 int denyreadset; 182 int denywriteset; 183 184 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) { 185 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE); 186 } 187 188 if ((access & (OPENACC_RD | OPENACC_DRD))) { 189 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0) 190 return readset; 191 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0) 192 return denyreadset; 193 194 if ((access & OPENACC_RD) && denyreadset) { 195 errno = EACCES; 196 return -1; 197 } 198 if ((access & OPENACC_DRD) && readset) { 199 errno = EACCES; 200 return -1; 201 } 202 /* boolean logic is not enough, because getforkmode is not always telling the 203 * true 204 */ 205 if ((access & OPENACC_RD)) { 206 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD); 207 if (ret) 208 return ret; 209 } 210 if ((access & OPENACC_DRD)) { 211 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD); 212 if (ret) 213 return ret; 214 } 215 } 216 /* ------------same for writing -------------- */ 217 if ((access & (OPENACC_WR | OPENACC_DWR))) { 218 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0) 219 return writeset; 220 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0) 221 return denywriteset; 222 223 if ((access & OPENACC_WR) && denywriteset) { 224 errno = EACCES; 225 return -1; 226 } 227 if ((access & OPENACC_DWR) && writeset) { 228 errno = EACCES; 229 return -1; 230 } 231 if ((access & OPENACC_WR)) { 232 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR); 233 if (ret) 234 return ret; 235 } 236 if ((access & OPENACC_DWR)) { 237 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR); 238 if (ret) 239 return ret; 240 } 241 } 242 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) { 243 return ad_excl_lock(adp, eid); 244 } 245 return 0; 246} 247 248/* ----------------------- */ 249int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 250{ 251 struct vol *vol; 252 struct dir *dir; 253 struct ofork *ofork, *opened; 254 struct adouble *adsame = NULL; 255 size_t buflen; 256 int ret, adflags, eid; 257 u_int32_t did; 258 u_int16_t vid, bitmap, access, ofrefnum; 259 char fork, *path, *upath; 260 struct stat *st; 261 u_int16_t bshort; 262 struct path *s_path; 263 264 ibuf++; 265 fork = *ibuf++; 266 memcpy(&vid, ibuf, sizeof( vid )); 267 ibuf += sizeof(vid); 268 269 *rbuflen = 0; 270 if (NULL == ( vol = getvolbyvid( vid ))) { 271 return( AFPERR_PARAM ); 272 } 273 274 memcpy(&did, ibuf, sizeof( did )); 275 ibuf += sizeof( int ); 276 277 if (NULL == ( dir = dirlookup( vol, did ))) { 278 return afp_errno; 279 } 280 281 memcpy(&bitmap, ibuf, sizeof( bitmap )); 282 bitmap = ntohs( bitmap ); 283 ibuf += sizeof( bitmap ); 284 memcpy(&access, ibuf, sizeof( access )); 285 access = ntohs( access ); 286 ibuf += sizeof( access ); 287 288 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) { 289 return AFPERR_VLOCK; 290 } 291 292 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) { 293 return get_afp_errno(AFPERR_PARAM); 294 } 295 296 if (*s_path->m_name == '\0') { 297 /* it's a dir ! */ 298 return AFPERR_BADTYPE; 299 } 300 301 /* stat() data fork st is set because it's not a dir */ 302 switch ( s_path->st_errno ) { 303 case 0: 304 break; 305 case ENOENT: 306 return AFPERR_NOOBJ; 307 case EACCES: 308 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; 309 default: 310 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); 311 return AFPERR_PARAM; 312 } 313 /* FIXME should we check it first ? */ 314 upath = s_path->u_name; 315 if (!vol_unix_priv(vol)) { 316 if (check_access(upath, access ) < 0) { 317 return AFPERR_ACCESS; 318 } 319 } 320 else { 321 if (file_access(s_path, access ) < 0) { 322 return AFPERR_ACCESS; 323 } 324 } 325 326 st = &s_path->st; 327 /* XXX: this probably isn't the best way to do this. the already 328 open bits should really be set if the fork is opened by any 329 program, not just this one. however, that's problematic to do 330 if we can't write lock files somewhere. opened is also passed to 331 ad_open so that we can keep file locks together. 332 FIXME: add the fork we are opening? 333 */ 334 if ((opened = of_findname(vol, s_path))) { 335 adsame = opened->of_ad; 336 } 337 338 if ( fork == OPENFORK_DATA ) { 339 eid = ADEID_DFORK; 340 adflags = ADFLAGS_DF|ADFLAGS_HF; 341 } else { 342 eid = ADEID_RFORK; 343 adflags = ADFLAGS_HF; 344 } 345 346 path = s_path->m_name; 347 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, 348 adsame, st)) == NULL ) { 349 return( AFPERR_NFILE ); 350 } 351 352 ret = AFPERR_NOOBJ; 353 if (access & OPENACC_WR) { 354 /* try opening in read-write mode */ 355 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) { 356 switch ( errno ) { 357 case EROFS: 358 ret = AFPERR_VLOCK; 359 case EACCES: 360 goto openfork_err; 361 break; 362 case ENOENT: 363 if (fork == OPENFORK_DATA) { 364 /* try to open only the data fork */ 365 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) { 366 goto openfork_err; 367 } 368 adflags = ADFLAGS_DF; 369 } 370 else { 371 /* here's the deal. we only try to create the resource 372 * fork if the user wants to open it for write acess. */ 373 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0) 374 goto openfork_err; 375 ofork->of_flags |= AFPFORK_OPEN; 376 } 377 break; 378 case EMFILE : 379 case ENFILE : 380 ret = AFPERR_NFILE; 381 goto openfork_err; 382 break; 383 case EISDIR : 384 ret = AFPERR_BADTYPE; 385 goto openfork_err; 386 break; 387 default: 388 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); 389 ret = AFPERR_PARAM; 390 goto openfork_err; 391 break; 392 } 393 } 394 else { 395 /* the ressource fork is open too */ 396 ofork->of_flags |= AFPFORK_OPEN; 397 } 398 } else { 399 /* try opening in read-only mode */ 400 ret = AFPERR_NOOBJ; 401 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) { 402 switch ( errno ) { 403 case EROFS: 404 ret = AFPERR_VLOCK; 405 case EACCES: 406 goto openfork_err; 407 break; 408 case ENOENT: 409 /* see if client asked for a read only data fork */ 410 if (fork == OPENFORK_DATA) { 411 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) { 412 goto openfork_err; 413 } 414 adflags = ADFLAGS_DF; 415 } 416 /* else we don't set AFPFORK_OPEN because there's no ressource fork file 417 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only 418 * then create in open read-write. 419 * FIXME , it doesn't play well with byte locking example: 420 * ressource fork open read only 421 * locking set on it (no effect, there's no file!) 422 * ressource fork open read write now 423 */ 424 break; 425 case EMFILE : 426 case ENFILE : 427 ret = AFPERR_NFILE; 428 goto openfork_err; 429 break; 430 case EISDIR : 431 ret = AFPERR_BADTYPE; 432 goto openfork_err; 433 break; 434 default: 435 LOG(log_error, logtype_afpd, "afp_openfork('%s/%s'): ad_open: errno: %i (%s)", 436 getcwdpath, s_path->m_name, errno, strerror(errno) ); 437 goto openfork_err; 438 break; 439 } 440 } 441 else { 442 /* the ressource fork is open too */ 443 ofork->of_flags |= AFPFORK_OPEN; 444 } 445 } 446 447 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) { 448 if (ad_setname(ofork->of_ad, path)) { 449 ad_flush( ofork->of_ad ); 450 } 451 } 452 453 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ), 454 &buflen )) != AFP_OK ) { 455 ad_close( ofork->of_ad, adflags ); 456 goto openfork_err; 457 } 458 459 *rbuflen = buflen + 2 * sizeof( u_int16_t ); 460 bitmap = htons( bitmap ); 461 memcpy(rbuf, &bitmap, sizeof( u_int16_t )); 462 rbuf += sizeof( u_int16_t ); 463 464 /* check WriteInhibit bit if we have a ressource fork 465 * the test is done here, after some Mac trafic capture 466 */ 467 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */ 468 ad_getattr(ofork->of_ad, &bshort); 469 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) { 470 ad_close( ofork->of_ad, adflags ); 471 of_dealloc( ofork ); 472 ofrefnum = 0; 473 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); 474 return(AFPERR_OLOCK); 475 } 476 } 477 478 /* 479 * synchronization locks: 480 */ 481 482 /* don't try to lock non-existent rforks. */ 483 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */ 484 485 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum); 486 /* can we access the fork? */ 487 if (ret < 0) { 488 ret = errno; 489 ad_close( ofork->of_ad, adflags ); 490 of_dealloc( ofork ); 491 switch (ret) { 492 case EAGAIN: /* return data anyway */ 493 case EACCES: 494 case EINVAL: 495 ofrefnum = 0; 496 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); 497 return( AFPERR_DENYCONF ); 498 break; 499 default: 500 *rbuflen = 0; 501 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) ); 502 return( AFPERR_PARAM ); 503 } 504 } 505 if ((access & OPENACC_WR)) 506 ofork->of_flags |= AFPFORK_ACCWR; 507 } 508 /* the file may be open read only without ressource fork */ 509 if ((access & OPENACC_RD)) 510 ofork->of_flags |= AFPFORK_ACCRD; 511 512 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); 513 return( AFP_OK ); 514 515openfork_err: 516 of_dealloc( ofork ); 517 if (errno == EACCES) 518 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; 519 return ret; 520} 521 522int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen) 523{ 524 struct ofork *ofork; 525 off_t size; 526 u_int16_t ofrefnum, bitmap; 527 int err; 528 int is64; 529 int eid; 530 off_t st_size; 531 532 ibuf += 2; 533 534 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 535 ibuf += sizeof( ofrefnum ); 536 537 memcpy(&bitmap, ibuf, sizeof(bitmap)); 538 bitmap = ntohs(bitmap); 539 ibuf += sizeof( bitmap ); 540 541 *rbuflen = 0; 542 if (NULL == ( ofork = of_find( ofrefnum )) ) { 543 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum ); 544 return( AFPERR_PARAM ); 545 } 546 547 if (ofork->of_vol->v_flags & AFPVOL_RO) 548 return AFPERR_VLOCK; 549 550 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) 551 return AFPERR_ACCESS; 552 553 if ( ofork->of_flags & AFPFORK_DATA) { 554 eid = ADEID_DFORK; 555 } else if (ofork->of_flags & AFPFORK_RSRC) { 556 eid = ADEID_RFORK; 557 } else 558 return AFPERR_PARAM; 559 560 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) )) 561 && eid == ADEID_RFORK 562 ) || 563 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) )) 564 && eid == ADEID_DFORK)) { 565 return AFPERR_BITMAP; 566 } 567 568 is64 = 0; 569 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) { 570 if (afp_version >= 30) { 571 is64 = 4; 572 } 573 else 574 return AFPERR_BITMAP; 575 } 576 577 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4) 578 return AFPERR_PARAM ; 579 580 size = get_off_t(&ibuf, is64); 581 582 if (size < 0) 583 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */ 584 585 586 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) { 587 st_size = ad_size(ofork->of_ad, eid); 588 err = -2; 589 if (st_size > size && 590 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) 591 goto afp_setfork_err; 592 593 err = ad_dtruncate( ofork->of_ad, size ); 594 if (st_size > size) 595 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); 596 if (err < 0) 597 goto afp_setfork_err; 598 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) { 599 ad_refresh( ofork->of_ad ); 600 601 st_size = ad_size(ofork->of_ad, eid); 602 err = -2; 603 if (st_size > size && 604 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) { 605 goto afp_setfork_err; 606 } 607 err = ad_rtruncate(ofork->of_ad, size); 608 if (st_size > size) 609 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); 610 if (err < 0) 611 goto afp_setfork_err; 612 613 if (ad_flush( ofork->of_ad ) < 0) { 614 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) ); 615 return AFPERR_PARAM; 616 } 617 } else 618 return AFPERR_BITMAP; 619 620#ifdef AFS 621 if ( flushfork( ofork ) < 0 ) { 622 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) ); 623 } 624#endif /* AFS */ 625 626 return( AFP_OK ); 627 628afp_setfork_err: 629 if (err == -2) 630 return AFPERR_LOCK; 631 else { 632 switch (errno) { 633 case EROFS: 634 return AFPERR_VLOCK; 635 case EPERM: 636 case EACCES: 637 return AFPERR_ACCESS; 638 case EDQUOT: 639 case EFBIG: 640 case ENOSPC: 641 LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL"); 642 return AFPERR_DFULL; 643 default: 644 return AFPERR_PARAM; 645 } 646 } 647} 648 649/* for this to work correctly, we need to check for locks before each 650 * read and write. that's most easily handled by always doing an 651 * appropriate check before each ad_read/ad_write. other things 652 * that can change files like truncate are handled internally to those 653 * functions. 654 */ 655#define ENDBIT(a) ((a) & 0x80) 656#define UNLOCKBIT(a) ((a) & 0x01) 657 658 659/* ---------------------- */ 660static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 661{ 662 struct ofork *ofork; 663 off_t offset, length; 664 int eid; 665 u_int16_t ofrefnum; 666 u_int8_t flags; 667 int lockop; 668 669 *rbuflen = 0; 670 671 /* figure out parameters */ 672 ibuf++; 673 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */ 674 ibuf++; 675 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); 676 ibuf += sizeof(ofrefnum); 677 678 if (NULL == ( ofork = of_find( ofrefnum )) ) { 679 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum ); 680 return( AFPERR_PARAM ); 681 } 682 683 if ( ofork->of_flags & AFPFORK_DATA) { 684 eid = ADEID_DFORK; 685 } else if (ofork->of_flags & AFPFORK_RSRC) { 686 eid = ADEID_RFORK; 687 } else 688 return AFPERR_PARAM; 689 690 offset = get_off_t(&ibuf, is64); 691 length = get_off_t(&ibuf, is64); 692 693 /* FIXME AD_FILELOCK test is surely wrong */ 694 if (length == -1) 695 length = BYTELOCK_MAX; 696 else if (!length || is_neg(is64, length)) { 697 return AFPERR_PARAM; 698 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/ 699 return AFPERR_LOCK; 700 } 701 702 if (ENDBIT(flags)) { 703 offset += ad_size(ofork->of_ad, eid); 704 /* FIXME what do we do if file size > 2 GB and 705 it's not byte_lock_ext? 706 */ 707 } 708 if (offset < 0) /* error if we have a negative offset */ 709 return AFPERR_PARAM; 710 711 /* if the file is a read-only file, we use read locks instead of 712 * write locks. that way, we can prevent anyone from initiating 713 * a write lock. */ 714 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR; 715 if (ad_lock(ofork->of_ad, eid, lockop, offset, length, 716 ofork->of_refnum) < 0) { 717 switch (errno) { 718 case EACCES: 719 case EAGAIN: 720 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK; 721 break; 722 case ENOLCK: 723 return AFPERR_NLOCK; 724 break; 725 case EINVAL: 726 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR; 727 break; 728 case EBADF: 729 default: 730 return AFPERR_PARAM; 731 break; 732 } 733 } 734 *rbuflen = set_off_t (offset, rbuf, is64); 735 return( AFP_OK ); 736} 737 738/* --------------------------- */ 739int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 740{ 741 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0); 742} 743 744/* --------------------------- */ 745int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 746{ 747 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1); 748} 749 750#undef UNLOCKBIT 751 752/* --------------------------- */ 753static int crlf(struct ofork *of) 754{ 755 struct extmap *em; 756 757 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */ 758 /* no resource fork or no finderinfo, use our files extension mapping */ 759 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) { 760 return 0; 761 } 762 /* file type is TEXT */ 763 return 1; 764 765 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) { 766 return 1; 767 } 768 return 0; 769} 770 771 772static ssize_t read_file(struct ofork *ofork, int eid, 773 off_t offset, u_char nlmask, 774 u_char nlchar, char *rbuf, 775 size_t *rbuflen, const int xlate) 776{ 777 ssize_t cc; 778 int eof = 0; 779 char *p, *q; 780 781 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen); 782 if ( cc < 0 ) { 783 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) ); 784 *rbuflen = 0; 785 return( AFPERR_PARAM ); 786 } 787 if ( (size_t)cc < *rbuflen ) { 788 eof = 1; 789 } 790 791 /* 792 * Do Newline check. 793 */ 794 if ( nlmask != 0 ) { 795 for ( p = rbuf, q = p + cc; p < q; ) { 796 if (( *p++ & nlmask ) == nlchar ) { 797 break; 798 } 799 } 800 if ( p != q ) { 801 cc = p - rbuf; 802 eof = 0; 803 } 804 } 805 806 /* 807 * If this file is of type TEXT, then swap \012 to \015. 808 */ 809 if (xlate) { 810 for ( p = rbuf, q = p + cc; p < q; p++ ) { 811 if ( *p == '\012' ) { 812 *p = '\015'; 813 } else if ( *p == '\015' ) { 814 *p = '\012'; 815 } 816 817 } 818 } 819 820 *rbuflen = cc; 821 if ( eof ) { 822 return( AFPERR_EOF ); 823 } 824 return AFP_OK; 825} 826 827/* ----------------------------- 828 * with ddp, afp_read can return fewer bytes than in reqcount 829 * so return EOF only if read actually past end of file not 830 * if offset +reqcount > size of file 831 * e.g.: 832 * getfork size ==> 10430 833 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF) 834 * read fork offset 4264 size 6128 ==> 4264 (without EOF) 835 * read fork offset 9248 size 1508 ==> 1182 (EOF) 836 * 10752 is a bug in Mac 7.5.x finder 837 * 838 * with dsi, should we check that reqcount < server quantum? 839*/ 840static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 841{ 842 struct ofork *ofork; 843 off_t offset, saveoff, reqcount, savereqcount; 844 ssize_t cc, err; 845 int eid, xlate = 0; 846 u_int16_t ofrefnum; 847 u_char nlmask, nlchar; 848 849 ibuf += 2; 850 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 851 ibuf += sizeof( u_short ); 852 853 if (NULL == ( ofork = of_find( ofrefnum )) ) { 854 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum ); 855 err = AFPERR_PARAM; 856 goto afp_read_err; 857 } 858 859 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) { 860 err = AFPERR_ACCESS; 861 goto afp_read_err; 862 } 863 offset = get_off_t(&ibuf, is64); 864 reqcount = get_off_t(&ibuf, is64); 865 866 if (is64) { 867 nlmask = nlchar = 0; 868 } 869 else { 870 nlmask = *ibuf++; 871 nlchar = *ibuf++; 872 } 873 /* if we wanted to be picky, we could add in the following 874 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask)) 875 */ 876 if (reqcount < 0 || offset < 0) { 877 err = AFPERR_PARAM; 878 goto afp_read_err; 879 } 880 881 if ( ofork->of_flags & AFPFORK_DATA) { 882 eid = ADEID_DFORK; 883 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; 884 } else if (ofork->of_flags & AFPFORK_RSRC) { 885 eid = ADEID_RFORK; 886 } else { /* fork wasn't opened. this should never really happen. */ 887 err = AFPERR_ACCESS; 888 goto afp_read_err; 889 } 890 891 /* zero request count */ 892 err = AFP_OK; 893 if (!reqcount) { 894 goto afp_read_err; 895 } 896 897 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)", 898 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount); 899 900 savereqcount = reqcount; 901 saveoff = offset; 902 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) { 903 err = AFPERR_LOCK; 904 goto afp_read_err; 905 } 906 907 *rbuflen = MIN(reqcount, *rbuflen); 908 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file", 909 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen); 910 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate); 911 if (err < 0) 912 goto afp_read_done; 913 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file", 914 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen); 915 916 /* dsi can stream requests. we can only do this if we're not checking 917 * for an end-of-line character. oh well. */ 918 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) { 919 DSI *dsi = obj->handle; 920 off_t size; 921 922 /* reqcount isn't always truthful. we need to deal with that. */ 923 size = ad_size(ofork->of_ad, eid); 924 925 /* subtract off the offset */ 926 size -= offset; 927 if (reqcount > size) { 928 reqcount = size; 929 err = AFPERR_EOF; 930 } 931 932 offset += *rbuflen; 933 934 /* dsi_readinit() returns size of next read buffer. by this point, 935 * we know that we're sending some data. if we fail, something 936 * horrible happened. */ 937 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) 938 goto afp_read_exit; 939 *rbuflen = cc; 940 /* due to the nature of afp packets, we have to exit if we get 941 an error. we can't do this with translation on. */ 942#ifdef WITH_SENDFILE 943 if (!(xlate || Debug(obj) )) { 944 int fd; 945 946 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0); 947 948 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) { 949 if (errno == EINVAL || errno == ENOSYS) 950 goto afp_read_loop; 951 else { 952 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno)); 953 goto afp_read_exit; 954 } 955 } 956 957 dsi_readdone(dsi); 958 goto afp_read_done; 959 } 960 961afp_read_loop: 962#endif 963 964 /* fill up our buffer. */ 965 while (*rbuflen > 0) { 966 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate); 967 if (cc < 0) 968 goto afp_read_exit; 969 970 offset += *rbuflen; 971 /* dsi_read() also returns buffer size of next allocation */ 972 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ 973 if (cc < 0) 974 goto afp_read_exit; 975 *rbuflen = cc; 976 } 977 dsi_readdone(dsi); 978 goto afp_read_done; 979 980afp_read_exit: 981 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno)); 982 dsi_readdone(dsi); 983 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); 984 obj->exit(EXITERR_CLNT); 985 } 986 987afp_read_done: 988 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); 989 return err; 990 991afp_read_err: 992 *rbuflen = 0; 993 return err; 994} 995 996/* ---------------------- */ 997int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 998{ 999 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); 1000} 1001 1002/* ---------------------- */ 1003int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1004{ 1005 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); 1006} 1007 1008/* ---------------------- */ 1009int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1010{ 1011 struct vol *vol; 1012 u_int16_t vid; 1013 1014 *rbuflen = 0; 1015 ibuf += 2; 1016 1017 memcpy(&vid, ibuf, sizeof(vid)); 1018 if (NULL == ( vol = getvolbyvid( vid )) ) { 1019 return( AFPERR_PARAM ); 1020 } 1021 1022 of_flush(vol); 1023 return( AFP_OK ); 1024} 1025 1026int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1027{ 1028 struct ofork *ofork; 1029 u_int16_t ofrefnum; 1030 1031 *rbuflen = 0; 1032 ibuf += 2; 1033 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1034 1035 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1036 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum ); 1037 return( AFPERR_PARAM ); 1038 } 1039 1040 if ( flushfork( ofork ) < 0 ) { 1041 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) ); 1042 } 1043 1044 return( AFP_OK ); 1045} 1046 1047/* 1048 FIXME 1049 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC. 1050 fsync(2) on OSX is implemented differently than on other platforms. 1051 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf. 1052 */ 1053int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1054{ 1055 struct ofork *ofork; 1056 u_int16_t ofrefnum; 1057 1058 *rbuflen = 0; 1059 ibuf += 2; 1060 1061 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); 1062 ibuf += sizeof( ofrefnum ); 1063 1064 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1065 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum ); 1066 return( AFPERR_PARAM ); 1067 } 1068 1069 if ( flushfork( ofork ) < 0 ) { 1070 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) ); 1071 return AFPERR_MISC; 1072 } 1073 1074 return( AFP_OK ); 1075} 1076 1077/* this is very similar to closefork */ 1078int flushfork(struct ofork *ofork) 1079{ 1080 struct timeval tv; 1081 1082 int err = 0, doflush = 0; 1083 1084 if ( ad_data_fileno( ofork->of_ad ) != -1 && 1085 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) { 1086 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s", 1087 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) ); 1088 err = -1; 1089 } 1090 1091 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */ 1092 (ofork->of_flags & AFPFORK_RSRC)) { 1093 1094 /* read in the rfork length */ 1095 ad_refresh(ofork->of_ad); 1096 1097 /* set the date if we're dirty */ 1098 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) { 1099 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec); 1100 ofork->of_flags &= ~AFPFORK_DIRTY; 1101 doflush++; 1102 } 1103 1104 /* flush the header */ 1105 if (doflush && ad_flush(ofork->of_ad) < 0) 1106 err = -1; 1107 1108 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0) 1109 err = -1; 1110 1111 if (err < 0) 1112 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s", 1113 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) ); 1114 } 1115 1116 return( err ); 1117} 1118 1119int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1120{ 1121 struct ofork *ofork; 1122 u_int16_t ofrefnum; 1123 1124 *rbuflen = 0; 1125 ibuf += 2; 1126 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1127 1128 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1129 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum ); 1130 return( AFPERR_PARAM ); 1131 } 1132 if ( of_closefork( ofork ) < 0 ) { 1133 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) ); 1134 return( AFPERR_PARAM ); 1135 } 1136 1137 return( AFP_OK ); 1138} 1139 1140 1141static ssize_t write_file(struct ofork *ofork, int eid, 1142 off_t offset, char *rbuf, 1143 size_t rbuflen, const int xlate) 1144{ 1145 char *p, *q; 1146 ssize_t cc; 1147 1148 /* 1149 * If this file is of type TEXT, swap \015 to \012. 1150 */ 1151 if (xlate) { 1152 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) { 1153 if ( *p == '\015' ) { 1154 *p = '\012'; 1155 } else if ( *p == '\012' ) { 1156 *p = '\015'; 1157 } 1158 } 1159 } 1160 1161 if (( cc = ad_write(ofork->of_ad, eid, offset, 0, 1162 rbuf, rbuflen)) < 0 ) { 1163 switch ( errno ) { 1164 case EDQUOT : 1165 case EFBIG : 1166 case ENOSPC : 1167 LOG(log_error, logtype_afpd, "write_file: DISK FULL"); 1168 return( AFPERR_DFULL ); 1169 case EACCES: 1170 return AFPERR_ACCESS; 1171 default : 1172 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) ); 1173 return( AFPERR_PARAM ); 1174 } 1175 } 1176 1177 return cc; 1178} 1179 1180 1181/* FPWrite. NOTE: on an error, we always use afp_write_err as 1182 * the client may have sent us a bunch of data that's not reflected 1183 * in reqcount et al. */ 1184static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 1185{ 1186 struct ofork *ofork; 1187 off_t offset, saveoff, reqcount, oldsize, newsize; 1188 int endflag, eid, xlate = 0, err = AFP_OK; 1189 u_int16_t ofrefnum; 1190 ssize_t cc; 1191 1192 /* figure out parameters */ 1193 ibuf++; 1194 endflag = ENDBIT(*ibuf); 1195 ibuf++; 1196 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1197 ibuf += sizeof( ofrefnum ); 1198 1199 offset = get_off_t(&ibuf, is64); 1200 reqcount = get_off_t(&ibuf, is64); 1201 1202 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1203 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum ); 1204 err = AFPERR_PARAM; 1205 goto afp_write_err; 1206 } 1207 1208 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { 1209 err = AFPERR_ACCESS; 1210 goto afp_write_err; 1211 } 1212 1213#ifdef AFS 1214 writtenfork = ofork; 1215#endif /* AFS */ 1216 1217 if ( ofork->of_flags & AFPFORK_DATA) { 1218 eid = ADEID_DFORK; 1219 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; 1220 } else if (ofork->of_flags & AFPFORK_RSRC) { 1221 eid = ADEID_RFORK; 1222 } else { 1223 err = AFPERR_ACCESS; /* should never happen */ 1224 goto afp_write_err; 1225 } 1226 1227 oldsize = ad_size(ofork->of_ad, eid); 1228 if (endflag) 1229 offset += oldsize; 1230 1231 /* handle bogus parameters */ 1232 if (reqcount < 0 || offset < 0) { 1233 err = AFPERR_PARAM; 1234 goto afp_write_err; 1235 } 1236 1237 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize; 1238 1239 /* offset can overflow on 64-bit capable filesystems. 1240 * report disk full if that's going to happen. */ 1241 if (sum_neg(is64, offset, reqcount)) { 1242 LOG(log_error, logtype_afpd, "write_fork: DISK FULL"); 1243 err = AFPERR_DFULL; 1244 goto afp_write_err; 1245 } 1246 1247 if (!reqcount) { /* handle request counts of 0 */ 1248 err = AFP_OK; 1249 *rbuflen = set_off_t (offset, rbuf, is64); 1250 goto afp_write_err; 1251 } 1252 1253 saveoff = offset; 1254 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, 1255 reqcount, ofork->of_refnum) < 0) { 1256 err = AFPERR_LOCK; 1257 goto afp_write_err; 1258 } 1259 1260 /* this is yucky, but dsi can stream i/o and asp can't */ 1261 switch (obj->proto) { 1262#ifndef NO_DDP 1263 case AFPPROTO_ASP: 1264 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) { 1265 *rbuflen = 0; 1266 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) ); 1267 return( AFPERR_PARAM ); 1268 } 1269 1270#ifdef DEBUG1 1271 if (obj->options.flags & OPTION_DEBUG) { 1272 printf("(write) len: %d\n", *rbuflen); 1273 bprint(rbuf, *rbuflen); 1274 } 1275#endif 1276 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen, 1277 xlate)) < 0) { 1278 *rbuflen = 0; 1279 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1280 return cc; 1281 } 1282 offset += cc; 1283 break; 1284#endif /* no afp/asp */ 1285 1286 case AFPPROTO_DSI: 1287 { 1288 DSI *dsi = obj->handle; 1289 1290 /* find out what we have already and write it out. */ 1291 cc = dsi_writeinit(dsi, rbuf, *rbuflen); 1292 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { 1293 dsi_writeflush(dsi); 1294 *rbuflen = 0; 1295 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1296 return cc; 1297 } 1298 offset += cc; 1299 1300#if 0 /*def HAVE_SENDFILE_WRITE*/ 1301 if (!(xlate || obj->options.flags & OPTION_DEBUG)) { 1302 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, 1303 offset, dsi->datasize)) < 0) { 1304 switch (errno) { 1305 case EDQUOT : 1306 case EFBIG : 1307 case ENOSPC : 1308 cc = AFPERR_DFULL; 1309 break; 1310 default : 1311 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) ); 1312 goto afp_write_loop; 1313 } 1314 dsi_writeflush(dsi); 1315 *rbuflen = 0; 1316 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 1317 reqcount, ofork->of_refnum); 1318 return cc; 1319 } 1320 1321 offset += cc; 1322 goto afp_write_done; 1323 } 1324#endif /* 0, was HAVE_SENDFILE_WRITE */ 1325 1326 /* loop until everything gets written. currently 1327 * dsi_write handles the end case by itself. */ 1328 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) { 1329 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { 1330 dsi_writeflush(dsi); 1331 *rbuflen = 0; 1332 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 1333 reqcount, ofork->of_refnum); 1334 return cc; 1335 } 1336 offset += cc; 1337 } 1338 } 1339 break; 1340 } 1341 1342 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1343 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */ 1344 ofork->of_flags |= AFPFORK_DIRTY; 1345 1346 /* we have modified any fork, remember until close_fork */ 1347 ofork->of_flags |= AFPFORK_MODIFIED; 1348 1349 /* update write count */ 1350 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0; 1351 1352 *rbuflen = set_off_t (offset, rbuf, is64); 1353 return( AFP_OK ); 1354 1355afp_write_err: 1356 if (obj->proto == AFPPROTO_DSI) { 1357 dsi_writeinit(obj->handle, rbuf, *rbuflen); 1358 dsi_writeflush(obj->handle); 1359 } 1360 if (err != AFP_OK) { 1361 *rbuflen = 0; 1362 } 1363 return err; 1364} 1365 1366/* ---------------------------- */ 1367int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1368{ 1369 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); 1370} 1371 1372/* ---------------------------- 1373 * FIXME need to deal with SIGXFSZ signal 1374*/ 1375int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1376{ 1377 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); 1378} 1379 1380/* ---------------------------- */ 1381int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 1382{ 1383 struct ofork *ofork; 1384 int ret; 1385 u_int16_t ofrefnum, bitmap; 1386 size_t buflen; 1387 ibuf += 2; 1388 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1389 ibuf += sizeof( ofrefnum ); 1390 memcpy(&bitmap, ibuf, sizeof( bitmap )); 1391 bitmap = ntohs( bitmap ); 1392 ibuf += sizeof( bitmap ); 1393 1394 *rbuflen = 0; 1395 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1396 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum ); 1397 return( AFPERR_PARAM ); 1398 } 1399 1400 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */ 1401 if ( ad_refresh( ofork->of_ad ) < 0 ) { 1402 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) ); 1403 return( AFPERR_PARAM ); 1404 } 1405 } 1406 1407 if (AFP_OK != ( ret = getforkparams( ofork, bitmap, 1408 rbuf + sizeof( u_short ), &buflen ))) { 1409 return( ret ); 1410 } 1411 1412 *rbuflen = buflen + sizeof( u_short ); 1413 bitmap = htons( bitmap ); 1414 memcpy(rbuf, &bitmap, sizeof( bitmap )); 1415 return( AFP_OK ); 1416} 1417 1418