2 * $Id: file.c,v 1.72 2003-01-12 14:39:59 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 (( 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 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 :
810 /* Keep special case to support crlf translations */
811 if ((unsigned int) achar == 0x04) {
812 fdType = (u_char *)"TEXT";
815 xyy[0] = ( u_char ) 'p';
821 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
822 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
828 goto setfilparam_done;
836 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
837 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
841 ad_setdate(adp, AD_DATE_MODIFY, newdate);
842 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
847 ad_flush( adp, ADFLAGS_HF );
848 ad_close( adp, ADFLAGS_HF );
852 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
853 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
854 bitmap = 1<<FILPBIT_MDATE;
855 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
859 LOG(log_info, logtype_afpd, "end setfilparams:");
865 * renamefile and copyfile take the old and new unix pathnames
866 * and the new mac name.
867 * NOTE: if we have to copy a file instead of renaming it, locks
868 * will break. Anyway it's an error because then we have 2 files.
870 * src the source path
871 * dst the dest filename in current dir
872 * newname the dest mac name
873 * adp adouble struct of src file, if open, or & zeroed one
876 int renamefile(src, dst, newname, noadouble, adp )
877 char *src, *dst, *newname;
881 char adsrc[ MAXPATHLEN + 1];
885 * Note that this is only checking the existance of the data file,
886 * not the header file. The thinking is that if the data file doesn't
887 * exist, but the header file does, the right thing to do is remove
888 * the data file silently.
891 /* existence check moved to afp_moveandrename */
894 LOG(log_info, logtype_afpd, "begin renamefile:");
897 if ( unix_rename( src, dst ) < 0 ) {
900 return( AFPERR_NOOBJ );
903 return( AFPERR_ACCESS );
906 case EXDEV : /* Cross device move -- try copy */
907 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
908 deletefile( dst, 0 );
911 return deletefile( src, 0);
913 return( AFPERR_PARAM );
917 strcpy( adsrc, ad_path( src, 0 ));
920 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
925 /* check for a source appledouble header. if it exists, make
926 * a dest appledouble directory and do the rename again. */
927 if (rc || stat(adsrc, &st) ||
928 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
931 ad_close(adp, ADFLAGS_HF);
935 return( AFPERR_ACCESS );
939 return( AFPERR_PARAM );
943 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
946 return( AFPERR_NOOBJ );
948 return( AFPERR_ACCESS );
952 return( AFPERR_PARAM );
956 len = strlen( newname );
957 ad_setentrylen( adp, ADEID_NAME, len );
958 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
959 ad_flush( adp, ADFLAGS_HF );
960 ad_close( adp, ADFLAGS_HF );
963 LOG(log_info, logtype_afpd, "end renamefile:");
969 int copy_path_name(char *newname, char *ibuf)
976 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
982 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
983 strncpy( newname, ibuf, plen );
984 newname[ plen ] = '\0';
985 if (strlen(newname) != plen) {
986 /* there's \0 in newname, e.g. it's a pathname not
994 memcpy(&hint, ibuf, sizeof(hint));
995 ibuf += sizeof(hint);
997 memcpy(&len16, ibuf, sizeof(len16));
998 ibuf += sizeof(len16);
1001 strncpy( newname, ibuf, plen );
1002 newname[ plen ] = '\0';
1003 if (strchr(newname,'/')) {
1012 /* -----------------------------------
1014 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1017 int ibuflen, *rbuflen;
1021 char *newname, *p, *upath;
1022 struct path *s_path;
1023 u_int32_t sdid, ddid;
1024 int err, retvalue = AFP_OK;
1025 u_int16_t svid, dvid;
1028 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1034 memcpy(&svid, ibuf, sizeof( svid ));
1035 ibuf += sizeof( svid );
1036 if (NULL == ( vol = getvolbyvid( svid )) ) {
1037 return( AFPERR_PARAM );
1040 memcpy(&sdid, ibuf, sizeof( sdid ));
1041 ibuf += sizeof( sdid );
1042 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1046 memcpy(&dvid, ibuf, sizeof( dvid ));
1047 ibuf += sizeof( dvid );
1048 memcpy(&ddid, ibuf, sizeof( ddid ));
1049 ibuf += sizeof( ddid );
1051 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1054 if ( *s_path->m_name == '\0' ) {
1055 return( AFPERR_BADTYPE );
1058 /* don't allow copies when the file is open.
1059 * XXX: the spec only calls for read/deny write access.
1060 * however, copyfile doesn't have any of that info,
1061 * and locks need to stay coherent. as a result,
1062 * we just balk if the file is opened already. */
1064 newname = obj->newtmp;
1065 strcpy( newname, s_path->m_name );
1067 if (of_findname(s_path))
1068 return AFPERR_DENYCONF;
1070 p = ctoupath( vol, curdir, newname );
1072 /* FIXME svid != dvid && dvid's user can't read svid */
1074 if (( vol = getvolbyvid( dvid )) == NULL ) {
1075 return( AFPERR_PARAM );
1078 if (vol->v_flags & AFPVOL_RO)
1079 return AFPERR_VLOCK;
1081 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1085 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1088 if ( *s_path->m_name != '\0' ) {
1089 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1092 /* one of the handful of places that knows about the path type */
1093 if (copy_path_name(newname, ibuf) < 0) {
1094 return( AFPERR_PARAM );
1097 upath = mtoupath(vol, newname);
1098 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1104 if (vol->v_flags & AFPVOL_DROPBOX) {
1105 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1107 #endif /* DROPKLUDGE */
1109 setvoltime(obj, vol );
1112 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1119 static __inline__ int copy_all(const int dfd, const void *buf,
1125 LOG(log_info, logtype_afpd, "begin copy_all:");
1128 while (buflen > 0) {
1129 if ((cc = write(dfd, buf, buflen)) < 0) {
1136 return AFPERR_DFULL;
1138 return AFPERR_VLOCK;
1140 return AFPERR_PARAM;
1147 LOG(log_info, logtype_afpd, "end copy_all:");
1153 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1154 * pass in vol and path */
1155 int copyfile(src, dst, newname, noadouble )
1156 char *src, *dst, *newname;
1157 const int noadouble;
1160 #ifdef SENDFILE_FLAVOR_LINUX
1164 int sfd, dfd, len, err = AFP_OK;
1166 char dpath[ MAXPATHLEN + 1];
1169 LOG(log_info, logtype_afpd, "begin copyfile:");
1172 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1173 admode = ad_mode( dst, 0666 );
1175 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1178 break; /* just copy the data fork */
1180 return( AFPERR_ACCESS );
1182 return( AFPERR_PARAM );
1185 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1189 return( AFPERR_NOOBJ );
1191 return( AFPERR_ACCESS );
1193 return AFPERR_VLOCK;
1195 return( AFPERR_PARAM );
1200 #ifdef SENDFILE_FLAVOR_LINUX
1201 if (fstat(sfd, &st) == 0) {
1202 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1216 goto copyheader_done;
1218 #endif /* SENDFILE_FLAVOR_LINUX */
1220 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1227 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1241 /* data fork copying */
1242 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1245 return( AFPERR_NOOBJ );
1247 return( AFPERR_ACCESS );
1249 return( AFPERR_PARAM );
1253 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1257 return( AFPERR_NOOBJ );
1259 return( AFPERR_ACCESS );
1261 return AFPERR_VLOCK;
1263 return( AFPERR_PARAM );
1267 #ifdef SENDFILE_FLAVOR_LINUX
1268 if (fstat(sfd, &st) == 0) {
1269 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1282 #endif /* SENDFILE_FLAVOR_LINUX */
1285 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1293 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1308 memset(&ad, 0, sizeof(ad));
1309 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1313 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1315 return( AFPERR_ACCESS );
1317 return AFPERR_VLOCK;
1319 return( AFPERR_PARAM );
1323 len = strlen( newname );
1324 ad_setentrylen( &ad, ADEID_NAME, len );
1325 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1326 ad_flush( &ad, ADFLAGS_HF );
1327 ad_close( &ad, ADFLAGS_HF );
1331 LOG(log_info, logtype_afpd, "end copyfile:");
1338 /* -----------------------------------
1339 checkAttrib: 1 check kFPDeleteInhibitBit
1340 ie deletfile called by afp_delete
1342 when deletefile is called we don't have lock on it, file is closed (for us)
1343 untrue if called by renamefile
1345 int deletefile( file, checkAttrib )
1350 int adflags, err = AFP_OK;
1351 int locktype = ADLOCK_WR;
1352 int openmode = O_RDWR;
1355 LOG(log_info, logtype_afpd, "begin deletefile:");
1360 * If can't open read/write then try again read-only. If it's open
1361 * read-only, we must do a read lock instead of a write lock.
1363 /* try to open both at once */
1364 adflags = ADFLAGS_DF|ADFLAGS_HF;
1365 memset(&ad, 0, sizeof(ad));
1366 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1369 adflags = ADFLAGS_DF;
1370 /* that failed. now try to open just the data fork */
1371 memset(&ad, 0, sizeof(ad));
1372 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1375 return AFPERR_NOOBJ;
1377 if(openmode == O_RDWR) {
1378 openmode = O_RDONLY;
1379 locktype = ADLOCK_RD;
1382 return AFPERR_ACCESS;
1385 return AFPERR_VLOCK;
1387 return AFPERR_PARAM;
1393 if(openmode == O_RDWR) {
1394 openmode = O_RDONLY;
1395 locktype = ADLOCK_RD;
1398 return AFPERR_ACCESS;
1401 return AFPERR_VLOCK;
1403 return( AFPERR_PARAM );
1406 break; /* from the while */
1409 * Does kFPDeleteInhibitBit (bit 8) set?
1411 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1414 ad_getattr(&ad, &bshort);
1415 if ((bshort & htons(ATTRBIT_NODELETE))) {
1416 ad_close( &ad, adflags );
1417 return(AFPERR_OLOCK);
1421 if ((adflags & ADFLAGS_HF) ) {
1422 /* FIXME we have a pb here because we want to know if a file is open
1423 * there's a 'priority inversion' if you can't open the ressource fork RW
1424 * you can delete it if it's open because you can't get a write lock.
1426 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1429 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1431 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1432 ad_close( &ad, adflags );
1433 return( AFPERR_BUSY );
1437 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1442 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1446 err = AFPERR_ACCESS;
1459 if ( unlink( file ) < 0 ) {
1463 err = AFPERR_ACCESS;
1477 if (adflags & ADFLAGS_HF)
1478 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1479 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1480 ad_close( &ad, adflags );
1483 LOG(log_info, logtype_afpd, "end deletefile:");
1489 /* ------------------------------------ */
1491 /* return a file id */
1492 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1495 int ibuflen, *rbuflen;
1498 #if AD_VERSION > AD_VERSION1
1507 struct path *s_path;
1510 LOG(log_info, logtype_afpd, "begin afp_createid:");
1516 memcpy(&vid, ibuf, sizeof(vid));
1517 ibuf += sizeof(vid);
1519 if (NULL == ( vol = getvolbyvid( vid )) ) {
1520 return( AFPERR_PARAM);
1523 if (vol->v_flags & AFPVOL_RO)
1524 return AFPERR_VLOCK;
1526 memcpy(&did, ibuf, sizeof( did ));
1527 ibuf += sizeof(did);
1529 if (( dir = dirlookup( vol, did )) == NULL ) {
1530 return( AFPERR_PARAM );
1533 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1534 return( AFPERR_PARAM );
1537 if ( *s_path->m_name == '\0' ) {
1538 return( AFPERR_BADTYPE );
1541 upath = s_path->u_name;
1542 switch (s_path->st_errno) {
1544 break; /* success */
1547 return AFPERR_ACCESS;
1549 return AFPERR_NOOBJ;
1551 return AFPERR_PARAM;
1554 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1555 memcpy(rbuf, &id, sizeof(id));
1556 *rbuflen = sizeof(id);
1557 return AFPERR_EXISTID;
1560 #if AD_VERSION > AD_VERSION1
1561 memset(&ad, 0, sizeof(ad));
1562 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1563 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1564 ad_close(&ad, ADFLAGS_HF);
1566 #endif /* AD_VERSION > AD_VERSION1 */
1568 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1569 memcpy(rbuf, &id, sizeof(id));
1570 *rbuflen = sizeof(id);
1575 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1580 return AFPERR_VLOCK;
1584 return AFPERR_ACCESS;
1587 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1588 return AFPERR_PARAM;
1592 /* ------------------------------
1593 resolve a file id */
1594 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1597 int ibuflen, *rbuflen;
1605 u_int16_t vid, bitmap;
1607 static char buffer[12 + MAXPATHLEN + 1];
1608 int len = 12 + MAXPATHLEN + 1;
1611 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1617 memcpy(&vid, ibuf, sizeof(vid));
1618 ibuf += sizeof(vid);
1620 if (( vol = getvolbyvid( vid )) == NULL ) {
1621 return( AFPERR_PARAM);
1624 memcpy(&id, ibuf, sizeof( id ));
1627 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1628 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1631 if (( dir = dirlookup( vol, id )) == NULL ) {
1632 return AFPERR_NOID; /* idem AFPERR_PARAM */
1634 path.u_name = upath;
1635 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1639 return AFPERR_ACCESS;
1643 return AFPERR_PARAM;
1646 /* directories are bad */
1647 if (S_ISDIR(path.st.st_mode))
1648 return AFPERR_BADTYPE;
1650 memcpy(&bitmap, ibuf, sizeof(bitmap));
1651 bitmap = ntohs( bitmap );
1652 path.m_name = utompath(vol, upath);
1653 if ((err = getfilparams(vol, bitmap, &path , curdir,
1654 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1657 *rbuflen = buflen + sizeof(bitmap);
1658 memcpy(rbuf, ibuf, sizeof(bitmap));
1661 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1667 /* ------------------------------ */
1668 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1671 int ibuflen, *rbuflen;
1681 static char buffer[12 + MAXPATHLEN + 1];
1682 int len = 12 + MAXPATHLEN + 1;
1685 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1691 memcpy(&vid, ibuf, sizeof(vid));
1692 ibuf += sizeof(vid);
1694 if (( vol = getvolbyvid( vid )) == NULL ) {
1695 return( AFPERR_PARAM);
1698 if (vol->v_flags & AFPVOL_RO)
1699 return AFPERR_VLOCK;
1701 memcpy(&id, ibuf, sizeof( id ));
1705 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1709 if (( dir = dirlookup( vol, id )) == NULL ) {
1710 return( AFPERR_PARAM );
1714 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1718 return AFPERR_ACCESS;
1720 /* still try to delete the id */
1724 return AFPERR_PARAM;
1728 /* directories are bad */
1729 if (S_ISDIR(st.st_mode))
1730 return AFPERR_BADTYPE;
1732 if (cnid_delete(vol->v_db, fileid)) {
1735 return AFPERR_VLOCK;
1738 return AFPERR_ACCESS;
1740 return AFPERR_PARAM;
1745 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1750 #endif /* CNID_DB */
1752 #define APPLETEMP ".AppleTempXXXXXX"
1754 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1757 int ibuflen, *rbuflen;
1759 struct stat srcst, destst;
1761 struct dir *dir, *sdir;
1762 char *spath, temp[17], *p;
1763 char *supath, *upath;
1768 struct adouble *adsp;
1769 struct adouble *addp;
1775 #endif /* CNID_DB */
1780 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1786 memcpy(&vid, ibuf, sizeof(vid));
1787 ibuf += sizeof(vid);
1789 if (NULL == ( vol = getvolbyvid( vid )) ) {
1790 return( AFPERR_PARAM);
1793 if (vol->v_flags & AFPVOL_RO)
1794 return AFPERR_VLOCK;
1796 /* source and destination dids */
1797 memcpy(&sid, ibuf, sizeof(sid));
1798 ibuf += sizeof(sid);
1799 memcpy(&did, ibuf, sizeof(did));
1800 ibuf += sizeof(did);
1803 if ((dir = dirlookup( vol, sid )) == NULL ) {
1804 return( AFPERR_PARAM );
1807 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1808 return( AFPERR_PARAM );
1811 if ( *path->m_name == '\0' ) {
1812 return( AFPERR_BADTYPE ); /* it's a dir */
1815 upath = path->u_name;
1816 switch (path->st_errno) {
1823 return AFPERR_ACCESS;
1825 return AFPERR_PARAM;
1827 memset(&ads, 0, sizeof(ads));
1829 if ((s_of = of_findname(path))) {
1830 /* reuse struct adouble so it won't break locks */
1833 memcpy(&srcst, &path->st, sizeof(struct stat));
1834 /* save some stuff */
1836 spath = obj->oldtmp;
1837 supath = obj->newtmp;
1838 strcpy(spath, path->m_name);
1839 strcpy(supath, upath); /* this is for the cnid changing */
1840 p = absupath( vol, sdir, upath);
1842 /* look for the source cnid. if it doesn't exist, don't worry about
1845 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1846 slen = strlen(supath));
1847 #endif /* CNID_DB */
1849 if (( dir = dirlookup( vol, did )) == NULL ) {
1850 return( AFPERR_PARAM );
1853 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1854 return( AFPERR_PARAM );
1857 if ( *path->m_name == '\0' ) {
1858 return( AFPERR_BADTYPE );
1861 /* FPExchangeFiles is the only call that can return the SameObj
1863 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1864 return AFPERR_SAMEOBJ;
1865 memcpy(&srcst, &path->st, sizeof(struct stat));
1874 return AFPERR_ACCESS;
1876 return AFPERR_PARAM;
1878 memset(&add, 0, sizeof(add));
1880 if ((d_of = of_findname( path))) {
1881 /* reuse struct adouble so it won't break locks */
1884 memcpy(&destst, &path->st, sizeof(struct stat));
1886 /* they are not on the same device and at least one is open
1888 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1891 upath = path->u_name;
1893 /* look for destination id. */
1894 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1895 dlen = strlen(upath));
1896 #endif /* CNID_DB */
1898 /* construct a temp name.
1899 * NOTE: the temp file will be in the dest file's directory. it
1900 * will also be inaccessible from AFP. */
1901 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1905 /* now, quickly rename the file. we error if we can't. */
1906 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1907 goto err_exchangefile;
1908 of_rename(vol, s_of, sdir, spath, curdir, temp);
1910 /* rename destination to source */
1911 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1912 goto err_src_to_tmp;
1913 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1915 /* rename temp to destination */
1916 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1917 goto err_dest_to_src;
1918 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1921 /* id's need switching. src -> dest and dest -> src. */
1922 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1923 upath, dlen) < 0)) {
1927 err = AFPERR_ACCESS;
1932 goto err_temp_to_dest;
1935 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1936 supath, slen) < 0)) {
1940 err = AFPERR_ACCESS;
1947 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1948 goto err_temp_to_dest;
1950 #endif /* CNID_DB */
1953 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1959 /* all this stuff is so that we can unwind a failed operation
1964 /* rename dest to temp */
1965 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1966 of_rename(vol, s_of, curdir, upath, curdir, temp);
1969 /* rename source back to dest */
1970 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1971 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1974 /* rename temp back to source */
1975 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1976 of_rename(vol, s_of, curdir, temp, sdir, spath);