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;
333 syslog(LOG_INFO, "afp_createfile");
336 creatf = (unsigned char) *ibuf++;
338 memcpy(&vid, ibuf, sizeof( vid ));
339 ibuf += sizeof( vid );
341 if (( vol = getvolbyvid( vid )) == NULL ) {
342 return( AFPERR_PARAM );
345 if (vol->v_flags & AFPVOL_RO)
348 memcpy(&did, ibuf, sizeof( did));
349 ibuf += sizeof( did );
351 if (( dir = dirsearch( vol, did )) == NULL ) {
352 return( AFPERR_NOOBJ );
355 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
356 return( AFPERR_NOOBJ );
359 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
360 strpbrk(path, MSWINDOWS_BADCHARS))
363 upath = mtoupath(vol, path);
365 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
368 if (!validupath(vol, upath))
371 if ((of = of_findname(vol, curdir, path))) {
374 memset(&ad, 0, sizeof(ad));
378 /* on a hard create, fail if file exists and is open */
379 if ((stat(upath, &st) == 0) && of)
381 openf = O_RDWR|O_CREAT|O_TRUNC;
383 openf = O_RDWR|O_CREAT|O_EXCL;
386 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
387 openf, 0666, adp) < 0 ) {
390 return( AFPERR_EXIST );
392 return( AFPERR_ACCESS );
394 /* on noadouble volumes, just creating the data fork is ok */
395 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
396 goto createfile_done;
399 return( AFPERR_PARAM );
403 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
404 memcpy(ad_entry( adp, ADEID_NAME ), path,
405 ad_getentrylen( adp, ADEID_NAME ));
406 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
407 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
413 /* The below code is an experimental, untested, incomplete kludge which
414 provides better dropbox support. It should NOT be turned on yet unless
415 you are a developer who wants to try it out and fix it. */
416 if (stat(".", &sb) == -1)
417 syslog (LOG_ERR, "Error checking directory %s: %m", dir->d_name);
420 if ( uid != sb.st_uid )
422 strcpy (adpath, "./.AppleDouble/");
423 strcat (adpath, path);
424 seteuid(0); /* Become root to change the owner of the file */
425 syslog (LOG_INFO, "Changing %s to uid=%d gid=%d", path, sb.st_uid, sb.st_gid);
426 if (chown(path, sb.st_uid, sb.st_gid)==-1)
427 syslog (LOG_ERR, "Error changing permissions: %m");
428 /* In order to write information to the file, the Mac client needs
429 to be able to read from it too, so read bits have to be turned on.
430 Directory permissions remain unchanged */
431 chmod(path,(sb.st_mode&0x0FFFF)| S_IRGRP| S_IROTH);
432 if (chown(adpath, sb.st_uid, sb.st_gid)==-1)
433 syslog (LOG_ERR, "Error changing AppleDouble permissions: %m");
434 syslog (LOG_INFO, "Changing afpd owner back to %d", uid);
435 seteuid(uid); /* Restore process ownership to normal */
441 setvoltime(obj, vol );
445 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
448 int ibuflen, *rbuflen;
454 u_int16_t vid, bitmap;
456 syslog (LOG_INFO, "afp_setfilparams");
460 memcpy(&vid, ibuf, sizeof( vid ));
461 ibuf += sizeof( vid );
462 if (( vol = getvolbyvid( vid )) == NULL ) {
463 return( AFPERR_PARAM );
466 if (vol->v_flags & AFPVOL_RO)
469 memcpy(&did, ibuf, sizeof( did ));
470 ibuf += sizeof( did );
471 if (( dir = dirsearch( vol, did )) == NULL ) {
472 return( AFPERR_NOOBJ );
475 memcpy(&bitmap, ibuf, sizeof( bitmap ));
476 bitmap = ntohs( bitmap );
477 ibuf += sizeof( bitmap );
479 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
480 return( AFPERR_NOOBJ );
483 if ((u_long)ibuf & 1 ) {
487 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
488 setvoltime(obj, vol );
495 int setfilparams(vol, path, bitmap, buf )
500 struct adouble ad, *adp;
503 int bit = 0, isad = 1, err = AFP_OK;
505 u_char achar, *fdType, xyy[4];
506 u_int16_t ashort, bshort;
510 upath = mtoupath(vol, path);
511 if ((of = of_findname(vol, curdir, path))) {
514 memset(&ad, 0, sizeof(ad));
517 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
518 O_RDWR|O_CREAT, 0666, adp) < 0) {
519 /* for some things, we don't need an adouble header */
520 if (bitmap & ~(1<<FILPBIT_MDATE)) {
521 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
524 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
525 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
526 memcpy(ad_entry( adp, ADEID_NAME ), path,
527 ad_getentrylen( adp, ADEID_NAME ));
530 while ( bitmap != 0 ) {
531 while (( bitmap & 1 ) == 0 ) {
538 memcpy(&ashort, buf, sizeof( ashort ));
539 ad_getattr(adp, &bshort);
540 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
541 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
545 ad_setattr(adp, bshort);
546 buf += sizeof( ashort );
550 memcpy(&aint, buf, sizeof(aint));
551 ad_setdate(adp, AD_DATE_CREATE, aint);
552 buf += sizeof( aint );
556 memcpy(&aint, buf, sizeof( aint ));
558 ad_setdate(adp, AD_DATE_MODIFY, aint);
559 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
561 buf += sizeof( aint );
565 memcpy(&aint, buf, sizeof(aint));
566 ad_setdate(adp, AD_DATE_BACKUP, aint);
567 buf += sizeof( aint );
571 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
572 && (em = getextmap( path )) &&
573 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
574 (memcmp(buf + 4, em->em_creator,
575 sizeof( em->em_creator )) == 0)) {
576 memcpy(buf, ufinderi, 8 );
578 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
582 /* Client needs to set the ProDOS file info for this file.
583 Use defined strings for the simple cases, and convert
584 all else into pXYY per Inside Appletalk. Always set
585 the creator as "pdos". <shirsch@ibm.net> */
586 case FILPBIT_PDINFO :
589 memcpy(&ashort, buf, sizeof( ashort ));
590 ashort = ntohs( ashort );
593 switch ( (unsigned int) achar )
596 fdType = ( u_char *) "TEXT";
600 fdType = ( u_char *) "PSYS";
604 fdType = ( u_char *) "PS16";
608 fdType = ( u_char *) "BINA";
612 xyy[0] = ( u_char ) 'p';
614 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
615 xyy[3] = ( u_char ) ashort & 0xff;
620 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
621 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
627 goto setfilparam_done;
636 ad_flush( adp, ADFLAGS_HF );
637 ad_close( adp, ADFLAGS_HF );
643 * renamefile and copyfile take the old and new unix pathnames
644 * and the new mac name.
645 * NOTE: if we have to copy a file instead of renaming it, locks
648 int renamefile(src, dst, newname, noadouble )
649 char *src, *dst, *newname;
653 char adsrc[ MAXPATHLEN + 1];
657 * Note that this is only checking the existance of the data file,
658 * not the header file. The thinking is that if the data file doesn't
659 * exist, but the header file does, the right thing to do is remove
660 * the data file silently.
663 /* existence check moved to afp_moveandrename */
665 if ( rename( src, dst ) < 0 ) {
668 return( AFPERR_NOOBJ );
671 return( AFPERR_ACCESS );
674 case EXDEV : /* Cross device move -- try copy */
675 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
679 return deletefile( src );
681 return( AFPERR_PARAM );
685 strcpy( adsrc, ad_path( src, 0 ));
688 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
693 /* check for a source appledouble header. if it exists, make
694 * a dest appledouble directory and do the rename again. */
695 memset(&ad, 0, sizeof(ad));
696 if (rc || stat(adsrc, &st) ||
697 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
700 ad_close(&ad, ADFLAGS_HF);
704 return( AFPERR_ACCESS );
708 return( AFPERR_PARAM );
712 memset(&ad, 0, sizeof(ad));
713 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
716 return( AFPERR_NOOBJ );
718 return( AFPERR_ACCESS );
722 return( AFPERR_PARAM );
726 len = strlen( newname );
727 ad_setentrylen( &ad, ADEID_NAME, len );
728 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
729 ad_flush( &ad, ADFLAGS_HF );
730 ad_close( &ad, ADFLAGS_HF );
735 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
738 int ibuflen, *rbuflen;
742 char *newname, *path, *p;
743 u_int32_t sdid, ddid;
745 u_int16_t svid, dvid;
747 syslog(LOG_INFO, "afp_copyfile");
751 memcpy(&svid, ibuf, sizeof( svid ));
752 ibuf += sizeof( svid );
753 if (( vol = getvolbyvid( svid )) == NULL ) {
754 return( AFPERR_PARAM );
757 memcpy(&sdid, ibuf, sizeof( sdid ));
758 ibuf += sizeof( sdid );
759 if (( dir = dirsearch( vol, sdid )) == NULL ) {
760 return( AFPERR_PARAM );
763 memcpy(&dvid, ibuf, sizeof( dvid ));
764 ibuf += sizeof( dvid );
765 memcpy(&ddid, ibuf, sizeof( ddid ));
766 ibuf += sizeof( ddid );
768 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
769 return( AFPERR_NOOBJ );
771 if ( *path == '\0' ) {
772 return( AFPERR_BADTYPE );
775 /* don't allow copies when the file is open.
776 * XXX: the spec only calls for read/deny write access.
777 * however, copyfile doesn't have any of that info,
778 * and locks need to stay coherent. as a result,
779 * we just balk if the file is opened already. */
780 if (of_findname(vol, curdir, path))
781 return AFPERR_DENYCONF;
783 newname = obj->newtmp;
784 strcpy( newname, path );
786 p = ctoupath( vol, curdir, newname );
788 if (( vol = getvolbyvid( dvid )) == NULL ) {
789 return( AFPERR_PARAM );
792 if (vol->v_flags & AFPVOL_RO)
795 if (( dir = dirsearch( vol, ddid )) == NULL ) {
796 return( AFPERR_PARAM );
799 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
800 return( AFPERR_NOOBJ );
802 if ( *path != '\0' ) {
803 return( AFPERR_BADTYPE );
806 /* one of the handful of places that knows about the path type */
807 if ( *ibuf++ != 2 ) {
808 return( AFPERR_PARAM );
810 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
811 strncpy( newname, ibuf, plen );
812 newname[ plen ] = '\0';
815 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
816 vol_noadouble(vol))) < 0 ) {
820 setvoltime(obj, vol );
825 static __inline__ int copy_all(const int dfd, const void *buf,
831 if ((cc = write(dfd, buf, buflen)) < 0) {
851 /* XXX: this needs to use ad_open and ad_lock. so, we need to
852 * pass in vol and path */
853 int copyfile(src, dst, newname, noadouble )
854 char *src, *dst, *newname;
860 int sfd, dfd, len, err = AFP_OK;
865 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
868 break; /* just copy the data fork */
870 return( AFPERR_ACCESS );
872 return( AFPERR_PARAM );
875 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
876 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
880 return( AFPERR_NOOBJ );
882 return( AFPERR_ACCESS );
886 return( AFPERR_PARAM );
891 #ifdef SENDFILE_FLAVOR_LINUX
892 if (fstat(sfd, &st) == 0) {
893 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
907 goto copyheader_done;
911 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
918 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
926 unlink(ad_path(dst, ADFLAGS_HF));
932 /* data fork copying */
933 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
936 return( AFPERR_NOOBJ );
938 return( AFPERR_ACCESS );
940 return( AFPERR_PARAM );
944 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
948 return( AFPERR_NOOBJ );
950 return( AFPERR_ACCESS );
954 return( AFPERR_PARAM );
958 #ifdef SENDFILE_FLAVOR_LINUX
959 if (fstat(sfd, &st) == 0) {
960 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
976 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
984 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
993 unlink(ad_path(dst, ADFLAGS_HF));
999 memset(&ad, 0, sizeof(ad));
1000 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1004 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1006 return( AFPERR_ACCESS );
1008 return AFPERR_VLOCK;
1010 return( AFPERR_PARAM );
1014 len = strlen( newname );
1015 ad_setentrylen( &ad, ADEID_NAME, len );
1016 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1017 ad_flush( &ad, ADFLAGS_HF );
1018 ad_close( &ad, ADFLAGS_HF );
1025 int deletefile( file )
1029 int adflags, err = AFP_OK;
1031 /* try to open both at once */
1032 adflags = ADFLAGS_DF|ADFLAGS_HF;
1033 memset(&ad, 0, sizeof(ad));
1034 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1037 adflags = ADFLAGS_DF;
1038 /* that failed. now try to open just the data fork */
1039 memset(&ad, 0, sizeof(ad));
1040 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1043 return AFPERR_NOOBJ;
1045 return AFPERR_ACCESS;
1047 return AFPERR_PARAM;
1053 return( AFPERR_ACCESS );
1055 return AFPERR_VLOCK;
1057 return( AFPERR_PARAM );
1061 if ((adflags & ADFLAGS_HF) &&
1062 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1063 ad_close( &ad, adflags );
1064 return( AFPERR_BUSY );
1067 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1072 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1076 err = AFPERR_ACCESS;
1089 if ( unlink( file ) < 0 ) {
1093 err = AFPERR_ACCESS;
1107 if (adflags & ADFLAGS_HF)
1108 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1109 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1110 ad_close( &ad, adflags );
1115 #if AD_VERSION > AD_VERSION1
1116 /* return a file id */
1117 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1120 int ibuflen, *rbuflen;
1131 syslog(LOG_INFO, "afp_createid");
1135 memcpy(&vid, ibuf, sizeof(vid));
1136 ibuf += sizeof(vid);
1138 if (( vol = getvolbyvid( vid )) == NULL ) {
1139 return( AFPERR_PARAM);
1142 if (vol->v_flags & AFPVOL_RO)
1143 return AFPERR_VLOCK;
1145 memcpy(&did, ibuf, sizeof( did ));
1146 ibuf += sizeof(did);
1148 if (( dir = dirsearch( vol, did )) == NULL ) {
1149 return( AFPERR_PARAM );
1152 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1153 return( AFPERR_PARAM );
1156 if ( *path == '\0' ) {
1157 return( AFPERR_BADTYPE );
1160 upath = mtoupath(vol, path);
1161 if (stat(upath, &st) < 0) {
1165 return AFPERR_ACCESS;
1167 return AFPERR_NOOBJ;
1169 return AFPERR_PARAM;
1173 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1174 memcpy(rbuf, &id, sizeof(id));
1175 *rbuflen = sizeof(id);
1176 return AFPERR_EXISTID;
1179 memset(&ad, 0, sizeof(ad));
1180 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1183 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1184 ad_close(upath, ADFLAGS_HF);
1187 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1188 memcpy(rbuf, &id, sizeof(id));
1189 *rbuflen = sizeof(id);
1195 return AFPERR_VLOCK;
1199 return AFPERR_ACCESS;
1202 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1203 return AFPERR_PARAM;
1207 /* resolve a file id */
1208 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1211 int ibuflen, *rbuflen;
1219 u_int16_t vid, bitmap;
1221 syslog(LOG_INFO, "afp_resolveid");
1225 memcpy(&vid, ibuf, sizeof(vid));
1226 ibuf += sizeof(vid);
1228 if (( vol = getvolbyvid( vid )) == NULL ) {
1229 return( AFPERR_PARAM);
1232 memcpy(&id, ibuf, sizeof( id ));
1235 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1236 return AFPERR_BADID;
1239 if (( dir = dirsearch( vol, id )) == NULL ) {
1240 return( AFPERR_PARAM );
1243 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1247 return AFPERR_ACCESS;
1251 return AFPERR_PARAM;
1255 /* directories are bad */
1256 if (S_ISDIR(st.st_mode))
1257 return AFPERR_BADTYPE;
1259 memcpy(&bitmap, ibuf, sizeof(bitmap));
1260 bitmap = ntohs( bitmap );
1262 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1263 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1266 *rbuflen = buflen + sizeof(bitmap);
1267 memcpy(rbuf, ibuf, sizeof(bitmap));
1271 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1274 int ibuflen, *rbuflen;
1284 syslog(LOG_INFO, "afp_deleteid");
1288 memcpy(&vid, ibuf, sizeof(vid));
1289 ibuf += sizeof(vid);
1291 if (( vol = getvolbyvid( vid )) == NULL ) {
1292 return( AFPERR_PARAM);
1295 if (vol->v_flags & AFPVOL_RO)
1296 return AFPERR_VLOCK;
1298 memcpy(&id, ibuf, sizeof( id ));
1301 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1305 if (( dir = dirsearch( vol, id )) == NULL ) {
1306 return( AFPERR_PARAM );
1310 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1314 return AFPERR_ACCESS;
1316 /* still try to delete the id */
1320 return AFPERR_PARAM;
1324 /* directories are bad */
1325 if (S_ISDIR(st.st_mode))
1326 return AFPERR_BADTYPE;
1328 if (cnid_delete(vol->v_db, id)) {
1331 return AFPERR_VLOCK;
1334 return AFPERR_ACCESS;
1336 return AFPERR_PARAM;
1344 #define APPLETEMP ".AppleTempXXXXXX"
1345 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1348 int ibuflen, *rbuflen;
1350 struct stat srcst, destst;
1352 struct dir *dir, *sdir;
1353 char *spath, temp[17], *path, *p;
1354 char *supath, *upath;
1356 #if AD_VERSION > AD_VERSION1
1362 syslog(LOG_INFO, "afp_exchangefiles");
1366 memcpy(&vid, ibuf, sizeof(vid));
1367 ibuf += sizeof(vid);
1369 if (( vol = getvolbyvid( vid )) == NULL ) {
1370 return( AFPERR_PARAM);
1373 if (vol->v_flags & AFPVOL_RO)
1374 return AFPERR_VLOCK;
1376 /* source and destination dids */
1377 memcpy(&sid, ibuf, sizeof(sid));
1378 ibuf += sizeof(sid);
1379 memcpy(&did, ibuf, sizeof(did));
1380 ibuf += sizeof(did);
1383 if ((dir = dirsearch( vol, sid )) == NULL ) {
1384 return( AFPERR_PARAM );
1387 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1388 return( AFPERR_PARAM );
1391 if ( *path == '\0' ) {
1392 return( AFPERR_BADTYPE );
1395 upath = mtoupath(vol, path);
1396 if (stat(upath, &srcst) < 0) {
1402 return AFPERR_ACCESS;
1404 return AFPERR_PARAM;
1408 /* save some stuff */
1410 spath = obj->oldtmp;
1411 supath = obj->newtmp;
1412 strcpy(spath, path);
1413 strcpy(supath, upath); /* this is for the cnid changing */
1414 p = ctoupath( vol, sdir, spath);
1416 /* look for the source cnid. if it doesn't exist, don't worry about
1418 #if AD_VERSION > AD_VERSION1
1419 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1420 slen = strlen(supath));
1423 if (( dir = dirsearch( vol, did )) == NULL ) {
1424 return( AFPERR_PARAM );
1427 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1428 return( AFPERR_PARAM );
1431 if ( *path == '\0' ) {
1432 return( AFPERR_BADTYPE );
1435 /* FPExchangeFiles is the only call that can return the SameObj
1437 if ((curdir == sdir) && strcmp(spath, path) == 0)
1438 return AFPERR_SAMEOBJ;
1440 upath = mtoupath(vol, path);
1441 if (stat(upath, &destst) < 0) {
1447 return AFPERR_ACCESS;
1449 return AFPERR_PARAM;
1453 #if AD_VERSION > AD_VERSION1
1454 /* look for destination id. */
1455 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1456 dlen = strlen(upath));
1459 /* construct a temp name.
1460 * NOTE: the temp file will be in the dest file's directory. it
1461 * will also be inaccessible from AFP. */
1462 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1466 /* now, quickly rename the file. we error if we can't. */
1467 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1468 goto err_exchangefile;
1469 of_rename(vol, sdir, spath, curdir, temp);
1471 /* rename destination to source */
1472 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1473 goto err_src_to_tmp;
1474 of_rename(vol, curdir, path, sdir, spath);
1476 /* rename temp to destination */
1477 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1478 goto err_dest_to_src;
1479 of_rename(vol, curdir, temp, curdir, path);
1481 #if AD_VERSION > AD_VERSION1
1482 /* id's need switching. src -> dest and dest -> src. */
1483 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1484 upath, dlen) < 0)) {
1488 err = AFPERR_ACCESS;
1492 goto err_temp_to_dest;
1495 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1496 supath, slen) < 0)) {
1500 err = AFPERR_ACCESS;
1506 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1507 goto err_temp_to_dest;
1513 /* all this stuff is so that we can unwind a failed operation
1516 /* rename dest to temp */
1517 renamefile(upath, temp, temp, vol_noadouble(vol));
1518 of_rename(vol, curdir, upath, curdir, temp);
1521 /* rename source back to dest */
1522 renamefile(p, upath, path, vol_noadouble(vol));
1523 of_rename(vol, sdir, spath, curdir, path);
1526 /* rename temp back to source */
1527 renamefile(temp, p, spath, vol_noadouble(vol));
1528 of_rename(vol, curdir, temp, sdir, spath);