2 * $Id: file.c,v 1.20 2001-05-31 18:48:32 srittau Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
22 #include <sys/syslog.h>
23 #include <sys/types.h>
25 #include <sys/param.h>
28 #include <netatalk/endian.h>
29 #include <atalk/adouble.h>
30 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
34 #include "directory.h"
44 #endif /* FORCE_UIDGID */
46 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
47 * field bytes subfield bytes
50 * ioFlFndrInfo 16 -> type 4 type field
51 * creator 4 creator field
52 * flags 2 finder flags:
54 * location 4 location in window
55 * folder 2 window that contains file
57 * ioFlXFndrInfo 16 -> iconID 2 icon id
59 * script 1 script system
61 * commentID 2 comment id
62 * putawayID 4 home directory id
65 const u_char ufinderi[] = {
66 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0
72 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
81 struct stat hst, lst, *lstp;
82 struct adouble ad, *adp;
85 char *data, *nameoff = NULL, *upath;
86 int bit = 0, isad = 1, aint;
88 u_char achar, fdType[4];
91 syslog(LOG_INFO, "begin getfilparams:");
94 upath = mtoupath(vol, path);
95 if ((of = of_findname(vol, curdir, path))) {
98 memset(&ad, 0, sizeof(ad));
102 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
104 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
105 syslog( LOG_ERR, "getfilparams fstat: %m" );
109 while ( bitmap != 0 ) {
110 while (( bitmap & 1 ) == 0 ) {
118 ad_getattr(adp, &ashort);
119 } else if (*upath == '.') {
120 ashort = htons(ATTRBIT_INVISIBLE);
123 memcpy(data, &ashort, sizeof( ashort ));
124 data += sizeof( u_short );
128 memcpy(data, &dir->d_did, sizeof( int ));
129 data += sizeof( int );
133 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
134 aint = AD_DATE_FROM_UNIX(st->st_mtime);
135 memcpy(data, &aint, sizeof( aint ));
136 data += sizeof( aint );
140 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
141 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
142 (hst.st_mtime < st->st_mtime)) {
143 aint = AD_DATE_FROM_UNIX(st->st_mtime);
146 aint = AD_DATE_FROM_UNIX(st->st_mtime);
148 memcpy(data, &aint, sizeof( int ));
149 data += sizeof( int );
153 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
154 aint = AD_DATE_START;
155 memcpy(data, &aint, sizeof( int ));
156 data += sizeof( int );
161 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
163 memcpy(data, ufinderi, 32);
164 if (*upath == '.') { /* make it invisible */
165 ashort = htons(FINDERINFO_INVISIBLE);
166 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
170 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
171 ufinderi, 8 ) == 0)) &&
172 (em = getextmap( path ))) {
173 memcpy(data, em->em_type, sizeof( em->em_type ));
174 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
181 data += sizeof( u_int16_t );
185 memset(data, 0, sizeof(u_int16_t));
186 data += sizeof( u_int16_t );
190 #if AD_VERSION > AD_VERSION1
191 /* use the CNID database if we're using AD v2 */
193 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
197 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
198 strlen(upath), aint))) {
201 * What a fucking mess. First thing: DID and FNUMs are
202 * in the same space for purposes of enumerate (and several
203 * other wierd places). While we consider this Apple's bug,
204 * this is the work-around: In order to maintain constant and
205 * unique DIDs and FNUMs, we monotonically generate the DIDs
206 * during the session, and derive the FNUMs from the filesystem.
207 * Since the DIDs are small, we insure that the FNUMs are fairly
208 * large by setting thier high bits to the device number.
210 * AFS already does something very similar to this for the
211 * inode number, so we don't repeat the procedure.
214 * due to complaints over did's being non-persistent,
215 * here's the current hack to provide semi-persistent
217 * 1) we reserve the first bit for file ids.
218 * 2) the next 7 bits are for the device.
219 * 3) the remaining 24 bits are for the inode.
221 * both the inode and device information are actually hashes
222 * that are then truncated to the requisite bit length.
224 * it should be okay to use lstat to deal with symlinks.
226 lstp = (lstat(upath, &lst) < 0) ? st : &lst;
227 aint = htonl(CNID(lstp, 1));
228 #if AD_VERSION > AD_VERSION1
231 memcpy(data, &aint, sizeof( aint ));
232 data += sizeof( aint );
236 aint = htonl( st->st_size );
237 memcpy(data, &aint, sizeof( aint ));
238 data += sizeof( aint );
243 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
247 memcpy(data, &aint, sizeof( aint ));
248 data += sizeof( aint );
251 /* Current client needs ProDOS info block for this file.
252 Use simple heuristic and let the Mac "type" string tell
253 us what the PD file code should be. Everything gets a
254 subtype of 0x0000 unless the original value was hashed
255 to "pXYZ" when we created it. See IA, Ver 2.
257 case FILPBIT_PDINFO :
259 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
261 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
265 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
269 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
273 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
277 else if ( fdType[0] == 'p' ) {
279 ashort = (fdType[2] * 256) + fdType[3];
293 memcpy(data, &ashort, sizeof( ashort ));
294 data += sizeof( ashort );
295 memset(data, 0, sizeof( ashort ));
296 data += sizeof( ashort );
301 ad_close( adp, ADFLAGS_HF );
303 return( AFPERR_BITMAP );
309 ashort = htons( data - buf );
310 memcpy(nameoff, &ashort, sizeof( ashort ));
311 if ((aint = strlen( path )) > MACFILELEN)
314 memcpy(data, path, aint );
318 ad_close( adp, ADFLAGS_HF );
320 *buflen = data - buf;
323 syslog(LOG_INFO, "end getfilparams:");
329 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
332 int ibuflen, *rbuflen;
335 struct adouble ad, *adp;
340 int creatf, did, openf, retvalue = AFP_OK;
347 syslog(LOG_INFO, "begin afp_createfile:");
352 creatf = (unsigned char) *ibuf++;
354 memcpy(&vid, ibuf, sizeof( vid ));
355 ibuf += sizeof( vid );
357 if (( vol = getvolbyvid( vid )) == NULL ) {
358 return( AFPERR_PARAM );
361 if (vol->v_flags & AFPVOL_RO)
364 memcpy(&did, ibuf, sizeof( did));
365 ibuf += sizeof( did );
367 if (( dir = dirsearch( vol, did )) == NULL ) {
368 return( AFPERR_NOOBJ );
371 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
372 return( AFPERR_NOOBJ );
375 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
376 strpbrk(path, MSWINDOWS_BADCHARS))
379 upath = mtoupath(vol, path);
381 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
384 if (!validupath(vol, upath))
387 if ((of = of_findname(vol, curdir, path))) {
390 memset(&ad, 0, sizeof(ad));
394 /* on a hard create, fail if file exists and is open */
395 if ((stat(upath, &st) == 0) && of)
397 openf = O_RDWR|O_CREAT|O_TRUNC;
399 openf = O_RDWR|O_CREAT|O_EXCL;
404 /* preserve current euid, egid */
405 save_uidgid ( uidgid );
407 /* perform all switching of users */
412 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
413 openf, 0666, adp) < 0 ) {
417 /* bring everything back to old euid, egid */
418 restore_uidgid ( uidgid );
420 return( AFPERR_EXIST );
423 /* bring everything back to old euid, egid */
424 restore_uidgid ( uidgid );
426 return( AFPERR_ACCESS );
428 /* on noadouble volumes, just creating the data fork is ok */
429 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
430 goto createfile_done;
434 /* bring everything back to old euid, egid */
435 restore_uidgid ( uidgid );
437 return( AFPERR_PARAM );
441 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
442 memcpy(ad_entry( adp, ADEID_NAME ), path,
443 ad_getentrylen( adp, ADEID_NAME ));
444 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
445 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
450 if (vol->v_flags & AFPVOL_DROPBOX) {
451 retvalue=matchfile2dirperms(upath, vol, did);
455 setvoltime(obj, vol );
458 syslog(LOG_INFO, "end afp_createfile");
462 /* bring everything back to old euid, egid */
463 restore_uidgid ( uidgid );
469 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
472 int ibuflen, *rbuflen;
478 u_int16_t vid, bitmap;
481 syslog(LOG_INFO, "begin afp_setfilparams:");
487 memcpy(&vid, ibuf, sizeof( vid ));
488 ibuf += sizeof( vid );
489 if (( vol = getvolbyvid( vid )) == NULL ) {
490 return( AFPERR_PARAM );
493 if (vol->v_flags & AFPVOL_RO)
496 memcpy(&did, ibuf, sizeof( did ));
497 ibuf += sizeof( did );
498 if (( dir = dirsearch( vol, did )) == NULL ) {
499 return( AFPERR_NOOBJ );
502 memcpy(&bitmap, ibuf, sizeof( bitmap ));
503 bitmap = ntohs( bitmap );
504 ibuf += sizeof( bitmap );
506 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
507 return( AFPERR_NOOBJ );
510 if ((u_long)ibuf & 1 ) {
514 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
515 setvoltime(obj, vol );
519 syslog(LOG_INFO, "end afp_setfilparams:");
526 int setfilparams(vol, path, bitmap, buf )
531 struct adouble ad, *adp;
534 int bit = 0, isad = 1, err = AFP_OK;
536 u_char achar, *fdType, xyy[4];
537 u_int16_t ashort, bshort;
546 syslog(LOG_INFO, "begin setfilparams:");
549 upath = mtoupath(vol, path);
550 if ((of = of_findname(vol, curdir, path))) {
553 memset(&ad, 0, sizeof(ad));
558 save_uidgid ( uidgid );
562 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
563 O_RDWR|O_CREAT, 0666, adp) < 0) {
564 /* for some things, we don't need an adouble header */
565 if (bitmap & ~(1<<FILPBIT_MDATE)) {
567 restore_uidgid ( uidgid );
569 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
572 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
573 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
574 memcpy(ad_entry( adp, ADEID_NAME ), path,
575 ad_getentrylen( adp, ADEID_NAME ));
578 while ( bitmap != 0 ) {
579 while (( bitmap & 1 ) == 0 ) {
586 memcpy(&ashort, buf, sizeof( ashort ));
587 ad_getattr(adp, &bshort);
588 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
589 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
593 ad_setattr(adp, bshort);
594 buf += sizeof( ashort );
598 memcpy(&aint, buf, sizeof(aint));
599 ad_setdate(adp, AD_DATE_CREATE, aint);
600 buf += sizeof( aint );
604 memcpy(&aint, buf, sizeof( aint ));
606 ad_setdate(adp, AD_DATE_MODIFY, aint);
607 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
609 buf += sizeof( aint );
613 memcpy(&aint, buf, sizeof(aint));
614 ad_setdate(adp, AD_DATE_BACKUP, aint);
615 buf += sizeof( aint );
619 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
620 && (em = getextmap( path )) &&
621 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
622 (memcmp(buf + 4, em->em_creator,
623 sizeof( em->em_creator )) == 0)) {
624 memcpy(buf, ufinderi, 8 );
626 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
630 /* Client needs to set the ProDOS file info for this file.
631 Use defined strings for the simple cases, and convert
632 all else into pXYY per Inside Appletalk. Always set
633 the creator as "pdos". <shirsch@ibm.net> */
634 case FILPBIT_PDINFO :
637 memcpy(&ashort, buf, sizeof( ashort ));
638 ashort = ntohs( ashort );
641 switch ( (unsigned int) achar )
644 fdType = ( u_char *) "TEXT";
648 fdType = ( u_char *) "PSYS";
652 fdType = ( u_char *) "PS16";
656 fdType = ( u_char *) "BINA";
660 xyy[0] = ( u_char ) 'p';
662 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
663 xyy[3] = ( u_char ) ashort & 0xff;
668 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
669 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
675 goto setfilparam_done;
684 ad_flush( adp, ADFLAGS_HF );
685 ad_close( adp, ADFLAGS_HF );
688 restore_uidgid ( uidgid );
694 syslog(LOG_INFO, "end setfilparams:");
701 * renamefile and copyfile take the old and new unix pathnames
702 * and the new mac name.
703 * NOTE: if we have to copy a file instead of renaming it, locks
706 int renamefile(src, dst, newname, noadouble )
707 char *src, *dst, *newname;
711 char adsrc[ MAXPATHLEN + 1];
715 * Note that this is only checking the existance of the data file,
716 * not the header file. The thinking is that if the data file doesn't
717 * exist, but the header file does, the right thing to do is remove
718 * the data file silently.
721 /* existence check moved to afp_moveandrename */
724 syslog (LOG_INFO, "begin renamefile:");
727 if ( rename( src, dst ) < 0 ) {
730 return( AFPERR_NOOBJ );
733 return( AFPERR_ACCESS );
736 case EXDEV : /* Cross device move -- try copy */
737 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
741 return deletefile( src );
743 return( AFPERR_PARAM );
747 strcpy( adsrc, ad_path( src, 0 ));
750 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
755 /* check for a source appledouble header. if it exists, make
756 * a dest appledouble directory and do the rename again. */
757 memset(&ad, 0, sizeof(ad));
758 if (rc || stat(adsrc, &st) ||
759 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
762 ad_close(&ad, ADFLAGS_HF);
766 return( AFPERR_ACCESS );
770 return( AFPERR_PARAM );
774 memset(&ad, 0, sizeof(ad));
775 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
778 return( AFPERR_NOOBJ );
780 return( AFPERR_ACCESS );
784 return( AFPERR_PARAM );
788 len = strlen( newname );
789 ad_setentrylen( &ad, ADEID_NAME, len );
790 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
791 ad_flush( &ad, ADFLAGS_HF );
792 ad_close( &ad, ADFLAGS_HF );
795 syslog (LOG_INFO, "end renamefile:");
801 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
804 int ibuflen, *rbuflen;
808 char *newname, *path, *p;
809 u_int32_t sdid, ddid;
810 int plen, err, retvalue = AFP_OK;
811 u_int16_t svid, dvid;
814 syslog (LOG_INFO, "begin afp_copyfile:");
820 memcpy(&svid, ibuf, sizeof( svid ));
821 ibuf += sizeof( svid );
822 if (( vol = getvolbyvid( svid )) == NULL ) {
823 return( AFPERR_PARAM );
826 memcpy(&sdid, ibuf, sizeof( sdid ));
827 ibuf += sizeof( sdid );
828 if (( dir = dirsearch( vol, sdid )) == NULL ) {
829 return( AFPERR_PARAM );
832 memcpy(&dvid, ibuf, sizeof( dvid ));
833 ibuf += sizeof( dvid );
834 memcpy(&ddid, ibuf, sizeof( ddid ));
835 ibuf += sizeof( ddid );
837 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
838 return( AFPERR_NOOBJ );
840 if ( *path == '\0' ) {
841 return( AFPERR_BADTYPE );
844 /* don't allow copies when the file is open.
845 * XXX: the spec only calls for read/deny write access.
846 * however, copyfile doesn't have any of that info,
847 * and locks need to stay coherent. as a result,
848 * we just balk if the file is opened already. */
849 if (of_findname(vol, curdir, path))
850 return AFPERR_DENYCONF;
852 newname = obj->newtmp;
853 strcpy( newname, path );
855 p = ctoupath( vol, curdir, newname );
857 if (( vol = getvolbyvid( dvid )) == NULL ) {
858 return( AFPERR_PARAM );
861 if (vol->v_flags & AFPVOL_RO)
864 if (( dir = dirsearch( vol, ddid )) == NULL ) {
865 return( AFPERR_PARAM );
868 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
869 return( AFPERR_NOOBJ );
871 if ( *path != '\0' ) {
872 return( AFPERR_BADTYPE );
875 /* one of the handful of places that knows about the path type */
876 if ( *ibuf++ != 2 ) {
877 return( AFPERR_PARAM );
879 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
880 strncpy( newname, ibuf, plen );
881 newname[ plen ] = '\0';
884 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
885 vol_noadouble(vol))) < 0 ) {
889 setvoltime(obj, vol );
892 if (vol->v_flags & AFPVOL_DROPBOX) {
893 retvalue=matchfile2dirperms(newname, vol, sdid);
898 syslog (LOG_INFO, "end afp_copyfile:");
905 static __inline__ int copy_all(const int dfd, const void *buf,
911 syslog(LOG_INFO, "begin copy_all:");
915 if ((cc = write(dfd, buf, buflen)) < 0) {
933 syslog(LOG_INFO, "end copy_all:");
939 /* XXX: this needs to use ad_open and ad_lock. so, we need to
940 * pass in vol and path */
941 int copyfile(src, dst, newname, noadouble )
942 char *src, *dst, *newname;
948 int sfd, dfd, len, err = AFP_OK;
952 syslog(LOG_INFO, "begin copyfile:");
956 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
959 break; /* just copy the data fork */
961 return( AFPERR_ACCESS );
963 return( AFPERR_PARAM );
966 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
967 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
971 return( AFPERR_NOOBJ );
973 return( AFPERR_ACCESS );
977 return( AFPERR_PARAM );
982 #ifdef SENDFILE_FLAVOR_LINUX
983 if (fstat(sfd, &st) == 0) {
984 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
998 goto copyheader_done;
1002 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1009 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1017 unlink(ad_path(dst, ADFLAGS_HF));
1023 /* data fork copying */
1024 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1027 return( AFPERR_NOOBJ );
1029 return( AFPERR_ACCESS );
1031 return( AFPERR_PARAM );
1035 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1039 return( AFPERR_NOOBJ );
1041 return( AFPERR_ACCESS );
1043 return AFPERR_VLOCK;
1045 return( AFPERR_PARAM );
1049 #ifdef SENDFILE_FLAVOR_LINUX
1050 if (fstat(sfd, &st) == 0) {
1051 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1067 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1075 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1084 unlink(ad_path(dst, ADFLAGS_HF));
1090 memset(&ad, 0, sizeof(ad));
1091 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1095 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1097 return( AFPERR_ACCESS );
1099 return AFPERR_VLOCK;
1101 return( AFPERR_PARAM );
1105 len = strlen( newname );
1106 ad_setentrylen( &ad, ADEID_NAME, len );
1107 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1108 ad_flush( &ad, ADFLAGS_HF );
1109 ad_close( &ad, ADFLAGS_HF );
1113 syslog(LOG_INFO, "end copyfile:");
1120 int deletefile( file )
1124 int adflags, err = AFP_OK;
1125 int locktype = ADLOCK_WR;
1126 int openmode = O_RDWR;
1129 syslog(LOG_INFO, "begin deletefile:");
1134 * If can't open read/write then try again read-only. If it's open
1135 * read-only, we must do a read lock instead of a write lock.
1137 /* try to open both at once */
1138 adflags = ADFLAGS_DF|ADFLAGS_HF;
1139 memset(&ad, 0, sizeof(ad));
1140 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1143 adflags = ADFLAGS_DF;
1144 /* that failed. now try to open just the data fork */
1145 memset(&ad, 0, sizeof(ad));
1146 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1149 return AFPERR_NOOBJ;
1151 if(openmode == O_RDWR) {
1152 openmode = O_RDONLY;
1153 locktype = ADLOCK_RD;
1156 return AFPERR_ACCESS;
1159 return AFPERR_VLOCK;
1161 return AFPERR_PARAM;
1167 if(openmode == O_RDWR) {
1168 openmode = O_RDONLY;
1169 locktype = ADLOCK_RD;
1172 return AFPERR_ACCESS;
1175 return AFPERR_VLOCK;
1177 return( AFPERR_PARAM );
1180 break; /* from the while */
1183 if ((adflags & ADFLAGS_HF) &&
1184 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1185 ad_close( &ad, adflags );
1186 return( AFPERR_BUSY );
1189 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1194 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1198 err = AFPERR_ACCESS;
1211 if ( unlink( file ) < 0 ) {
1215 err = AFPERR_ACCESS;
1229 if (adflags & ADFLAGS_HF)
1230 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1231 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1232 ad_close( &ad, adflags );
1235 syslog(LOG_INFO, "end deletefile:");
1242 #if AD_VERSION > AD_VERSION1
1243 /* return a file id */
1244 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1247 int ibuflen, *rbuflen;
1259 syslog(LOG_INFO, "begin afp_createid:");
1265 memcpy(&vid, ibuf, sizeof(vid));
1266 ibuf += sizeof(vid);
1268 if (( vol = getvolbyvid( vid )) == NULL ) {
1269 return( AFPERR_PARAM);
1272 if (vol->v_flags & AFPVOL_RO)
1273 return AFPERR_VLOCK;
1275 memcpy(&did, ibuf, sizeof( did ));
1276 ibuf += sizeof(did);
1278 if (( dir = dirsearch( vol, did )) == NULL ) {
1279 return( AFPERR_PARAM );
1282 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1283 return( AFPERR_PARAM );
1286 if ( *path == '\0' ) {
1287 return( AFPERR_BADTYPE );
1290 upath = mtoupath(vol, path);
1291 if (stat(upath, &st) < 0) {
1295 return AFPERR_ACCESS;
1297 return AFPERR_NOOBJ;
1299 return AFPERR_PARAM;
1303 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1304 memcpy(rbuf, &id, sizeof(id));
1305 *rbuflen = sizeof(id);
1306 return AFPERR_EXISTID;
1309 memset(&ad, 0, sizeof(ad));
1310 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1313 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1314 ad_close(&ad, ADFLAGS_HF);
1317 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1318 memcpy(rbuf, &id, sizeof(id));
1319 *rbuflen = sizeof(id);
1324 syslog(LOG_INFO, "ending afp_createid...:");
1329 return AFPERR_VLOCK;
1333 return AFPERR_ACCESS;
1336 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1337 return AFPERR_PARAM;
1341 /* resolve a file id */
1342 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1345 int ibuflen, *rbuflen;
1353 u_int16_t vid, bitmap;
1356 syslog(LOG_INFO, "begin afp_resolveid:");
1362 memcpy(&vid, ibuf, sizeof(vid));
1363 ibuf += sizeof(vid);
1365 if (( vol = getvolbyvid( vid )) == NULL ) {
1366 return( AFPERR_PARAM);
1369 memcpy(&id, ibuf, sizeof( id ));
1372 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1373 return AFPERR_BADID;
1376 if (( dir = dirsearch( vol, id )) == NULL ) {
1377 return( AFPERR_PARAM );
1380 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1384 return AFPERR_ACCESS;
1388 return AFPERR_PARAM;
1392 /* directories are bad */
1393 if (S_ISDIR(st.st_mode))
1394 return AFPERR_BADTYPE;
1396 memcpy(&bitmap, ibuf, sizeof(bitmap));
1397 bitmap = ntohs( bitmap );
1399 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1400 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1403 *rbuflen = buflen + sizeof(bitmap);
1404 memcpy(rbuf, ibuf, sizeof(bitmap));
1407 syslog(LOG_INFO, "end afp_resolveid:");
1413 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1416 int ibuflen, *rbuflen;
1427 syslog(LOG_INFO, "begin afp_deleteid:");
1433 memcpy(&vid, ibuf, sizeof(vid));
1434 ibuf += sizeof(vid);
1436 if (( vol = getvolbyvid( vid )) == NULL ) {
1437 return( AFPERR_PARAM);
1440 if (vol->v_flags & AFPVOL_RO)
1441 return AFPERR_VLOCK;
1443 memcpy(&id, ibuf, sizeof( id ));
1446 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1450 if (( dir = dirsearch( vol, id )) == NULL ) {
1451 return( AFPERR_PARAM );
1455 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1459 return AFPERR_ACCESS;
1461 /* still try to delete the id */
1465 return AFPERR_PARAM;
1469 /* directories are bad */
1470 if (S_ISDIR(st.st_mode))
1471 return AFPERR_BADTYPE;
1473 if (cnid_delete(vol->v_db, id)) {
1476 return AFPERR_VLOCK;
1479 return AFPERR_ACCESS;
1481 return AFPERR_PARAM;
1486 syslog(LOG_INFO, "end afp_deleteid:");
1493 #define APPLETEMP ".AppleTempXXXXXX"
1494 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1497 int ibuflen, *rbuflen;
1499 struct stat srcst, destst;
1501 struct dir *dir, *sdir;
1502 char *spath, temp[17], *path, *p;
1503 char *supath, *upath;
1505 #if AD_VERSION > AD_VERSION1
1512 syslog(LOG_INFO, "begin afp_exchangefiles:");
1518 memcpy(&vid, ibuf, sizeof(vid));
1519 ibuf += sizeof(vid);
1521 if (( vol = getvolbyvid( vid )) == NULL ) {
1522 return( AFPERR_PARAM);
1525 if (vol->v_flags & AFPVOL_RO)
1526 return AFPERR_VLOCK;
1528 /* source and destination dids */
1529 memcpy(&sid, ibuf, sizeof(sid));
1530 ibuf += sizeof(sid);
1531 memcpy(&did, ibuf, sizeof(did));
1532 ibuf += sizeof(did);
1535 if ((dir = dirsearch( vol, sid )) == NULL ) {
1536 return( AFPERR_PARAM );
1539 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1540 return( AFPERR_PARAM );
1543 if ( *path == '\0' ) {
1544 return( AFPERR_BADTYPE );
1547 upath = mtoupath(vol, path);
1548 if (stat(upath, &srcst) < 0) {
1554 return AFPERR_ACCESS;
1556 return AFPERR_PARAM;
1560 /* save some stuff */
1562 spath = obj->oldtmp;
1563 supath = obj->newtmp;
1564 strcpy(spath, path);
1565 strcpy(supath, upath); /* this is for the cnid changing */
1566 p = ctoupath( vol, sdir, spath);
1568 /* look for the source cnid. if it doesn't exist, don't worry about
1570 #if AD_VERSION > AD_VERSION1
1571 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1572 slen = strlen(supath));
1575 if (( dir = dirsearch( vol, did )) == NULL ) {
1576 return( AFPERR_PARAM );
1579 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1580 return( AFPERR_PARAM );
1583 if ( *path == '\0' ) {
1584 return( AFPERR_BADTYPE );
1587 /* FPExchangeFiles is the only call that can return the SameObj
1589 if ((curdir == sdir) && strcmp(spath, path) == 0)
1590 return AFPERR_SAMEOBJ;
1592 upath = mtoupath(vol, path);
1593 if (stat(upath, &destst) < 0) {
1599 return AFPERR_ACCESS;
1601 return AFPERR_PARAM;
1605 #if AD_VERSION > AD_VERSION1
1606 /* look for destination id. */
1607 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1608 dlen = strlen(upath));
1611 /* construct a temp name.
1612 * NOTE: the temp file will be in the dest file's directory. it
1613 * will also be inaccessible from AFP. */
1614 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1618 /* now, quickly rename the file. we error if we can't. */
1619 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1620 goto err_exchangefile;
1621 of_rename(vol, sdir, spath, curdir, temp);
1623 /* rename destination to source */
1624 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1625 goto err_src_to_tmp;
1626 of_rename(vol, curdir, path, sdir, spath);
1628 /* rename temp to destination */
1629 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1630 goto err_dest_to_src;
1631 of_rename(vol, curdir, temp, curdir, path);
1633 #if AD_VERSION > AD_VERSION1
1634 /* id's need switching. src -> dest and dest -> src. */
1635 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1636 upath, dlen) < 0)) {
1640 err = AFPERR_ACCESS;
1644 goto err_temp_to_dest;
1647 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1648 supath, slen) < 0)) {
1652 err = AFPERR_ACCESS;
1658 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1659 goto err_temp_to_dest;
1664 syslog(LOG_INFO, "ending afp_exchangefiles:");
1670 /* all this stuff is so that we can unwind a failed operation
1673 /* rename dest to temp */
1674 renamefile(upath, temp, temp, vol_noadouble(vol));
1675 of_rename(vol, curdir, upath, curdir, temp);
1678 /* rename source back to dest */
1679 renamefile(p, upath, path, vol_noadouble(vol));
1680 of_rename(vol, sdir, spath, curdir, path);
1683 /* rename temp back to source */
1684 renamefile(temp, p, spath, vol_noadouble(vol));
1685 of_rename(vol, curdir, temp, sdir, spath);