5 * afp_XXXcomment are (the only) functions able to open
6 * a ressource fork when there's no data fork, eg after
7 * it was removed with samba.
12 #endif /* HAVE_CONFIG_H */
20 #include <atalk/adouble.h>
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <arpa/inet.h>
26 #include <atalk/dsi.h>
27 #include <atalk/afp.h>
28 #include <atalk/util.h>
29 #include <atalk/logger.h>
30 #include <atalk/globals.h>
32 #include "directory.h"
38 int afp_opendt(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
45 memcpy( &vid, ibuf, sizeof(vid));
46 if (NULL == ( vol = getvolbyvid( vid )) ) {
48 return( AFPERR_PARAM );
51 memcpy( rbuf, &vid, sizeof(vid));
52 *rbuflen = sizeof(vid);
56 int afp_closedt(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
62 static struct savedt si = { { 0, 0, 0, 0 }, -1, 0, 0 };
64 static char *icon_dtfile(struct vol *vol, u_char creator[ 4 ])
66 return dtfile( vol, creator, ".icon" );
69 static int iconopen(struct vol *vol, u_char creator[ 4 ], int flags, int mode)
71 char *dtf, *adt, *adts;
73 if ( si.sdt_fd != -1 ) {
74 if ( memcmp( si.sdt_creator, creator, sizeof( CreatorType )) == 0 &&
75 si.sdt_vid == vol->v_vid ) {
82 dtf = icon_dtfile( vol, creator);
84 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
85 if ( errno == ENOENT && ( flags & O_CREAT )) {
86 if (( adts = strrchr( dtf, '/' )) == NULL ) {
90 if (( adt = strrchr( dtf, '/' )) == NULL ) {
94 (void) ad_mkdir( dtf, DIRBITS | 0777 );
96 (void) ad_mkdir( dtf, DIRBITS | 0777 );
99 if (( si.sdt_fd = open( dtf, flags, ad_mode( dtf, mode ))) < 0 ) {
100 LOG(log_error, logtype_afpd, "iconopen(%s): open: %s", dtf, strerror(errno) );
108 memcpy( si.sdt_creator, creator, sizeof( CreatorType ));
109 si.sdt_vid = vol->v_vid;
114 int afp_addicon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
117 u_char fcreator[ 4 ], imh[ 12 ], irh[ 12 ], *p;
118 int itype, cc = AFP_OK, iovcnt = 0;
120 uint32_t ftype, itag;
121 uint16_t bsize, rsize, vid;
127 memcpy( &vid, ibuf, sizeof( vid ));
128 ibuf += sizeof( vid );
129 if (NULL == ( vol = getvolbyvid( vid )) ) {
134 memcpy( fcreator, ibuf, sizeof( fcreator ));
135 ibuf += sizeof( fcreator );
137 memcpy( &ftype, ibuf, sizeof( ftype ));
138 ibuf += sizeof( ftype );
140 itype = (unsigned char) *ibuf;
143 memcpy( &itag, ibuf, sizeof( itag ));
144 ibuf += sizeof( itag );
146 memcpy( &bsize, ibuf, sizeof( bsize ));
147 bsize = ntohs( bsize );
149 if ( si.sdt_fd != -1 ) {
150 (void)close( si.sdt_fd );
154 if (iconopen( vol, fcreator, O_RDWR|O_CREAT, 0666 ) < 0) {
159 if (lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0) {
162 LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
168 * Read icon elements until we find a match to replace, or
169 * we get to the end to insert.
172 memcpy( p, &itag, sizeof( itag ));
174 memcpy( p, &ftype, sizeof( ftype ));
175 p += sizeof( ftype );
178 bsize = htons( bsize );
179 memcpy( p, &bsize, sizeof( bsize ));
180 bsize = ntohs( bsize );
181 while (( cc = read( si.sdt_fd, irh, sizeof( irh ))) > 0 ) {
182 memcpy( &rsize, irh + 10, sizeof( rsize ));
183 rsize = ntohs( rsize );
185 * Is this our set of headers?
187 if ( memcmp( irh, imh, sizeof( irh ) - sizeof( u_short )) == 0 ) {
189 * Is the size correct?
191 if ( bsize != rsize )
196 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
197 LOG(log_error, logtype_afpd, "afp_addicon(%s): lseek: %s", icon_dtfile(vol, fcreator),strerror(errno) );
203 * Some error occurred, return.
207 if (obj->proto == AFPPROTO_DSI) {
208 dsi_writeinit(obj->handle, rbuf, buflen);
209 dsi_writeflush(obj->handle);
214 switch (obj->proto) {
217 DSI *dsi = obj->handle;
219 iovcnt = dsi_writeinit(dsi, rbuf, buflen);
221 /* add headers at end of file */
222 if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
223 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
228 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
229 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
234 while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
235 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
236 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
250 static const u_char utag[] = { 0, 0, 0, 0 };
251 static const u_char ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
252 static const u_char utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
253 static const short usize = 256;
256 static const u_char uicon[] = {
257 0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
258 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
259 0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
260 0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
261 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
262 0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
263 0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
264 0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
265 0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
266 0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
267 0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
268 0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
269 0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
270 0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
271 0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
272 0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
273 0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
274 0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
275 0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
276 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
277 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
278 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
279 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
280 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
281 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
282 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
283 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
284 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
285 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
286 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
287 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
288 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
292 int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
295 unsigned char fcreator[ 4 ], ih[ 12 ];
296 uint16_t vid, iindex, bsize;
301 memcpy( &vid, ibuf, sizeof( vid ));
302 ibuf += sizeof( vid );
303 if (NULL == ( vol = getvolbyvid( vid )) ) {
304 return( AFPERR_PARAM );
307 memcpy( fcreator, ibuf, sizeof( fcreator ));
308 ibuf += sizeof( fcreator );
309 memcpy( &iindex, ibuf, sizeof( iindex ));
310 iindex = ntohs( iindex );
312 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
314 return( AFPERR_NOITEM );
316 memcpy( ih, utag, sizeof( utag ));
317 memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
318 *( ih + sizeof( utag ) + sizeof( utype )) = 1;
319 *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
320 memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
322 memcpy( rbuf, ih, sizeof( ih ));
323 *rbuflen = sizeof( ih );
327 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
328 return( AFPERR_NOITEM );
331 if ( iindex < si.sdt_index ) {
332 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
333 return( AFPERR_PARAM );
339 * Position to the correct spot.
342 if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
345 return( AFPERR_NOITEM );
347 memcpy( &bsize, ih + 10, sizeof( bsize ));
348 bsize = ntohs(bsize);
349 if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
350 LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
351 return( AFPERR_PARAM );
353 if ( si.sdt_index == iindex ) {
354 memcpy( rbuf, ih, sizeof( ih ));
355 *rbuflen = sizeof( ih );
363 int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
368 u_char fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
369 uint16_t vid, bsize, rsize;
375 memcpy( &vid, ibuf, sizeof( vid ));
376 ibuf += sizeof( vid );
377 if (NULL == ( vol = getvolbyvid( vid )) ) {
378 return( AFPERR_PARAM );
381 memcpy( fcreator, ibuf, sizeof( fcreator ));
382 ibuf += sizeof( fcreator );
383 memcpy( ftype, ibuf, sizeof( ftype ));
384 ibuf += sizeof( ftype );
385 itype = (unsigned char) *ibuf++;
387 memcpy( &bsize, ibuf, sizeof( bsize ));
388 bsize = ntohs( bsize );
391 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
392 memcmp( ftype, utype, sizeof( utype )) == 0 &&
395 memcpy( rbuf, uicon, bsize);
401 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
402 return( AFPERR_NOITEM );
405 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
408 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
409 return( AFPERR_PARAM );
414 while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
416 offset += sizeof(ih);
417 if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
418 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
421 memcpy( &rsize, ih + 10, sizeof( rsize ));
422 rsize = ntohs( rsize );
423 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
424 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
425 return( AFPERR_PARAM );
431 LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
432 return( AFPERR_PARAM );
436 return( AFPERR_NOITEM );
439 memcpy( &rsize, ih + 10, sizeof( rsize ));
440 rsize = ntohs( rsize );
441 #define min(a,b) ((a)<(b)?(a):(b))
442 rc = min( bsize, rsize );
444 if ((obj->proto == AFPPROTO_DSI) && (buflen < rc)) {
445 DSI *dsi = obj->handle;
449 size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
450 if (size < rc + offset) {
454 if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
458 /* do to the streaming nature, we have to exit if we encounter
459 * a problem. much confusion results otherwise. */
460 while (*rbuflen > 0) {
462 if (!obj->options.flags & OPTION_DEBUG) {
463 if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
466 case EINVAL: /* there's no guarantee that all fs support sendfile */
478 buflen = read(si.sdt_fd, rbuf, *rbuflen);
482 /* dsi_read() also returns buffer size of next allocation */
483 buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
494 LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
496 obj->exit(EXITERR_SYS);
500 if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
501 return( AFPERR_PARAM );
508 /* ---------------------- */
509 static const char hexdig[] = "0123456789abcdef";
510 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
512 static char path[ MAXPATHLEN + 1];
516 strcpy( path, vol->v_path );
517 strcat( path, "/.AppleDesktop/" );
518 for ( p = path; *p != '\0'; p++ )
521 if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
522 *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
523 *p++ = hexdig[ creator[ 0 ] & 0x0f ];
530 for ( i = 0; i < sizeof( CreatorType ); i++ ) {
531 if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
532 *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
533 *p++ = hexdig[ creator[ i ] & 0x0f ];
544 /* ---------------------------
545 * mpath is only a filename
546 * did filename parent directory ID.
549 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
551 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
557 if ( *mpath == '\0' ) {
562 /* set conversion flags */
563 flags = vol->v_mtou_flags;
565 m = demangle(vol, mpath, did);
576 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)) ) {
577 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
582 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
590 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
592 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
598 outlen = strlen(upath);
600 flags = vol->v_utom_flags;
604 /* convert charsets */
605 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)) ) {
606 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
610 flags = !!(flags & CONV_REQMANGLE);
615 m = mangle(vol, mpath, outlen, upath, id, flags);
618 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
624 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
628 /* ------------------------- */
629 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
635 struct adouble ad, *adp;
637 clen = (u_char)*ibuf++;
638 clen = min( clen, 199 );
640 upath = path->u_name;
641 if (check_access(upath, OPENACC_WR ) < 0) {
642 return AFPERR_ACCESS;
645 isadir = path_isadir(path);
646 if (isadir || !(of = of_findname(path))) {
647 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
652 if (ad_open(adp, upath,
653 ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
656 return( AFPERR_ACCESS );
659 if (ad_getentryoff(adp, ADEID_COMMENT)) {
660 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
661 if ( *path->m_name == '\0' ) {
662 name = (char *)curdir->d_m_name->data;
666 ad_setname(adp, name);
668 ad_setentrylen( adp, ADEID_COMMENT, clen );
669 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
672 ad_close_metadata( adp);
676 /* ----------------------------- */
677 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
688 memcpy( &vid, ibuf, sizeof( vid ));
689 ibuf += sizeof( vid );
690 if (NULL == ( vol = getvolbyvid( vid )) ) {
691 return( AFPERR_PARAM );
694 memcpy( &did, ibuf, sizeof( did ));
695 ibuf += sizeof( did );
696 if (NULL == ( dir = dirlookup( vol, did )) ) {
700 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
701 return get_afp_errno(AFPERR_NOOBJ);
704 if ((u_long)ibuf & 1 ) {
708 return ad_addcomment(vol, path, ibuf);
711 /* -------------------- */
712 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
714 struct adouble ad, *adp;
720 upath = path->u_name;
721 isadir = path_isadir(path);
722 if (isadir || !(of = of_findname(path))) {
723 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
728 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
729 return( AFPERR_NOITEM );
732 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
733 ad_close_metadata( adp );
734 return AFPERR_NOITEM;
737 * Make sure the AD file is not bogus.
739 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
740 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
741 ad_close_metadata( adp );
742 return( AFPERR_NOITEM );
745 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
747 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
749 ad_close_metadata( adp);
754 /* -------------------- */
755 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
766 memcpy( &vid, ibuf, sizeof( vid ));
767 ibuf += sizeof( vid );
768 if (NULL == ( vol = getvolbyvid( vid )) ) {
769 return( AFPERR_PARAM );
772 memcpy( &did, ibuf, sizeof( did ));
773 ibuf += sizeof( did );
774 if (NULL == ( dir = dirlookup( vol, did )) ) {
778 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
779 return get_afp_errno(AFPERR_NOOBJ);
782 return ad_getcomment(vol, s_path, rbuf, rbuflen);
785 /* ----------------------- */
786 static int ad_rmvcomment(struct vol *vol, struct path *path)
788 struct adouble ad, *adp;
793 upath = path->u_name;
794 if (check_access(upath, OPENACC_WR ) < 0) {
795 return AFPERR_ACCESS;
798 isadir = path_isadir(path);
799 if (isadir || !(of = of_findname(path))) {
800 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
805 if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
808 return( AFPERR_NOITEM );
810 return( AFPERR_ACCESS );
812 return( AFPERR_PARAM );
816 if (ad_getentryoff(adp, ADEID_COMMENT)) {
817 ad_setentrylen( adp, ADEID_COMMENT, 0 );
820 ad_close_metadata( adp);
824 /* ----------------------- */
825 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
836 memcpy( &vid, ibuf, sizeof( vid ));
837 ibuf += sizeof( vid );
838 if (NULL == ( vol = getvolbyvid( vid )) ) {
839 return( AFPERR_PARAM );
842 memcpy( &did, ibuf, sizeof( did ));
843 ibuf += sizeof( did );
844 if (NULL == ( dir = dirlookup( vol, did )) ) {
848 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
849 return get_afp_errno(AFPERR_NOOBJ);
852 return ad_rmvcomment(vol, s_path);