2 * $Id: file.c,v 1.88 2003-03-15 01:34:35 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
52 #include <atalk/cnid.h>
54 #include "directory.h"
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63 * field bytes subfield bytes
66 * ioFlFndrInfo 16 -> type 4 type field
67 * creator 4 creator field
68 * flags 2 finder flags:
70 * location 4 location in window
71 * folder 2 window that contains file
73 * ioFlXFndrInfo 16 -> iconID 2 icon id
75 * script 1 script system
77 * commentID 2 comment id
78 * putawayID 4 home directory id
81 const u_char ufinderi[] = {
82 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
94 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
116 aint = strlen( name );
120 if (utf8_encoding()) {
121 /* but name is an utf8 mac name */
124 /* global static variable... */
126 if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
146 memcpy(data, &utf8, sizeof(utf8));
147 data += sizeof(utf8);
150 memcpy(data, &temp, sizeof(temp));
151 data += sizeof(temp);
154 memcpy( data, src, aint );
164 * FIXME: PDINFO is UTF8 and doesn't need adp
166 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
167 (1 << FILPBIT_CDATE) |\
168 (1 << FILPBIT_MDATE) |\
169 (1 << FILPBIT_BDATE) |\
170 (1 << FILPBIT_FINFO) |\
171 (1 << FILPBIT_RFLEN) |\
172 (1 << FILPBIT_EXTRFLEN) |\
173 (1 << FILPBIT_PDINFO)))
175 /* -------------------------- */
176 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
177 const cnid_t did, const char *upath, const int len)
183 aint = cnid_add(vol->v_db, st, did, upath, len, aint);
184 /* Throw errors if cnid_add fails. */
185 if (aint == CNID_INVALID) {
187 case CNID_ERR_CLOSE: /* the db is closed */
190 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
191 afp_errno = AFPERR_PARAM;
194 afp_errno = AFPERR_PARAM;
197 afp_errno = AFPERR_MISC;
205 * First thing: DID and FNUMs are
206 * in the same space for purposes of enumerate (and several
207 * other wierd places). While we consider this Apple's bug,
208 * this is the work-around: In order to maintain constant and
209 * unique DIDs and FNUMs, we monotonically generate the DIDs
210 * during the session, and derive the FNUMs from the filesystem.
211 * Since the DIDs are small, we insure that the FNUMs are fairly
212 * large by setting thier high bits to the device number.
214 * AFS already does something very similar to this for the
215 * inode number, so we don't repeat the procedure.
218 * due to complaints over did's being non-persistent,
219 * here's the current hack to provide semi-persistent
221 * 1) we reserve the first bit for file ids.
222 * 2) the next 7 bits are for the device.
223 * 3) the remaining 24 bits are for the inode.
225 * both the inode and device information are actually hashes
226 * that are then truncated to the requisite bit length.
228 * it should be okay to use lstat to deal with symlinks.
231 if ( S_ISDIR(st->st_mode)) {
232 aint = htonl( vol->v_lastdid++ );
236 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
238 #else /* USE_LASTDID */
241 const struct stat *lstp;
243 lstp = lstat(upath, &lst) < 0 ? st : &lst;
244 aint = htonl(CNID(lstp, 1));
246 #endif /* USE_LASTDID */
251 /* -------------------------- */
252 int getmetadata(struct vol *vol,
254 struct path *path, struct dir *dir,
255 char *buf, int *buflen, struct adouble *adp, int attrbits )
257 char *data, *l_nameoff = NULL, *upath;
258 char *utf_nameoff = NULL;
262 u_char achar, fdType[4];
266 LOG(log_info, logtype_afpd, "begin getmetadata:");
269 upath = path->u_name;
273 while ( bitmap != 0 ) {
274 while (( bitmap & 1 ) == 0 ) {
282 ad_getattr(adp, &ashort);
283 } else if (*upath == '.') {
284 ashort = htons(ATTRBIT_INVISIBLE);
288 /* FIXME do we want a visual clue if the file is read only
291 accessmode( ".", &ma, dir , NULL);
292 if ((ma.ma_user & AR_UWRITE)) {
293 accessmode( upath, &ma, dir , st);
294 if (!(ma.ma_user & AR_UWRITE)) {
295 attrbits |= ATTRBIT_NOWRITE;
300 ashort = htons(ntohs(ashort) | attrbits);
301 memcpy(data, &ashort, sizeof( ashort ));
302 data += sizeof( ashort );
306 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
307 data += sizeof( u_int32_t );
311 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
312 aint = AD_DATE_FROM_UNIX(st->st_mtime);
313 memcpy(data, &aint, sizeof( aint ));
314 data += sizeof( aint );
318 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
319 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
325 memcpy(data, &aint, sizeof( int ));
326 data += sizeof( int );
330 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
331 aint = AD_DATE_START;
332 memcpy(data, &aint, sizeof( int ));
333 data += sizeof( int );
337 get_finderinfo(path->m_name, adp, (char *)data);
339 if (*upath == '.') { /* make it invisible */
340 ashort = htons(FINDERINFO_INVISIBLE);
341 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
349 data += sizeof( u_int16_t );
353 memset(data, 0, sizeof(u_int16_t));
354 data += sizeof( u_int16_t );
358 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
361 memcpy(data, &aint, sizeof( aint ));
362 data += sizeof( aint );
366 if (st->st_size > 0xffffffff)
369 aint = htonl( st->st_size );
370 memcpy(data, &aint, sizeof( aint ));
371 data += sizeof( aint );
376 if (adp->ad_rlen > 0xffffffff)
379 aint = htonl( adp->ad_rlen);
383 memcpy(data, &aint, sizeof( aint ));
384 data += sizeof( aint );
387 /* Current client needs ProDOS info block for this file.
388 Use simple heuristic and let the Mac "type" string tell
389 us what the PD file code should be. Everything gets a
390 subtype of 0x0000 unless the original value was hashed
391 to "pXYZ" when we created it. See IA, Ver 2.
392 <shirsch@adelphia.net> */
393 case FILPBIT_PDINFO :
394 if (afp_version >= 30) { /* UTF8 name */
395 utf8 = kTextEncodingUTF8;
397 data += sizeof( u_int16_t );
399 memcpy(data, &aint, sizeof( aint ));
400 data += sizeof( aint );
404 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
406 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
418 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
422 else if ( fdType[0] == 'p' ) {
424 ashort = (fdType[2] * 256) + fdType[3];
438 memcpy(data, &ashort, sizeof( ashort ));
439 data += sizeof( ashort );
440 memset(data, 0, sizeof( ashort ));
441 data += sizeof( ashort );
444 case FILPBIT_EXTDFLEN:
445 aint = htonl(st->st_size >> 32);
446 memcpy(data, &aint, sizeof( aint ));
447 data += sizeof( aint );
448 aint = htonl(st->st_size);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 case FILPBIT_EXTRFLEN:
455 aint = htonl(adp->ad_rlen >> 32);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
459 aint = htonl(adp->ad_rlen);
460 memcpy(data, &aint, sizeof( aint ));
461 data += sizeof( aint );
464 return( AFPERR_BITMAP );
470 ashort = htons( data - buf );
471 memcpy(l_nameoff, &ashort, sizeof( ashort ));
472 data = set_name(vol, data, path->m_name, 0);
475 ashort = htons( data - buf );
476 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
477 data = set_name(vol, data, path->m_name, utf8);
479 *buflen = data - buf;
483 /* ----------------------- */
484 int getfilparams(struct vol *vol,
486 struct path *path, struct dir *dir,
487 char *buf, int *buflen )
489 struct adouble ad, *adp;
492 u_int16_t attrbits = 0;
497 LOG(log_info, logtype_default, "begin getfilparams:");
500 opened = PARAM_NEED_ADP(bitmap);
503 upath = path->u_name;
504 if ((of = of_findname(path))) {
506 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
507 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
509 memset(&ad, 0, sizeof(ad));
513 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
518 we need to check if the file is open by another process.
519 it's slow so we only do it if we have to:
520 - bitmap is requested.
521 - we don't already have the answer!
523 if ((bitmap & (1 << FILPBIT_ATTR))) {
524 if (!(attrbits & ATTRBIT_ROPEN)) {
526 if (!(attrbits & ATTRBIT_DOPEN)) {
531 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
533 ad_close( adp, ADFLAGS_HF );
536 LOG(log_info, logtype_afpd, "end getfilparams:");
542 /* ----------------------------- */
543 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
546 int ibuflen, *rbuflen;
548 struct adouble ad, *adp;
551 struct ofork *of = NULL;
553 int creatf, did, openf, retvalue = AFP_OK;
559 LOG(log_info, logtype_afpd, "begin afp_createfile:");
564 creatf = (unsigned char) *ibuf++;
566 memcpy(&vid, ibuf, sizeof( vid ));
567 ibuf += sizeof( vid );
569 if (NULL == ( vol = getvolbyvid( vid )) ) {
570 return( AFPERR_PARAM );
573 if (vol->v_flags & AFPVOL_RO)
576 memcpy(&did, ibuf, sizeof( did));
577 ibuf += sizeof( did );
579 if (NULL == ( dir = dirlookup( vol, did )) ) {
583 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
584 return get_afp_errno(AFPERR_PARAM);
587 if ( *s_path->m_name == '\0' ) {
588 return( AFPERR_BADTYPE );
591 upath = s_path->u_name;
592 if (0 != (ret = check_name(vol, upath)))
595 /* if upath is deleted we already in trouble anyway */
596 if ((of = of_findname(s_path))) {
599 memset(&ad, 0, sizeof(ad));
603 /* on a hard create, fail if file exists and is open */
606 openf = O_RDWR|O_CREAT|O_TRUNC;
608 /* on a soft create, if the file is open then ad_open won't fail
609 because open syscall is not called
614 openf = O_RDWR|O_CREAT|O_EXCL;
617 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
618 openf, 0666, adp) < 0 ) {
620 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
621 return ( AFPERR_NOOBJ );
623 return( AFPERR_EXIST );
625 return( AFPERR_ACCESS );
627 return( AFPERR_PARAM );
630 if ( ad_hfileno( adp ) == -1 ) {
631 /* on noadouble volumes, just creating the data fork is ok */
632 if (vol_noadouble(vol))
633 goto createfile_done;
634 /* FIXME with hard create on an existing file, we already
635 * corrupted the data file.
637 netatalk_unlink( upath );
638 ad_close( adp, ADFLAGS_DF );
639 return AFPERR_ACCESS;
642 path = s_path->m_name;
643 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
644 memcpy(ad_entry( adp, ADEID_NAME ), path,
645 ad_getentrylen( adp, ADEID_NAME ));
646 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
647 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
653 if (vol->v_flags & AFPVOL_DROPBOX) {
654 retvalue = matchfile2dirperms(upath, vol, did);
656 #endif /* DROPKLUDGE */
658 setvoltime(obj, vol );
661 LOG(log_info, logtype_afpd, "end afp_createfile");
667 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
670 int ibuflen, *rbuflen;
676 u_int16_t vid, bitmap;
679 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
685 memcpy(&vid, ibuf, sizeof( vid ));
686 ibuf += sizeof( vid );
687 if (NULL == ( vol = getvolbyvid( vid )) ) {
688 return( AFPERR_PARAM );
691 if (vol->v_flags & AFPVOL_RO)
694 memcpy(&did, ibuf, sizeof( did ));
695 ibuf += sizeof( did );
696 if (NULL == ( dir = dirlookup( vol, did )) ) {
697 return afp_errno; /* was AFPERR_NOOBJ */
700 memcpy(&bitmap, ibuf, sizeof( bitmap ));
701 bitmap = ntohs( bitmap );
702 ibuf += sizeof( bitmap );
704 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
705 return get_afp_errno(AFPERR_PARAM);
708 if (path_isadir(s_path)) {
709 return( AFPERR_BADTYPE ); /* it's a directory */
712 if ((u_long)ibuf & 1 ) {
716 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
717 setvoltime(obj, vol );
721 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
728 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
731 extern struct path Cur_Path;
733 int setfilparams(struct vol *vol,
734 struct path *path, u_int16_t bitmap, char *buf )
736 struct adouble ad, *adp;
739 int bit = 0, isad = 1, err = AFP_OK;
741 u_char achar, *fdType, xyy[4];
742 u_int16_t ashort, bshort;
746 int change_mdate = 0;
747 int change_parent_mdate = 0;
753 LOG(log_info, logtype_afpd, "begin setfilparams:");
756 upath = path->u_name;
757 if ((of = of_findname(path))) {
760 memset(&ad, 0, sizeof(ad));
764 if (check_access(upath, OPENACC_WR ) < 0) {
765 return AFPERR_ACCESS;
768 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
769 O_RDWR|O_CREAT, 0666, adp) < 0) {
770 /* for some things, we don't need an adouble header */
771 if (bitmap & ~(1<<FILPBIT_MDATE)) {
772 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
775 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
776 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
777 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
778 ad_getentrylen( adp, ADEID_NAME ));
781 while ( bitmap != 0 ) {
782 while (( bitmap & 1 ) == 0 ) {
790 memcpy(&ashort, buf, sizeof( ashort ));
791 ad_getattr(adp, &bshort);
792 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
793 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
797 if ((ashort & htons(ATTRBIT_INVISIBLE)))
798 change_parent_mdate = 1;
799 ad_setattr(adp, bshort);
800 buf += sizeof( ashort );
805 memcpy(&aint, buf, sizeof(aint));
806 ad_setdate(adp, AD_DATE_CREATE, aint);
807 buf += sizeof( aint );
811 memcpy(&newdate, buf, sizeof( newdate ));
812 buf += sizeof( newdate );
817 memcpy(&aint, buf, sizeof(aint));
818 ad_setdate(adp, AD_DATE_BACKUP, aint);
819 buf += sizeof( aint );
825 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
827 ((em = getextmap( path->m_name )) &&
828 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
829 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
830 || ((em = getdefextmap()) &&
831 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
832 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
834 memcpy(buf, ufinderi, 8 );
837 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
841 /* Client needs to set the ProDOS file info for this file.
842 Use a defined string for TEXT to support crlf
843 translations and convert all else into pXYY per Inside
844 Appletalk. Always set the creator as "pdos". Changes
845 from original by Marsha Jackson. */
846 case FILPBIT_PDINFO :
847 if (afp_version < 30) { /* else it's UTF8 name */
850 /* Keep special case to support crlf translations */
851 if ((unsigned int) achar == 0x04) {
852 fdType = (u_char *)"TEXT";
855 xyy[0] = ( u_char ) 'p';
861 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
862 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
868 goto setfilparam_done;
876 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
877 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
881 ad_setdate(adp, AD_DATE_MODIFY, newdate);
882 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
887 ad_flush( adp, ADFLAGS_HF );
888 ad_close( adp, ADFLAGS_HF );
892 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
893 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
894 bitmap = 1<<FILPBIT_MDATE;
895 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
899 LOG(log_info, logtype_afpd, "end setfilparams:");
905 * renamefile and copyfile take the old and new unix pathnames
906 * and the new mac name.
908 * src the source path
909 * dst the dest filename in current dir
910 * newname the dest mac name
911 * adp adouble struct of src file, if open, or & zeroed one
914 int renamefile(src, dst, newname, noadouble, adp )
915 char *src, *dst, *newname;
919 char adsrc[ MAXPATHLEN + 1];
924 LOG(log_info, logtype_afpd, "begin renamefile:");
927 if ( unix_rename( src, dst ) < 0 ) {
930 return( AFPERR_NOOBJ );
933 return( AFPERR_ACCESS );
936 case EXDEV : /* Cross device move -- try copy */
937 /* NOTE: with open file it's an error because after the copy we will
938 * get two files, it's fixable for our process (eg reopen the new file, get the
939 * locks, and so on. But it doesn't solve the case with a second process
941 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
942 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
943 return AFPERR_OLOCK; /* little lie */
945 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
946 /* on error copyfile delete dest */
949 return deletefile(NULL, src, 0);
951 return( AFPERR_PARAM );
955 strcpy( adsrc, ad_path( src, 0 ));
957 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
962 if (errno == ENOENT) {
965 if (stat(adsrc, &st)) /* source has no ressource fork, */
968 /* We are here because :
969 * -there's no dest folder.
970 * -there's no .AppleDouble in the dest folder.
971 * if we use the struct adouble passed in parameter it will not
972 * create .AppleDouble if the file is already opened, so we
973 * use a diff one, it's not a pb,ie it's not the same file, yet.
975 memset(&ad, 0, sizeof(ad));
976 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
977 ad_close(&ad, ADFLAGS_HF);
978 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
983 else { /* it's something else, bail out */
987 /* try to undo the data fork rename,
988 * we know we are on the same device
991 unix_rename( dst, src );
992 /* return the first error */
998 return AFPERR_ACCESS ;
1000 return AFPERR_VLOCK;
1002 return AFPERR_PARAM ;
1007 /* don't care if we can't open the newly renamed ressource fork
1009 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1010 len = strlen( newname );
1011 ad_setentrylen( adp, ADEID_NAME, len );
1012 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1013 ad_flush( adp, ADFLAGS_HF );
1014 ad_close( adp, ADFLAGS_HF );
1017 LOG(log_info, logtype_afpd, "end renamefile:");
1023 int copy_path_name(char *newname, char *ibuf)
1030 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1036 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1037 strncpy( newname, ibuf, plen );
1038 newname[ plen ] = '\0';
1039 if (strlen(newname) != plen) {
1040 /* there's \0 in newname, e.g. it's a pathname not
1048 memcpy(&hint, ibuf, sizeof(hint));
1049 ibuf += sizeof(hint);
1051 memcpy(&len16, ibuf, sizeof(len16));
1052 ibuf += sizeof(len16);
1053 plen = ntohs(len16);
1055 strncpy( newname, ibuf, plen );
1056 newname[ plen ] = '\0';
1057 if (strlen(newname) != plen) {
1066 /* -----------------------------------
1068 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1071 int ibuflen, *rbuflen;
1075 char *newname, *p, *upath;
1076 struct path *s_path;
1077 u_int32_t sdid, ddid;
1078 int err, retvalue = AFP_OK;
1079 u_int16_t svid, dvid;
1082 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1088 memcpy(&svid, ibuf, sizeof( svid ));
1089 ibuf += sizeof( svid );
1090 if (NULL == ( vol = getvolbyvid( svid )) ) {
1091 return( AFPERR_PARAM );
1094 memcpy(&sdid, ibuf, sizeof( sdid ));
1095 ibuf += sizeof( sdid );
1096 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1100 memcpy(&dvid, ibuf, sizeof( dvid ));
1101 ibuf += sizeof( dvid );
1102 memcpy(&ddid, ibuf, sizeof( ddid ));
1103 ibuf += sizeof( ddid );
1105 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1106 return get_afp_errno(AFPERR_PARAM);
1108 if ( path_isadir(s_path) ) {
1109 return( AFPERR_BADTYPE );
1112 /* don't allow copies when the file is open.
1113 * XXX: the spec only calls for read/deny write access.
1114 * however, copyfile doesn't have any of that info,
1115 * and locks need to stay coherent. as a result,
1116 * we just balk if the file is opened already. */
1118 newname = obj->newtmp;
1119 strcpy( newname, s_path->m_name );
1121 if (of_findname(s_path))
1122 return AFPERR_DENYCONF;
1124 p = ctoupath( vol, curdir, newname );
1126 return AFPERR_PARAM;
1130 /* FIXME svid != dvid && dvid's user can't read svid */
1132 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1133 return( AFPERR_PARAM );
1136 if (vol->v_flags & AFPVOL_RO)
1137 return AFPERR_VLOCK;
1139 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1143 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1144 return get_afp_errno(AFPERR_NOOBJ);
1146 if ( *s_path->m_name != '\0' ) {
1147 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1150 /* one of the handful of places that knows about the path type */
1151 if (copy_path_name(newname, ibuf) < 0) {
1152 return( AFPERR_PARAM );
1155 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1156 return( AFPERR_PARAM );
1158 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1164 if (vol->v_flags & AFPVOL_DROPBOX) {
1165 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1167 #endif /* DROPKLUDGE */
1169 setvoltime(obj, vol );
1172 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1179 static __inline__ int copy_all(const int dfd, const void *buf,
1185 LOG(log_info, logtype_afpd, "begin copy_all:");
1188 while (buflen > 0) {
1189 if ((cc = write(dfd, buf, buflen)) < 0) {
1196 return AFPERR_DFULL;
1198 return AFPERR_VLOCK;
1200 return AFPERR_PARAM;
1207 LOG(log_info, logtype_afpd, "end copy_all:");
1213 /* -------------------------- */
1214 static int copy_fd(int dfd, int sfd)
1220 #ifdef SENDFILE_FLAVOR_LINUX
1223 if (fstat(sfd, &st) == 0) {
1224 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1226 case EINVAL: /* there's no guarantee that all fs support sendfile */
1231 return AFPERR_DFULL;
1233 return AFPERR_VLOCK;
1235 return AFPERR_PARAM;
1242 #endif /* SENDFILE_FLAVOR_LINUX */
1245 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1252 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1258 /* ----------------------------------
1259 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1260 * because we are doing it elsewhere.
1262 int copyfile(src, dst, newname, noadouble )
1263 char *src, *dst, *newname;
1264 const int noadouble;
1266 struct adouble ads, add;
1267 int len, err = AFP_OK;
1271 LOG(log_info, logtype_afpd, "begin copyfile:");
1274 memset(&ads, 0, sizeof(ads));
1275 memset(&add, 0, sizeof(add));
1276 adflags = ADFLAGS_DF;
1278 adflags |= ADFLAGS_HF;
1281 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1284 return( AFPERR_NOOBJ );
1286 return( AFPERR_ACCESS );
1288 return( AFPERR_PARAM );
1291 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1292 ad_close( &ads, adflags );
1293 if (EEXIST != (err = errno)) {
1294 deletefile(NULL, dst, 0);
1298 return AFPERR_EXIST;
1300 return( AFPERR_NOOBJ );
1302 return( AFPERR_ACCESS );
1304 return AFPERR_VLOCK;
1306 return( AFPERR_PARAM );
1309 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1310 /* copy the data fork */
1311 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1315 len = strlen( newname );
1316 ad_setentrylen( &add, ADEID_NAME, len );
1317 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1320 ad_close( &ads, adflags );
1321 ad_flush( &add, adflags );
1322 if (ad_close( &add, adflags ) <0) {
1325 if (err != AFP_OK) {
1326 deletefile(NULL, dst, 0);
1329 return( AFPERR_NOOBJ );
1331 return( AFPERR_ACCESS );
1333 return( AFPERR_PARAM );
1338 LOG(log_info, logtype_afpd, "end copyfile:");
1345 /* -----------------------------------
1346 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1347 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1349 when deletefile is called we don't have lock on it, file is closed (for us)
1350 untrue if called by renamefile
1352 ad_open always try to open file RDWR first and ad_lock takes care of
1353 WRITE lock on read only file.
1355 int deletefile( vol, file, checkAttrib )
1361 int adflags, err = AFP_OK;
1364 LOG(log_info, logtype_afpd, "begin deletefile:");
1367 /* try to open both forks at once */
1368 adflags = ADFLAGS_DF|ADFLAGS_HF;
1370 memset(&ad, 0, sizeof(ad));
1371 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1374 if (adflags == ADFLAGS_DF)
1375 return AFPERR_NOOBJ;
1377 /* that failed. now try to open just the data fork */
1378 adflags = ADFLAGS_DF;
1382 return AFPERR_ACCESS;
1384 return AFPERR_VLOCK;
1386 return( AFPERR_PARAM );
1389 break; /* from the while */
1392 * Does kFPDeleteInhibitBit (bit 8) set?
1394 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1397 ad_getattr(&ad, &bshort);
1398 if ((bshort & htons(ATTRBIT_NODELETE))) {
1399 ad_close( &ad, adflags );
1400 return(AFPERR_OLOCK);
1404 if ((adflags & ADFLAGS_HF) ) {
1405 /* FIXME we have a pb here because we want to know if a file is open
1406 * there's a 'priority inversion' if you can't open the ressource fork RW
1407 * you can delete it if it's open because you can't get a write lock.
1409 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1412 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1414 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1415 ad_close( &ad, adflags );
1416 return( AFPERR_BUSY );
1420 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1423 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1424 !(err = netatalk_unlink( file )) ) {
1425 #ifdef CNID_DB /* get rid of entry */
1427 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1429 cnid_delete(vol->v_db, id);
1431 #endif /* CNID_DB */
1434 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1437 LOG(log_info, logtype_afpd, "end deletefile:");
1443 /* ------------------------------------ */
1445 /* return a file id */
1446 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1449 int ibuflen, *rbuflen;
1458 struct path *s_path;
1461 LOG(log_info, logtype_afpd, "begin afp_createid:");
1468 memcpy(&vid, ibuf, sizeof(vid));
1469 ibuf += sizeof(vid);
1471 if (NULL == ( vol = getvolbyvid( vid )) ) {
1472 return( AFPERR_PARAM);
1475 if (vol->v_db == NULL) {
1479 if (vol->v_flags & AFPVOL_RO)
1480 return AFPERR_VLOCK;
1482 memcpy(&did, ibuf, sizeof( did ));
1483 ibuf += sizeof(did);
1485 if (NULL == ( dir = dirlookup( vol, did )) ) {
1486 return afp_errno; /* was AFPERR_PARAM */
1489 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1490 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1493 if ( path_isadir(s_path) ) {
1494 return( AFPERR_BADTYPE );
1497 upath = s_path->u_name;
1498 switch (s_path->st_errno) {
1500 break; /* success */
1503 return AFPERR_ACCESS;
1505 return AFPERR_NOOBJ;
1507 return AFPERR_PARAM;
1510 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1511 memcpy(rbuf, &id, sizeof(id));
1512 *rbuflen = sizeof(id);
1513 return AFPERR_EXISTID;
1516 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1517 memcpy(rbuf, &id, sizeof(id));
1518 *rbuflen = sizeof(id);
1523 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1528 /* ------------------------------
1529 resolve a file id */
1530 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1533 int ibuflen, *rbuflen;
1541 u_int16_t vid, bitmap;
1543 static char buffer[12 + MAXPATHLEN + 1];
1544 int len = 12 + MAXPATHLEN + 1;
1547 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1553 memcpy(&vid, ibuf, sizeof(vid));
1554 ibuf += sizeof(vid);
1556 if (NULL == ( vol = getvolbyvid( vid )) ) {
1557 return( AFPERR_PARAM);
1560 if (vol->v_db == NULL) {
1564 memcpy(&id, ibuf, sizeof( id ));
1567 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1568 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1571 if (NULL == ( dir = dirlookup( vol, id )) ) {
1572 return AFPERR_NOID; /* idem AFPERR_PARAM */
1574 path.u_name = upath;
1575 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1579 return AFPERR_ACCESS;
1583 return AFPERR_PARAM;
1586 /* directories are bad */
1587 if (S_ISDIR(path.st.st_mode))
1588 return AFPERR_BADTYPE;
1590 memcpy(&bitmap, ibuf, sizeof(bitmap));
1591 bitmap = ntohs( bitmap );
1592 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1595 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1596 rbuf + sizeof(bitmap), &buflen))) {
1599 *rbuflen = buflen + sizeof(bitmap);
1600 memcpy(rbuf, ibuf, sizeof(bitmap));
1603 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1609 /* ------------------------------ */
1610 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1613 int ibuflen, *rbuflen;
1623 static char buffer[12 + MAXPATHLEN + 1];
1624 int len = 12 + MAXPATHLEN + 1;
1627 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1633 memcpy(&vid, ibuf, sizeof(vid));
1634 ibuf += sizeof(vid);
1636 if (NULL == ( vol = getvolbyvid( vid )) ) {
1637 return( AFPERR_PARAM);
1640 if (vol->v_db == NULL) {
1644 if (vol->v_flags & AFPVOL_RO)
1645 return AFPERR_VLOCK;
1647 memcpy(&id, ibuf, sizeof( id ));
1651 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1655 if (NULL == ( dir = dirlookup( vol, id )) ) {
1656 return( AFPERR_PARAM );
1660 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1664 return AFPERR_ACCESS;
1666 /* still try to delete the id */
1670 return AFPERR_PARAM;
1673 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1674 return AFPERR_BADTYPE;
1676 if (cnid_delete(vol->v_db, fileid)) {
1679 return AFPERR_VLOCK;
1682 return AFPERR_ACCESS;
1684 return AFPERR_PARAM;
1689 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1694 #endif /* CNID_DB */
1696 #define APPLETEMP ".AppleTempXXXXXX"
1698 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1701 int ibuflen, *rbuflen;
1703 struct stat srcst, destst;
1705 struct dir *dir, *sdir;
1706 char *spath, temp[17], *p;
1707 char *supath, *upath;
1712 struct adouble *adsp;
1713 struct adouble *addp;
1720 #endif /* CNID_DB */
1725 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1731 memcpy(&vid, ibuf, sizeof(vid));
1732 ibuf += sizeof(vid);
1734 if (NULL == ( vol = getvolbyvid( vid )) ) {
1735 return( AFPERR_PARAM);
1738 if (vol->v_flags & AFPVOL_RO)
1739 return AFPERR_VLOCK;
1741 /* source and destination dids */
1742 memcpy(&sid, ibuf, sizeof(sid));
1743 ibuf += sizeof(sid);
1744 memcpy(&did, ibuf, sizeof(did));
1745 ibuf += sizeof(did);
1748 if (NULL == (dir = dirlookup( vol, sid )) ) {
1749 return afp_errno; /* was AFPERR_PARAM */
1752 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1753 return get_afp_errno(AFPERR_NOOBJ);
1756 if ( path_isadir(path) ) {
1757 return( AFPERR_BADTYPE ); /* it's a dir */
1760 upath = path->u_name;
1761 switch (path->st_errno) {
1768 return AFPERR_ACCESS;
1770 return AFPERR_PARAM;
1772 memset(&ads, 0, sizeof(ads));
1774 if ((s_of = of_findname(path))) {
1775 /* reuse struct adouble so it won't break locks */
1778 memcpy(&srcst, &path->st, sizeof(struct stat));
1779 /* save some stuff */
1781 spath = obj->oldtmp;
1782 supath = obj->newtmp;
1783 strcpy(spath, path->m_name);
1784 strcpy(supath, upath); /* this is for the cnid changing */
1785 p = absupath( vol, sdir, upath);
1787 /* pathname too long */
1788 return AFPERR_PARAM ;
1791 /* look for the source cnid. if it doesn't exist, don't worry about
1794 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1795 slen = strlen(supath));
1796 #endif /* CNID_DB */
1798 if (NULL == ( dir = dirlookup( vol, did )) ) {
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 );
1810 /* FPExchangeFiles is the only call that can return the SameObj
1812 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1813 return AFPERR_SAMEOBJ;
1815 switch (path->st_errno) {
1822 return AFPERR_ACCESS;
1824 return AFPERR_PARAM;
1826 memset(&add, 0, sizeof(add));
1828 if ((d_of = of_findname( path))) {
1829 /* reuse struct adouble so it won't break locks */
1832 memcpy(&destst, &path->st, sizeof(struct stat));
1834 /* they are not on the same device and at least one is open
1836 crossdev = (srcst.st_dev != destst.st_dev);
1837 if ((d_of || s_of) && crossdev)
1840 upath = path->u_name;
1842 /* look for destination id. */
1843 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1844 dlen = strlen(upath));
1845 #endif /* CNID_DB */
1847 /* construct a temp name.
1848 * NOTE: the temp file will be in the dest file's directory. it
1849 * will also be inaccessible from AFP. */
1850 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1854 /* now, quickly rename the file. we error if we can't. */
1855 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1856 goto err_exchangefile;
1857 of_rename(vol, s_of, sdir, spath, curdir, temp);
1859 /* rename destination to source */
1860 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1861 goto err_src_to_tmp;
1862 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1864 /* rename temp to destination */
1865 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1866 goto err_dest_to_src;
1867 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1870 /* id's need switching. src -> dest and dest -> src.
1871 * we need to re-stat() if it was a cross device copy.
1874 cnid_delete(vol->v_db, sid);
1877 cnid_delete(vol->v_db, did);
1879 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1880 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1882 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1883 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1888 err = AFPERR_ACCESS;
1893 goto err_temp_to_dest;
1895 #endif /* CNID_DB */
1898 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1904 /* all this stuff is so that we can unwind a failed operation
1909 /* rename dest to temp */
1910 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1911 of_rename(vol, s_of, curdir, upath, curdir, temp);
1914 /* rename source back to dest */
1915 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1916 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1919 /* rename temp back to source */
1920 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1921 of_rename(vol, s_of, curdir, temp, sdir, spath);