2 * $Id: file.c,v 1.77 2003-01-24 07:08:42 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) {
1447 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1451 err = AFPERR_ACCESS;
1464 if ( unlink( file ) < 0 ) {
1468 err = AFPERR_ACCESS;
1482 if (adflags & ADFLAGS_HF)
1483 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0, 0);
1484 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
1485 ad_close( &ad, adflags );
1488 LOG(log_info, logtype_afpd, "end deletefile:");
1494 /* ------------------------------------ */
1496 /* return a file id */
1497 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1500 int ibuflen, *rbuflen;
1503 #if AD_VERSION > AD_VERSION1
1512 struct path *s_path;
1515 LOG(log_info, logtype_afpd, "begin afp_createid:");
1521 memcpy(&vid, ibuf, sizeof(vid));
1522 ibuf += sizeof(vid);
1524 if (NULL == ( vol = getvolbyvid( vid )) ) {
1525 return( AFPERR_PARAM);
1528 if (vol->v_flags & AFPVOL_RO)
1529 return AFPERR_VLOCK;
1531 memcpy(&did, ibuf, sizeof( did ));
1532 ibuf += sizeof(did);
1534 if (NULL == ( dir = dirlookup( vol, did )) ) {
1535 return( AFPERR_PARAM );
1538 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1539 return afp_errno; /* was AFPERR_PARAM */
1542 if ( path_isadir(s_path) ) {
1543 return( AFPERR_BADTYPE );
1546 upath = s_path->u_name;
1547 switch (s_path->st_errno) {
1549 break; /* success */
1552 return AFPERR_ACCESS;
1554 return AFPERR_NOOBJ;
1556 return AFPERR_PARAM;
1559 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1560 memcpy(rbuf, &id, sizeof(id));
1561 *rbuflen = sizeof(id);
1562 return AFPERR_EXISTID;
1565 #if AD_VERSION > AD_VERSION1
1566 memset(&ad, 0, sizeof(ad));
1567 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1568 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1569 ad_close(&ad, ADFLAGS_HF);
1571 #endif /* AD_VERSION > AD_VERSION1 */
1573 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1574 memcpy(rbuf, &id, sizeof(id));
1575 *rbuflen = sizeof(id);
1580 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1585 return AFPERR_VLOCK;
1589 return AFPERR_ACCESS;
1592 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1593 return AFPERR_PARAM;
1597 /* ------------------------------
1598 resolve a file id */
1599 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1602 int ibuflen, *rbuflen;
1610 u_int16_t vid, bitmap;
1612 static char buffer[12 + MAXPATHLEN + 1];
1613 int len = 12 + MAXPATHLEN + 1;
1616 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1622 memcpy(&vid, ibuf, sizeof(vid));
1623 ibuf += sizeof(vid);
1625 if (NULL == ( vol = getvolbyvid( vid )) ) {
1626 return( AFPERR_PARAM);
1629 memcpy(&id, ibuf, sizeof( id ));
1632 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1633 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1636 if (( dir = dirlookup( vol, id )) == NULL ) {
1637 return AFPERR_NOID; /* idem AFPERR_PARAM */
1639 path.u_name = upath;
1640 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1644 return AFPERR_ACCESS;
1648 return AFPERR_PARAM;
1651 /* directories are bad */
1652 if (S_ISDIR(path.st.st_mode))
1653 return AFPERR_BADTYPE;
1655 memcpy(&bitmap, ibuf, sizeof(bitmap));
1656 bitmap = ntohs( bitmap );
1657 path.m_name = utompath(vol, upath);
1658 if ((err = getfilparams(vol, bitmap, &path , curdir,
1659 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1662 *rbuflen = buflen + sizeof(bitmap);
1663 memcpy(rbuf, ibuf, sizeof(bitmap));
1666 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1672 /* ------------------------------ */
1673 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1676 int ibuflen, *rbuflen;
1686 static char buffer[12 + MAXPATHLEN + 1];
1687 int len = 12 + MAXPATHLEN + 1;
1690 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1696 memcpy(&vid, ibuf, sizeof(vid));
1697 ibuf += sizeof(vid);
1699 if (NULL == ( vol = getvolbyvid( vid )) ) {
1700 return( AFPERR_PARAM);
1703 if (vol->v_flags & AFPVOL_RO)
1704 return AFPERR_VLOCK;
1706 memcpy(&id, ibuf, sizeof( id ));
1710 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1714 if (( dir = dirlookup( vol, id )) == NULL ) {
1715 return( AFPERR_PARAM );
1719 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1723 return AFPERR_ACCESS;
1725 /* still try to delete the id */
1729 return AFPERR_PARAM;
1733 /* directories are bad */
1734 if (S_ISDIR(st.st_mode))
1735 return AFPERR_BADTYPE;
1737 if (cnid_delete(vol->v_db, fileid)) {
1740 return AFPERR_VLOCK;
1743 return AFPERR_ACCESS;
1745 return AFPERR_PARAM;
1750 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1755 #endif /* CNID_DB */
1757 #define APPLETEMP ".AppleTempXXXXXX"
1759 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1762 int ibuflen, *rbuflen;
1764 struct stat srcst, destst;
1766 struct dir *dir, *sdir;
1767 char *spath, temp[17], *p;
1768 char *supath, *upath;
1773 struct adouble *adsp;
1774 struct adouble *addp;
1780 #endif /* CNID_DB */
1785 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1791 memcpy(&vid, ibuf, sizeof(vid));
1792 ibuf += sizeof(vid);
1794 if (NULL == ( vol = getvolbyvid( vid )) ) {
1795 return( AFPERR_PARAM);
1798 if (vol->v_flags & AFPVOL_RO)
1799 return AFPERR_VLOCK;
1801 /* source and destination dids */
1802 memcpy(&sid, ibuf, sizeof(sid));
1803 ibuf += sizeof(sid);
1804 memcpy(&did, ibuf, sizeof(did));
1805 ibuf += sizeof(did);
1808 if (NULL == (dir = dirlookup( vol, sid )) ) {
1809 return( AFPERR_PARAM );
1812 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1813 return afp_errno; /* was AFPERR_PARAM */
1816 if ( path_isadir(path) ) {
1817 return( AFPERR_BADTYPE ); /* it's a dir */
1820 upath = path->u_name;
1821 switch (path->st_errno) {
1828 return AFPERR_ACCESS;
1830 return AFPERR_PARAM;
1832 memset(&ads, 0, sizeof(ads));
1834 if ((s_of = of_findname(path))) {
1835 /* reuse struct adouble so it won't break locks */
1838 memcpy(&srcst, &path->st, sizeof(struct stat));
1839 /* save some stuff */
1841 spath = obj->oldtmp;
1842 supath = obj->newtmp;
1843 strcpy(spath, path->m_name);
1844 strcpy(supath, upath); /* this is for the cnid changing */
1845 p = absupath( vol, sdir, upath);
1847 /* pathname too long */
1848 return AFPERR_PARAM ;
1851 /* look for the source cnid. if it doesn't exist, don't worry about
1854 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1855 slen = strlen(supath));
1856 #endif /* CNID_DB */
1858 if (NULL == ( dir = dirlookup( vol, did )) ) {
1859 return( AFPERR_PARAM );
1862 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1863 return( AFPERR_PARAM );
1866 if ( path_isadir(path) ) {
1867 return( AFPERR_BADTYPE );
1870 /* FPExchangeFiles is the only call that can return the SameObj
1872 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1873 return AFPERR_SAMEOBJ;
1874 memcpy(&srcst, &path->st, sizeof(struct stat));
1883 return AFPERR_ACCESS;
1885 return AFPERR_PARAM;
1887 memset(&add, 0, sizeof(add));
1889 if ((d_of = of_findname( path))) {
1890 /* reuse struct adouble so it won't break locks */
1893 memcpy(&destst, &path->st, sizeof(struct stat));
1895 /* they are not on the same device and at least one is open
1897 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1900 upath = path->u_name;
1902 /* look for destination id. */
1903 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1904 dlen = strlen(upath));
1905 #endif /* CNID_DB */
1907 /* construct a temp name.
1908 * NOTE: the temp file will be in the dest file's directory. it
1909 * will also be inaccessible from AFP. */
1910 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1914 /* now, quickly rename the file. we error if we can't. */
1915 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1916 goto err_exchangefile;
1917 of_rename(vol, s_of, sdir, spath, curdir, temp);
1919 /* rename destination to source */
1920 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1921 goto err_src_to_tmp;
1922 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1924 /* rename temp to destination */
1925 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1926 goto err_dest_to_src;
1927 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1930 /* id's need switching. src -> dest and dest -> src. */
1931 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1932 upath, dlen) < 0)) {
1936 err = AFPERR_ACCESS;
1941 goto err_temp_to_dest;
1944 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1945 supath, slen) < 0)) {
1949 err = AFPERR_ACCESS;
1956 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1957 goto err_temp_to_dest;
1959 #endif /* CNID_DB */
1962 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1968 /* all this stuff is so that we can unwind a failed operation
1973 /* rename dest to temp */
1974 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1975 of_rename(vol, s_of, curdir, upath, curdir, temp);
1978 /* rename source back to dest */
1979 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1980 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1983 /* rename temp back to source */
1984 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1985 of_rename(vol, s_of, curdir, temp, sdir, spath);