2 * $Id: file.c,v 1.70 2003-01-08 15:01:34 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 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
94 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(char *data, const char *name, u_int32_t utf8)
115 aint = strlen( name );
118 if (afp_version >= 30) {
119 /* the name is in utf8 */
121 if (aint > MACFILELEN)
128 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
132 memcpy(data, &utf8, sizeof(utf8));
133 data += sizeof(utf8);
136 memcpy(data, &temp, sizeof(temp));
137 data += sizeof(temp);
140 memcpy( data, name, aint );
147 * FIXME: PDINFO is UTF8 and doesn't need adp
149 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
150 (1 << FILPBIT_CDATE) |\
151 (1 << FILPBIT_MDATE) |\
152 (1 << FILPBIT_BDATE) |\
153 (1 << FILPBIT_FINFO) |\
154 (1 << FILPBIT_RFLEN) |\
155 (1 << FILPBIT_EXTRFLEN) |\
156 (1 << FILPBIT_PDINFO)))
159 /* -------------------------- */
160 int getmetadata(struct vol *vol,
162 char *path, struct dir *dir, struct stat *st,
163 char *buf, int *buflen, struct adouble *adp, int attrbits )
166 struct stat lst, *lstp;
167 #endif /* USE_LASTDID */
168 char *data, *l_nameoff = NULL, *upath;
169 char *utf_nameoff = NULL;
173 u_char achar, fdType[4];
177 LOG(log_info, logtype_afpd, "begin getmetadata:");
180 upath = mtoupath(vol, path);
183 while ( bitmap != 0 ) {
184 while (( bitmap & 1 ) == 0 ) {
192 ad_getattr(adp, &ashort);
193 } else if (*upath == '.') {
194 ashort = htons(ATTRBIT_INVISIBLE);
198 /* FIXME do we want a visual clue if the file is read only
201 accessmode( ".", &ma, dir , NULL);
202 if ((ma.ma_user & AR_UWRITE)) {
203 accessmode( upath, &ma, dir , st);
204 if (!(ma.ma_user & AR_UWRITE)) {
205 attrbits |= ATTRBIT_NOWRITE;
210 ashort = htons(ntohs(ashort) | attrbits);
211 memcpy(data, &ashort, sizeof( ashort ));
212 data += sizeof( ashort );
216 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
217 data += sizeof( u_int32_t );
221 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
222 aint = AD_DATE_FROM_UNIX(st->st_mtime);
223 memcpy(data, &aint, sizeof( aint ));
224 data += sizeof( aint );
228 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
229 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
230 aint = AD_DATE_FROM_UNIX(st->st_mtime);
233 aint = AD_DATE_FROM_UNIX(st->st_mtime);
235 memcpy(data, &aint, sizeof( int ));
236 data += sizeof( int );
240 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
241 aint = AD_DATE_START;
242 memcpy(data, &aint, sizeof( int ));
243 data += sizeof( int );
247 get_finderinfo(path, adp, (char *)data);
249 if (*upath == '.') { /* make it invisible */
250 ashort = htons(FINDERINFO_INVISIBLE);
251 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
260 data += sizeof( u_int16_t );
264 memset(data, 0, sizeof(u_int16_t));
265 data += sizeof( u_int16_t );
270 #if AD_VERSION > AD_VERSION1
271 /* look in AD v2 header */
273 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
274 #endif /* AD_VERSION > AD_VERSION1 */
277 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
278 strlen(upath), aint);
279 /* Throw errors if cnid_add fails. */
280 if (aint == CNID_INVALID) {
283 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
284 return(AFPERR_PARAM);
286 return(AFPERR_PARAM);
296 * What a fucking mess. First thing: DID and FNUMs are
297 * in the same space for purposes of enumerate (and several
298 * other wierd places). While we consider this Apple's bug,
299 * this is the work-around: In order to maintain constant and
300 * unique DIDs and FNUMs, we monotonically generate the DIDs
301 * during the session, and derive the FNUMs from the filesystem.
302 * Since the DIDs are small, we insure that the FNUMs are fairly
303 * large by setting thier high bits to the device number.
305 * AFS already does something very similar to this for the
306 * inode number, so we don't repeat the procedure.
309 * due to complaints over did's being non-persistent,
310 * here's the current hack to provide semi-persistent
312 * 1) we reserve the first bit for file ids.
313 * 2) the next 7 bits are for the device.
314 * 3) the remaining 24 bits are for the inode.
316 * both the inode and device information are actually hashes
317 * that are then truncated to the requisite bit length.
319 * it should be okay to use lstat to deal with symlinks.
322 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
323 #else /* USE_LASTDID */
324 lstp = lstat(upath, &lst) < 0 ? st : &lst;
325 aint = htonl(CNID(lstp, 1));
326 #endif /* USE_LASTDID */
329 memcpy(data, &aint, sizeof( aint ));
330 data += sizeof( aint );
334 if (st->st_size > 0xffffffff)
337 aint = htonl( st->st_size );
338 memcpy(data, &aint, sizeof( aint ));
339 data += sizeof( aint );
344 if (adp->ad_rlen > 0xffffffff)
347 aint = htonl( adp->ad_rlen);
351 memcpy(data, &aint, sizeof( aint ));
352 data += sizeof( aint );
355 /* Current client needs ProDOS info block for this file.
356 Use simple heuristic and let the Mac "type" string tell
357 us what the PD file code should be. Everything gets a
358 subtype of 0x0000 unless the original value was hashed
359 to "pXYZ" when we created it. See IA, Ver 2.
361 case FILPBIT_PDINFO :
362 if (afp_version >= 30) { /* UTF8 name */
363 utf8 = kTextEncodingUTF8;
365 data += sizeof( u_int16_t );
367 memcpy(data, &aint, sizeof( aint ));
368 data += sizeof( aint );
372 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
374 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
378 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
382 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
386 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
390 else if ( fdType[0] == 'p' ) {
392 ashort = (fdType[2] * 256) + fdType[3];
406 memcpy(data, &ashort, sizeof( ashort ));
407 data += sizeof( ashort );
408 memset(data, 0, sizeof( ashort ));
409 data += sizeof( ashort );
412 case FILPBIT_EXTDFLEN:
413 aint = htonl(st->st_size >> 32);
414 memcpy(data, &aint, sizeof( aint ));
415 data += sizeof( aint );
416 aint = htonl(st->st_size);
417 memcpy(data, &aint, sizeof( aint ));
418 data += sizeof( aint );
420 case FILPBIT_EXTRFLEN:
423 aint = htonl(adp->ad_rlen >> 32);
424 memcpy(data, &aint, sizeof( aint ));
425 data += sizeof( aint );
427 aint = htonl(adp->ad_rlen);
428 memcpy(data, &aint, sizeof( aint ));
429 data += sizeof( aint );
432 return( AFPERR_BITMAP );
438 ashort = htons( data - buf );
439 memcpy(l_nameoff, &ashort, sizeof( ashort ));
440 data = set_name(data, path, 0);
443 ashort = htons( data - buf );
444 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
445 data = set_name(data, path, utf8);
447 *buflen = data - buf;
451 /* ----------------------- */
452 int getfilparams(struct vol *vol,
454 struct path *path, struct dir *dir,
455 char *buf, int *buflen )
457 struct adouble ad, *adp;
460 u_int16_t attrbits = 0;
465 LOG(log_info, logtype_default, "begin getfilparams:");
468 opened = PARAM_NEED_ADP(bitmap);
471 upath = path->u_name;
472 if ((of = of_findname(path))) {
474 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
475 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
477 memset(&ad, 0, sizeof(ad));
481 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
486 we need to check if the file is open by another process.
487 it's slow so we only do it if we have to:
488 - bitmap is requested.
489 - we don't already have the answer!
491 if ((bitmap & (1 << FILPBIT_ATTR))) {
492 if (!(attrbits & ATTRBIT_ROPEN)) {
494 if (!(attrbits & ATTRBIT_DOPEN)) {
499 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
501 ad_close( adp, ADFLAGS_HF );
504 LOG(log_info, logtype_afpd, "end getfilparams:");
510 /* ----------------------------- */
511 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
514 int ibuflen, *rbuflen;
517 struct adouble ad, *adp;
520 struct ofork *of = NULL;
522 int creatf, did, openf, retvalue = AFP_OK;
528 LOG(log_info, logtype_afpd, "begin afp_createfile:");
533 creatf = (unsigned char) *ibuf++;
535 memcpy(&vid, ibuf, sizeof( vid ));
536 ibuf += sizeof( vid );
538 if (( vol = getvolbyvid( vid )) == NULL ) {
539 return( AFPERR_PARAM );
542 if (vol->v_flags & AFPVOL_RO)
545 memcpy(&did, ibuf, sizeof( did));
546 ibuf += sizeof( did );
548 if (( dir = dirlookup( vol, did )) == NULL ) {
552 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
556 if ( *s_path->m_name == '\0' ) {
557 return( AFPERR_BADTYPE );
560 upath = s_path->u_name;
561 if (0 != (ret = check_name(vol, upath)))
564 /* if upath is deleted we already in trouble anyway */
565 if ((of = of_findname(s_path))) {
568 memset(&ad, 0, sizeof(ad));
572 /* on a hard create, fail if file exists and is open */
575 openf = O_RDWR|O_CREAT|O_TRUNC;
577 /* on a soft create, if the file is open then ad_open won't fail
578 because open syscall is not called
583 openf = O_RDWR|O_CREAT|O_EXCL;
586 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
587 openf, 0666, adp) < 0 ) {
590 return( AFPERR_EXIST );
592 return( AFPERR_ACCESS );
594 /* on noadouble volumes, just creating the data fork is ok */
596 if (vol_noadouble(vol) && (stat(upath, st) == 0))
597 goto createfile_done;
600 return( AFPERR_PARAM );
603 path = s_path->m_name;
604 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
605 memcpy(ad_entry( adp, ADEID_NAME ), path,
606 ad_getentrylen( adp, ADEID_NAME ));
607 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
608 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
614 if (vol->v_flags & AFPVOL_DROPBOX) {
615 retvalue = matchfile2dirperms(upath, vol, did);
617 #endif /* DROPKLUDGE */
619 setvoltime(obj, vol );
622 LOG(log_info, logtype_afpd, "end afp_createfile");
628 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
631 int ibuflen, *rbuflen;
637 u_int16_t vid, bitmap;
640 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
646 memcpy(&vid, ibuf, sizeof( vid ));
647 ibuf += sizeof( vid );
648 if (( vol = getvolbyvid( vid )) == NULL ) {
649 return( AFPERR_PARAM );
652 if (vol->v_flags & AFPVOL_RO)
655 memcpy(&did, ibuf, sizeof( did ));
656 ibuf += sizeof( did );
657 if (( dir = dirlookup( vol, did )) == NULL ) {
658 return( AFPERR_NOOBJ );
661 memcpy(&bitmap, ibuf, sizeof( bitmap ));
662 bitmap = ntohs( bitmap );
663 ibuf += sizeof( bitmap );
665 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
669 if ( *s_path->m_name == '\0' ) {
670 return( AFPERR_BADTYPE ); /* it's a directory */
673 if ((u_long)ibuf & 1 ) {
677 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
678 setvoltime(obj, vol );
682 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
689 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
692 extern struct path Cur_Path;
694 int setfilparams(struct vol *vol,
695 struct path *path, u_int16_t bitmap, char *buf )
697 struct adouble ad, *adp;
700 int bit = 0, isad = 1, err = AFP_OK;
702 u_char achar, *fdType, xyy[4];
703 u_int16_t ashort, bshort;
707 int change_mdate = 0;
708 int change_parent_mdate = 0;
714 LOG(log_info, logtype_afpd, "begin setfilparams:");
717 upath = path->u_name;
718 if ((of = of_findname(path))) {
721 memset(&ad, 0, sizeof(ad));
725 if (check_access(upath, OPENACC_WR ) < 0) {
726 return AFPERR_ACCESS;
729 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
730 O_RDWR|O_CREAT, 0666, adp) < 0) {
731 /* for some things, we don't need an adouble header */
732 if (bitmap & ~(1<<FILPBIT_MDATE)) {
733 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
736 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
737 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
738 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
739 ad_getentrylen( adp, ADEID_NAME ));
742 while ( bitmap != 0 ) {
743 while (( bitmap & 1 ) == 0 ) {
751 memcpy(&ashort, buf, sizeof( ashort ));
752 ad_getattr(adp, &bshort);
753 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
754 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
758 if ((ashort & htons(ATTRBIT_INVISIBLE)))
759 change_parent_mdate = 1;
760 ad_setattr(adp, bshort);
761 buf += sizeof( ashort );
766 memcpy(&aint, buf, sizeof(aint));
767 ad_setdate(adp, AD_DATE_CREATE, aint);
768 buf += sizeof( aint );
772 memcpy(&newdate, buf, sizeof( newdate ));
773 buf += sizeof( newdate );
778 memcpy(&aint, buf, sizeof(aint));
779 ad_setdate(adp, AD_DATE_BACKUP, aint);
780 buf += sizeof( aint );
786 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
788 ((em = getextmap( path->m_name )) &&
789 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
790 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
791 || ((em = getdefextmap()) &&
792 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
793 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
795 memcpy(buf, ufinderi, 8 );
798 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
802 /* Client needs to set the ProDOS file info for this file.
803 Use defined strings for the simple cases, and convert
804 all else into pXYY per Inside Appletalk. Always set
805 the creator as "pdos". <shirsch@ibm.net> */
806 case FILPBIT_PDINFO :
809 memcpy(&ashort, buf, sizeof( ashort ));
810 ashort = ntohs( ashort );
813 switch ( (unsigned int) achar )
816 fdType = ( u_char *) "TEXT";
820 fdType = ( u_char *) "PSYS";
824 fdType = ( u_char *) "PS16";
828 fdType = ( u_char *) "BINA";
832 xyy[0] = ( u_char ) 'p';
834 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
835 xyy[3] = ( u_char ) ashort & 0xff;
840 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
841 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
847 goto setfilparam_done;
855 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
856 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
860 ad_setdate(adp, AD_DATE_MODIFY, newdate);
861 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
866 ad_flush( adp, ADFLAGS_HF );
867 ad_close( adp, ADFLAGS_HF );
871 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
872 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
873 bitmap = 1<<FILPBIT_MDATE;
874 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
878 LOG(log_info, logtype_afpd, "end setfilparams:");
884 * renamefile and copyfile take the old and new unix pathnames
885 * and the new mac name.
886 * NOTE: if we have to copy a file instead of renaming it, locks
887 * will break. Anyway it's an error because then we have 2 files.
889 * src the source path
890 * dst the dest filename in current dir
891 * newname the dest mac name
892 * adp adouble struct of src file, if open, or & zeroed one
895 int renamefile(src, dst, newname, noadouble, adp )
896 char *src, *dst, *newname;
900 char adsrc[ MAXPATHLEN + 1];
904 * Note that this is only checking the existance of the data file,
905 * not the header file. The thinking is that if the data file doesn't
906 * exist, but the header file does, the right thing to do is remove
907 * the data file silently.
910 /* existence check moved to afp_moveandrename */
913 LOG(log_info, logtype_afpd, "begin renamefile:");
916 if ( unix_rename( src, dst ) < 0 ) {
919 return( AFPERR_NOOBJ );
922 return( AFPERR_ACCESS );
925 case EXDEV : /* Cross device move -- try copy */
926 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
927 deletefile( dst, 0 );
930 return deletefile( src, 0);
932 return( AFPERR_PARAM );
936 strcpy( adsrc, ad_path( src, 0 ));
939 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
944 /* check for a source appledouble header. if it exists, make
945 * a dest appledouble directory and do the rename again. */
946 if (rc || stat(adsrc, &st) ||
947 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
950 ad_close(adp, ADFLAGS_HF);
954 return( AFPERR_ACCESS );
958 return( AFPERR_PARAM );
962 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
965 return( AFPERR_NOOBJ );
967 return( AFPERR_ACCESS );
971 return( AFPERR_PARAM );
975 len = strlen( newname );
976 ad_setentrylen( adp, ADEID_NAME, len );
977 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
978 ad_flush( adp, ADFLAGS_HF );
979 ad_close( adp, ADFLAGS_HF );
982 LOG(log_info, logtype_afpd, "end renamefile:");
988 int copy_path_name(char *newname, char *ibuf)
995 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1001 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1002 strncpy( newname, ibuf, plen );
1003 newname[ plen ] = '\0';
1004 if (strlen(newname) != plen) {
1005 /* there's \0 in newname, e.g. it's a pathname not
1013 memcpy(&hint, ibuf, sizeof(hint));
1014 ibuf += sizeof(hint);
1016 memcpy(&len16, ibuf, sizeof(len16));
1017 ibuf += sizeof(len16);
1018 plen = ntohs(len16);
1020 strncpy( newname, ibuf, plen );
1021 newname[ plen ] = '\0';
1022 if (strchr(newname,'/')) {
1031 /* -----------------------------------
1033 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1036 int ibuflen, *rbuflen;
1040 char *newname, *p, *upath;
1041 struct path *s_path;
1042 u_int32_t sdid, ddid;
1043 int err, retvalue = AFP_OK;
1044 u_int16_t svid, dvid;
1047 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1053 memcpy(&svid, ibuf, sizeof( svid ));
1054 ibuf += sizeof( svid );
1055 if (( vol = getvolbyvid( svid )) == NULL ) {
1056 return( AFPERR_PARAM );
1059 memcpy(&sdid, ibuf, sizeof( sdid ));
1060 ibuf += sizeof( sdid );
1061 if (( dir = dirlookup( vol, sdid )) == NULL ) {
1065 memcpy(&dvid, ibuf, sizeof( dvid ));
1066 ibuf += sizeof( dvid );
1067 memcpy(&ddid, ibuf, sizeof( ddid ));
1068 ibuf += sizeof( ddid );
1070 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1073 if ( *s_path->m_name == '\0' ) {
1074 return( AFPERR_BADTYPE );
1077 /* don't allow copies when the file is open.
1078 * XXX: the spec only calls for read/deny write access.
1079 * however, copyfile doesn't have any of that info,
1080 * and locks need to stay coherent. as a result,
1081 * we just balk if the file is opened already. */
1083 newname = obj->newtmp;
1084 strcpy( newname, s_path->m_name );
1086 if (of_findname(s_path))
1087 return AFPERR_DENYCONF;
1089 p = ctoupath( vol, curdir, newname );
1091 /* FIXME svid != dvid && dvid's user can't read svid */
1093 if (( vol = getvolbyvid( dvid )) == NULL ) {
1094 return( AFPERR_PARAM );
1097 if (vol->v_flags & AFPVOL_RO)
1098 return AFPERR_VLOCK;
1100 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1104 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1107 if ( *s_path->m_name != '\0' ) {
1108 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1111 /* one of the handful of places that knows about the path type */
1112 if (copy_path_name(newname, ibuf) < 0) {
1113 return( AFPERR_PARAM );
1116 upath = mtoupath(vol, newname);
1117 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1123 if (vol->v_flags & AFPVOL_DROPBOX) {
1124 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1126 #endif /* DROPKLUDGE */
1128 setvoltime(obj, vol );
1131 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1138 static __inline__ int copy_all(const int dfd, const void *buf,
1144 LOG(log_info, logtype_afpd, "begin copy_all:");
1147 while (buflen > 0) {
1148 if ((cc = write(dfd, buf, buflen)) < 0) {
1155 return AFPERR_DFULL;
1157 return AFPERR_VLOCK;
1159 return AFPERR_PARAM;
1166 LOG(log_info, logtype_afpd, "end copy_all:");
1172 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1173 * pass in vol and path */
1174 int copyfile(src, dst, newname, noadouble )
1175 char *src, *dst, *newname;
1176 const int noadouble;
1179 #ifdef SENDFILE_FLAVOR_LINUX
1183 int sfd, dfd, len, err = AFP_OK;
1185 char dpath[ MAXPATHLEN + 1];
1188 LOG(log_info, logtype_afpd, "begin copyfile:");
1191 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1192 admode = ad_mode( dst, 0666 );
1194 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1197 break; /* just copy the data fork */
1199 return( AFPERR_ACCESS );
1201 return( AFPERR_PARAM );
1204 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1208 return( AFPERR_NOOBJ );
1210 return( AFPERR_ACCESS );
1212 return AFPERR_VLOCK;
1214 return( AFPERR_PARAM );
1219 #ifdef SENDFILE_FLAVOR_LINUX
1220 if (fstat(sfd, &st) == 0) {
1221 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1235 goto copyheader_done;
1237 #endif /* SENDFILE_FLAVOR_LINUX */
1239 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1246 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1260 /* data fork copying */
1261 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1264 return( AFPERR_NOOBJ );
1266 return( AFPERR_ACCESS );
1268 return( AFPERR_PARAM );
1272 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1276 return( AFPERR_NOOBJ );
1278 return( AFPERR_ACCESS );
1280 return AFPERR_VLOCK;
1282 return( AFPERR_PARAM );
1286 #ifdef SENDFILE_FLAVOR_LINUX
1287 if (fstat(sfd, &st) == 0) {
1288 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1301 #endif /* SENDFILE_FLAVOR_LINUX */
1304 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1312 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1327 memset(&ad, 0, sizeof(ad));
1328 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1332 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1334 return( AFPERR_ACCESS );
1336 return AFPERR_VLOCK;
1338 return( AFPERR_PARAM );
1342 len = strlen( newname );
1343 ad_setentrylen( &ad, ADEID_NAME, len );
1344 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1345 ad_flush( &ad, ADFLAGS_HF );
1346 ad_close( &ad, ADFLAGS_HF );
1350 LOG(log_info, logtype_afpd, "end copyfile:");
1357 /* -----------------------------------
1358 checkAttrib: 1 check kFPDeleteInhibitBit
1359 ie deletfile called by afp_delete
1361 when deletefile is called we don't have lock on it, file is closed (for us)
1362 untrue if called by renamefile
1364 int deletefile( file, checkAttrib )
1369 int adflags, err = AFP_OK;
1370 int locktype = ADLOCK_WR;
1371 int openmode = O_RDWR;
1374 LOG(log_info, logtype_afpd, "begin deletefile:");
1379 * If can't open read/write then try again read-only. If it's open
1380 * read-only, we must do a read lock instead of a write lock.
1382 /* try to open both at once */
1383 adflags = ADFLAGS_DF|ADFLAGS_HF;
1384 memset(&ad, 0, sizeof(ad));
1385 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1388 adflags = ADFLAGS_DF;
1389 /* that failed. now try to open just the data fork */
1390 memset(&ad, 0, sizeof(ad));
1391 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1394 return AFPERR_NOOBJ;
1396 if(openmode == O_RDWR) {
1397 openmode = O_RDONLY;
1398 locktype = ADLOCK_RD;
1401 return AFPERR_ACCESS;
1404 return AFPERR_VLOCK;
1406 return AFPERR_PARAM;
1412 if(openmode == O_RDWR) {
1413 openmode = O_RDONLY;
1414 locktype = ADLOCK_RD;
1417 return AFPERR_ACCESS;
1420 return AFPERR_VLOCK;
1422 return( AFPERR_PARAM );
1425 break; /* from the while */
1428 * Does kFPDeleteInhibitBit (bit 8) set?
1430 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1433 ad_getattr(&ad, &bshort);
1434 if ((bshort & htons(ATTRBIT_NODELETE))) {
1435 ad_close( &ad, adflags );
1436 return(AFPERR_OLOCK);
1440 if ((adflags & ADFLAGS_HF) ) {
1441 /* FIXME we have a pb here because we want to know if a file is open
1442 * there's a 'priority inversion' if you can't open the ressource fork RW
1443 * you can delete it if it's open because you can't get a write lock.
1445 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1448 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1450 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1451 ad_close( &ad, adflags );
1452 return( AFPERR_BUSY );
1456 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1461 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1465 err = AFPERR_ACCESS;
1478 if ( unlink( file ) < 0 ) {
1482 err = AFPERR_ACCESS;
1496 if (adflags & ADFLAGS_HF)
1497 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1498 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1499 ad_close( &ad, adflags );
1502 LOG(log_info, logtype_afpd, "end deletefile:");
1508 /* ------------------------------------ */
1510 /* return a file id */
1511 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1514 int ibuflen, *rbuflen;
1517 #if AD_VERSION > AD_VERSION1
1526 struct path *s_path;
1529 LOG(log_info, logtype_afpd, "begin afp_createid:");
1535 memcpy(&vid, ibuf, sizeof(vid));
1536 ibuf += sizeof(vid);
1538 if (( vol = getvolbyvid( vid )) == NULL ) {
1539 return( AFPERR_PARAM);
1542 if (vol->v_flags & AFPVOL_RO)
1543 return AFPERR_VLOCK;
1545 memcpy(&did, ibuf, sizeof( did ));
1546 ibuf += sizeof(did);
1548 if (( dir = dirlookup( vol, did )) == NULL ) {
1549 return( AFPERR_PARAM );
1552 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1553 return( AFPERR_PARAM );
1556 if ( *s_path->m_name == '\0' ) {
1557 return( AFPERR_BADTYPE );
1560 upath = s_path->u_name;
1561 switch (s_path->st_errno) {
1563 break; /* success */
1566 return AFPERR_ACCESS;
1568 return AFPERR_NOOBJ;
1570 return AFPERR_PARAM;
1573 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1574 memcpy(rbuf, &id, sizeof(id));
1575 *rbuflen = sizeof(id);
1576 return AFPERR_EXISTID;
1579 #if AD_VERSION > AD_VERSION1
1580 memset(&ad, 0, sizeof(ad));
1581 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1582 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1583 ad_close(&ad, ADFLAGS_HF);
1585 #endif /* AD_VERSION > AD_VERSION1 */
1587 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1588 memcpy(rbuf, &id, sizeof(id));
1589 *rbuflen = sizeof(id);
1594 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1599 return AFPERR_VLOCK;
1603 return AFPERR_ACCESS;
1606 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1607 return AFPERR_PARAM;
1611 /* ------------------------------
1612 resolve a file id */
1613 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1616 int ibuflen, *rbuflen;
1624 u_int16_t vid, bitmap;
1626 static char buffer[12 + MAXPATHLEN + 1];
1627 int len = 12 + MAXPATHLEN + 1;
1630 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1636 memcpy(&vid, ibuf, sizeof(vid));
1637 ibuf += sizeof(vid);
1639 if (( vol = getvolbyvid( vid )) == NULL ) {
1640 return( AFPERR_PARAM);
1643 memcpy(&id, ibuf, sizeof( id ));
1646 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1647 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1650 if (( dir = dirlookup( vol, id )) == NULL ) {
1651 return AFPERR_NOID; /* idem AFPERR_PARAM */
1653 path.u_name = upath;
1654 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1658 return AFPERR_ACCESS;
1662 return AFPERR_PARAM;
1665 /* directories are bad */
1666 if (S_ISDIR(path.st.st_mode))
1667 return AFPERR_BADTYPE;
1669 memcpy(&bitmap, ibuf, sizeof(bitmap));
1670 bitmap = ntohs( bitmap );
1671 path.m_name = utompath(vol, upath);
1672 if ((err = getfilparams(vol, bitmap, &path , curdir,
1673 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1676 *rbuflen = buflen + sizeof(bitmap);
1677 memcpy(rbuf, ibuf, sizeof(bitmap));
1680 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1686 /* ------------------------------ */
1687 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1690 int ibuflen, *rbuflen;
1700 static char buffer[12 + MAXPATHLEN + 1];
1701 int len = 12 + MAXPATHLEN + 1;
1704 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1710 memcpy(&vid, ibuf, sizeof(vid));
1711 ibuf += sizeof(vid);
1713 if (( vol = getvolbyvid( vid )) == NULL ) {
1714 return( AFPERR_PARAM);
1717 if (vol->v_flags & AFPVOL_RO)
1718 return AFPERR_VLOCK;
1720 memcpy(&id, ibuf, sizeof( id ));
1724 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1728 if (( dir = dirlookup( vol, id )) == NULL ) {
1729 return( AFPERR_PARAM );
1733 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1737 return AFPERR_ACCESS;
1739 /* still try to delete the id */
1743 return AFPERR_PARAM;
1747 /* directories are bad */
1748 if (S_ISDIR(st.st_mode))
1749 return AFPERR_BADTYPE;
1751 if (cnid_delete(vol->v_db, fileid)) {
1754 return AFPERR_VLOCK;
1757 return AFPERR_ACCESS;
1759 return AFPERR_PARAM;
1764 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1769 #endif /* CNID_DB */
1771 #define APPLETEMP ".AppleTempXXXXXX"
1773 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1776 int ibuflen, *rbuflen;
1778 struct stat srcst, destst;
1780 struct dir *dir, *sdir;
1781 char *spath, temp[17], *p;
1782 char *supath, *upath;
1787 struct adouble *adsp;
1788 struct adouble *addp;
1794 #endif /* CNID_DB */
1799 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1805 memcpy(&vid, ibuf, sizeof(vid));
1806 ibuf += sizeof(vid);
1808 if (( vol = getvolbyvid( vid )) == NULL ) {
1809 return( AFPERR_PARAM);
1812 if (vol->v_flags & AFPVOL_RO)
1813 return AFPERR_VLOCK;
1815 /* source and destination dids */
1816 memcpy(&sid, ibuf, sizeof(sid));
1817 ibuf += sizeof(sid);
1818 memcpy(&did, ibuf, sizeof(did));
1819 ibuf += sizeof(did);
1822 if ((dir = dirlookup( vol, sid )) == NULL ) {
1823 return( AFPERR_PARAM );
1826 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1827 return( AFPERR_PARAM );
1830 if ( *path->m_name == '\0' ) {
1831 return( AFPERR_BADTYPE ); /* it's a dir */
1834 upath = path->u_name;
1835 switch (path->st_errno) {
1842 return AFPERR_ACCESS;
1844 return AFPERR_PARAM;
1846 memset(&ads, 0, sizeof(ads));
1848 if ((s_of = of_findname(path))) {
1849 /* reuse struct adouble so it won't break locks */
1852 memcpy(&srcst, &path->st, sizeof(struct stat));
1853 /* save some stuff */
1855 spath = obj->oldtmp;
1856 supath = obj->newtmp;
1857 strcpy(spath, path->m_name);
1858 strcpy(supath, upath); /* this is for the cnid changing */
1859 p = absupath( vol, sdir, upath);
1861 /* look for the source cnid. if it doesn't exist, don't worry about
1864 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1865 slen = strlen(supath));
1866 #endif /* CNID_DB */
1868 if (( dir = dirlookup( vol, did )) == NULL ) {
1869 return( AFPERR_PARAM );
1872 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1873 return( AFPERR_PARAM );
1876 if ( *path->m_name == '\0' ) {
1877 return( AFPERR_BADTYPE );
1880 /* FPExchangeFiles is the only call that can return the SameObj
1882 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1883 return AFPERR_SAMEOBJ;
1884 memcpy(&srcst, &path->st, sizeof(struct stat));
1893 return AFPERR_ACCESS;
1895 return AFPERR_PARAM;
1897 memset(&add, 0, sizeof(add));
1899 if ((d_of = of_findname( path))) {
1900 /* reuse struct adouble so it won't break locks */
1903 memcpy(&destst, &path->st, sizeof(struct stat));
1905 /* they are not on the same device and at least one is open
1907 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1910 upath = path->u_name;
1912 /* look for destination id. */
1913 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1914 dlen = strlen(upath));
1915 #endif /* CNID_DB */
1917 /* construct a temp name.
1918 * NOTE: the temp file will be in the dest file's directory. it
1919 * will also be inaccessible from AFP. */
1920 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1924 /* now, quickly rename the file. we error if we can't. */
1925 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1926 goto err_exchangefile;
1927 of_rename(vol, s_of, sdir, spath, curdir, temp);
1929 /* rename destination to source */
1930 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1931 goto err_src_to_tmp;
1932 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1934 /* rename temp to destination */
1935 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1936 goto err_dest_to_src;
1937 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1940 /* id's need switching. src -> dest and dest -> src. */
1941 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1942 upath, dlen) < 0)) {
1946 err = AFPERR_ACCESS;
1951 goto err_temp_to_dest;
1954 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1955 supath, slen) < 0)) {
1959 err = AFPERR_ACCESS;
1966 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1967 goto err_temp_to_dest;
1969 #endif /* CNID_DB */
1972 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1978 /* all this stuff is so that we can unwind a failed operation
1983 /* rename dest to temp */
1984 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1985 of_rename(vol, s_of, curdir, upath, curdir, temp);
1988 /* rename source back to dest */
1989 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1990 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1993 /* rename temp back to source */
1994 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1995 of_rename(vol, s_of, curdir, temp, sdir, spath);