2 * $Id: desktop.c,v 1.26.2.4.2.5 2003-10-17 00:01:10 didg Exp $
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.
14 #endif /* HAVE_CONFIG_H */
16 #include <atalk/logger.h>
18 #include <sys/types.h>
21 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netatalk/at.h>
25 #include <netatalk/endian.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
30 #include <atalk/adouble.h>
31 #include <atalk/util.h>
35 #endif /* HAVE_FCNTL_H */
41 #endif /* HAVE_FCNTL_H */
44 #include "directory.h"
53 #include <atalk/unicode.h>
56 int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen )
59 int ibuflen, *rbuflen;
66 memcpy( &vid, ibuf, sizeof(vid));
67 if (NULL == ( vol = getvolbyvid( vid )) ) {
69 return( AFPERR_PARAM );
72 memcpy( rbuf, &vid, sizeof(vid));
73 *rbuflen = sizeof(vid);
77 int afp_closedt(obj, ibuf, ibuflen, rbuf, rbuflen )
80 int ibuflen, *rbuflen;
86 struct savedt si = { { 0, 0, 0, 0 }, -1, 0 };
88 static int iconopen( vol, creator, flags, mode )
92 char *dtf, *adt, *adts;
94 if ( si.sdt_fd != -1 ) {
95 if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
96 si.sdt_vid == vol->v_vid ) {
103 dtf = dtfile( vol, creator, ".icon" );
105 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
106 if ( errno == ENOENT && ( flags & O_CREAT )) {
107 if (( adts = strrchr( dtf, '/' )) == NULL ) {
111 if (( adt = strrchr( dtf, '/' )) == NULL ) {
115 (void) ad_mkdir( dtf, DIRBITS | 0777 );
117 (void) ad_mkdir( dtf, DIRBITS | 0777 );
120 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
121 LOG(log_error, logtype_afpd, "iconopen: open %s: %s", dtf, strerror(errno) );
129 memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
130 si.sdt_vid = vol->v_vid;
135 int afp_addicon(obj, ibuf, ibuflen, rbuf, rbuflen)
138 int ibuflen, *rbuflen;
141 struct iovec iov[ 2 ];
142 u_char fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
143 int itype, cc = AFP_OK, iovcnt = 0, buflen;
144 u_int32_t ftype, itag;
145 u_int16_t bsize, rsize, vid;
151 memcpy( &vid, ibuf, sizeof( vid ));
152 ibuf += sizeof( vid );
153 if (NULL == ( vol = getvolbyvid( vid )) ) {
158 memcpy( fcreator, ibuf, sizeof( fcreator ));
159 ibuf += sizeof( fcreator );
161 memcpy( &ftype, ibuf, sizeof( ftype ));
162 ibuf += sizeof( ftype );
164 itype = (unsigned char) *ibuf;
167 memcpy( &itag, ibuf, sizeof( itag ));
168 ibuf += sizeof( itag );
170 memcpy( &bsize, ibuf, sizeof( bsize ));
171 bsize = ntohs( bsize );
173 if ( si.sdt_fd != -1 ) {
174 (void)close( si.sdt_fd );
178 if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
183 if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
186 LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
192 * Read icon elements until we find a match to replace, or
193 * we get to the end to insert.
196 memcpy( p, &itag, sizeof( itag ));
198 memcpy( p, &ftype, sizeof( ftype ));
199 p += sizeof( ftype );
202 bsize = htons( bsize );
203 memcpy( p, &bsize, sizeof( bsize ));
204 bsize = ntohs( bsize );
205 while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
206 memcpy( &rsize, irh + 10, sizeof( rsize ));
207 rsize = ntohs( rsize );
209 * Is this our set of headers?
211 if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
213 * Is the size correct?
215 if ( bsize != rsize )
220 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
221 LOG(log_error, logtype_afpd, "afp_addicon: lseek: %s", strerror(errno) );
227 * Some error occurred, return.
231 LOG(log_error, logtype_afpd, "afp_addicon: %s", strerror(errno) );
232 if (obj->proto == AFPPROTO_DSI) {
233 dsi_writeinit(obj->handle, rbuf, buflen);
234 dsi_writeflush(obj->handle);
240 switch (obj->proto) {
244 if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
245 return( AFPERR_PARAM );
248 if (obj->options.flags & OPTION_DEBUG) {
249 printf("(write) len: %d\n", buflen);
250 bprint(rbuf, buflen);
255 * We're at the end of the file, add the headers, etc. */
257 iov[ 0 ].iov_base = (caddr_t)imh;
258 iov[ 0 ].iov_len = sizeof( imh );
259 iov[ 1 ].iov_base = rbuf;
260 iov[ 1 ].iov_len = bsize;
265 * We found an icon to replace.
268 iov[ 0 ].iov_base = rbuf;
269 iov[ 0 ].iov_len = bsize;
273 if ( writev( si.sdt_fd, iov, iovcnt ) < 0 ) {
274 LOG(log_error, logtype_afpd, "afp_addicon: writev: %s", strerror(errno) );
275 return( AFPERR_PARAM );
278 #endif /* no afp/asp */
281 DSI *dsi = obj->handle;
283 iovcnt = dsi_writeinit(dsi, rbuf, buflen);
285 /* add headers at end of file */
286 if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
287 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
292 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
293 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
298 while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
300 if ( obj->options.flags & OPTION_DEBUG ) {
301 printf("(write) command cont'd: %d\n", iovcnt);
302 bprint(rbuf, iovcnt);
305 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
306 LOG(log_error, logtype_afpd, "afp_addicon: write: %s", strerror(errno));
320 u_char utag[] = { 0, 0, 0, 0 };
321 u_char ucreator[] = { 'U', 'N', 'I', 'X' };
322 u_char utype[] = { 'T', 'E', 'X', 'T' };
325 0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
326 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
327 0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
328 0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
329 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
330 0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
331 0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
332 0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
333 0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
334 0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
335 0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
336 0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
337 0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
338 0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
339 0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
340 0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
341 0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
342 0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
343 0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
344 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
345 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
346 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
347 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
348 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
349 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
350 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
351 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
352 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
353 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
354 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
355 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
356 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
359 int afp_geticoninfo(obj, ibuf, ibuflen, rbuf, rbuflen )
362 int ibuflen, *rbuflen;
365 u_char fcreator[ 4 ], ih[ 12 ];
366 u_int16_t vid, iindex, bsize;
371 memcpy( &vid, ibuf, sizeof( vid ));
372 ibuf += sizeof( vid );
373 if (NULL == ( vol = getvolbyvid( vid )) ) {
374 return( AFPERR_PARAM );
377 memcpy( fcreator, ibuf, sizeof( fcreator ));
378 ibuf += sizeof( fcreator );
379 memcpy( &iindex, ibuf, sizeof( iindex ));
380 iindex = ntohs( iindex );
382 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
384 return( AFPERR_NOITEM );
386 memcpy( ih, utag, sizeof( utag ));
387 memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
388 *( ih + sizeof( utag ) + sizeof( utype )) = 1;
389 *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
390 memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
392 memcpy( rbuf, ih, sizeof( ih ));
393 *rbuflen = sizeof( ih );
397 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
398 return( AFPERR_NOITEM );
401 if ( iindex < si.sdt_index ) {
402 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
403 return( AFPERR_PARAM );
409 * Position to the correct spot.
412 if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
415 return( AFPERR_NOITEM );
417 memcpy( &bsize, ih + 10, sizeof( bsize ));
418 bsize = ntohs(bsize);
419 if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
420 LOG(log_error, logtype_afpd, "afp_iconinfo: lseek: %s", strerror(errno) );
421 return( AFPERR_PARAM );
423 if ( si.sdt_index == iindex ) {
424 memcpy( rbuf, ih, sizeof( ih ));
425 *rbuflen = sizeof( ih );
433 int afp_geticon(obj, ibuf, ibuflen, rbuf, rbuflen )
436 int ibuflen, *rbuflen;
441 u_char fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
442 u_int16_t vid, bsize, rsize;
448 memcpy( &vid, ibuf, sizeof( vid ));
449 ibuf += sizeof( vid );
450 if (NULL == ( vol = getvolbyvid( vid )) ) {
451 return( AFPERR_PARAM );
454 memcpy( fcreator, ibuf, sizeof( fcreator ));
455 ibuf += sizeof( fcreator );
456 memcpy( ftype, ibuf, sizeof( ftype ));
457 ibuf += sizeof( ftype );
458 itype = (unsigned char) *ibuf++;
460 memcpy( &bsize, ibuf, sizeof( bsize ));
461 bsize = ntohs( bsize );
463 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
464 memcmp( ftype, utype, sizeof( utype )) == 0 &&
467 memcpy( rbuf, uicon, bsize);
472 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
473 return( AFPERR_NOITEM );
476 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
479 LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno));
480 return( AFPERR_PARAM );
485 while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
487 offset += sizeof(ih);
488 if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
489 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
492 memcpy( &rsize, ih + 10, sizeof( rsize ));
493 rsize = ntohs( rsize );
494 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
495 LOG(log_error, logtype_afpd, "afp_geticon: lseek: %s", strerror(errno) );
496 return( AFPERR_PARAM );
502 LOG(log_error, logtype_afpd, "afp_geticon: read: %s", strerror(errno));
503 return( AFPERR_PARAM );
507 return( AFPERR_NOITEM );
510 memcpy( &rsize, ih + 10, sizeof( rsize ));
511 rsize = ntohs( rsize );
512 #define min(a,b) ((a)<(b)?(a):(b))
513 rc = min( bsize, rsize );
515 if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
516 DSI *dsi = obj->handle;
520 size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
521 if (size < rc + offset) {
525 if ((*rbuflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
528 /* do to the streaming nature, we have to exit if we encounter
529 * a problem. much confusion results otherwise. */
530 while (*rbuflen > 0) {
532 if (!obj->options.flags & OPTION_DEBUG) {
533 if (sys_sendfile(dsi->socket, si.sdt_fd, &offset, dsi->datasize) < 0) {
536 case EINVAL: /* there's no guarantee that all fs support sendfile */
545 buflen = read(si.sdt_fd, rbuf, *rbuflen);
550 if (obj->options.flags & OPTION_DEBUG) {
551 printf( "(read) reply: %d, %d\n", buflen, dsi->clientID);
552 bprint(rbuf, buflen);
555 /* dsi_read() also returns buffer size of next allocation */
556 buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
568 LOG(log_info, logtype_afpd, "afp_geticon: %s", strerror(errno));
574 if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
575 return( AFPERR_PARAM );
582 /* ---------------------- */
583 static char hexdig[] = "0123456789abcdef";
584 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
586 static char path[ MAXPATHLEN + 1];
590 strcpy( path, vol->v_path );
591 strcat( path, "/.AppleDesktop/" );
592 for ( p = path; *p != '\0'; p++ )
595 if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
596 *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
597 *p++ = hexdig[ creator[ 0 ] & 0x0f ];
604 for ( i = 0; i < sizeof( CreatorType ); i++ ) {
605 if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
606 *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
607 *p++ = hexdig[ creator[ i ] & 0x0f ];
618 /* ---------------------------
619 * mpath is only a filename
620 * did filename parent directory ID.
622 static char upath[ MAXPATHLEN + 1];
623 static char mpath[ MAXPATHLEN + 1];
624 static char ucs2[ MAXPATHLEN + 1];
626 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
633 if ( *mpath == '\0' ) {
637 /* set conversion flags */
638 if (!(vol->v_flags & AFPVOL_NOHEX))
639 flags |= CONV_ESCAPEHEX;
640 if (!(vol->v_flags & AFPVOL_USEDOTS))
641 flags |= CONV_ESCAPEDOTS;
643 if ((vol->v_casefold & AFPVOL_MTOUUPPER))
644 flags |= CONV_TOUPPER;
645 else if ((vol->v_casefold & AFPVOL_MTOULOWER))
646 flags |= CONV_TOLOWER;
648 m = demangle(vol, mpath, did);
659 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)) ) {
660 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
666 LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
674 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
677 u_int16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
681 outlen = strlen(upath);
683 if (vol->v_casefold & AFPVOL_UTOMUPPER)
684 flags |= CONV_TOUPPER;
685 else if (vol->v_casefold & AFPVOL_UTOMLOWER)
686 flags |= CONV_TOLOWER;
690 /* convert charsets */
691 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)) ) {
692 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
697 if (!(flags & CONV_REQMANGLE))
700 m = mangle(vol, mpath, upath, id, flags);
703 LOG(log_debug, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
709 m = mangle(vol, u, upath, id, 1);
713 /* ----------------------------- */
714 int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
717 int ibuflen, *rbuflen;
719 struct adouble ad, *adp;
733 memcpy( &vid, ibuf, sizeof( vid ));
734 ibuf += sizeof( vid );
735 if (NULL == ( vol = getvolbyvid( vid )) ) {
736 return( AFPERR_PARAM );
739 memcpy( &did, ibuf, sizeof( did ));
740 ibuf += sizeof( did );
741 if (NULL == ( dir = dirlookup( vol, did )) ) {
745 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
746 return get_afp_errno(AFPERR_NOOBJ);
749 if ((u_long)ibuf & 1 ) {
753 clen = (u_char)*ibuf++;
754 clen = min( clen, 199 );
756 upath = path->u_name;
757 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
758 return AFPERR_ACCESS;
761 isadir = path_isadir(path);
762 if (isadir || !(of = of_findname(path))) {
763 ad_init(&ad, vol->v_adouble);
768 if (ad_open( upath , vol_noadouble(vol) |
769 (( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF),
770 O_RDWR|O_CREAT, 0666, adp) < 0 ) {
771 return( AFPERR_ACCESS );
774 if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
775 if ( *path->m_name == '\0' ) {
776 name = curdir->d_m_name;
780 ad_setentrylen( adp, ADEID_NAME, strlen( name ));
781 memcpy( ad_entry( adp, ADEID_NAME ), name,
782 ad_getentrylen( adp, ADEID_NAME ));
785 ad_setentrylen( adp, ADEID_COMMENT, clen );
786 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
787 ad_flush( adp, ADFLAGS_HF );
788 ad_close( adp, ADFLAGS_HF );
792 int afp_getcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
795 int ibuflen, *rbuflen;
797 struct adouble ad, *adp;
810 memcpy( &vid, ibuf, sizeof( vid ));
811 ibuf += sizeof( vid );
812 if (NULL == ( vol = getvolbyvid( vid )) ) {
813 return( AFPERR_PARAM );
816 memcpy( &did, ibuf, sizeof( did ));
817 ibuf += sizeof( did );
818 if (NULL == ( dir = dirlookup( vol, did )) ) {
822 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
823 return get_afp_errno(AFPERR_NOOBJ);
826 upath = s_path->u_name;
827 isadir = path_isadir(s_path);
828 if (isadir || !(of = of_findname(s_path))) {
829 ad_init(&ad, vol->v_adouble);
834 ( isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
835 O_RDONLY, 0666, adp) < 0 ) {
836 return( AFPERR_NOITEM );
840 * Make sure the AD file is not bogus.
842 if ( ad_getentrylen( adp, ADEID_COMMENT ) < 0 ||
843 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
844 ad_close( adp, ADFLAGS_HF );
845 return( AFPERR_NOITEM );
848 *rbuf++ = ad_getentrylen( adp, ADEID_COMMENT );
849 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ),
850 ad_getentrylen( adp, ADEID_COMMENT ));
851 *rbuflen = ad_getentrylen( adp, ADEID_COMMENT ) + 1;
852 ad_close( adp, ADFLAGS_HF );
854 /* return AFPERR_NOITEM if len == 0 ? */
858 int afp_rmvcomment(obj, ibuf, ibuflen, rbuf, rbuflen )
861 int ibuflen, *rbuflen;
863 struct adouble ad, *adp;
876 memcpy( &vid, ibuf, sizeof( vid ));
877 ibuf += sizeof( vid );
878 if (NULL == ( vol = getvolbyvid( vid )) ) {
879 return( AFPERR_PARAM );
882 memcpy( &did, ibuf, sizeof( did ));
883 ibuf += sizeof( did );
884 if (NULL == ( dir = dirlookup( vol, did )) ) {
888 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
889 return get_afp_errno(AFPERR_NOOBJ);
892 upath = s_path->u_name;
893 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
894 return AFPERR_ACCESS;
897 isadir = path_isadir(s_path);
898 if (isadir || !(of = of_findname(s_path))) {
899 ad_init(&ad, vol->v_adouble);
905 (isadir) ? ADFLAGS_HF|ADFLAGS_DIR : ADFLAGS_HF,
906 O_RDWR, 0, adp) < 0 ) {
909 return( AFPERR_NOITEM );
911 return( AFPERR_ACCESS );
913 return( AFPERR_PARAM );
917 ad_setentrylen( adp, ADEID_COMMENT, 0 );
918 ad_flush( adp, ADFLAGS_HF );
919 ad_close( adp, ADFLAGS_HF );