2 * $Id: file.c,v 1.84 2003-02-16 12:35:04 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));
109 /* ---------------------
111 char *set_name(char *data, const char *name, u_int32_t utf8)
115 aint = strlen( name );
118 if (afp_version >= 30) {
119 /* the name is in utf8 */
121 if (aint > MACFILELEN)
128 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
132 memcpy(data, &utf8, sizeof(utf8));
133 data += sizeof(utf8);
136 memcpy(data, &temp, sizeof(temp));
137 data += sizeof(temp);
140 memcpy( data, name, aint );
147 * FIXME: PDINFO is UTF8 and doesn't need adp
149 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
150 (1 << FILPBIT_CDATE) |\
151 (1 << FILPBIT_MDATE) |\
152 (1 << FILPBIT_BDATE) |\
153 (1 << FILPBIT_FINFO) |\
154 (1 << FILPBIT_RFLEN) |\
155 (1 << FILPBIT_EXTRFLEN) |\
156 (1 << FILPBIT_PDINFO)))
159 /* -------------------------- */
160 int getmetadata(struct vol *vol,
162 struct path *path, struct dir *dir,
163 char *buf, int *buflen, struct adouble *adp, int attrbits )
166 struct stat lst, *lstp;
167 #endif /* USE_LASTDID */
168 char *data, *l_nameoff = NULL, *upath;
169 char *utf_nameoff = NULL;
173 u_char achar, fdType[4];
177 LOG(log_info, logtype_afpd, "begin getmetadata:");
180 upath = path->u_name;
184 while ( bitmap != 0 ) {
185 while (( bitmap & 1 ) == 0 ) {
193 ad_getattr(adp, &ashort);
194 } else if (*upath == '.') {
195 ashort = htons(ATTRBIT_INVISIBLE);
199 /* FIXME do we want a visual clue if the file is read only
202 accessmode( ".", &ma, dir , NULL);
203 if ((ma.ma_user & AR_UWRITE)) {
204 accessmode( upath, &ma, dir , st);
205 if (!(ma.ma_user & AR_UWRITE)) {
206 attrbits |= ATTRBIT_NOWRITE;
211 ashort = htons(ntohs(ashort) | attrbits);
212 memcpy(data, &ashort, sizeof( ashort ));
213 data += sizeof( ashort );
217 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
218 data += sizeof( u_int32_t );
222 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
223 aint = AD_DATE_FROM_UNIX(st->st_mtime);
224 memcpy(data, &aint, sizeof( aint ));
225 data += sizeof( aint );
229 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
230 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
231 aint = AD_DATE_FROM_UNIX(st->st_mtime);
234 aint = AD_DATE_FROM_UNIX(st->st_mtime);
236 memcpy(data, &aint, sizeof( int ));
237 data += sizeof( int );
241 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
242 aint = AD_DATE_START;
243 memcpy(data, &aint, sizeof( int ));
244 data += sizeof( int );
248 get_finderinfo(path->m_name, adp, (char *)data);
250 if (*upath == '.') { /* make it invisible */
251 ashort = htons(FINDERINFO_INVISIBLE);
252 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
261 data += sizeof( u_int16_t );
265 memset(data, 0, sizeof(u_int16_t));
266 data += sizeof( u_int16_t );
271 #if AD_VERSION > AD_VERSION1
272 /* look in AD v2 header */
274 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
275 #endif /* AD_VERSION > AD_VERSION1 */
278 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
279 strlen(upath), aint);
280 /* Throw errors if cnid_add fails. */
281 if (aint == CNID_INVALID) {
284 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
285 return(AFPERR_PARAM);
287 return(AFPERR_PARAM);
297 * What a fucking mess. First thing: DID and FNUMs are
298 * in the same space for purposes of enumerate (and several
299 * other wierd places). While we consider this Apple's bug,
300 * this is the work-around: In order to maintain constant and
301 * unique DIDs and FNUMs, we monotonically generate the DIDs
302 * during the session, and derive the FNUMs from the filesystem.
303 * Since the DIDs are small, we insure that the FNUMs are fairly
304 * large by setting thier high bits to the device number.
306 * AFS already does something very similar to this for the
307 * inode number, so we don't repeat the procedure.
310 * due to complaints over did's being non-persistent,
311 * here's the current hack to provide semi-persistent
313 * 1) we reserve the first bit for file ids.
314 * 2) the next 7 bits are for the device.
315 * 3) the remaining 24 bits are for the inode.
317 * both the inode and device information are actually hashes
318 * that are then truncated to the requisite bit length.
320 * it should be okay to use lstat to deal with symlinks.
323 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
324 #else /* USE_LASTDID */
325 lstp = lstat(upath, &lst) < 0 ? st : &lst;
326 aint = htonl(CNID(lstp, 1));
327 #endif /* USE_LASTDID */
330 memcpy(data, &aint, sizeof( aint ));
331 data += sizeof( aint );
335 if (st->st_size > 0xffffffff)
338 aint = htonl( st->st_size );
339 memcpy(data, &aint, sizeof( aint ));
340 data += sizeof( aint );
345 if (adp->ad_rlen > 0xffffffff)
348 aint = htonl( adp->ad_rlen);
352 memcpy(data, &aint, sizeof( aint ));
353 data += sizeof( aint );
356 /* Current client needs ProDOS info block for this file.
357 Use simple heuristic and let the Mac "type" string tell
358 us what the PD file code should be. Everything gets a
359 subtype of 0x0000 unless the original value was hashed
360 to "pXYZ" when we created it. See IA, Ver 2.
361 <shirsch@adelphia.net> */
362 case FILPBIT_PDINFO :
363 if (afp_version >= 30) { /* UTF8 name */
364 utf8 = kTextEncodingUTF8;
366 data += sizeof( u_int16_t );
368 memcpy(data, &aint, sizeof( aint ));
369 data += sizeof( aint );
373 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
375 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
379 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
383 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
387 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
391 else if ( fdType[0] == 'p' ) {
393 ashort = (fdType[2] * 256) + fdType[3];
407 memcpy(data, &ashort, sizeof( ashort ));
408 data += sizeof( ashort );
409 memset(data, 0, sizeof( ashort ));
410 data += sizeof( ashort );
413 case FILPBIT_EXTDFLEN:
414 aint = htonl(st->st_size >> 32);
415 memcpy(data, &aint, sizeof( aint ));
416 data += sizeof( aint );
417 aint = htonl(st->st_size);
418 memcpy(data, &aint, sizeof( aint ));
419 data += sizeof( aint );
421 case FILPBIT_EXTRFLEN:
424 aint = htonl(adp->ad_rlen >> 32);
425 memcpy(data, &aint, sizeof( aint ));
426 data += sizeof( aint );
428 aint = htonl(adp->ad_rlen);
429 memcpy(data, &aint, sizeof( aint ));
430 data += sizeof( aint );
433 return( AFPERR_BITMAP );
439 ashort = htons( data - buf );
440 memcpy(l_nameoff, &ashort, sizeof( ashort ));
441 data = set_name(data, path->m_name, 0);
444 ashort = htons( data - buf );
445 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
446 data = set_name(data, path->m_name, utf8);
448 *buflen = data - buf;
452 /* ----------------------- */
453 int getfilparams(struct vol *vol,
455 struct path *path, struct dir *dir,
456 char *buf, int *buflen )
458 struct adouble ad, *adp;
461 u_int16_t attrbits = 0;
466 LOG(log_info, logtype_default, "begin getfilparams:");
469 opened = PARAM_NEED_ADP(bitmap);
472 upath = path->u_name;
473 if ((of = of_findname(path))) {
475 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
476 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
478 memset(&ad, 0, sizeof(ad));
482 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
487 we need to check if the file is open by another process.
488 it's slow so we only do it if we have to:
489 - bitmap is requested.
490 - we don't already have the answer!
492 if ((bitmap & (1 << FILPBIT_ATTR))) {
493 if (!(attrbits & ATTRBIT_ROPEN)) {
495 if (!(attrbits & ATTRBIT_DOPEN)) {
500 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
502 ad_close( adp, ADFLAGS_HF );
505 LOG(log_info, logtype_afpd, "end getfilparams:");
511 /* ----------------------------- */
512 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
515 int ibuflen, *rbuflen;
517 struct adouble ad, *adp;
520 struct ofork *of = NULL;
522 int creatf, did, openf, retvalue = AFP_OK;
528 LOG(log_info, logtype_afpd, "begin afp_createfile:");
533 creatf = (unsigned char) *ibuf++;
535 memcpy(&vid, ibuf, sizeof( vid ));
536 ibuf += sizeof( vid );
538 if (NULL == ( vol = getvolbyvid( vid )) ) {
539 return( AFPERR_PARAM );
542 if (vol->v_flags & AFPVOL_RO)
545 memcpy(&did, ibuf, sizeof( did));
546 ibuf += sizeof( did );
548 if (NULL == ( dir = dirlookup( vol, did )) ) {
552 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
556 if ( *s_path->m_name == '\0' ) {
557 return( AFPERR_BADTYPE );
560 upath = s_path->u_name;
561 if (0 != (ret = check_name(vol, upath)))
564 /* if upath is deleted we already in trouble anyway */
565 if ((of = of_findname(s_path))) {
568 memset(&ad, 0, sizeof(ad));
572 /* on a hard create, fail if file exists and is open */
575 openf = O_RDWR|O_CREAT|O_TRUNC;
577 /* on a soft create, if the file is open then ad_open won't fail
578 because open syscall is not called
583 openf = O_RDWR|O_CREAT|O_EXCL;
586 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
587 openf, 0666, adp) < 0 ) {
590 return( AFPERR_EXIST );
592 return( AFPERR_ACCESS );
594 return( AFPERR_PARAM );
597 if ( ad_hfileno( adp ) == -1 ) {
598 /* on noadouble volumes, just creating the data fork is ok */
599 if (vol_noadouble(vol))
600 goto createfile_done;
601 /* FIXME with hard create on an existing file, we already
602 * corrupted the data file.
604 netatalk_unlink( upath );
605 ad_close( adp, ADFLAGS_DF );
606 return AFPERR_ACCESS;
609 path = s_path->m_name;
610 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
611 memcpy(ad_entry( adp, ADEID_NAME ), path,
612 ad_getentrylen( adp, ADEID_NAME ));
613 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
614 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
620 if (vol->v_flags & AFPVOL_DROPBOX) {
621 retvalue = matchfile2dirperms(upath, vol, did);
623 #endif /* DROPKLUDGE */
625 setvoltime(obj, vol );
628 LOG(log_info, logtype_afpd, "end afp_createfile");
634 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
637 int ibuflen, *rbuflen;
643 u_int16_t vid, bitmap;
646 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
652 memcpy(&vid, ibuf, sizeof( vid ));
653 ibuf += sizeof( vid );
654 if (NULL == ( vol = getvolbyvid( vid )) ) {
655 return( AFPERR_PARAM );
658 if (vol->v_flags & AFPVOL_RO)
661 memcpy(&did, ibuf, sizeof( did ));
662 ibuf += sizeof( did );
663 if (NULL == ( dir = dirlookup( vol, did )) ) {
664 return afp_errno; /* was AFPERR_NOOBJ */
667 memcpy(&bitmap, ibuf, sizeof( bitmap ));
668 bitmap = ntohs( bitmap );
669 ibuf += sizeof( bitmap );
671 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
675 if (path_isadir(s_path)) {
676 return( AFPERR_BADTYPE ); /* it's a directory */
679 if ((u_long)ibuf & 1 ) {
683 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
684 setvoltime(obj, vol );
688 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
695 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
698 extern struct path Cur_Path;
700 int setfilparams(struct vol *vol,
701 struct path *path, u_int16_t bitmap, char *buf )
703 struct adouble ad, *adp;
706 int bit = 0, isad = 1, err = AFP_OK;
708 u_char achar, *fdType, xyy[4];
709 u_int16_t ashort, bshort;
713 int change_mdate = 0;
714 int change_parent_mdate = 0;
720 LOG(log_info, logtype_afpd, "begin setfilparams:");
723 upath = path->u_name;
724 if ((of = of_findname(path))) {
727 memset(&ad, 0, sizeof(ad));
731 if (check_access(upath, OPENACC_WR ) < 0) {
732 return AFPERR_ACCESS;
735 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
736 O_RDWR|O_CREAT, 0666, adp) < 0) {
737 /* for some things, we don't need an adouble header */
738 if (bitmap & ~(1<<FILPBIT_MDATE)) {
739 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
742 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
743 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
744 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
745 ad_getentrylen( adp, ADEID_NAME ));
748 while ( bitmap != 0 ) {
749 while (( bitmap & 1 ) == 0 ) {
757 memcpy(&ashort, buf, sizeof( ashort ));
758 ad_getattr(adp, &bshort);
759 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
760 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
764 if ((ashort & htons(ATTRBIT_INVISIBLE)))
765 change_parent_mdate = 1;
766 ad_setattr(adp, bshort);
767 buf += sizeof( ashort );
772 memcpy(&aint, buf, sizeof(aint));
773 ad_setdate(adp, AD_DATE_CREATE, aint);
774 buf += sizeof( aint );
778 memcpy(&newdate, buf, sizeof( newdate ));
779 buf += sizeof( newdate );
784 memcpy(&aint, buf, sizeof(aint));
785 ad_setdate(adp, AD_DATE_BACKUP, aint);
786 buf += sizeof( aint );
792 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
794 ((em = getextmap( path->m_name )) &&
795 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
796 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
797 || ((em = getdefextmap()) &&
798 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
799 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
801 memcpy(buf, ufinderi, 8 );
804 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
808 /* Client needs to set the ProDOS file info for this file.
809 Use a defined string for TEXT to support crlf
810 translations and convert all else into pXYY per Inside
811 Appletalk. Always set the creator as "pdos". Changes
812 from original by Marsha Jackson. */
813 case FILPBIT_PDINFO :
814 if (afp_version < 30) { /* else it's UTF8 name */
817 /* Keep special case to support crlf translations */
818 if ((unsigned int) achar == 0x04) {
819 fdType = (u_char *)"TEXT";
822 xyy[0] = ( u_char ) 'p';
828 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
829 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
835 goto setfilparam_done;
843 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
844 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
848 ad_setdate(adp, AD_DATE_MODIFY, newdate);
849 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
854 ad_flush( adp, ADFLAGS_HF );
855 ad_close( adp, ADFLAGS_HF );
859 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
860 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
861 bitmap = 1<<FILPBIT_MDATE;
862 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
866 LOG(log_info, logtype_afpd, "end setfilparams:");
872 * renamefile and copyfile take the old and new unix pathnames
873 * and the new mac name.
875 * src the source path
876 * dst the dest filename in current dir
877 * newname the dest mac name
878 * adp adouble struct of src file, if open, or & zeroed one
881 int renamefile(src, dst, newname, noadouble, adp )
882 char *src, *dst, *newname;
886 char adsrc[ MAXPATHLEN + 1];
891 LOG(log_info, logtype_afpd, "begin renamefile:");
894 if ( unix_rename( src, dst ) < 0 ) {
897 return( AFPERR_NOOBJ );
900 return( AFPERR_ACCESS );
903 case EXDEV : /* Cross device move -- try copy */
904 /* NOTE: with open file it's an error because after the copy we will
905 * get two files, it's fixable for our process (eg reopen the new file, get the
906 * locks, and so on. But it doesn't solve the case with a second process
908 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
909 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
910 return AFPERR_OLOCK; /* little lie */
912 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
913 /* on error copyfile delete dest */
916 return deletefile(NULL, src, 0);
918 return( AFPERR_PARAM );
922 strcpy( adsrc, ad_path( src, 0 ));
924 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
929 if (errno == ENOENT) {
932 if (stat(adsrc, &st)) /* source has no ressource fork, */
935 /* We are here because :
936 * -there's no dest folder.
937 * -there's no .AppleDouble in the dest folder.
938 * if we use the struct adouble passed in parameter it will not
939 * create .AppleDouble if the file is already opened, so we
940 * use a diff one, it's not a pb,ie it's not the same file, yet.
942 memset(&ad, 0, sizeof(ad));
943 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
944 ad_close(&ad, ADFLAGS_HF);
945 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
950 else { /* it's something else, bail out */
954 /* try to undo the data fork rename,
955 * we know we are on the same device
958 unix_rename( dst, src );
959 /* return the first error */
965 return AFPERR_ACCESS ;
969 return AFPERR_PARAM ;
974 /* don't care if we can't open the newly renamed ressource fork
976 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
977 len = strlen( newname );
978 ad_setentrylen( adp, ADEID_NAME, len );
979 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
980 ad_flush( adp, ADFLAGS_HF );
981 ad_close( adp, ADFLAGS_HF );
984 LOG(log_info, logtype_afpd, "end renamefile:");
990 int copy_path_name(char *newname, char *ibuf)
997 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1003 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1004 strncpy( newname, ibuf, plen );
1005 newname[ plen ] = '\0';
1006 if (strlen(newname) != plen) {
1007 /* there's \0 in newname, e.g. it's a pathname not
1015 memcpy(&hint, ibuf, sizeof(hint));
1016 ibuf += sizeof(hint);
1018 memcpy(&len16, ibuf, sizeof(len16));
1019 ibuf += sizeof(len16);
1020 plen = ntohs(len16);
1022 strncpy( newname, ibuf, plen );
1023 newname[ plen ] = '\0';
1024 if (strlen(newname) != plen) {
1033 /* -----------------------------------
1035 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1038 int ibuflen, *rbuflen;
1042 char *newname, *p, *upath;
1043 struct path *s_path;
1044 u_int32_t sdid, ddid;
1045 int err, retvalue = AFP_OK;
1046 u_int16_t svid, dvid;
1049 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1055 memcpy(&svid, ibuf, sizeof( svid ));
1056 ibuf += sizeof( svid );
1057 if (NULL == ( vol = getvolbyvid( svid )) ) {
1058 return( AFPERR_PARAM );
1061 memcpy(&sdid, ibuf, sizeof( sdid ));
1062 ibuf += sizeof( sdid );
1063 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1067 memcpy(&dvid, ibuf, sizeof( dvid ));
1068 ibuf += sizeof( dvid );
1069 memcpy(&ddid, ibuf, sizeof( ddid ));
1070 ibuf += sizeof( ddid );
1072 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1075 if ( path_isadir(s_path) ) {
1076 return( AFPERR_BADTYPE );
1079 /* don't allow copies when the file is open.
1080 * XXX: the spec only calls for read/deny write access.
1081 * however, copyfile doesn't have any of that info,
1082 * and locks need to stay coherent. as a result,
1083 * we just balk if the file is opened already. */
1085 newname = obj->newtmp;
1086 strcpy( newname, s_path->m_name );
1088 if (of_findname(s_path))
1089 return AFPERR_DENYCONF;
1091 p = ctoupath( vol, curdir, newname );
1093 return AFPERR_PARAM;
1097 /* FIXME svid != dvid && dvid's user can't read svid */
1099 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1100 return( AFPERR_PARAM );
1103 if (vol->v_flags & AFPVOL_RO)
1104 return AFPERR_VLOCK;
1106 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1110 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1113 if ( *s_path->m_name != '\0' ) {
1114 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1117 /* one of the handful of places that knows about the path type */
1118 if (copy_path_name(newname, ibuf) < 0) {
1119 return( AFPERR_PARAM );
1122 upath = mtoupath(vol, newname);
1123 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1129 if (vol->v_flags & AFPVOL_DROPBOX) {
1130 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1132 #endif /* DROPKLUDGE */
1134 setvoltime(obj, vol );
1137 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1144 static __inline__ int copy_all(const int dfd, const void *buf,
1150 LOG(log_info, logtype_afpd, "begin copy_all:");
1153 while (buflen > 0) {
1154 if ((cc = write(dfd, buf, buflen)) < 0) {
1161 return AFPERR_DFULL;
1163 return AFPERR_VLOCK;
1165 return AFPERR_PARAM;
1172 LOG(log_info, logtype_afpd, "end copy_all:");
1178 /* -------------------------- */
1179 static int copy_fd(int dfd, int sfd)
1185 #ifdef SENDFILE_FLAVOR_LINUX
1188 if (fstat(sfd, &st) == 0) {
1189 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1191 case EINVAL: /* there's no guarantee that all fs support sendfile */
1196 return AFPERR_DFULL;
1198 return AFPERR_VLOCK;
1200 return AFPERR_PARAM;
1207 #endif /* SENDFILE_FLAVOR_LINUX */
1210 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1217 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1223 /* ----------------------------------
1224 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1225 * because we are doing it elsewhere.
1227 int copyfile(src, dst, newname, noadouble )
1228 char *src, *dst, *newname;
1229 const int noadouble;
1231 struct adouble ads, add;
1232 int len, err = AFP_OK;
1236 LOG(log_info, logtype_afpd, "begin copyfile:");
1239 memset(&ads, 0, sizeof(ads));
1240 memset(&add, 0, sizeof(add));
1241 adflags = ADFLAGS_DF;
1243 adflags |= ADFLAGS_HF;
1246 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1249 return( AFPERR_NOOBJ );
1251 return( AFPERR_ACCESS );
1253 return( AFPERR_PARAM );
1256 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1257 ad_close( &ads, adflags );
1258 if (EEXIST != (err = errno)) {
1259 deletefile(NULL, dst, 0);
1263 return AFPERR_EXIST;
1265 return( AFPERR_NOOBJ );
1267 return( AFPERR_ACCESS );
1269 return AFPERR_VLOCK;
1271 return( AFPERR_PARAM );
1274 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1275 /* copy the data fork */
1276 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1280 len = strlen( newname );
1281 ad_setentrylen( &add, ADEID_NAME, len );
1282 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1285 ad_close( &ads, adflags );
1286 ad_flush( &add, adflags );
1287 if (ad_close( &add, adflags ) <0) {
1290 if (err != AFP_OK) {
1291 deletefile(NULL, dst, 0);
1294 return( AFPERR_NOOBJ );
1296 return( AFPERR_ACCESS );
1298 return( AFPERR_PARAM );
1303 LOG(log_info, logtype_afpd, "end copyfile:");
1310 /* -----------------------------------
1311 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1312 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1314 when deletefile is called we don't have lock on it, file is closed (for us)
1315 untrue if called by renamefile
1317 ad_open always try to open file RDWR first and ad_lock takes care of
1318 WRITE lock on read only file.
1320 int deletefile( vol, file, checkAttrib )
1326 int adflags, err = AFP_OK;
1329 LOG(log_info, logtype_afpd, "begin deletefile:");
1332 /* try to open both forks at once */
1333 adflags = ADFLAGS_DF|ADFLAGS_HF;
1335 memset(&ad, 0, sizeof(ad));
1336 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1339 if (adflags == ADFLAGS_DF)
1340 return AFPERR_NOOBJ;
1342 /* that failed. now try to open just the data fork */
1343 adflags = ADFLAGS_DF;
1347 return AFPERR_ACCESS;
1349 return AFPERR_VLOCK;
1351 return( AFPERR_PARAM );
1354 break; /* from the while */
1357 * Does kFPDeleteInhibitBit (bit 8) set?
1359 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1362 ad_getattr(&ad, &bshort);
1363 if ((bshort & htons(ATTRBIT_NODELETE))) {
1364 ad_close( &ad, adflags );
1365 return(AFPERR_OLOCK);
1369 if ((adflags & ADFLAGS_HF) ) {
1370 /* FIXME we have a pb here because we want to know if a file is open
1371 * there's a 'priority inversion' if you can't open the ressource fork RW
1372 * you can delete it if it's open because you can't get a write lock.
1374 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1377 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1379 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1380 ad_close( &ad, adflags );
1381 return( AFPERR_BUSY );
1385 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1388 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1389 !(err = netatalk_unlink( file )) ) {
1390 #ifdef CNID_DB /* get rid of entry */
1392 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1394 cnid_delete(vol->v_db, id);
1396 #endif /* CNID_DB */
1399 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1402 LOG(log_info, logtype_afpd, "end deletefile:");
1408 /* ------------------------------------ */
1410 /* return a file id */
1411 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1414 int ibuflen, *rbuflen;
1417 #if AD_VERSION > AD_VERSION1
1426 struct path *s_path;
1429 LOG(log_info, logtype_afpd, "begin afp_createid:");
1435 memcpy(&vid, ibuf, sizeof(vid));
1436 ibuf += sizeof(vid);
1438 if (NULL == ( vol = getvolbyvid( vid )) ) {
1439 return( AFPERR_PARAM);
1442 if (vol->v_flags & AFPVOL_RO)
1443 return AFPERR_VLOCK;
1445 memcpy(&did, ibuf, sizeof( did ));
1446 ibuf += sizeof(did);
1448 if (NULL == ( dir = dirlookup( vol, did )) ) {
1449 return( AFPERR_PARAM );
1452 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1453 return afp_errno; /* was AFPERR_PARAM */
1456 if ( path_isadir(s_path) ) {
1457 return( AFPERR_BADTYPE );
1460 upath = s_path->u_name;
1461 switch (s_path->st_errno) {
1463 break; /* success */
1466 return AFPERR_ACCESS;
1468 return AFPERR_NOOBJ;
1470 return AFPERR_PARAM;
1473 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1474 memcpy(rbuf, &id, sizeof(id));
1475 *rbuflen = sizeof(id);
1476 return AFPERR_EXISTID;
1479 #if AD_VERSION > AD_VERSION1
1480 memset(&ad, 0, sizeof(ad));
1481 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1482 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1483 ad_close(&ad, ADFLAGS_HF);
1485 #endif /* AD_VERSION > AD_VERSION1 */
1487 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1488 memcpy(rbuf, &id, sizeof(id));
1489 *rbuflen = sizeof(id);
1494 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1499 return AFPERR_VLOCK;
1503 return AFPERR_ACCESS;
1506 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1507 return AFPERR_PARAM;
1511 /* ------------------------------
1512 resolve a file id */
1513 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1516 int ibuflen, *rbuflen;
1524 u_int16_t vid, bitmap;
1526 static char buffer[12 + MAXPATHLEN + 1];
1527 int len = 12 + MAXPATHLEN + 1;
1530 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1536 memcpy(&vid, ibuf, sizeof(vid));
1537 ibuf += sizeof(vid);
1539 if (NULL == ( vol = getvolbyvid( vid )) ) {
1540 return( AFPERR_PARAM);
1543 memcpy(&id, ibuf, sizeof( id ));
1546 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1547 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1550 if (NULL == ( dir = dirlookup( vol, id )) ) {
1551 return AFPERR_NOID; /* idem AFPERR_PARAM */
1553 path.u_name = upath;
1554 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1558 return AFPERR_ACCESS;
1562 return AFPERR_PARAM;
1565 /* directories are bad */
1566 if (S_ISDIR(path.st.st_mode))
1567 return AFPERR_BADTYPE;
1569 memcpy(&bitmap, ibuf, sizeof(bitmap));
1570 bitmap = ntohs( bitmap );
1571 path.m_name = utompath(vol, upath);
1572 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1573 rbuf + sizeof(bitmap), &buflen))) {
1576 *rbuflen = buflen + sizeof(bitmap);
1577 memcpy(rbuf, ibuf, sizeof(bitmap));
1580 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1586 /* ------------------------------ */
1587 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1590 int ibuflen, *rbuflen;
1600 static char buffer[12 + MAXPATHLEN + 1];
1601 int len = 12 + MAXPATHLEN + 1;
1604 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1610 memcpy(&vid, ibuf, sizeof(vid));
1611 ibuf += sizeof(vid);
1613 if (NULL == ( vol = getvolbyvid( vid )) ) {
1614 return( AFPERR_PARAM);
1617 if (vol->v_flags & AFPVOL_RO)
1618 return AFPERR_VLOCK;
1620 memcpy(&id, ibuf, sizeof( id ));
1624 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1628 if (NULL == ( dir = dirlookup( vol, id )) ) {
1629 return( AFPERR_PARAM );
1633 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1637 return AFPERR_ACCESS;
1639 /* still try to delete the id */
1643 return AFPERR_PARAM;
1646 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1647 return AFPERR_BADTYPE;
1649 if (cnid_delete(vol->v_db, fileid)) {
1652 return AFPERR_VLOCK;
1655 return AFPERR_ACCESS;
1657 return AFPERR_PARAM;
1662 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1667 #endif /* CNID_DB */
1669 #define APPLETEMP ".AppleTempXXXXXX"
1671 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1674 int ibuflen, *rbuflen;
1676 struct stat srcst, destst;
1678 struct dir *dir, *sdir;
1679 char *spath, temp[17], *p;
1680 char *supath, *upath;
1685 struct adouble *adsp;
1686 struct adouble *addp;
1693 #endif /* CNID_DB */
1698 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1704 memcpy(&vid, ibuf, sizeof(vid));
1705 ibuf += sizeof(vid);
1707 if (NULL == ( vol = getvolbyvid( vid )) ) {
1708 return( AFPERR_PARAM);
1711 if (vol->v_flags & AFPVOL_RO)
1712 return AFPERR_VLOCK;
1714 /* source and destination dids */
1715 memcpy(&sid, ibuf, sizeof(sid));
1716 ibuf += sizeof(sid);
1717 memcpy(&did, ibuf, sizeof(did));
1718 ibuf += sizeof(did);
1721 if (NULL == (dir = dirlookup( vol, sid )) ) {
1722 return( AFPERR_PARAM );
1725 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1726 return afp_errno; /* was AFPERR_PARAM */
1729 if ( path_isadir(path) ) {
1730 return( AFPERR_BADTYPE ); /* it's a dir */
1733 upath = path->u_name;
1734 switch (path->st_errno) {
1741 return AFPERR_ACCESS;
1743 return AFPERR_PARAM;
1745 memset(&ads, 0, sizeof(ads));
1747 if ((s_of = of_findname(path))) {
1748 /* reuse struct adouble so it won't break locks */
1751 memcpy(&srcst, &path->st, sizeof(struct stat));
1752 /* save some stuff */
1754 spath = obj->oldtmp;
1755 supath = obj->newtmp;
1756 strcpy(spath, path->m_name);
1757 strcpy(supath, upath); /* this is for the cnid changing */
1758 p = absupath( vol, sdir, upath);
1760 /* pathname too long */
1761 return AFPERR_PARAM ;
1764 /* look for the source cnid. if it doesn't exist, don't worry about
1767 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1768 slen = strlen(supath));
1769 #endif /* CNID_DB */
1771 if (NULL == ( dir = dirlookup( vol, did )) ) {
1772 return( AFPERR_PARAM );
1775 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1776 return( AFPERR_PARAM );
1779 if ( path_isadir(path) ) {
1780 return( AFPERR_BADTYPE );
1783 /* FPExchangeFiles is the only call that can return the SameObj
1785 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1786 return AFPERR_SAMEOBJ;
1788 switch (path->st_errno) {
1795 return AFPERR_ACCESS;
1797 return AFPERR_PARAM;
1799 memset(&add, 0, sizeof(add));
1801 if ((d_of = of_findname( path))) {
1802 /* reuse struct adouble so it won't break locks */
1805 memcpy(&destst, &path->st, sizeof(struct stat));
1807 /* they are not on the same device and at least one is open
1809 crossdev = (srcst.st_dev != destst.st_dev);
1810 if ((d_of || s_of) && crossdev)
1813 upath = path->u_name;
1815 /* look for destination id. */
1816 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1817 dlen = strlen(upath));
1818 #endif /* CNID_DB */
1820 /* construct a temp name.
1821 * NOTE: the temp file will be in the dest file's directory. it
1822 * will also be inaccessible from AFP. */
1823 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1827 /* now, quickly rename the file. we error if we can't. */
1828 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1829 goto err_exchangefile;
1830 of_rename(vol, s_of, sdir, spath, curdir, temp);
1832 /* rename destination to source */
1833 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1834 goto err_src_to_tmp;
1835 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1837 /* rename temp to destination */
1838 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1839 goto err_dest_to_src;
1840 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1843 /* id's need switching. src -> dest and dest -> src.
1844 * we need to re-stat() if it was a cross device copy.
1847 cnid_delete(vol->v_db, sid);
1850 cnid_delete(vol->v_db, did);
1852 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1853 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1855 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1856 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1861 err = AFPERR_ACCESS;
1866 goto err_temp_to_dest;
1868 #endif /* CNID_DB */
1871 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1877 /* all this stuff is so that we can unwind a failed operation
1882 /* rename dest to temp */
1883 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1884 of_rename(vol, s_of, curdir, upath, curdir, temp);
1887 /* rename source back to dest */
1888 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1889 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1892 /* rename temp back to source */
1893 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1894 of_rename(vol, s_of, curdir, temp, sdir, spath);