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, int 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, int 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(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 return AFPERR_DFULL; 642 default: 643 return AFPERR_PARAM; 644 } 645 } 646} 647 648/* for this to work correctly, we need to check for locks before each 649 * read and write. that's most easily handled by always doing an 650 * appropriate check before each ad_read/ad_write. other things 651 * that can change files like truncate are handled internally to those 652 * functions. 653 */ 654#define ENDBIT(a) ((a) & 0x80) 655#define UNLOCKBIT(a) ((a) & 0x01) 656 657 658/* ---------------------- */ 659static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 660{ 661 struct ofork *ofork; 662 off_t offset, length; 663 int eid; 664 u_int16_t ofrefnum; 665 u_int8_t flags; 666 int lockop; 667 668 *rbuflen = 0; 669 670 /* figure out parameters */ 671 ibuf++; 672 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */ 673 ibuf++; 674 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); 675 ibuf += sizeof(ofrefnum); 676 677 if (NULL == ( ofork = of_find( ofrefnum )) ) { 678 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum ); 679 return( AFPERR_PARAM ); 680 } 681 682 if ( ofork->of_flags & AFPFORK_DATA) { 683 eid = ADEID_DFORK; 684 } else if (ofork->of_flags & AFPFORK_RSRC) { 685 eid = ADEID_RFORK; 686 } else 687 return AFPERR_PARAM; 688 689 offset = get_off_t(&ibuf, is64); 690 length = get_off_t(&ibuf, is64); 691 692 /* FIXME AD_FILELOCK test is surely wrong */ 693 if (length == -1) 694 length = BYTELOCK_MAX; 695 else if (!length || is_neg(is64, length)) { 696 return AFPERR_PARAM; 697 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/ 698 return AFPERR_LOCK; 699 } 700 701 if (ENDBIT(flags)) { 702 offset += ad_size(ofork->of_ad, eid); 703 /* FIXME what do we do if file size > 2 GB and 704 it's not byte_lock_ext? 705 */ 706 } 707 if (offset < 0) /* error if we have a negative offset */ 708 return AFPERR_PARAM; 709 710 /* if the file is a read-only file, we use read locks instead of 711 * write locks. that way, we can prevent anyone from initiating 712 * a write lock. */ 713 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR; 714 if (ad_lock(ofork->of_ad, eid, lockop, offset, length, 715 ofork->of_refnum) < 0) { 716 switch (errno) { 717 case EACCES: 718 case EAGAIN: 719 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK; 720 break; 721 case ENOLCK: 722 return AFPERR_NLOCK; 723 break; 724 case EINVAL: 725 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR; 726 break; 727 case EBADF: 728 default: 729 return AFPERR_PARAM; 730 break; 731 } 732 } 733 *rbuflen = set_off_t (offset, rbuf, is64); 734 return( AFP_OK ); 735} 736 737/* --------------------------- */ 738int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 739{ 740 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0); 741} 742 743/* --------------------------- */ 744int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 745{ 746 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1); 747} 748 749#undef UNLOCKBIT 750 751/* --------------------------- */ 752static int crlf(struct ofork *of) 753{ 754 struct extmap *em; 755 756 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */ 757 /* no resource fork or no finderinfo, use our files extension mapping */ 758 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) { 759 return 0; 760 } 761 /* file type is TEXT */ 762 return 1; 763 764 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) { 765 return 1; 766 } 767 return 0; 768} 769 770 771static ssize_t read_file(struct ofork *ofork, int eid, 772 off_t offset, u_char nlmask, 773 u_char nlchar, char *rbuf, 774 size_t *rbuflen, const int xlate) 775{ 776 ssize_t cc; 777 int eof = 0; 778 char *p, *q; 779 780 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen); 781 if ( cc < 0 ) { 782 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) ); 783 *rbuflen = 0; 784 return( AFPERR_PARAM ); 785 } 786 if ( (size_t)cc < *rbuflen ) { 787 eof = 1; 788 } 789 790 /* 791 * Do Newline check. 792 */ 793 if ( nlmask != 0 ) { 794 for ( p = rbuf, q = p + cc; p < q; ) { 795 if (( *p++ & nlmask ) == nlchar ) { 796 break; 797 } 798 } 799 if ( p != q ) { 800 cc = p - rbuf; 801 eof = 0; 802 } 803 } 804 805 /* 806 * If this file is of type TEXT, then swap \012 to \015. 807 */ 808 if (xlate) { 809 for ( p = rbuf, q = p + cc; p < q; p++ ) { 810 if ( *p == '\012' ) { 811 *p = '\015'; 812 } else if ( *p == '\015' ) { 813 *p = '\012'; 814 } 815 816 } 817 } 818 819 *rbuflen = cc; 820 if ( eof ) { 821 return( AFPERR_EOF ); 822 } 823 return AFP_OK; 824} 825 826/* ----------------------------- 827 * with ddp, afp_read can return fewer bytes than in reqcount 828 * so return EOF only if read actually past end of file not 829 * if offset +reqcount > size of file 830 * e.g.: 831 * getfork size ==> 10430 832 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF) 833 * read fork offset 4264 size 6128 ==> 4264 (without EOF) 834 * read fork offset 9248 size 1508 ==> 1182 (EOF) 835 * 10752 is a bug in Mac 7.5.x finder 836 * 837 * with dsi, should we check that reqcount < server quantum? 838*/ 839static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 840{ 841 struct ofork *ofork; 842 off_t offset, saveoff, reqcount, savereqcount; 843 ssize_t cc, err; 844 int eid, xlate = 0; 845 u_int16_t ofrefnum; 846 u_char nlmask, nlchar; 847 848 ibuf += 2; 849 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 850 ibuf += sizeof( u_short ); 851 852 if (NULL == ( ofork = of_find( ofrefnum )) ) { 853 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum ); 854 err = AFPERR_PARAM; 855 goto afp_read_err; 856 } 857 858 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) { 859 err = AFPERR_ACCESS; 860 goto afp_read_err; 861 } 862 offset = get_off_t(&ibuf, is64); 863 reqcount = get_off_t(&ibuf, is64); 864 865 if (is64) { 866 nlmask = nlchar = 0; 867 } 868 else { 869 nlmask = *ibuf++; 870 nlchar = *ibuf++; 871 } 872 /* if we wanted to be picky, we could add in the following 873 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask)) 874 */ 875 if (reqcount < 0 || offset < 0) { 876 err = AFPERR_PARAM; 877 goto afp_read_err; 878 } 879 880 if ( ofork->of_flags & AFPFORK_DATA) { 881 eid = ADEID_DFORK; 882 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; 883 } else if (ofork->of_flags & AFPFORK_RSRC) { 884 eid = ADEID_RFORK; 885 } else { /* fork wasn't opened. this should never really happen. */ 886 err = AFPERR_ACCESS; 887 goto afp_read_err; 888 } 889 890 /* zero request count */ 891 err = AFP_OK; 892 if (!reqcount) { 893 goto afp_read_err; 894 } 895 896 savereqcount = reqcount; 897 saveoff = offset; 898 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) { 899 err = AFPERR_LOCK; 900 goto afp_read_err; 901 } 902 903#define min(a,b) ((a)<(b)?(a):(b)) 904 *rbuflen = min( reqcount, *rbuflen ); 905 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate); 906 if (err < 0) 907 goto afp_read_done; 908 909 /* dsi can stream requests. we can only do this if we're not checking 910 * for an end-of-line character. oh well. */ 911 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) { 912 DSI *dsi = obj->handle; 913 off_t size; 914 915 /* reqcount isn't always truthful. we need to deal with that. */ 916 size = ad_size(ofork->of_ad, eid); 917 918 /* subtract off the offset */ 919 size -= offset; 920 if (reqcount > size) { 921 reqcount = size; 922 err = AFPERR_EOF; 923 } 924 925 offset += *rbuflen; 926 927 /* dsi_readinit() returns size of next read buffer. by this point, 928 * we know that we're sending some data. if we fail, something 929 * horrible happened. */ 930 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) 931 goto afp_read_exit; 932 *rbuflen = cc; 933 /* due to the nature of afp packets, we have to exit if we get 934 an error. we can't do this with translation on. */ 935#ifdef WITH_SENDFILE 936 if (!(xlate || Debug(obj) )) { 937 int fd; 938 939 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0); 940 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) { 941 if (errno == EINVAL || errno == ENOSYS) 942 goto afp_read_loop; 943 else { 944 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno)); 945 goto afp_read_exit; 946 } 947 } 948 949 dsi_readdone(dsi); 950 goto afp_read_done; 951 } 952 953afp_read_loop: 954#endif 955 956 /* fill up our buffer. */ 957 while (*rbuflen > 0) { 958 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate); 959 if (cc < 0) 960 goto afp_read_exit; 961 962 offset += *rbuflen; 963#ifdef DEBUG1 964 if (obj->options.flags & OPTION_DEBUG) { 965 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID); 966 bprint(rbuf, *rbuflen); 967 } 968#endif 969 /* dsi_read() also returns buffer size of next allocation */ 970 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ 971 if (cc < 0) 972 goto afp_read_exit; 973 *rbuflen = cc; 974 } 975 dsi_readdone(dsi); 976 goto afp_read_done; 977 978afp_read_exit: 979 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno)); 980 dsi_readdone(dsi); 981 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); 982 obj->exit(EXITERR_CLNT); 983 } 984 985afp_read_done: 986 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); 987 return err; 988 989afp_read_err: 990 *rbuflen = 0; 991 return err; 992} 993 994/* ---------------------- */ 995int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 996{ 997 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); 998} 999 1000/* ---------------------- */ 1001int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1002{ 1003 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); 1004} 1005 1006/* ---------------------- */ 1007int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1008{ 1009 struct vol *vol; 1010 u_int16_t vid; 1011 1012 *rbuflen = 0; 1013 ibuf += 2; 1014 1015 memcpy(&vid, ibuf, sizeof(vid)); 1016 if (NULL == ( vol = getvolbyvid( vid )) ) { 1017 return( AFPERR_PARAM ); 1018 } 1019 1020 of_flush(vol); 1021 return( AFP_OK ); 1022} 1023 1024int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1025{ 1026 struct ofork *ofork; 1027 u_int16_t ofrefnum; 1028 1029 *rbuflen = 0; 1030 ibuf += 2; 1031 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1032 1033 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1034 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum ); 1035 return( AFPERR_PARAM ); 1036 } 1037 1038 if ( flushfork( ofork ) < 0 ) { 1039 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) ); 1040 } 1041 1042 return( AFP_OK ); 1043} 1044 1045/* 1046 FIXME 1047 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC. 1048 fsync(2) on OSX is implemented differently than on other platforms. 1049 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf. 1050 */ 1051int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1052{ 1053 struct ofork *ofork; 1054 u_int16_t ofrefnum; 1055 1056 *rbuflen = 0; 1057 ibuf += 2; 1058 1059 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); 1060 ibuf += sizeof( ofrefnum ); 1061 1062 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1063 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum ); 1064 return( AFPERR_PARAM ); 1065 } 1066 1067 if ( flushfork( ofork ) < 0 ) { 1068 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) ); 1069 return AFPERR_MISC; 1070 } 1071 1072 return( AFP_OK ); 1073} 1074 1075/* this is very similar to closefork */ 1076int flushfork(struct ofork *ofork) 1077{ 1078 struct timeval tv; 1079 1080 int err = 0, doflush = 0; 1081 1082 if ( ad_data_fileno( ofork->of_ad ) != -1 && 1083 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) { 1084 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s", 1085 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) ); 1086 err = -1; 1087 } 1088 1089 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */ 1090 (ofork->of_flags & AFPFORK_RSRC)) { 1091 1092 /* read in the rfork length */ 1093 ad_refresh(ofork->of_ad); 1094 1095 /* set the date if we're dirty */ 1096 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) { 1097 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec); 1098 ofork->of_flags &= ~AFPFORK_DIRTY; 1099 doflush++; 1100 } 1101 1102 /* flush the header */ 1103 if (doflush && ad_flush(ofork->of_ad) < 0) 1104 err = -1; 1105 1106 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0) 1107 err = -1; 1108 1109 if (err < 0) 1110 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s", 1111 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) ); 1112 } 1113 1114 return( err ); 1115} 1116 1117int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 1118{ 1119 struct ofork *ofork; 1120 u_int16_t ofrefnum; 1121 1122 *rbuflen = 0; 1123 ibuf += 2; 1124 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1125 1126 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1127 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum ); 1128 return( AFPERR_PARAM ); 1129 } 1130 if ( of_closefork( ofork ) < 0 ) { 1131 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) ); 1132 return( AFPERR_PARAM ); 1133 } 1134 1135 return( AFP_OK ); 1136} 1137 1138 1139static ssize_t write_file(struct ofork *ofork, int eid, 1140 off_t offset, char *rbuf, 1141 size_t rbuflen, const int xlate) 1142{ 1143 char *p, *q; 1144 ssize_t cc; 1145 1146 /* 1147 * If this file is of type TEXT, swap \015 to \012. 1148 */ 1149 if (xlate) { 1150 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) { 1151 if ( *p == '\015' ) { 1152 *p = '\012'; 1153 } else if ( *p == '\012' ) { 1154 *p = '\015'; 1155 } 1156 } 1157 } 1158 1159 if (( cc = ad_write(ofork->of_ad, eid, offset, 0, 1160 rbuf, rbuflen)) < 0 ) { 1161 switch ( errno ) { 1162 case EDQUOT : 1163 case EFBIG : 1164 case ENOSPC : 1165 return( AFPERR_DFULL ); 1166 case EACCES: 1167 return AFPERR_ACCESS; 1168 default : 1169 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) ); 1170 return( AFPERR_PARAM ); 1171 } 1172 } 1173 1174 return cc; 1175} 1176 1177 1178/* FPWrite. NOTE: on an error, we always use afp_write_err as 1179 * the client may have sent us a bunch of data that's not reflected 1180 * in reqcount et al. */ 1181static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) 1182{ 1183 struct ofork *ofork; 1184 off_t offset, saveoff, reqcount; 1185 int endflag, eid, xlate = 0, err = AFP_OK; 1186 u_int16_t ofrefnum; 1187 ssize_t cc; 1188 1189 /* figure out parameters */ 1190 ibuf++; 1191 endflag = ENDBIT(*ibuf); 1192 ibuf++; 1193 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1194 ibuf += sizeof( ofrefnum ); 1195 1196 offset = get_off_t(&ibuf, is64); 1197 reqcount = get_off_t(&ibuf, is64); 1198 1199 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1200 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum ); 1201 err = AFPERR_PARAM; 1202 goto afp_write_err; 1203 } 1204 1205 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { 1206 err = AFPERR_ACCESS; 1207 goto afp_write_err; 1208 } 1209 1210#ifdef AFS 1211 writtenfork = ofork; 1212#endif /* AFS */ 1213 1214 if ( ofork->of_flags & AFPFORK_DATA) { 1215 eid = ADEID_DFORK; 1216 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; 1217 } else if (ofork->of_flags & AFPFORK_RSRC) { 1218 eid = ADEID_RFORK; 1219 } else { 1220 err = AFPERR_ACCESS; /* should never happen */ 1221 goto afp_write_err; 1222 } 1223 1224 if (endflag) 1225 offset += ad_size(ofork->of_ad, eid); 1226 1227 /* handle bogus parameters */ 1228 if (reqcount < 0 || offset < 0) { 1229 err = AFPERR_PARAM; 1230 goto afp_write_err; 1231 } 1232 1233 /* offset can overflow on 64-bit capable filesystems. 1234 * report disk full if that's going to happen. */ 1235 if (sum_neg(is64, offset, reqcount)) { 1236 err = AFPERR_DFULL; 1237 goto afp_write_err; 1238 } 1239 1240 if (!reqcount) { /* handle request counts of 0 */ 1241 err = AFP_OK; 1242 *rbuflen = set_off_t (offset, rbuf, is64); 1243 goto afp_write_err; 1244 } 1245 1246 saveoff = offset; 1247 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, 1248 reqcount, ofork->of_refnum) < 0) { 1249 err = AFPERR_LOCK; 1250 goto afp_write_err; 1251 } 1252 1253 /* this is yucky, but dsi can stream i/o and asp can't */ 1254 switch (obj->proto) { 1255#ifndef NO_DDP 1256 case AFPPROTO_ASP: 1257 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) { 1258 *rbuflen = 0; 1259 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) ); 1260 return( AFPERR_PARAM ); 1261 } 1262 1263#ifdef DEBUG1 1264 if (obj->options.flags & OPTION_DEBUG) { 1265 printf("(write) len: %d\n", *rbuflen); 1266 bprint(rbuf, *rbuflen); 1267 } 1268#endif 1269 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen, 1270 xlate)) < 0) { 1271 *rbuflen = 0; 1272 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1273 return cc; 1274 } 1275 offset += cc; 1276 break; 1277#endif /* no afp/asp */ 1278 1279 case AFPPROTO_DSI: 1280 { 1281 DSI *dsi = obj->handle; 1282 1283 /* find out what we have already and write it out. */ 1284 cc = dsi_writeinit(dsi, rbuf, *rbuflen); 1285 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { 1286 dsi_writeflush(dsi); 1287 *rbuflen = 0; 1288 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1289 return cc; 1290 } 1291 offset += cc; 1292 1293#if 0 /*def HAVE_SENDFILE_WRITE*/ 1294 if (!(xlate || obj->options.flags & OPTION_DEBUG)) { 1295 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, 1296 offset, dsi->datasize)) < 0) { 1297 switch (errno) { 1298 case EDQUOT : 1299 case EFBIG : 1300 case ENOSPC : 1301 cc = AFPERR_DFULL; 1302 break; 1303 default : 1304 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) ); 1305 goto afp_write_loop; 1306 } 1307 dsi_writeflush(dsi); 1308 *rbuflen = 0; 1309 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 1310 reqcount, ofork->of_refnum); 1311 return cc; 1312 } 1313 1314 offset += cc; 1315 goto afp_write_done; 1316 } 1317#endif /* 0, was HAVE_SENDFILE_WRITE */ 1318 1319 /* loop until everything gets written. currently 1320 * dsi_write handles the end case by itself. */ 1321 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) { 1322 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { 1323 dsi_writeflush(dsi); 1324 *rbuflen = 0; 1325 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 1326 reqcount, ofork->of_refnum); 1327 return cc; 1328 } 1329 offset += cc; 1330 } 1331 } 1332 break; 1333 } 1334 1335 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); 1336 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */ 1337 ofork->of_flags |= AFPFORK_DIRTY; 1338 1339 /* we have modified any fork, remember until close_fork */ 1340 ofork->of_flags |= AFPFORK_MODIFIED; 1341 1342 /* update write count */ 1343 ofork->of_vol->v_written += reqcount; 1344 1345 *rbuflen = set_off_t (offset, rbuf, is64); 1346 return( AFP_OK ); 1347 1348afp_write_err: 1349 if (obj->proto == AFPPROTO_DSI) { 1350 dsi_writeinit(obj->handle, rbuf, *rbuflen); 1351 dsi_writeflush(obj->handle); 1352 } 1353 if (err != AFP_OK) { 1354 *rbuflen = 0; 1355 } 1356 return err; 1357} 1358 1359/* ---------------------------- */ 1360int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1361{ 1362 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); 1363} 1364 1365/* ---------------------------- 1366 * FIXME need to deal with SIGXFSZ signal 1367*/ 1368int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) 1369{ 1370 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); 1371} 1372 1373/* ---------------------------- */ 1374int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 1375{ 1376 struct ofork *ofork; 1377 int ret; 1378 u_int16_t ofrefnum, bitmap; 1379 size_t buflen; 1380 ibuf += 2; 1381 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); 1382 ibuf += sizeof( ofrefnum ); 1383 memcpy(&bitmap, ibuf, sizeof( bitmap )); 1384 bitmap = ntohs( bitmap ); 1385 ibuf += sizeof( bitmap ); 1386 1387 *rbuflen = 0; 1388 if (NULL == ( ofork = of_find( ofrefnum )) ) { 1389 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum ); 1390 return( AFPERR_PARAM ); 1391 } 1392 1393 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */ 1394 if ( ad_refresh( ofork->of_ad ) < 0 ) { 1395 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) ); 1396 return( AFPERR_PARAM ); 1397 } 1398 } 1399 1400 if (AFP_OK != ( ret = getforkparams( ofork, bitmap, 1401 rbuf + sizeof( u_short ), &buflen ))) { 1402 return( ret ); 1403 } 1404 1405 *rbuflen = buflen + sizeof( u_short ); 1406 bitmap = htons( bitmap ); 1407 memcpy(rbuf, &bitmap, sizeof( bitmap )); 1408 return( AFP_OK ); 1409} 1410 1411