2 * $Id: file.c,v 1.21 2001-06-19 18:04:39 rufustfirefly Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
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"
42 /* check for mtab DID code */
44 #include "parse_mtab.h"
49 #endif /* FORCE_UIDGID */
51 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
52 * field bytes subfield bytes
55 * ioFlFndrInfo 16 -> type 4 type field
56 * creator 4 creator field
57 * flags 2 finder flags:
59 * location 4 location in window
60 * folder 2 window that contains file
62 * ioFlXFndrInfo 16 -> iconID 2 icon id
64 * script 1 script system
66 * commentID 2 comment id
67 * putawayID 4 home directory id
70 const u_char ufinderi[] = {
71 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
72 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0
77 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
87 struct stat hst, lst, *lstp;
88 #else /* USE_LASTDID */
90 #endif /* USE_LASTDID */
91 struct adouble ad, *adp;
94 char *data, *nameoff = NULL, *upath;
95 int bit = 0, isad = 1, aint;
97 u_char achar, fdType[4];
100 syslog(LOG_INFO, "begin getfilparams:");
103 upath = mtoupath(vol, path);
104 if ((of = of_findname(vol, curdir, path))) {
107 memset(&ad, 0, sizeof(ad));
111 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
113 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
114 syslog( LOG_ERR, "getfilparams fstat: %m" );
118 while ( bitmap != 0 ) {
119 while (( bitmap & 1 ) == 0 ) {
127 ad_getattr(adp, &ashort);
128 } else if (*upath == '.') {
129 ashort = htons(ATTRBIT_INVISIBLE);
132 memcpy(data, &ashort, sizeof( ashort ));
133 data += sizeof( u_short );
137 memcpy(data, &dir->d_did, sizeof( int ));
138 data += sizeof( int );
142 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
143 aint = AD_DATE_FROM_UNIX(st->st_mtime);
144 memcpy(data, &aint, sizeof( aint ));
145 data += sizeof( aint );
149 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
150 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
151 (hst.st_mtime < st->st_mtime)) {
152 aint = AD_DATE_FROM_UNIX(st->st_mtime);
155 aint = AD_DATE_FROM_UNIX(st->st_mtime);
157 memcpy(data, &aint, sizeof( int ));
158 data += sizeof( int );
162 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
163 aint = AD_DATE_START;
164 memcpy(data, &aint, sizeof( int ));
165 data += sizeof( int );
170 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
172 memcpy(data, ufinderi, 32);
173 if (*upath == '.') { /* make it invisible */
174 ashort = htons(FINDERINFO_INVISIBLE);
175 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
179 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
180 ufinderi, 8 ) == 0)) &&
181 (em = getextmap( path ))) {
182 memcpy(data, em->em_type, sizeof( em->em_type ));
183 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
190 data += sizeof( u_int16_t );
194 memset(data, 0, sizeof(u_int16_t));
195 data += sizeof( u_int16_t );
199 #if AD_VERSION > AD_VERSION1
200 /* use the CNID database if we're using AD v2 */
202 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
206 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
207 strlen(upath), aint))) {
208 #endif /* AD_VERSION > AD_VERSION1 */
210 * What a fucking mess. First thing: DID and FNUMs are
211 * in the same space for purposes of enumerate (and several
212 * other wierd places). While we consider this Apple's bug,
213 * this is the work-around: In order to maintain constant and
214 * unique DIDs and FNUMs, we monotonically generate the DIDs
215 * during the session, and derive the FNUMs from the filesystem.
216 * Since the DIDs are small, we insure that the FNUMs are fairly
217 * large by setting thier high bits to the device number.
219 * AFS already does something very similar to this for the
220 * inode number, so we don't repeat the procedure.
223 * due to complaints over did's being non-persistent,
224 * here's the current hack to provide semi-persistent
226 * 1) we reserve the first bit for file ids.
227 * 2) the next 7 bits are for the device.
228 * 3) the remaining 24 bits are for the inode.
230 * both the inode and device information are actually hashes
231 * that are then truncated to the requisite bit length.
233 * it should be okay to use lstat to deal with symlinks.
236 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
237 #else /* USE_LASTDID */
238 lstp = lstat(upath, &lst) < 0 ? st : &lst;
240 aint = htonl( afpd_st_cnid ( lstp ) );
242 aint = htonl(CNID(lstp, 1));
243 #endif /* DID_MTAB */
244 #endif /* USE_LASTDID */
246 #if AD_VERSION > AD_VERSION1
248 #endif /* AD_VERSION > AD_VERSION1 */
249 memcpy(data, &aint, sizeof( aint ));
250 data += sizeof( aint );
254 aint = htonl( st->st_size );
255 memcpy(data, &aint, sizeof( aint ));
256 data += sizeof( aint );
261 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
265 memcpy(data, &aint, sizeof( aint ));
266 data += sizeof( aint );
269 /* Current client needs ProDOS info block for this file.
270 Use simple heuristic and let the Mac "type" string tell
271 us what the PD file code should be. Everything gets a
272 subtype of 0x0000 unless the original value was hashed
273 to "pXYZ" when we created it. See IA, Ver 2.
275 case FILPBIT_PDINFO :
277 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
279 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
283 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
287 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
291 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
295 else if ( fdType[0] == 'p' ) {
297 ashort = (fdType[2] * 256) + fdType[3];
311 memcpy(data, &ashort, sizeof( ashort ));
312 data += sizeof( ashort );
313 memset(data, 0, sizeof( ashort ));
314 data += sizeof( ashort );
319 ad_close( adp, ADFLAGS_HF );
321 return( AFPERR_BITMAP );
327 ashort = htons( data - buf );
328 memcpy(nameoff, &ashort, sizeof( ashort ));
329 if ((aint = strlen( path )) > MACFILELEN)
332 memcpy(data, path, aint );
336 ad_close( adp, ADFLAGS_HF );
338 *buflen = data - buf;
341 syslog(LOG_INFO, "end getfilparams:");
347 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
350 int ibuflen, *rbuflen;
353 struct adouble ad, *adp;
358 int creatf, did, openf, retvalue = AFP_OK;
362 #endif /* FORCE_UIDGID */
365 syslog(LOG_INFO, "begin afp_createfile:");
370 creatf = (unsigned char) *ibuf++;
372 memcpy(&vid, ibuf, sizeof( vid ));
373 ibuf += sizeof( vid );
375 if (( vol = getvolbyvid( vid )) == NULL ) {
376 return( AFPERR_PARAM );
379 if (vol->v_flags & AFPVOL_RO)
382 memcpy(&did, ibuf, sizeof( did));
383 ibuf += sizeof( did );
385 if (( dir = dirsearch( vol, did )) == NULL ) {
386 return( AFPERR_NOOBJ );
389 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
390 return( AFPERR_NOOBJ );
393 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
394 strpbrk(path, MSWINDOWS_BADCHARS))
397 upath = mtoupath(vol, path);
399 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
402 if (!validupath(vol, upath))
405 if ((of = of_findname(vol, curdir, path))) {
408 memset(&ad, 0, sizeof(ad));
412 /* on a hard create, fail if file exists and is open */
413 if ((stat(upath, &st) == 0) && of)
415 openf = O_RDWR|O_CREAT|O_TRUNC;
417 openf = O_RDWR|O_CREAT|O_EXCL;
422 /* preserve current euid, egid */
423 save_uidgid ( uidgid );
425 /* perform all switching of users */
428 #endif /* FORCE_UIDGID */
430 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
431 openf, 0666, adp) < 0 ) {
435 /* bring everything back to old euid, egid */
436 restore_uidgid ( uidgid );
437 #endif /* FORCE_UIDGID */
438 return( AFPERR_EXIST );
441 /* bring everything back to old euid, egid */
442 restore_uidgid ( uidgid );
443 #endif /* FORCE_UIDGID */
444 return( AFPERR_ACCESS );
446 /* on noadouble volumes, just creating the data fork is ok */
447 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
448 goto createfile_done;
452 /* bring everything back to old euid, egid */
453 restore_uidgid ( uidgid );
454 #endif /* FORCE_UIDGID */
455 return( AFPERR_PARAM );
459 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
460 memcpy(ad_entry( adp, ADEID_NAME ), path,
461 ad_getentrylen( adp, ADEID_NAME ));
462 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
463 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
468 if (vol->v_flags & AFPVOL_DROPBOX) {
469 retvalue = matchfile2dirperms(upath, vol, did);
471 #endif /* DROPKLUDGE */
473 setvoltime(obj, vol );
476 syslog(LOG_INFO, "end afp_createfile");
480 /* bring everything back to old euid, egid */
481 restore_uidgid ( uidgid );
482 #endif /* FORCE_UIDGID */
487 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
490 int ibuflen, *rbuflen;
496 u_int16_t vid, bitmap;
499 syslog(LOG_INFO, "begin afp_setfilparams:");
505 memcpy(&vid, ibuf, sizeof( vid ));
506 ibuf += sizeof( vid );
507 if (( vol = getvolbyvid( vid )) == NULL ) {
508 return( AFPERR_PARAM );
511 if (vol->v_flags & AFPVOL_RO)
514 memcpy(&did, ibuf, sizeof( did ));
515 ibuf += sizeof( did );
516 if (( dir = dirsearch( vol, did )) == NULL ) {
517 return( AFPERR_NOOBJ );
520 memcpy(&bitmap, ibuf, sizeof( bitmap ));
521 bitmap = ntohs( bitmap );
522 ibuf += sizeof( bitmap );
524 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
525 return( AFPERR_NOOBJ );
528 if ((u_long)ibuf & 1 ) {
532 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
533 setvoltime(obj, vol );
537 syslog(LOG_INFO, "end afp_setfilparams:");
544 int setfilparams(vol, path, bitmap, buf )
549 struct adouble ad, *adp;
552 int bit = 0, isad = 1, err = AFP_OK;
554 u_char achar, *fdType, xyy[4];
555 u_int16_t ashort, bshort;
561 #endif /* FORCE_UIDGID */
564 syslog(LOG_INFO, "begin setfilparams:");
567 upath = mtoupath(vol, path);
568 if ((of = of_findname(vol, curdir, path))) {
571 memset(&ad, 0, sizeof(ad));
576 save_uidgid ( uidgid );
578 #endif /* FORCE_UIDGID */
580 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
581 O_RDWR|O_CREAT, 0666, adp) < 0) {
582 /* for some things, we don't need an adouble header */
583 if (bitmap & ~(1<<FILPBIT_MDATE)) {
585 restore_uidgid ( uidgid );
586 #endif /* FORCE_UIDGID */
587 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
590 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
591 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
592 memcpy(ad_entry( adp, ADEID_NAME ), path,
593 ad_getentrylen( adp, ADEID_NAME ));
596 while ( bitmap != 0 ) {
597 while (( bitmap & 1 ) == 0 ) {
604 memcpy(&ashort, buf, sizeof( ashort ));
605 ad_getattr(adp, &bshort);
606 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
607 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
611 ad_setattr(adp, bshort);
612 buf += sizeof( ashort );
616 memcpy(&aint, buf, sizeof(aint));
617 ad_setdate(adp, AD_DATE_CREATE, aint);
618 buf += sizeof( aint );
622 memcpy(&aint, buf, sizeof( aint ));
624 ad_setdate(adp, AD_DATE_MODIFY, aint);
625 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
627 buf += sizeof( aint );
631 memcpy(&aint, buf, sizeof(aint));
632 ad_setdate(adp, AD_DATE_BACKUP, aint);
633 buf += sizeof( aint );
637 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
638 && (em = getextmap( path )) &&
639 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
640 (memcmp(buf + 4, em->em_creator,
641 sizeof( em->em_creator )) == 0)) {
642 memcpy(buf, ufinderi, 8 );
644 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
648 /* Client needs to set the ProDOS file info for this file.
649 Use defined strings for the simple cases, and convert
650 all else into pXYY per Inside Appletalk. Always set
651 the creator as "pdos". <shirsch@ibm.net> */
652 case FILPBIT_PDINFO :
655 memcpy(&ashort, buf, sizeof( ashort ));
656 ashort = ntohs( ashort );
659 switch ( (unsigned int) achar )
662 fdType = ( u_char *) "TEXT";
666 fdType = ( u_char *) "PSYS";
670 fdType = ( u_char *) "PS16";
674 fdType = ( u_char *) "BINA";
678 xyy[0] = ( u_char ) 'p';
680 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
681 xyy[3] = ( u_char ) ashort & 0xff;
686 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
687 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
693 goto setfilparam_done;
702 ad_flush( adp, ADFLAGS_HF );
703 ad_close( adp, ADFLAGS_HF );
706 restore_uidgid ( uidgid );
707 #endif /* FORCE_UIDGID */
712 syslog(LOG_INFO, "end setfilparams:");
719 * renamefile and copyfile take the old and new unix pathnames
720 * and the new mac name.
721 * NOTE: if we have to copy a file instead of renaming it, locks
724 int renamefile(src, dst, newname, noadouble )
725 char *src, *dst, *newname;
729 char adsrc[ MAXPATHLEN + 1];
733 * Note that this is only checking the existance of the data file,
734 * not the header file. The thinking is that if the data file doesn't
735 * exist, but the header file does, the right thing to do is remove
736 * the data file silently.
739 /* existence check moved to afp_moveandrename */
742 syslog (LOG_INFO, "begin renamefile:");
745 if ( rename( src, dst ) < 0 ) {
748 return( AFPERR_NOOBJ );
751 return( AFPERR_ACCESS );
754 case EXDEV : /* Cross device move -- try copy */
755 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
759 return deletefile( src );
761 return( AFPERR_PARAM );
765 strcpy( adsrc, ad_path( src, 0 ));
768 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
773 /* check for a source appledouble header. if it exists, make
774 * a dest appledouble directory and do the rename again. */
775 memset(&ad, 0, sizeof(ad));
776 if (rc || stat(adsrc, &st) ||
777 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
780 ad_close(&ad, ADFLAGS_HF);
784 return( AFPERR_ACCESS );
788 return( AFPERR_PARAM );
792 memset(&ad, 0, sizeof(ad));
793 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
796 return( AFPERR_NOOBJ );
798 return( AFPERR_ACCESS );
802 return( AFPERR_PARAM );
806 len = strlen( newname );
807 ad_setentrylen( &ad, ADEID_NAME, len );
808 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
809 ad_flush( &ad, ADFLAGS_HF );
810 ad_close( &ad, ADFLAGS_HF );
813 syslog (LOG_INFO, "end renamefile:");
819 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
822 int ibuflen, *rbuflen;
826 char *newname, *path, *p;
827 u_int32_t sdid, ddid;
828 int plen, err, retvalue = AFP_OK;
829 u_int16_t svid, dvid;
832 syslog (LOG_INFO, "begin afp_copyfile:");
838 memcpy(&svid, ibuf, sizeof( svid ));
839 ibuf += sizeof( svid );
840 if (( vol = getvolbyvid( svid )) == NULL ) {
841 return( AFPERR_PARAM );
844 memcpy(&sdid, ibuf, sizeof( sdid ));
845 ibuf += sizeof( sdid );
846 if (( dir = dirsearch( vol, sdid )) == NULL ) {
847 return( AFPERR_PARAM );
850 memcpy(&dvid, ibuf, sizeof( dvid ));
851 ibuf += sizeof( dvid );
852 memcpy(&ddid, ibuf, sizeof( ddid ));
853 ibuf += sizeof( ddid );
855 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
856 return( AFPERR_NOOBJ );
858 if ( *path == '\0' ) {
859 return( AFPERR_BADTYPE );
862 /* don't allow copies when the file is open.
863 * XXX: the spec only calls for read/deny write access.
864 * however, copyfile doesn't have any of that info,
865 * and locks need to stay coherent. as a result,
866 * we just balk if the file is opened already. */
867 if (of_findname(vol, curdir, path))
868 return AFPERR_DENYCONF;
870 newname = obj->newtmp;
871 strcpy( newname, path );
873 p = ctoupath( vol, curdir, newname );
875 if (( vol = getvolbyvid( dvid )) == NULL ) {
876 return( AFPERR_PARAM );
879 if (vol->v_flags & AFPVOL_RO)
882 if (( dir = dirsearch( vol, ddid )) == NULL ) {
883 return( AFPERR_PARAM );
886 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
887 return( AFPERR_NOOBJ );
889 if ( *path != '\0' ) {
890 return( AFPERR_BADTYPE );
893 /* one of the handful of places that knows about the path type */
894 if ( *ibuf++ != 2 ) {
895 return( AFPERR_PARAM );
897 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
898 strncpy( newname, ibuf, plen );
899 newname[ plen ] = '\0';
902 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
903 vol_noadouble(vol))) < 0 ) {
907 setvoltime(obj, vol );
910 if (vol->v_flags & AFPVOL_DROPBOX) {
911 retvalue=matchfile2dirperms(newname, vol, sdid);
913 #endif /* DROPKLUDGE */
916 syslog (LOG_INFO, "end afp_copyfile:");
923 static __inline__ int copy_all(const int dfd, const void *buf,
929 syslog(LOG_INFO, "begin copy_all:");
933 if ((cc = write(dfd, buf, buflen)) < 0) {
951 syslog(LOG_INFO, "end copy_all:");
957 /* XXX: this needs to use ad_open and ad_lock. so, we need to
958 * pass in vol and path */
959 int copyfile(src, dst, newname, noadouble )
960 char *src, *dst, *newname;
966 int sfd, dfd, len, err = AFP_OK;
970 syslog(LOG_INFO, "begin copyfile:");
974 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
977 break; /* just copy the data fork */
979 return( AFPERR_ACCESS );
981 return( AFPERR_PARAM );
984 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
985 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
989 return( AFPERR_NOOBJ );
991 return( AFPERR_ACCESS );
995 return( AFPERR_PARAM );
1000 #ifdef SENDFILE_FLAVOR_LINUX
1001 if (fstat(sfd, &st) == 0) {
1002 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1016 goto copyheader_done;
1018 #endif /* SENDFILE_FLAVOR_LINUX */
1020 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1027 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1035 unlink(ad_path(dst, ADFLAGS_HF));
1041 /* data fork copying */
1042 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1045 return( AFPERR_NOOBJ );
1047 return( AFPERR_ACCESS );
1049 return( AFPERR_PARAM );
1053 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1057 return( AFPERR_NOOBJ );
1059 return( AFPERR_ACCESS );
1061 return AFPERR_VLOCK;
1063 return( AFPERR_PARAM );
1067 #ifdef SENDFILE_FLAVOR_LINUX
1068 if (fstat(sfd, &st) == 0) {
1069 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1082 #endif /* SENDFILE_FLAVOR_LINUX */
1085 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1093 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1102 unlink(ad_path(dst, ADFLAGS_HF));
1108 memset(&ad, 0, sizeof(ad));
1109 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1113 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1115 return( AFPERR_ACCESS );
1117 return AFPERR_VLOCK;
1119 return( AFPERR_PARAM );
1123 len = strlen( newname );
1124 ad_setentrylen( &ad, ADEID_NAME, len );
1125 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1126 ad_flush( &ad, ADFLAGS_HF );
1127 ad_close( &ad, ADFLAGS_HF );
1131 syslog(LOG_INFO, "end copyfile:");
1138 int deletefile( file )
1142 int adflags, err = AFP_OK;
1143 int locktype = ADLOCK_WR;
1144 int openmode = O_RDWR;
1147 syslog(LOG_INFO, "begin deletefile:");
1152 * If can't open read/write then try again read-only. If it's open
1153 * read-only, we must do a read lock instead of a write lock.
1155 /* try to open both at once */
1156 adflags = ADFLAGS_DF|ADFLAGS_HF;
1157 memset(&ad, 0, sizeof(ad));
1158 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1161 adflags = ADFLAGS_DF;
1162 /* that failed. now try to open just the data fork */
1163 memset(&ad, 0, sizeof(ad));
1164 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1167 return AFPERR_NOOBJ;
1169 if(openmode == O_RDWR) {
1170 openmode = O_RDONLY;
1171 locktype = ADLOCK_RD;
1174 return AFPERR_ACCESS;
1177 return AFPERR_VLOCK;
1179 return AFPERR_PARAM;
1185 if(openmode == O_RDWR) {
1186 openmode = O_RDONLY;
1187 locktype = ADLOCK_RD;
1190 return AFPERR_ACCESS;
1193 return AFPERR_VLOCK;
1195 return( AFPERR_PARAM );
1198 break; /* from the while */
1201 if ((adflags & ADFLAGS_HF) &&
1202 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1203 ad_close( &ad, adflags );
1204 return( AFPERR_BUSY );
1207 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1212 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1216 err = AFPERR_ACCESS;
1229 if ( unlink( file ) < 0 ) {
1233 err = AFPERR_ACCESS;
1247 if (adflags & ADFLAGS_HF)
1248 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1249 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1250 ad_close( &ad, adflags );
1253 syslog(LOG_INFO, "end deletefile:");
1260 #if AD_VERSION > AD_VERSION1
1261 /* return a file id */
1262 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1265 int ibuflen, *rbuflen;
1277 syslog(LOG_INFO, "begin afp_createid:");
1283 memcpy(&vid, ibuf, sizeof(vid));
1284 ibuf += sizeof(vid);
1286 if (( vol = getvolbyvid( vid )) == NULL ) {
1287 return( AFPERR_PARAM);
1290 if (vol->v_flags & AFPVOL_RO)
1291 return AFPERR_VLOCK;
1293 memcpy(&did, ibuf, sizeof( did ));
1294 ibuf += sizeof(did);
1296 if (( dir = dirsearch( vol, did )) == NULL ) {
1297 return( AFPERR_PARAM );
1300 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1301 return( AFPERR_PARAM );
1304 if ( *path == '\0' ) {
1305 return( AFPERR_BADTYPE );
1308 upath = mtoupath(vol, path);
1309 if (stat(upath, &st) < 0) {
1313 return AFPERR_ACCESS;
1315 return AFPERR_NOOBJ;
1317 return AFPERR_PARAM;
1321 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1322 memcpy(rbuf, &id, sizeof(id));
1323 *rbuflen = sizeof(id);
1324 return AFPERR_EXISTID;
1327 memset(&ad, 0, sizeof(ad));
1328 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1331 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1332 ad_close(&ad, ADFLAGS_HF);
1335 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1336 memcpy(rbuf, &id, sizeof(id));
1337 *rbuflen = sizeof(id);
1342 syslog(LOG_INFO, "ending afp_createid...:");
1347 return AFPERR_VLOCK;
1351 return AFPERR_ACCESS;
1354 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1355 return AFPERR_PARAM;
1359 /* resolve a file id */
1360 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1363 int ibuflen, *rbuflen;
1371 u_int16_t vid, bitmap;
1374 syslog(LOG_INFO, "begin afp_resolveid:");
1380 memcpy(&vid, ibuf, sizeof(vid));
1381 ibuf += sizeof(vid);
1383 if (( vol = getvolbyvid( vid )) == NULL ) {
1384 return( AFPERR_PARAM);
1387 memcpy(&id, ibuf, sizeof( id ));
1390 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1391 return AFPERR_BADID;
1394 if (( dir = dirsearch( vol, id )) == NULL ) {
1395 return( AFPERR_PARAM );
1398 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1402 return AFPERR_ACCESS;
1406 return AFPERR_PARAM;
1410 /* directories are bad */
1411 if (S_ISDIR(st.st_mode))
1412 return AFPERR_BADTYPE;
1414 memcpy(&bitmap, ibuf, sizeof(bitmap));
1415 bitmap = ntohs( bitmap );
1417 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1418 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1421 *rbuflen = buflen + sizeof(bitmap);
1422 memcpy(rbuf, ibuf, sizeof(bitmap));
1425 syslog(LOG_INFO, "end afp_resolveid:");
1431 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1434 int ibuflen, *rbuflen;
1445 syslog(LOG_INFO, "begin afp_deleteid:");
1451 memcpy(&vid, ibuf, sizeof(vid));
1452 ibuf += sizeof(vid);
1454 if (( vol = getvolbyvid( vid )) == NULL ) {
1455 return( AFPERR_PARAM);
1458 if (vol->v_flags & AFPVOL_RO)
1459 return AFPERR_VLOCK;
1461 memcpy(&id, ibuf, sizeof( id ));
1464 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1468 if (( dir = dirsearch( vol, id )) == NULL ) {
1469 return( AFPERR_PARAM );
1473 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1477 return AFPERR_ACCESS;
1479 /* still try to delete the id */
1483 return AFPERR_PARAM;
1487 /* directories are bad */
1488 if (S_ISDIR(st.st_mode))
1489 return AFPERR_BADTYPE;
1491 if (cnid_delete(vol->v_db, id)) {
1494 return AFPERR_VLOCK;
1497 return AFPERR_ACCESS;
1499 return AFPERR_PARAM;
1504 syslog(LOG_INFO, "end afp_deleteid:");
1509 #endif /* AD_VERSION > AD_VERSION1 */
1511 #define APPLETEMP ".AppleTempXXXXXX"
1513 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1516 int ibuflen, *rbuflen;
1518 struct stat srcst, destst;
1520 struct dir *dir, *sdir;
1521 char *spath, temp[17], *path, *p;
1522 char *supath, *upath;
1524 #if AD_VERSION > AD_VERSION1
1526 #endif /* AD_VERSION > AD_VERSION1 */
1531 syslog(LOG_INFO, "begin afp_exchangefiles:");
1537 memcpy(&vid, ibuf, sizeof(vid));
1538 ibuf += sizeof(vid);
1540 if (( vol = getvolbyvid( vid )) == NULL ) {
1541 return( AFPERR_PARAM);
1544 if (vol->v_flags & AFPVOL_RO)
1545 return AFPERR_VLOCK;
1547 /* source and destination dids */
1548 memcpy(&sid, ibuf, sizeof(sid));
1549 ibuf += sizeof(sid);
1550 memcpy(&did, ibuf, sizeof(did));
1551 ibuf += sizeof(did);
1554 if ((dir = dirsearch( vol, sid )) == NULL ) {
1555 return( AFPERR_PARAM );
1558 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1559 return( AFPERR_PARAM );
1562 if ( *path == '\0' ) {
1563 return( AFPERR_BADTYPE );
1566 upath = mtoupath(vol, path);
1567 if (stat(upath, &srcst) < 0) {
1573 return AFPERR_ACCESS;
1575 return AFPERR_PARAM;
1579 /* save some stuff */
1581 spath = obj->oldtmp;
1582 supath = obj->newtmp;
1583 strcpy(spath, path);
1584 strcpy(supath, upath); /* this is for the cnid changing */
1585 p = ctoupath( vol, sdir, spath);
1587 /* look for the source cnid. if it doesn't exist, don't worry about
1589 #if AD_VERSION > AD_VERSION1
1590 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1591 slen = strlen(supath));
1592 #endif /* AD_VERSION > AD_VERSION1 */
1594 if (( dir = dirsearch( vol, did )) == NULL ) {
1595 return( AFPERR_PARAM );
1598 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1599 return( AFPERR_PARAM );
1602 if ( *path == '\0' ) {
1603 return( AFPERR_BADTYPE );
1606 /* FPExchangeFiles is the only call that can return the SameObj
1608 if ((curdir == sdir) && strcmp(spath, path) == 0)
1609 return AFPERR_SAMEOBJ;
1611 upath = mtoupath(vol, path);
1612 if (stat(upath, &destst) < 0) {
1618 return AFPERR_ACCESS;
1620 return AFPERR_PARAM;
1624 #if AD_VERSION > AD_VERSION1
1625 /* look for destination id. */
1626 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1627 dlen = strlen(upath));
1628 #endif /* AD_VERSION > AD_VERSION1 */
1630 /* construct a temp name.
1631 * NOTE: the temp file will be in the dest file's directory. it
1632 * will also be inaccessible from AFP. */
1633 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1637 /* now, quickly rename the file. we error if we can't. */
1638 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1639 goto err_exchangefile;
1640 of_rename(vol, sdir, spath, curdir, temp);
1642 /* rename destination to source */
1643 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1644 goto err_src_to_tmp;
1645 of_rename(vol, curdir, path, sdir, spath);
1647 /* rename temp to destination */
1648 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1649 goto err_dest_to_src;
1650 of_rename(vol, curdir, temp, curdir, path);
1652 #if AD_VERSION > AD_VERSION1
1653 /* id's need switching. src -> dest and dest -> src. */
1654 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1655 upath, dlen) < 0)) {
1659 err = AFPERR_ACCESS;
1663 goto err_temp_to_dest;
1666 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1667 supath, slen) < 0)) {
1671 err = AFPERR_ACCESS;
1677 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1678 goto err_temp_to_dest;
1680 #endif /* AD_VERSION > AD_VERSION1 */
1683 syslog(LOG_INFO, "ending afp_exchangefiles:");
1689 /* all this stuff is so that we can unwind a failed operation
1692 /* rename dest to temp */
1693 renamefile(upath, temp, temp, vol_noadouble(vol));
1694 of_rename(vol, curdir, upath, curdir, temp);
1697 /* rename source back to dest */
1698 renamefile(p, upath, path, vol_noadouble(vol));
1699 of_rename(vol, sdir, spath, curdir, path);
1702 /* rename temp back to source */
1703 renamefile(temp, p, spath, vol_noadouble(vol));
1704 of_rename(vol, curdir, temp, sdir, spath);