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 dsi_writeinit(obj->dsi, rbuf, buflen);
208 dsi_writeflush(obj->dsi);
214 iovcnt = dsi_writeinit(dsi, rbuf, buflen);
216 /* add headers at end of file */
217 if ((cc == 0) && (write(si.sdt_fd, imh, sizeof(imh)) < 0)) {
218 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
223 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
224 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
229 while ((iovcnt = dsi_write(dsi, rbuf, buflen))) {
230 if ((cc = write(si.sdt_fd, rbuf, iovcnt)) < 0) {
231 LOG(log_error, logtype_afpd, "afp_addicon(%s): write: %s", icon_dtfile(vol, fcreator), strerror(errno));
242 static const u_char utag[] = { 0, 0, 0, 0 };
243 static const u_char ucreator[] = { 0, 0, 0, 0 };/* { 'U', 'N', 'I', 'X' };*/
244 static const u_char utype[] = { 0, 0, 0, 0 };/* { 'T', 'E', 'X', 'T' };*/
245 static const short usize = 256;
248 static const u_char uicon[] = {
249 0x1F, 0xFF, 0xFC, 0x00, 0x10, 0x00, 0x06, 0x00,
250 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x80,
251 0x10, 0x00, 0x04, 0x40, 0x10, 0x00, 0x04, 0x20,
252 0x10, 0x00, 0x07, 0xF0, 0x10, 0x00, 0x00, 0x10,
253 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,
254 0x10, 0x00, 0x00, 0x10, 0x10, 0x80, 0x02, 0x10,
255 0x11, 0x80, 0x03, 0x10, 0x12, 0x80, 0x02, 0x90,
256 0x12, 0x80, 0x02, 0x90, 0x14, 0x80, 0x02, 0x50,
257 0x14, 0x87, 0xC2, 0x50, 0x14, 0x58, 0x34, 0x50,
258 0x14, 0x20, 0x08, 0x50, 0x12, 0x16, 0xD0, 0x90,
259 0x11, 0x01, 0x01, 0x10, 0x12, 0x80, 0x02, 0x90,
260 0x12, 0x9C, 0x72, 0x90, 0x14, 0x22, 0x88, 0x50,
261 0x14, 0x41, 0x04, 0x50, 0x14, 0x49, 0x24, 0x50,
262 0x14, 0x55, 0x54, 0x50, 0x14, 0x5D, 0x74, 0x50,
263 0x14, 0x5D, 0x74, 0x50, 0x12, 0x49, 0x24, 0x90,
264 0x12, 0x22, 0x88, 0x90, 0x1F, 0xFF, 0xFF, 0xF0,
265 0x1F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00,
266 0x1F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80,
267 0x1F, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xE0,
268 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
269 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
270 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
271 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
272 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
273 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
274 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
275 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0,
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,
284 int afp_geticoninfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
287 unsigned char fcreator[ 4 ], ih[ 12 ];
288 uint16_t vid, iindex, bsize;
293 memcpy( &vid, ibuf, sizeof( vid ));
294 ibuf += sizeof( vid );
295 if (NULL == ( vol = getvolbyvid( vid )) ) {
296 return( AFPERR_PARAM );
299 memcpy( fcreator, ibuf, sizeof( fcreator ));
300 ibuf += sizeof( fcreator );
301 memcpy( &iindex, ibuf, sizeof( iindex ));
302 iindex = ntohs( iindex );
304 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 ) {
306 return( AFPERR_NOITEM );
308 memcpy( ih, utag, sizeof( utag ));
309 memcpy( ih + sizeof( utag ), utype, sizeof( utype ));
310 *( ih + sizeof( utag ) + sizeof( utype )) = 1;
311 *( ih + sizeof( utag ) + sizeof( utype ) + 1 ) = 0;
312 memcpy( ih + sizeof( utag ) + sizeof( utype ) + 2, &usize,
314 memcpy( rbuf, ih, sizeof( ih ));
315 *rbuflen = sizeof( ih );
319 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
320 return( AFPERR_NOITEM );
323 if ( iindex < si.sdt_index ) {
324 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
325 return( AFPERR_PARAM );
331 * Position to the correct spot.
334 if ( read( si.sdt_fd, ih, sizeof( ih )) != sizeof( ih )) {
337 return( AFPERR_NOITEM );
339 memcpy( &bsize, ih + 10, sizeof( bsize ));
340 bsize = ntohs(bsize);
341 if ( lseek( si.sdt_fd, (off_t) bsize, SEEK_CUR ) < 0 ) {
342 LOG(log_error, logtype_afpd, "afp_iconinfo(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
343 return( AFPERR_PARAM );
345 if ( si.sdt_index == iindex ) {
346 memcpy( rbuf, ih, sizeof( ih ));
347 *rbuflen = sizeof( ih );
355 int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
360 u_char fcreator[ 4 ], ftype[ 4 ], itype, ih[ 12 ];
361 uint16_t vid, bsize, rsize;
367 memcpy( &vid, ibuf, sizeof( vid ));
368 ibuf += sizeof( vid );
369 if (NULL == ( vol = getvolbyvid( vid )) ) {
370 return( AFPERR_PARAM );
373 memcpy( fcreator, ibuf, sizeof( fcreator ));
374 ibuf += sizeof( fcreator );
375 memcpy( ftype, ibuf, sizeof( ftype ));
376 ibuf += sizeof( ftype );
377 itype = (unsigned char) *ibuf++;
379 memcpy( &bsize, ibuf, sizeof( bsize ));
380 bsize = ntohs( bsize );
383 if ( memcmp( fcreator, ucreator, sizeof( ucreator )) == 0 &&
384 memcmp( ftype, utype, sizeof( utype )) == 0 &&
387 memcpy( rbuf, uicon, bsize);
393 if ( iconopen( vol, fcreator, O_RDONLY, 0 ) < 0) {
394 return( AFPERR_NOITEM );
397 if ( lseek( si.sdt_fd, (off_t) 0L, SEEK_SET ) < 0 ) {
400 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno));
401 return( AFPERR_PARAM );
406 while (( rc = read( si.sdt_fd, ih, sizeof( ih ))) > 0 ) {
408 offset += sizeof(ih);
409 if ( memcmp( ih + sizeof( int ), ftype, sizeof( ftype )) == 0 &&
410 *(ih + sizeof( int ) + sizeof( ftype )) == itype ) {
413 memcpy( &rsize, ih + 10, sizeof( rsize ));
414 rsize = ntohs( rsize );
415 if ( lseek( si.sdt_fd, (off_t) rsize, SEEK_CUR ) < 0 ) {
416 LOG(log_error, logtype_afpd, "afp_geticon(%s): lseek: %s", icon_dtfile(vol, fcreator), strerror(errno) );
417 return( AFPERR_PARAM );
423 LOG(log_error, logtype_afpd, "afp_geticon(%s): read: %s", icon_dtfile(vol, fcreator), strerror(errno));
424 return( AFPERR_PARAM );
428 return( AFPERR_NOITEM );
431 memcpy( &rsize, ih + 10, sizeof( rsize ));
432 rsize = ntohs( rsize );
433 #define min(a,b) ((a)<(b)?(a):(b))
434 rc = min( bsize, rsize );
441 size = (fstat(si.sdt_fd, &st) < 0) ? 0 : st.st_size;
442 if (size < rc + offset) {
446 if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
450 /* do to the streaming nature, we have to exit if we encounter
451 * a problem. much confusion results otherwise. */
452 while (*rbuflen > 0) {
454 if (!obj->options.flags & OPTION_DEBUG) {
455 if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
458 case EINVAL: /* there's no guarantee that all fs support sendfile */
470 buflen = read(si.sdt_fd, rbuf, *rbuflen);
474 /* dsi_read() also returns buffer size of next allocation */
475 buflen = dsi_read(dsi, rbuf, buflen); /* send it off */
486 LOG(log_error, logtype_afpd, "afp_geticon(%s): %s", icon_dtfile(vol, fcreator), strerror(errno));
488 obj->exit(EXITERR_SYS);
492 if ( read( si.sdt_fd, rbuf, rc ) < rc ) {
493 return( AFPERR_PARAM );
500 /* ---------------------- */
501 static const char hexdig[] = "0123456789abcdef";
502 char *dtfile(const struct vol *vol, u_char creator[], char *ext )
504 static char path[ MAXPATHLEN + 1];
508 strcpy( path, vol->v_path );
509 strcat( path, "/.AppleDesktop/" );
510 for ( p = path; *p != '\0'; p++ )
513 if ( !isprint( creator[ 0 ] ) || creator[ 0 ] == '/' ) {
514 *p++ = hexdig[ ( creator[ 0 ] & 0xf0 ) >> 4 ];
515 *p++ = hexdig[ creator[ 0 ] & 0x0f ];
522 for ( i = 0; i < sizeof( CreatorType ); i++ ) {
523 if ( !isprint( creator[ i ] ) || creator[ i ] == '/' ) {
524 *p++ = hexdig[ ( creator[ i ] & 0xf0 ) >> 4 ];
525 *p++ = hexdig[ creator[ i ] & 0x0f ];
536 /* ---------------------------
537 * mpath is only a filename
538 * did filename parent directory ID.
541 char *mtoupath(const struct vol *vol, char *mpath, cnid_t did, int utf8)
543 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
549 if ( *mpath == '\0' ) {
554 /* set conversion flags */
555 flags = vol->v_mtou_flags;
557 m = demangle(vol, mpath, did);
568 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)) ) {
569 LOG(log_error, logtype_afpd, "conversion from %s to %s for %s failed.", (utf8)?"UTF8-MAC":vol->v_maccodepage, vol->v_volcodepage, mpath);
574 LOG(log_debug9, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath);
582 char *utompath(const struct vol *vol, char *upath, cnid_t id, int utf8)
584 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
590 outlen = strlen(upath);
592 flags = vol->v_utom_flags;
596 /* convert charsets */
597 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)) ) {
598 LOG(log_error, logtype_afpd, "Conversion from %s to %s for %s (%u) failed.", vol->v_volcodepage, vol->v_maccodepage, u, ntohl(id));
602 flags = !!(flags & CONV_REQMANGLE);
607 m = mangle(vol, mpath, outlen, upath, id, flags);
610 LOG(log_debug9, logtype_afpd, "utompath: '%s':'%s':'%2.2X'", upath, m, ntohl(id));
616 m = mangle(vol, u, strlen(u), upath, id, (utf8)?3:1);
620 /* ------------------------- */
621 static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
627 struct adouble ad, *adp;
629 clen = (u_char)*ibuf++;
630 clen = min( clen, 199 );
632 upath = path->u_name;
633 if (check_access(upath, OPENACC_WR ) < 0) {
634 return AFPERR_ACCESS;
637 isadir = path_isadir(path);
638 if (isadir || !(of = of_findname(path))) {
644 if (ad_open(adp, upath,
645 ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0) | ADFLAGS_CREATE | ADFLAGS_RDWR,
647 return( AFPERR_ACCESS );
650 if (ad_getentryoff(adp, ADEID_COMMENT)) {
651 if ( (ad_get_MD_flags( adp ) & O_CREAT) ) {
652 if ( *path->m_name == '\0' ) {
653 name = (char *)curdir->d_m_name->data;
657 ad_setname(adp, name);
659 ad_setentrylen( adp, ADEID_COMMENT, clen );
660 memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
663 ad_close(adp, ADFLAGS_HF);
667 /* ----------------------------- */
668 int afp_addcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
679 memcpy( &vid, ibuf, sizeof( vid ));
680 ibuf += sizeof( vid );
681 if (NULL == ( vol = getvolbyvid( vid )) ) {
682 return( AFPERR_PARAM );
685 memcpy( &did, ibuf, sizeof( did ));
686 ibuf += sizeof( did );
687 if (NULL == ( dir = dirlookup( vol, did )) ) {
691 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
692 return get_afp_errno(AFPERR_NOOBJ);
695 if ((u_long)ibuf & 1 ) {
699 return ad_addcomment(vol, path, ibuf);
702 /* -------------------- */
703 static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t *rbuflen)
705 struct adouble ad, *adp;
711 upath = path->u_name;
712 isadir = path_isadir(path);
713 if (isadir || !(of = of_findname(path))) {
719 if ( ad_metadata( upath, ((isadir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
720 return( AFPERR_NOITEM );
723 if (!ad_getentryoff(adp, ADEID_COMMENT)) {
724 ad_close(adp, ADFLAGS_HF);
725 return AFPERR_NOITEM;
728 * Make sure the AD file is not bogus.
730 if ( ad_getentrylen( adp, ADEID_COMMENT ) <= 0 ||
731 ad_getentrylen( adp, ADEID_COMMENT ) > 199 ) {
732 ad_close(adp, ADFLAGS_HF);
733 return( AFPERR_NOITEM );
736 clen = min( ad_getentrylen( adp, ADEID_COMMENT ), 128 ); /* OSX only use 128, greater kill Adobe CS2 */
738 memcpy( rbuf, ad_entry( adp, ADEID_COMMENT ), clen);
740 ad_close(adp, ADFLAGS_HF);
745 /* -------------------- */
746 int afp_getcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
757 memcpy( &vid, ibuf, sizeof( vid ));
758 ibuf += sizeof( vid );
759 if (NULL == ( vol = getvolbyvid( vid )) ) {
760 return( AFPERR_PARAM );
763 memcpy( &did, ibuf, sizeof( did ));
764 ibuf += sizeof( did );
765 if (NULL == ( dir = dirlookup( vol, did )) ) {
769 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
770 return get_afp_errno(AFPERR_NOOBJ);
773 return ad_getcomment(vol, s_path, rbuf, rbuflen);
776 /* ----------------------- */
777 static int ad_rmvcomment(struct vol *vol, struct path *path)
779 struct adouble ad, *adp;
784 upath = path->u_name;
785 if (check_access(upath, OPENACC_WR ) < 0) {
786 return AFPERR_ACCESS;
789 isadir = path_isadir(path);
790 if (isadir || !(of = of_findname(path))) {
796 if ( ad_open(adp, upath, ADFLAGS_HF | ADFLAGS_RDWR | ((isadir) ? ADFLAGS_DIR : 0)) < 0 ) {
799 return( AFPERR_NOITEM );
801 return( AFPERR_ACCESS );
803 return( AFPERR_PARAM );
807 if (ad_getentryoff(adp, ADEID_COMMENT)) {
808 ad_setentrylen( adp, ADEID_COMMENT, 0 );
811 ad_close(adp, ADFLAGS_HF);
815 /* ----------------------- */
816 int afp_rmvcomment(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
827 memcpy( &vid, ibuf, sizeof( vid ));
828 ibuf += sizeof( vid );
829 if (NULL == ( vol = getvolbyvid( vid )) ) {
830 return( AFPERR_PARAM );
833 memcpy( &did, ibuf, sizeof( did ));
834 ibuf += sizeof( did );
835 if (NULL == ( dir = dirlookup( vol, did )) ) {
839 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
840 return get_afp_errno(AFPERR_NOOBJ);
843 return ad_rmvcomment(vol, s_path);