2 * $Id: file.c,v 1.60 2002-09-29 23:31:24 sibaz 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_afpd, "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;
427 struct ofork *of = NULL;
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 newname = obj->newtmp;
937 strcpy( newname, path );
939 upath = mtoupath(vol, newname );
940 if (of_findname(upath, NULL))
941 return AFPERR_DENYCONF;
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 );
979 upath = mtoupath(vol, newname);
980 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
985 if (vol->v_flags & AFPVOL_DROPBOX) {
986 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
988 #endif /* DROPKLUDGE */
990 setvoltime(obj, vol );
993 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1000 static __inline__ int copy_all(const int dfd, const void *buf,
1006 LOG(log_info, logtype_afpd, "begin copy_all:");
1009 while (buflen > 0) {
1010 if ((cc = write(dfd, buf, buflen)) < 0) {
1017 return AFPERR_DFULL;
1019 return AFPERR_VLOCK;
1021 return AFPERR_PARAM;
1028 LOG(log_info, logtype_afpd, "end copy_all:");
1034 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1035 * pass in vol and path */
1036 int copyfile(src, dst, newname, noadouble )
1037 char *src, *dst, *newname;
1038 const int noadouble;
1043 int sfd, dfd, len, err = AFP_OK;
1045 char dpath[ MAXPATHLEN + 1];
1048 LOG(log_info, logtype_afpd, "begin copyfile:");
1051 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1052 admode = ad_mode( dst, 0666 );
1054 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1057 break; /* just copy the data fork */
1059 return( AFPERR_ACCESS );
1061 return( AFPERR_PARAM );
1064 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1068 return( AFPERR_NOOBJ );
1070 return( AFPERR_ACCESS );
1072 return AFPERR_VLOCK;
1074 return( AFPERR_PARAM );
1079 #ifdef SENDFILE_FLAVOR_LINUX
1080 if (fstat(sfd, &st) == 0) {
1081 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1095 goto copyheader_done;
1097 #endif /* SENDFILE_FLAVOR_LINUX */
1099 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1106 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1120 /* data fork copying */
1121 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1124 return( AFPERR_NOOBJ );
1126 return( AFPERR_ACCESS );
1128 return( AFPERR_PARAM );
1132 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1136 return( AFPERR_NOOBJ );
1138 return( AFPERR_ACCESS );
1140 return AFPERR_VLOCK;
1142 return( AFPERR_PARAM );
1146 #ifdef SENDFILE_FLAVOR_LINUX
1147 if (fstat(sfd, &st) == 0) {
1148 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1161 #endif /* SENDFILE_FLAVOR_LINUX */
1164 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1172 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1187 memset(&ad, 0, sizeof(ad));
1188 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1192 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1194 return( AFPERR_ACCESS );
1196 return AFPERR_VLOCK;
1198 return( AFPERR_PARAM );
1202 len = strlen( newname );
1203 ad_setentrylen( &ad, ADEID_NAME, len );
1204 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1205 ad_flush( &ad, ADFLAGS_HF );
1206 ad_close( &ad, ADFLAGS_HF );
1210 LOG(log_info, logtype_afpd, "end copyfile:");
1217 /* -----------------------------------
1218 checkAttrib: 1 check kFPDeleteInhibitBit
1219 ie deletfile called by afp_delete
1221 when deletefile is called we don't have lock on it, file is closed (for us)
1222 untrue if called by renamefile
1224 int deletefile( file, checkAttrib )
1229 int adflags, err = AFP_OK;
1230 int locktype = ADLOCK_WR;
1231 int openmode = O_RDWR;
1234 LOG(log_info, logtype_afpd, "begin deletefile:");
1239 * If can't open read/write then try again read-only. If it's open
1240 * read-only, we must do a read lock instead of a write lock.
1242 /* try to open both at once */
1243 adflags = ADFLAGS_DF|ADFLAGS_HF;
1244 memset(&ad, 0, sizeof(ad));
1245 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1248 adflags = ADFLAGS_DF;
1249 /* that failed. now try to open just the data fork */
1250 memset(&ad, 0, sizeof(ad));
1251 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1254 return AFPERR_NOOBJ;
1256 if(openmode == O_RDWR) {
1257 openmode = O_RDONLY;
1258 locktype = ADLOCK_RD;
1261 return AFPERR_ACCESS;
1264 return AFPERR_VLOCK;
1266 return AFPERR_PARAM;
1272 if(openmode == O_RDWR) {
1273 openmode = O_RDONLY;
1274 locktype = ADLOCK_RD;
1277 return AFPERR_ACCESS;
1280 return AFPERR_VLOCK;
1282 return( AFPERR_PARAM );
1285 break; /* from the while */
1288 * Does kFPDeleteInhibitBit (bit 8) set?
1290 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1293 ad_getattr(&ad, &bshort);
1294 if ((bshort & htons(ATTRBIT_NODELETE))) {
1295 ad_close( &ad, adflags );
1296 return(AFPERR_OLOCK);
1300 if ((adflags & ADFLAGS_HF) ) {
1301 /* FIXME we have a pb here because we want to know if a file is open
1302 * there's a 'priority inversion' if you can't open the ressource fork RW
1303 * you can delete it if it's open because you can't get a write lock.
1305 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1308 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1310 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1311 ad_close( &ad, adflags );
1312 return( AFPERR_BUSY );
1316 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1321 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1325 err = AFPERR_ACCESS;
1338 if ( unlink( file ) < 0 ) {
1342 err = AFPERR_ACCESS;
1356 if (adflags & ADFLAGS_HF)
1357 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1358 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1359 ad_close( &ad, adflags );
1362 LOG(log_info, logtype_afpd, "end deletefile:");
1370 /* return a file id */
1371 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1374 int ibuflen, *rbuflen;
1386 LOG(log_info, logtype_afpd, "begin afp_createid:");
1392 memcpy(&vid, ibuf, sizeof(vid));
1393 ibuf += sizeof(vid);
1395 if (( vol = getvolbyvid( vid )) == NULL ) {
1396 return( AFPERR_PARAM);
1399 if (vol->v_flags & AFPVOL_RO)
1400 return AFPERR_VLOCK;
1402 memcpy(&did, ibuf, sizeof( did ));
1403 ibuf += sizeof(did);
1405 if (( dir = dirsearch( vol, did )) == NULL ) {
1406 return( AFPERR_PARAM );
1409 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1410 return( AFPERR_PARAM );
1413 if ( *path == '\0' ) {
1414 return( AFPERR_BADTYPE );
1417 upath = mtoupath(vol, path);
1418 if (stat(upath, &st) < 0) {
1422 return AFPERR_ACCESS;
1424 return AFPERR_NOOBJ;
1426 return AFPERR_PARAM;
1430 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1431 memcpy(rbuf, &id, sizeof(id));
1432 *rbuflen = sizeof(id);
1433 return AFPERR_EXISTID;
1436 #if AD_VERSION > AD_VERSION1
1437 memset(&ad, 0, sizeof(ad));
1438 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1439 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1440 ad_close(&ad, ADFLAGS_HF);
1442 #endif /* AD_VERSION > AD_VERSION1 */
1444 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1445 memcpy(rbuf, &id, sizeof(id));
1446 *rbuflen = sizeof(id);
1451 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1456 return AFPERR_VLOCK;
1460 return AFPERR_ACCESS;
1463 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1464 return AFPERR_PARAM;
1468 /* resolve a file id */
1469 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1472 int ibuflen, *rbuflen;
1480 u_int16_t vid, bitmap;
1482 static char buffer[12 + MAXPATHLEN + 1];
1483 int len = 12 + MAXPATHLEN + 1;
1486 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1492 memcpy(&vid, ibuf, sizeof(vid));
1493 ibuf += sizeof(vid);
1495 if (( vol = getvolbyvid( vid )) == NULL ) {
1496 return( AFPERR_PARAM);
1499 memcpy(&id, ibuf, sizeof( id ));
1502 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1503 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1506 if (( dir = dirlookup( vol, id )) == NULL ) {
1507 return AFPERR_NOID; /* idem AFPERR_PARAM */
1510 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1514 return AFPERR_ACCESS;
1518 return AFPERR_PARAM;
1522 /* directories are bad */
1523 if (S_ISDIR(st.st_mode))
1524 return AFPERR_BADTYPE;
1526 memcpy(&bitmap, ibuf, sizeof(bitmap));
1527 bitmap = ntohs( bitmap );
1529 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1530 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1533 *rbuflen = buflen + sizeof(bitmap);
1534 memcpy(rbuf, ibuf, sizeof(bitmap));
1537 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1543 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1546 int ibuflen, *rbuflen;
1556 static char buffer[12 + MAXPATHLEN + 1];
1557 int len = 12 + MAXPATHLEN + 1;
1560 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1566 memcpy(&vid, ibuf, sizeof(vid));
1567 ibuf += sizeof(vid);
1569 if (( vol = getvolbyvid( vid )) == NULL ) {
1570 return( AFPERR_PARAM);
1573 if (vol->v_flags & AFPVOL_RO)
1574 return AFPERR_VLOCK;
1576 memcpy(&id, ibuf, sizeof( id ));
1580 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1584 if (( dir = dirlookup( vol, id )) == NULL ) {
1585 return( AFPERR_PARAM );
1589 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1593 return AFPERR_ACCESS;
1595 /* still try to delete the id */
1599 return AFPERR_PARAM;
1603 /* directories are bad */
1604 if (S_ISDIR(st.st_mode))
1605 return AFPERR_BADTYPE;
1607 if (cnid_delete(vol->v_db, fileid)) {
1610 return AFPERR_VLOCK;
1613 return AFPERR_ACCESS;
1615 return AFPERR_PARAM;
1620 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1625 #endif /* CNID_DB */
1627 #define APPLETEMP ".AppleTempXXXXXX"
1629 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1632 int ibuflen, *rbuflen;
1634 struct stat srcst, destst;
1636 struct dir *dir, *sdir;
1637 char *spath, temp[17], *path, *p;
1638 char *supath, *upath;
1642 struct adouble *adsp;
1643 struct adouble *addp;
1649 #endif /* CNID_DB */
1654 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1660 memcpy(&vid, ibuf, sizeof(vid));
1661 ibuf += sizeof(vid);
1663 if (( vol = getvolbyvid( vid )) == NULL ) {
1664 return( AFPERR_PARAM);
1667 if (vol->v_flags & AFPVOL_RO)
1668 return AFPERR_VLOCK;
1670 /* source and destination dids */
1671 memcpy(&sid, ibuf, sizeof(sid));
1672 ibuf += sizeof(sid);
1673 memcpy(&did, ibuf, sizeof(did));
1674 ibuf += sizeof(did);
1677 if ((dir = dirsearch( vol, sid )) == NULL ) {
1678 return( AFPERR_PARAM );
1681 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1682 return( AFPERR_PARAM );
1685 if ( *path == '\0' ) {
1686 return( AFPERR_BADTYPE ); /* it's a dir */
1689 upath = mtoupath(vol, path);
1690 if (stat(upath, &srcst) < 0) {
1696 return AFPERR_ACCESS;
1698 return AFPERR_PARAM;
1701 memset(&ads, 0, sizeof(ads));
1703 if ((s_of = of_findname(upath, &srcst))) {
1704 /* reuse struct adouble so it won't break locks */
1707 /* save some stuff */
1709 spath = obj->oldtmp;
1710 supath = obj->newtmp;
1711 strcpy(spath, path);
1712 strcpy(supath, upath); /* this is for the cnid changing */
1713 p = ctoupath( vol, sdir, spath);
1715 /* look for the source cnid. if it doesn't exist, don't worry about
1718 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1719 slen = strlen(supath));
1720 #endif /* CNID_DB */
1722 if (( dir = dirsearch( vol, did )) == NULL ) {
1723 return( AFPERR_PARAM );
1726 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1727 return( AFPERR_PARAM );
1730 if ( *path == '\0' ) {
1731 return( AFPERR_BADTYPE );
1734 /* FPExchangeFiles is the only call that can return the SameObj
1736 if ((curdir == sdir) && strcmp(spath, path) == 0)
1737 return AFPERR_SAMEOBJ;
1739 upath = mtoupath(vol, path);
1740 if (stat(upath, &destst) < 0) {
1746 return AFPERR_ACCESS;
1748 return AFPERR_PARAM;
1751 memset(&add, 0, sizeof(add));
1753 if ((d_of = of_findname( upath, &destst))) {
1754 /* reuse struct adouble so it won't break locks */
1758 /* they are not on the same device and at least one is open
1760 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1764 /* look for destination id. */
1765 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1766 dlen = strlen(upath));
1767 #endif /* CNID_DB */
1769 /* construct a temp name.
1770 * NOTE: the temp file will be in the dest file's directory. it
1771 * will also be inaccessible from AFP. */
1772 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1776 /* now, quickly rename the file. we error if we can't. */
1777 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1778 goto err_exchangefile;
1779 of_rename(vol, s_of, sdir, spath, curdir, temp);
1781 /* rename destination to source */
1782 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1783 goto err_src_to_tmp;
1784 of_rename(vol, d_of, curdir, path, sdir, spath);
1786 /* rename temp to destination */
1787 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1788 goto err_dest_to_src;
1789 of_rename(vol, s_of, curdir, temp, curdir, path);
1792 /* id's need switching. src -> dest and dest -> src. */
1793 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1794 upath, dlen) < 0)) {
1798 err = AFPERR_ACCESS;
1803 goto err_temp_to_dest;
1806 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1807 supath, slen) < 0)) {
1811 err = AFPERR_ACCESS;
1818 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1819 goto err_temp_to_dest;
1821 #endif /* CNID_DB */
1824 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1830 /* all this stuff is so that we can unwind a failed operation
1835 /* rename dest to temp */
1836 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1837 of_rename(vol, s_of, curdir, upath, curdir, temp);
1840 /* rename source back to dest */
1841 renamefile(p, upath, path, vol_noadouble(vol), addp);
1842 of_rename(vol, d_of, sdir, spath, curdir, path);
1845 /* rename temp back to source */
1846 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1847 of_rename(vol, s_of, curdir, temp, sdir, spath);