2 * $Id: file.c,v 1.56 2002-09-06 02:57:49 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* check for mtab DID code */
64 #include "parse_mtab.h"
67 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
68 * field bytes subfield bytes
71 * ioFlFndrInfo 16 -> type 4 type field
72 * creator 4 creator field
73 * flags 2 finder flags:
75 * location 4 location in window
76 * folder 2 window that contains file
78 * ioFlXFndrInfo 16 -> iconID 2 icon id
80 * script 1 script system
82 * commentID 2 comment id
83 * putawayID 4 home directory id
86 const u_char ufinderi[] = {
87 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
88 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0
93 int getmetadata(struct vol *vol,
95 char *path, struct dir *dir, struct stat *st,
96 char *buf, int *buflen, struct adouble *adp, int attrbits )
99 struct stat lst, *lstp;
100 #endif /* USE_LASTDID */
103 char *data, *nameoff = NULL, *upath;
107 u_char achar, fdType[4];
111 LOG(log_info, logtype_afpd, "begin getmetadata:");
114 upath = mtoupath(vol, path);
117 while ( bitmap != 0 ) {
118 while (( bitmap & 1 ) == 0 ) {
126 ad_getattr(adp, &ashort);
127 } else if (*upath == '.') {
128 ashort = htons(ATTRBIT_INVISIBLE);
132 /* FIXME do we want a visual clue if the file is read only
134 accessmode( ".", &ma, dir , NULL);
135 if ((ma.ma_user & AR_UWRITE)) {
136 accessmode( upath, &ma, dir , st);
137 if (!(ma.ma_user & AR_UWRITE)) {
138 attrbits |= ATTRBIT_NOWRITE;
143 ashort = htons(ntohs(ashort) | attrbits);
144 memcpy(data, &ashort, sizeof( ashort ));
145 data += sizeof( ashort );
149 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
150 data += sizeof( u_int32_t );
154 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
155 aint = AD_DATE_FROM_UNIX(st->st_mtime);
156 memcpy(data, &aint, sizeof( aint ));
157 data += sizeof( aint );
161 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
162 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
163 aint = AD_DATE_FROM_UNIX(st->st_mtime);
166 aint = AD_DATE_FROM_UNIX(st->st_mtime);
168 memcpy(data, &aint, sizeof( int ));
169 data += sizeof( int );
173 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
174 aint = AD_DATE_START;
175 memcpy(data, &aint, sizeof( int ));
176 data += sizeof( int );
181 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
183 memcpy(data, ufinderi, 32);
184 if (*upath == '.') { /* make it invisible */
185 ashort = htons(FINDERINFO_INVISIBLE);
186 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
190 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
191 && (em = getextmap( path ))
193 memcpy(data, em->em_type, sizeof( em->em_type ));
194 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
201 data += sizeof( u_int16_t );
205 memset(data, 0, sizeof(u_int16_t));
206 data += sizeof( u_int16_t );
211 #if AD_VERSION > AD_VERSION1
212 /* look in AD v2 header */
214 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
215 #endif /* AD_VERSION > AD_VERSION1 */
218 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
219 strlen(upath), aint);
220 /* Throw errors if cnid_add fails. */
221 if (aint == CNID_INVALID) {
224 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
225 return(AFPERR_PARAM);
227 return(AFPERR_PARAM);
237 * What a fucking mess. First thing: DID and FNUMs are
238 * in the same space for purposes of enumerate (and several
239 * other wierd places). While we consider this Apple's bug,
240 * this is the work-around: In order to maintain constant and
241 * unique DIDs and FNUMs, we monotonically generate the DIDs
242 * during the session, and derive the FNUMs from the filesystem.
243 * Since the DIDs are small, we insure that the FNUMs are fairly
244 * large by setting thier high bits to the device number.
246 * AFS already does something very similar to this for the
247 * inode number, so we don't repeat the procedure.
250 * due to complaints over did's being non-persistent,
251 * here's the current hack to provide semi-persistent
253 * 1) we reserve the first bit for file ids.
254 * 2) the next 7 bits are for the device.
255 * 3) the remaining 24 bits are for the inode.
257 * both the inode and device information are actually hashes
258 * that are then truncated to the requisite bit length.
260 * it should be okay to use lstat to deal with symlinks.
263 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
264 #else /* USE_LASTDID */
265 lstp = lstat(upath, &lst) < 0 ? st : &lst;
267 aint = htonl( afpd_st_cnid ( lstp ) );
269 aint = htonl(CNID(lstp, 1));
270 #endif /* DID_MTAB */
271 #endif /* USE_LASTDID */
274 memcpy(data, &aint, sizeof( aint ));
275 data += sizeof( aint );
279 aint = htonl( st->st_size );
280 memcpy(data, &aint, sizeof( aint ));
281 data += sizeof( aint );
286 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
290 memcpy(data, &aint, sizeof( aint ));
291 data += sizeof( aint );
294 /* Current client needs ProDOS info block for this file.
295 Use simple heuristic and let the Mac "type" string tell
296 us what the PD file code should be. Everything gets a
297 subtype of 0x0000 unless the original value was hashed
298 to "pXYZ" when we created it. See IA, Ver 2.
300 case FILPBIT_PDINFO :
302 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
304 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
308 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
312 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
316 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
320 else if ( fdType[0] == 'p' ) {
322 ashort = (fdType[2] * 256) + fdType[3];
336 memcpy(data, &ashort, sizeof( ashort ));
337 data += sizeof( ashort );
338 memset(data, 0, sizeof( ashort ));
339 data += sizeof( ashort );
343 return( AFPERR_BITMAP );
349 ashort = htons( data - buf );
350 memcpy(nameoff, &ashort, sizeof( ashort ));
351 if ((aint = strlen( path )) > MACFILELEN)
354 memcpy(data, path, aint );
357 *buflen = data - buf;
361 /* ----------------------- */
362 int getfilparams(struct vol *vol,
364 char *path, struct dir *dir, struct stat *st,
365 char *buf, int *buflen )
367 struct adouble ad, *adp;
370 u_int16_t attrbits = 0;
373 LOG(log_info, logtype_default, "begin getfilparams:");
376 upath = mtoupath(vol, path);
377 if ((of = of_findname(upath, st))) {
379 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
380 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
383 memset(&ad, 0, sizeof(ad));
387 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
393 we need to check if the file is open by another process.
394 it's slow so we only do it if we have to:
395 - bitmap is requested.
396 - we don't already have the answer!
398 if ((bitmap & (1 << FILPBIT_ATTR))) {
399 if (!(attrbits & ATTRBIT_ROPEN)) {
401 if (!(attrbits & ATTRBIT_DOPEN)) {
406 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
408 ad_close( adp, ADFLAGS_HF );
411 LOG(log_info, logtype_afpd, "end getfilparams:");
417 /* ----------------------------- */
418 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
421 int ibuflen, *rbuflen;
424 struct adouble ad, *adp;
429 int creatf, did, openf, retvalue = AFP_OK;
433 LOG(log_info, logtype_afpd, "begin afp_createfile:");
438 creatf = (unsigned char) *ibuf++;
440 memcpy(&vid, ibuf, sizeof( vid ));
441 ibuf += sizeof( vid );
443 if (( vol = getvolbyvid( vid )) == NULL ) {
444 return( AFPERR_PARAM );
447 if (vol->v_flags & AFPVOL_RO)
450 memcpy(&did, ibuf, sizeof( did));
451 ibuf += sizeof( did );
453 if (( dir = dirsearch( vol, did )) == NULL ) {
454 return( AFPERR_NOOBJ );
457 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
458 return( AFPERR_NOOBJ );
461 upath = mtoupath(vol, path);
462 if (0 != (ret = check_name(vol, upath)))
465 ret = stat(upath, &st);
466 /* if upath is deleted we already in trouble anyway */
467 if (!ret && (of = of_findname(upath, &st))) {
470 memset(&ad, 0, sizeof(ad));
474 /* on a hard create, fail if file exists and is open */
477 openf = O_RDWR|O_CREAT|O_TRUNC;
479 /* on a soft create, if the file is open then ad_open won't fail
480 because open syscall is not called
485 openf = O_RDWR|O_CREAT|O_EXCL;
488 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
489 openf, 0666, adp) < 0 ) {
492 return( AFPERR_EXIST );
494 return( AFPERR_ACCESS );
496 /* on noadouble volumes, just creating the data fork is ok */
497 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
498 goto createfile_done;
501 return( AFPERR_PARAM );
505 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
506 memcpy(ad_entry( adp, ADEID_NAME ), path,
507 ad_getentrylen( adp, ADEID_NAME ));
508 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
509 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
514 if (vol->v_flags & AFPVOL_DROPBOX) {
515 retvalue = matchfile2dirperms(upath, vol, did);
517 #endif /* DROPKLUDGE */
519 setvoltime(obj, vol );
522 LOG(log_info, logtype_afpd, "end afp_createfile");
528 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
531 int ibuflen, *rbuflen;
537 u_int16_t vid, bitmap;
540 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
546 memcpy(&vid, ibuf, sizeof( vid ));
547 ibuf += sizeof( vid );
548 if (( vol = getvolbyvid( vid )) == NULL ) {
549 return( AFPERR_PARAM );
552 if (vol->v_flags & AFPVOL_RO)
555 memcpy(&did, ibuf, sizeof( did ));
556 ibuf += sizeof( did );
557 if (( dir = dirsearch( vol, did )) == NULL ) {
558 return( AFPERR_NOOBJ );
561 memcpy(&bitmap, ibuf, sizeof( bitmap ));
562 bitmap = ntohs( bitmap );
563 ibuf += sizeof( bitmap );
565 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
566 return( AFPERR_NOOBJ );
569 if ( *path == '\0' ) {
570 return( AFPERR_BADTYPE ); /* it's a directory */
573 if ((u_long)ibuf & 1 ) {
577 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
578 setvoltime(obj, vol );
582 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
589 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
593 int setfilparams(struct vol *vol,
594 char *path, u_int16_t bitmap, char *buf )
596 struct adouble ad, *adp;
599 int bit = 0, isad = 1, err = AFP_OK;
601 u_char achar, *fdType, xyy[4];
602 u_int16_t ashort, bshort;
606 int change_mdate = 0;
607 int change_parent_mdate = 0;
613 LOG(log_info, logtype_afpd, "begin setfilparams:");
616 upath = mtoupath(vol, path);
617 if ((of = of_findname(upath, NULL))) {
620 memset(&ad, 0, sizeof(ad));
624 if (check_access(upath, OPENACC_WR ) < 0) {
625 return AFPERR_ACCESS;
628 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
629 O_RDWR|O_CREAT, 0666, adp) < 0) {
630 /* for some things, we don't need an adouble header */
631 if (bitmap & ~(1<<FILPBIT_MDATE)) {
632 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
635 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
636 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
637 memcpy(ad_entry( adp, ADEID_NAME ), path,
638 ad_getentrylen( adp, ADEID_NAME ));
641 while ( bitmap != 0 ) {
642 while (( bitmap & 1 ) == 0 ) {
650 memcpy(&ashort, buf, sizeof( ashort ));
651 ad_getattr(adp, &bshort);
652 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
653 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
657 if ((ashort & htons(ATTRBIT_INVISIBLE)))
658 change_parent_mdate = 1;
659 ad_setattr(adp, bshort);
660 buf += sizeof( ashort );
665 memcpy(&aint, buf, sizeof(aint));
666 ad_setdate(adp, AD_DATE_CREATE, aint);
667 buf += sizeof( aint );
671 memcpy(&newdate, buf, sizeof( newdate ));
672 buf += sizeof( newdate );
677 memcpy(&aint, buf, sizeof(aint));
678 ad_setdate(adp, AD_DATE_BACKUP, aint);
679 buf += sizeof( aint );
685 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
687 ((em = getextmap( path )) &&
688 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
689 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
690 || ((em = getdefextmap()) &&
691 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
692 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
694 memcpy(buf, ufinderi, 8 );
697 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
701 /* Client needs to set the ProDOS file info for this file.
702 Use defined strings for the simple cases, and convert
703 all else into pXYY per Inside Appletalk. Always set
704 the creator as "pdos". <shirsch@ibm.net> */
705 case FILPBIT_PDINFO :
708 memcpy(&ashort, buf, sizeof( ashort ));
709 ashort = ntohs( ashort );
712 switch ( (unsigned int) achar )
715 fdType = ( u_char *) "TEXT";
719 fdType = ( u_char *) "PSYS";
723 fdType = ( u_char *) "PS16";
727 fdType = ( u_char *) "BINA";
731 xyy[0] = ( u_char ) 'p';
733 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
734 xyy[3] = ( u_char ) ashort & 0xff;
739 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
740 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
746 goto setfilparam_done;
754 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
755 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
759 ad_setdate(adp, AD_DATE_MODIFY, newdate);
760 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
765 ad_flush( adp, ADFLAGS_HF );
766 ad_close( adp, ADFLAGS_HF );
770 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
771 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
772 bitmap = 1<<FILPBIT_MDATE;
773 setdirparams(vol, "", bitmap, (char *)&newdate);
777 LOG(log_info, logtype_afpd, "end setfilparams:");
783 * renamefile and copyfile take the old and new unix pathnames
784 * and the new mac name.
785 * NOTE: if we have to copy a file instead of renaming it, locks
786 * will break. Anyway it's an error because then we have 2 files.
788 * src the source path
789 * dst the dest filename in current dir
790 * newname the dest mac name
791 * adp adouble struct of src file, if open, or & zeroed one
794 int renamefile(src, dst, newname, noadouble, adp )
795 char *src, *dst, *newname;
799 char adsrc[ MAXPATHLEN + 1];
803 * Note that this is only checking the existance of the data file,
804 * not the header file. The thinking is that if the data file doesn't
805 * exist, but the header file does, the right thing to do is remove
806 * the data file silently.
809 /* existence check moved to afp_moveandrename */
812 LOG(log_info, logtype_afpd, "begin renamefile:");
815 if ( rename( src, dst ) < 0 ) {
818 return( AFPERR_NOOBJ );
821 return( AFPERR_ACCESS );
824 case EXDEV : /* Cross device move -- try copy */
825 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
826 deletefile( dst, 0 );
829 return deletefile( src, 0);
831 return( AFPERR_PARAM );
835 strcpy( adsrc, ad_path( src, 0 ));
838 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
843 /* check for a source appledouble header. if it exists, make
844 * a dest appledouble directory and do the rename again. */
845 if (rc || stat(adsrc, &st) ||
846 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
849 ad_close(adp, ADFLAGS_HF);
853 return( AFPERR_ACCESS );
857 return( AFPERR_PARAM );
861 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
864 return( AFPERR_NOOBJ );
866 return( AFPERR_ACCESS );
870 return( AFPERR_PARAM );
874 len = strlen( newname );
875 ad_setentrylen( adp, ADEID_NAME, len );
876 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
877 ad_flush( adp, ADFLAGS_HF );
878 ad_close( adp, ADFLAGS_HF );
881 LOG(log_info, logtype_afpd, "end renamefile:");
887 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
890 int ibuflen, *rbuflen;
894 char *newname, *path, *p, *upath;
895 u_int32_t sdid, ddid;
896 int plen, err, retvalue = AFP_OK;
897 u_int16_t svid, dvid;
900 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
906 memcpy(&svid, ibuf, sizeof( svid ));
907 ibuf += sizeof( svid );
908 if (( vol = getvolbyvid( svid )) == NULL ) {
909 return( AFPERR_PARAM );
912 memcpy(&sdid, ibuf, sizeof( sdid ));
913 ibuf += sizeof( sdid );
914 if (( dir = dirsearch( vol, sdid )) == NULL ) {
915 return( AFPERR_PARAM );
918 memcpy(&dvid, ibuf, sizeof( dvid ));
919 ibuf += sizeof( dvid );
920 memcpy(&ddid, ibuf, sizeof( ddid ));
921 ibuf += sizeof( ddid );
923 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
924 return( AFPERR_NOOBJ );
926 if ( *path == '\0' ) {
927 return( AFPERR_BADTYPE );
930 /* don't allow copies when the file is open.
931 * XXX: the spec only calls for read/deny write access.
932 * however, copyfile doesn't have any of that info,
933 * and locks need to stay coherent. as a result,
934 * we just balk if the file is opened already. */
936 upath = mtoupath(vol, newname );
937 if (of_findname(upath, NULL))
938 return AFPERR_DENYCONF;
940 newname = obj->newtmp;
941 strcpy( newname, path );
943 p = ctoupath( vol, curdir, newname );
945 /* FIXME svid != dvid && dvid's user can't read svid */
947 if (( vol = getvolbyvid( dvid )) == NULL ) {
948 return( AFPERR_PARAM );
951 if (vol->v_flags & AFPVOL_RO)
954 if (( dir = dirsearch( vol, ddid )) == NULL ) {
955 return( AFPERR_PARAM );
958 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
959 return( AFPERR_NOOBJ );
961 if ( *path != '\0' ) {
962 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
965 /* one of the handful of places that knows about the path type */
966 if ( *ibuf++ != 2 ) {
967 return( AFPERR_PARAM );
969 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
970 strncpy( newname, ibuf, plen );
971 newname[ plen ] = '\0';
972 if (strlen(newname) != plen) {
973 /* there's \0 in newname, e.g. it's a pathname not
976 return( AFPERR_PARAM );
980 if ( (err = copyfile(p, mtoupath(vol, newname),
981 newname, vol_noadouble(vol))) < 0 ) {
986 if (vol->v_flags & AFPVOL_DROPBOX) {
987 retvalue=matchfile2dirperms(newname, vol, sdid);
989 #endif /* DROPKLUDGE */
991 setvoltime(obj, vol );
994 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1001 static __inline__ int copy_all(const int dfd, const void *buf,
1007 LOG(log_info, logtype_afpd, "begin copy_all:");
1010 while (buflen > 0) {
1011 if ((cc = write(dfd, buf, buflen)) < 0) {
1018 return AFPERR_DFULL;
1020 return AFPERR_VLOCK;
1022 return AFPERR_PARAM;
1029 LOG(log_info, logtype_afpd, "end copy_all:");
1035 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1036 * pass in vol and path */
1037 int copyfile(src, dst, newname, noadouble )
1038 char *src, *dst, *newname;
1039 const int noadouble;
1044 int sfd, dfd, len, err = AFP_OK;
1049 LOG(log_info, logtype_afpd, "begin copyfile:");
1052 dpath = ad_path( dst, ADFLAGS_HF );
1053 admode = ad_mode( dst, 0666 );
1055 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1058 break; /* just copy the data fork */
1060 return( AFPERR_ACCESS );
1062 return( AFPERR_PARAM );
1065 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1069 return( AFPERR_NOOBJ );
1071 return( AFPERR_ACCESS );
1073 return AFPERR_VLOCK;
1075 return( AFPERR_PARAM );
1080 #ifdef SENDFILE_FLAVOR_LINUX
1081 if (fstat(sfd, &st) == 0) {
1082 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1096 goto copyheader_done;
1098 #endif /* SENDFILE_FLAVOR_LINUX */
1100 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1107 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1121 /* data fork copying */
1122 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1125 return( AFPERR_NOOBJ );
1127 return( AFPERR_ACCESS );
1129 return( AFPERR_PARAM );
1133 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1137 return( AFPERR_NOOBJ );
1139 return( AFPERR_ACCESS );
1141 return AFPERR_VLOCK;
1143 return( AFPERR_PARAM );
1147 #ifdef SENDFILE_FLAVOR_LINUX
1148 if (fstat(sfd, &st) == 0) {
1149 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1162 #endif /* SENDFILE_FLAVOR_LINUX */
1165 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1173 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1188 memset(&ad, 0, sizeof(ad));
1189 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1193 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1195 return( AFPERR_ACCESS );
1197 return AFPERR_VLOCK;
1199 return( AFPERR_PARAM );
1203 len = strlen( newname );
1204 ad_setentrylen( &ad, ADEID_NAME, len );
1205 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1206 ad_flush( &ad, ADFLAGS_HF );
1207 ad_close( &ad, ADFLAGS_HF );
1211 LOG(log_info, logtype_afpd, "end copyfile:");
1218 /* -----------------------------------
1219 checkAttrib: 1 check kFPDeleteInhibitBit
1220 ie deletfile called by afp_delete
1222 when deletefile is called we don't have lock on it, file is closed (for us)
1223 untrue if called by renamefile
1225 int deletefile( file, checkAttrib )
1230 int adflags, err = AFP_OK;
1231 int locktype = ADLOCK_WR;
1232 int openmode = O_RDWR;
1235 LOG(log_info, logtype_afpd, "begin deletefile:");
1240 * If can't open read/write then try again read-only. If it's open
1241 * read-only, we must do a read lock instead of a write lock.
1243 /* try to open both at once */
1244 adflags = ADFLAGS_DF|ADFLAGS_HF;
1245 memset(&ad, 0, sizeof(ad));
1246 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1249 adflags = ADFLAGS_DF;
1250 /* that failed. now try to open just the data fork */
1251 memset(&ad, 0, sizeof(ad));
1252 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1255 return AFPERR_NOOBJ;
1257 if(openmode == O_RDWR) {
1258 openmode = O_RDONLY;
1259 locktype = ADLOCK_RD;
1262 return AFPERR_ACCESS;
1265 return AFPERR_VLOCK;
1267 return AFPERR_PARAM;
1273 if(openmode == O_RDWR) {
1274 openmode = O_RDONLY;
1275 locktype = ADLOCK_RD;
1278 return AFPERR_ACCESS;
1281 return AFPERR_VLOCK;
1283 return( AFPERR_PARAM );
1286 break; /* from the while */
1289 * Does kFPDeleteInhibitBit (bit 8) set?
1291 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1294 ad_getattr(&ad, &bshort);
1295 if ((bshort & htons(ATTRBIT_NODELETE))) {
1296 ad_close( &ad, adflags );
1297 return(AFPERR_OLOCK);
1301 if ((adflags & ADFLAGS_HF) ) {
1302 /* FIXME we have a pb here because we want to know if a file is open
1303 * there's a 'priority inversion' if you can't open the ressource fork RW
1304 * you can delete it if it's open because you can't get a write lock.
1306 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1309 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1311 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1312 ad_close( &ad, adflags );
1313 return( AFPERR_BUSY );
1317 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1322 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1326 err = AFPERR_ACCESS;
1339 if ( unlink( file ) < 0 ) {
1343 err = AFPERR_ACCESS;
1357 if (adflags & ADFLAGS_HF)
1358 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1359 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1360 ad_close( &ad, adflags );
1363 LOG(log_info, logtype_afpd, "end deletefile:");
1371 /* return a file id */
1372 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1375 int ibuflen, *rbuflen;
1387 LOG(log_info, logtype_afpd, "begin afp_createid:");
1393 memcpy(&vid, ibuf, sizeof(vid));
1394 ibuf += sizeof(vid);
1396 if (( vol = getvolbyvid( vid )) == NULL ) {
1397 return( AFPERR_PARAM);
1400 if (vol->v_flags & AFPVOL_RO)
1401 return AFPERR_VLOCK;
1403 memcpy(&did, ibuf, sizeof( did ));
1404 ibuf += sizeof(did);
1406 if (( dir = dirsearch( vol, did )) == NULL ) {
1407 return( AFPERR_PARAM );
1410 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1411 return( AFPERR_PARAM );
1414 if ( *path == '\0' ) {
1415 return( AFPERR_BADTYPE );
1418 upath = mtoupath(vol, path);
1419 if (stat(upath, &st) < 0) {
1423 return AFPERR_ACCESS;
1425 return AFPERR_NOOBJ;
1427 return AFPERR_PARAM;
1431 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1432 memcpy(rbuf, &id, sizeof(id));
1433 *rbuflen = sizeof(id);
1434 return AFPERR_EXISTID;
1437 #if AD_VERSION > AD_VERSION1
1438 memset(&ad, 0, sizeof(ad));
1439 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1440 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1441 ad_close(&ad, ADFLAGS_HF);
1443 #endif /* AD_VERSION > AD_VERSION1 */
1445 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1446 memcpy(rbuf, &id, sizeof(id));
1447 *rbuflen = sizeof(id);
1452 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1457 return AFPERR_VLOCK;
1461 return AFPERR_ACCESS;
1464 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1465 return AFPERR_PARAM;
1469 /* resolve a file id */
1470 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1473 int ibuflen, *rbuflen;
1481 u_int16_t vid, bitmap;
1483 static char buffer[12 + MAXPATHLEN + 1];
1484 int len = 12 + MAXPATHLEN + 1;
1487 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1493 memcpy(&vid, ibuf, sizeof(vid));
1494 ibuf += sizeof(vid);
1496 if (( vol = getvolbyvid( vid )) == NULL ) {
1497 return( AFPERR_PARAM);
1500 memcpy(&id, ibuf, sizeof( id ));
1503 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1504 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1507 if (( dir = dirlookup( vol, id )) == NULL ) {
1508 return AFPERR_NOID; /* idem AFPERR_PARAM */
1511 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1515 return AFPERR_ACCESS;
1519 return AFPERR_PARAM;
1523 /* directories are bad */
1524 if (S_ISDIR(st.st_mode))
1525 return AFPERR_BADTYPE;
1527 memcpy(&bitmap, ibuf, sizeof(bitmap));
1528 bitmap = ntohs( bitmap );
1530 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1531 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1534 *rbuflen = buflen + sizeof(bitmap);
1535 memcpy(rbuf, ibuf, sizeof(bitmap));
1538 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1544 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1547 int ibuflen, *rbuflen;
1557 static char buffer[12 + MAXPATHLEN + 1];
1558 int len = 12 + MAXPATHLEN + 1;
1561 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1567 memcpy(&vid, ibuf, sizeof(vid));
1568 ibuf += sizeof(vid);
1570 if (( vol = getvolbyvid( vid )) == NULL ) {
1571 return( AFPERR_PARAM);
1574 if (vol->v_flags & AFPVOL_RO)
1575 return AFPERR_VLOCK;
1577 memcpy(&id, ibuf, sizeof( id ));
1581 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1585 if (( dir = dirlookup( vol, id )) == NULL ) {
1586 return( AFPERR_PARAM );
1590 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1594 return AFPERR_ACCESS;
1596 /* still try to delete the id */
1600 return AFPERR_PARAM;
1604 /* directories are bad */
1605 if (S_ISDIR(st.st_mode))
1606 return AFPERR_BADTYPE;
1608 if (cnid_delete(vol->v_db, fileid)) {
1611 return AFPERR_VLOCK;
1614 return AFPERR_ACCESS;
1616 return AFPERR_PARAM;
1621 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1626 #endif /* CNID_DB */
1628 #define APPLETEMP ".AppleTempXXXXXX"
1630 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1633 int ibuflen, *rbuflen;
1635 struct stat srcst, destst;
1637 struct dir *dir, *sdir;
1638 char *spath, temp[17], *path, *p;
1639 char *supath, *upath;
1643 struct adouble *adsp;
1644 struct adouble *addp;
1650 #endif /* CNID_DB */
1655 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1661 memcpy(&vid, ibuf, sizeof(vid));
1662 ibuf += sizeof(vid);
1664 if (( vol = getvolbyvid( vid )) == NULL ) {
1665 return( AFPERR_PARAM);
1668 if (vol->v_flags & AFPVOL_RO)
1669 return AFPERR_VLOCK;
1671 /* source and destination dids */
1672 memcpy(&sid, ibuf, sizeof(sid));
1673 ibuf += sizeof(sid);
1674 memcpy(&did, ibuf, sizeof(did));
1675 ibuf += sizeof(did);
1678 if ((dir = dirsearch( vol, sid )) == NULL ) {
1679 return( AFPERR_PARAM );
1682 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1683 return( AFPERR_PARAM );
1686 if ( *path == '\0' ) {
1687 return( AFPERR_BADTYPE ); /* it's a dir */
1690 upath = mtoupath(vol, path);
1691 if (stat(upath, &srcst) < 0) {
1697 return AFPERR_ACCESS;
1699 return AFPERR_PARAM;
1702 memset(&ads, 0, sizeof(ads));
1704 if ((s_of = of_findname(upath, &srcst))) {
1705 /* reuse struct adouble so it won't break locks */
1708 /* save some stuff */
1710 spath = obj->oldtmp;
1711 supath = obj->newtmp;
1712 strcpy(spath, path);
1713 strcpy(supath, upath); /* this is for the cnid changing */
1714 p = ctoupath( vol, sdir, spath);
1716 /* look for the source cnid. if it doesn't exist, don't worry about
1719 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1720 slen = strlen(supath));
1721 #endif /* CNID_DB */
1723 if (( dir = dirsearch( vol, did )) == NULL ) {
1724 return( AFPERR_PARAM );
1727 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1728 return( AFPERR_PARAM );
1731 if ( *path == '\0' ) {
1732 return( AFPERR_BADTYPE );
1735 /* FPExchangeFiles is the only call that can return the SameObj
1737 if ((curdir == sdir) && strcmp(spath, path) == 0)
1738 return AFPERR_SAMEOBJ;
1740 upath = mtoupath(vol, path);
1741 if (stat(upath, &destst) < 0) {
1747 return AFPERR_ACCESS;
1749 return AFPERR_PARAM;
1752 memset(&add, 0, sizeof(add));
1754 if ((d_of = of_findname( upath, &destst))) {
1755 /* reuse struct adouble so it won't break locks */
1759 /* they are not on the same device and at least one is open
1761 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1765 /* look for destination id. */
1766 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1767 dlen = strlen(upath));
1768 #endif /* CNID_DB */
1770 /* construct a temp name.
1771 * NOTE: the temp file will be in the dest file's directory. it
1772 * will also be inaccessible from AFP. */
1773 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1777 /* now, quickly rename the file. we error if we can't. */
1778 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1779 goto err_exchangefile;
1780 of_rename(vol, s_of, sdir, spath, curdir, temp);
1782 /* rename destination to source */
1783 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1784 goto err_src_to_tmp;
1785 of_rename(vol, d_of, curdir, path, sdir, spath);
1787 /* rename temp to destination */
1788 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1789 goto err_dest_to_src;
1790 of_rename(vol, s_of, curdir, temp, curdir, path);
1793 /* id's need switching. src -> dest and dest -> src. */
1794 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1795 upath, dlen) < 0)) {
1799 err = AFPERR_ACCESS;
1804 goto err_temp_to_dest;
1807 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1808 supath, slen) < 0)) {
1812 err = AFPERR_ACCESS;
1819 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1820 goto err_temp_to_dest;
1822 #endif /* CNID_DB */
1825 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1831 /* all this stuff is so that we can unwind a failed operation
1836 /* rename dest to temp */
1837 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1838 of_rename(vol, s_of, curdir, upath, curdir, temp);
1841 /* rename source back to dest */
1842 renamefile(p, upath, path, vol_noadouble(vol), addp);
1843 of_rename(vol, d_of, sdir, spath, curdir, path);
1846 /* rename temp back to source */
1847 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1848 of_rename(vol, s_of, curdir, temp, sdir, spath);