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 changes the way file ownership is determined in the name of
413 fixing dropboxes. It has known security problem. See the netatalk FAQ for
415 if (stat(".", &sb) == -1)
416 syslog (LOG_ERR, "Error checking directory %s: %m", dir->d_name);
419 if ( uid != sb.st_uid )
421 strcpy (adpath, "./.AppleDouble/");
422 strcat (adpath, mtoupath(vol, path));
423 seteuid(0); /* Become root to change the owner of the file */
424 if (chown(mtoupath(vol, path), sb.st_uid, sb.st_gid) < 0)
426 syslog (LOG_ERR, "Error changing owner/gid: %m");
429 /* In order to write information to the file, the Mac client needs
430 to be able to read from it too, so read bits have to be turned on.
431 Directory permissions remain unchanged */
433 if (chmod(mtoupath(vol,path),(st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
435 syslog (LOG_ERR, "Error adding file read permissions: %m");
438 else syslog (LOG_DEBUG, "Added S_IRGRP and S_IROTH: %m");
439 if (chown(adpath, sb.st_uid, sb.st_gid) < 0)
441 syslog (LOG_ERR, "Error changing AppleDouble owner/gid: %m");
444 if (chmod(adpath, (st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
446 syslog (LOG_ERR, "Error adding AD file read permissions: %m");
449 else syslog (LOG_DEBUG, "Added S_IRGRP and S_IROTH to AD: %m");
450 syslog (LOG_DEBUG, "Changing afpd owner back to %d", uid);
451 seteuid(uid); /* Restore process ownership to normal */
457 setvoltime(obj, vol );
461 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
464 int ibuflen, *rbuflen;
470 u_int16_t vid, bitmap;
475 memcpy(&vid, ibuf, sizeof( vid ));
476 ibuf += sizeof( vid );
477 if (( vol = getvolbyvid( vid )) == NULL ) {
478 return( AFPERR_PARAM );
481 if (vol->v_flags & AFPVOL_RO)
484 memcpy(&did, ibuf, sizeof( did ));
485 ibuf += sizeof( did );
486 if (( dir = dirsearch( vol, did )) == NULL ) {
487 return( AFPERR_NOOBJ );
490 memcpy(&bitmap, ibuf, sizeof( bitmap ));
491 bitmap = ntohs( bitmap );
492 ibuf += sizeof( bitmap );
494 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
495 return( AFPERR_NOOBJ );
498 if ((u_long)ibuf & 1 ) {
502 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
503 setvoltime(obj, vol );
510 int setfilparams(vol, path, bitmap, buf )
515 struct adouble ad, *adp;
518 int bit = 0, isad = 1, err = AFP_OK;
520 u_char achar, *fdType, xyy[4];
521 u_int16_t ashort, bshort;
525 upath = mtoupath(vol, path);
526 if ((of = of_findname(vol, curdir, path))) {
529 memset(&ad, 0, sizeof(ad));
532 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
533 O_RDWR|O_CREAT, 0666, adp) < 0) {
534 /* for some things, we don't need an adouble header */
535 if (bitmap & ~(1<<FILPBIT_MDATE)) {
536 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
539 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
540 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
541 memcpy(ad_entry( adp, ADEID_NAME ), path,
542 ad_getentrylen( adp, ADEID_NAME ));
545 while ( bitmap != 0 ) {
546 while (( bitmap & 1 ) == 0 ) {
553 memcpy(&ashort, buf, sizeof( ashort ));
554 ad_getattr(adp, &bshort);
555 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
556 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
560 ad_setattr(adp, bshort);
561 buf += sizeof( ashort );
565 memcpy(&aint, buf, sizeof(aint));
566 ad_setdate(adp, AD_DATE_CREATE, aint);
567 buf += sizeof( aint );
571 memcpy(&aint, buf, sizeof( aint ));
573 ad_setdate(adp, AD_DATE_MODIFY, aint);
574 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
576 buf += sizeof( aint );
580 memcpy(&aint, buf, sizeof(aint));
581 ad_setdate(adp, AD_DATE_BACKUP, aint);
582 buf += sizeof( aint );
586 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
587 && (em = getextmap( path )) &&
588 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
589 (memcmp(buf + 4, em->em_creator,
590 sizeof( em->em_creator )) == 0)) {
591 memcpy(buf, ufinderi, 8 );
593 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
597 /* Client needs to set the ProDOS file info for this file.
598 Use defined strings for the simple cases, and convert
599 all else into pXYY per Inside Appletalk. Always set
600 the creator as "pdos". <shirsch@ibm.net> */
601 case FILPBIT_PDINFO :
604 memcpy(&ashort, buf, sizeof( ashort ));
605 ashort = ntohs( ashort );
608 switch ( (unsigned int) achar )
611 fdType = ( u_char *) "TEXT";
615 fdType = ( u_char *) "PSYS";
619 fdType = ( u_char *) "PS16";
623 fdType = ( u_char *) "BINA";
627 xyy[0] = ( u_char ) 'p';
629 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
630 xyy[3] = ( u_char ) ashort & 0xff;
635 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
636 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
642 goto setfilparam_done;
651 ad_flush( adp, ADFLAGS_HF );
652 ad_close( adp, ADFLAGS_HF );
658 * renamefile and copyfile take the old and new unix pathnames
659 * and the new mac name.
660 * NOTE: if we have to copy a file instead of renaming it, locks
663 int renamefile(src, dst, newname, noadouble )
664 char *src, *dst, *newname;
668 char adsrc[ MAXPATHLEN + 1];
672 * Note that this is only checking the existance of the data file,
673 * not the header file. The thinking is that if the data file doesn't
674 * exist, but the header file does, the right thing to do is remove
675 * the data file silently.
678 /* existence check moved to afp_moveandrename */
680 if ( rename( src, dst ) < 0 ) {
683 return( AFPERR_NOOBJ );
686 return( AFPERR_ACCESS );
689 case EXDEV : /* Cross device move -- try copy */
690 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
694 return deletefile( src );
696 return( AFPERR_PARAM );
700 strcpy( adsrc, ad_path( src, 0 ));
703 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
708 /* check for a source appledouble header. if it exists, make
709 * a dest appledouble directory and do the rename again. */
710 memset(&ad, 0, sizeof(ad));
711 if (rc || stat(adsrc, &st) ||
712 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
715 ad_close(&ad, ADFLAGS_HF);
719 return( AFPERR_ACCESS );
723 return( AFPERR_PARAM );
727 memset(&ad, 0, sizeof(ad));
728 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
731 return( AFPERR_NOOBJ );
733 return( AFPERR_ACCESS );
737 return( AFPERR_PARAM );
741 len = strlen( newname );
742 ad_setentrylen( &ad, ADEID_NAME, len );
743 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
744 ad_flush( &ad, ADFLAGS_HF );
745 ad_close( &ad, ADFLAGS_HF );
750 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
753 int ibuflen, *rbuflen;
757 char *newname, *path, *p;
758 u_int32_t sdid, ddid;
760 u_int16_t svid, dvid;
765 memcpy(&svid, ibuf, sizeof( svid ));
766 ibuf += sizeof( svid );
767 if (( vol = getvolbyvid( svid )) == NULL ) {
768 return( AFPERR_PARAM );
771 memcpy(&sdid, ibuf, sizeof( sdid ));
772 ibuf += sizeof( sdid );
773 if (( dir = dirsearch( vol, sdid )) == NULL ) {
774 return( AFPERR_PARAM );
777 memcpy(&dvid, ibuf, sizeof( dvid ));
778 ibuf += sizeof( dvid );
779 memcpy(&ddid, ibuf, sizeof( ddid ));
780 ibuf += sizeof( ddid );
782 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
783 return( AFPERR_NOOBJ );
785 if ( *path == '\0' ) {
786 return( AFPERR_BADTYPE );
789 /* don't allow copies when the file is open.
790 * XXX: the spec only calls for read/deny write access.
791 * however, copyfile doesn't have any of that info,
792 * and locks need to stay coherent. as a result,
793 * we just balk if the file is opened already. */
794 if (of_findname(vol, curdir, path))
795 return AFPERR_DENYCONF;
797 newname = obj->newtmp;
798 strcpy( newname, path );
800 p = ctoupath( vol, curdir, newname );
802 if (( vol = getvolbyvid( dvid )) == NULL ) {
803 return( AFPERR_PARAM );
806 if (vol->v_flags & AFPVOL_RO)
809 if (( dir = dirsearch( vol, ddid )) == NULL ) {
810 return( AFPERR_PARAM );
813 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
814 return( AFPERR_NOOBJ );
816 if ( *path != '\0' ) {
817 return( AFPERR_BADTYPE );
820 /* one of the handful of places that knows about the path type */
821 if ( *ibuf++ != 2 ) {
822 return( AFPERR_PARAM );
824 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
825 strncpy( newname, ibuf, plen );
826 newname[ plen ] = '\0';
829 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
830 vol_noadouble(vol))) < 0 ) {
834 setvoltime(obj, vol );
839 static __inline__ int copy_all(const int dfd, const void *buf,
845 if ((cc = write(dfd, buf, buflen)) < 0) {
865 /* XXX: this needs to use ad_open and ad_lock. so, we need to
866 * pass in vol and path */
867 int copyfile(src, dst, newname, noadouble )
868 char *src, *dst, *newname;
874 int sfd, dfd, len, err = AFP_OK;
879 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
882 break; /* just copy the data fork */
884 return( AFPERR_ACCESS );
886 return( AFPERR_PARAM );
889 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
890 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
894 return( AFPERR_NOOBJ );
896 return( AFPERR_ACCESS );
900 return( AFPERR_PARAM );
905 #ifdef SENDFILE_FLAVOR_LINUX
906 if (fstat(sfd, &st) == 0) {
907 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
921 goto copyheader_done;
925 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
932 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
940 unlink(ad_path(dst, ADFLAGS_HF));
946 /* data fork copying */
947 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
950 return( AFPERR_NOOBJ );
952 return( AFPERR_ACCESS );
954 return( AFPERR_PARAM );
958 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
962 return( AFPERR_NOOBJ );
964 return( AFPERR_ACCESS );
968 return( AFPERR_PARAM );
972 #ifdef SENDFILE_FLAVOR_LINUX
973 if (fstat(sfd, &st) == 0) {
974 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
990 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
998 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1007 unlink(ad_path(dst, ADFLAGS_HF));
1013 memset(&ad, 0, sizeof(ad));
1014 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1018 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1020 return( AFPERR_ACCESS );
1022 return AFPERR_VLOCK;
1024 return( AFPERR_PARAM );
1028 len = strlen( newname );
1029 ad_setentrylen( &ad, ADEID_NAME, len );
1030 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1031 ad_flush( &ad, ADFLAGS_HF );
1032 ad_close( &ad, ADFLAGS_HF );
1039 int deletefile( file )
1043 int adflags, err = AFP_OK;
1045 /* try to open both at once */
1046 adflags = ADFLAGS_DF|ADFLAGS_HF;
1047 memset(&ad, 0, sizeof(ad));
1048 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1051 adflags = ADFLAGS_DF;
1052 /* that failed. now try to open just the data fork */
1053 memset(&ad, 0, sizeof(ad));
1054 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1057 return AFPERR_NOOBJ;
1059 return AFPERR_ACCESS;
1061 return AFPERR_PARAM;
1067 return( AFPERR_ACCESS );
1069 return AFPERR_VLOCK;
1071 return( AFPERR_PARAM );
1075 if ((adflags & ADFLAGS_HF) &&
1076 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1077 ad_close( &ad, adflags );
1078 return( AFPERR_BUSY );
1081 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1086 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1090 err = AFPERR_ACCESS;
1103 if ( unlink( file ) < 0 ) {
1107 err = AFPERR_ACCESS;
1121 if (adflags & ADFLAGS_HF)
1122 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1123 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1124 ad_close( &ad, adflags );
1129 #if AD_VERSION > AD_VERSION1
1130 /* return a file id */
1131 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1134 int ibuflen, *rbuflen;
1148 memcpy(&vid, ibuf, sizeof(vid));
1149 ibuf += sizeof(vid);
1151 if (( vol = getvolbyvid( vid )) == NULL ) {
1152 return( AFPERR_PARAM);
1155 if (vol->v_flags & AFPVOL_RO)
1156 return AFPERR_VLOCK;
1158 memcpy(&did, ibuf, sizeof( did ));
1159 ibuf += sizeof(did);
1161 if (( dir = dirsearch( vol, did )) == NULL ) {
1162 return( AFPERR_PARAM );
1165 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1166 return( AFPERR_PARAM );
1169 if ( *path == '\0' ) {
1170 return( AFPERR_BADTYPE );
1173 upath = mtoupath(vol, path);
1174 if (stat(upath, &st) < 0) {
1178 return AFPERR_ACCESS;
1180 return AFPERR_NOOBJ;
1182 return AFPERR_PARAM;
1186 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1187 memcpy(rbuf, &id, sizeof(id));
1188 *rbuflen = sizeof(id);
1189 return AFPERR_EXISTID;
1192 memset(&ad, 0, sizeof(ad));
1193 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1196 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1197 ad_close(upath, ADFLAGS_HF);
1200 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1201 memcpy(rbuf, &id, sizeof(id));
1202 *rbuflen = sizeof(id);
1208 return AFPERR_VLOCK;
1212 return AFPERR_ACCESS;
1215 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1216 return AFPERR_PARAM;
1220 /* resolve a file id */
1221 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1224 int ibuflen, *rbuflen;
1232 u_int16_t vid, bitmap;
1237 memcpy(&vid, ibuf, sizeof(vid));
1238 ibuf += sizeof(vid);
1240 if (( vol = getvolbyvid( vid )) == NULL ) {
1241 return( AFPERR_PARAM);
1244 memcpy(&id, ibuf, sizeof( id ));
1247 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1248 return AFPERR_BADID;
1251 if (( dir = dirsearch( vol, id )) == NULL ) {
1252 return( AFPERR_PARAM );
1255 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1259 return AFPERR_ACCESS;
1263 return AFPERR_PARAM;
1267 /* directories are bad */
1268 if (S_ISDIR(st.st_mode))
1269 return AFPERR_BADTYPE;
1271 memcpy(&bitmap, ibuf, sizeof(bitmap));
1272 bitmap = ntohs( bitmap );
1274 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1275 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1278 *rbuflen = buflen + sizeof(bitmap);
1279 memcpy(rbuf, ibuf, sizeof(bitmap));
1283 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1286 int ibuflen, *rbuflen;
1299 memcpy(&vid, ibuf, sizeof(vid));
1300 ibuf += sizeof(vid);
1302 if (( vol = getvolbyvid( vid )) == NULL ) {
1303 return( AFPERR_PARAM);
1306 if (vol->v_flags & AFPVOL_RO)
1307 return AFPERR_VLOCK;
1309 memcpy(&id, ibuf, sizeof( id ));
1312 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1316 if (( dir = dirsearch( vol, id )) == NULL ) {
1317 return( AFPERR_PARAM );
1321 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1325 return AFPERR_ACCESS;
1327 /* still try to delete the id */
1331 return AFPERR_PARAM;
1335 /* directories are bad */
1336 if (S_ISDIR(st.st_mode))
1337 return AFPERR_BADTYPE;
1339 if (cnid_delete(vol->v_db, id)) {
1342 return AFPERR_VLOCK;
1345 return AFPERR_ACCESS;
1347 return AFPERR_PARAM;
1355 #define APPLETEMP ".AppleTempXXXXXX"
1356 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1359 int ibuflen, *rbuflen;
1361 struct stat srcst, destst;
1363 struct dir *dir, *sdir;
1364 char *spath, temp[17], *path, *p;
1365 char *supath, *upath;
1367 #if AD_VERSION > AD_VERSION1
1376 memcpy(&vid, ibuf, sizeof(vid));
1377 ibuf += sizeof(vid);
1379 if (( vol = getvolbyvid( vid )) == NULL ) {
1380 return( AFPERR_PARAM);
1383 if (vol->v_flags & AFPVOL_RO)
1384 return AFPERR_VLOCK;
1386 /* source and destination dids */
1387 memcpy(&sid, ibuf, sizeof(sid));
1388 ibuf += sizeof(sid);
1389 memcpy(&did, ibuf, sizeof(did));
1390 ibuf += sizeof(did);
1393 if ((dir = dirsearch( vol, sid )) == NULL ) {
1394 return( AFPERR_PARAM );
1397 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1398 return( AFPERR_PARAM );
1401 if ( *path == '\0' ) {
1402 return( AFPERR_BADTYPE );
1405 upath = mtoupath(vol, path);
1406 if (stat(upath, &srcst) < 0) {
1412 return AFPERR_ACCESS;
1414 return AFPERR_PARAM;
1418 /* save some stuff */
1420 spath = obj->oldtmp;
1421 supath = obj->newtmp;
1422 strcpy(spath, path);
1423 strcpy(supath, upath); /* this is for the cnid changing */
1424 p = ctoupath( vol, sdir, spath);
1426 /* look for the source cnid. if it doesn't exist, don't worry about
1428 #if AD_VERSION > AD_VERSION1
1429 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1430 slen = strlen(supath));
1433 if (( dir = dirsearch( vol, did )) == NULL ) {
1434 return( AFPERR_PARAM );
1437 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1438 return( AFPERR_PARAM );
1441 if ( *path == '\0' ) {
1442 return( AFPERR_BADTYPE );
1445 /* FPExchangeFiles is the only call that can return the SameObj
1447 if ((curdir == sdir) && strcmp(spath, path) == 0)
1448 return AFPERR_SAMEOBJ;
1450 upath = mtoupath(vol, path);
1451 if (stat(upath, &destst) < 0) {
1457 return AFPERR_ACCESS;
1459 return AFPERR_PARAM;
1463 #if AD_VERSION > AD_VERSION1
1464 /* look for destination id. */
1465 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1466 dlen = strlen(upath));
1469 /* construct a temp name.
1470 * NOTE: the temp file will be in the dest file's directory. it
1471 * will also be inaccessible from AFP. */
1472 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1476 /* now, quickly rename the file. we error if we can't. */
1477 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1478 goto err_exchangefile;
1479 of_rename(vol, sdir, spath, curdir, temp);
1481 /* rename destination to source */
1482 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1483 goto err_src_to_tmp;
1484 of_rename(vol, curdir, path, sdir, spath);
1486 /* rename temp to destination */
1487 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1488 goto err_dest_to_src;
1489 of_rename(vol, curdir, temp, curdir, path);
1491 #if AD_VERSION > AD_VERSION1
1492 /* id's need switching. src -> dest and dest -> src. */
1493 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1494 upath, dlen) < 0)) {
1498 err = AFPERR_ACCESS;
1502 goto err_temp_to_dest;
1505 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1506 supath, slen) < 0)) {
1510 err = AFPERR_ACCESS;
1516 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1517 goto err_temp_to_dest;
1523 /* all this stuff is so that we can unwind a failed operation
1526 /* rename dest to temp */
1527 renamefile(upath, temp, temp, vol_noadouble(vol));
1528 of_rename(vol, curdir, upath, curdir, temp);
1531 /* rename source back to dest */
1532 renamefile(p, upath, path, vol_noadouble(vol));
1533 of_rename(vol, sdir, spath, curdir, path);
1536 /* rename temp back to source */
1537 renamefile(temp, p, spath, vol_noadouble(vol));
1538 of_rename(vol, curdir, temp, sdir, spath);