2 * $Id: file.c,v 1.63 2002-10-11 14:18:29 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 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
110 (1 << FILPBIT_CDATE) |\
111 (1 << FILPBIT_MDATE) |\
112 (1 << FILPBIT_BDATE) |\
113 (1 << FILPBIT_FINFO) |\
114 (1 << FILPBIT_RFLEN) |\
115 (1 << FILPBIT_EXTRFLEN) |\
116 (1 << FILPBIT_PDINFO)))
119 int getmetadata(struct vol *vol,
121 char *path, struct dir *dir, struct stat *st,
122 char *buf, int *buflen, struct adouble *adp, int attrbits )
125 struct stat lst, *lstp;
126 #endif /* USE_LASTDID */
127 char *data, *nameoff = NULL, *upath;
131 u_char achar, fdType[4];
134 LOG(log_info, logtype_afpd, "begin getmetadata:");
137 upath = mtoupath(vol, path);
140 while ( bitmap != 0 ) {
141 while (( bitmap & 1 ) == 0 ) {
149 ad_getattr(adp, &ashort);
150 } else if (*upath == '.') {
151 ashort = htons(ATTRBIT_INVISIBLE);
155 /* FIXME do we want a visual clue if the file is read only
158 accessmode( ".", &ma, dir , NULL);
159 if ((ma.ma_user & AR_UWRITE)) {
160 accessmode( upath, &ma, dir , st);
161 if (!(ma.ma_user & AR_UWRITE)) {
162 attrbits |= ATTRBIT_NOWRITE;
167 ashort = htons(ntohs(ashort) | attrbits);
168 memcpy(data, &ashort, sizeof( ashort ));
169 data += sizeof( ashort );
173 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
174 data += sizeof( u_int32_t );
178 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
179 aint = AD_DATE_FROM_UNIX(st->st_mtime);
180 memcpy(data, &aint, sizeof( aint ));
181 data += sizeof( aint );
185 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
186 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
187 aint = AD_DATE_FROM_UNIX(st->st_mtime);
190 aint = AD_DATE_FROM_UNIX(st->st_mtime);
192 memcpy(data, &aint, sizeof( int ));
193 data += sizeof( int );
197 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
198 aint = AD_DATE_START;
199 memcpy(data, &aint, sizeof( int ));
200 data += sizeof( int );
204 get_finderinfo(path, adp, (char *)data);
206 if (*upath == '.') { /* make it invisible */
207 ashort = htons(FINDERINFO_INVISIBLE);
208 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
217 data += sizeof( u_int16_t );
221 memset(data, 0, sizeof(u_int16_t));
222 data += sizeof( u_int16_t );
227 #if AD_VERSION > AD_VERSION1
228 /* look in AD v2 header */
230 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
231 #endif /* AD_VERSION > AD_VERSION1 */
234 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
235 strlen(upath), aint);
236 /* Throw errors if cnid_add fails. */
237 if (aint == CNID_INVALID) {
240 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
241 return(AFPERR_PARAM);
243 return(AFPERR_PARAM);
253 * What a fucking mess. First thing: DID and FNUMs are
254 * in the same space for purposes of enumerate (and several
255 * other wierd places). While we consider this Apple's bug,
256 * this is the work-around: In order to maintain constant and
257 * unique DIDs and FNUMs, we monotonically generate the DIDs
258 * during the session, and derive the FNUMs from the filesystem.
259 * Since the DIDs are small, we insure that the FNUMs are fairly
260 * large by setting thier high bits to the device number.
262 * AFS already does something very similar to this for the
263 * inode number, so we don't repeat the procedure.
266 * due to complaints over did's being non-persistent,
267 * here's the current hack to provide semi-persistent
269 * 1) we reserve the first bit for file ids.
270 * 2) the next 7 bits are for the device.
271 * 3) the remaining 24 bits are for the inode.
273 * both the inode and device information are actually hashes
274 * that are then truncated to the requisite bit length.
276 * it should be okay to use lstat to deal with symlinks.
279 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
280 #else /* USE_LASTDID */
281 lstp = lstat(upath, &lst) < 0 ? st : &lst;
282 aint = htonl(CNID(lstp, 1));
283 #endif /* USE_LASTDID */
286 memcpy(data, &aint, sizeof( aint ));
287 data += sizeof( aint );
291 if (st->st_size > 0xffffffff)
294 aint = htonl( st->st_size );
295 memcpy(data, &aint, sizeof( aint ));
296 data += sizeof( aint );
301 if (adp->ad_rlen > 0xffffffff)
304 aint = htonl( adp->ad_rlen);
308 memcpy(data, &aint, sizeof( aint ));
309 data += sizeof( aint );
312 /* Current client needs ProDOS info block for this file.
313 Use simple heuristic and let the Mac "type" string tell
314 us what the PD file code should be. Everything gets a
315 subtype of 0x0000 unless the original value was hashed
316 to "pXYZ" when we created it. See IA, Ver 2.
318 case FILPBIT_PDINFO :
320 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
322 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
326 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
330 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
334 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
338 else if ( fdType[0] == 'p' ) {
340 ashort = (fdType[2] * 256) + fdType[3];
354 memcpy(data, &ashort, sizeof( ashort ));
355 data += sizeof( ashort );
356 memset(data, 0, sizeof( ashort ));
357 data += sizeof( ashort );
359 case FILPBIT_EXTDFLEN:
360 aint = htonl(st->st_size >> 32);
361 memcpy(data, &aint, sizeof( aint ));
362 data += sizeof( aint );
363 aint = htonl(st->st_size);
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
367 case FILPBIT_EXTRFLEN:
370 aint = htonl(adp->ad_rlen >> 32);
371 memcpy(data, &aint, sizeof( aint ));
372 data += sizeof( aint );
374 aint = htonl(adp->ad_rlen);
375 memcpy(data, &aint, sizeof( aint ));
376 data += sizeof( aint );
379 return( AFPERR_BITMAP );
385 ashort = htons( data - buf );
386 memcpy(nameoff, &ashort, sizeof( ashort ));
387 if ((aint = strlen( path )) > MACFILELEN)
390 memcpy(data, path, aint );
393 *buflen = data - buf;
397 /* ----------------------- */
398 int getfilparams(struct vol *vol,
400 struct path *path, struct dir *dir,
401 char *buf, int *buflen )
403 struct adouble ad, *adp;
406 u_int16_t attrbits = 0;
411 LOG(log_info, logtype_default, "begin getfilparams:");
414 opened = PARAM_NEED_ADP(bitmap);
417 upath = path->u_name;
418 if ((of = of_findname(path))) {
420 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
421 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
423 memset(&ad, 0, sizeof(ad));
427 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
432 we need to check if the file is open by another process.
433 it's slow so we only do it if we have to:
434 - bitmap is requested.
435 - we don't already have the answer!
437 if ((bitmap & (1 << FILPBIT_ATTR))) {
438 if (!(attrbits & ATTRBIT_ROPEN)) {
440 if (!(attrbits & ATTRBIT_DOPEN)) {
445 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
447 ad_close( adp, ADFLAGS_HF );
450 LOG(log_info, logtype_afpd, "end getfilparams:");
456 /* ----------------------------- */
457 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
460 int ibuflen, *rbuflen;
463 struct adouble ad, *adp;
466 struct ofork *of = NULL;
468 int creatf, did, openf, retvalue = AFP_OK;
474 LOG(log_info, logtype_afpd, "begin afp_createfile:");
479 creatf = (unsigned char) *ibuf++;
481 memcpy(&vid, ibuf, sizeof( vid ));
482 ibuf += sizeof( vid );
484 if (( vol = getvolbyvid( vid )) == NULL ) {
485 return( AFPERR_PARAM );
488 if (vol->v_flags & AFPVOL_RO)
491 memcpy(&did, ibuf, sizeof( did));
492 ibuf += sizeof( did );
494 if (( dir = dirlookup( vol, did )) == NULL ) {
495 return( AFPERR_NOOBJ );
498 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
499 return( AFPERR_NOOBJ );
502 if ( *s_path->m_name == '\0' ) {
503 return( AFPERR_BADTYPE );
506 upath = s_path->u_name;
507 if (0 != (ret = check_name(vol, upath)))
510 /* if upath is deleted we already in trouble anyway */
511 if ((of = of_findname(s_path))) {
514 memset(&ad, 0, sizeof(ad));
518 /* on a hard create, fail if file exists and is open */
521 openf = O_RDWR|O_CREAT|O_TRUNC;
523 /* on a soft create, if the file is open then ad_open won't fail
524 because open syscall is not called
529 openf = O_RDWR|O_CREAT|O_EXCL;
532 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
533 openf, 0666, adp) < 0 ) {
536 return( AFPERR_EXIST );
538 return( AFPERR_ACCESS );
540 /* on noadouble volumes, just creating the data fork is ok */
542 if (vol_noadouble(vol) && (stat(upath, st) == 0))
543 goto createfile_done;
546 return( AFPERR_PARAM );
549 path = s_path->m_name;
550 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
551 memcpy(ad_entry( adp, ADEID_NAME ), path,
552 ad_getentrylen( adp, ADEID_NAME ));
553 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
554 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
559 if (vol->v_flags & AFPVOL_DROPBOX) {
560 retvalue = matchfile2dirperms(upath, vol, did);
562 #endif /* DROPKLUDGE */
564 setvoltime(obj, vol );
567 LOG(log_info, logtype_afpd, "end afp_createfile");
573 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
576 int ibuflen, *rbuflen;
582 u_int16_t vid, bitmap;
585 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
591 memcpy(&vid, ibuf, sizeof( vid ));
592 ibuf += sizeof( vid );
593 if (( vol = getvolbyvid( vid )) == NULL ) {
594 return( AFPERR_PARAM );
597 if (vol->v_flags & AFPVOL_RO)
600 memcpy(&did, ibuf, sizeof( did ));
601 ibuf += sizeof( did );
602 if (( dir = dirlookup( vol, did )) == NULL ) {
603 return( AFPERR_NOOBJ );
606 memcpy(&bitmap, ibuf, sizeof( bitmap ));
607 bitmap = ntohs( bitmap );
608 ibuf += sizeof( bitmap );
610 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
611 return( AFPERR_NOOBJ );
614 if ( *s_path->m_name == '\0' ) {
615 return( AFPERR_BADTYPE ); /* it's a directory */
618 if ((u_long)ibuf & 1 ) {
622 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
623 setvoltime(obj, vol );
627 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
634 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
637 extern struct path Cur_Path;
639 int setfilparams(struct vol *vol,
640 struct path *path, u_int16_t bitmap, char *buf )
642 struct adouble ad, *adp;
645 int bit = 0, isad = 1, err = AFP_OK;
647 u_char achar, *fdType, xyy[4];
648 u_int16_t ashort, bshort;
652 int change_mdate = 0;
653 int change_parent_mdate = 0;
659 LOG(log_info, logtype_afpd, "begin setfilparams:");
662 upath = path->u_name;
663 if ((of = of_findname(path))) {
666 memset(&ad, 0, sizeof(ad));
670 if (check_access(upath, OPENACC_WR ) < 0) {
671 return AFPERR_ACCESS;
674 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
675 O_RDWR|O_CREAT, 0666, adp) < 0) {
676 /* for some things, we don't need an adouble header */
677 if (bitmap & ~(1<<FILPBIT_MDATE)) {
678 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
681 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
682 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
683 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
684 ad_getentrylen( adp, ADEID_NAME ));
687 while ( bitmap != 0 ) {
688 while (( bitmap & 1 ) == 0 ) {
696 memcpy(&ashort, buf, sizeof( ashort ));
697 ad_getattr(adp, &bshort);
698 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
699 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
703 if ((ashort & htons(ATTRBIT_INVISIBLE)))
704 change_parent_mdate = 1;
705 ad_setattr(adp, bshort);
706 buf += sizeof( ashort );
711 memcpy(&aint, buf, sizeof(aint));
712 ad_setdate(adp, AD_DATE_CREATE, aint);
713 buf += sizeof( aint );
717 memcpy(&newdate, buf, sizeof( newdate ));
718 buf += sizeof( newdate );
723 memcpy(&aint, buf, sizeof(aint));
724 ad_setdate(adp, AD_DATE_BACKUP, aint);
725 buf += sizeof( aint );
731 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
733 ((em = getextmap( path->m_name )) &&
734 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
735 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
736 || ((em = getdefextmap()) &&
737 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
738 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
740 memcpy(buf, ufinderi, 8 );
743 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
747 /* Client needs to set the ProDOS file info for this file.
748 Use defined strings for the simple cases, and convert
749 all else into pXYY per Inside Appletalk. Always set
750 the creator as "pdos". <shirsch@ibm.net> */
751 case FILPBIT_PDINFO :
754 memcpy(&ashort, buf, sizeof( ashort ));
755 ashort = ntohs( ashort );
758 switch ( (unsigned int) achar )
761 fdType = ( u_char *) "TEXT";
765 fdType = ( u_char *) "PSYS";
769 fdType = ( u_char *) "PS16";
773 fdType = ( u_char *) "BINA";
777 xyy[0] = ( u_char ) 'p';
779 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
780 xyy[3] = ( u_char ) ashort & 0xff;
785 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
786 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
792 goto setfilparam_done;
800 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
801 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
805 ad_setdate(adp, AD_DATE_MODIFY, newdate);
806 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
811 ad_flush( adp, ADFLAGS_HF );
812 ad_close( adp, ADFLAGS_HF );
816 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
817 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
818 bitmap = 1<<FILPBIT_MDATE;
819 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
823 LOG(log_info, logtype_afpd, "end setfilparams:");
829 * renamefile and copyfile take the old and new unix pathnames
830 * and the new mac name.
831 * NOTE: if we have to copy a file instead of renaming it, locks
832 * will break. Anyway it's an error because then we have 2 files.
834 * src the source path
835 * dst the dest filename in current dir
836 * newname the dest mac name
837 * adp adouble struct of src file, if open, or & zeroed one
840 int renamefile(src, dst, newname, noadouble, adp )
841 char *src, *dst, *newname;
845 char adsrc[ MAXPATHLEN + 1];
849 * Note that this is only checking the existance of the data file,
850 * not the header file. The thinking is that if the data file doesn't
851 * exist, but the header file does, the right thing to do is remove
852 * the data file silently.
855 /* existence check moved to afp_moveandrename */
858 LOG(log_info, logtype_afpd, "begin renamefile:");
861 if ( rename( src, dst ) < 0 ) {
864 return( AFPERR_NOOBJ );
867 return( AFPERR_ACCESS );
870 case EXDEV : /* Cross device move -- try copy */
871 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
872 deletefile( dst, 0 );
875 return deletefile( src, 0);
877 return( AFPERR_PARAM );
881 strcpy( adsrc, ad_path( src, 0 ));
884 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
889 /* check for a source appledouble header. if it exists, make
890 * a dest appledouble directory and do the rename again. */
891 if (rc || stat(adsrc, &st) ||
892 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
895 ad_close(adp, ADFLAGS_HF);
899 return( AFPERR_ACCESS );
903 return( AFPERR_PARAM );
907 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
910 return( AFPERR_NOOBJ );
912 return( AFPERR_ACCESS );
916 return( AFPERR_PARAM );
920 len = strlen( newname );
921 ad_setentrylen( adp, ADEID_NAME, len );
922 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
923 ad_flush( adp, ADFLAGS_HF );
924 ad_close( adp, ADFLAGS_HF );
927 LOG(log_info, logtype_afpd, "end renamefile:");
933 /* -----------------------------------
935 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
938 int ibuflen, *rbuflen;
942 char *newname, *p, *upath;
944 u_int32_t sdid, ddid;
946 int err, retvalue = AFP_OK;
947 u_int16_t svid, dvid;
950 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
956 memcpy(&svid, ibuf, sizeof( svid ));
957 ibuf += sizeof( svid );
958 if (( vol = getvolbyvid( svid )) == NULL ) {
959 return( AFPERR_PARAM );
962 memcpy(&sdid, ibuf, sizeof( sdid ));
963 ibuf += sizeof( sdid );
964 if (( dir = dirlookup( vol, sdid )) == NULL ) {
965 return( AFPERR_PARAM );
968 memcpy(&dvid, ibuf, sizeof( dvid ));
969 ibuf += sizeof( dvid );
970 memcpy(&ddid, ibuf, sizeof( ddid ));
971 ibuf += sizeof( ddid );
973 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
974 return( AFPERR_NOOBJ );
976 if ( *s_path->m_name == '\0' ) {
977 return( AFPERR_BADTYPE );
980 /* don't allow copies when the file is open.
981 * XXX: the spec only calls for read/deny write access.
982 * however, copyfile doesn't have any of that info,
983 * and locks need to stay coherent. as a result,
984 * we just balk if the file is opened already. */
986 newname = obj->newtmp;
987 strcpy( newname, s_path->m_name );
989 if (of_findname(s_path))
990 return AFPERR_DENYCONF;
992 p = ctoupath( vol, curdir, newname );
994 /* FIXME svid != dvid && dvid's user can't read svid */
996 if (( vol = getvolbyvid( dvid )) == NULL ) {
997 return( AFPERR_PARAM );
1000 if (vol->v_flags & AFPVOL_RO)
1001 return AFPERR_VLOCK;
1003 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1004 return( AFPERR_PARAM );
1007 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1008 return( AFPERR_NOOBJ );
1010 if ( *s_path->m_name != '\0' ) {
1011 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1014 /* one of the handful of places that knows about the path type */
1015 if ( *ibuf++ != 2 ) {
1016 return( AFPERR_PARAM );
1018 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1019 strncpy( newname, ibuf, plen );
1020 newname[ plen ] = '\0';
1021 if (strlen(newname) != plen) {
1022 /* there's \0 in newname, e.g. it's a pathname not
1025 return( AFPERR_PARAM );
1028 upath = mtoupath(vol, newname);
1029 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1034 if (vol->v_flags & AFPVOL_DROPBOX) {
1035 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1037 #endif /* DROPKLUDGE */
1039 setvoltime(obj, vol );
1042 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1049 static __inline__ int copy_all(const int dfd, const void *buf,
1055 LOG(log_info, logtype_afpd, "begin copy_all:");
1058 while (buflen > 0) {
1059 if ((cc = write(dfd, buf, buflen)) < 0) {
1066 return AFPERR_DFULL;
1068 return AFPERR_VLOCK;
1070 return AFPERR_PARAM;
1077 LOG(log_info, logtype_afpd, "end copy_all:");
1083 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1084 * pass in vol and path */
1085 int copyfile(src, dst, newname, noadouble )
1086 char *src, *dst, *newname;
1087 const int noadouble;
1090 #ifdef SENDFILE_FLAVOR_LINUX
1094 int sfd, dfd, len, err = AFP_OK;
1096 char dpath[ MAXPATHLEN + 1];
1099 LOG(log_info, logtype_afpd, "begin copyfile:");
1102 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1103 admode = ad_mode( dst, 0666 );
1105 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1108 break; /* just copy the data fork */
1110 return( AFPERR_ACCESS );
1112 return( AFPERR_PARAM );
1115 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1119 return( AFPERR_NOOBJ );
1121 return( AFPERR_ACCESS );
1123 return AFPERR_VLOCK;
1125 return( AFPERR_PARAM );
1130 #ifdef SENDFILE_FLAVOR_LINUX
1131 if (fstat(sfd, &st) == 0) {
1132 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1146 goto copyheader_done;
1148 #endif /* SENDFILE_FLAVOR_LINUX */
1150 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1157 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1171 /* data fork copying */
1172 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1175 return( AFPERR_NOOBJ );
1177 return( AFPERR_ACCESS );
1179 return( AFPERR_PARAM );
1183 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1187 return( AFPERR_NOOBJ );
1189 return( AFPERR_ACCESS );
1191 return AFPERR_VLOCK;
1193 return( AFPERR_PARAM );
1197 #ifdef SENDFILE_FLAVOR_LINUX
1198 if (fstat(sfd, &st) == 0) {
1199 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1212 #endif /* SENDFILE_FLAVOR_LINUX */
1215 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1223 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1238 memset(&ad, 0, sizeof(ad));
1239 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1243 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1245 return( AFPERR_ACCESS );
1247 return AFPERR_VLOCK;
1249 return( AFPERR_PARAM );
1253 len = strlen( newname );
1254 ad_setentrylen( &ad, ADEID_NAME, len );
1255 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1256 ad_flush( &ad, ADFLAGS_HF );
1257 ad_close( &ad, ADFLAGS_HF );
1261 LOG(log_info, logtype_afpd, "end copyfile:");
1268 /* -----------------------------------
1269 checkAttrib: 1 check kFPDeleteInhibitBit
1270 ie deletfile called by afp_delete
1272 when deletefile is called we don't have lock on it, file is closed (for us)
1273 untrue if called by renamefile
1275 int deletefile( file, checkAttrib )
1280 int adflags, err = AFP_OK;
1281 int locktype = ADLOCK_WR;
1282 int openmode = O_RDWR;
1285 LOG(log_info, logtype_afpd, "begin deletefile:");
1290 * If can't open read/write then try again read-only. If it's open
1291 * read-only, we must do a read lock instead of a write lock.
1293 /* try to open both at once */
1294 adflags = ADFLAGS_DF|ADFLAGS_HF;
1295 memset(&ad, 0, sizeof(ad));
1296 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1299 adflags = ADFLAGS_DF;
1300 /* that failed. now try to open just the data fork */
1301 memset(&ad, 0, sizeof(ad));
1302 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1305 return AFPERR_NOOBJ;
1307 if(openmode == O_RDWR) {
1308 openmode = O_RDONLY;
1309 locktype = ADLOCK_RD;
1312 return AFPERR_ACCESS;
1315 return AFPERR_VLOCK;
1317 return AFPERR_PARAM;
1323 if(openmode == O_RDWR) {
1324 openmode = O_RDONLY;
1325 locktype = ADLOCK_RD;
1328 return AFPERR_ACCESS;
1331 return AFPERR_VLOCK;
1333 return( AFPERR_PARAM );
1336 break; /* from the while */
1339 * Does kFPDeleteInhibitBit (bit 8) set?
1341 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1344 ad_getattr(&ad, &bshort);
1345 if ((bshort & htons(ATTRBIT_NODELETE))) {
1346 ad_close( &ad, adflags );
1347 return(AFPERR_OLOCK);
1351 if ((adflags & ADFLAGS_HF) ) {
1352 /* FIXME we have a pb here because we want to know if a file is open
1353 * there's a 'priority inversion' if you can't open the ressource fork RW
1354 * you can delete it if it's open because you can't get a write lock.
1356 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1359 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1361 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1362 ad_close( &ad, adflags );
1363 return( AFPERR_BUSY );
1367 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1372 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1376 err = AFPERR_ACCESS;
1389 if ( unlink( file ) < 0 ) {
1393 err = AFPERR_ACCESS;
1407 if (adflags & ADFLAGS_HF)
1408 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1409 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1410 ad_close( &ad, adflags );
1413 LOG(log_info, logtype_afpd, "end deletefile:");
1419 /* ------------------------------------ */
1421 /* return a file id */
1422 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1425 int ibuflen, *rbuflen;
1428 #if AD_VERSION > AD_VERSION1
1437 struct path *s_path;
1440 LOG(log_info, logtype_afpd, "begin afp_createid:");
1446 memcpy(&vid, ibuf, sizeof(vid));
1447 ibuf += sizeof(vid);
1449 if (( vol = getvolbyvid( vid )) == NULL ) {
1450 return( AFPERR_PARAM);
1453 if (vol->v_flags & AFPVOL_RO)
1454 return AFPERR_VLOCK;
1456 memcpy(&did, ibuf, sizeof( did ));
1457 ibuf += sizeof(did);
1459 if (( dir = dirlookup( vol, did )) == NULL ) {
1460 return( AFPERR_PARAM );
1463 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1464 return( AFPERR_PARAM );
1467 if ( *s_path->m_name == '\0' ) {
1468 return( AFPERR_BADTYPE );
1471 upath = s_path->u_name;
1472 switch (s_path->st_errno) {
1474 break; /* success */
1477 return AFPERR_ACCESS;
1479 return AFPERR_NOOBJ;
1481 return AFPERR_PARAM;
1484 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1485 memcpy(rbuf, &id, sizeof(id));
1486 *rbuflen = sizeof(id);
1487 return AFPERR_EXISTID;
1490 #if AD_VERSION > AD_VERSION1
1491 memset(&ad, 0, sizeof(ad));
1492 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1493 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1494 ad_close(&ad, ADFLAGS_HF);
1496 #endif /* AD_VERSION > AD_VERSION1 */
1498 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1499 memcpy(rbuf, &id, sizeof(id));
1500 *rbuflen = sizeof(id);
1505 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1510 return AFPERR_VLOCK;
1514 return AFPERR_ACCESS;
1517 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1518 return AFPERR_PARAM;
1522 /* ------------------------------
1523 resolve a file id */
1524 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1527 int ibuflen, *rbuflen;
1535 u_int16_t vid, bitmap;
1537 static char buffer[12 + MAXPATHLEN + 1];
1538 int len = 12 + MAXPATHLEN + 1;
1541 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1547 memcpy(&vid, ibuf, sizeof(vid));
1548 ibuf += sizeof(vid);
1550 if (( vol = getvolbyvid( vid )) == NULL ) {
1551 return( AFPERR_PARAM);
1554 memcpy(&id, ibuf, sizeof( id ));
1557 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1558 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1561 if (( dir = dirlookup( vol, id )) == NULL ) {
1562 return AFPERR_NOID; /* idem AFPERR_PARAM */
1564 path.u_name = upath;
1565 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1569 return AFPERR_ACCESS;
1573 return AFPERR_PARAM;
1576 /* directories are bad */
1577 if (S_ISDIR(path.st.st_mode))
1578 return AFPERR_BADTYPE;
1580 memcpy(&bitmap, ibuf, sizeof(bitmap));
1581 bitmap = ntohs( bitmap );
1582 path.m_name = utompath(vol, upath);
1583 if ((err = getfilparams(vol, bitmap, &path , curdir,
1584 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1587 *rbuflen = buflen + sizeof(bitmap);
1588 memcpy(rbuf, ibuf, sizeof(bitmap));
1591 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1597 /* ------------------------------ */
1598 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1601 int ibuflen, *rbuflen;
1611 static char buffer[12 + MAXPATHLEN + 1];
1612 int len = 12 + MAXPATHLEN + 1;
1615 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1621 memcpy(&vid, ibuf, sizeof(vid));
1622 ibuf += sizeof(vid);
1624 if (( vol = getvolbyvid( vid )) == NULL ) {
1625 return( AFPERR_PARAM);
1628 if (vol->v_flags & AFPVOL_RO)
1629 return AFPERR_VLOCK;
1631 memcpy(&id, ibuf, sizeof( id ));
1635 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1639 if (( dir = dirlookup( vol, id )) == NULL ) {
1640 return( AFPERR_PARAM );
1644 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1648 return AFPERR_ACCESS;
1650 /* still try to delete the id */
1654 return AFPERR_PARAM;
1658 /* directories are bad */
1659 if (S_ISDIR(st.st_mode))
1660 return AFPERR_BADTYPE;
1662 if (cnid_delete(vol->v_db, fileid)) {
1665 return AFPERR_VLOCK;
1668 return AFPERR_ACCESS;
1670 return AFPERR_PARAM;
1675 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1680 #endif /* CNID_DB */
1682 #define APPLETEMP ".AppleTempXXXXXX"
1684 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1687 int ibuflen, *rbuflen;
1689 struct stat srcst, destst;
1691 struct dir *dir, *sdir;
1692 char *spath, temp[17], *p;
1693 char *supath, *upath;
1698 struct adouble *adsp;
1699 struct adouble *addp;
1705 #endif /* CNID_DB */
1710 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1716 memcpy(&vid, ibuf, sizeof(vid));
1717 ibuf += sizeof(vid);
1719 if (( vol = getvolbyvid( vid )) == NULL ) {
1720 return( AFPERR_PARAM);
1723 if (vol->v_flags & AFPVOL_RO)
1724 return AFPERR_VLOCK;
1726 /* source and destination dids */
1727 memcpy(&sid, ibuf, sizeof(sid));
1728 ibuf += sizeof(sid);
1729 memcpy(&did, ibuf, sizeof(did));
1730 ibuf += sizeof(did);
1733 if ((dir = dirlookup( vol, sid )) == NULL ) {
1734 return( AFPERR_PARAM );
1737 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1738 return( AFPERR_PARAM );
1741 if ( *path->m_name == '\0' ) {
1742 return( AFPERR_BADTYPE ); /* it's a dir */
1745 upath = path->u_name;
1746 switch (path->st_errno) {
1753 return AFPERR_ACCESS;
1755 return AFPERR_PARAM;
1757 memset(&ads, 0, sizeof(ads));
1759 if ((s_of = of_findname(path))) {
1760 /* reuse struct adouble so it won't break locks */
1763 memcpy(&srcst, &path->st, sizeof(struct stat));
1764 /* save some stuff */
1766 spath = obj->oldtmp;
1767 supath = obj->newtmp;
1768 strcpy(spath, path->m_name);
1769 strcpy(supath, upath); /* this is for the cnid changing */
1770 p = absupath( vol, sdir, upath);
1772 /* look for the source cnid. if it doesn't exist, don't worry about
1775 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1776 slen = strlen(supath));
1777 #endif /* CNID_DB */
1779 if (( dir = dirlookup( vol, did )) == NULL ) {
1780 return( AFPERR_PARAM );
1783 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1784 return( AFPERR_PARAM );
1787 if ( *path->m_name == '\0' ) {
1788 return( AFPERR_BADTYPE );
1791 /* FPExchangeFiles is the only call that can return the SameObj
1793 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1794 return AFPERR_SAMEOBJ;
1795 memcpy(&srcst, &path->st, sizeof(struct stat));
1804 return AFPERR_ACCESS;
1806 return AFPERR_PARAM;
1808 memset(&add, 0, sizeof(add));
1810 if ((d_of = of_findname( path))) {
1811 /* reuse struct adouble so it won't break locks */
1814 memcpy(&destst, &path->st, sizeof(struct stat));
1816 /* they are not on the same device and at least one is open
1818 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1821 upath = path->u_name;
1823 /* look for destination id. */
1824 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1825 dlen = strlen(upath));
1826 #endif /* CNID_DB */
1828 /* construct a temp name.
1829 * NOTE: the temp file will be in the dest file's directory. it
1830 * will also be inaccessible from AFP. */
1831 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1835 /* now, quickly rename the file. we error if we can't. */
1836 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1837 goto err_exchangefile;
1838 of_rename(vol, s_of, sdir, spath, curdir, temp);
1840 /* rename destination to source */
1841 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1842 goto err_src_to_tmp;
1843 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1845 /* rename temp to destination */
1846 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1847 goto err_dest_to_src;
1848 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1851 /* id's need switching. src -> dest and dest -> src. */
1852 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1853 upath, dlen) < 0)) {
1857 err = AFPERR_ACCESS;
1862 goto err_temp_to_dest;
1865 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1866 supath, slen) < 0)) {
1870 err = AFPERR_ACCESS;
1877 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1878 goto err_temp_to_dest;
1880 #endif /* CNID_DB */
1883 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1889 /* all this stuff is so that we can unwind a failed operation
1894 /* rename dest to temp */
1895 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1896 of_rename(vol, s_of, curdir, upath, curdir, temp);
1899 /* rename source back to dest */
1900 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1901 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1904 /* rename temp back to source */
1905 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1906 of_rename(vol, s_of, curdir, temp, sdir, spath);