2 * $Id: file.c,v 1.92.2.2.2.31.2.22 2008-11-25 15:16:33 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[ADEDLEN_FINDERI] = {
72 0, 0, 0, 0, 0, 0, 0, 0,
73 1, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0
78 static const u_char old_ufinderi[] = {
79 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
82 /* ----------------------
84 static int default_type(void *finder)
86 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
95 void *ad_finder = NULL;
99 ad_finder = ad_entry(adp, ADEID_FINDERI);
102 memcpy(data, ad_finder, ADEDLEN_FINDERI);
104 if (default_type(ad_finder))
108 memcpy(data, ufinderi, ADEDLEN_FINDERI);
110 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
117 /** Only enter if no appledouble information and no finder information found. */
118 if (chk_ext && (em = getextmap( upath ))) {
119 memcpy(data, em->em_type, sizeof( em->em_type ));
120 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
125 /* ---------------------
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
132 aint = strlen( name );
136 if (utf8_encoding()) {
137 /* but name is an utf8 mac name */
140 /* global static variable... */
142 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
151 if (aint > MACFILELEN)
158 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
161 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
162 memcpy(data, &utf8, sizeof(utf8));
163 data += sizeof(utf8);
166 memcpy(data, &temp, sizeof(temp));
167 data += sizeof(temp);
170 memcpy( data, src, aint );
180 * FIXME: PDINFO is UTF8 and doesn't need adp
182 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
183 (1 << FILPBIT_CDATE) |\
184 (1 << FILPBIT_MDATE) |\
185 (1 << FILPBIT_BDATE) |\
186 (1 << FILPBIT_FINFO) |\
187 (1 << FILPBIT_RFLEN) |\
188 (1 << FILPBIT_EXTRFLEN) |\
189 (1 << FILPBIT_PDINFO) |\
190 (1 << FILPBIT_UNIXPR)))
192 /* -------------------------- */
193 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
194 const cnid_t did, char *upath, const int len)
198 #if AD_VERSION > AD_VERSION1
200 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
205 if (vol->v_cdb != NULL) {
206 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
207 /* Throw errors if cnid_add fails. */
208 if (aint == CNID_INVALID) {
210 case CNID_ERR_CLOSE: /* the db is closed */
213 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
214 afp_errno = AFPERR_PARAM;
217 afp_errno = AFPERR_PARAM;
220 afp_errno = AFPERR_MISC;
224 #if AD_VERSION > AD_VERSION1
226 /* update the ressource fork
227 * for a folder adp is always null
229 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
230 ad_flush(adp, ADFLAGS_HF);
238 /* -------------------------- */
239 int getmetadata(struct vol *vol,
241 struct path *path, struct dir *dir,
242 char *buf, int *buflen, struct adouble *adp, int attrbits )
244 char *data, *l_nameoff = NULL, *upath;
245 char *utf_nameoff = NULL;
250 u_char achar, fdType[4];
256 LOG(log_info, logtype_afpd, "begin getmetadata:");
259 upath = path->u_name;
264 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
265 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
266 || (bitmap & (1 << FILPBIT_FNUM))) {
268 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
272 path->m_name = utompath(vol, upath, id, utf8_encoding());
275 while ( bitmap != 0 ) {
276 while (( bitmap & 1 ) == 0 ) {
284 ad_getattr(adp, &ashort);
285 } else if (vol_inv_dots(vol) && *upath == '.') {
286 ashort = htons(ATTRBIT_INVISIBLE);
290 /* FIXME do we want a visual clue if the file is read only
293 accessmode( ".", &ma, dir , NULL);
294 if ((ma.ma_user & AR_UWRITE)) {
295 accessmode( upath, &ma, dir , st);
296 if (!(ma.ma_user & AR_UWRITE)) {
297 attrbits |= ATTRBIT_NOWRITE;
302 ashort = htons(ntohs(ashort) | attrbits);
303 memcpy(data, &ashort, sizeof( ashort ));
304 data += sizeof( ashort );
308 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
309 data += sizeof( u_int32_t );
313 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
314 aint = AD_DATE_FROM_UNIX(st->st_mtime);
315 memcpy(data, &aint, sizeof( aint ));
316 data += sizeof( aint );
320 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
321 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
325 aint = AD_DATE_FROM_UNIX(st->st_mtime);
327 memcpy(data, &aint, sizeof( int ));
328 data += sizeof( int );
332 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
333 aint = AD_DATE_START;
334 memcpy(data, &aint, sizeof( int ));
335 data += sizeof( int );
339 get_finderinfo(vol, upath, adp, (char *)data);
340 data += ADEDLEN_FINDERI;
345 data += sizeof( u_int16_t );
349 memset(data, 0, sizeof(u_int16_t));
350 data += sizeof( u_int16_t );
354 memcpy(data, &id, sizeof( id ));
355 data += sizeof( id );
359 if (st->st_size > 0xffffffff)
362 aint = htonl( st->st_size );
363 memcpy(data, &aint, sizeof( aint ));
364 data += sizeof( aint );
369 if (adp->ad_rlen > 0xffffffff)
372 aint = htonl( adp->ad_rlen);
376 memcpy(data, &aint, sizeof( aint ));
377 data += sizeof( aint );
380 /* Current client needs ProDOS info block for this file.
381 Use simple heuristic and let the Mac "type" string tell
382 us what the PD file code should be. Everything gets a
383 subtype of 0x0000 unless the original value was hashed
384 to "pXYZ" when we created it. See IA, Ver 2.
385 <shirsch@adelphia.net> */
386 case FILPBIT_PDINFO :
387 if (afp_version >= 30) { /* UTF8 name */
388 utf8 = kTextEncodingUTF8;
390 data += sizeof( u_int16_t );
392 memcpy(data, &aint, sizeof( aint ));
393 data += sizeof( aint );
397 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
399 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
403 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
407 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
411 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
415 else if ( fdType[0] == 'p' ) {
417 ashort = (fdType[2] * 256) + fdType[3];
431 memcpy(data, &ashort, sizeof( ashort ));
432 data += sizeof( ashort );
433 memset(data, 0, sizeof( ashort ));
434 data += sizeof( ashort );
437 case FILPBIT_EXTDFLEN:
438 aint = htonl(st->st_size >> 32);
439 memcpy(data, &aint, sizeof( aint ));
440 data += sizeof( aint );
441 aint = htonl(st->st_size);
442 memcpy(data, &aint, sizeof( aint ));
443 data += sizeof( aint );
445 case FILPBIT_EXTRFLEN:
448 aint = htonl(adp->ad_rlen >> 32);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 aint = htonl(adp->ad_rlen);
453 memcpy(data, &aint, sizeof( aint ));
454 data += sizeof( aint );
456 case FILPBIT_UNIXPR :
457 /* accessmode may change st_mode with ACLs */
458 accessmode( upath, &ma, dir , st);
460 aint = htonl(st->st_uid);
461 memcpy( data, &aint, sizeof( aint ));
462 data += sizeof( aint );
463 aint = htonl(st->st_gid);
464 memcpy( data, &aint, sizeof( aint ));
465 data += sizeof( aint );
468 type == slnk indicates an OSX style symlink,
469 we have to add S_IFLNK to the mode, otherwise
470 10.3 clients freak out. */
474 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
475 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
481 memcpy( data, &aint, sizeof( aint ));
482 data += sizeof( aint );
484 *data++ = ma.ma_user;
485 *data++ = ma.ma_world;
486 *data++ = ma.ma_group;
487 *data++ = ma.ma_owner;
491 return( AFPERR_BITMAP );
497 ashort = htons( data - buf );
498 memcpy(l_nameoff, &ashort, sizeof( ashort ));
499 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
502 ashort = htons( data - buf );
503 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
504 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
506 *buflen = data - buf;
510 /* ----------------------- */
511 int getfilparams(struct vol *vol,
513 struct path *path, struct dir *dir,
514 char *buf, int *buflen )
516 struct adouble ad, *adp;
519 u_int16_t attrbits = 0;
524 LOG(log_info, logtype_default, "begin getfilparams:");
527 opened = PARAM_NEED_ADP(bitmap);
530 upath = path->u_name;
531 if ((of = of_findname(path))) {
533 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
534 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
536 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
540 if ( ad_metadata( upath, 0, adp) < 0 ) {
543 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
544 upath, strerror(errno));
545 return AFPERR_ACCESS;
547 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
557 we need to check if the file is open by another process.
558 it's slow so we only do it if we have to:
559 - bitmap is requested.
560 - we don't already have the answer!
562 if ((bitmap & (1 << FILPBIT_ATTR))) {
563 if (!(attrbits & ATTRBIT_ROPEN)) {
564 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
565 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
567 if (!(attrbits & ATTRBIT_DOPEN)) {
568 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
569 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
574 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
576 ad_close( adp, ADFLAGS_HF );
579 LOG(log_info, logtype_afpd, "end getfilparams:");
585 /* ----------------------------- */
586 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
588 char *ibuf, *rbuf _U_;
589 int ibuflen _U_, *rbuflen;
591 struct adouble ad, *adp;
594 struct ofork *of = NULL;
596 int creatf, did, openf, retvalue = AFP_OK;
602 LOG(log_info, logtype_afpd, "begin afp_createfile:");
607 creatf = (unsigned char) *ibuf++;
609 memcpy(&vid, ibuf, sizeof( vid ));
610 ibuf += sizeof( vid );
612 if (NULL == ( vol = getvolbyvid( vid )) ) {
613 return( AFPERR_PARAM );
616 if (vol->v_flags & AFPVOL_RO)
619 memcpy(&did, ibuf, sizeof( did));
620 ibuf += sizeof( did );
622 if (NULL == ( dir = dirlookup( vol, did )) ) {
626 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
627 return get_afp_errno(AFPERR_PARAM);
630 if ( *s_path->m_name == '\0' ) {
631 return( AFPERR_BADTYPE );
634 upath = s_path->u_name;
635 if (0 != (ret = check_name(vol, upath)))
638 /* if upath is deleted we already in trouble anyway */
639 if ((of = of_findname(s_path))) {
642 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
646 /* on a hard create, fail if file exists and is open */
649 openf = O_RDWR|O_CREAT|O_TRUNC;
651 /* on a soft create, if the file is open then ad_open won't fail
652 because open syscall is not called
657 openf = O_RDWR|O_CREAT|O_EXCL;
660 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
661 openf, 0666, adp) < 0 ) {
665 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
666 return ( AFPERR_NOOBJ );
668 return( AFPERR_EXIST );
670 return( AFPERR_ACCESS );
673 return( AFPERR_DFULL );
675 return( AFPERR_PARAM );
678 if ( ad_hfileno( adp ) == -1 ) {
679 /* on noadouble volumes, just creating the data fork is ok */
680 if (vol_noadouble(vol)) {
681 ad_close( adp, ADFLAGS_DF );
682 goto createfile_done;
684 /* FIXME with hard create on an existing file, we already
685 * corrupted the data file.
687 netatalk_unlink( upath );
688 ad_close( adp, ADFLAGS_DF );
689 return AFPERR_ACCESS;
692 path = s_path->m_name;
693 ad_setname(adp, path);
694 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
695 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
701 if (vol->v_flags & AFPVOL_DROPBOX) {
702 retvalue = matchfile2dirperms(upath, vol, did);
704 #endif /* DROPKLUDGE */
706 setvoltime(obj, vol );
709 LOG(log_info, logtype_afpd, "end afp_createfile");
715 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
717 char *ibuf, *rbuf _U_;
718 int ibuflen _U_, *rbuflen;
724 u_int16_t vid, bitmap;
727 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
733 memcpy(&vid, ibuf, sizeof( vid ));
734 ibuf += sizeof( vid );
735 if (NULL == ( vol = getvolbyvid( vid )) ) {
736 return( AFPERR_PARAM );
739 if (vol->v_flags & AFPVOL_RO)
742 memcpy(&did, ibuf, sizeof( did ));
743 ibuf += sizeof( did );
744 if (NULL == ( dir = dirlookup( vol, did )) ) {
745 return afp_errno; /* was AFPERR_NOOBJ */
748 memcpy(&bitmap, ibuf, sizeof( bitmap ));
749 bitmap = ntohs( bitmap );
750 ibuf += sizeof( bitmap );
752 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
753 return get_afp_errno(AFPERR_PARAM);
756 if (path_isadir(s_path)) {
757 return( AFPERR_BADTYPE ); /* it's a directory */
760 if ( s_path->st_errno != 0 ) {
761 return( AFPERR_NOOBJ );
764 if ((u_long)ibuf & 1 ) {
768 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
769 setvoltime(obj, vol );
773 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
780 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
783 extern struct path Cur_Path;
785 int setfilparams(struct vol *vol,
786 struct path *path, u_int16_t f_bitmap, char *buf )
788 struct adouble ad, *adp;
790 int bit, isad = 1, err = AFP_OK;
792 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
793 u_int16_t ashort, bshort;
796 u_int16_t upriv_bit = 0;
800 int change_mdate = 0;
801 int change_parent_mdate = 0;
806 u_int16_t bitmap = f_bitmap;
807 u_int32_t cdate,bdate;
808 u_char finder_buf[32];
811 LOG(log_info, logtype_afpd, "begin setfilparams:");
814 upath = path->u_name;
815 adp = of_ad(vol, path, &ad);
818 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
819 return AFPERR_ACCESS;
822 /* with unix priv maybe we have to change adouble file priv first */
824 while ( bitmap != 0 ) {
825 while (( bitmap & 1 ) == 0 ) {
832 memcpy(&ashort, buf, sizeof( ashort ));
833 buf += sizeof( ashort );
837 memcpy(&cdate, buf, sizeof(cdate));
838 buf += sizeof( cdate );
841 memcpy(&newdate, buf, sizeof( newdate ));
842 buf += sizeof( newdate );
846 memcpy(&bdate, buf, sizeof( bdate));
847 buf += sizeof( bdate );
851 memcpy(finder_buf, buf, 32 );
854 case FILPBIT_UNIXPR :
855 if (!vol_unix_priv(vol)) {
856 /* this volume doesn't use unix priv */
862 change_parent_mdate = 1;
864 memcpy( &aint, buf, sizeof( aint ));
865 f_uid = ntohl (aint);
866 buf += sizeof( aint );
867 memcpy( &aint, buf, sizeof( aint ));
868 f_gid = ntohl (aint);
869 buf += sizeof( aint );
870 setfilowner(vol, f_uid, f_gid, path);
872 memcpy( &upriv, buf, sizeof( upriv ));
873 buf += sizeof( upriv );
874 upriv = ntohl (upriv);
875 if ((upriv & S_IWUSR)) {
876 setfilunixmode(vol, path, upriv);
883 case FILPBIT_PDINFO :
884 if (afp_version < 30) { /* else it's UTF8 name */
887 /* Keep special case to support crlf translations */
888 if ((unsigned int) achar == 0x04) {
889 fdType = (u_char *)"TEXT";
892 xyy[0] = ( u_char ) 'p';
903 /* break while loop */
912 /* second try with adouble open
914 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
915 O_RDWR|O_CREAT, 0666, adp) < 0) {
916 /* for some things, we don't need an adouble header */
917 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
918 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
921 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
922 ad_setname(adp, path->m_name);
927 while ( bitmap != 0 ) {
928 while (( bitmap & 1 ) == 0 ) {
935 ad_getattr(adp, &bshort);
936 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
937 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
938 change_parent_mdate = 1;
939 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
940 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
944 ad_setattr(adp, bshort);
947 ad_setdate(adp, AD_DATE_CREATE, cdate);
952 ad_setdate(adp, AD_DATE_BACKUP, bdate);
955 if (default_type( ad_entry( adp, ADEID_FINDERI ))
957 ((em = getextmap( path->m_name )) &&
958 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
959 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
960 || ((em = getdefextmap()) &&
961 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
962 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
964 memcpy(finder_buf, ufinderi, 8 );
966 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
968 case FILPBIT_UNIXPR :
970 setfilunixmode(vol, path, upriv);
973 case FILPBIT_PDINFO :
974 if (afp_version < 30) { /* else it's UTF8 name */
975 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
976 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
982 goto setfilparam_done;
989 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
990 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
994 ad_setdate(adp, AD_DATE_MODIFY, newdate);
995 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
1000 ad_flush( adp, ADFLAGS_HF );
1001 ad_close( adp, ADFLAGS_HF );
1005 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1006 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1007 bitmap = 1<<FILPBIT_MDATE;
1008 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1012 LOG(log_info, logtype_afpd, "end setfilparams:");
1018 * renamefile and copyfile take the old and new unix pathnames
1019 * and the new mac name.
1021 * src the source path
1022 * dst the dest filename in current dir
1023 * newname the dest mac name
1024 * adp adouble struct of src file, if open, or & zeroed one
1027 int renamefile(vol, src, dst, newname, adp )
1028 const struct vol *vol;
1029 char *src, *dst, *newname;
1030 struct adouble *adp;
1032 char adsrc[ MAXPATHLEN + 1];
1036 LOG(log_info, logtype_afpd, "begin renamefile:");
1039 if ( unix_rename( src, dst ) < 0 ) {
1042 return( AFPERR_NOOBJ );
1045 return( AFPERR_ACCESS );
1047 return AFPERR_VLOCK;
1048 case EXDEV : /* Cross device move -- try copy */
1049 /* NOTE: with open file it's an error because after the copy we will
1050 * get two files, it's fixable for our process (eg reopen the new file, get the
1051 * locks, and so on. But it doesn't solve the case with a second process
1053 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1054 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1055 return AFPERR_OLOCK; /* little lie */
1057 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1058 /* on error copyfile delete dest */
1061 return deletefile(vol, src, 0);
1063 return( AFPERR_PARAM );
1067 strcpy( adsrc, vol->ad_path( src, 0 ));
1069 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1074 if (errno == ENOENT) {
1077 if (stat(adsrc, &st)) /* source has no ressource fork, */
1080 /* We are here because :
1081 * -there's no dest folder.
1082 * -there's no .AppleDouble in the dest folder.
1083 * if we use the struct adouble passed in parameter it will not
1084 * create .AppleDouble if the file is already opened, so we
1085 * use a diff one, it's not a pb,ie it's not the same file, yet.
1087 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1088 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1089 ad_close(&ad, ADFLAGS_HF);
1090 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1095 else { /* it's something else, bail out */
1099 /* try to undo the data fork rename,
1100 * we know we are on the same device
1103 unix_rename( dst, src );
1104 /* return the first error */
1107 return AFPERR_NOOBJ;
1110 return AFPERR_ACCESS ;
1112 return AFPERR_VLOCK;
1114 return AFPERR_PARAM ;
1119 /* don't care if we can't open the newly renamed ressource fork
1121 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1122 ad_setname(adp, newname);
1123 ad_flush( adp, ADFLAGS_HF );
1124 ad_close( adp, ADFLAGS_HF );
1127 LOG(log_info, logtype_afpd, "end renamefile:");
1134 convert a Mac long name to an utf8 name,
1136 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1140 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1146 /* ---------------- */
1147 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1154 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1160 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1161 if (afp_version >= 30) {
1162 /* convert it to UTF8
1164 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1168 strncpy( newname, ibuf, plen );
1169 newname[ plen ] = '\0';
1171 if (strlen(newname) != plen) {
1172 /* there's \0 in newname, e.g. it's a pathname not
1180 memcpy(&hint, ibuf, sizeof(hint));
1181 ibuf += sizeof(hint);
1183 memcpy(&len16, ibuf, sizeof(len16));
1184 ibuf += sizeof(len16);
1185 plen = ntohs(len16);
1188 if (plen > AFPOBJ_TMPSIZ) {
1191 strncpy( newname, ibuf, plen );
1192 newname[ plen ] = '\0';
1193 if (strlen(newname) != plen) {
1202 /* -----------------------------------
1204 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1206 char *ibuf, *rbuf _U_;
1207 int ibuflen _U_, *rbuflen;
1209 struct vol *s_vol, *d_vol;
1211 char *newname, *p, *upath;
1212 struct path *s_path;
1213 u_int32_t sdid, ddid;
1214 int err, retvalue = AFP_OK;
1215 u_int16_t svid, dvid;
1217 struct adouble ad, *adp;
1221 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1227 memcpy(&svid, ibuf, sizeof( svid ));
1228 ibuf += sizeof( svid );
1229 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1230 return( AFPERR_PARAM );
1233 memcpy(&sdid, ibuf, sizeof( sdid ));
1234 ibuf += sizeof( sdid );
1235 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1239 memcpy(&dvid, ibuf, sizeof( dvid ));
1240 ibuf += sizeof( dvid );
1241 memcpy(&ddid, ibuf, sizeof( ddid ));
1242 ibuf += sizeof( ddid );
1244 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1245 return get_afp_errno(AFPERR_PARAM);
1247 if ( path_isadir(s_path) ) {
1248 return( AFPERR_BADTYPE );
1251 /* don't allow copies when the file is open.
1252 * XXX: the spec only calls for read/deny write access.
1253 * however, copyfile doesn't have any of that info,
1254 * and locks need to stay coherent. as a result,
1255 * we just balk if the file is opened already. */
1257 adp = of_ad(s_vol, s_path, &ad);
1259 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1260 return AFPERR_DENYCONF;
1262 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1263 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1264 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1266 return AFPERR_DENYCONF;
1269 newname = obj->newtmp;
1270 strcpy( newname, s_path->m_name );
1272 p = ctoupath( s_vol, curdir, newname );
1274 return AFPERR_PARAM;
1278 /* FIXME svid != dvid && dvid's user can't read svid */
1280 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1281 return( AFPERR_PARAM );
1284 if (d_vol->v_flags & AFPVOL_RO)
1285 return AFPERR_VLOCK;
1287 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1291 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1292 return get_afp_errno(AFPERR_NOOBJ);
1294 if ( *s_path->m_name != '\0' ) {
1295 path_error(s_path, AFPERR_PARAM);
1298 /* one of the handful of places that knows about the path type */
1299 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1300 return( AFPERR_PARAM );
1302 /* newname is always only a filename so curdir *is* its
1305 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1306 return( AFPERR_PARAM );
1308 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1314 if (vol->v_flags & AFPVOL_DROPBOX) {
1315 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1317 #endif /* DROPKLUDGE */
1319 setvoltime(obj, d_vol );
1322 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1328 /* ----------------------- */
1329 static int copy_all(const int dfd, const void *buf,
1335 LOG(log_info, logtype_afpd, "begin copy_all:");
1338 while (buflen > 0) {
1339 if ((cc = write(dfd, buf, buflen)) < 0) {
1351 LOG(log_info, logtype_afpd, "end copy_all:");
1357 /* -------------------------- */
1358 static int copy_fd(int dfd, int sfd)
1364 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1365 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1369 #define BUF 128*1024*1024
1371 if (fstat(sfd, &st) == 0) {
1374 if ( offset >= st.st_size) {
1377 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1378 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1381 case EINVAL: /* there's no guarantee that all fs support sendfile */
1390 lseek(sfd, offset, SEEK_SET);
1394 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1401 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1408 /* ----------------------------------
1409 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1410 * because we are doing it elsewhere.
1411 * currently if newname is NULL then adp is NULL.
1413 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1414 const struct vol *s_vol, *d_vol;
1415 char *src, *dst, *newname;
1416 struct adouble *adp;
1418 struct adouble ads, add;
1422 int noadouble = vol_noadouble(d_vol);
1427 LOG(log_info, logtype_afpd, "begin copyfile:");
1431 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1434 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1435 adflags = ADFLAGS_DF;
1437 adflags |= ADFLAGS_HF;
1440 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1445 if (ad_hfileno(adp) == -1) {
1446 /* no resource fork, don't create one for dst file */
1447 adflags &= ~ADFLAGS_HF;
1450 stat_result = fstat(ad_dfileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1452 if (stat_result < 0) {
1453 /* unlikely but if fstat fails, the default file mode will be 0666. */
1454 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1457 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1459 ad_close( adp, adflags );
1460 if (EEXIST != ret_err) {
1461 deletefile(d_vol, dst, 0);
1464 return AFPERR_EXIST;
1466 /* XXX if the source and the dest don't use the same resource type it's broken
1468 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1469 /* copy the data fork */
1470 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1473 /* Now, reopen destination file */
1477 ad_close( adp, adflags );
1479 if (ad_close( &add, adflags ) <0) {
1483 deletefile(d_vol, dst, 0);
1487 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1488 /* set the new name in the resource fork */
1489 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1490 if (ad_open(dst , ADFLAGS_HF | noadouble, O_RDWR, 0666, &add) < 0) {
1494 ad_setname(&add, newname);
1495 ad_flush( &add, ADFLAGS_HF );
1496 if (ad_close( &add, ADFLAGS_HF ) <0) {
1503 deletefile(d_vol, dst, 0);
1505 else if (stat_result == 0) {
1506 /* set dest modification date to src date */
1509 ut.actime = ut.modtime = st.st_mtime;
1511 /* FIXME netatalk doesn't use resource fork file date
1512 * but maybe we should set its modtime too.
1517 LOG(log_info, logtype_afpd, "end copyfile:");
1521 switch ( ret_err ) {
1527 return AFPERR_DFULL;
1529 return AFPERR_NOOBJ;
1531 return AFPERR_ACCESS;
1533 return AFPERR_VLOCK;
1535 return AFPERR_PARAM;
1539 /* -----------------------------------
1540 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1541 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1543 when deletefile is called we don't have lock on it, file is closed (for us)
1544 untrue if called by renamefile
1546 ad_open always try to open file RDWR first and ad_lock takes care of
1547 WRITE lock on read only file.
1549 int deletefile( vol, file, checkAttrib )
1550 const struct vol *vol;
1555 struct adouble *adp = &ad;
1556 int adflags, err = AFP_OK;
1559 LOG(log_info, logtype_afpd, "begin deletefile:");
1562 /* try to open both forks at once */
1563 adflags = ADFLAGS_DF|ADFLAGS_HF;
1564 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1566 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1569 if (adflags == ADFLAGS_DF)
1570 return AFPERR_NOOBJ;
1572 /* that failed. now try to open just the data fork */
1573 adflags = ADFLAGS_DF;
1577 adp = NULL; /* maybe it's a file we no rw mode for us */
1578 break; /* was return AFPERR_ACCESS;*/
1580 return AFPERR_VLOCK;
1582 return( AFPERR_PARAM );
1585 break; /* from the while */
1588 * Does kFPDeleteInhibitBit (bit 8) set?
1593 if (adp && (adflags & ADFLAGS_HF)) {
1595 ad_getattr(&ad, &bshort);
1596 if ((bshort & htons(ATTRBIT_NODELETE))) {
1597 ad_close( &ad, adflags );
1598 return(AFPERR_OLOCK);
1602 /* was EACCESS error try to get only metadata */
1603 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1604 if ( ad_metadata( file , 0, &ad) == 0 ) {
1605 ad_getattr(&ad, &bshort);
1606 ad_close( &ad, ADFLAGS_HF );
1607 if ((bshort & htons(ATTRBIT_NODELETE))) {
1608 return AFPERR_OLOCK;
1614 if (adp && (adflags & ADFLAGS_HF) ) {
1615 /* FIXME we have a pb here because we want to know if a file is open
1616 * there's a 'priority inversion' if you can't open the ressource fork RW
1617 * you can delete it if it's open because you can't get a write lock.
1619 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1622 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1624 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1625 ad_close( &ad, adflags );
1626 return( AFPERR_BUSY );
1630 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1633 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1634 !(err = netatalk_unlink( file )) ) {
1636 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1638 cnid_delete(vol->v_cdb, id);
1643 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1646 LOG(log_info, logtype_afpd, "end deletefile:");
1652 /* ------------------------------------ */
1653 /* return a file id */
1654 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1657 int ibuflen _U_, *rbuflen;
1666 struct path *s_path;
1669 LOG(log_info, logtype_afpd, "begin afp_createid:");
1676 memcpy(&vid, ibuf, sizeof(vid));
1677 ibuf += sizeof(vid);
1679 if (NULL == ( vol = getvolbyvid( vid )) ) {
1680 return( AFPERR_PARAM);
1683 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1687 if (vol->v_flags & AFPVOL_RO)
1688 return AFPERR_VLOCK;
1690 memcpy(&did, ibuf, sizeof( did ));
1691 ibuf += sizeof(did);
1693 if (NULL == ( dir = dirlookup( vol, did )) ) {
1694 return afp_errno; /* was AFPERR_PARAM */
1697 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1698 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1701 if ( path_isadir(s_path) ) {
1702 return( AFPERR_BADTYPE );
1705 upath = s_path->u_name;
1706 switch (s_path->st_errno) {
1708 break; /* success */
1711 return AFPERR_ACCESS;
1713 return AFPERR_NOOBJ;
1715 return AFPERR_PARAM;
1718 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1719 memcpy(rbuf, &id, sizeof(id));
1720 *rbuflen = sizeof(id);
1721 return AFPERR_EXISTID;
1724 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1725 memcpy(rbuf, &id, sizeof(id));
1726 *rbuflen = sizeof(id);
1731 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1737 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1745 memset(&path, 0, sizeof(path));
1746 if (vol->v_cdb == NULL) {
1749 if (NULL == ( dp = opendir( name)) ) {
1753 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1754 if (NULL == check_dirent(vol, de->d_name))
1757 if ( stat(de->d_name, &path.st)<0 )
1760 /* update or add to cnid */
1761 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1763 #if AD_VERSION > AD_VERSION1
1764 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1765 struct adouble ad, *adp;
1769 path.u_name = de->d_name;
1771 adp = of_ad(vol, &path, &ad);
1773 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1776 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1777 ad_flush(adp, ADFLAGS_HF);
1779 ad_close(adp, ADFLAGS_HF);
1781 #endif /* AD_VERSION > AD_VERSION1 */
1790 /* ------------------------------
1791 resolve a file id */
1792 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1795 int ibuflen _U_, *rbuflen;
1801 int err, buflen, retry=0;
1803 u_int16_t vid, bitmap;
1805 static char buffer[12 + MAXPATHLEN + 1];
1806 int len = 12 + MAXPATHLEN + 1;
1809 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1815 memcpy(&vid, ibuf, sizeof(vid));
1816 ibuf += sizeof(vid);
1818 if (NULL == ( vol = getvolbyvid( vid )) ) {
1819 return( AFPERR_PARAM);
1822 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1826 memcpy(&id, ibuf, sizeof( id ));
1831 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1835 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1836 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1839 if (NULL == ( dir = dirlookup( vol, id )) ) {
1840 return AFPERR_NOID; /* idem AFPERR_PARAM */
1842 path.u_name = upath;
1843 if (movecwd(vol, dir) < 0) {
1847 return AFPERR_ACCESS;
1851 return AFPERR_PARAM;
1855 if ( of_stat(&path) < 0 ) {
1857 /* with nfs and our working directory is deleted */
1858 if (errno == ESTALE) {
1862 if ( errno == ENOENT && !retry) {
1863 /* cnid db is out of sync, reenumerate the directory and updated ids */
1864 reenumerate_id(vol, ".", id);
1872 return AFPERR_ACCESS;
1876 return AFPERR_PARAM;
1880 /* directories are bad */
1881 if (S_ISDIR(path.st.st_mode))
1882 return AFPERR_BADTYPE;
1884 memcpy(&bitmap, ibuf, sizeof(bitmap));
1885 bitmap = ntohs( bitmap );
1886 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1889 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1890 rbuf + sizeof(bitmap), &buflen))) {
1893 *rbuflen = buflen + sizeof(bitmap);
1894 memcpy(rbuf, ibuf, sizeof(bitmap));
1897 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1903 /* ------------------------------ */
1904 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1906 char *ibuf, *rbuf _U_;
1907 int ibuflen _U_, *rbuflen;
1917 static char buffer[12 + MAXPATHLEN + 1];
1918 int len = 12 + MAXPATHLEN + 1;
1921 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1927 memcpy(&vid, ibuf, sizeof(vid));
1928 ibuf += sizeof(vid);
1930 if (NULL == ( vol = getvolbyvid( vid )) ) {
1931 return( AFPERR_PARAM);
1934 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1938 if (vol->v_flags & AFPVOL_RO)
1939 return AFPERR_VLOCK;
1941 memcpy(&id, ibuf, sizeof( id ));
1945 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1949 if (NULL == ( dir = dirlookup( vol, id )) ) {
1950 return( AFPERR_PARAM );
1954 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1958 return AFPERR_ACCESS;
1963 /* still try to delete the id */
1967 return AFPERR_PARAM;
1970 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1971 return AFPERR_BADTYPE;
1973 if (cnid_delete(vol->v_cdb, fileid)) {
1976 return AFPERR_VLOCK;
1979 return AFPERR_ACCESS;
1981 return AFPERR_PARAM;
1986 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1992 /* ------------------------------ */
1993 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1997 if (path->st_errno) {
1998 switch (path->st_errno) {
2000 afp_errno = AFPERR_NOID;
2004 afp_errno = AFPERR_ACCESS;
2007 afp_errno = AFPERR_PARAM;
2012 /* we use file_access both for legacy Mac perm and
2013 * for unix privilege, rename will take care of folder perms
2015 if (file_access(path, OPENACC_WR ) < 0) {
2016 afp_errno = AFPERR_ACCESS;
2020 if ((*of = of_findname(path))) {
2021 /* reuse struct adouble so it won't break locks */
2025 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2026 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2028 * The user must have the Read & Write privilege for both files in order to use this command.
2030 ad_close(adp, ADFLAGS_HF);
2031 afp_errno = AFPERR_ACCESS;
2038 #define APPLETEMP ".AppleTempXXXXXX"
2040 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2042 char *ibuf, *rbuf _U_ ;
2043 int ibuflen _U_, *rbuflen;
2045 struct stat srcst, destst;
2047 struct dir *dir, *sdir;
2048 char *spath, temp[17], *p;
2049 char *supath, *upath;
2054 struct adouble *adsp = NULL;
2055 struct adouble *addp = NULL;
2056 struct ofork *s_of = NULL;
2057 struct ofork *d_of = NULL;
2068 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2074 memcpy(&vid, ibuf, sizeof(vid));
2075 ibuf += sizeof(vid);
2077 if (NULL == ( vol = getvolbyvid( vid )) ) {
2078 return( AFPERR_PARAM);
2081 if ((vol->v_flags & AFPVOL_RO))
2082 return AFPERR_VLOCK;
2084 /* source and destination dids */
2085 memcpy(&sid, ibuf, sizeof(sid));
2086 ibuf += sizeof(sid);
2087 memcpy(&did, ibuf, sizeof(did));
2088 ibuf += sizeof(did);
2091 if (NULL == (dir = dirlookup( vol, sid )) ) {
2092 return afp_errno; /* was AFPERR_PARAM */
2095 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2096 return get_afp_errno(AFPERR_NOOBJ);
2099 if ( path_isadir(path) ) {
2100 return AFPERR_BADTYPE; /* it's a dir */
2103 /* save some stuff */
2106 spath = obj->oldtmp;
2107 supath = obj->newtmp;
2108 strcpy(spath, path->m_name);
2109 strcpy(supath, path->u_name); /* this is for the cnid changing */
2110 p = absupath( vol, sdir, supath);
2112 /* pathname too long */
2113 return AFPERR_PARAM ;
2116 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2117 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2121 /* ***** from here we may have resource fork open **** */
2123 /* look for the source cnid. if it doesn't exist, don't worry about
2125 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2127 if (NULL == ( dir = dirlookup( vol, did )) ) {
2128 err = afp_errno; /* was AFPERR_PARAM */
2129 goto err_exchangefile;
2132 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2133 err = get_afp_errno(AFPERR_NOOBJ);
2134 goto err_exchangefile;
2137 if ( path_isadir(path) ) {
2138 err = AFPERR_BADTYPE;
2139 goto err_exchangefile;
2142 /* FPExchangeFiles is the only call that can return the SameObj
2144 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2145 err = AFPERR_SAMEOBJ;
2146 goto err_exchangefile;
2149 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2150 if (!(addp = find_adouble( path, &d_of, &add))) {
2152 goto err_exchangefile;
2156 /* they are not on the same device and at least one is open
2157 * FIXME broken for for crossdev and adouble v2
2160 crossdev = (srcst.st_dev != destst.st_dev);
2161 if (/* (d_of || s_of) && */ crossdev) {
2163 goto err_exchangefile;
2166 /* look for destination id. */
2167 upath = path->u_name;
2168 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2170 /* construct a temp name.
2171 * NOTE: the temp file will be in the dest file's directory. it
2172 * will also be inaccessible from AFP. */
2173 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2174 if (!mktemp(temp)) {
2176 goto err_exchangefile;
2180 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2181 ad_close(adsp, ADFLAGS_HF);
2182 ad_close(addp, ADFLAGS_HF);
2185 /* now, quickly rename the file. we error if we can't. */
2186 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2187 goto err_exchangefile;
2188 of_rename(vol, s_of, sdir, spath, curdir, temp);
2190 /* rename destination to source */
2191 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2192 goto err_src_to_tmp;
2193 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2195 /* rename temp to destination */
2196 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2197 goto err_dest_to_src;
2198 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2200 /* id's need switching. src -> dest and dest -> src.
2201 * we need to re-stat() if it was a cross device copy.
2204 cnid_delete(vol->v_cdb, sid);
2207 cnid_delete(vol->v_cdb, did);
2209 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2210 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2212 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2213 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2218 err = AFPERR_ACCESS;
2223 goto err_temp_to_dest;
2226 /* here we need to reopen if crossdev */
2227 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2229 ad_flush( addp, ADFLAGS_HF );
2232 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2234 ad_flush( adsp, ADFLAGS_HF );
2237 /* change perms, src gets dest perm and vice versa */
2242 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2243 err = AFP_OK; /* ignore error */
2244 goto err_temp_to_dest;
2248 * we need to exchange ACL entries as well
2250 /* exchange_acls(vol, p, upath); */
2255 path->m_name = NULL;
2256 path->u_name = upath;
2258 setfilunixmode(vol, path, destst.st_mode);
2259 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2266 setfilunixmode(vol, path, srcst.st_mode);
2267 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2269 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2270 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2275 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2279 goto err_exchangefile;
2281 /* all this stuff is so that we can unwind a failed operation
2284 /* rename dest to temp */
2285 renamefile(vol, upath, temp, temp, adsp);
2286 of_rename(vol, s_of, curdir, upath, curdir, temp);
2289 /* rename source back to dest */
2290 renamefile(vol, p, upath, path->m_name, addp);
2291 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2294 /* rename temp back to source */
2295 renamefile(vol, temp, p, spath, adsp);
2296 of_rename(vol, s_of, curdir, temp, sdir, spath);
2299 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2300 ad_close(adsp, ADFLAGS_HF);
2302 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2303 ad_close(addp, ADFLAGS_HF);