2 * $Id: file.c,v 1.94 2003-06-05 09:17:11 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
52 #include <atalk/cnid.h>
54 #include "directory.h"
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];
268 LOG(log_info, logtype_afpd, "begin getmetadata:");
271 upath = path->u_name;
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(path->m_name, adp, (char *)data);
341 if (*upath == '.') { /* make it invisible */
342 ashort = htons(FINDERINFO_INVISIBLE);
343 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
351 data += sizeof( u_int16_t );
355 memset(data, 0, sizeof(u_int16_t));
356 data += sizeof( u_int16_t );
360 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
363 memcpy(data, &aint, sizeof( aint ));
364 data += sizeof( aint );
368 if (st->st_size > 0xffffffff)
371 aint = htonl( st->st_size );
372 memcpy(data, &aint, sizeof( aint ));
373 data += sizeof( aint );
378 if (adp->ad_rlen > 0xffffffff)
381 aint = htonl( adp->ad_rlen);
385 memcpy(data, &aint, sizeof( aint ));
386 data += sizeof( aint );
389 /* Current client needs ProDOS info block for this file.
390 Use simple heuristic and let the Mac "type" string tell
391 us what the PD file code should be. Everything gets a
392 subtype of 0x0000 unless the original value was hashed
393 to "pXYZ" when we created it. See IA, Ver 2.
394 <shirsch@adelphia.net> */
395 case FILPBIT_PDINFO :
396 if (afp_version >= 30) { /* UTF8 name */
397 utf8 = kTextEncodingUTF8;
399 data += sizeof( u_int16_t );
401 memcpy(data, &aint, sizeof( aint ));
402 data += sizeof( aint );
406 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
408 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
416 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
420 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
424 else if ( fdType[0] == 'p' ) {
426 ashort = (fdType[2] * 256) + fdType[3];
440 memcpy(data, &ashort, sizeof( ashort ));
441 data += sizeof( ashort );
442 memset(data, 0, sizeof( ashort ));
443 data += sizeof( ashort );
446 case FILPBIT_EXTDFLEN:
447 aint = htonl(st->st_size >> 32);
448 memcpy(data, &aint, sizeof( aint ));
449 data += sizeof( aint );
450 aint = htonl(st->st_size);
451 memcpy(data, &aint, sizeof( aint ));
452 data += sizeof( aint );
454 case FILPBIT_EXTRFLEN:
457 aint = htonl(adp->ad_rlen >> 32);
458 memcpy(data, &aint, sizeof( aint ));
459 data += sizeof( aint );
461 aint = htonl(adp->ad_rlen);
462 memcpy(data, &aint, sizeof( aint ));
463 data += sizeof( aint );
465 case FILPBIT_UNIXPR :
466 aint = htonl(st->st_uid);
467 memcpy( data, &aint, sizeof( aint ));
468 data += sizeof( aint );
469 aint = htonl(st->st_gid);
470 memcpy( data, &aint, sizeof( aint ));
471 data += sizeof( aint );
473 aint = htonl(st->st_mode);
474 memcpy( data, &aint, sizeof( aint ));
475 data += sizeof( aint );
477 accessmode( upath, &ma, dir , st);
479 *data++ = ma.ma_user;
480 *data++ = ma.ma_world;
481 *data++ = ma.ma_group;
482 *data++ = ma.ma_owner;
486 return( AFPERR_BITMAP );
492 ashort = htons( data - buf );
493 memcpy(l_nameoff, &ashort, sizeof( ashort ));
494 data = set_name(vol, data, path->m_name, 0);
497 ashort = htons( data - buf );
498 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
499 data = set_name(vol, data, path->m_name, utf8);
501 *buflen = data - buf;
505 /* ----------------------- */
506 int getfilparams(struct vol *vol,
508 struct path *path, struct dir *dir,
509 char *buf, int *buflen )
511 struct adouble ad, *adp;
514 u_int16_t attrbits = 0;
519 LOG(log_info, logtype_default, "begin getfilparams:");
522 opened = PARAM_NEED_ADP(bitmap);
525 upath = path->u_name;
526 if ((of = of_findname(path))) {
528 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
529 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
531 memset(&ad, 0, sizeof(ad));
535 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
540 we need to check if the file is open by another process.
541 it's slow so we only do it if we have to:
542 - bitmap is requested.
543 - we don't already have the answer!
545 if ((bitmap & (1 << FILPBIT_ATTR))) {
546 if (!(attrbits & ATTRBIT_ROPEN)) {
548 if (!(attrbits & ATTRBIT_DOPEN)) {
553 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
555 ad_close( adp, ADFLAGS_HF );
558 LOG(log_info, logtype_afpd, "end getfilparams:");
564 /* ----------------------------- */
565 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
568 int ibuflen, *rbuflen;
570 struct adouble ad, *adp;
573 struct ofork *of = NULL;
575 int creatf, did, openf, retvalue = AFP_OK;
581 LOG(log_info, logtype_afpd, "begin afp_createfile:");
586 creatf = (unsigned char) *ibuf++;
588 memcpy(&vid, ibuf, sizeof( vid ));
589 ibuf += sizeof( vid );
591 if (NULL == ( vol = getvolbyvid( vid )) ) {
592 return( AFPERR_PARAM );
595 if (vol->v_flags & AFPVOL_RO)
598 memcpy(&did, ibuf, sizeof( did));
599 ibuf += sizeof( did );
601 if (NULL == ( dir = dirlookup( vol, did )) ) {
605 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
606 return get_afp_errno(AFPERR_PARAM);
609 if ( *s_path->m_name == '\0' ) {
610 return( AFPERR_BADTYPE );
613 upath = s_path->u_name;
614 if (0 != (ret = check_name(vol, upath)))
617 /* if upath is deleted we already in trouble anyway */
618 if ((of = of_findname(s_path))) {
621 memset(&ad, 0, sizeof(ad));
625 /* on a hard create, fail if file exists and is open */
628 openf = O_RDWR|O_CREAT|O_TRUNC;
630 /* on a soft create, if the file is open then ad_open won't fail
631 because open syscall is not called
636 openf = O_RDWR|O_CREAT|O_EXCL;
639 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
640 openf, 0666, adp) < 0 ) {
644 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
645 return ( AFPERR_NOOBJ );
647 return( AFPERR_EXIST );
649 return( AFPERR_ACCESS );
651 return( AFPERR_PARAM );
654 if ( ad_hfileno( adp ) == -1 ) {
655 /* on noadouble volumes, just creating the data fork is ok */
656 if (vol_noadouble(vol)) {
657 ad_close( adp, ADFLAGS_DF );
658 goto createfile_done;
660 /* FIXME with hard create on an existing file, we already
661 * corrupted the data file.
663 netatalk_unlink( upath );
664 ad_close( adp, ADFLAGS_DF );
665 return AFPERR_ACCESS;
668 path = s_path->m_name;
669 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
670 memcpy(ad_entry( adp, ADEID_NAME ), path,
671 ad_getentrylen( adp, ADEID_NAME ));
672 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
673 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
679 if (vol->v_flags & AFPVOL_DROPBOX) {
680 retvalue = matchfile2dirperms(upath, vol, did);
682 #endif /* DROPKLUDGE */
684 setvoltime(obj, vol );
687 LOG(log_info, logtype_afpd, "end afp_createfile");
693 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
696 int ibuflen, *rbuflen;
702 u_int16_t vid, bitmap;
705 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
711 memcpy(&vid, ibuf, sizeof( vid ));
712 ibuf += sizeof( vid );
713 if (NULL == ( vol = getvolbyvid( vid )) ) {
714 return( AFPERR_PARAM );
717 if (vol->v_flags & AFPVOL_RO)
720 memcpy(&did, ibuf, sizeof( did ));
721 ibuf += sizeof( did );
722 if (NULL == ( dir = dirlookup( vol, did )) ) {
723 return afp_errno; /* was AFPERR_NOOBJ */
726 memcpy(&bitmap, ibuf, sizeof( bitmap ));
727 bitmap = ntohs( bitmap );
728 ibuf += sizeof( bitmap );
730 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
731 return get_afp_errno(AFPERR_PARAM);
734 if (path_isadir(s_path)) {
735 return( AFPERR_BADTYPE ); /* it's a directory */
738 if ( s_path->st_errno != 0 ) {
739 return( AFPERR_NOOBJ );
742 if ((u_long)ibuf & 1 ) {
746 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
747 setvoltime(obj, vol );
751 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
758 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
761 extern struct path Cur_Path;
763 int setfilparams(struct vol *vol,
764 struct path *path, u_int16_t bitmap, char *buf )
766 struct adouble ad, *adp;
769 int bit = 0, isad = 1, err = AFP_OK;
771 u_char achar, *fdType, xyy[4];
772 u_int16_t ashort, bshort;
776 int change_mdate = 0;
777 int change_parent_mdate = 0;
783 LOG(log_info, logtype_afpd, "begin setfilparams:");
786 upath = path->u_name;
787 if ((of = of_findname(path))) {
790 memset(&ad, 0, sizeof(ad));
794 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
795 return AFPERR_ACCESS;
798 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
799 O_RDWR|O_CREAT, 0666, adp) < 0) {
800 /* for some things, we don't need an adouble header */
801 if (bitmap & ~(1<<FILPBIT_MDATE)) {
802 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
805 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
806 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
807 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
808 ad_getentrylen( adp, ADEID_NAME ));
811 while ( bitmap != 0 ) {
812 while (( bitmap & 1 ) == 0 ) {
820 memcpy(&ashort, buf, sizeof( ashort ));
821 ad_getattr(adp, &bshort);
822 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
823 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
827 if ((ashort & htons(ATTRBIT_INVISIBLE)))
828 change_parent_mdate = 1;
829 ad_setattr(adp, bshort);
830 buf += sizeof( ashort );
835 memcpy(&aint, buf, sizeof(aint));
836 ad_setdate(adp, AD_DATE_CREATE, aint);
837 buf += sizeof( aint );
841 memcpy(&newdate, buf, sizeof( newdate ));
842 buf += sizeof( newdate );
847 memcpy(&aint, buf, sizeof(aint));
848 ad_setdate(adp, AD_DATE_BACKUP, aint);
849 buf += sizeof( aint );
855 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
857 ((em = getextmap( path->m_name )) &&
858 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
859 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
860 || ((em = getdefextmap()) &&
861 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
862 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
864 memcpy(buf, ufinderi, 8 );
867 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
871 /* Client needs to set the ProDOS file info for this file.
872 Use a defined string for TEXT to support crlf
873 translations and convert all else into pXYY per Inside
874 Appletalk. Always set the creator as "pdos". Changes
875 from original by Marsha Jackson. */
876 case FILPBIT_PDINFO :
877 if (afp_version < 30) { /* else it's UTF8 name */
880 /* Keep special case to support crlf translations */
881 if ((unsigned int) achar == 0x04) {
882 fdType = (u_char *)"TEXT";
885 xyy[0] = ( u_char ) 'p';
891 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
892 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
896 case FILPBIT_UNIXPR :
897 /* Skip the UIG/GID, no way to set them from OSX clients */
898 buf += sizeof( aint );
899 buf += sizeof( aint );
902 change_parent_mdate = 1;
903 memcpy( &aint, buf, sizeof( aint ));
904 buf += sizeof( aint );
907 setfilemode(path, aint);
911 goto setfilparam_done;
919 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
920 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
924 ad_setdate(adp, AD_DATE_MODIFY, newdate);
925 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
930 ad_flush( adp, ADFLAGS_HF );
931 ad_close( adp, ADFLAGS_HF );
935 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
936 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
937 bitmap = 1<<FILPBIT_MDATE;
938 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
942 LOG(log_info, logtype_afpd, "end setfilparams:");
948 * renamefile and copyfile take the old and new unix pathnames
949 * and the new mac name.
951 * src the source path
952 * dst the dest filename in current dir
953 * newname the dest mac name
954 * adp adouble struct of src file, if open, or & zeroed one
957 int renamefile(src, dst, newname, noadouble, adp )
958 char *src, *dst, *newname;
962 char adsrc[ MAXPATHLEN + 1];
967 LOG(log_info, logtype_afpd, "begin renamefile:");
970 if ( unix_rename( src, dst ) < 0 ) {
973 return( AFPERR_NOOBJ );
976 return( AFPERR_ACCESS );
979 case EXDEV : /* Cross device move -- try copy */
980 /* NOTE: with open file it's an error because after the copy we will
981 * get two files, it's fixable for our process (eg reopen the new file, get the
982 * locks, and so on. But it doesn't solve the case with a second process
984 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
985 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
986 return AFPERR_OLOCK; /* little lie */
988 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
989 /* on error copyfile delete dest */
992 return deletefile(NULL, src, 0);
994 return( AFPERR_PARAM );
998 strcpy( adsrc, ad_path( src, 0 ));
1000 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
1005 if (errno == ENOENT) {
1008 if (stat(adsrc, &st)) /* source has no ressource fork, */
1011 /* We are here because :
1012 * -there's no dest folder.
1013 * -there's no .AppleDouble in the dest folder.
1014 * if we use the struct adouble passed in parameter it will not
1015 * create .AppleDouble if the file is already opened, so we
1016 * use a diff one, it's not a pb,ie it's not the same file, yet.
1018 memset(&ad, 0, sizeof(ad));
1019 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1020 ad_close(&ad, ADFLAGS_HF);
1021 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
1026 else { /* it's something else, bail out */
1030 /* try to undo the data fork rename,
1031 * we know we are on the same device
1034 unix_rename( dst, src );
1035 /* return the first error */
1038 return AFPERR_NOOBJ;
1041 return AFPERR_ACCESS ;
1043 return AFPERR_VLOCK;
1045 return AFPERR_PARAM ;
1050 /* don't care if we can't open the newly renamed ressource fork
1052 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1053 len = strlen( newname );
1054 ad_setentrylen( adp, ADEID_NAME, len );
1055 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1056 ad_flush( adp, ADFLAGS_HF );
1057 ad_close( adp, ADFLAGS_HF );
1060 LOG(log_info, logtype_afpd, "end renamefile:");
1066 int copy_path_name(char *newname, char *ibuf)
1073 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1079 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1080 strncpy( newname, ibuf, plen );
1081 newname[ plen ] = '\0';
1082 if (strlen(newname) != plen) {
1083 /* there's \0 in newname, e.g. it's a pathname not
1091 memcpy(&hint, ibuf, sizeof(hint));
1092 ibuf += sizeof(hint);
1094 memcpy(&len16, ibuf, sizeof(len16));
1095 ibuf += sizeof(len16);
1096 plen = ntohs(len16);
1099 if (plen > AFPOBJ_TMPSIZ) {
1102 strncpy( newname, ibuf, plen );
1103 newname[ plen ] = '\0';
1104 if (strlen(newname) != plen) {
1113 /* -----------------------------------
1115 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1118 int ibuflen, *rbuflen;
1122 char *newname, *p, *upath;
1123 struct path *s_path;
1124 u_int32_t sdid, ddid;
1125 int err, retvalue = AFP_OK;
1126 u_int16_t svid, dvid;
1129 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1135 memcpy(&svid, ibuf, sizeof( svid ));
1136 ibuf += sizeof( svid );
1137 if (NULL == ( vol = getvolbyvid( svid )) ) {
1138 return( AFPERR_PARAM );
1141 memcpy(&sdid, ibuf, sizeof( sdid ));
1142 ibuf += sizeof( sdid );
1143 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1147 memcpy(&dvid, ibuf, sizeof( dvid ));
1148 ibuf += sizeof( dvid );
1149 memcpy(&ddid, ibuf, sizeof( ddid ));
1150 ibuf += sizeof( ddid );
1152 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1153 return get_afp_errno(AFPERR_PARAM);
1155 if ( path_isadir(s_path) ) {
1156 return( AFPERR_BADTYPE );
1159 /* don't allow copies when the file is open.
1160 * XXX: the spec only calls for read/deny write access.
1161 * however, copyfile doesn't have any of that info,
1162 * and locks need to stay coherent. as a result,
1163 * we just balk if the file is opened already. */
1165 newname = obj->newtmp;
1166 strcpy( newname, s_path->m_name );
1168 if (of_findname(s_path))
1169 return AFPERR_DENYCONF;
1171 p = ctoupath( vol, curdir, newname );
1173 return AFPERR_PARAM;
1177 /* FIXME svid != dvid && dvid's user can't read svid */
1179 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1180 return( AFPERR_PARAM );
1183 if (vol->v_flags & AFPVOL_RO)
1184 return AFPERR_VLOCK;
1186 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1190 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1191 return get_afp_errno(AFPERR_NOOBJ);
1193 if ( *s_path->m_name != '\0' ) {
1195 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1197 path_error(s_path, AFPERR_PARAM);
1200 /* one of the handful of places that knows about the path type */
1201 if (copy_path_name(newname, ibuf) < 0) {
1202 return( AFPERR_PARAM );
1205 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1206 return( AFPERR_PARAM );
1208 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1214 if (vol->v_flags & AFPVOL_DROPBOX) {
1215 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1217 #endif /* DROPKLUDGE */
1219 setvoltime(obj, vol );
1222 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1229 static __inline__ int copy_all(const int dfd, const void *buf,
1235 LOG(log_info, logtype_afpd, "begin copy_all:");
1238 while (buflen > 0) {
1239 if ((cc = write(dfd, buf, buflen)) < 0) {
1246 return AFPERR_DFULL;
1248 return AFPERR_VLOCK;
1250 return AFPERR_PARAM;
1257 LOG(log_info, logtype_afpd, "end copy_all:");
1263 /* -------------------------- */
1264 static int copy_fd(int dfd, int sfd)
1270 #ifdef SENDFILE_FLAVOR_LINUX
1273 if (fstat(sfd, &st) == 0) {
1274 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1276 case EINVAL: /* there's no guarantee that all fs support sendfile */
1281 return AFPERR_DFULL;
1283 return AFPERR_VLOCK;
1285 return AFPERR_PARAM;
1292 #endif /* SENDFILE_FLAVOR_LINUX */
1295 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1302 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1308 /* ----------------------------------
1309 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1310 * because we are doing it elsewhere.
1312 int copyfile(src, dst, newname, noadouble )
1313 char *src, *dst, *newname;
1314 const int noadouble;
1316 struct adouble ads, add;
1317 int len, err = AFP_OK;
1321 LOG(log_info, logtype_afpd, "begin copyfile:");
1324 memset(&ads, 0, sizeof(ads));
1325 memset(&add, 0, sizeof(add));
1326 adflags = ADFLAGS_DF;
1328 adflags |= ADFLAGS_HF;
1331 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1334 return( AFPERR_NOOBJ );
1336 return( AFPERR_ACCESS );
1338 return( AFPERR_PARAM );
1341 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1342 ad_close( &ads, adflags );
1343 if (EEXIST != (err = errno)) {
1344 deletefile(NULL, dst, 0);
1348 return AFPERR_EXIST;
1350 return( AFPERR_NOOBJ );
1352 return( AFPERR_ACCESS );
1354 return AFPERR_VLOCK;
1356 return( AFPERR_PARAM );
1359 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1360 /* copy the data fork */
1361 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1365 len = strlen( newname );
1366 ad_setentrylen( &add, ADEID_NAME, len );
1367 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1370 ad_close( &ads, adflags );
1371 ad_flush( &add, adflags );
1372 if (ad_close( &add, adflags ) <0) {
1375 if (err != AFP_OK) {
1376 deletefile(NULL, dst, 0);
1379 return( AFPERR_NOOBJ );
1381 return( AFPERR_ACCESS );
1383 return( AFPERR_PARAM );
1388 LOG(log_info, logtype_afpd, "end copyfile:");
1395 /* -----------------------------------
1396 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1397 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1399 when deletefile is called we don't have lock on it, file is closed (for us)
1400 untrue if called by renamefile
1402 ad_open always try to open file RDWR first and ad_lock takes care of
1403 WRITE lock on read only file.
1405 int deletefile( vol, file, checkAttrib )
1411 int adflags, err = AFP_OK;
1414 LOG(log_info, logtype_afpd, "begin deletefile:");
1417 /* try to open both forks at once */
1418 adflags = ADFLAGS_DF|ADFLAGS_HF;
1420 memset(&ad, 0, sizeof(ad));
1421 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1424 if (adflags == ADFLAGS_DF)
1425 return AFPERR_NOOBJ;
1427 /* that failed. now try to open just the data fork */
1428 adflags = ADFLAGS_DF;
1432 return AFPERR_ACCESS;
1434 return AFPERR_VLOCK;
1436 return( AFPERR_PARAM );
1439 break; /* from the while */
1442 * Does kFPDeleteInhibitBit (bit 8) set?
1444 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1447 ad_getattr(&ad, &bshort);
1448 if ((bshort & htons(ATTRBIT_NODELETE))) {
1449 ad_close( &ad, adflags );
1450 return(AFPERR_OLOCK);
1454 if ((adflags & ADFLAGS_HF) ) {
1455 /* FIXME we have a pb here because we want to know if a file is open
1456 * there's a 'priority inversion' if you can't open the ressource fork RW
1457 * you can delete it if it's open because you can't get a write lock.
1459 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1462 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1464 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1465 ad_close( &ad, adflags );
1466 return( AFPERR_BUSY );
1470 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1473 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1474 !(err = netatalk_unlink( file )) ) {
1475 #ifdef CNID_DB /* get rid of entry */
1477 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1479 cnid_delete(vol->v_db, id);
1481 #endif /* CNID_DB */
1484 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1487 LOG(log_info, logtype_afpd, "end deletefile:");
1493 /* ------------------------------------ */
1495 /* return a file id */
1496 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1499 int ibuflen, *rbuflen;
1508 struct path *s_path;
1511 LOG(log_info, logtype_afpd, "begin afp_createid:");
1518 memcpy(&vid, ibuf, sizeof(vid));
1519 ibuf += sizeof(vid);
1521 if (NULL == ( vol = getvolbyvid( vid )) ) {
1522 return( AFPERR_PARAM);
1525 if (vol->v_db == NULL) {
1529 if (vol->v_flags & AFPVOL_RO)
1530 return AFPERR_VLOCK;
1532 memcpy(&did, ibuf, sizeof( did ));
1533 ibuf += sizeof(did);
1535 if (NULL == ( dir = dirlookup( vol, did )) ) {
1536 return afp_errno; /* was AFPERR_PARAM */
1539 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1540 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1543 if ( path_isadir(s_path) ) {
1544 return( AFPERR_BADTYPE );
1547 upath = s_path->u_name;
1548 switch (s_path->st_errno) {
1550 break; /* success */
1553 return AFPERR_ACCESS;
1555 return AFPERR_NOOBJ;
1557 return AFPERR_PARAM;
1560 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1561 memcpy(rbuf, &id, sizeof(id));
1562 *rbuflen = sizeof(id);
1563 return AFPERR_EXISTID;
1566 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1567 memcpy(rbuf, &id, sizeof(id));
1568 *rbuflen = sizeof(id);
1573 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1578 /* ------------------------------
1579 resolve a file id */
1580 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1583 int ibuflen, *rbuflen;
1591 u_int16_t vid, bitmap;
1593 static char buffer[12 + MAXPATHLEN + 1];
1594 int len = 12 + MAXPATHLEN + 1;
1597 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1603 memcpy(&vid, ibuf, sizeof(vid));
1604 ibuf += sizeof(vid);
1606 if (NULL == ( vol = getvolbyvid( vid )) ) {
1607 return( AFPERR_PARAM);
1610 if (vol->v_db == NULL) {
1614 memcpy(&id, ibuf, sizeof( id ));
1617 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1618 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1621 if (NULL == ( dir = dirlookup( vol, id )) ) {
1622 return AFPERR_NOID; /* idem AFPERR_PARAM */
1624 path.u_name = upath;
1625 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1629 return AFPERR_ACCESS;
1633 return AFPERR_PARAM;
1636 /* directories are bad */
1637 if (S_ISDIR(path.st.st_mode))
1638 return AFPERR_BADTYPE;
1640 memcpy(&bitmap, ibuf, sizeof(bitmap));
1641 bitmap = ntohs( bitmap );
1642 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1645 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1646 rbuf + sizeof(bitmap), &buflen))) {
1649 *rbuflen = buflen + sizeof(bitmap);
1650 memcpy(rbuf, ibuf, sizeof(bitmap));
1653 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1659 /* ------------------------------ */
1660 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1663 int ibuflen, *rbuflen;
1673 static char buffer[12 + MAXPATHLEN + 1];
1674 int len = 12 + MAXPATHLEN + 1;
1677 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1683 memcpy(&vid, ibuf, sizeof(vid));
1684 ibuf += sizeof(vid);
1686 if (NULL == ( vol = getvolbyvid( vid )) ) {
1687 return( AFPERR_PARAM);
1690 if (vol->v_db == NULL) {
1694 if (vol->v_flags & AFPVOL_RO)
1695 return AFPERR_VLOCK;
1697 memcpy(&id, ibuf, sizeof( id ));
1701 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1705 if (NULL == ( dir = dirlookup( vol, id )) ) {
1706 return( AFPERR_PARAM );
1710 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1714 return AFPERR_ACCESS;
1716 /* still try to delete the id */
1720 return AFPERR_PARAM;
1723 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1724 return AFPERR_BADTYPE;
1726 if (cnid_delete(vol->v_db, fileid)) {
1729 return AFPERR_VLOCK;
1732 return AFPERR_ACCESS;
1734 return AFPERR_PARAM;
1739 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1744 #endif /* CNID_DB */
1746 #define APPLETEMP ".AppleTempXXXXXX"
1748 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1751 int ibuflen, *rbuflen;
1753 struct stat srcst, destst;
1755 struct dir *dir, *sdir;
1756 char *spath, temp[17], *p;
1757 char *supath, *upath;
1762 struct adouble *adsp;
1763 struct adouble *addp;
1770 #endif /* CNID_DB */
1775 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1781 memcpy(&vid, ibuf, sizeof(vid));
1782 ibuf += sizeof(vid);
1784 if (NULL == ( vol = getvolbyvid( vid )) ) {
1785 return( AFPERR_PARAM);
1788 if (vol->v_flags & AFPVOL_RO)
1789 return AFPERR_VLOCK;
1791 /* source and destination dids */
1792 memcpy(&sid, ibuf, sizeof(sid));
1793 ibuf += sizeof(sid);
1794 memcpy(&did, ibuf, sizeof(did));
1795 ibuf += sizeof(did);
1798 if (NULL == (dir = dirlookup( vol, sid )) ) {
1799 return afp_errno; /* was AFPERR_PARAM */
1802 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1803 return get_afp_errno(AFPERR_NOOBJ);
1806 if ( path_isadir(path) ) {
1807 return( AFPERR_BADTYPE ); /* it's a dir */
1810 upath = path->u_name;
1811 switch (path->st_errno) {
1818 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1822 memset(&ads, 0, sizeof(ads));
1824 if ((s_of = of_findname(path))) {
1825 /* reuse struct adouble so it won't break locks */
1828 memcpy(&srcst, &path->st, sizeof(struct stat));
1829 /* save some stuff */
1831 spath = obj->oldtmp;
1832 supath = obj->newtmp;
1833 strcpy(spath, path->m_name);
1834 strcpy(supath, upath); /* this is for the cnid changing */
1835 p = absupath( vol, sdir, upath);
1837 /* pathname too long */
1838 return AFPERR_PARAM ;
1841 /* look for the source cnid. if it doesn't exist, don't worry about
1844 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1845 slen = strlen(supath));
1846 #endif /* CNID_DB */
1848 if (NULL == ( dir = dirlookup( vol, did )) ) {
1849 return afp_errno; /* was AFPERR_PARAM */
1852 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1853 return get_afp_errno(AFPERR_NOOBJ);
1856 if ( path_isadir(path) ) {
1857 return( AFPERR_BADTYPE );
1860 /* FPExchangeFiles is the only call that can return the SameObj
1862 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1863 return AFPERR_SAMEOBJ;
1865 switch (path->st_errno) {
1872 return AFPERR_ACCESS;
1874 return AFPERR_PARAM;
1876 memset(&add, 0, sizeof(add));
1878 if ((d_of = of_findname( path))) {
1879 /* reuse struct adouble so it won't break locks */
1882 memcpy(&destst, &path->st, sizeof(struct stat));
1884 /* they are not on the same device and at least one is open
1886 crossdev = (srcst.st_dev != destst.st_dev);
1887 if ((d_of || s_of) && crossdev)
1890 upath = path->u_name;
1892 /* look for destination id. */
1893 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1894 dlen = strlen(upath));
1895 #endif /* CNID_DB */
1897 /* construct a temp name.
1898 * NOTE: the temp file will be in the dest file's directory. it
1899 * will also be inaccessible from AFP. */
1900 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1904 /* now, quickly rename the file. we error if we can't. */
1905 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1906 goto err_exchangefile;
1907 of_rename(vol, s_of, sdir, spath, curdir, temp);
1909 /* rename destination to source */
1910 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1911 goto err_src_to_tmp;
1912 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1914 /* rename temp to destination */
1915 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1916 goto err_dest_to_src;
1917 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1920 /* id's need switching. src -> dest and dest -> src.
1921 * we need to re-stat() if it was a cross device copy.
1924 cnid_delete(vol->v_db, sid);
1927 cnid_delete(vol->v_db, did);
1929 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1930 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1932 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1933 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1938 err = AFPERR_ACCESS;
1943 goto err_temp_to_dest;
1945 #endif /* CNID_DB */
1948 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1954 /* all this stuff is so that we can unwind a failed operation
1959 /* rename dest to temp */
1960 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1961 of_rename(vol, s_of, curdir, upath, curdir, temp);
1964 /* rename source back to dest */
1965 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1966 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1969 /* rename temp back to source */
1970 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1971 of_rename(vol, s_of, curdir, temp, sdir, spath);