2 * $Id: file.c,v 1.48 2002-08-20 19:40:43 srittau 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 char adsrc[ MAXPATHLEN + 1];
815 * Note that this is only checking the existance of the data file,
816 * not the header file. The thinking is that if the data file doesn't
817 * exist, but the header file does, the right thing to do is remove
818 * the data file silently.
821 /* existence check moved to afp_moveandrename */
824 LOG(log_info, logtype_afpd, "begin renamefile:");
827 if ( rename( src, dst ) < 0 ) {
830 return( AFPERR_NOOBJ );
833 return( AFPERR_ACCESS );
836 case EXDEV : /* Cross device move -- try copy */
837 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
838 deletefile( dst, 0 );
841 return deletefile( src, 0);
843 return( AFPERR_PARAM );
847 strcpy( adsrc, ad_path( src, 0 ));
850 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
855 /* check for a source appledouble header. if it exists, make
856 * a dest appledouble directory and do the rename again. */
857 if (rc || stat(adsrc, &st) ||
858 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
861 ad_close(adp, ADFLAGS_HF);
865 return( AFPERR_ACCESS );
869 return( AFPERR_PARAM );
873 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
876 return( AFPERR_NOOBJ );
878 return( AFPERR_ACCESS );
882 return( AFPERR_PARAM );
886 len = strlen( newname );
887 ad_setentrylen( adp, ADEID_NAME, len );
888 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
889 ad_flush( adp, ADFLAGS_HF );
890 ad_close( adp, ADFLAGS_HF );
893 LOG(log_info, logtype_afpd, "end renamefile:");
899 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
902 int ibuflen, *rbuflen;
906 char *newname, *path, *p;
907 u_int32_t sdid, ddid;
908 int plen, err, retvalue = AFP_OK;
909 u_int16_t svid, dvid;
912 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
918 memcpy(&svid, ibuf, sizeof( svid ));
919 ibuf += sizeof( svid );
920 if (( vol = getvolbyvid( svid )) == NULL ) {
921 return( AFPERR_PARAM );
924 memcpy(&sdid, ibuf, sizeof( sdid ));
925 ibuf += sizeof( sdid );
926 if (( dir = dirsearch( vol, sdid )) == NULL ) {
927 return( AFPERR_PARAM );
930 memcpy(&dvid, ibuf, sizeof( dvid ));
931 ibuf += sizeof( dvid );
932 memcpy(&ddid, ibuf, sizeof( ddid ));
933 ibuf += sizeof( ddid );
935 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
936 return( AFPERR_NOOBJ );
938 if ( *path == '\0' ) {
939 return( AFPERR_BADTYPE );
942 /* don't allow copies when the file is open.
943 * XXX: the spec only calls for read/deny write access.
944 * however, copyfile doesn't have any of that info,
945 * and locks need to stay coherent. as a result,
946 * we just balk if the file is opened already. */
947 if (of_findname(vol, curdir, path))
948 return AFPERR_DENYCONF;
950 newname = obj->newtmp;
951 strcpy( newname, path );
953 p = ctoupath( vol, curdir, newname );
955 if (( vol = getvolbyvid( dvid )) == NULL ) {
956 return( AFPERR_PARAM );
959 if (vol->v_flags & AFPVOL_RO)
962 if (( dir = dirsearch( vol, ddid )) == NULL ) {
963 return( AFPERR_PARAM );
966 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
967 return( AFPERR_NOOBJ );
969 if ( *path != '\0' ) {
970 return( AFPERR_BADTYPE );
973 /* one of the handful of places that knows about the path type */
974 if ( *ibuf++ != 2 ) {
975 return( AFPERR_PARAM );
977 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
978 strncpy( newname, ibuf, plen );
979 newname[ plen ] = '\0';
982 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
983 vol_noadouble(vol))) < 0 ) {
987 setvoltime(obj, vol );
990 if (vol->v_flags & AFPVOL_DROPBOX) {
991 retvalue=matchfile2dirperms(newname, vol, sdid);
993 #endif /* DROPKLUDGE */
996 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1003 static __inline__ int copy_all(const int dfd, const void *buf,
1009 LOG(log_info, logtype_afpd, "begin copy_all:");
1012 while (buflen > 0) {
1013 if ((cc = write(dfd, buf, buflen)) < 0) {
1020 return AFPERR_DFULL;
1022 return AFPERR_VLOCK;
1024 return AFPERR_PARAM;
1031 LOG(log_info, logtype_afpd, "end copy_all:");
1037 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1038 * pass in vol and path */
1039 int copyfile(src, dst, newname, noadouble )
1040 char *src, *dst, *newname;
1041 const int noadouble;
1046 int sfd, dfd, len, err = AFP_OK;
1050 LOG(log_info, logtype_afpd, "begin copyfile:");
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( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1065 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1069 return( AFPERR_NOOBJ );
1071 return( AFPERR_ACCESS );
1073 return AFPERR_VLOCK;
1075 return( AFPERR_PARAM );
1080 #ifdef SENDFILE_FLAVOR_LINUX
1081 if (fstat(sfd, &st) == 0) {
1082 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1096 goto copyheader_done;
1098 #endif /* SENDFILE_FLAVOR_LINUX */
1100 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1107 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1115 unlink(ad_path(dst, ADFLAGS_HF));
1121 /* data fork copying */
1122 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1125 return( AFPERR_NOOBJ );
1127 return( AFPERR_ACCESS );
1129 return( AFPERR_PARAM );
1133 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1137 return( AFPERR_NOOBJ );
1139 return( AFPERR_ACCESS );
1141 return AFPERR_VLOCK;
1143 return( AFPERR_PARAM );
1147 #ifdef SENDFILE_FLAVOR_LINUX
1148 if (fstat(sfd, &st) == 0) {
1149 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1162 #endif /* SENDFILE_FLAVOR_LINUX */
1165 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1173 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1182 unlink(ad_path(dst, ADFLAGS_HF));
1188 memset(&ad, 0, sizeof(ad));
1189 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1193 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1195 return( AFPERR_ACCESS );
1197 return AFPERR_VLOCK;
1199 return( AFPERR_PARAM );
1203 len = strlen( newname );
1204 ad_setentrylen( &ad, ADEID_NAME, len );
1205 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1206 ad_flush( &ad, ADFLAGS_HF );
1207 ad_close( &ad, ADFLAGS_HF );
1211 LOG(log_info, logtype_afpd, "end copyfile:");
1218 /* -----------------------------------
1219 checkAttrib: 1 check kFPDeleteInhibitBit
1220 ie deletfile called by afp_delete
1222 when deletefile is called we don't have lock on it, file is closed (for us)
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_BADID;
1506 if (( dir = dirlookup( vol, id )) == NULL ) {
1507 return( 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(path, 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);