2 * $Id: file.c,v 1.69 2003-01-07 15:55:21 rlewczuk 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, *l_nameoff = NULL, *upath;
164 char *utf_nameoff = NULL;
168 u_char achar, fdType[4];
172 LOG(log_info, logtype_afpd, "begin getmetadata:");
175 upath = mtoupath(vol, path);
178 while ( bitmap != 0 ) {
179 while (( bitmap & 1 ) == 0 ) {
187 ad_getattr(adp, &ashort);
188 } else if (*upath == '.') {
189 ashort = htons(ATTRBIT_INVISIBLE);
193 /* FIXME do we want a visual clue if the file is read only
196 accessmode( ".", &ma, dir , NULL);
197 if ((ma.ma_user & AR_UWRITE)) {
198 accessmode( upath, &ma, dir , st);
199 if (!(ma.ma_user & AR_UWRITE)) {
200 attrbits |= ATTRBIT_NOWRITE;
205 ashort = htons(ntohs(ashort) | attrbits);
206 memcpy(data, &ashort, sizeof( ashort ));
207 data += sizeof( ashort );
211 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
212 data += sizeof( u_int32_t );
216 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
217 aint = AD_DATE_FROM_UNIX(st->st_mtime);
218 memcpy(data, &aint, sizeof( aint ));
219 data += sizeof( aint );
223 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
224 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
225 aint = AD_DATE_FROM_UNIX(st->st_mtime);
228 aint = AD_DATE_FROM_UNIX(st->st_mtime);
230 memcpy(data, &aint, sizeof( int ));
231 data += sizeof( int );
235 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
236 aint = AD_DATE_START;
237 memcpy(data, &aint, sizeof( int ));
238 data += sizeof( int );
242 get_finderinfo(path, adp, (char *)data);
244 if (*upath == '.') { /* make it invisible */
245 ashort = htons(FINDERINFO_INVISIBLE);
246 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
255 data += sizeof( u_int16_t );
259 memset(data, 0, sizeof(u_int16_t));
260 data += sizeof( u_int16_t );
265 #if AD_VERSION > AD_VERSION1
266 /* look in AD v2 header */
268 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
269 #endif /* AD_VERSION > AD_VERSION1 */
272 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
273 strlen(upath), aint);
274 /* Throw errors if cnid_add fails. */
275 if (aint == CNID_INVALID) {
278 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
279 return(AFPERR_PARAM);
281 return(AFPERR_PARAM);
291 * What a fucking mess. First thing: DID and FNUMs are
292 * in the same space for purposes of enumerate (and several
293 * other wierd places). While we consider this Apple's bug,
294 * this is the work-around: In order to maintain constant and
295 * unique DIDs and FNUMs, we monotonically generate the DIDs
296 * during the session, and derive the FNUMs from the filesystem.
297 * Since the DIDs are small, we insure that the FNUMs are fairly
298 * large by setting thier high bits to the device number.
300 * AFS already does something very similar to this for the
301 * inode number, so we don't repeat the procedure.
304 * due to complaints over did's being non-persistent,
305 * here's the current hack to provide semi-persistent
307 * 1) we reserve the first bit for file ids.
308 * 2) the next 7 bits are for the device.
309 * 3) the remaining 24 bits are for the inode.
311 * both the inode and device information are actually hashes
312 * that are then truncated to the requisite bit length.
314 * it should be okay to use lstat to deal with symlinks.
317 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
318 #else /* USE_LASTDID */
319 lstp = lstat(upath, &lst) < 0 ? st : &lst;
320 aint = htonl(CNID(lstp, 1));
321 #endif /* USE_LASTDID */
324 memcpy(data, &aint, sizeof( aint ));
325 data += sizeof( aint );
329 if (st->st_size > 0xffffffff)
332 aint = htonl( st->st_size );
333 memcpy(data, &aint, sizeof( aint ));
334 data += sizeof( aint );
339 if (adp->ad_rlen > 0xffffffff)
342 aint = htonl( adp->ad_rlen);
346 memcpy(data, &aint, sizeof( aint ));
347 data += sizeof( aint );
350 /* Current client needs ProDOS info block for this file.
351 Use simple heuristic and let the Mac "type" string tell
352 us what the PD file code should be. Everything gets a
353 subtype of 0x0000 unless the original value was hashed
354 to "pXYZ" when we created it. See IA, Ver 2.
356 case FILPBIT_PDINFO :
357 if (afp_version >= 30) { /* UTF8 name */
358 utf8 = kTextEncodingUTF8;
360 data += sizeof( u_int16_t );
362 memcpy(data, &aint, sizeof( aint ));
363 data += sizeof( aint );
367 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
369 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
373 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
377 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
381 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
385 else if ( fdType[0] == 'p' ) {
387 ashort = (fdType[2] * 256) + fdType[3];
401 memcpy(data, &ashort, sizeof( ashort ));
402 data += sizeof( ashort );
403 memset(data, 0, sizeof( ashort ));
404 data += sizeof( ashort );
407 case FILPBIT_EXTDFLEN:
408 aint = htonl(st->st_size >> 32);
409 memcpy(data, &aint, sizeof( aint ));
410 data += sizeof( aint );
411 aint = htonl(st->st_size);
412 memcpy(data, &aint, sizeof( aint ));
413 data += sizeof( aint );
415 case FILPBIT_EXTRFLEN:
418 aint = htonl(adp->ad_rlen >> 32);
419 memcpy(data, &aint, sizeof( aint ));
420 data += sizeof( aint );
422 aint = htonl(adp->ad_rlen);
423 memcpy(data, &aint, sizeof( aint ));
424 data += sizeof( aint );
427 return( AFPERR_BITMAP );
433 ashort = htons( data - buf );
434 memcpy(l_nameoff, &ashort, sizeof( ashort ));
435 data = set_name(data, path, 0);
438 ashort = htons( data - buf );
439 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
440 data = set_name(data, path, utf8);
442 *buflen = data - buf;
446 /* ----------------------- */
447 int getfilparams(struct vol *vol,
449 struct path *path, struct dir *dir,
450 char *buf, int *buflen )
452 struct adouble ad, *adp;
455 u_int16_t attrbits = 0;
460 LOG(log_info, logtype_default, "begin getfilparams:");
463 opened = PARAM_NEED_ADP(bitmap);
466 upath = path->u_name;
467 if ((of = of_findname(path))) {
469 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
470 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
472 memset(&ad, 0, sizeof(ad));
476 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
481 we need to check if the file is open by another process.
482 it's slow so we only do it if we have to:
483 - bitmap is requested.
484 - we don't already have the answer!
486 if ((bitmap & (1 << FILPBIT_ATTR))) {
487 if (!(attrbits & ATTRBIT_ROPEN)) {
489 if (!(attrbits & ATTRBIT_DOPEN)) {
494 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
496 ad_close( adp, ADFLAGS_HF );
499 LOG(log_info, logtype_afpd, "end getfilparams:");
505 /* ----------------------------- */
506 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
509 int ibuflen, *rbuflen;
512 struct adouble ad, *adp;
515 struct ofork *of = NULL;
517 int creatf, did, openf, retvalue = AFP_OK;
523 LOG(log_info, logtype_afpd, "begin afp_createfile:");
528 creatf = (unsigned char) *ibuf++;
530 memcpy(&vid, ibuf, sizeof( vid ));
531 ibuf += sizeof( vid );
533 if (( vol = getvolbyvid( vid )) == NULL ) {
534 return( AFPERR_PARAM );
537 if (vol->v_flags & AFPVOL_RO)
540 memcpy(&did, ibuf, sizeof( did));
541 ibuf += sizeof( did );
543 if (( dir = dirlookup( vol, did )) == NULL ) {
544 return( AFPERR_NOOBJ );
547 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
548 return( AFPERR_NOOBJ );
551 if ( *s_path->m_name == '\0' ) {
552 return( AFPERR_BADTYPE );
555 upath = s_path->u_name;
556 if (0 != (ret = check_name(vol, upath)))
559 /* if upath is deleted we already in trouble anyway */
560 if ((of = of_findname(s_path))) {
563 memset(&ad, 0, sizeof(ad));
567 /* on a hard create, fail if file exists and is open */
570 openf = O_RDWR|O_CREAT|O_TRUNC;
572 /* on a soft create, if the file is open then ad_open won't fail
573 because open syscall is not called
578 openf = O_RDWR|O_CREAT|O_EXCL;
581 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
582 openf, 0666, adp) < 0 ) {
585 return( AFPERR_EXIST );
587 return( AFPERR_ACCESS );
589 /* on noadouble volumes, just creating the data fork is ok */
591 if (vol_noadouble(vol) && (stat(upath, st) == 0))
592 goto createfile_done;
595 return( AFPERR_PARAM );
598 path = s_path->m_name;
599 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
600 memcpy(ad_entry( adp, ADEID_NAME ), path,
601 ad_getentrylen( adp, ADEID_NAME ));
602 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
603 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
609 if (vol->v_flags & AFPVOL_DROPBOX) {
610 retvalue = matchfile2dirperms(upath, vol, did);
612 #endif /* DROPKLUDGE */
614 setvoltime(obj, vol );
617 LOG(log_info, logtype_afpd, "end afp_createfile");
623 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
626 int ibuflen, *rbuflen;
632 u_int16_t vid, bitmap;
635 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
641 memcpy(&vid, ibuf, sizeof( vid ));
642 ibuf += sizeof( vid );
643 if (( vol = getvolbyvid( vid )) == NULL ) {
644 return( AFPERR_PARAM );
647 if (vol->v_flags & AFPVOL_RO)
650 memcpy(&did, ibuf, sizeof( did ));
651 ibuf += sizeof( did );
652 if (( dir = dirlookup( vol, did )) == NULL ) {
653 return( AFPERR_NOOBJ );
656 memcpy(&bitmap, ibuf, sizeof( bitmap ));
657 bitmap = ntohs( bitmap );
658 ibuf += sizeof( bitmap );
660 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
661 return( AFPERR_NOOBJ );
664 if ( *s_path->m_name == '\0' ) {
665 return( AFPERR_BADTYPE ); /* it's a directory */
668 if ((u_long)ibuf & 1 ) {
672 if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
673 setvoltime(obj, vol );
677 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
684 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
687 extern struct path Cur_Path;
689 int setfilparams(struct vol *vol,
690 struct path *path, u_int16_t bitmap, char *buf )
692 struct adouble ad, *adp;
695 int bit = 0, isad = 1, err = AFP_OK;
697 u_char achar, *fdType, xyy[4];
698 u_int16_t ashort, bshort;
702 int change_mdate = 0;
703 int change_parent_mdate = 0;
709 LOG(log_info, logtype_afpd, "begin setfilparams:");
712 upath = path->u_name;
713 if ((of = of_findname(path))) {
716 memset(&ad, 0, sizeof(ad));
720 if (check_access(upath, OPENACC_WR ) < 0) {
721 return AFPERR_ACCESS;
724 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
725 O_RDWR|O_CREAT, 0666, adp) < 0) {
726 /* for some things, we don't need an adouble header */
727 if (bitmap & ~(1<<FILPBIT_MDATE)) {
728 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
731 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
732 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
733 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
734 ad_getentrylen( adp, ADEID_NAME ));
737 while ( bitmap != 0 ) {
738 while (( bitmap & 1 ) == 0 ) {
746 memcpy(&ashort, buf, sizeof( ashort ));
747 ad_getattr(adp, &bshort);
748 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
749 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
753 if ((ashort & htons(ATTRBIT_INVISIBLE)))
754 change_parent_mdate = 1;
755 ad_setattr(adp, bshort);
756 buf += sizeof( ashort );
761 memcpy(&aint, buf, sizeof(aint));
762 ad_setdate(adp, AD_DATE_CREATE, aint);
763 buf += sizeof( aint );
767 memcpy(&newdate, buf, sizeof( newdate ));
768 buf += sizeof( newdate );
773 memcpy(&aint, buf, sizeof(aint));
774 ad_setdate(adp, AD_DATE_BACKUP, aint);
775 buf += sizeof( aint );
781 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
783 ((em = getextmap( path->m_name )) &&
784 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
785 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
786 || ((em = getdefextmap()) &&
787 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
788 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
790 memcpy(buf, ufinderi, 8 );
793 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
797 /* Client needs to set the ProDOS file info for this file.
798 Use defined strings for the simple cases, and convert
799 all else into pXYY per Inside Appletalk. Always set
800 the creator as "pdos". <shirsch@ibm.net> */
801 case FILPBIT_PDINFO :
804 memcpy(&ashort, buf, sizeof( ashort ));
805 ashort = ntohs( ashort );
808 switch ( (unsigned int) achar )
811 fdType = ( u_char *) "TEXT";
815 fdType = ( u_char *) "PSYS";
819 fdType = ( u_char *) "PS16";
823 fdType = ( u_char *) "BINA";
827 xyy[0] = ( u_char ) 'p';
829 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
830 xyy[3] = ( u_char ) ashort & 0xff;
835 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
836 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
842 goto setfilparam_done;
850 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
851 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
855 ad_setdate(adp, AD_DATE_MODIFY, newdate);
856 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
861 ad_flush( adp, ADFLAGS_HF );
862 ad_close( adp, ADFLAGS_HF );
866 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
867 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
868 bitmap = 1<<FILPBIT_MDATE;
869 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
873 LOG(log_info, logtype_afpd, "end setfilparams:");
879 * renamefile and copyfile take the old and new unix pathnames
880 * and the new mac name.
881 * NOTE: if we have to copy a file instead of renaming it, locks
882 * will break. Anyway it's an error because then we have 2 files.
884 * src the source path
885 * dst the dest filename in current dir
886 * newname the dest mac name
887 * adp adouble struct of src file, if open, or & zeroed one
890 int renamefile(src, dst, newname, noadouble, adp )
891 char *src, *dst, *newname;
895 char adsrc[ MAXPATHLEN + 1];
899 * Note that this is only checking the existance of the data file,
900 * not the header file. The thinking is that if the data file doesn't
901 * exist, but the header file does, the right thing to do is remove
902 * the data file silently.
905 /* existence check moved to afp_moveandrename */
908 LOG(log_info, logtype_afpd, "begin renamefile:");
911 if ( unix_rename( src, dst ) < 0 ) {
914 return( AFPERR_NOOBJ );
917 return( AFPERR_ACCESS );
920 case EXDEV : /* Cross device move -- try copy */
921 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
922 deletefile( dst, 0 );
925 return deletefile( src, 0);
927 return( AFPERR_PARAM );
931 strcpy( adsrc, ad_path( src, 0 ));
934 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
939 /* check for a source appledouble header. if it exists, make
940 * a dest appledouble directory and do the rename again. */
941 if (rc || stat(adsrc, &st) ||
942 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
945 ad_close(adp, ADFLAGS_HF);
949 return( AFPERR_ACCESS );
953 return( AFPERR_PARAM );
957 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
960 return( AFPERR_NOOBJ );
962 return( AFPERR_ACCESS );
966 return( AFPERR_PARAM );
970 len = strlen( newname );
971 ad_setentrylen( adp, ADEID_NAME, len );
972 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
973 ad_flush( adp, ADFLAGS_HF );
974 ad_close( adp, ADFLAGS_HF );
977 LOG(log_info, logtype_afpd, "end renamefile:");
983 int copy_path_name(char *newname, char *ibuf)
990 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
996 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
997 strncpy( newname, ibuf, plen );
998 newname[ plen ] = '\0';
999 if (strlen(newname) != plen) {
1000 /* there's \0 in newname, e.g. it's a pathname not
1008 memcpy(&hint, ibuf, sizeof(hint));
1009 ibuf += sizeof(hint);
1011 memcpy(&len16, ibuf, sizeof(len16));
1012 ibuf += sizeof(len16);
1013 plen = ntohs(len16);
1015 strncpy( newname, ibuf, plen );
1016 newname[ plen ] = '\0';
1017 if (strchr(newname,'/')) {
1026 /* -----------------------------------
1028 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1031 int ibuflen, *rbuflen;
1035 char *newname, *p, *upath;
1036 struct path *s_path;
1037 u_int32_t sdid, ddid;
1038 int err, retvalue = AFP_OK;
1039 u_int16_t svid, dvid;
1042 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1048 memcpy(&svid, ibuf, sizeof( svid ));
1049 ibuf += sizeof( svid );
1050 if (( vol = getvolbyvid( svid )) == NULL ) {
1051 return( AFPERR_PARAM );
1054 memcpy(&sdid, ibuf, sizeof( sdid ));
1055 ibuf += sizeof( sdid );
1056 if (( dir = dirlookup( vol, sdid )) == NULL ) {
1057 return( AFPERR_PARAM );
1060 memcpy(&dvid, ibuf, sizeof( dvid ));
1061 ibuf += sizeof( dvid );
1062 memcpy(&ddid, ibuf, sizeof( ddid ));
1063 ibuf += sizeof( ddid );
1065 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1066 return( AFPERR_NOOBJ );
1068 if ( *s_path->m_name == '\0' ) {
1069 return( AFPERR_BADTYPE );
1072 /* don't allow copies when the file is open.
1073 * XXX: the spec only calls for read/deny write access.
1074 * however, copyfile doesn't have any of that info,
1075 * and locks need to stay coherent. as a result,
1076 * we just balk if the file is opened already. */
1078 newname = obj->newtmp;
1079 strcpy( newname, s_path->m_name );
1081 if (of_findname(s_path))
1082 return AFPERR_DENYCONF;
1084 p = ctoupath( vol, curdir, newname );
1086 /* FIXME svid != dvid && dvid's user can't read svid */
1088 if (( vol = getvolbyvid( dvid )) == NULL ) {
1089 return( AFPERR_PARAM );
1092 if (vol->v_flags & AFPVOL_RO)
1093 return AFPERR_VLOCK;
1095 if (( dir = dirlookup( vol, ddid )) == NULL ) {
1096 return( AFPERR_PARAM );
1099 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1100 return( AFPERR_NOOBJ );
1102 if ( *s_path->m_name != '\0' ) {
1103 return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1106 /* one of the handful of places that knows about the path type */
1107 if (copy_path_name(newname, ibuf) < 0) {
1108 return( AFPERR_PARAM );
1111 upath = mtoupath(vol, newname);
1112 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1118 if (vol->v_flags & AFPVOL_DROPBOX) {
1119 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1121 #endif /* DROPKLUDGE */
1123 setvoltime(obj, vol );
1126 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1133 static __inline__ int copy_all(const int dfd, const void *buf,
1139 LOG(log_info, logtype_afpd, "begin copy_all:");
1142 while (buflen > 0) {
1143 if ((cc = write(dfd, buf, buflen)) < 0) {
1150 return AFPERR_DFULL;
1152 return AFPERR_VLOCK;
1154 return AFPERR_PARAM;
1161 LOG(log_info, logtype_afpd, "end copy_all:");
1167 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1168 * pass in vol and path */
1169 int copyfile(src, dst, newname, noadouble )
1170 char *src, *dst, *newname;
1171 const int noadouble;
1174 #ifdef SENDFILE_FLAVOR_LINUX
1178 int sfd, dfd, len, err = AFP_OK;
1180 char dpath[ MAXPATHLEN + 1];
1183 LOG(log_info, logtype_afpd, "begin copyfile:");
1186 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1187 admode = ad_mode( dst, 0666 );
1189 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1192 break; /* just copy the data fork */
1194 return( AFPERR_ACCESS );
1196 return( AFPERR_PARAM );
1199 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1203 return( AFPERR_NOOBJ );
1205 return( AFPERR_ACCESS );
1207 return AFPERR_VLOCK;
1209 return( AFPERR_PARAM );
1214 #ifdef SENDFILE_FLAVOR_LINUX
1215 if (fstat(sfd, &st) == 0) {
1216 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1230 goto copyheader_done;
1232 #endif /* SENDFILE_FLAVOR_LINUX */
1234 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1241 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1255 /* data fork copying */
1256 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1259 return( AFPERR_NOOBJ );
1261 return( AFPERR_ACCESS );
1263 return( AFPERR_PARAM );
1267 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1271 return( AFPERR_NOOBJ );
1273 return( AFPERR_ACCESS );
1275 return AFPERR_VLOCK;
1277 return( AFPERR_PARAM );
1281 #ifdef SENDFILE_FLAVOR_LINUX
1282 if (fstat(sfd, &st) == 0) {
1283 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1296 #endif /* SENDFILE_FLAVOR_LINUX */
1299 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1307 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1322 memset(&ad, 0, sizeof(ad));
1323 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1327 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1329 return( AFPERR_ACCESS );
1331 return AFPERR_VLOCK;
1333 return( AFPERR_PARAM );
1337 len = strlen( newname );
1338 ad_setentrylen( &ad, ADEID_NAME, len );
1339 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1340 ad_flush( &ad, ADFLAGS_HF );
1341 ad_close( &ad, ADFLAGS_HF );
1345 LOG(log_info, logtype_afpd, "end copyfile:");
1352 /* -----------------------------------
1353 checkAttrib: 1 check kFPDeleteInhibitBit
1354 ie deletfile called by afp_delete
1356 when deletefile is called we don't have lock on it, file is closed (for us)
1357 untrue if called by renamefile
1359 int deletefile( file, checkAttrib )
1364 int adflags, err = AFP_OK;
1365 int locktype = ADLOCK_WR;
1366 int openmode = O_RDWR;
1369 LOG(log_info, logtype_afpd, "begin deletefile:");
1374 * If can't open read/write then try again read-only. If it's open
1375 * read-only, we must do a read lock instead of a write lock.
1377 /* try to open both at once */
1378 adflags = ADFLAGS_DF|ADFLAGS_HF;
1379 memset(&ad, 0, sizeof(ad));
1380 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1383 adflags = ADFLAGS_DF;
1384 /* that failed. now try to open just the data fork */
1385 memset(&ad, 0, sizeof(ad));
1386 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1389 return AFPERR_NOOBJ;
1391 if(openmode == O_RDWR) {
1392 openmode = O_RDONLY;
1393 locktype = ADLOCK_RD;
1396 return AFPERR_ACCESS;
1399 return AFPERR_VLOCK;
1401 return AFPERR_PARAM;
1407 if(openmode == O_RDWR) {
1408 openmode = O_RDONLY;
1409 locktype = ADLOCK_RD;
1412 return AFPERR_ACCESS;
1415 return AFPERR_VLOCK;
1417 return( AFPERR_PARAM );
1420 break; /* from the while */
1423 * Does kFPDeleteInhibitBit (bit 8) set?
1425 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1428 ad_getattr(&ad, &bshort);
1429 if ((bshort & htons(ATTRBIT_NODELETE))) {
1430 ad_close( &ad, adflags );
1431 return(AFPERR_OLOCK);
1435 if ((adflags & ADFLAGS_HF) ) {
1436 /* FIXME we have a pb here because we want to know if a file is open
1437 * there's a 'priority inversion' if you can't open the ressource fork RW
1438 * you can delete it if it's open because you can't get a write lock.
1440 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1443 * FIXME it doesn't for RFORK open read only and fork open without deny mode
1445 if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1446 ad_close( &ad, adflags );
1447 return( AFPERR_BUSY );
1451 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1456 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1460 err = AFPERR_ACCESS;
1473 if ( unlink( file ) < 0 ) {
1477 err = AFPERR_ACCESS;
1491 if (adflags & ADFLAGS_HF)
1492 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1493 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1494 ad_close( &ad, adflags );
1497 LOG(log_info, logtype_afpd, "end deletefile:");
1503 /* ------------------------------------ */
1505 /* return a file id */
1506 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1509 int ibuflen, *rbuflen;
1512 #if AD_VERSION > AD_VERSION1
1521 struct path *s_path;
1524 LOG(log_info, logtype_afpd, "begin afp_createid:");
1530 memcpy(&vid, ibuf, sizeof(vid));
1531 ibuf += sizeof(vid);
1533 if (( vol = getvolbyvid( vid )) == NULL ) {
1534 return( AFPERR_PARAM);
1537 if (vol->v_flags & AFPVOL_RO)
1538 return AFPERR_VLOCK;
1540 memcpy(&did, ibuf, sizeof( did ));
1541 ibuf += sizeof(did);
1543 if (( dir = dirlookup( vol, did )) == NULL ) {
1544 return( AFPERR_PARAM );
1547 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1548 return( AFPERR_PARAM );
1551 if ( *s_path->m_name == '\0' ) {
1552 return( AFPERR_BADTYPE );
1555 upath = s_path->u_name;
1556 switch (s_path->st_errno) {
1558 break; /* success */
1561 return AFPERR_ACCESS;
1563 return AFPERR_NOOBJ;
1565 return AFPERR_PARAM;
1568 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1569 memcpy(rbuf, &id, sizeof(id));
1570 *rbuflen = sizeof(id);
1571 return AFPERR_EXISTID;
1574 #if AD_VERSION > AD_VERSION1
1575 memset(&ad, 0, sizeof(ad));
1576 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1577 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1578 ad_close(&ad, ADFLAGS_HF);
1580 #endif /* AD_VERSION > AD_VERSION1 */
1582 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1583 memcpy(rbuf, &id, sizeof(id));
1584 *rbuflen = sizeof(id);
1589 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1594 return AFPERR_VLOCK;
1598 return AFPERR_ACCESS;
1601 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1602 return AFPERR_PARAM;
1606 /* ------------------------------
1607 resolve a file id */
1608 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1611 int ibuflen, *rbuflen;
1619 u_int16_t vid, bitmap;
1621 static char buffer[12 + MAXPATHLEN + 1];
1622 int len = 12 + MAXPATHLEN + 1;
1625 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1631 memcpy(&vid, ibuf, sizeof(vid));
1632 ibuf += sizeof(vid);
1634 if (( vol = getvolbyvid( vid )) == NULL ) {
1635 return( AFPERR_PARAM);
1638 memcpy(&id, ibuf, sizeof( id ));
1641 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1642 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1645 if (( dir = dirlookup( vol, id )) == NULL ) {
1646 return AFPERR_NOID; /* idem AFPERR_PARAM */
1648 path.u_name = upath;
1649 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1653 return AFPERR_ACCESS;
1657 return AFPERR_PARAM;
1660 /* directories are bad */
1661 if (S_ISDIR(path.st.st_mode))
1662 return AFPERR_BADTYPE;
1664 memcpy(&bitmap, ibuf, sizeof(bitmap));
1665 bitmap = ntohs( bitmap );
1666 path.m_name = utompath(vol, upath);
1667 if ((err = getfilparams(vol, bitmap, &path , curdir,
1668 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1671 *rbuflen = buflen + sizeof(bitmap);
1672 memcpy(rbuf, ibuf, sizeof(bitmap));
1675 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1681 /* ------------------------------ */
1682 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1685 int ibuflen, *rbuflen;
1695 static char buffer[12 + MAXPATHLEN + 1];
1696 int len = 12 + MAXPATHLEN + 1;
1699 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1705 memcpy(&vid, ibuf, sizeof(vid));
1706 ibuf += sizeof(vid);
1708 if (( vol = getvolbyvid( vid )) == NULL ) {
1709 return( AFPERR_PARAM);
1712 if (vol->v_flags & AFPVOL_RO)
1713 return AFPERR_VLOCK;
1715 memcpy(&id, ibuf, sizeof( id ));
1719 if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1723 if (( dir = dirlookup( vol, id )) == NULL ) {
1724 return( AFPERR_PARAM );
1728 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1732 return AFPERR_ACCESS;
1734 /* still try to delete the id */
1738 return AFPERR_PARAM;
1742 /* directories are bad */
1743 if (S_ISDIR(st.st_mode))
1744 return AFPERR_BADTYPE;
1746 if (cnid_delete(vol->v_db, fileid)) {
1749 return AFPERR_VLOCK;
1752 return AFPERR_ACCESS;
1754 return AFPERR_PARAM;
1759 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1764 #endif /* CNID_DB */
1766 #define APPLETEMP ".AppleTempXXXXXX"
1768 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1771 int ibuflen, *rbuflen;
1773 struct stat srcst, destst;
1775 struct dir *dir, *sdir;
1776 char *spath, temp[17], *p;
1777 char *supath, *upath;
1782 struct adouble *adsp;
1783 struct adouble *addp;
1789 #endif /* CNID_DB */
1794 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1800 memcpy(&vid, ibuf, sizeof(vid));
1801 ibuf += sizeof(vid);
1803 if (( vol = getvolbyvid( vid )) == NULL ) {
1804 return( AFPERR_PARAM);
1807 if (vol->v_flags & AFPVOL_RO)
1808 return AFPERR_VLOCK;
1810 /* source and destination dids */
1811 memcpy(&sid, ibuf, sizeof(sid));
1812 ibuf += sizeof(sid);
1813 memcpy(&did, ibuf, sizeof(did));
1814 ibuf += sizeof(did);
1817 if ((dir = dirlookup( vol, sid )) == NULL ) {
1818 return( AFPERR_PARAM );
1821 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1822 return( AFPERR_PARAM );
1825 if ( *path->m_name == '\0' ) {
1826 return( AFPERR_BADTYPE ); /* it's a dir */
1829 upath = path->u_name;
1830 switch (path->st_errno) {
1837 return AFPERR_ACCESS;
1839 return AFPERR_PARAM;
1841 memset(&ads, 0, sizeof(ads));
1843 if ((s_of = of_findname(path))) {
1844 /* reuse struct adouble so it won't break locks */
1847 memcpy(&srcst, &path->st, sizeof(struct stat));
1848 /* save some stuff */
1850 spath = obj->oldtmp;
1851 supath = obj->newtmp;
1852 strcpy(spath, path->m_name);
1853 strcpy(supath, upath); /* this is for the cnid changing */
1854 p = absupath( vol, sdir, upath);
1856 /* look for the source cnid. if it doesn't exist, don't worry about
1859 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1860 slen = strlen(supath));
1861 #endif /* CNID_DB */
1863 if (( dir = dirlookup( vol, did )) == NULL ) {
1864 return( AFPERR_PARAM );
1867 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1868 return( AFPERR_PARAM );
1871 if ( *path->m_name == '\0' ) {
1872 return( AFPERR_BADTYPE );
1875 /* FPExchangeFiles is the only call that can return the SameObj
1877 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1878 return AFPERR_SAMEOBJ;
1879 memcpy(&srcst, &path->st, sizeof(struct stat));
1888 return AFPERR_ACCESS;
1890 return AFPERR_PARAM;
1892 memset(&add, 0, sizeof(add));
1894 if ((d_of = of_findname( path))) {
1895 /* reuse struct adouble so it won't break locks */
1898 memcpy(&destst, &path->st, sizeof(struct stat));
1900 /* they are not on the same device and at least one is open
1902 if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1905 upath = path->u_name;
1907 /* look for destination id. */
1908 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1909 dlen = strlen(upath));
1910 #endif /* CNID_DB */
1912 /* construct a temp name.
1913 * NOTE: the temp file will be in the dest file's directory. it
1914 * will also be inaccessible from AFP. */
1915 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1919 /* now, quickly rename the file. we error if we can't. */
1920 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1921 goto err_exchangefile;
1922 of_rename(vol, s_of, sdir, spath, curdir, temp);
1924 /* rename destination to source */
1925 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1926 goto err_src_to_tmp;
1927 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1929 /* rename temp to destination */
1930 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1931 goto err_dest_to_src;
1932 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1935 /* id's need switching. src -> dest and dest -> src. */
1936 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1937 upath, dlen) < 0)) {
1941 err = AFPERR_ACCESS;
1946 goto err_temp_to_dest;
1949 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1950 supath, slen) < 0)) {
1954 err = AFPERR_ACCESS;
1961 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1962 goto err_temp_to_dest;
1964 #endif /* CNID_DB */
1967 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1973 /* all this stuff is so that we can unwind a failed operation
1978 /* rename dest to temp */
1979 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1980 of_rename(vol, s_of, curdir, upath, curdir, temp);
1983 /* rename source back to dest */
1984 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1985 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1988 /* rename temp back to source */
1989 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1990 of_rename(vol, s_of, curdir, temp, sdir, spath);