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;
320 struct adouble ad, *adp;
325 int creatf, did, openf;
330 creatf = (unsigned char) *ibuf++;
332 memcpy(&vid, ibuf, sizeof( vid ));
333 ibuf += sizeof( vid );
335 if (( vol = getvolbyvid( vid )) == NULL ) {
336 return( AFPERR_PARAM );
339 if (vol->v_flags & AFPVOL_RO)
342 memcpy(&did, ibuf, sizeof( did));
343 ibuf += sizeof( did );
345 if (( dir = dirsearch( vol, did )) == NULL ) {
346 return( AFPERR_NOOBJ );
349 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
350 return( AFPERR_NOOBJ );
353 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
354 strpbrk(path, MSWINDOWS_BADCHARS))
357 upath = mtoupath(vol, path);
359 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
362 if (!validupath(vol, upath))
365 if ((of = of_findname(vol, curdir, path))) {
368 memset(&ad, 0, sizeof(ad));
372 /* on a hard create, fail if file exists and is open */
373 if ((stat(upath, &st) == 0) && of)
375 openf = O_RDWR|O_CREAT|O_TRUNC;
377 openf = O_RDWR|O_CREAT|O_EXCL;
380 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
381 openf, 0666, adp) < 0 ) {
384 return( AFPERR_EXIST );
386 return( AFPERR_ACCESS );
388 /* on noadouble volumes, just creating the data fork is ok */
389 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
390 goto createfile_done;
393 return( AFPERR_PARAM );
397 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
398 memcpy(ad_entry( adp, ADEID_NAME ), path,
399 ad_getentrylen( adp, ADEID_NAME ));
400 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
401 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
404 setvoltime(obj, vol );
408 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
411 int ibuflen, *rbuflen;
417 u_int16_t vid, bitmap;
422 memcpy(&vid, ibuf, sizeof( vid ));
423 ibuf += sizeof( vid );
424 if (( vol = getvolbyvid( vid )) == NULL ) {
425 return( AFPERR_PARAM );
428 if (vol->v_flags & AFPVOL_RO)
431 memcpy(&did, ibuf, sizeof( did ));
432 ibuf += sizeof( did );
433 if (( dir = dirsearch( vol, did )) == NULL ) {
434 return( AFPERR_NOOBJ );
437 memcpy(&bitmap, ibuf, sizeof( bitmap ));
438 bitmap = ntohs( bitmap );
439 ibuf += sizeof( bitmap );
441 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
442 return( AFPERR_NOOBJ );
445 if ((u_long)ibuf & 1 ) {
449 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
450 setvoltime(obj, vol );
457 int setfilparams(vol, path, bitmap, buf )
462 struct adouble ad, *adp;
465 int bit = 0, isad = 1, err = AFP_OK;
467 u_char achar, *fdType, xyy[4];
468 u_int16_t ashort, bshort;
472 upath = mtoupath(vol, path);
473 if ((of = of_findname(vol, curdir, path))) {
476 memset(&ad, 0, sizeof(ad));
479 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
480 O_RDWR|O_CREAT, 0666, adp) < 0) {
481 /* for some things, we don't need an adouble header */
482 if (bitmap & ~(1<<FILPBIT_MDATE)) {
483 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
486 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
487 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
488 memcpy(ad_entry( adp, ADEID_NAME ), path,
489 ad_getentrylen( adp, ADEID_NAME ));
492 while ( bitmap != 0 ) {
493 while (( bitmap & 1 ) == 0 ) {
500 memcpy(&ashort, buf, sizeof( ashort ));
501 ad_getattr(adp, &bshort);
502 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
503 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
507 ad_setattr(adp, bshort);
508 buf += sizeof( ashort );
512 memcpy(&aint, buf, sizeof(aint));
513 ad_setdate(adp, AD_DATE_CREATE, aint);
514 buf += sizeof( aint );
518 memcpy(&aint, buf, sizeof( aint ));
520 ad_setdate(adp, AD_DATE_MODIFY, aint);
521 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
523 buf += sizeof( aint );
527 memcpy(&aint, buf, sizeof(aint));
528 ad_setdate(adp, AD_DATE_BACKUP, aint);
529 buf += sizeof( aint );
533 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
534 && (em = getextmap( path )) &&
535 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
536 (memcmp(buf + 4, em->em_creator,
537 sizeof( em->em_creator )) == 0)) {
538 memcpy(buf, ufinderi, 8 );
540 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
544 /* Client needs to set the ProDOS file info for this file.
545 Use defined strings for the simple cases, and convert
546 all else into pXYY per Inside Appletalk. Always set
547 the creator as "pdos". <shirsch@ibm.net> */
548 case FILPBIT_PDINFO :
551 memcpy(&ashort, buf, sizeof( ashort ));
552 ashort = ntohs( ashort );
555 switch ( (unsigned int) achar )
558 fdType = ( u_char *) "TEXT";
562 fdType = ( u_char *) "PSYS";
566 fdType = ( u_char *) "PS16";
570 fdType = ( u_char *) "BINA";
574 xyy[0] = ( u_char ) 'p';
576 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
577 xyy[3] = ( u_char ) ashort & 0xff;
582 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
583 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
589 goto setfilparam_done;
598 ad_flush( adp, ADFLAGS_HF );
599 ad_close( adp, ADFLAGS_HF );
605 * renamefile and copyfile take the old and new unix pathnames
606 * and the new mac name.
607 * NOTE: if we have to copy a file instead of renaming it, locks
610 int renamefile(src, dst, newname, noadouble )
611 char *src, *dst, *newname;
615 char adsrc[ MAXPATHLEN + 1];
619 * Note that this is only checking the existance of the data file,
620 * not the header file. The thinking is that if the data file doesn't
621 * exist, but the header file does, the right thing to do is remove
622 * the data file silently.
625 /* existence check moved to afp_moveandrename */
627 if ( rename( src, dst ) < 0 ) {
630 return( AFPERR_NOOBJ );
633 return( AFPERR_ACCESS );
636 case EXDEV : /* Cross device move -- try copy */
637 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
641 return deletefile( src );
643 return( AFPERR_PARAM );
647 strcpy( adsrc, ad_path( src, 0 ));
650 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
655 /* check for a source appledouble header. if it exists, make
656 * a dest appledouble directory and do the rename again. */
657 memset(&ad, 0, sizeof(ad));
658 if (rc || stat(adsrc, &st) ||
659 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
662 ad_close(&ad, ADFLAGS_HF);
666 return( AFPERR_ACCESS );
670 return( AFPERR_PARAM );
674 memset(&ad, 0, sizeof(ad));
675 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
678 return( AFPERR_NOOBJ );
680 return( AFPERR_ACCESS );
684 return( AFPERR_PARAM );
688 len = strlen( newname );
689 ad_setentrylen( &ad, ADEID_NAME, len );
690 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
691 ad_flush( &ad, ADFLAGS_HF );
692 ad_close( &ad, ADFLAGS_HF );
697 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
700 int ibuflen, *rbuflen;
704 char *newname, *path, *p;
705 u_int32_t sdid, ddid;
707 u_int16_t svid, dvid;
712 memcpy(&svid, ibuf, sizeof( svid ));
713 ibuf += sizeof( svid );
714 if (( vol = getvolbyvid( svid )) == NULL ) {
715 return( AFPERR_PARAM );
718 memcpy(&sdid, ibuf, sizeof( sdid ));
719 ibuf += sizeof( sdid );
720 if (( dir = dirsearch( vol, sdid )) == NULL ) {
721 return( AFPERR_PARAM );
724 memcpy(&dvid, ibuf, sizeof( dvid ));
725 ibuf += sizeof( dvid );
726 memcpy(&ddid, ibuf, sizeof( ddid ));
727 ibuf += sizeof( ddid );
729 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
730 return( AFPERR_NOOBJ );
732 if ( *path == '\0' ) {
733 return( AFPERR_BADTYPE );
736 /* don't allow copies when the file is open.
737 * XXX: the spec only calls for read/deny write access.
738 * however, copyfile doesn't have any of that info,
739 * and locks need to stay coherent. as a result,
740 * we just balk if the file is opened already. */
741 if (of_findname(vol, curdir, path))
742 return AFPERR_DENYCONF;
744 newname = obj->newtmp;
745 strcpy( newname, path );
747 p = ctoupath( vol, curdir, newname );
749 if (( vol = getvolbyvid( dvid )) == NULL ) {
750 return( AFPERR_PARAM );
753 if (vol->v_flags & AFPVOL_RO)
756 if (( dir = dirsearch( vol, ddid )) == NULL ) {
757 return( AFPERR_PARAM );
760 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
761 return( AFPERR_NOOBJ );
763 if ( *path != '\0' ) {
764 return( AFPERR_BADTYPE );
767 /* one of the handful of places that knows about the path type */
768 if ( *ibuf++ != 2 ) {
769 return( AFPERR_PARAM );
771 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
772 strncpy( newname, ibuf, plen );
773 newname[ plen ] = '\0';
776 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
777 vol_noadouble(vol))) < 0 ) {
781 setvoltime(obj, vol );
786 static __inline__ int copy_all(const int dfd, const void *buf,
792 if ((cc = write(dfd, buf, buflen)) < 0) {
812 /* XXX: this needs to use ad_open and ad_lock. so, we need to
813 * pass in vol and path */
814 int copyfile(src, dst, newname, noadouble )
815 char *src, *dst, *newname;
821 int sfd, dfd, len, err = AFP_OK;
826 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
829 break; /* just copy the data fork */
831 return( AFPERR_ACCESS );
833 return( AFPERR_PARAM );
836 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
837 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
841 return( AFPERR_NOOBJ );
843 return( AFPERR_ACCESS );
847 return( AFPERR_PARAM );
852 #ifdef SENDFILE_FLAVOR_LINUX
853 if (fstat(sfd, &st) == 0) {
854 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
868 goto copyheader_done;
872 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
879 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
887 unlink(ad_path(dst, ADFLAGS_HF));
893 /* data fork copying */
894 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
897 return( AFPERR_NOOBJ );
899 return( AFPERR_ACCESS );
901 return( AFPERR_PARAM );
905 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
909 return( AFPERR_NOOBJ );
911 return( AFPERR_ACCESS );
915 return( AFPERR_PARAM );
919 #ifdef SENDFILE_FLAVOR_LINUX
920 if (fstat(sfd, &st) == 0) {
921 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
937 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
945 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
954 unlink(ad_path(dst, ADFLAGS_HF));
960 memset(&ad, 0, sizeof(ad));
961 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
965 return noadouble ? AFP_OK : AFPERR_NOOBJ;
967 return( AFPERR_ACCESS );
971 return( AFPERR_PARAM );
975 len = strlen( newname );
976 ad_setentrylen( &ad, ADEID_NAME, len );
977 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
978 ad_flush( &ad, ADFLAGS_HF );
979 ad_close( &ad, ADFLAGS_HF );
986 int deletefile( file )
990 int adflags, err = AFP_OK;
992 /* try to open both at once */
993 adflags = ADFLAGS_DF|ADFLAGS_HF;
994 memset(&ad, 0, sizeof(ad));
995 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
998 adflags = ADFLAGS_DF;
999 /* that failed. now try to open just the data fork */
1000 memset(&ad, 0, sizeof(ad));
1001 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1004 return AFPERR_NOOBJ;
1006 return AFPERR_ACCESS;
1008 return AFPERR_PARAM;
1014 return( AFPERR_ACCESS );
1016 return AFPERR_VLOCK;
1018 return( AFPERR_PARAM );
1022 if ((adflags & ADFLAGS_HF) &&
1023 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1024 ad_close( &ad, adflags );
1025 return( AFPERR_BUSY );
1028 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1033 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1037 err = AFPERR_ACCESS;
1050 if ( unlink( file ) < 0 ) {
1054 err = AFPERR_ACCESS;
1068 if (adflags & ADFLAGS_HF)
1069 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1070 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1071 ad_close( &ad, adflags );
1076 #if AD_VERSION > AD_VERSION1
1077 /* return a file id */
1078 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1081 int ibuflen, *rbuflen;
1096 memcpy(&vid, ibuf, sizeof(vid));
1097 ibuf += sizeof(vid);
1099 if (( vol = getvolbyvid( vid )) == NULL ) {
1100 return( AFPERR_PARAM);
1103 if (vol->v_flags & AFPVOL_RO)
1104 return AFPERR_VLOCK;
1106 memcpy(&did, ibuf, sizeof( did ));
1107 ibuf += sizeof(did);
1109 if (( dir = dirsearch( vol, did )) == NULL ) {
1110 return( AFPERR_PARAM );
1113 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1114 return( AFPERR_PARAM );
1117 if ( *path == '\0' ) {
1118 return( AFPERR_BADTYPE );
1121 upath = mtoupath(vol, path);
1122 if (stat(upath, &st) < 0) {
1126 return AFPERR_ACCESS;
1128 return AFPERR_NOOBJ;
1130 return AFPERR_PARAM;
1134 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1135 memcpy(rbuf, &id, sizeof(id));
1136 *rbuflen = sizeof(id);
1137 return AFPERR_EXISTID;
1140 memset(&ad, 0, sizeof(ad));
1141 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1144 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1145 ad_close(upath, ADFLAGS_HF);
1148 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1149 memcpy(rbuf, &id, sizeof(id));
1150 *rbuflen = sizeof(id);
1156 return AFPERR_VLOCK;
1160 return AFPERR_ACCESS;
1163 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1164 return AFPERR_PARAM;
1168 /* resolve a file id */
1169 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1172 int ibuflen, *rbuflen;
1180 u_int16_t vid, bitmap;
1186 memcpy(&vid, ibuf, sizeof(vid));
1187 ibuf += sizeof(vid);
1189 if (( vol = getvolbyvid( vid )) == NULL ) {
1190 return( AFPERR_PARAM);
1193 memcpy(&id, ibuf, sizeof( id ));
1196 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1197 return AFPERR_BADID;
1200 if (( dir = dirsearch( vol, id )) == NULL ) {
1201 return( AFPERR_PARAM );
1204 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1208 return AFPERR_ACCESS;
1212 return AFPERR_PARAM;
1216 /* directories are bad */
1217 if (S_ISDIR(st.st_mode))
1218 return AFPERR_BADTYPE;
1220 memcpy(&bitmap, ibuf, sizeof(bitmap));
1221 bitmap = ntohs( bitmap );
1223 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1224 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1227 *rbuflen = buflen + sizeof(bitmap);
1228 memcpy(rbuf, ibuf, sizeof(bitmap));
1232 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1235 int ibuflen, *rbuflen;
1249 memcpy(&vid, ibuf, sizeof(vid));
1250 ibuf += sizeof(vid);
1252 if (( vol = getvolbyvid( vid )) == NULL ) {
1253 return( AFPERR_PARAM);
1256 if (vol->v_flags & AFPVOL_RO)
1257 return AFPERR_VLOCK;
1259 memcpy(&id, ibuf, sizeof( id ));
1262 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1266 if (( dir = dirsearch( vol, id )) == NULL ) {
1267 return( AFPERR_PARAM );
1271 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1275 return AFPERR_ACCESS;
1277 /* still try to delete the id */
1281 return AFPERR_PARAM;
1285 /* directories are bad */
1286 if (S_ISDIR(st.st_mode))
1287 return AFPERR_BADTYPE;
1289 if (cnid_delete(vol->v_db, id)) {
1292 return AFPERR_VLOCK;
1295 return AFPERR_ACCESS;
1297 return AFPERR_PARAM;
1305 #define APPLETEMP ".AppleTempXXXXXX"
1306 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1309 int ibuflen, *rbuflen;
1311 struct stat srcst, destst;
1313 struct dir *dir, *sdir;
1314 char *spath, temp[17], *path, *p;
1315 char *supath, *upath;
1317 #if AD_VERSION > AD_VERSION1
1327 memcpy(&vid, ibuf, sizeof(vid));
1328 ibuf += sizeof(vid);
1330 if (( vol = getvolbyvid( vid )) == NULL ) {
1331 return( AFPERR_PARAM);
1334 if (vol->v_flags & AFPVOL_RO)
1335 return AFPERR_VLOCK;
1337 /* source and destination dids */
1338 memcpy(&sid, ibuf, sizeof(sid));
1339 ibuf += sizeof(sid);
1340 memcpy(&did, ibuf, sizeof(did));
1341 ibuf += sizeof(did);
1344 if ((dir = dirsearch( vol, sid )) == NULL ) {
1345 return( AFPERR_PARAM );
1348 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1349 return( AFPERR_PARAM );
1352 if ( *path == '\0' ) {
1353 return( AFPERR_BADTYPE );
1356 upath = mtoupath(vol, path);
1357 if (stat(upath, &srcst) < 0) {
1363 return AFPERR_ACCESS;
1365 return AFPERR_PARAM;
1369 /* save some stuff */
1371 spath = obj->oldtmp;
1372 supath = obj->newtmp;
1373 strcpy(spath, path);
1374 strcpy(supath, upath); /* this is for the cnid changing */
1375 p = ctoupath( vol, sdir, spath);
1377 /* look for the source cnid. if it doesn't exist, don't worry about
1379 #if AD_VERSION > AD_VERSION1
1380 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1381 slen = strlen(supath));
1384 if (( dir = dirsearch( vol, did )) == NULL ) {
1385 return( AFPERR_PARAM );
1388 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1389 return( AFPERR_PARAM );
1392 if ( *path == '\0' ) {
1393 return( AFPERR_BADTYPE );
1396 /* FPExchangeFiles is the only call that can return the SameObj
1398 if ((curdir == sdir) && strcmp(spath, path) == 0)
1399 return AFPERR_SAMEOBJ;
1401 upath = mtoupath(vol, path);
1402 if (stat(upath, &destst) < 0) {
1408 return AFPERR_ACCESS;
1410 return AFPERR_PARAM;
1414 #if AD_VERSION > AD_VERSION1
1415 /* look for destination id. */
1416 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1417 dlen = strlen(upath));
1420 /* construct a temp name.
1421 * NOTE: the temp file will be in the dest file's directory. it
1422 * will also be inaccessible from AFP. */
1423 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1427 /* now, quickly rename the file. we error if we can't. */
1428 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1429 goto err_exchangefile;
1430 of_rename(vol, sdir, spath, curdir, temp);
1432 /* rename destination to source */
1433 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1434 goto err_src_to_tmp;
1435 of_rename(vol, curdir, path, sdir, spath);
1437 /* rename temp to destination */
1438 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1439 goto err_dest_to_src;
1440 of_rename(vol, curdir, temp, curdir, path);
1442 #if AD_VERSION > AD_VERSION1
1443 /* id's need switching. src -> dest and dest -> src. */
1444 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1445 upath, dlen) < 0)) {
1449 err = AFPERR_ACCESS;
1453 goto err_temp_to_dest;
1456 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1457 supath, slen) < 0)) {
1461 err = AFPERR_ACCESS;
1467 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1468 goto err_temp_to_dest;
1474 /* all this stuff is so that we can unwind a failed operation
1477 /* rename dest to temp */
1478 renamefile(upath, temp, temp, vol_noadouble(vol));
1479 of_rename(vol, curdir, upath, curdir, temp);
1482 /* rename source back to dest */
1483 renamefile(p, upath, path, vol_noadouble(vol));
1484 of_rename(vol, sdir, spath, curdir, path);
1487 /* rename temp back to source */
1488 renamefile(temp, p, spath, vol_noadouble(vol));
1489 of_rename(vol, curdir, temp, sdir, spath);