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) | ADFLAGS_CREATE | ADFLAGS_RDWR,
655 return( AFPERR_ACCESS );
658 if (ad_getentryoff(adp, ADEID_COMMENT)) {
659 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
660 if ( *path->m_name == '\0' ) {
661 name = (char *)curdir->d_m_name->data;
665 ad_setname(adp, name);
667 ad_setentrylen( adp, ADEID_COMMENT, clen );
668 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
671 ad_close(adp, ADFLAGS_HF);
675 /* ----------------------------- */
676 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
687 memcpy( &vid, ibuf, sizeof( vid ));
688 ibuf += sizeof( vid );
689 if (NULL == ( vol = getvolbyvid( vid )) ) {
690 return( AFPERR_PARAM );
693 memcpy( &did, ibuf, sizeof( did ));
694 ibuf += sizeof( did );
695 if (NULL == ( dir = dirlookup( vol, did )) ) {
699 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
700 return get_afp_errno(AFPERR_NOOBJ);
703 if ((u_long)ibuf & 1 ) {
707 return ad_addcomment(vol, path, ibuf);
710 /* -------------------- */
711 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
713 struct adouble ad, *adp;
719 upath = path->u_name;
720 isadir = path_isadir(path);
721 if (isadir || !(of = of_findname(path))) {
722 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
727 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
728 return( AFPERR_NOITEM );
731 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
732 ad_close(adp, ADFLAGS_HF);
733 return AFPERR_NOITEM;
736 * Make sure the AD file is not bogus.
738 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
739 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
740 ad_close(adp, ADFLAGS_HF);
741 return( AFPERR_NOITEM );
744 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
746 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
748 ad_close(adp, ADFLAGS_HF);
753 /* -------------------- */
754 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
765 memcpy( &vid, ibuf, sizeof( vid ));
766 ibuf += sizeof( vid );
767 if (NULL == ( vol = getvolbyvid( vid )) ) {
768 return( AFPERR_PARAM );
771 memcpy( &did, ibuf, sizeof( did ));
772 ibuf += sizeof( did );
773 if (NULL == ( dir = dirlookup( vol, did )) ) {
777 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
778 return get_afp_errno(AFPERR_NOOBJ);
781 return ad_getcomment(vol, s_path, rbuf, rbuflen);
784 /* ----------------------- */
785 static int ad_rmvcomment(struct vol *vol, struct path *path)
787 struct adouble ad, *adp;
792 upath = path->u_name;
793 if (check_access(upath, OPENACC_WR ) < 0) {
794 return AFPERR_ACCESS;
797 isadir = path_isadir(path);
798 if (isadir || !(of = of_findname(path))) {
799 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
804 if ( ad_open(adp, upath, ADFLAGS_HF | ADFLAGS_RDWR | (isadir) ? ADFLAGS_DIR : 0) < 0 ) {
807 return( AFPERR_NOITEM );
809 return( AFPERR_ACCESS );
811 return( AFPERR_PARAM );
815 if (ad_getentryoff(adp, ADEID_COMMENT)) {
816 ad_setentrylen( adp, ADEID_COMMENT, 0 );
819 ad_close(adp, ADFLAGS_HF);
823 /* ----------------------- */
824 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
835 memcpy( &vid, ibuf, sizeof( vid ));
836 ibuf += sizeof( vid );
837 if (NULL == ( vol = getvolbyvid( vid )) ) {
838 return( AFPERR_PARAM );
841 memcpy( &did, ibuf, sizeof( did ));
842 ibuf += sizeof( did );
843 if (NULL == ( dir = dirlookup( vol, did )) ) {
847 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
848 return get_afp_errno(AFPERR_NOOBJ);
851 return ad_rmvcomment(vol, s_path);