2 * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm 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 */
22 #include <atalk/adouble.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>
36 #include "directory.h"
42 int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
49 memcpy( &vid, ibuf, sizeof(vid));
50 if (NULL == ( vol = getvolbyvid( vid )) ) {
52 return( AFPERR_PARAM );
55 memcpy( rbuf, &vid, sizeof(vid));
56 *rbuflen = sizeof(vid);
60 int afp_closedt(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
66 static struct savedt si = { { 0, 0, 0, 0 }, -1, 0, 0 };
68 static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
70 return dtfile( vol, creator, ".icon" );
73 static int iconopen(struct vol *vol, u_char creator[ 4 ], int flags, int mode)
75 char *dtf, *adt, *adts;
77 if ( si.sdt_fd != -1 ) {
78 if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
79 si.sdt_vid == vol->v_vid ) {
86 dtf = icon_dtfile( vol, creator);
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 ) {
94 if (( adt = strrchr( dtf, '/' )) == NULL ) {
98 (void) ad_mkdir( dtf, DIRBITS | 0777 );
100 (void) ad_mkdir( dtf, DIRBITS | 0777 );
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) );
112 memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
113 si.sdt_vid = vol->v_vid;
118 int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
122 struct iovec iov[ 2 ];
124 u_char fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
125 int itype, cc = AFP_OK, iovcnt = 0;
127 u_int32_t ftype, itag;
128 u_int16_t bsize, rsize, vid;
134 memcpy( &vid, ibuf, sizeof( vid ));
135 ibuf += sizeof( vid );
136 if (NULL == ( vol = getvolbyvid( vid )) ) {
141 memcpy( fcreator, ibuf, sizeof( fcreator ));
142 ibuf += sizeof( fcreator );
144 memcpy( &ftype, ibuf, sizeof( ftype ));
145 ibuf += sizeof( ftype );
147 itype = (unsigned char) *ibuf;
150 memcpy( &itag, ibuf, sizeof( itag ));
151 ibuf += sizeof( itag );
153 memcpy( &bsize, ibuf, sizeof( bsize ));
154 bsize = ntohs( bsize );
156 if ( si.sdt_fd != -1 ) {
157 (void)close( si.sdt_fd );
161 if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
166 if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
169 LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
175 * Read icon elements until we find a match to replace, or
176 * we get to the end to insert.
179 memcpy( p, &itag, sizeof( itag ));
181 memcpy( p, &ftype, sizeof( ftype ));
182 p += sizeof( ftype );
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 );
192 * Is this our set of headers?
194 if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
196 * Is the size correct?
198 if ( bsize != rsize )
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) );
210 * Some error occurred, return.
214 if (obj->proto == AFPPROTO_DSI) {
215 dsi_writeinit(obj->handle, rbuf, buflen);
216 dsi_writeflush(obj->handle);
221 switch (obj->proto) {
225 if ((asp_wrtcont(obj->handle, rbuf, &buflen) < 0) || buflen != bsize)
226 return( AFPERR_PARAM );
229 if (obj->options.flags & OPTION_DEBUG) {
230 printf("(write) len: %d\n", buflen);
231 bprint(rbuf, buflen);
236 * We're at the end of the file, add the headers, etc. */
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;
246 * We found an icon to replace.
249 iov[ 0 ].iov_base = rbuf;
250 iov[ 0 ].iov_len = bsize;
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 );
259 #endif /* no afp/asp */
262 DSI *dsi = obj->handle;
264 iovcnt = dsi_writeinit(dsi, rbuf, buflen);
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));
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));
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));
295 static const u_char utag[] = { 0, 0, 0, 0 };
296 static const u_char ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
297 static const u_char utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
298 static const short usize = 256;
301 static 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,
337 int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
340 u_char fcreator[ 4 ], ih[ 12 ];
341 u_int16_t vid, iindex, bsize;
346 memcpy( &vid, ibuf, sizeof( vid ));
347 ibuf += sizeof( vid );
348 if (NULL == ( vol = getvolbyvid( vid )) ) {
349 return( AFPERR_PARAM );
352 memcpy( fcreator, ibuf, sizeof( fcreator ));
353 ibuf += sizeof( fcreator );
354 memcpy( &iindex, ibuf, sizeof( iindex ));
355 iindex = ntohs( iindex );
357 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
359 return( AFPERR_NOITEM );
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,
367 memcpy( rbuf, ih, sizeof( ih ));
368 *rbuflen = sizeof( ih );
372 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
373 return( AFPERR_NOITEM );
376 if ( iindex < si.sdt_index ) {
377 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
378 return( AFPERR_PARAM );
384 * Position to the correct spot.
387 if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
390 return( AFPERR_NOITEM );
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 );
398 if ( si.sdt_index == iindex ) {
399 memcpy( rbuf, ih, sizeof( ih ));
400 *rbuflen = sizeof( ih );
408 int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
413 u_char fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
414 u_int16_t vid, bsize, rsize;
420 memcpy( &vid, ibuf, sizeof( vid ));
421 ibuf += sizeof( vid );
422 if (NULL == ( vol = getvolbyvid( vid )) ) {
423 return( AFPERR_PARAM );
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++;
432 memcpy( &bsize, ibuf, sizeof( bsize ));
433 bsize = ntohs( bsize );
436 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
437 memcmp( ftype, utype, sizeof( utype )) == 0 &&
440 memcpy( rbuf, uicon, bsize);
446 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
447 return( AFPERR_NOITEM );
450 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
453 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
454 return( AFPERR_PARAM );
459 while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
461 offset += sizeof(ih);
462 if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
463 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
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 );
476 LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
477 return( AFPERR_PARAM );
481 return( AFPERR_NOITEM );
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 );
489 if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
490 DSI *dsi = obj->handle;
494 size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
495 if (size < rc + offset) {
499 if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
503 /* do to the streaming nature, we have to exit if we encounter
504 * a problem. much confusion results otherwise. */
505 while (*rbuflen > 0) {
507 if (!obj->options.flags & OPTION_DEBUG) {
508 if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
511 case EINVAL: /* there's no guarantee that all fs support sendfile */
523 buflen = read(si.sdt_fd, rbuf, *rbuflen);
527 /* dsi_read() also returns buffer size of next allocation */
528 buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
539 LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
541 obj->exit(EXITERR_SYS);
545 if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
546 return( AFPERR_PARAM );
553 /* ---------------------- */
554 static const char hexdig[] = "0123456789abcdef";
555 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
557 static char path[ MAXPATHLEN + 1];
561 strcpy( path, vol->v_path );
562 strcat( path, "/.AppleDesktop/" );
563 for ( p = path; *p != '\0'; p++ )
566 if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
567 *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
568 *p++ = hexdig[ creator[ 0 ] & 0x0f ];
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 ];
589 /* ---------------------------
590 * mpath is only a filename
591 * did filename parent directory ID.
594 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
596 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
602 if ( *mpath == '\0' ) {
607 /* set conversion flags */
608 flags = vol->v_mtou_flags;
610 m = demangle(vol, mpath, did);
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);
627 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
635 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
637 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
643 outlen = strlen(upath);
645 flags = vol->v_utom_flags;
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));
655 flags = !!(flags & CONV_REQMANGLE);
660 m = mangle(vol, mpath, outlen, upath, id, flags);
663 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
669 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
673 /* ------------------------- */
674 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
680 struct adouble ad, *adp;
682 clen = (u_char)*ibuf++;
683 clen = min( clen, 199 );
685 upath = path->u_name;
686 if (check_access(upath, OPENACC_WR ) < 0) {
687 return AFPERR_ACCESS;
690 isadir = path_isadir(path);
691 if (isadir || !(of = of_findname(path))) {
692 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
697 if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) {
698 return( AFPERR_ACCESS );
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;
708 ad_setname(adp, name);
710 ad_setentrylen( adp, ADEID_COMMENT, clen );
711 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
714 ad_close_metadata( adp);
718 /* ----------------------------- */
719 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
730 memcpy( &vid, ibuf, sizeof( vid ));
731 ibuf += sizeof( vid );
732 if (NULL == ( vol = getvolbyvid( vid )) ) {
733 return( AFPERR_PARAM );
736 memcpy( &did, ibuf, sizeof( did ));
737 ibuf += sizeof( did );
738 if (NULL == ( dir = dirlookup( vol, did )) ) {
742 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
743 return get_afp_errno(AFPERR_NOOBJ);
746 if ((u_long)ibuf & 1 ) {
750 return ad_addcomment(vol, path, ibuf);
753 /* -------------------- */
754 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
756 struct adouble ad, *adp;
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);
770 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
771 return( AFPERR_NOITEM );
774 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
775 ad_close_metadata( adp );
776 return AFPERR_NOITEM;
779 * Make sure the AD file is not bogus.
781 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
782 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
783 ad_close_metadata( adp );
784 return( AFPERR_NOITEM );
787 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
789 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
791 ad_close_metadata( adp);
796 /* -------------------- */
797 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
808 memcpy( &vid, ibuf, sizeof( vid ));
809 ibuf += sizeof( vid );
810 if (NULL == ( vol = getvolbyvid( vid )) ) {
811 return( AFPERR_PARAM );
814 memcpy( &did, ibuf, sizeof( did ));
815 ibuf += sizeof( did );
816 if (NULL == ( dir = dirlookup( vol, did )) ) {
820 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
821 return get_afp_errno(AFPERR_NOOBJ);
824 return ad_getcomment(vol, s_path, rbuf, rbuflen);
827 /* ----------------------- */
828 static int ad_rmvcomment(struct vol *vol, struct path *path)
830 struct adouble ad, *adp;
835 upath = path->u_name;
836 if (check_access(upath, OPENACC_WR ) < 0) {
837 return AFPERR_ACCESS;
840 isadir = path_isadir(path);
841 if (isadir || !(of = of_findname(path))) {
842 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
847 if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
850 return( AFPERR_NOITEM );
852 return( AFPERR_ACCESS );
854 return( AFPERR_PARAM );
858 if (ad_getentryoff(adp, ADEID_COMMENT)) {
859 ad_setentrylen( adp, ADEID_COMMENT, 0 );
862 ad_close_metadata( adp);
866 /* ----------------------- */
867 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
878 memcpy( &vid, ibuf, sizeof( vid ));
879 ibuf += sizeof( vid );
880 if (NULL == ( vol = getvolbyvid( vid )) ) {
881 return( AFPERR_PARAM );
884 memcpy( &did, ibuf, sizeof( did ));
885 ibuf += sizeof( did );
886 if (NULL == ( dir = dirlookup( vol, did )) ) {
890 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
891 return get_afp_errno(AFPERR_NOOBJ);
894 return ad_rmvcomment(vol, s_path);