2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
16 #include <sys/syslog.h>
17 #include <sys/types.h>
19 #include <sys/param.h>
22 #include <netatalk/endian.h>
23 #include <atalk/adouble.h>
24 #include <atalk/afp.h>
25 #include <atalk/util.h>
26 #include <atalk/cnid.h>
28 #include "directory.h"
36 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
37 * field bytes subfield bytes
40 * ioFlFndrInfo 16 -> type 4 type field
41 * creator 4 creator field
42 * flags 2 finder flags:
44 * location 4 location in window
45 * folder 2 window that contains file
47 * ioFlXFndrInfo 16 -> iconID 2 icon id
49 * script 1 script system
51 * commentID 2 comment id
52 * putawayID 4 home directory id
55 const u_char ufinderi[] = {
56 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
57 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0
62 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
71 struct stat hst, lst, *lstp;
72 struct adouble ad, *adp;
75 char *data, *nameoff = NULL, *upath;
76 int bit = 0, isad = 1, aint;
78 u_char achar, fdType[4];
80 upath = mtoupath(vol, path);
81 if ((of = of_findname(vol, curdir, path))) {
84 memset(&ad, 0, sizeof(ad));
88 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
90 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
91 syslog( LOG_ERR, "getfilparams fstat: %m" );
95 while ( bitmap != 0 ) {
96 while (( bitmap & 1 ) == 0 ) {
104 ad_getattr(adp, &ashort);
105 } else if (*upath == '.') {
106 ashort = htons(ATTRBIT_INVISIBLE);
109 memcpy(data, &ashort, sizeof( ashort ));
110 data += sizeof( u_short );
114 memcpy(data, &dir->d_did, sizeof( int ));
115 data += sizeof( int );
119 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
120 aint = AD_DATE_FROM_UNIX(st->st_mtime);
121 memcpy(data, &aint, sizeof( aint ));
122 data += sizeof( aint );
126 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
127 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
128 (hst.st_mtime < st->st_mtime)) {
129 aint = AD_DATE_FROM_UNIX(st->st_mtime);
132 aint = AD_DATE_FROM_UNIX(st->st_mtime);
134 memcpy(data, &aint, sizeof( int ));
135 data += sizeof( int );
139 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
140 aint = AD_DATE_START;
141 memcpy(data, &aint, sizeof( int ));
142 data += sizeof( int );
147 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
149 memcpy(data, ufinderi, 32);
150 if (*upath == '.') { /* make it invisible */
151 ashort = htons(FINDERINFO_INVISIBLE);
152 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
156 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
157 ufinderi, 8 ) == 0)) &&
158 (em = getextmap( path ))) {
159 memcpy(data, em->em_type, sizeof( em->em_type ));
160 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
167 data += sizeof( u_int16_t );
171 memset(data, 0, sizeof(u_int16_t));
172 data += sizeof( u_int16_t );
176 #if AD_VERSION > AD_VERSION1
177 /* use the CNID database if we're using AD v2 */
179 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
183 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
184 strlen(upath), aint))) {
187 * What a fucking mess. First thing: DID and FNUMs are
188 * in the same space for purposes of enumerate (and several
189 * other wierd places). While we consider this Apple's bug,
190 * this is the work-around: In order to maintain constant and
191 * unique DIDs and FNUMs, we monotonically generate the DIDs
192 * during the session, and derive the FNUMs from the filesystem.
193 * Since the DIDs are small, we insure that the FNUMs are fairly
194 * large by setting thier high bits to the device number.
196 * AFS already does something very similar to this for the
197 * inode number, so we don't repeat the procedure.
200 * due to complaints over did's being non-persistent,
201 * here's the current hack to provide semi-persistent
203 * 1) we reserve the first bit for file ids.
204 * 2) the next 7 bits are for the device.
205 * 3) the remaining 24 bits are for the inode.
207 * both the inode and device information are actually hashes
208 * that are then truncated to the requisite bit length.
210 * it should be okay to use lstat to deal with symlinks.
212 lstp = (lstat(upath, &lst) < 0) ? st : &lst;
213 aint = htonl(CNID(lstp, 1));
214 #if AD_VERSION > AD_VERSION1
217 memcpy(data, &aint, sizeof( aint ));
218 data += sizeof( aint );
222 aint = htonl( st->st_size );
223 memcpy(data, &aint, sizeof( aint ));
224 data += sizeof( aint );
229 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
233 memcpy(data, &aint, sizeof( aint ));
234 data += sizeof( aint );
237 /* Current client needs ProDOS info block for this file.
238 Use simple heuristic and let the Mac "type" string tell
239 us what the PD file code should be. Everything gets a
240 subtype of 0x0000 unless the original value was hashed
241 to "pXYZ" when we created it. See IA, Ver 2.
243 case FILPBIT_PDINFO :
245 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
247 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
251 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
255 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
259 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
263 else if ( fdType[0] == 'p' ) {
265 ashort = (fdType[2] * 256) + fdType[3];
279 memcpy(data, &ashort, sizeof( ashort ));
280 data += sizeof( ashort );
281 memset(data, 0, sizeof( ashort ));
282 data += sizeof( ashort );
287 ad_close( adp, ADFLAGS_HF );
289 return( AFPERR_BITMAP );
295 ashort = htons( data - buf );
296 memcpy(nameoff, &ashort, sizeof( ashort ));
297 if ((aint = strlen( path )) > MACFILELEN)
300 memcpy(data, path, aint );
304 ad_close( adp, ADFLAGS_HF );
306 *buflen = data - buf;
310 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
313 int ibuflen, *rbuflen;
316 struct adouble ad, *adp;
321 int creatf, did, openf;
326 creatf = (unsigned char) *ibuf++;
328 memcpy(&vid, ibuf, sizeof( vid ));
329 ibuf += sizeof( vid );
331 if (( vol = getvolbyvid( vid )) == NULL ) {
332 return( AFPERR_PARAM );
335 if (vol->v_flags & AFPVOL_RO)
338 memcpy(&did, ibuf, sizeof( did));
339 ibuf += sizeof( did );
341 if (( dir = dirsearch( vol, did )) == NULL ) {
342 return( AFPERR_NOOBJ );
345 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
346 return( AFPERR_NOOBJ );
349 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
350 strpbrk(path, MSWINDOWS_BADCHARS))
353 upath = mtoupath(vol, path);
355 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
358 if (!validupath(vol, upath))
361 if ((of = of_findname(vol, curdir, path))) {
364 memset(&ad, 0, sizeof(ad));
368 /* on a hard create, fail if file exists and is open */
369 if ((stat(upath, &st) == 0) && of)
371 openf = O_RDWR|O_CREAT|O_TRUNC;
373 openf = O_RDWR|O_CREAT|O_EXCL;
376 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
377 openf, 0666, adp) < 0 ) {
380 return( AFPERR_EXIST );
382 return( AFPERR_ACCESS );
384 /* on noadouble volumes, just creating the data fork is ok */
385 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
386 goto createfile_done;
389 return( AFPERR_PARAM );
393 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
394 memcpy(ad_entry( adp, ADEID_NAME ), path,
395 ad_getentrylen( adp, ADEID_NAME ));
396 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
397 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
400 setvoltime(obj, vol );
404 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
407 int ibuflen, *rbuflen;
413 u_int16_t vid, bitmap;
418 memcpy(&vid, ibuf, sizeof( vid ));
419 ibuf += sizeof( vid );
420 if (( vol = getvolbyvid( vid )) == NULL ) {
421 return( AFPERR_PARAM );
424 if (vol->v_flags & AFPVOL_RO)
427 memcpy(&did, ibuf, sizeof( did ));
428 ibuf += sizeof( did );
429 if (( dir = dirsearch( vol, did )) == NULL ) {
430 return( AFPERR_NOOBJ );
433 memcpy(&bitmap, ibuf, sizeof( bitmap ));
434 bitmap = ntohs( bitmap );
435 ibuf += sizeof( bitmap );
437 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
438 return( AFPERR_NOOBJ );
441 if ((u_long)ibuf & 1 ) {
445 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
446 setvoltime(obj, vol );
453 int setfilparams(vol, path, bitmap, buf )
458 struct adouble ad, *adp;
461 int bit = 0, isad = 1, err = AFP_OK;
463 u_char achar, *fdType, xyy[4];
464 u_int16_t ashort, bshort;
468 upath = mtoupath(vol, path);
469 if ((of = of_findname(vol, curdir, path))) {
472 memset(&ad, 0, sizeof(ad));
475 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
476 O_RDWR|O_CREAT, 0666, adp) < 0) {
477 /* for some things, we don't need an adouble header */
478 if (bitmap & ~(1<<FILPBIT_MDATE)) {
479 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
482 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
483 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
484 memcpy(ad_entry( adp, ADEID_NAME ), path,
485 ad_getentrylen( adp, ADEID_NAME ));
488 while ( bitmap != 0 ) {
489 while (( bitmap & 1 ) == 0 ) {
496 memcpy(&ashort, buf, sizeof( ashort ));
497 ad_getattr(adp, &bshort);
498 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
499 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
503 ad_setattr(adp, bshort);
504 buf += sizeof( ashort );
508 memcpy(&aint, buf, sizeof(aint));
509 ad_setdate(adp, AD_DATE_CREATE, aint);
510 buf += sizeof( aint );
514 memcpy(&aint, buf, sizeof( aint ));
516 ad_setdate(adp, AD_DATE_MODIFY, aint);
517 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
519 buf += sizeof( aint );
523 memcpy(&aint, buf, sizeof(aint));
524 ad_setdate(adp, AD_DATE_BACKUP, aint);
525 buf += sizeof( aint );
529 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
530 && (em = getextmap( path )) &&
531 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
532 (memcmp(buf + 4, em->em_creator,
533 sizeof( em->em_creator )) == 0)) {
534 memcpy(buf, ufinderi, 8 );
536 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
540 /* Client needs to set the ProDOS file info for this file.
541 Use defined strings for the simple cases, and convert
542 all else into pXYY per Inside Appletalk. Always set
543 the creator as "pdos". <shirsch@ibm.net> */
544 case FILPBIT_PDINFO :
547 memcpy(&ashort, buf, sizeof( ashort ));
548 ashort = ntohs( ashort );
551 switch ( (unsigned int) achar )
554 fdType = ( u_char *) "TEXT";
558 fdType = ( u_char *) "PSYS";
562 fdType = ( u_char *) "PS16";
566 fdType = ( u_char *) "BINA";
570 xyy[0] = ( u_char ) 'p';
572 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
573 xyy[3] = ( u_char ) ashort & 0xff;
578 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
579 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
585 goto setfilparam_done;
594 ad_flush( adp, ADFLAGS_HF );
595 ad_close( adp, ADFLAGS_HF );
601 * renamefile and copyfile take the old and new unix pathnames
602 * and the new mac name.
603 * NOTE: if we have to copy a file instead of renaming it, locks
606 int renamefile(src, dst, newname, noadouble )
607 char *src, *dst, *newname;
611 char adsrc[ MAXPATHLEN + 1];
615 * Note that this is only checking the existance of the data file,
616 * not the header file. The thinking is that if the data file doesn't
617 * exist, but the header file does, the right thing to do is remove
618 * the data file silently.
621 /* existence check moved to afp_moveandrename */
623 if ( rename( src, dst ) < 0 ) {
626 return( AFPERR_NOOBJ );
629 return( AFPERR_ACCESS );
632 case EXDEV : /* Cross device move -- try copy */
633 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
637 return deletefile( src );
639 return( AFPERR_PARAM );
643 strcpy( adsrc, ad_path( src, 0 ));
646 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
651 /* check for a source appledouble header. if it exists, make
652 * a dest appledouble directory and do the rename again. */
653 memset(&ad, 0, sizeof(ad));
654 if (rc || stat(adsrc, &st) ||
655 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
658 ad_close(&ad, ADFLAGS_HF);
662 return( AFPERR_ACCESS );
666 return( AFPERR_PARAM );
670 memset(&ad, 0, sizeof(ad));
671 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
674 return( AFPERR_NOOBJ );
676 return( AFPERR_ACCESS );
680 return( AFPERR_PARAM );
684 len = strlen( newname );
685 ad_setentrylen( &ad, ADEID_NAME, len );
686 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
687 ad_flush( &ad, ADFLAGS_HF );
688 ad_close( &ad, ADFLAGS_HF );
693 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
696 int ibuflen, *rbuflen;
700 char *newname, *path, *p;
701 u_int32_t sdid, ddid;
703 u_int16_t svid, dvid;
708 memcpy(&svid, ibuf, sizeof( svid ));
709 ibuf += sizeof( svid );
710 if (( vol = getvolbyvid( svid )) == NULL ) {
711 return( AFPERR_PARAM );
714 memcpy(&sdid, ibuf, sizeof( sdid ));
715 ibuf += sizeof( sdid );
716 if (( dir = dirsearch( vol, sdid )) == NULL ) {
717 return( AFPERR_PARAM );
720 memcpy(&dvid, ibuf, sizeof( dvid ));
721 ibuf += sizeof( dvid );
722 memcpy(&ddid, ibuf, sizeof( ddid ));
723 ibuf += sizeof( ddid );
725 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
726 return( AFPERR_NOOBJ );
728 if ( *path == '\0' ) {
729 return( AFPERR_BADTYPE );
732 /* don't allow copies when the file is open.
733 * XXX: the spec only calls for read/deny write access.
734 * however, copyfile doesn't have any of that info,
735 * and locks need to stay coherent. as a result,
736 * we just balk if the file is opened already. */
737 if (of_findname(vol, curdir, path))
738 return AFPERR_DENYCONF;
740 newname = obj->newtmp;
741 strcpy( newname, path );
743 p = ctoupath( vol, curdir, newname );
745 if (( vol = getvolbyvid( dvid )) == NULL ) {
746 return( AFPERR_PARAM );
749 if (vol->v_flags & AFPVOL_RO)
752 if (( dir = dirsearch( vol, ddid )) == NULL ) {
753 return( AFPERR_PARAM );
756 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
757 return( AFPERR_NOOBJ );
759 if ( *path != '\0' ) {
760 return( AFPERR_BADTYPE );
763 /* one of the handful of places that knows about the path type */
764 if ( *ibuf++ != 2 ) {
765 return( AFPERR_PARAM );
767 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
768 strncpy( newname, ibuf, plen );
769 newname[ plen ] = '\0';
772 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
773 vol_noadouble(vol))) < 0 ) {
777 setvoltime(obj, vol );
782 static __inline__ int copy_all(const int dfd, const void *buf,
788 if ((cc = write(dfd, buf, buflen)) < 0) {
808 /* XXX: this needs to use ad_open and ad_lock. so, we need to
809 * pass in vol and path */
810 int copyfile(src, dst, newname, noadouble )
811 char *src, *dst, *newname;
817 int sfd, dfd, len, err = AFP_OK;
822 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
825 break; /* just copy the data fork */
827 return( AFPERR_ACCESS );
829 return( AFPERR_PARAM );
832 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
833 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
837 return( AFPERR_NOOBJ );
839 return( AFPERR_ACCESS );
843 return( AFPERR_PARAM );
848 #ifdef SENDFILE_FLAVOR_LINUX
849 if (fstat(sfd, &st) == 0) {
850 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
864 goto copyheader_done;
868 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
875 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
883 unlink(ad_path(dst, ADFLAGS_HF));
889 /* data fork copying */
890 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
893 return( AFPERR_NOOBJ );
895 return( AFPERR_ACCESS );
897 return( AFPERR_PARAM );
901 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
905 return( AFPERR_NOOBJ );
907 return( AFPERR_ACCESS );
911 return( AFPERR_PARAM );
915 #ifdef SENDFILE_FLAVOR_LINUX
916 if (fstat(sfd, &st) == 0) {
917 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
933 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
941 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
950 unlink(ad_path(dst, ADFLAGS_HF));
956 memset(&ad, 0, sizeof(ad));
957 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
961 return noadouble ? AFP_OK : AFPERR_NOOBJ;
963 return( AFPERR_ACCESS );
967 return( AFPERR_PARAM );
971 len = strlen( newname );
972 ad_setentrylen( &ad, ADEID_NAME, len );
973 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
974 ad_flush( &ad, ADFLAGS_HF );
975 ad_close( &ad, ADFLAGS_HF );
982 int deletefile( file )
986 int adflags, err = AFP_OK;
988 /* try to open both at once */
989 adflags = ADFLAGS_DF|ADFLAGS_HF;
990 memset(&ad, 0, sizeof(ad));
991 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
994 adflags = ADFLAGS_DF;
995 /* that failed. now try to open just the data fork */
996 memset(&ad, 0, sizeof(ad));
997 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1000 return AFPERR_NOOBJ;
1002 return AFPERR_ACCESS;
1004 return AFPERR_PARAM;
1010 return( AFPERR_ACCESS );
1012 return AFPERR_VLOCK;
1014 return( AFPERR_PARAM );
1018 if ((adflags & ADFLAGS_HF) &&
1019 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1020 ad_close( &ad, adflags );
1021 return( AFPERR_BUSY );
1024 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1029 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1033 err = AFPERR_ACCESS;
1046 if ( unlink( file ) < 0 ) {
1050 err = AFPERR_ACCESS;
1064 if (adflags & ADFLAGS_HF)
1065 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1066 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1067 ad_close( &ad, adflags );
1072 #if AD_VERSION > AD_VERSION1
1073 /* return a file id */
1074 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1077 int ibuflen, *rbuflen;
1092 memcpy(&vid, ibuf, sizeof(vid));
1093 ibuf += sizeof(vid);
1095 if (( vol = getvolbyvid( vid )) == NULL ) {
1096 return( AFPERR_PARAM);
1099 if (vol->v_flags & AFPVOL_RO)
1100 return AFPERR_VLOCK;
1102 memcpy(&did, ibuf, sizeof( did ));
1103 ibuf += sizeof(did);
1105 if (( dir = dirsearch( vol, did )) == NULL ) {
1106 return( AFPERR_PARAM );
1109 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1110 return( AFPERR_PARAM );
1113 if ( *path == '\0' ) {
1114 return( AFPERR_BADTYPE );
1117 upath = mtoupath(vol, path);
1118 if (stat(upath, &st) < 0) {
1122 return AFPERR_ACCESS;
1124 return AFPERR_NOOBJ;
1126 return AFPERR_PARAM;
1130 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1131 memcpy(rbuf, &id, sizeof(id));
1132 *rbuflen = sizeof(id);
1133 return AFPERR_EXISTID;
1136 memset(&ad, 0, sizeof(ad));
1137 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1140 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1141 ad_close(upath, ADFLAGS_HF);
1144 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1145 memcpy(rbuf, &id, sizeof(id));
1146 *rbuflen = sizeof(id);
1152 return AFPERR_VLOCK;
1156 return AFPERR_ACCESS;
1159 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1160 return AFPERR_PARAM;
1164 /* resolve a file id */
1165 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1168 int ibuflen, *rbuflen;
1176 u_int16_t vid, bitmap;
1182 memcpy(&vid, ibuf, sizeof(vid));
1183 ibuf += sizeof(vid);
1185 if (( vol = getvolbyvid( vid )) == NULL ) {
1186 return( AFPERR_PARAM);
1189 memcpy(&id, ibuf, sizeof( id ));
1192 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1193 return AFPERR_BADID;
1196 if (( dir = dirsearch( vol, id )) == NULL ) {
1197 return( AFPERR_PARAM );
1200 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1204 return AFPERR_ACCESS;
1208 return AFPERR_PARAM;
1212 /* directories are bad */
1213 if (S_ISDIR(st.st_mode))
1214 return AFPERR_BADTYPE;
1216 memcpy(&bitmap, ibuf, sizeof(bitmap));
1217 bitmap = ntohs( bitmap );
1219 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1220 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1223 *rbuflen = buflen + sizeof(bitmap);
1224 memcpy(rbuf, ibuf, sizeof(bitmap));
1228 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1231 int ibuflen, *rbuflen;
1245 memcpy(&vid, ibuf, sizeof(vid));
1246 ibuf += sizeof(vid);
1248 if (( vol = getvolbyvid( vid )) == NULL ) {
1249 return( AFPERR_PARAM);
1252 if (vol->v_flags & AFPVOL_RO)
1253 return AFPERR_VLOCK;
1255 memcpy(&id, ibuf, sizeof( id ));
1258 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1262 if (( dir = dirsearch( vol, id )) == NULL ) {
1263 return( AFPERR_PARAM );
1267 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1271 return AFPERR_ACCESS;
1273 /* still try to delete the id */
1277 return AFPERR_PARAM;
1281 /* directories are bad */
1282 if (S_ISDIR(st.st_mode))
1283 return AFPERR_BADTYPE;
1285 if (cnid_delete(vol->v_db, id)) {
1288 return AFPERR_VLOCK;
1291 return AFPERR_ACCESS;
1293 return AFPERR_PARAM;
1301 #define APPLETEMP ".AppleTempXXXXXX"
1302 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1305 int ibuflen, *rbuflen;
1307 struct stat srcst, destst;
1309 struct dir *dir, *sdir;
1310 char *spath, temp[17], *path, *p;
1311 char *supath, *upath;
1313 #if AD_VERSION > AD_VERSION1
1323 memcpy(&vid, ibuf, sizeof(vid));
1324 ibuf += sizeof(vid);
1326 if (( vol = getvolbyvid( vid )) == NULL ) {
1327 return( AFPERR_PARAM);
1330 if (vol->v_flags & AFPVOL_RO)
1331 return AFPERR_VLOCK;
1333 /* source and destination dids */
1334 memcpy(&sid, ibuf, sizeof(sid));
1335 ibuf += sizeof(sid);
1336 memcpy(&did, ibuf, sizeof(did));
1337 ibuf += sizeof(did);
1340 if ((dir = dirsearch( vol, sid )) == NULL ) {
1341 return( AFPERR_PARAM );
1344 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1345 return( AFPERR_PARAM );
1348 if ( *path == '\0' ) {
1349 return( AFPERR_BADTYPE );
1352 upath = mtoupath(vol, path);
1353 if (stat(upath, &srcst) < 0) {
1359 return AFPERR_ACCESS;
1361 return AFPERR_PARAM;
1365 /* save some stuff */
1367 spath = obj->oldtmp;
1368 supath = obj->newtmp;
1369 strcpy(spath, path);
1370 strcpy(supath, upath); /* this is for the cnid changing */
1371 p = ctoupath( vol, sdir, spath);
1373 /* look for the source cnid. if it doesn't exist, don't worry about
1375 #if AD_VERSION > AD_VERSION1
1376 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1377 slen = strlen(supath));
1380 if (( dir = dirsearch( vol, did )) == NULL ) {
1381 return( AFPERR_PARAM );
1384 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1385 return( AFPERR_PARAM );
1388 if ( *path == '\0' ) {
1389 return( AFPERR_BADTYPE );
1392 /* FPExchangeFiles is the only call that can return the SameObj
1394 if ((curdir == sdir) && strcmp(spath, path) == 0)
1395 return AFPERR_SAMEOBJ;
1397 upath = mtoupath(vol, path);
1398 if (stat(upath, &destst) < 0) {
1404 return AFPERR_ACCESS;
1406 return AFPERR_PARAM;
1410 #if AD_VERSION > AD_VERSION1
1411 /* look for destination id. */
1412 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1413 dlen = strlen(upath));
1416 /* construct a temp name.
1417 * NOTE: the temp file will be in the dest file's directory. it
1418 * will also be inaccessible from AFP. */
1419 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1423 /* now, quickly rename the file. we error if we can't. */
1424 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1425 goto err_exchangefile;
1426 of_rename(vol, sdir, spath, curdir, temp);
1428 /* rename destination to source */
1429 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1430 goto err_src_to_tmp;
1431 of_rename(vol, curdir, path, sdir, spath);
1433 /* rename temp to destination */
1434 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1435 goto err_dest_to_src;
1436 of_rename(vol, curdir, temp, curdir, path);
1438 #if AD_VERSION > AD_VERSION1
1439 /* id's need switching. src -> dest and dest -> src. */
1440 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1441 upath, dlen) < 0)) {
1445 err = AFPERR_ACCESS;
1449 goto err_temp_to_dest;
1452 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1453 supath, slen) < 0)) {
1457 err = AFPERR_ACCESS;
1463 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1464 goto err_temp_to_dest;
1470 /* all this stuff is so that we can unwind a failed operation
1473 /* rename dest to temp */
1474 renamefile(upath, temp, temp, vol_noadouble(vol));
1475 of_rename(vol, curdir, upath, curdir, temp);
1478 /* rename source back to dest */
1479 renamefile(p, upath, path, vol_noadouble(vol));
1480 of_rename(vol, sdir, spath, curdir, path);
1483 /* rename temp back to source */
1484 renamefile(temp, p, spath, vol_noadouble(vol));
1485 of_rename(vol, curdir, temp, sdir, spath);