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"
42 #endif /* FORCE_UIDGID */
44 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
45 * field bytes subfield bytes
48 * ioFlFndrInfo 16 -> type 4 type field
49 * creator 4 creator field
50 * flags 2 finder flags:
52 * location 4 location in window
53 * folder 2 window that contains file
55 * ioFlXFndrInfo 16 -> iconID 2 icon id
57 * script 1 script system
59 * commentID 2 comment id
60 * putawayID 4 home directory id
63 const u_char ufinderi[] = {
64 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
65 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0
70 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
79 struct stat hst, lst, *lstp;
80 struct adouble ad, *adp;
83 char *data, *nameoff = NULL, *upath;
84 int bit = 0, isad = 1, aint;
86 u_char achar, fdType[4];
89 syslog(LOG_INFO, "begin getfilparams:");
92 upath = mtoupath(vol, path);
93 if ((of = of_findname(vol, curdir, path))) {
96 memset(&ad, 0, sizeof(ad));
100 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
102 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
103 syslog( LOG_ERR, "getfilparams fstat: %m" );
107 while ( bitmap != 0 ) {
108 while (( bitmap & 1 ) == 0 ) {
116 ad_getattr(adp, &ashort);
117 } else if (*upath == '.') {
118 ashort = htons(ATTRBIT_INVISIBLE);
121 memcpy(data, &ashort, sizeof( ashort ));
122 data += sizeof( u_short );
126 memcpy(data, &dir->d_did, sizeof( int ));
127 data += sizeof( int );
131 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
132 aint = AD_DATE_FROM_UNIX(st->st_mtime);
133 memcpy(data, &aint, sizeof( aint ));
134 data += sizeof( aint );
138 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
139 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
140 (hst.st_mtime < st->st_mtime)) {
141 aint = AD_DATE_FROM_UNIX(st->st_mtime);
144 aint = AD_DATE_FROM_UNIX(st->st_mtime);
146 memcpy(data, &aint, sizeof( int ));
147 data += sizeof( int );
151 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
152 aint = AD_DATE_START;
153 memcpy(data, &aint, sizeof( int ));
154 data += sizeof( int );
159 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
161 memcpy(data, ufinderi, 32);
162 if (*upath == '.') { /* make it invisible */
163 ashort = htons(FINDERINFO_INVISIBLE);
164 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
168 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
169 ufinderi, 8 ) == 0)) &&
170 (em = getextmap( path ))) {
171 memcpy(data, em->em_type, sizeof( em->em_type ));
172 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
179 data += sizeof( u_int16_t );
183 memset(data, 0, sizeof(u_int16_t));
184 data += sizeof( u_int16_t );
188 #if AD_VERSION > AD_VERSION1
189 /* use the CNID database if we're using AD v2 */
191 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
195 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
196 strlen(upath), aint))) {
199 * What a fucking mess. First thing: DID and FNUMs are
200 * in the same space for purposes of enumerate (and several
201 * other wierd places). While we consider this Apple's bug,
202 * this is the work-around: In order to maintain constant and
203 * unique DIDs and FNUMs, we monotonically generate the DIDs
204 * during the session, and derive the FNUMs from the filesystem.
205 * Since the DIDs are small, we insure that the FNUMs are fairly
206 * large by setting thier high bits to the device number.
208 * AFS already does something very similar to this for the
209 * inode number, so we don't repeat the procedure.
212 * due to complaints over did's being non-persistent,
213 * here's the current hack to provide semi-persistent
215 * 1) we reserve the first bit for file ids.
216 * 2) the next 7 bits are for the device.
217 * 3) the remaining 24 bits are for the inode.
219 * both the inode and device information are actually hashes
220 * that are then truncated to the requisite bit length.
222 * it should be okay to use lstat to deal with symlinks.
224 lstp = (lstat(upath, &lst) < 0) ? st : &lst;
225 aint = htonl(CNID(lstp, 1));
226 #if AD_VERSION > AD_VERSION1
229 memcpy(data, &aint, sizeof( aint ));
230 data += sizeof( aint );
234 aint = htonl( st->st_size );
235 memcpy(data, &aint, sizeof( aint ));
236 data += sizeof( aint );
241 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
245 memcpy(data, &aint, sizeof( aint ));
246 data += sizeof( aint );
249 /* Current client needs ProDOS info block for this file.
250 Use simple heuristic and let the Mac "type" string tell
251 us what the PD file code should be. Everything gets a
252 subtype of 0x0000 unless the original value was hashed
253 to "pXYZ" when we created it. See IA, Ver 2.
255 case FILPBIT_PDINFO :
257 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
259 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
263 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
267 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
271 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
275 else if ( fdType[0] == 'p' ) {
277 ashort = (fdType[2] * 256) + fdType[3];
291 memcpy(data, &ashort, sizeof( ashort ));
292 data += sizeof( ashort );
293 memset(data, 0, sizeof( ashort ));
294 data += sizeof( ashort );
299 ad_close( adp, ADFLAGS_HF );
301 return( AFPERR_BITMAP );
307 ashort = htons( data - buf );
308 memcpy(nameoff, &ashort, sizeof( ashort ));
309 if ((aint = strlen( path )) > MACFILELEN)
312 memcpy(data, path, aint );
316 ad_close( adp, ADFLAGS_HF );
318 *buflen = data - buf;
321 syslog(LOG_INFO, "end getfilparams:");
327 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
330 int ibuflen, *rbuflen;
333 struct adouble ad, *adp;
338 int creatf, did, openf, retvalue = AFP_OK;
345 syslog(LOG_INFO, "begin afp_createfile:");
350 creatf = (unsigned char) *ibuf++;
352 memcpy(&vid, ibuf, sizeof( vid ));
353 ibuf += sizeof( vid );
355 if (( vol = getvolbyvid( vid )) == NULL ) {
356 return( AFPERR_PARAM );
359 if (vol->v_flags & AFPVOL_RO)
362 memcpy(&did, ibuf, sizeof( did));
363 ibuf += sizeof( did );
365 if (( dir = dirsearch( vol, did )) == NULL ) {
366 return( AFPERR_NOOBJ );
369 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
370 return( AFPERR_NOOBJ );
373 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
374 strpbrk(path, MSWINDOWS_BADCHARS))
377 upath = mtoupath(vol, path);
379 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
382 if (!validupath(vol, upath))
385 if ((of = of_findname(vol, curdir, path))) {
388 memset(&ad, 0, sizeof(ad));
392 /* on a hard create, fail if file exists and is open */
393 if ((stat(upath, &st) == 0) && of)
395 openf = O_RDWR|O_CREAT|O_TRUNC;
397 openf = O_RDWR|O_CREAT|O_EXCL;
402 /* preserve current euid, egid */
403 save_uidgid ( uidgid );
405 /* perform all switching of users */
410 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
411 openf, 0666, adp) < 0 ) {
415 /* bring everything back to old euid, egid */
416 restore_uidgid ( uidgid );
418 return( AFPERR_EXIST );
421 /* bring everything back to old euid, egid */
422 restore_uidgid ( uidgid );
424 return( AFPERR_ACCESS );
426 /* on noadouble volumes, just creating the data fork is ok */
427 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
428 goto createfile_done;
432 /* bring everything back to old euid, egid */
433 restore_uidgid ( uidgid );
435 return( AFPERR_PARAM );
439 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
440 memcpy(ad_entry( adp, ADEID_NAME ), path,
441 ad_getentrylen( adp, ADEID_NAME ));
442 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
443 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
448 retvalue=matchfile2dirperms(upath, vol, did);
451 setvoltime(obj, vol );
454 syslog(LOG_INFO, "end afp_createfile");
458 /* bring everything back to old euid, egid */
459 restore_uidgid ( uidgid );
465 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
468 int ibuflen, *rbuflen;
474 u_int16_t vid, bitmap;
477 syslog(LOG_INFO, "begin afp_setfilparams:");
483 memcpy(&vid, ibuf, sizeof( vid ));
484 ibuf += sizeof( vid );
485 if (( vol = getvolbyvid( vid )) == NULL ) {
486 return( AFPERR_PARAM );
489 if (vol->v_flags & AFPVOL_RO)
492 memcpy(&did, ibuf, sizeof( did ));
493 ibuf += sizeof( did );
494 if (( dir = dirsearch( vol, did )) == NULL ) {
495 return( AFPERR_NOOBJ );
498 memcpy(&bitmap, ibuf, sizeof( bitmap ));
499 bitmap = ntohs( bitmap );
500 ibuf += sizeof( bitmap );
502 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
503 return( AFPERR_NOOBJ );
506 if ((u_long)ibuf & 1 ) {
510 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
511 setvoltime(obj, vol );
515 syslog(LOG_INFO, "end afp_setfilparams:");
522 int setfilparams(vol, path, bitmap, buf )
527 struct adouble ad, *adp;
530 int bit = 0, isad = 1, err = AFP_OK;
532 u_char achar, *fdType, xyy[4];
533 u_int16_t ashort, bshort;
542 syslog(LOG_INFO, "begin setfilparams:");
545 upath = mtoupath(vol, path);
546 if ((of = of_findname(vol, curdir, path))) {
549 memset(&ad, 0, sizeof(ad));
554 save_uidgid ( uidgid );
558 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
559 O_RDWR|O_CREAT, 0666, adp) < 0) {
560 /* for some things, we don't need an adouble header */
561 if (bitmap & ~(1<<FILPBIT_MDATE)) {
563 restore_uidgid ( uidgid );
565 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
568 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
569 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
570 memcpy(ad_entry( adp, ADEID_NAME ), path,
571 ad_getentrylen( adp, ADEID_NAME ));
574 while ( bitmap != 0 ) {
575 while (( bitmap & 1 ) == 0 ) {
582 memcpy(&ashort, buf, sizeof( ashort ));
583 ad_getattr(adp, &bshort);
584 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
585 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
589 ad_setattr(adp, bshort);
590 buf += sizeof( ashort );
594 memcpy(&aint, buf, sizeof(aint));
595 ad_setdate(adp, AD_DATE_CREATE, aint);
596 buf += sizeof( aint );
600 memcpy(&aint, buf, sizeof( aint ));
602 ad_setdate(adp, AD_DATE_MODIFY, aint);
603 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
605 buf += sizeof( aint );
609 memcpy(&aint, buf, sizeof(aint));
610 ad_setdate(adp, AD_DATE_BACKUP, aint);
611 buf += sizeof( aint );
615 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
616 && (em = getextmap( path )) &&
617 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
618 (memcmp(buf + 4, em->em_creator,
619 sizeof( em->em_creator )) == 0)) {
620 memcpy(buf, ufinderi, 8 );
622 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
626 /* Client needs to set the ProDOS file info for this file.
627 Use defined strings for the simple cases, and convert
628 all else into pXYY per Inside Appletalk. Always set
629 the creator as "pdos". <shirsch@ibm.net> */
630 case FILPBIT_PDINFO :
633 memcpy(&ashort, buf, sizeof( ashort ));
634 ashort = ntohs( ashort );
637 switch ( (unsigned int) achar )
640 fdType = ( u_char *) "TEXT";
644 fdType = ( u_char *) "PSYS";
648 fdType = ( u_char *) "PS16";
652 fdType = ( u_char *) "BINA";
656 xyy[0] = ( u_char ) 'p';
658 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
659 xyy[3] = ( u_char ) ashort & 0xff;
664 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
665 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
671 goto setfilparam_done;
680 ad_flush( adp, ADFLAGS_HF );
681 ad_close( adp, ADFLAGS_HF );
684 restore_uidgid ( uidgid );
690 syslog(LOG_INFO, "end setfilparams:");
697 * renamefile and copyfile take the old and new unix pathnames
698 * and the new mac name.
699 * NOTE: if we have to copy a file instead of renaming it, locks
702 int renamefile(src, dst, newname, noadouble )
703 char *src, *dst, *newname;
707 char adsrc[ MAXPATHLEN + 1];
711 * Note that this is only checking the existance of the data file,
712 * not the header file. The thinking is that if the data file doesn't
713 * exist, but the header file does, the right thing to do is remove
714 * the data file silently.
717 /* existence check moved to afp_moveandrename */
720 syslog (LOG_INFO, "begin renamefile:");
723 if ( rename( src, dst ) < 0 ) {
726 return( AFPERR_NOOBJ );
729 return( AFPERR_ACCESS );
732 case EXDEV : /* Cross device move -- try copy */
733 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
737 return deletefile( src );
739 return( AFPERR_PARAM );
743 strcpy( adsrc, ad_path( src, 0 ));
746 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
751 /* check for a source appledouble header. if it exists, make
752 * a dest appledouble directory and do the rename again. */
753 memset(&ad, 0, sizeof(ad));
754 if (rc || stat(adsrc, &st) ||
755 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
758 ad_close(&ad, ADFLAGS_HF);
762 return( AFPERR_ACCESS );
766 return( AFPERR_PARAM );
770 memset(&ad, 0, sizeof(ad));
771 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
774 return( AFPERR_NOOBJ );
776 return( AFPERR_ACCESS );
780 return( AFPERR_PARAM );
784 len = strlen( newname );
785 ad_setentrylen( &ad, ADEID_NAME, len );
786 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
787 ad_flush( &ad, ADFLAGS_HF );
788 ad_close( &ad, ADFLAGS_HF );
791 syslog (LOG_INFO, "end renamefile:");
797 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
800 int ibuflen, *rbuflen;
804 char *newname, *path, *p;
805 u_int32_t sdid, ddid;
806 int plen, err, did, retvalue = AFP_OK;
807 u_int16_t svid, dvid;
810 syslog (LOG_INFO, "begin afp_copyfile:");
816 memcpy(&svid, ibuf, sizeof( svid ));
817 ibuf += sizeof( svid );
818 if (( vol = getvolbyvid( svid )) == NULL ) {
819 return( AFPERR_PARAM );
822 memcpy(&sdid, ibuf, sizeof( sdid ));
823 ibuf += sizeof( sdid );
824 if (( dir = dirsearch( vol, sdid )) == NULL ) {
825 return( AFPERR_PARAM );
828 memcpy(&dvid, ibuf, sizeof( dvid ));
829 ibuf += sizeof( dvid );
830 memcpy(&ddid, ibuf, sizeof( ddid ));
831 ibuf += sizeof( ddid );
833 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
834 return( AFPERR_NOOBJ );
836 if ( *path == '\0' ) {
837 return( AFPERR_BADTYPE );
840 /* don't allow copies when the file is open.
841 * XXX: the spec only calls for read/deny write access.
842 * however, copyfile doesn't have any of that info,
843 * and locks need to stay coherent. as a result,
844 * we just balk if the file is opened already. */
845 if (of_findname(vol, curdir, path))
846 return AFPERR_DENYCONF;
848 newname = obj->newtmp;
849 strcpy( newname, path );
851 p = ctoupath( vol, curdir, newname );
853 if (( vol = getvolbyvid( dvid )) == NULL ) {
854 return( AFPERR_PARAM );
857 if (vol->v_flags & AFPVOL_RO)
860 if (( dir = dirsearch( vol, ddid )) == NULL ) {
861 return( AFPERR_PARAM );
864 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
865 return( AFPERR_NOOBJ );
867 if ( *path != '\0' ) {
868 return( AFPERR_BADTYPE );
871 /* one of the handful of places that knows about the path type */
872 if ( *ibuf++ != 2 ) {
873 return( AFPERR_PARAM );
875 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
876 strncpy( newname, ibuf, plen );
877 newname[ plen ] = '\0';
880 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
881 vol_noadouble(vol))) < 0 ) {
885 setvoltime(obj, vol );
888 retvalue=matchfile2dirperms(newname, vol, sdid);
892 syslog (LOG_INFO, "end afp_copyfile:");
899 static __inline__ int copy_all(const int dfd, const void *buf,
905 syslog(LOG_INFO, "begin copy_all:");
909 if ((cc = write(dfd, buf, buflen)) < 0) {
927 syslog(LOG_INFO, "end copy_all:");
933 /* XXX: this needs to use ad_open and ad_lock. so, we need to
934 * pass in vol and path */
935 int copyfile(src, dst, newname, noadouble )
936 char *src, *dst, *newname;
942 int sfd, dfd, len, err = AFP_OK;
946 syslog(LOG_INFO, "begin copyfile:");
950 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
953 break; /* just copy the data fork */
955 return( AFPERR_ACCESS );
957 return( AFPERR_PARAM );
960 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
961 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
965 return( AFPERR_NOOBJ );
967 return( AFPERR_ACCESS );
971 return( AFPERR_PARAM );
976 #ifdef SENDFILE_FLAVOR_LINUX
977 if (fstat(sfd, &st) == 0) {
978 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
992 goto copyheader_done;
996 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1003 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1011 unlink(ad_path(dst, ADFLAGS_HF));
1017 /* data fork copying */
1018 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1021 return( AFPERR_NOOBJ );
1023 return( AFPERR_ACCESS );
1025 return( AFPERR_PARAM );
1029 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1033 return( AFPERR_NOOBJ );
1035 return( AFPERR_ACCESS );
1037 return AFPERR_VLOCK;
1039 return( AFPERR_PARAM );
1043 #ifdef SENDFILE_FLAVOR_LINUX
1044 if (fstat(sfd, &st) == 0) {
1045 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1061 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1069 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1078 unlink(ad_path(dst, ADFLAGS_HF));
1084 memset(&ad, 0, sizeof(ad));
1085 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1089 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1091 return( AFPERR_ACCESS );
1093 return AFPERR_VLOCK;
1095 return( AFPERR_PARAM );
1099 len = strlen( newname );
1100 ad_setentrylen( &ad, ADEID_NAME, len );
1101 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1102 ad_flush( &ad, ADFLAGS_HF );
1103 ad_close( &ad, ADFLAGS_HF );
1107 syslog(LOG_INFO, "end copyfile:");
1114 int deletefile( file )
1118 int adflags, err = AFP_OK;
1121 syslog(LOG_INFO, "begin deletefile:");
1124 /* try to open both at once */
1125 adflags = ADFLAGS_DF|ADFLAGS_HF;
1126 memset(&ad, 0, sizeof(ad));
1127 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1130 adflags = ADFLAGS_DF;
1131 /* that failed. now try to open just the data fork */
1132 memset(&ad, 0, sizeof(ad));
1133 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1136 return AFPERR_NOOBJ;
1138 return AFPERR_ACCESS;
1140 return AFPERR_PARAM;
1146 return( AFPERR_ACCESS );
1148 return AFPERR_VLOCK;
1150 return( AFPERR_PARAM );
1154 if ((adflags & ADFLAGS_HF) &&
1155 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1156 ad_close( &ad, adflags );
1157 return( AFPERR_BUSY );
1160 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1165 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1169 err = AFPERR_ACCESS;
1182 if ( unlink( file ) < 0 ) {
1186 err = AFPERR_ACCESS;
1200 if (adflags & ADFLAGS_HF)
1201 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1202 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1203 ad_close( &ad, adflags );
1206 syslog(LOG_INFO, "end deletefile:");
1213 #if AD_VERSION > AD_VERSION1
1214 /* return a file id */
1215 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1218 int ibuflen, *rbuflen;
1230 syslog(LOG_INFO, "begin afp_createid:");
1236 memcpy(&vid, ibuf, sizeof(vid));
1237 ibuf += sizeof(vid);
1239 if (( vol = getvolbyvid( vid )) == NULL ) {
1240 return( AFPERR_PARAM);
1243 if (vol->v_flags & AFPVOL_RO)
1244 return AFPERR_VLOCK;
1246 memcpy(&did, ibuf, sizeof( did ));
1247 ibuf += sizeof(did);
1249 if (( dir = dirsearch( vol, did )) == NULL ) {
1250 return( AFPERR_PARAM );
1253 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1254 return( AFPERR_PARAM );
1257 if ( *path == '\0' ) {
1258 return( AFPERR_BADTYPE );
1261 upath = mtoupath(vol, path);
1262 if (stat(upath, &st) < 0) {
1266 return AFPERR_ACCESS;
1268 return AFPERR_NOOBJ;
1270 return AFPERR_PARAM;
1274 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1275 memcpy(rbuf, &id, sizeof(id));
1276 *rbuflen = sizeof(id);
1277 return AFPERR_EXISTID;
1280 memset(&ad, 0, sizeof(ad));
1281 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1284 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1285 ad_close(upath, ADFLAGS_HF);
1288 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1289 memcpy(rbuf, &id, sizeof(id));
1290 *rbuflen = sizeof(id);
1295 syslog(LOG_INFO, "ending afp_createid...:");
1300 return AFPERR_VLOCK;
1304 return AFPERR_ACCESS;
1307 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1308 return AFPERR_PARAM;
1312 /* resolve a file id */
1313 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1316 int ibuflen, *rbuflen;
1324 u_int16_t vid, bitmap;
1327 syslog(LOG_INFO, "begin afp_resolveid:");
1333 memcpy(&vid, ibuf, sizeof(vid));
1334 ibuf += sizeof(vid);
1336 if (( vol = getvolbyvid( vid )) == NULL ) {
1337 return( AFPERR_PARAM);
1340 memcpy(&id, ibuf, sizeof( id ));
1343 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1344 return AFPERR_BADID;
1347 if (( dir = dirsearch( vol, id )) == NULL ) {
1348 return( AFPERR_PARAM );
1351 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1355 return AFPERR_ACCESS;
1359 return AFPERR_PARAM;
1363 /* directories are bad */
1364 if (S_ISDIR(st.st_mode))
1365 return AFPERR_BADTYPE;
1367 memcpy(&bitmap, ibuf, sizeof(bitmap));
1368 bitmap = ntohs( bitmap );
1370 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1371 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1374 *rbuflen = buflen + sizeof(bitmap);
1375 memcpy(rbuf, ibuf, sizeof(bitmap));
1378 syslog(LOG_INFO, "end afp_resolveid:");
1384 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1387 int ibuflen, *rbuflen;
1398 syslog(LOG_INFO, "begin afp_deleteid:");
1404 memcpy(&vid, ibuf, sizeof(vid));
1405 ibuf += sizeof(vid);
1407 if (( vol = getvolbyvid( vid )) == NULL ) {
1408 return( AFPERR_PARAM);
1411 if (vol->v_flags & AFPVOL_RO)
1412 return AFPERR_VLOCK;
1414 memcpy(&id, ibuf, sizeof( id ));
1417 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1421 if (( dir = dirsearch( vol, id )) == NULL ) {
1422 return( AFPERR_PARAM );
1426 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1430 return AFPERR_ACCESS;
1432 /* still try to delete the id */
1436 return AFPERR_PARAM;
1440 /* directories are bad */
1441 if (S_ISDIR(st.st_mode))
1442 return AFPERR_BADTYPE;
1444 if (cnid_delete(vol->v_db, id)) {
1447 return AFPERR_VLOCK;
1450 return AFPERR_ACCESS;
1452 return AFPERR_PARAM;
1457 syslog(LOG_INFO, "end afp_deleteid:");
1464 #define APPLETEMP ".AppleTempXXXXXX"
1465 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1468 int ibuflen, *rbuflen;
1470 struct stat srcst, destst;
1472 struct dir *dir, *sdir;
1473 char *spath, temp[17], *path, *p;
1474 char *supath, *upath;
1476 #if AD_VERSION > AD_VERSION1
1483 syslog(LOG_INFO, "begin afp_exchangefiles:");
1489 memcpy(&vid, ibuf, sizeof(vid));
1490 ibuf += sizeof(vid);
1492 if (( vol = getvolbyvid( vid )) == NULL ) {
1493 return( AFPERR_PARAM);
1496 if (vol->v_flags & AFPVOL_RO)
1497 return AFPERR_VLOCK;
1499 /* source and destination dids */
1500 memcpy(&sid, ibuf, sizeof(sid));
1501 ibuf += sizeof(sid);
1502 memcpy(&did, ibuf, sizeof(did));
1503 ibuf += sizeof(did);
1506 if ((dir = dirsearch( vol, sid )) == NULL ) {
1507 return( AFPERR_PARAM );
1510 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1511 return( AFPERR_PARAM );
1514 if ( *path == '\0' ) {
1515 return( AFPERR_BADTYPE );
1518 upath = mtoupath(vol, path);
1519 if (stat(upath, &srcst) < 0) {
1525 return AFPERR_ACCESS;
1527 return AFPERR_PARAM;
1531 /* save some stuff */
1533 spath = obj->oldtmp;
1534 supath = obj->newtmp;
1535 strcpy(spath, path);
1536 strcpy(supath, upath); /* this is for the cnid changing */
1537 p = ctoupath( vol, sdir, spath);
1539 /* look for the source cnid. if it doesn't exist, don't worry about
1541 #if AD_VERSION > AD_VERSION1
1542 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1543 slen = strlen(supath));
1546 if (( dir = dirsearch( vol, did )) == NULL ) {
1547 return( AFPERR_PARAM );
1550 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1551 return( AFPERR_PARAM );
1554 if ( *path == '\0' ) {
1555 return( AFPERR_BADTYPE );
1558 /* FPExchangeFiles is the only call that can return the SameObj
1560 if ((curdir == sdir) && strcmp(spath, path) == 0)
1561 return AFPERR_SAMEOBJ;
1563 upath = mtoupath(vol, path);
1564 if (stat(upath, &destst) < 0) {
1570 return AFPERR_ACCESS;
1572 return AFPERR_PARAM;
1576 #if AD_VERSION > AD_VERSION1
1577 /* look for destination id. */
1578 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1579 dlen = strlen(upath));
1582 /* construct a temp name.
1583 * NOTE: the temp file will be in the dest file's directory. it
1584 * will also be inaccessible from AFP. */
1585 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1589 /* now, quickly rename the file. we error if we can't. */
1590 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1591 goto err_exchangefile;
1592 of_rename(vol, sdir, spath, curdir, temp);
1594 /* rename destination to source */
1595 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1596 goto err_src_to_tmp;
1597 of_rename(vol, curdir, path, sdir, spath);
1599 /* rename temp to destination */
1600 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1601 goto err_dest_to_src;
1602 of_rename(vol, curdir, temp, curdir, path);
1604 #if AD_VERSION > AD_VERSION1
1605 /* id's need switching. src -> dest and dest -> src. */
1606 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1607 upath, dlen) < 0)) {
1611 err = AFPERR_ACCESS;
1615 goto err_temp_to_dest;
1618 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1619 supath, slen) < 0)) {
1623 err = AFPERR_ACCESS;
1629 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1630 goto err_temp_to_dest;
1635 syslog(LOG_INFO, "ending afp_exchangefiles:");
1641 /* all this stuff is so that we can unwind a failed operation
1644 /* rename dest to temp */
1645 renamefile(upath, temp, temp, vol_noadouble(vol));
1646 of_rename(vol, curdir, upath, curdir, temp);
1649 /* rename source back to dest */
1650 renamefile(p, upath, path, vol_noadouble(vol));
1651 of_rename(vol, sdir, spath, curdir, path);
1654 /* rename temp back to source */
1655 renamefile(temp, p, spath, vol_noadouble(vol));
1656 of_rename(vol, curdir, temp, sdir, spath);