2 * $Id: file.c,v 1.76 2003-01-21 10:09:13 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.
360 <shirsch@adelphia.net> */
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 (NULL == ( vol = getvolbyvid( vid )) ) {
539 return( AFPERR_PARAM );
542 if (vol->v_flags & AFPVOL_RO)
545 memcpy(&did, ibuf, sizeof( did));
546 ibuf += sizeof( did );
548 if (NULL == ( dir = dirlookup( vol, did )) ) {
552 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
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 (NULL == ( vol = getvolbyvid( vid )) ) {
649 return( AFPERR_PARAM );
652 if (vol->v_flags & AFPVOL_RO)
655 memcpy(&did, ibuf, sizeof( did ));
656 ibuf += sizeof( did );
657 if (NULL == ( dir = dirlookup( vol, did )) ) {
658 return( AFPERR_NOOBJ );
661 memcpy(&bitmap, ibuf, sizeof( bitmap ));
662 bitmap = ntohs( bitmap );
663 ibuf += sizeof( bitmap );
665 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
669 if ( *s_path->m_name == '\0' ) {
670 return( AFPERR_BADTYPE ); /* it's a directory */
673 if ((u_long)ibuf & 1 ) {
677 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
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 a defined string for TEXT to support crlf
804 translations and convert all else into pXYY per Inside
805 Appletalk. Always set the creator as "pdos". Changes
806 from original by Marsha Jackson. */
807 case FILPBIT_PDINFO :
808 if (afp_version < 30) { /* else it's UTF8 name */
811 /* Keep special case to support crlf translations */
812 if ((unsigned int) achar == 0x04) {
813 fdType = (u_char *)"TEXT";
816 xyy[0] = ( u_char ) 'p';
822 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
823 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
829 goto setfilparam_done;
837 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
838 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
842 ad_setdate(adp, AD_DATE_MODIFY, newdate);
843 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
848 ad_flush( adp, ADFLAGS_HF );
849 ad_close( adp, ADFLAGS_HF );
853 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
854 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
855 bitmap = 1<<FILPBIT_MDATE;
856 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
860 LOG(log_info, logtype_afpd, "end setfilparams:");
866 * renamefile and copyfile take the old and new unix pathnames
867 * and the new mac name.
868 * NOTE: if we have to copy a file instead of renaming it, locks
869 * will break. Anyway it's an error because then we have 2 files.
871 * src the source path
872 * dst the dest filename in current dir
873 * newname the dest mac name
874 * adp adouble struct of src file, if open, or & zeroed one
877 int renamefile(src, dst, newname, noadouble, adp )
878 char *src, *dst, *newname;
882 char adsrc[ MAXPATHLEN + 1];
886 * Note that this is only checking the existance of the data file,
887 * not the header file. The thinking is that if the data file doesn't
888 * exist, but the header file does, the right thing to do is remove
889 * the data file silently.
892 /* existence check moved to afp_moveandrename */
895 LOG(log_info, logtype_afpd, "begin renamefile:");
898 if ( unix_rename( src, dst ) < 0 ) {
901 return( AFPERR_NOOBJ );
904 return( AFPERR_ACCESS );
907 case EXDEV : /* Cross device move -- try copy */
908 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
909 deletefile( dst, 0 );
912 return deletefile( src, 0);
914 return( AFPERR_PARAM );
918 strcpy( adsrc, ad_path( src, 0 ));
921 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
926 /* check for a source appledouble header. if it exists, make
927 * a dest appledouble directory and do the rename again. */
928 if (rc || stat(adsrc, &st) ||
929 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
932 ad_close(adp, ADFLAGS_HF);
936 return( AFPERR_ACCESS );
940 return( AFPERR_PARAM );
944 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
947 return( AFPERR_NOOBJ );
949 return( AFPERR_ACCESS );
953 return( AFPERR_PARAM );
957 len = strlen( newname );
958 ad_setentrylen( adp, ADEID_NAME, len );
959 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
960 ad_flush( adp, ADFLAGS_HF );
961 ad_close( adp, ADFLAGS_HF );
964 LOG(log_info, logtype_afpd, "end renamefile:");
970 int copy_path_name(char *newname, char *ibuf)
977 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
983 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
984 strncpy( newname, ibuf, plen );
985 newname[ plen ] = '\0';
986 if (strlen(newname) != plen) {
987 /* there's \0 in newname, e.g. it's a pathname not
995 memcpy(&hint, ibuf, sizeof(hint));
996 ibuf += sizeof(hint);
998 memcpy(&len16, ibuf, sizeof(len16));
999 ibuf += sizeof(len16);
1000 plen = ntohs(len16);
1002 strncpy( newname, ibuf, plen );
1003 newname[ plen ] = '\0';
1004 if (strchr(newname,'/')) {
1013 /* -----------------------------------
1015 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1018 int ibuflen, *rbuflen;
1022 char *newname, *p, *upath;
1023 struct path *s_path;
1024 u_int32_t sdid, ddid;
1025 int err, retvalue = AFP_OK;
1026 u_int16_t svid, dvid;
1029 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1035 memcpy(&svid, ibuf, sizeof( svid ));
1036 ibuf += sizeof( svid );
1037 if (NULL == ( vol = getvolbyvid( svid )) ) {
1038 return( AFPERR_PARAM );
1041 memcpy(&sdid, ibuf, sizeof( sdid ));
1042 ibuf += sizeof( sdid );
1043 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1047 memcpy(&dvid, ibuf, sizeof( dvid ));
1048 ibuf += sizeof( dvid );
1049 memcpy(&ddid, ibuf, sizeof( ddid ));
1050 ibuf += sizeof( ddid );
1052 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1055 if ( *s_path->m_name == '\0' ) {
1056 return( AFPERR_BADTYPE );
1059 /* don't allow copies when the file is open.
1060 * XXX: the spec only calls for read/deny write access.
1061 * however, copyfile doesn't have any of that info,
1062 * and locks need to stay coherent. as a result,
1063 * we just balk if the file is opened already. */
1065 newname = obj->newtmp;
1066 strcpy( newname, s_path->m_name );
1068 if (of_findname(s_path))
1069 return AFPERR_DENYCONF;
1071 p = ctoupath( vol, curdir, newname );
1073 /* FIXME svid != dvid && dvid's user can't read svid */
1075 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1076 return( AFPERR_PARAM );
1079 if (vol->v_flags & AFPVOL_RO)
1080 return AFPERR_VLOCK;
1082 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1086 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1089 if ( *s_path->m_name != '\0' ) {
1090 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1093 /* one of the handful of places that knows about the path type */
1094 if (copy_path_name(newname, ibuf) < 0) {
1095 return( AFPERR_PARAM );
1098 upath = mtoupath(vol, newname);
1099 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1105 if (vol->v_flags & AFPVOL_DROPBOX) {
1106 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1108 #endif /* DROPKLUDGE */
1110 setvoltime(obj, vol );
1113 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1120 static __inline__ int copy_all(const int dfd, const void *buf,
1126 LOG(log_info, logtype_afpd, "begin copy_all:");
1129 while (buflen > 0) {
1130 if ((cc = write(dfd, buf, buflen)) < 0) {
1137 return AFPERR_DFULL;
1139 return AFPERR_VLOCK;
1141 return AFPERR_PARAM;
1148 LOG(log_info, logtype_afpd, "end copy_all:");
1154 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1155 * pass in vol and path */
1156 int copyfile(src, dst, newname, noadouble )
1157 char *src, *dst, *newname;
1158 const int noadouble;
1161 #ifdef SENDFILE_FLAVOR_LINUX
1165 int sfd, dfd, len, err = AFP_OK;
1167 char dpath[ MAXPATHLEN + 1];
1170 LOG(log_info, logtype_afpd, "begin copyfile:");
1173 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1174 admode = ad_mode( dst, 0666 );
1176 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1179 break; /* just copy the data fork */
1181 return( AFPERR_ACCESS );
1183 return( AFPERR_PARAM );
1186 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1190 return( AFPERR_NOOBJ );
1192 return( AFPERR_ACCESS );
1194 return AFPERR_VLOCK;
1196 return( AFPERR_PARAM );
1201 #ifdef SENDFILE_FLAVOR_LINUX
1202 if (fstat(sfd, &st) == 0) {
1203 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1217 goto copyheader_done;
1219 #endif /* SENDFILE_FLAVOR_LINUX */
1221 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1228 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1242 /* data fork copying */
1243 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1246 return( AFPERR_NOOBJ );
1248 return( AFPERR_ACCESS );
1250 return( AFPERR_PARAM );
1254 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1258 return( AFPERR_NOOBJ );
1260 return( AFPERR_ACCESS );
1262 return AFPERR_VLOCK;
1264 return( AFPERR_PARAM );
1268 #ifdef SENDFILE_FLAVOR_LINUX
1269 if (fstat(sfd, &st) == 0) {
1270 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1283 #endif /* SENDFILE_FLAVOR_LINUX */
1286 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1294 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1309 memset(&ad, 0, sizeof(ad));
1310 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1314 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1316 return( AFPERR_ACCESS );
1318 return AFPERR_VLOCK;
1320 return( AFPERR_PARAM );
1324 len = strlen( newname );
1325 ad_setentrylen( &ad, ADEID_NAME, len );
1326 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1327 ad_flush( &ad, ADFLAGS_HF );
1328 ad_close( &ad, ADFLAGS_HF );
1332 LOG(log_info, logtype_afpd, "end copyfile:");
1339 /* -----------------------------------
1340 checkAttrib: 1 check kFPDeleteInhibitBit
1341 ie deletfile called by afp_delete
1343 when deletefile is called we don't have lock on it, file is closed (for us)
1344 untrue if called by renamefile
1346 int deletefile( file, checkAttrib )
1351 int adflags, err = AFP_OK;
1352 int locktype = ADLOCK_WR;
1353 int openmode = O_RDWR;
1356 LOG(log_info, logtype_afpd, "begin deletefile:");
1361 * If can't open read/write then try again read-only. If it's open
1362 * read-only, we must do a read lock instead of a write lock.
1364 /* try to open both at once */
1365 adflags = ADFLAGS_DF|ADFLAGS_HF;
1366 memset(&ad, 0, sizeof(ad));
1367 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1370 adflags = ADFLAGS_DF;
1371 /* that failed. now try to open just the data fork */
1372 memset(&ad, 0, sizeof(ad));
1373 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1376 return AFPERR_NOOBJ;
1378 if(openmode == O_RDWR) {
1379 openmode = O_RDONLY;
1380 locktype = ADLOCK_RD;
1383 return AFPERR_ACCESS;
1386 return AFPERR_VLOCK;
1388 return AFPERR_PARAM;
1394 if(openmode == O_RDWR) {
1395 openmode = O_RDONLY;
1396 locktype = ADLOCK_RD;
1399 return AFPERR_ACCESS;
1402 return AFPERR_VLOCK;
1404 return( AFPERR_PARAM );
1407 break; /* from the while */
1410 * Does kFPDeleteInhibitBit (bit 8) set?
1412 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1415 ad_getattr(&ad, &bshort);
1416 if ((bshort & htons(ATTRBIT_NODELETE))) {
1417 ad_close( &ad, adflags );
1418 return(AFPERR_OLOCK);
1422 if ((adflags & ADFLAGS_HF) ) {
1423 /* FIXME we have a pb here because we want to know if a file is open
1424 * there's a 'priority inversion' if you can't open the ressource fork RW
1425 * you can delete it if it's open because you can't get a write lock.
1427 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1430 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1432 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1433 ad_close( &ad, adflags );
1434 return( AFPERR_BUSY );
1438 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0, 0 ) < 0) {
1443 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1447 err = AFPERR_ACCESS;
1460 if ( unlink( file ) < 0 ) {
1464 err = AFPERR_ACCESS;
1478 if (adflags & ADFLAGS_HF)
1479 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0, 0);
1480 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
1481 ad_close( &ad, adflags );
1484 LOG(log_info, logtype_afpd, "end deletefile:");
1490 /* ------------------------------------ */
1492 /* return a file id */
1493 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1496 int ibuflen, *rbuflen;
1499 #if AD_VERSION > AD_VERSION1
1508 struct path *s_path;
1511 LOG(log_info, logtype_afpd, "begin afp_createid:");
1517 memcpy(&vid, ibuf, sizeof(vid));
1518 ibuf += sizeof(vid);
1520 if (NULL == ( vol = getvolbyvid( vid )) ) {
1521 return( AFPERR_PARAM);
1524 if (vol->v_flags & AFPVOL_RO)
1525 return AFPERR_VLOCK;
1527 memcpy(&did, ibuf, sizeof( did ));
1528 ibuf += sizeof(did);
1530 if (NULL == ( dir = dirlookup( vol, did )) ) {
1531 return( AFPERR_PARAM );
1534 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1535 return( AFPERR_PARAM );
1538 if ( *s_path->m_name == '\0' ) {
1539 return( AFPERR_BADTYPE );
1542 upath = s_path->u_name;
1543 switch (s_path->st_errno) {
1545 break; /* success */
1548 return AFPERR_ACCESS;
1550 return AFPERR_NOOBJ;
1552 return AFPERR_PARAM;
1555 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1556 memcpy(rbuf, &id, sizeof(id));
1557 *rbuflen = sizeof(id);
1558 return AFPERR_EXISTID;
1561 #if AD_VERSION > AD_VERSION1
1562 memset(&ad, 0, sizeof(ad));
1563 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1564 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1565 ad_close(&ad, ADFLAGS_HF);
1567 #endif /* AD_VERSION > AD_VERSION1 */
1569 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1570 memcpy(rbuf, &id, sizeof(id));
1571 *rbuflen = sizeof(id);
1576 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1581 return AFPERR_VLOCK;
1585 return AFPERR_ACCESS;
1588 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1589 return AFPERR_PARAM;
1593 /* ------------------------------
1594 resolve a file id */
1595 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1598 int ibuflen, *rbuflen;
1606 u_int16_t vid, bitmap;
1608 static char buffer[12 + MAXPATHLEN + 1];
1609 int len = 12 + MAXPATHLEN + 1;
1612 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1618 memcpy(&vid, ibuf, sizeof(vid));
1619 ibuf += sizeof(vid);
1621 if (NULL == ( vol = getvolbyvid( vid )) ) {
1622 return( AFPERR_PARAM);
1625 memcpy(&id, ibuf, sizeof( id ));
1628 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1629 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1632 if (( dir = dirlookup( vol, id )) == NULL ) {
1633 return AFPERR_NOID; /* idem AFPERR_PARAM */
1635 path.u_name = upath;
1636 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1640 return AFPERR_ACCESS;
1644 return AFPERR_PARAM;
1647 /* directories are bad */
1648 if (S_ISDIR(path.st.st_mode))
1649 return AFPERR_BADTYPE;
1651 memcpy(&bitmap, ibuf, sizeof(bitmap));
1652 bitmap = ntohs( bitmap );
1653 path.m_name = utompath(vol, upath);
1654 if ((err = getfilparams(vol, bitmap, &path , curdir,
1655 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1658 *rbuflen = buflen + sizeof(bitmap);
1659 memcpy(rbuf, ibuf, sizeof(bitmap));
1662 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1668 /* ------------------------------ */
1669 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1672 int ibuflen, *rbuflen;
1682 static char buffer[12 + MAXPATHLEN + 1];
1683 int len = 12 + MAXPATHLEN + 1;
1686 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1692 memcpy(&vid, ibuf, sizeof(vid));
1693 ibuf += sizeof(vid);
1695 if (NULL == ( vol = getvolbyvid( vid )) ) {
1696 return( AFPERR_PARAM);
1699 if (vol->v_flags & AFPVOL_RO)
1700 return AFPERR_VLOCK;
1702 memcpy(&id, ibuf, sizeof( id ));
1706 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1710 if (( dir = dirlookup( vol, id )) == NULL ) {
1711 return( AFPERR_PARAM );
1715 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1719 return AFPERR_ACCESS;
1721 /* still try to delete the id */
1725 return AFPERR_PARAM;
1729 /* directories are bad */
1730 if (S_ISDIR(st.st_mode))
1731 return AFPERR_BADTYPE;
1733 if (cnid_delete(vol->v_db, fileid)) {
1736 return AFPERR_VLOCK;
1739 return AFPERR_ACCESS;
1741 return AFPERR_PARAM;
1746 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1751 #endif /* CNID_DB */
1753 #define APPLETEMP ".AppleTempXXXXXX"
1755 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1758 int ibuflen, *rbuflen;
1760 struct stat srcst, destst;
1762 struct dir *dir, *sdir;
1763 char *spath, temp[17], *p;
1764 char *supath, *upath;
1769 struct adouble *adsp;
1770 struct adouble *addp;
1776 #endif /* CNID_DB */
1781 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1787 memcpy(&vid, ibuf, sizeof(vid));
1788 ibuf += sizeof(vid);
1790 if (NULL == ( vol = getvolbyvid( vid )) ) {
1791 return( AFPERR_PARAM);
1794 if (vol->v_flags & AFPVOL_RO)
1795 return AFPERR_VLOCK;
1797 /* source and destination dids */
1798 memcpy(&sid, ibuf, sizeof(sid));
1799 ibuf += sizeof(sid);
1800 memcpy(&did, ibuf, sizeof(did));
1801 ibuf += sizeof(did);
1804 if (NULL == (dir = dirlookup( vol, sid )) ) {
1805 return( AFPERR_PARAM );
1808 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1809 return( AFPERR_PARAM );
1812 if ( *path->m_name == '\0' ) {
1813 return( AFPERR_BADTYPE ); /* it's a dir */
1816 upath = path->u_name;
1817 switch (path->st_errno) {
1824 return AFPERR_ACCESS;
1826 return AFPERR_PARAM;
1828 memset(&ads, 0, sizeof(ads));
1830 if ((s_of = of_findname(path))) {
1831 /* reuse struct adouble so it won't break locks */
1834 memcpy(&srcst, &path->st, sizeof(struct stat));
1835 /* save some stuff */
1837 spath = obj->oldtmp;
1838 supath = obj->newtmp;
1839 strcpy(spath, path->m_name);
1840 strcpy(supath, upath); /* this is for the cnid changing */
1841 p = absupath( vol, sdir, upath);
1843 /* look for the source cnid. if it doesn't exist, don't worry about
1846 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1847 slen = strlen(supath));
1848 #endif /* CNID_DB */
1850 if (NULL == ( dir = dirlookup( vol, did )) ) {
1851 return( AFPERR_PARAM );
1854 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1855 return( AFPERR_PARAM );
1858 if ( *path->m_name == '\0' ) {
1859 return( AFPERR_BADTYPE );
1862 /* FPExchangeFiles is the only call that can return the SameObj
1864 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1865 return AFPERR_SAMEOBJ;
1866 memcpy(&srcst, &path->st, sizeof(struct stat));
1875 return AFPERR_ACCESS;
1877 return AFPERR_PARAM;
1879 memset(&add, 0, sizeof(add));
1881 if ((d_of = of_findname( path))) {
1882 /* reuse struct adouble so it won't break locks */
1885 memcpy(&destst, &path->st, sizeof(struct stat));
1887 /* they are not on the same device and at least one is open
1889 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1892 upath = path->u_name;
1894 /* look for destination id. */
1895 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1896 dlen = strlen(upath));
1897 #endif /* CNID_DB */
1899 /* construct a temp name.
1900 * NOTE: the temp file will be in the dest file's directory. it
1901 * will also be inaccessible from AFP. */
1902 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1906 /* now, quickly rename the file. we error if we can't. */
1907 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1908 goto err_exchangefile;
1909 of_rename(vol, s_of, sdir, spath, curdir, temp);
1911 /* rename destination to source */
1912 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1913 goto err_src_to_tmp;
1914 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1916 /* rename temp to destination */
1917 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1918 goto err_dest_to_src;
1919 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1922 /* id's need switching. src -> dest and dest -> src. */
1923 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1924 upath, dlen) < 0)) {
1928 err = AFPERR_ACCESS;
1933 goto err_temp_to_dest;
1936 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1937 supath, slen) < 0)) {
1941 err = AFPERR_ACCESS;
1948 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1949 goto err_temp_to_dest;
1951 #endif /* CNID_DB */
1954 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1960 /* all this stuff is so that we can unwind a failed operation
1965 /* rename dest to temp */
1966 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1967 of_rename(vol, s_of, curdir, upath, curdir, temp);
1970 /* rename source back to dest */
1971 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1972 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1975 /* rename temp back to source */
1976 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1977 of_rename(vol, s_of, curdir, temp, sdir, spath);