2 * $Id: file.c,v 1.46 2002-06-17 18:23:03 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 ((u_long)ibuf & 1 ) {
603 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
604 setvoltime(obj, vol );
608 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
615 int setfilparams(struct vol *vol,
616 char *path, u_int16_t bitmap, char *buf )
618 struct adouble ad, *adp;
621 int bit = 0, isad = 1, err = AFP_OK;
623 u_char achar, *fdType, xyy[4];
624 u_int16_t ashort, bshort;
631 uidgid = malloc(sizeof(uidgidset));
632 #endif /* FORCE_UIDGID */
635 LOG(log_info, logtype_afpd, "begin setfilparams:");
638 upath = mtoupath(vol, path);
639 if ((of = of_findname(vol, curdir, path))) {
642 memset(&ad, 0, sizeof(ad));
647 save_uidgid ( uidgid );
649 #endif /* FORCE_UIDGID */
651 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
652 O_RDWR|O_CREAT, 0666, adp) < 0) {
653 /* for some things, we don't need an adouble header */
654 if (bitmap & ~(1<<FILPBIT_MDATE)) {
656 restore_uidgid ( uidgid );
657 #endif /* FORCE_UIDGID */
658 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
661 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
662 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
663 memcpy(ad_entry( adp, ADEID_NAME ), path,
664 ad_getentrylen( adp, ADEID_NAME ));
667 while ( bitmap != 0 ) {
668 while (( bitmap & 1 ) == 0 ) {
675 memcpy(&ashort, buf, sizeof( ashort ));
676 ad_getattr(adp, &bshort);
677 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
678 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
682 ad_setattr(adp, bshort);
683 buf += sizeof( ashort );
687 memcpy(&aint, buf, sizeof(aint));
688 ad_setdate(adp, AD_DATE_CREATE, aint);
689 buf += sizeof( aint );
693 memcpy(&aint, buf, sizeof( aint ));
695 ad_setdate(adp, AD_DATE_MODIFY, aint);
696 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
698 buf += sizeof( aint );
702 memcpy(&aint, buf, sizeof(aint));
703 ad_setdate(adp, AD_DATE_BACKUP, aint);
704 buf += sizeof( aint );
708 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
709 && (em = getextmap( path )) &&
710 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
711 (memcmp(buf + 4, em->em_creator,
712 sizeof( em->em_creator )) == 0)) {
713 memcpy(buf, ufinderi, 8 );
715 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
719 /* Client needs to set the ProDOS file info for this file.
720 Use defined strings for the simple cases, and convert
721 all else into pXYY per Inside Appletalk. Always set
722 the creator as "pdos". <shirsch@ibm.net> */
723 case FILPBIT_PDINFO :
726 memcpy(&ashort, buf, sizeof( ashort ));
727 ashort = ntohs( ashort );
730 switch ( (unsigned int) achar )
733 fdType = ( u_char *) "TEXT";
737 fdType = ( u_char *) "PSYS";
741 fdType = ( u_char *) "PS16";
745 fdType = ( u_char *) "BINA";
749 xyy[0] = ( u_char ) 'p';
751 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
752 xyy[3] = ( u_char ) ashort & 0xff;
757 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
758 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
764 goto setfilparam_done;
773 ad_flush( adp, ADFLAGS_HF );
774 ad_close( adp, ADFLAGS_HF );
777 restore_uidgid ( uidgid );
778 #endif /* FORCE_UIDGID */
783 LOG(log_info, logtype_afpd, "end setfilparams:");
790 * renamefile and copyfile take the old and new unix pathnames
791 * and the new mac name.
792 * NOTE: if we have to copy a file instead of renaming it, locks
794 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
796 * src the full source absolute path
797 * dst the dest filename in current dir
798 * newname the dest mac name
799 * adp adouble struct of src file, if open, or & zeroed one
802 int renamefile(src, dst, newname, noadouble, adp )
803 char *src, *dst, *newname;
807 struct ofork *opened;
808 char adsrc[ MAXPATHLEN + 1];
812 * Note that this is only checking the existance of the data file,
813 * not the header file. The thinking is that if the data file doesn't
814 * exist, but the header file does, the right thing to do is remove
815 * the data file silently.
818 /* existence check moved to afp_moveandrename */
821 LOG(log_info, logtype_afpd, "begin renamefile:");
824 if ( rename( src, dst ) < 0 ) {
827 return( AFPERR_NOOBJ );
830 return( AFPERR_ACCESS );
833 case EXDEV : /* Cross device move -- try copy */
834 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
835 deletefile( dst, 0 );
838 return deletefile( src, 0);
840 return( AFPERR_PARAM );
844 strcpy( adsrc, ad_path( src, 0 ));
847 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
852 /* check for a source appledouble header. if it exists, make
853 * a dest appledouble directory and do the rename again. */
854 if (rc || stat(adsrc, &st) ||
855 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
858 ad_close(adp, ADFLAGS_HF);
862 return( AFPERR_ACCESS );
866 return( AFPERR_PARAM );
870 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
873 return( AFPERR_NOOBJ );
875 return( AFPERR_ACCESS );
879 return( AFPERR_PARAM );
883 len = strlen( newname );
884 ad_setentrylen( adp, ADEID_NAME, len );
885 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
886 ad_flush( adp, ADFLAGS_HF );
887 ad_close( adp, ADFLAGS_HF );
890 LOG(log_info, logtype_afpd, "end renamefile:");
896 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
899 int ibuflen, *rbuflen;
903 char *newname, *path, *p;
904 u_int32_t sdid, ddid;
905 int plen, err, retvalue = AFP_OK;
906 u_int16_t svid, dvid;
909 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
915 memcpy(&svid, ibuf, sizeof( svid ));
916 ibuf += sizeof( svid );
917 if (( vol = getvolbyvid( svid )) == NULL ) {
918 return( AFPERR_PARAM );
921 memcpy(&sdid, ibuf, sizeof( sdid ));
922 ibuf += sizeof( sdid );
923 if (( dir = dirsearch( vol, sdid )) == NULL ) {
924 return( AFPERR_PARAM );
927 memcpy(&dvid, ibuf, sizeof( dvid ));
928 ibuf += sizeof( dvid );
929 memcpy(&ddid, ibuf, sizeof( ddid ));
930 ibuf += sizeof( ddid );
932 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
933 return( AFPERR_NOOBJ );
935 if ( *path == '\0' ) {
936 return( AFPERR_BADTYPE );
939 /* don't allow copies when the file is open.
940 * XXX: the spec only calls for read/deny write access.
941 * however, copyfile doesn't have any of that info,
942 * and locks need to stay coherent. as a result,
943 * we just balk if the file is opened already. */
944 if (of_findname(vol, curdir, path))
945 return AFPERR_DENYCONF;
947 newname = obj->newtmp;
948 strcpy( newname, path );
950 p = ctoupath( vol, curdir, newname );
952 if (( vol = getvolbyvid( dvid )) == NULL ) {
953 return( AFPERR_PARAM );
956 if (vol->v_flags & AFPVOL_RO)
959 if (( dir = dirsearch( vol, ddid )) == NULL ) {
960 return( AFPERR_PARAM );
963 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
964 return( AFPERR_NOOBJ );
966 if ( *path != '\0' ) {
967 return( AFPERR_BADTYPE );
970 /* one of the handful of places that knows about the path type */
971 if ( *ibuf++ != 2 ) {
972 return( AFPERR_PARAM );
974 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
975 strncpy( newname, ibuf, plen );
976 newname[ plen ] = '\0';
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;
1047 LOG(log_info, logtype_afpd, "begin copyfile:");
1051 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1054 break; /* just copy the data fork */
1056 return( AFPERR_ACCESS );
1058 return( AFPERR_PARAM );
1061 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1062 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1066 return( AFPERR_NOOBJ );
1068 return( AFPERR_ACCESS );
1070 return AFPERR_VLOCK;
1072 return( AFPERR_PARAM );
1077 #ifdef SENDFILE_FLAVOR_LINUX
1078 if (fstat(sfd, &st) == 0) {
1079 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1093 goto copyheader_done;
1095 #endif /* SENDFILE_FLAVOR_LINUX */
1097 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1104 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1112 unlink(ad_path(dst, ADFLAGS_HF));
1118 /* data fork copying */
1119 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1122 return( AFPERR_NOOBJ );
1124 return( AFPERR_ACCESS );
1126 return( AFPERR_PARAM );
1130 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1134 return( AFPERR_NOOBJ );
1136 return( AFPERR_ACCESS );
1138 return AFPERR_VLOCK;
1140 return( AFPERR_PARAM );
1144 #ifdef SENDFILE_FLAVOR_LINUX
1145 if (fstat(sfd, &st) == 0) {
1146 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1159 #endif /* SENDFILE_FLAVOR_LINUX */
1162 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1170 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1179 unlink(ad_path(dst, ADFLAGS_HF));
1185 memset(&ad, 0, sizeof(ad));
1186 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1190 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1192 return( AFPERR_ACCESS );
1194 return AFPERR_VLOCK;
1196 return( AFPERR_PARAM );
1200 len = strlen( newname );
1201 ad_setentrylen( &ad, ADEID_NAME, len );
1202 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1203 ad_flush( &ad, ADFLAGS_HF );
1204 ad_close( &ad, ADFLAGS_HF );
1208 LOG(log_info, logtype_afpd, "end copyfile:");
1215 /* -----------------------------------
1216 checkAttrib: 1 check kFPDeleteInhibitBit
1217 ie deletfile called by afp_delete
1219 when deletefile is called we don't have lock on it, file is closed (for us)
1221 int deletefile( file, checkAttrib )
1226 int adflags, err = AFP_OK;
1227 int locktype = ADLOCK_WR;
1228 int openmode = O_RDWR;
1231 LOG(log_info, logtype_afpd, "begin deletefile:");
1236 * If can't open read/write then try again read-only. If it's open
1237 * read-only, we must do a read lock instead of a write lock.
1239 /* try to open both at once */
1240 adflags = ADFLAGS_DF|ADFLAGS_HF;
1241 memset(&ad, 0, sizeof(ad));
1242 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1245 adflags = ADFLAGS_DF;
1246 /* that failed. now try to open just the data fork */
1247 memset(&ad, 0, sizeof(ad));
1248 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1251 return AFPERR_NOOBJ;
1253 if(openmode == O_RDWR) {
1254 openmode = O_RDONLY;
1255 locktype = ADLOCK_RD;
1258 return AFPERR_ACCESS;
1261 return AFPERR_VLOCK;
1263 return AFPERR_PARAM;
1269 if(openmode == O_RDWR) {
1270 openmode = O_RDONLY;
1271 locktype = ADLOCK_RD;
1274 return AFPERR_ACCESS;
1277 return AFPERR_VLOCK;
1279 return( AFPERR_PARAM );
1282 break; /* from the while */
1285 * Does kFPDeleteInhibitBit (bit 8) set?
1287 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1290 ad_getattr(&ad, &bshort);
1291 if ((bshort & htons(ATTRBIT_NODELETE))) {
1292 ad_close( &ad, adflags );
1293 return(AFPERR_OLOCK);
1297 if ((adflags & ADFLAGS_HF) ) {
1298 /* FIXME we have a pb here because we want to know if a file is open
1299 * there's a 'priority inversion' if you can't open the ressource fork RW
1300 * you can delete it if it's open because you can't get a write lock.
1302 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1305 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1307 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1308 ad_close( &ad, adflags );
1309 return( AFPERR_BUSY );
1313 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1318 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1322 err = AFPERR_ACCESS;
1335 if ( unlink( file ) < 0 ) {
1339 err = AFPERR_ACCESS;
1353 if (adflags & ADFLAGS_HF)
1354 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1355 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1356 ad_close( &ad, adflags );
1359 LOG(log_info, logtype_afpd, "end deletefile:");
1367 /* return a file id */
1368 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1371 int ibuflen, *rbuflen;
1383 LOG(log_info, logtype_afpd, "begin afp_createid:");
1389 memcpy(&vid, ibuf, sizeof(vid));
1390 ibuf += sizeof(vid);
1392 if (( vol = getvolbyvid( vid )) == NULL ) {
1393 return( AFPERR_PARAM);
1396 if (vol->v_flags & AFPVOL_RO)
1397 return AFPERR_VLOCK;
1399 memcpy(&did, ibuf, sizeof( did ));
1400 ibuf += sizeof(did);
1402 if (( dir = dirsearch( vol, did )) == NULL ) {
1403 return( AFPERR_PARAM );
1406 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1407 return( AFPERR_PARAM );
1410 if ( *path == '\0' ) {
1411 return( AFPERR_BADTYPE );
1414 upath = mtoupath(vol, path);
1415 if (stat(upath, &st) < 0) {
1419 return AFPERR_ACCESS;
1421 return AFPERR_NOOBJ;
1423 return AFPERR_PARAM;
1427 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1428 memcpy(rbuf, &id, sizeof(id));
1429 *rbuflen = sizeof(id);
1430 return AFPERR_EXISTID;
1433 #if AD_VERSION > AD_VERSION1
1434 memset(&ad, 0, sizeof(ad));
1435 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1436 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1437 ad_close(&ad, ADFLAGS_HF);
1439 #endif /* AD_VERSION > AD_VERSION1 */
1441 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1442 memcpy(rbuf, &id, sizeof(id));
1443 *rbuflen = sizeof(id);
1448 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1453 return AFPERR_VLOCK;
1457 return AFPERR_ACCESS;
1460 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1461 return AFPERR_PARAM;
1465 /* resolve a file id */
1466 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1469 int ibuflen, *rbuflen;
1477 u_int16_t vid, bitmap;
1479 static char buffer[12 + MAXPATHLEN + 1];
1480 int len = 12 + MAXPATHLEN + 1;
1483 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1489 memcpy(&vid, ibuf, sizeof(vid));
1490 ibuf += sizeof(vid);
1492 if (( vol = getvolbyvid( vid )) == NULL ) {
1493 return( AFPERR_PARAM);
1496 memcpy(&id, ibuf, sizeof( id ));
1499 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1500 return AFPERR_BADID;
1503 if (( dir = dirlookup( vol, id )) == NULL ) {
1504 return( AFPERR_PARAM );
1507 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1511 return AFPERR_ACCESS;
1515 return AFPERR_PARAM;
1519 /* directories are bad */
1520 if (S_ISDIR(st.st_mode))
1521 return AFPERR_BADTYPE;
1523 memcpy(&bitmap, ibuf, sizeof(bitmap));
1524 bitmap = ntohs( bitmap );
1526 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1527 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1530 *rbuflen = buflen + sizeof(bitmap);
1531 memcpy(rbuf, ibuf, sizeof(bitmap));
1534 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1540 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1543 int ibuflen, *rbuflen;
1553 static char buffer[12 + MAXPATHLEN + 1];
1554 int len = 12 + MAXPATHLEN + 1;
1557 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1563 memcpy(&vid, ibuf, sizeof(vid));
1564 ibuf += sizeof(vid);
1566 if (( vol = getvolbyvid( vid )) == NULL ) {
1567 return( AFPERR_PARAM);
1570 if (vol->v_flags & AFPVOL_RO)
1571 return AFPERR_VLOCK;
1573 memcpy(&id, ibuf, sizeof( id ));
1577 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1581 if (( dir = dirlookup( vol, id )) == NULL ) {
1582 return( AFPERR_PARAM );
1586 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1590 return AFPERR_ACCESS;
1592 /* still try to delete the id */
1596 return AFPERR_PARAM;
1600 /* directories are bad */
1601 if (S_ISDIR(st.st_mode))
1602 return AFPERR_BADTYPE;
1604 if (cnid_delete(vol->v_db, fileid)) {
1607 return AFPERR_VLOCK;
1610 return AFPERR_ACCESS;
1612 return AFPERR_PARAM;
1617 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1622 #endif /* CNID_DB */
1624 #define APPLETEMP ".AppleTempXXXXXX"
1626 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1629 int ibuflen, *rbuflen;
1631 struct stat srcst, destst;
1633 struct dir *dir, *sdir;
1634 char *spath, temp[17], *path, *p;
1635 char *supath, *upath;
1639 struct adouble *adsp;
1640 struct adouble *addp;
1641 struct ofork *opened;
1645 #endif /* CNID_DB */
1650 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1656 memcpy(&vid, ibuf, sizeof(vid));
1657 ibuf += sizeof(vid);
1659 if (( vol = getvolbyvid( vid )) == NULL ) {
1660 return( AFPERR_PARAM);
1663 if (vol->v_flags & AFPVOL_RO)
1664 return AFPERR_VLOCK;
1666 /* source and destination dids */
1667 memcpy(&sid, ibuf, sizeof(sid));
1668 ibuf += sizeof(sid);
1669 memcpy(&did, ibuf, sizeof(did));
1670 ibuf += sizeof(did);
1673 if ((dir = dirsearch( vol, sid )) == NULL ) {
1674 return( AFPERR_PARAM );
1677 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1678 return( AFPERR_PARAM );
1681 if ( *path == '\0' ) {
1682 return( AFPERR_BADTYPE ); /* it's a dir */
1685 upath = mtoupath(vol, path);
1686 if (stat(upath, &srcst) < 0) {
1692 return AFPERR_ACCESS;
1694 return AFPERR_PARAM;
1697 memset(&ads, 0, sizeof(ads));
1699 if ((opened = of_findname(vol, curdir, path))) {
1700 /* reuse struct adouble so it won't break locks */
1701 adsp = opened->of_ad;
1703 /* save some stuff */
1705 spath = obj->oldtmp;
1706 supath = obj->newtmp;
1707 strcpy(spath, path);
1708 strcpy(supath, upath); /* this is for the cnid changing */
1709 p = ctoupath( vol, sdir, spath);
1711 /* look for the source cnid. if it doesn't exist, don't worry about
1714 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1715 slen = strlen(supath));
1716 #endif /* CNID_DB */
1718 if (( dir = dirsearch( vol, did )) == NULL ) {
1719 return( AFPERR_PARAM );
1722 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1723 return( AFPERR_PARAM );
1726 if ( *path == '\0' ) {
1727 return( AFPERR_BADTYPE );
1730 /* FPExchangeFiles is the only call that can return the SameObj
1732 if ((curdir == sdir) && strcmp(spath, path) == 0)
1733 return AFPERR_SAMEOBJ;
1735 upath = mtoupath(vol, path);
1736 if (stat(upath, &destst) < 0) {
1742 return AFPERR_ACCESS;
1744 return AFPERR_PARAM;
1747 memset(&add, 0, sizeof(add));
1749 if ((opened = of_findname(vol, curdir, path))) {
1750 /* reuse struct adouble so it won't break locks */
1751 addp = opened->of_ad;
1754 /* look for destination id. */
1755 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1756 dlen = strlen(upath));
1757 #endif /* CNID_DB */
1759 /* construct a temp name.
1760 * NOTE: the temp file will be in the dest file's directory. it
1761 * will also be inaccessible from AFP. */
1762 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1766 /* now, quickly rename the file. we error if we can't. */
1767 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1768 goto err_exchangefile;
1769 of_rename(vol, sdir, spath, curdir, temp);
1771 /* rename destination to source */
1772 if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1773 goto err_src_to_tmp;
1774 of_rename(vol, curdir, path, sdir, spath);
1776 /* rename temp to destination */
1777 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1778 goto err_dest_to_src;
1779 of_rename(vol, curdir, temp, curdir, path);
1782 /* id's need switching. src -> dest and dest -> src. */
1783 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1784 upath, dlen) < 0)) {
1788 err = AFPERR_ACCESS;
1793 goto err_temp_to_dest;
1796 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1797 supath, slen) < 0)) {
1801 err = AFPERR_ACCESS;
1808 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1809 goto err_temp_to_dest;
1811 #endif /* CNID_DB */
1814 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1820 /* all this stuff is so that we can unwind a failed operation
1823 /* rename dest to temp */
1824 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1825 of_rename(vol, curdir, upath, curdir, temp);
1828 /* rename source back to dest */
1829 renamefile(p, upath, path, vol_noadouble(vol), addp);
1830 of_rename(vol, sdir, spath, curdir, path);
1833 /* rename temp back to source */
1834 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1835 of_rename(vol, curdir, temp, sdir, spath);