2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
20 #include <sys/syslog.h>
21 #include <sys/types.h>
23 #include <sys/param.h>
26 #include <netatalk/endian.h>
27 #include <atalk/adouble.h>
28 #include <atalk/afp.h>
29 #include <atalk/util.h>
30 #include <atalk/cnid.h>
32 #include "directory.h"
40 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
41 * field bytes subfield bytes
44 * ioFlFndrInfo 16 -> type 4 type field
45 * creator 4 creator field
46 * flags 2 finder flags:
48 * location 4 location in window
49 * folder 2 window that contains file
51 * ioFlXFndrInfo 16 -> iconID 2 icon id
53 * script 1 script system
55 * commentID 2 comment id
56 * putawayID 4 home directory id
59 const u_char ufinderi[] = {
60 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
61 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0
66 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
75 struct stat hst, lst, *lstp;
76 struct adouble ad, *adp;
79 char *data, *nameoff = NULL, *upath;
80 int bit = 0, isad = 1, aint;
82 u_char achar, fdType[4];
84 upath = mtoupath(vol, path);
85 if ((of = of_findname(vol, curdir, path))) {
88 memset(&ad, 0, sizeof(ad));
92 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
94 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
95 syslog( LOG_ERR, "getfilparams fstat: %m" );
99 while ( bitmap != 0 ) {
100 while (( bitmap & 1 ) == 0 ) {
108 ad_getattr(adp, &ashort);
109 } else if (*upath == '.') {
110 ashort = htons(ATTRBIT_INVISIBLE);
113 memcpy(data, &ashort, sizeof( ashort ));
114 data += sizeof( u_short );
118 memcpy(data, &dir->d_did, sizeof( int ));
119 data += sizeof( int );
123 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
124 aint = AD_DATE_FROM_UNIX(st->st_mtime);
125 memcpy(data, &aint, sizeof( aint ));
126 data += sizeof( aint );
130 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
131 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
132 (hst.st_mtime < st->st_mtime)) {
133 aint = AD_DATE_FROM_UNIX(st->st_mtime);
136 aint = AD_DATE_FROM_UNIX(st->st_mtime);
138 memcpy(data, &aint, sizeof( int ));
139 data += sizeof( int );
143 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
144 aint = AD_DATE_START;
145 memcpy(data, &aint, sizeof( int ));
146 data += sizeof( int );
151 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
153 memcpy(data, ufinderi, 32);
154 if (*upath == '.') { /* make it invisible */
155 ashort = htons(FINDERINFO_INVISIBLE);
156 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
160 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
161 ufinderi, 8 ) == 0)) &&
162 (em = getextmap( path ))) {
163 memcpy(data, em->em_type, sizeof( em->em_type ));
164 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
171 data += sizeof( u_int16_t );
175 memset(data, 0, sizeof(u_int16_t));
176 data += sizeof( u_int16_t );
180 #if AD_VERSION > AD_VERSION1
181 /* use the CNID database if we're using AD v2 */
183 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
187 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
188 strlen(upath), aint))) {
191 * What a fucking mess. First thing: DID and FNUMs are
192 * in the same space for purposes of enumerate (and several
193 * other wierd places). While we consider this Apple's bug,
194 * this is the work-around: In order to maintain constant and
195 * unique DIDs and FNUMs, we monotonically generate the DIDs
196 * during the session, and derive the FNUMs from the filesystem.
197 * Since the DIDs are small, we insure that the FNUMs are fairly
198 * large by setting thier high bits to the device number.
200 * AFS already does something very similar to this for the
201 * inode number, so we don't repeat the procedure.
204 * due to complaints over did's being non-persistent,
205 * here's the current hack to provide semi-persistent
207 * 1) we reserve the first bit for file ids.
208 * 2) the next 7 bits are for the device.
209 * 3) the remaining 24 bits are for the inode.
211 * both the inode and device information are actually hashes
212 * that are then truncated to the requisite bit length.
214 * it should be okay to use lstat to deal with symlinks.
216 lstp = (lstat(upath, &lst) < 0) ? st : &lst;
217 aint = htonl(CNID(lstp, 1));
218 #if AD_VERSION > AD_VERSION1
221 memcpy(data, &aint, sizeof( aint ));
222 data += sizeof( aint );
226 aint = htonl( st->st_size );
227 memcpy(data, &aint, sizeof( aint ));
228 data += sizeof( aint );
233 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
237 memcpy(data, &aint, sizeof( aint ));
238 data += sizeof( aint );
241 /* Current client needs ProDOS info block for this file.
242 Use simple heuristic and let the Mac "type" string tell
243 us what the PD file code should be. Everything gets a
244 subtype of 0x0000 unless the original value was hashed
245 to "pXYZ" when we created it. See IA, Ver 2.
247 case FILPBIT_PDINFO :
249 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
251 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
255 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
259 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
263 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
267 else if ( fdType[0] == 'p' ) {
269 ashort = (fdType[2] * 256) + fdType[3];
283 memcpy(data, &ashort, sizeof( ashort ));
284 data += sizeof( ashort );
285 memset(data, 0, sizeof( ashort ));
286 data += sizeof( ashort );
291 ad_close( adp, ADFLAGS_HF );
293 return( AFPERR_BITMAP );
299 ashort = htons( data - buf );
300 memcpy(nameoff, &ashort, sizeof( ashort ));
301 if ((aint = strlen( path )) > MACFILELEN)
304 memcpy(data, path, aint );
308 ad_close( adp, ADFLAGS_HF );
310 *buflen = data - buf;
314 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
317 int ibuflen, *rbuflen;
325 struct adouble ad, *adp;
330 int creatf, did, openf;
335 creatf = (unsigned char) *ibuf++;
337 memcpy(&vid, ibuf, sizeof( vid ));
338 ibuf += sizeof( vid );
340 if (( vol = getvolbyvid( vid )) == NULL ) {
341 return( AFPERR_PARAM );
344 if (vol->v_flags & AFPVOL_RO)
347 memcpy(&did, ibuf, sizeof( did));
348 ibuf += sizeof( did );
350 if (( dir = dirsearch( vol, did )) == NULL ) {
351 return( AFPERR_NOOBJ );
354 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
355 return( AFPERR_NOOBJ );
358 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
359 strpbrk(path, MSWINDOWS_BADCHARS))
362 upath = mtoupath(vol, path);
364 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
367 if (!validupath(vol, upath))
370 if ((of = of_findname(vol, curdir, path))) {
373 memset(&ad, 0, sizeof(ad));
377 /* on a hard create, fail if file exists and is open */
378 if ((stat(upath, &st) == 0) && of)
380 openf = O_RDWR|O_CREAT|O_TRUNC;
382 openf = O_RDWR|O_CREAT|O_EXCL;
385 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
386 openf, 0666, adp) < 0 ) {
389 return( AFPERR_EXIST );
391 return( AFPERR_ACCESS );
393 /* on noadouble volumes, just creating the data fork is ok */
394 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
395 goto createfile_done;
398 return( AFPERR_PARAM );
402 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
403 memcpy(ad_entry( adp, ADEID_NAME ), path,
404 ad_getentrylen( adp, ADEID_NAME ));
405 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
406 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
412 /* The below code is an experimental, untested, incomplete kludge which
413 provides better dropbox support. It should NOT be turned on yet unless
414 you are a developer who wants to try it out and fix it. */
415 if (stat(".", &sb) == -1)
416 syslog (LOG_ERR, "Error checking directory %s: %m", dir->d_name);
419 strcpy (adpath, "./.AppleDouble/");
420 strcat (adpath, path);
421 seteuid(0); /* Become root to change the owner of the file */
422 syslog (LOG_INFO, "Changing %s to uid=%d gid=%d", path, sb.st_uid, sb.st_gid);
423 if (chown(path, sb.st_uid, -1)==-1)
424 syslog (LOG_ERR, "Error changing permissions: %m");
425 if (chown(adpath, sb.st_uid, -1)==-1)
426 syslog (LOG_ERR, "Error changing AppleDouble permissions: %m");
427 syslog (LOG_INFO, "Changing afpd owner back to %d", uid);
428 seteuid(uid); /* Restore process ownership to normal */
433 setvoltime(obj, vol );
437 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
440 int ibuflen, *rbuflen;
446 u_int16_t vid, bitmap;
451 memcpy(&vid, ibuf, sizeof( vid ));
452 ibuf += sizeof( vid );
453 if (( vol = getvolbyvid( vid )) == NULL ) {
454 return( AFPERR_PARAM );
457 if (vol->v_flags & AFPVOL_RO)
460 memcpy(&did, ibuf, sizeof( did ));
461 ibuf += sizeof( did );
462 if (( dir = dirsearch( vol, did )) == NULL ) {
463 return( AFPERR_NOOBJ );
466 memcpy(&bitmap, ibuf, sizeof( bitmap ));
467 bitmap = ntohs( bitmap );
468 ibuf += sizeof( bitmap );
470 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
471 return( AFPERR_NOOBJ );
474 if ((u_long)ibuf & 1 ) {
478 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
479 setvoltime(obj, vol );
486 int setfilparams(vol, path, bitmap, buf )
491 struct adouble ad, *adp;
494 int bit = 0, isad = 1, err = AFP_OK;
496 u_char achar, *fdType, xyy[4];
497 u_int16_t ashort, bshort;
501 upath = mtoupath(vol, path);
502 if ((of = of_findname(vol, curdir, path))) {
505 memset(&ad, 0, sizeof(ad));
508 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
509 O_RDWR|O_CREAT, 0666, adp) < 0) {
510 /* for some things, we don't need an adouble header */
511 if (bitmap & ~(1<<FILPBIT_MDATE)) {
512 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
515 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
516 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
517 memcpy(ad_entry( adp, ADEID_NAME ), path,
518 ad_getentrylen( adp, ADEID_NAME ));
521 while ( bitmap != 0 ) {
522 while (( bitmap & 1 ) == 0 ) {
529 memcpy(&ashort, buf, sizeof( ashort ));
530 ad_getattr(adp, &bshort);
531 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
532 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
536 ad_setattr(adp, bshort);
537 buf += sizeof( ashort );
541 memcpy(&aint, buf, sizeof(aint));
542 ad_setdate(adp, AD_DATE_CREATE, aint);
543 buf += sizeof( aint );
547 memcpy(&aint, buf, sizeof( aint ));
549 ad_setdate(adp, AD_DATE_MODIFY, aint);
550 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
552 buf += sizeof( aint );
556 memcpy(&aint, buf, sizeof(aint));
557 ad_setdate(adp, AD_DATE_BACKUP, aint);
558 buf += sizeof( aint );
562 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
563 && (em = getextmap( path )) &&
564 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
565 (memcmp(buf + 4, em->em_creator,
566 sizeof( em->em_creator )) == 0)) {
567 memcpy(buf, ufinderi, 8 );
569 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
573 /* Client needs to set the ProDOS file info for this file.
574 Use defined strings for the simple cases, and convert
575 all else into pXYY per Inside Appletalk. Always set
576 the creator as "pdos". <shirsch@ibm.net> */
577 case FILPBIT_PDINFO :
580 memcpy(&ashort, buf, sizeof( ashort ));
581 ashort = ntohs( ashort );
584 switch ( (unsigned int) achar )
587 fdType = ( u_char *) "TEXT";
591 fdType = ( u_char *) "PSYS";
595 fdType = ( u_char *) "PS16";
599 fdType = ( u_char *) "BINA";
603 xyy[0] = ( u_char ) 'p';
605 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
606 xyy[3] = ( u_char ) ashort & 0xff;
611 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
612 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
618 goto setfilparam_done;
627 ad_flush( adp, ADFLAGS_HF );
628 ad_close( adp, ADFLAGS_HF );
634 * renamefile and copyfile take the old and new unix pathnames
635 * and the new mac name.
636 * NOTE: if we have to copy a file instead of renaming it, locks
639 int renamefile(src, dst, newname, noadouble )
640 char *src, *dst, *newname;
644 char adsrc[ MAXPATHLEN + 1];
648 * Note that this is only checking the existance of the data file,
649 * not the header file. The thinking is that if the data file doesn't
650 * exist, but the header file does, the right thing to do is remove
651 * the data file silently.
654 /* existence check moved to afp_moveandrename */
656 if ( rename( src, dst ) < 0 ) {
659 return( AFPERR_NOOBJ );
662 return( AFPERR_ACCESS );
665 case EXDEV : /* Cross device move -- try copy */
666 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
670 return deletefile( src );
672 return( AFPERR_PARAM );
676 strcpy( adsrc, ad_path( src, 0 ));
679 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
684 /* check for a source appledouble header. if it exists, make
685 * a dest appledouble directory and do the rename again. */
686 memset(&ad, 0, sizeof(ad));
687 if (rc || stat(adsrc, &st) ||
688 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
691 ad_close(&ad, ADFLAGS_HF);
695 return( AFPERR_ACCESS );
699 return( AFPERR_PARAM );
703 memset(&ad, 0, sizeof(ad));
704 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
707 return( AFPERR_NOOBJ );
709 return( AFPERR_ACCESS );
713 return( AFPERR_PARAM );
717 len = strlen( newname );
718 ad_setentrylen( &ad, ADEID_NAME, len );
719 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
720 ad_flush( &ad, ADFLAGS_HF );
721 ad_close( &ad, ADFLAGS_HF );
726 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
729 int ibuflen, *rbuflen;
733 char *newname, *path, *p;
734 u_int32_t sdid, ddid;
736 u_int16_t svid, dvid;
741 memcpy(&svid, ibuf, sizeof( svid ));
742 ibuf += sizeof( svid );
743 if (( vol = getvolbyvid( svid )) == NULL ) {
744 return( AFPERR_PARAM );
747 memcpy(&sdid, ibuf, sizeof( sdid ));
748 ibuf += sizeof( sdid );
749 if (( dir = dirsearch( vol, sdid )) == NULL ) {
750 return( AFPERR_PARAM );
753 memcpy(&dvid, ibuf, sizeof( dvid ));
754 ibuf += sizeof( dvid );
755 memcpy(&ddid, ibuf, sizeof( ddid ));
756 ibuf += sizeof( ddid );
758 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
759 return( AFPERR_NOOBJ );
761 if ( *path == '\0' ) {
762 return( AFPERR_BADTYPE );
765 /* don't allow copies when the file is open.
766 * XXX: the spec only calls for read/deny write access.
767 * however, copyfile doesn't have any of that info,
768 * and locks need to stay coherent. as a result,
769 * we just balk if the file is opened already. */
770 if (of_findname(vol, curdir, path))
771 return AFPERR_DENYCONF;
773 newname = obj->newtmp;
774 strcpy( newname, path );
776 p = ctoupath( vol, curdir, newname );
778 if (( vol = getvolbyvid( dvid )) == NULL ) {
779 return( AFPERR_PARAM );
782 if (vol->v_flags & AFPVOL_RO)
785 if (( dir = dirsearch( vol, ddid )) == NULL ) {
786 return( AFPERR_PARAM );
789 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
790 return( AFPERR_NOOBJ );
792 if ( *path != '\0' ) {
793 return( AFPERR_BADTYPE );
796 /* one of the handful of places that knows about the path type */
797 if ( *ibuf++ != 2 ) {
798 return( AFPERR_PARAM );
800 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
801 strncpy( newname, ibuf, plen );
802 newname[ plen ] = '\0';
805 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
806 vol_noadouble(vol))) < 0 ) {
810 setvoltime(obj, vol );
815 static __inline__ int copy_all(const int dfd, const void *buf,
821 if ((cc = write(dfd, buf, buflen)) < 0) {
841 /* XXX: this needs to use ad_open and ad_lock. so, we need to
842 * pass in vol and path */
843 int copyfile(src, dst, newname, noadouble )
844 char *src, *dst, *newname;
850 int sfd, dfd, len, err = AFP_OK;
855 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
858 break; /* just copy the data fork */
860 return( AFPERR_ACCESS );
862 return( AFPERR_PARAM );
865 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
866 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
870 return( AFPERR_NOOBJ );
872 return( AFPERR_ACCESS );
876 return( AFPERR_PARAM );
881 #ifdef SENDFILE_FLAVOR_LINUX
882 if (fstat(sfd, &st) == 0) {
883 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
897 goto copyheader_done;
901 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
908 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
916 unlink(ad_path(dst, ADFLAGS_HF));
922 /* data fork copying */
923 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
926 return( AFPERR_NOOBJ );
928 return( AFPERR_ACCESS );
930 return( AFPERR_PARAM );
934 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
938 return( AFPERR_NOOBJ );
940 return( AFPERR_ACCESS );
944 return( AFPERR_PARAM );
948 #ifdef SENDFILE_FLAVOR_LINUX
949 if (fstat(sfd, &st) == 0) {
950 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
966 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
974 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
983 unlink(ad_path(dst, ADFLAGS_HF));
989 memset(&ad, 0, sizeof(ad));
990 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
994 return noadouble ? AFP_OK : AFPERR_NOOBJ;
996 return( AFPERR_ACCESS );
1000 return( AFPERR_PARAM );
1004 len = strlen( newname );
1005 ad_setentrylen( &ad, ADEID_NAME, len );
1006 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1007 ad_flush( &ad, ADFLAGS_HF );
1008 ad_close( &ad, ADFLAGS_HF );
1015 int deletefile( file )
1019 int adflags, err = AFP_OK;
1021 /* try to open both at once */
1022 adflags = ADFLAGS_DF|ADFLAGS_HF;
1023 memset(&ad, 0, sizeof(ad));
1024 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1027 adflags = ADFLAGS_DF;
1028 /* that failed. now try to open just the data fork */
1029 memset(&ad, 0, sizeof(ad));
1030 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1033 return AFPERR_NOOBJ;
1035 return AFPERR_ACCESS;
1037 return AFPERR_PARAM;
1043 return( AFPERR_ACCESS );
1045 return AFPERR_VLOCK;
1047 return( AFPERR_PARAM );
1051 if ((adflags & ADFLAGS_HF) &&
1052 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1053 ad_close( &ad, adflags );
1054 return( AFPERR_BUSY );
1057 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1062 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1066 err = AFPERR_ACCESS;
1079 if ( unlink( file ) < 0 ) {
1083 err = AFPERR_ACCESS;
1097 if (adflags & ADFLAGS_HF)
1098 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1099 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1100 ad_close( &ad, adflags );
1105 #if AD_VERSION > AD_VERSION1
1106 /* return a file id */
1107 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1110 int ibuflen, *rbuflen;
1125 memcpy(&vid, ibuf, sizeof(vid));
1126 ibuf += sizeof(vid);
1128 if (( vol = getvolbyvid( vid )) == NULL ) {
1129 return( AFPERR_PARAM);
1132 if (vol->v_flags & AFPVOL_RO)
1133 return AFPERR_VLOCK;
1135 memcpy(&did, ibuf, sizeof( did ));
1136 ibuf += sizeof(did);
1138 if (( dir = dirsearch( vol, did )) == NULL ) {
1139 return( AFPERR_PARAM );
1142 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1143 return( AFPERR_PARAM );
1146 if ( *path == '\0' ) {
1147 return( AFPERR_BADTYPE );
1150 upath = mtoupath(vol, path);
1151 if (stat(upath, &st) < 0) {
1155 return AFPERR_ACCESS;
1157 return AFPERR_NOOBJ;
1159 return AFPERR_PARAM;
1163 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1164 memcpy(rbuf, &id, sizeof(id));
1165 *rbuflen = sizeof(id);
1166 return AFPERR_EXISTID;
1169 memset(&ad, 0, sizeof(ad));
1170 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1173 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1174 ad_close(upath, ADFLAGS_HF);
1177 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1178 memcpy(rbuf, &id, sizeof(id));
1179 *rbuflen = sizeof(id);
1185 return AFPERR_VLOCK;
1189 return AFPERR_ACCESS;
1192 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1193 return AFPERR_PARAM;
1197 /* resolve a file id */
1198 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1201 int ibuflen, *rbuflen;
1209 u_int16_t vid, bitmap;
1215 memcpy(&vid, ibuf, sizeof(vid));
1216 ibuf += sizeof(vid);
1218 if (( vol = getvolbyvid( vid )) == NULL ) {
1219 return( AFPERR_PARAM);
1222 memcpy(&id, ibuf, sizeof( id ));
1225 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1226 return AFPERR_BADID;
1229 if (( dir = dirsearch( vol, id )) == NULL ) {
1230 return( AFPERR_PARAM );
1233 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1237 return AFPERR_ACCESS;
1241 return AFPERR_PARAM;
1245 /* directories are bad */
1246 if (S_ISDIR(st.st_mode))
1247 return AFPERR_BADTYPE;
1249 memcpy(&bitmap, ibuf, sizeof(bitmap));
1250 bitmap = ntohs( bitmap );
1252 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1253 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1256 *rbuflen = buflen + sizeof(bitmap);
1257 memcpy(rbuf, ibuf, sizeof(bitmap));
1261 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1264 int ibuflen, *rbuflen;
1278 memcpy(&vid, ibuf, sizeof(vid));
1279 ibuf += sizeof(vid);
1281 if (( vol = getvolbyvid( vid )) == NULL ) {
1282 return( AFPERR_PARAM);
1285 if (vol->v_flags & AFPVOL_RO)
1286 return AFPERR_VLOCK;
1288 memcpy(&id, ibuf, sizeof( id ));
1291 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1295 if (( dir = dirsearch( vol, id )) == NULL ) {
1296 return( AFPERR_PARAM );
1300 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1304 return AFPERR_ACCESS;
1306 /* still try to delete the id */
1310 return AFPERR_PARAM;
1314 /* directories are bad */
1315 if (S_ISDIR(st.st_mode))
1316 return AFPERR_BADTYPE;
1318 if (cnid_delete(vol->v_db, id)) {
1321 return AFPERR_VLOCK;
1324 return AFPERR_ACCESS;
1326 return AFPERR_PARAM;
1334 #define APPLETEMP ".AppleTempXXXXXX"
1335 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1338 int ibuflen, *rbuflen;
1340 struct stat srcst, destst;
1342 struct dir *dir, *sdir;
1343 char *spath, temp[17], *path, *p;
1344 char *supath, *upath;
1346 #if AD_VERSION > AD_VERSION1
1356 memcpy(&vid, ibuf, sizeof(vid));
1357 ibuf += sizeof(vid);
1359 if (( vol = getvolbyvid( vid )) == NULL ) {
1360 return( AFPERR_PARAM);
1363 if (vol->v_flags & AFPVOL_RO)
1364 return AFPERR_VLOCK;
1366 /* source and destination dids */
1367 memcpy(&sid, ibuf, sizeof(sid));
1368 ibuf += sizeof(sid);
1369 memcpy(&did, ibuf, sizeof(did));
1370 ibuf += sizeof(did);
1373 if ((dir = dirsearch( vol, sid )) == NULL ) {
1374 return( AFPERR_PARAM );
1377 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1378 return( AFPERR_PARAM );
1381 if ( *path == '\0' ) {
1382 return( AFPERR_BADTYPE );
1385 upath = mtoupath(vol, path);
1386 if (stat(upath, &srcst) < 0) {
1392 return AFPERR_ACCESS;
1394 return AFPERR_PARAM;
1398 /* save some stuff */
1400 spath = obj->oldtmp;
1401 supath = obj->newtmp;
1402 strcpy(spath, path);
1403 strcpy(supath, upath); /* this is for the cnid changing */
1404 p = ctoupath( vol, sdir, spath);
1406 /* look for the source cnid. if it doesn't exist, don't worry about
1408 #if AD_VERSION > AD_VERSION1
1409 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1410 slen = strlen(supath));
1413 if (( dir = dirsearch( vol, did )) == NULL ) {
1414 return( AFPERR_PARAM );
1417 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1418 return( AFPERR_PARAM );
1421 if ( *path == '\0' ) {
1422 return( AFPERR_BADTYPE );
1425 /* FPExchangeFiles is the only call that can return the SameObj
1427 if ((curdir == sdir) && strcmp(spath, path) == 0)
1428 return AFPERR_SAMEOBJ;
1430 upath = mtoupath(vol, path);
1431 if (stat(upath, &destst) < 0) {
1437 return AFPERR_ACCESS;
1439 return AFPERR_PARAM;
1443 #if AD_VERSION > AD_VERSION1
1444 /* look for destination id. */
1445 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1446 dlen = strlen(upath));
1449 /* construct a temp name.
1450 * NOTE: the temp file will be in the dest file's directory. it
1451 * will also be inaccessible from AFP. */
1452 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1456 /* now, quickly rename the file. we error if we can't. */
1457 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1458 goto err_exchangefile;
1459 of_rename(vol, sdir, spath, curdir, temp);
1461 /* rename destination to source */
1462 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1463 goto err_src_to_tmp;
1464 of_rename(vol, curdir, path, sdir, spath);
1466 /* rename temp to destination */
1467 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1468 goto err_dest_to_src;
1469 of_rename(vol, curdir, temp, curdir, path);
1471 #if AD_VERSION > AD_VERSION1
1472 /* id's need switching. src -> dest and dest -> src. */
1473 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1474 upath, dlen) < 0)) {
1478 err = AFPERR_ACCESS;
1482 goto err_temp_to_dest;
1485 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1486 supath, slen) < 0)) {
1490 err = AFPERR_ACCESS;
1496 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1497 goto err_temp_to_dest;
1503 /* all this stuff is so that we can unwind a failed operation
1506 /* rename dest to temp */
1507 renamefile(upath, temp, temp, vol_noadouble(vol));
1508 of_rename(vol, curdir, upath, curdir, temp);
1511 /* rename source back to dest */
1512 renamefile(p, upath, path, vol_noadouble(vol));
1513 of_rename(vol, sdir, spath, curdir, path);
1516 /* rename temp back to source */
1517 renamefile(temp, p, spath, vol_noadouble(vol));
1518 of_rename(vol, curdir, temp, sdir, spath);