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