2 * $Id: file.c,v 1.65 2002-10-13 06:18:13 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 );
363 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
365 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
369 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
373 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
377 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
381 else if ( fdType[0] == 'p' ) {
383 ashort = (fdType[2] * 256) + fdType[3];
397 memcpy(data, &ashort, sizeof( ashort ));
398 data += sizeof( ashort );
399 memset(data, 0, sizeof( ashort ));
400 data += sizeof( ashort );
403 case FILPBIT_EXTDFLEN:
404 aint = htonl(st->st_size >> 32);
405 memcpy(data, &aint, sizeof( aint ));
406 data += sizeof( aint );
407 aint = htonl(st->st_size);
408 memcpy(data, &aint, sizeof( aint ));
409 data += sizeof( aint );
411 case FILPBIT_EXTRFLEN:
414 aint = htonl(adp->ad_rlen >> 32);
415 memcpy(data, &aint, sizeof( aint ));
416 data += sizeof( aint );
418 aint = htonl(adp->ad_rlen);
419 memcpy(data, &aint, sizeof( aint ));
420 data += sizeof( aint );
423 return( AFPERR_BITMAP );
429 ashort = htons( data - buf );
430 memcpy(nameoff, &ashort, sizeof( ashort ));
431 data = set_name(data, path, utf8);
433 *buflen = data - buf;
437 /* ----------------------- */
438 int getfilparams(struct vol *vol,
440 struct path *path, struct dir *dir,
441 char *buf, int *buflen )
443 struct adouble ad, *adp;
446 u_int16_t attrbits = 0;
451 LOG(log_info, logtype_default, "begin getfilparams:");
454 opened = PARAM_NEED_ADP(bitmap);
457 upath = path->u_name;
458 if ((of = of_findname(path))) {
460 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
461 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
463 memset(&ad, 0, sizeof(ad));
467 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
472 we need to check if the file is open by another process.
473 it's slow so we only do it if we have to:
474 - bitmap is requested.
475 - we don't already have the answer!
477 if ((bitmap & (1 << FILPBIT_ATTR))) {
478 if (!(attrbits & ATTRBIT_ROPEN)) {
480 if (!(attrbits & ATTRBIT_DOPEN)) {
485 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
487 ad_close( adp, ADFLAGS_HF );
490 LOG(log_info, logtype_afpd, "end getfilparams:");
496 /* ----------------------------- */
497 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
500 int ibuflen, *rbuflen;
503 struct adouble ad, *adp;
506 struct ofork *of = NULL;
508 int creatf, did, openf, retvalue = AFP_OK;
514 LOG(log_info, logtype_afpd, "begin afp_createfile:");
519 creatf = (unsigned char) *ibuf++;
521 memcpy(&vid, ibuf, sizeof( vid ));
522 ibuf += sizeof( vid );
524 if (( vol = getvolbyvid( vid )) == NULL ) {
525 return( AFPERR_PARAM );
528 if (vol->v_flags & AFPVOL_RO)
531 memcpy(&did, ibuf, sizeof( did));
532 ibuf += sizeof( did );
534 if (( dir = dirlookup( vol, did )) == NULL ) {
535 return( AFPERR_NOOBJ );
538 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
539 return( AFPERR_NOOBJ );
542 if ( *s_path->m_name == '\0' ) {
543 return( AFPERR_BADTYPE );
546 upath = s_path->u_name;
547 if (0 != (ret = check_name(vol, upath)))
550 /* if upath is deleted we already in trouble anyway */
551 if ((of = of_findname(s_path))) {
554 memset(&ad, 0, sizeof(ad));
558 /* on a hard create, fail if file exists and is open */
561 openf = O_RDWR|O_CREAT|O_TRUNC;
563 /* on a soft create, if the file is open then ad_open won't fail
564 because open syscall is not called
569 openf = O_RDWR|O_CREAT|O_EXCL;
572 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
573 openf, 0666, adp) < 0 ) {
576 return( AFPERR_EXIST );
578 return( AFPERR_ACCESS );
580 /* on noadouble volumes, just creating the data fork is ok */
582 if (vol_noadouble(vol) && (stat(upath, st) == 0))
583 goto createfile_done;
586 return( AFPERR_PARAM );
589 path = s_path->m_name;
590 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
591 memcpy(ad_entry( adp, ADEID_NAME ), path,
592 ad_getentrylen( adp, ADEID_NAME ));
593 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
594 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
599 if (vol->v_flags & AFPVOL_DROPBOX) {
600 retvalue = matchfile2dirperms(upath, vol, did);
602 #endif /* DROPKLUDGE */
604 setvoltime(obj, vol );
607 LOG(log_info, logtype_afpd, "end afp_createfile");
613 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
616 int ibuflen, *rbuflen;
622 u_int16_t vid, bitmap;
625 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
631 memcpy(&vid, ibuf, sizeof( vid ));
632 ibuf += sizeof( vid );
633 if (( vol = getvolbyvid( vid )) == NULL ) {
634 return( AFPERR_PARAM );
637 if (vol->v_flags & AFPVOL_RO)
640 memcpy(&did, ibuf, sizeof( did ));
641 ibuf += sizeof( did );
642 if (( dir = dirlookup( vol, did )) == NULL ) {
643 return( AFPERR_NOOBJ );
646 memcpy(&bitmap, ibuf, sizeof( bitmap ));
647 bitmap = ntohs( bitmap );
648 ibuf += sizeof( bitmap );
650 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
651 return( AFPERR_NOOBJ );
654 if ( *s_path->m_name == '\0' ) {
655 return( AFPERR_BADTYPE ); /* it's a directory */
658 if ((u_long)ibuf & 1 ) {
662 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
663 setvoltime(obj, vol );
667 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
674 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
677 extern struct path Cur_Path;
679 int setfilparams(struct vol *vol,
680 struct path *path, u_int16_t bitmap, char *buf )
682 struct adouble ad, *adp;
685 int bit = 0, isad = 1, err = AFP_OK;
687 u_char achar, *fdType, xyy[4];
688 u_int16_t ashort, bshort;
692 int change_mdate = 0;
693 int change_parent_mdate = 0;
699 LOG(log_info, logtype_afpd, "begin setfilparams:");
702 upath = path->u_name;
703 if ((of = of_findname(path))) {
706 memset(&ad, 0, sizeof(ad));
710 if (check_access(upath, OPENACC_WR ) < 0) {
711 return AFPERR_ACCESS;
714 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
715 O_RDWR|O_CREAT, 0666, adp) < 0) {
716 /* for some things, we don't need an adouble header */
717 if (bitmap & ~(1<<FILPBIT_MDATE)) {
718 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
721 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
722 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
723 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
724 ad_getentrylen( adp, ADEID_NAME ));
727 while ( bitmap != 0 ) {
728 while (( bitmap & 1 ) == 0 ) {
736 memcpy(&ashort, buf, sizeof( ashort ));
737 ad_getattr(adp, &bshort);
738 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
739 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
743 if ((ashort & htons(ATTRBIT_INVISIBLE)))
744 change_parent_mdate = 1;
745 ad_setattr(adp, bshort);
746 buf += sizeof( ashort );
751 memcpy(&aint, buf, sizeof(aint));
752 ad_setdate(adp, AD_DATE_CREATE, aint);
753 buf += sizeof( aint );
757 memcpy(&newdate, buf, sizeof( newdate ));
758 buf += sizeof( newdate );
763 memcpy(&aint, buf, sizeof(aint));
764 ad_setdate(adp, AD_DATE_BACKUP, aint);
765 buf += sizeof( aint );
771 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
773 ((em = getextmap( path->m_name )) &&
774 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
775 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
776 || ((em = getdefextmap()) &&
777 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
778 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
780 memcpy(buf, ufinderi, 8 );
783 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
787 /* Client needs to set the ProDOS file info for this file.
788 Use defined strings for the simple cases, and convert
789 all else into pXYY per Inside Appletalk. Always set
790 the creator as "pdos". <shirsch@ibm.net> */
791 case FILPBIT_PDINFO :
794 memcpy(&ashort, buf, sizeof( ashort ));
795 ashort = ntohs( ashort );
798 switch ( (unsigned int) achar )
801 fdType = ( u_char *) "TEXT";
805 fdType = ( u_char *) "PSYS";
809 fdType = ( u_char *) "PS16";
813 fdType = ( u_char *) "BINA";
817 xyy[0] = ( u_char ) 'p';
819 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
820 xyy[3] = ( u_char ) ashort & 0xff;
825 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
826 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
832 goto setfilparam_done;
840 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
841 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
845 ad_setdate(adp, AD_DATE_MODIFY, newdate);
846 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
851 ad_flush( adp, ADFLAGS_HF );
852 ad_close( adp, ADFLAGS_HF );
856 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
857 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
858 bitmap = 1<<FILPBIT_MDATE;
859 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
863 LOG(log_info, logtype_afpd, "end setfilparams:");
869 * renamefile and copyfile take the old and new unix pathnames
870 * and the new mac name.
871 * NOTE: if we have to copy a file instead of renaming it, locks
872 * will break. Anyway it's an error because then we have 2 files.
874 * src the source path
875 * dst the dest filename in current dir
876 * newname the dest mac name
877 * adp adouble struct of src file, if open, or & zeroed one
880 int renamefile(src, dst, newname, noadouble, adp )
881 char *src, *dst, *newname;
885 char adsrc[ MAXPATHLEN + 1];
889 * Note that this is only checking the existance of the data file,
890 * not the header file. The thinking is that if the data file doesn't
891 * exist, but the header file does, the right thing to do is remove
892 * the data file silently.
895 /* existence check moved to afp_moveandrename */
898 LOG(log_info, logtype_afpd, "begin renamefile:");
901 if ( rename( src, dst ) < 0 ) {
904 return( AFPERR_NOOBJ );
907 return( AFPERR_ACCESS );
910 case EXDEV : /* Cross device move -- try copy */
911 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
912 deletefile( dst, 0 );
915 return deletefile( src, 0);
917 return( AFPERR_PARAM );
921 strcpy( adsrc, ad_path( src, 0 ));
924 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
929 /* check for a source appledouble header. if it exists, make
930 * a dest appledouble directory and do the rename again. */
931 if (rc || stat(adsrc, &st) ||
932 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
935 ad_close(adp, ADFLAGS_HF);
939 return( AFPERR_ACCESS );
943 return( AFPERR_PARAM );
947 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
950 return( AFPERR_NOOBJ );
952 return( AFPERR_ACCESS );
956 return( AFPERR_PARAM );
960 len = strlen( newname );
961 ad_setentrylen( adp, ADEID_NAME, len );
962 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
963 ad_flush( adp, ADFLAGS_HF );
964 ad_close( adp, ADFLAGS_HF );
967 LOG(log_info, logtype_afpd, "end renamefile:");
973 int copy_path_name(char *newname, char *ibuf)
980 if ( type != 2 || (afp_version >= 30 && type != 3) ) {
986 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
987 strncpy( newname, ibuf, plen );
988 newname[ plen ] = '\0';
989 if (strlen(newname) != plen) {
990 /* there's \0 in newname, e.g. it's a pathname not
998 memcpy(&hint, ibuf, sizeof(hint));
999 ibuf += sizeof(hint);
1001 memcpy(&len16, ibuf, sizeof(len16));
1002 ibuf += sizeof(len16);
1003 plen = ntohs(len16);
1005 strncpy( newname, ibuf, plen );
1006 newname[ plen ] = '\0';
1007 if (strchr(newname,'/')) {
1016 /* -----------------------------------
1018 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1021 int ibuflen, *rbuflen;
1025 char *newname, *p, *upath;
1026 struct path *s_path;
1027 u_int32_t sdid, ddid;
1028 int err, retvalue = AFP_OK;
1029 u_int16_t svid, dvid;
1032 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1038 memcpy(&svid, ibuf, sizeof( svid ));
1039 ibuf += sizeof( svid );
1040 if (( vol = getvolbyvid( svid )) == NULL ) {
1041 return( AFPERR_PARAM );
1044 memcpy(&sdid, ibuf, sizeof( sdid ));
1045 ibuf += sizeof( sdid );
1046 if (( dir = dirlookup( vol, sdid )) == NULL ) {
1047 return( AFPERR_PARAM );
1050 memcpy(&dvid, ibuf, sizeof( dvid ));
1051 ibuf += sizeof( dvid );
1052 memcpy(&ddid, ibuf, sizeof( ddid ));
1053 ibuf += sizeof( ddid );
1055 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1056 return( AFPERR_NOOBJ );
1058 if ( *s_path->m_name == '\0' ) {
1059 return( AFPERR_BADTYPE );
1062 /* don't allow copies when the file is open.
1063 * XXX: the spec only calls for read/deny write access.
1064 * however, copyfile doesn't have any of that info,
1065 * and locks need to stay coherent. as a result,
1066 * we just balk if the file is opened already. */
1068 newname = obj->newtmp;
1069 strcpy( newname, s_path->m_name );
1071 if (of_findname(s_path))
1072 return AFPERR_DENYCONF;
1074 p = ctoupath( vol, curdir, newname );
1076 /* FIXME svid != dvid && dvid's user can't read svid */
1078 if (( vol = getvolbyvid( dvid )) == NULL ) {
1079 return( AFPERR_PARAM );
1082 if (vol->v_flags & AFPVOL_RO)
1083 return AFPERR_VLOCK;
1085 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1086 return( AFPERR_PARAM );
1089 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1090 return( AFPERR_NOOBJ );
1092 if ( *s_path->m_name != '\0' ) {
1093 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1096 /* one of the handful of places that knows about the path type */
1097 if (copy_path_name(newname, ibuf) < 0) {
1098 return( AFPERR_PARAM );
1101 upath = mtoupath(vol, newname);
1102 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1107 if (vol->v_flags & AFPVOL_DROPBOX) {
1108 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1110 #endif /* DROPKLUDGE */
1112 setvoltime(obj, vol );
1115 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1122 static __inline__ int copy_all(const int dfd, const void *buf,
1128 LOG(log_info, logtype_afpd, "begin copy_all:");
1131 while (buflen > 0) {
1132 if ((cc = write(dfd, buf, buflen)) < 0) {
1139 return AFPERR_DFULL;
1141 return AFPERR_VLOCK;
1143 return AFPERR_PARAM;
1150 LOG(log_info, logtype_afpd, "end copy_all:");
1156 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1157 * pass in vol and path */
1158 int copyfile(src, dst, newname, noadouble )
1159 char *src, *dst, *newname;
1160 const int noadouble;
1163 #ifdef SENDFILE_FLAVOR_LINUX
1167 int sfd, dfd, len, err = AFP_OK;
1169 char dpath[ MAXPATHLEN + 1];
1172 LOG(log_info, logtype_afpd, "begin copyfile:");
1175 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1176 admode = ad_mode( dst, 0666 );
1178 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1181 break; /* just copy the data fork */
1183 return( AFPERR_ACCESS );
1185 return( AFPERR_PARAM );
1188 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1192 return( AFPERR_NOOBJ );
1194 return( AFPERR_ACCESS );
1196 return AFPERR_VLOCK;
1198 return( AFPERR_PARAM );
1203 #ifdef SENDFILE_FLAVOR_LINUX
1204 if (fstat(sfd, &st) == 0) {
1205 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1219 goto copyheader_done;
1221 #endif /* SENDFILE_FLAVOR_LINUX */
1223 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1230 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1244 /* data fork copying */
1245 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1248 return( AFPERR_NOOBJ );
1250 return( AFPERR_ACCESS );
1252 return( AFPERR_PARAM );
1256 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1260 return( AFPERR_NOOBJ );
1262 return( AFPERR_ACCESS );
1264 return AFPERR_VLOCK;
1266 return( AFPERR_PARAM );
1270 #ifdef SENDFILE_FLAVOR_LINUX
1271 if (fstat(sfd, &st) == 0) {
1272 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1285 #endif /* SENDFILE_FLAVOR_LINUX */
1288 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1296 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1311 memset(&ad, 0, sizeof(ad));
1312 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1316 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1318 return( AFPERR_ACCESS );
1320 return AFPERR_VLOCK;
1322 return( AFPERR_PARAM );
1326 len = strlen( newname );
1327 ad_setentrylen( &ad, ADEID_NAME, len );
1328 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1329 ad_flush( &ad, ADFLAGS_HF );
1330 ad_close( &ad, ADFLAGS_HF );
1334 LOG(log_info, logtype_afpd, "end copyfile:");
1341 /* -----------------------------------
1342 checkAttrib: 1 check kFPDeleteInhibitBit
1343 ie deletfile called by afp_delete
1345 when deletefile is called we don't have lock on it, file is closed (for us)
1346 untrue if called by renamefile
1348 int deletefile( file, checkAttrib )
1353 int adflags, err = AFP_OK;
1354 int locktype = ADLOCK_WR;
1355 int openmode = O_RDWR;
1358 LOG(log_info, logtype_afpd, "begin deletefile:");
1363 * If can't open read/write then try again read-only. If it's open
1364 * read-only, we must do a read lock instead of a write lock.
1366 /* try to open both at once */
1367 adflags = ADFLAGS_DF|ADFLAGS_HF;
1368 memset(&ad, 0, sizeof(ad));
1369 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1372 adflags = ADFLAGS_DF;
1373 /* that failed. now try to open just the data fork */
1374 memset(&ad, 0, sizeof(ad));
1375 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1378 return AFPERR_NOOBJ;
1380 if(openmode == O_RDWR) {
1381 openmode = O_RDONLY;
1382 locktype = ADLOCK_RD;
1385 return AFPERR_ACCESS;
1388 return AFPERR_VLOCK;
1390 return AFPERR_PARAM;
1396 if(openmode == O_RDWR) {
1397 openmode = O_RDONLY;
1398 locktype = ADLOCK_RD;
1401 return AFPERR_ACCESS;
1404 return AFPERR_VLOCK;
1406 return( AFPERR_PARAM );
1409 break; /* from the while */
1412 * Does kFPDeleteInhibitBit (bit 8) set?
1414 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1417 ad_getattr(&ad, &bshort);
1418 if ((bshort & htons(ATTRBIT_NODELETE))) {
1419 ad_close( &ad, adflags );
1420 return(AFPERR_OLOCK);
1424 if ((adflags & ADFLAGS_HF) ) {
1425 /* FIXME we have a pb here because we want to know if a file is open
1426 * there's a 'priority inversion' if you can't open the ressource fork RW
1427 * you can delete it if it's open because you can't get a write lock.
1429 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1432 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1434 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1435 ad_close( &ad, adflags );
1436 return( AFPERR_BUSY );
1440 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1445 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1449 err = AFPERR_ACCESS;
1462 if ( unlink( file ) < 0 ) {
1466 err = AFPERR_ACCESS;
1480 if (adflags & ADFLAGS_HF)
1481 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1482 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1483 ad_close( &ad, adflags );
1486 LOG(log_info, logtype_afpd, "end deletefile:");
1492 /* ------------------------------------ */
1494 /* return a file id */
1495 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1498 int ibuflen, *rbuflen;
1501 #if AD_VERSION > AD_VERSION1
1510 struct path *s_path;
1513 LOG(log_info, logtype_afpd, "begin afp_createid:");
1519 memcpy(&vid, ibuf, sizeof(vid));
1520 ibuf += sizeof(vid);
1522 if (( vol = getvolbyvid( vid )) == NULL ) {
1523 return( AFPERR_PARAM);
1526 if (vol->v_flags & AFPVOL_RO)
1527 return AFPERR_VLOCK;
1529 memcpy(&did, ibuf, sizeof( did ));
1530 ibuf += sizeof(did);
1532 if (( dir = dirlookup( vol, did )) == NULL ) {
1533 return( AFPERR_PARAM );
1536 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1537 return( AFPERR_PARAM );
1540 if ( *s_path->m_name == '\0' ) {
1541 return( AFPERR_BADTYPE );
1544 upath = s_path->u_name;
1545 switch (s_path->st_errno) {
1547 break; /* success */
1550 return AFPERR_ACCESS;
1552 return AFPERR_NOOBJ;
1554 return AFPERR_PARAM;
1557 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1558 memcpy(rbuf, &id, sizeof(id));
1559 *rbuflen = sizeof(id);
1560 return AFPERR_EXISTID;
1563 #if AD_VERSION > AD_VERSION1
1564 memset(&ad, 0, sizeof(ad));
1565 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1566 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1567 ad_close(&ad, ADFLAGS_HF);
1569 #endif /* AD_VERSION > AD_VERSION1 */
1571 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1572 memcpy(rbuf, &id, sizeof(id));
1573 *rbuflen = sizeof(id);
1578 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1583 return AFPERR_VLOCK;
1587 return AFPERR_ACCESS;
1590 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1591 return AFPERR_PARAM;
1595 /* ------------------------------
1596 resolve a file id */
1597 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1600 int ibuflen, *rbuflen;
1608 u_int16_t vid, bitmap;
1610 static char buffer[12 + MAXPATHLEN + 1];
1611 int len = 12 + MAXPATHLEN + 1;
1614 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1620 memcpy(&vid, ibuf, sizeof(vid));
1621 ibuf += sizeof(vid);
1623 if (( vol = getvolbyvid( vid )) == NULL ) {
1624 return( AFPERR_PARAM);
1627 memcpy(&id, ibuf, sizeof( id ));
1630 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1631 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1634 if (( dir = dirlookup( vol, id )) == NULL ) {
1635 return AFPERR_NOID; /* idem AFPERR_PARAM */
1637 path.u_name = upath;
1638 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1642 return AFPERR_ACCESS;
1646 return AFPERR_PARAM;
1649 /* directories are bad */
1650 if (S_ISDIR(path.st.st_mode))
1651 return AFPERR_BADTYPE;
1653 memcpy(&bitmap, ibuf, sizeof(bitmap));
1654 bitmap = ntohs( bitmap );
1655 path.m_name = utompath(vol, upath);
1656 if ((err = getfilparams(vol, bitmap, &path , curdir,
1657 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1660 *rbuflen = buflen + sizeof(bitmap);
1661 memcpy(rbuf, ibuf, sizeof(bitmap));
1664 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1670 /* ------------------------------ */
1671 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1674 int ibuflen, *rbuflen;
1684 static char buffer[12 + MAXPATHLEN + 1];
1685 int len = 12 + MAXPATHLEN + 1;
1688 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1694 memcpy(&vid, ibuf, sizeof(vid));
1695 ibuf += sizeof(vid);
1697 if (( vol = getvolbyvid( vid )) == NULL ) {
1698 return( AFPERR_PARAM);
1701 if (vol->v_flags & AFPVOL_RO)
1702 return AFPERR_VLOCK;
1704 memcpy(&id, ibuf, sizeof( id ));
1708 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1712 if (( dir = dirlookup( vol, id )) == NULL ) {
1713 return( AFPERR_PARAM );
1717 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1721 return AFPERR_ACCESS;
1723 /* still try to delete the id */
1727 return AFPERR_PARAM;
1731 /* directories are bad */
1732 if (S_ISDIR(st.st_mode))
1733 return AFPERR_BADTYPE;
1735 if (cnid_delete(vol->v_db, fileid)) {
1738 return AFPERR_VLOCK;
1741 return AFPERR_ACCESS;
1743 return AFPERR_PARAM;
1748 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1753 #endif /* CNID_DB */
1755 #define APPLETEMP ".AppleTempXXXXXX"
1757 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1760 int ibuflen, *rbuflen;
1762 struct stat srcst, destst;
1764 struct dir *dir, *sdir;
1765 char *spath, temp[17], *p;
1766 char *supath, *upath;
1771 struct adouble *adsp;
1772 struct adouble *addp;
1778 #endif /* CNID_DB */
1783 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1789 memcpy(&vid, ibuf, sizeof(vid));
1790 ibuf += sizeof(vid);
1792 if (( vol = getvolbyvid( vid )) == NULL ) {
1793 return( AFPERR_PARAM);
1796 if (vol->v_flags & AFPVOL_RO)
1797 return AFPERR_VLOCK;
1799 /* source and destination dids */
1800 memcpy(&sid, ibuf, sizeof(sid));
1801 ibuf += sizeof(sid);
1802 memcpy(&did, ibuf, sizeof(did));
1803 ibuf += sizeof(did);
1806 if ((dir = dirlookup( vol, sid )) == NULL ) {
1807 return( AFPERR_PARAM );
1810 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1811 return( AFPERR_PARAM );
1814 if ( *path->m_name == '\0' ) {
1815 return( AFPERR_BADTYPE ); /* it's a dir */
1818 upath = path->u_name;
1819 switch (path->st_errno) {
1826 return AFPERR_ACCESS;
1828 return AFPERR_PARAM;
1830 memset(&ads, 0, sizeof(ads));
1832 if ((s_of = of_findname(path))) {
1833 /* reuse struct adouble so it won't break locks */
1836 memcpy(&srcst, &path->st, sizeof(struct stat));
1837 /* save some stuff */
1839 spath = obj->oldtmp;
1840 supath = obj->newtmp;
1841 strcpy(spath, path->m_name);
1842 strcpy(supath, upath); /* this is for the cnid changing */
1843 p = absupath( vol, sdir, upath);
1845 /* look for the source cnid. if it doesn't exist, don't worry about
1848 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1849 slen = strlen(supath));
1850 #endif /* CNID_DB */
1852 if (( dir = dirlookup( vol, did )) == NULL ) {
1853 return( AFPERR_PARAM );
1856 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1857 return( AFPERR_PARAM );
1860 if ( *path->m_name == '\0' ) {
1861 return( AFPERR_BADTYPE );
1864 /* FPExchangeFiles is the only call that can return the SameObj
1866 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1867 return AFPERR_SAMEOBJ;
1868 memcpy(&srcst, &path->st, sizeof(struct stat));
1877 return AFPERR_ACCESS;
1879 return AFPERR_PARAM;
1881 memset(&add, 0, sizeof(add));
1883 if ((d_of = of_findname( path))) {
1884 /* reuse struct adouble so it won't break locks */
1887 memcpy(&destst, &path->st, sizeof(struct stat));
1889 /* they are not on the same device and at least one is open
1891 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1894 upath = path->u_name;
1896 /* look for destination id. */
1897 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1898 dlen = strlen(upath));
1899 #endif /* CNID_DB */
1901 /* construct a temp name.
1902 * NOTE: the temp file will be in the dest file's directory. it
1903 * will also be inaccessible from AFP. */
1904 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1908 /* now, quickly rename the file. we error if we can't. */
1909 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1910 goto err_exchangefile;
1911 of_rename(vol, s_of, sdir, spath, curdir, temp);
1913 /* rename destination to source */
1914 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1915 goto err_src_to_tmp;
1916 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1918 /* rename temp to destination */
1919 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1920 goto err_dest_to_src;
1921 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1924 /* id's need switching. src -> dest and dest -> src. */
1925 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1926 upath, dlen) < 0)) {
1930 err = AFPERR_ACCESS;
1935 goto err_temp_to_dest;
1938 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1939 supath, slen) < 0)) {
1943 err = AFPERR_ACCESS;
1950 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1951 goto err_temp_to_dest;
1953 #endif /* CNID_DB */
1956 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1962 /* all this stuff is so that we can unwind a failed operation
1967 /* rename dest to temp */
1968 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1969 of_rename(vol, s_of, curdir, upath, curdir, temp);
1972 /* rename source back to dest */
1973 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1974 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1977 /* rename temp back to source */
1978 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1979 of_rename(vol, s_of, curdir, temp, sdir, spath);