2 * $Id: desktop.c,v 1.48 2010-01-05 12:06:33 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>
35 #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_info, 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' ) {
606 /* set conversion flags */
607 flags = vol->v_mtou_flags;
609 m = demangle(vol, mpath, did);
620 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)) ) {
621 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
626 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
634 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
636 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
642 outlen = strlen(upath);
644 flags = vol->v_utom_flags;
648 /* convert charsets */
649 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)) ) {
650 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
654 flags = !!(flags & CONV_REQMANGLE);
659 m = mangle(vol, mpath, outlen, upath, id, flags);
662 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
668 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
672 /* ------------------------- */
673 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
679 struct adouble ad, *adp;
681 clen = (u_char)*ibuf++;
682 clen = min( clen, 199 );
684 upath = path->u_name;
685 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
686 return AFPERR_ACCESS;
689 isadir = path_isadir(path);
690 if (isadir || !(of = of_findname(path))) {
691 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
696 if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) {
697 return( AFPERR_ACCESS );
700 if (ad_getentryoff(adp, ADEID_COMMENT)) {
701 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
702 if ( *path->m_name == '\0' ) {
703 name = curdir->d_m_name;
707 ad_setname(adp, name);
709 ad_setentrylen( adp, ADEID_COMMENT, clen );
710 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
713 ad_close_metadata( adp);
717 /* ----------------------------- */
718 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
729 memcpy( &vid, ibuf, sizeof( vid ));
730 ibuf += sizeof( vid );
731 if (NULL == ( vol = getvolbyvid( vid )) ) {
732 return( AFPERR_PARAM );
735 memcpy( &did, ibuf, sizeof( did ));
736 ibuf += sizeof( did );
737 if (NULL == ( dir = dirlookup( vol, did )) ) {
741 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
742 return get_afp_errno(AFPERR_NOOBJ);
745 if ((u_long)ibuf & 1 ) {
749 return ad_addcomment(vol, path, ibuf);
752 /* -------------------- */
753 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
755 struct adouble ad, *adp;
761 upath = path->u_name;
762 isadir = path_isadir(path);
763 if (isadir || !(of = of_findname(path))) {
764 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
769 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
770 return( AFPERR_NOITEM );
773 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
774 ad_close_metadata( adp );
775 return AFPERR_NOITEM;
778 * Make sure the AD file is not bogus.
780 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
781 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
782 ad_close_metadata( adp );
783 return( AFPERR_NOITEM );
786 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
788 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
790 ad_close_metadata( adp);
795 /* -------------------- */
796 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
807 memcpy( &vid, ibuf, sizeof( vid ));
808 ibuf += sizeof( vid );
809 if (NULL == ( vol = getvolbyvid( vid )) ) {
810 return( AFPERR_PARAM );
813 memcpy( &did, ibuf, sizeof( did ));
814 ibuf += sizeof( did );
815 if (NULL == ( dir = dirlookup( vol, did )) ) {
819 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
820 return get_afp_errno(AFPERR_NOOBJ);
823 return ad_getcomment(vol, s_path, rbuf, rbuflen);
826 /* ----------------------- */
827 static int ad_rmvcomment(struct vol *vol, struct path *path)
829 struct adouble ad, *adp;
834 upath = path->u_name;
835 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
836 return AFPERR_ACCESS;
839 isadir = path_isadir(path);
840 if (isadir || !(of = of_findname(path))) {
841 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
846 if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
849 return( AFPERR_NOITEM );
851 return( AFPERR_ACCESS );
853 return( AFPERR_PARAM );
857 if (ad_getentryoff(adp, ADEID_COMMENT)) {
858 ad_setentrylen( adp, ADEID_COMMENT, 0 );
861 ad_close_metadata( adp);
865 /* ----------------------- */
866 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
877 memcpy( &vid, ibuf, sizeof( vid ));
878 ibuf += sizeof( vid );
879 if (NULL == ( vol = getvolbyvid( vid )) ) {
880 return( AFPERR_PARAM );
883 memcpy( &did, ibuf, sizeof( did ));
884 ibuf += sizeof( did );
885 if (NULL == ( dir = dirlookup( vol, did )) ) {
889 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
890 return get_afp_errno(AFPERR_NOOBJ);
893 return ad_rmvcomment(vol, s_path);