2 * $Id: file.c,v 1.43 2002-03-24 17:43:39 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_afpd, "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_afpd, "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_afpd, "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_afpd, "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_afpd, "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 upath = mtoupath(vol, path);
427 /* check for illegal bits in the unix filename */
428 if (!wincheck(vol, upath))
431 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
434 if (!validupath(vol, upath))
437 /* check for vetoed filenames */
438 if (veto_file(vol->v_veto, upath))
441 if ((of = of_findname(vol, curdir, path))) {
444 memset(&ad, 0, sizeof(ad));
448 /* on a hard create, fail if file exists and is open */
449 if ((stat(upath, &st) == 0) && of)
451 openf = O_RDWR|O_CREAT|O_TRUNC;
453 openf = O_RDWR|O_CREAT|O_EXCL;
458 /* preserve current euid, egid */
459 save_uidgid ( uidgid );
461 /* perform all switching of users */
464 #endif /* FORCE_UIDGID */
466 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
467 openf, 0666, adp) < 0 ) {
471 /* bring everything back to old euid, egid */
472 restore_uidgid ( uidgid );
473 #endif /* FORCE_UIDGID */
474 return( AFPERR_EXIST );
477 /* bring everything back to old euid, egid */
478 restore_uidgid ( uidgid );
479 #endif /* FORCE_UIDGID */
480 return( AFPERR_ACCESS );
482 /* on noadouble volumes, just creating the data fork is ok */
483 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
484 goto createfile_done;
488 /* bring everything back to old euid, egid */
489 restore_uidgid ( uidgid );
490 #endif /* FORCE_UIDGID */
491 return( AFPERR_PARAM );
495 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
496 memcpy(ad_entry( adp, ADEID_NAME ), path,
497 ad_getentrylen( adp, ADEID_NAME ));
498 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
499 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
504 if (vol->v_flags & AFPVOL_DROPBOX) {
505 retvalue = matchfile2dirperms(upath, vol, did);
507 #endif /* DROPKLUDGE */
509 setvoltime(obj, vol );
512 LOG(log_info, logtype_afpd, "end afp_createfile");
516 /* bring everything back to old euid, egid */
517 restore_uidgid ( uidgid );
518 #endif /* FORCE_UIDGID */
523 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
526 int ibuflen, *rbuflen;
532 u_int16_t vid, bitmap;
535 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
541 memcpy(&vid, ibuf, sizeof( vid ));
542 ibuf += sizeof( vid );
543 if (( vol = getvolbyvid( vid )) == NULL ) {
544 return( AFPERR_PARAM );
547 if (vol->v_flags & AFPVOL_RO)
550 memcpy(&did, ibuf, sizeof( did ));
551 ibuf += sizeof( did );
552 if (( dir = dirsearch( vol, did )) == NULL ) {
553 return( AFPERR_NOOBJ );
556 memcpy(&bitmap, ibuf, sizeof( bitmap ));
557 bitmap = ntohs( bitmap );
558 ibuf += sizeof( bitmap );
560 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
561 return( AFPERR_NOOBJ );
564 if ((u_long)ibuf & 1 ) {
568 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
569 setvoltime(obj, vol );
573 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
580 int setfilparams(struct vol *vol,
581 char *path, u_int16_t bitmap, char *buf )
583 struct adouble ad, *adp;
586 int bit = 0, isad = 1, err = AFP_OK;
588 u_char achar, *fdType, xyy[4];
589 u_int16_t ashort, bshort;
596 uidgid = malloc(sizeof(uidgidset));
597 #endif /* FORCE_UIDGID */
600 LOG(log_info, logtype_afpd, "begin setfilparams:");
603 upath = mtoupath(vol, path);
604 if ((of = of_findname(vol, curdir, path))) {
607 memset(&ad, 0, sizeof(ad));
612 save_uidgid ( uidgid );
614 #endif /* FORCE_UIDGID */
616 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
617 O_RDWR|O_CREAT, 0666, adp) < 0) {
618 /* for some things, we don't need an adouble header */
619 if (bitmap & ~(1<<FILPBIT_MDATE)) {
621 restore_uidgid ( uidgid );
622 #endif /* FORCE_UIDGID */
623 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
626 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
627 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
628 memcpy(ad_entry( adp, ADEID_NAME ), path,
629 ad_getentrylen( adp, ADEID_NAME ));
632 while ( bitmap != 0 ) {
633 while (( bitmap & 1 ) == 0 ) {
640 memcpy(&ashort, buf, sizeof( ashort ));
641 ad_getattr(adp, &bshort);
642 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
643 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
647 ad_setattr(adp, bshort);
648 buf += sizeof( ashort );
652 memcpy(&aint, buf, sizeof(aint));
653 ad_setdate(adp, AD_DATE_CREATE, aint);
654 buf += sizeof( aint );
658 memcpy(&aint, buf, sizeof( aint ));
660 ad_setdate(adp, AD_DATE_MODIFY, aint);
661 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
663 buf += sizeof( aint );
667 memcpy(&aint, buf, sizeof(aint));
668 ad_setdate(adp, AD_DATE_BACKUP, aint);
669 buf += sizeof( aint );
673 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
674 && (em = getextmap( path )) &&
675 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
676 (memcmp(buf + 4, em->em_creator,
677 sizeof( em->em_creator )) == 0)) {
678 memcpy(buf, ufinderi, 8 );
680 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
684 /* Client needs to set the ProDOS file info for this file.
685 Use defined strings for the simple cases, and convert
686 all else into pXYY per Inside Appletalk. Always set
687 the creator as "pdos". <shirsch@ibm.net> */
688 case FILPBIT_PDINFO :
691 memcpy(&ashort, buf, sizeof( ashort ));
692 ashort = ntohs( ashort );
695 switch ( (unsigned int) achar )
698 fdType = ( u_char *) "TEXT";
702 fdType = ( u_char *) "PSYS";
706 fdType = ( u_char *) "PS16";
710 fdType = ( u_char *) "BINA";
714 xyy[0] = ( u_char ) 'p';
716 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
717 xyy[3] = ( u_char ) ashort & 0xff;
722 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
723 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
729 goto setfilparam_done;
738 ad_flush( adp, ADFLAGS_HF );
739 ad_close( adp, ADFLAGS_HF );
742 restore_uidgid ( uidgid );
743 #endif /* FORCE_UIDGID */
748 LOG(log_info, logtype_afpd, "end setfilparams:");
755 * renamefile and copyfile take the old and new unix pathnames
756 * and the new mac name.
757 * NOTE: if we have to copy a file instead of renaming it, locks
760 int renamefile(src, dst, newname, noadouble )
761 char *src, *dst, *newname;
765 char adsrc[ MAXPATHLEN + 1];
769 * Note that this is only checking the existance of the data file,
770 * not the header file. The thinking is that if the data file doesn't
771 * exist, but the header file does, the right thing to do is remove
772 * the data file silently.
775 /* existence check moved to afp_moveandrename */
778 LOG(log_info, logtype_afpd, "begin renamefile:");
781 if ( rename( src, dst ) < 0 ) {
784 return( AFPERR_NOOBJ );
787 return( AFPERR_ACCESS );
790 case EXDEV : /* Cross device move -- try copy */
791 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
792 deletefile( dst, 0 );
795 return deletefile( src, 0);
797 return( AFPERR_PARAM );
801 strcpy( adsrc, ad_path( src, 0 ));
804 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
809 /* check for a source appledouble header. if it exists, make
810 * a dest appledouble directory and do the rename again. */
811 memset(&ad, 0, sizeof(ad));
812 if (rc || stat(adsrc, &st) ||
813 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
816 ad_close(&ad, ADFLAGS_HF);
820 return( AFPERR_ACCESS );
824 return( AFPERR_PARAM );
828 memset(&ad, 0, sizeof(ad));
829 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
832 return( AFPERR_NOOBJ );
834 return( AFPERR_ACCESS );
838 return( AFPERR_PARAM );
842 len = strlen( newname );
843 ad_setentrylen( &ad, ADEID_NAME, len );
844 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
845 ad_flush( &ad, ADFLAGS_HF );
846 ad_close( &ad, ADFLAGS_HF );
849 LOG(log_info, logtype_afpd, "end renamefile:");
855 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
858 int ibuflen, *rbuflen;
862 char *newname, *path, *p;
863 u_int32_t sdid, ddid;
864 int plen, err, retvalue = AFP_OK;
865 u_int16_t svid, dvid;
868 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
874 memcpy(&svid, ibuf, sizeof( svid ));
875 ibuf += sizeof( svid );
876 if (( vol = getvolbyvid( svid )) == NULL ) {
877 return( AFPERR_PARAM );
880 memcpy(&sdid, ibuf, sizeof( sdid ));
881 ibuf += sizeof( sdid );
882 if (( dir = dirsearch( vol, sdid )) == NULL ) {
883 return( AFPERR_PARAM );
886 memcpy(&dvid, ibuf, sizeof( dvid ));
887 ibuf += sizeof( dvid );
888 memcpy(&ddid, ibuf, sizeof( ddid ));
889 ibuf += sizeof( ddid );
891 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
892 return( AFPERR_NOOBJ );
894 if ( *path == '\0' ) {
895 return( AFPERR_BADTYPE );
898 /* don't allow copies when the file is open.
899 * XXX: the spec only calls for read/deny write access.
900 * however, copyfile doesn't have any of that info,
901 * and locks need to stay coherent. as a result,
902 * we just balk if the file is opened already. */
903 if (of_findname(vol, curdir, path))
904 return AFPERR_DENYCONF;
906 newname = obj->newtmp;
907 strcpy( newname, path );
909 p = ctoupath( vol, curdir, newname );
911 if (( vol = getvolbyvid( dvid )) == NULL ) {
912 return( AFPERR_PARAM );
915 if (vol->v_flags & AFPVOL_RO)
918 if (( dir = dirsearch( vol, ddid )) == NULL ) {
919 return( AFPERR_PARAM );
922 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
923 return( AFPERR_NOOBJ );
925 if ( *path != '\0' ) {
926 return( AFPERR_BADTYPE );
929 /* one of the handful of places that knows about the path type */
930 if ( *ibuf++ != 2 ) {
931 return( AFPERR_PARAM );
933 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
934 strncpy( newname, ibuf, plen );
935 newname[ plen ] = '\0';
938 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
939 vol_noadouble(vol))) < 0 ) {
943 setvoltime(obj, vol );
946 if (vol->v_flags & AFPVOL_DROPBOX) {
947 retvalue=matchfile2dirperms(newname, vol, sdid);
949 #endif /* DROPKLUDGE */
952 LOG(log_info, logtype_afpd, "end afp_copyfile:");
959 static __inline__ int copy_all(const int dfd, const void *buf,
965 LOG(log_info, logtype_afpd, "begin copy_all:");
969 if ((cc = write(dfd, buf, buflen)) < 0) {
987 LOG(log_info, logtype_afpd, "end copy_all:");
993 /* XXX: this needs to use ad_open and ad_lock. so, we need to
994 * pass in vol and path */
995 int copyfile(src, dst, newname, noadouble )
996 char *src, *dst, *newname;
1002 int sfd, dfd, len, err = AFP_OK;
1006 LOG(log_info, logtype_afpd, "begin copyfile:");
1010 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1013 break; /* just copy the data fork */
1015 return( AFPERR_ACCESS );
1017 return( AFPERR_PARAM );
1020 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1021 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1025 return( AFPERR_NOOBJ );
1027 return( AFPERR_ACCESS );
1029 return AFPERR_VLOCK;
1031 return( AFPERR_PARAM );
1036 #ifdef SENDFILE_FLAVOR_LINUX
1037 if (fstat(sfd, &st) == 0) {
1038 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1052 goto copyheader_done;
1054 #endif /* SENDFILE_FLAVOR_LINUX */
1056 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1063 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1071 unlink(ad_path(dst, ADFLAGS_HF));
1077 /* data fork copying */
1078 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1081 return( AFPERR_NOOBJ );
1083 return( AFPERR_ACCESS );
1085 return( AFPERR_PARAM );
1089 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1093 return( AFPERR_NOOBJ );
1095 return( AFPERR_ACCESS );
1097 return AFPERR_VLOCK;
1099 return( AFPERR_PARAM );
1103 #ifdef SENDFILE_FLAVOR_LINUX
1104 if (fstat(sfd, &st) == 0) {
1105 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1118 #endif /* SENDFILE_FLAVOR_LINUX */
1121 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1129 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1138 unlink(ad_path(dst, ADFLAGS_HF));
1144 memset(&ad, 0, sizeof(ad));
1145 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1149 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1151 return( AFPERR_ACCESS );
1153 return AFPERR_VLOCK;
1155 return( AFPERR_PARAM );
1159 len = strlen( newname );
1160 ad_setentrylen( &ad, ADEID_NAME, len );
1161 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1162 ad_flush( &ad, ADFLAGS_HF );
1163 ad_close( &ad, ADFLAGS_HF );
1167 LOG(log_info, logtype_afpd, "end copyfile:");
1174 /* -----------------------------------
1175 checkAttrib: 1 check kFPDeleteInhibitBit
1176 ie deletfile called from afp_delete
1179 int deletefile( file, checkAttrib )
1184 int adflags, err = AFP_OK;
1185 int locktype = ADLOCK_WR;
1186 int openmode = O_RDWR;
1189 LOG(log_info, logtype_afpd, "begin deletefile:");
1194 * If can't open read/write then try again read-only. If it's open
1195 * read-only, we must do a read lock instead of a write lock.
1197 /* try to open both at once */
1198 adflags = ADFLAGS_DF|ADFLAGS_HF;
1199 memset(&ad, 0, sizeof(ad));
1200 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1203 adflags = ADFLAGS_DF;
1204 /* that failed. now try to open just the data fork */
1205 memset(&ad, 0, sizeof(ad));
1206 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1209 return AFPERR_NOOBJ;
1211 if(openmode == O_RDWR) {
1212 openmode = O_RDONLY;
1213 locktype = ADLOCK_RD;
1216 return AFPERR_ACCESS;
1219 return AFPERR_VLOCK;
1221 return AFPERR_PARAM;
1227 if(openmode == O_RDWR) {
1228 openmode = O_RDONLY;
1229 locktype = ADLOCK_RD;
1232 return AFPERR_ACCESS;
1235 return AFPERR_VLOCK;
1237 return( AFPERR_PARAM );
1240 break; /* from the while */
1243 * Does kFPDeleteInhibitBit (bit 8) set?
1245 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1248 ad_getattr(&ad, &bshort);
1249 if ((bshort & htons(ATTRBIT_NODELETE))) {
1250 ad_close( &ad, adflags );
1251 return(AFPERR_OLOCK);
1255 if ((adflags & ADFLAGS_HF) &&
1256 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1257 ad_close( &ad, adflags );
1258 return( AFPERR_BUSY );
1261 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1266 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1270 err = AFPERR_ACCESS;
1283 if ( unlink( file ) < 0 ) {
1287 err = AFPERR_ACCESS;
1301 if (adflags & ADFLAGS_HF)
1302 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1303 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1304 ad_close( &ad, adflags );
1307 LOG(log_info, logtype_afpd, "end deletefile:");
1315 /* return a file id */
1316 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1319 int ibuflen, *rbuflen;
1331 LOG(log_info, logtype_afpd, "begin afp_createid:");
1337 memcpy(&vid, ibuf, sizeof(vid));
1338 ibuf += sizeof(vid);
1340 if (( vol = getvolbyvid( vid )) == NULL ) {
1341 return( AFPERR_PARAM);
1344 if (vol->v_flags & AFPVOL_RO)
1345 return AFPERR_VLOCK;
1347 memcpy(&did, ibuf, sizeof( did ));
1348 ibuf += sizeof(did);
1350 if (( dir = dirsearch( vol, did )) == NULL ) {
1351 return( AFPERR_PARAM );
1354 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1355 return( AFPERR_PARAM );
1358 if ( *path == '\0' ) {
1359 return( AFPERR_BADTYPE );
1362 upath = mtoupath(vol, path);
1363 if (stat(upath, &st) < 0) {
1367 return AFPERR_ACCESS;
1369 return AFPERR_NOOBJ;
1371 return AFPERR_PARAM;
1375 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1376 memcpy(rbuf, &id, sizeof(id));
1377 *rbuflen = sizeof(id);
1378 return AFPERR_EXISTID;
1381 #if AD_VERSION > AD_VERSION1
1382 memset(&ad, 0, sizeof(ad));
1383 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1384 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1385 ad_close(&ad, ADFLAGS_HF);
1387 #endif /* AD_VERSION > AD_VERSION1 */
1389 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1390 memcpy(rbuf, &id, sizeof(id));
1391 *rbuflen = sizeof(id);
1396 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1401 return AFPERR_VLOCK;
1405 return AFPERR_ACCESS;
1408 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1409 return AFPERR_PARAM;
1413 /* resolve a file id */
1414 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1417 int ibuflen, *rbuflen;
1425 u_int16_t vid, bitmap;
1427 static char buffer[12 + MAXPATHLEN + 1];
1428 int len = 12 + MAXPATHLEN + 1;
1431 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1437 memcpy(&vid, ibuf, sizeof(vid));
1438 ibuf += sizeof(vid);
1440 if (( vol = getvolbyvid( vid )) == NULL ) {
1441 return( AFPERR_PARAM);
1444 memcpy(&id, ibuf, sizeof( id ));
1447 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1448 return AFPERR_BADID;
1451 if (( dir = dirlookup( vol, id )) == NULL ) {
1452 return( AFPERR_PARAM );
1455 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1459 return AFPERR_ACCESS;
1463 return AFPERR_PARAM;
1467 /* directories are bad */
1468 if (S_ISDIR(st.st_mode))
1469 return AFPERR_BADTYPE;
1471 memcpy(&bitmap, ibuf, sizeof(bitmap));
1472 bitmap = ntohs( bitmap );
1474 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1475 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1478 *rbuflen = buflen + sizeof(bitmap);
1479 memcpy(rbuf, ibuf, sizeof(bitmap));
1482 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1488 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1491 int ibuflen, *rbuflen;
1501 static char buffer[12 + MAXPATHLEN + 1];
1502 int len = 12 + MAXPATHLEN + 1;
1505 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1511 memcpy(&vid, ibuf, sizeof(vid));
1512 ibuf += sizeof(vid);
1514 if (( vol = getvolbyvid( vid )) == NULL ) {
1515 return( AFPERR_PARAM);
1518 if (vol->v_flags & AFPVOL_RO)
1519 return AFPERR_VLOCK;
1521 memcpy(&id, ibuf, sizeof( id ));
1525 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1529 if (( dir = dirlookup( vol, id )) == NULL ) {
1530 return( AFPERR_PARAM );
1534 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1538 return AFPERR_ACCESS;
1540 /* still try to delete the id */
1544 return AFPERR_PARAM;
1548 /* directories are bad */
1549 if (S_ISDIR(st.st_mode))
1550 return AFPERR_BADTYPE;
1552 if (cnid_delete(vol->v_db, fileid)) {
1555 return AFPERR_VLOCK;
1558 return AFPERR_ACCESS;
1560 return AFPERR_PARAM;
1565 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1570 #endif /* CNID_DB */
1572 #define APPLETEMP ".AppleTempXXXXXX"
1574 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1577 int ibuflen, *rbuflen;
1579 struct stat srcst, destst;
1581 struct dir *dir, *sdir;
1582 char *spath, temp[17], *path, *p;
1583 char *supath, *upath;
1587 #endif /* CNID_DB */
1592 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1598 memcpy(&vid, ibuf, sizeof(vid));
1599 ibuf += sizeof(vid);
1601 if (( vol = getvolbyvid( vid )) == NULL ) {
1602 return( AFPERR_PARAM);
1605 if (vol->v_flags & AFPVOL_RO)
1606 return AFPERR_VLOCK;
1608 /* source and destination dids */
1609 memcpy(&sid, ibuf, sizeof(sid));
1610 ibuf += sizeof(sid);
1611 memcpy(&did, ibuf, sizeof(did));
1612 ibuf += sizeof(did);
1615 if ((dir = dirsearch( vol, sid )) == NULL ) {
1616 return( AFPERR_PARAM );
1619 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1620 return( AFPERR_PARAM );
1623 if ( *path == '\0' ) {
1624 return( AFPERR_BADTYPE );
1627 upath = mtoupath(vol, path);
1628 if (stat(upath, &srcst) < 0) {
1634 return AFPERR_ACCESS;
1636 return AFPERR_PARAM;
1640 /* save some stuff */
1642 spath = obj->oldtmp;
1643 supath = obj->newtmp;
1644 strcpy(spath, path);
1645 strcpy(supath, upath); /* this is for the cnid changing */
1646 p = ctoupath( vol, sdir, spath);
1648 /* look for the source cnid. if it doesn't exist, don't worry about
1651 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1652 slen = strlen(supath));
1653 #endif /* CNID_DB */
1655 if (( dir = dirsearch( vol, did )) == NULL ) {
1656 return( AFPERR_PARAM );
1659 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1660 return( AFPERR_PARAM );
1663 if ( *path == '\0' ) {
1664 return( AFPERR_BADTYPE );
1667 /* FPExchangeFiles is the only call that can return the SameObj
1669 if ((curdir == sdir) && strcmp(spath, path) == 0)
1670 return AFPERR_SAMEOBJ;
1672 upath = mtoupath(vol, path);
1673 if (stat(upath, &destst) < 0) {
1679 return AFPERR_ACCESS;
1681 return AFPERR_PARAM;
1686 /* look for destination id. */
1687 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1688 dlen = strlen(upath));
1689 #endif /* CNID_DB */
1691 /* construct a temp name.
1692 * NOTE: the temp file will be in the dest file's directory. it
1693 * will also be inaccessible from AFP. */
1694 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1698 /* now, quickly rename the file. we error if we can't. */
1699 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1700 goto err_exchangefile;
1701 of_rename(vol, sdir, spath, curdir, temp);
1703 /* rename destination to source */
1704 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1705 goto err_src_to_tmp;
1706 of_rename(vol, curdir, path, sdir, spath);
1708 /* rename temp to destination */
1709 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1710 goto err_dest_to_src;
1711 of_rename(vol, curdir, temp, curdir, path);
1714 /* id's need switching. src -> dest and dest -> src. */
1715 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1716 upath, dlen) < 0)) {
1720 err = AFPERR_ACCESS;
1725 goto err_temp_to_dest;
1728 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1729 supath, slen) < 0)) {
1733 err = AFPERR_ACCESS;
1740 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1741 goto err_temp_to_dest;
1743 #endif /* CNID_DB */
1746 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1752 /* all this stuff is so that we can unwind a failed operation
1755 /* rename dest to temp */
1756 renamefile(upath, temp, temp, vol_noadouble(vol));
1757 of_rename(vol, curdir, upath, curdir, temp);
1760 /* rename source back to dest */
1761 renamefile(p, upath, path, vol_noadouble(vol));
1762 of_rename(vol, sdir, spath, curdir, path);
1765 /* rename temp back to source */
1766 renamefile(temp, p, spath, vol_noadouble(vol));
1767 of_rename(vol, curdir, temp, sdir, spath);