2 * $Id: file.c,v 1.44 2002-05-13 04:59:36 jmarcus 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;
371 LOG(log_info, logtype_default, "begin getfilparams:");
374 upath = mtoupath(vol, path);
375 if ((of = of_findname(vol, dir, path))) {
378 memset(&ad, 0, sizeof(ad));
382 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
385 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, 0);
387 ad_close( adp, ADFLAGS_HF );
390 LOG(log_info, logtype_afpd, "end getfilparams:");
396 /* ----------------------------- */
397 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
400 int ibuflen, *rbuflen;
403 struct adouble ad, *adp;
408 int creatf, did, openf, retvalue = AFP_OK;
412 #endif /* FORCE_UIDGID */
415 LOG(log_info, logtype_afpd, "begin afp_createfile:");
420 creatf = (unsigned char) *ibuf++;
422 memcpy(&vid, ibuf, sizeof( vid ));
423 ibuf += sizeof( vid );
425 if (( vol = getvolbyvid( vid )) == NULL ) {
426 return( AFPERR_PARAM );
429 if (vol->v_flags & AFPVOL_RO)
432 memcpy(&did, ibuf, sizeof( did));
433 ibuf += sizeof( did );
435 if (( dir = dirsearch( vol, did )) == NULL ) {
436 return( AFPERR_NOOBJ );
439 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
440 return( AFPERR_NOOBJ );
443 upath = mtoupath(vol, path);
446 if (0 != (ret = check_name(vol, upath)))
450 if ((of = of_findname(vol, curdir, path))) {
453 memset(&ad, 0, sizeof(ad));
457 /* on a hard create, fail if file exists and is open */
458 if ((stat(upath, &st) == 0) && of)
460 openf = O_RDWR|O_CREAT|O_TRUNC;
462 openf = O_RDWR|O_CREAT|O_EXCL;
467 /* preserve current euid, egid */
468 save_uidgid ( uidgid );
470 /* perform all switching of users */
473 #endif /* FORCE_UIDGID */
475 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
476 openf, 0666, adp) < 0 ) {
480 /* bring everything back to old euid, egid */
481 restore_uidgid ( uidgid );
482 #endif /* FORCE_UIDGID */
483 return( AFPERR_EXIST );
486 /* bring everything back to old euid, egid */
487 restore_uidgid ( uidgid );
488 #endif /* FORCE_UIDGID */
489 return( AFPERR_ACCESS );
491 /* on noadouble volumes, just creating the data fork is ok */
492 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
493 goto createfile_done;
497 /* bring everything back to old euid, egid */
498 restore_uidgid ( uidgid );
499 #endif /* FORCE_UIDGID */
500 return( AFPERR_PARAM );
504 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
505 memcpy(ad_entry( adp, ADEID_NAME ), path,
506 ad_getentrylen( adp, ADEID_NAME ));
507 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
508 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
513 if (vol->v_flags & AFPVOL_DROPBOX) {
514 retvalue = matchfile2dirperms(upath, vol, did);
516 #endif /* DROPKLUDGE */
518 setvoltime(obj, vol );
521 LOG(log_info, logtype_afpd, "end afp_createfile");
525 /* bring everything back to old euid, egid */
526 restore_uidgid ( uidgid );
527 #endif /* FORCE_UIDGID */
532 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
535 int ibuflen, *rbuflen;
541 u_int16_t vid, bitmap;
544 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
550 memcpy(&vid, ibuf, sizeof( vid ));
551 ibuf += sizeof( vid );
552 if (( vol = getvolbyvid( vid )) == NULL ) {
553 return( AFPERR_PARAM );
556 if (vol->v_flags & AFPVOL_RO)
559 memcpy(&did, ibuf, sizeof( did ));
560 ibuf += sizeof( did );
561 if (( dir = dirsearch( vol, did )) == NULL ) {
562 return( AFPERR_NOOBJ );
565 memcpy(&bitmap, ibuf, sizeof( bitmap ));
566 bitmap = ntohs( bitmap );
567 ibuf += sizeof( bitmap );
569 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
570 return( AFPERR_NOOBJ );
573 if ((u_long)ibuf & 1 ) {
577 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
578 setvoltime(obj, vol );
582 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
589 int setfilparams(struct vol *vol,
590 char *path, u_int16_t bitmap, char *buf )
592 struct adouble ad, *adp;
595 int bit = 0, isad = 1, err = AFP_OK;
597 u_char achar, *fdType, xyy[4];
598 u_int16_t ashort, bshort;
605 uidgid = malloc(sizeof(uidgidset));
606 #endif /* FORCE_UIDGID */
609 LOG(log_info, logtype_afpd, "begin setfilparams:");
612 upath = mtoupath(vol, path);
613 if ((of = of_findname(vol, curdir, path))) {
616 memset(&ad, 0, sizeof(ad));
621 save_uidgid ( uidgid );
623 #endif /* FORCE_UIDGID */
625 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
626 O_RDWR|O_CREAT, 0666, adp) < 0) {
627 /* for some things, we don't need an adouble header */
628 if (bitmap & ~(1<<FILPBIT_MDATE)) {
630 restore_uidgid ( uidgid );
631 #endif /* FORCE_UIDGID */
632 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
635 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
636 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
637 memcpy(ad_entry( adp, ADEID_NAME ), path,
638 ad_getentrylen( adp, ADEID_NAME ));
641 while ( bitmap != 0 ) {
642 while (( bitmap & 1 ) == 0 ) {
649 memcpy(&ashort, buf, sizeof( ashort ));
650 ad_getattr(adp, &bshort);
651 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
652 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
656 ad_setattr(adp, bshort);
657 buf += sizeof( ashort );
661 memcpy(&aint, buf, sizeof(aint));
662 ad_setdate(adp, AD_DATE_CREATE, aint);
663 buf += sizeof( aint );
667 memcpy(&aint, buf, sizeof( aint ));
669 ad_setdate(adp, AD_DATE_MODIFY, aint);
670 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
672 buf += sizeof( aint );
676 memcpy(&aint, buf, sizeof(aint));
677 ad_setdate(adp, AD_DATE_BACKUP, aint);
678 buf += sizeof( aint );
682 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
683 && (em = getextmap( path )) &&
684 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
685 (memcmp(buf + 4, em->em_creator,
686 sizeof( em->em_creator )) == 0)) {
687 memcpy(buf, ufinderi, 8 );
689 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
693 /* Client needs to set the ProDOS file info for this file.
694 Use defined strings for the simple cases, and convert
695 all else into pXYY per Inside Appletalk. Always set
696 the creator as "pdos". <shirsch@ibm.net> */
697 case FILPBIT_PDINFO :
700 memcpy(&ashort, buf, sizeof( ashort ));
701 ashort = ntohs( ashort );
704 switch ( (unsigned int) achar )
707 fdType = ( u_char *) "TEXT";
711 fdType = ( u_char *) "PSYS";
715 fdType = ( u_char *) "PS16";
719 fdType = ( u_char *) "BINA";
723 xyy[0] = ( u_char ) 'p';
725 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
726 xyy[3] = ( u_char ) ashort & 0xff;
731 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
732 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
738 goto setfilparam_done;
747 ad_flush( adp, ADFLAGS_HF );
748 ad_close( adp, ADFLAGS_HF );
751 restore_uidgid ( uidgid );
752 #endif /* FORCE_UIDGID */
757 LOG(log_info, logtype_afpd, "end setfilparams:");
764 * renamefile and copyfile take the old and new unix pathnames
765 * and the new mac name.
766 * NOTE: if we have to copy a file instead of renaming it, locks
768 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
770 * src the full source absolute path
771 * dst the dest filename in current dir
772 * newname the dest mac name
773 * adp adouble struct of src file, if open, or & zeroed one
776 int renamefile(src, dst, newname, noadouble, adp )
777 char *src, *dst, *newname;
781 struct ofork *opened;
782 char adsrc[ MAXPATHLEN + 1];
786 * Note that this is only checking the existance of the data file,
787 * not the header file. The thinking is that if the data file doesn't
788 * exist, but the header file does, the right thing to do is remove
789 * the data file silently.
792 /* existence check moved to afp_moveandrename */
795 LOG(log_info, logtype_afpd, "begin renamefile:");
798 if ( rename( src, dst ) < 0 ) {
801 return( AFPERR_NOOBJ );
804 return( AFPERR_ACCESS );
807 case EXDEV : /* Cross device move -- try copy */
808 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
809 deletefile( dst, 0 );
812 return deletefile( src, 0);
814 return( AFPERR_PARAM );
818 strcpy( adsrc, ad_path( src, 0 ));
821 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
826 /* check for a source appledouble header. if it exists, make
827 * a dest appledouble directory and do the rename again. */
828 if (rc || stat(adsrc, &st) ||
829 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
832 ad_close(adp, ADFLAGS_HF);
836 return( AFPERR_ACCESS );
840 return( AFPERR_PARAM );
844 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
847 return( AFPERR_NOOBJ );
849 return( AFPERR_ACCESS );
853 return( AFPERR_PARAM );
857 len = strlen( newname );
858 ad_setentrylen( adp, ADEID_NAME, len );
859 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
860 ad_flush( adp, ADFLAGS_HF );
861 ad_close( adp, ADFLAGS_HF );
864 LOG(log_info, logtype_afpd, "end renamefile:");
870 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
873 int ibuflen, *rbuflen;
877 char *newname, *path, *p;
878 u_int32_t sdid, ddid;
879 int plen, err, retvalue = AFP_OK;
880 u_int16_t svid, dvid;
883 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
889 memcpy(&svid, ibuf, sizeof( svid ));
890 ibuf += sizeof( svid );
891 if (( vol = getvolbyvid( svid )) == NULL ) {
892 return( AFPERR_PARAM );
895 memcpy(&sdid, ibuf, sizeof( sdid ));
896 ibuf += sizeof( sdid );
897 if (( dir = dirsearch( vol, sdid )) == NULL ) {
898 return( AFPERR_PARAM );
901 memcpy(&dvid, ibuf, sizeof( dvid ));
902 ibuf += sizeof( dvid );
903 memcpy(&ddid, ibuf, sizeof( ddid ));
904 ibuf += sizeof( ddid );
906 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
907 return( AFPERR_NOOBJ );
909 if ( *path == '\0' ) {
910 return( AFPERR_BADTYPE );
913 /* don't allow copies when the file is open.
914 * XXX: the spec only calls for read/deny write access.
915 * however, copyfile doesn't have any of that info,
916 * and locks need to stay coherent. as a result,
917 * we just balk if the file is opened already. */
918 if (of_findname(vol, curdir, path))
919 return AFPERR_DENYCONF;
921 newname = obj->newtmp;
922 strcpy( newname, path );
924 p = ctoupath( vol, curdir, newname );
926 if (( vol = getvolbyvid( dvid )) == NULL ) {
927 return( AFPERR_PARAM );
930 if (vol->v_flags & AFPVOL_RO)
933 if (( dir = dirsearch( vol, ddid )) == NULL ) {
934 return( AFPERR_PARAM );
937 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
938 return( AFPERR_NOOBJ );
940 if ( *path != '\0' ) {
941 return( AFPERR_BADTYPE );
944 /* one of the handful of places that knows about the path type */
945 if ( *ibuf++ != 2 ) {
946 return( AFPERR_PARAM );
948 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
949 strncpy( newname, ibuf, plen );
950 newname[ plen ] = '\0';
953 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
954 vol_noadouble(vol))) < 0 ) {
958 setvoltime(obj, vol );
961 if (vol->v_flags & AFPVOL_DROPBOX) {
962 retvalue=matchfile2dirperms(newname, vol, sdid);
964 #endif /* DROPKLUDGE */
967 LOG(log_info, logtype_afpd, "end afp_copyfile:");
974 static __inline__ int copy_all(const int dfd, const void *buf,
980 LOG(log_info, logtype_afpd, "begin copy_all:");
984 if ((cc = write(dfd, buf, buflen)) < 0) {
1002 LOG(log_info, logtype_afpd, "end copy_all:");
1008 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1009 * pass in vol and path */
1010 int copyfile(src, dst, newname, noadouble )
1011 char *src, *dst, *newname;
1012 const int noadouble;
1017 int sfd, dfd, len, err = AFP_OK;
1021 LOG(log_info, logtype_afpd, "begin copyfile:");
1025 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1028 break; /* just copy the data fork */
1030 return( AFPERR_ACCESS );
1032 return( AFPERR_PARAM );
1035 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1036 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1040 return( AFPERR_NOOBJ );
1042 return( AFPERR_ACCESS );
1044 return AFPERR_VLOCK;
1046 return( AFPERR_PARAM );
1051 #ifdef SENDFILE_FLAVOR_LINUX
1052 if (fstat(sfd, &st) == 0) {
1053 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1067 goto copyheader_done;
1069 #endif /* SENDFILE_FLAVOR_LINUX */
1071 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1078 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1086 unlink(ad_path(dst, ADFLAGS_HF));
1092 /* data fork copying */
1093 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1096 return( AFPERR_NOOBJ );
1098 return( AFPERR_ACCESS );
1100 return( AFPERR_PARAM );
1104 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1108 return( AFPERR_NOOBJ );
1110 return( AFPERR_ACCESS );
1112 return AFPERR_VLOCK;
1114 return( AFPERR_PARAM );
1118 #ifdef SENDFILE_FLAVOR_LINUX
1119 if (fstat(sfd, &st) == 0) {
1120 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1133 #endif /* SENDFILE_FLAVOR_LINUX */
1136 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1144 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1153 unlink(ad_path(dst, ADFLAGS_HF));
1159 memset(&ad, 0, sizeof(ad));
1160 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1164 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1166 return( AFPERR_ACCESS );
1168 return AFPERR_VLOCK;
1170 return( AFPERR_PARAM );
1174 len = strlen( newname );
1175 ad_setentrylen( &ad, ADEID_NAME, len );
1176 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1177 ad_flush( &ad, ADFLAGS_HF );
1178 ad_close( &ad, ADFLAGS_HF );
1182 LOG(log_info, logtype_afpd, "end copyfile:");
1189 /* -----------------------------------
1190 checkAttrib: 1 check kFPDeleteInhibitBit
1191 ie deletfile called by afp_delete
1193 when deletefile is called we don't have lock on it, file is closed (for us)
1195 int deletefile( file, checkAttrib )
1200 int adflags, err = AFP_OK;
1201 int locktype = ADLOCK_WR;
1202 int openmode = O_RDWR;
1205 LOG(log_info, logtype_afpd, "begin deletefile:");
1210 * If can't open read/write then try again read-only. If it's open
1211 * read-only, we must do a read lock instead of a write lock.
1213 /* try to open both at once */
1214 adflags = ADFLAGS_DF|ADFLAGS_HF;
1215 memset(&ad, 0, sizeof(ad));
1216 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1219 adflags = ADFLAGS_DF;
1220 /* that failed. now try to open just the data fork */
1221 memset(&ad, 0, sizeof(ad));
1222 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1225 return AFPERR_NOOBJ;
1227 if(openmode == O_RDWR) {
1228 openmode = O_RDONLY;
1229 locktype = ADLOCK_RD;
1232 return AFPERR_ACCESS;
1235 return AFPERR_VLOCK;
1237 return AFPERR_PARAM;
1243 if(openmode == O_RDWR) {
1244 openmode = O_RDONLY;
1245 locktype = ADLOCK_RD;
1248 return AFPERR_ACCESS;
1251 return AFPERR_VLOCK;
1253 return( AFPERR_PARAM );
1256 break; /* from the while */
1259 * Does kFPDeleteInhibitBit (bit 8) set?
1261 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1264 ad_getattr(&ad, &bshort);
1265 if ((bshort & htons(ATTRBIT_NODELETE))) {
1266 ad_close( &ad, adflags );
1267 return(AFPERR_OLOCK);
1271 if ((adflags & ADFLAGS_HF) ) {
1272 /* FIXME we have a pb here because we want to know if a file is open
1273 * there's a 'priority inversion' if you can't open the ressource fork RW
1274 * you can delete it if it's open because you can't get a write lock.
1276 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1279 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1281 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1282 ad_close( &ad, adflags );
1283 return( AFPERR_BUSY );
1287 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1292 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1296 err = AFPERR_ACCESS;
1309 if ( unlink( file ) < 0 ) {
1313 err = AFPERR_ACCESS;
1327 if (adflags & ADFLAGS_HF)
1328 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1329 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1330 ad_close( &ad, adflags );
1333 LOG(log_info, logtype_afpd, "end deletefile:");
1341 /* return a file id */
1342 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1345 int ibuflen, *rbuflen;
1357 LOG(log_info, logtype_afpd, "begin afp_createid:");
1363 memcpy(&vid, ibuf, sizeof(vid));
1364 ibuf += sizeof(vid);
1366 if (( vol = getvolbyvid( vid )) == NULL ) {
1367 return( AFPERR_PARAM);
1370 if (vol->v_flags & AFPVOL_RO)
1371 return AFPERR_VLOCK;
1373 memcpy(&did, ibuf, sizeof( did ));
1374 ibuf += sizeof(did);
1376 if (( dir = dirsearch( vol, did )) == NULL ) {
1377 return( AFPERR_PARAM );
1380 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1381 return( AFPERR_PARAM );
1384 if ( *path == '\0' ) {
1385 return( AFPERR_BADTYPE );
1388 upath = mtoupath(vol, path);
1389 if (stat(upath, &st) < 0) {
1393 return AFPERR_ACCESS;
1395 return AFPERR_NOOBJ;
1397 return AFPERR_PARAM;
1401 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1402 memcpy(rbuf, &id, sizeof(id));
1403 *rbuflen = sizeof(id);
1404 return AFPERR_EXISTID;
1407 #if AD_VERSION > AD_VERSION1
1408 memset(&ad, 0, sizeof(ad));
1409 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1410 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1411 ad_close(&ad, ADFLAGS_HF);
1413 #endif /* AD_VERSION > AD_VERSION1 */
1415 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1416 memcpy(rbuf, &id, sizeof(id));
1417 *rbuflen = sizeof(id);
1422 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1427 return AFPERR_VLOCK;
1431 return AFPERR_ACCESS;
1434 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1435 return AFPERR_PARAM;
1439 /* resolve a file id */
1440 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1443 int ibuflen, *rbuflen;
1451 u_int16_t vid, bitmap;
1453 static char buffer[12 + MAXPATHLEN + 1];
1454 int len = 12 + MAXPATHLEN + 1;
1457 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1463 memcpy(&vid, ibuf, sizeof(vid));
1464 ibuf += sizeof(vid);
1466 if (( vol = getvolbyvid( vid )) == NULL ) {
1467 return( AFPERR_PARAM);
1470 memcpy(&id, ibuf, sizeof( id ));
1473 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1474 return AFPERR_BADID;
1477 if (( dir = dirlookup( vol, id )) == NULL ) {
1478 return( AFPERR_PARAM );
1481 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1485 return AFPERR_ACCESS;
1489 return AFPERR_PARAM;
1493 /* directories are bad */
1494 if (S_ISDIR(st.st_mode))
1495 return AFPERR_BADTYPE;
1497 memcpy(&bitmap, ibuf, sizeof(bitmap));
1498 bitmap = ntohs( bitmap );
1500 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1501 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1504 *rbuflen = buflen + sizeof(bitmap);
1505 memcpy(rbuf, ibuf, sizeof(bitmap));
1508 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1514 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1517 int ibuflen, *rbuflen;
1527 static char buffer[12 + MAXPATHLEN + 1];
1528 int len = 12 + MAXPATHLEN + 1;
1531 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1537 memcpy(&vid, ibuf, sizeof(vid));
1538 ibuf += sizeof(vid);
1540 if (( vol = getvolbyvid( vid )) == NULL ) {
1541 return( AFPERR_PARAM);
1544 if (vol->v_flags & AFPVOL_RO)
1545 return AFPERR_VLOCK;
1547 memcpy(&id, ibuf, sizeof( id ));
1551 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1555 if (( dir = dirlookup( vol, id )) == NULL ) {
1556 return( AFPERR_PARAM );
1560 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1564 return AFPERR_ACCESS;
1566 /* still try to delete the id */
1570 return AFPERR_PARAM;
1574 /* directories are bad */
1575 if (S_ISDIR(st.st_mode))
1576 return AFPERR_BADTYPE;
1578 if (cnid_delete(vol->v_db, fileid)) {
1581 return AFPERR_VLOCK;
1584 return AFPERR_ACCESS;
1586 return AFPERR_PARAM;
1591 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1596 #endif /* CNID_DB */
1598 #define APPLETEMP ".AppleTempXXXXXX"
1600 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1603 int ibuflen, *rbuflen;
1605 struct stat srcst, destst;
1607 struct dir *dir, *sdir;
1608 char *spath, temp[17], *path, *p;
1609 char *supath, *upath;
1613 struct adouble *adsp;
1614 struct adouble *addp;
1615 struct ofork *opened;
1619 #endif /* CNID_DB */
1624 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1630 memcpy(&vid, ibuf, sizeof(vid));
1631 ibuf += sizeof(vid);
1633 if (( vol = getvolbyvid( vid )) == NULL ) {
1634 return( AFPERR_PARAM);
1637 if (vol->v_flags & AFPVOL_RO)
1638 return AFPERR_VLOCK;
1640 /* source and destination dids */
1641 memcpy(&sid, ibuf, sizeof(sid));
1642 ibuf += sizeof(sid);
1643 memcpy(&did, ibuf, sizeof(did));
1644 ibuf += sizeof(did);
1647 if ((dir = dirsearch( vol, sid )) == NULL ) {
1648 return( AFPERR_PARAM );
1651 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1652 return( AFPERR_PARAM );
1655 if ( *path == '\0' ) {
1656 return( AFPERR_BADTYPE ); /* it's a dir */
1659 upath = mtoupath(vol, path);
1660 if (stat(upath, &srcst) < 0) {
1666 return AFPERR_ACCESS;
1668 return AFPERR_PARAM;
1671 memset(&ads, 0, sizeof(ads));
1673 if ((opened = of_findname(vol, curdir, path))) {
1674 /* reuse struct adouble so it won't break locks */
1675 adsp = opened->of_ad;
1677 /* save some stuff */
1679 spath = obj->oldtmp;
1680 supath = obj->newtmp;
1681 strcpy(spath, path);
1682 strcpy(supath, upath); /* this is for the cnid changing */
1683 p = ctoupath( vol, sdir, spath);
1685 /* look for the source cnid. if it doesn't exist, don't worry about
1688 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1689 slen = strlen(supath));
1690 #endif /* CNID_DB */
1692 if (( dir = dirsearch( vol, did )) == NULL ) {
1693 return( AFPERR_PARAM );
1696 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1697 return( AFPERR_PARAM );
1700 if ( *path == '\0' ) {
1701 return( AFPERR_BADTYPE );
1704 /* FPExchangeFiles is the only call that can return the SameObj
1706 if ((curdir == sdir) && strcmp(spath, path) == 0)
1707 return AFPERR_SAMEOBJ;
1709 upath = mtoupath(vol, path);
1710 if (stat(upath, &destst) < 0) {
1716 return AFPERR_ACCESS;
1718 return AFPERR_PARAM;
1721 memset(&add, 0, sizeof(add));
1723 if ((opened = of_findname(vol, curdir, path))) {
1724 /* reuse struct adouble so it won't break locks */
1725 addp = opened->of_ad;
1728 /* look for destination id. */
1729 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1730 dlen = strlen(upath));
1731 #endif /* CNID_DB */
1733 /* construct a temp name.
1734 * NOTE: the temp file will be in the dest file's directory. it
1735 * will also be inaccessible from AFP. */
1736 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1740 /* now, quickly rename the file. we error if we can't. */
1741 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1742 goto err_exchangefile;
1743 of_rename(vol, sdir, spath, curdir, temp);
1745 /* rename destination to source */
1746 if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1747 goto err_src_to_tmp;
1748 of_rename(vol, curdir, path, sdir, spath);
1750 /* rename temp to destination */
1751 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1752 goto err_dest_to_src;
1753 of_rename(vol, curdir, temp, curdir, path);
1756 /* id's need switching. src -> dest and dest -> src. */
1757 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1758 upath, dlen) < 0)) {
1762 err = AFPERR_ACCESS;
1767 goto err_temp_to_dest;
1770 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1771 supath, slen) < 0)) {
1775 err = AFPERR_ACCESS;
1782 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1783 goto err_temp_to_dest;
1785 #endif /* CNID_DB */
1788 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1794 /* all this stuff is so that we can unwind a failed operation
1797 /* rename dest to temp */
1798 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1799 of_rename(vol, curdir, upath, curdir, temp);
1802 /* rename source back to dest */
1803 renamefile(p, upath, path, vol_noadouble(vol), addp);
1804 of_rename(vol, sdir, spath, curdir, path);
1807 /* rename temp back to source */
1808 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1809 of_rename(vol, curdir, temp, sdir, spath);