2 * $Id: file.c,v 1.79 2003-01-26 10:42:40 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 locktype = ADLOCK_WR;
1357 int openmode = O_RDWR;
1360 LOG(log_info, logtype_afpd, "begin deletefile:");
1365 * If can't open read/write then try again read-only. If it's open
1366 * read-only, we must do a read lock instead of a write lock.
1368 /* try to open both at once */
1369 adflags = ADFLAGS_DF|ADFLAGS_HF;
1370 memset(&ad, 0, sizeof(ad));
1371 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1374 adflags = ADFLAGS_DF;
1375 /* that failed. now try to open just the data fork */
1376 memset(&ad, 0, sizeof(ad));
1377 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1380 return AFPERR_NOOBJ;
1382 if(openmode == O_RDWR) {
1383 openmode = O_RDONLY;
1384 locktype = ADLOCK_RD;
1387 return AFPERR_ACCESS;
1390 return AFPERR_VLOCK;
1392 return AFPERR_PARAM;
1398 if(openmode == O_RDWR) {
1399 openmode = O_RDONLY;
1400 locktype = ADLOCK_RD;
1403 return AFPERR_ACCESS;
1406 return AFPERR_VLOCK;
1408 return( AFPERR_PARAM );
1411 break; /* from the while */
1414 * Does kFPDeleteInhibitBit (bit 8) set?
1416 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1419 ad_getattr(&ad, &bshort);
1420 if ((bshort & htons(ATTRBIT_NODELETE))) {
1421 ad_close( &ad, adflags );
1422 return(AFPERR_OLOCK);
1426 if ((adflags & ADFLAGS_HF) ) {
1427 /* FIXME we have a pb here because we want to know if a file is open
1428 * there's a 'priority inversion' if you can't open the ressource fork RW
1429 * you can delete it if it's open because you can't get a write lock.
1431 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1434 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1436 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1437 ad_close( &ad, adflags );
1438 return( AFPERR_BUSY );
1442 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0, 0 ) < 0) {
1445 else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
1446 err = netatalk_unlink( file );
1449 if (adflags & ADFLAGS_HF)
1450 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0, 0);
1451 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
1452 ad_close( &ad, adflags );
1455 LOG(log_info, logtype_afpd, "end deletefile:");
1461 /* ------------------------------------ */
1463 /* return a file id */
1464 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1467 int ibuflen, *rbuflen;
1470 #if AD_VERSION > AD_VERSION1
1479 struct path *s_path;
1482 LOG(log_info, logtype_afpd, "begin afp_createid:");
1488 memcpy(&vid, ibuf, sizeof(vid));
1489 ibuf += sizeof(vid);
1491 if (NULL == ( vol = getvolbyvid( vid )) ) {
1492 return( AFPERR_PARAM);
1495 if (vol->v_flags & AFPVOL_RO)
1496 return AFPERR_VLOCK;
1498 memcpy(&did, ibuf, sizeof( did ));
1499 ibuf += sizeof(did);
1501 if (NULL == ( dir = dirlookup( vol, did )) ) {
1502 return( AFPERR_PARAM );
1505 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1506 return afp_errno; /* was AFPERR_PARAM */
1509 if ( path_isadir(s_path) ) {
1510 return( AFPERR_BADTYPE );
1513 upath = s_path->u_name;
1514 switch (s_path->st_errno) {
1516 break; /* success */
1519 return AFPERR_ACCESS;
1521 return AFPERR_NOOBJ;
1523 return AFPERR_PARAM;
1526 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1527 memcpy(rbuf, &id, sizeof(id));
1528 *rbuflen = sizeof(id);
1529 return AFPERR_EXISTID;
1532 #if AD_VERSION > AD_VERSION1
1533 memset(&ad, 0, sizeof(ad));
1534 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1535 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1536 ad_close(&ad, ADFLAGS_HF);
1538 #endif /* AD_VERSION > AD_VERSION1 */
1540 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1541 memcpy(rbuf, &id, sizeof(id));
1542 *rbuflen = sizeof(id);
1547 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1552 return AFPERR_VLOCK;
1556 return AFPERR_ACCESS;
1559 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1560 return AFPERR_PARAM;
1564 /* ------------------------------
1565 resolve a file id */
1566 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1569 int ibuflen, *rbuflen;
1577 u_int16_t vid, bitmap;
1579 static char buffer[12 + MAXPATHLEN + 1];
1580 int len = 12 + MAXPATHLEN + 1;
1583 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1589 memcpy(&vid, ibuf, sizeof(vid));
1590 ibuf += sizeof(vid);
1592 if (NULL == ( vol = getvolbyvid( vid )) ) {
1593 return( AFPERR_PARAM);
1596 memcpy(&id, ibuf, sizeof( id ));
1599 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1600 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1603 if (( dir = dirlookup( vol, id )) == NULL ) {
1604 return AFPERR_NOID; /* idem AFPERR_PARAM */
1606 path.u_name = upath;
1607 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1611 return AFPERR_ACCESS;
1615 return AFPERR_PARAM;
1618 /* directories are bad */
1619 if (S_ISDIR(path.st.st_mode))
1620 return AFPERR_BADTYPE;
1622 memcpy(&bitmap, ibuf, sizeof(bitmap));
1623 bitmap = ntohs( bitmap );
1624 path.m_name = utompath(vol, upath);
1625 if ((err = getfilparams(vol, bitmap, &path , curdir,
1626 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1629 *rbuflen = buflen + sizeof(bitmap);
1630 memcpy(rbuf, ibuf, sizeof(bitmap));
1633 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1639 /* ------------------------------ */
1640 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1643 int ibuflen, *rbuflen;
1653 static char buffer[12 + MAXPATHLEN + 1];
1654 int len = 12 + MAXPATHLEN + 1;
1657 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1663 memcpy(&vid, ibuf, sizeof(vid));
1664 ibuf += sizeof(vid);
1666 if (NULL == ( vol = getvolbyvid( vid )) ) {
1667 return( AFPERR_PARAM);
1670 if (vol->v_flags & AFPVOL_RO)
1671 return AFPERR_VLOCK;
1673 memcpy(&id, ibuf, sizeof( id ));
1677 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1681 if (( dir = dirlookup( vol, id )) == NULL ) {
1682 return( AFPERR_PARAM );
1686 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1690 return AFPERR_ACCESS;
1692 /* still try to delete the id */
1696 return AFPERR_PARAM;
1700 /* directories are bad */
1701 if (S_ISDIR(st.st_mode))
1702 return AFPERR_BADTYPE;
1704 if (cnid_delete(vol->v_db, fileid)) {
1707 return AFPERR_VLOCK;
1710 return AFPERR_ACCESS;
1712 return AFPERR_PARAM;
1717 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1722 #endif /* CNID_DB */
1724 #define APPLETEMP ".AppleTempXXXXXX"
1726 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1729 int ibuflen, *rbuflen;
1731 struct stat srcst, destst;
1733 struct dir *dir, *sdir;
1734 char *spath, temp[17], *p;
1735 char *supath, *upath;
1740 struct adouble *adsp;
1741 struct adouble *addp;
1748 #endif /* CNID_DB */
1753 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1759 memcpy(&vid, ibuf, sizeof(vid));
1760 ibuf += sizeof(vid);
1762 if (NULL == ( vol = getvolbyvid( vid )) ) {
1763 return( AFPERR_PARAM);
1766 if (vol->v_flags & AFPVOL_RO)
1767 return AFPERR_VLOCK;
1769 /* source and destination dids */
1770 memcpy(&sid, ibuf, sizeof(sid));
1771 ibuf += sizeof(sid);
1772 memcpy(&did, ibuf, sizeof(did));
1773 ibuf += sizeof(did);
1776 if (NULL == (dir = dirlookup( vol, sid )) ) {
1777 return( AFPERR_PARAM );
1780 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1781 return afp_errno; /* was AFPERR_PARAM */
1784 if ( path_isadir(path) ) {
1785 return( AFPERR_BADTYPE ); /* it's a dir */
1788 upath = path->u_name;
1789 switch (path->st_errno) {
1796 return AFPERR_ACCESS;
1798 return AFPERR_PARAM;
1800 memset(&ads, 0, sizeof(ads));
1802 if ((s_of = of_findname(path))) {
1803 /* reuse struct adouble so it won't break locks */
1806 memcpy(&srcst, &path->st, sizeof(struct stat));
1807 /* save some stuff */
1809 spath = obj->oldtmp;
1810 supath = obj->newtmp;
1811 strcpy(spath, path->m_name);
1812 strcpy(supath, upath); /* this is for the cnid changing */
1813 p = absupath( vol, sdir, upath);
1815 /* pathname too long */
1816 return AFPERR_PARAM ;
1819 /* look for the source cnid. if it doesn't exist, don't worry about
1822 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1823 slen = strlen(supath));
1824 #endif /* CNID_DB */
1826 if (NULL == ( dir = dirlookup( vol, did )) ) {
1827 return( AFPERR_PARAM );
1830 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1831 return( AFPERR_PARAM );
1834 if ( path_isadir(path) ) {
1835 return( AFPERR_BADTYPE );
1838 /* FPExchangeFiles is the only call that can return the SameObj
1840 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1841 return AFPERR_SAMEOBJ;
1843 switch (path->st_errno) {
1850 return AFPERR_ACCESS;
1852 return AFPERR_PARAM;
1854 memset(&add, 0, sizeof(add));
1856 if ((d_of = of_findname( path))) {
1857 /* reuse struct adouble so it won't break locks */
1860 memcpy(&destst, &path->st, sizeof(struct stat));
1862 /* they are not on the same device and at least one is open
1864 crossdev = (srcst.st_dev != destst.st_dev);
1865 if ((d_of || s_of) && crossdev)
1868 upath = path->u_name;
1870 /* look for destination id. */
1871 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1872 dlen = strlen(upath));
1873 #endif /* CNID_DB */
1875 /* construct a temp name.
1876 * NOTE: the temp file will be in the dest file's directory. it
1877 * will also be inaccessible from AFP. */
1878 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1882 /* now, quickly rename the file. we error if we can't. */
1883 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1884 goto err_exchangefile;
1885 of_rename(vol, s_of, sdir, spath, curdir, temp);
1887 /* rename destination to source */
1888 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1889 goto err_src_to_tmp;
1890 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1892 /* rename temp to destination */
1893 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1894 goto err_dest_to_src;
1895 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1898 /* id's need switching. src -> dest and dest -> src.
1899 * we need to re-stat() if it was a cross device copy.
1902 cnid_delete(vol->v_db, sid);
1905 cnid_delete(vol->v_db, did);
1907 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1908 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1910 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1911 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1916 err = AFPERR_ACCESS;
1921 goto err_temp_to_dest;
1923 #endif /* CNID_DB */
1926 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1932 /* all this stuff is so that we can unwind a failed operation
1937 /* rename dest to temp */
1938 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1939 of_rename(vol, s_of, curdir, upath, curdir, temp);
1942 /* rename source back to dest */
1943 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1944 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1947 /* rename temp back to source */
1948 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1949 of_rename(vol, s_of, curdir, temp, sdir, spath);