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];
85 syslog(LOG_INFO, "begin getfilparams:");
88 upath = mtoupath(vol, path);
89 if ((of = of_findname(vol, curdir, path))) {
92 memset(&ad, 0, sizeof(ad));
96 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
98 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
99 syslog( LOG_ERR, "getfilparams fstat: %m" );
103 while ( bitmap != 0 ) {
104 while (( bitmap & 1 ) == 0 ) {
112 ad_getattr(adp, &ashort);
113 } else if (*upath == '.') {
114 ashort = htons(ATTRBIT_INVISIBLE);
117 memcpy(data, &ashort, sizeof( ashort ));
118 data += sizeof( u_short );
122 memcpy(data, &dir->d_did, sizeof( int ));
123 data += sizeof( int );
127 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
128 aint = AD_DATE_FROM_UNIX(st->st_mtime);
129 memcpy(data, &aint, sizeof( aint ));
130 data += sizeof( aint );
134 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
135 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
136 (hst.st_mtime < st->st_mtime)) {
137 aint = AD_DATE_FROM_UNIX(st->st_mtime);
140 aint = AD_DATE_FROM_UNIX(st->st_mtime);
142 memcpy(data, &aint, sizeof( int ));
143 data += sizeof( int );
147 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
148 aint = AD_DATE_START;
149 memcpy(data, &aint, sizeof( int ));
150 data += sizeof( int );
155 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
157 memcpy(data, ufinderi, 32);
158 if (*upath == '.') { /* make it invisible */
159 ashort = htons(FINDERINFO_INVISIBLE);
160 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
164 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
165 ufinderi, 8 ) == 0)) &&
166 (em = getextmap( path ))) {
167 memcpy(data, em->em_type, sizeof( em->em_type ));
168 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
175 data += sizeof( u_int16_t );
179 memset(data, 0, sizeof(u_int16_t));
180 data += sizeof( u_int16_t );
184 #if AD_VERSION > AD_VERSION1
185 /* use the CNID database if we're using AD v2 */
187 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
191 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
192 strlen(upath), aint))) {
195 * What a fucking mess. First thing: DID and FNUMs are
196 * in the same space for purposes of enumerate (and several
197 * other wierd places). While we consider this Apple's bug,
198 * this is the work-around: In order to maintain constant and
199 * unique DIDs and FNUMs, we monotonically generate the DIDs
200 * during the session, and derive the FNUMs from the filesystem.
201 * Since the DIDs are small, we insure that the FNUMs are fairly
202 * large by setting thier high bits to the device number.
204 * AFS already does something very similar to this for the
205 * inode number, so we don't repeat the procedure.
208 * due to complaints over did's being non-persistent,
209 * here's the current hack to provide semi-persistent
211 * 1) we reserve the first bit for file ids.
212 * 2) the next 7 bits are for the device.
213 * 3) the remaining 24 bits are for the inode.
215 * both the inode and device information are actually hashes
216 * that are then truncated to the requisite bit length.
218 * it should be okay to use lstat to deal with symlinks.
220 lstp = (lstat(upath, &lst) < 0) ? st : &lst;
221 aint = htonl(CNID(lstp, 1));
222 #if AD_VERSION > AD_VERSION1
225 memcpy(data, &aint, sizeof( aint ));
226 data += sizeof( aint );
230 aint = htonl( st->st_size );
231 memcpy(data, &aint, sizeof( aint ));
232 data += sizeof( aint );
237 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
241 memcpy(data, &aint, sizeof( aint ));
242 data += sizeof( aint );
245 /* Current client needs ProDOS info block for this file.
246 Use simple heuristic and let the Mac "type" string tell
247 us what the PD file code should be. Everything gets a
248 subtype of 0x0000 unless the original value was hashed
249 to "pXYZ" when we created it. See IA, Ver 2.
251 case FILPBIT_PDINFO :
253 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
255 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
259 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
263 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
267 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
271 else if ( fdType[0] == 'p' ) {
273 ashort = (fdType[2] * 256) + fdType[3];
287 memcpy(data, &ashort, sizeof( ashort ));
288 data += sizeof( ashort );
289 memset(data, 0, sizeof( ashort ));
290 data += sizeof( ashort );
295 ad_close( adp, ADFLAGS_HF );
297 return( AFPERR_BITMAP );
303 ashort = htons( data - buf );
304 memcpy(nameoff, &ashort, sizeof( ashort ));
305 if ((aint = strlen( path )) > MACFILELEN)
308 memcpy(data, path, aint );
312 ad_close( adp, ADFLAGS_HF );
314 *buflen = data - buf;
317 syslog(LOG_INFO, "end getfilparams:");
323 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
326 int ibuflen, *rbuflen;
329 struct adouble ad, *adp;
334 int creatf, did, openf, retvalue = AFP_OK;
338 syslog(LOG_INFO, "begin afp_createfile:");
343 creatf = (unsigned char) *ibuf++;
345 memcpy(&vid, ibuf, sizeof( vid ));
346 ibuf += sizeof( vid );
348 if (( vol = getvolbyvid( vid )) == NULL ) {
349 return( AFPERR_PARAM );
352 if (vol->v_flags & AFPVOL_RO)
355 memcpy(&did, ibuf, sizeof( did));
356 ibuf += sizeof( did );
358 if (( dir = dirsearch( vol, did )) == NULL ) {
359 return( AFPERR_NOOBJ );
362 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
363 return( AFPERR_NOOBJ );
366 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
367 strpbrk(path, MSWINDOWS_BADCHARS))
370 upath = mtoupath(vol, path);
372 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
375 if (!validupath(vol, upath))
378 if ((of = of_findname(vol, curdir, path))) {
381 memset(&ad, 0, sizeof(ad));
385 /* on a hard create, fail if file exists and is open */
386 if ((stat(upath, &st) == 0) && of)
388 openf = O_RDWR|O_CREAT|O_TRUNC;
390 openf = O_RDWR|O_CREAT|O_EXCL;
393 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
394 openf, 0666, adp) < 0 ) {
397 return( AFPERR_EXIST );
399 return( AFPERR_ACCESS );
401 /* on noadouble volumes, just creating the data fork is ok */
402 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
403 goto createfile_done;
406 return( AFPERR_PARAM );
410 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
411 memcpy(ad_entry( adp, ADEID_NAME ), path,
412 ad_getentrylen( adp, ADEID_NAME ));
413 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
414 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
419 retvalue=matchfile2dirperms(upath, vol, did);
422 setvoltime(obj, vol );
425 syslog(LOG_INFO, "end afp_createfile");
431 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
434 int ibuflen, *rbuflen;
440 u_int16_t vid, bitmap;
443 syslog(LOG_INFO, "begin afp_setfilparams:");
449 memcpy(&vid, ibuf, sizeof( vid ));
450 ibuf += sizeof( vid );
451 if (( vol = getvolbyvid( vid )) == NULL ) {
452 return( AFPERR_PARAM );
455 if (vol->v_flags & AFPVOL_RO)
458 memcpy(&did, ibuf, sizeof( did ));
459 ibuf += sizeof( did );
460 if (( dir = dirsearch( vol, did )) == NULL ) {
461 return( AFPERR_NOOBJ );
464 memcpy(&bitmap, ibuf, sizeof( bitmap ));
465 bitmap = ntohs( bitmap );
466 ibuf += sizeof( bitmap );
468 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
469 return( AFPERR_NOOBJ );
472 if ((u_long)ibuf & 1 ) {
476 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
477 setvoltime(obj, vol );
481 syslog(LOG_INFO, "end afp_setfilparams:");
488 int setfilparams(vol, path, bitmap, buf )
493 struct adouble ad, *adp;
496 int bit = 0, isad = 1, err = AFP_OK;
498 u_char achar, *fdType, xyy[4];
499 u_int16_t ashort, bshort;
504 syslog(LOG_INFO, "begin setfilparams:");
507 upath = mtoupath(vol, path);
508 if ((of = of_findname(vol, curdir, path))) {
511 memset(&ad, 0, sizeof(ad));
514 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
515 O_RDWR|O_CREAT, 0666, adp) < 0) {
516 /* for some things, we don't need an adouble header */
517 if (bitmap & ~(1<<FILPBIT_MDATE)) {
518 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
521 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
522 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
523 memcpy(ad_entry( adp, ADEID_NAME ), path,
524 ad_getentrylen( adp, ADEID_NAME ));
527 while ( bitmap != 0 ) {
528 while (( bitmap & 1 ) == 0 ) {
535 memcpy(&ashort, buf, sizeof( ashort ));
536 ad_getattr(adp, &bshort);
537 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
538 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
542 ad_setattr(adp, bshort);
543 buf += sizeof( ashort );
547 memcpy(&aint, buf, sizeof(aint));
548 ad_setdate(adp, AD_DATE_CREATE, aint);
549 buf += sizeof( aint );
553 memcpy(&aint, buf, sizeof( aint ));
555 ad_setdate(adp, AD_DATE_MODIFY, aint);
556 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
558 buf += sizeof( aint );
562 memcpy(&aint, buf, sizeof(aint));
563 ad_setdate(adp, AD_DATE_BACKUP, aint);
564 buf += sizeof( aint );
568 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
569 && (em = getextmap( path )) &&
570 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
571 (memcmp(buf + 4, em->em_creator,
572 sizeof( em->em_creator )) == 0)) {
573 memcpy(buf, ufinderi, 8 );
575 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
579 /* Client needs to set the ProDOS file info for this file.
580 Use defined strings for the simple cases, and convert
581 all else into pXYY per Inside Appletalk. Always set
582 the creator as "pdos". <shirsch@ibm.net> */
583 case FILPBIT_PDINFO :
586 memcpy(&ashort, buf, sizeof( ashort ));
587 ashort = ntohs( ashort );
590 switch ( (unsigned int) achar )
593 fdType = ( u_char *) "TEXT";
597 fdType = ( u_char *) "PSYS";
601 fdType = ( u_char *) "PS16";
605 fdType = ( u_char *) "BINA";
609 xyy[0] = ( u_char ) 'p';
611 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
612 xyy[3] = ( u_char ) ashort & 0xff;
617 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
618 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
624 goto setfilparam_done;
633 ad_flush( adp, ADFLAGS_HF );
634 ad_close( adp, ADFLAGS_HF );
638 syslog(LOG_INFO, "end setfilparams:");
645 * renamefile and copyfile take the old and new unix pathnames
646 * and the new mac name.
647 * NOTE: if we have to copy a file instead of renaming it, locks
650 int renamefile(src, dst, newname, noadouble )
651 char *src, *dst, *newname;
655 char adsrc[ MAXPATHLEN + 1];
659 * Note that this is only checking the existance of the data file,
660 * not the header file. The thinking is that if the data file doesn't
661 * exist, but the header file does, the right thing to do is remove
662 * the data file silently.
665 /* existence check moved to afp_moveandrename */
668 syslog (LOG_INFO, "begin renamefile:");
671 if ( rename( src, dst ) < 0 ) {
674 return( AFPERR_NOOBJ );
677 return( AFPERR_ACCESS );
680 case EXDEV : /* Cross device move -- try copy */
681 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
685 return deletefile( src );
687 return( AFPERR_PARAM );
691 strcpy( adsrc, ad_path( src, 0 ));
694 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
699 /* check for a source appledouble header. if it exists, make
700 * a dest appledouble directory and do the rename again. */
701 memset(&ad, 0, sizeof(ad));
702 if (rc || stat(adsrc, &st) ||
703 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
706 ad_close(&ad, ADFLAGS_HF);
710 return( AFPERR_ACCESS );
714 return( AFPERR_PARAM );
718 memset(&ad, 0, sizeof(ad));
719 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
722 return( AFPERR_NOOBJ );
724 return( AFPERR_ACCESS );
728 return( AFPERR_PARAM );
732 len = strlen( newname );
733 ad_setentrylen( &ad, ADEID_NAME, len );
734 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
735 ad_flush( &ad, ADFLAGS_HF );
736 ad_close( &ad, ADFLAGS_HF );
739 syslog (LOG_INFO, "end renamefile:");
745 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
748 int ibuflen, *rbuflen;
752 char *newname, *path, *p;
753 u_int32_t sdid, ddid;
754 int plen, err, did, retvalue = AFP_OK;
755 u_int16_t svid, dvid;
758 syslog (LOG_INFO, "begin afp_copyfile:");
764 memcpy(&svid, ibuf, sizeof( svid ));
765 ibuf += sizeof( svid );
766 if (( vol = getvolbyvid( svid )) == NULL ) {
767 return( AFPERR_PARAM );
770 memcpy(&sdid, ibuf, sizeof( sdid ));
771 ibuf += sizeof( sdid );
772 if (( dir = dirsearch( vol, sdid )) == NULL ) {
773 return( AFPERR_PARAM );
776 memcpy(&dvid, ibuf, sizeof( dvid ));
777 ibuf += sizeof( dvid );
778 memcpy(&ddid, ibuf, sizeof( ddid ));
779 ibuf += sizeof( ddid );
781 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
782 return( AFPERR_NOOBJ );
784 if ( *path == '\0' ) {
785 return( AFPERR_BADTYPE );
788 /* don't allow copies when the file is open.
789 * XXX: the spec only calls for read/deny write access.
790 * however, copyfile doesn't have any of that info,
791 * and locks need to stay coherent. as a result,
792 * we just balk if the file is opened already. */
793 if (of_findname(vol, curdir, path))
794 return AFPERR_DENYCONF;
796 newname = obj->newtmp;
797 strcpy( newname, path );
799 p = ctoupath( vol, curdir, newname );
801 if (( vol = getvolbyvid( dvid )) == NULL ) {
802 return( AFPERR_PARAM );
805 if (vol->v_flags & AFPVOL_RO)
808 if (( dir = dirsearch( vol, ddid )) == NULL ) {
809 return( AFPERR_PARAM );
812 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
813 return( AFPERR_NOOBJ );
815 if ( *path != '\0' ) {
816 return( AFPERR_BADTYPE );
819 /* one of the handful of places that knows about the path type */
820 if ( *ibuf++ != 2 ) {
821 return( AFPERR_PARAM );
823 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
824 strncpy( newname, ibuf, plen );
825 newname[ plen ] = '\0';
828 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
829 vol_noadouble(vol))) < 0 ) {
833 setvoltime(obj, vol );
836 retvalue=matchfile2dirperms(newname, vol, sdid);
840 syslog (LOG_INFO, "end afp_copyfile:");
847 static __inline__ int copy_all(const int dfd, const void *buf,
853 syslog(LOG_INFO, "begin copy_all:");
857 if ((cc = write(dfd, buf, buflen)) < 0) {
875 syslog(LOG_INFO, "end copy_all:");
881 /* XXX: this needs to use ad_open and ad_lock. so, we need to
882 * pass in vol and path */
883 int copyfile(src, dst, newname, noadouble )
884 char *src, *dst, *newname;
890 int sfd, dfd, len, err = AFP_OK;
894 syslog(LOG_INFO, "begin copyfile:");
898 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
901 break; /* just copy the data fork */
903 return( AFPERR_ACCESS );
905 return( AFPERR_PARAM );
908 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
909 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
913 return( AFPERR_NOOBJ );
915 return( AFPERR_ACCESS );
919 return( AFPERR_PARAM );
924 #ifdef SENDFILE_FLAVOR_LINUX
925 if (fstat(sfd, &st) == 0) {
926 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
940 goto copyheader_done;
944 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
951 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
959 unlink(ad_path(dst, ADFLAGS_HF));
965 /* data fork copying */
966 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
969 return( AFPERR_NOOBJ );
971 return( AFPERR_ACCESS );
973 return( AFPERR_PARAM );
977 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
981 return( AFPERR_NOOBJ );
983 return( AFPERR_ACCESS );
987 return( AFPERR_PARAM );
991 #ifdef SENDFILE_FLAVOR_LINUX
992 if (fstat(sfd, &st) == 0) {
993 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1009 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1017 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1026 unlink(ad_path(dst, ADFLAGS_HF));
1032 memset(&ad, 0, sizeof(ad));
1033 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1037 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1039 return( AFPERR_ACCESS );
1041 return AFPERR_VLOCK;
1043 return( AFPERR_PARAM );
1047 len = strlen( newname );
1048 ad_setentrylen( &ad, ADEID_NAME, len );
1049 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1050 ad_flush( &ad, ADFLAGS_HF );
1051 ad_close( &ad, ADFLAGS_HF );
1055 syslog(LOG_INFO, "end copyfile:");
1062 int deletefile( file )
1066 int adflags, err = AFP_OK;
1069 syslog(LOG_INFO, "begin deletefile:");
1072 /* try to open both at once */
1073 adflags = ADFLAGS_DF|ADFLAGS_HF;
1074 memset(&ad, 0, sizeof(ad));
1075 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1078 adflags = ADFLAGS_DF;
1079 /* that failed. now try to open just the data fork */
1080 memset(&ad, 0, sizeof(ad));
1081 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1084 return AFPERR_NOOBJ;
1086 return AFPERR_ACCESS;
1088 return AFPERR_PARAM;
1094 return( AFPERR_ACCESS );
1096 return AFPERR_VLOCK;
1098 return( AFPERR_PARAM );
1102 if ((adflags & ADFLAGS_HF) &&
1103 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1104 ad_close( &ad, adflags );
1105 return( AFPERR_BUSY );
1108 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1113 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1117 err = AFPERR_ACCESS;
1130 if ( unlink( file ) < 0 ) {
1134 err = AFPERR_ACCESS;
1148 if (adflags & ADFLAGS_HF)
1149 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1150 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1151 ad_close( &ad, adflags );
1154 syslog(LOG_INFO, "end deletefile:");
1161 #if AD_VERSION > AD_VERSION1
1162 /* return a file id */
1163 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1166 int ibuflen, *rbuflen;
1178 syslog(LOG_INFO, "begin afp_createid:");
1184 memcpy(&vid, ibuf, sizeof(vid));
1185 ibuf += sizeof(vid);
1187 if (( vol = getvolbyvid( vid )) == NULL ) {
1188 return( AFPERR_PARAM);
1191 if (vol->v_flags & AFPVOL_RO)
1192 return AFPERR_VLOCK;
1194 memcpy(&did, ibuf, sizeof( did ));
1195 ibuf += sizeof(did);
1197 if (( dir = dirsearch( vol, did )) == NULL ) {
1198 return( AFPERR_PARAM );
1201 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1202 return( AFPERR_PARAM );
1205 if ( *path == '\0' ) {
1206 return( AFPERR_BADTYPE );
1209 upath = mtoupath(vol, path);
1210 if (stat(upath, &st) < 0) {
1214 return AFPERR_ACCESS;
1216 return AFPERR_NOOBJ;
1218 return AFPERR_PARAM;
1222 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1223 memcpy(rbuf, &id, sizeof(id));
1224 *rbuflen = sizeof(id);
1225 return AFPERR_EXISTID;
1228 memset(&ad, 0, sizeof(ad));
1229 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1232 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1233 ad_close(upath, ADFLAGS_HF);
1236 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1237 memcpy(rbuf, &id, sizeof(id));
1238 *rbuflen = sizeof(id);
1243 syslog(LOG_INFO, "ending afp_createid...:");
1248 return AFPERR_VLOCK;
1252 return AFPERR_ACCESS;
1255 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1256 return AFPERR_PARAM;
1260 /* resolve a file id */
1261 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1264 int ibuflen, *rbuflen;
1272 u_int16_t vid, bitmap;
1275 syslog(LOG_INFO, "begin afp_resolveid:");
1281 memcpy(&vid, ibuf, sizeof(vid));
1282 ibuf += sizeof(vid);
1284 if (( vol = getvolbyvid( vid )) == NULL ) {
1285 return( AFPERR_PARAM);
1288 memcpy(&id, ibuf, sizeof( id ));
1291 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1292 return AFPERR_BADID;
1295 if (( dir = dirsearch( vol, id )) == NULL ) {
1296 return( AFPERR_PARAM );
1299 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1303 return AFPERR_ACCESS;
1307 return AFPERR_PARAM;
1311 /* directories are bad */
1312 if (S_ISDIR(st.st_mode))
1313 return AFPERR_BADTYPE;
1315 memcpy(&bitmap, ibuf, sizeof(bitmap));
1316 bitmap = ntohs( bitmap );
1318 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1319 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1322 *rbuflen = buflen + sizeof(bitmap);
1323 memcpy(rbuf, ibuf, sizeof(bitmap));
1326 syslog(LOG_INFO, "end afp_resolveid:");
1332 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1335 int ibuflen, *rbuflen;
1346 syslog(LOG_INFO, "begin afp_deleteid:");
1352 memcpy(&vid, ibuf, sizeof(vid));
1353 ibuf += sizeof(vid);
1355 if (( vol = getvolbyvid( vid )) == NULL ) {
1356 return( AFPERR_PARAM);
1359 if (vol->v_flags & AFPVOL_RO)
1360 return AFPERR_VLOCK;
1362 memcpy(&id, ibuf, sizeof( id ));
1365 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1369 if (( dir = dirsearch( vol, id )) == NULL ) {
1370 return( AFPERR_PARAM );
1374 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1378 return AFPERR_ACCESS;
1380 /* still try to delete the id */
1384 return AFPERR_PARAM;
1388 /* directories are bad */
1389 if (S_ISDIR(st.st_mode))
1390 return AFPERR_BADTYPE;
1392 if (cnid_delete(vol->v_db, id)) {
1395 return AFPERR_VLOCK;
1398 return AFPERR_ACCESS;
1400 return AFPERR_PARAM;
1405 syslog(LOG_INFO, "end afp_deleteid:");
1412 #define APPLETEMP ".AppleTempXXXXXX"
1413 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1416 int ibuflen, *rbuflen;
1418 struct stat srcst, destst;
1420 struct dir *dir, *sdir;
1421 char *spath, temp[17], *path, *p;
1422 char *supath, *upath;
1424 #if AD_VERSION > AD_VERSION1
1431 syslog(LOG_INFO, "begin afp_exchangefiles:");
1437 memcpy(&vid, ibuf, sizeof(vid));
1438 ibuf += sizeof(vid);
1440 if (( vol = getvolbyvid( vid )) == NULL ) {
1441 return( AFPERR_PARAM);
1444 if (vol->v_flags & AFPVOL_RO)
1445 return AFPERR_VLOCK;
1447 /* source and destination dids */
1448 memcpy(&sid, ibuf, sizeof(sid));
1449 ibuf += sizeof(sid);
1450 memcpy(&did, ibuf, sizeof(did));
1451 ibuf += sizeof(did);
1454 if ((dir = dirsearch( vol, sid )) == NULL ) {
1455 return( AFPERR_PARAM );
1458 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1459 return( AFPERR_PARAM );
1462 if ( *path == '\0' ) {
1463 return( AFPERR_BADTYPE );
1466 upath = mtoupath(vol, path);
1467 if (stat(upath, &srcst) < 0) {
1473 return AFPERR_ACCESS;
1475 return AFPERR_PARAM;
1479 /* save some stuff */
1481 spath = obj->oldtmp;
1482 supath = obj->newtmp;
1483 strcpy(spath, path);
1484 strcpy(supath, upath); /* this is for the cnid changing */
1485 p = ctoupath( vol, sdir, spath);
1487 /* look for the source cnid. if it doesn't exist, don't worry about
1489 #if AD_VERSION > AD_VERSION1
1490 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1491 slen = strlen(supath));
1494 if (( dir = dirsearch( vol, did )) == NULL ) {
1495 return( AFPERR_PARAM );
1498 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1499 return( AFPERR_PARAM );
1502 if ( *path == '\0' ) {
1503 return( AFPERR_BADTYPE );
1506 /* FPExchangeFiles is the only call that can return the SameObj
1508 if ((curdir == sdir) && strcmp(spath, path) == 0)
1509 return AFPERR_SAMEOBJ;
1511 upath = mtoupath(vol, path);
1512 if (stat(upath, &destst) < 0) {
1518 return AFPERR_ACCESS;
1520 return AFPERR_PARAM;
1524 #if AD_VERSION > AD_VERSION1
1525 /* look for destination id. */
1526 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1527 dlen = strlen(upath));
1530 /* construct a temp name.
1531 * NOTE: the temp file will be in the dest file's directory. it
1532 * will also be inaccessible from AFP. */
1533 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1537 /* now, quickly rename the file. we error if we can't. */
1538 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1539 goto err_exchangefile;
1540 of_rename(vol, sdir, spath, curdir, temp);
1542 /* rename destination to source */
1543 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1544 goto err_src_to_tmp;
1545 of_rename(vol, curdir, path, sdir, spath);
1547 /* rename temp to destination */
1548 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1549 goto err_dest_to_src;
1550 of_rename(vol, curdir, temp, curdir, path);
1552 #if AD_VERSION > AD_VERSION1
1553 /* id's need switching. src -> dest and dest -> src. */
1554 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1555 upath, dlen) < 0)) {
1559 err = AFPERR_ACCESS;
1563 goto err_temp_to_dest;
1566 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1567 supath, slen) < 0)) {
1571 err = AFPERR_ACCESS;
1577 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1578 goto err_temp_to_dest;
1583 syslog(LOG_INFO, "ending afp_exchangefiles:");
1589 /* all this stuff is so that we can unwind a failed operation
1592 /* rename dest to temp */
1593 renamefile(upath, temp, temp, vol_noadouble(vol));
1594 of_rename(vol, curdir, upath, curdir, temp);
1597 /* rename source back to dest */
1598 renamefile(p, upath, path, vol_noadouble(vol));
1599 of_rename(vol, sdir, spath, curdir, path);
1602 /* rename temp back to source */
1603 renamefile(temp, p, spath, vol_noadouble(vol));
1604 of_rename(vol, curdir, temp, sdir, spath);