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 if (vol->v_flags & AFPVOL_DROPBOX) {
449 retvalue=matchfile2dirperms(upath, vol, did);
453 setvoltime(obj, vol );
456 syslog(LOG_INFO, "end afp_createfile");
460 /* bring everything back to old euid, egid */
461 restore_uidgid ( uidgid );
467 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
470 int ibuflen, *rbuflen;
476 u_int16_t vid, bitmap;
479 syslog(LOG_INFO, "begin afp_setfilparams:");
485 memcpy(&vid, ibuf, sizeof( vid ));
486 ibuf += sizeof( vid );
487 if (( vol = getvolbyvid( vid )) == NULL ) {
488 return( AFPERR_PARAM );
491 if (vol->v_flags & AFPVOL_RO)
494 memcpy(&did, ibuf, sizeof( did ));
495 ibuf += sizeof( did );
496 if (( dir = dirsearch( vol, did )) == NULL ) {
497 return( AFPERR_NOOBJ );
500 memcpy(&bitmap, ibuf, sizeof( bitmap ));
501 bitmap = ntohs( bitmap );
502 ibuf += sizeof( bitmap );
504 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
505 return( AFPERR_NOOBJ );
508 if ((u_long)ibuf & 1 ) {
512 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
513 setvoltime(obj, vol );
517 syslog(LOG_INFO, "end afp_setfilparams:");
524 int setfilparams(vol, path, bitmap, buf )
529 struct adouble ad, *adp;
532 int bit = 0, isad = 1, err = AFP_OK;
534 u_char achar, *fdType, xyy[4];
535 u_int16_t ashort, bshort;
544 syslog(LOG_INFO, "begin setfilparams:");
547 upath = mtoupath(vol, path);
548 if ((of = of_findname(vol, curdir, path))) {
551 memset(&ad, 0, sizeof(ad));
556 save_uidgid ( uidgid );
560 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
561 O_RDWR|O_CREAT, 0666, adp) < 0) {
562 /* for some things, we don't need an adouble header */
563 if (bitmap & ~(1<<FILPBIT_MDATE)) {
565 restore_uidgid ( uidgid );
567 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
570 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
571 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
572 memcpy(ad_entry( adp, ADEID_NAME ), path,
573 ad_getentrylen( adp, ADEID_NAME ));
576 while ( bitmap != 0 ) {
577 while (( bitmap & 1 ) == 0 ) {
584 memcpy(&ashort, buf, sizeof( ashort ));
585 ad_getattr(adp, &bshort);
586 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
587 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
591 ad_setattr(adp, bshort);
592 buf += sizeof( ashort );
596 memcpy(&aint, buf, sizeof(aint));
597 ad_setdate(adp, AD_DATE_CREATE, aint);
598 buf += sizeof( aint );
602 memcpy(&aint, buf, sizeof( aint ));
604 ad_setdate(adp, AD_DATE_MODIFY, aint);
605 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
607 buf += sizeof( aint );
611 memcpy(&aint, buf, sizeof(aint));
612 ad_setdate(adp, AD_DATE_BACKUP, aint);
613 buf += sizeof( aint );
617 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
618 && (em = getextmap( path )) &&
619 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
620 (memcmp(buf + 4, em->em_creator,
621 sizeof( em->em_creator )) == 0)) {
622 memcpy(buf, ufinderi, 8 );
624 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
628 /* Client needs to set the ProDOS file info for this file.
629 Use defined strings for the simple cases, and convert
630 all else into pXYY per Inside Appletalk. Always set
631 the creator as "pdos". <shirsch@ibm.net> */
632 case FILPBIT_PDINFO :
635 memcpy(&ashort, buf, sizeof( ashort ));
636 ashort = ntohs( ashort );
639 switch ( (unsigned int) achar )
642 fdType = ( u_char *) "TEXT";
646 fdType = ( u_char *) "PSYS";
650 fdType = ( u_char *) "PS16";
654 fdType = ( u_char *) "BINA";
658 xyy[0] = ( u_char ) 'p';
660 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
661 xyy[3] = ( u_char ) ashort & 0xff;
666 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
667 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
673 goto setfilparam_done;
682 ad_flush( adp, ADFLAGS_HF );
683 ad_close( adp, ADFLAGS_HF );
686 restore_uidgid ( uidgid );
692 syslog(LOG_INFO, "end setfilparams:");
699 * renamefile and copyfile take the old and new unix pathnames
700 * and the new mac name.
701 * NOTE: if we have to copy a file instead of renaming it, locks
704 int renamefile(src, dst, newname, noadouble )
705 char *src, *dst, *newname;
709 char adsrc[ MAXPATHLEN + 1];
713 * Note that this is only checking the existance of the data file,
714 * not the header file. The thinking is that if the data file doesn't
715 * exist, but the header file does, the right thing to do is remove
716 * the data file silently.
719 /* existence check moved to afp_moveandrename */
722 syslog (LOG_INFO, "begin renamefile:");
725 if ( rename( src, dst ) < 0 ) {
728 return( AFPERR_NOOBJ );
731 return( AFPERR_ACCESS );
734 case EXDEV : /* Cross device move -- try copy */
735 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
739 return deletefile( src );
741 return( AFPERR_PARAM );
745 strcpy( adsrc, ad_path( src, 0 ));
748 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
753 /* check for a source appledouble header. if it exists, make
754 * a dest appledouble directory and do the rename again. */
755 memset(&ad, 0, sizeof(ad));
756 if (rc || stat(adsrc, &st) ||
757 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
760 ad_close(&ad, ADFLAGS_HF);
764 return( AFPERR_ACCESS );
768 return( AFPERR_PARAM );
772 memset(&ad, 0, sizeof(ad));
773 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
776 return( AFPERR_NOOBJ );
778 return( AFPERR_ACCESS );
782 return( AFPERR_PARAM );
786 len = strlen( newname );
787 ad_setentrylen( &ad, ADEID_NAME, len );
788 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
789 ad_flush( &ad, ADFLAGS_HF );
790 ad_close( &ad, ADFLAGS_HF );
793 syslog (LOG_INFO, "end renamefile:");
799 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
802 int ibuflen, *rbuflen;
806 char *newname, *path, *p;
807 u_int32_t sdid, ddid;
808 int plen, err, did, retvalue = AFP_OK;
809 u_int16_t svid, dvid;
812 syslog (LOG_INFO, "begin afp_copyfile:");
818 memcpy(&svid, ibuf, sizeof( svid ));
819 ibuf += sizeof( svid );
820 if (( vol = getvolbyvid( svid )) == NULL ) {
821 return( AFPERR_PARAM );
824 memcpy(&sdid, ibuf, sizeof( sdid ));
825 ibuf += sizeof( sdid );
826 if (( dir = dirsearch( vol, sdid )) == NULL ) {
827 return( AFPERR_PARAM );
830 memcpy(&dvid, ibuf, sizeof( dvid ));
831 ibuf += sizeof( dvid );
832 memcpy(&ddid, ibuf, sizeof( ddid ));
833 ibuf += sizeof( ddid );
835 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
836 return( AFPERR_NOOBJ );
838 if ( *path == '\0' ) {
839 return( AFPERR_BADTYPE );
842 /* don't allow copies when the file is open.
843 * XXX: the spec only calls for read/deny write access.
844 * however, copyfile doesn't have any of that info,
845 * and locks need to stay coherent. as a result,
846 * we just balk if the file is opened already. */
847 if (of_findname(vol, curdir, path))
848 return AFPERR_DENYCONF;
850 newname = obj->newtmp;
851 strcpy( newname, path );
853 p = ctoupath( vol, curdir, newname );
855 if (( vol = getvolbyvid( dvid )) == NULL ) {
856 return( AFPERR_PARAM );
859 if (vol->v_flags & AFPVOL_RO)
862 if (( dir = dirsearch( vol, ddid )) == NULL ) {
863 return( AFPERR_PARAM );
866 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
867 return( AFPERR_NOOBJ );
869 if ( *path != '\0' ) {
870 return( AFPERR_BADTYPE );
873 /* one of the handful of places that knows about the path type */
874 if ( *ibuf++ != 2 ) {
875 return( AFPERR_PARAM );
877 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
878 strncpy( newname, ibuf, plen );
879 newname[ plen ] = '\0';
882 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
883 vol_noadouble(vol))) < 0 ) {
887 setvoltime(obj, vol );
890 if (vol->v_flags & AFPVOL_DROPBOX) {
891 retvalue=matchfile2dirperms(newname, vol, sdid);
896 syslog (LOG_INFO, "end afp_copyfile:");
903 static __inline__ int copy_all(const int dfd, const void *buf,
909 syslog(LOG_INFO, "begin copy_all:");
913 if ((cc = write(dfd, buf, buflen)) < 0) {
931 syslog(LOG_INFO, "end copy_all:");
937 /* XXX: this needs to use ad_open and ad_lock. so, we need to
938 * pass in vol and path */
939 int copyfile(src, dst, newname, noadouble )
940 char *src, *dst, *newname;
946 int sfd, dfd, len, err = AFP_OK;
950 syslog(LOG_INFO, "begin copyfile:");
954 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
957 break; /* just copy the data fork */
959 return( AFPERR_ACCESS );
961 return( AFPERR_PARAM );
964 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
965 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
969 return( AFPERR_NOOBJ );
971 return( AFPERR_ACCESS );
975 return( AFPERR_PARAM );
980 #ifdef SENDFILE_FLAVOR_LINUX
981 if (fstat(sfd, &st) == 0) {
982 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
996 goto copyheader_done;
1000 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1007 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1015 unlink(ad_path(dst, ADFLAGS_HF));
1021 /* data fork copying */
1022 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1025 return( AFPERR_NOOBJ );
1027 return( AFPERR_ACCESS );
1029 return( AFPERR_PARAM );
1033 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1037 return( AFPERR_NOOBJ );
1039 return( AFPERR_ACCESS );
1041 return AFPERR_VLOCK;
1043 return( AFPERR_PARAM );
1047 #ifdef SENDFILE_FLAVOR_LINUX
1048 if (fstat(sfd, &st) == 0) {
1049 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1065 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1073 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1082 unlink(ad_path(dst, ADFLAGS_HF));
1088 memset(&ad, 0, sizeof(ad));
1089 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1093 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1095 return( AFPERR_ACCESS );
1097 return AFPERR_VLOCK;
1099 return( AFPERR_PARAM );
1103 len = strlen( newname );
1104 ad_setentrylen( &ad, ADEID_NAME, len );
1105 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1106 ad_flush( &ad, ADFLAGS_HF );
1107 ad_close( &ad, ADFLAGS_HF );
1111 syslog(LOG_INFO, "end copyfile:");
1118 int deletefile( file )
1122 int adflags, err = AFP_OK;
1125 syslog(LOG_INFO, "begin deletefile:");
1128 /* try to open both at once */
1129 adflags = ADFLAGS_DF|ADFLAGS_HF;
1130 memset(&ad, 0, sizeof(ad));
1131 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1134 adflags = ADFLAGS_DF;
1135 /* that failed. now try to open just the data fork */
1136 memset(&ad, 0, sizeof(ad));
1137 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1140 return AFPERR_NOOBJ;
1142 return AFPERR_ACCESS;
1144 return AFPERR_PARAM;
1150 return( AFPERR_ACCESS );
1152 return AFPERR_VLOCK;
1154 return( AFPERR_PARAM );
1158 if ((adflags & ADFLAGS_HF) &&
1159 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1160 ad_close( &ad, adflags );
1161 return( AFPERR_BUSY );
1164 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1169 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1173 err = AFPERR_ACCESS;
1186 if ( unlink( file ) < 0 ) {
1190 err = AFPERR_ACCESS;
1204 if (adflags & ADFLAGS_HF)
1205 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1206 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1207 ad_close( &ad, adflags );
1210 syslog(LOG_INFO, "end deletefile:");
1217 #if AD_VERSION > AD_VERSION1
1218 /* return a file id */
1219 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1222 int ibuflen, *rbuflen;
1234 syslog(LOG_INFO, "begin afp_createid:");
1240 memcpy(&vid, ibuf, sizeof(vid));
1241 ibuf += sizeof(vid);
1243 if (( vol = getvolbyvid( vid )) == NULL ) {
1244 return( AFPERR_PARAM);
1247 if (vol->v_flags & AFPVOL_RO)
1248 return AFPERR_VLOCK;
1250 memcpy(&did, ibuf, sizeof( did ));
1251 ibuf += sizeof(did);
1253 if (( dir = dirsearch( vol, did )) == NULL ) {
1254 return( AFPERR_PARAM );
1257 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1258 return( AFPERR_PARAM );
1261 if ( *path == '\0' ) {
1262 return( AFPERR_BADTYPE );
1265 upath = mtoupath(vol, path);
1266 if (stat(upath, &st) < 0) {
1270 return AFPERR_ACCESS;
1272 return AFPERR_NOOBJ;
1274 return AFPERR_PARAM;
1278 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1279 memcpy(rbuf, &id, sizeof(id));
1280 *rbuflen = sizeof(id);
1281 return AFPERR_EXISTID;
1284 memset(&ad, 0, sizeof(ad));
1285 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1288 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1289 ad_close(upath, ADFLAGS_HF);
1292 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1293 memcpy(rbuf, &id, sizeof(id));
1294 *rbuflen = sizeof(id);
1299 syslog(LOG_INFO, "ending afp_createid...:");
1304 return AFPERR_VLOCK;
1308 return AFPERR_ACCESS;
1311 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1312 return AFPERR_PARAM;
1316 /* resolve a file id */
1317 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1320 int ibuflen, *rbuflen;
1328 u_int16_t vid, bitmap;
1331 syslog(LOG_INFO, "begin afp_resolveid:");
1337 memcpy(&vid, ibuf, sizeof(vid));
1338 ibuf += sizeof(vid);
1340 if (( vol = getvolbyvid( vid )) == NULL ) {
1341 return( AFPERR_PARAM);
1344 memcpy(&id, ibuf, sizeof( id ));
1347 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1348 return AFPERR_BADID;
1351 if (( dir = dirsearch( vol, id )) == NULL ) {
1352 return( AFPERR_PARAM );
1355 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1359 return AFPERR_ACCESS;
1363 return AFPERR_PARAM;
1367 /* directories are bad */
1368 if (S_ISDIR(st.st_mode))
1369 return AFPERR_BADTYPE;
1371 memcpy(&bitmap, ibuf, sizeof(bitmap));
1372 bitmap = ntohs( bitmap );
1374 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1375 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1378 *rbuflen = buflen + sizeof(bitmap);
1379 memcpy(rbuf, ibuf, sizeof(bitmap));
1382 syslog(LOG_INFO, "end afp_resolveid:");
1388 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1391 int ibuflen, *rbuflen;
1402 syslog(LOG_INFO, "begin afp_deleteid:");
1408 memcpy(&vid, ibuf, sizeof(vid));
1409 ibuf += sizeof(vid);
1411 if (( vol = getvolbyvid( vid )) == NULL ) {
1412 return( AFPERR_PARAM);
1415 if (vol->v_flags & AFPVOL_RO)
1416 return AFPERR_VLOCK;
1418 memcpy(&id, ibuf, sizeof( id ));
1421 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1425 if (( dir = dirsearch( vol, id )) == NULL ) {
1426 return( AFPERR_PARAM );
1430 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1434 return AFPERR_ACCESS;
1436 /* still try to delete the id */
1440 return AFPERR_PARAM;
1444 /* directories are bad */
1445 if (S_ISDIR(st.st_mode))
1446 return AFPERR_BADTYPE;
1448 if (cnid_delete(vol->v_db, id)) {
1451 return AFPERR_VLOCK;
1454 return AFPERR_ACCESS;
1456 return AFPERR_PARAM;
1461 syslog(LOG_INFO, "end afp_deleteid:");
1468 #define APPLETEMP ".AppleTempXXXXXX"
1469 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1472 int ibuflen, *rbuflen;
1474 struct stat srcst, destst;
1476 struct dir *dir, *sdir;
1477 char *spath, temp[17], *path, *p;
1478 char *supath, *upath;
1480 #if AD_VERSION > AD_VERSION1
1487 syslog(LOG_INFO, "begin afp_exchangefiles:");
1493 memcpy(&vid, ibuf, sizeof(vid));
1494 ibuf += sizeof(vid);
1496 if (( vol = getvolbyvid( vid )) == NULL ) {
1497 return( AFPERR_PARAM);
1500 if (vol->v_flags & AFPVOL_RO)
1501 return AFPERR_VLOCK;
1503 /* source and destination dids */
1504 memcpy(&sid, ibuf, sizeof(sid));
1505 ibuf += sizeof(sid);
1506 memcpy(&did, ibuf, sizeof(did));
1507 ibuf += sizeof(did);
1510 if ((dir = dirsearch( vol, sid )) == NULL ) {
1511 return( AFPERR_PARAM );
1514 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1515 return( AFPERR_PARAM );
1518 if ( *path == '\0' ) {
1519 return( AFPERR_BADTYPE );
1522 upath = mtoupath(vol, path);
1523 if (stat(upath, &srcst) < 0) {
1529 return AFPERR_ACCESS;
1531 return AFPERR_PARAM;
1535 /* save some stuff */
1537 spath = obj->oldtmp;
1538 supath = obj->newtmp;
1539 strcpy(spath, path);
1540 strcpy(supath, upath); /* this is for the cnid changing */
1541 p = ctoupath( vol, sdir, spath);
1543 /* look for the source cnid. if it doesn't exist, don't worry about
1545 #if AD_VERSION > AD_VERSION1
1546 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1547 slen = strlen(supath));
1550 if (( dir = dirsearch( vol, did )) == NULL ) {
1551 return( AFPERR_PARAM );
1554 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1555 return( AFPERR_PARAM );
1558 if ( *path == '\0' ) {
1559 return( AFPERR_BADTYPE );
1562 /* FPExchangeFiles is the only call that can return the SameObj
1564 if ((curdir == sdir) && strcmp(spath, path) == 0)
1565 return AFPERR_SAMEOBJ;
1567 upath = mtoupath(vol, path);
1568 if (stat(upath, &destst) < 0) {
1574 return AFPERR_ACCESS;
1576 return AFPERR_PARAM;
1580 #if AD_VERSION > AD_VERSION1
1581 /* look for destination id. */
1582 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1583 dlen = strlen(upath));
1586 /* construct a temp name.
1587 * NOTE: the temp file will be in the dest file's directory. it
1588 * will also be inaccessible from AFP. */
1589 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1593 /* now, quickly rename the file. we error if we can't. */
1594 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1595 goto err_exchangefile;
1596 of_rename(vol, sdir, spath, curdir, temp);
1598 /* rename destination to source */
1599 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1600 goto err_src_to_tmp;
1601 of_rename(vol, curdir, path, sdir, spath);
1603 /* rename temp to destination */
1604 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1605 goto err_dest_to_src;
1606 of_rename(vol, curdir, temp, curdir, path);
1608 #if AD_VERSION > AD_VERSION1
1609 /* id's need switching. src -> dest and dest -> src. */
1610 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1611 upath, dlen) < 0)) {
1615 err = AFPERR_ACCESS;
1619 goto err_temp_to_dest;
1622 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1623 supath, slen) < 0)) {
1627 err = AFPERR_ACCESS;
1633 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1634 goto err_temp_to_dest;
1639 syslog(LOG_INFO, "ending afp_exchangefiles:");
1645 /* all this stuff is so that we can unwind a failed operation
1648 /* rename dest to temp */
1649 renamefile(upath, temp, temp, vol_noadouble(vol));
1650 of_rename(vol, curdir, upath, curdir, temp);
1653 /* rename source back to dest */
1654 renamefile(p, upath, path, vol_noadouble(vol));
1655 of_rename(vol, sdir, spath, curdir, path);
1658 /* rename temp back to source */
1659 renamefile(temp, p, spath, vol_noadouble(vol));
1660 of_rename(vol, curdir, temp, sdir, spath);