2 * $Id: desktop.c,v 1.45 2009-10-29 13:38:15 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 */
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 if (!(vol->v_flags & AFPVOL_NOHEX))
608 flags |= CONV_ESCAPEHEX;
609 if (!(vol->v_flags & AFPVOL_USEDOTS))
610 flags |= CONV_ESCAPEDOTS;
612 if ((vol->v_casefold & AFPVOL_MTOUUPPER))
613 flags |= CONV_TOUPPER;
614 else if ((vol->v_casefold & AFPVOL_MTOULOWER))
615 flags |= CONV_TOLOWER;
617 if ((vol->v_flags & AFPVOL_EILSEQ)) {
618 flags |= CONV__EILSEQ;
621 m = demangle(vol, mpath, did);
632 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)) ) {
633 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
638 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
646 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
648 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
650 u_int16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
654 outlen = strlen(upath);
656 if ((vol->v_casefold & AFPVOL_UTOMUPPER))
657 flags |= CONV_TOUPPER;
658 else if ((vol->v_casefold & AFPVOL_UTOMLOWER))
659 flags |= CONV_TOLOWER;
661 if ((vol->v_flags & AFPVOL_EILSEQ)) {
662 flags |= CONV__EILSEQ;
667 /* convert charsets */
668 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)) ) {
669 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
673 if (!(flags & CONV_REQMANGLE))
681 m = mangle(vol, mpath, outlen, upath, id, flags);
684 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
690 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
694 /* ------------------------- */
695 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
701 struct adouble ad, *adp;
703 clen = (u_char)*ibuf++;
704 clen = min( clen, 199 );
706 upath = path->u_name;
707 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
708 return AFPERR_ACCESS;
711 isadir = path_isadir(path);
712 if (isadir || !(of = of_findname(path))) {
713 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
718 if (ad_open_metadata( upath , vol_noadouble(vol) | ( (isadir) ? ADFLAGS_DIR :0),O_CREAT, adp) < 0 ) {
719 return( AFPERR_ACCESS );
722 if (ad_getentryoff(adp, ADEID_COMMENT)) {
723 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
724 if ( *path->m_name == '\0' ) {
725 name = curdir->d_m_name;
729 ad_setname(adp, name);
731 ad_setentrylen( adp, ADEID_COMMENT, clen );
732 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
735 ad_close_metadata( adp);
739 /* ----------------------------- */
740 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
751 memcpy( &vid, ibuf, sizeof( vid ));
752 ibuf += sizeof( vid );
753 if (NULL == ( vol = getvolbyvid( vid )) ) {
754 return( AFPERR_PARAM );
757 memcpy( &did, ibuf, sizeof( did ));
758 ibuf += sizeof( did );
759 if (NULL == ( dir = dirlookup( vol, did )) ) {
763 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
764 return get_afp_errno(AFPERR_NOOBJ);
767 if ((u_long)ibuf & 1 ) {
771 return ad_addcomment(vol, path, ibuf);
774 /* -------------------- */
775 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
777 struct adouble ad, *adp;
783 upath = path->u_name;
784 isadir = path_isadir(path);
785 if (isadir || !(of = of_findname(path))) {
786 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
791 if ( ad_metadata( upath,( isadir) ? ADFLAGS_DIR : 0, adp) < 0 ) {
792 return( AFPERR_NOITEM );
795 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
796 ad_close_metadata( adp );
797 return AFPERR_NOITEM;
800 * Make sure the AD file is not bogus.
802 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
803 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
804 ad_close_metadata( adp );
805 return( AFPERR_NOITEM );
808 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
810 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
812 ad_close_metadata( adp);
817 /* -------------------- */
818 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
829 memcpy( &vid, ibuf, sizeof( vid ));
830 ibuf += sizeof( vid );
831 if (NULL == ( vol = getvolbyvid( vid )) ) {
832 return( AFPERR_PARAM );
835 memcpy( &did, ibuf, sizeof( did ));
836 ibuf += sizeof( did );
837 if (NULL == ( dir = dirlookup( vol, did )) ) {
841 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
842 return get_afp_errno(AFPERR_NOOBJ);
845 return ad_getcomment(vol, s_path, rbuf, rbuflen);
848 /* ----------------------- */
849 static int ad_rmvcomment(struct vol *vol, struct path *path)
851 struct adouble ad, *adp;
856 upath = path->u_name;
857 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
858 return AFPERR_ACCESS;
861 isadir = path_isadir(path);
862 if (isadir || !(of = of_findname(path))) {
863 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
868 if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
871 return( AFPERR_NOITEM );
873 return( AFPERR_ACCESS );
875 return( AFPERR_PARAM );
879 if (ad_getentryoff(adp, ADEID_COMMENT)) {
880 ad_setentrylen( adp, ADEID_COMMENT, 0 );
883 ad_close_metadata( adp);
887 /* ----------------------- */
888 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
899 memcpy( &vid, ibuf, sizeof( vid ));
900 ibuf += sizeof( vid );
901 if (NULL == ( vol = getvolbyvid( vid )) ) {
902 return( AFPERR_PARAM );
905 memcpy( &did, ibuf, sizeof( did ));
906 ibuf += sizeof( did );
907 if (NULL == ( dir = dirlookup( vol, did )) ) {
911 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
912 return get_afp_errno(AFPERR_NOOBJ);
915 return ad_rmvcomment(vol, s_path);