2 * $Id: file.c,v 1.52 2002-08-29 18:57:26 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 /* check for mtab DID code */
64 #include "parse_mtab.h"
70 #endif /* FORCE_UIDGID */
72 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
73 * field bytes subfield bytes
76 * ioFlFndrInfo 16 -> type 4 type field
77 * creator 4 creator field
78 * flags 2 finder flags:
80 * location 4 location in window
81 * folder 2 window that contains file
83 * ioFlXFndrInfo 16 -> iconID 2 icon id
85 * script 1 script system
87 * commentID 2 comment id
88 * putawayID 4 home directory id
91 const u_char ufinderi[] = {
92 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
93 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0
98 int getmetadata(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen, struct adouble *adp, int attrbits )
104 struct stat lst, *lstp;
105 #endif /* USE_LASTDID */
108 char *data, *nameoff = NULL, *upath;
112 u_char achar, fdType[4];
116 LOG(log_info, logtype_afpd, "begin getmetadata:");
119 upath = mtoupath(vol, path);
122 while ( bitmap != 0 ) {
123 while (( bitmap & 1 ) == 0 ) {
131 ad_getattr(adp, &ashort);
132 } else if (*upath == '.') {
133 ashort = htons(ATTRBIT_INVISIBLE);
137 /* FIXME do we want a visual clue if the file is read only
139 accessmode( ".", &ma, dir , NULL);
140 if ((ma.ma_user & AR_UWRITE)) {
141 accessmode( upath, &ma, dir , st);
142 if (!(ma.ma_user & AR_UWRITE)) {
143 attrbits |= ATTRBIT_NOWRITE;
148 ashort = htons(ntohs(ashort) | attrbits);
149 memcpy(data, &ashort, sizeof( ashort ));
150 data += sizeof( ashort );
154 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
155 data += sizeof( u_int32_t );
159 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
160 aint = AD_DATE_FROM_UNIX(st->st_mtime);
161 memcpy(data, &aint, sizeof( aint ));
162 data += sizeof( aint );
166 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
167 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
168 aint = AD_DATE_FROM_UNIX(st->st_mtime);
171 aint = AD_DATE_FROM_UNIX(st->st_mtime);
173 memcpy(data, &aint, sizeof( int ));
174 data += sizeof( int );
178 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
179 aint = AD_DATE_START;
180 memcpy(data, &aint, sizeof( int ));
181 data += sizeof( int );
186 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
188 memcpy(data, ufinderi, 32);
189 if (*upath == '.') { /* make it invisible */
190 ashort = htons(FINDERINFO_INVISIBLE);
191 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
195 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
196 && (em = getextmap( path ))
198 memcpy(data, em->em_type, sizeof( em->em_type ));
199 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
206 data += sizeof( u_int16_t );
210 memset(data, 0, sizeof(u_int16_t));
211 data += sizeof( u_int16_t );
216 #if AD_VERSION > AD_VERSION1
217 /* look in AD v2 header */
219 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
220 #endif /* AD_VERSION > AD_VERSION1 */
223 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
224 strlen(upath), aint);
225 /* Throw errors if cnid_add fails. */
226 if (aint == CNID_INVALID) {
229 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
230 return(AFPERR_PARAM);
232 return(AFPERR_PARAM);
242 * What a fucking mess. First thing: DID and FNUMs are
243 * in the same space for purposes of enumerate (and several
244 * other wierd places). While we consider this Apple's bug,
245 * this is the work-around: In order to maintain constant and
246 * unique DIDs and FNUMs, we monotonically generate the DIDs
247 * during the session, and derive the FNUMs from the filesystem.
248 * Since the DIDs are small, we insure that the FNUMs are fairly
249 * large by setting thier high bits to the device number.
251 * AFS already does something very similar to this for the
252 * inode number, so we don't repeat the procedure.
255 * due to complaints over did's being non-persistent,
256 * here's the current hack to provide semi-persistent
258 * 1) we reserve the first bit for file ids.
259 * 2) the next 7 bits are for the device.
260 * 3) the remaining 24 bits are for the inode.
262 * both the inode and device information are actually hashes
263 * that are then truncated to the requisite bit length.
265 * it should be okay to use lstat to deal with symlinks.
268 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
269 #else /* USE_LASTDID */
270 lstp = lstat(upath, &lst) < 0 ? st : &lst;
272 aint = htonl( afpd_st_cnid ( lstp ) );
274 aint = htonl(CNID(lstp, 1));
275 #endif /* DID_MTAB */
276 #endif /* USE_LASTDID */
279 memcpy(data, &aint, sizeof( aint ));
280 data += sizeof( aint );
284 aint = htonl( st->st_size );
285 memcpy(data, &aint, sizeof( aint ));
286 data += sizeof( aint );
291 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
295 memcpy(data, &aint, sizeof( aint ));
296 data += sizeof( aint );
299 /* Current client needs ProDOS info block for this file.
300 Use simple heuristic and let the Mac "type" string tell
301 us what the PD file code should be. Everything gets a
302 subtype of 0x0000 unless the original value was hashed
303 to "pXYZ" when we created it. See IA, Ver 2.
305 case FILPBIT_PDINFO :
307 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
309 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
313 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
317 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
321 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
325 else if ( fdType[0] == 'p' ) {
327 ashort = (fdType[2] * 256) + fdType[3];
341 memcpy(data, &ashort, sizeof( ashort ));
342 data += sizeof( ashort );
343 memset(data, 0, sizeof( ashort ));
344 data += sizeof( ashort );
348 return( AFPERR_BITMAP );
354 ashort = htons( data - buf );
355 memcpy(nameoff, &ashort, sizeof( ashort ));
356 if ((aint = strlen( path )) > MACFILELEN)
359 memcpy(data, path, aint );
362 *buflen = data - buf;
366 /* ----------------------- */
367 int getfilparams(struct vol *vol,
369 char *path, struct dir *dir, struct stat *st,
370 char *buf, int *buflen )
372 struct adouble ad, *adp;
375 u_int16_t attrbits = 0;
378 LOG(log_info, logtype_default, "begin getfilparams:");
381 upath = mtoupath(vol, path);
382 if ((of = of_findname(vol, dir, path))) {
384 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
385 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
388 memset(&ad, 0, sizeof(ad));
392 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
398 we need to check if the file is open by another process.
399 it's slow so we only do it if we have to:
400 - bitmap is requested.
401 - we don't already have the answer!
403 if ((bitmap & (1 << FILPBIT_ATTR))) {
404 if (!(attrbits & ATTRBIT_ROPEN)) {
406 if (!(attrbits & ATTRBIT_DOPEN)) {
411 rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
413 ad_close( adp, ADFLAGS_HF );
416 LOG(log_info, logtype_afpd, "end getfilparams:");
422 /* ----------------------------- */
423 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
426 int ibuflen, *rbuflen;
429 struct adouble ad, *adp;
434 int creatf, did, openf, retvalue = AFP_OK;
438 #endif /* FORCE_UIDGID */
441 LOG(log_info, logtype_afpd, "begin afp_createfile:");
446 creatf = (unsigned char) *ibuf++;
448 memcpy(&vid, ibuf, sizeof( vid ));
449 ibuf += sizeof( vid );
451 if (( vol = getvolbyvid( vid )) == NULL ) {
452 return( AFPERR_PARAM );
455 if (vol->v_flags & AFPVOL_RO)
458 memcpy(&did, ibuf, sizeof( did));
459 ibuf += sizeof( did );
461 if (( dir = dirsearch( vol, did )) == NULL ) {
462 return( AFPERR_NOOBJ );
465 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
466 return( AFPERR_NOOBJ );
469 upath = mtoupath(vol, path);
472 if (0 != (ret = check_name(vol, upath)))
476 if ((of = of_findname(vol, curdir, path))) {
479 memset(&ad, 0, sizeof(ad));
483 /* on a hard create, fail if file exists and is open */
484 if ((stat(upath, &st) == 0) && of)
486 openf = O_RDWR|O_CREAT|O_TRUNC;
488 /* on a soft create, if the file is open then ad_open won't failed
489 because open syscall is not called
494 openf = O_RDWR|O_CREAT|O_EXCL;
499 /* preserve current euid, egid */
500 save_uidgid ( uidgid );
502 /* perform all switching of users */
505 #endif /* FORCE_UIDGID */
507 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
508 openf, 0666, adp) < 0 ) {
512 /* bring everything back to old euid, egid */
513 restore_uidgid ( uidgid );
514 #endif /* FORCE_UIDGID */
515 return( AFPERR_EXIST );
518 /* bring everything back to old euid, egid */
519 restore_uidgid ( uidgid );
520 #endif /* FORCE_UIDGID */
521 return( AFPERR_ACCESS );
523 /* on noadouble volumes, just creating the data fork is ok */
524 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
525 goto createfile_done;
529 /* bring everything back to old euid, egid */
530 restore_uidgid ( uidgid );
531 #endif /* FORCE_UIDGID */
532 return( AFPERR_PARAM );
536 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
537 memcpy(ad_entry( adp, ADEID_NAME ), path,
538 ad_getentrylen( adp, ADEID_NAME ));
539 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
540 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
545 if (vol->v_flags & AFPVOL_DROPBOX) {
546 retvalue = matchfile2dirperms(upath, vol, did);
548 #endif /* DROPKLUDGE */
550 setvoltime(obj, vol );
553 LOG(log_info, logtype_afpd, "end afp_createfile");
557 /* bring everything back to old euid, egid */
558 restore_uidgid ( uidgid );
559 #endif /* FORCE_UIDGID */
564 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
567 int ibuflen, *rbuflen;
573 u_int16_t vid, bitmap;
576 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
584 if (( vol = getvolbyvid( vid )) == NULL ) {
585 return( AFPERR_PARAM );
588 if (vol->v_flags & AFPVOL_RO)
591 memcpy(&did, ibuf, sizeof( did ));
592 ibuf += sizeof( did );
593 if (( dir = dirsearch( vol, did )) == NULL ) {
594 return( AFPERR_NOOBJ );
597 memcpy(&bitmap, ibuf, sizeof( bitmap ));
598 bitmap = ntohs( bitmap );
599 ibuf += sizeof( bitmap );
601 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
602 return( AFPERR_NOOBJ );
605 if ( *path == '\0' ) {
606 return( AFPERR_BADTYPE ); /* it's a directory */
609 if ((u_long)ibuf & 1 ) {
613 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
614 setvoltime(obj, vol );
618 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
625 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
629 int setfilparams(struct vol *vol,
630 char *path, u_int16_t bitmap, char *buf )
632 struct adouble ad, *adp;
635 int bit = 0, isad = 1, err = AFP_OK;
637 u_char achar, *fdType, xyy[4];
638 u_int16_t ashort, bshort;
642 int change_mdate = 0;
643 int change_parent_mdate = 0;
650 uidgid = malloc(sizeof(uidgidset));
651 #endif /* FORCE_UIDGID */
654 LOG(log_info, logtype_afpd, "begin setfilparams:");
657 upath = mtoupath(vol, path);
658 if ((of = of_findname(vol, curdir, path))) {
661 memset(&ad, 0, sizeof(ad));
666 save_uidgid ( uidgid );
668 #endif /* FORCE_UIDGID */
670 if (check_access(upath, OPENACC_WR ) < 0) {
672 restore_uidgid ( uidgid );
673 #endif /* FORCE_UIDGID */
674 return AFPERR_ACCESS;
677 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
678 O_RDWR|O_CREAT, 0666, adp) < 0) {
679 /* for some things, we don't need an adouble header */
680 if (bitmap & ~(1<<FILPBIT_MDATE)) {
682 restore_uidgid ( uidgid );
683 #endif /* FORCE_UIDGID */
684 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
687 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
688 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
689 memcpy(ad_entry( adp, ADEID_NAME ), path,
690 ad_getentrylen( adp, ADEID_NAME ));
693 while ( bitmap != 0 ) {
694 while (( bitmap & 1 ) == 0 ) {
702 memcpy(&ashort, buf, sizeof( ashort ));
703 ad_getattr(adp, &bshort);
704 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
705 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
709 if ((ashort & htons(ATTRBIT_INVISIBLE)))
710 change_parent_mdate = 1;
711 ad_setattr(adp, bshort);
712 buf += sizeof( ashort );
717 memcpy(&aint, buf, sizeof(aint));
718 ad_setdate(adp, AD_DATE_CREATE, aint);
719 buf += sizeof( aint );
723 memcpy(&newdate, buf, sizeof( newdate ));
724 buf += sizeof( newdate );
729 memcpy(&aint, buf, sizeof(aint));
730 ad_setdate(adp, AD_DATE_BACKUP, aint);
731 buf += sizeof( aint );
737 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
739 ((em = getextmap( path )) &&
740 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
741 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
742 || ((em = getdefextmap()) &&
743 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
744 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
746 memcpy(buf, ufinderi, 8 );
749 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
753 /* Client needs to set the ProDOS file info for this file.
754 Use defined strings for the simple cases, and convert
755 all else into pXYY per Inside Appletalk. Always set
756 the creator as "pdos". <shirsch@ibm.net> */
757 case FILPBIT_PDINFO :
760 memcpy(&ashort, buf, sizeof( ashort ));
761 ashort = ntohs( ashort );
764 switch ( (unsigned int) achar )
767 fdType = ( u_char *) "TEXT";
771 fdType = ( u_char *) "PSYS";
775 fdType = ( u_char *) "PS16";
779 fdType = ( u_char *) "BINA";
783 xyy[0] = ( u_char ) 'p';
785 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
786 xyy[3] = ( u_char ) ashort & 0xff;
791 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
792 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
798 goto setfilparam_done;
806 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
807 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
811 ad_setdate(adp, AD_DATE_MODIFY, newdate);
812 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
817 ad_flush( adp, ADFLAGS_HF );
818 ad_close( adp, ADFLAGS_HF );
821 restore_uidgid ( uidgid );
822 #endif /* FORCE_UIDGID */
826 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
827 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
828 bitmap = 1<<FILPBIT_MDATE;
829 setdirparams(vol, "", bitmap, (char *)&newdate);
833 LOG(log_info, logtype_afpd, "end setfilparams:");
839 * renamefile and copyfile take the old and new unix pathnames
840 * and the new mac name.
841 * NOTE: if we have to copy a file instead of renaming it, locks
842 * will break. Anyway it's an error because then we have 2 files.
844 * src the source path
845 * dst the dest filename in current dir
846 * newname the dest mac name
847 * adp adouble struct of src file, if open, or & zeroed one
850 int renamefile(src, dst, newname, noadouble, adp )
851 char *src, *dst, *newname;
855 char adsrc[ MAXPATHLEN + 1];
859 * Note that this is only checking the existance of the data file,
860 * not the header file. The thinking is that if the data file doesn't
861 * exist, but the header file does, the right thing to do is remove
862 * the data file silently.
865 /* existence check moved to afp_moveandrename */
868 LOG(log_info, logtype_afpd, "begin renamefile:");
871 if ( rename( src, dst ) < 0 ) {
874 return( AFPERR_NOOBJ );
877 return( AFPERR_ACCESS );
880 case EXDEV : /* Cross device move -- try copy */
881 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
882 deletefile( dst, 0 );
885 return deletefile( src, 0);
887 return( AFPERR_PARAM );
891 strcpy( adsrc, ad_path( src, 0 ));
894 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
899 /* check for a source appledouble header. if it exists, make
900 * a dest appledouble directory and do the rename again. */
901 if (rc || stat(adsrc, &st) ||
902 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
905 ad_close(adp, ADFLAGS_HF);
909 return( AFPERR_ACCESS );
913 return( AFPERR_PARAM );
917 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
920 return( AFPERR_NOOBJ );
922 return( AFPERR_ACCESS );
926 return( AFPERR_PARAM );
930 len = strlen( newname );
931 ad_setentrylen( adp, ADEID_NAME, len );
932 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
933 ad_flush( adp, ADFLAGS_HF );
934 ad_close( adp, ADFLAGS_HF );
937 LOG(log_info, logtype_afpd, "end renamefile:");
943 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
946 int ibuflen, *rbuflen;
950 char *newname, *path, *p;
951 u_int32_t sdid, ddid;
952 int plen, err, retvalue = AFP_OK;
953 u_int16_t svid, dvid;
956 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
962 memcpy(&svid, ibuf, sizeof( svid ));
963 ibuf += sizeof( svid );
964 if (( vol = getvolbyvid( svid )) == NULL ) {
965 return( AFPERR_PARAM );
968 memcpy(&sdid, ibuf, sizeof( sdid ));
969 ibuf += sizeof( sdid );
970 if (( dir = dirsearch( vol, sdid )) == NULL ) {
971 return( AFPERR_PARAM );
974 memcpy(&dvid, ibuf, sizeof( dvid ));
975 ibuf += sizeof( dvid );
976 memcpy(&ddid, ibuf, sizeof( ddid ));
977 ibuf += sizeof( ddid );
979 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
980 return( AFPERR_NOOBJ );
982 if ( *path == '\0' ) {
983 return( AFPERR_BADTYPE );
986 /* don't allow copies when the file is open.
987 * XXX: the spec only calls for read/deny write access.
988 * however, copyfile doesn't have any of that info,
989 * and locks need to stay coherent. as a result,
990 * we just balk if the file is opened already. */
991 if (of_findname(vol, curdir, path))
992 return AFPERR_DENYCONF;
994 newname = obj->newtmp;
995 strcpy( newname, path );
997 p = ctoupath( vol, curdir, newname );
999 if (( vol = getvolbyvid( dvid )) == NULL ) {
1000 return( AFPERR_PARAM );
1003 if (vol->v_flags & AFPVOL_RO)
1004 return AFPERR_VLOCK;
1006 if (( dir = dirsearch( vol, ddid )) == NULL ) {
1007 return( AFPERR_PARAM );
1010 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1011 return( AFPERR_NOOBJ );
1013 if ( *path != '\0' ) {
1014 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1017 /* one of the handful of places that knows about the path type */
1018 if ( *ibuf++ != 2 ) {
1019 return( AFPERR_PARAM );
1021 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1022 strncpy( newname, ibuf, plen );
1023 newname[ plen ] = '\0';
1024 if (strlen(newname) != plen) {
1025 /* there's \0 in newname, e.g. it's a pathname not
1028 return( AFPERR_PARAM );
1032 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
1033 vol_noadouble(vol))) < 0 ) {
1037 setvoltime(obj, vol );
1040 if (vol->v_flags & AFPVOL_DROPBOX) {
1041 retvalue=matchfile2dirperms(newname, vol, sdid);
1043 #endif /* DROPKLUDGE */
1046 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1053 static __inline__ int copy_all(const int dfd, const void *buf,
1059 LOG(log_info, logtype_afpd, "begin copy_all:");
1062 while (buflen > 0) {
1063 if ((cc = write(dfd, buf, buflen)) < 0) {
1070 return AFPERR_DFULL;
1072 return AFPERR_VLOCK;
1074 return AFPERR_PARAM;
1081 LOG(log_info, logtype_afpd, "end copy_all:");
1087 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1088 * pass in vol and path */
1089 int copyfile(src, dst, newname, noadouble )
1090 char *src, *dst, *newname;
1091 const int noadouble;
1096 int sfd, dfd, len, err = AFP_OK;
1101 LOG(log_info, logtype_afpd, "begin copyfile:");
1104 dpath = ad_path( dst, ADFLAGS_HF );
1105 admode = ad_mode( dst, 0666 );
1107 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1110 break; /* just copy the data fork */
1112 return( AFPERR_ACCESS );
1114 return( AFPERR_PARAM );
1117 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1121 return( AFPERR_NOOBJ );
1123 return( AFPERR_ACCESS );
1125 return AFPERR_VLOCK;
1127 return( AFPERR_PARAM );
1132 #ifdef SENDFILE_FLAVOR_LINUX
1133 if (fstat(sfd, &st) == 0) {
1134 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1148 goto copyheader_done;
1150 #endif /* SENDFILE_FLAVOR_LINUX */
1152 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1159 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1173 /* data fork copying */
1174 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1177 return( AFPERR_NOOBJ );
1179 return( AFPERR_ACCESS );
1181 return( AFPERR_PARAM );
1185 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1189 return( AFPERR_NOOBJ );
1191 return( AFPERR_ACCESS );
1193 return AFPERR_VLOCK;
1195 return( AFPERR_PARAM );
1199 #ifdef SENDFILE_FLAVOR_LINUX
1200 if (fstat(sfd, &st) == 0) {
1201 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1214 #endif /* SENDFILE_FLAVOR_LINUX */
1217 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1225 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1240 memset(&ad, 0, sizeof(ad));
1241 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1245 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1247 return( AFPERR_ACCESS );
1249 return AFPERR_VLOCK;
1251 return( AFPERR_PARAM );
1255 len = strlen( newname );
1256 ad_setentrylen( &ad, ADEID_NAME, len );
1257 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1258 ad_flush( &ad, ADFLAGS_HF );
1259 ad_close( &ad, ADFLAGS_HF );
1263 LOG(log_info, logtype_afpd, "end copyfile:");
1270 /* -----------------------------------
1271 checkAttrib: 1 check kFPDeleteInhibitBit
1272 ie deletfile called by afp_delete
1274 when deletefile is called we don't have lock on it, file is closed (for us)
1275 untrue if called by renamefile
1277 int deletefile( file, checkAttrib )
1282 int adflags, err = AFP_OK;
1283 int locktype = ADLOCK_WR;
1284 int openmode = O_RDWR;
1287 LOG(log_info, logtype_afpd, "begin deletefile:");
1292 * If can't open read/write then try again read-only. If it's open
1293 * read-only, we must do a read lock instead of a write lock.
1295 /* try to open both at once */
1296 adflags = ADFLAGS_DF|ADFLAGS_HF;
1297 memset(&ad, 0, sizeof(ad));
1298 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1301 adflags = ADFLAGS_DF;
1302 /* that failed. now try to open just the data fork */
1303 memset(&ad, 0, sizeof(ad));
1304 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1307 return AFPERR_NOOBJ;
1309 if(openmode == O_RDWR) {
1310 openmode = O_RDONLY;
1311 locktype = ADLOCK_RD;
1314 return AFPERR_ACCESS;
1317 return AFPERR_VLOCK;
1319 return AFPERR_PARAM;
1325 if(openmode == O_RDWR) {
1326 openmode = O_RDONLY;
1327 locktype = ADLOCK_RD;
1330 return AFPERR_ACCESS;
1333 return AFPERR_VLOCK;
1335 return( AFPERR_PARAM );
1338 break; /* from the while */
1341 * Does kFPDeleteInhibitBit (bit 8) set?
1343 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1346 ad_getattr(&ad, &bshort);
1347 if ((bshort & htons(ATTRBIT_NODELETE))) {
1348 ad_close( &ad, adflags );
1349 return(AFPERR_OLOCK);
1353 if ((adflags & ADFLAGS_HF) ) {
1354 /* FIXME we have a pb here because we want to know if a file is open
1355 * there's a 'priority inversion' if you can't open the ressource fork RW
1356 * you can delete it if it's open because you can't get a write lock.
1358 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1361 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1363 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1364 ad_close( &ad, adflags );
1365 return( AFPERR_BUSY );
1369 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1374 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1378 err = AFPERR_ACCESS;
1391 if ( unlink( file ) < 0 ) {
1395 err = AFPERR_ACCESS;
1409 if (adflags & ADFLAGS_HF)
1410 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1411 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1412 ad_close( &ad, adflags );
1415 LOG(log_info, logtype_afpd, "end deletefile:");
1423 /* return a file id */
1424 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1427 int ibuflen, *rbuflen;
1439 LOG(log_info, logtype_afpd, "begin afp_createid:");
1445 memcpy(&vid, ibuf, sizeof(vid));
1446 ibuf += sizeof(vid);
1448 if (( vol = getvolbyvid( vid )) == NULL ) {
1449 return( AFPERR_PARAM);
1452 if (vol->v_flags & AFPVOL_RO)
1453 return AFPERR_VLOCK;
1455 memcpy(&did, ibuf, sizeof( did ));
1456 ibuf += sizeof(did);
1458 if (( dir = dirsearch( vol, did )) == NULL ) {
1459 return( AFPERR_PARAM );
1462 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1463 return( AFPERR_PARAM );
1466 if ( *path == '\0' ) {
1467 return( AFPERR_BADTYPE );
1470 upath = mtoupath(vol, path);
1471 if (stat(upath, &st) < 0) {
1475 return AFPERR_ACCESS;
1477 return AFPERR_NOOBJ;
1479 return AFPERR_PARAM;
1483 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1484 memcpy(rbuf, &id, sizeof(id));
1485 *rbuflen = sizeof(id);
1486 return AFPERR_EXISTID;
1489 #if AD_VERSION > AD_VERSION1
1490 memset(&ad, 0, sizeof(ad));
1491 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1492 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1493 ad_close(&ad, ADFLAGS_HF);
1495 #endif /* AD_VERSION > AD_VERSION1 */
1497 if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1498 memcpy(rbuf, &id, sizeof(id));
1499 *rbuflen = sizeof(id);
1504 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1509 return AFPERR_VLOCK;
1513 return AFPERR_ACCESS;
1516 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1517 return AFPERR_PARAM;
1521 /* resolve a file id */
1522 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1525 int ibuflen, *rbuflen;
1533 u_int16_t vid, bitmap;
1535 static char buffer[12 + MAXPATHLEN + 1];
1536 int len = 12 + MAXPATHLEN + 1;
1539 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1545 memcpy(&vid, ibuf, sizeof(vid));
1546 ibuf += sizeof(vid);
1548 if (( vol = getvolbyvid( vid )) == NULL ) {
1549 return( AFPERR_PARAM);
1552 memcpy(&id, ibuf, sizeof( id ));
1555 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1556 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1559 if (( dir = dirlookup( vol, id )) == NULL ) {
1560 return AFPERR_NOID; /* idem AFPERR_PARAM */
1563 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1567 return AFPERR_ACCESS;
1571 return AFPERR_PARAM;
1575 /* directories are bad */
1576 if (S_ISDIR(st.st_mode))
1577 return AFPERR_BADTYPE;
1579 memcpy(&bitmap, ibuf, sizeof(bitmap));
1580 bitmap = ntohs( bitmap );
1582 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1583 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1586 *rbuflen = buflen + sizeof(bitmap);
1587 memcpy(rbuf, ibuf, sizeof(bitmap));
1590 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1596 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1599 int ibuflen, *rbuflen;
1609 static char buffer[12 + MAXPATHLEN + 1];
1610 int len = 12 + MAXPATHLEN + 1;
1613 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1619 memcpy(&vid, ibuf, sizeof(vid));
1620 ibuf += sizeof(vid);
1622 if (( vol = getvolbyvid( vid )) == NULL ) {
1623 return( AFPERR_PARAM);
1626 if (vol->v_flags & AFPVOL_RO)
1627 return AFPERR_VLOCK;
1629 memcpy(&id, ibuf, sizeof( id ));
1633 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1637 if (( dir = dirlookup( vol, id )) == NULL ) {
1638 return( AFPERR_PARAM );
1642 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1646 return AFPERR_ACCESS;
1648 /* still try to delete the id */
1652 return AFPERR_PARAM;
1656 /* directories are bad */
1657 if (S_ISDIR(st.st_mode))
1658 return AFPERR_BADTYPE;
1660 if (cnid_delete(vol->v_db, fileid)) {
1663 return AFPERR_VLOCK;
1666 return AFPERR_ACCESS;
1668 return AFPERR_PARAM;
1673 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1678 #endif /* CNID_DB */
1680 #define APPLETEMP ".AppleTempXXXXXX"
1682 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1685 int ibuflen, *rbuflen;
1687 struct stat srcst, destst;
1689 struct dir *dir, *sdir;
1690 char *spath, temp[17], *path, *p;
1691 char *supath, *upath;
1695 struct adouble *adsp;
1696 struct adouble *addp;
1697 struct ofork *opened;
1701 #endif /* CNID_DB */
1706 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1712 memcpy(&vid, ibuf, sizeof(vid));
1713 ibuf += sizeof(vid);
1715 if (( vol = getvolbyvid( vid )) == NULL ) {
1716 return( AFPERR_PARAM);
1719 if (vol->v_flags & AFPVOL_RO)
1720 return AFPERR_VLOCK;
1722 /* source and destination dids */
1723 memcpy(&sid, ibuf, sizeof(sid));
1724 ibuf += sizeof(sid);
1725 memcpy(&did, ibuf, sizeof(did));
1726 ibuf += sizeof(did);
1729 if ((dir = dirsearch( vol, sid )) == NULL ) {
1730 return( AFPERR_PARAM );
1733 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1734 return( AFPERR_PARAM );
1737 if ( *path == '\0' ) {
1738 return( AFPERR_BADTYPE ); /* it's a dir */
1741 upath = mtoupath(vol, path);
1742 if (stat(upath, &srcst) < 0) {
1748 return AFPERR_ACCESS;
1750 return AFPERR_PARAM;
1753 memset(&ads, 0, sizeof(ads));
1755 if ((opened = of_findname(vol, curdir, path))) {
1756 /* reuse struct adouble so it won't break locks */
1757 adsp = opened->of_ad;
1759 /* save some stuff */
1761 spath = obj->oldtmp;
1762 supath = obj->newtmp;
1763 strcpy(spath, path);
1764 strcpy(supath, upath); /* this is for the cnid changing */
1765 p = ctoupath( vol, sdir, spath);
1767 /* look for the source cnid. if it doesn't exist, don't worry about
1770 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1771 slen = strlen(supath));
1772 #endif /* CNID_DB */
1774 if (( dir = dirsearch( vol, did )) == NULL ) {
1775 return( AFPERR_PARAM );
1778 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1779 return( AFPERR_PARAM );
1782 if ( *path == '\0' ) {
1783 return( AFPERR_BADTYPE );
1786 /* FPExchangeFiles is the only call that can return the SameObj
1788 if ((curdir == sdir) && strcmp(spath, path) == 0)
1789 return AFPERR_SAMEOBJ;
1791 upath = mtoupath(vol, path);
1792 if (stat(upath, &destst) < 0) {
1798 return AFPERR_ACCESS;
1800 return AFPERR_PARAM;
1803 memset(&add, 0, sizeof(add));
1805 if ((opened = of_findname(vol, curdir, path))) {
1806 /* reuse struct adouble so it won't break locks */
1807 addp = opened->of_ad;
1810 /* look for destination id. */
1811 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1812 dlen = strlen(upath));
1813 #endif /* CNID_DB */
1815 /* construct a temp name.
1816 * NOTE: the temp file will be in the dest file's directory. it
1817 * will also be inaccessible from AFP. */
1818 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1822 /* now, quickly rename the file. we error if we can't. */
1823 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1824 goto err_exchangefile;
1825 of_rename(vol, sdir, spath, curdir, temp);
1827 /* rename destination to source */
1828 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1829 goto err_src_to_tmp;
1830 of_rename(vol, curdir, path, sdir, spath);
1832 /* rename temp to destination */
1833 if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1834 goto err_dest_to_src;
1835 of_rename(vol, curdir, temp, curdir, path);
1838 /* id's need switching. src -> dest and dest -> src. */
1839 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1840 upath, dlen) < 0)) {
1844 err = AFPERR_ACCESS;
1849 goto err_temp_to_dest;
1852 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1853 supath, slen) < 0)) {
1857 err = AFPERR_ACCESS;
1864 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1865 goto err_temp_to_dest;
1867 #endif /* CNID_DB */
1870 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1876 /* all this stuff is so that we can unwind a failed operation
1881 /* rename dest to temp */
1882 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1883 of_rename(vol, curdir, upath, curdir, temp);
1886 /* rename source back to dest */
1887 renamefile(p, upath, path, vol_noadouble(vol), addp);
1888 of_rename(vol, sdir, spath, curdir, path);
1891 /* rename temp back to source */
1892 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1893 of_rename(vol, curdir, temp, sdir, spath);