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) < 0) {
416 syslog (LOG_ERR, "afp_createfile: Error checking directory \"%s\": %m", dir->d_name);
421 if ( uid != sb.st_uid )
423 strcpy (adpath, "./.AppleDouble/");
424 strcat (adpath, upath);
425 seteuid(0); /* Become root to change the owner of the file */
426 if (lchown(upath, sb.st_uid, sb.st_gid) < 0)
428 syslog (LOG_ERR, "afp_createfile: Error changing owner/gid: %m");
431 /* In order to write information to the file, the Mac client needs
432 to be able to read from it too, so read bits have to be turned on.
433 Directory permissions remain unchanged */
435 if (chmod(upath,(st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
437 syslog (LOG_ERR, "afp_createfile: Error adding file read permissions: %m");
440 else syslog (LOG_DEBUG, "afp_createfile: Added S_IRGRP and S_IROTH: %m");
441 if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
443 syslog (LOG_ERR, "afp_createfile: Error changing AppleDouble owner/gid: %m");
446 if (chmod(adpath, (st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
448 syslog (LOG_ERR, "afp_createfile: Error adding AD file read permissions: %m");
451 else syslog (LOG_DEBUG, "afp_createfile: Added S_IRGRP and S_IROTH to AD: %m");
452 syslog (LOG_DEBUG, "afp_createfile: Changing afpd owner back to %d", uid);
453 seteuid(uid); /* Restore process ownership to normal */
459 setvoltime(obj, vol );
463 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
466 int ibuflen, *rbuflen;
472 u_int16_t vid, bitmap;
477 memcpy(&vid, ibuf, sizeof( vid ));
478 ibuf += sizeof( vid );
479 if (( vol = getvolbyvid( vid )) == NULL ) {
480 return( AFPERR_PARAM );
483 if (vol->v_flags & AFPVOL_RO)
486 memcpy(&did, ibuf, sizeof( did ));
487 ibuf += sizeof( did );
488 if (( dir = dirsearch( vol, did )) == NULL ) {
489 return( AFPERR_NOOBJ );
492 memcpy(&bitmap, ibuf, sizeof( bitmap ));
493 bitmap = ntohs( bitmap );
494 ibuf += sizeof( bitmap );
496 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
497 return( AFPERR_NOOBJ );
500 if ((u_long)ibuf & 1 ) {
504 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
505 setvoltime(obj, vol );
512 int setfilparams(vol, path, bitmap, buf )
517 struct adouble ad, *adp;
520 int bit = 0, isad = 1, err = AFP_OK;
522 u_char achar, *fdType, xyy[4];
523 u_int16_t ashort, bshort;
527 upath = mtoupath(vol, path);
528 if ((of = of_findname(vol, curdir, path))) {
531 memset(&ad, 0, sizeof(ad));
534 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
535 O_RDWR|O_CREAT, 0666, adp) < 0) {
536 /* for some things, we don't need an adouble header */
537 if (bitmap & ~(1<<FILPBIT_MDATE)) {
538 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
541 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
542 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
543 memcpy(ad_entry( adp, ADEID_NAME ), path,
544 ad_getentrylen( adp, ADEID_NAME ));
547 while ( bitmap != 0 ) {
548 while (( bitmap & 1 ) == 0 ) {
555 memcpy(&ashort, buf, sizeof( ashort ));
556 ad_getattr(adp, &bshort);
557 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
558 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
562 ad_setattr(adp, bshort);
563 buf += sizeof( ashort );
567 memcpy(&aint, buf, sizeof(aint));
568 ad_setdate(adp, AD_DATE_CREATE, aint);
569 buf += sizeof( aint );
573 memcpy(&aint, buf, sizeof( aint ));
575 ad_setdate(adp, AD_DATE_MODIFY, aint);
576 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
578 buf += sizeof( aint );
582 memcpy(&aint, buf, sizeof(aint));
583 ad_setdate(adp, AD_DATE_BACKUP, aint);
584 buf += sizeof( aint );
588 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
589 && (em = getextmap( path )) &&
590 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
591 (memcmp(buf + 4, em->em_creator,
592 sizeof( em->em_creator )) == 0)) {
593 memcpy(buf, ufinderi, 8 );
595 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
599 /* Client needs to set the ProDOS file info for this file.
600 Use defined strings for the simple cases, and convert
601 all else into pXYY per Inside Appletalk. Always set
602 the creator as "pdos". <shirsch@ibm.net> */
603 case FILPBIT_PDINFO :
606 memcpy(&ashort, buf, sizeof( ashort ));
607 ashort = ntohs( ashort );
610 switch ( (unsigned int) achar )
613 fdType = ( u_char *) "TEXT";
617 fdType = ( u_char *) "PSYS";
621 fdType = ( u_char *) "PS16";
625 fdType = ( u_char *) "BINA";
629 xyy[0] = ( u_char ) 'p';
631 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
632 xyy[3] = ( u_char ) ashort & 0xff;
637 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
638 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
644 goto setfilparam_done;
653 ad_flush( adp, ADFLAGS_HF );
654 ad_close( adp, ADFLAGS_HF );
660 * renamefile and copyfile take the old and new unix pathnames
661 * and the new mac name.
662 * NOTE: if we have to copy a file instead of renaming it, locks
665 int renamefile(src, dst, newname, noadouble )
666 char *src, *dst, *newname;
670 char adsrc[ MAXPATHLEN + 1];
674 * Note that this is only checking the existance of the data file,
675 * not the header file. The thinking is that if the data file doesn't
676 * exist, but the header file does, the right thing to do is remove
677 * the data file silently.
680 /* existence check moved to afp_moveandrename */
682 if ( rename( src, dst ) < 0 ) {
685 return( AFPERR_NOOBJ );
688 return( AFPERR_ACCESS );
691 case EXDEV : /* Cross device move -- try copy */
692 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
696 return deletefile( src );
698 return( AFPERR_PARAM );
702 strcpy( adsrc, ad_path( src, 0 ));
705 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
710 /* check for a source appledouble header. if it exists, make
711 * a dest appledouble directory and do the rename again. */
712 memset(&ad, 0, sizeof(ad));
713 if (rc || stat(adsrc, &st) ||
714 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
717 ad_close(&ad, ADFLAGS_HF);
721 return( AFPERR_ACCESS );
725 return( AFPERR_PARAM );
729 memset(&ad, 0, sizeof(ad));
730 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
733 return( AFPERR_NOOBJ );
735 return( AFPERR_ACCESS );
739 return( AFPERR_PARAM );
743 len = strlen( newname );
744 ad_setentrylen( &ad, ADEID_NAME, len );
745 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
746 ad_flush( &ad, ADFLAGS_HF );
747 ad_close( &ad, ADFLAGS_HF );
752 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
755 int ibuflen, *rbuflen;
759 char *newname, *path, *p;
760 u_int32_t sdid, ddid;
762 u_int16_t svid, dvid;
767 memcpy(&svid, ibuf, sizeof( svid ));
768 ibuf += sizeof( svid );
769 if (( vol = getvolbyvid( svid )) == NULL ) {
770 return( AFPERR_PARAM );
773 memcpy(&sdid, ibuf, sizeof( sdid ));
774 ibuf += sizeof( sdid );
775 if (( dir = dirsearch( vol, sdid )) == NULL ) {
776 return( AFPERR_PARAM );
779 memcpy(&dvid, ibuf, sizeof( dvid ));
780 ibuf += sizeof( dvid );
781 memcpy(&ddid, ibuf, sizeof( ddid ));
782 ibuf += sizeof( ddid );
784 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
785 return( AFPERR_NOOBJ );
787 if ( *path == '\0' ) {
788 return( AFPERR_BADTYPE );
791 /* don't allow copies when the file is open.
792 * XXX: the spec only calls for read/deny write access.
793 * however, copyfile doesn't have any of that info,
794 * and locks need to stay coherent. as a result,
795 * we just balk if the file is opened already. */
796 if (of_findname(vol, curdir, path))
797 return AFPERR_DENYCONF;
799 newname = obj->newtmp;
800 strcpy( newname, path );
802 p = ctoupath( vol, curdir, newname );
804 if (( vol = getvolbyvid( dvid )) == NULL ) {
805 return( AFPERR_PARAM );
808 if (vol->v_flags & AFPVOL_RO)
811 if (( dir = dirsearch( vol, ddid )) == NULL ) {
812 return( AFPERR_PARAM );
815 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
816 return( AFPERR_NOOBJ );
818 if ( *path != '\0' ) {
819 return( AFPERR_BADTYPE );
822 /* one of the handful of places that knows about the path type */
823 if ( *ibuf++ != 2 ) {
824 return( AFPERR_PARAM );
826 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
827 strncpy( newname, ibuf, plen );
828 newname[ plen ] = '\0';
831 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
832 vol_noadouble(vol))) < 0 ) {
836 setvoltime(obj, vol );
841 static __inline__ int copy_all(const int dfd, const void *buf,
847 if ((cc = write(dfd, buf, buflen)) < 0) {
867 /* XXX: this needs to use ad_open and ad_lock. so, we need to
868 * pass in vol and path */
869 int copyfile(src, dst, newname, noadouble )
870 char *src, *dst, *newname;
876 int sfd, dfd, len, err = AFP_OK;
881 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
884 break; /* just copy the data fork */
886 return( AFPERR_ACCESS );
888 return( AFPERR_PARAM );
891 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
892 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
896 return( AFPERR_NOOBJ );
898 return( AFPERR_ACCESS );
902 return( AFPERR_PARAM );
907 #ifdef SENDFILE_FLAVOR_LINUX
908 if (fstat(sfd, &st) == 0) {
909 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
923 goto copyheader_done;
927 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
934 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
942 unlink(ad_path(dst, ADFLAGS_HF));
948 /* data fork copying */
949 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
952 return( AFPERR_NOOBJ );
954 return( AFPERR_ACCESS );
956 return( AFPERR_PARAM );
960 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
964 return( AFPERR_NOOBJ );
966 return( AFPERR_ACCESS );
970 return( AFPERR_PARAM );
974 #ifdef SENDFILE_FLAVOR_LINUX
975 if (fstat(sfd, &st) == 0) {
976 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
992 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1000 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1009 unlink(ad_path(dst, ADFLAGS_HF));
1015 memset(&ad, 0, sizeof(ad));
1016 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1020 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1022 return( AFPERR_ACCESS );
1024 return AFPERR_VLOCK;
1026 return( AFPERR_PARAM );
1030 len = strlen( newname );
1031 ad_setentrylen( &ad, ADEID_NAME, len );
1032 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1033 ad_flush( &ad, ADFLAGS_HF );
1034 ad_close( &ad, ADFLAGS_HF );
1041 int deletefile( file )
1045 int adflags, err = AFP_OK;
1047 /* try to open both at once */
1048 adflags = ADFLAGS_DF|ADFLAGS_HF;
1049 memset(&ad, 0, sizeof(ad));
1050 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1053 adflags = ADFLAGS_DF;
1054 /* that failed. now try to open just the data fork */
1055 memset(&ad, 0, sizeof(ad));
1056 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1059 return AFPERR_NOOBJ;
1061 return AFPERR_ACCESS;
1063 return AFPERR_PARAM;
1069 return( AFPERR_ACCESS );
1071 return AFPERR_VLOCK;
1073 return( AFPERR_PARAM );
1077 if ((adflags & ADFLAGS_HF) &&
1078 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1079 ad_close( &ad, adflags );
1080 return( AFPERR_BUSY );
1083 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1088 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1092 err = AFPERR_ACCESS;
1105 if ( unlink( file ) < 0 ) {
1109 err = AFPERR_ACCESS;
1123 if (adflags & ADFLAGS_HF)
1124 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1125 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1126 ad_close( &ad, adflags );
1131 #if AD_VERSION > AD_VERSION1
1132 /* return a file id */
1133 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1136 int ibuflen, *rbuflen;
1150 memcpy(&vid, ibuf, sizeof(vid));
1151 ibuf += sizeof(vid);
1153 if (( vol = getvolbyvid( vid )) == NULL ) {
1154 return( AFPERR_PARAM);
1157 if (vol->v_flags & AFPVOL_RO)
1158 return AFPERR_VLOCK;
1160 memcpy(&did, ibuf, sizeof( did ));
1161 ibuf += sizeof(did);
1163 if (( dir = dirsearch( vol, did )) == NULL ) {
1164 return( AFPERR_PARAM );
1167 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1168 return( AFPERR_PARAM );
1171 if ( *path == '\0' ) {
1172 return( AFPERR_BADTYPE );
1175 upath = mtoupath(vol, path);
1176 if (stat(upath, &st) < 0) {
1180 return AFPERR_ACCESS;
1182 return AFPERR_NOOBJ;
1184 return AFPERR_PARAM;
1188 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1189 memcpy(rbuf, &id, sizeof(id));
1190 *rbuflen = sizeof(id);
1191 return AFPERR_EXISTID;
1194 memset(&ad, 0, sizeof(ad));
1195 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1198 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1199 ad_close(upath, ADFLAGS_HF);
1202 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1203 memcpy(rbuf, &id, sizeof(id));
1204 *rbuflen = sizeof(id);
1210 return AFPERR_VLOCK;
1214 return AFPERR_ACCESS;
1217 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1218 return AFPERR_PARAM;
1222 /* resolve a file id */
1223 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1226 int ibuflen, *rbuflen;
1234 u_int16_t vid, bitmap;
1239 memcpy(&vid, ibuf, sizeof(vid));
1240 ibuf += sizeof(vid);
1242 if (( vol = getvolbyvid( vid )) == NULL ) {
1243 return( AFPERR_PARAM);
1246 memcpy(&id, ibuf, sizeof( id ));
1249 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1250 return AFPERR_BADID;
1253 if (( dir = dirsearch( vol, id )) == NULL ) {
1254 return( AFPERR_PARAM );
1257 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1261 return AFPERR_ACCESS;
1265 return AFPERR_PARAM;
1269 /* directories are bad */
1270 if (S_ISDIR(st.st_mode))
1271 return AFPERR_BADTYPE;
1273 memcpy(&bitmap, ibuf, sizeof(bitmap));
1274 bitmap = ntohs( bitmap );
1276 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1277 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1280 *rbuflen = buflen + sizeof(bitmap);
1281 memcpy(rbuf, ibuf, sizeof(bitmap));
1285 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1288 int ibuflen, *rbuflen;
1301 memcpy(&vid, ibuf, sizeof(vid));
1302 ibuf += sizeof(vid);
1304 if (( vol = getvolbyvid( vid )) == NULL ) {
1305 return( AFPERR_PARAM);
1308 if (vol->v_flags & AFPVOL_RO)
1309 return AFPERR_VLOCK;
1311 memcpy(&id, ibuf, sizeof( id ));
1314 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1318 if (( dir = dirsearch( vol, id )) == NULL ) {
1319 return( AFPERR_PARAM );
1323 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1327 return AFPERR_ACCESS;
1329 /* still try to delete the id */
1333 return AFPERR_PARAM;
1337 /* directories are bad */
1338 if (S_ISDIR(st.st_mode))
1339 return AFPERR_BADTYPE;
1341 if (cnid_delete(vol->v_db, id)) {
1344 return AFPERR_VLOCK;
1347 return AFPERR_ACCESS;
1349 return AFPERR_PARAM;
1357 #define APPLETEMP ".AppleTempXXXXXX"
1358 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1361 int ibuflen, *rbuflen;
1363 struct stat srcst, destst;
1365 struct dir *dir, *sdir;
1366 char *spath, temp[17], *path, *p;
1367 char *supath, *upath;
1369 #if AD_VERSION > AD_VERSION1
1378 memcpy(&vid, ibuf, sizeof(vid));
1379 ibuf += sizeof(vid);
1381 if (( vol = getvolbyvid( vid )) == NULL ) {
1382 return( AFPERR_PARAM);
1385 if (vol->v_flags & AFPVOL_RO)
1386 return AFPERR_VLOCK;
1388 /* source and destination dids */
1389 memcpy(&sid, ibuf, sizeof(sid));
1390 ibuf += sizeof(sid);
1391 memcpy(&did, ibuf, sizeof(did));
1392 ibuf += sizeof(did);
1395 if ((dir = dirsearch( vol, sid )) == NULL ) {
1396 return( AFPERR_PARAM );
1399 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1400 return( AFPERR_PARAM );
1403 if ( *path == '\0' ) {
1404 return( AFPERR_BADTYPE );
1407 upath = mtoupath(vol, path);
1408 if (stat(upath, &srcst) < 0) {
1414 return AFPERR_ACCESS;
1416 return AFPERR_PARAM;
1420 /* save some stuff */
1422 spath = obj->oldtmp;
1423 supath = obj->newtmp;
1424 strcpy(spath, path);
1425 strcpy(supath, upath); /* this is for the cnid changing */
1426 p = ctoupath( vol, sdir, spath);
1428 /* look for the source cnid. if it doesn't exist, don't worry about
1430 #if AD_VERSION > AD_VERSION1
1431 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1432 slen = strlen(supath));
1435 if (( dir = dirsearch( vol, did )) == NULL ) {
1436 return( AFPERR_PARAM );
1439 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1440 return( AFPERR_PARAM );
1443 if ( *path == '\0' ) {
1444 return( AFPERR_BADTYPE );
1447 /* FPExchangeFiles is the only call that can return the SameObj
1449 if ((curdir == sdir) && strcmp(spath, path) == 0)
1450 return AFPERR_SAMEOBJ;
1452 upath = mtoupath(vol, path);
1453 if (stat(upath, &destst) < 0) {
1459 return AFPERR_ACCESS;
1461 return AFPERR_PARAM;
1465 #if AD_VERSION > AD_VERSION1
1466 /* look for destination id. */
1467 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1468 dlen = strlen(upath));
1471 /* construct a temp name.
1472 * NOTE: the temp file will be in the dest file's directory. it
1473 * will also be inaccessible from AFP. */
1474 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1478 /* now, quickly rename the file. we error if we can't. */
1479 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1480 goto err_exchangefile;
1481 of_rename(vol, sdir, spath, curdir, temp);
1483 /* rename destination to source */
1484 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1485 goto err_src_to_tmp;
1486 of_rename(vol, curdir, path, sdir, spath);
1488 /* rename temp to destination */
1489 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1490 goto err_dest_to_src;
1491 of_rename(vol, curdir, temp, curdir, path);
1493 #if AD_VERSION > AD_VERSION1
1494 /* id's need switching. src -> dest and dest -> src. */
1495 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1496 upath, dlen) < 0)) {
1500 err = AFPERR_ACCESS;
1504 goto err_temp_to_dest;
1507 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1508 supath, slen) < 0)) {
1512 err = AFPERR_ACCESS;
1518 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1519 goto err_temp_to_dest;
1525 /* all this stuff is so that we can unwind a failed operation
1528 /* rename dest to temp */
1529 renamefile(upath, temp, temp, vol_noadouble(vol));
1530 of_rename(vol, curdir, upath, curdir, temp);
1533 /* rename source back to dest */
1534 renamefile(p, upath, path, vol_noadouble(vol));
1535 of_rename(vol, sdir, spath, curdir, path);
1538 /* rename temp back to source */
1539 renamefile(temp, p, spath, vol_noadouble(vol));
1540 of_rename(vol, curdir, temp, sdir, spath);