2 * $Id: file.c,v 1.83 2003-02-04 18:26:20 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 char *path, struct dir *dir, struct stat *st,
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 = mtoupath(vol, path);
183 while ( bitmap != 0 ) {
184 while (( bitmap & 1 ) == 0 ) {
192 ad_getattr(adp, &ashort);
193 } else if (*upath == '.') {
194 ashort = htons(ATTRBIT_INVISIBLE);
198 /* FIXME do we want a visual clue if the file is read only
201 accessmode( ".", &ma, dir , NULL);
202 if ((ma.ma_user & AR_UWRITE)) {
203 accessmode( upath, &ma, dir , st);
204 if (!(ma.ma_user & AR_UWRITE)) {
205 attrbits |= ATTRBIT_NOWRITE;
210 ashort = htons(ntohs(ashort) | attrbits);
211 memcpy(data, &ashort, sizeof( ashort ));
212 data += sizeof( ashort );
216 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
217 data += sizeof( u_int32_t );
221 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
222 aint = AD_DATE_FROM_UNIX(st->st_mtime);
223 memcpy(data, &aint, sizeof( aint ));
224 data += sizeof( aint );
228 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
229 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
230 aint = AD_DATE_FROM_UNIX(st->st_mtime);
233 aint = AD_DATE_FROM_UNIX(st->st_mtime);
235 memcpy(data, &aint, sizeof( int ));
236 data += sizeof( int );
240 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
241 aint = AD_DATE_START;
242 memcpy(data, &aint, sizeof( int ));
243 data += sizeof( int );
247 get_finderinfo(path, adp, (char *)data);
249 if (*upath == '.') { /* make it invisible */
250 ashort = htons(FINDERINFO_INVISIBLE);
251 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
260 data += sizeof( u_int16_t );
264 memset(data, 0, sizeof(u_int16_t));
265 data += sizeof( u_int16_t );
270 #if AD_VERSION > AD_VERSION1
271 /* look in AD v2 header */
273 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
274 #endif /* AD_VERSION > AD_VERSION1 */
277 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
278 strlen(upath), aint);
279 /* Throw errors if cnid_add fails. */
280 if (aint == CNID_INVALID) {
283 LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
284 return(AFPERR_PARAM);
286 return(AFPERR_PARAM);
296 * What a fucking mess. First thing: DID and FNUMs are
297 * in the same space for purposes of enumerate (and several
298 * other wierd places). While we consider this Apple's bug,
299 * this is the work-around: In order to maintain constant and
300 * unique DIDs and FNUMs, we monotonically generate the DIDs
301 * during the session, and derive the FNUMs from the filesystem.
302 * Since the DIDs are small, we insure that the FNUMs are fairly
303 * large by setting thier high bits to the device number.
305 * AFS already does something very similar to this for the
306 * inode number, so we don't repeat the procedure.
309 * due to complaints over did's being non-persistent,
310 * here's the current hack to provide semi-persistent
312 * 1) we reserve the first bit for file ids.
313 * 2) the next 7 bits are for the device.
314 * 3) the remaining 24 bits are for the inode.
316 * both the inode and device information are actually hashes
317 * that are then truncated to the requisite bit length.
319 * it should be okay to use lstat to deal with symlinks.
322 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
323 #else /* USE_LASTDID */
324 lstp = lstat(upath, &lst) < 0 ? st : &lst;
325 aint = htonl(CNID(lstp, 1));
326 #endif /* USE_LASTDID */
329 memcpy(data, &aint, sizeof( aint ));
330 data += sizeof( aint );
334 if (st->st_size > 0xffffffff)
337 aint = htonl( st->st_size );
338 memcpy(data, &aint, sizeof( aint ));
339 data += sizeof( aint );
344 if (adp->ad_rlen > 0xffffffff)
347 aint = htonl( adp->ad_rlen);
351 memcpy(data, &aint, sizeof( aint ));
352 data += sizeof( aint );
355 /* Current client needs ProDOS info block for this file.
356 Use simple heuristic and let the Mac "type" string tell
357 us what the PD file code should be. Everything gets a
358 subtype of 0x0000 unless the original value was hashed
359 to "pXYZ" when we created it. See IA, Ver 2.
360 <shirsch@adelphia.net> */
361 case FILPBIT_PDINFO :
362 if (afp_version >= 30) { /* UTF8 name */
363 utf8 = kTextEncodingUTF8;
365 data += sizeof( u_int16_t );
367 memcpy(data, &aint, sizeof( aint ));
368 data += sizeof( aint );
372 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
374 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
378 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
382 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
386 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
390 else if ( fdType[0] == 'p' ) {
392 ashort = (fdType[2] * 256) + fdType[3];
406 memcpy(data, &ashort, sizeof( ashort ));
407 data += sizeof( ashort );
408 memset(data, 0, sizeof( ashort ));
409 data += sizeof( ashort );
412 case FILPBIT_EXTDFLEN:
413 aint = htonl(st->st_size >> 32);
414 memcpy(data, &aint, sizeof( aint ));
415 data += sizeof( aint );
416 aint = htonl(st->st_size);
417 memcpy(data, &aint, sizeof( aint ));
418 data += sizeof( aint );
420 case FILPBIT_EXTRFLEN:
423 aint = htonl(adp->ad_rlen >> 32);
424 memcpy(data, &aint, sizeof( aint ));
425 data += sizeof( aint );
427 aint = htonl(adp->ad_rlen);
428 memcpy(data, &aint, sizeof( aint ));
429 data += sizeof( aint );
432 return( AFPERR_BITMAP );
438 ashort = htons( data - buf );
439 memcpy(l_nameoff, &ashort, sizeof( ashort ));
440 data = set_name(data, path, 0);
443 ashort = htons( data - buf );
444 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
445 data = set_name(data, path, utf8);
447 *buflen = data - buf;
451 /* ----------------------- */
452 int getfilparams(struct vol *vol,
454 struct path *path, struct dir *dir,
455 char *buf, int *buflen )
457 struct adouble ad, *adp;
460 u_int16_t attrbits = 0;
465 LOG(log_info, logtype_default, "begin getfilparams:");
468 opened = PARAM_NEED_ADP(bitmap);
471 upath = path->u_name;
472 if ((of = of_findname(path))) {
474 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
475 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
477 memset(&ad, 0, sizeof(ad));
481 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
486 we need to check if the file is open by another process.
487 it's slow so we only do it if we have to:
488 - bitmap is requested.
489 - we don't already have the answer!
491 if ((bitmap & (1 << FILPBIT_ATTR))) {
492 if (!(attrbits & ATTRBIT_ROPEN)) {
494 if (!(attrbits & ATTRBIT_DOPEN)) {
499 rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
501 ad_close( adp, ADFLAGS_HF );
504 LOG(log_info, logtype_afpd, "end getfilparams:");
510 /* ----------------------------- */
511 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
514 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,
587 openf, 0666, adp) < 0 ) {
590 return( AFPERR_EXIST );
592 return( AFPERR_ACCESS );
594 /* on noadouble volumes, just creating the data fork is ok */
596 if (vol_noadouble(vol) && (stat(upath, st) == 0))
597 goto createfile_done;
600 return( AFPERR_PARAM );
603 path = s_path->m_name;
604 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
605 memcpy(ad_entry( adp, ADEID_NAME ), path,
606 ad_getentrylen( adp, ADEID_NAME ));
607 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
608 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
614 if (vol->v_flags & AFPVOL_DROPBOX) {
615 retvalue = matchfile2dirperms(upath, vol, did);
617 #endif /* DROPKLUDGE */
619 setvoltime(obj, vol );
622 LOG(log_info, logtype_afpd, "end afp_createfile");
628 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
631 int ibuflen, *rbuflen;
637 u_int16_t vid, bitmap;
640 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
646 memcpy(&vid, ibuf, sizeof( vid ));
647 ibuf += sizeof( vid );
648 if (NULL == ( vol = getvolbyvid( vid )) ) {
649 return( AFPERR_PARAM );
652 if (vol->v_flags & AFPVOL_RO)
655 memcpy(&did, ibuf, sizeof( did ));
656 ibuf += sizeof( did );
657 if (NULL == ( dir = dirlookup( vol, did )) ) {
658 return afp_errno; /* was AFPERR_NOOBJ */
661 memcpy(&bitmap, ibuf, sizeof( bitmap ));
662 bitmap = ntohs( bitmap );
663 ibuf += sizeof( bitmap );
665 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
669 if (path_isadir(s_path)) {
670 return( AFPERR_BADTYPE ); /* it's a directory */
673 if ((u_long)ibuf & 1 ) {
677 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
678 setvoltime(obj, vol );
682 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
689 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
692 extern struct path Cur_Path;
694 int setfilparams(struct vol *vol,
695 struct path *path, u_int16_t bitmap, char *buf )
697 struct adouble ad, *adp;
700 int bit = 0, isad = 1, err = AFP_OK;
702 u_char achar, *fdType, xyy[4];
703 u_int16_t ashort, bshort;
707 int change_mdate = 0;
708 int change_parent_mdate = 0;
714 LOG(log_info, logtype_afpd, "begin setfilparams:");
717 upath = path->u_name;
718 if ((of = of_findname(path))) {
721 memset(&ad, 0, sizeof(ad));
725 if (check_access(upath, OPENACC_WR ) < 0) {
726 return AFPERR_ACCESS;
729 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
730 O_RDWR|O_CREAT, 0666, adp) < 0) {
731 /* for some things, we don't need an adouble header */
732 if (bitmap & ~(1<<FILPBIT_MDATE)) {
733 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
736 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
737 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
738 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
739 ad_getentrylen( adp, ADEID_NAME ));
742 while ( bitmap != 0 ) {
743 while (( bitmap & 1 ) == 0 ) {
751 memcpy(&ashort, buf, sizeof( ashort ));
752 ad_getattr(adp, &bshort);
753 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
754 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
758 if ((ashort & htons(ATTRBIT_INVISIBLE)))
759 change_parent_mdate = 1;
760 ad_setattr(adp, bshort);
761 buf += sizeof( ashort );
766 memcpy(&aint, buf, sizeof(aint));
767 ad_setdate(adp, AD_DATE_CREATE, aint);
768 buf += sizeof( aint );
772 memcpy(&newdate, buf, sizeof( newdate ));
773 buf += sizeof( newdate );
778 memcpy(&aint, buf, sizeof(aint));
779 ad_setdate(adp, AD_DATE_BACKUP, aint);
780 buf += sizeof( aint );
786 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
788 ((em = getextmap( path->m_name )) &&
789 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
790 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
791 || ((em = getdefextmap()) &&
792 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
793 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
795 memcpy(buf, ufinderi, 8 );
798 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
802 /* Client needs to set the ProDOS file info for this file.
803 Use a defined string for TEXT to support crlf
804 translations and convert all else into pXYY per Inside
805 Appletalk. Always set the creator as "pdos". Changes
806 from original by Marsha Jackson. */
807 case FILPBIT_PDINFO :
808 if (afp_version < 30) { /* else it's UTF8 name */
811 /* Keep special case to support crlf translations */
812 if ((unsigned int) achar == 0x04) {
813 fdType = (u_char *)"TEXT";
816 xyy[0] = ( u_char ) 'p';
822 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
823 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
829 goto setfilparam_done;
837 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
838 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
842 ad_setdate(adp, AD_DATE_MODIFY, newdate);
843 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
848 ad_flush( adp, ADFLAGS_HF );
849 ad_close( adp, ADFLAGS_HF );
853 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
854 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
855 bitmap = 1<<FILPBIT_MDATE;
856 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
860 LOG(log_info, logtype_afpd, "end setfilparams:");
866 * renamefile and copyfile take the old and new unix pathnames
867 * and the new mac name.
869 * src the source path
870 * dst the dest filename in current dir
871 * newname the dest mac name
872 * adp adouble struct of src file, if open, or & zeroed one
875 int renamefile(src, dst, newname, noadouble, adp )
876 char *src, *dst, *newname;
880 char adsrc[ MAXPATHLEN + 1];
885 LOG(log_info, logtype_afpd, "begin renamefile:");
888 if ( unix_rename( src, dst ) < 0 ) {
891 return( AFPERR_NOOBJ );
894 return( AFPERR_ACCESS );
897 case EXDEV : /* Cross device move -- try copy */
898 /* NOTE: with open file it's an error because after the copy we will
899 * get two files, it's fixable for our process (eg reopen the new file, get the
900 * locks, and so on. But it doesn't solve the case with a second process
902 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
903 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
904 return AFPERR_OLOCK; /* little lie */
906 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
907 deletefile( dst, 0 );
910 return deletefile( src, 0);
912 return( AFPERR_PARAM );
916 strcpy( adsrc, ad_path( src, 0 ));
918 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
923 if (errno == ENOENT) {
926 if (stat(adsrc, &st)) /* source has no ressource fork, */
929 /* We are here because :
930 * -there's no dest folder.
931 * -there's no .AppleDouble in the dest folder.
932 * if we use the struct adouble passed in parameter it will not
933 * create .AppleDouble if the file is already opened, so we
934 * use a diff one, it's not a pb,ie it's not the same file, yet.
936 memset(&ad, 0, sizeof(ad));
937 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
938 ad_close(&ad, ADFLAGS_HF);
939 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
944 else { /* it's something else, bail out */
948 /* try to undo the data fork rename,
949 * we know we are on the same device
952 unix_rename( dst, src );
953 /* return the first error */
959 return AFPERR_ACCESS ;
963 return AFPERR_PARAM ;
968 /* don't care if we can't open the newly renamed ressource fork
970 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
971 len = strlen( newname );
972 ad_setentrylen( adp, ADEID_NAME, len );
973 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
974 ad_flush( adp, ADFLAGS_HF );
975 ad_close( adp, ADFLAGS_HF );
978 LOG(log_info, logtype_afpd, "end renamefile:");
984 int copy_path_name(char *newname, char *ibuf)
991 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
997 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
998 strncpy( newname, ibuf, plen );
999 newname[ plen ] = '\0';
1000 if (strlen(newname) != plen) {
1001 /* there's \0 in newname, e.g. it's a pathname not
1009 memcpy(&hint, ibuf, sizeof(hint));
1010 ibuf += sizeof(hint);
1012 memcpy(&len16, ibuf, sizeof(len16));
1013 ibuf += sizeof(len16);
1014 plen = ntohs(len16);
1016 strncpy( newname, ibuf, plen );
1017 newname[ plen ] = '\0';
1018 if (strlen(newname) != plen) {
1027 /* -----------------------------------
1029 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1032 int ibuflen, *rbuflen;
1036 char *newname, *p, *upath;
1037 struct path *s_path;
1038 u_int32_t sdid, ddid;
1039 int err, retvalue = AFP_OK;
1040 u_int16_t svid, dvid;
1043 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1049 memcpy(&svid, ibuf, sizeof( svid ));
1050 ibuf += sizeof( svid );
1051 if (NULL == ( vol = getvolbyvid( svid )) ) {
1052 return( AFPERR_PARAM );
1055 memcpy(&sdid, ibuf, sizeof( sdid ));
1056 ibuf += sizeof( sdid );
1057 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1061 memcpy(&dvid, ibuf, sizeof( dvid ));
1062 ibuf += sizeof( dvid );
1063 memcpy(&ddid, ibuf, sizeof( ddid ));
1064 ibuf += sizeof( ddid );
1066 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1069 if ( path_isadir(s_path) ) {
1070 return( AFPERR_BADTYPE );
1073 /* don't allow copies when the file is open.
1074 * XXX: the spec only calls for read/deny write access.
1075 * however, copyfile doesn't have any of that info,
1076 * and locks need to stay coherent. as a result,
1077 * we just balk if the file is opened already. */
1079 newname = obj->newtmp;
1080 strcpy( newname, s_path->m_name );
1082 if (of_findname(s_path))
1083 return AFPERR_DENYCONF;
1085 p = ctoupath( vol, curdir, newname );
1087 return AFPERR_PARAM;
1091 /* FIXME svid != dvid && dvid's user can't read svid */
1093 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1094 return( AFPERR_PARAM );
1097 if (vol->v_flags & AFPVOL_RO)
1098 return AFPERR_VLOCK;
1100 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1104 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1107 if ( *s_path->m_name != '\0' ) {
1108 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1111 /* one of the handful of places that knows about the path type */
1112 if (copy_path_name(newname, ibuf) < 0) {
1113 return( AFPERR_PARAM );
1116 upath = mtoupath(vol, newname);
1117 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1123 if (vol->v_flags & AFPVOL_DROPBOX) {
1124 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1126 #endif /* DROPKLUDGE */
1128 setvoltime(obj, vol );
1131 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1138 static __inline__ int copy_all(const int dfd, const void *buf,
1144 LOG(log_info, logtype_afpd, "begin copy_all:");
1147 while (buflen > 0) {
1148 if ((cc = write(dfd, buf, buflen)) < 0) {
1155 return AFPERR_DFULL;
1157 return AFPERR_VLOCK;
1159 return AFPERR_PARAM;
1166 LOG(log_info, logtype_afpd, "end copy_all:");
1172 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1173 * pass in vol and path */
1174 int copyfile(src, dst, newname, noadouble )
1175 char *src, *dst, *newname;
1176 const int noadouble;
1179 #ifdef SENDFILE_FLAVOR_LINUX
1183 int sfd, dfd, len, err = AFP_OK;
1185 char dpath[ MAXPATHLEN + 1];
1188 LOG(log_info, logtype_afpd, "begin copyfile:");
1191 strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1192 admode = ad_mode( dst, 0666 );
1194 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1197 break; /* just copy the data fork */
1199 return( AFPERR_ACCESS );
1201 return( AFPERR_PARAM );
1204 if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1208 return( AFPERR_NOOBJ );
1210 return( AFPERR_ACCESS );
1212 return AFPERR_VLOCK;
1214 return( AFPERR_PARAM );
1219 #ifdef SENDFILE_FLAVOR_LINUX
1220 if (fstat(sfd, &st) == 0) {
1221 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1235 goto copyheader_done;
1237 #endif /* SENDFILE_FLAVOR_LINUX */
1239 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1246 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1260 /* data fork copying */
1261 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1264 return( AFPERR_NOOBJ );
1266 return( AFPERR_ACCESS );
1268 return( AFPERR_PARAM );
1272 if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1276 return( AFPERR_NOOBJ );
1278 return( AFPERR_ACCESS );
1280 return AFPERR_VLOCK;
1282 return( AFPERR_PARAM );
1286 #ifdef SENDFILE_FLAVOR_LINUX
1287 if (fstat(sfd, &st) == 0) {
1288 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1301 #endif /* SENDFILE_FLAVOR_LINUX */
1304 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1312 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1327 memset(&ad, 0, sizeof(ad));
1328 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1332 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1334 return( AFPERR_ACCESS );
1336 return AFPERR_VLOCK;
1338 return( AFPERR_PARAM );
1342 len = strlen( newname );
1343 ad_setentrylen( &ad, ADEID_NAME, len );
1344 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1345 ad_flush( &ad, ADFLAGS_HF );
1346 ad_close( &ad, ADFLAGS_HF );
1350 LOG(log_info, logtype_afpd, "end copyfile:");
1357 /* -----------------------------------
1358 checkAttrib: 1 check kFPDeleteInhibitBit
1359 ie deletfile called by afp_delete
1361 when deletefile is called we don't have lock on it, file is closed (for us)
1362 untrue if called by renamefile
1364 ad_open always try to open file RDWR first and ad_lock takes care of
1365 WRITE lock on read only file.
1367 int deletefile( file, checkAttrib )
1372 int adflags, err = AFP_OK;
1375 LOG(log_info, logtype_afpd, "begin deletefile:");
1378 /* try to open both forks at once */
1379 adflags = ADFLAGS_DF|ADFLAGS_HF;
1381 memset(&ad, 0, sizeof(ad));
1382 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1385 if (adflags == ADFLAGS_DF)
1386 return AFPERR_NOOBJ;
1388 /* that failed. now try to open just the data fork */
1389 adflags = ADFLAGS_DF;
1393 return AFPERR_ACCESS;
1395 return AFPERR_VLOCK;
1397 return( AFPERR_PARAM );
1400 break; /* from the while */
1403 * Does kFPDeleteInhibitBit (bit 8) set?
1405 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1408 ad_getattr(&ad, &bshort);
1409 if ((bshort & htons(ATTRBIT_NODELETE))) {
1410 ad_close( &ad, adflags );
1411 return(AFPERR_OLOCK);
1415 if ((adflags & ADFLAGS_HF) ) {
1416 /* FIXME we have a pb here because we want to know if a file is open
1417 * there's a 'priority inversion' if you can't open the ressource fork RW
1418 * you can delete it if it's open because you can't get a write lock.
1420 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1423 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1425 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1426 ad_close( &ad, adflags );
1427 return( AFPERR_BUSY );
1431 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1434 else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
1435 err = netatalk_unlink( file );
1437 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1440 LOG(log_info, logtype_afpd, "end deletefile:");
1446 /* ------------------------------------ */
1448 /* return a file id */
1449 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1452 int ibuflen, *rbuflen;
1455 #if AD_VERSION > AD_VERSION1
1464 struct path *s_path;
1467 LOG(log_info, logtype_afpd, "begin afp_createid:");
1473 memcpy(&vid, ibuf, sizeof(vid));
1474 ibuf += sizeof(vid);
1476 if (NULL == ( vol = getvolbyvid( vid )) ) {
1477 return( AFPERR_PARAM);
1480 if (vol->v_flags & AFPVOL_RO)
1481 return AFPERR_VLOCK;
1483 memcpy(&did, ibuf, sizeof( did ));
1484 ibuf += sizeof(did);
1486 if (NULL == ( dir = dirlookup( vol, did )) ) {
1487 return( AFPERR_PARAM );
1490 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1491 return afp_errno; /* was AFPERR_PARAM */
1494 if ( path_isadir(s_path) ) {
1495 return( AFPERR_BADTYPE );
1498 upath = s_path->u_name;
1499 switch (s_path->st_errno) {
1501 break; /* success */
1504 return AFPERR_ACCESS;
1506 return AFPERR_NOOBJ;
1508 return AFPERR_PARAM;
1511 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1512 memcpy(rbuf, &id, sizeof(id));
1513 *rbuflen = sizeof(id);
1514 return AFPERR_EXISTID;
1517 #if AD_VERSION > AD_VERSION1
1518 memset(&ad, 0, sizeof(ad));
1519 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1520 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1521 ad_close(&ad, ADFLAGS_HF);
1523 #endif /* AD_VERSION > AD_VERSION1 */
1525 if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1526 memcpy(rbuf, &id, sizeof(id));
1527 *rbuflen = sizeof(id);
1532 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1537 return AFPERR_VLOCK;
1541 return AFPERR_ACCESS;
1544 LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1545 return AFPERR_PARAM;
1549 /* ------------------------------
1550 resolve a file id */
1551 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1554 int ibuflen, *rbuflen;
1562 u_int16_t vid, bitmap;
1564 static char buffer[12 + MAXPATHLEN + 1];
1565 int len = 12 + MAXPATHLEN + 1;
1568 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1574 memcpy(&vid, ibuf, sizeof(vid));
1575 ibuf += sizeof(vid);
1577 if (NULL == ( vol = getvolbyvid( vid )) ) {
1578 return( AFPERR_PARAM);
1581 memcpy(&id, ibuf, sizeof( id ));
1584 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1585 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1588 if (( dir = dirlookup( vol, id )) == NULL ) {
1589 return AFPERR_NOID; /* idem AFPERR_PARAM */
1591 path.u_name = upath;
1592 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1596 return AFPERR_ACCESS;
1600 return AFPERR_PARAM;
1603 /* directories are bad */
1604 if (S_ISDIR(path.st.st_mode))
1605 return AFPERR_BADTYPE;
1607 memcpy(&bitmap, ibuf, sizeof(bitmap));
1608 bitmap = ntohs( bitmap );
1609 path.m_name = utompath(vol, upath);
1610 if ((err = getfilparams(vol, bitmap, &path , curdir,
1611 rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1614 *rbuflen = buflen + sizeof(bitmap);
1615 memcpy(rbuf, ibuf, sizeof(bitmap));
1618 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1624 /* ------------------------------ */
1625 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1628 int ibuflen, *rbuflen;
1638 static char buffer[12 + MAXPATHLEN + 1];
1639 int len = 12 + MAXPATHLEN + 1;
1642 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1648 memcpy(&vid, ibuf, sizeof(vid));
1649 ibuf += sizeof(vid);
1651 if (NULL == ( vol = getvolbyvid( vid )) ) {
1652 return( AFPERR_PARAM);
1655 if (vol->v_flags & AFPVOL_RO)
1656 return AFPERR_VLOCK;
1658 memcpy(&id, ibuf, sizeof( id ));
1662 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1666 if (( dir = dirlookup( vol, id )) == NULL ) {
1667 return( AFPERR_PARAM );
1671 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1675 return AFPERR_ACCESS;
1677 /* still try to delete the id */
1681 return AFPERR_PARAM;
1685 /* directories are bad */
1686 if (S_ISDIR(st.st_mode))
1687 return AFPERR_BADTYPE;
1689 if (cnid_delete(vol->v_db, fileid)) {
1692 return AFPERR_VLOCK;
1695 return AFPERR_ACCESS;
1697 return AFPERR_PARAM;
1702 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1707 #endif /* CNID_DB */
1709 #define APPLETEMP ".AppleTempXXXXXX"
1711 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1714 int ibuflen, *rbuflen;
1716 struct stat srcst, destst;
1718 struct dir *dir, *sdir;
1719 char *spath, temp[17], *p;
1720 char *supath, *upath;
1725 struct adouble *adsp;
1726 struct adouble *addp;
1733 #endif /* CNID_DB */
1738 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1744 memcpy(&vid, ibuf, sizeof(vid));
1745 ibuf += sizeof(vid);
1747 if (NULL == ( vol = getvolbyvid( vid )) ) {
1748 return( AFPERR_PARAM);
1751 if (vol->v_flags & AFPVOL_RO)
1752 return AFPERR_VLOCK;
1754 /* source and destination dids */
1755 memcpy(&sid, ibuf, sizeof(sid));
1756 ibuf += sizeof(sid);
1757 memcpy(&did, ibuf, sizeof(did));
1758 ibuf += sizeof(did);
1761 if (NULL == (dir = dirlookup( vol, sid )) ) {
1762 return( AFPERR_PARAM );
1765 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1766 return afp_errno; /* was AFPERR_PARAM */
1769 if ( path_isadir(path) ) {
1770 return( AFPERR_BADTYPE ); /* it's a dir */
1773 upath = path->u_name;
1774 switch (path->st_errno) {
1781 return AFPERR_ACCESS;
1783 return AFPERR_PARAM;
1785 memset(&ads, 0, sizeof(ads));
1787 if ((s_of = of_findname(path))) {
1788 /* reuse struct adouble so it won't break locks */
1791 memcpy(&srcst, &path->st, sizeof(struct stat));
1792 /* save some stuff */
1794 spath = obj->oldtmp;
1795 supath = obj->newtmp;
1796 strcpy(spath, path->m_name);
1797 strcpy(supath, upath); /* this is for the cnid changing */
1798 p = absupath( vol, sdir, upath);
1800 /* pathname too long */
1801 return AFPERR_PARAM ;
1804 /* look for the source cnid. if it doesn't exist, don't worry about
1807 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1808 slen = strlen(supath));
1809 #endif /* CNID_DB */
1811 if (NULL == ( dir = dirlookup( vol, did )) ) {
1812 return( AFPERR_PARAM );
1815 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1816 return( AFPERR_PARAM );
1819 if ( path_isadir(path) ) {
1820 return( AFPERR_BADTYPE );
1823 /* FPExchangeFiles is the only call that can return the SameObj
1825 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1826 return AFPERR_SAMEOBJ;
1828 switch (path->st_errno) {
1835 return AFPERR_ACCESS;
1837 return AFPERR_PARAM;
1839 memset(&add, 0, sizeof(add));
1841 if ((d_of = of_findname( path))) {
1842 /* reuse struct adouble so it won't break locks */
1845 memcpy(&destst, &path->st, sizeof(struct stat));
1847 /* they are not on the same device and at least one is open
1849 crossdev = (srcst.st_dev != destst.st_dev);
1850 if ((d_of || s_of) && crossdev)
1853 upath = path->u_name;
1855 /* look for destination id. */
1856 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1857 dlen = strlen(upath));
1858 #endif /* CNID_DB */
1860 /* construct a temp name.
1861 * NOTE: the temp file will be in the dest file's directory. it
1862 * will also be inaccessible from AFP. */
1863 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1867 /* now, quickly rename the file. we error if we can't. */
1868 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1869 goto err_exchangefile;
1870 of_rename(vol, s_of, sdir, spath, curdir, temp);
1872 /* rename destination to source */
1873 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1874 goto err_src_to_tmp;
1875 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1877 /* rename temp to destination */
1878 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1879 goto err_dest_to_src;
1880 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1883 /* id's need switching. src -> dest and dest -> src.
1884 * we need to re-stat() if it was a cross device copy.
1887 cnid_delete(vol->v_db, sid);
1890 cnid_delete(vol->v_db, did);
1892 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1893 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1895 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1896 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1901 err = AFPERR_ACCESS;
1906 goto err_temp_to_dest;
1908 #endif /* CNID_DB */
1911 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1917 /* all this stuff is so that we can unwind a failed operation
1922 /* rename dest to temp */
1923 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1924 of_rename(vol, s_of, curdir, upath, curdir, temp);
1927 /* rename source back to dest */
1928 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1929 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1932 /* rename temp back to source */
1933 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1934 of_rename(vol, s_of, curdir, temp, sdir, spath);