2 * $Id: file.c,v 1.95 2003-06-09 14:42:39 srittau 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"
63 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
64 * field bytes subfield bytes
67 * ioFlFndrInfo 16 -> type 4 type field
68 * creator 4 creator field
69 * flags 2 finder flags:
71 * location 4 location in window
72 * folder 2 window that contains file
74 * ioFlXFndrInfo 16 -> iconID 2 icon id
76 * script 1 script system
78 * commentID 2 comment id
79 * putawayID 4 home directory id
82 const u_char ufinderi[] = {
83 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0
89 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
90 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
95 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
98 memcpy(data, ufinderi, 32);
101 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
102 && (em = getextmap( mpath ))
104 memcpy(data, em->em_type, sizeof( em->em_type ));
105 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
110 /* ---------------------
112 char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
117 aint = strlen( name );
121 if (utf8_encoding()) {
122 /* but name is an utf8 mac name */
125 /* global static variable... */
127 if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
136 if (aint > MACFILELEN)
143 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
146 utf8 = 0; /* htonl(utf8) */
147 memcpy(data, &utf8, sizeof(utf8));
148 data += sizeof(utf8);
151 memcpy(data, &temp, sizeof(temp));
152 data += sizeof(temp);
155 memcpy( data, src, aint );
165 * FIXME: PDINFO is UTF8 and doesn't need adp
167 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
168 (1 << FILPBIT_CDATE) |\
169 (1 << FILPBIT_MDATE) |\
170 (1 << FILPBIT_BDATE) |\
171 (1 << FILPBIT_FINFO) |\
172 (1 << FILPBIT_RFLEN) |\
173 (1 << FILPBIT_EXTRFLEN) |\
174 (1 << FILPBIT_PDINFO)))
176 /* -------------------------- */
177 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
178 const cnid_t did, const char *upath, const int len)
184 aint = cnid_add(vol->v_db, st, did, upath, len, aint);
185 /* Throw errors if cnid_add fails. */
186 if (aint == CNID_INVALID) {
188 case CNID_ERR_CLOSE: /* the db is closed */
191 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
192 afp_errno = AFPERR_PARAM;
195 afp_errno = AFPERR_PARAM;
198 afp_errno = AFPERR_MISC;
206 * First thing: DID and FNUMs are
207 * in the same space for purposes of enumerate (and several
208 * other wierd places). While we consider this Apple's bug,
209 * this is the work-around: In order to maintain constant and
210 * unique DIDs and FNUMs, we monotonically generate the DIDs
211 * during the session, and derive the FNUMs from the filesystem.
212 * Since the DIDs are small, we insure that the FNUMs are fairly
213 * large by setting thier high bits to the device number.
215 * AFS already does something very similar to this for the
216 * inode number, so we don't repeat the procedure.
219 * due to complaints over did's being non-persistent,
220 * here's the current hack to provide semi-persistent
222 * 1) we reserve the first bit for file ids.
223 * 2) the next 7 bits are for the device.
224 * 3) the remaining 24 bits are for the inode.
226 * both the inode and device information are actually hashes
227 * that are then truncated to the requisite bit length.
229 * it should be okay to use lstat to deal with symlinks.
232 if ( S_ISDIR(st->st_mode)) {
233 aint = htonl( vol->v_lastdid++ );
237 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
239 #else /* USE_LASTDID */
242 const struct stat *lstp;
244 lstp = lstat(upath, &lst) < 0 ? st : &lst;
245 aint = htonl(CNID(lstp, 1));
247 #endif /* USE_LASTDID */
252 /* -------------------------- */
253 int getmetadata(struct vol *vol,
255 struct path *path, struct dir *dir,
256 char *buf, int *buflen, struct adouble *adp, int attrbits )
258 char *data, *l_nameoff = NULL, *upath;
259 char *utf_nameoff = NULL;
263 u_char achar, fdType[4];
269 LOG(log_info, logtype_afpd, "begin getmetadata:");
272 upath = path->u_name;
276 while ( bitmap != 0 ) {
277 while (( bitmap & 1 ) == 0 ) {
285 ad_getattr(adp, &ashort);
286 } else if (*upath == '.') {
287 ashort = htons(ATTRBIT_INVISIBLE);
291 /* FIXME do we want a visual clue if the file is read only
294 accessmode( ".", &ma, dir , NULL);
295 if ((ma.ma_user & AR_UWRITE)) {
296 accessmode( upath, &ma, dir , st);
297 if (!(ma.ma_user & AR_UWRITE)) {
298 attrbits |= ATTRBIT_NOWRITE;
303 ashort = htons(ntohs(ashort) | attrbits);
304 memcpy(data, &ashort, sizeof( ashort ));
305 data += sizeof( ashort );
309 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
310 data += sizeof( u_int32_t );
314 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
315 aint = AD_DATE_FROM_UNIX(st->st_mtime);
316 memcpy(data, &aint, sizeof( aint ));
317 data += sizeof( aint );
321 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
322 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 aint = AD_DATE_FROM_UNIX(st->st_mtime);
328 memcpy(data, &aint, sizeof( int ));
329 data += sizeof( int );
333 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
334 aint = AD_DATE_START;
335 memcpy(data, &aint, sizeof( int ));
336 data += sizeof( int );
340 get_finderinfo(path->m_name, adp, (char *)data);
342 if (*upath == '.') { /* make it invisible */
343 ashort = htons(FINDERINFO_INVISIBLE);
344 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
352 data += sizeof( u_int16_t );
356 memset(data, 0, sizeof(u_int16_t));
357 data += sizeof( u_int16_t );
361 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
369 if (st->st_size > 0xffffffff)
372 aint = htonl( st->st_size );
373 memcpy(data, &aint, sizeof( aint ));
374 data += sizeof( aint );
379 if (adp->ad_rlen > 0xffffffff)
382 aint = htonl( adp->ad_rlen);
386 memcpy(data, &aint, sizeof( aint ));
387 data += sizeof( aint );
390 /* Current client needs ProDOS info block for this file.
391 Use simple heuristic and let the Mac "type" string tell
392 us what the PD file code should be. Everything gets a
393 subtype of 0x0000 unless the original value was hashed
394 to "pXYZ" when we created it. See IA, Ver 2.
395 <shirsch@adelphia.net> */
396 case FILPBIT_PDINFO :
397 if (afp_version >= 30) { /* UTF8 name */
398 utf8 = kTextEncodingUTF8;
400 data += sizeof( u_int16_t );
402 memcpy(data, &aint, sizeof( aint ));
403 data += sizeof( aint );
407 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
409 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
413 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
417 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
421 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
425 else if ( fdType[0] == 'p' ) {
427 ashort = (fdType[2] * 256) + fdType[3];
441 memcpy(data, &ashort, sizeof( ashort ));
442 data += sizeof( ashort );
443 memset(data, 0, sizeof( ashort ));
444 data += sizeof( ashort );
447 case FILPBIT_EXTDFLEN:
448 aint = htonl(st->st_size >> 32);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
451 aint = htonl(st->st_size);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 case FILPBIT_EXTRFLEN:
458 aint = htonl(adp->ad_rlen >> 32);
459 memcpy(data, &aint, sizeof( aint ));
460 data += sizeof( aint );
462 aint = htonl(adp->ad_rlen);
463 memcpy(data, &aint, sizeof( aint ));
464 data += sizeof( aint );
466 case FILPBIT_UNIXPR :
467 aint = htonl(st->st_uid);
468 memcpy( data, &aint, sizeof( aint ));
469 data += sizeof( aint );
470 aint = htonl(st->st_gid);
471 memcpy( data, &aint, sizeof( aint ));
472 data += sizeof( aint );
474 aint = htonl(st->st_mode);
475 memcpy( data, &aint, sizeof( aint ));
476 data += sizeof( aint );
478 accessmode( upath, &ma, dir , st);
480 *data++ = ma.ma_user;
481 *data++ = ma.ma_world;
482 *data++ = ma.ma_group;
483 *data++ = ma.ma_owner;
487 return( AFPERR_BITMAP );
493 ashort = htons( data - buf );
494 memcpy(l_nameoff, &ashort, sizeof( ashort ));
495 data = set_name(vol, data, path->m_name, 0);
498 ashort = htons( data - buf );
499 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
500 data = set_name(vol, data, path->m_name, utf8);
502 *buflen = data - buf;
506 /* ----------------------- */
507 int getfilparams(struct vol *vol,
509 struct path *path, struct dir *dir,
510 char *buf, int *buflen )
512 struct adouble ad, *adp;
515 u_int16_t attrbits = 0;
520 LOG(log_info, logtype_default, "begin getfilparams:");
523 opened = PARAM_NEED_ADP(bitmap);
526 upath = path->u_name;
527 if ((of = of_findname(path))) {
529 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
530 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
532 memset(&ad, 0, sizeof(ad));
536 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
541 we need to check if the file is open by another process.
542 it's slow so we only do it if we have to:
543 - bitmap is requested.
544 - we don't already have the answer!
546 if ((bitmap & (1 << FILPBIT_ATTR))) {
547 if (!(attrbits & ATTRBIT_ROPEN)) {
549 if (!(attrbits & ATTRBIT_DOPEN)) {
554 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
556 ad_close( adp, ADFLAGS_HF );
559 LOG(log_info, logtype_afpd, "end getfilparams:");
565 /* ----------------------------- */
566 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
569 int ibuflen, *rbuflen;
571 struct adouble ad, *adp;
574 struct ofork *of = NULL;
576 int creatf, did, openf, retvalue = AFP_OK;
582 LOG(log_info, logtype_afpd, "begin afp_createfile:");
587 creatf = (unsigned char) *ibuf++;
589 memcpy(&vid, ibuf, sizeof( vid ));
590 ibuf += sizeof( vid );
592 if (NULL == ( vol = getvolbyvid( vid )) ) {
593 return( AFPERR_PARAM );
596 if (vol->v_flags & AFPVOL_RO)
599 memcpy(&did, ibuf, sizeof( did));
600 ibuf += sizeof( did );
602 if (NULL == ( dir = dirlookup( vol, did )) ) {
606 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
607 return get_afp_errno(AFPERR_PARAM);
610 if ( *s_path->m_name == '\0' ) {
611 return( AFPERR_BADTYPE );
614 upath = s_path->u_name;
615 if (0 != (ret = check_name(vol, upath)))
618 /* if upath is deleted we already in trouble anyway */
619 if ((of = of_findname(s_path))) {
622 memset(&ad, 0, sizeof(ad));
626 /* on a hard create, fail if file exists and is open */
629 openf = O_RDWR|O_CREAT|O_TRUNC;
631 /* on a soft create, if the file is open then ad_open won't fail
632 because open syscall is not called
637 openf = O_RDWR|O_CREAT|O_EXCL;
640 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
641 openf, 0666, adp) < 0 ) {
645 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
646 return ( AFPERR_NOOBJ );
648 return( AFPERR_EXIST );
650 return( AFPERR_ACCESS );
652 return( AFPERR_PARAM );
655 if ( ad_hfileno( adp ) == -1 ) {
656 /* on noadouble volumes, just creating the data fork is ok */
657 if (vol_noadouble(vol)) {
658 ad_close( adp, ADFLAGS_DF );
659 goto createfile_done;
661 /* FIXME with hard create on an existing file, we already
662 * corrupted the data file.
664 netatalk_unlink( upath );
665 ad_close( adp, ADFLAGS_DF );
666 return AFPERR_ACCESS;
669 path = s_path->m_name;
670 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
671 memcpy(ad_entry( adp, ADEID_NAME ), path,
672 ad_getentrylen( adp, ADEID_NAME ));
673 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
674 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
680 if (vol->v_flags & AFPVOL_DROPBOX) {
681 retvalue = matchfile2dirperms(upath, vol, did);
683 #endif /* DROPKLUDGE */
685 setvoltime(obj, vol );
688 LOG(log_info, logtype_afpd, "end afp_createfile");
694 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
697 int ibuflen, *rbuflen;
703 u_int16_t vid, bitmap;
706 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
712 memcpy(&vid, ibuf, sizeof( vid ));
713 ibuf += sizeof( vid );
714 if (NULL == ( vol = getvolbyvid( vid )) ) {
715 return( AFPERR_PARAM );
718 if (vol->v_flags & AFPVOL_RO)
721 memcpy(&did, ibuf, sizeof( did ));
722 ibuf += sizeof( did );
723 if (NULL == ( dir = dirlookup( vol, did )) ) {
724 return afp_errno; /* was AFPERR_NOOBJ */
727 memcpy(&bitmap, ibuf, sizeof( bitmap ));
728 bitmap = ntohs( bitmap );
729 ibuf += sizeof( bitmap );
731 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
732 return get_afp_errno(AFPERR_PARAM);
735 if (path_isadir(s_path)) {
736 return( AFPERR_BADTYPE ); /* it's a directory */
739 if ( s_path->st_errno != 0 ) {
740 return( AFPERR_NOOBJ );
743 if ((u_long)ibuf & 1 ) {
747 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
748 setvoltime(obj, vol );
752 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
759 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
762 extern struct path Cur_Path;
764 int setfilparams(struct vol *vol,
765 struct path *path, u_int16_t bitmap, char *buf )
767 struct adouble ad, *adp;
770 int bit = 0, isad = 1, err = AFP_OK;
772 u_char achar, *fdType, xyy[4];
773 u_int16_t ashort, bshort;
777 int change_mdate = 0;
778 int change_parent_mdate = 0;
784 LOG(log_info, logtype_afpd, "begin setfilparams:");
787 upath = path->u_name;
788 if ((of = of_findname(path))) {
791 memset(&ad, 0, sizeof(ad));
795 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
796 return AFPERR_ACCESS;
799 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
800 O_RDWR|O_CREAT, 0666, adp) < 0) {
801 /* for some things, we don't need an adouble header */
802 if (bitmap & ~(1<<FILPBIT_MDATE)) {
803 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
806 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
807 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
808 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
809 ad_getentrylen( adp, ADEID_NAME ));
812 while ( bitmap != 0 ) {
813 while (( bitmap & 1 ) == 0 ) {
821 memcpy(&ashort, buf, sizeof( ashort ));
822 ad_getattr(adp, &bshort);
823 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
824 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
828 if ((ashort & htons(ATTRBIT_INVISIBLE)))
829 change_parent_mdate = 1;
830 ad_setattr(adp, bshort);
831 buf += sizeof( ashort );
836 memcpy(&aint, buf, sizeof(aint));
837 ad_setdate(adp, AD_DATE_CREATE, aint);
838 buf += sizeof( aint );
842 memcpy(&newdate, buf, sizeof( newdate ));
843 buf += sizeof( newdate );
848 memcpy(&aint, buf, sizeof(aint));
849 ad_setdate(adp, AD_DATE_BACKUP, aint);
850 buf += sizeof( aint );
856 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
858 ((em = getextmap( path->m_name )) &&
859 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
860 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
861 || ((em = getdefextmap()) &&
862 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
863 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
865 memcpy(buf, ufinderi, 8 );
868 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
872 /* Client needs to set the ProDOS file info for this file.
873 Use a defined string for TEXT to support crlf
874 translations and convert all else into pXYY per Inside
875 Appletalk. Always set the creator as "pdos". Changes
876 from original by Marsha Jackson. */
877 case FILPBIT_PDINFO :
878 if (afp_version < 30) { /* else it's UTF8 name */
881 /* Keep special case to support crlf translations */
882 if ((unsigned int) achar == 0x04) {
883 fdType = (u_char *)"TEXT";
886 xyy[0] = ( u_char ) 'p';
892 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
893 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
897 case FILPBIT_UNIXPR :
898 /* Skip the UIG/GID, no way to set them from OSX clients */
899 buf += sizeof( aint );
900 buf += sizeof( aint );
903 change_parent_mdate = 1;
904 memcpy( &aint, buf, sizeof( aint ));
905 buf += sizeof( aint );
908 setfilemode(path, aint);
912 goto setfilparam_done;
920 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
921 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
925 ad_setdate(adp, AD_DATE_MODIFY, newdate);
926 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
931 ad_flush( adp, ADFLAGS_HF );
932 ad_close( adp, ADFLAGS_HF );
936 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
937 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
938 bitmap = 1<<FILPBIT_MDATE;
939 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
943 LOG(log_info, logtype_afpd, "end setfilparams:");
949 * renamefile and copyfile take the old and new unix pathnames
950 * and the new mac name.
952 * src the source path
953 * dst the dest filename in current dir
954 * newname the dest mac name
955 * adp adouble struct of src file, if open, or & zeroed one
958 int renamefile(src, dst, newname, noadouble, adp )
959 char *src, *dst, *newname;
963 char adsrc[ MAXPATHLEN + 1];
968 LOG(log_info, logtype_afpd, "begin renamefile:");
971 if ( unix_rename( src, dst ) < 0 ) {
974 return( AFPERR_NOOBJ );
977 return( AFPERR_ACCESS );
980 case EXDEV : /* Cross device move -- try copy */
981 /* NOTE: with open file it's an error because after the copy we will
982 * get two files, it's fixable for our process (eg reopen the new file, get the
983 * locks, and so on. But it doesn't solve the case with a second process
985 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
986 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
987 return AFPERR_OLOCK; /* little lie */
989 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
990 /* on error copyfile delete dest */
993 return deletefile(NULL, src, 0);
995 return( AFPERR_PARAM );
999 strcpy( adsrc, ad_path( src, 0 ));
1001 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
1006 if (errno == ENOENT) {
1009 if (stat(adsrc, &st)) /* source has no ressource fork, */
1012 /* We are here because :
1013 * -there's no dest folder.
1014 * -there's no .AppleDouble in the dest folder.
1015 * if we use the struct adouble passed in parameter it will not
1016 * create .AppleDouble if the file is already opened, so we
1017 * use a diff one, it's not a pb,ie it's not the same file, yet.
1019 memset(&ad, 0, sizeof(ad));
1020 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1021 ad_close(&ad, ADFLAGS_HF);
1022 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
1027 else { /* it's something else, bail out */
1031 /* try to undo the data fork rename,
1032 * we know we are on the same device
1035 unix_rename( dst, src );
1036 /* return the first error */
1039 return AFPERR_NOOBJ;
1042 return AFPERR_ACCESS ;
1044 return AFPERR_VLOCK;
1046 return AFPERR_PARAM ;
1051 /* don't care if we can't open the newly renamed ressource fork
1053 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1054 len = strlen( newname );
1055 ad_setentrylen( adp, ADEID_NAME, len );
1056 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1057 ad_flush( adp, ADFLAGS_HF );
1058 ad_close( adp, ADFLAGS_HF );
1061 LOG(log_info, logtype_afpd, "end renamefile:");
1067 int copy_path_name(char *newname, char *ibuf)
1074 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1080 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1081 strncpy( newname, ibuf, plen );
1082 newname[ plen ] = '\0';
1083 if (strlen(newname) != plen) {
1084 /* there's \0 in newname, e.g. it's a pathname not
1092 memcpy(&hint, ibuf, sizeof(hint));
1093 ibuf += sizeof(hint);
1095 memcpy(&len16, ibuf, sizeof(len16));
1096 ibuf += sizeof(len16);
1097 plen = ntohs(len16);
1100 if (plen > AFPOBJ_TMPSIZ) {
1103 strncpy( newname, ibuf, plen );
1104 newname[ plen ] = '\0';
1105 if (strlen(newname) != plen) {
1114 /* -----------------------------------
1116 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1119 int ibuflen, *rbuflen;
1123 char *newname, *p, *upath;
1124 struct path *s_path;
1125 u_int32_t sdid, ddid;
1126 int err, retvalue = AFP_OK;
1127 u_int16_t svid, dvid;
1130 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1136 memcpy(&svid, ibuf, sizeof( svid ));
1137 ibuf += sizeof( svid );
1138 if (NULL == ( vol = getvolbyvid( svid )) ) {
1139 return( AFPERR_PARAM );
1142 memcpy(&sdid, ibuf, sizeof( sdid ));
1143 ibuf += sizeof( sdid );
1144 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1148 memcpy(&dvid, ibuf, sizeof( dvid ));
1149 ibuf += sizeof( dvid );
1150 memcpy(&ddid, ibuf, sizeof( ddid ));
1151 ibuf += sizeof( ddid );
1153 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1154 return get_afp_errno(AFPERR_PARAM);
1156 if ( path_isadir(s_path) ) {
1157 return( AFPERR_BADTYPE );
1160 /* don't allow copies when the file is open.
1161 * XXX: the spec only calls for read/deny write access.
1162 * however, copyfile doesn't have any of that info,
1163 * and locks need to stay coherent. as a result,
1164 * we just balk if the file is opened already. */
1166 newname = obj->newtmp;
1167 strcpy( newname, s_path->m_name );
1169 if (of_findname(s_path))
1170 return AFPERR_DENYCONF;
1172 p = ctoupath( vol, curdir, newname );
1174 return AFPERR_PARAM;
1178 /* FIXME svid != dvid && dvid's user can't read svid */
1180 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1181 return( AFPERR_PARAM );
1184 if (vol->v_flags & AFPVOL_RO)
1185 return AFPERR_VLOCK;
1187 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1191 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1192 return get_afp_errno(AFPERR_NOOBJ);
1194 if ( *s_path->m_name != '\0' ) {
1196 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1198 path_error(s_path, AFPERR_PARAM);
1201 /* one of the handful of places that knows about the path type */
1202 if (copy_path_name(newname, ibuf) < 0) {
1203 return( AFPERR_PARAM );
1206 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1207 return( AFPERR_PARAM );
1209 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1215 if (vol->v_flags & AFPVOL_DROPBOX) {
1216 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1218 #endif /* DROPKLUDGE */
1220 setvoltime(obj, vol );
1223 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1230 static __inline__ int copy_all(const int dfd, const void *buf,
1236 LOG(log_info, logtype_afpd, "begin copy_all:");
1239 while (buflen > 0) {
1240 if ((cc = write(dfd, buf, buflen)) < 0) {
1247 return AFPERR_DFULL;
1249 return AFPERR_VLOCK;
1251 return AFPERR_PARAM;
1258 LOG(log_info, logtype_afpd, "end copy_all:");
1264 /* -------------------------- */
1265 static int copy_fd(int dfd, int sfd)
1271 #ifdef SENDFILE_FLAVOR_LINUX
1274 if (fstat(sfd, &st) == 0) {
1275 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1277 case EINVAL: /* there's no guarantee that all fs support sendfile */
1282 return AFPERR_DFULL;
1284 return AFPERR_VLOCK;
1286 return AFPERR_PARAM;
1293 #endif /* SENDFILE_FLAVOR_LINUX */
1296 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1303 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1309 /* ----------------------------------
1310 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1311 * because we are doing it elsewhere.
1313 int copyfile(src, dst, newname, noadouble )
1314 char *src, *dst, *newname;
1315 const int noadouble;
1317 struct adouble ads, add;
1318 int len, err = AFP_OK;
1322 LOG(log_info, logtype_afpd, "begin copyfile:");
1325 memset(&ads, 0, sizeof(ads));
1326 memset(&add, 0, sizeof(add));
1327 adflags = ADFLAGS_DF;
1329 adflags |= ADFLAGS_HF;
1332 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1335 return( AFPERR_NOOBJ );
1337 return( AFPERR_ACCESS );
1339 return( AFPERR_PARAM );
1342 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1343 ad_close( &ads, adflags );
1344 if (EEXIST != (err = errno)) {
1345 deletefile(NULL, dst, 0);
1349 return AFPERR_EXIST;
1351 return( AFPERR_NOOBJ );
1353 return( AFPERR_ACCESS );
1355 return AFPERR_VLOCK;
1357 return( AFPERR_PARAM );
1360 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1361 /* copy the data fork */
1362 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1366 len = strlen( newname );
1367 ad_setentrylen( &add, ADEID_NAME, len );
1368 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1371 ad_close( &ads, adflags );
1372 ad_flush( &add, adflags );
1373 if (ad_close( &add, adflags ) <0) {
1376 if (err != AFP_OK) {
1377 deletefile(NULL, dst, 0);
1380 return( AFPERR_NOOBJ );
1382 return( AFPERR_ACCESS );
1384 return( AFPERR_PARAM );
1389 LOG(log_info, logtype_afpd, "end copyfile:");
1396 /* -----------------------------------
1397 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1398 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1400 when deletefile is called we don't have lock on it, file is closed (for us)
1401 untrue if called by renamefile
1403 ad_open always try to open file RDWR first and ad_lock takes care of
1404 WRITE lock on read only file.
1406 int deletefile( vol, file, checkAttrib )
1412 int adflags, err = AFP_OK;
1415 LOG(log_info, logtype_afpd, "begin deletefile:");
1418 /* try to open both forks at once */
1419 adflags = ADFLAGS_DF|ADFLAGS_HF;
1421 memset(&ad, 0, sizeof(ad));
1422 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1425 if (adflags == ADFLAGS_DF)
1426 return AFPERR_NOOBJ;
1428 /* that failed. now try to open just the data fork */
1429 adflags = ADFLAGS_DF;
1433 return AFPERR_ACCESS;
1435 return AFPERR_VLOCK;
1437 return( AFPERR_PARAM );
1440 break; /* from the while */
1443 * Does kFPDeleteInhibitBit (bit 8) set?
1445 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1448 ad_getattr(&ad, &bshort);
1449 if ((bshort & htons(ATTRBIT_NODELETE))) {
1450 ad_close( &ad, adflags );
1451 return(AFPERR_OLOCK);
1455 if ((adflags & ADFLAGS_HF) ) {
1456 /* FIXME we have a pb here because we want to know if a file is open
1457 * there's a 'priority inversion' if you can't open the ressource fork RW
1458 * you can delete it if it's open because you can't get a write lock.
1460 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1463 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1465 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1466 ad_close( &ad, adflags );
1467 return( AFPERR_BUSY );
1471 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1474 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1475 !(err = netatalk_unlink( file )) ) {
1476 #ifdef CNID_DB /* get rid of entry */
1478 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1480 cnid_delete(vol->v_db, id);
1482 #endif /* CNID_DB */
1485 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1488 LOG(log_info, logtype_afpd, "end deletefile:");
1494 /* ------------------------------------ */
1496 /* return a file id */
1497 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1500 int ibuflen, *rbuflen;
1509 struct path *s_path;
1512 LOG(log_info, logtype_afpd, "begin afp_createid:");
1519 memcpy(&vid, ibuf, sizeof(vid));
1520 ibuf += sizeof(vid);
1522 if (NULL == ( vol = getvolbyvid( vid )) ) {
1523 return( AFPERR_PARAM);
1526 if (vol->v_db == NULL) {
1530 if (vol->v_flags & AFPVOL_RO)
1531 return AFPERR_VLOCK;
1533 memcpy(&did, ibuf, sizeof( did ));
1534 ibuf += sizeof(did);
1536 if (NULL == ( dir = dirlookup( vol, did )) ) {
1537 return afp_errno; /* was AFPERR_PARAM */
1540 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1541 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1544 if ( path_isadir(s_path) ) {
1545 return( AFPERR_BADTYPE );
1548 upath = s_path->u_name;
1549 switch (s_path->st_errno) {
1551 break; /* success */
1554 return AFPERR_ACCESS;
1556 return AFPERR_NOOBJ;
1558 return AFPERR_PARAM;
1561 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1562 memcpy(rbuf, &id, sizeof(id));
1563 *rbuflen = sizeof(id);
1564 return AFPERR_EXISTID;
1567 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1568 memcpy(rbuf, &id, sizeof(id));
1569 *rbuflen = sizeof(id);
1574 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1579 /* ------------------------------
1580 resolve a file id */
1581 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1584 int ibuflen, *rbuflen;
1592 u_int16_t vid, bitmap;
1594 static char buffer[12 + MAXPATHLEN + 1];
1595 int len = 12 + MAXPATHLEN + 1;
1598 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1604 memcpy(&vid, ibuf, sizeof(vid));
1605 ibuf += sizeof(vid);
1607 if (NULL == ( vol = getvolbyvid( vid )) ) {
1608 return( AFPERR_PARAM);
1611 if (vol->v_db == NULL) {
1615 memcpy(&id, ibuf, sizeof( id ));
1618 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1619 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1622 if (NULL == ( dir = dirlookup( vol, id )) ) {
1623 return AFPERR_NOID; /* idem AFPERR_PARAM */
1625 path.u_name = upath;
1626 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1630 return AFPERR_ACCESS;
1634 return AFPERR_PARAM;
1637 /* directories are bad */
1638 if (S_ISDIR(path.st.st_mode))
1639 return AFPERR_BADTYPE;
1641 memcpy(&bitmap, ibuf, sizeof(bitmap));
1642 bitmap = ntohs( bitmap );
1643 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1646 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1647 rbuf + sizeof(bitmap), &buflen))) {
1650 *rbuflen = buflen + sizeof(bitmap);
1651 memcpy(rbuf, ibuf, sizeof(bitmap));
1654 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1660 /* ------------------------------ */
1661 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1664 int ibuflen, *rbuflen;
1674 static char buffer[12 + MAXPATHLEN + 1];
1675 int len = 12 + MAXPATHLEN + 1;
1678 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1684 memcpy(&vid, ibuf, sizeof(vid));
1685 ibuf += sizeof(vid);
1687 if (NULL == ( vol = getvolbyvid( vid )) ) {
1688 return( AFPERR_PARAM);
1691 if (vol->v_db == NULL) {
1695 if (vol->v_flags & AFPVOL_RO)
1696 return AFPERR_VLOCK;
1698 memcpy(&id, ibuf, sizeof( id ));
1702 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1706 if (NULL == ( dir = dirlookup( vol, id )) ) {
1707 return( AFPERR_PARAM );
1711 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1715 return AFPERR_ACCESS;
1717 /* still try to delete the id */
1721 return AFPERR_PARAM;
1724 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1725 return AFPERR_BADTYPE;
1727 if (cnid_delete(vol->v_db, fileid)) {
1730 return AFPERR_VLOCK;
1733 return AFPERR_ACCESS;
1735 return AFPERR_PARAM;
1740 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1745 #endif /* CNID_DB */
1747 #define APPLETEMP ".AppleTempXXXXXX"
1749 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1752 int ibuflen, *rbuflen;
1754 struct stat srcst, destst;
1756 struct dir *dir, *sdir;
1757 char *spath, temp[17], *p;
1758 char *supath, *upath;
1763 struct adouble *adsp;
1764 struct adouble *addp;
1771 #endif /* CNID_DB */
1776 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1782 memcpy(&vid, ibuf, sizeof(vid));
1783 ibuf += sizeof(vid);
1785 if (NULL == ( vol = getvolbyvid( vid )) ) {
1786 return( AFPERR_PARAM);
1789 if (vol->v_flags & AFPVOL_RO)
1790 return AFPERR_VLOCK;
1792 /* source and destination dids */
1793 memcpy(&sid, ibuf, sizeof(sid));
1794 ibuf += sizeof(sid);
1795 memcpy(&did, ibuf, sizeof(did));
1796 ibuf += sizeof(did);
1799 if (NULL == (dir = dirlookup( vol, sid )) ) {
1800 return afp_errno; /* was AFPERR_PARAM */
1803 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1804 return get_afp_errno(AFPERR_NOOBJ);
1807 if ( path_isadir(path) ) {
1808 return( AFPERR_BADTYPE ); /* it's a dir */
1811 upath = path->u_name;
1812 switch (path->st_errno) {
1819 return AFPERR_ACCESS;
1821 return AFPERR_PARAM;
1823 memset(&ads, 0, sizeof(ads));
1825 if ((s_of = of_findname(path))) {
1826 /* reuse struct adouble so it won't break locks */
1829 memcpy(&srcst, &path->st, sizeof(struct stat));
1830 /* save some stuff */
1832 spath = obj->oldtmp;
1833 supath = obj->newtmp;
1834 strcpy(spath, path->m_name);
1835 strcpy(supath, upath); /* this is for the cnid changing */
1836 p = absupath( vol, sdir, upath);
1838 /* pathname too long */
1839 return AFPERR_PARAM ;
1842 /* look for the source cnid. if it doesn't exist, don't worry about
1845 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1846 slen = strlen(supath));
1847 #endif /* CNID_DB */
1849 if (NULL == ( dir = dirlookup( vol, did )) ) {
1850 return afp_errno; /* was AFPERR_PARAM */
1853 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1854 return get_afp_errno(AFPERR_NOOBJ);
1857 if ( path_isadir(path) ) {
1858 return( AFPERR_BADTYPE );
1861 /* FPExchangeFiles is the only call that can return the SameObj
1863 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1864 return AFPERR_SAMEOBJ;
1866 switch (path->st_errno) {
1873 return AFPERR_ACCESS;
1875 return AFPERR_PARAM;
1877 memset(&add, 0, sizeof(add));
1879 if ((d_of = of_findname( path))) {
1880 /* reuse struct adouble so it won't break locks */
1883 memcpy(&destst, &path->st, sizeof(struct stat));
1885 /* they are not on the same device and at least one is open
1887 crossdev = (srcst.st_dev != destst.st_dev);
1888 if ((d_of || s_of) && crossdev)
1891 upath = path->u_name;
1893 /* look for destination id. */
1894 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1895 dlen = strlen(upath));
1896 #endif /* CNID_DB */
1898 /* construct a temp name.
1899 * NOTE: the temp file will be in the dest file's directory. it
1900 * will also be inaccessible from AFP. */
1901 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1905 /* now, quickly rename the file. we error if we can't. */
1906 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1907 goto err_exchangefile;
1908 of_rename(vol, s_of, sdir, spath, curdir, temp);
1910 /* rename destination to source */
1911 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1912 goto err_src_to_tmp;
1913 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1915 /* rename temp to destination */
1916 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1917 goto err_dest_to_src;
1918 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1921 /* id's need switching. src -> dest and dest -> src.
1922 * we need to re-stat() if it was a cross device copy.
1925 cnid_delete(vol->v_db, sid);
1928 cnid_delete(vol->v_db, did);
1930 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1931 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1933 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1934 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1939 err = AFPERR_ACCESS;
1944 goto err_temp_to_dest;
1946 #endif /* CNID_DB */
1949 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1955 /* all this stuff is so that we can unwind a failed operation
1960 /* rename dest to temp */
1961 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1962 of_rename(vol, s_of, curdir, upath, curdir, temp);
1965 /* rename source back to dest */
1966 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1967 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1970 /* rename temp back to source */
1971 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1972 of_rename(vol, s_of, curdir, temp, sdir, spath);