2 * $Id: file.c,v 1.62 2002-10-05 14:04:47 didg 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 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63 * field bytes subfield bytes
66 * ioFlFndrInfo 16 -> type 4 type field
67 * creator 4 creator field
68 * flags 2 finder flags:
70 * location 4 location in window
71 * folder 2 window that contains file
73 * ioFlXFndrInfo 16 -> iconID 2 icon id
75 * script 1 script system
77 * commentID 2 comment id
78 * putawayID 4 home directory id
81 const u_char ufinderi[] = {
82 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0
88 int getmetadata(struct vol *vol,
90 char *path, struct dir *dir, struct stat *st,
91 char *buf, int *buflen, struct adouble *adp, int attrbits )
94 struct stat lst, *lstp;
95 #endif /* USE_LASTDID */
98 char *data, *nameoff = NULL, *upath;
102 u_char achar, fdType[4];
106 LOG(log_info, logtype_afpd, "begin getmetadata:");
109 upath = mtoupath(vol, path);
112 while ( bitmap != 0 ) {
113 while (( bitmap & 1 ) == 0 ) {
121 ad_getattr(adp, &ashort);
122 } else if (*upath == '.') {
123 ashort = htons(ATTRBIT_INVISIBLE);
127 /* FIXME do we want a visual clue if the file is read only
129 accessmode( ".", &ma, dir , NULL);
130 if ((ma.ma_user & AR_UWRITE)) {
131 accessmode( upath, &ma, dir , st);
132 if (!(ma.ma_user & AR_UWRITE)) {
133 attrbits |= ATTRBIT_NOWRITE;
138 ashort = htons(ntohs(ashort) | attrbits);
139 memcpy(data, &ashort, sizeof( ashort ));
140 data += sizeof( ashort );
144 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
145 data += sizeof( u_int32_t );
149 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
150 aint = AD_DATE_FROM_UNIX(st->st_mtime);
151 memcpy(data, &aint, sizeof( aint ));
152 data += sizeof( aint );
156 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
157 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
158 aint = AD_DATE_FROM_UNIX(st->st_mtime);
161 aint = AD_DATE_FROM_UNIX(st->st_mtime);
163 memcpy(data, &aint, sizeof( int ));
164 data += sizeof( int );
168 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
169 aint = AD_DATE_START;
170 memcpy(data, &aint, sizeof( int ));
171 data += sizeof( int );
176 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
178 memcpy(data, ufinderi, 32);
179 if (*upath == '.') { /* make it invisible */
180 ashort = htons(FINDERINFO_INVISIBLE);
181 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
185 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
186 && (em = getextmap( path ))
188 memcpy(data, em->em_type, sizeof( em->em_type ));
189 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
196 data += sizeof( u_int16_t );
200 memset(data, 0, sizeof(u_int16_t));
201 data += sizeof( u_int16_t );
206 #if AD_VERSION > AD_VERSION1
207 /* look in AD v2 header */
209 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
210 #endif /* AD_VERSION > AD_VERSION1 */
213 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
214 strlen(upath), aint);
215 /* Throw errors if cnid_add fails. */
216 if (aint == CNID_INVALID) {
219 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
220 return(AFPERR_PARAM);
222 return(AFPERR_PARAM);
232 * What a fucking mess. First thing: DID and FNUMs are
233 * in the same space for purposes of enumerate (and several
234 * other wierd places). While we consider this Apple's bug,
235 * this is the work-around: In order to maintain constant and
236 * unique DIDs and FNUMs, we monotonically generate the DIDs
237 * during the session, and derive the FNUMs from the filesystem.
238 * Since the DIDs are small, we insure that the FNUMs are fairly
239 * large by setting thier high bits to the device number.
241 * AFS already does something very similar to this for the
242 * inode number, so we don't repeat the procedure.
245 * due to complaints over did's being non-persistent,
246 * here's the current hack to provide semi-persistent
248 * 1) we reserve the first bit for file ids.
249 * 2) the next 7 bits are for the device.
250 * 3) the remaining 24 bits are for the inode.
252 * both the inode and device information are actually hashes
253 * that are then truncated to the requisite bit length.
255 * it should be okay to use lstat to deal with symlinks.
258 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
259 #else /* USE_LASTDID */
260 lstp = lstat(upath, &lst) < 0 ? st : &lst;
261 aint = htonl(CNID(lstp, 1));
262 #endif /* USE_LASTDID */
265 memcpy(data, &aint, sizeof( aint ));
266 data += sizeof( aint );
270 aint = htonl( st->st_size );
271 memcpy(data, &aint, sizeof( aint ));
272 data += sizeof( aint );
277 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
281 memcpy(data, &aint, sizeof( aint ));
282 data += sizeof( aint );
285 /* Current client needs ProDOS info block for this file.
286 Use simple heuristic and let the Mac "type" string tell
287 us what the PD file code should be. Everything gets a
288 subtype of 0x0000 unless the original value was hashed
289 to "pXYZ" when we created it. See IA, Ver 2.
291 case FILPBIT_PDINFO :
293 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
295 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
299 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
303 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
307 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
311 else if ( fdType[0] == 'p' ) {
313 ashort = (fdType[2] * 256) + fdType[3];
327 memcpy(data, &ashort, sizeof( ashort ));
328 data += sizeof( ashort );
329 memset(data, 0, sizeof( ashort ));
330 data += sizeof( ashort );
334 return( AFPERR_BITMAP );
340 ashort = htons( data - buf );
341 memcpy(nameoff, &ashort, sizeof( ashort ));
342 if ((aint = strlen( path )) > MACFILELEN)
345 memcpy(data, path, aint );
348 *buflen = data - buf;
352 /* ----------------------- */
353 int getfilparams(struct vol *vol,
355 char *path, struct dir *dir, struct stat *st,
356 char *buf, int *buflen )
358 struct adouble ad, *adp;
361 u_int16_t attrbits = 0;
364 LOG(log_info, logtype_afpd, "begin getfilparams:");
367 upath = mtoupath(vol, path);
368 if ((of = of_findname(upath, st))) {
370 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
371 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
374 memset(&ad, 0, sizeof(ad));
378 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
384 we need to check if the file is open by another process.
385 it's slow so we only do it if we have to:
386 - bitmap is requested.
387 - we don't already have the answer!
389 if ((bitmap & (1 << FILPBIT_ATTR))) {
390 if (!(attrbits & ATTRBIT_ROPEN)) {
392 if (!(attrbits & ATTRBIT_DOPEN)) {
397 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
399 ad_close( adp, ADFLAGS_HF );
402 LOG(log_info, logtype_afpd, "end getfilparams:");
408 /* ----------------------------- */
409 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
412 int ibuflen, *rbuflen;
415 struct adouble ad, *adp;
418 struct ofork *of = NULL;
420 int creatf, did, openf, retvalue = AFP_OK;
424 LOG(log_info, logtype_afpd, "begin afp_createfile:");
429 creatf = (unsigned char) *ibuf++;
431 memcpy(&vid, ibuf, sizeof( vid ));
432 ibuf += sizeof( vid );
434 if (( vol = getvolbyvid( vid )) == NULL ) {
435 return( AFPERR_PARAM );
438 if (vol->v_flags & AFPVOL_RO)
441 memcpy(&did, ibuf, sizeof( did));
442 ibuf += sizeof( did );
444 if (( dir = dirlookup( vol, did )) == NULL ) {
445 return( AFPERR_NOOBJ );
448 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
449 return( AFPERR_NOOBJ );
452 upath = mtoupath(vol, path);
453 if (0 != (ret = check_name(vol, upath)))
456 ret = stat(upath, &st);
457 /* if upath is deleted we already in trouble anyway */
458 if (!ret && (of = of_findname(upath, &st))) {
461 memset(&ad, 0, sizeof(ad));
465 /* on a hard create, fail if file exists and is open */
468 openf = O_RDWR|O_CREAT|O_TRUNC;
470 /* on a soft create, if the file is open then ad_open won't fail
471 because open syscall is not called
476 openf = O_RDWR|O_CREAT|O_EXCL;
479 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
480 openf, 0666, adp) < 0 ) {
483 return( AFPERR_EXIST );
485 return( AFPERR_ACCESS );
487 /* on noadouble volumes, just creating the data fork is ok */
488 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
489 goto createfile_done;
492 return( AFPERR_PARAM );
496 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
497 memcpy(ad_entry( adp, ADEID_NAME ), path,
498 ad_getentrylen( adp, ADEID_NAME ));
499 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
500 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
505 if (vol->v_flags & AFPVOL_DROPBOX) {
506 retvalue = matchfile2dirperms(upath, vol, did);
508 #endif /* DROPKLUDGE */
510 setvoltime(obj, vol );
513 LOG(log_info, logtype_afpd, "end afp_createfile");
519 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
522 int ibuflen, *rbuflen;
528 u_int16_t vid, bitmap;
531 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
537 memcpy(&vid, ibuf, sizeof( vid ));
538 ibuf += sizeof( vid );
539 if (( vol = getvolbyvid( vid )) == NULL ) {
540 return( AFPERR_PARAM );
543 if (vol->v_flags & AFPVOL_RO)
546 memcpy(&did, ibuf, sizeof( did ));
547 ibuf += sizeof( did );
548 if (( dir = dirlookup( vol, did )) == NULL ) {
549 return( AFPERR_NOOBJ );
552 memcpy(&bitmap, ibuf, sizeof( bitmap ));
553 bitmap = ntohs( bitmap );
554 ibuf += sizeof( bitmap );
556 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
557 return( AFPERR_NOOBJ );
560 if ( *path == '\0' ) {
561 return( AFPERR_BADTYPE ); /* it's a directory */
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 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
584 int setfilparams(struct vol *vol,
585 char *path, u_int16_t bitmap, char *buf )
587 struct adouble ad, *adp;
590 int bit = 0, isad = 1, err = AFP_OK;
592 u_char achar, *fdType, xyy[4];
593 u_int16_t ashort, bshort;
597 int change_mdate = 0;
598 int change_parent_mdate = 0;
604 LOG(log_info, logtype_afpd, "begin setfilparams:");
607 upath = mtoupath(vol, path);
608 if ((of = of_findname(upath, NULL))) {
611 memset(&ad, 0, sizeof(ad));
615 if (check_access(upath, OPENACC_WR ) < 0) {
616 return AFPERR_ACCESS;
619 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
620 O_RDWR|O_CREAT, 0666, adp) < 0) {
621 /* for some things, we don't need an adouble header */
622 if (bitmap & ~(1<<FILPBIT_MDATE)) {
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 ) {
641 memcpy(&ashort, buf, sizeof( ashort ));
642 ad_getattr(adp, &bshort);
643 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
644 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
648 if ((ashort & htons(ATTRBIT_INVISIBLE)))
649 change_parent_mdate = 1;
650 ad_setattr(adp, bshort);
651 buf += sizeof( ashort );
656 memcpy(&aint, buf, sizeof(aint));
657 ad_setdate(adp, AD_DATE_CREATE, aint);
658 buf += sizeof( aint );
662 memcpy(&newdate, buf, sizeof( newdate ));
663 buf += sizeof( newdate );
668 memcpy(&aint, buf, sizeof(aint));
669 ad_setdate(adp, AD_DATE_BACKUP, aint);
670 buf += sizeof( aint );
676 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
678 ((em = getextmap( path )) &&
679 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
680 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
681 || ((em = getdefextmap()) &&
682 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
683 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
685 memcpy(buf, ufinderi, 8 );
688 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
692 /* Client needs to set the ProDOS file info for this file.
693 Use defined strings for the simple cases, and convert
694 all else into pXYY per Inside Appletalk. Always set
695 the creator as "pdos". <shirsch@ibm.net> */
696 case FILPBIT_PDINFO :
699 memcpy(&ashort, buf, sizeof( ashort ));
700 ashort = ntohs( ashort );
703 switch ( (unsigned int) achar )
706 fdType = ( u_char *) "TEXT";
710 fdType = ( u_char *) "PSYS";
714 fdType = ( u_char *) "PS16";
718 fdType = ( u_char *) "BINA";
722 xyy[0] = ( u_char ) 'p';
724 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
725 xyy[3] = ( u_char ) ashort & 0xff;
730 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
731 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
737 goto setfilparam_done;
745 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
746 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
750 ad_setdate(adp, AD_DATE_MODIFY, newdate);
751 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
756 ad_flush( adp, ADFLAGS_HF );
757 ad_close( adp, ADFLAGS_HF );
761 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
762 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
763 bitmap = 1<<FILPBIT_MDATE;
764 setdirparams(vol, "", bitmap, (char *)&newdate);
768 LOG(log_info, logtype_afpd, "end setfilparams:");
774 * renamefile and copyfile take the old and new unix pathnames
775 * and the new mac name.
776 * NOTE: if we have to copy a file instead of renaming it, locks
777 * will break. Anyway it's an error because then we have 2 files.
779 * src the source path
780 * dst the dest filename in current dir
781 * newname the dest mac name
782 * adp adouble struct of src file, if open, or & zeroed one
785 int renamefile(src, dst, newname, noadouble, adp )
786 char *src, *dst, *newname;
790 char adsrc[ MAXPATHLEN + 1];
794 * Note that this is only checking the existance of the data file,
795 * not the header file. The thinking is that if the data file doesn't
796 * exist, but the header file does, the right thing to do is remove
797 * the data file silently.
800 /* existence check moved to afp_moveandrename */
803 LOG(log_info, logtype_afpd, "begin renamefile:");
806 if ( rename( src, dst ) < 0 ) {
809 return( AFPERR_NOOBJ );
812 return( AFPERR_ACCESS );
815 case EXDEV : /* Cross device move -- try copy */
816 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
817 deletefile( dst, 0 );
820 return deletefile( src, 0);
822 return( AFPERR_PARAM );
826 strcpy( adsrc, ad_path( src, 0 ));
829 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
834 /* check for a source appledouble header. if it exists, make
835 * a dest appledouble directory and do the rename again. */
836 if (rc || stat(adsrc, &st) ||
837 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
840 ad_close(adp, ADFLAGS_HF);
844 return( AFPERR_ACCESS );
848 return( AFPERR_PARAM );
852 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
855 return( AFPERR_NOOBJ );
857 return( AFPERR_ACCESS );
861 return( AFPERR_PARAM );
865 len = strlen( newname );
866 ad_setentrylen( adp, ADEID_NAME, len );
867 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
868 ad_flush( adp, ADFLAGS_HF );
869 ad_close( adp, ADFLAGS_HF );
872 LOG(log_info, logtype_afpd, "end renamefile:");
878 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
881 int ibuflen, *rbuflen;
885 char *newname, *path, *p, *upath;
886 u_int32_t sdid, ddid;
887 int plen, err, retvalue = AFP_OK;
888 u_int16_t svid, dvid;
891 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
897 memcpy(&svid, ibuf, sizeof( svid ));
898 ibuf += sizeof( svid );
899 if (( vol = getvolbyvid( svid )) == NULL ) {
900 return( AFPERR_PARAM );
903 memcpy(&sdid, ibuf, sizeof( sdid ));
904 ibuf += sizeof( sdid );
905 if (( dir = dirlookup( vol, sdid )) == NULL ) {
906 return( AFPERR_PARAM );
909 memcpy(&dvid, ibuf, sizeof( dvid ));
910 ibuf += sizeof( dvid );
911 memcpy(&ddid, ibuf, sizeof( ddid ));
912 ibuf += sizeof( ddid );
914 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
915 return( AFPERR_NOOBJ );
917 if ( *path == '\0' ) {
918 return( AFPERR_BADTYPE );
921 /* don't allow copies when the file is open.
922 * XXX: the spec only calls for read/deny write access.
923 * however, copyfile doesn't have any of that info,
924 * and locks need to stay coherent. as a result,
925 * we just balk if the file is opened already. */
927 newname = obj->newtmp;
928 strcpy( newname, path );
930 upath = mtoupath(vol, newname );
931 if (of_findname(upath, NULL))
932 return AFPERR_DENYCONF;
934 p = ctoupath( vol, curdir, newname );
936 /* FIXME svid != dvid && dvid's user can't read svid */
938 if (( vol = getvolbyvid( dvid )) == NULL ) {
939 return( AFPERR_PARAM );
942 if (vol->v_flags & AFPVOL_RO)
945 if (( dir = dirlookup( vol, ddid )) == NULL ) {
946 return( AFPERR_PARAM );
949 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
950 return( AFPERR_NOOBJ );
952 if ( *path != '\0' ) {
953 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
956 /* one of the handful of places that knows about the path type */
957 if ( *ibuf++ != 2 ) {
958 return( AFPERR_PARAM );
960 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
961 strncpy( newname, ibuf, plen );
962 newname[ plen ] = '\0';
963 if (strlen(newname) != plen) {
964 /* there's \0 in newname, e.g. it's a pathname not
967 return( AFPERR_PARAM );
970 upath = mtoupath(vol, newname);
971 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
976 if (vol->v_flags & AFPVOL_DROPBOX) {
977 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
979 #endif /* DROPKLUDGE */
981 setvoltime(obj, vol );
984 LOG(log_info, logtype_afpd, "end afp_copyfile:");
991 static __inline__ int copy_all(const int dfd, const void *buf,
997 LOG(log_info, logtype_afpd, "begin copy_all:");
1000 while (buflen > 0) {
1001 if ((cc = write(dfd, buf, buflen)) < 0) {
1008 return AFPERR_DFULL;
1010 return AFPERR_VLOCK;
1012 return AFPERR_PARAM;
1019 LOG(log_info, logtype_afpd, "end copy_all:");
1025 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1026 * pass in vol and path */
1027 int copyfile(src, dst, newname, noadouble )
1028 char *src, *dst, *newname;
1029 const int noadouble;
1034 int sfd, dfd, len, err = AFP_OK;
1036 char dpath[ MAXPATHLEN + 1];
1039 LOG(log_info, logtype_afpd, "begin copyfile:");
1042 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1043 admode = ad_mode( dst, 0666 );
1045 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1048 break; /* just copy the data fork */
1050 return( AFPERR_ACCESS );
1052 return( AFPERR_PARAM );
1055 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1059 return( AFPERR_NOOBJ );
1061 return( AFPERR_ACCESS );
1063 return AFPERR_VLOCK;
1065 return( AFPERR_PARAM );
1070 #ifdef SENDFILE_FLAVOR_LINUX
1071 if (fstat(sfd, &st) == 0) {
1072 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1086 goto copyheader_done;
1088 #endif /* SENDFILE_FLAVOR_LINUX */
1090 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1097 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1111 /* data fork copying */
1112 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1115 return( AFPERR_NOOBJ );
1117 return( AFPERR_ACCESS );
1119 return( AFPERR_PARAM );
1123 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1127 return( AFPERR_NOOBJ );
1129 return( AFPERR_ACCESS );
1131 return AFPERR_VLOCK;
1133 return( AFPERR_PARAM );
1137 #ifdef SENDFILE_FLAVOR_LINUX
1138 if (fstat(sfd, &st) == 0) {
1139 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1152 #endif /* SENDFILE_FLAVOR_LINUX */
1155 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1163 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1178 memset(&ad, 0, sizeof(ad));
1179 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1183 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1185 return( AFPERR_ACCESS );
1187 return AFPERR_VLOCK;
1189 return( AFPERR_PARAM );
1193 len = strlen( newname );
1194 ad_setentrylen( &ad, ADEID_NAME, len );
1195 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1196 ad_flush( &ad, ADFLAGS_HF );
1197 ad_close( &ad, ADFLAGS_HF );
1201 LOG(log_info, logtype_afpd, "end copyfile:");
1208 /* -----------------------------------
1209 checkAttrib: 1 check kFPDeleteInhibitBit
1210 ie deletfile called by afp_delete
1212 when deletefile is called we don't have lock on it, file is closed (for us)
1213 untrue if called by renamefile
1215 int deletefile( file, checkAttrib )
1220 int adflags, err = AFP_OK;
1221 int locktype = ADLOCK_WR;
1222 int openmode = O_RDWR;
1225 LOG(log_info, logtype_afpd, "begin deletefile:");
1230 * If can't open read/write then try again read-only. If it's open
1231 * read-only, we must do a read lock instead of a write lock.
1233 /* try to open both at once */
1234 adflags = ADFLAGS_DF|ADFLAGS_HF;
1235 memset(&ad, 0, sizeof(ad));
1236 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1239 adflags = ADFLAGS_DF;
1240 /* that failed. now try to open just the data fork */
1241 memset(&ad, 0, sizeof(ad));
1242 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1245 return AFPERR_NOOBJ;
1247 if(openmode == O_RDWR) {
1248 openmode = O_RDONLY;
1249 locktype = ADLOCK_RD;
1252 return AFPERR_ACCESS;
1255 return AFPERR_VLOCK;
1257 return AFPERR_PARAM;
1263 if(openmode == O_RDWR) {
1264 openmode = O_RDONLY;
1265 locktype = ADLOCK_RD;
1268 return AFPERR_ACCESS;
1271 return AFPERR_VLOCK;
1273 return( AFPERR_PARAM );
1276 break; /* from the while */
1279 * Does kFPDeleteInhibitBit (bit 8) set?
1281 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1284 ad_getattr(&ad, &bshort);
1285 if ((bshort & htons(ATTRBIT_NODELETE))) {
1286 ad_close( &ad, adflags );
1287 return(AFPERR_OLOCK);
1291 if ((adflags & ADFLAGS_HF) ) {
1292 /* FIXME we have a pb here because we want to know if a file is open
1293 * there's a 'priority inversion' if you can't open the ressource fork RW
1294 * you can delete it if it's open because you can't get a write lock.
1296 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1299 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1301 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1302 ad_close( &ad, adflags );
1303 return( AFPERR_BUSY );
1307 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1312 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1316 err = AFPERR_ACCESS;
1329 if ( unlink( file ) < 0 ) {
1333 err = AFPERR_ACCESS;
1347 if (adflags & ADFLAGS_HF)
1348 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1349 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1350 ad_close( &ad, adflags );
1353 LOG(log_info, logtype_afpd, "end deletefile:");
1361 /* return a file id */
1362 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1365 int ibuflen, *rbuflen;
1377 LOG(log_info, logtype_afpd, "begin afp_createid:");
1383 memcpy(&vid, ibuf, sizeof(vid));
1384 ibuf += sizeof(vid);
1386 if (( vol = getvolbyvid( vid )) == NULL ) {
1387 return( AFPERR_PARAM);
1390 if (vol->v_flags & AFPVOL_RO)
1391 return AFPERR_VLOCK;
1393 memcpy(&did, ibuf, sizeof( did ));
1394 ibuf += sizeof(did);
1396 if (( dir = dirlookup( vol, did )) == NULL ) {
1397 return( AFPERR_PARAM );
1400 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1401 return( AFPERR_PARAM );
1404 if ( *path == '\0' ) {
1405 return( AFPERR_BADTYPE );
1408 upath = mtoupath(vol, path);
1409 if (stat(upath, &st) < 0) {
1413 return AFPERR_ACCESS;
1415 return AFPERR_NOOBJ;
1417 return AFPERR_PARAM;
1421 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1422 memcpy(rbuf, &id, sizeof(id));
1423 *rbuflen = sizeof(id);
1424 return AFPERR_EXISTID;
1427 #if AD_VERSION > AD_VERSION1
1428 memset(&ad, 0, sizeof(ad));
1429 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1430 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1431 ad_close(&ad, ADFLAGS_HF);
1433 #endif /* AD_VERSION > AD_VERSION1 */
1435 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1436 memcpy(rbuf, &id, sizeof(id));
1437 *rbuflen = sizeof(id);
1442 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1447 return AFPERR_VLOCK;
1451 return AFPERR_ACCESS;
1454 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1455 return AFPERR_PARAM;
1459 /* resolve a file id */
1460 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1463 int ibuflen, *rbuflen;
1471 u_int16_t vid, bitmap;
1473 static char buffer[12 + MAXPATHLEN + 1];
1474 int len = 12 + MAXPATHLEN + 1;
1477 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1483 memcpy(&vid, ibuf, sizeof(vid));
1484 ibuf += sizeof(vid);
1486 if (( vol = getvolbyvid( vid )) == NULL ) {
1487 return( AFPERR_PARAM);
1490 memcpy(&id, ibuf, sizeof( id ));
1493 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1494 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1497 if (( dir = dirlookup( vol, id )) == NULL ) {
1498 return AFPERR_NOID; /* idem AFPERR_PARAM */
1501 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1505 return AFPERR_ACCESS;
1509 return AFPERR_PARAM;
1513 /* directories are bad */
1514 if (S_ISDIR(st.st_mode))
1515 return AFPERR_BADTYPE;
1517 memcpy(&bitmap, ibuf, sizeof(bitmap));
1518 bitmap = ntohs( bitmap );
1520 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1521 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1524 *rbuflen = buflen + sizeof(bitmap);
1525 memcpy(rbuf, ibuf, sizeof(bitmap));
1528 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1534 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1537 int ibuflen, *rbuflen;
1547 static char buffer[12 + MAXPATHLEN + 1];
1548 int len = 12 + MAXPATHLEN + 1;
1551 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1557 memcpy(&vid, ibuf, sizeof(vid));
1558 ibuf += sizeof(vid);
1560 if (( vol = getvolbyvid( vid )) == NULL ) {
1561 return( AFPERR_PARAM);
1564 if (vol->v_flags & AFPVOL_RO)
1565 return AFPERR_VLOCK;
1567 memcpy(&id, ibuf, sizeof( id ));
1571 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1575 if (( dir = dirlookup( vol, id )) == NULL ) {
1576 return( AFPERR_PARAM );
1580 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1584 return AFPERR_ACCESS;
1586 /* still try to delete the id */
1590 return AFPERR_PARAM;
1594 /* directories are bad */
1595 if (S_ISDIR(st.st_mode))
1596 return AFPERR_BADTYPE;
1598 if (cnid_delete(vol->v_db, fileid)) {
1601 return AFPERR_VLOCK;
1604 return AFPERR_ACCESS;
1606 return AFPERR_PARAM;
1611 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1616 #endif /* CNID_DB */
1618 #define APPLETEMP ".AppleTempXXXXXX"
1620 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1623 int ibuflen, *rbuflen;
1625 struct stat srcst, destst;
1627 struct dir *dir, *sdir;
1628 char *spath, temp[17], *path, *p;
1629 char *supath, *upath;
1633 struct adouble *adsp;
1634 struct adouble *addp;
1640 #endif /* CNID_DB */
1645 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1651 memcpy(&vid, ibuf, sizeof(vid));
1652 ibuf += sizeof(vid);
1654 if (( vol = getvolbyvid( vid )) == NULL ) {
1655 return( AFPERR_PARAM);
1658 if (vol->v_flags & AFPVOL_RO)
1659 return AFPERR_VLOCK;
1661 /* source and destination dids */
1662 memcpy(&sid, ibuf, sizeof(sid));
1663 ibuf += sizeof(sid);
1664 memcpy(&did, ibuf, sizeof(did));
1665 ibuf += sizeof(did);
1668 if ((dir = dirlookup( vol, sid )) == NULL ) {
1669 return( AFPERR_PARAM );
1672 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1673 return( AFPERR_PARAM );
1676 if ( *path == '\0' ) {
1677 return( AFPERR_BADTYPE ); /* it's a dir */
1680 upath = mtoupath(vol, path);
1681 if (stat(upath, &srcst) < 0) {
1687 return AFPERR_ACCESS;
1689 return AFPERR_PARAM;
1692 memset(&ads, 0, sizeof(ads));
1694 if ((s_of = of_findname(upath, &srcst))) {
1695 /* reuse struct adouble so it won't break locks */
1698 /* save some stuff */
1700 spath = obj->oldtmp;
1701 supath = obj->newtmp;
1702 strcpy(spath, path);
1703 strcpy(supath, upath); /* this is for the cnid changing */
1704 p = ctoupath( vol, sdir, spath);
1706 /* look for the source cnid. if it doesn't exist, don't worry about
1709 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1710 slen = strlen(supath));
1711 #endif /* CNID_DB */
1713 if (( dir = dirlookup( vol, did )) == NULL ) {
1714 return( AFPERR_PARAM );
1717 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1718 return( AFPERR_PARAM );
1721 if ( *path == '\0' ) {
1722 return( AFPERR_BADTYPE );
1725 /* FPExchangeFiles is the only call that can return the SameObj
1727 if ((curdir == sdir) && strcmp(spath, path) == 0)
1728 return AFPERR_SAMEOBJ;
1730 upath = mtoupath(vol, path);
1731 if (stat(upath, &destst) < 0) {
1737 return AFPERR_ACCESS;
1739 return AFPERR_PARAM;
1742 memset(&add, 0, sizeof(add));
1744 if ((d_of = of_findname( upath, &destst))) {
1745 /* reuse struct adouble so it won't break locks */
1749 /* they are not on the same device and at least one is open
1751 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1755 /* look for destination id. */
1756 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1757 dlen = strlen(upath));
1758 #endif /* CNID_DB */
1760 /* construct a temp name.
1761 * NOTE: the temp file will be in the dest file's directory. it
1762 * will also be inaccessible from AFP. */
1763 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1767 /* now, quickly rename the file. we error if we can't. */
1768 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1769 goto err_exchangefile;
1770 of_rename(vol, s_of, sdir, spath, curdir, temp);
1772 /* rename destination to source */
1773 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1774 goto err_src_to_tmp;
1775 of_rename(vol, d_of, curdir, path, sdir, spath);
1777 /* rename temp to destination */
1778 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1779 goto err_dest_to_src;
1780 of_rename(vol, s_of, curdir, temp, curdir, path);
1783 /* id's need switching. src -> dest and dest -> src. */
1784 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1785 upath, dlen) < 0)) {
1789 err = AFPERR_ACCESS;
1794 goto err_temp_to_dest;
1797 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1798 supath, slen) < 0)) {
1802 err = AFPERR_ACCESS;
1809 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1810 goto err_temp_to_dest;
1812 #endif /* CNID_DB */
1815 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1821 /* all this stuff is so that we can unwind a failed operation
1826 /* rename dest to temp */
1827 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1828 of_rename(vol, s_of, curdir, upath, curdir, temp);
1831 /* rename source back to dest */
1832 renamefile(p, upath, path, vol_noadouble(vol), addp);
1833 of_rename(vol, d_of, sdir, spath, curdir, path);
1836 /* rename temp back to source */
1837 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1838 of_rename(vol, s_of, curdir, temp, sdir, spath);