2 * $Id: file.c,v 1.39 2002-02-02 19:11:33 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;
1480 LOG(log_info, logtype_default, "begin afp_deleteid:");
1486 memcpy(&vid, ibuf, sizeof(vid));
1487 ibuf += sizeof(vid);
1489 if (( vol = getvolbyvid( vid )) == NULL ) {
1490 return( AFPERR_PARAM);
1493 if (vol->v_flags & AFPVOL_RO)
1494 return AFPERR_VLOCK;
1496 memcpy(&id, ibuf, sizeof( id ));
1499 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1503 if (( dir = dirsearch( vol, id )) == NULL ) {
1504 return( AFPERR_PARAM );
1508 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1512 return AFPERR_ACCESS;
1514 /* still try to delete the id */
1518 return AFPERR_PARAM;
1522 /* directories are bad */
1523 if (S_ISDIR(st.st_mode))
1524 return AFPERR_BADTYPE;
1526 if (cnid_delete(vol->v_db, id)) {
1529 return AFPERR_VLOCK;
1532 return AFPERR_ACCESS;
1534 return AFPERR_PARAM;
1539 LOG(log_info, logtype_default, "end afp_deleteid:");
1544 #endif /* CNID_DB */
1546 #define APPLETEMP ".AppleTempXXXXXX"
1548 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1551 int ibuflen, *rbuflen;
1553 struct stat srcst, destst;
1555 struct dir *dir, *sdir;
1556 char *spath, temp[17], *path, *p;
1557 char *supath, *upath;
1561 #endif /* CNID_DB */
1566 LOG(log_info, logtype_default, "begin afp_exchangefiles:");
1572 memcpy(&vid, ibuf, sizeof(vid));
1573 ibuf += sizeof(vid);
1575 if (( vol = getvolbyvid( vid )) == NULL ) {
1576 return( AFPERR_PARAM);
1579 if (vol->v_flags & AFPVOL_RO)
1580 return AFPERR_VLOCK;
1582 /* source and destination dids */
1583 memcpy(&sid, ibuf, sizeof(sid));
1584 ibuf += sizeof(sid);
1585 memcpy(&did, ibuf, sizeof(did));
1586 ibuf += sizeof(did);
1589 if ((dir = dirsearch( vol, sid )) == NULL ) {
1590 return( AFPERR_PARAM );
1593 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1594 return( AFPERR_PARAM );
1597 if ( *path == '\0' ) {
1598 return( AFPERR_BADTYPE );
1601 upath = mtoupath(vol, path);
1602 if (stat(upath, &srcst) < 0) {
1608 return AFPERR_ACCESS;
1610 return AFPERR_PARAM;
1614 /* save some stuff */
1616 spath = obj->oldtmp;
1617 supath = obj->newtmp;
1618 strcpy(spath, path);
1619 strcpy(supath, upath); /* this is for the cnid changing */
1620 p = ctoupath( vol, sdir, spath);
1622 /* look for the source cnid. if it doesn't exist, don't worry about
1625 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1626 slen = strlen(supath));
1627 #endif /* CNID_DB */
1629 if (( dir = dirsearch( vol, did )) == NULL ) {
1630 return( AFPERR_PARAM );
1633 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1634 return( AFPERR_PARAM );
1637 if ( *path == '\0' ) {
1638 return( AFPERR_BADTYPE );
1641 /* FPExchangeFiles is the only call that can return the SameObj
1643 if ((curdir == sdir) && strcmp(spath, path) == 0)
1644 return AFPERR_SAMEOBJ;
1646 upath = mtoupath(vol, path);
1647 if (stat(upath, &destst) < 0) {
1653 return AFPERR_ACCESS;
1655 return AFPERR_PARAM;
1660 /* look for destination id. */
1661 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1662 dlen = strlen(upath));
1663 #endif /* CNID_DB */
1665 /* construct a temp name.
1666 * NOTE: the temp file will be in the dest file's directory. it
1667 * will also be inaccessible from AFP. */
1668 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1672 /* now, quickly rename the file. we error if we can't. */
1673 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1674 goto err_exchangefile;
1675 of_rename(vol, sdir, spath, curdir, temp);
1677 /* rename destination to source */
1678 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1679 goto err_src_to_tmp;
1680 of_rename(vol, curdir, path, sdir, spath);
1682 /* rename temp to destination */
1683 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1684 goto err_dest_to_src;
1685 of_rename(vol, curdir, temp, curdir, path);
1688 /* id's need switching. src -> dest and dest -> src. */
1689 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1690 upath, dlen) < 0)) {
1694 err = AFPERR_ACCESS;
1699 goto err_temp_to_dest;
1702 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1703 supath, slen) < 0)) {
1707 err = AFPERR_ACCESS;
1714 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1715 goto err_temp_to_dest;
1717 #endif /* CNID_DB */
1720 LOG(log_info, logtype_default, "ending afp_exchangefiles:");
1726 /* all this stuff is so that we can unwind a failed operation
1729 /* rename dest to temp */
1730 renamefile(upath, temp, temp, vol_noadouble(vol));
1731 of_rename(vol, curdir, upath, curdir, temp);
1734 /* rename source back to dest */
1735 renamefile(p, upath, path, vol_noadouble(vol));
1736 of_rename(vol, sdir, spath, curdir, path);
1739 /* rename temp back to source */
1740 renamefile(temp, p, spath, vol_noadouble(vol));
1741 of_rename(vol, curdir, temp, sdir, spath);