2 * $Id: file.c,v 1.49 2002-08-21 07:52:04 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),ufinderi , 8 ))
190 && (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 )
714 ((em = getextmap( path )) &&
715 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
716 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
717 || ((em = getdefextmap()) &&
718 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
719 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
721 memcpy(buf, ufinderi, 8 );
724 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
728 /* Client needs to set the ProDOS file info for this file.
729 Use defined strings for the simple cases, and convert
730 all else into pXYY per Inside Appletalk. Always set
731 the creator as "pdos". <shirsch@ibm.net> */
732 case FILPBIT_PDINFO :
735 memcpy(&ashort, buf, sizeof( ashort ));
736 ashort = ntohs( ashort );
739 switch ( (unsigned int) achar )
742 fdType = ( u_char *) "TEXT";
746 fdType = ( u_char *) "PSYS";
750 fdType = ( u_char *) "PS16";
754 fdType = ( u_char *) "BINA";
758 xyy[0] = ( u_char ) 'p';
760 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
761 xyy[3] = ( u_char ) ashort & 0xff;
766 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
767 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
773 goto setfilparam_done;
782 ad_flush( adp, ADFLAGS_HF );
783 ad_close( adp, ADFLAGS_HF );
786 restore_uidgid ( uidgid );
787 #endif /* FORCE_UIDGID */
792 LOG(log_info, logtype_afpd, "end setfilparams:");
799 * renamefile and copyfile take the old and new unix pathnames
800 * and the new mac name.
801 * NOTE: if we have to copy a file instead of renaming it, locks
803 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
805 * src the full source absolute path
806 * dst the dest filename in current dir
807 * newname the dest mac name
808 * adp adouble struct of src file, if open, or & zeroed one
811 int renamefile(src, dst, newname, noadouble, adp )
812 char *src, *dst, *newname;
816 char adsrc[ MAXPATHLEN + 1];
820 * Note that this is only checking the existance of the data file,
821 * not the header file. The thinking is that if the data file doesn't
822 * exist, but the header file does, the right thing to do is remove
823 * the data file silently.
826 /* existence check moved to afp_moveandrename */
829 LOG(log_info, logtype_afpd, "begin renamefile:");
832 if ( rename( src, dst ) < 0 ) {
835 return( AFPERR_NOOBJ );
838 return( AFPERR_ACCESS );
841 case EXDEV : /* Cross device move -- try copy */
842 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
843 deletefile( dst, 0 );
846 return deletefile( src, 0);
848 return( AFPERR_PARAM );
852 strcpy( adsrc, ad_path( src, 0 ));
855 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
860 /* check for a source appledouble header. if it exists, make
861 * a dest appledouble directory and do the rename again. */
862 if (rc || stat(adsrc, &st) ||
863 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
866 ad_close(adp, ADFLAGS_HF);
870 return( AFPERR_ACCESS );
874 return( AFPERR_PARAM );
878 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
881 return( AFPERR_NOOBJ );
883 return( AFPERR_ACCESS );
887 return( AFPERR_PARAM );
891 len = strlen( newname );
892 ad_setentrylen( adp, ADEID_NAME, len );
893 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
894 ad_flush( adp, ADFLAGS_HF );
895 ad_close( adp, ADFLAGS_HF );
898 LOG(log_info, logtype_afpd, "end renamefile:");
904 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
907 int ibuflen, *rbuflen;
911 char *newname, *path, *p;
912 u_int32_t sdid, ddid;
913 int plen, err, retvalue = AFP_OK;
914 u_int16_t svid, dvid;
917 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
923 memcpy(&svid, ibuf, sizeof( svid ));
924 ibuf += sizeof( svid );
925 if (( vol = getvolbyvid( svid )) == NULL ) {
926 return( AFPERR_PARAM );
929 memcpy(&sdid, ibuf, sizeof( sdid ));
930 ibuf += sizeof( sdid );
931 if (( dir = dirsearch( vol, sdid )) == NULL ) {
932 return( AFPERR_PARAM );
935 memcpy(&dvid, ibuf, sizeof( dvid ));
936 ibuf += sizeof( dvid );
937 memcpy(&ddid, ibuf, sizeof( ddid ));
938 ibuf += sizeof( ddid );
940 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
941 return( AFPERR_NOOBJ );
943 if ( *path == '\0' ) {
944 return( AFPERR_BADTYPE );
947 /* don't allow copies when the file is open.
948 * XXX: the spec only calls for read/deny write access.
949 * however, copyfile doesn't have any of that info,
950 * and locks need to stay coherent. as a result,
951 * we just balk if the file is opened already. */
952 if (of_findname(vol, curdir, path))
953 return AFPERR_DENYCONF;
955 newname = obj->newtmp;
956 strcpy( newname, path );
958 p = ctoupath( vol, curdir, newname );
960 if (( vol = getvolbyvid( dvid )) == NULL ) {
961 return( AFPERR_PARAM );
964 if (vol->v_flags & AFPVOL_RO)
967 if (( dir = dirsearch( vol, ddid )) == NULL ) {
968 return( AFPERR_PARAM );
971 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
972 return( AFPERR_NOOBJ );
974 if ( *path != '\0' ) {
975 return( AFPERR_BADTYPE );
978 /* one of the handful of places that knows about the path type */
979 if ( *ibuf++ != 2 ) {
980 return( AFPERR_PARAM );
982 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
983 strncpy( newname, ibuf, plen );
984 newname[ plen ] = '\0';
987 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
988 vol_noadouble(vol))) < 0 ) {
992 setvoltime(obj, vol );
995 if (vol->v_flags & AFPVOL_DROPBOX) {
996 retvalue=matchfile2dirperms(newname, vol, sdid);
998 #endif /* DROPKLUDGE */
1001 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1008 static __inline__ int copy_all(const int dfd, const void *buf,
1014 LOG(log_info, logtype_afpd, "begin copy_all:");
1017 while (buflen > 0) {
1018 if ((cc = write(dfd, buf, buflen)) < 0) {
1025 return AFPERR_DFULL;
1027 return AFPERR_VLOCK;
1029 return AFPERR_PARAM;
1036 LOG(log_info, logtype_afpd, "end copy_all:");
1042 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1043 * pass in vol and path */
1044 int copyfile(src, dst, newname, noadouble )
1045 char *src, *dst, *newname;
1046 const int noadouble;
1051 int sfd, dfd, len, err = AFP_OK;
1055 LOG(log_info, logtype_afpd, "begin copyfile:");
1059 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1062 break; /* just copy the data fork */
1064 return( AFPERR_ACCESS );
1066 return( AFPERR_PARAM );
1069 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1070 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1074 return( AFPERR_NOOBJ );
1076 return( AFPERR_ACCESS );
1078 return AFPERR_VLOCK;
1080 return( AFPERR_PARAM );
1085 #ifdef SENDFILE_FLAVOR_LINUX
1086 if (fstat(sfd, &st) == 0) {
1087 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1101 goto copyheader_done;
1103 #endif /* SENDFILE_FLAVOR_LINUX */
1105 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1112 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1120 unlink(ad_path(dst, ADFLAGS_HF));
1126 /* data fork copying */
1127 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1130 return( AFPERR_NOOBJ );
1132 return( AFPERR_ACCESS );
1134 return( AFPERR_PARAM );
1138 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1142 return( AFPERR_NOOBJ );
1144 return( AFPERR_ACCESS );
1146 return AFPERR_VLOCK;
1148 return( AFPERR_PARAM );
1152 #ifdef SENDFILE_FLAVOR_LINUX
1153 if (fstat(sfd, &st) == 0) {
1154 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1167 #endif /* SENDFILE_FLAVOR_LINUX */
1170 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1178 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1187 unlink(ad_path(dst, ADFLAGS_HF));
1193 memset(&ad, 0, sizeof(ad));
1194 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1198 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1200 return( AFPERR_ACCESS );
1202 return AFPERR_VLOCK;
1204 return( AFPERR_PARAM );
1208 len = strlen( newname );
1209 ad_setentrylen( &ad, ADEID_NAME, len );
1210 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1211 ad_flush( &ad, ADFLAGS_HF );
1212 ad_close( &ad, ADFLAGS_HF );
1216 LOG(log_info, logtype_afpd, "end copyfile:");
1223 /* -----------------------------------
1224 checkAttrib: 1 check kFPDeleteInhibitBit
1225 ie deletfile called by afp_delete
1227 when deletefile is called we don't have lock on it, file is closed (for us)
1229 int deletefile( file, checkAttrib )
1234 int adflags, err = AFP_OK;
1235 int locktype = ADLOCK_WR;
1236 int openmode = O_RDWR;
1239 LOG(log_info, logtype_afpd, "begin deletefile:");
1244 * If can't open read/write then try again read-only. If it's open
1245 * read-only, we must do a read lock instead of a write lock.
1247 /* try to open both at once */
1248 adflags = ADFLAGS_DF|ADFLAGS_HF;
1249 memset(&ad, 0, sizeof(ad));
1250 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1253 adflags = ADFLAGS_DF;
1254 /* that failed. now try to open just the data fork */
1255 memset(&ad, 0, sizeof(ad));
1256 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1259 return AFPERR_NOOBJ;
1261 if(openmode == O_RDWR) {
1262 openmode = O_RDONLY;
1263 locktype = ADLOCK_RD;
1266 return AFPERR_ACCESS;
1269 return AFPERR_VLOCK;
1271 return AFPERR_PARAM;
1277 if(openmode == O_RDWR) {
1278 openmode = O_RDONLY;
1279 locktype = ADLOCK_RD;
1282 return AFPERR_ACCESS;
1285 return AFPERR_VLOCK;
1287 return( AFPERR_PARAM );
1290 break; /* from the while */
1293 * Does kFPDeleteInhibitBit (bit 8) set?
1295 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1298 ad_getattr(&ad, &bshort);
1299 if ((bshort & htons(ATTRBIT_NODELETE))) {
1300 ad_close( &ad, adflags );
1301 return(AFPERR_OLOCK);
1305 if ((adflags & ADFLAGS_HF) ) {
1306 /* FIXME we have a pb here because we want to know if a file is open
1307 * there's a 'priority inversion' if you can't open the ressource fork RW
1308 * you can delete it if it's open because you can't get a write lock.
1310 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1313 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1315 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1316 ad_close( &ad, adflags );
1317 return( AFPERR_BUSY );
1321 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1326 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1330 err = AFPERR_ACCESS;
1343 if ( unlink( file ) < 0 ) {
1347 err = AFPERR_ACCESS;
1361 if (adflags & ADFLAGS_HF)
1362 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1363 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1364 ad_close( &ad, adflags );
1367 LOG(log_info, logtype_afpd, "end deletefile:");
1375 /* return a file id */
1376 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1379 int ibuflen, *rbuflen;
1391 LOG(log_info, logtype_afpd, "begin afp_createid:");
1397 memcpy(&vid, ibuf, sizeof(vid));
1398 ibuf += sizeof(vid);
1400 if (( vol = getvolbyvid( vid )) == NULL ) {
1401 return( AFPERR_PARAM);
1404 if (vol->v_flags & AFPVOL_RO)
1405 return AFPERR_VLOCK;
1407 memcpy(&did, ibuf, sizeof( did ));
1408 ibuf += sizeof(did);
1410 if (( dir = dirsearch( vol, did )) == NULL ) {
1411 return( AFPERR_PARAM );
1414 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1415 return( AFPERR_PARAM );
1418 if ( *path == '\0' ) {
1419 return( AFPERR_BADTYPE );
1422 upath = mtoupath(vol, path);
1423 if (stat(upath, &st) < 0) {
1427 return AFPERR_ACCESS;
1429 return AFPERR_NOOBJ;
1431 return AFPERR_PARAM;
1435 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1436 memcpy(rbuf, &id, sizeof(id));
1437 *rbuflen = sizeof(id);
1438 return AFPERR_EXISTID;
1441 #if AD_VERSION > AD_VERSION1
1442 memset(&ad, 0, sizeof(ad));
1443 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1444 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1445 ad_close(&ad, ADFLAGS_HF);
1447 #endif /* AD_VERSION > AD_VERSION1 */
1449 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1450 memcpy(rbuf, &id, sizeof(id));
1451 *rbuflen = sizeof(id);
1456 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1461 return AFPERR_VLOCK;
1465 return AFPERR_ACCESS;
1468 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1469 return AFPERR_PARAM;
1473 /* resolve a file id */
1474 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1477 int ibuflen, *rbuflen;
1485 u_int16_t vid, bitmap;
1487 static char buffer[12 + MAXPATHLEN + 1];
1488 int len = 12 + MAXPATHLEN + 1;
1491 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1497 memcpy(&vid, ibuf, sizeof(vid));
1498 ibuf += sizeof(vid);
1500 if (( vol = getvolbyvid( vid )) == NULL ) {
1501 return( AFPERR_PARAM);
1504 memcpy(&id, ibuf, sizeof( id ));
1507 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1508 return AFPERR_BADID;
1511 if (( dir = dirlookup( vol, id )) == NULL ) {
1512 return( AFPERR_PARAM );
1515 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1519 return AFPERR_ACCESS;
1523 return AFPERR_PARAM;
1527 /* directories are bad */
1528 if (S_ISDIR(st.st_mode))
1529 return AFPERR_BADTYPE;
1531 memcpy(&bitmap, ibuf, sizeof(bitmap));
1532 bitmap = ntohs( bitmap );
1534 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1535 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1538 *rbuflen = buflen + sizeof(bitmap);
1539 memcpy(rbuf, ibuf, sizeof(bitmap));
1542 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1548 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1551 int ibuflen, *rbuflen;
1561 static char buffer[12 + MAXPATHLEN + 1];
1562 int len = 12 + MAXPATHLEN + 1;
1565 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1571 memcpy(&vid, ibuf, sizeof(vid));
1572 ibuf += sizeof(vid);
1574 if (( vol = getvolbyvid( vid )) == NULL ) {
1575 return( AFPERR_PARAM);
1578 if (vol->v_flags & AFPVOL_RO)
1579 return AFPERR_VLOCK;
1581 memcpy(&id, ibuf, sizeof( id ));
1585 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1589 if (( dir = dirlookup( vol, id )) == NULL ) {
1590 return( AFPERR_PARAM );
1594 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1598 return AFPERR_ACCESS;
1600 /* still try to delete the id */
1604 return AFPERR_PARAM;
1608 /* directories are bad */
1609 if (S_ISDIR(st.st_mode))
1610 return AFPERR_BADTYPE;
1612 if (cnid_delete(vol->v_db, fileid)) {
1615 return AFPERR_VLOCK;
1618 return AFPERR_ACCESS;
1620 return AFPERR_PARAM;
1625 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1630 #endif /* CNID_DB */
1632 #define APPLETEMP ".AppleTempXXXXXX"
1634 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1637 int ibuflen, *rbuflen;
1639 struct stat srcst, destst;
1641 struct dir *dir, *sdir;
1642 char *spath, temp[17], *path, *p;
1643 char *supath, *upath;
1647 struct adouble *adsp;
1648 struct adouble *addp;
1649 struct ofork *opened;
1653 #endif /* CNID_DB */
1658 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1664 memcpy(&vid, ibuf, sizeof(vid));
1665 ibuf += sizeof(vid);
1667 if (( vol = getvolbyvid( vid )) == NULL ) {
1668 return( AFPERR_PARAM);
1671 if (vol->v_flags & AFPVOL_RO)
1672 return AFPERR_VLOCK;
1674 /* source and destination dids */
1675 memcpy(&sid, ibuf, sizeof(sid));
1676 ibuf += sizeof(sid);
1677 memcpy(&did, ibuf, sizeof(did));
1678 ibuf += sizeof(did);
1681 if ((dir = dirsearch( vol, sid )) == NULL ) {
1682 return( AFPERR_PARAM );
1685 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1686 return( AFPERR_PARAM );
1689 if ( *path == '\0' ) {
1690 return( AFPERR_BADTYPE ); /* it's a dir */
1693 upath = mtoupath(vol, path);
1694 if (stat(upath, &srcst) < 0) {
1700 return AFPERR_ACCESS;
1702 return AFPERR_PARAM;
1705 memset(&ads, 0, sizeof(ads));
1707 if ((opened = of_findname(vol, curdir, path))) {
1708 /* reuse struct adouble so it won't break locks */
1709 adsp = opened->of_ad;
1711 /* save some stuff */
1713 spath = obj->oldtmp;
1714 supath = obj->newtmp;
1715 strcpy(spath, path);
1716 strcpy(supath, upath); /* this is for the cnid changing */
1717 p = ctoupath( vol, sdir, spath);
1719 /* look for the source cnid. if it doesn't exist, don't worry about
1722 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1723 slen = strlen(supath));
1724 #endif /* CNID_DB */
1726 if (( dir = dirsearch( vol, did )) == NULL ) {
1727 return( AFPERR_PARAM );
1730 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1731 return( AFPERR_PARAM );
1734 if ( *path == '\0' ) {
1735 return( AFPERR_BADTYPE );
1738 /* FPExchangeFiles is the only call that can return the SameObj
1740 if ((curdir == sdir) && strcmp(spath, path) == 0)
1741 return AFPERR_SAMEOBJ;
1743 upath = mtoupath(vol, path);
1744 if (stat(upath, &destst) < 0) {
1750 return AFPERR_ACCESS;
1752 return AFPERR_PARAM;
1755 memset(&add, 0, sizeof(add));
1757 if ((opened = of_findname(vol, curdir, path))) {
1758 /* reuse struct adouble so it won't break locks */
1759 addp = opened->of_ad;
1762 /* look for destination id. */
1763 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1764 dlen = strlen(upath));
1765 #endif /* CNID_DB */
1767 /* construct a temp name.
1768 * NOTE: the temp file will be in the dest file's directory. it
1769 * will also be inaccessible from AFP. */
1770 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1774 /* now, quickly rename the file. we error if we can't. */
1775 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1776 goto err_exchangefile;
1777 of_rename(vol, sdir, spath, curdir, temp);
1779 /* rename destination to source */
1780 if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1781 goto err_src_to_tmp;
1782 of_rename(vol, curdir, path, sdir, spath);
1784 /* rename temp to destination */
1785 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1786 goto err_dest_to_src;
1787 of_rename(vol, curdir, temp, curdir, path);
1790 /* id's need switching. src -> dest and dest -> src. */
1791 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1792 upath, dlen) < 0)) {
1796 err = AFPERR_ACCESS;
1801 goto err_temp_to_dest;
1804 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1805 supath, slen) < 0)) {
1809 err = AFPERR_ACCESS;
1816 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1817 goto err_temp_to_dest;
1819 #endif /* CNID_DB */
1822 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1828 /* all this stuff is so that we can unwind a failed operation
1833 /* rename dest to temp */
1834 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1835 of_rename(vol, curdir, upath, curdir, temp);
1838 /* rename source back to dest */
1839 renamefile(p, upath, path, vol_noadouble(vol), addp);
1840 of_rename(vol, sdir, spath, curdir, path);
1843 /* rename temp back to source */
1844 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1845 of_rename(vol, curdir, temp, sdir, spath);