2 * $Id: file.c,v 1.51 2002-08-28 15:08:16 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 /* 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 getmetadata(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen, struct adouble *adp, int attrbits )
104 struct stat lst, *lstp;
105 #endif /* USE_LASTDID */
108 char *data, *nameoff = NULL, *upath;
112 u_char achar, fdType[4];
115 LOG(log_info, logtype_afpd, "begin getmetadata:");
118 upath = mtoupath(vol, path);
121 while ( bitmap != 0 ) {
122 while (( bitmap & 1 ) == 0 ) {
130 ad_getattr(adp, &ashort);
131 } else if (*upath == '.') {
132 ashort = htons(ATTRBIT_INVISIBLE);
136 ashort = htons(ntohs(ashort) | attrbits);
137 memcpy(data, &ashort, sizeof( ashort ));
138 data += sizeof( ashort );
142 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
143 data += sizeof( u_int32_t );
147 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
148 aint = AD_DATE_FROM_UNIX(st->st_mtime);
149 memcpy(data, &aint, sizeof( aint ));
150 data += sizeof( aint );
154 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
155 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
156 aint = AD_DATE_FROM_UNIX(st->st_mtime);
159 aint = AD_DATE_FROM_UNIX(st->st_mtime);
161 memcpy(data, &aint, sizeof( int ));
162 data += sizeof( int );
166 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
167 aint = AD_DATE_START;
168 memcpy(data, &aint, sizeof( int ));
169 data += sizeof( int );
174 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
176 memcpy(data, ufinderi, 32);
177 if (*upath == '.') { /* make it invisible */
178 ashort = htons(FINDERINFO_INVISIBLE);
179 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
183 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
184 && (em = getextmap( path ))
186 memcpy(data, em->em_type, sizeof( em->em_type ));
187 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
194 data += sizeof( u_int16_t );
198 memset(data, 0, sizeof(u_int16_t));
199 data += sizeof( u_int16_t );
204 #if AD_VERSION > AD_VERSION1
205 /* look in AD v2 header */
207 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
208 #endif /* AD_VERSION > AD_VERSION1 */
211 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
212 strlen(upath), aint);
213 /* Throw errors if cnid_add fails. */
214 if (aint == CNID_INVALID) {
217 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
218 return(AFPERR_PARAM);
220 return(AFPERR_PARAM);
230 * What a fucking mess. First thing: DID and FNUMs are
231 * in the same space for purposes of enumerate (and several
232 * other wierd places). While we consider this Apple's bug,
233 * this is the work-around: In order to maintain constant and
234 * unique DIDs and FNUMs, we monotonically generate the DIDs
235 * during the session, and derive the FNUMs from the filesystem.
236 * Since the DIDs are small, we insure that the FNUMs are fairly
237 * large by setting thier high bits to the device number.
239 * AFS already does something very similar to this for the
240 * inode number, so we don't repeat the procedure.
243 * due to complaints over did's being non-persistent,
244 * here's the current hack to provide semi-persistent
246 * 1) we reserve the first bit for file ids.
247 * 2) the next 7 bits are for the device.
248 * 3) the remaining 24 bits are for the inode.
250 * both the inode and device information are actually hashes
251 * that are then truncated to the requisite bit length.
253 * it should be okay to use lstat to deal with symlinks.
256 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
257 #else /* USE_LASTDID */
258 lstp = lstat(upath, &lst) < 0 ? st : &lst;
260 aint = htonl( afpd_st_cnid ( lstp ) );
262 aint = htonl(CNID(lstp, 1));
263 #endif /* DID_MTAB */
264 #endif /* USE_LASTDID */
267 memcpy(data, &aint, sizeof( aint ));
268 data += sizeof( aint );
272 aint = htonl( st->st_size );
273 memcpy(data, &aint, sizeof( aint ));
274 data += sizeof( aint );
279 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
283 memcpy(data, &aint, sizeof( aint ));
284 data += sizeof( aint );
287 /* Current client needs ProDOS info block for this file.
288 Use simple heuristic and let the Mac "type" string tell
289 us what the PD file code should be. Everything gets a
290 subtype of 0x0000 unless the original value was hashed
291 to "pXYZ" when we created it. See IA, Ver 2.
293 case FILPBIT_PDINFO :
295 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
297 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
301 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
305 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
309 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
313 else if ( fdType[0] == 'p' ) {
315 ashort = (fdType[2] * 256) + fdType[3];
329 memcpy(data, &ashort, sizeof( ashort ));
330 data += sizeof( ashort );
331 memset(data, 0, sizeof( ashort ));
332 data += sizeof( ashort );
336 return( AFPERR_BITMAP );
342 ashort = htons( data - buf );
343 memcpy(nameoff, &ashort, sizeof( ashort ));
344 if ((aint = strlen( path )) > MACFILELEN)
347 memcpy(data, path, aint );
350 *buflen = data - buf;
354 /* ----------------------- */
355 int getfilparams(struct vol *vol,
357 char *path, struct dir *dir, struct stat *st,
358 char *buf, int *buflen )
360 struct adouble ad, *adp;
363 u_int16_t attrbits = 0;
366 LOG(log_info, logtype_default, "begin getfilparams:");
369 upath = mtoupath(vol, path);
370 if ((of = of_findname(vol, dir, path))) {
372 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
373 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
376 memset(&ad, 0, sizeof(ad));
380 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
386 we need to check if the file is open by another process.
387 it's slow so we only do it if we have to:
388 - bitmap is requested.
389 - we don't already have the answer!
391 if ((bitmap & (1 << FILPBIT_ATTR))) {
392 if (!(attrbits & ATTRBIT_ROPEN)) {
394 if (!(attrbits & ATTRBIT_DOPEN)) {
399 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
401 ad_close( adp, ADFLAGS_HF );
404 LOG(log_info, logtype_afpd, "end getfilparams:");
410 /* ----------------------------- */
411 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
414 int ibuflen, *rbuflen;
417 struct adouble ad, *adp;
422 int creatf, did, openf, retvalue = AFP_OK;
426 #endif /* FORCE_UIDGID */
429 LOG(log_info, logtype_afpd, "begin afp_createfile:");
434 creatf = (unsigned char) *ibuf++;
436 memcpy(&vid, ibuf, sizeof( vid ));
437 ibuf += sizeof( vid );
439 if (( vol = getvolbyvid( vid )) == NULL ) {
440 return( AFPERR_PARAM );
443 if (vol->v_flags & AFPVOL_RO)
446 memcpy(&did, ibuf, sizeof( did));
447 ibuf += sizeof( did );
449 if (( dir = dirsearch( vol, did )) == NULL ) {
450 return( AFPERR_NOOBJ );
453 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
454 return( AFPERR_NOOBJ );
457 upath = mtoupath(vol, path);
460 if (0 != (ret = check_name(vol, upath)))
464 if ((of = of_findname(vol, curdir, path))) {
467 memset(&ad, 0, sizeof(ad));
471 /* on a hard create, fail if file exists and is open */
472 if ((stat(upath, &st) == 0) && of)
474 openf = O_RDWR|O_CREAT|O_TRUNC;
476 /* on a soft create, if the file is open then ad_open won't failed
477 because open syscall is not called
482 openf = O_RDWR|O_CREAT|O_EXCL;
487 /* preserve current euid, egid */
488 save_uidgid ( uidgid );
490 /* perform all switching of users */
493 #endif /* FORCE_UIDGID */
495 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
496 openf, 0666, adp) < 0 ) {
500 /* bring everything back to old euid, egid */
501 restore_uidgid ( uidgid );
502 #endif /* FORCE_UIDGID */
503 return( AFPERR_EXIST );
506 /* bring everything back to old euid, egid */
507 restore_uidgid ( uidgid );
508 #endif /* FORCE_UIDGID */
509 return( AFPERR_ACCESS );
511 /* on noadouble volumes, just creating the data fork is ok */
512 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
513 goto createfile_done;
517 /* bring everything back to old euid, egid */
518 restore_uidgid ( uidgid );
519 #endif /* FORCE_UIDGID */
520 return( AFPERR_PARAM );
524 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
525 memcpy(ad_entry( adp, ADEID_NAME ), path,
526 ad_getentrylen( adp, ADEID_NAME ));
527 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
528 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
533 if (vol->v_flags & AFPVOL_DROPBOX) {
534 retvalue = matchfile2dirperms(upath, vol, did);
536 #endif /* DROPKLUDGE */
538 setvoltime(obj, vol );
541 LOG(log_info, logtype_afpd, "end afp_createfile");
545 /* bring everything back to old euid, egid */
546 restore_uidgid ( uidgid );
547 #endif /* FORCE_UIDGID */
552 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
555 int ibuflen, *rbuflen;
561 u_int16_t vid, bitmap;
564 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
570 memcpy(&vid, ibuf, sizeof( vid ));
571 ibuf += sizeof( vid );
572 if (( vol = getvolbyvid( vid )) == NULL ) {
573 return( AFPERR_PARAM );
576 if (vol->v_flags & AFPVOL_RO)
579 memcpy(&did, ibuf, sizeof( did ));
580 ibuf += sizeof( did );
581 if (( dir = dirsearch( vol, did )) == NULL ) {
582 return( AFPERR_NOOBJ );
585 memcpy(&bitmap, ibuf, sizeof( bitmap ));
586 bitmap = ntohs( bitmap );
587 ibuf += sizeof( bitmap );
589 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
590 return( AFPERR_NOOBJ );
593 if ( *path == '\0' ) {
594 return( AFPERR_BADTYPE ); /* it's a directory */
597 if ((u_long)ibuf & 1 ) {
601 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
602 setvoltime(obj, vol );
606 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
613 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
617 int setfilparams(struct vol *vol,
618 char *path, u_int16_t bitmap, char *buf )
620 struct adouble ad, *adp;
623 int bit = 0, isad = 1, err = AFP_OK;
625 u_char achar, *fdType, xyy[4];
626 u_int16_t ashort, bshort;
630 int change_mdate = 0;
631 int change_parent_mdate = 0;
638 uidgid = malloc(sizeof(uidgidset));
639 #endif /* FORCE_UIDGID */
642 LOG(log_info, logtype_afpd, "begin setfilparams:");
645 upath = mtoupath(vol, path);
646 if ((of = of_findname(vol, curdir, path))) {
649 memset(&ad, 0, sizeof(ad));
654 save_uidgid ( uidgid );
656 #endif /* FORCE_UIDGID */
658 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
659 O_RDWR|O_CREAT, 0666, adp) < 0) {
660 /* for some things, we don't need an adouble header */
661 if (bitmap & ~(1<<FILPBIT_MDATE)) {
663 restore_uidgid ( uidgid );
664 #endif /* FORCE_UIDGID */
665 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
668 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
669 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
670 memcpy(ad_entry( adp, ADEID_NAME ), path,
671 ad_getentrylen( adp, ADEID_NAME ));
674 while ( bitmap != 0 ) {
675 while (( bitmap & 1 ) == 0 ) {
683 memcpy(&ashort, buf, sizeof( ashort ));
684 ad_getattr(adp, &bshort);
685 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
686 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
690 if ((ashort & htons(ATTRBIT_INVISIBLE)))
691 change_parent_mdate = 1;
692 ad_setattr(adp, bshort);
693 buf += sizeof( ashort );
698 memcpy(&aint, buf, sizeof(aint));
699 ad_setdate(adp, AD_DATE_CREATE, aint);
700 buf += sizeof( aint );
704 memcpy(&newdate, buf, sizeof( newdate ));
705 buf += sizeof( newdate );
710 memcpy(&aint, buf, sizeof(aint));
711 ad_setdate(adp, AD_DATE_BACKUP, aint);
712 buf += sizeof( aint );
718 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
720 ((em = getextmap( path )) &&
721 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
722 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
723 || ((em = getdefextmap()) &&
724 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
725 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
727 memcpy(buf, ufinderi, 8 );
730 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
734 /* Client needs to set the ProDOS file info for this file.
735 Use defined strings for the simple cases, and convert
736 all else into pXYY per Inside Appletalk. Always set
737 the creator as "pdos". <shirsch@ibm.net> */
738 case FILPBIT_PDINFO :
741 memcpy(&ashort, buf, sizeof( ashort ));
742 ashort = ntohs( ashort );
745 switch ( (unsigned int) achar )
748 fdType = ( u_char *) "TEXT";
752 fdType = ( u_char *) "PSYS";
756 fdType = ( u_char *) "PS16";
760 fdType = ( u_char *) "BINA";
764 xyy[0] = ( u_char ) 'p';
766 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
767 xyy[3] = ( u_char ) ashort & 0xff;
772 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
773 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
779 goto setfilparam_done;
787 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
788 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
792 ad_setdate(adp, AD_DATE_MODIFY, newdate);
793 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
798 ad_flush( adp, ADFLAGS_HF );
799 ad_close( adp, ADFLAGS_HF );
802 restore_uidgid ( uidgid );
803 #endif /* FORCE_UIDGID */
807 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
808 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
809 bitmap = 1<<FILPBIT_MDATE;
810 setdirparams(vol, "", bitmap, (char *)&newdate);
814 LOG(log_info, logtype_afpd, "end setfilparams:");
820 * renamefile and copyfile take the old and new unix pathnames
821 * and the new mac name.
822 * NOTE: if we have to copy a file instead of renaming it, locks
823 * will break. Anyway it's an error because then we have 2 files.
824 * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
826 * src the full source absolute path
827 * dst the dest filename in current dir
828 * newname the dest mac name
829 * adp adouble struct of src file, if open, or & zeroed one
832 int renamefile(src, dst, newname, noadouble, adp )
833 char *src, *dst, *newname;
837 char adsrc[ MAXPATHLEN + 1];
841 * Note that this is only checking the existance of the data file,
842 * not the header file. The thinking is that if the data file doesn't
843 * exist, but the header file does, the right thing to do is remove
844 * the data file silently.
847 /* existence check moved to afp_moveandrename */
850 LOG(log_info, logtype_afpd, "begin renamefile:");
853 if ( rename( src, dst ) < 0 ) {
856 return( AFPERR_NOOBJ );
859 return( AFPERR_ACCESS );
862 case EXDEV : /* Cross device move -- try copy */
863 /* if source is open bail out */
864 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
865 deletefile( dst, 0 );
868 return deletefile( src, 0);
870 return( AFPERR_PARAM );
874 strcpy( adsrc, ad_path( src, 0 ));
877 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
882 /* check for a source appledouble header. if it exists, make
883 * a dest appledouble directory and do the rename again. */
884 if (rc || stat(adsrc, &st) ||
885 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
888 ad_close(adp, ADFLAGS_HF);
892 return( AFPERR_ACCESS );
896 return( AFPERR_PARAM );
900 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
903 return( AFPERR_NOOBJ );
905 return( AFPERR_ACCESS );
909 return( AFPERR_PARAM );
913 len = strlen( newname );
914 ad_setentrylen( adp, ADEID_NAME, len );
915 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
916 ad_flush( adp, ADFLAGS_HF );
917 ad_close( adp, ADFLAGS_HF );
920 LOG(log_info, logtype_afpd, "end renamefile:");
926 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
929 int ibuflen, *rbuflen;
933 char *newname, *path, *p;
934 u_int32_t sdid, ddid;
935 int plen, err, retvalue = AFP_OK;
936 u_int16_t svid, dvid;
939 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
945 memcpy(&svid, ibuf, sizeof( svid ));
946 ibuf += sizeof( svid );
947 if (( vol = getvolbyvid( svid )) == NULL ) {
948 return( AFPERR_PARAM );
951 memcpy(&sdid, ibuf, sizeof( sdid ));
952 ibuf += sizeof( sdid );
953 if (( dir = dirsearch( vol, sdid )) == NULL ) {
954 return( AFPERR_PARAM );
957 memcpy(&dvid, ibuf, sizeof( dvid ));
958 ibuf += sizeof( dvid );
959 memcpy(&ddid, ibuf, sizeof( ddid ));
960 ibuf += sizeof( ddid );
962 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
963 return( AFPERR_NOOBJ );
965 if ( *path == '\0' ) {
966 return( AFPERR_BADTYPE );
969 /* don't allow copies when the file is open.
970 * XXX: the spec only calls for read/deny write access.
971 * however, copyfile doesn't have any of that info,
972 * and locks need to stay coherent. as a result,
973 * we just balk if the file is opened already. */
974 if (of_findname(vol, curdir, path))
975 return AFPERR_DENYCONF;
977 newname = obj->newtmp;
978 strcpy( newname, path );
980 p = ctoupath( vol, curdir, newname );
982 if (( vol = getvolbyvid( dvid )) == NULL ) {
983 return( AFPERR_PARAM );
986 if (vol->v_flags & AFPVOL_RO)
989 if (( dir = dirsearch( vol, ddid )) == NULL ) {
990 return( AFPERR_PARAM );
993 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
994 return( AFPERR_NOOBJ );
996 if ( *path != '\0' ) {
997 return( AFPERR_BADTYPE );
1000 /* one of the handful of places that knows about the path type */
1001 if ( *ibuf++ != 2 ) {
1002 return( AFPERR_PARAM );
1004 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1005 strncpy( newname, ibuf, plen );
1006 newname[ plen ] = '\0';
1009 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
1010 vol_noadouble(vol))) < 0 ) {
1014 setvoltime(obj, vol );
1017 if (vol->v_flags & AFPVOL_DROPBOX) {
1018 retvalue=matchfile2dirperms(newname, vol, sdid);
1020 #endif /* DROPKLUDGE */
1023 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1030 static __inline__ int copy_all(const int dfd, const void *buf,
1036 LOG(log_info, logtype_afpd, "begin copy_all:");
1039 while (buflen > 0) {
1040 if ((cc = write(dfd, buf, buflen)) < 0) {
1047 return AFPERR_DFULL;
1049 return AFPERR_VLOCK;
1051 return AFPERR_PARAM;
1058 LOG(log_info, logtype_afpd, "end copy_all:");
1064 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1065 * pass in vol and path */
1066 int copyfile(src, dst, newname, noadouble )
1067 char *src, *dst, *newname;
1068 const int noadouble;
1073 int sfd, dfd, len, err = AFP_OK;
1077 LOG(log_info, logtype_afpd, "begin copyfile:");
1081 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1084 break; /* just copy the data fork */
1086 return( AFPERR_ACCESS );
1088 return( AFPERR_PARAM );
1091 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1092 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1096 return( AFPERR_NOOBJ );
1098 return( AFPERR_ACCESS );
1100 return AFPERR_VLOCK;
1102 return( AFPERR_PARAM );
1107 #ifdef SENDFILE_FLAVOR_LINUX
1108 if (fstat(sfd, &st) == 0) {
1109 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1123 goto copyheader_done;
1125 #endif /* SENDFILE_FLAVOR_LINUX */
1127 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1134 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1142 unlink(ad_path(dst, ADFLAGS_HF));
1148 /* data fork copying */
1149 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1152 return( AFPERR_NOOBJ );
1154 return( AFPERR_ACCESS );
1156 return( AFPERR_PARAM );
1160 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1164 return( AFPERR_NOOBJ );
1166 return( AFPERR_ACCESS );
1168 return AFPERR_VLOCK;
1170 return( AFPERR_PARAM );
1174 #ifdef SENDFILE_FLAVOR_LINUX
1175 if (fstat(sfd, &st) == 0) {
1176 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1189 #endif /* SENDFILE_FLAVOR_LINUX */
1192 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1200 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1209 unlink(ad_path(dst, ADFLAGS_HF));
1215 memset(&ad, 0, sizeof(ad));
1216 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1220 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1222 return( AFPERR_ACCESS );
1224 return AFPERR_VLOCK;
1226 return( AFPERR_PARAM );
1230 len = strlen( newname );
1231 ad_setentrylen( &ad, ADEID_NAME, len );
1232 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1233 ad_flush( &ad, ADFLAGS_HF );
1234 ad_close( &ad, ADFLAGS_HF );
1238 LOG(log_info, logtype_afpd, "end copyfile:");
1245 /* -----------------------------------
1246 checkAttrib: 1 check kFPDeleteInhibitBit
1247 ie deletfile called by afp_delete
1249 when deletefile is called we don't have lock on it, file is closed (for us)
1251 int deletefile( file, checkAttrib )
1256 int adflags, err = AFP_OK;
1257 int locktype = ADLOCK_WR;
1258 int openmode = O_RDWR;
1261 LOG(log_info, logtype_afpd, "begin deletefile:");
1266 * If can't open read/write then try again read-only. If it's open
1267 * read-only, we must do a read lock instead of a write lock.
1269 /* try to open both at once */
1270 adflags = ADFLAGS_DF|ADFLAGS_HF;
1271 memset(&ad, 0, sizeof(ad));
1272 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1275 adflags = ADFLAGS_DF;
1276 /* that failed. now try to open just the data fork */
1277 memset(&ad, 0, sizeof(ad));
1278 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1281 return AFPERR_NOOBJ;
1283 if(openmode == O_RDWR) {
1284 openmode = O_RDONLY;
1285 locktype = ADLOCK_RD;
1288 return AFPERR_ACCESS;
1291 return AFPERR_VLOCK;
1293 return AFPERR_PARAM;
1299 if(openmode == O_RDWR) {
1300 openmode = O_RDONLY;
1301 locktype = ADLOCK_RD;
1304 return AFPERR_ACCESS;
1307 return AFPERR_VLOCK;
1309 return( AFPERR_PARAM );
1312 break; /* from the while */
1315 * Does kFPDeleteInhibitBit (bit 8) set?
1317 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1320 ad_getattr(&ad, &bshort);
1321 if ((bshort & htons(ATTRBIT_NODELETE))) {
1322 ad_close( &ad, adflags );
1323 return(AFPERR_OLOCK);
1327 if ((adflags & ADFLAGS_HF) ) {
1328 /* FIXME we have a pb here because we want to know if a file is open
1329 * there's a 'priority inversion' if you can't open the ressource fork RW
1330 * you can delete it if it's open because you can't get a write lock.
1332 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1335 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1337 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1338 ad_close( &ad, adflags );
1339 return( AFPERR_BUSY );
1343 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1348 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1352 err = AFPERR_ACCESS;
1365 if ( unlink( file ) < 0 ) {
1369 err = AFPERR_ACCESS;
1383 if (adflags & ADFLAGS_HF)
1384 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1385 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1386 ad_close( &ad, adflags );
1389 LOG(log_info, logtype_afpd, "end deletefile:");
1397 /* return a file id */
1398 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1401 int ibuflen, *rbuflen;
1413 LOG(log_info, logtype_afpd, "begin afp_createid:");
1419 memcpy(&vid, ibuf, sizeof(vid));
1420 ibuf += sizeof(vid);
1422 if (( vol = getvolbyvid( vid )) == NULL ) {
1423 return( AFPERR_PARAM);
1426 if (vol->v_flags & AFPVOL_RO)
1427 return AFPERR_VLOCK;
1429 memcpy(&did, ibuf, sizeof( did ));
1430 ibuf += sizeof(did);
1432 if (( dir = dirsearch( vol, did )) == NULL ) {
1433 return( AFPERR_PARAM );
1436 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1437 return( AFPERR_PARAM );
1440 if ( *path == '\0' ) {
1441 return( AFPERR_BADTYPE );
1444 upath = mtoupath(vol, path);
1445 if (stat(upath, &st) < 0) {
1449 return AFPERR_ACCESS;
1451 return AFPERR_NOOBJ;
1453 return AFPERR_PARAM;
1457 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1458 memcpy(rbuf, &id, sizeof(id));
1459 *rbuflen = sizeof(id);
1460 return AFPERR_EXISTID;
1463 #if AD_VERSION > AD_VERSION1
1464 memset(&ad, 0, sizeof(ad));
1465 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1466 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1467 ad_close(&ad, ADFLAGS_HF);
1469 #endif /* AD_VERSION > AD_VERSION1 */
1471 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1472 memcpy(rbuf, &id, sizeof(id));
1473 *rbuflen = sizeof(id);
1478 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1483 return AFPERR_VLOCK;
1487 return AFPERR_ACCESS;
1490 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1491 return AFPERR_PARAM;
1495 /* resolve a file id */
1496 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1499 int ibuflen, *rbuflen;
1507 u_int16_t vid, bitmap;
1509 static char buffer[12 + MAXPATHLEN + 1];
1510 int len = 12 + MAXPATHLEN + 1;
1513 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1519 memcpy(&vid, ibuf, sizeof(vid));
1520 ibuf += sizeof(vid);
1522 if (( vol = getvolbyvid( vid )) == NULL ) {
1523 return( AFPERR_PARAM);
1526 memcpy(&id, ibuf, sizeof( id ));
1529 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1530 return AFPERR_BADID;
1533 if (( dir = dirlookup( vol, id )) == NULL ) {
1534 return( AFPERR_PARAM );
1537 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1541 return AFPERR_ACCESS;
1545 return AFPERR_PARAM;
1549 /* directories are bad */
1550 if (S_ISDIR(st.st_mode))
1551 return AFPERR_BADTYPE;
1553 memcpy(&bitmap, ibuf, sizeof(bitmap));
1554 bitmap = ntohs( bitmap );
1556 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1557 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1560 *rbuflen = buflen + sizeof(bitmap);
1561 memcpy(rbuf, ibuf, sizeof(bitmap));
1564 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1570 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1573 int ibuflen, *rbuflen;
1583 static char buffer[12 + MAXPATHLEN + 1];
1584 int len = 12 + MAXPATHLEN + 1;
1587 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1593 memcpy(&vid, ibuf, sizeof(vid));
1594 ibuf += sizeof(vid);
1596 if (( vol = getvolbyvid( vid )) == NULL ) {
1597 return( AFPERR_PARAM);
1600 if (vol->v_flags & AFPVOL_RO)
1601 return AFPERR_VLOCK;
1603 memcpy(&id, ibuf, sizeof( id ));
1607 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1611 if (( dir = dirlookup( vol, id )) == NULL ) {
1612 return( AFPERR_PARAM );
1616 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1620 return AFPERR_ACCESS;
1622 /* still try to delete the id */
1626 return AFPERR_PARAM;
1630 /* directories are bad */
1631 if (S_ISDIR(st.st_mode))
1632 return AFPERR_BADTYPE;
1634 if (cnid_delete(vol->v_db, fileid)) {
1637 return AFPERR_VLOCK;
1640 return AFPERR_ACCESS;
1642 return AFPERR_PARAM;
1647 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1652 #endif /* CNID_DB */
1654 #define APPLETEMP ".AppleTempXXXXXX"
1656 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1659 int ibuflen, *rbuflen;
1661 struct stat srcst, destst;
1663 struct dir *dir, *sdir;
1664 char *spath, temp[17], *path, *p;
1665 char *supath, *upath;
1669 struct adouble *adsp;
1670 struct adouble *addp;
1671 struct ofork *opened;
1675 #endif /* CNID_DB */
1680 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1686 memcpy(&vid, ibuf, sizeof(vid));
1687 ibuf += sizeof(vid);
1689 if (( vol = getvolbyvid( vid )) == NULL ) {
1690 return( AFPERR_PARAM);
1693 if (vol->v_flags & AFPVOL_RO)
1694 return AFPERR_VLOCK;
1696 /* source and destination dids */
1697 memcpy(&sid, ibuf, sizeof(sid));
1698 ibuf += sizeof(sid);
1699 memcpy(&did, ibuf, sizeof(did));
1700 ibuf += sizeof(did);
1703 if ((dir = dirsearch( vol, sid )) == NULL ) {
1704 return( AFPERR_PARAM );
1707 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1708 return( AFPERR_PARAM );
1711 if ( *path == '\0' ) {
1712 return( AFPERR_BADTYPE ); /* it's a dir */
1715 upath = mtoupath(vol, path);
1716 if (stat(upath, &srcst) < 0) {
1722 return AFPERR_ACCESS;
1724 return AFPERR_PARAM;
1727 memset(&ads, 0, sizeof(ads));
1729 if ((opened = of_findname(vol, curdir, path))) {
1730 /* reuse struct adouble so it won't break locks */
1731 adsp = opened->of_ad;
1733 /* save some stuff */
1735 spath = obj->oldtmp;
1736 supath = obj->newtmp;
1737 strcpy(spath, path);
1738 strcpy(supath, upath); /* this is for the cnid changing */
1739 p = ctoupath( vol, sdir, spath);
1741 /* look for the source cnid. if it doesn't exist, don't worry about
1744 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1745 slen = strlen(supath));
1746 #endif /* CNID_DB */
1748 if (( dir = dirsearch( vol, did )) == NULL ) {
1749 return( AFPERR_PARAM );
1752 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1753 return( AFPERR_PARAM );
1756 if ( *path == '\0' ) {
1757 return( AFPERR_BADTYPE );
1760 /* FPExchangeFiles is the only call that can return the SameObj
1762 if ((curdir == sdir) && strcmp(spath, path) == 0)
1763 return AFPERR_SAMEOBJ;
1765 upath = mtoupath(vol, path);
1766 if (stat(upath, &destst) < 0) {
1772 return AFPERR_ACCESS;
1774 return AFPERR_PARAM;
1777 memset(&add, 0, sizeof(add));
1779 if ((opened = of_findname(vol, curdir, path))) {
1780 /* reuse struct adouble so it won't break locks */
1781 addp = opened->of_ad;
1784 /* look for destination id. */
1785 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1786 dlen = strlen(upath));
1787 #endif /* CNID_DB */
1789 /* construct a temp name.
1790 * NOTE: the temp file will be in the dest file's directory. it
1791 * will also be inaccessible from AFP. */
1792 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1796 /* now, quickly rename the file. we error if we can't. */
1797 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1798 goto err_exchangefile;
1799 of_rename(vol, sdir, spath, curdir, temp);
1801 /* rename destination to source */
1802 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1803 goto err_src_to_tmp;
1804 of_rename(vol, curdir, path, sdir, spath);
1806 /* rename temp to destination */
1807 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1808 goto err_dest_to_src;
1809 of_rename(vol, curdir, temp, curdir, path);
1812 /* id's need switching. src -> dest and dest -> src. */
1813 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1814 upath, dlen) < 0)) {
1818 err = AFPERR_ACCESS;
1823 goto err_temp_to_dest;
1826 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1827 supath, slen) < 0)) {
1831 err = AFPERR_ACCESS;
1838 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1839 goto err_temp_to_dest;
1841 #endif /* CNID_DB */
1844 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1850 /* all this stuff is so that we can unwind a failed operation
1855 /* rename dest to temp */
1856 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1857 of_rename(vol, curdir, upath, curdir, temp);
1860 /* rename source back to dest */
1861 renamefile(p, upath, path, vol_noadouble(vol), addp);
1862 of_rename(vol, sdir, spath, curdir, path);
1865 /* rename temp back to source */
1866 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1867 of_rename(vol, curdir, temp, sdir, spath);