2 * $Id: file.c,v 1.64 2002-10-12 04:02:46 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63 * field bytes subfield bytes
66 * ioFlFndrInfo 16 -> type 4 type field
67 * creator 4 creator field
68 * flags 2 finder flags:
70 * location 4 location in window
71 * folder 2 window that contains file
73 * ioFlXFndrInfo 16 -> iconID 2 icon id
75 * script 1 script system
77 * commentID 2 comment id
78 * putawayID 4 home directory id
81 const u_char ufinderi[] = {
82 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
94 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
110 * FIXME: PDINFO is UTF8 and doesn't need adp
112 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
113 (1 << FILPBIT_CDATE) |\
114 (1 << FILPBIT_MDATE) |\
115 (1 << FILPBIT_BDATE) |\
116 (1 << FILPBIT_FINFO) |\
117 (1 << FILPBIT_RFLEN) |\
118 (1 << FILPBIT_EXTRFLEN) |\
119 (1 << FILPBIT_PDINFO)))
122 char *set_name(char *data, const char *name, u_int32_t utf8)
126 aint = strlen( name );
129 if (aint > MACFILELEN)
136 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
140 memcpy(data, &utf8, sizeof(utf8));
141 data += sizeof(utf8);
144 memcpy(data, &temp, sizeof(temp));
145 data += sizeof(temp);
148 memcpy( data, name, aint );
154 /* -------------------------- */
155 int getmetadata(struct vol *vol,
157 char *path, struct dir *dir, struct stat *st,
158 char *buf, int *buflen, struct adouble *adp, int attrbits )
161 struct stat lst, *lstp;
162 #endif /* USE_LASTDID */
163 char *data, *nameoff = NULL, *upath;
167 u_char achar, fdType[4];
171 LOG(log_info, logtype_afpd, "begin getmetadata:");
174 upath = mtoupath(vol, path);
177 while ( bitmap != 0 ) {
178 while (( bitmap & 1 ) == 0 ) {
186 ad_getattr(adp, &ashort);
187 } else if (*upath == '.') {
188 ashort = htons(ATTRBIT_INVISIBLE);
192 /* FIXME do we want a visual clue if the file is read only
195 accessmode( ".", &ma, dir , NULL);
196 if ((ma.ma_user & AR_UWRITE)) {
197 accessmode( upath, &ma, dir , st);
198 if (!(ma.ma_user & AR_UWRITE)) {
199 attrbits |= ATTRBIT_NOWRITE;
204 ashort = htons(ntohs(ashort) | attrbits);
205 memcpy(data, &ashort, sizeof( ashort ));
206 data += sizeof( ashort );
210 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
211 data += sizeof( u_int32_t );
215 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
216 aint = AD_DATE_FROM_UNIX(st->st_mtime);
217 memcpy(data, &aint, sizeof( aint ));
218 data += sizeof( aint );
222 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
223 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
224 aint = AD_DATE_FROM_UNIX(st->st_mtime);
227 aint = AD_DATE_FROM_UNIX(st->st_mtime);
229 memcpy(data, &aint, sizeof( int ));
230 data += sizeof( int );
234 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
235 aint = AD_DATE_START;
236 memcpy(data, &aint, sizeof( int ));
237 data += sizeof( int );
241 get_finderinfo(path, adp, (char *)data);
243 if (*upath == '.') { /* make it invisible */
244 ashort = htons(FINDERINFO_INVISIBLE);
245 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
254 data += sizeof( u_int16_t );
258 memset(data, 0, sizeof(u_int16_t));
259 data += sizeof( u_int16_t );
264 #if AD_VERSION > AD_VERSION1
265 /* look in AD v2 header */
267 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
268 #endif /* AD_VERSION > AD_VERSION1 */
271 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
272 strlen(upath), aint);
273 /* Throw errors if cnid_add fails. */
274 if (aint == CNID_INVALID) {
277 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
278 return(AFPERR_PARAM);
280 return(AFPERR_PARAM);
290 * What a fucking mess. First thing: DID and FNUMs are
291 * in the same space for purposes of enumerate (and several
292 * other wierd places). While we consider this Apple's bug,
293 * this is the work-around: In order to maintain constant and
294 * unique DIDs and FNUMs, we monotonically generate the DIDs
295 * during the session, and derive the FNUMs from the filesystem.
296 * Since the DIDs are small, we insure that the FNUMs are fairly
297 * large by setting thier high bits to the device number.
299 * AFS already does something very similar to this for the
300 * inode number, so we don't repeat the procedure.
303 * due to complaints over did's being non-persistent,
304 * here's the current hack to provide semi-persistent
306 * 1) we reserve the first bit for file ids.
307 * 2) the next 7 bits are for the device.
308 * 3) the remaining 24 bits are for the inode.
310 * both the inode and device information are actually hashes
311 * that are then truncated to the requisite bit length.
313 * it should be okay to use lstat to deal with symlinks.
316 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
317 #else /* USE_LASTDID */
318 lstp = lstat(upath, &lst) < 0 ? st : &lst;
319 aint = htonl(CNID(lstp, 1));
320 #endif /* USE_LASTDID */
323 memcpy(data, &aint, sizeof( aint ));
324 data += sizeof( aint );
328 if (st->st_size > 0xffffffff)
331 aint = htonl( st->st_size );
332 memcpy(data, &aint, sizeof( aint ));
333 data += sizeof( aint );
338 if (adp->ad_rlen > 0xffffffff)
341 aint = htonl( adp->ad_rlen);
345 memcpy(data, &aint, sizeof( aint ));
346 data += sizeof( aint );
349 /* Current client needs ProDOS info block for this file.
350 Use simple heuristic and let the Mac "type" string tell
351 us what the PD file code should be. Everything gets a
352 subtype of 0x0000 unless the original value was hashed
353 to "pXYZ" when we created it. See IA, Ver 2.
355 case FILPBIT_PDINFO :
356 if (afp_version >= 30) { /* UTF8 name */
357 utf8 = kTextEncodingUTF8;
358 data += sizeof( u_int16_t );
362 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
364 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
368 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
372 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
376 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
380 else if ( fdType[0] == 'p' ) {
382 ashort = (fdType[2] * 256) + fdType[3];
396 memcpy(data, &ashort, sizeof( ashort ));
397 data += sizeof( ashort );
398 memset(data, 0, sizeof( ashort ));
399 data += sizeof( ashort );
402 case FILPBIT_EXTDFLEN:
403 aint = htonl(st->st_size >> 32);
404 memcpy(data, &aint, sizeof( aint ));
405 data += sizeof( aint );
406 aint = htonl(st->st_size);
407 memcpy(data, &aint, sizeof( aint ));
408 data += sizeof( aint );
410 case FILPBIT_EXTRFLEN:
413 aint = htonl(adp->ad_rlen >> 32);
414 memcpy(data, &aint, sizeof( aint ));
415 data += sizeof( aint );
417 aint = htonl(adp->ad_rlen);
418 memcpy(data, &aint, sizeof( aint ));
419 data += sizeof( aint );
422 return( AFPERR_BITMAP );
428 ashort = htons( data - buf );
429 memcpy(nameoff, &ashort, sizeof( ashort ));
430 data = set_name(data, path, utf8);
432 *buflen = data - buf;
436 /* ----------------------- */
437 int getfilparams(struct vol *vol,
439 struct path *path, struct dir *dir,
440 char *buf, int *buflen )
442 struct adouble ad, *adp;
445 u_int16_t attrbits = 0;
450 LOG(log_info, logtype_default, "begin getfilparams:");
453 opened = PARAM_NEED_ADP(bitmap);
456 upath = path->u_name;
457 if ((of = of_findname(path))) {
459 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
460 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
462 memset(&ad, 0, sizeof(ad));
466 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
471 we need to check if the file is open by another process.
472 it's slow so we only do it if we have to:
473 - bitmap is requested.
474 - we don't already have the answer!
476 if ((bitmap & (1 << FILPBIT_ATTR))) {
477 if (!(attrbits & ATTRBIT_ROPEN)) {
479 if (!(attrbits & ATTRBIT_DOPEN)) {
484 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
486 ad_close( adp, ADFLAGS_HF );
489 LOG(log_info, logtype_afpd, "end getfilparams:");
495 /* ----------------------------- */
496 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
499 int ibuflen, *rbuflen;
502 struct adouble ad, *adp;
505 struct ofork *of = NULL;
507 int creatf, did, openf, retvalue = AFP_OK;
513 LOG(log_info, logtype_afpd, "begin afp_createfile:");
518 creatf = (unsigned char) *ibuf++;
520 memcpy(&vid, ibuf, sizeof( vid ));
521 ibuf += sizeof( vid );
523 if (( vol = getvolbyvid( vid )) == NULL ) {
524 return( AFPERR_PARAM );
527 if (vol->v_flags & AFPVOL_RO)
530 memcpy(&did, ibuf, sizeof( did));
531 ibuf += sizeof( did );
533 if (( dir = dirlookup( vol, did )) == NULL ) {
534 return( AFPERR_NOOBJ );
537 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
538 return( AFPERR_NOOBJ );
541 if ( *s_path->m_name == '\0' ) {
542 return( AFPERR_BADTYPE );
545 upath = s_path->u_name;
546 if (0 != (ret = check_name(vol, upath)))
549 /* if upath is deleted we already in trouble anyway */
550 if ((of = of_findname(s_path))) {
553 memset(&ad, 0, sizeof(ad));
557 /* on a hard create, fail if file exists and is open */
560 openf = O_RDWR|O_CREAT|O_TRUNC;
562 /* on a soft create, if the file is open then ad_open won't fail
563 because open syscall is not called
568 openf = O_RDWR|O_CREAT|O_EXCL;
571 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
572 openf, 0666, adp) < 0 ) {
575 return( AFPERR_EXIST );
577 return( AFPERR_ACCESS );
579 /* on noadouble volumes, just creating the data fork is ok */
581 if (vol_noadouble(vol) && (stat(upath, st) == 0))
582 goto createfile_done;
585 return( AFPERR_PARAM );
588 path = s_path->m_name;
589 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
590 memcpy(ad_entry( adp, ADEID_NAME ), path,
591 ad_getentrylen( adp, ADEID_NAME ));
592 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
593 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
598 if (vol->v_flags & AFPVOL_DROPBOX) {
599 retvalue = matchfile2dirperms(upath, vol, did);
601 #endif /* DROPKLUDGE */
603 setvoltime(obj, vol );
606 LOG(log_info, logtype_afpd, "end afp_createfile");
612 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
615 int ibuflen, *rbuflen;
621 u_int16_t vid, bitmap;
624 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
630 memcpy(&vid, ibuf, sizeof( vid ));
631 ibuf += sizeof( vid );
632 if (( vol = getvolbyvid( vid )) == NULL ) {
633 return( AFPERR_PARAM );
636 if (vol->v_flags & AFPVOL_RO)
639 memcpy(&did, ibuf, sizeof( did ));
640 ibuf += sizeof( did );
641 if (( dir = dirlookup( vol, did )) == NULL ) {
642 return( AFPERR_NOOBJ );
645 memcpy(&bitmap, ibuf, sizeof( bitmap ));
646 bitmap = ntohs( bitmap );
647 ibuf += sizeof( bitmap );
649 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
650 return( AFPERR_NOOBJ );
653 if ( *s_path->m_name == '\0' ) {
654 return( AFPERR_BADTYPE ); /* it's a directory */
657 if ((u_long)ibuf & 1 ) {
661 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
662 setvoltime(obj, vol );
666 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
673 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
676 extern struct path Cur_Path;
678 int setfilparams(struct vol *vol,
679 struct path *path, u_int16_t bitmap, char *buf )
681 struct adouble ad, *adp;
684 int bit = 0, isad = 1, err = AFP_OK;
686 u_char achar, *fdType, xyy[4];
687 u_int16_t ashort, bshort;
691 int change_mdate = 0;
692 int change_parent_mdate = 0;
698 LOG(log_info, logtype_afpd, "begin setfilparams:");
701 upath = path->u_name;
702 if ((of = of_findname(path))) {
705 memset(&ad, 0, sizeof(ad));
709 if (check_access(upath, OPENACC_WR ) < 0) {
710 return AFPERR_ACCESS;
713 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
714 O_RDWR|O_CREAT, 0666, adp) < 0) {
715 /* for some things, we don't need an adouble header */
716 if (bitmap & ~(1<<FILPBIT_MDATE)) {
717 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
720 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
721 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
722 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
723 ad_getentrylen( adp, ADEID_NAME ));
726 while ( bitmap != 0 ) {
727 while (( bitmap & 1 ) == 0 ) {
735 memcpy(&ashort, buf, sizeof( ashort ));
736 ad_getattr(adp, &bshort);
737 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
738 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
742 if ((ashort & htons(ATTRBIT_INVISIBLE)))
743 change_parent_mdate = 1;
744 ad_setattr(adp, bshort);
745 buf += sizeof( ashort );
750 memcpy(&aint, buf, sizeof(aint));
751 ad_setdate(adp, AD_DATE_CREATE, aint);
752 buf += sizeof( aint );
756 memcpy(&newdate, buf, sizeof( newdate ));
757 buf += sizeof( newdate );
762 memcpy(&aint, buf, sizeof(aint));
763 ad_setdate(adp, AD_DATE_BACKUP, aint);
764 buf += sizeof( aint );
770 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
772 ((em = getextmap( path->m_name )) &&
773 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
774 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
775 || ((em = getdefextmap()) &&
776 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
777 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
779 memcpy(buf, ufinderi, 8 );
782 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
786 /* Client needs to set the ProDOS file info for this file.
787 Use defined strings for the simple cases, and convert
788 all else into pXYY per Inside Appletalk. Always set
789 the creator as "pdos". <shirsch@ibm.net> */
790 case FILPBIT_PDINFO :
793 memcpy(&ashort, buf, sizeof( ashort ));
794 ashort = ntohs( ashort );
797 switch ( (unsigned int) achar )
800 fdType = ( u_char *) "TEXT";
804 fdType = ( u_char *) "PSYS";
808 fdType = ( u_char *) "PS16";
812 fdType = ( u_char *) "BINA";
816 xyy[0] = ( u_char ) 'p';
818 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
819 xyy[3] = ( u_char ) ashort & 0xff;
824 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
825 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
831 goto setfilparam_done;
839 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
840 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
844 ad_setdate(adp, AD_DATE_MODIFY, newdate);
845 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
850 ad_flush( adp, ADFLAGS_HF );
851 ad_close( adp, ADFLAGS_HF );
855 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
856 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
857 bitmap = 1<<FILPBIT_MDATE;
858 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
862 LOG(log_info, logtype_afpd, "end setfilparams:");
868 * renamefile and copyfile take the old and new unix pathnames
869 * and the new mac name.
870 * NOTE: if we have to copy a file instead of renaming it, locks
871 * will break. Anyway it's an error because then we have 2 files.
873 * src the source path
874 * dst the dest filename in current dir
875 * newname the dest mac name
876 * adp adouble struct of src file, if open, or & zeroed one
879 int renamefile(src, dst, newname, noadouble, adp )
880 char *src, *dst, *newname;
884 char adsrc[ MAXPATHLEN + 1];
888 * Note that this is only checking the existance of the data file,
889 * not the header file. The thinking is that if the data file doesn't
890 * exist, but the header file does, the right thing to do is remove
891 * the data file silently.
894 /* existence check moved to afp_moveandrename */
897 LOG(log_info, logtype_afpd, "begin renamefile:");
900 if ( rename( src, dst ) < 0 ) {
903 return( AFPERR_NOOBJ );
906 return( AFPERR_ACCESS );
909 case EXDEV : /* Cross device move -- try copy */
910 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
911 deletefile( dst, 0 );
914 return deletefile( src, 0);
916 return( AFPERR_PARAM );
920 strcpy( adsrc, ad_path( src, 0 ));
923 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
928 /* check for a source appledouble header. if it exists, make
929 * a dest appledouble directory and do the rename again. */
930 if (rc || stat(adsrc, &st) ||
931 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
934 ad_close(adp, ADFLAGS_HF);
938 return( AFPERR_ACCESS );
942 return( AFPERR_PARAM );
946 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
949 return( AFPERR_NOOBJ );
951 return( AFPERR_ACCESS );
955 return( AFPERR_PARAM );
959 len = strlen( newname );
960 ad_setentrylen( adp, ADEID_NAME, len );
961 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
962 ad_flush( adp, ADFLAGS_HF );
963 ad_close( adp, ADFLAGS_HF );
966 LOG(log_info, logtype_afpd, "end renamefile:");
972 /* -----------------------------------
974 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
977 int ibuflen, *rbuflen;
981 char *newname, *p, *upath;
983 u_int32_t sdid, ddid;
985 int err, retvalue = AFP_OK;
986 u_int16_t svid, dvid;
989 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
995 memcpy(&svid, ibuf, sizeof( svid ));
996 ibuf += sizeof( svid );
997 if (( vol = getvolbyvid( svid )) == NULL ) {
998 return( AFPERR_PARAM );
1001 memcpy(&sdid, ibuf, sizeof( sdid ));
1002 ibuf += sizeof( sdid );
1003 if (( dir = dirlookup( vol, sdid )) == NULL ) {
1004 return( AFPERR_PARAM );
1007 memcpy(&dvid, ibuf, sizeof( dvid ));
1008 ibuf += sizeof( dvid );
1009 memcpy(&ddid, ibuf, sizeof( ddid ));
1010 ibuf += sizeof( ddid );
1012 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1013 return( AFPERR_NOOBJ );
1015 if ( *s_path->m_name == '\0' ) {
1016 return( AFPERR_BADTYPE );
1019 /* don't allow copies when the file is open.
1020 * XXX: the spec only calls for read/deny write access.
1021 * however, copyfile doesn't have any of that info,
1022 * and locks need to stay coherent. as a result,
1023 * we just balk if the file is opened already. */
1025 newname = obj->newtmp;
1026 strcpy( newname, s_path->m_name );
1028 if (of_findname(s_path))
1029 return AFPERR_DENYCONF;
1031 p = ctoupath( vol, curdir, newname );
1033 /* FIXME svid != dvid && dvid's user can't read svid */
1035 if (( vol = getvolbyvid( dvid )) == NULL ) {
1036 return( AFPERR_PARAM );
1039 if (vol->v_flags & AFPVOL_RO)
1040 return AFPERR_VLOCK;
1042 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1043 return( AFPERR_PARAM );
1046 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1047 return( AFPERR_NOOBJ );
1049 if ( *s_path->m_name != '\0' ) {
1050 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1053 /* one of the handful of places that knows about the path type */
1054 if ( *ibuf++ != 2 ) {
1055 return( AFPERR_PARAM );
1057 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1058 strncpy( newname, ibuf, plen );
1059 newname[ plen ] = '\0';
1060 if (strlen(newname) != plen) {
1061 /* there's \0 in newname, e.g. it's a pathname not
1064 return( AFPERR_PARAM );
1067 upath = mtoupath(vol, newname);
1068 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1073 if (vol->v_flags & AFPVOL_DROPBOX) {
1074 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1076 #endif /* DROPKLUDGE */
1078 setvoltime(obj, vol );
1081 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1088 static __inline__ int copy_all(const int dfd, const void *buf,
1094 LOG(log_info, logtype_afpd, "begin copy_all:");
1097 while (buflen > 0) {
1098 if ((cc = write(dfd, buf, buflen)) < 0) {
1105 return AFPERR_DFULL;
1107 return AFPERR_VLOCK;
1109 return AFPERR_PARAM;
1116 LOG(log_info, logtype_afpd, "end copy_all:");
1122 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1123 * pass in vol and path */
1124 int copyfile(src, dst, newname, noadouble )
1125 char *src, *dst, *newname;
1126 const int noadouble;
1129 #ifdef SENDFILE_FLAVOR_LINUX
1133 int sfd, dfd, len, err = AFP_OK;
1135 char dpath[ MAXPATHLEN + 1];
1138 LOG(log_info, logtype_afpd, "begin copyfile:");
1141 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1142 admode = ad_mode( dst, 0666 );
1144 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1147 break; /* just copy the data fork */
1149 return( AFPERR_ACCESS );
1151 return( AFPERR_PARAM );
1154 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1158 return( AFPERR_NOOBJ );
1160 return( AFPERR_ACCESS );
1162 return AFPERR_VLOCK;
1164 return( AFPERR_PARAM );
1169 #ifdef SENDFILE_FLAVOR_LINUX
1170 if (fstat(sfd, &st) == 0) {
1171 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1185 goto copyheader_done;
1187 #endif /* SENDFILE_FLAVOR_LINUX */
1189 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1196 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1210 /* data fork copying */
1211 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1214 return( AFPERR_NOOBJ );
1216 return( AFPERR_ACCESS );
1218 return( AFPERR_PARAM );
1222 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1226 return( AFPERR_NOOBJ );
1228 return( AFPERR_ACCESS );
1230 return AFPERR_VLOCK;
1232 return( AFPERR_PARAM );
1236 #ifdef SENDFILE_FLAVOR_LINUX
1237 if (fstat(sfd, &st) == 0) {
1238 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1251 #endif /* SENDFILE_FLAVOR_LINUX */
1254 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1262 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1277 memset(&ad, 0, sizeof(ad));
1278 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1282 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1284 return( AFPERR_ACCESS );
1286 return AFPERR_VLOCK;
1288 return( AFPERR_PARAM );
1292 len = strlen( newname );
1293 ad_setentrylen( &ad, ADEID_NAME, len );
1294 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1295 ad_flush( &ad, ADFLAGS_HF );
1296 ad_close( &ad, ADFLAGS_HF );
1300 LOG(log_info, logtype_afpd, "end copyfile:");
1307 /* -----------------------------------
1308 checkAttrib: 1 check kFPDeleteInhibitBit
1309 ie deletfile called by afp_delete
1311 when deletefile is called we don't have lock on it, file is closed (for us)
1312 untrue if called by renamefile
1314 int deletefile( file, checkAttrib )
1319 int adflags, err = AFP_OK;
1320 int locktype = ADLOCK_WR;
1321 int openmode = O_RDWR;
1324 LOG(log_info, logtype_afpd, "begin deletefile:");
1329 * If can't open read/write then try again read-only. If it's open
1330 * read-only, we must do a read lock instead of a write lock.
1332 /* try to open both at once */
1333 adflags = ADFLAGS_DF|ADFLAGS_HF;
1334 memset(&ad, 0, sizeof(ad));
1335 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1338 adflags = ADFLAGS_DF;
1339 /* that failed. now try to open just the data fork */
1340 memset(&ad, 0, sizeof(ad));
1341 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1344 return AFPERR_NOOBJ;
1346 if(openmode == O_RDWR) {
1347 openmode = O_RDONLY;
1348 locktype = ADLOCK_RD;
1351 return AFPERR_ACCESS;
1354 return AFPERR_VLOCK;
1356 return AFPERR_PARAM;
1362 if(openmode == O_RDWR) {
1363 openmode = O_RDONLY;
1364 locktype = ADLOCK_RD;
1367 return AFPERR_ACCESS;
1370 return AFPERR_VLOCK;
1372 return( AFPERR_PARAM );
1375 break; /* from the while */
1378 * Does kFPDeleteInhibitBit (bit 8) set?
1380 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1383 ad_getattr(&ad, &bshort);
1384 if ((bshort & htons(ATTRBIT_NODELETE))) {
1385 ad_close( &ad, adflags );
1386 return(AFPERR_OLOCK);
1390 if ((adflags & ADFLAGS_HF) ) {
1391 /* FIXME we have a pb here because we want to know if a file is open
1392 * there's a 'priority inversion' if you can't open the ressource fork RW
1393 * you can delete it if it's open because you can't get a write lock.
1395 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1398 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1400 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1401 ad_close( &ad, adflags );
1402 return( AFPERR_BUSY );
1406 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1411 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1415 err = AFPERR_ACCESS;
1428 if ( unlink( file ) < 0 ) {
1432 err = AFPERR_ACCESS;
1446 if (adflags & ADFLAGS_HF)
1447 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1448 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1449 ad_close( &ad, adflags );
1452 LOG(log_info, logtype_afpd, "end deletefile:");
1458 /* ------------------------------------ */
1460 /* return a file id */
1461 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1464 int ibuflen, *rbuflen;
1467 #if AD_VERSION > AD_VERSION1
1476 struct path *s_path;
1479 LOG(log_info, logtype_afpd, "begin afp_createid:");
1485 memcpy(&vid, ibuf, sizeof(vid));
1486 ibuf += sizeof(vid);
1488 if (( vol = getvolbyvid( vid )) == NULL ) {
1489 return( AFPERR_PARAM);
1492 if (vol->v_flags & AFPVOL_RO)
1493 return AFPERR_VLOCK;
1495 memcpy(&did, ibuf, sizeof( did ));
1496 ibuf += sizeof(did);
1498 if (( dir = dirlookup( vol, did )) == NULL ) {
1499 return( AFPERR_PARAM );
1502 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1503 return( AFPERR_PARAM );
1506 if ( *s_path->m_name == '\0' ) {
1507 return( AFPERR_BADTYPE );
1510 upath = s_path->u_name;
1511 switch (s_path->st_errno) {
1513 break; /* success */
1516 return AFPERR_ACCESS;
1518 return AFPERR_NOOBJ;
1520 return AFPERR_PARAM;
1523 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1524 memcpy(rbuf, &id, sizeof(id));
1525 *rbuflen = sizeof(id);
1526 return AFPERR_EXISTID;
1529 #if AD_VERSION > AD_VERSION1
1530 memset(&ad, 0, sizeof(ad));
1531 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1532 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1533 ad_close(&ad, ADFLAGS_HF);
1535 #endif /* AD_VERSION > AD_VERSION1 */
1537 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1538 memcpy(rbuf, &id, sizeof(id));
1539 *rbuflen = sizeof(id);
1544 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1549 return AFPERR_VLOCK;
1553 return AFPERR_ACCESS;
1556 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1557 return AFPERR_PARAM;
1561 /* ------------------------------
1562 resolve a file id */
1563 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1566 int ibuflen, *rbuflen;
1574 u_int16_t vid, bitmap;
1576 static char buffer[12 + MAXPATHLEN + 1];
1577 int len = 12 + MAXPATHLEN + 1;
1580 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1586 memcpy(&vid, ibuf, sizeof(vid));
1587 ibuf += sizeof(vid);
1589 if (( vol = getvolbyvid( vid )) == NULL ) {
1590 return( AFPERR_PARAM);
1593 memcpy(&id, ibuf, sizeof( id ));
1596 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1597 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1600 if (( dir = dirlookup( vol, id )) == NULL ) {
1601 return AFPERR_NOID; /* idem AFPERR_PARAM */
1603 path.u_name = upath;
1604 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1608 return AFPERR_ACCESS;
1612 return AFPERR_PARAM;
1615 /* directories are bad */
1616 if (S_ISDIR(path.st.st_mode))
1617 return AFPERR_BADTYPE;
1619 memcpy(&bitmap, ibuf, sizeof(bitmap));
1620 bitmap = ntohs( bitmap );
1621 path.m_name = utompath(vol, upath);
1622 if ((err = getfilparams(vol, bitmap, &path , curdir,
1623 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1626 *rbuflen = buflen + sizeof(bitmap);
1627 memcpy(rbuf, ibuf, sizeof(bitmap));
1630 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1636 /* ------------------------------ */
1637 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1640 int ibuflen, *rbuflen;
1650 static char buffer[12 + MAXPATHLEN + 1];
1651 int len = 12 + MAXPATHLEN + 1;
1654 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1660 memcpy(&vid, ibuf, sizeof(vid));
1661 ibuf += sizeof(vid);
1663 if (( vol = getvolbyvid( vid )) == NULL ) {
1664 return( AFPERR_PARAM);
1667 if (vol->v_flags & AFPVOL_RO)
1668 return AFPERR_VLOCK;
1670 memcpy(&id, ibuf, sizeof( id ));
1674 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1678 if (( dir = dirlookup( vol, id )) == NULL ) {
1679 return( AFPERR_PARAM );
1683 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1687 return AFPERR_ACCESS;
1689 /* still try to delete the id */
1693 return AFPERR_PARAM;
1697 /* directories are bad */
1698 if (S_ISDIR(st.st_mode))
1699 return AFPERR_BADTYPE;
1701 if (cnid_delete(vol->v_db, fileid)) {
1704 return AFPERR_VLOCK;
1707 return AFPERR_ACCESS;
1709 return AFPERR_PARAM;
1714 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1719 #endif /* CNID_DB */
1721 #define APPLETEMP ".AppleTempXXXXXX"
1723 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1726 int ibuflen, *rbuflen;
1728 struct stat srcst, destst;
1730 struct dir *dir, *sdir;
1731 char *spath, temp[17], *p;
1732 char *supath, *upath;
1737 struct adouble *adsp;
1738 struct adouble *addp;
1744 #endif /* CNID_DB */
1749 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1755 memcpy(&vid, ibuf, sizeof(vid));
1756 ibuf += sizeof(vid);
1758 if (( vol = getvolbyvid( vid )) == NULL ) {
1759 return( AFPERR_PARAM);
1762 if (vol->v_flags & AFPVOL_RO)
1763 return AFPERR_VLOCK;
1765 /* source and destination dids */
1766 memcpy(&sid, ibuf, sizeof(sid));
1767 ibuf += sizeof(sid);
1768 memcpy(&did, ibuf, sizeof(did));
1769 ibuf += sizeof(did);
1772 if ((dir = dirlookup( vol, sid )) == NULL ) {
1773 return( AFPERR_PARAM );
1776 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1777 return( AFPERR_PARAM );
1780 if ( *path->m_name == '\0' ) {
1781 return( AFPERR_BADTYPE ); /* it's a dir */
1784 upath = path->u_name;
1785 switch (path->st_errno) {
1792 return AFPERR_ACCESS;
1794 return AFPERR_PARAM;
1796 memset(&ads, 0, sizeof(ads));
1798 if ((s_of = of_findname(path))) {
1799 /* reuse struct adouble so it won't break locks */
1802 memcpy(&srcst, &path->st, sizeof(struct stat));
1803 /* save some stuff */
1805 spath = obj->oldtmp;
1806 supath = obj->newtmp;
1807 strcpy(spath, path->m_name);
1808 strcpy(supath, upath); /* this is for the cnid changing */
1809 p = absupath( vol, sdir, upath);
1811 /* look for the source cnid. if it doesn't exist, don't worry about
1814 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1815 slen = strlen(supath));
1816 #endif /* CNID_DB */
1818 if (( dir = dirlookup( vol, did )) == NULL ) {
1819 return( AFPERR_PARAM );
1822 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1823 return( AFPERR_PARAM );
1826 if ( *path->m_name == '\0' ) {
1827 return( AFPERR_BADTYPE );
1830 /* FPExchangeFiles is the only call that can return the SameObj
1832 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1833 return AFPERR_SAMEOBJ;
1834 memcpy(&srcst, &path->st, sizeof(struct stat));
1843 return AFPERR_ACCESS;
1845 return AFPERR_PARAM;
1847 memset(&add, 0, sizeof(add));
1849 if ((d_of = of_findname( path))) {
1850 /* reuse struct adouble so it won't break locks */
1853 memcpy(&destst, &path->st, sizeof(struct stat));
1855 /* they are not on the same device and at least one is open
1857 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1860 upath = path->u_name;
1862 /* look for destination id. */
1863 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1864 dlen = strlen(upath));
1865 #endif /* CNID_DB */
1867 /* construct a temp name.
1868 * NOTE: the temp file will be in the dest file's directory. it
1869 * will also be inaccessible from AFP. */
1870 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1874 /* now, quickly rename the file. we error if we can't. */
1875 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1876 goto err_exchangefile;
1877 of_rename(vol, s_of, sdir, spath, curdir, temp);
1879 /* rename destination to source */
1880 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1881 goto err_src_to_tmp;
1882 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1884 /* rename temp to destination */
1885 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1886 goto err_dest_to_src;
1887 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1890 /* id's need switching. src -> dest and dest -> src. */
1891 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1892 upath, dlen) < 0)) {
1896 err = AFPERR_ACCESS;
1901 goto err_temp_to_dest;
1904 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1905 supath, slen) < 0)) {
1909 err = AFPERR_ACCESS;
1916 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1917 goto err_temp_to_dest;
1919 #endif /* CNID_DB */
1922 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1928 /* all this stuff is so that we can unwind a failed operation
1933 /* rename dest to temp */
1934 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1935 of_rename(vol, s_of, curdir, upath, curdir, temp);
1938 /* rename source back to dest */
1939 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1940 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1943 /* rename temp back to source */
1944 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1945 of_rename(vol, s_of, curdir, temp, sdir, spath);