2 * $Id: file.c,v 1.67 2002-10-13 21:30:55 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;
359 data += sizeof( u_int16_t );
361 memcpy(data, &aint, sizeof( aint ));
362 data += sizeof( aint );
366 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
368 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
372 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
376 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
380 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
384 else if ( fdType[0] == 'p' ) {
386 ashort = (fdType[2] * 256) + fdType[3];
400 memcpy(data, &ashort, sizeof( ashort ));
401 data += sizeof( ashort );
402 memset(data, 0, sizeof( ashort ));
403 data += sizeof( ashort );
406 case FILPBIT_EXTDFLEN:
407 aint = htonl(st->st_size >> 32);
408 memcpy(data, &aint, sizeof( aint ));
409 data += sizeof( aint );
410 aint = htonl(st->st_size);
411 memcpy(data, &aint, sizeof( aint ));
412 data += sizeof( aint );
414 case FILPBIT_EXTRFLEN:
417 aint = htonl(adp->ad_rlen >> 32);
418 memcpy(data, &aint, sizeof( aint ));
419 data += sizeof( aint );
421 aint = htonl(adp->ad_rlen);
422 memcpy(data, &aint, sizeof( aint ));
423 data += sizeof( aint );
426 return( AFPERR_BITMAP );
432 ashort = htons( data - buf );
433 memcpy(nameoff, &ashort, sizeof( ashort ));
434 data = set_name(data, path, utf8);
436 *buflen = data - buf;
440 /* ----------------------- */
441 int getfilparams(struct vol *vol,
443 struct path *path, struct dir *dir,
444 char *buf, int *buflen )
446 struct adouble ad, *adp;
449 u_int16_t attrbits = 0;
454 LOG(log_info, logtype_default, "begin getfilparams:");
457 opened = PARAM_NEED_ADP(bitmap);
460 upath = path->u_name;
461 if ((of = of_findname(path))) {
463 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
464 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
466 memset(&ad, 0, sizeof(ad));
470 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
475 we need to check if the file is open by another process.
476 it's slow so we only do it if we have to:
477 - bitmap is requested.
478 - we don't already have the answer!
480 if ((bitmap & (1 << FILPBIT_ATTR))) {
481 if (!(attrbits & ATTRBIT_ROPEN)) {
483 if (!(attrbits & ATTRBIT_DOPEN)) {
488 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
490 ad_close( adp, ADFLAGS_HF );
493 LOG(log_info, logtype_afpd, "end getfilparams:");
499 /* ----------------------------- */
500 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
503 int ibuflen, *rbuflen;
506 struct adouble ad, *adp;
509 struct ofork *of = NULL;
511 int creatf, did, openf, retvalue = AFP_OK;
517 LOG(log_info, logtype_afpd, "begin afp_createfile:");
522 creatf = (unsigned char) *ibuf++;
524 memcpy(&vid, ibuf, sizeof( vid ));
525 ibuf += sizeof( vid );
527 if (( vol = getvolbyvid( vid )) == NULL ) {
528 return( AFPERR_PARAM );
531 if (vol->v_flags & AFPVOL_RO)
534 memcpy(&did, ibuf, sizeof( did));
535 ibuf += sizeof( did );
537 if (( dir = dirlookup( vol, did )) == NULL ) {
538 return( AFPERR_NOOBJ );
541 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
542 return( AFPERR_NOOBJ );
545 if ( *s_path->m_name == '\0' ) {
546 return( AFPERR_BADTYPE );
549 upath = s_path->u_name;
550 if (0 != (ret = check_name(vol, upath)))
553 /* if upath is deleted we already in trouble anyway */
554 if ((of = of_findname(s_path))) {
557 memset(&ad, 0, sizeof(ad));
561 /* on a hard create, fail if file exists and is open */
564 openf = O_RDWR|O_CREAT|O_TRUNC;
566 /* on a soft create, if the file is open then ad_open won't fail
567 because open syscall is not called
572 openf = O_RDWR|O_CREAT|O_EXCL;
575 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
576 openf, 0666, adp) < 0 ) {
579 return( AFPERR_EXIST );
581 return( AFPERR_ACCESS );
583 /* on noadouble volumes, just creating the data fork is ok */
585 if (vol_noadouble(vol) && (stat(upath, st) == 0))
586 goto createfile_done;
589 return( AFPERR_PARAM );
592 path = s_path->m_name;
593 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
594 memcpy(ad_entry( adp, ADEID_NAME ), path,
595 ad_getentrylen( adp, ADEID_NAME ));
596 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
597 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
602 if (vol->v_flags & AFPVOL_DROPBOX) {
603 retvalue = matchfile2dirperms(upath, vol, did);
605 #endif /* DROPKLUDGE */
607 setvoltime(obj, vol );
610 LOG(log_info, logtype_afpd, "end afp_createfile");
616 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
619 int ibuflen, *rbuflen;
625 u_int16_t vid, bitmap;
628 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
634 memcpy(&vid, ibuf, sizeof( vid ));
635 ibuf += sizeof( vid );
636 if (( vol = getvolbyvid( vid )) == NULL ) {
637 return( AFPERR_PARAM );
640 if (vol->v_flags & AFPVOL_RO)
643 memcpy(&did, ibuf, sizeof( did ));
644 ibuf += sizeof( did );
645 if (( dir = dirlookup( vol, did )) == NULL ) {
646 return( AFPERR_NOOBJ );
649 memcpy(&bitmap, ibuf, sizeof( bitmap ));
650 bitmap = ntohs( bitmap );
651 ibuf += sizeof( bitmap );
653 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
654 return( AFPERR_NOOBJ );
657 if ( *s_path->m_name == '\0' ) {
658 return( AFPERR_BADTYPE ); /* it's a directory */
661 if ((u_long)ibuf & 1 ) {
665 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
666 setvoltime(obj, vol );
670 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
677 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
680 extern struct path Cur_Path;
682 int setfilparams(struct vol *vol,
683 struct path *path, u_int16_t bitmap, char *buf )
685 struct adouble ad, *adp;
688 int bit = 0, isad = 1, err = AFP_OK;
690 u_char achar, *fdType, xyy[4];
691 u_int16_t ashort, bshort;
695 int change_mdate = 0;
696 int change_parent_mdate = 0;
702 LOG(log_info, logtype_afpd, "begin setfilparams:");
705 upath = path->u_name;
706 if ((of = of_findname(path))) {
709 memset(&ad, 0, sizeof(ad));
713 if (check_access(upath, OPENACC_WR ) < 0) {
714 return AFPERR_ACCESS;
717 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
718 O_RDWR|O_CREAT, 0666, adp) < 0) {
719 /* for some things, we don't need an adouble header */
720 if (bitmap & ~(1<<FILPBIT_MDATE)) {
721 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
724 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
725 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
726 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
727 ad_getentrylen( adp, ADEID_NAME ));
730 while ( bitmap != 0 ) {
731 while (( bitmap & 1 ) == 0 ) {
739 memcpy(&ashort, buf, sizeof( ashort ));
740 ad_getattr(adp, &bshort);
741 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
742 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
746 if ((ashort & htons(ATTRBIT_INVISIBLE)))
747 change_parent_mdate = 1;
748 ad_setattr(adp, bshort);
749 buf += sizeof( ashort );
754 memcpy(&aint, buf, sizeof(aint));
755 ad_setdate(adp, AD_DATE_CREATE, aint);
756 buf += sizeof( aint );
760 memcpy(&newdate, buf, sizeof( newdate ));
761 buf += sizeof( newdate );
766 memcpy(&aint, buf, sizeof(aint));
767 ad_setdate(adp, AD_DATE_BACKUP, aint);
768 buf += sizeof( aint );
774 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
776 ((em = getextmap( path->m_name )) &&
777 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
778 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
779 || ((em = getdefextmap()) &&
780 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
781 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
783 memcpy(buf, ufinderi, 8 );
786 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
790 /* Client needs to set the ProDOS file info for this file.
791 Use defined strings for the simple cases, and convert
792 all else into pXYY per Inside Appletalk. Always set
793 the creator as "pdos". <shirsch@ibm.net> */
794 case FILPBIT_PDINFO :
797 memcpy(&ashort, buf, sizeof( ashort ));
798 ashort = ntohs( ashort );
801 switch ( (unsigned int) achar )
804 fdType = ( u_char *) "TEXT";
808 fdType = ( u_char *) "PSYS";
812 fdType = ( u_char *) "PS16";
816 fdType = ( u_char *) "BINA";
820 xyy[0] = ( u_char ) 'p';
822 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
823 xyy[3] = ( u_char ) ashort & 0xff;
828 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
829 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
835 goto setfilparam_done;
843 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
844 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
848 ad_setdate(adp, AD_DATE_MODIFY, newdate);
849 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
854 ad_flush( adp, ADFLAGS_HF );
855 ad_close( adp, ADFLAGS_HF );
859 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
860 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
861 bitmap = 1<<FILPBIT_MDATE;
862 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
866 LOG(log_info, logtype_afpd, "end setfilparams:");
872 * renamefile and copyfile take the old and new unix pathnames
873 * and the new mac name.
874 * NOTE: if we have to copy a file instead of renaming it, locks
875 * will break. Anyway it's an error because then we have 2 files.
877 * src the source path
878 * dst the dest filename in current dir
879 * newname the dest mac name
880 * adp adouble struct of src file, if open, or & zeroed one
883 int renamefile(src, dst, newname, noadouble, adp )
884 char *src, *dst, *newname;
888 char adsrc[ MAXPATHLEN + 1];
892 * Note that this is only checking the existance of the data file,
893 * not the header file. The thinking is that if the data file doesn't
894 * exist, but the header file does, the right thing to do is remove
895 * the data file silently.
898 /* existence check moved to afp_moveandrename */
901 LOG(log_info, logtype_afpd, "begin renamefile:");
904 if ( rename( src, dst ) < 0 ) {
907 return( AFPERR_NOOBJ );
910 return( AFPERR_ACCESS );
913 case EXDEV : /* Cross device move -- try copy */
914 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
915 deletefile( dst, 0 );
918 return deletefile( src, 0);
920 return( AFPERR_PARAM );
924 strcpy( adsrc, ad_path( src, 0 ));
927 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
932 /* check for a source appledouble header. if it exists, make
933 * a dest appledouble directory and do the rename again. */
934 if (rc || stat(adsrc, &st) ||
935 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
938 ad_close(adp, ADFLAGS_HF);
942 return( AFPERR_ACCESS );
946 return( AFPERR_PARAM );
950 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
953 return( AFPERR_NOOBJ );
955 return( AFPERR_ACCESS );
959 return( AFPERR_PARAM );
963 len = strlen( newname );
964 ad_setentrylen( adp, ADEID_NAME, len );
965 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
966 ad_flush( adp, ADFLAGS_HF );
967 ad_close( adp, ADFLAGS_HF );
970 LOG(log_info, logtype_afpd, "end renamefile:");
976 int copy_path_name(char *newname, char *ibuf)
983 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
989 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
990 strncpy( newname, ibuf, plen );
991 newname[ plen ] = '\0';
992 if (strlen(newname) != plen) {
993 /* there's \0 in newname, e.g. it's a pathname not
1001 memcpy(&hint, ibuf, sizeof(hint));
1002 ibuf += sizeof(hint);
1004 memcpy(&len16, ibuf, sizeof(len16));
1005 ibuf += sizeof(len16);
1006 plen = ntohs(len16);
1008 strncpy( newname, ibuf, plen );
1009 newname[ plen ] = '\0';
1010 if (strchr(newname,'/')) {
1019 /* -----------------------------------
1021 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1024 int ibuflen, *rbuflen;
1028 char *newname, *p, *upath;
1029 struct path *s_path;
1030 u_int32_t sdid, ddid;
1031 int err, retvalue = AFP_OK;
1032 u_int16_t svid, dvid;
1035 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1041 memcpy(&svid, ibuf, sizeof( svid ));
1042 ibuf += sizeof( svid );
1043 if (( vol = getvolbyvid( svid )) == NULL ) {
1044 return( AFPERR_PARAM );
1047 memcpy(&sdid, ibuf, sizeof( sdid ));
1048 ibuf += sizeof( sdid );
1049 if (( dir = dirlookup( vol, sdid )) == NULL ) {
1050 return( AFPERR_PARAM );
1053 memcpy(&dvid, ibuf, sizeof( dvid ));
1054 ibuf += sizeof( dvid );
1055 memcpy(&ddid, ibuf, sizeof( ddid ));
1056 ibuf += sizeof( ddid );
1058 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1059 return( AFPERR_NOOBJ );
1061 if ( *s_path->m_name == '\0' ) {
1062 return( AFPERR_BADTYPE );
1065 /* don't allow copies when the file is open.
1066 * XXX: the spec only calls for read/deny write access.
1067 * however, copyfile doesn't have any of that info,
1068 * and locks need to stay coherent. as a result,
1069 * we just balk if the file is opened already. */
1071 newname = obj->newtmp;
1072 strcpy( newname, s_path->m_name );
1074 if (of_findname(s_path))
1075 return AFPERR_DENYCONF;
1077 p = ctoupath( vol, curdir, newname );
1079 /* FIXME svid != dvid && dvid's user can't read svid */
1081 if (( vol = getvolbyvid( dvid )) == NULL ) {
1082 return( AFPERR_PARAM );
1085 if (vol->v_flags & AFPVOL_RO)
1086 return AFPERR_VLOCK;
1088 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1089 return( AFPERR_PARAM );
1092 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1093 return( AFPERR_NOOBJ );
1095 if ( *s_path->m_name != '\0' ) {
1096 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1099 /* one of the handful of places that knows about the path type */
1100 if (copy_path_name(newname, ibuf) < 0) {
1101 return( AFPERR_PARAM );
1104 upath = mtoupath(vol, newname);
1105 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1110 if (vol->v_flags & AFPVOL_DROPBOX) {
1111 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1113 #endif /* DROPKLUDGE */
1115 setvoltime(obj, vol );
1118 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1125 static __inline__ int copy_all(const int dfd, const void *buf,
1131 LOG(log_info, logtype_afpd, "begin copy_all:");
1134 while (buflen > 0) {
1135 if ((cc = write(dfd, buf, buflen)) < 0) {
1142 return AFPERR_DFULL;
1144 return AFPERR_VLOCK;
1146 return AFPERR_PARAM;
1153 LOG(log_info, logtype_afpd, "end copy_all:");
1159 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1160 * pass in vol and path */
1161 int copyfile(src, dst, newname, noadouble )
1162 char *src, *dst, *newname;
1163 const int noadouble;
1166 #ifdef SENDFILE_FLAVOR_LINUX
1170 int sfd, dfd, len, err = AFP_OK;
1172 char dpath[ MAXPATHLEN + 1];
1175 LOG(log_info, logtype_afpd, "begin copyfile:");
1178 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1179 admode = ad_mode( dst, 0666 );
1181 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1184 break; /* just copy the data fork */
1186 return( AFPERR_ACCESS );
1188 return( AFPERR_PARAM );
1191 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1195 return( AFPERR_NOOBJ );
1197 return( AFPERR_ACCESS );
1199 return AFPERR_VLOCK;
1201 return( AFPERR_PARAM );
1206 #ifdef SENDFILE_FLAVOR_LINUX
1207 if (fstat(sfd, &st) == 0) {
1208 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1222 goto copyheader_done;
1224 #endif /* SENDFILE_FLAVOR_LINUX */
1226 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1233 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1247 /* data fork copying */
1248 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1251 return( AFPERR_NOOBJ );
1253 return( AFPERR_ACCESS );
1255 return( AFPERR_PARAM );
1259 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1263 return( AFPERR_NOOBJ );
1265 return( AFPERR_ACCESS );
1267 return AFPERR_VLOCK;
1269 return( AFPERR_PARAM );
1273 #ifdef SENDFILE_FLAVOR_LINUX
1274 if (fstat(sfd, &st) == 0) {
1275 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1288 #endif /* SENDFILE_FLAVOR_LINUX */
1291 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1299 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1314 memset(&ad, 0, sizeof(ad));
1315 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1319 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1321 return( AFPERR_ACCESS );
1323 return AFPERR_VLOCK;
1325 return( AFPERR_PARAM );
1329 len = strlen( newname );
1330 ad_setentrylen( &ad, ADEID_NAME, len );
1331 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1332 ad_flush( &ad, ADFLAGS_HF );
1333 ad_close( &ad, ADFLAGS_HF );
1337 LOG(log_info, logtype_afpd, "end copyfile:");
1344 /* -----------------------------------
1345 checkAttrib: 1 check kFPDeleteInhibitBit
1346 ie deletfile called by afp_delete
1348 when deletefile is called we don't have lock on it, file is closed (for us)
1349 untrue if called by renamefile
1351 int deletefile( file, checkAttrib )
1356 int adflags, err = AFP_OK;
1357 int locktype = ADLOCK_WR;
1358 int openmode = O_RDWR;
1361 LOG(log_info, logtype_afpd, "begin deletefile:");
1366 * If can't open read/write then try again read-only. If it's open
1367 * read-only, we must do a read lock instead of a write lock.
1369 /* try to open both at once */
1370 adflags = ADFLAGS_DF|ADFLAGS_HF;
1371 memset(&ad, 0, sizeof(ad));
1372 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1375 adflags = ADFLAGS_DF;
1376 /* that failed. now try to open just the data fork */
1377 memset(&ad, 0, sizeof(ad));
1378 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1381 return AFPERR_NOOBJ;
1383 if(openmode == O_RDWR) {
1384 openmode = O_RDONLY;
1385 locktype = ADLOCK_RD;
1388 return AFPERR_ACCESS;
1391 return AFPERR_VLOCK;
1393 return AFPERR_PARAM;
1399 if(openmode == O_RDWR) {
1400 openmode = O_RDONLY;
1401 locktype = ADLOCK_RD;
1404 return AFPERR_ACCESS;
1407 return AFPERR_VLOCK;
1409 return( AFPERR_PARAM );
1412 break; /* from the while */
1415 * Does kFPDeleteInhibitBit (bit 8) set?
1417 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1420 ad_getattr(&ad, &bshort);
1421 if ((bshort & htons(ATTRBIT_NODELETE))) {
1422 ad_close( &ad, adflags );
1423 return(AFPERR_OLOCK);
1427 if ((adflags & ADFLAGS_HF) ) {
1428 /* FIXME we have a pb here because we want to know if a file is open
1429 * there's a 'priority inversion' if you can't open the ressource fork RW
1430 * you can delete it if it's open because you can't get a write lock.
1432 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1435 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1437 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1438 ad_close( &ad, adflags );
1439 return( AFPERR_BUSY );
1443 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1448 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1452 err = AFPERR_ACCESS;
1465 if ( unlink( file ) < 0 ) {
1469 err = AFPERR_ACCESS;
1483 if (adflags & ADFLAGS_HF)
1484 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1485 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1486 ad_close( &ad, adflags );
1489 LOG(log_info, logtype_afpd, "end deletefile:");
1495 /* ------------------------------------ */
1497 /* return a file id */
1498 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1501 int ibuflen, *rbuflen;
1504 #if AD_VERSION > AD_VERSION1
1513 struct path *s_path;
1516 LOG(log_info, logtype_afpd, "begin afp_createid:");
1522 memcpy(&vid, ibuf, sizeof(vid));
1523 ibuf += sizeof(vid);
1525 if (( vol = getvolbyvid( vid )) == NULL ) {
1526 return( AFPERR_PARAM);
1529 if (vol->v_flags & AFPVOL_RO)
1530 return AFPERR_VLOCK;
1532 memcpy(&did, ibuf, sizeof( did ));
1533 ibuf += sizeof(did);
1535 if (( dir = dirlookup( vol, did )) == NULL ) {
1536 return( AFPERR_PARAM );
1539 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1540 return( AFPERR_PARAM );
1543 if ( *s_path->m_name == '\0' ) {
1544 return( AFPERR_BADTYPE );
1547 upath = s_path->u_name;
1548 switch (s_path->st_errno) {
1550 break; /* success */
1553 return AFPERR_ACCESS;
1555 return AFPERR_NOOBJ;
1557 return AFPERR_PARAM;
1560 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1561 memcpy(rbuf, &id, sizeof(id));
1562 *rbuflen = sizeof(id);
1563 return AFPERR_EXISTID;
1566 #if AD_VERSION > AD_VERSION1
1567 memset(&ad, 0, sizeof(ad));
1568 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1569 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1570 ad_close(&ad, ADFLAGS_HF);
1572 #endif /* AD_VERSION > AD_VERSION1 */
1574 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1575 memcpy(rbuf, &id, sizeof(id));
1576 *rbuflen = sizeof(id);
1581 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1586 return AFPERR_VLOCK;
1590 return AFPERR_ACCESS;
1593 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1594 return AFPERR_PARAM;
1598 /* ------------------------------
1599 resolve a file id */
1600 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1603 int ibuflen, *rbuflen;
1611 u_int16_t vid, bitmap;
1613 static char buffer[12 + MAXPATHLEN + 1];
1614 int len = 12 + MAXPATHLEN + 1;
1617 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1623 memcpy(&vid, ibuf, sizeof(vid));
1624 ibuf += sizeof(vid);
1626 if (( vol = getvolbyvid( vid )) == NULL ) {
1627 return( AFPERR_PARAM);
1630 memcpy(&id, ibuf, sizeof( id ));
1633 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1634 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1637 if (( dir = dirlookup( vol, id )) == NULL ) {
1638 return AFPERR_NOID; /* idem AFPERR_PARAM */
1640 path.u_name = upath;
1641 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1645 return AFPERR_ACCESS;
1649 return AFPERR_PARAM;
1652 /* directories are bad */
1653 if (S_ISDIR(path.st.st_mode))
1654 return AFPERR_BADTYPE;
1656 memcpy(&bitmap, ibuf, sizeof(bitmap));
1657 bitmap = ntohs( bitmap );
1658 path.m_name = utompath(vol, upath);
1659 if ((err = getfilparams(vol, bitmap, &path , curdir,
1660 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1663 *rbuflen = buflen + sizeof(bitmap);
1664 memcpy(rbuf, ibuf, sizeof(bitmap));
1667 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1673 /* ------------------------------ */
1674 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1677 int ibuflen, *rbuflen;
1687 static char buffer[12 + MAXPATHLEN + 1];
1688 int len = 12 + MAXPATHLEN + 1;
1691 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1697 memcpy(&vid, ibuf, sizeof(vid));
1698 ibuf += sizeof(vid);
1700 if (( vol = getvolbyvid( vid )) == NULL ) {
1701 return( AFPERR_PARAM);
1704 if (vol->v_flags & AFPVOL_RO)
1705 return AFPERR_VLOCK;
1707 memcpy(&id, ibuf, sizeof( id ));
1711 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1715 if (( dir = dirlookup( vol, id )) == NULL ) {
1716 return( AFPERR_PARAM );
1720 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1724 return AFPERR_ACCESS;
1726 /* still try to delete the id */
1730 return AFPERR_PARAM;
1734 /* directories are bad */
1735 if (S_ISDIR(st.st_mode))
1736 return AFPERR_BADTYPE;
1738 if (cnid_delete(vol->v_db, fileid)) {
1741 return AFPERR_VLOCK;
1744 return AFPERR_ACCESS;
1746 return AFPERR_PARAM;
1751 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1756 #endif /* CNID_DB */
1758 #define APPLETEMP ".AppleTempXXXXXX"
1760 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1763 int ibuflen, *rbuflen;
1765 struct stat srcst, destst;
1767 struct dir *dir, *sdir;
1768 char *spath, temp[17], *p;
1769 char *supath, *upath;
1774 struct adouble *adsp;
1775 struct adouble *addp;
1781 #endif /* CNID_DB */
1786 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1792 memcpy(&vid, ibuf, sizeof(vid));
1793 ibuf += sizeof(vid);
1795 if (( vol = getvolbyvid( vid )) == NULL ) {
1796 return( AFPERR_PARAM);
1799 if (vol->v_flags & AFPVOL_RO)
1800 return AFPERR_VLOCK;
1802 /* source and destination dids */
1803 memcpy(&sid, ibuf, sizeof(sid));
1804 ibuf += sizeof(sid);
1805 memcpy(&did, ibuf, sizeof(did));
1806 ibuf += sizeof(did);
1809 if ((dir = dirlookup( vol, sid )) == NULL ) {
1810 return( AFPERR_PARAM );
1813 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1814 return( AFPERR_PARAM );
1817 if ( *path->m_name == '\0' ) {
1818 return( AFPERR_BADTYPE ); /* it's a dir */
1821 upath = path->u_name;
1822 switch (path->st_errno) {
1829 return AFPERR_ACCESS;
1831 return AFPERR_PARAM;
1833 memset(&ads, 0, sizeof(ads));
1835 if ((s_of = of_findname(path))) {
1836 /* reuse struct adouble so it won't break locks */
1839 memcpy(&srcst, &path->st, sizeof(struct stat));
1840 /* save some stuff */
1842 spath = obj->oldtmp;
1843 supath = obj->newtmp;
1844 strcpy(spath, path->m_name);
1845 strcpy(supath, upath); /* this is for the cnid changing */
1846 p = absupath( vol, sdir, upath);
1848 /* look for the source cnid. if it doesn't exist, don't worry about
1851 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1852 slen = strlen(supath));
1853 #endif /* CNID_DB */
1855 if (( dir = dirlookup( vol, did )) == NULL ) {
1856 return( AFPERR_PARAM );
1859 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1860 return( AFPERR_PARAM );
1863 if ( *path->m_name == '\0' ) {
1864 return( AFPERR_BADTYPE );
1867 /* FPExchangeFiles is the only call that can return the SameObj
1869 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1870 return AFPERR_SAMEOBJ;
1871 memcpy(&srcst, &path->st, sizeof(struct stat));
1880 return AFPERR_ACCESS;
1882 return AFPERR_PARAM;
1884 memset(&add, 0, sizeof(add));
1886 if ((d_of = of_findname( path))) {
1887 /* reuse struct adouble so it won't break locks */
1890 memcpy(&destst, &path->st, sizeof(struct stat));
1892 /* they are not on the same device and at least one is open
1894 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1897 upath = path->u_name;
1899 /* look for destination id. */
1900 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1901 dlen = strlen(upath));
1902 #endif /* CNID_DB */
1904 /* construct a temp name.
1905 * NOTE: the temp file will be in the dest file's directory. it
1906 * will also be inaccessible from AFP. */
1907 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1911 /* now, quickly rename the file. we error if we can't. */
1912 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1913 goto err_exchangefile;
1914 of_rename(vol, s_of, sdir, spath, curdir, temp);
1916 /* rename destination to source */
1917 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1918 goto err_src_to_tmp;
1919 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1921 /* rename temp to destination */
1922 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1923 goto err_dest_to_src;
1924 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1927 /* id's need switching. src -> dest and dest -> src. */
1928 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1929 upath, dlen) < 0)) {
1933 err = AFPERR_ACCESS;
1938 goto err_temp_to_dest;
1941 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1942 supath, slen) < 0)) {
1946 err = AFPERR_ACCESS;
1953 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1954 goto err_temp_to_dest;
1956 #endif /* CNID_DB */
1959 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1965 /* all this stuff is so that we can unwind a failed operation
1970 /* rename dest to temp */
1971 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1972 of_rename(vol, s_of, curdir, upath, curdir, temp);
1975 /* rename source back to dest */
1976 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1977 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1980 /* rename temp back to source */
1981 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1982 of_rename(vol, s_of, curdir, temp, sdir, spath);