1/* 2 * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm Exp $ 3 * 4 * See COPYRIGHT. 5 * 6 * bug: 7 * afp_XXXcomment are (the only) functions able to open 8 * a ressource fork when there's no data fork, eg after 9 * it was removed with samba. 10 */ 11 12#ifdef HAVE_CONFIG_H 13#include "config.h" 14#endif /* HAVE_CONFIG_H */ 15 16#include <stdio.h> 17#include <string.h> 18#include <ctype.h> 19 20#include <errno.h> 21 22#include <atalk/adouble.h> 23#include <sys/uio.h> 24#include <sys/param.h> 25#include <sys/socket.h> 26#include <netatalk/at.h> 27#include <netatalk/endian.h> 28#include <atalk/dsi.h> 29#include <atalk/atp.h> 30#include <atalk/asp.h> 31#include <atalk/afp.h> 32#include <atalk/util.h> 33#include <atalk/logger.h> 34#include <atalk/globals.h> 35#include "volume.h" 36#include "directory.h" 37#include "fork.h" 38#include "desktop.h" 39#include "mangle.h" 40 41 42int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 43{ 44 struct vol *vol; 45 u_int16_t vid; 46 47 ibuf += 2; 48 49 memcpy( &vid, ibuf, sizeof(vid)); 50 if (NULL == ( vol = getvolbyvid( vid )) ) { 51 *rbuflen = 0; 52 return( AFPERR_PARAM ); 53 } 54 55 memcpy( rbuf, &vid, sizeof(vid)); 56 *rbuflen = sizeof(vid); 57 return( AFP_OK ); 58} 59 60int afp_closedt(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 61{ 62 *rbuflen = 0; 63 return( AFP_OK ); 64} 65 66static struct savedt si = { { 0, 0, 0, 0 }, -1, 0, 0 }; 67 68static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ]) 69{ 70 return dtfile( vol, creator, ".icon" ); 71} 72 73static int iconopen(struct vol *vol, u_char creator[ 4 ], int flags, int mode) 74{ 75 char *dtf, *adt, *adts; 76 77 if ( si.sdt_fd != -1 ) { 78 if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 && 79 si.sdt_vid == vol->v_vid ) { 80 return 0; 81 } 82 close( si.sdt_fd ); 83 si.sdt_fd = -1; 84 } 85 86 dtf = icon_dtfile( vol, creator); 87 88 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) { 89 if ( errno == ENOENT && ( flags & O_CREAT )) { 90 if (( adts = strrchr( dtf, '/' )) == NULL ) { 91 return -1; 92 } 93 *adts = '\0'; 94 if (( adt = strrchr( dtf, '/' )) == NULL ) { 95 return -1; 96 } 97 *adt = '\0'; 98 (void) ad_mkdir( dtf, DIRBITS | 0777 ); 99 *adt = '/'; 100 (void) ad_mkdir( dtf, DIRBITS | 0777 ); 101 *adts = '/'; 102 103 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) { 104 LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) ); 105 return -1; 106 } 107 } else { 108 return -1; 109 } 110 } 111 112 memcpy( si.sdt_creator, creator, sizeof( CreatorType )); 113 si.sdt_vid = vol->v_vid; 114 si.sdt_index = 1; 115 return 0; 116} 117 118int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 119{ 120 struct vol *vol; 121#ifndef NO_DDP 122 struct iovec iov[ 2 ]; 123#endif 124 u_char fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p; 125 int itype, cc = AFP_OK, iovcnt = 0; 126 size_t buflen; 127 u_int32_t ftype, itag; 128 u_int16_t bsize, rsize, vid; 129 130 buflen = *rbuflen; 131 *rbuflen = 0; 132 ibuf += 2; 133 134 memcpy( &vid, ibuf, sizeof( vid )); 135 ibuf += sizeof( vid ); 136 if (NULL == ( vol = getvolbyvid( vid )) ) { 137 cc = AFPERR_PARAM; 138 goto addicon_err; 139 } 140 141 memcpy( fcreator, ibuf, sizeof( fcreator )); 142 ibuf += sizeof( fcreator ); 143 144 memcpy( &ftype, ibuf, sizeof( ftype )); 145 ibuf += sizeof( ftype ); 146 147 itype = (unsigned char) *ibuf; 148 ibuf += 2; 149 150 memcpy( &itag, ibuf, sizeof( itag )); 151 ibuf += sizeof( itag ); 152 153 memcpy( &bsize, ibuf, sizeof( bsize )); 154 bsize = ntohs( bsize ); 155 156 if ( si.sdt_fd != -1 ) { 157 (void)close( si.sdt_fd ); 158 si.sdt_fd = -1; 159 } 160 161 if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) { 162 cc = AFPERR_NOITEM; 163 goto addicon_err; 164 } 165 166 if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) { 167 close(si.sdt_fd); 168 si.sdt_fd = -1; 169 LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) ); 170 cc = AFPERR_PARAM; 171 goto addicon_err; 172 } 173 174 /* 175 * Read icon elements until we find a match to replace, or 176 * we get to the end to insert. 177 */ 178 p = imh; 179 memcpy( p, &itag, sizeof( itag )); 180 p += sizeof( itag ); 181 memcpy( p, &ftype, sizeof( ftype )); 182 p += sizeof( ftype ); 183 *p++ = itype; 184 *p++ = 0; 185 bsize = htons( bsize ); 186 memcpy( p, &bsize, sizeof( bsize )); 187 bsize = ntohs( bsize ); 188 while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) { 189 memcpy( &rsize, irh + 10, sizeof( rsize )); 190 rsize = ntohs( rsize ); 191 /* 192 * Is this our set of headers? 193 */ 194 if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) { 195 /* 196 * Is the size correct? 197 */ 198 if ( bsize != rsize ) 199 cc = AFPERR_ITYPE; 200 break; 201 } 202 203 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) { 204 LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) ); 205 cc = AFPERR_PARAM; 206 } 207 } 208 209 /* 210 * Some error occurred, return. 211 */ 212addicon_err: 213 if ( cc < 0 ) { 214 if (obj->proto == AFPPROTO_DSI) { 215 dsi_writeinit(obj->handle, rbuf, buflen); 216 dsi_writeflush(obj->handle); 217 } 218 return cc; 219 } 220 221 switch (obj->proto) { 222#ifndef NO_DDP 223 case AFPPROTO_ASP: 224 buflen = bsize; 225 if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize) 226 return( AFPERR_PARAM ); 227 228#ifdef DEBUG1 229 if (obj->options.flags & OPTION_DEBUG) { 230 printf("(write) len: %d\n", buflen); 231 bprint(rbuf, buflen); 232 } 233#endif 234 235 /* 236 * We're at the end of the file, add the headers, etc. */ 237 if ( cc == 0 ) { 238 iov[ 0 ].iov_base = (caddr_t)imh; 239 iov[ 0 ].iov_len = sizeof( imh ); 240 iov[ 1 ].iov_base = rbuf; 241 iov[ 1 ].iov_len = bsize; 242 iovcnt = 2; 243 } 244 245 /* 246 * We found an icon to replace. 247 */ 248 if ( cc > 0 ) { 249 iov[ 0 ].iov_base = rbuf; 250 iov[ 0 ].iov_len = bsize; 251 iovcnt = 1; 252 } 253 254 if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) { 255 LOG(log_error, logtype_afpd, "afp_addicon(%s): writev: %s", icon_dtfile(vol, fcreator), strerror(errno) ); 256 return( AFPERR_PARAM ); 257 } 258 break; 259#endif /* no afp/asp */ 260 case AFPPROTO_DSI: 261 { 262 DSI *dsi = obj->handle; 263 264 iovcnt = dsi_writeinit(dsi, rbuf, buflen); 265 266 /* add headers at end of file */ 267 if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) { 268 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno)); 269 dsi_writeflush(dsi); 270 return AFPERR_PARAM; 271 } 272 273 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) { 274 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno)); 275 dsi_writeflush(dsi); 276 return AFPERR_PARAM; 277 } 278 279 while ((iovcnt = dsi_write(dsi, rbuf, buflen))) { 280 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) { 281 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno)); 282 dsi_writeflush(dsi); 283 return AFPERR_PARAM; 284 } 285 } 286 } 287 break; 288 } 289 290 close( si.sdt_fd ); 291 si.sdt_fd = -1; 292 return( AFP_OK ); 293} 294 295static const u_char utag[] = { 0, 0, 0, 0 }; 296static const u_char ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/ 297static const u_char utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/ 298static const short usize = 256; 299 300#if 0 301static const u_char uicon[] = { 302 0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00, 303 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80, 304 0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20, 305 0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10, 306 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 307 0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10, 308 0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90, 309 0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50, 310 0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50, 311 0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90, 312 0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90, 313 0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50, 314 0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50, 315 0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50, 316 0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90, 317 0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0, 318 0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 319 0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 320 0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0, 321 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 322 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 323 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 324 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 325 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 326 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 327 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 328 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 329 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 330 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 331 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 332 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 333 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 334}; 335#endif 336 337int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 338{ 339 struct vol *vol; 340 u_char fcreator[ 4 ], ih[ 12 ]; 341 u_int16_t vid, iindex, bsize; 342 343 *rbuflen = 0; 344 ibuf += 2; 345 346 memcpy( &vid, ibuf, sizeof( vid )); 347 ibuf += sizeof( vid ); 348 if (NULL == ( vol = getvolbyvid( vid )) ) { 349 return( AFPERR_PARAM ); 350 } 351 352 memcpy( fcreator, ibuf, sizeof( fcreator )); 353 ibuf += sizeof( fcreator ); 354 memcpy( &iindex, ibuf, sizeof( iindex )); 355 iindex = ntohs( iindex ); 356 357 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) { 358 if ( iindex > 1 ) { 359 return( AFPERR_NOITEM ); 360 } 361 memcpy( ih, utag, sizeof( utag )); 362 memcpy( ih + sizeof( utag ), utype, sizeof( utype )); 363 *( ih + sizeof( utag ) + sizeof( utype )) = 1; 364 *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0; 365 memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize, 366 sizeof( usize )); 367 memcpy( rbuf, ih, sizeof( ih )); 368 *rbuflen = sizeof( ih ); 369 return( AFP_OK ); 370 } 371 372 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) { 373 return( AFPERR_NOITEM ); 374 } 375 376 if ( iindex < si.sdt_index ) { 377 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) { 378 return( AFPERR_PARAM ); 379 } 380 si.sdt_index = 1; 381 } 382 383 /* 384 * Position to the correct spot. 385 */ 386 for (;;) { 387 if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) { 388 close( si.sdt_fd ); 389 si.sdt_fd = -1; 390 return( AFPERR_NOITEM ); 391 } 392 memcpy( &bsize, ih + 10, sizeof( bsize )); 393 bsize = ntohs(bsize); 394 if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) { 395 LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) ); 396 return( AFPERR_PARAM ); 397 } 398 if ( si.sdt_index == iindex ) { 399 memcpy( rbuf, ih, sizeof( ih )); 400 *rbuflen = sizeof( ih ); 401 return( AFP_OK ); 402 } 403 si.sdt_index++; 404 } 405} 406 407 408int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 409{ 410 struct vol *vol; 411 off_t offset; 412 ssize_t rc, buflen; 413 u_char fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ]; 414 u_int16_t vid, bsize, rsize; 415 416 buflen = *rbuflen; 417 *rbuflen = 0; 418 ibuf += 2; 419 420 memcpy( &vid, ibuf, sizeof( vid )); 421 ibuf += sizeof( vid ); 422 if (NULL == ( vol = getvolbyvid( vid )) ) { 423 return( AFPERR_PARAM ); 424 } 425 426 memcpy( fcreator, ibuf, sizeof( fcreator )); 427 ibuf += sizeof( fcreator ); 428 memcpy( ftype, ibuf, sizeof( ftype )); 429 ibuf += sizeof( ftype ); 430 itype = (unsigned char) *ibuf++; 431 ibuf++; 432 memcpy( &bsize, ibuf, sizeof( bsize )); 433 bsize = ntohs( bsize ); 434 435#if 0 436 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 && 437 memcmp( ftype, utype, sizeof( utype )) == 0 && 438 itype == 1 && 439 bsize <= usize ) { 440 memcpy( rbuf, uicon, bsize); 441 *rbuflen = bsize; 442 return( AFP_OK ); 443 } 444#endif 445 446 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) { 447 return( AFPERR_NOITEM ); 448 } 449 450 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) { 451 close(si.sdt_fd); 452 si.sdt_fd = -1; 453 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno)); 454 return( AFPERR_PARAM ); 455 } 456 457 si.sdt_index = 1; 458 offset = 0; 459 while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) { 460 si.sdt_index++; 461 offset += sizeof(ih); 462 if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 && 463 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) { 464 break; 465 } 466 memcpy( &rsize, ih + 10, sizeof( rsize )); 467 rsize = ntohs( rsize ); 468 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) { 469 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) ); 470 return( AFPERR_PARAM ); 471 } 472 offset += rsize; 473 } 474 475 if ( rc < 0 ) { 476 LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno)); 477 return( AFPERR_PARAM ); 478 } 479 480 if ( rc == 0 ) { 481 return( AFPERR_NOITEM ); 482 } 483 484 memcpy( &rsize, ih + 10, sizeof( rsize )); 485 rsize = ntohs( rsize ); 486#define min(a,b) ((a)<(b)?(a):(b)) 487 rc = min( bsize, rsize ); 488 489 if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) { 490 DSI *dsi = obj->handle; 491 struct stat st; 492 off_t size; 493 494 size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size; 495 if (size < rc + offset) { 496 return AFPERR_PARAM; 497 } 498 499 if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0) 500 goto geticon_exit; 501 502 *rbuflen = buflen; 503 /* do to the streaming nature, we have to exit if we encounter 504 * a problem. much confusion results otherwise. */ 505 while (*rbuflen > 0) { 506#ifdef WITH_SENDFILE 507 if (!obj->options.flags & OPTION_DEBUG) { 508 if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) { 509 switch (errno) { 510 case ENOSYS: 511 case EINVAL: /* there's no guarantee that all fs support sendfile */ 512 break; 513 default: 514 goto geticon_exit; 515 } 516 } 517 else { 518 dsi_readdone(dsi); 519 return AFP_OK; 520 } 521 } 522#endif 523 buflen = read(si.sdt_fd, rbuf, *rbuflen); 524 if (buflen < 0) 525 goto geticon_exit; 526 527 /* dsi_read() also returns buffer size of next allocation */ 528 buflen = dsi_read(dsi, rbuf, buflen); /* send it off */ 529 if (buflen < 0) 530 goto geticon_exit; 531 532 *rbuflen = buflen; 533 } 534 535 dsi_readdone(dsi); 536 return AFP_OK; 537 538geticon_exit: 539 LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno)); 540 dsi_readdone(dsi); 541 obj->exit(EXITERR_SYS); 542 return AFP_OK; 543 544 } else { 545 if ( read( si.sdt_fd, rbuf, rc ) < rc ) { 546 return( AFPERR_PARAM ); 547 } 548 *rbuflen = rc; 549 } 550 return AFP_OK; 551} 552 553/* ---------------------- */ 554static const char hexdig[] = "0123456789abcdef"; 555char *dtfile(const struct vol *vol, u_char creator[], char *ext ) 556{ 557 static char path[ MAXPATHLEN + 1]; 558 char *p; 559 unsigned int i; 560 561 strcpy( path, vol->v_path ); 562 strcat( path, "/.AppleDesktop/" ); 563 for ( p = path; *p != '\0'; p++ ) 564 ; 565 566 if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) { 567 *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ]; 568 *p++ = hexdig[ creator[ 0 ] & 0x0f ]; 569 } else { 570 *p++ = creator[ 0 ]; 571 } 572 573 *p++ = '/'; 574 575 for ( i = 0; i < sizeof( CreatorType ); i++ ) { 576 if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) { 577 *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ]; 578 *p++ = hexdig[ creator[ i ] & 0x0f ]; 579 } else { 580 *p++ = creator[ i ]; 581 } 582 } 583 *p = '\0'; 584 strcat( path, ext ); 585 586 return( path ); 587} 588 589/* --------------------------- 590 * mpath is only a filename 591 * did filename parent directory ID. 592*/ 593 594char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8) 595{ 596 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 597 char *m, *u; 598 size_t inplen; 599 size_t outlen; 600 u_int16_t flags; 601 602 if ( *mpath == '\0' ) { 603 strcpy(upath, "."); 604 return upath; 605 } 606 607 /* set conversion flags */ 608 flags = vol->v_mtou_flags; 609 610 m = demangle(vol, mpath, did); 611 if (m != mpath) { 612 return m; 613 } 614 615 m = mpath; 616 u = upath; 617 618 inplen = strlen(m); 619 outlen = MAXPATHLEN; 620 621 if ((size_t)-1 == (outlen = convert_charset ( (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_volcharset, vol->v_maccharset, m, inplen, u, outlen, &flags)) ) { 622 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath); 623 return NULL; 624 } 625 626#ifdef DEBUG 627 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath); 628#endif /* DEBUG */ 629 return( upath ); 630} 631 632/* --------------- 633 * id filename ID 634*/ 635char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8) 636{ 637 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 638 char *m, *u; 639 u_int16_t flags; 640 size_t outlen; 641 642 m = mpath; 643 outlen = strlen(upath); 644 645 flags = vol->v_utom_flags; 646 647 u = upath; 648 649 /* convert charsets */ 650 if ((size_t)-1 == ( outlen = convert_charset ( vol->v_volcharset, (utf8)?CH_UTF8_MAC:vol->v_maccharset, vol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { 651 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id)); 652 goto utompath_error; 653 } 654 655 flags = !!(flags & CONV_REQMANGLE); 656 657 if (utf8) 658 flags |= 2; 659 660 m = mangle(vol, mpath, outlen, upath, id, flags); 661 662#ifdef DEBUG 663 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id)); 664#endif /* DEBUG */ 665 return(m); 666 667utompath_error: 668 u = "???"; 669 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1); 670 return(m); 671} 672 673/* ------------------------- */ 674static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf) 675{ 676 struct ofork *of; 677 char *name, *upath; 678 int isadir; 679 int clen; 680 struct adouble ad, *adp; 681 682 clen = (u_char)*ibuf++; 683 clen = min( clen, 199 ); 684 685 upath = path->u_name; 686 if (check_access(upath, OPENACC_WR ) < 0) { 687 return AFPERR_ACCESS; 688 } 689 690 isadir = path_isadir(path); 691 if (isadir || !(of = of_findname(path))) { 692 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 693 adp = &ad; 694 } else 695 adp = of->of_ad; 696 697 if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) { 698 return( AFPERR_ACCESS ); 699 } 700 701 if (ad_getentryoff(adp, ADEID_COMMENT)) { 702 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) { 703 if ( *path->m_name == '\0' ) { 704 name = (char *)curdir->d_m_name->data; 705 } else { 706 name = path->m_name; 707 } 708 ad_setname(adp, name); 709 } 710 ad_setentrylen( adp, ADEID_COMMENT, clen ); 711 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen ); 712 ad_flush( adp ); 713 } 714 ad_close_metadata( adp); 715 return( AFP_OK ); 716} 717 718/* ----------------------------- */ 719int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 720{ 721 struct vol *vol; 722 struct dir *dir; 723 struct path *path; 724 u_int32_t did; 725 u_int16_t vid; 726 727 *rbuflen = 0; 728 ibuf += 2; 729 730 memcpy( &vid, ibuf, sizeof( vid )); 731 ibuf += sizeof( vid ); 732 if (NULL == ( vol = getvolbyvid( vid )) ) { 733 return( AFPERR_PARAM ); 734 } 735 736 memcpy( &did, ibuf, sizeof( did )); 737 ibuf += sizeof( did ); 738 if (NULL == ( dir = dirlookup( vol, did )) ) { 739 return afp_errno; 740 } 741 742 if (NULL == ( path = cname( vol, dir, &ibuf )) ) { 743 return get_afp_errno(AFPERR_NOOBJ); 744 } 745 746 if ((u_long)ibuf & 1 ) { 747 ibuf++; 748 } 749 750 return ad_addcomment(vol, path, ibuf); 751} 752 753/* -------------------- */ 754static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen) 755{ 756 struct adouble ad, *adp; 757 struct ofork *of; 758 char *upath; 759 int isadir; 760 int clen; 761 762 upath = path->u_name; 763 isadir = path_isadir(path); 764 if (isadir || !(of = of_findname(path))) { 765 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 766 adp = &ad; 767 } else 768 adp = of->of_ad; 769 770 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) { 771 return( AFPERR_NOITEM ); 772 } 773 774 if (!ad_getentryoff(adp, ADEID_COMMENT)) { 775 ad_close_metadata( adp ); 776 return AFPERR_NOITEM; 777 } 778 /* 779 * Make sure the AD file is not bogus. 780 */ 781 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 || 782 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) { 783 ad_close_metadata( adp ); 784 return( AFPERR_NOITEM ); 785 } 786 787 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */ 788 *rbuf++ = clen; 789 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen); 790 *rbuflen = clen + 1; 791 ad_close_metadata( adp); 792 793 return( AFP_OK ); 794} 795 796/* -------------------- */ 797int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 798{ 799 struct vol *vol; 800 struct dir *dir; 801 struct path *s_path; 802 u_int32_t did; 803 u_int16_t vid; 804 805 *rbuflen = 0; 806 ibuf += 2; 807 808 memcpy( &vid, ibuf, sizeof( vid )); 809 ibuf += sizeof( vid ); 810 if (NULL == ( vol = getvolbyvid( vid )) ) { 811 return( AFPERR_PARAM ); 812 } 813 814 memcpy( &did, ibuf, sizeof( did )); 815 ibuf += sizeof( did ); 816 if (NULL == ( dir = dirlookup( vol, did )) ) { 817 return afp_errno; 818 } 819 820 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { 821 return get_afp_errno(AFPERR_NOOBJ); 822 } 823 824 return ad_getcomment(vol, s_path, rbuf, rbuflen); 825} 826 827/* ----------------------- */ 828static int ad_rmvcomment(struct vol *vol, struct path *path) 829{ 830 struct adouble ad, *adp; 831 struct ofork *of; 832 int isadir; 833 char *upath; 834 835 upath = path->u_name; 836 if (check_access(upath, OPENACC_WR ) < 0) { 837 return AFPERR_ACCESS; 838 } 839 840 isadir = path_isadir(path); 841 if (isadir || !(of = of_findname(path))) { 842 ad_init(&ad, vol->v_adouble, vol->v_ad_options); 843 adp = &ad; 844 } else 845 adp = of->of_ad; 846 847 if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) { 848 switch ( errno ) { 849 case ENOENT : 850 return( AFPERR_NOITEM ); 851 case EACCES : 852 return( AFPERR_ACCESS ); 853 default : 854 return( AFPERR_PARAM ); 855 } 856 } 857 858 if (ad_getentryoff(adp, ADEID_COMMENT)) { 859 ad_setentrylen( adp, ADEID_COMMENT, 0 ); 860 ad_flush( adp ); 861 } 862 ad_close_metadata( adp); 863 return( AFP_OK ); 864} 865 866/* ----------------------- */ 867int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) 868{ 869 struct vol *vol; 870 struct dir *dir; 871 struct path *s_path; 872 u_int32_t did; 873 u_int16_t vid; 874 875 *rbuflen = 0; 876 ibuf += 2; 877 878 memcpy( &vid, ibuf, sizeof( vid )); 879 ibuf += sizeof( vid ); 880 if (NULL == ( vol = getvolbyvid( vid )) ) { 881 return( AFPERR_PARAM ); 882 } 883 884 memcpy( &did, ibuf, sizeof( did )); 885 ibuf += sizeof( did ); 886 if (NULL == ( dir = dirlookup( vol, did )) ) { 887 return afp_errno; 888 } 889 890 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) { 891 return get_afp_errno(AFPERR_NOOBJ); 892 } 893 894 return ad_rmvcomment(vol, s_path); 895} 896