2 * $Id: file.c,v 1.40 2002-03-05 02:04:46 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_INVALID) {
231 LOG(log_error, logtype_default, "getfilparams: Incorrect parameters passed to cnid_add");
232 return(AFPERR_PARAM);
234 return(AFPERR_PARAM);
244 * What a fucking mess. First thing: DID and FNUMs are
245 * in the same space for purposes of enumerate (and several
246 * other wierd places). While we consider this Apple's bug,
247 * this is the work-around: In order to maintain constant and
248 * unique DIDs and FNUMs, we monotonically generate the DIDs
249 * during the session, and derive the FNUMs from the filesystem.
250 * Since the DIDs are small, we insure that the FNUMs are fairly
251 * large by setting thier high bits to the device number.
253 * AFS already does something very similar to this for the
254 * inode number, so we don't repeat the procedure.
257 * due to complaints over did's being non-persistent,
258 * here's the current hack to provide semi-persistent
260 * 1) we reserve the first bit for file ids.
261 * 2) the next 7 bits are for the device.
262 * 3) the remaining 24 bits are for the inode.
264 * both the inode and device information are actually hashes
265 * that are then truncated to the requisite bit length.
267 * it should be okay to use lstat to deal with symlinks.
270 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
271 #else /* USE_LASTDID */
272 lstp = lstat(upath, &lst) < 0 ? st : &lst;
274 aint = htonl( afpd_st_cnid ( lstp ) );
276 aint = htonl(CNID(lstp, 1));
277 #endif /* DID_MTAB */
278 #endif /* USE_LASTDID */
281 memcpy(data, &aint, sizeof( aint ));
282 data += sizeof( aint );
286 aint = htonl( st->st_size );
287 memcpy(data, &aint, sizeof( aint ));
288 data += sizeof( aint );
293 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
297 memcpy(data, &aint, sizeof( aint ));
298 data += sizeof( aint );
301 /* Current client needs ProDOS info block for this file.
302 Use simple heuristic and let the Mac "type" string tell
303 us what the PD file code should be. Everything gets a
304 subtype of 0x0000 unless the original value was hashed
305 to "pXYZ" when we created it. See IA, Ver 2.
307 case FILPBIT_PDINFO :
309 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
311 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
315 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
319 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
323 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
327 else if ( fdType[0] == 'p' ) {
329 ashort = (fdType[2] * 256) + fdType[3];
343 memcpy(data, &ashort, sizeof( ashort ));
344 data += sizeof( ashort );
345 memset(data, 0, sizeof( ashort ));
346 data += sizeof( ashort );
351 ad_close( adp, ADFLAGS_HF );
353 return( AFPERR_BITMAP );
359 ashort = htons( data - buf );
360 memcpy(nameoff, &ashort, sizeof( ashort ));
361 if ((aint = strlen( path )) > MACFILELEN)
364 memcpy(data, path, aint );
368 ad_close( adp, ADFLAGS_HF );
370 *buflen = data - buf;
373 LOG(log_info, logtype_default, "end getfilparams:");
379 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
382 int ibuflen, *rbuflen;
385 struct adouble ad, *adp;
390 int creatf, did, openf, retvalue = AFP_OK;
394 #endif /* FORCE_UIDGID */
397 LOG(log_info, logtype_default, "begin afp_createfile:");
402 creatf = (unsigned char) *ibuf++;
404 memcpy(&vid, ibuf, sizeof( vid ));
405 ibuf += sizeof( vid );
407 if (( vol = getvolbyvid( vid )) == NULL ) {
408 return( AFPERR_PARAM );
411 if (vol->v_flags & AFPVOL_RO)
414 memcpy(&did, ibuf, sizeof( did));
415 ibuf += sizeof( did );
417 if (( dir = dirsearch( vol, did )) == NULL ) {
418 return( AFPERR_NOOBJ );
421 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
422 return( AFPERR_NOOBJ );
425 if (!wincheck(vol, path))
428 upath = mtoupath(vol, path);
430 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
433 if (!validupath(vol, upath))
436 /* check for vetoed filenames */
437 if (veto_file(vol->v_veto, upath))
440 if ((of = of_findname(vol, curdir, path))) {
443 memset(&ad, 0, sizeof(ad));
447 /* on a hard create, fail if file exists and is open */
448 if ((stat(upath, &st) == 0) && of)
450 openf = O_RDWR|O_CREAT|O_TRUNC;
452 openf = O_RDWR|O_CREAT|O_EXCL;
457 /* preserve current euid, egid */
458 save_uidgid ( uidgid );
460 /* perform all switching of users */
463 #endif /* FORCE_UIDGID */
465 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
466 openf, 0666, adp) < 0 ) {
470 /* bring everything back to old euid, egid */
471 restore_uidgid ( uidgid );
472 #endif /* FORCE_UIDGID */
473 return( AFPERR_EXIST );
476 /* bring everything back to old euid, egid */
477 restore_uidgid ( uidgid );
478 #endif /* FORCE_UIDGID */
479 return( AFPERR_ACCESS );
481 /* on noadouble volumes, just creating the data fork is ok */
482 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
483 goto createfile_done;
487 /* bring everything back to old euid, egid */
488 restore_uidgid ( uidgid );
489 #endif /* FORCE_UIDGID */
490 return( AFPERR_PARAM );
494 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
495 memcpy(ad_entry( adp, ADEID_NAME ), path,
496 ad_getentrylen( adp, ADEID_NAME ));
497 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
498 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
503 if (vol->v_flags & AFPVOL_DROPBOX) {
504 retvalue = matchfile2dirperms(upath, vol, did);
506 #endif /* DROPKLUDGE */
508 setvoltime(obj, vol );
511 LOG(log_info, logtype_default, "end afp_createfile");
515 /* bring everything back to old euid, egid */
516 restore_uidgid ( uidgid );
517 #endif /* FORCE_UIDGID */
522 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
525 int ibuflen, *rbuflen;
531 u_int16_t vid, bitmap;
534 LOG(log_info, logtype_default, "begin afp_setfilparams:");
540 memcpy(&vid, ibuf, sizeof( vid ));
541 ibuf += sizeof( vid );
542 if (( vol = getvolbyvid( vid )) == NULL ) {
543 return( AFPERR_PARAM );
546 if (vol->v_flags & AFPVOL_RO)
549 memcpy(&did, ibuf, sizeof( did ));
550 ibuf += sizeof( did );
551 if (( dir = dirsearch( vol, did )) == NULL ) {
552 return( AFPERR_NOOBJ );
555 memcpy(&bitmap, ibuf, sizeof( bitmap ));
556 bitmap = ntohs( bitmap );
557 ibuf += sizeof( bitmap );
559 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
560 return( AFPERR_NOOBJ );
563 if ((u_long)ibuf & 1 ) {
567 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
568 setvoltime(obj, vol );
572 LOG(log_info, logtype_default, "end afp_setfilparams:");
579 int setfilparams(struct vol *vol,
580 char *path, u_int16_t bitmap, char *buf )
582 struct adouble ad, *adp;
585 int bit = 0, isad = 1, err = AFP_OK;
587 u_char achar, *fdType, xyy[4];
588 u_int16_t ashort, bshort;
595 uidgid = malloc(sizeof(uidgidset));
596 #endif /* FORCE_UIDGID */
599 LOG(log_info, logtype_default, "begin setfilparams:");
602 upath = mtoupath(vol, path);
603 if ((of = of_findname(vol, curdir, path))) {
606 memset(&ad, 0, sizeof(ad));
611 save_uidgid ( uidgid );
613 #endif /* FORCE_UIDGID */
615 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
616 O_RDWR|O_CREAT, 0666, adp) < 0) {
617 /* for some things, we don't need an adouble header */
618 if (bitmap & ~(1<<FILPBIT_MDATE)) {
620 restore_uidgid ( uidgid );
621 #endif /* FORCE_UIDGID */
622 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
625 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
626 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
627 memcpy(ad_entry( adp, ADEID_NAME ), path,
628 ad_getentrylen( adp, ADEID_NAME ));
631 while ( bitmap != 0 ) {
632 while (( bitmap & 1 ) == 0 ) {
639 memcpy(&ashort, buf, sizeof( ashort ));
640 ad_getattr(adp, &bshort);
641 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
642 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
646 ad_setattr(adp, bshort);
647 buf += sizeof( ashort );
651 memcpy(&aint, buf, sizeof(aint));
652 ad_setdate(adp, AD_DATE_CREATE, aint);
653 buf += sizeof( aint );
657 memcpy(&aint, buf, sizeof( aint ));
659 ad_setdate(adp, AD_DATE_MODIFY, aint);
660 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
662 buf += sizeof( aint );
666 memcpy(&aint, buf, sizeof(aint));
667 ad_setdate(adp, AD_DATE_BACKUP, aint);
668 buf += sizeof( aint );
672 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
673 && (em = getextmap( path )) &&
674 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
675 (memcmp(buf + 4, em->em_creator,
676 sizeof( em->em_creator )) == 0)) {
677 memcpy(buf, ufinderi, 8 );
679 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
683 /* Client needs to set the ProDOS file info for this file.
684 Use defined strings for the simple cases, and convert
685 all else into pXYY per Inside Appletalk. Always set
686 the creator as "pdos". <shirsch@ibm.net> */
687 case FILPBIT_PDINFO :
690 memcpy(&ashort, buf, sizeof( ashort ));
691 ashort = ntohs( ashort );
694 switch ( (unsigned int) achar )
697 fdType = ( u_char *) "TEXT";
701 fdType = ( u_char *) "PSYS";
705 fdType = ( u_char *) "PS16";
709 fdType = ( u_char *) "BINA";
713 xyy[0] = ( u_char ) 'p';
715 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
716 xyy[3] = ( u_char ) ashort & 0xff;
721 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
722 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
728 goto setfilparam_done;
737 ad_flush( adp, ADFLAGS_HF );
738 ad_close( adp, ADFLAGS_HF );
741 restore_uidgid ( uidgid );
742 #endif /* FORCE_UIDGID */
747 LOG(log_info, logtype_default, "end setfilparams:");
754 * renamefile and copyfile take the old and new unix pathnames
755 * and the new mac name.
756 * NOTE: if we have to copy a file instead of renaming it, locks
759 int renamefile(src, dst, newname, noadouble )
760 char *src, *dst, *newname;
764 char adsrc[ MAXPATHLEN + 1];
768 * Note that this is only checking the existance of the data file,
769 * not the header file. The thinking is that if the data file doesn't
770 * exist, but the header file does, the right thing to do is remove
771 * the data file silently.
774 /* existence check moved to afp_moveandrename */
777 LOG(log_info, logtype_default, "begin renamefile:");
780 if ( rename( src, dst ) < 0 ) {
783 return( AFPERR_NOOBJ );
786 return( AFPERR_ACCESS );
789 case EXDEV : /* Cross device move -- try copy */
790 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
794 return deletefile( src );
796 return( AFPERR_PARAM );
800 strcpy( adsrc, ad_path( src, 0 ));
803 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
808 /* check for a source appledouble header. if it exists, make
809 * a dest appledouble directory and do the rename again. */
810 memset(&ad, 0, sizeof(ad));
811 if (rc || stat(adsrc, &st) ||
812 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
815 ad_close(&ad, ADFLAGS_HF);
819 return( AFPERR_ACCESS );
823 return( AFPERR_PARAM );
827 memset(&ad, 0, sizeof(ad));
828 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
831 return( AFPERR_NOOBJ );
833 return( AFPERR_ACCESS );
837 return( AFPERR_PARAM );
841 len = strlen( newname );
842 ad_setentrylen( &ad, ADEID_NAME, len );
843 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
844 ad_flush( &ad, ADFLAGS_HF );
845 ad_close( &ad, ADFLAGS_HF );
848 LOG(log_info, logtype_default, "end renamefile:");
854 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
857 int ibuflen, *rbuflen;
861 char *newname, *path, *p;
862 u_int32_t sdid, ddid;
863 int plen, err, retvalue = AFP_OK;
864 u_int16_t svid, dvid;
867 LOG(log_info, logtype_default, "begin afp_copyfile:");
873 memcpy(&svid, ibuf, sizeof( svid ));
874 ibuf += sizeof( svid );
875 if (( vol = getvolbyvid( svid )) == NULL ) {
876 return( AFPERR_PARAM );
879 memcpy(&sdid, ibuf, sizeof( sdid ));
880 ibuf += sizeof( sdid );
881 if (( dir = dirsearch( vol, sdid )) == NULL ) {
882 return( AFPERR_PARAM );
885 memcpy(&dvid, ibuf, sizeof( dvid ));
886 ibuf += sizeof( dvid );
887 memcpy(&ddid, ibuf, sizeof( ddid ));
888 ibuf += sizeof( ddid );
890 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
891 return( AFPERR_NOOBJ );
893 if ( *path == '\0' ) {
894 return( AFPERR_BADTYPE );
897 /* don't allow copies when the file is open.
898 * XXX: the spec only calls for read/deny write access.
899 * however, copyfile doesn't have any of that info,
900 * and locks need to stay coherent. as a result,
901 * we just balk if the file is opened already. */
902 if (of_findname(vol, curdir, path))
903 return AFPERR_DENYCONF;
905 newname = obj->newtmp;
906 strcpy( newname, path );
908 p = ctoupath( vol, curdir, newname );
910 if (( vol = getvolbyvid( dvid )) == NULL ) {
911 return( AFPERR_PARAM );
914 if (vol->v_flags & AFPVOL_RO)
917 if (( dir = dirsearch( vol, ddid )) == NULL ) {
918 return( AFPERR_PARAM );
921 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
922 return( AFPERR_NOOBJ );
924 if ( *path != '\0' ) {
925 return( AFPERR_BADTYPE );
928 /* one of the handful of places that knows about the path type */
929 if ( *ibuf++ != 2 ) {
930 return( AFPERR_PARAM );
932 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
933 strncpy( newname, ibuf, plen );
934 newname[ plen ] = '\0';
937 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
938 vol_noadouble(vol))) < 0 ) {
942 setvoltime(obj, vol );
945 if (vol->v_flags & AFPVOL_DROPBOX) {
946 retvalue=matchfile2dirperms(newname, vol, sdid);
948 #endif /* DROPKLUDGE */
951 LOG(log_info, logtype_default, "end afp_copyfile:");
958 static __inline__ int copy_all(const int dfd, const void *buf,
964 LOG(log_info, logtype_default, "begin copy_all:");
968 if ((cc = write(dfd, buf, buflen)) < 0) {
986 LOG(log_info, logtype_default, "end copy_all:");
992 /* XXX: this needs to use ad_open and ad_lock. so, we need to
993 * pass in vol and path */
994 int copyfile(src, dst, newname, noadouble )
995 char *src, *dst, *newname;
1001 int sfd, dfd, len, err = AFP_OK;
1005 LOG(log_info, logtype_default, "begin copyfile:");
1009 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1012 break; /* just copy the data fork */
1014 return( AFPERR_ACCESS );
1016 return( AFPERR_PARAM );
1019 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1020 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1024 return( AFPERR_NOOBJ );
1026 return( AFPERR_ACCESS );
1028 return AFPERR_VLOCK;
1030 return( AFPERR_PARAM );
1035 #ifdef SENDFILE_FLAVOR_LINUX
1036 if (fstat(sfd, &st) == 0) {
1037 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1051 goto copyheader_done;
1053 #endif /* SENDFILE_FLAVOR_LINUX */
1055 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1062 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1070 unlink(ad_path(dst, ADFLAGS_HF));
1076 /* data fork copying */
1077 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1080 return( AFPERR_NOOBJ );
1082 return( AFPERR_ACCESS );
1084 return( AFPERR_PARAM );
1088 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1092 return( AFPERR_NOOBJ );
1094 return( AFPERR_ACCESS );
1096 return AFPERR_VLOCK;
1098 return( AFPERR_PARAM );
1102 #ifdef SENDFILE_FLAVOR_LINUX
1103 if (fstat(sfd, &st) == 0) {
1104 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1117 #endif /* SENDFILE_FLAVOR_LINUX */
1120 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1128 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1137 unlink(ad_path(dst, ADFLAGS_HF));
1143 memset(&ad, 0, sizeof(ad));
1144 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1148 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1150 return( AFPERR_ACCESS );
1152 return AFPERR_VLOCK;
1154 return( AFPERR_PARAM );
1158 len = strlen( newname );
1159 ad_setentrylen( &ad, ADEID_NAME, len );
1160 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1161 ad_flush( &ad, ADFLAGS_HF );
1162 ad_close( &ad, ADFLAGS_HF );
1166 LOG(log_info, logtype_default, "end copyfile:");
1173 int deletefile( file )
1177 int adflags, err = AFP_OK;
1178 int locktype = ADLOCK_WR;
1179 int openmode = O_RDWR;
1182 LOG(log_info, logtype_default, "begin deletefile:");
1187 * If can't open read/write then try again read-only. If it's open
1188 * read-only, we must do a read lock instead of a write lock.
1190 /* try to open both at once */
1191 adflags = ADFLAGS_DF|ADFLAGS_HF;
1192 memset(&ad, 0, sizeof(ad));
1193 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1196 adflags = ADFLAGS_DF;
1197 /* that failed. now try to open just the data fork */
1198 memset(&ad, 0, sizeof(ad));
1199 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1202 return AFPERR_NOOBJ;
1204 if(openmode == O_RDWR) {
1205 openmode = O_RDONLY;
1206 locktype = ADLOCK_RD;
1209 return AFPERR_ACCESS;
1212 return AFPERR_VLOCK;
1214 return AFPERR_PARAM;
1220 if(openmode == O_RDWR) {
1221 openmode = O_RDONLY;
1222 locktype = ADLOCK_RD;
1225 return AFPERR_ACCESS;
1228 return AFPERR_VLOCK;
1230 return( AFPERR_PARAM );
1233 break; /* from the while */
1236 if ((adflags & ADFLAGS_HF) &&
1237 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1238 ad_close( &ad, adflags );
1239 return( AFPERR_BUSY );
1242 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1247 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1251 err = AFPERR_ACCESS;
1264 if ( unlink( file ) < 0 ) {
1268 err = AFPERR_ACCESS;
1282 if (adflags & ADFLAGS_HF)
1283 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1284 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1285 ad_close( &ad, adflags );
1288 LOG(log_info, logtype_default, "end deletefile:");
1296 /* return a file id */
1297 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1300 int ibuflen, *rbuflen;
1312 LOG(log_info, logtype_default, "begin afp_createid:");
1318 memcpy(&vid, ibuf, sizeof(vid));
1319 ibuf += sizeof(vid);
1321 if (( vol = getvolbyvid( vid )) == NULL ) {
1322 return( AFPERR_PARAM);
1325 if (vol->v_flags & AFPVOL_RO)
1326 return AFPERR_VLOCK;
1328 memcpy(&did, ibuf, sizeof( did ));
1329 ibuf += sizeof(did);
1331 if (( dir = dirsearch( vol, did )) == NULL ) {
1332 return( AFPERR_PARAM );
1335 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1336 return( AFPERR_PARAM );
1339 if ( *path == '\0' ) {
1340 return( AFPERR_BADTYPE );
1343 upath = mtoupath(vol, path);
1344 if (stat(upath, &st) < 0) {
1348 return AFPERR_ACCESS;
1350 return AFPERR_NOOBJ;
1352 return AFPERR_PARAM;
1356 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1357 memcpy(rbuf, &id, sizeof(id));
1358 *rbuflen = sizeof(id);
1359 return AFPERR_EXISTID;
1362 #if AD_VERSION > AD_VERSION1
1363 memset(&ad, 0, sizeof(ad));
1364 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1365 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1366 ad_close(&ad, ADFLAGS_HF);
1368 #endif /* AD_VERSION > AD_VERSION1 */
1370 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1371 memcpy(rbuf, &id, sizeof(id));
1372 *rbuflen = sizeof(id);
1377 LOG(log_info, logtype_default, "ending afp_createid...:");
1382 return AFPERR_VLOCK;
1386 return AFPERR_ACCESS;
1389 LOG(log_error, logtype_default, "afp_createid: cnid_add: %s", strerror(errno));
1390 return AFPERR_PARAM;
1394 /* resolve a file id */
1395 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1398 int ibuflen, *rbuflen;
1406 u_int16_t vid, bitmap;
1409 LOG(log_info, logtype_default, "begin afp_resolveid:");
1415 memcpy(&vid, ibuf, sizeof(vid));
1416 ibuf += sizeof(vid);
1418 if (( vol = getvolbyvid( vid )) == NULL ) {
1419 return( AFPERR_PARAM);
1422 memcpy(&id, ibuf, sizeof( id ));
1425 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1426 return AFPERR_BADID;
1429 if (( dir = dirsearch( vol, id )) == NULL ) {
1430 return( AFPERR_PARAM );
1433 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1437 return AFPERR_ACCESS;
1441 return AFPERR_PARAM;
1445 /* directories are bad */
1446 if (S_ISDIR(st.st_mode))
1447 return AFPERR_BADTYPE;
1449 memcpy(&bitmap, ibuf, sizeof(bitmap));
1450 bitmap = ntohs( bitmap );
1452 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1453 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1456 *rbuflen = buflen + sizeof(bitmap);
1457 memcpy(rbuf, ibuf, sizeof(bitmap));
1460 LOG(log_info, logtype_default, "end afp_resolveid:");
1466 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1469 int ibuflen, *rbuflen;
1481 LOG(log_info, logtype_default, "begin afp_deleteid:");
1487 memcpy(&vid, ibuf, sizeof(vid));
1488 ibuf += sizeof(vid);
1490 if (( vol = getvolbyvid( vid )) == NULL ) {
1491 return( AFPERR_PARAM);
1494 if (vol->v_flags & AFPVOL_RO)
1495 return AFPERR_VLOCK;
1497 memcpy(&id, ibuf, sizeof( id ));
1501 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1505 if (( dir = dirsearch( vol, id )) == NULL ) {
1506 return( AFPERR_PARAM );
1510 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1514 return AFPERR_ACCESS;
1516 /* still try to delete the id */
1520 return AFPERR_PARAM;
1524 /* directories are bad */
1525 if (S_ISDIR(st.st_mode))
1526 return AFPERR_BADTYPE;
1528 if (cnid_delete(vol->v_db, fileid)) {
1531 return AFPERR_VLOCK;
1534 return AFPERR_ACCESS;
1536 return AFPERR_PARAM;
1541 LOG(log_info, logtype_default, "end afp_deleteid:");
1546 #endif /* CNID_DB */
1548 #define APPLETEMP ".AppleTempXXXXXX"
1550 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1553 int ibuflen, *rbuflen;
1555 struct stat srcst, destst;
1557 struct dir *dir, *sdir;
1558 char *spath, temp[17], *path, *p;
1559 char *supath, *upath;
1563 #endif /* CNID_DB */
1568 LOG(log_info, logtype_default, "begin afp_exchangefiles:");
1574 memcpy(&vid, ibuf, sizeof(vid));
1575 ibuf += sizeof(vid);
1577 if (( vol = getvolbyvid( vid )) == NULL ) {
1578 return( AFPERR_PARAM);
1581 if (vol->v_flags & AFPVOL_RO)
1582 return AFPERR_VLOCK;
1584 /* source and destination dids */
1585 memcpy(&sid, ibuf, sizeof(sid));
1586 ibuf += sizeof(sid);
1587 memcpy(&did, ibuf, sizeof(did));
1588 ibuf += sizeof(did);
1591 if ((dir = dirsearch( vol, sid )) == NULL ) {
1592 return( AFPERR_PARAM );
1595 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1596 return( AFPERR_PARAM );
1599 if ( *path == '\0' ) {
1600 return( AFPERR_BADTYPE );
1603 upath = mtoupath(vol, path);
1604 if (stat(upath, &srcst) < 0) {
1610 return AFPERR_ACCESS;
1612 return AFPERR_PARAM;
1616 /* save some stuff */
1618 spath = obj->oldtmp;
1619 supath = obj->newtmp;
1620 strcpy(spath, path);
1621 strcpy(supath, upath); /* this is for the cnid changing */
1622 p = ctoupath( vol, sdir, spath);
1624 /* look for the source cnid. if it doesn't exist, don't worry about
1627 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1628 slen = strlen(supath));
1629 #endif /* CNID_DB */
1631 if (( dir = dirsearch( vol, did )) == NULL ) {
1632 return( AFPERR_PARAM );
1635 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1636 return( AFPERR_PARAM );
1639 if ( *path == '\0' ) {
1640 return( AFPERR_BADTYPE );
1643 /* FPExchangeFiles is the only call that can return the SameObj
1645 if ((curdir == sdir) && strcmp(spath, path) == 0)
1646 return AFPERR_SAMEOBJ;
1648 upath = mtoupath(vol, path);
1649 if (stat(upath, &destst) < 0) {
1655 return AFPERR_ACCESS;
1657 return AFPERR_PARAM;
1662 /* look for destination id. */
1663 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1664 dlen = strlen(upath));
1665 #endif /* CNID_DB */
1667 /* construct a temp name.
1668 * NOTE: the temp file will be in the dest file's directory. it
1669 * will also be inaccessible from AFP. */
1670 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1674 /* now, quickly rename the file. we error if we can't. */
1675 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1676 goto err_exchangefile;
1677 of_rename(vol, sdir, spath, curdir, temp);
1679 /* rename destination to source */
1680 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1681 goto err_src_to_tmp;
1682 of_rename(vol, curdir, path, sdir, spath);
1684 /* rename temp to destination */
1685 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1686 goto err_dest_to_src;
1687 of_rename(vol, curdir, temp, curdir, path);
1690 /* id's need switching. src -> dest and dest -> src. */
1691 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1692 upath, dlen) < 0)) {
1696 err = AFPERR_ACCESS;
1701 goto err_temp_to_dest;
1704 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1705 supath, slen) < 0)) {
1709 err = AFPERR_ACCESS;
1716 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1717 goto err_temp_to_dest;
1719 #endif /* CNID_DB */
1722 LOG(log_info, logtype_default, "ending afp_exchangefiles:");
1728 /* all this stuff is so that we can unwind a failed operation
1731 /* rename dest to temp */
1732 renamefile(upath, temp, temp, vol_noadouble(vol));
1733 of_rename(vol, curdir, upath, curdir, temp);
1736 /* rename source back to dest */
1737 renamefile(p, upath, path, vol_noadouble(vol));
1738 of_rename(vol, sdir, spath, curdir, path);
1741 /* rename temp back to source */
1742 renamefile(temp, p, spath, vol_noadouble(vol));
1743 of_rename(vol, curdir, temp, sdir, spath);