2 * $Id: file.c,v 1.80 2003-01-30 17:32:46 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 afp_errno; /* was 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 (path_isadir(s_path)) {
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 ( path_isadir(s_path) ) {
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 return AFPERR_PARAM;
1077 /* FIXME svid != dvid && dvid's user can't read svid */
1079 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1080 return( AFPERR_PARAM );
1083 if (vol->v_flags & AFPVOL_RO)
1084 return AFPERR_VLOCK;
1086 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1090 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1093 if ( *s_path->m_name != '\0' ) {
1094 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1097 /* one of the handful of places that knows about the path type */
1098 if (copy_path_name(newname, ibuf) < 0) {
1099 return( AFPERR_PARAM );
1102 upath = mtoupath(vol, newname);
1103 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1109 if (vol->v_flags & AFPVOL_DROPBOX) {
1110 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1112 #endif /* DROPKLUDGE */
1114 setvoltime(obj, vol );
1117 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1124 static __inline__ int copy_all(const int dfd, const void *buf,
1130 LOG(log_info, logtype_afpd, "begin copy_all:");
1133 while (buflen > 0) {
1134 if ((cc = write(dfd, buf, buflen)) < 0) {
1141 return AFPERR_DFULL;
1143 return AFPERR_VLOCK;
1145 return AFPERR_PARAM;
1152 LOG(log_info, logtype_afpd, "end copy_all:");
1158 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1159 * pass in vol and path */
1160 int copyfile(src, dst, newname, noadouble )
1161 char *src, *dst, *newname;
1162 const int noadouble;
1165 #ifdef SENDFILE_FLAVOR_LINUX
1169 int sfd, dfd, len, err = AFP_OK;
1171 char dpath[ MAXPATHLEN + 1];
1174 LOG(log_info, logtype_afpd, "begin copyfile:");
1177 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1178 admode = ad_mode( dst, 0666 );
1180 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1183 break; /* just copy the data fork */
1185 return( AFPERR_ACCESS );
1187 return( AFPERR_PARAM );
1190 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1194 return( AFPERR_NOOBJ );
1196 return( AFPERR_ACCESS );
1198 return AFPERR_VLOCK;
1200 return( AFPERR_PARAM );
1205 #ifdef SENDFILE_FLAVOR_LINUX
1206 if (fstat(sfd, &st) == 0) {
1207 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1221 goto copyheader_done;
1223 #endif /* SENDFILE_FLAVOR_LINUX */
1225 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1232 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1246 /* data fork copying */
1247 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1250 return( AFPERR_NOOBJ );
1252 return( AFPERR_ACCESS );
1254 return( AFPERR_PARAM );
1258 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1262 return( AFPERR_NOOBJ );
1264 return( AFPERR_ACCESS );
1266 return AFPERR_VLOCK;
1268 return( AFPERR_PARAM );
1272 #ifdef SENDFILE_FLAVOR_LINUX
1273 if (fstat(sfd, &st) == 0) {
1274 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1287 #endif /* SENDFILE_FLAVOR_LINUX */
1290 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1298 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1313 memset(&ad, 0, sizeof(ad));
1314 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1318 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1320 return( AFPERR_ACCESS );
1322 return AFPERR_VLOCK;
1324 return( AFPERR_PARAM );
1328 len = strlen( newname );
1329 ad_setentrylen( &ad, ADEID_NAME, len );
1330 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1331 ad_flush( &ad, ADFLAGS_HF );
1332 ad_close( &ad, ADFLAGS_HF );
1336 LOG(log_info, logtype_afpd, "end copyfile:");
1343 /* -----------------------------------
1344 checkAttrib: 1 check kFPDeleteInhibitBit
1345 ie deletfile called by afp_delete
1347 when deletefile is called we don't have lock on it, file is closed (for us)
1348 untrue if called by renamefile
1350 int deletefile( file, checkAttrib )
1355 int adflags, err = AFP_OK;
1356 int openmode = O_RDWR;
1359 LOG(log_info, logtype_afpd, "begin deletefile:");
1364 * If can't open read/write then try again read-only. If it's open
1365 * read-only, we must do a read lock instead of a write lock.
1367 /* try to open both at once */
1368 adflags = ADFLAGS_DF|ADFLAGS_HF;
1369 memset(&ad, 0, sizeof(ad));
1370 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1373 adflags = ADFLAGS_DF;
1374 /* that failed. now try to open just the data fork */
1375 memset(&ad, 0, sizeof(ad));
1376 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1379 return AFPERR_NOOBJ;
1381 if(openmode == O_RDWR) {
1382 openmode = O_RDONLY;
1385 return AFPERR_ACCESS;
1388 return AFPERR_VLOCK;
1390 return AFPERR_PARAM;
1396 if(openmode == O_RDWR) {
1397 openmode = O_RDONLY;
1400 return AFPERR_ACCESS;
1403 return AFPERR_VLOCK;
1405 return( AFPERR_PARAM );
1408 break; /* from the while */
1411 * Does kFPDeleteInhibitBit (bit 8) set?
1413 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1416 ad_getattr(&ad, &bshort);
1417 if ((bshort & htons(ATTRBIT_NODELETE))) {
1418 ad_close( &ad, adflags );
1419 return(AFPERR_OLOCK);
1423 if ((adflags & ADFLAGS_HF) ) {
1424 /* FIXME we have a pb here because we want to know if a file is open
1425 * there's a 'priority inversion' if you can't open the ressource fork RW
1426 * you can delete it if it's open because you can't get a write lock.
1428 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1431 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1433 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1434 ad_close( &ad, adflags );
1435 return( AFPERR_BUSY );
1439 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1442 else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
1443 err = netatalk_unlink( file );
1446 if (adflags & ADFLAGS_HF)
1447 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0, 0);
1448 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
1449 ad_close( &ad, adflags );
1452 LOG(log_info, logtype_afpd, "end deletefile:");
1458 /* ------------------------------------ */
1460 /* return a file id */
1461 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1464 int ibuflen, *rbuflen;
1467 #if AD_VERSION > AD_VERSION1
1476 struct path *s_path;
1479 LOG(log_info, logtype_afpd, "begin afp_createid:");
1485 memcpy(&vid, ibuf, sizeof(vid));
1486 ibuf += sizeof(vid);
1488 if (NULL == ( vol = getvolbyvid( vid )) ) {
1489 return( AFPERR_PARAM);
1492 if (vol->v_flags & AFPVOL_RO)
1493 return AFPERR_VLOCK;
1495 memcpy(&did, ibuf, sizeof( did ));
1496 ibuf += sizeof(did);
1498 if (NULL == ( dir = dirlookup( vol, did )) ) {
1499 return( AFPERR_PARAM );
1502 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1503 return afp_errno; /* was AFPERR_PARAM */
1506 if ( path_isadir(s_path) ) {
1507 return( AFPERR_BADTYPE );
1510 upath = s_path->u_name;
1511 switch (s_path->st_errno) {
1513 break; /* success */
1516 return AFPERR_ACCESS;
1518 return AFPERR_NOOBJ;
1520 return AFPERR_PARAM;
1523 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1524 memcpy(rbuf, &id, sizeof(id));
1525 *rbuflen = sizeof(id);
1526 return AFPERR_EXISTID;
1529 #if AD_VERSION > AD_VERSION1
1530 memset(&ad, 0, sizeof(ad));
1531 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1532 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1533 ad_close(&ad, ADFLAGS_HF);
1535 #endif /* AD_VERSION > AD_VERSION1 */
1537 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1538 memcpy(rbuf, &id, sizeof(id));
1539 *rbuflen = sizeof(id);
1544 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1549 return AFPERR_VLOCK;
1553 return AFPERR_ACCESS;
1556 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1557 return AFPERR_PARAM;
1561 /* ------------------------------
1562 resolve a file id */
1563 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1566 int ibuflen, *rbuflen;
1574 u_int16_t vid, bitmap;
1576 static char buffer[12 + MAXPATHLEN + 1];
1577 int len = 12 + MAXPATHLEN + 1;
1580 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1586 memcpy(&vid, ibuf, sizeof(vid));
1587 ibuf += sizeof(vid);
1589 if (NULL == ( vol = getvolbyvid( vid )) ) {
1590 return( AFPERR_PARAM);
1593 memcpy(&id, ibuf, sizeof( id ));
1596 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1597 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1600 if (( dir = dirlookup( vol, id )) == NULL ) {
1601 return AFPERR_NOID; /* idem AFPERR_PARAM */
1603 path.u_name = upath;
1604 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1608 return AFPERR_ACCESS;
1612 return AFPERR_PARAM;
1615 /* directories are bad */
1616 if (S_ISDIR(path.st.st_mode))
1617 return AFPERR_BADTYPE;
1619 memcpy(&bitmap, ibuf, sizeof(bitmap));
1620 bitmap = ntohs( bitmap );
1621 path.m_name = utompath(vol, upath);
1622 if ((err = getfilparams(vol, bitmap, &path , curdir,
1623 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1626 *rbuflen = buflen + sizeof(bitmap);
1627 memcpy(rbuf, ibuf, sizeof(bitmap));
1630 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1636 /* ------------------------------ */
1637 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1640 int ibuflen, *rbuflen;
1650 static char buffer[12 + MAXPATHLEN + 1];
1651 int len = 12 + MAXPATHLEN + 1;
1654 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1660 memcpy(&vid, ibuf, sizeof(vid));
1661 ibuf += sizeof(vid);
1663 if (NULL == ( vol = getvolbyvid( vid )) ) {
1664 return( AFPERR_PARAM);
1667 if (vol->v_flags & AFPVOL_RO)
1668 return AFPERR_VLOCK;
1670 memcpy(&id, ibuf, sizeof( id ));
1674 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1678 if (( dir = dirlookup( vol, id )) == NULL ) {
1679 return( AFPERR_PARAM );
1683 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1687 return AFPERR_ACCESS;
1689 /* still try to delete the id */
1693 return AFPERR_PARAM;
1697 /* directories are bad */
1698 if (S_ISDIR(st.st_mode))
1699 return AFPERR_BADTYPE;
1701 if (cnid_delete(vol->v_db, fileid)) {
1704 return AFPERR_VLOCK;
1707 return AFPERR_ACCESS;
1709 return AFPERR_PARAM;
1714 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1719 #endif /* CNID_DB */
1721 #define APPLETEMP ".AppleTempXXXXXX"
1723 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1726 int ibuflen, *rbuflen;
1728 struct stat srcst, destst;
1730 struct dir *dir, *sdir;
1731 char *spath, temp[17], *p;
1732 char *supath, *upath;
1737 struct adouble *adsp;
1738 struct adouble *addp;
1745 #endif /* CNID_DB */
1750 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1756 memcpy(&vid, ibuf, sizeof(vid));
1757 ibuf += sizeof(vid);
1759 if (NULL == ( vol = getvolbyvid( vid )) ) {
1760 return( AFPERR_PARAM);
1763 if (vol->v_flags & AFPVOL_RO)
1764 return AFPERR_VLOCK;
1766 /* source and destination dids */
1767 memcpy(&sid, ibuf, sizeof(sid));
1768 ibuf += sizeof(sid);
1769 memcpy(&did, ibuf, sizeof(did));
1770 ibuf += sizeof(did);
1773 if (NULL == (dir = dirlookup( vol, sid )) ) {
1774 return( AFPERR_PARAM );
1777 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1778 return afp_errno; /* was AFPERR_PARAM */
1781 if ( path_isadir(path) ) {
1782 return( AFPERR_BADTYPE ); /* it's a dir */
1785 upath = path->u_name;
1786 switch (path->st_errno) {
1793 return AFPERR_ACCESS;
1795 return AFPERR_PARAM;
1797 memset(&ads, 0, sizeof(ads));
1799 if ((s_of = of_findname(path))) {
1800 /* reuse struct adouble so it won't break locks */
1803 memcpy(&srcst, &path->st, sizeof(struct stat));
1804 /* save some stuff */
1806 spath = obj->oldtmp;
1807 supath = obj->newtmp;
1808 strcpy(spath, path->m_name);
1809 strcpy(supath, upath); /* this is for the cnid changing */
1810 p = absupath( vol, sdir, upath);
1812 /* pathname too long */
1813 return AFPERR_PARAM ;
1816 /* look for the source cnid. if it doesn't exist, don't worry about
1819 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1820 slen = strlen(supath));
1821 #endif /* CNID_DB */
1823 if (NULL == ( dir = dirlookup( vol, did )) ) {
1824 return( AFPERR_PARAM );
1827 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1828 return( AFPERR_PARAM );
1831 if ( path_isadir(path) ) {
1832 return( AFPERR_BADTYPE );
1835 /* FPExchangeFiles is the only call that can return the SameObj
1837 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1838 return AFPERR_SAMEOBJ;
1840 switch (path->st_errno) {
1847 return AFPERR_ACCESS;
1849 return AFPERR_PARAM;
1851 memset(&add, 0, sizeof(add));
1853 if ((d_of = of_findname( path))) {
1854 /* reuse struct adouble so it won't break locks */
1857 memcpy(&destst, &path->st, sizeof(struct stat));
1859 /* they are not on the same device and at least one is open
1861 crossdev = (srcst.st_dev != destst.st_dev);
1862 if ((d_of || s_of) && crossdev)
1865 upath = path->u_name;
1867 /* look for destination id. */
1868 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1869 dlen = strlen(upath));
1870 #endif /* CNID_DB */
1872 /* construct a temp name.
1873 * NOTE: the temp file will be in the dest file's directory. it
1874 * will also be inaccessible from AFP. */
1875 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1879 /* now, quickly rename the file. we error if we can't. */
1880 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1881 goto err_exchangefile;
1882 of_rename(vol, s_of, sdir, spath, curdir, temp);
1884 /* rename destination to source */
1885 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1886 goto err_src_to_tmp;
1887 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1889 /* rename temp to destination */
1890 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1891 goto err_dest_to_src;
1892 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1895 /* id's need switching. src -> dest and dest -> src.
1896 * we need to re-stat() if it was a cross device copy.
1899 cnid_delete(vol->v_db, sid);
1902 cnid_delete(vol->v_db, did);
1904 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1905 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1907 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1908 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1913 err = AFPERR_ACCESS;
1918 goto err_temp_to_dest;
1920 #endif /* CNID_DB */
1923 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1929 /* all this stuff is so that we can unwind a failed operation
1934 /* rename dest to temp */
1935 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1936 of_rename(vol, s_of, curdir, upath, curdir, temp);
1939 /* rename source back to dest */
1940 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1941 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1944 /* rename temp back to source */
1945 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1946 of_rename(vol, s_of, curdir, temp, sdir, spath);