2 * $Id: file.c,v 1.36 2002-01-17 16:19:06 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 getfilparams(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen )
104 struct stat hst, lst, *lstp;
105 #else /* USE_LASTDID */
107 #endif /* USE_LASTDID */
108 struct adouble ad, *adp;
111 char *data, *nameoff = NULL, *upath;
112 int bit = 0, isad = 1;
115 u_char achar, fdType[4];
118 LOG(log_info, logtype_default, "begin getfilparams:");
121 upath = mtoupath(vol, path);
122 if ((of = of_findname(vol, curdir, path))) {
125 memset(&ad, 0, sizeof(ad));
129 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
131 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
132 LOG(log_error, logtype_default, "getfilparams fstat: %s", strerror(errno) );
136 while ( bitmap != 0 ) {
137 while (( bitmap & 1 ) == 0 ) {
145 ad_getattr(adp, &ashort);
146 } else if (*upath == '.') {
147 ashort = htons(ATTRBIT_INVISIBLE);
150 memcpy(data, &ashort, sizeof( ashort ));
151 data += sizeof( u_short );
155 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
156 data += sizeof( u_int32_t );
160 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
161 aint = AD_DATE_FROM_UNIX(st->st_mtime);
162 memcpy(data, &aint, sizeof( aint ));
163 data += sizeof( aint );
167 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
168 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
169 (hst.st_mtime < st->st_mtime)) {
170 aint = AD_DATE_FROM_UNIX(st->st_mtime);
173 aint = AD_DATE_FROM_UNIX(st->st_mtime);
175 memcpy(data, &aint, sizeof( int ));
176 data += sizeof( int );
180 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
181 aint = AD_DATE_START;
182 memcpy(data, &aint, sizeof( int ));
183 data += sizeof( int );
188 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
190 memcpy(data, ufinderi, 32);
191 if (*upath == '.') { /* make it invisible */
192 ashort = htons(FINDERINFO_INVISIBLE);
193 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
197 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
198 ufinderi, 8 ) == 0)) &&
199 (em = getextmap( path ))) {
200 memcpy(data, em->em_type, sizeof( em->em_type ));
201 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
208 data += sizeof( u_int16_t );
212 memset(data, 0, sizeof(u_int16_t));
213 data += sizeof( u_int16_t );
218 #if AD_VERSION > AD_VERSION1
219 /* look in AD v2 header */
221 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
222 #endif /* AD_VERSION > AD_VERSION1 */
225 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
226 strlen(upath), aint);
227 /* Throw errors if cnid_add fails. */
228 if (aint > CNID_MAX) {
231 LOG(log_error, logtype_default, "getfilparams: Incorrect parameters passed to cnid_add");
232 return(AFPERR_PARAM);
234 return(AFPERR_PARAM);
243 * What a fucking mess. First thing: DID and FNUMs are
244 * in the same space for purposes of enumerate (and several
245 * other wierd places). While we consider this Apple's bug,
246 * this is the work-around: In order to maintain constant and
247 * unique DIDs and FNUMs, we monotonically generate the DIDs
248 * during the session, and derive the FNUMs from the filesystem.
249 * Since the DIDs are small, we insure that the FNUMs are fairly
250 * large by setting thier high bits to the device number.
252 * AFS already does something very similar to this for the
253 * inode number, so we don't repeat the procedure.
256 * due to complaints over did's being non-persistent,
257 * here's the current hack to provide semi-persistent
259 * 1) we reserve the first bit for file ids.
260 * 2) the next 7 bits are for the device.
261 * 3) the remaining 24 bits are for the inode.
263 * both the inode and device information are actually hashes
264 * that are then truncated to the requisite bit length.
266 * it should be okay to use lstat to deal with symlinks.
269 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
270 #else /* USE_LASTDID */
271 lstp = lstat(upath, &lst) < 0 ? st : &lst;
273 aint = htonl( afpd_st_cnid ( lstp ) );
275 aint = htonl(CNID(lstp, 1));
276 #endif /* DID_MTAB */
277 #endif /* USE_LASTDID */
280 memcpy(data, &aint, sizeof( aint ));
281 data += sizeof( aint );
285 aint = htonl( st->st_size );
286 memcpy(data, &aint, sizeof( aint ));
287 data += sizeof( aint );
292 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
296 memcpy(data, &aint, sizeof( aint ));
297 data += sizeof( aint );
300 /* Current client needs ProDOS info block for this file.
301 Use simple heuristic and let the Mac "type" string tell
302 us what the PD file code should be. Everything gets a
303 subtype of 0x0000 unless the original value was hashed
304 to "pXYZ" when we created it. See IA, Ver 2.
306 case FILPBIT_PDINFO :
308 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
310 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
314 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
318 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
322 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
326 else if ( fdType[0] == 'p' ) {
328 ashort = (fdType[2] * 256) + fdType[3];
342 memcpy(data, &ashort, sizeof( ashort ));
343 data += sizeof( ashort );
344 memset(data, 0, sizeof( ashort ));
345 data += sizeof( ashort );
350 ad_close( adp, ADFLAGS_HF );
352 return( AFPERR_BITMAP );
358 ashort = htons( data - buf );
359 memcpy(nameoff, &ashort, sizeof( ashort ));
360 if ((aint = strlen( path )) > MACFILELEN)
363 memcpy(data, path, aint );
367 ad_close( adp, ADFLAGS_HF );
369 *buflen = data - buf;
372 LOG(log_info, logtype_default, "end getfilparams:");
378 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
381 int ibuflen, *rbuflen;
384 struct adouble ad, *adp;
389 int creatf, did, openf, retvalue = AFP_OK;
393 #endif /* FORCE_UIDGID */
396 LOG(log_info, logtype_default, "begin afp_createfile:");
401 creatf = (unsigned char) *ibuf++;
403 memcpy(&vid, ibuf, sizeof( vid ));
404 ibuf += sizeof( vid );
406 if (( vol = getvolbyvid( vid )) == NULL ) {
407 return( AFPERR_PARAM );
410 if (vol->v_flags & AFPVOL_RO)
413 memcpy(&did, ibuf, sizeof( did));
414 ibuf += sizeof( did );
416 if (( dir = dirsearch( vol, did )) == NULL ) {
417 return( AFPERR_NOOBJ );
420 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
421 return( AFPERR_NOOBJ );
424 if (!wincheck(vol, path))
427 upath = mtoupath(vol, path);
429 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
432 if (!validupath(vol, upath))
435 /* check for vetoed filenames */
436 if (veto_file(vol->v_veto, upath))
439 if ((of = of_findname(vol, curdir, path))) {
442 memset(&ad, 0, sizeof(ad));
446 /* on a hard create, fail if file exists and is open */
447 if ((stat(upath, &st) == 0) && of)
449 openf = O_RDWR|O_CREAT|O_TRUNC;
451 openf = O_RDWR|O_CREAT|O_EXCL;
456 /* preserve current euid, egid */
457 save_uidgid ( uidgid );
459 /* perform all switching of users */
462 #endif /* FORCE_UIDGID */
464 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
465 openf, 0666, adp) < 0 ) {
469 /* bring everything back to old euid, egid */
470 restore_uidgid ( uidgid );
471 #endif /* FORCE_UIDGID */
472 return( AFPERR_EXIST );
475 /* bring everything back to old euid, egid */
476 restore_uidgid ( uidgid );
477 #endif /* FORCE_UIDGID */
478 return( AFPERR_ACCESS );
480 /* on noadouble volumes, just creating the data fork is ok */
481 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
482 goto createfile_done;
486 /* bring everything back to old euid, egid */
487 restore_uidgid ( uidgid );
488 #endif /* FORCE_UIDGID */
489 return( AFPERR_PARAM );
493 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
494 memcpy(ad_entry( adp, ADEID_NAME ), path,
495 ad_getentrylen( adp, ADEID_NAME ));
496 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
497 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
502 if (vol->v_flags & AFPVOL_DROPBOX) {
503 retvalue = matchfile2dirperms(upath, vol, did);
505 #endif /* DROPKLUDGE */
507 setvoltime(obj, vol );
510 LOG(log_info, logtype_default, "end afp_createfile");
514 /* bring everything back to old euid, egid */
515 restore_uidgid ( uidgid );
516 #endif /* FORCE_UIDGID */
521 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
524 int ibuflen, *rbuflen;
530 u_int16_t vid, bitmap;
533 LOG(log_info, logtype_default, "begin afp_setfilparams:");
539 memcpy(&vid, ibuf, sizeof( vid ));
540 ibuf += sizeof( vid );
541 if (( vol = getvolbyvid( vid )) == NULL ) {
542 return( AFPERR_PARAM );
545 if (vol->v_flags & AFPVOL_RO)
548 memcpy(&did, ibuf, sizeof( did ));
549 ibuf += sizeof( did );
550 if (( dir = dirsearch( vol, did )) == NULL ) {
551 return( AFPERR_NOOBJ );
554 memcpy(&bitmap, ibuf, sizeof( bitmap ));
555 bitmap = ntohs( bitmap );
556 ibuf += sizeof( bitmap );
558 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
559 return( AFPERR_NOOBJ );
562 if ((u_long)ibuf & 1 ) {
566 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
567 setvoltime(obj, vol );
571 LOG(log_info, logtype_default, "end afp_setfilparams:");
578 int setfilparams(struct vol *vol,
579 char *path, u_int16_t bitmap, char *buf )
581 struct adouble ad, *adp;
584 int bit = 0, isad = 1, err = AFP_OK;
586 u_char achar, *fdType, xyy[4];
587 u_int16_t ashort, bshort;
594 uidgid = malloc(sizeof(uidgidset));
595 #endif /* FORCE_UIDGID */
598 LOG(log_info, logtype_default, "begin setfilparams:");
601 upath = mtoupath(vol, path);
602 if ((of = of_findname(vol, curdir, path))) {
605 memset(&ad, 0, sizeof(ad));
610 save_uidgid ( uidgid );
612 #endif /* FORCE_UIDGID */
614 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
615 O_RDWR|O_CREAT, 0666, adp) < 0) {
616 /* for some things, we don't need an adouble header */
617 if (bitmap & ~(1<<FILPBIT_MDATE)) {
619 restore_uidgid ( uidgid );
620 #endif /* FORCE_UIDGID */
621 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
624 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
625 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
626 memcpy(ad_entry( adp, ADEID_NAME ), path,
627 ad_getentrylen( adp, ADEID_NAME ));
630 while ( bitmap != 0 ) {
631 while (( bitmap & 1 ) == 0 ) {
638 memcpy(&ashort, buf, sizeof( ashort ));
639 ad_getattr(adp, &bshort);
640 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
641 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
645 ad_setattr(adp, bshort);
646 buf += sizeof( ashort );
650 memcpy(&aint, buf, sizeof(aint));
651 ad_setdate(adp, AD_DATE_CREATE, aint);
652 buf += sizeof( aint );
656 memcpy(&aint, buf, sizeof( aint ));
658 ad_setdate(adp, AD_DATE_MODIFY, aint);
659 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
661 buf += sizeof( aint );
665 memcpy(&aint, buf, sizeof(aint));
666 ad_setdate(adp, AD_DATE_BACKUP, aint);
667 buf += sizeof( aint );
671 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
672 && (em = getextmap( path )) &&
673 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
674 (memcmp(buf + 4, em->em_creator,
675 sizeof( em->em_creator )) == 0)) {
676 memcpy(buf, ufinderi, 8 );
678 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
682 /* Client needs to set the ProDOS file info for this file.
683 Use defined strings for the simple cases, and convert
684 all else into pXYY per Inside Appletalk. Always set
685 the creator as "pdos". <shirsch@ibm.net> */
686 case FILPBIT_PDINFO :
689 memcpy(&ashort, buf, sizeof( ashort ));
690 ashort = ntohs( ashort );
693 switch ( (unsigned int) achar )
696 fdType = ( u_char *) "TEXT";
700 fdType = ( u_char *) "PSYS";
704 fdType = ( u_char *) "PS16";
708 fdType = ( u_char *) "BINA";
712 xyy[0] = ( u_char ) 'p';
714 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
715 xyy[3] = ( u_char ) ashort & 0xff;
720 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
721 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
727 goto setfilparam_done;
736 ad_flush( adp, ADFLAGS_HF );
737 ad_close( adp, ADFLAGS_HF );
740 restore_uidgid ( uidgid );
741 #endif /* FORCE_UIDGID */
746 LOG(log_info, logtype_default, "end setfilparams:");
753 * renamefile and copyfile take the old and new unix pathnames
754 * and the new mac name.
755 * NOTE: if we have to copy a file instead of renaming it, locks
758 int renamefile(src, dst, newname, noadouble )
759 char *src, *dst, *newname;
763 char adsrc[ MAXPATHLEN + 1];
767 * Note that this is only checking the existance of the data file,
768 * not the header file. The thinking is that if the data file doesn't
769 * exist, but the header file does, the right thing to do is remove
770 * the data file silently.
773 /* existence check moved to afp_moveandrename */
776 LOG(log_info, logtype_default, "begin renamefile:");
779 if ( rename( src, dst ) < 0 ) {
782 return( AFPERR_NOOBJ );
785 return( AFPERR_ACCESS );
788 case EXDEV : /* Cross device move -- try copy */
789 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
793 return deletefile( src );
795 return( AFPERR_PARAM );
799 strcpy( adsrc, ad_path( src, 0 ));
802 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
807 /* check for a source appledouble header. if it exists, make
808 * a dest appledouble directory and do the rename again. */
809 memset(&ad, 0, sizeof(ad));
810 if (rc || stat(adsrc, &st) ||
811 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
814 ad_close(&ad, ADFLAGS_HF);
818 return( AFPERR_ACCESS );
822 return( AFPERR_PARAM );
826 memset(&ad, 0, sizeof(ad));
827 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
830 return( AFPERR_NOOBJ );
832 return( AFPERR_ACCESS );
836 return( AFPERR_PARAM );
840 len = strlen( newname );
841 ad_setentrylen( &ad, ADEID_NAME, len );
842 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
843 ad_flush( &ad, ADFLAGS_HF );
844 ad_close( &ad, ADFLAGS_HF );
847 LOG(log_info, logtype_default, "end renamefile:");
853 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
856 int ibuflen, *rbuflen;
860 char *newname, *path, *p;
861 u_int32_t sdid, ddid;
862 int plen, err, retvalue = AFP_OK;
863 u_int16_t svid, dvid;
866 LOG(log_info, logtype_default, "begin afp_copyfile:");
872 memcpy(&svid, ibuf, sizeof( svid ));
873 ibuf += sizeof( svid );
874 if (( vol = getvolbyvid( svid )) == NULL ) {
875 return( AFPERR_PARAM );
878 memcpy(&sdid, ibuf, sizeof( sdid ));
879 ibuf += sizeof( sdid );
880 if (( dir = dirsearch( vol, sdid )) == NULL ) {
881 return( AFPERR_PARAM );
884 memcpy(&dvid, ibuf, sizeof( dvid ));
885 ibuf += sizeof( dvid );
886 memcpy(&ddid, ibuf, sizeof( ddid ));
887 ibuf += sizeof( ddid );
889 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
890 return( AFPERR_NOOBJ );
892 if ( *path == '\0' ) {
893 return( AFPERR_BADTYPE );
896 /* don't allow copies when the file is open.
897 * XXX: the spec only calls for read/deny write access.
898 * however, copyfile doesn't have any of that info,
899 * and locks need to stay coherent. as a result,
900 * we just balk if the file is opened already. */
901 if (of_findname(vol, curdir, path))
902 return AFPERR_DENYCONF;
904 newname = obj->newtmp;
905 strcpy( newname, path );
907 p = ctoupath( vol, curdir, newname );
909 if (( vol = getvolbyvid( dvid )) == NULL ) {
910 return( AFPERR_PARAM );
913 if (vol->v_flags & AFPVOL_RO)
916 if (( dir = dirsearch( vol, ddid )) == NULL ) {
917 return( AFPERR_PARAM );
920 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
921 return( AFPERR_NOOBJ );
923 if ( *path != '\0' ) {
924 return( AFPERR_BADTYPE );
927 /* one of the handful of places that knows about the path type */
928 if ( *ibuf++ != 2 ) {
929 return( AFPERR_PARAM );
931 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
932 strncpy( newname, ibuf, plen );
933 newname[ plen ] = '\0';
936 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
937 vol_noadouble(vol))) < 0 ) {
941 setvoltime(obj, vol );
944 if (vol->v_flags & AFPVOL_DROPBOX) {
945 retvalue=matchfile2dirperms(newname, vol, sdid);
947 #endif /* DROPKLUDGE */
950 LOG(log_info, logtype_default, "end afp_copyfile:");
957 static __inline__ int copy_all(const int dfd, const void *buf,
963 LOG(log_info, logtype_default, "begin copy_all:");
967 if ((cc = write(dfd, buf, buflen)) < 0) {
985 LOG(log_info, logtype_default, "end copy_all:");
991 /* XXX: this needs to use ad_open and ad_lock. so, we need to
992 * pass in vol and path */
993 int copyfile(src, dst, newname, noadouble )
994 char *src, *dst, *newname;
1000 int sfd, dfd, len, err = AFP_OK;
1004 LOG(log_info, logtype_default, "begin copyfile:");
1008 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1011 break; /* just copy the data fork */
1013 return( AFPERR_ACCESS );
1015 return( AFPERR_PARAM );
1018 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1019 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1023 return( AFPERR_NOOBJ );
1025 return( AFPERR_ACCESS );
1027 return AFPERR_VLOCK;
1029 return( AFPERR_PARAM );
1034 #ifdef SENDFILE_FLAVOR_LINUX
1035 if (fstat(sfd, &st) == 0) {
1036 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1050 goto copyheader_done;
1052 #endif /* SENDFILE_FLAVOR_LINUX */
1054 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1061 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1069 unlink(ad_path(dst, ADFLAGS_HF));
1075 /* data fork copying */
1076 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1079 return( AFPERR_NOOBJ );
1081 return( AFPERR_ACCESS );
1083 return( AFPERR_PARAM );
1087 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1091 return( AFPERR_NOOBJ );
1093 return( AFPERR_ACCESS );
1095 return AFPERR_VLOCK;
1097 return( AFPERR_PARAM );
1101 #ifdef SENDFILE_FLAVOR_LINUX
1102 if (fstat(sfd, &st) == 0) {
1103 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1116 #endif /* SENDFILE_FLAVOR_LINUX */
1119 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1127 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1136 unlink(ad_path(dst, ADFLAGS_HF));
1142 memset(&ad, 0, sizeof(ad));
1143 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1147 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1149 return( AFPERR_ACCESS );
1151 return AFPERR_VLOCK;
1153 return( AFPERR_PARAM );
1157 len = strlen( newname );
1158 ad_setentrylen( &ad, ADEID_NAME, len );
1159 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1160 ad_flush( &ad, ADFLAGS_HF );
1161 ad_close( &ad, ADFLAGS_HF );
1165 LOG(log_info, logtype_default, "end copyfile:");
1172 int deletefile( file )
1176 int adflags, err = AFP_OK;
1177 int locktype = ADLOCK_WR;
1178 int openmode = O_RDWR;
1181 LOG(log_info, logtype_default, "begin deletefile:");
1186 * If can't open read/write then try again read-only. If it's open
1187 * read-only, we must do a read lock instead of a write lock.
1189 /* try to open both at once */
1190 adflags = ADFLAGS_DF|ADFLAGS_HF;
1191 memset(&ad, 0, sizeof(ad));
1192 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1195 adflags = ADFLAGS_DF;
1196 /* that failed. now try to open just the data fork */
1197 memset(&ad, 0, sizeof(ad));
1198 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1201 return AFPERR_NOOBJ;
1203 if(openmode == O_RDWR) {
1204 openmode = O_RDONLY;
1205 locktype = ADLOCK_RD;
1208 return AFPERR_ACCESS;
1211 return AFPERR_VLOCK;
1213 return AFPERR_PARAM;
1219 if(openmode == O_RDWR) {
1220 openmode = O_RDONLY;
1221 locktype = ADLOCK_RD;
1224 return AFPERR_ACCESS;
1227 return AFPERR_VLOCK;
1229 return( AFPERR_PARAM );
1232 break; /* from the while */
1235 if ((adflags & ADFLAGS_HF) &&
1236 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1237 ad_close( &ad, adflags );
1238 return( AFPERR_BUSY );
1241 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1246 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1250 err = AFPERR_ACCESS;
1263 if ( unlink( file ) < 0 ) {
1267 err = AFPERR_ACCESS;
1281 if (adflags & ADFLAGS_HF)
1282 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1283 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1284 ad_close( &ad, adflags );
1287 LOG(log_info, logtype_default, "end deletefile:");
1295 /* return a file id */
1296 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1299 int ibuflen, *rbuflen;
1311 LOG(log_info, logtype_default, "begin afp_createid:");
1317 memcpy(&vid, ibuf, sizeof(vid));
1318 ibuf += sizeof(vid);
1320 if (( vol = getvolbyvid( vid )) == NULL ) {
1321 return( AFPERR_PARAM);
1324 if (vol->v_flags & AFPVOL_RO)
1325 return AFPERR_VLOCK;
1327 memcpy(&did, ibuf, sizeof( did ));
1328 ibuf += sizeof(did);
1330 if (( dir = dirsearch( vol, did )) == NULL ) {
1331 return( AFPERR_PARAM );
1334 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1335 return( AFPERR_PARAM );
1338 if ( *path == '\0' ) {
1339 return( AFPERR_BADTYPE );
1342 upath = mtoupath(vol, path);
1343 if (stat(upath, &st) < 0) {
1347 return AFPERR_ACCESS;
1349 return AFPERR_NOOBJ;
1351 return AFPERR_PARAM;
1355 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1356 memcpy(rbuf, &id, sizeof(id));
1357 *rbuflen = sizeof(id);
1358 return AFPERR_EXISTID;
1361 #if AD_VERSION > AD_VERSION1
1362 memset(&ad, 0, sizeof(ad));
1363 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1364 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1365 ad_close(&ad, ADFLAGS_HF);
1367 #endif /* AD_VERSION > AD_VERSION1 */
1369 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1370 memcpy(rbuf, &id, sizeof(id));
1371 *rbuflen = sizeof(id);
1376 LOG(log_info, logtype_default, "ending afp_createid...:");
1381 return AFPERR_VLOCK;
1385 return AFPERR_ACCESS;
1388 LOG(log_error, logtype_default, "afp_createid: cnid_add: %s", strerror(errno));
1389 return AFPERR_PARAM;
1393 /* resolve a file id */
1394 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1397 int ibuflen, *rbuflen;
1405 u_int16_t vid, bitmap;
1408 LOG(log_info, logtype_default, "begin afp_resolveid:");
1414 memcpy(&vid, ibuf, sizeof(vid));
1415 ibuf += sizeof(vid);
1417 if (( vol = getvolbyvid( vid )) == NULL ) {
1418 return( AFPERR_PARAM);
1421 memcpy(&id, ibuf, sizeof( id ));
1424 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1425 return AFPERR_BADID;
1428 if (( dir = dirsearch( vol, id )) == NULL ) {
1429 return( AFPERR_PARAM );
1432 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1436 return AFPERR_ACCESS;
1440 return AFPERR_PARAM;
1444 /* directories are bad */
1445 if (S_ISDIR(st.st_mode))
1446 return AFPERR_BADTYPE;
1448 memcpy(&bitmap, ibuf, sizeof(bitmap));
1449 bitmap = ntohs( bitmap );
1451 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1452 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1455 *rbuflen = buflen + sizeof(bitmap);
1456 memcpy(rbuf, ibuf, sizeof(bitmap));
1459 LOG(log_info, logtype_default, "end afp_resolveid:");
1465 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1468 int ibuflen, *rbuflen;
1479 LOG(log_info, logtype_default, "begin afp_deleteid:");
1485 memcpy(&vid, ibuf, sizeof(vid));
1486 ibuf += sizeof(vid);
1488 if (( vol = getvolbyvid( vid )) == NULL ) {
1489 return( AFPERR_PARAM);
1492 if (vol->v_flags & AFPVOL_RO)
1493 return AFPERR_VLOCK;
1495 memcpy(&id, ibuf, sizeof( id ));
1498 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1502 if (( dir = dirsearch( vol, id )) == NULL ) {
1503 return( AFPERR_PARAM );
1507 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1511 return AFPERR_ACCESS;
1513 /* still try to delete the id */
1517 return AFPERR_PARAM;
1521 /* directories are bad */
1522 if (S_ISDIR(st.st_mode))
1523 return AFPERR_BADTYPE;
1525 if (cnid_delete(vol->v_db, id)) {
1528 return AFPERR_VLOCK;
1531 return AFPERR_ACCESS;
1533 return AFPERR_PARAM;
1538 LOG(log_info, logtype_default, "end afp_deleteid:");
1543 #endif /* CNID_DB */
1545 #define APPLETEMP ".AppleTempXXXXXX"
1547 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1550 int ibuflen, *rbuflen;
1552 struct stat srcst, destst;
1554 struct dir *dir, *sdir;
1555 char *spath, temp[17], *path, *p;
1556 char *supath, *upath;
1560 #endif /* CNID_DB */
1565 LOG(log_info, logtype_default, "begin afp_exchangefiles:");
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 /* source and destination dids */
1582 memcpy(&sid, ibuf, sizeof(sid));
1583 ibuf += sizeof(sid);
1584 memcpy(&did, ibuf, sizeof(did));
1585 ibuf += sizeof(did);
1588 if ((dir = dirsearch( vol, sid )) == NULL ) {
1589 return( AFPERR_PARAM );
1592 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1593 return( AFPERR_PARAM );
1596 if ( *path == '\0' ) {
1597 return( AFPERR_BADTYPE );
1600 upath = mtoupath(vol, path);
1601 if (stat(upath, &srcst) < 0) {
1607 return AFPERR_ACCESS;
1609 return AFPERR_PARAM;
1613 /* save some stuff */
1615 spath = obj->oldtmp;
1616 supath = obj->newtmp;
1617 strcpy(spath, path);
1618 strcpy(supath, upath); /* this is for the cnid changing */
1619 p = ctoupath( vol, sdir, spath);
1621 /* look for the source cnid. if it doesn't exist, don't worry about
1624 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1625 slen = strlen(supath));
1626 #endif /* CNID_DB */
1628 if (( dir = dirsearch( vol, did )) == NULL ) {
1629 return( AFPERR_PARAM );
1632 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1633 return( AFPERR_PARAM );
1636 if ( *path == '\0' ) {
1637 return( AFPERR_BADTYPE );
1640 /* FPExchangeFiles is the only call that can return the SameObj
1642 if ((curdir == sdir) && strcmp(spath, path) == 0)
1643 return AFPERR_SAMEOBJ;
1645 upath = mtoupath(vol, path);
1646 if (stat(upath, &destst) < 0) {
1652 return AFPERR_ACCESS;
1654 return AFPERR_PARAM;
1659 /* look for destination id. */
1660 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1661 dlen = strlen(upath));
1662 #endif /* CNID_DB */
1664 /* construct a temp name.
1665 * NOTE: the temp file will be in the dest file's directory. it
1666 * will also be inaccessible from AFP. */
1667 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1671 /* now, quickly rename the file. we error if we can't. */
1672 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1673 goto err_exchangefile;
1674 of_rename(vol, sdir, spath, curdir, temp);
1676 /* rename destination to source */
1677 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1678 goto err_src_to_tmp;
1679 of_rename(vol, curdir, path, sdir, spath);
1681 /* rename temp to destination */
1682 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1683 goto err_dest_to_src;
1684 of_rename(vol, curdir, temp, curdir, path);
1687 /* id's need switching. src -> dest and dest -> src. */
1688 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1689 upath, dlen) < 0)) {
1693 err = AFPERR_ACCESS;
1698 goto err_temp_to_dest;
1701 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1702 supath, slen) < 0)) {
1706 err = AFPERR_ACCESS;
1713 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1714 goto err_temp_to_dest;
1716 #endif /* CNID_DB */
1719 LOG(log_info, logtype_default, "ending afp_exchangefiles:");
1725 /* all this stuff is so that we can unwind a failed operation
1728 /* rename dest to temp */
1729 renamefile(upath, temp, temp, vol_noadouble(vol));
1730 of_rename(vol, curdir, upath, curdir, temp);
1733 /* rename source back to dest */
1734 renamefile(p, upath, path, vol_noadouble(vol));
1735 of_rename(vol, sdir, spath, curdir, path);
1738 /* rename temp back to source */
1739 renamefile(temp, p, spath, vol_noadouble(vol));
1740 of_rename(vol, curdir, temp, sdir, spath);