2 * $Id: file.c,v 1.47 2002-08-16 00:42:56 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"
70 #endif /* FORCE_UIDGID */
72 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
73 * field bytes subfield bytes
76 * ioFlFndrInfo 16 -> type 4 type field
77 * creator 4 creator field
78 * flags 2 finder flags:
80 * location 4 location in window
81 * folder 2 window that contains file
83 * ioFlXFndrInfo 16 -> iconID 2 icon id
85 * script 1 script system
87 * commentID 2 comment id
88 * putawayID 4 home directory id
91 const u_char ufinderi[] = {
92 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
93 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0
98 int getmetadata(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen, struct adouble *adp, int attrbits )
104 struct stat lst, *lstp;
105 #endif /* USE_LASTDID */
108 char *data, *nameoff = NULL, *upath;
112 u_char achar, fdType[4];
115 LOG(log_info, logtype_afpd, "begin getmetadata:");
118 upath = mtoupath(vol, path);
121 while ( bitmap != 0 ) {
122 while (( bitmap & 1 ) == 0 ) {
130 ad_getattr(adp, &ashort);
131 } else if (*upath == '.') {
132 ashort = htons(ATTRBIT_INVISIBLE);
136 ashort = htons(ntohs(ashort) | attrbits);
137 memcpy(data, &ashort, sizeof( ashort ));
138 data += sizeof( ashort );
142 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
143 data += sizeof( u_int32_t );
147 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
148 aint = AD_DATE_FROM_UNIX(st->st_mtime);
149 memcpy(data, &aint, sizeof( aint ));
150 data += sizeof( aint );
154 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
155 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
156 if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
157 LOG(log_error, logtype_default, "getfilparams fstat: %s", strerror(errno) );
159 else if (hst.st_mtime < st->st_mtime)
160 aint = AD_DATE_FROM_UNIX(st->st_mtime);
162 aint = AD_DATE_FROM_UNIX(hst.st_mtime);
165 aint = AD_DATE_FROM_UNIX(st->st_mtime);
167 memcpy(data, &aint, sizeof( int ));
168 data += sizeof( int );
172 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
173 aint = AD_DATE_START;
174 memcpy(data, &aint, sizeof( int ));
175 data += sizeof( int );
180 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
182 memcpy(data, ufinderi, 32);
183 if (*upath == '.') { /* make it invisible */
184 ashort = htons(FINDERINFO_INVISIBLE);
185 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
189 if ((!adp || (memcmp(ad_entry(adp, ADEID_FINDERI),
190 ufinderi, 8 ) == 0)) &&
191 (em = getextmap( path ))) {
192 memcpy(data, em->em_type, sizeof( em->em_type ));
193 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
200 data += sizeof( u_int16_t );
204 memset(data, 0, sizeof(u_int16_t));
205 data += sizeof( u_int16_t );
210 #if AD_VERSION > AD_VERSION1
211 /* look in AD v2 header */
213 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
214 #endif /* AD_VERSION > AD_VERSION1 */
217 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
218 strlen(upath), aint);
219 /* Throw errors if cnid_add fails. */
220 if (aint == CNID_INVALID) {
223 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
224 return(AFPERR_PARAM);
226 return(AFPERR_PARAM);
236 * What a fucking mess. First thing: DID and FNUMs are
237 * in the same space for purposes of enumerate (and several
238 * other wierd places). While we consider this Apple's bug,
239 * this is the work-around: In order to maintain constant and
240 * unique DIDs and FNUMs, we monotonically generate the DIDs
241 * during the session, and derive the FNUMs from the filesystem.
242 * Since the DIDs are small, we insure that the FNUMs are fairly
243 * large by setting thier high bits to the device number.
245 * AFS already does something very similar to this for the
246 * inode number, so we don't repeat the procedure.
249 * due to complaints over did's being non-persistent,
250 * here's the current hack to provide semi-persistent
252 * 1) we reserve the first bit for file ids.
253 * 2) the next 7 bits are for the device.
254 * 3) the remaining 24 bits are for the inode.
256 * both the inode and device information are actually hashes
257 * that are then truncated to the requisite bit length.
259 * it should be okay to use lstat to deal with symlinks.
262 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
263 #else /* USE_LASTDID */
264 lstp = lstat(upath, &lst) < 0 ? st : &lst;
266 aint = htonl( afpd_st_cnid ( lstp ) );
268 aint = htonl(CNID(lstp, 1));
269 #endif /* DID_MTAB */
270 #endif /* USE_LASTDID */
273 memcpy(data, &aint, sizeof( aint ));
274 data += sizeof( aint );
278 aint = htonl( st->st_size );
279 memcpy(data, &aint, sizeof( aint ));
280 data += sizeof( aint );
285 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
289 memcpy(data, &aint, sizeof( aint ));
290 data += sizeof( aint );
293 /* Current client needs ProDOS info block for this file.
294 Use simple heuristic and let the Mac "type" string tell
295 us what the PD file code should be. Everything gets a
296 subtype of 0x0000 unless the original value was hashed
297 to "pXYZ" when we created it. See IA, Ver 2.
299 case FILPBIT_PDINFO :
301 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
303 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
307 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
311 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
315 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
319 else if ( fdType[0] == 'p' ) {
321 ashort = (fdType[2] * 256) + fdType[3];
335 memcpy(data, &ashort, sizeof( ashort ));
336 data += sizeof( ashort );
337 memset(data, 0, sizeof( ashort ));
338 data += sizeof( ashort );
342 return( AFPERR_BITMAP );
348 ashort = htons( data - buf );
349 memcpy(nameoff, &ashort, sizeof( ashort ));
350 if ((aint = strlen( path )) > MACFILELEN)
353 memcpy(data, path, aint );
356 *buflen = data - buf;
360 /* ----------------------- */
361 int getfilparams(struct vol *vol,
363 char *path, struct dir *dir, struct stat *st,
364 char *buf, int *buflen )
366 struct adouble ad, *adp;
369 u_int16_t attrbits = 0;
372 LOG(log_info, logtype_default, "begin getfilparams:");
375 upath = mtoupath(vol, path);
376 if ((of = of_findname(vol, dir, path))) {
378 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
379 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
382 memset(&ad, 0, sizeof(ad));
386 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
392 we need to check if the file is open by another process.
393 it's slow so we only do it if we have to:
394 - bitmap is requested.
395 - we don't already have the answer!
397 if ((bitmap & (1 << FILPBIT_ATTR))) {
398 if (!(attrbits & ATTRBIT_ROPEN)) {
400 if (!(attrbits & ATTRBIT_DOPEN)) {
405 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
407 ad_close( adp, ADFLAGS_HF );
410 LOG(log_info, logtype_afpd, "end getfilparams:");
416 /* ----------------------------- */
417 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
420 int ibuflen, *rbuflen;
423 struct adouble ad, *adp;
428 int creatf, did, openf, retvalue = AFP_OK;
432 #endif /* FORCE_UIDGID */
435 LOG(log_info, logtype_afpd, "begin afp_createfile:");
440 creatf = (unsigned char) *ibuf++;
442 memcpy(&vid, ibuf, sizeof( vid ));
443 ibuf += sizeof( vid );
445 if (( vol = getvolbyvid( vid )) == NULL ) {
446 return( AFPERR_PARAM );
449 if (vol->v_flags & AFPVOL_RO)
452 memcpy(&did, ibuf, sizeof( did));
453 ibuf += sizeof( did );
455 if (( dir = dirsearch( vol, did )) == NULL ) {
456 return( AFPERR_NOOBJ );
459 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
460 return( AFPERR_NOOBJ );
463 upath = mtoupath(vol, path);
466 if (0 != (ret = check_name(vol, upath)))
470 if ((of = of_findname(vol, curdir, path))) {
473 memset(&ad, 0, sizeof(ad));
477 /* on a hard create, fail if file exists and is open */
478 if ((stat(upath, &st) == 0) && of)
480 openf = O_RDWR|O_CREAT|O_TRUNC;
482 /* on a soft create, if the file is open then ad_open won't failed
483 because open syscall is not called
488 openf = O_RDWR|O_CREAT|O_EXCL;
493 /* preserve current euid, egid */
494 save_uidgid ( uidgid );
496 /* perform all switching of users */
499 #endif /* FORCE_UIDGID */
501 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
502 openf, 0666, adp) < 0 ) {
506 /* bring everything back to old euid, egid */
507 restore_uidgid ( uidgid );
508 #endif /* FORCE_UIDGID */
509 return( AFPERR_EXIST );
512 /* bring everything back to old euid, egid */
513 restore_uidgid ( uidgid );
514 #endif /* FORCE_UIDGID */
515 return( AFPERR_ACCESS );
517 /* on noadouble volumes, just creating the data fork is ok */
518 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
519 goto createfile_done;
523 /* bring everything back to old euid, egid */
524 restore_uidgid ( uidgid );
525 #endif /* FORCE_UIDGID */
526 return( AFPERR_PARAM );
530 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
531 memcpy(ad_entry( adp, ADEID_NAME ), path,
532 ad_getentrylen( adp, ADEID_NAME ));
533 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
534 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
539 if (vol->v_flags & AFPVOL_DROPBOX) {
540 retvalue = matchfile2dirperms(upath, vol, did);
542 #endif /* DROPKLUDGE */
544 setvoltime(obj, vol );
547 LOG(log_info, logtype_afpd, "end afp_createfile");
551 /* bring everything back to old euid, egid */
552 restore_uidgid ( uidgid );
553 #endif /* FORCE_UIDGID */
558 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
561 int ibuflen, *rbuflen;
567 u_int16_t vid, bitmap;
570 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
576 memcpy(&vid, ibuf, sizeof( vid ));
577 ibuf += sizeof( vid );
578 if (( vol = getvolbyvid( vid )) == NULL ) {
579 return( AFPERR_PARAM );
582 if (vol->v_flags & AFPVOL_RO)
585 memcpy(&did, ibuf, sizeof( did ));
586 ibuf += sizeof( did );
587 if (( dir = dirsearch( vol, did )) == NULL ) {
588 return( AFPERR_NOOBJ );
591 memcpy(&bitmap, ibuf, sizeof( bitmap ));
592 bitmap = ntohs( bitmap );
593 ibuf += sizeof( bitmap );
595 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
596 return( AFPERR_NOOBJ );
599 if ( *path == '\0' ) {
600 return( AFPERR_BADTYPE ); /* it's a directory */
603 if ((u_long)ibuf & 1 ) {
607 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
608 setvoltime(obj, vol );
612 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
619 int setfilparams(struct vol *vol,
620 char *path, u_int16_t bitmap, char *buf )
622 struct adouble ad, *adp;
625 int bit = 0, isad = 1, err = AFP_OK;
627 u_char achar, *fdType, xyy[4];
628 u_int16_t ashort, bshort;
635 uidgid = malloc(sizeof(uidgidset));
636 #endif /* FORCE_UIDGID */
639 LOG(log_info, logtype_afpd, "begin setfilparams:");
642 upath = mtoupath(vol, path);
643 if ((of = of_findname(vol, curdir, path))) {
646 memset(&ad, 0, sizeof(ad));
651 save_uidgid ( uidgid );
653 #endif /* FORCE_UIDGID */
655 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
656 O_RDWR|O_CREAT, 0666, adp) < 0) {
657 /* for some things, we don't need an adouble header */
658 if (bitmap & ~(1<<FILPBIT_MDATE)) {
660 restore_uidgid ( uidgid );
661 #endif /* FORCE_UIDGID */
662 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
665 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
666 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
667 memcpy(ad_entry( adp, ADEID_NAME ), path,
668 ad_getentrylen( adp, ADEID_NAME ));
671 while ( bitmap != 0 ) {
672 while (( bitmap & 1 ) == 0 ) {
679 memcpy(&ashort, buf, sizeof( ashort ));
680 ad_getattr(adp, &bshort);
681 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
682 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
686 ad_setattr(adp, bshort);
687 buf += sizeof( ashort );
691 memcpy(&aint, buf, sizeof(aint));
692 ad_setdate(adp, AD_DATE_CREATE, aint);
693 buf += sizeof( aint );
697 memcpy(&aint, buf, sizeof( aint ));
699 ad_setdate(adp, AD_DATE_MODIFY, aint);
700 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
702 buf += sizeof( aint );
706 memcpy(&aint, buf, sizeof(aint));
707 ad_setdate(adp, AD_DATE_BACKUP, aint);
708 buf += sizeof( aint );
712 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
713 && (em = getextmap( path )) &&
714 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
715 (memcmp(buf + 4, em->em_creator,
716 sizeof( em->em_creator )) == 0)) {
717 memcpy(buf, ufinderi, 8 );
719 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
723 /* Client needs to set the ProDOS file info for this file.
724 Use defined strings for the simple cases, and convert
725 all else into pXYY per Inside Appletalk. Always set
726 the creator as "pdos". <shirsch@ibm.net> */
727 case FILPBIT_PDINFO :
730 memcpy(&ashort, buf, sizeof( ashort ));
731 ashort = ntohs( ashort );
734 switch ( (unsigned int) achar )
737 fdType = ( u_char *) "TEXT";
741 fdType = ( u_char *) "PSYS";
745 fdType = ( u_char *) "PS16";
749 fdType = ( u_char *) "BINA";
753 xyy[0] = ( u_char ) 'p';
755 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
756 xyy[3] = ( u_char ) ashort & 0xff;
761 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
762 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
768 goto setfilparam_done;
777 ad_flush( adp, ADFLAGS_HF );
778 ad_close( adp, ADFLAGS_HF );
781 restore_uidgid ( uidgid );
782 #endif /* FORCE_UIDGID */
787 LOG(log_info, logtype_afpd, "end setfilparams:");
794 * renamefile and copyfile take the old and new unix pathnames
795 * and the new mac name.
796 * NOTE: if we have to copy a file instead of renaming it, locks
798 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
800 * src the full source absolute path
801 * dst the dest filename in current dir
802 * newname the dest mac name
803 * adp adouble struct of src file, if open, or & zeroed one
806 int renamefile(src, dst, newname, noadouble, adp )
807 char *src, *dst, *newname;
811 struct ofork *opened;
812 char adsrc[ MAXPATHLEN + 1];
816 * Note that this is only checking the existance of the data file,
817 * not the header file. The thinking is that if the data file doesn't
818 * exist, but the header file does, the right thing to do is remove
819 * the data file silently.
822 /* existence check moved to afp_moveandrename */
825 LOG(log_info, logtype_afpd, "begin renamefile:");
828 if ( rename( src, dst ) < 0 ) {
831 return( AFPERR_NOOBJ );
834 return( AFPERR_ACCESS );
837 case EXDEV : /* Cross device move -- try copy */
838 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
839 deletefile( dst, 0 );
842 return deletefile( src, 0);
844 return( AFPERR_PARAM );
848 strcpy( adsrc, ad_path( src, 0 ));
851 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
856 /* check for a source appledouble header. if it exists, make
857 * a dest appledouble directory and do the rename again. */
858 if (rc || stat(adsrc, &st) ||
859 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
862 ad_close(adp, ADFLAGS_HF);
866 return( AFPERR_ACCESS );
870 return( AFPERR_PARAM );
874 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
877 return( AFPERR_NOOBJ );
879 return( AFPERR_ACCESS );
883 return( AFPERR_PARAM );
887 len = strlen( newname );
888 ad_setentrylen( adp, ADEID_NAME, len );
889 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
890 ad_flush( adp, ADFLAGS_HF );
891 ad_close( adp, ADFLAGS_HF );
894 LOG(log_info, logtype_afpd, "end renamefile:");
900 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
903 int ibuflen, *rbuflen;
907 char *newname, *path, *p;
908 u_int32_t sdid, ddid;
909 int plen, err, retvalue = AFP_OK;
910 u_int16_t svid, dvid;
913 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
919 memcpy(&svid, ibuf, sizeof( svid ));
920 ibuf += sizeof( svid );
921 if (( vol = getvolbyvid( svid )) == NULL ) {
922 return( AFPERR_PARAM );
925 memcpy(&sdid, ibuf, sizeof( sdid ));
926 ibuf += sizeof( sdid );
927 if (( dir = dirsearch( vol, sdid )) == NULL ) {
928 return( AFPERR_PARAM );
931 memcpy(&dvid, ibuf, sizeof( dvid ));
932 ibuf += sizeof( dvid );
933 memcpy(&ddid, ibuf, sizeof( ddid ));
934 ibuf += sizeof( ddid );
936 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
937 return( AFPERR_NOOBJ );
939 if ( *path == '\0' ) {
940 return( AFPERR_BADTYPE );
943 /* don't allow copies when the file is open.
944 * XXX: the spec only calls for read/deny write access.
945 * however, copyfile doesn't have any of that info,
946 * and locks need to stay coherent. as a result,
947 * we just balk if the file is opened already. */
948 if (of_findname(vol, curdir, path))
949 return AFPERR_DENYCONF;
951 newname = obj->newtmp;
952 strcpy( newname, path );
954 p = ctoupath( vol, curdir, newname );
956 if (( vol = getvolbyvid( dvid )) == NULL ) {
957 return( AFPERR_PARAM );
960 if (vol->v_flags & AFPVOL_RO)
963 if (( dir = dirsearch( vol, ddid )) == NULL ) {
964 return( AFPERR_PARAM );
967 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
968 return( AFPERR_NOOBJ );
970 if ( *path != '\0' ) {
971 return( AFPERR_BADTYPE );
974 /* one of the handful of places that knows about the path type */
975 if ( *ibuf++ != 2 ) {
976 return( AFPERR_PARAM );
978 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
979 strncpy( newname, ibuf, plen );
980 newname[ plen ] = '\0';
983 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
984 vol_noadouble(vol))) < 0 ) {
988 setvoltime(obj, vol );
991 if (vol->v_flags & AFPVOL_DROPBOX) {
992 retvalue=matchfile2dirperms(newname, vol, sdid);
994 #endif /* DROPKLUDGE */
997 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1004 static __inline__ int copy_all(const int dfd, const void *buf,
1010 LOG(log_info, logtype_afpd, "begin copy_all:");
1013 while (buflen > 0) {
1014 if ((cc = write(dfd, buf, buflen)) < 0) {
1021 return AFPERR_DFULL;
1023 return AFPERR_VLOCK;
1025 return AFPERR_PARAM;
1032 LOG(log_info, logtype_afpd, "end copy_all:");
1038 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1039 * pass in vol and path */
1040 int copyfile(src, dst, newname, noadouble )
1041 char *src, *dst, *newname;
1042 const int noadouble;
1047 int sfd, dfd, len, err = AFP_OK;
1051 LOG(log_info, logtype_afpd, "begin copyfile:");
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( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1066 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1070 return( AFPERR_NOOBJ );
1072 return( AFPERR_ACCESS );
1074 return AFPERR_VLOCK;
1076 return( AFPERR_PARAM );
1081 #ifdef SENDFILE_FLAVOR_LINUX
1082 if (fstat(sfd, &st) == 0) {
1083 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1097 goto copyheader_done;
1099 #endif /* SENDFILE_FLAVOR_LINUX */
1101 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1108 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1116 unlink(ad_path(dst, ADFLAGS_HF));
1122 /* data fork copying */
1123 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1126 return( AFPERR_NOOBJ );
1128 return( AFPERR_ACCESS );
1130 return( AFPERR_PARAM );
1134 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1138 return( AFPERR_NOOBJ );
1140 return( AFPERR_ACCESS );
1142 return AFPERR_VLOCK;
1144 return( AFPERR_PARAM );
1148 #ifdef SENDFILE_FLAVOR_LINUX
1149 if (fstat(sfd, &st) == 0) {
1150 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1163 #endif /* SENDFILE_FLAVOR_LINUX */
1166 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1174 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1183 unlink(ad_path(dst, ADFLAGS_HF));
1189 memset(&ad, 0, sizeof(ad));
1190 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1194 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1196 return( AFPERR_ACCESS );
1198 return AFPERR_VLOCK;
1200 return( AFPERR_PARAM );
1204 len = strlen( newname );
1205 ad_setentrylen( &ad, ADEID_NAME, len );
1206 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1207 ad_flush( &ad, ADFLAGS_HF );
1208 ad_close( &ad, ADFLAGS_HF );
1212 LOG(log_info, logtype_afpd, "end copyfile:");
1219 /* -----------------------------------
1220 checkAttrib: 1 check kFPDeleteInhibitBit
1221 ie deletfile called by afp_delete
1223 when deletefile is called we don't have lock on it, file is closed (for us)
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_BADID;
1507 if (( dir = dirlookup( vol, id )) == NULL ) {
1508 return( 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;
1645 struct ofork *opened;
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 ((opened = of_findname(vol, curdir, path))) {
1704 /* reuse struct adouble so it won't break locks */
1705 adsp = opened->of_ad;
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 ((opened = of_findname(vol, curdir, path))) {
1754 /* reuse struct adouble so it won't break locks */
1755 addp = opened->of_ad;
1758 /* look for destination id. */
1759 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1760 dlen = strlen(upath));
1761 #endif /* CNID_DB */
1763 /* construct a temp name.
1764 * NOTE: the temp file will be in the dest file's directory. it
1765 * will also be inaccessible from AFP. */
1766 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1770 /* now, quickly rename the file. we error if we can't. */
1771 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1772 goto err_exchangefile;
1773 of_rename(vol, sdir, spath, curdir, temp);
1775 /* rename destination to source */
1776 if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1777 goto err_src_to_tmp;
1778 of_rename(vol, curdir, path, sdir, spath);
1780 /* rename temp to destination */
1781 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1782 goto err_dest_to_src;
1783 of_rename(vol, curdir, temp, curdir, path);
1786 /* id's need switching. src -> dest and dest -> src. */
1787 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1788 upath, dlen) < 0)) {
1792 err = AFPERR_ACCESS;
1797 goto err_temp_to_dest;
1800 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1801 supath, slen) < 0)) {
1805 err = AFPERR_ACCESS;
1812 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1813 goto err_temp_to_dest;
1815 #endif /* CNID_DB */
1818 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1824 /* all this stuff is so that we can unwind a failed operation
1827 /* rename dest to temp */
1828 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1829 of_rename(vol, curdir, upath, curdir, temp);
1832 /* rename source back to dest */
1833 renamefile(p, upath, path, vol_noadouble(vol), addp);
1834 of_rename(vol, sdir, spath, curdir, path);
1837 /* rename temp back to source */
1838 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1839 of_rename(vol, curdir, temp, sdir, spath);