2 * $Id: file.c,v 1.92.2.2.2.31.2.15 2005-09-27 10:40:41 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 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 (*upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy(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 (*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(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,
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 );
672 return( AFPERR_PARAM );
675 if ( ad_hfileno( adp ) == -1 ) {
676 /* on noadouble volumes, just creating the data fork is ok */
677 if (vol_noadouble(vol)) {
678 ad_close( adp, ADFLAGS_DF );
679 goto createfile_done;
681 /* FIXME with hard create on an existing file, we already
682 * corrupted the data file.
684 netatalk_unlink( upath );
685 ad_close( adp, ADFLAGS_DF );
686 return AFPERR_ACCESS;
689 path = s_path->m_name;
690 ad_setname(adp, path);
691 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
692 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
698 if (vol->v_flags & AFPVOL_DROPBOX) {
699 retvalue = matchfile2dirperms(upath, vol, did);
701 #endif /* DROPKLUDGE */
703 setvoltime(obj, vol );
706 LOG(log_info, logtype_afpd, "end afp_createfile");
712 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
714 char *ibuf, *rbuf _U_;
715 int ibuflen _U_, *rbuflen;
721 u_int16_t vid, bitmap;
724 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
730 memcpy(&vid, ibuf, sizeof( vid ));
731 ibuf += sizeof( vid );
732 if (NULL == ( vol = getvolbyvid( vid )) ) {
733 return( AFPERR_PARAM );
736 if (vol->v_flags & AFPVOL_RO)
739 memcpy(&did, ibuf, sizeof( did ));
740 ibuf += sizeof( did );
741 if (NULL == ( dir = dirlookup( vol, did )) ) {
742 return afp_errno; /* was AFPERR_NOOBJ */
745 memcpy(&bitmap, ibuf, sizeof( bitmap ));
746 bitmap = ntohs( bitmap );
747 ibuf += sizeof( bitmap );
749 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
750 return get_afp_errno(AFPERR_PARAM);
753 if (path_isadir(s_path)) {
754 return( AFPERR_BADTYPE ); /* it's a directory */
757 if ( s_path->st_errno != 0 ) {
758 return( AFPERR_NOOBJ );
761 if ((u_long)ibuf & 1 ) {
765 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
766 setvoltime(obj, vol );
770 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
777 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
780 extern struct path Cur_Path;
782 int setfilparams(struct vol *vol,
783 struct path *path, u_int16_t f_bitmap, char *buf )
785 struct adouble ad, *adp;
787 int bit, isad = 1, err = AFP_OK;
789 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
790 u_int16_t ashort, bshort;
793 u_int16_t upriv_bit = 0;
797 int change_mdate = 0;
798 int change_parent_mdate = 0;
803 u_int16_t bitmap = f_bitmap;
804 u_int32_t cdate,bdate;
805 u_char finder_buf[32];
808 LOG(log_info, logtype_afpd, "begin setfilparams:");
811 upath = path->u_name;
812 adp = of_ad(vol, path, &ad);
815 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
816 return AFPERR_ACCESS;
819 /* with unix priv maybe we have to change adouble file priv first */
821 while ( bitmap != 0 ) {
822 while (( bitmap & 1 ) == 0 ) {
829 memcpy(&ashort, buf, sizeof( ashort ));
830 buf += sizeof( ashort );
834 memcpy(&cdate, buf, sizeof(cdate));
835 buf += sizeof( cdate );
838 memcpy(&newdate, buf, sizeof( newdate ));
839 buf += sizeof( newdate );
843 memcpy(&bdate, buf, sizeof( bdate));
844 buf += sizeof( bdate );
848 memcpy(finder_buf, buf, 32 );
851 case FILPBIT_UNIXPR :
852 if (!vol_unix_priv(vol)) {
853 /* this volume doesn't use unix priv */
859 change_parent_mdate = 1;
861 memcpy( &aint, buf, sizeof( aint ));
862 f_uid = ntohl (aint);
863 buf += sizeof( aint );
864 memcpy( &aint, buf, sizeof( aint ));
865 f_gid = ntohl (aint);
866 buf += sizeof( aint );
867 setfilowner(vol, f_uid, f_gid, path);
869 memcpy( &upriv, buf, sizeof( upriv ));
870 buf += sizeof( upriv );
871 upriv = ntohl (upriv);
872 if ((upriv & S_IWUSR)) {
873 setfilunixmode(vol, path, upriv);
880 case FILPBIT_PDINFO :
881 if (afp_version < 30) { /* else it's UTF8 name */
884 /* Keep special case to support crlf translations */
885 if ((unsigned int) achar == 0x04) {
886 fdType = (u_char *)"TEXT";
889 xyy[0] = ( u_char ) 'p';
900 /* break while loop */
909 /* second try with adouble open
911 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
912 O_RDWR|O_CREAT, 0666, adp) < 0) {
913 /* for some things, we don't need an adouble header */
914 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
915 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
918 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
919 ad_setname(adp, path->m_name);
924 while ( bitmap != 0 ) {
925 while (( bitmap & 1 ) == 0 ) {
932 ad_getattr(adp, &bshort);
933 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
934 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
935 change_parent_mdate = 1;
936 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
937 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
941 ad_setattr(adp, bshort);
944 ad_setdate(adp, AD_DATE_CREATE, cdate);
949 ad_setdate(adp, AD_DATE_BACKUP, bdate);
952 if (default_type( ad_entry( adp, ADEID_FINDERI ))
954 ((em = getextmap( path->m_name )) &&
955 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
956 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
957 || ((em = getdefextmap()) &&
958 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
959 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
961 memcpy(finder_buf, ufinderi, 8 );
963 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
965 case FILPBIT_UNIXPR :
967 setfilunixmode(vol, path, upriv);
970 case FILPBIT_PDINFO :
971 if (afp_version < 30) { /* else it's UTF8 name */
972 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
973 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
979 goto setfilparam_done;
986 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
987 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
991 ad_setdate(adp, AD_DATE_MODIFY, newdate);
992 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
997 ad_flush( adp, ADFLAGS_HF );
998 ad_close( adp, ADFLAGS_HF );
1002 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1003 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1004 bitmap = 1<<FILPBIT_MDATE;
1005 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1009 LOG(log_info, logtype_afpd, "end setfilparams:");
1015 * renamefile and copyfile take the old and new unix pathnames
1016 * and the new mac name.
1018 * src the source path
1019 * dst the dest filename in current dir
1020 * newname the dest mac name
1021 * adp adouble struct of src file, if open, or & zeroed one
1024 int renamefile(vol, src, dst, newname, adp )
1025 const struct vol *vol;
1026 char *src, *dst, *newname;
1027 struct adouble *adp;
1029 char adsrc[ MAXPATHLEN + 1];
1033 LOG(log_info, logtype_afpd, "begin renamefile:");
1036 if ( unix_rename( src, dst ) < 0 ) {
1039 return( AFPERR_NOOBJ );
1042 return( AFPERR_ACCESS );
1044 return AFPERR_VLOCK;
1045 case EXDEV : /* Cross device move -- try copy */
1046 /* NOTE: with open file it's an error because after the copy we will
1047 * get two files, it's fixable for our process (eg reopen the new file, get the
1048 * locks, and so on. But it doesn't solve the case with a second process
1050 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1051 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1052 return AFPERR_OLOCK; /* little lie */
1054 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1055 /* on error copyfile delete dest */
1058 return deletefile(vol, src, 0);
1060 return( AFPERR_PARAM );
1064 strcpy( adsrc, vol->ad_path( src, 0 ));
1066 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1071 if (errno == ENOENT) {
1074 if (stat(adsrc, &st)) /* source has no ressource fork, */
1077 /* We are here because :
1078 * -there's no dest folder.
1079 * -there's no .AppleDouble in the dest folder.
1080 * if we use the struct adouble passed in parameter it will not
1081 * create .AppleDouble if the file is already opened, so we
1082 * use a diff one, it's not a pb,ie it's not the same file, yet.
1084 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1085 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1086 ad_close(&ad, ADFLAGS_HF);
1087 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1092 else { /* it's something else, bail out */
1096 /* try to undo the data fork rename,
1097 * we know we are on the same device
1100 unix_rename( dst, src );
1101 /* return the first error */
1104 return AFPERR_NOOBJ;
1107 return AFPERR_ACCESS ;
1109 return AFPERR_VLOCK;
1111 return AFPERR_PARAM ;
1116 /* don't care if we can't open the newly renamed ressource fork
1118 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1119 ad_setname(adp, newname);
1120 ad_flush( adp, ADFLAGS_HF );
1121 ad_close( adp, ADFLAGS_HF );
1124 LOG(log_info, logtype_afpd, "end renamefile:");
1131 convert a Mac long name to an utf8 name,
1133 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1137 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1143 /* ---------------- */
1144 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1151 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1157 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1158 if (afp_version >= 30) {
1159 /* convert it to UTF8
1161 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1165 strncpy( newname, ibuf, plen );
1166 newname[ plen ] = '\0';
1168 if (strlen(newname) != plen) {
1169 /* there's \0 in newname, e.g. it's a pathname not
1177 memcpy(&hint, ibuf, sizeof(hint));
1178 ibuf += sizeof(hint);
1180 memcpy(&len16, ibuf, sizeof(len16));
1181 ibuf += sizeof(len16);
1182 plen = ntohs(len16);
1185 if (plen > AFPOBJ_TMPSIZ) {
1188 strncpy( newname, ibuf, plen );
1189 newname[ plen ] = '\0';
1190 if (strlen(newname) != plen) {
1199 /* -----------------------------------
1201 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1203 char *ibuf, *rbuf _U_;
1204 int ibuflen _U_, *rbuflen;
1206 struct vol *s_vol, *d_vol;
1208 char *newname, *p, *upath;
1209 struct path *s_path;
1210 u_int32_t sdid, ddid;
1211 int err, retvalue = AFP_OK;
1212 u_int16_t svid, dvid;
1214 struct adouble ad, *adp;
1218 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1224 memcpy(&svid, ibuf, sizeof( svid ));
1225 ibuf += sizeof( svid );
1226 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1227 return( AFPERR_PARAM );
1230 memcpy(&sdid, ibuf, sizeof( sdid ));
1231 ibuf += sizeof( sdid );
1232 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1236 memcpy(&dvid, ibuf, sizeof( dvid ));
1237 ibuf += sizeof( dvid );
1238 memcpy(&ddid, ibuf, sizeof( ddid ));
1239 ibuf += sizeof( ddid );
1241 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1242 return get_afp_errno(AFPERR_PARAM);
1244 if ( path_isadir(s_path) ) {
1245 return( AFPERR_BADTYPE );
1248 /* don't allow copies when the file is open.
1249 * XXX: the spec only calls for read/deny write access.
1250 * however, copyfile doesn't have any of that info,
1251 * and locks need to stay coherent. as a result,
1252 * we just balk if the file is opened already. */
1254 adp = of_ad(s_vol, s_path, &ad);
1256 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1257 return AFPERR_DENYCONF;
1259 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1260 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1261 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1263 return AFPERR_DENYCONF;
1266 newname = obj->newtmp;
1267 strcpy( newname, s_path->m_name );
1269 p = ctoupath( s_vol, curdir, newname );
1271 return AFPERR_PARAM;
1275 /* FIXME svid != dvid && dvid's user can't read svid */
1277 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1278 return( AFPERR_PARAM );
1281 if (d_vol->v_flags & AFPVOL_RO)
1282 return AFPERR_VLOCK;
1284 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1288 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1289 return get_afp_errno(AFPERR_NOOBJ);
1291 if ( *s_path->m_name != '\0' ) {
1292 path_error(s_path, AFPERR_PARAM);
1295 /* one of the handful of places that knows about the path type */
1296 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1297 return( AFPERR_PARAM );
1299 /* newname is always only a filename so curdir *is* its
1302 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1303 return( AFPERR_PARAM );
1305 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1311 if (vol->v_flags & AFPVOL_DROPBOX) {
1312 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1314 #endif /* DROPKLUDGE */
1316 setvoltime(obj, d_vol );
1319 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1325 /* ----------------------- */
1326 static __inline__ int copy_all(const int dfd, const void *buf,
1332 LOG(log_info, logtype_afpd, "begin copy_all:");
1335 while (buflen > 0) {
1336 if ((cc = write(dfd, buf, buflen)) < 0) {
1348 LOG(log_info, logtype_afpd, "end copy_all:");
1354 /* -------------------------- */
1355 static int copy_fd(int dfd, int sfd)
1361 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1362 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1366 #define BUF 128*1024*1024
1368 if (fstat(sfd, &st) == 0) {
1371 if ( offset >= st.st_size) {
1374 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1375 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1378 case EINVAL: /* there's no guarantee that all fs support sendfile */
1387 lseek(sfd, offset, SEEK_SET);
1391 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1398 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1405 /* ----------------------------------
1406 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1407 * because we are doing it elsewhere.
1408 * currently if newname is NULL then adp is NULL.
1410 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1411 const struct vol *s_vol, *d_vol;
1412 char *src, *dst, *newname;
1413 struct adouble *adp;
1415 struct adouble ads, add;
1419 int noadouble = vol_noadouble(d_vol);
1424 LOG(log_info, logtype_afpd, "begin copyfile:");
1428 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1431 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1432 adflags = ADFLAGS_DF;
1434 adflags |= ADFLAGS_HF;
1437 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1442 if (ad_hfileno(adp) == -1) {
1443 /* no resource fork, don't create one for dst file */
1444 adflags &= ~ADFLAGS_HF;
1447 stat_result = fstat(ad_dfileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1449 if (stat_result < 0) {
1450 /* unlikely but if fstat fails, the default file mode will be 0666. */
1451 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1454 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1456 ad_close( adp, adflags );
1457 if (EEXIST != ret_err) {
1458 deletefile(d_vol, dst, 0);
1461 return AFPERR_EXIST;
1463 /* XXX if the source and the dest don't use the same resource type it's broken
1465 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1466 /* copy the data fork */
1467 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1470 /* Now, reopen destination file */
1474 ad_close( adp, adflags );
1476 if (ad_close( &add, adflags ) <0) {
1477 deletefile(d_vol, dst, 0);
1482 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1483 /* set the new name in the resource fork */
1484 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1485 if (ad_open(dst , ADFLAGS_HF | noadouble, O_RDWR, 0666, &add) < 0) {
1489 ad_setname(&add, newname);
1490 ad_flush( &add, ADFLAGS_HF );
1491 if (ad_close( &add, ADFLAGS_HF ) <0) {
1498 deletefile(d_vol, dst, 0);
1500 else if (stat_result == 0) {
1501 /* set dest modification date to src date */
1504 ut.actime = ut.modtime = st.st_mtime;
1506 /* FIXME netatalk doesn't use resource fork file date
1507 * but maybe we should set its modtime too.
1512 LOG(log_info, logtype_afpd, "end copyfile:");
1516 switch ( ret_err ) {
1522 return AFPERR_DFULL;
1524 return AFPERR_NOOBJ;
1526 return AFPERR_ACCESS;
1528 return AFPERR_VLOCK;
1530 return AFPERR_PARAM;
1534 /* -----------------------------------
1535 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1536 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1538 when deletefile is called we don't have lock on it, file is closed (for us)
1539 untrue if called by renamefile
1541 ad_open always try to open file RDWR first and ad_lock takes care of
1542 WRITE lock on read only file.
1544 int deletefile( vol, file, checkAttrib )
1545 const struct vol *vol;
1550 struct adouble *adp = &ad;
1551 int adflags, err = AFP_OK;
1554 LOG(log_info, logtype_afpd, "begin deletefile:");
1557 /* try to open both forks at once */
1558 adflags = ADFLAGS_DF|ADFLAGS_HF;
1559 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1561 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1564 if (adflags == ADFLAGS_DF)
1565 return AFPERR_NOOBJ;
1567 /* that failed. now try to open just the data fork */
1568 adflags = ADFLAGS_DF;
1572 adp = NULL; /* maybe it's a file we no rw mode for us */
1573 break; /* was return AFPERR_ACCESS;*/
1575 return AFPERR_VLOCK;
1577 return( AFPERR_PARAM );
1580 break; /* from the while */
1583 * Does kFPDeleteInhibitBit (bit 8) set?
1588 if (adp && (adflags & ADFLAGS_HF)) {
1590 ad_getattr(&ad, &bshort);
1591 if ((bshort & htons(ATTRBIT_NODELETE))) {
1592 ad_close( &ad, adflags );
1593 return(AFPERR_OLOCK);
1597 /* was EACCESS error try to get only metadata */
1598 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1599 if ( ad_metadata( file , 0, &ad) == 0 ) {
1600 ad_getattr(&ad, &bshort);
1601 ad_close( &ad, ADFLAGS_HF );
1602 if ((bshort & htons(ATTRBIT_NODELETE))) {
1603 return AFPERR_OLOCK;
1609 if (adp && (adflags & ADFLAGS_HF) ) {
1610 /* FIXME we have a pb here because we want to know if a file is open
1611 * there's a 'priority inversion' if you can't open the ressource fork RW
1612 * you can delete it if it's open because you can't get a write lock.
1614 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1617 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1619 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1620 ad_close( &ad, adflags );
1621 return( AFPERR_BUSY );
1625 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1628 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1629 !(err = netatalk_unlink( file )) ) {
1631 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1633 cnid_delete(vol->v_cdb, id);
1638 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1641 LOG(log_info, logtype_afpd, "end deletefile:");
1647 /* ------------------------------------ */
1648 /* return a file id */
1649 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1652 int ibuflen _U_, *rbuflen;
1661 struct path *s_path;
1664 LOG(log_info, logtype_afpd, "begin afp_createid:");
1671 memcpy(&vid, ibuf, sizeof(vid));
1672 ibuf += sizeof(vid);
1674 if (NULL == ( vol = getvolbyvid( vid )) ) {
1675 return( AFPERR_PARAM);
1678 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1682 if (vol->v_flags & AFPVOL_RO)
1683 return AFPERR_VLOCK;
1685 memcpy(&did, ibuf, sizeof( did ));
1686 ibuf += sizeof(did);
1688 if (NULL == ( dir = dirlookup( vol, did )) ) {
1689 return afp_errno; /* was AFPERR_PARAM */
1692 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1693 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1696 if ( path_isadir(s_path) ) {
1697 return( AFPERR_BADTYPE );
1700 upath = s_path->u_name;
1701 switch (s_path->st_errno) {
1703 break; /* success */
1706 return AFPERR_ACCESS;
1708 return AFPERR_NOOBJ;
1710 return AFPERR_PARAM;
1713 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1714 memcpy(rbuf, &id, sizeof(id));
1715 *rbuflen = sizeof(id);
1716 return AFPERR_EXISTID;
1719 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1720 memcpy(rbuf, &id, sizeof(id));
1721 *rbuflen = sizeof(id);
1726 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1732 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1740 memset(&path, 0, sizeof(path));
1741 if (vol->v_cdb == NULL) {
1744 if (NULL == ( dp = opendir( name)) ) {
1748 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1749 if (NULL == check_dirent(vol, de->d_name))
1752 if ( stat(de->d_name, &path.st)<0 )
1755 /* update or add to cnid */
1756 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1758 #if AD_VERSION > AD_VERSION1
1759 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1760 struct adouble ad, *adp;
1764 path.u_name = de->d_name;
1766 adp = of_ad(vol, &path, &ad);
1768 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1771 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1772 ad_flush(adp, ADFLAGS_HF);
1774 ad_close(adp, ADFLAGS_HF);
1776 #endif /* AD_VERSION > AD_VERSION1 */
1785 /* ------------------------------
1786 resolve a file id */
1787 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1790 int ibuflen _U_, *rbuflen;
1796 int err, buflen, retry=0;
1798 u_int16_t vid, bitmap;
1800 static char buffer[12 + MAXPATHLEN + 1];
1801 int len = 12 + MAXPATHLEN + 1;
1804 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1810 memcpy(&vid, ibuf, sizeof(vid));
1811 ibuf += sizeof(vid);
1813 if (NULL == ( vol = getvolbyvid( vid )) ) {
1814 return( AFPERR_PARAM);
1817 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1821 memcpy(&id, ibuf, sizeof( id ));
1826 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1830 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1831 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1834 if (NULL == ( dir = dirlookup( vol, id )) ) {
1835 return AFPERR_NOID; /* idem AFPERR_PARAM */
1837 path.u_name = upath;
1838 if (movecwd(vol, dir) < 0) {
1842 return AFPERR_ACCESS;
1846 return AFPERR_PARAM;
1850 if ( of_stat(&path) < 0 ) {
1852 /* with nfs and our working directory is deleted */
1853 if (errno == ESTALE) {
1857 if ( errno == ENOENT && !retry) {
1858 /* cnid db is out of sync, reenumerate the directory and updated ids */
1859 reenumerate_id(vol, ".", id);
1867 return AFPERR_ACCESS;
1871 return AFPERR_PARAM;
1875 /* directories are bad */
1876 if (S_ISDIR(path.st.st_mode))
1877 return AFPERR_BADTYPE;
1879 memcpy(&bitmap, ibuf, sizeof(bitmap));
1880 bitmap = ntohs( bitmap );
1881 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1884 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1885 rbuf + sizeof(bitmap), &buflen))) {
1888 *rbuflen = buflen + sizeof(bitmap);
1889 memcpy(rbuf, ibuf, sizeof(bitmap));
1892 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1898 /* ------------------------------ */
1899 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1901 char *ibuf, *rbuf _U_;
1902 int ibuflen _U_, *rbuflen;
1912 static char buffer[12 + MAXPATHLEN + 1];
1913 int len = 12 + MAXPATHLEN + 1;
1916 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1922 memcpy(&vid, ibuf, sizeof(vid));
1923 ibuf += sizeof(vid);
1925 if (NULL == ( vol = getvolbyvid( vid )) ) {
1926 return( AFPERR_PARAM);
1929 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1933 if (vol->v_flags & AFPVOL_RO)
1934 return AFPERR_VLOCK;
1936 memcpy(&id, ibuf, sizeof( id ));
1940 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1944 if (NULL == ( dir = dirlookup( vol, id )) ) {
1945 return( AFPERR_PARAM );
1949 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1953 return AFPERR_ACCESS;
1958 /* still try to delete the id */
1962 return AFPERR_PARAM;
1965 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1966 return AFPERR_BADTYPE;
1968 if (cnid_delete(vol->v_cdb, fileid)) {
1971 return AFPERR_VLOCK;
1974 return AFPERR_ACCESS;
1976 return AFPERR_PARAM;
1981 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1987 /* ------------------------------ */
1988 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1992 if (path->st_errno) {
1993 switch (path->st_errno) {
1995 afp_errno = AFPERR_NOID;
1999 afp_errno = AFPERR_ACCESS;
2002 afp_errno = AFPERR_PARAM;
2007 /* we use file_access both for legacy Mac perm and
2008 * for unix privilege, rename will take care of folder perms
2010 if (file_access(path, OPENACC_WR ) < 0) {
2011 afp_errno = AFPERR_ACCESS;
2015 if ((*of = of_findname(path))) {
2016 /* reuse struct adouble so it won't break locks */
2020 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2021 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2023 * The user must have the Read & Write privilege for both files in order to use this command.
2025 ad_close(adp, ADFLAGS_HF);
2026 afp_errno = AFPERR_ACCESS;
2033 #define APPLETEMP ".AppleTempXXXXXX"
2035 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2037 char *ibuf, *rbuf _U_ ;
2038 int ibuflen _U_, *rbuflen;
2040 struct stat srcst, destst;
2042 struct dir *dir, *sdir;
2043 char *spath, temp[17], *p;
2044 char *supath, *upath;
2049 struct adouble *adsp = NULL;
2050 struct adouble *addp = NULL;
2051 struct ofork *s_of = NULL;
2052 struct ofork *d_of = NULL;
2063 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2069 memcpy(&vid, ibuf, sizeof(vid));
2070 ibuf += sizeof(vid);
2072 if (NULL == ( vol = getvolbyvid( vid )) ) {
2073 return( AFPERR_PARAM);
2076 if ((vol->v_flags & AFPVOL_RO))
2077 return AFPERR_VLOCK;
2079 /* source and destination dids */
2080 memcpy(&sid, ibuf, sizeof(sid));
2081 ibuf += sizeof(sid);
2082 memcpy(&did, ibuf, sizeof(did));
2083 ibuf += sizeof(did);
2086 if (NULL == (dir = dirlookup( vol, sid )) ) {
2087 return afp_errno; /* was AFPERR_PARAM */
2090 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2091 return get_afp_errno(AFPERR_NOOBJ);
2094 if ( path_isadir(path) ) {
2095 return AFPERR_BADTYPE; /* it's a dir */
2098 /* save some stuff */
2101 spath = obj->oldtmp;
2102 supath = obj->newtmp;
2103 strcpy(spath, path->m_name);
2104 strcpy(supath, path->u_name); /* this is for the cnid changing */
2105 p = absupath( vol, sdir, supath);
2107 /* pathname too long */
2108 return AFPERR_PARAM ;
2111 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2112 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2116 /* ***** from here we may have resource fork open **** */
2118 /* look for the source cnid. if it doesn't exist, don't worry about
2120 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2122 if (NULL == ( dir = dirlookup( vol, did )) ) {
2123 err = afp_errno; /* was AFPERR_PARAM */
2124 goto err_exchangefile;
2127 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2128 err = get_afp_errno(AFPERR_NOOBJ);
2129 goto err_exchangefile;
2132 if ( path_isadir(path) ) {
2133 err = AFPERR_BADTYPE;
2134 goto err_exchangefile;
2137 /* FPExchangeFiles is the only call that can return the SameObj
2139 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2140 err = AFPERR_SAMEOBJ;
2141 goto err_exchangefile;
2144 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2145 if (!(addp = find_adouble( path, &d_of, &add))) {
2147 goto err_exchangefile;
2151 /* they are not on the same device and at least one is open
2152 * FIXME broken for for crossdev and adouble v2
2155 crossdev = (srcst.st_dev != destst.st_dev);
2156 if (/* (d_of || s_of) && */ crossdev) {
2158 goto err_exchangefile;
2161 /* look for destination id. */
2162 upath = path->u_name;
2163 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2165 /* construct a temp name.
2166 * NOTE: the temp file will be in the dest file's directory. it
2167 * will also be inaccessible from AFP. */
2168 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2169 if (!mktemp(temp)) {
2171 goto err_exchangefile;
2175 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2176 ad_close(adsp, ADFLAGS_HF);
2177 ad_close(addp, ADFLAGS_HF);
2180 /* now, quickly rename the file. we error if we can't. */
2181 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2182 goto err_exchangefile;
2183 of_rename(vol, s_of, sdir, spath, curdir, temp);
2185 /* rename destination to source */
2186 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2187 goto err_src_to_tmp;
2188 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2190 /* rename temp to destination */
2191 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2192 goto err_dest_to_src;
2193 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2195 /* id's need switching. src -> dest and dest -> src.
2196 * we need to re-stat() if it was a cross device copy.
2199 cnid_delete(vol->v_cdb, sid);
2202 cnid_delete(vol->v_cdb, did);
2204 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2205 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2207 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2208 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2213 err = AFPERR_ACCESS;
2218 goto err_temp_to_dest;
2221 /* here we need to reopen if crossdev */
2222 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2224 ad_flush( addp, ADFLAGS_HF );
2227 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2229 ad_flush( adsp, ADFLAGS_HF );
2232 /* change perms, src gets dest perm and vice versa */
2237 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2238 err = AFP_OK; /* ignore error */
2239 goto err_temp_to_dest;
2243 * we need to exchange ACL entries as well
2245 /* exchange_acls(vol, p, upath); */
2250 path->m_name = NULL;
2251 path->u_name = upath;
2253 setfilunixmode(vol, path, destst.st_mode);
2254 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2261 setfilunixmode(vol, path, srcst.st_mode);
2262 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2264 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2265 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2270 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2274 goto err_exchangefile;
2276 /* all this stuff is so that we can unwind a failed operation
2279 /* rename dest to temp */
2280 renamefile(vol, upath, temp, temp, adsp);
2281 of_rename(vol, s_of, curdir, upath, curdir, temp);
2284 /* rename source back to dest */
2285 renamefile(vol, p, upath, path->m_name, addp);
2286 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2289 /* rename temp back to source */
2290 renamefile(vol, temp, p, spath, adsp);
2291 of_rename(vol, s_of, curdir, temp, sdir, spath);
2294 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2295 ad_close(adsp, ADFLAGS_HF);
2297 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2298 ad_close(addp, ADFLAGS_HF);