2 * $Id: file.c,v 1.81 2003-01-31 17:38:01 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_get_HF_flags( adp ) & 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:");
1362 /* try to open both at once */
1363 adflags = ADFLAGS_DF|ADFLAGS_HF;
1365 memset(&ad, 0, sizeof(ad));
1366 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1369 if (adflags == ADFLAGS_DF)
1370 return AFPERR_NOOBJ;
1372 /* that failed. now try to open just the data fork */
1373 adflags = ADFLAGS_DF;
1377 /* If can't open read/write then try again read-only. */
1378 if(openmode == O_RDWR) {
1379 openmode = O_RDONLY;
1382 return AFPERR_ACCESS;
1384 return AFPERR_VLOCK;
1386 return( AFPERR_PARAM );
1389 break; /* from the while */
1392 * Does kFPDeleteInhibitBit (bit 8) set?
1394 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1397 ad_getattr(&ad, &bshort);
1398 if ((bshort & htons(ATTRBIT_NODELETE))) {
1399 ad_close( &ad, adflags );
1400 return(AFPERR_OLOCK);
1404 if ((adflags & ADFLAGS_HF) ) {
1405 /* FIXME we have a pb here because we want to know if a file is open
1406 * there's a 'priority inversion' if you can't open the ressource fork RW
1407 * you can delete it if it's open because you can't get a write lock.
1409 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1412 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1414 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1415 ad_close( &ad, adflags );
1416 return( AFPERR_BUSY );
1420 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1423 else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
1424 err = netatalk_unlink( file );
1427 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1430 LOG(log_info, logtype_afpd, "end deletefile:");
1436 /* ------------------------------------ */
1438 /* return a file id */
1439 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1442 int ibuflen, *rbuflen;
1445 #if AD_VERSION > AD_VERSION1
1454 struct path *s_path;
1457 LOG(log_info, logtype_afpd, "begin afp_createid:");
1463 memcpy(&vid, ibuf, sizeof(vid));
1464 ibuf += sizeof(vid);
1466 if (NULL == ( vol = getvolbyvid( vid )) ) {
1467 return( AFPERR_PARAM);
1470 if (vol->v_flags & AFPVOL_RO)
1471 return AFPERR_VLOCK;
1473 memcpy(&did, ibuf, sizeof( did ));
1474 ibuf += sizeof(did);
1476 if (NULL == ( dir = dirlookup( vol, did )) ) {
1477 return( AFPERR_PARAM );
1480 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1481 return afp_errno; /* was AFPERR_PARAM */
1484 if ( path_isadir(s_path) ) {
1485 return( AFPERR_BADTYPE );
1488 upath = s_path->u_name;
1489 switch (s_path->st_errno) {
1491 break; /* success */
1494 return AFPERR_ACCESS;
1496 return AFPERR_NOOBJ;
1498 return AFPERR_PARAM;
1501 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1502 memcpy(rbuf, &id, sizeof(id));
1503 *rbuflen = sizeof(id);
1504 return AFPERR_EXISTID;
1507 #if AD_VERSION > AD_VERSION1
1508 memset(&ad, 0, sizeof(ad));
1509 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1510 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1511 ad_close(&ad, ADFLAGS_HF);
1513 #endif /* AD_VERSION > AD_VERSION1 */
1515 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1516 memcpy(rbuf, &id, sizeof(id));
1517 *rbuflen = sizeof(id);
1522 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1527 return AFPERR_VLOCK;
1531 return AFPERR_ACCESS;
1534 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1535 return AFPERR_PARAM;
1539 /* ------------------------------
1540 resolve a file id */
1541 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1544 int ibuflen, *rbuflen;
1552 u_int16_t vid, bitmap;
1554 static char buffer[12 + MAXPATHLEN + 1];
1555 int len = 12 + MAXPATHLEN + 1;
1558 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1564 memcpy(&vid, ibuf, sizeof(vid));
1565 ibuf += sizeof(vid);
1567 if (NULL == ( vol = getvolbyvid( vid )) ) {
1568 return( AFPERR_PARAM);
1571 memcpy(&id, ibuf, sizeof( id ));
1574 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1575 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1578 if (( dir = dirlookup( vol, id )) == NULL ) {
1579 return AFPERR_NOID; /* idem AFPERR_PARAM */
1581 path.u_name = upath;
1582 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1586 return AFPERR_ACCESS;
1590 return AFPERR_PARAM;
1593 /* directories are bad */
1594 if (S_ISDIR(path.st.st_mode))
1595 return AFPERR_BADTYPE;
1597 memcpy(&bitmap, ibuf, sizeof(bitmap));
1598 bitmap = ntohs( bitmap );
1599 path.m_name = utompath(vol, upath);
1600 if ((err = getfilparams(vol, bitmap, &path , curdir,
1601 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1604 *rbuflen = buflen + sizeof(bitmap);
1605 memcpy(rbuf, ibuf, sizeof(bitmap));
1608 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1614 /* ------------------------------ */
1615 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1618 int ibuflen, *rbuflen;
1628 static char buffer[12 + MAXPATHLEN + 1];
1629 int len = 12 + MAXPATHLEN + 1;
1632 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1638 memcpy(&vid, ibuf, sizeof(vid));
1639 ibuf += sizeof(vid);
1641 if (NULL == ( vol = getvolbyvid( vid )) ) {
1642 return( AFPERR_PARAM);
1645 if (vol->v_flags & AFPVOL_RO)
1646 return AFPERR_VLOCK;
1648 memcpy(&id, ibuf, sizeof( id ));
1652 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1656 if (( dir = dirlookup( vol, id )) == NULL ) {
1657 return( AFPERR_PARAM );
1661 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1665 return AFPERR_ACCESS;
1667 /* still try to delete the id */
1671 return AFPERR_PARAM;
1675 /* directories are bad */
1676 if (S_ISDIR(st.st_mode))
1677 return AFPERR_BADTYPE;
1679 if (cnid_delete(vol->v_db, fileid)) {
1682 return AFPERR_VLOCK;
1685 return AFPERR_ACCESS;
1687 return AFPERR_PARAM;
1692 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1697 #endif /* CNID_DB */
1699 #define APPLETEMP ".AppleTempXXXXXX"
1701 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1704 int ibuflen, *rbuflen;
1706 struct stat srcst, destst;
1708 struct dir *dir, *sdir;
1709 char *spath, temp[17], *p;
1710 char *supath, *upath;
1715 struct adouble *adsp;
1716 struct adouble *addp;
1723 #endif /* CNID_DB */
1728 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1734 memcpy(&vid, ibuf, sizeof(vid));
1735 ibuf += sizeof(vid);
1737 if (NULL == ( vol = getvolbyvid( vid )) ) {
1738 return( AFPERR_PARAM);
1741 if (vol->v_flags & AFPVOL_RO)
1742 return AFPERR_VLOCK;
1744 /* source and destination dids */
1745 memcpy(&sid, ibuf, sizeof(sid));
1746 ibuf += sizeof(sid);
1747 memcpy(&did, ibuf, sizeof(did));
1748 ibuf += sizeof(did);
1751 if (NULL == (dir = dirlookup( vol, sid )) ) {
1752 return( AFPERR_PARAM );
1755 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1756 return afp_errno; /* was AFPERR_PARAM */
1759 if ( path_isadir(path) ) {
1760 return( AFPERR_BADTYPE ); /* it's a dir */
1763 upath = path->u_name;
1764 switch (path->st_errno) {
1771 return AFPERR_ACCESS;
1773 return AFPERR_PARAM;
1775 memset(&ads, 0, sizeof(ads));
1777 if ((s_of = of_findname(path))) {
1778 /* reuse struct adouble so it won't break locks */
1781 memcpy(&srcst, &path->st, sizeof(struct stat));
1782 /* save some stuff */
1784 spath = obj->oldtmp;
1785 supath = obj->newtmp;
1786 strcpy(spath, path->m_name);
1787 strcpy(supath, upath); /* this is for the cnid changing */
1788 p = absupath( vol, sdir, upath);
1790 /* pathname too long */
1791 return AFPERR_PARAM ;
1794 /* look for the source cnid. if it doesn't exist, don't worry about
1797 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1798 slen = strlen(supath));
1799 #endif /* CNID_DB */
1801 if (NULL == ( dir = dirlookup( vol, did )) ) {
1802 return( AFPERR_PARAM );
1805 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1806 return( AFPERR_PARAM );
1809 if ( path_isadir(path) ) {
1810 return( AFPERR_BADTYPE );
1813 /* FPExchangeFiles is the only call that can return the SameObj
1815 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1816 return AFPERR_SAMEOBJ;
1818 switch (path->st_errno) {
1825 return AFPERR_ACCESS;
1827 return AFPERR_PARAM;
1829 memset(&add, 0, sizeof(add));
1831 if ((d_of = of_findname( path))) {
1832 /* reuse struct adouble so it won't break locks */
1835 memcpy(&destst, &path->st, sizeof(struct stat));
1837 /* they are not on the same device and at least one is open
1839 crossdev = (srcst.st_dev != destst.st_dev);
1840 if ((d_of || s_of) && crossdev)
1843 upath = path->u_name;
1845 /* look for destination id. */
1846 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1847 dlen = strlen(upath));
1848 #endif /* CNID_DB */
1850 /* construct a temp name.
1851 * NOTE: the temp file will be in the dest file's directory. it
1852 * will also be inaccessible from AFP. */
1853 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1857 /* now, quickly rename the file. we error if we can't. */
1858 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1859 goto err_exchangefile;
1860 of_rename(vol, s_of, sdir, spath, curdir, temp);
1862 /* rename destination to source */
1863 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1864 goto err_src_to_tmp;
1865 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1867 /* rename temp to destination */
1868 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1869 goto err_dest_to_src;
1870 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1873 /* id's need switching. src -> dest and dest -> src.
1874 * we need to re-stat() if it was a cross device copy.
1877 cnid_delete(vol->v_db, sid);
1880 cnid_delete(vol->v_db, did);
1882 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1883 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1885 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1886 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1891 err = AFPERR_ACCESS;
1896 goto err_temp_to_dest;
1898 #endif /* CNID_DB */
1901 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1907 /* all this stuff is so that we can unwind a failed operation
1912 /* rename dest to temp */
1913 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1914 of_rename(vol, s_of, curdir, upath, curdir, temp);
1917 /* rename source back to dest */
1918 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1919 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1922 /* rename temp back to source */
1923 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1924 of_rename(vol, s_of, curdir, temp, sdir, spath);