2 * $Id: file.c,v 1.53 2002-08-30 19:32:41 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(vol, dir, path))) {
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);
464 if (0 != (ret = check_name(vol, upath)))
468 if ((of = of_findname(vol, curdir, path))) {
471 memset(&ad, 0, sizeof(ad));
475 /* on a hard create, fail if file exists and is open */
476 if ((stat(upath, &st) == 0) && of)
478 openf = O_RDWR|O_CREAT|O_TRUNC;
480 /* on a soft create, if the file is open then ad_open won't failed
481 because open syscall is not called
486 openf = O_RDWR|O_CREAT|O_EXCL;
489 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
490 openf, 0666, adp) < 0 ) {
493 return( AFPERR_EXIST );
495 return( AFPERR_ACCESS );
497 /* on noadouble volumes, just creating the data fork is ok */
498 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
499 goto createfile_done;
502 return( AFPERR_PARAM );
506 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
507 memcpy(ad_entry( adp, ADEID_NAME ), path,
508 ad_getentrylen( adp, ADEID_NAME ));
509 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
510 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
515 if (vol->v_flags & AFPVOL_DROPBOX) {
516 retvalue = matchfile2dirperms(upath, vol, did);
518 #endif /* DROPKLUDGE */
520 setvoltime(obj, vol );
523 LOG(log_info, logtype_afpd, "end afp_createfile");
529 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
532 int ibuflen, *rbuflen;
538 u_int16_t vid, bitmap;
541 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
547 memcpy(&vid, ibuf, sizeof( vid ));
548 ibuf += sizeof( vid );
549 if (( vol = getvolbyvid( vid )) == NULL ) {
550 return( AFPERR_PARAM );
553 if (vol->v_flags & AFPVOL_RO)
556 memcpy(&did, ibuf, sizeof( did ));
557 ibuf += sizeof( did );
558 if (( dir = dirsearch( vol, did )) == NULL ) {
559 return( AFPERR_NOOBJ );
562 memcpy(&bitmap, ibuf, sizeof( bitmap ));
563 bitmap = ntohs( bitmap );
564 ibuf += sizeof( bitmap );
566 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
567 return( AFPERR_NOOBJ );
570 if ( *path == '\0' ) {
571 return( AFPERR_BADTYPE ); /* it's a directory */
574 if ((u_long)ibuf & 1 ) {
578 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
579 setvoltime(obj, vol );
583 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
590 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
594 int setfilparams(struct vol *vol,
595 char *path, u_int16_t bitmap, char *buf )
597 struct adouble ad, *adp;
600 int bit = 0, isad = 1, err = AFP_OK;
602 u_char achar, *fdType, xyy[4];
603 u_int16_t ashort, bshort;
607 int change_mdate = 0;
608 int change_parent_mdate = 0;
614 LOG(log_info, logtype_afpd, "begin setfilparams:");
617 upath = mtoupath(vol, path);
618 if ((of = of_findname(vol, curdir, path))) {
621 memset(&ad, 0, sizeof(ad));
625 if (check_access(upath, OPENACC_WR ) < 0) {
626 return AFPERR_ACCESS;
629 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
630 O_RDWR|O_CREAT, 0666, adp) < 0) {
631 /* for some things, we don't need an adouble header */
632 if (bitmap & ~(1<<FILPBIT_MDATE)) {
633 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
636 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
637 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
638 memcpy(ad_entry( adp, ADEID_NAME ), path,
639 ad_getentrylen( adp, ADEID_NAME ));
642 while ( bitmap != 0 ) {
643 while (( bitmap & 1 ) == 0 ) {
651 memcpy(&ashort, buf, sizeof( ashort ));
652 ad_getattr(adp, &bshort);
653 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
654 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
658 if ((ashort & htons(ATTRBIT_INVISIBLE)))
659 change_parent_mdate = 1;
660 ad_setattr(adp, bshort);
661 buf += sizeof( ashort );
666 memcpy(&aint, buf, sizeof(aint));
667 ad_setdate(adp, AD_DATE_CREATE, aint);
668 buf += sizeof( aint );
672 memcpy(&newdate, buf, sizeof( newdate ));
673 buf += sizeof( newdate );
678 memcpy(&aint, buf, sizeof(aint));
679 ad_setdate(adp, AD_DATE_BACKUP, aint);
680 buf += sizeof( aint );
686 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
688 ((em = getextmap( path )) &&
689 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
690 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
691 || ((em = getdefextmap()) &&
692 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
693 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
695 memcpy(buf, ufinderi, 8 );
698 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
702 /* Client needs to set the ProDOS file info for this file.
703 Use defined strings for the simple cases, and convert
704 all else into pXYY per Inside Appletalk. Always set
705 the creator as "pdos". <shirsch@ibm.net> */
706 case FILPBIT_PDINFO :
709 memcpy(&ashort, buf, sizeof( ashort ));
710 ashort = ntohs( ashort );
713 switch ( (unsigned int) achar )
716 fdType = ( u_char *) "TEXT";
720 fdType = ( u_char *) "PSYS";
724 fdType = ( u_char *) "PS16";
728 fdType = ( u_char *) "BINA";
732 xyy[0] = ( u_char ) 'p';
734 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
735 xyy[3] = ( u_char ) ashort & 0xff;
740 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
741 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
747 goto setfilparam_done;
755 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
756 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
760 ad_setdate(adp, AD_DATE_MODIFY, newdate);
761 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
766 ad_flush( adp, ADFLAGS_HF );
767 ad_close( adp, ADFLAGS_HF );
771 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
772 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
773 bitmap = 1<<FILPBIT_MDATE;
774 setdirparams(vol, "", bitmap, (char *)&newdate);
778 LOG(log_info, logtype_afpd, "end setfilparams:");
784 * renamefile and copyfile take the old and new unix pathnames
785 * and the new mac name.
786 * NOTE: if we have to copy a file instead of renaming it, locks
787 * will break. Anyway it's an error because then we have 2 files.
789 * src the source path
790 * dst the dest filename in current dir
791 * newname the dest mac name
792 * adp adouble struct of src file, if open, or & zeroed one
795 int renamefile(src, dst, newname, noadouble, adp )
796 char *src, *dst, *newname;
800 char adsrc[ MAXPATHLEN + 1];
804 * Note that this is only checking the existance of the data file,
805 * not the header file. The thinking is that if the data file doesn't
806 * exist, but the header file does, the right thing to do is remove
807 * the data file silently.
810 /* existence check moved to afp_moveandrename */
813 LOG(log_info, logtype_afpd, "begin renamefile:");
816 if ( rename( src, dst ) < 0 ) {
819 return( AFPERR_NOOBJ );
822 return( AFPERR_ACCESS );
825 case EXDEV : /* Cross device move -- try copy */
826 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
827 deletefile( dst, 0 );
830 return deletefile( src, 0);
832 return( AFPERR_PARAM );
836 strcpy( adsrc, ad_path( src, 0 ));
839 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
844 /* check for a source appledouble header. if it exists, make
845 * a dest appledouble directory and do the rename again. */
846 if (rc || stat(adsrc, &st) ||
847 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
850 ad_close(adp, ADFLAGS_HF);
854 return( AFPERR_ACCESS );
858 return( AFPERR_PARAM );
862 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
865 return( AFPERR_NOOBJ );
867 return( AFPERR_ACCESS );
871 return( AFPERR_PARAM );
875 len = strlen( newname );
876 ad_setentrylen( adp, ADEID_NAME, len );
877 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
878 ad_flush( adp, ADFLAGS_HF );
879 ad_close( adp, ADFLAGS_HF );
882 LOG(log_info, logtype_afpd, "end renamefile:");
888 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
891 int ibuflen, *rbuflen;
895 char *newname, *path, *p;
896 u_int32_t sdid, ddid;
897 int plen, err, retvalue = AFP_OK;
898 u_int16_t svid, dvid;
901 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
907 memcpy(&svid, ibuf, sizeof( svid ));
908 ibuf += sizeof( svid );
909 if (( vol = getvolbyvid( svid )) == NULL ) {
910 return( AFPERR_PARAM );
913 memcpy(&sdid, ibuf, sizeof( sdid ));
914 ibuf += sizeof( sdid );
915 if (( dir = dirsearch( vol, sdid )) == NULL ) {
916 return( AFPERR_PARAM );
919 memcpy(&dvid, ibuf, sizeof( dvid ));
920 ibuf += sizeof( dvid );
921 memcpy(&ddid, ibuf, sizeof( ddid ));
922 ibuf += sizeof( ddid );
924 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
925 return( AFPERR_NOOBJ );
927 if ( *path == '\0' ) {
928 return( AFPERR_BADTYPE );
931 /* don't allow copies when the file is open.
932 * XXX: the spec only calls for read/deny write access.
933 * however, copyfile doesn't have any of that info,
934 * and locks need to stay coherent. as a result,
935 * we just balk if the file is opened already. */
936 if (of_findname(vol, curdir, path))
937 return AFPERR_DENYCONF;
939 newname = obj->newtmp;
940 strcpy( newname, path );
942 p = ctoupath( vol, curdir, newname );
944 /* FIXME svid != dvid && dvid's user can't read svid */
946 if (( vol = getvolbyvid( dvid )) == NULL ) {
947 return( AFPERR_PARAM );
950 if (vol->v_flags & AFPVOL_RO)
953 if (( dir = dirsearch( vol, ddid )) == NULL ) {
954 return( AFPERR_PARAM );
957 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
958 return( AFPERR_NOOBJ );
960 if ( *path != '\0' ) {
961 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
964 /* one of the handful of places that knows about the path type */
965 if ( *ibuf++ != 2 ) {
966 return( AFPERR_PARAM );
968 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
969 strncpy( newname, ibuf, plen );
970 newname[ plen ] = '\0';
971 if (strlen(newname) != plen) {
972 /* there's \0 in newname, e.g. it's a pathname not
975 return( AFPERR_PARAM );
979 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
980 vol_noadouble(vol))) < 0 ) {
984 setvoltime(obj, vol );
987 if (vol->v_flags & AFPVOL_DROPBOX) {
988 retvalue=matchfile2dirperms(newname, vol, sdid);
990 #endif /* DROPKLUDGE */
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;
1048 LOG(log_info, logtype_afpd, "begin copyfile:");
1051 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;
1644 struct ofork *opened;
1648 #endif /* CNID_DB */
1653 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1659 memcpy(&vid, ibuf, sizeof(vid));
1660 ibuf += sizeof(vid);
1662 if (( vol = getvolbyvid( vid )) == NULL ) {
1663 return( AFPERR_PARAM);
1666 if (vol->v_flags & AFPVOL_RO)
1667 return AFPERR_VLOCK;
1669 /* source and destination dids */
1670 memcpy(&sid, ibuf, sizeof(sid));
1671 ibuf += sizeof(sid);
1672 memcpy(&did, ibuf, sizeof(did));
1673 ibuf += sizeof(did);
1676 if ((dir = dirsearch( vol, sid )) == NULL ) {
1677 return( AFPERR_PARAM );
1680 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1681 return( AFPERR_PARAM );
1684 if ( *path == '\0' ) {
1685 return( AFPERR_BADTYPE ); /* it's a dir */
1688 upath = mtoupath(vol, path);
1689 if (stat(upath, &srcst) < 0) {
1695 return AFPERR_ACCESS;
1697 return AFPERR_PARAM;
1700 memset(&ads, 0, sizeof(ads));
1702 if ((opened = of_findname(vol, curdir, path))) {
1703 /* reuse struct adouble so it won't break locks */
1704 adsp = opened->of_ad;
1706 /* save some stuff */
1708 spath = obj->oldtmp;
1709 supath = obj->newtmp;
1710 strcpy(spath, path);
1711 strcpy(supath, upath); /* this is for the cnid changing */
1712 p = ctoupath( vol, sdir, spath);
1714 /* look for the source cnid. if it doesn't exist, don't worry about
1717 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1718 slen = strlen(supath));
1719 #endif /* CNID_DB */
1721 if (( dir = dirsearch( vol, did )) == NULL ) {
1722 return( AFPERR_PARAM );
1725 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1726 return( AFPERR_PARAM );
1729 if ( *path == '\0' ) {
1730 return( AFPERR_BADTYPE );
1733 /* FPExchangeFiles is the only call that can return the SameObj
1735 if ((curdir == sdir) && strcmp(spath, path) == 0)
1736 return AFPERR_SAMEOBJ;
1738 upath = mtoupath(vol, path);
1739 if (stat(upath, &destst) < 0) {
1745 return AFPERR_ACCESS;
1747 return AFPERR_PARAM;
1750 memset(&add, 0, sizeof(add));
1752 if ((opened = of_findname(vol, curdir, path))) {
1753 /* reuse struct adouble so it won't break locks */
1754 addp = opened->of_ad;
1757 /* look for destination id. */
1758 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1759 dlen = strlen(upath));
1760 #endif /* CNID_DB */
1762 /* construct a temp name.
1763 * NOTE: the temp file will be in the dest file's directory. it
1764 * will also be inaccessible from AFP. */
1765 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1769 /* now, quickly rename the file. we error if we can't. */
1770 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1771 goto err_exchangefile;
1772 of_rename(vol, sdir, spath, curdir, temp);
1774 /* rename destination to source */
1775 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1776 goto err_src_to_tmp;
1777 of_rename(vol, curdir, path, sdir, spath);
1779 /* rename temp to destination */
1780 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1781 goto err_dest_to_src;
1782 of_rename(vol, curdir, temp, curdir, path);
1785 /* id's need switching. src -> dest and dest -> src. */
1786 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1787 upath, dlen) < 0)) {
1791 err = AFPERR_ACCESS;
1796 goto err_temp_to_dest;
1799 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1800 supath, slen) < 0)) {
1804 err = AFPERR_ACCESS;
1811 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1812 goto err_temp_to_dest;
1814 #endif /* CNID_DB */
1817 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1823 /* all this stuff is so that we can unwind a failed operation
1828 /* rename dest to temp */
1829 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1830 of_rename(vol, curdir, upath, curdir, temp);
1833 /* rename source back to dest */
1834 renamefile(p, upath, path, vol_noadouble(vol), addp);
1835 of_rename(vol, sdir, spath, curdir, path);
1838 /* rename temp back to source */
1839 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1840 of_rename(vol, curdir, temp, sdir, spath);