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;
323 struct adouble ad, *adp;
327 char *path, *upath, adpath[50];
328 int creatf, did, openf, uid;
333 creatf = (unsigned char) *ibuf++;
335 memcpy(&vid, ibuf, sizeof( vid ));
336 ibuf += sizeof( vid );
338 if (( vol = getvolbyvid( vid )) == NULL ) {
339 return( AFPERR_PARAM );
342 if (vol->v_flags & AFPVOL_RO)
345 memcpy(&did, ibuf, sizeof( did));
346 ibuf += sizeof( did );
348 if (( dir = dirsearch( vol, did )) == NULL ) {
349 return( AFPERR_NOOBJ );
352 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
353 return( AFPERR_NOOBJ );
356 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
357 strpbrk(path, MSWINDOWS_BADCHARS))
360 upath = mtoupath(vol, path);
362 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
365 if (!validupath(vol, upath))
368 if ((of = of_findname(vol, curdir, path))) {
371 memset(&ad, 0, sizeof(ad));
375 /* on a hard create, fail if file exists and is open */
376 if ((stat(upath, &st) == 0) && of)
378 openf = O_RDWR|O_CREAT|O_TRUNC;
380 openf = O_RDWR|O_CREAT|O_EXCL;
383 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
384 openf, 0666, adp) < 0 ) {
387 return( AFPERR_EXIST );
389 return( AFPERR_ACCESS );
391 /* on noadouble volumes, just creating the data fork is ok */
392 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
393 goto createfile_done;
396 return( AFPERR_PARAM );
400 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
401 memcpy(ad_entry( adp, ADEID_NAME ), path,
402 ad_getentrylen( adp, ADEID_NAME ));
403 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
404 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
407 setvoltime(obj, vol );
411 /* The below code is an experimental, untested, incomplete kludge which
412 provides better dropbox support. It should NOT be turned on yet unless
413 you are a developer who wants to try it out and fix it. */
414 if (stat(".", &sb) == -1)
415 syslog (LOG_ERR, "Error checking directory %s: %m", dir->d_name);
418 strcpy (adpath, "./.AppleDouble/");
419 strcat (adpath, path);
420 seteuid(0); /* Become root to change the owner of the file */
421 syslog (LOG_INFO, "Changing %s to uid=%d gid=%d", path, sb.st_uid, sb.st_gid);
422 if (chown(path, sb.st_uid, -1)==-1)
423 syslog (LOG_ERR, "Error changing permissions: %m");
424 if (chown(adpath, sb.st_uid, -1)==-1)
425 syslog (LOG_ERR, "Error changing AppleDouble permissions: %m");
426 syslog (LOG_INFO, "Changing afpd owner back to %d", uid);
427 seteuid(uid); /* Restore process ownership to normal */
435 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
438 int ibuflen, *rbuflen;
444 u_int16_t vid, bitmap;
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 );
484 int setfilparams(vol, path, bitmap, buf )
489 struct adouble ad, *adp;
492 int bit = 0, isad = 1, err = AFP_OK;
494 u_char achar, *fdType, xyy[4];
495 u_int16_t ashort, bshort;
499 upath = mtoupath(vol, path);
500 if ((of = of_findname(vol, curdir, path))) {
503 memset(&ad, 0, sizeof(ad));
506 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
507 O_RDWR|O_CREAT, 0666, adp) < 0) {
508 /* for some things, we don't need an adouble header */
509 if (bitmap & ~(1<<FILPBIT_MDATE)) {
510 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
513 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
514 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
515 memcpy(ad_entry( adp, ADEID_NAME ), path,
516 ad_getentrylen( adp, ADEID_NAME ));
519 while ( bitmap != 0 ) {
520 while (( bitmap & 1 ) == 0 ) {
527 memcpy(&ashort, buf, sizeof( ashort ));
528 ad_getattr(adp, &bshort);
529 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
530 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
534 ad_setattr(adp, bshort);
535 buf += sizeof( ashort );
539 memcpy(&aint, buf, sizeof(aint));
540 ad_setdate(adp, AD_DATE_CREATE, aint);
541 buf += sizeof( aint );
545 memcpy(&aint, buf, sizeof( aint ));
547 ad_setdate(adp, AD_DATE_MODIFY, aint);
548 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
550 buf += sizeof( aint );
554 memcpy(&aint, buf, sizeof(aint));
555 ad_setdate(adp, AD_DATE_BACKUP, aint);
556 buf += sizeof( aint );
560 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
561 && (em = getextmap( path )) &&
562 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
563 (memcmp(buf + 4, em->em_creator,
564 sizeof( em->em_creator )) == 0)) {
565 memcpy(buf, ufinderi, 8 );
567 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
571 /* Client needs to set the ProDOS file info for this file.
572 Use defined strings for the simple cases, and convert
573 all else into pXYY per Inside Appletalk. Always set
574 the creator as "pdos". <shirsch@ibm.net> */
575 case FILPBIT_PDINFO :
578 memcpy(&ashort, buf, sizeof( ashort ));
579 ashort = ntohs( ashort );
582 switch ( (unsigned int) achar )
585 fdType = ( u_char *) "TEXT";
589 fdType = ( u_char *) "PSYS";
593 fdType = ( u_char *) "PS16";
597 fdType = ( u_char *) "BINA";
601 xyy[0] = ( u_char ) 'p';
603 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
604 xyy[3] = ( u_char ) ashort & 0xff;
609 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
610 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
616 goto setfilparam_done;
625 ad_flush( adp, ADFLAGS_HF );
626 ad_close( adp, ADFLAGS_HF );
632 * renamefile and copyfile take the old and new unix pathnames
633 * and the new mac name.
634 * NOTE: if we have to copy a file instead of renaming it, locks
637 int renamefile(src, dst, newname, noadouble )
638 char *src, *dst, *newname;
642 char adsrc[ MAXPATHLEN + 1];
646 * Note that this is only checking the existance of the data file,
647 * not the header file. The thinking is that if the data file doesn't
648 * exist, but the header file does, the right thing to do is remove
649 * the data file silently.
652 /* existence check moved to afp_moveandrename */
654 if ( rename( src, dst ) < 0 ) {
657 return( AFPERR_NOOBJ );
660 return( AFPERR_ACCESS );
663 case EXDEV : /* Cross device move -- try copy */
664 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
668 return deletefile( src );
670 return( AFPERR_PARAM );
674 strcpy( adsrc, ad_path( src, 0 ));
677 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
682 /* check for a source appledouble header. if it exists, make
683 * a dest appledouble directory and do the rename again. */
684 memset(&ad, 0, sizeof(ad));
685 if (rc || stat(adsrc, &st) ||
686 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
689 ad_close(&ad, ADFLAGS_HF);
693 return( AFPERR_ACCESS );
697 return( AFPERR_PARAM );
701 memset(&ad, 0, sizeof(ad));
702 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
705 return( AFPERR_NOOBJ );
707 return( AFPERR_ACCESS );
711 return( AFPERR_PARAM );
715 len = strlen( newname );
716 ad_setentrylen( &ad, ADEID_NAME, len );
717 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
718 ad_flush( &ad, ADFLAGS_HF );
719 ad_close( &ad, ADFLAGS_HF );
724 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
727 int ibuflen, *rbuflen;
731 char *newname, *path, *p;
732 u_int32_t sdid, ddid;
734 u_int16_t svid, dvid;
739 memcpy(&svid, ibuf, sizeof( svid ));
740 ibuf += sizeof( svid );
741 if (( vol = getvolbyvid( svid )) == NULL ) {
742 return( AFPERR_PARAM );
745 memcpy(&sdid, ibuf, sizeof( sdid ));
746 ibuf += sizeof( sdid );
747 if (( dir = dirsearch( vol, sdid )) == NULL ) {
748 return( AFPERR_PARAM );
751 memcpy(&dvid, ibuf, sizeof( dvid ));
752 ibuf += sizeof( dvid );
753 memcpy(&ddid, ibuf, sizeof( ddid ));
754 ibuf += sizeof( ddid );
756 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
757 return( AFPERR_NOOBJ );
759 if ( *path == '\0' ) {
760 return( AFPERR_BADTYPE );
763 /* don't allow copies when the file is open.
764 * XXX: the spec only calls for read/deny write access.
765 * however, copyfile doesn't have any of that info,
766 * and locks need to stay coherent. as a result,
767 * we just balk if the file is opened already. */
768 if (of_findname(vol, curdir, path))
769 return AFPERR_DENYCONF;
771 newname = obj->newtmp;
772 strcpy( newname, path );
774 p = ctoupath( vol, curdir, newname );
776 if (( vol = getvolbyvid( dvid )) == NULL ) {
777 return( AFPERR_PARAM );
780 if (vol->v_flags & AFPVOL_RO)
783 if (( dir = dirsearch( vol, ddid )) == NULL ) {
784 return( AFPERR_PARAM );
787 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
788 return( AFPERR_NOOBJ );
790 if ( *path != '\0' ) {
791 return( AFPERR_BADTYPE );
794 /* one of the handful of places that knows about the path type */
795 if ( *ibuf++ != 2 ) {
796 return( AFPERR_PARAM );
798 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
799 strncpy( newname, ibuf, plen );
800 newname[ plen ] = '\0';
803 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
804 vol_noadouble(vol))) < 0 ) {
808 setvoltime(obj, vol );
813 static __inline__ int copy_all(const int dfd, const void *buf,
819 if ((cc = write(dfd, buf, buflen)) < 0) {
839 /* XXX: this needs to use ad_open and ad_lock. so, we need to
840 * pass in vol and path */
841 int copyfile(src, dst, newname, noadouble )
842 char *src, *dst, *newname;
848 int sfd, dfd, len, err = AFP_OK;
853 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
856 break; /* just copy the data fork */
858 return( AFPERR_ACCESS );
860 return( AFPERR_PARAM );
863 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
864 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
868 return( AFPERR_NOOBJ );
870 return( AFPERR_ACCESS );
874 return( AFPERR_PARAM );
879 #ifdef SENDFILE_FLAVOR_LINUX
880 if (fstat(sfd, &st) == 0) {
881 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
895 goto copyheader_done;
899 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
906 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
914 unlink(ad_path(dst, ADFLAGS_HF));
920 /* data fork copying */
921 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
924 return( AFPERR_NOOBJ );
926 return( AFPERR_ACCESS );
928 return( AFPERR_PARAM );
932 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
936 return( AFPERR_NOOBJ );
938 return( AFPERR_ACCESS );
942 return( AFPERR_PARAM );
946 #ifdef SENDFILE_FLAVOR_LINUX
947 if (fstat(sfd, &st) == 0) {
948 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
964 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
972 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
981 unlink(ad_path(dst, ADFLAGS_HF));
987 memset(&ad, 0, sizeof(ad));
988 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
992 return noadouble ? AFP_OK : AFPERR_NOOBJ;
994 return( AFPERR_ACCESS );
998 return( AFPERR_PARAM );
1002 len = strlen( newname );
1003 ad_setentrylen( &ad, ADEID_NAME, len );
1004 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1005 ad_flush( &ad, ADFLAGS_HF );
1006 ad_close( &ad, ADFLAGS_HF );
1013 int deletefile( file )
1017 int adflags, err = AFP_OK;
1019 /* try to open both at once */
1020 adflags = ADFLAGS_DF|ADFLAGS_HF;
1021 memset(&ad, 0, sizeof(ad));
1022 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1025 adflags = ADFLAGS_DF;
1026 /* that failed. now try to open just the data fork */
1027 memset(&ad, 0, sizeof(ad));
1028 if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1031 return AFPERR_NOOBJ;
1033 return AFPERR_ACCESS;
1035 return AFPERR_PARAM;
1041 return( AFPERR_ACCESS );
1043 return AFPERR_VLOCK;
1045 return( AFPERR_PARAM );
1049 if ((adflags & ADFLAGS_HF) &&
1050 (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1051 ad_close( &ad, adflags );
1052 return( AFPERR_BUSY );
1055 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1060 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1064 err = AFPERR_ACCESS;
1077 if ( unlink( file ) < 0 ) {
1081 err = AFPERR_ACCESS;
1095 if (adflags & ADFLAGS_HF)
1096 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1097 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1098 ad_close( &ad, adflags );
1103 #if AD_VERSION > AD_VERSION1
1104 /* return a file id */
1105 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1108 int ibuflen, *rbuflen;
1123 memcpy(&vid, ibuf, sizeof(vid));
1124 ibuf += sizeof(vid);
1126 if (( vol = getvolbyvid( vid )) == NULL ) {
1127 return( AFPERR_PARAM);
1130 if (vol->v_flags & AFPVOL_RO)
1131 return AFPERR_VLOCK;
1133 memcpy(&did, ibuf, sizeof( did ));
1134 ibuf += sizeof(did);
1136 if (( dir = dirsearch( vol, did )) == NULL ) {
1137 return( AFPERR_PARAM );
1140 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1141 return( AFPERR_PARAM );
1144 if ( *path == '\0' ) {
1145 return( AFPERR_BADTYPE );
1148 upath = mtoupath(vol, path);
1149 if (stat(upath, &st) < 0) {
1153 return AFPERR_ACCESS;
1155 return AFPERR_NOOBJ;
1157 return AFPERR_PARAM;
1161 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1162 memcpy(rbuf, &id, sizeof(id));
1163 *rbuflen = sizeof(id);
1164 return AFPERR_EXISTID;
1167 memset(&ad, 0, sizeof(ad));
1168 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1171 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1172 ad_close(upath, ADFLAGS_HF);
1175 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1176 memcpy(rbuf, &id, sizeof(id));
1177 *rbuflen = sizeof(id);
1183 return AFPERR_VLOCK;
1187 return AFPERR_ACCESS;
1190 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1191 return AFPERR_PARAM;
1195 /* resolve a file id */
1196 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1199 int ibuflen, *rbuflen;
1207 u_int16_t vid, bitmap;
1213 memcpy(&vid, ibuf, sizeof(vid));
1214 ibuf += sizeof(vid);
1216 if (( vol = getvolbyvid( vid )) == NULL ) {
1217 return( AFPERR_PARAM);
1220 memcpy(&id, ibuf, sizeof( id ));
1223 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1224 return AFPERR_BADID;
1227 if (( dir = dirsearch( vol, id )) == NULL ) {
1228 return( AFPERR_PARAM );
1231 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1235 return AFPERR_ACCESS;
1239 return AFPERR_PARAM;
1243 /* directories are bad */
1244 if (S_ISDIR(st.st_mode))
1245 return AFPERR_BADTYPE;
1247 memcpy(&bitmap, ibuf, sizeof(bitmap));
1248 bitmap = ntohs( bitmap );
1250 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1251 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1254 *rbuflen = buflen + sizeof(bitmap);
1255 memcpy(rbuf, ibuf, sizeof(bitmap));
1259 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1262 int ibuflen, *rbuflen;
1276 memcpy(&vid, ibuf, sizeof(vid));
1277 ibuf += sizeof(vid);
1279 if (( vol = getvolbyvid( vid )) == NULL ) {
1280 return( AFPERR_PARAM);
1283 if (vol->v_flags & AFPVOL_RO)
1284 return AFPERR_VLOCK;
1286 memcpy(&id, ibuf, sizeof( id ));
1289 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1293 if (( dir = dirsearch( vol, id )) == NULL ) {
1294 return( AFPERR_PARAM );
1298 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1302 return AFPERR_ACCESS;
1304 /* still try to delete the id */
1308 return AFPERR_PARAM;
1312 /* directories are bad */
1313 if (S_ISDIR(st.st_mode))
1314 return AFPERR_BADTYPE;
1316 if (cnid_delete(vol->v_db, id)) {
1319 return AFPERR_VLOCK;
1322 return AFPERR_ACCESS;
1324 return AFPERR_PARAM;
1332 #define APPLETEMP ".AppleTempXXXXXX"
1333 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1336 int ibuflen, *rbuflen;
1338 struct stat srcst, destst;
1340 struct dir *dir, *sdir;
1341 char *spath, temp[17], *path, *p;
1342 char *supath, *upath;
1344 #if AD_VERSION > AD_VERSION1
1354 memcpy(&vid, ibuf, sizeof(vid));
1355 ibuf += sizeof(vid);
1357 if (( vol = getvolbyvid( vid )) == NULL ) {
1358 return( AFPERR_PARAM);
1361 if (vol->v_flags & AFPVOL_RO)
1362 return AFPERR_VLOCK;
1364 /* source and destination dids */
1365 memcpy(&sid, ibuf, sizeof(sid));
1366 ibuf += sizeof(sid);
1367 memcpy(&did, ibuf, sizeof(did));
1368 ibuf += sizeof(did);
1371 if ((dir = dirsearch( vol, sid )) == NULL ) {
1372 return( AFPERR_PARAM );
1375 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1376 return( AFPERR_PARAM );
1379 if ( *path == '\0' ) {
1380 return( AFPERR_BADTYPE );
1383 upath = mtoupath(vol, path);
1384 if (stat(upath, &srcst) < 0) {
1390 return AFPERR_ACCESS;
1392 return AFPERR_PARAM;
1396 /* save some stuff */
1398 spath = obj->oldtmp;
1399 supath = obj->newtmp;
1400 strcpy(spath, path);
1401 strcpy(supath, upath); /* this is for the cnid changing */
1402 p = ctoupath( vol, sdir, spath);
1404 /* look for the source cnid. if it doesn't exist, don't worry about
1406 #if AD_VERSION > AD_VERSION1
1407 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1408 slen = strlen(supath));
1411 if (( dir = dirsearch( vol, did )) == NULL ) {
1412 return( AFPERR_PARAM );
1415 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1416 return( AFPERR_PARAM );
1419 if ( *path == '\0' ) {
1420 return( AFPERR_BADTYPE );
1423 /* FPExchangeFiles is the only call that can return the SameObj
1425 if ((curdir == sdir) && strcmp(spath, path) == 0)
1426 return AFPERR_SAMEOBJ;
1428 upath = mtoupath(vol, path);
1429 if (stat(upath, &destst) < 0) {
1435 return AFPERR_ACCESS;
1437 return AFPERR_PARAM;
1441 #if AD_VERSION > AD_VERSION1
1442 /* look for destination id. */
1443 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1444 dlen = strlen(upath));
1447 /* construct a temp name.
1448 * NOTE: the temp file will be in the dest file's directory. it
1449 * will also be inaccessible from AFP. */
1450 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1454 /* now, quickly rename the file. we error if we can't. */
1455 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1456 goto err_exchangefile;
1457 of_rename(vol, sdir, spath, curdir, temp);
1459 /* rename destination to source */
1460 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1461 goto err_src_to_tmp;
1462 of_rename(vol, curdir, path, sdir, spath);
1464 /* rename temp to destination */
1465 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1466 goto err_dest_to_src;
1467 of_rename(vol, curdir, temp, curdir, path);
1469 #if AD_VERSION > AD_VERSION1
1470 /* id's need switching. src -> dest and dest -> src. */
1471 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1472 upath, dlen) < 0)) {
1476 err = AFPERR_ACCESS;
1480 goto err_temp_to_dest;
1483 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1484 supath, slen) < 0)) {
1488 err = AFPERR_ACCESS;
1494 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1495 goto err_temp_to_dest;
1501 /* all this stuff is so that we can unwind a failed operation
1504 /* rename dest to temp */
1505 renamefile(upath, temp, temp, vol_noadouble(vol));
1506 of_rename(vol, curdir, upath, curdir, temp);
1509 /* rename source back to dest */
1510 renamefile(p, upath, path, vol_noadouble(vol));
1511 of_rename(vol, sdir, spath, curdir, path);
1514 /* rename temp back to source */
1515 renamefile(temp, p, spath, vol_noadouble(vol));
1516 of_rename(vol, curdir, temp, sdir, spath);