2 * $Id: file.c,v 1.90 2003-04-20 06:13: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 */
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 ad_close( adp, ADFLAGS_DF );
634 goto createfile_done;
636 /* FIXME with hard create on an existing file, we already
637 * corrupted the data file.
639 netatalk_unlink( upath );
640 ad_close( adp, ADFLAGS_DF );
641 return AFPERR_ACCESS;
644 path = s_path->m_name;
645 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
646 memcpy(ad_entry( adp, ADEID_NAME ), path,
647 ad_getentrylen( adp, ADEID_NAME ));
648 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
649 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
655 if (vol->v_flags & AFPVOL_DROPBOX) {
656 retvalue = matchfile2dirperms(upath, vol, did);
658 #endif /* DROPKLUDGE */
660 setvoltime(obj, vol );
663 LOG(log_info, logtype_afpd, "end afp_createfile");
669 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
672 int ibuflen, *rbuflen;
678 u_int16_t vid, bitmap;
681 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
687 memcpy(&vid, ibuf, sizeof( vid ));
688 ibuf += sizeof( vid );
689 if (NULL == ( vol = getvolbyvid( vid )) ) {
690 return( AFPERR_PARAM );
693 if (vol->v_flags & AFPVOL_RO)
696 memcpy(&did, ibuf, sizeof( did ));
697 ibuf += sizeof( did );
698 if (NULL == ( dir = dirlookup( vol, did )) ) {
699 return afp_errno; /* was AFPERR_NOOBJ */
702 memcpy(&bitmap, ibuf, sizeof( bitmap ));
703 bitmap = ntohs( bitmap );
704 ibuf += sizeof( bitmap );
706 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
707 return get_afp_errno(AFPERR_PARAM);
710 if (path_isadir(s_path)) {
711 return( AFPERR_BADTYPE ); /* it's a directory */
714 if ((u_long)ibuf & 1 ) {
718 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
719 setvoltime(obj, vol );
723 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
730 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
733 extern struct path Cur_Path;
735 int setfilparams(struct vol *vol,
736 struct path *path, u_int16_t bitmap, char *buf )
738 struct adouble ad, *adp;
741 int bit = 0, isad = 1, err = AFP_OK;
743 u_char achar, *fdType, xyy[4];
744 u_int16_t ashort, bshort;
748 int change_mdate = 0;
749 int change_parent_mdate = 0;
755 LOG(log_info, logtype_afpd, "begin setfilparams:");
758 upath = path->u_name;
759 if ((of = of_findname(path))) {
762 memset(&ad, 0, sizeof(ad));
766 if (check_access(upath, OPENACC_WR ) < 0) {
767 return AFPERR_ACCESS;
770 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
771 O_RDWR|O_CREAT, 0666, adp) < 0) {
772 /* for some things, we don't need an adouble header */
773 if (bitmap & ~(1<<FILPBIT_MDATE)) {
774 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
777 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
778 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
779 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
780 ad_getentrylen( adp, ADEID_NAME ));
783 while ( bitmap != 0 ) {
784 while (( bitmap & 1 ) == 0 ) {
792 memcpy(&ashort, buf, sizeof( ashort ));
793 ad_getattr(adp, &bshort);
794 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
795 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
799 if ((ashort & htons(ATTRBIT_INVISIBLE)))
800 change_parent_mdate = 1;
801 ad_setattr(adp, bshort);
802 buf += sizeof( ashort );
807 memcpy(&aint, buf, sizeof(aint));
808 ad_setdate(adp, AD_DATE_CREATE, aint);
809 buf += sizeof( aint );
813 memcpy(&newdate, buf, sizeof( newdate ));
814 buf += sizeof( newdate );
819 memcpy(&aint, buf, sizeof(aint));
820 ad_setdate(adp, AD_DATE_BACKUP, aint);
821 buf += sizeof( aint );
827 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
829 ((em = getextmap( path->m_name )) &&
830 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
831 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
832 || ((em = getdefextmap()) &&
833 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
834 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
836 memcpy(buf, ufinderi, 8 );
839 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
843 /* Client needs to set the ProDOS file info for this file.
844 Use a defined string for TEXT to support crlf
845 translations and convert all else into pXYY per Inside
846 Appletalk. Always set the creator as "pdos". Changes
847 from original by Marsha Jackson. */
848 case FILPBIT_PDINFO :
849 if (afp_version < 30) { /* else it's UTF8 name */
852 /* Keep special case to support crlf translations */
853 if ((unsigned int) achar == 0x04) {
854 fdType = (u_char *)"TEXT";
857 xyy[0] = ( u_char ) 'p';
863 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
864 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
870 goto setfilparam_done;
878 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
879 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
883 ad_setdate(adp, AD_DATE_MODIFY, newdate);
884 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
889 ad_flush( adp, ADFLAGS_HF );
890 ad_close( adp, ADFLAGS_HF );
894 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
895 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
896 bitmap = 1<<FILPBIT_MDATE;
897 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
901 LOG(log_info, logtype_afpd, "end setfilparams:");
907 * renamefile and copyfile take the old and new unix pathnames
908 * and the new mac name.
910 * src the source path
911 * dst the dest filename in current dir
912 * newname the dest mac name
913 * adp adouble struct of src file, if open, or & zeroed one
916 int renamefile(src, dst, newname, noadouble, adp )
917 char *src, *dst, *newname;
921 char adsrc[ MAXPATHLEN + 1];
926 LOG(log_info, logtype_afpd, "begin renamefile:");
929 if ( unix_rename( src, dst ) < 0 ) {
932 return( AFPERR_NOOBJ );
935 return( AFPERR_ACCESS );
938 case EXDEV : /* Cross device move -- try copy */
939 /* NOTE: with open file it's an error because after the copy we will
940 * get two files, it's fixable for our process (eg reopen the new file, get the
941 * locks, and so on. But it doesn't solve the case with a second process
943 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
944 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
945 return AFPERR_OLOCK; /* little lie */
947 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
948 /* on error copyfile delete dest */
951 return deletefile(NULL, src, 0);
953 return( AFPERR_PARAM );
957 strcpy( adsrc, ad_path( src, 0 ));
959 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
964 if (errno == ENOENT) {
967 if (stat(adsrc, &st)) /* source has no ressource fork, */
970 /* We are here because :
971 * -there's no dest folder.
972 * -there's no .AppleDouble in the dest folder.
973 * if we use the struct adouble passed in parameter it will not
974 * create .AppleDouble if the file is already opened, so we
975 * use a diff one, it's not a pb,ie it's not the same file, yet.
977 memset(&ad, 0, sizeof(ad));
978 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
979 ad_close(&ad, ADFLAGS_HF);
980 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
985 else { /* it's something else, bail out */
989 /* try to undo the data fork rename,
990 * we know we are on the same device
993 unix_rename( dst, src );
994 /* return the first error */
1000 return AFPERR_ACCESS ;
1002 return AFPERR_VLOCK;
1004 return AFPERR_PARAM ;
1009 /* don't care if we can't open the newly renamed ressource fork
1011 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1012 len = strlen( newname );
1013 ad_setentrylen( adp, ADEID_NAME, len );
1014 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1015 ad_flush( adp, ADFLAGS_HF );
1016 ad_close( adp, ADFLAGS_HF );
1019 LOG(log_info, logtype_afpd, "end renamefile:");
1025 int copy_path_name(char *newname, char *ibuf)
1032 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1038 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1039 strncpy( newname, ibuf, plen );
1040 newname[ plen ] = '\0';
1041 if (strlen(newname) != plen) {
1042 /* there's \0 in newname, e.g. it's a pathname not
1050 memcpy(&hint, ibuf, sizeof(hint));
1051 ibuf += sizeof(hint);
1053 memcpy(&len16, ibuf, sizeof(len16));
1054 ibuf += sizeof(len16);
1055 plen = ntohs(len16);
1058 if (plen > AFPOBJ_TMPSIZ) {
1061 strncpy( newname, ibuf, plen );
1062 newname[ plen ] = '\0';
1063 if (strlen(newname) != plen) {
1072 /* -----------------------------------
1074 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1077 int ibuflen, *rbuflen;
1081 char *newname, *p, *upath;
1082 struct path *s_path;
1083 u_int32_t sdid, ddid;
1084 int err, retvalue = AFP_OK;
1085 u_int16_t svid, dvid;
1088 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1094 memcpy(&svid, ibuf, sizeof( svid ));
1095 ibuf += sizeof( svid );
1096 if (NULL == ( vol = getvolbyvid( svid )) ) {
1097 return( AFPERR_PARAM );
1100 memcpy(&sdid, ibuf, sizeof( sdid ));
1101 ibuf += sizeof( sdid );
1102 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1106 memcpy(&dvid, ibuf, sizeof( dvid ));
1107 ibuf += sizeof( dvid );
1108 memcpy(&ddid, ibuf, sizeof( ddid ));
1109 ibuf += sizeof( ddid );
1111 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1112 return get_afp_errno(AFPERR_PARAM);
1114 if ( path_isadir(s_path) ) {
1115 return( AFPERR_BADTYPE );
1118 /* don't allow copies when the file is open.
1119 * XXX: the spec only calls for read/deny write access.
1120 * however, copyfile doesn't have any of that info,
1121 * and locks need to stay coherent. as a result,
1122 * we just balk if the file is opened already. */
1124 newname = obj->newtmp;
1125 strcpy( newname, s_path->m_name );
1127 if (of_findname(s_path))
1128 return AFPERR_DENYCONF;
1130 p = ctoupath( vol, curdir, newname );
1132 return AFPERR_PARAM;
1136 /* FIXME svid != dvid && dvid's user can't read svid */
1138 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1139 return( AFPERR_PARAM );
1142 if (vol->v_flags & AFPVOL_RO)
1143 return AFPERR_VLOCK;
1145 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1149 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1150 return get_afp_errno(AFPERR_NOOBJ);
1152 if ( *s_path->m_name != '\0' ) {
1153 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1156 /* one of the handful of places that knows about the path type */
1157 if (copy_path_name(newname, ibuf) < 0) {
1158 return( AFPERR_PARAM );
1161 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1162 return( AFPERR_PARAM );
1164 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1170 if (vol->v_flags & AFPVOL_DROPBOX) {
1171 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1173 #endif /* DROPKLUDGE */
1175 setvoltime(obj, vol );
1178 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1185 static __inline__ int copy_all(const int dfd, const void *buf,
1191 LOG(log_info, logtype_afpd, "begin copy_all:");
1194 while (buflen > 0) {
1195 if ((cc = write(dfd, buf, buflen)) < 0) {
1202 return AFPERR_DFULL;
1204 return AFPERR_VLOCK;
1206 return AFPERR_PARAM;
1213 LOG(log_info, logtype_afpd, "end copy_all:");
1219 /* -------------------------- */
1220 static int copy_fd(int dfd, int sfd)
1226 #ifdef SENDFILE_FLAVOR_LINUX
1229 if (fstat(sfd, &st) == 0) {
1230 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1232 case EINVAL: /* there's no guarantee that all fs support sendfile */
1237 return AFPERR_DFULL;
1239 return AFPERR_VLOCK;
1241 return AFPERR_PARAM;
1248 #endif /* SENDFILE_FLAVOR_LINUX */
1251 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1258 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1264 /* ----------------------------------
1265 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1266 * because we are doing it elsewhere.
1268 int copyfile(src, dst, newname, noadouble )
1269 char *src, *dst, *newname;
1270 const int noadouble;
1272 struct adouble ads, add;
1273 int len, err = AFP_OK;
1277 LOG(log_info, logtype_afpd, "begin copyfile:");
1280 memset(&ads, 0, sizeof(ads));
1281 memset(&add, 0, sizeof(add));
1282 adflags = ADFLAGS_DF;
1284 adflags |= ADFLAGS_HF;
1287 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1290 return( AFPERR_NOOBJ );
1292 return( AFPERR_ACCESS );
1294 return( AFPERR_PARAM );
1297 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1298 ad_close( &ads, adflags );
1299 if (EEXIST != (err = errno)) {
1300 deletefile(NULL, dst, 0);
1304 return AFPERR_EXIST;
1306 return( AFPERR_NOOBJ );
1308 return( AFPERR_ACCESS );
1310 return AFPERR_VLOCK;
1312 return( AFPERR_PARAM );
1315 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1316 /* copy the data fork */
1317 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1321 len = strlen( newname );
1322 ad_setentrylen( &add, ADEID_NAME, len );
1323 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1326 ad_close( &ads, adflags );
1327 ad_flush( &add, adflags );
1328 if (ad_close( &add, adflags ) <0) {
1331 if (err != AFP_OK) {
1332 deletefile(NULL, dst, 0);
1335 return( AFPERR_NOOBJ );
1337 return( AFPERR_ACCESS );
1339 return( AFPERR_PARAM );
1344 LOG(log_info, logtype_afpd, "end copyfile:");
1351 /* -----------------------------------
1352 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1353 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1355 when deletefile is called we don't have lock on it, file is closed (for us)
1356 untrue if called by renamefile
1358 ad_open always try to open file RDWR first and ad_lock takes care of
1359 WRITE lock on read only file.
1361 int deletefile( vol, file, checkAttrib )
1367 int adflags, err = AFP_OK;
1370 LOG(log_info, logtype_afpd, "begin deletefile:");
1373 /* try to open both forks at once */
1374 adflags = ADFLAGS_DF|ADFLAGS_HF;
1376 memset(&ad, 0, sizeof(ad));
1377 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1380 if (adflags == ADFLAGS_DF)
1381 return AFPERR_NOOBJ;
1383 /* that failed. now try to open just the data fork */
1384 adflags = ADFLAGS_DF;
1388 return AFPERR_ACCESS;
1390 return AFPERR_VLOCK;
1392 return( AFPERR_PARAM );
1395 break; /* from the while */
1398 * Does kFPDeleteInhibitBit (bit 8) set?
1400 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1403 ad_getattr(&ad, &bshort);
1404 if ((bshort & htons(ATTRBIT_NODELETE))) {
1405 ad_close( &ad, adflags );
1406 return(AFPERR_OLOCK);
1410 if ((adflags & ADFLAGS_HF) ) {
1411 /* FIXME we have a pb here because we want to know if a file is open
1412 * there's a 'priority inversion' if you can't open the ressource fork RW
1413 * you can delete it if it's open because you can't get a write lock.
1415 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1418 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1420 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1421 ad_close( &ad, adflags );
1422 return( AFPERR_BUSY );
1426 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1429 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1430 !(err = netatalk_unlink( file )) ) {
1431 #ifdef CNID_DB /* get rid of entry */
1433 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1435 cnid_delete(vol->v_db, id);
1437 #endif /* CNID_DB */
1440 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1443 LOG(log_info, logtype_afpd, "end deletefile:");
1449 /* ------------------------------------ */
1451 /* return a file id */
1452 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1455 int ibuflen, *rbuflen;
1464 struct path *s_path;
1467 LOG(log_info, logtype_afpd, "begin afp_createid:");
1474 memcpy(&vid, ibuf, sizeof(vid));
1475 ibuf += sizeof(vid);
1477 if (NULL == ( vol = getvolbyvid( vid )) ) {
1478 return( AFPERR_PARAM);
1481 if (vol->v_db == NULL) {
1485 if (vol->v_flags & AFPVOL_RO)
1486 return AFPERR_VLOCK;
1488 memcpy(&did, ibuf, sizeof( did ));
1489 ibuf += sizeof(did);
1491 if (NULL == ( dir = dirlookup( vol, did )) ) {
1492 return afp_errno; /* was AFPERR_PARAM */
1495 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1496 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1499 if ( path_isadir(s_path) ) {
1500 return( AFPERR_BADTYPE );
1503 upath = s_path->u_name;
1504 switch (s_path->st_errno) {
1506 break; /* success */
1509 return AFPERR_ACCESS;
1511 return AFPERR_NOOBJ;
1513 return AFPERR_PARAM;
1516 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1517 memcpy(rbuf, &id, sizeof(id));
1518 *rbuflen = sizeof(id);
1519 return AFPERR_EXISTID;
1522 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1523 memcpy(rbuf, &id, sizeof(id));
1524 *rbuflen = sizeof(id);
1529 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1534 /* ------------------------------
1535 resolve a file id */
1536 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1539 int ibuflen, *rbuflen;
1547 u_int16_t vid, bitmap;
1549 static char buffer[12 + MAXPATHLEN + 1];
1550 int len = 12 + MAXPATHLEN + 1;
1553 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1559 memcpy(&vid, ibuf, sizeof(vid));
1560 ibuf += sizeof(vid);
1562 if (NULL == ( vol = getvolbyvid( vid )) ) {
1563 return( AFPERR_PARAM);
1566 if (vol->v_db == NULL) {
1570 memcpy(&id, ibuf, sizeof( id ));
1573 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1574 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1577 if (NULL == ( dir = dirlookup( vol, id )) ) {
1578 return AFPERR_NOID; /* idem AFPERR_PARAM */
1580 path.u_name = upath;
1581 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1585 return AFPERR_ACCESS;
1589 return AFPERR_PARAM;
1592 /* directories are bad */
1593 if (S_ISDIR(path.st.st_mode))
1594 return AFPERR_BADTYPE;
1596 memcpy(&bitmap, ibuf, sizeof(bitmap));
1597 bitmap = ntohs( bitmap );
1598 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1601 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1602 rbuf + sizeof(bitmap), &buflen))) {
1605 *rbuflen = buflen + sizeof(bitmap);
1606 memcpy(rbuf, ibuf, sizeof(bitmap));
1609 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1615 /* ------------------------------ */
1616 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1619 int ibuflen, *rbuflen;
1629 static char buffer[12 + MAXPATHLEN + 1];
1630 int len = 12 + MAXPATHLEN + 1;
1633 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1639 memcpy(&vid, ibuf, sizeof(vid));
1640 ibuf += sizeof(vid);
1642 if (NULL == ( vol = getvolbyvid( vid )) ) {
1643 return( AFPERR_PARAM);
1646 if (vol->v_db == NULL) {
1650 if (vol->v_flags & AFPVOL_RO)
1651 return AFPERR_VLOCK;
1653 memcpy(&id, ibuf, sizeof( id ));
1657 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1661 if (NULL == ( dir = dirlookup( vol, id )) ) {
1662 return( AFPERR_PARAM );
1666 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1670 return AFPERR_ACCESS;
1672 /* still try to delete the id */
1676 return AFPERR_PARAM;
1679 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1680 return AFPERR_BADTYPE;
1682 if (cnid_delete(vol->v_db, fileid)) {
1685 return AFPERR_VLOCK;
1688 return AFPERR_ACCESS;
1690 return AFPERR_PARAM;
1695 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1700 #endif /* CNID_DB */
1702 #define APPLETEMP ".AppleTempXXXXXX"
1704 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1707 int ibuflen, *rbuflen;
1709 struct stat srcst, destst;
1711 struct dir *dir, *sdir;
1712 char *spath, temp[17], *p;
1713 char *supath, *upath;
1718 struct adouble *adsp;
1719 struct adouble *addp;
1726 #endif /* CNID_DB */
1731 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1737 memcpy(&vid, ibuf, sizeof(vid));
1738 ibuf += sizeof(vid);
1740 if (NULL == ( vol = getvolbyvid( vid )) ) {
1741 return( AFPERR_PARAM);
1744 if (vol->v_flags & AFPVOL_RO)
1745 return AFPERR_VLOCK;
1747 /* source and destination dids */
1748 memcpy(&sid, ibuf, sizeof(sid));
1749 ibuf += sizeof(sid);
1750 memcpy(&did, ibuf, sizeof(did));
1751 ibuf += sizeof(did);
1754 if (NULL == (dir = dirlookup( vol, sid )) ) {
1755 return afp_errno; /* was AFPERR_PARAM */
1758 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1759 return get_afp_errno(AFPERR_NOOBJ);
1762 if ( path_isadir(path) ) {
1763 return( AFPERR_BADTYPE ); /* it's a dir */
1766 upath = path->u_name;
1767 switch (path->st_errno) {
1774 return AFPERR_ACCESS;
1776 return AFPERR_PARAM;
1778 memset(&ads, 0, sizeof(ads));
1780 if ((s_of = of_findname(path))) {
1781 /* reuse struct adouble so it won't break locks */
1784 memcpy(&srcst, &path->st, sizeof(struct stat));
1785 /* save some stuff */
1787 spath = obj->oldtmp;
1788 supath = obj->newtmp;
1789 strcpy(spath, path->m_name);
1790 strcpy(supath, upath); /* this is for the cnid changing */
1791 p = absupath( vol, sdir, upath);
1793 /* pathname too long */
1794 return AFPERR_PARAM ;
1797 /* look for the source cnid. if it doesn't exist, don't worry about
1800 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1801 slen = strlen(supath));
1802 #endif /* CNID_DB */
1804 if (NULL == ( dir = dirlookup( vol, did )) ) {
1805 return afp_errno; /* was AFPERR_PARAM */
1808 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1809 return get_afp_errno(AFPERR_NOOBJ);
1812 if ( path_isadir(path) ) {
1813 return( AFPERR_BADTYPE );
1816 /* FPExchangeFiles is the only call that can return the SameObj
1818 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1819 return AFPERR_SAMEOBJ;
1821 switch (path->st_errno) {
1828 return AFPERR_ACCESS;
1830 return AFPERR_PARAM;
1832 memset(&add, 0, sizeof(add));
1834 if ((d_of = of_findname( path))) {
1835 /* reuse struct adouble so it won't break locks */
1838 memcpy(&destst, &path->st, sizeof(struct stat));
1840 /* they are not on the same device and at least one is open
1842 crossdev = (srcst.st_dev != destst.st_dev);
1843 if ((d_of || s_of) && crossdev)
1846 upath = path->u_name;
1848 /* look for destination id. */
1849 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1850 dlen = strlen(upath));
1851 #endif /* CNID_DB */
1853 /* construct a temp name.
1854 * NOTE: the temp file will be in the dest file's directory. it
1855 * will also be inaccessible from AFP. */
1856 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1860 /* now, quickly rename the file. we error if we can't. */
1861 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1862 goto err_exchangefile;
1863 of_rename(vol, s_of, sdir, spath, curdir, temp);
1865 /* rename destination to source */
1866 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1867 goto err_src_to_tmp;
1868 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1870 /* rename temp to destination */
1871 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1872 goto err_dest_to_src;
1873 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1876 /* id's need switching. src -> dest and dest -> src.
1877 * we need to re-stat() if it was a cross device copy.
1880 cnid_delete(vol->v_db, sid);
1883 cnid_delete(vol->v_db, did);
1885 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1886 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1888 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1889 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1894 err = AFPERR_ACCESS;
1899 goto err_temp_to_dest;
1901 #endif /* CNID_DB */
1904 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1910 /* all this stuff is so that we can unwind a failed operation
1915 /* rename dest to temp */
1916 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1917 of_rename(vol, s_of, curdir, upath, curdir, temp);
1920 /* rename source back to dest */
1921 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1922 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1925 /* rename temp back to source */
1926 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1927 of_rename(vol, s_of, curdir, temp, sdir, spath);