2 * $Id: file.c,v 1.45 2002-05-20 15:03:19 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 /* on a soft create, if the file is open then ad_open won't failed
463 because open syscall is not called
468 openf = O_RDWR|O_CREAT|O_EXCL;
473 /* preserve current euid, egid */
474 save_uidgid ( uidgid );
476 /* perform all switching of users */
479 #endif /* FORCE_UIDGID */
481 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
482 openf, 0666, adp) < 0 ) {
486 /* bring everything back to old euid, egid */
487 restore_uidgid ( uidgid );
488 #endif /* FORCE_UIDGID */
489 return( AFPERR_EXIST );
492 /* bring everything back to old euid, egid */
493 restore_uidgid ( uidgid );
494 #endif /* FORCE_UIDGID */
495 return( AFPERR_ACCESS );
497 /* on noadouble volumes, just creating the data fork is ok */
498 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
499 goto createfile_done;
503 /* bring everything back to old euid, egid */
504 restore_uidgid ( uidgid );
505 #endif /* FORCE_UIDGID */
506 return( AFPERR_PARAM );
510 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
511 memcpy(ad_entry( adp, ADEID_NAME ), path,
512 ad_getentrylen( adp, ADEID_NAME ));
513 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
514 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
519 if (vol->v_flags & AFPVOL_DROPBOX) {
520 retvalue = matchfile2dirperms(upath, vol, did);
522 #endif /* DROPKLUDGE */
524 setvoltime(obj, vol );
527 LOG(log_info, logtype_afpd, "end afp_createfile");
531 /* bring everything back to old euid, egid */
532 restore_uidgid ( uidgid );
533 #endif /* FORCE_UIDGID */
538 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
541 int ibuflen, *rbuflen;
547 u_int16_t vid, bitmap;
550 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
556 memcpy(&vid, ibuf, sizeof( vid ));
557 ibuf += sizeof( vid );
558 if (( vol = getvolbyvid( vid )) == NULL ) {
559 return( AFPERR_PARAM );
562 if (vol->v_flags & AFPVOL_RO)
565 memcpy(&did, ibuf, sizeof( did ));
566 ibuf += sizeof( did );
567 if (( dir = dirsearch( vol, did )) == NULL ) {
568 return( AFPERR_NOOBJ );
571 memcpy(&bitmap, ibuf, sizeof( bitmap ));
572 bitmap = ntohs( bitmap );
573 ibuf += sizeof( bitmap );
575 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
576 return( AFPERR_NOOBJ );
579 if ((u_long)ibuf & 1 ) {
583 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
584 setvoltime(obj, vol );
588 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
595 int setfilparams(struct vol *vol,
596 char *path, u_int16_t bitmap, char *buf )
598 struct adouble ad, *adp;
601 int bit = 0, isad = 1, err = AFP_OK;
603 u_char achar, *fdType, xyy[4];
604 u_int16_t ashort, bshort;
611 uidgid = malloc(sizeof(uidgidset));
612 #endif /* FORCE_UIDGID */
615 LOG(log_info, logtype_afpd, "begin setfilparams:");
618 upath = mtoupath(vol, path);
619 if ((of = of_findname(vol, curdir, path))) {
622 memset(&ad, 0, sizeof(ad));
627 save_uidgid ( uidgid );
629 #endif /* FORCE_UIDGID */
631 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
632 O_RDWR|O_CREAT, 0666, adp) < 0) {
633 /* for some things, we don't need an adouble header */
634 if (bitmap & ~(1<<FILPBIT_MDATE)) {
636 restore_uidgid ( uidgid );
637 #endif /* FORCE_UIDGID */
638 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
641 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
642 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
643 memcpy(ad_entry( adp, ADEID_NAME ), path,
644 ad_getentrylen( adp, ADEID_NAME ));
647 while ( bitmap != 0 ) {
648 while (( bitmap & 1 ) == 0 ) {
655 memcpy(&ashort, buf, sizeof( ashort ));
656 ad_getattr(adp, &bshort);
657 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
658 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
662 ad_setattr(adp, bshort);
663 buf += sizeof( ashort );
667 memcpy(&aint, buf, sizeof(aint));
668 ad_setdate(adp, AD_DATE_CREATE, aint);
669 buf += sizeof( aint );
673 memcpy(&aint, buf, sizeof( aint ));
675 ad_setdate(adp, AD_DATE_MODIFY, aint);
676 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
678 buf += sizeof( aint );
682 memcpy(&aint, buf, sizeof(aint));
683 ad_setdate(adp, AD_DATE_BACKUP, aint);
684 buf += sizeof( aint );
688 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
689 && (em = getextmap( path )) &&
690 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
691 (memcmp(buf + 4, em->em_creator,
692 sizeof( em->em_creator )) == 0)) {
693 memcpy(buf, ufinderi, 8 );
695 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
699 /* Client needs to set the ProDOS file info for this file.
700 Use defined strings for the simple cases, and convert
701 all else into pXYY per Inside Appletalk. Always set
702 the creator as "pdos". <shirsch@ibm.net> */
703 case FILPBIT_PDINFO :
706 memcpy(&ashort, buf, sizeof( ashort ));
707 ashort = ntohs( ashort );
710 switch ( (unsigned int) achar )
713 fdType = ( u_char *) "TEXT";
717 fdType = ( u_char *) "PSYS";
721 fdType = ( u_char *) "PS16";
725 fdType = ( u_char *) "BINA";
729 xyy[0] = ( u_char ) 'p';
731 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
732 xyy[3] = ( u_char ) ashort & 0xff;
737 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
738 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
744 goto setfilparam_done;
753 ad_flush( adp, ADFLAGS_HF );
754 ad_close( adp, ADFLAGS_HF );
757 restore_uidgid ( uidgid );
758 #endif /* FORCE_UIDGID */
763 LOG(log_info, logtype_afpd, "end setfilparams:");
770 * renamefile and copyfile take the old and new unix pathnames
771 * and the new mac name.
772 * NOTE: if we have to copy a file instead of renaming it, locks
774 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
776 * src the full source absolute path
777 * dst the dest filename in current dir
778 * newname the dest mac name
779 * adp adouble struct of src file, if open, or & zeroed one
782 int renamefile(src, dst, newname, noadouble, adp )
783 char *src, *dst, *newname;
787 struct ofork *opened;
788 char adsrc[ MAXPATHLEN + 1];
792 * Note that this is only checking the existance of the data file,
793 * not the header file. The thinking is that if the data file doesn't
794 * exist, but the header file does, the right thing to do is remove
795 * the data file silently.
798 /* existence check moved to afp_moveandrename */
801 LOG(log_info, logtype_afpd, "begin renamefile:");
804 if ( rename( src, dst ) < 0 ) {
807 return( AFPERR_NOOBJ );
810 return( AFPERR_ACCESS );
813 case EXDEV : /* Cross device move -- try copy */
814 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
815 deletefile( dst, 0 );
818 return deletefile( src, 0);
820 return( AFPERR_PARAM );
824 strcpy( adsrc, ad_path( src, 0 ));
827 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
832 /* check for a source appledouble header. if it exists, make
833 * a dest appledouble directory and do the rename again. */
834 if (rc || stat(adsrc, &st) ||
835 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
838 ad_close(adp, ADFLAGS_HF);
842 return( AFPERR_ACCESS );
846 return( AFPERR_PARAM );
850 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
853 return( AFPERR_NOOBJ );
855 return( AFPERR_ACCESS );
859 return( AFPERR_PARAM );
863 len = strlen( newname );
864 ad_setentrylen( adp, ADEID_NAME, len );
865 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
866 ad_flush( adp, ADFLAGS_HF );
867 ad_close( adp, ADFLAGS_HF );
870 LOG(log_info, logtype_afpd, "end renamefile:");
876 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
879 int ibuflen, *rbuflen;
883 char *newname, *path, *p;
884 u_int32_t sdid, ddid;
885 int plen, err, retvalue = AFP_OK;
886 u_int16_t svid, dvid;
889 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
895 memcpy(&svid, ibuf, sizeof( svid ));
896 ibuf += sizeof( svid );
897 if (( vol = getvolbyvid( svid )) == NULL ) {
898 return( AFPERR_PARAM );
901 memcpy(&sdid, ibuf, sizeof( sdid ));
902 ibuf += sizeof( sdid );
903 if (( dir = dirsearch( vol, sdid )) == NULL ) {
904 return( AFPERR_PARAM );
907 memcpy(&dvid, ibuf, sizeof( dvid ));
908 ibuf += sizeof( dvid );
909 memcpy(&ddid, ibuf, sizeof( ddid ));
910 ibuf += sizeof( ddid );
912 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
913 return( AFPERR_NOOBJ );
915 if ( *path == '\0' ) {
916 return( AFPERR_BADTYPE );
919 /* don't allow copies when the file is open.
920 * XXX: the spec only calls for read/deny write access.
921 * however, copyfile doesn't have any of that info,
922 * and locks need to stay coherent. as a result,
923 * we just balk if the file is opened already. */
924 if (of_findname(vol, curdir, path))
925 return AFPERR_DENYCONF;
927 newname = obj->newtmp;
928 strcpy( newname, path );
930 p = ctoupath( vol, curdir, newname );
932 if (( vol = getvolbyvid( dvid )) == NULL ) {
933 return( AFPERR_PARAM );
936 if (vol->v_flags & AFPVOL_RO)
939 if (( dir = dirsearch( vol, ddid )) == NULL ) {
940 return( AFPERR_PARAM );
943 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
944 return( AFPERR_NOOBJ );
946 if ( *path != '\0' ) {
947 return( AFPERR_BADTYPE );
950 /* one of the handful of places that knows about the path type */
951 if ( *ibuf++ != 2 ) {
952 return( AFPERR_PARAM );
954 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
955 strncpy( newname, ibuf, plen );
956 newname[ plen ] = '\0';
959 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
960 vol_noadouble(vol))) < 0 ) {
964 setvoltime(obj, vol );
967 if (vol->v_flags & AFPVOL_DROPBOX) {
968 retvalue=matchfile2dirperms(newname, vol, sdid);
970 #endif /* DROPKLUDGE */
973 LOG(log_info, logtype_afpd, "end afp_copyfile:");
980 static __inline__ int copy_all(const int dfd, const void *buf,
986 LOG(log_info, logtype_afpd, "begin copy_all:");
990 if ((cc = write(dfd, buf, buflen)) < 0) {
1001 return AFPERR_PARAM;
1008 LOG(log_info, logtype_afpd, "end copy_all:");
1014 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1015 * pass in vol and path */
1016 int copyfile(src, dst, newname, noadouble )
1017 char *src, *dst, *newname;
1018 const int noadouble;
1023 int sfd, dfd, len, err = AFP_OK;
1027 LOG(log_info, logtype_afpd, "begin copyfile:");
1031 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1034 break; /* just copy the data fork */
1036 return( AFPERR_ACCESS );
1038 return( AFPERR_PARAM );
1041 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1042 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1046 return( AFPERR_NOOBJ );
1048 return( AFPERR_ACCESS );
1050 return AFPERR_VLOCK;
1052 return( AFPERR_PARAM );
1057 #ifdef SENDFILE_FLAVOR_LINUX
1058 if (fstat(sfd, &st) == 0) {
1059 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1073 goto copyheader_done;
1075 #endif /* SENDFILE_FLAVOR_LINUX */
1077 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1084 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1092 unlink(ad_path(dst, ADFLAGS_HF));
1098 /* data fork copying */
1099 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1102 return( AFPERR_NOOBJ );
1104 return( AFPERR_ACCESS );
1106 return( AFPERR_PARAM );
1110 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1114 return( AFPERR_NOOBJ );
1116 return( AFPERR_ACCESS );
1118 return AFPERR_VLOCK;
1120 return( AFPERR_PARAM );
1124 #ifdef SENDFILE_FLAVOR_LINUX
1125 if (fstat(sfd, &st) == 0) {
1126 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1139 #endif /* SENDFILE_FLAVOR_LINUX */
1142 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1150 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1159 unlink(ad_path(dst, ADFLAGS_HF));
1165 memset(&ad, 0, sizeof(ad));
1166 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1170 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1172 return( AFPERR_ACCESS );
1174 return AFPERR_VLOCK;
1176 return( AFPERR_PARAM );
1180 len = strlen( newname );
1181 ad_setentrylen( &ad, ADEID_NAME, len );
1182 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1183 ad_flush( &ad, ADFLAGS_HF );
1184 ad_close( &ad, ADFLAGS_HF );
1188 LOG(log_info, logtype_afpd, "end copyfile:");
1195 /* -----------------------------------
1196 checkAttrib: 1 check kFPDeleteInhibitBit
1197 ie deletfile called by afp_delete
1199 when deletefile is called we don't have lock on it, file is closed (for us)
1201 int deletefile( file, checkAttrib )
1206 int adflags, err = AFP_OK;
1207 int locktype = ADLOCK_WR;
1208 int openmode = O_RDWR;
1211 LOG(log_info, logtype_afpd, "begin deletefile:");
1216 * If can't open read/write then try again read-only. If it's open
1217 * read-only, we must do a read lock instead of a write lock.
1219 /* try to open both at once */
1220 adflags = ADFLAGS_DF|ADFLAGS_HF;
1221 memset(&ad, 0, sizeof(ad));
1222 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1225 adflags = ADFLAGS_DF;
1226 /* that failed. now try to open just the data fork */
1227 memset(&ad, 0, sizeof(ad));
1228 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1231 return AFPERR_NOOBJ;
1233 if(openmode == O_RDWR) {
1234 openmode = O_RDONLY;
1235 locktype = ADLOCK_RD;
1238 return AFPERR_ACCESS;
1241 return AFPERR_VLOCK;
1243 return AFPERR_PARAM;
1249 if(openmode == O_RDWR) {
1250 openmode = O_RDONLY;
1251 locktype = ADLOCK_RD;
1254 return AFPERR_ACCESS;
1257 return AFPERR_VLOCK;
1259 return( AFPERR_PARAM );
1262 break; /* from the while */
1265 * Does kFPDeleteInhibitBit (bit 8) set?
1267 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1270 ad_getattr(&ad, &bshort);
1271 if ((bshort & htons(ATTRBIT_NODELETE))) {
1272 ad_close( &ad, adflags );
1273 return(AFPERR_OLOCK);
1277 if ((adflags & ADFLAGS_HF) ) {
1278 /* FIXME we have a pb here because we want to know if a file is open
1279 * there's a 'priority inversion' if you can't open the ressource fork RW
1280 * you can delete it if it's open because you can't get a write lock.
1282 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1285 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1287 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1288 ad_close( &ad, adflags );
1289 return( AFPERR_BUSY );
1293 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1298 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1302 err = AFPERR_ACCESS;
1315 if ( unlink( file ) < 0 ) {
1319 err = AFPERR_ACCESS;
1333 if (adflags & ADFLAGS_HF)
1334 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1335 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1336 ad_close( &ad, adflags );
1339 LOG(log_info, logtype_afpd, "end deletefile:");
1347 /* return a file id */
1348 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1351 int ibuflen, *rbuflen;
1363 LOG(log_info, logtype_afpd, "begin afp_createid:");
1369 memcpy(&vid, ibuf, sizeof(vid));
1370 ibuf += sizeof(vid);
1372 if (( vol = getvolbyvid( vid )) == NULL ) {
1373 return( AFPERR_PARAM);
1376 if (vol->v_flags & AFPVOL_RO)
1377 return AFPERR_VLOCK;
1379 memcpy(&did, ibuf, sizeof( did ));
1380 ibuf += sizeof(did);
1382 if (( dir = dirsearch( vol, did )) == NULL ) {
1383 return( AFPERR_PARAM );
1386 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1387 return( AFPERR_PARAM );
1390 if ( *path == '\0' ) {
1391 return( AFPERR_BADTYPE );
1394 upath = mtoupath(vol, path);
1395 if (stat(upath, &st) < 0) {
1399 return AFPERR_ACCESS;
1401 return AFPERR_NOOBJ;
1403 return AFPERR_PARAM;
1407 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1408 memcpy(rbuf, &id, sizeof(id));
1409 *rbuflen = sizeof(id);
1410 return AFPERR_EXISTID;
1413 #if AD_VERSION > AD_VERSION1
1414 memset(&ad, 0, sizeof(ad));
1415 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1416 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1417 ad_close(&ad, ADFLAGS_HF);
1419 #endif /* AD_VERSION > AD_VERSION1 */
1421 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1422 memcpy(rbuf, &id, sizeof(id));
1423 *rbuflen = sizeof(id);
1428 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1433 return AFPERR_VLOCK;
1437 return AFPERR_ACCESS;
1440 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1441 return AFPERR_PARAM;
1445 /* resolve a file id */
1446 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1449 int ibuflen, *rbuflen;
1457 u_int16_t vid, bitmap;
1459 static char buffer[12 + MAXPATHLEN + 1];
1460 int len = 12 + MAXPATHLEN + 1;
1463 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1469 memcpy(&vid, ibuf, sizeof(vid));
1470 ibuf += sizeof(vid);
1472 if (( vol = getvolbyvid( vid )) == NULL ) {
1473 return( AFPERR_PARAM);
1476 memcpy(&id, ibuf, sizeof( id ));
1479 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1480 return AFPERR_BADID;
1483 if (( dir = dirlookup( vol, id )) == NULL ) {
1484 return( AFPERR_PARAM );
1487 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1491 return AFPERR_ACCESS;
1495 return AFPERR_PARAM;
1499 /* directories are bad */
1500 if (S_ISDIR(st.st_mode))
1501 return AFPERR_BADTYPE;
1503 memcpy(&bitmap, ibuf, sizeof(bitmap));
1504 bitmap = ntohs( bitmap );
1506 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1507 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1510 *rbuflen = buflen + sizeof(bitmap);
1511 memcpy(rbuf, ibuf, sizeof(bitmap));
1514 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1520 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1523 int ibuflen, *rbuflen;
1533 static char buffer[12 + MAXPATHLEN + 1];
1534 int len = 12 + MAXPATHLEN + 1;
1537 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1543 memcpy(&vid, ibuf, sizeof(vid));
1544 ibuf += sizeof(vid);
1546 if (( vol = getvolbyvid( vid )) == NULL ) {
1547 return( AFPERR_PARAM);
1550 if (vol->v_flags & AFPVOL_RO)
1551 return AFPERR_VLOCK;
1553 memcpy(&id, ibuf, sizeof( id ));
1557 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1561 if (( dir = dirlookup( vol, id )) == NULL ) {
1562 return( AFPERR_PARAM );
1566 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1570 return AFPERR_ACCESS;
1572 /* still try to delete the id */
1576 return AFPERR_PARAM;
1580 /* directories are bad */
1581 if (S_ISDIR(st.st_mode))
1582 return AFPERR_BADTYPE;
1584 if (cnid_delete(vol->v_db, fileid)) {
1587 return AFPERR_VLOCK;
1590 return AFPERR_ACCESS;
1592 return AFPERR_PARAM;
1597 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1602 #endif /* CNID_DB */
1604 #define APPLETEMP ".AppleTempXXXXXX"
1606 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1609 int ibuflen, *rbuflen;
1611 struct stat srcst, destst;
1613 struct dir *dir, *sdir;
1614 char *spath, temp[17], *path, *p;
1615 char *supath, *upath;
1619 struct adouble *adsp;
1620 struct adouble *addp;
1621 struct ofork *opened;
1625 #endif /* CNID_DB */
1630 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1636 memcpy(&vid, ibuf, sizeof(vid));
1637 ibuf += sizeof(vid);
1639 if (( vol = getvolbyvid( vid )) == NULL ) {
1640 return( AFPERR_PARAM);
1643 if (vol->v_flags & AFPVOL_RO)
1644 return AFPERR_VLOCK;
1646 /* source and destination dids */
1647 memcpy(&sid, ibuf, sizeof(sid));
1648 ibuf += sizeof(sid);
1649 memcpy(&did, ibuf, sizeof(did));
1650 ibuf += sizeof(did);
1653 if ((dir = dirsearch( vol, sid )) == NULL ) {
1654 return( AFPERR_PARAM );
1657 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1658 return( AFPERR_PARAM );
1661 if ( *path == '\0' ) {
1662 return( AFPERR_BADTYPE ); /* it's a dir */
1665 upath = mtoupath(vol, path);
1666 if (stat(upath, &srcst) < 0) {
1672 return AFPERR_ACCESS;
1674 return AFPERR_PARAM;
1677 memset(&ads, 0, sizeof(ads));
1679 if ((opened = of_findname(vol, curdir, path))) {
1680 /* reuse struct adouble so it won't break locks */
1681 adsp = opened->of_ad;
1683 /* save some stuff */
1685 spath = obj->oldtmp;
1686 supath = obj->newtmp;
1687 strcpy(spath, path);
1688 strcpy(supath, upath); /* this is for the cnid changing */
1689 p = ctoupath( vol, sdir, spath);
1691 /* look for the source cnid. if it doesn't exist, don't worry about
1694 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1695 slen = strlen(supath));
1696 #endif /* CNID_DB */
1698 if (( dir = dirsearch( vol, did )) == NULL ) {
1699 return( AFPERR_PARAM );
1702 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1703 return( AFPERR_PARAM );
1706 if ( *path == '\0' ) {
1707 return( AFPERR_BADTYPE );
1710 /* FPExchangeFiles is the only call that can return the SameObj
1712 if ((curdir == sdir) && strcmp(spath, path) == 0)
1713 return AFPERR_SAMEOBJ;
1715 upath = mtoupath(vol, path);
1716 if (stat(upath, &destst) < 0) {
1722 return AFPERR_ACCESS;
1724 return AFPERR_PARAM;
1727 memset(&add, 0, sizeof(add));
1729 if ((opened = of_findname(vol, curdir, path))) {
1730 /* reuse struct adouble so it won't break locks */
1731 addp = opened->of_ad;
1734 /* look for destination id. */
1735 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1736 dlen = strlen(upath));
1737 #endif /* CNID_DB */
1739 /* construct a temp name.
1740 * NOTE: the temp file will be in the dest file's directory. it
1741 * will also be inaccessible from AFP. */
1742 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1746 /* now, quickly rename the file. we error if we can't. */
1747 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1748 goto err_exchangefile;
1749 of_rename(vol, sdir, spath, curdir, temp);
1751 /* rename destination to source */
1752 if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1753 goto err_src_to_tmp;
1754 of_rename(vol, curdir, path, sdir, spath);
1756 /* rename temp to destination */
1757 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1758 goto err_dest_to_src;
1759 of_rename(vol, curdir, temp, curdir, path);
1762 /* id's need switching. src -> dest and dest -> src. */
1763 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1764 upath, dlen) < 0)) {
1768 err = AFPERR_ACCESS;
1773 goto err_temp_to_dest;
1776 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1777 supath, slen) < 0)) {
1781 err = AFPERR_ACCESS;
1788 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1789 goto err_temp_to_dest;
1791 #endif /* CNID_DB */
1794 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1800 /* all this stuff is so that we can unwind a failed operation
1803 /* rename dest to temp */
1804 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1805 of_rename(vol, curdir, upath, curdir, temp);
1808 /* rename source back to dest */
1809 renamefile(p, upath, path, vol_noadouble(vol), addp);
1810 of_rename(vol, sdir, spath, curdir, path);
1813 /* rename temp back to source */
1814 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1815 of_rename(vol, curdir, temp, sdir, spath);