2 * $Id: file.c,v 1.41 2002-03-13 19:29:17 srittau 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 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_default, "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_default, "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_default, "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_default, "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_default, "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_default, "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 ) {
795 return deletefile( src );
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_default, "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_default, "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_default, "end afp_copyfile:");
959 static __inline__ int copy_all(const int dfd, const void *buf,
965 LOG(log_info, logtype_default, "begin copy_all:");
969 if ((cc = write(dfd, buf, buflen)) < 0) {
987 LOG(log_info, logtype_default, "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_default, "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_default, "end copyfile:");
1174 int deletefile( file )
1178 int adflags, err = AFP_OK;
1179 int locktype = ADLOCK_WR;
1180 int openmode = O_RDWR;
1183 LOG(log_info, logtype_default, "begin deletefile:");
1188 * If can't open read/write then try again read-only. If it's open
1189 * read-only, we must do a read lock instead of a write lock.
1191 /* try to open both at once */
1192 adflags = ADFLAGS_DF|ADFLAGS_HF;
1193 memset(&ad, 0, sizeof(ad));
1194 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1197 adflags = ADFLAGS_DF;
1198 /* that failed. now try to open just the data fork */
1199 memset(&ad, 0, sizeof(ad));
1200 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1203 return AFPERR_NOOBJ;
1205 if(openmode == O_RDWR) {
1206 openmode = O_RDONLY;
1207 locktype = ADLOCK_RD;
1210 return AFPERR_ACCESS;
1213 return AFPERR_VLOCK;
1215 return AFPERR_PARAM;
1221 if(openmode == O_RDWR) {
1222 openmode = O_RDONLY;
1223 locktype = ADLOCK_RD;
1226 return AFPERR_ACCESS;
1229 return AFPERR_VLOCK;
1231 return( AFPERR_PARAM );
1234 break; /* from the while */
1237 if ((adflags & ADFLAGS_HF) &&
1238 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1239 ad_close( &ad, adflags );
1240 return( AFPERR_BUSY );
1243 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1248 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1252 err = AFPERR_ACCESS;
1265 if ( unlink( file ) < 0 ) {
1269 err = AFPERR_ACCESS;
1283 if (adflags & ADFLAGS_HF)
1284 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1285 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1286 ad_close( &ad, adflags );
1289 LOG(log_info, logtype_default, "end deletefile:");
1297 /* return a file id */
1298 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1301 int ibuflen, *rbuflen;
1313 LOG(log_info, logtype_default, "begin afp_createid:");
1319 memcpy(&vid, ibuf, sizeof(vid));
1320 ibuf += sizeof(vid);
1322 if (( vol = getvolbyvid( vid )) == NULL ) {
1323 return( AFPERR_PARAM);
1326 if (vol->v_flags & AFPVOL_RO)
1327 return AFPERR_VLOCK;
1329 memcpy(&did, ibuf, sizeof( did ));
1330 ibuf += sizeof(did);
1332 if (( dir = dirsearch( vol, did )) == NULL ) {
1333 return( AFPERR_PARAM );
1336 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1337 return( AFPERR_PARAM );
1340 if ( *path == '\0' ) {
1341 return( AFPERR_BADTYPE );
1344 upath = mtoupath(vol, path);
1345 if (stat(upath, &st) < 0) {
1349 return AFPERR_ACCESS;
1351 return AFPERR_NOOBJ;
1353 return AFPERR_PARAM;
1357 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1358 memcpy(rbuf, &id, sizeof(id));
1359 *rbuflen = sizeof(id);
1360 return AFPERR_EXISTID;
1363 #if AD_VERSION > AD_VERSION1
1364 memset(&ad, 0, sizeof(ad));
1365 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1366 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1367 ad_close(&ad, ADFLAGS_HF);
1369 #endif /* AD_VERSION > AD_VERSION1 */
1371 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1372 memcpy(rbuf, &id, sizeof(id));
1373 *rbuflen = sizeof(id);
1378 LOG(log_info, logtype_default, "ending afp_createid...:");
1383 return AFPERR_VLOCK;
1387 return AFPERR_ACCESS;
1390 LOG(log_error, logtype_default, "afp_createid: cnid_add: %s", strerror(errno));
1391 return AFPERR_PARAM;
1395 /* resolve a file id */
1396 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1399 int ibuflen, *rbuflen;
1407 u_int16_t vid, bitmap;
1410 LOG(log_info, logtype_default, "begin afp_resolveid:");
1416 memcpy(&vid, ibuf, sizeof(vid));
1417 ibuf += sizeof(vid);
1419 if (( vol = getvolbyvid( vid )) == NULL ) {
1420 return( AFPERR_PARAM);
1423 memcpy(&id, ibuf, sizeof( id ));
1426 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1427 return AFPERR_BADID;
1430 if (( dir = dirsearch( vol, id )) == NULL ) {
1431 return( AFPERR_PARAM );
1434 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1438 return AFPERR_ACCESS;
1442 return AFPERR_PARAM;
1446 /* directories are bad */
1447 if (S_ISDIR(st.st_mode))
1448 return AFPERR_BADTYPE;
1450 memcpy(&bitmap, ibuf, sizeof(bitmap));
1451 bitmap = ntohs( bitmap );
1453 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1454 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1457 *rbuflen = buflen + sizeof(bitmap);
1458 memcpy(rbuf, ibuf, sizeof(bitmap));
1461 LOG(log_info, logtype_default, "end afp_resolveid:");
1467 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1470 int ibuflen, *rbuflen;
1482 LOG(log_info, logtype_default, "begin afp_deleteid:");
1488 memcpy(&vid, ibuf, sizeof(vid));
1489 ibuf += sizeof(vid);
1491 if (( vol = getvolbyvid( vid )) == NULL ) {
1492 return( AFPERR_PARAM);
1495 if (vol->v_flags & AFPVOL_RO)
1496 return AFPERR_VLOCK;
1498 memcpy(&id, ibuf, sizeof( id ));
1502 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1506 if (( dir = dirsearch( vol, id )) == NULL ) {
1507 return( AFPERR_PARAM );
1511 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1515 return AFPERR_ACCESS;
1517 /* still try to delete the id */
1521 return AFPERR_PARAM;
1525 /* directories are bad */
1526 if (S_ISDIR(st.st_mode))
1527 return AFPERR_BADTYPE;
1529 if (cnid_delete(vol->v_db, fileid)) {
1532 return AFPERR_VLOCK;
1535 return AFPERR_ACCESS;
1537 return AFPERR_PARAM;
1542 LOG(log_info, logtype_default, "end afp_deleteid:");
1547 #endif /* CNID_DB */
1549 #define APPLETEMP ".AppleTempXXXXXX"
1551 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1554 int ibuflen, *rbuflen;
1556 struct stat srcst, destst;
1558 struct dir *dir, *sdir;
1559 char *spath, temp[17], *path, *p;
1560 char *supath, *upath;
1564 #endif /* CNID_DB */
1569 LOG(log_info, logtype_default, "begin afp_exchangefiles:");
1575 memcpy(&vid, ibuf, sizeof(vid));
1576 ibuf += sizeof(vid);
1578 if (( vol = getvolbyvid( vid )) == NULL ) {
1579 return( AFPERR_PARAM);
1582 if (vol->v_flags & AFPVOL_RO)
1583 return AFPERR_VLOCK;
1585 /* source and destination dids */
1586 memcpy(&sid, ibuf, sizeof(sid));
1587 ibuf += sizeof(sid);
1588 memcpy(&did, ibuf, sizeof(did));
1589 ibuf += sizeof(did);
1592 if ((dir = dirsearch( vol, sid )) == NULL ) {
1593 return( AFPERR_PARAM );
1596 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1597 return( AFPERR_PARAM );
1600 if ( *path == '\0' ) {
1601 return( AFPERR_BADTYPE );
1604 upath = mtoupath(vol, path);
1605 if (stat(upath, &srcst) < 0) {
1611 return AFPERR_ACCESS;
1613 return AFPERR_PARAM;
1617 /* save some stuff */
1619 spath = obj->oldtmp;
1620 supath = obj->newtmp;
1621 strcpy(spath, path);
1622 strcpy(supath, upath); /* this is for the cnid changing */
1623 p = ctoupath( vol, sdir, spath);
1625 /* look for the source cnid. if it doesn't exist, don't worry about
1628 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1629 slen = strlen(supath));
1630 #endif /* CNID_DB */
1632 if (( dir = dirsearch( vol, did )) == NULL ) {
1633 return( AFPERR_PARAM );
1636 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1637 return( AFPERR_PARAM );
1640 if ( *path == '\0' ) {
1641 return( AFPERR_BADTYPE );
1644 /* FPExchangeFiles is the only call that can return the SameObj
1646 if ((curdir == sdir) && strcmp(spath, path) == 0)
1647 return AFPERR_SAMEOBJ;
1649 upath = mtoupath(vol, path);
1650 if (stat(upath, &destst) < 0) {
1656 return AFPERR_ACCESS;
1658 return AFPERR_PARAM;
1663 /* look for destination id. */
1664 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1665 dlen = strlen(upath));
1666 #endif /* CNID_DB */
1668 /* construct a temp name.
1669 * NOTE: the temp file will be in the dest file's directory. it
1670 * will also be inaccessible from AFP. */
1671 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1675 /* now, quickly rename the file. we error if we can't. */
1676 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1677 goto err_exchangefile;
1678 of_rename(vol, sdir, spath, curdir, temp);
1680 /* rename destination to source */
1681 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1682 goto err_src_to_tmp;
1683 of_rename(vol, curdir, path, sdir, spath);
1685 /* rename temp to destination */
1686 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1687 goto err_dest_to_src;
1688 of_rename(vol, curdir, temp, curdir, path);
1691 /* id's need switching. src -> dest and dest -> src. */
1692 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1693 upath, dlen) < 0)) {
1697 err = AFPERR_ACCESS;
1702 goto err_temp_to_dest;
1705 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1706 supath, slen) < 0)) {
1710 err = AFPERR_ACCESS;
1717 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1718 goto err_temp_to_dest;
1720 #endif /* CNID_DB */
1723 LOG(log_info, logtype_default, "ending afp_exchangefiles:");
1729 /* all this stuff is so that we can unwind a failed operation
1732 /* rename dest to temp */
1733 renamefile(upath, temp, temp, vol_noadouble(vol));
1734 of_rename(vol, curdir, upath, curdir, temp);
1737 /* rename source back to dest */
1738 renamefile(p, upath, path, vol_noadouble(vol));
1739 of_rename(vol, sdir, spath, curdir, path);
1742 /* rename temp back to source */
1743 renamefile(temp, p, spath, vol_noadouble(vol));
1744 of_rename(vol, curdir, temp, sdir, spath);