2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
8 #endif /* HAVE_CONFIG_H */
16 #include <sys/param.h>
18 #include <atalk/adouble.h>
19 #include <atalk/vfs.h>
20 #include <atalk/logger.h>
21 #include <atalk/afp.h>
22 #include <atalk/util.h>
23 #include <atalk/cnid.h>
24 #include <atalk/unix.h>
25 #include <atalk/globals.h>
26 #include <atalk/fce_api.h>
28 #include "directory.h"
37 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
38 * field bytes subfield bytes
41 * ioFlFndrInfo 16 -> type 4 type field
42 * creator 4 creator field
43 * flags 2 finder flags:
45 * location 4 location in window
46 * folder 2 window that contains file
48 * ioFlXFndrInfo 16 -> iconID 2 icon id
50 * script 1 script system
52 * commentID 2 comment id
53 * putawayID 4 home directory id
56 const u_char ufinderi[ADEDLEN_FINDERI] = {
57 0, 0, 0, 0, 0, 0, 0, 0,
58 1, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0
63 static const u_char old_ufinderi[] = {
64 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
67 /* ----------------------
69 static int default_type(void *finder)
71 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
76 /* FIXME path : unix or mac name ? (for now it's unix name ) */
77 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink)
80 void *ad_finder = NULL;
84 ad_finder = ad_entry(adp, ADEID_FINDERI);
87 memcpy(data, ad_finder, ADEDLEN_FINDERI);
89 if (default_type(ad_finder))
93 memcpy(data, ufinderi, ADEDLEN_FINDERI);
95 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
98 ashort = htons(FINDERINFO_INVISIBLE);
99 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
105 memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2);
106 linkflag |= htons(FINDERINFO_ISALIAS);
107 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2);
108 memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4);
109 memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4);
113 /** Only enter if no appledouble information and no finder information found. */
114 if (chk_ext && (em = getextmap( upath ))) {
115 memcpy(data, em->em_type, sizeof( em->em_type ));
116 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
121 /* ---------------------
123 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, uint32_t utf8)
128 aint = strlen( name );
132 if (utf8_encoding()) {
133 /* but name is an utf8 mac name */
136 /* global static variable... */
138 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
147 if (aint > MACFILELEN)
154 if (aint > UTF8FILELEN_EARLY) /* FIXME safeguard, anyway if no ascii char it's game over*/
155 aint = UTF8FILELEN_EARLY;
157 utf8 = vol->v_kTextEncoding;
158 memcpy(data, &utf8, sizeof(utf8));
159 data += sizeof(utf8);
162 memcpy(data, &temp, sizeof(temp));
163 data += sizeof(temp);
166 memcpy( data, src, aint );
176 * FIXME: PDINFO is UTF8 and doesn't need adp
178 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
179 (1 << FILPBIT_CDATE) |\
180 (1 << FILPBIT_MDATE) |\
181 (1 << FILPBIT_BDATE) |\
182 (1 << FILPBIT_FINFO) |\
183 (1 << FILPBIT_RFLEN) |\
184 (1 << FILPBIT_EXTRFLEN) |\
185 (1 << FILPBIT_PDINFO) |\
186 (1 << FILPBIT_FNUM) |\
187 (1 << FILPBIT_UNIXPR)))
190 * @brief Get CNID for did/upath args both from database and adouble file
192 * 1. Get the objects CNID as stored in its adouble file
193 * 2. Get the objects CNID from the database
194 * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory
195 * 4. In case 2 and 3 differ, store 3 in the adouble file
197 * @param vol (rw) volume
198 * @param adp (rw) adouble struct of object upath, might be NULL
199 * @param st (r) stat of upath, must NOT be NULL
200 * @param did (r) parent CNID of upath
201 * @param upath (r) name of object
202 * @param len (r) strlen of upath
204 uint32_t get_id(struct vol *vol,
206 const struct stat *st,
211 static int first = 1; /* mark if this func is called the first time */
213 uint32_t dbcnid = CNID_INVALID;
216 if (vol->v_cdb != NULL) {
217 /* prime aint with what we think is the cnid, set did to zero for
218 catching moved files */
219 adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */
221 dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */
222 /* Throw errors if cnid_add fails. */
223 if (dbcnid == CNID_INVALID) {
225 case CNID_ERR_CLOSE: /* the db is closed */
228 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
229 afp_errno = AFPERR_PARAM;
232 afp_errno = AFPERR_PARAM;
235 /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */
236 /* we have to do it here for "dbd" because it uses "lazy opening" */
237 /* In order to not end in a loop somehow with goto restart below */
239 if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */
240 cnid_close(vol->v_cdb);
241 free(vol->v_cnidscheme);
242 vol->v_cnidscheme = strdup("tdb");
244 int flags = CNID_FLAG_MEMORY;
245 if ((vol->v_flags & AFPVOL_NODEV)) {
246 flags |= CNID_FLAG_NODEV;
248 LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
250 vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL);
252 /* deactivate cnid caching/storing in AppleDouble files and set ro mode*/
253 vol->v_flags &= ~AFPVOL_CACHE;
254 vol->v_flags |= AFPVOL_RO;
256 /* kill ourself with SIGUSR2 aka msg pending */
257 setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead."
258 "Check server messages for details. Switching to read-only mode.");
259 kill(getpid(), SIGUSR2);
261 goto restart; /* not try again with the temp CNID db */
264 setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!"
265 "Check server messages for details, can't recover from this state!");
269 afp_errno = AFPERR_MISC;
273 else if (adp && (adcnid != dbcnid)) { /* 4 */
274 /* Update the ressource fork. For a folder adp is always null */
275 LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)",
276 getcwdpath(), upath, htonl(adcnid), htonl(dbcnid));
277 if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
288 /* -------------------------- */
289 int getmetadata(struct vol *vol,
291 struct path *path, struct dir *dir,
292 char *buf, size_t *buflen, struct adouble *adp)
294 char *data, *l_nameoff = NULL, *upath;
295 char *utf_nameoff = NULL;
300 u_char achar, fdType[4];
305 LOG(log_debug, logtype_afpd, "getmetadata(\"%s\")", path->u_name);
307 upath = path->u_name;
311 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
312 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
313 || (bitmap & (1 << FILPBIT_FNUM))) {
316 struct dir *cachedfile;
317 int len = strlen(upath);
318 if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != NULL)
319 id = cachedfile->d_did;
321 id = get_id(vol, adp, st, dir->d_did, upath, len);
323 /* Add it to the cache */
324 LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u",
325 ntohl(dir->d_did), upath, ntohl(id));
327 /* Get macname from unixname first */
328 if (path->m_name == NULL) {
329 if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) {
330 LOG(log_error, logtype_afpd, "getmetadata: utompath error");
336 if (((fullpath = bstrcpy(dir->d_fullpath)) == NULL)
337 || (bconchar(fullpath, '/') != BSTR_OK)
338 || (bcatcstr(fullpath, upath)) != BSTR_OK) {
339 LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno));
343 if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, fullpath, st)) == NULL) {
344 LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
348 if ((dircache_add(vol, cachedfile)) != 0) {
349 LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
357 if (id == CNID_INVALID)
361 path->m_name = utompath(vol, upath, id, utf8_encoding());
364 while ( bitmap != 0 ) {
365 while (( bitmap & 1 ) == 0 ) {
373 ad_getattr(adp, &ashort);
374 } else if (vol_inv_dots(vol) && *upath == '.') {
375 ashort = htons(ATTRBIT_INVISIBLE);
379 /* FIXME do we want a visual clue if the file is read only
382 accessmode(vol, ".", &ma, dir , NULL);
383 if ((ma.ma_user & AR_UWRITE)) {
384 accessmode(vol, upath, &ma, dir , st);
385 if (!(ma.ma_user & AR_UWRITE)) {
386 ashort |= htons(ATTRBIT_NOWRITE);
390 memcpy(data, &ashort, sizeof( ashort ));
391 data += sizeof( ashort );
392 LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x",
393 path->u_name, ntohs(ashort));
397 memcpy(data, &dir->d_did, sizeof( uint32_t ));
398 data += sizeof( uint32_t );
399 LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u",
400 path->u_name, ntohl(dir->d_did));
404 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
405 aint = AD_DATE_FROM_UNIX(st->st_mtime);
406 memcpy(data, &aint, sizeof( aint ));
407 data += sizeof( aint );
411 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
412 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
413 aint = AD_DATE_FROM_UNIX(st->st_mtime);
416 aint = AD_DATE_FROM_UNIX(st->st_mtime);
418 memcpy(data, &aint, sizeof( int ));
419 data += sizeof( int );
423 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
424 aint = AD_DATE_START;
425 memcpy(data, &aint, sizeof( int ));
426 data += sizeof( int );
430 get_finderinfo(vol, upath, adp, (char *)data,S_ISLNK(st->st_mode));
431 data += ADEDLEN_FINDERI;
436 data += sizeof( uint16_t );
440 memset(data, 0, sizeof(uint16_t));
441 data += sizeof( uint16_t );
445 memcpy(data, &id, sizeof( id ));
446 data += sizeof( id );
447 LOG(log_debug, logtype_afpd, "metadata('%s'): CNID: %u",
448 path->u_name, ntohl(id));
452 if (st->st_size > 0xffffffff)
455 aint = htonl( st->st_size );
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
462 if (adp->ad_rlen > 0xffffffff)
465 aint = htonl( adp->ad_rlen);
469 memcpy(data, &aint, sizeof( aint ));
470 data += sizeof( aint );
473 /* Current client needs ProDOS info block for this file.
474 Use simple heuristic and let the Mac "type" string tell
475 us what the PD file code should be. Everything gets a
476 subtype of 0x0000 unless the original value was hashed
477 to "pXYZ" when we created it. See IA, Ver 2.
478 <shirsch@adelphia.net> */
479 case FILPBIT_PDINFO :
480 if (afp_version >= 30) { /* UTF8 name */
481 utf8 = kTextEncodingUTF8;
483 data += sizeof( uint16_t );
485 memcpy(data, &aint, sizeof( aint ));
486 data += sizeof( aint );
490 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
492 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
496 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
500 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
504 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
508 else if ( fdType[0] == 'p' ) {
510 ashort = (fdType[2] * 256) + fdType[3];
524 memcpy(data, &ashort, sizeof( ashort ));
525 data += sizeof( ashort );
526 memset(data, 0, sizeof( ashort ));
527 data += sizeof( ashort );
530 case FILPBIT_EXTDFLEN:
531 aint = htonl(st->st_size >> 32);
532 memcpy(data, &aint, sizeof( aint ));
533 data += sizeof( aint );
534 aint = htonl(st->st_size);
535 memcpy(data, &aint, sizeof( aint ));
536 data += sizeof( aint );
538 case FILPBIT_EXTRFLEN:
541 aint = htonl(adp->ad_rlen >> 32);
542 memcpy(data, &aint, sizeof( aint ));
543 data += sizeof( aint );
545 aint = htonl(adp->ad_rlen);
546 memcpy(data, &aint, sizeof( aint ));
547 data += sizeof( aint );
549 case FILPBIT_UNIXPR :
550 /* accessmode may change st_mode with ACLs */
551 accessmode(vol, upath, &ma, dir , st);
553 aint = htonl(st->st_uid);
554 memcpy( data, &aint, sizeof( aint ));
555 data += sizeof( aint );
556 aint = htonl(st->st_gid);
557 memcpy( data, &aint, sizeof( aint ));
558 data += sizeof( aint );
561 type == slnk indicates an OSX style symlink,
562 we have to add S_IFLNK to the mode, otherwise
563 10.3 clients freak out. */
567 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
568 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
574 memcpy( data, &aint, sizeof( aint ));
575 data += sizeof( aint );
577 *data++ = ma.ma_user;
578 *data++ = ma.ma_world;
579 *data++ = ma.ma_group;
580 *data++ = ma.ma_owner;
584 return( AFPERR_BITMAP );
590 ashort = htons( data - buf );
591 memcpy(l_nameoff, &ashort, sizeof( ashort ));
592 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
595 ashort = htons( data - buf );
596 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
597 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
599 *buflen = data - buf;
603 /* ----------------------- */
604 int getfilparams(struct vol *vol,
606 struct path *path, struct dir *dir,
607 char *buf, size_t *buflen )
609 struct adouble ad, *adp;
613 LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name);
615 opened = PARAM_NEED_ADP(bitmap);
620 int flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0;
622 adp = of_ad(vol, path, &ad);
623 upath = path->u_name;
625 if ( ad_metadata( upath, flags, adp) < 0 ) {
628 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
629 upath, strerror(errno));
630 return AFPERR_ACCESS;
632 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
641 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
642 ad_close(adp, ADFLAGS_HF);
647 /* ----------------------------- */
648 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
653 struct ofork *of = NULL;
655 int creatf, did, openf, retvalue = AFP_OK;
661 creatf = (unsigned char) *ibuf++;
663 memcpy(&vid, ibuf, sizeof( vid ));
664 ibuf += sizeof( vid );
666 if (NULL == ( vol = getvolbyvid( vid )) )
667 return( AFPERR_PARAM );
669 if (vol->v_flags & AFPVOL_RO)
672 memcpy(&did, ibuf, sizeof( did));
673 ibuf += sizeof( did );
675 if (NULL == ( dir = dirlookup( vol, did )) )
678 if (NULL == ( s_path = cname( vol, dir, &ibuf )) )
679 return get_afp_errno(AFPERR_PARAM);
681 if ( *s_path->m_name == '\0' )
682 return( AFPERR_BADTYPE );
684 upath = s_path->u_name;
687 /* if upath is deleted we already in trouble anyway */
688 if ((of = of_findname(s_path))) {
696 openf = ADFLAGS_RDWR | ADFLAGS_CREATE | ADFLAGS_TRUNC;
698 /* on a soft create, if the file is open then ad_open won't fail
699 because open syscall is not called */
700 openf = ADFLAGS_RDWR | ADFLAGS_CREATE | ADFLAGS_EXCL;
702 if (ad_open(&ad, upath, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | openf, 0666) < 0) {
706 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
707 return ( AFPERR_NOOBJ );
709 return( AFPERR_EXIST );
711 return( AFPERR_ACCESS );
714 return( AFPERR_DFULL );
716 return( AFPERR_PARAM );
719 if ( ad_meta_fileno( &ad ) == -1 ) { /* Hard META / HF */
720 /* FIXME with hard create on an existing file, we already
721 * corrupted the data file.
723 netatalk_unlink( upath );
724 ad_close( &ad, ADFLAGS_DF );
725 return AFPERR_ACCESS;
728 path = s_path->m_name;
729 ad_setname(&ad, path);
732 if (lstat(upath, &st) != 0) {
733 LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): stat: %s",
734 upath, strerror(errno));
735 ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF);
739 (void)get_id(vol, &ad, &st, dir->d_did, upath, strlen(upath));
742 ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
743 fce_register_new_file(s_path);
748 setvoltime(obj, vol );
753 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
759 uint16_t vid, bitmap;
764 memcpy(&vid, ibuf, sizeof( vid ));
765 ibuf += sizeof( vid );
766 if (NULL == ( vol = getvolbyvid( vid )) ) {
767 return( AFPERR_PARAM );
770 if (vol->v_flags & AFPVOL_RO)
773 memcpy(&did, ibuf, sizeof( did ));
774 ibuf += sizeof( did );
775 if (NULL == ( dir = dirlookup( vol, did )) ) {
776 return afp_errno; /* was AFPERR_NOOBJ */
779 memcpy(&bitmap, ibuf, sizeof( bitmap ));
780 bitmap = ntohs( bitmap );
781 ibuf += sizeof( bitmap );
783 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
784 return get_afp_errno(AFPERR_PARAM);
787 if (path_isadir(s_path)) {
788 return( AFPERR_BADTYPE ); /* it's a directory */
791 if ( s_path->st_errno != 0 ) {
792 return( AFPERR_NOOBJ );
795 if ((u_long)ibuf & 1 ) {
799 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
800 setvoltime(obj, vol );
807 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
810 extern struct path Cur_Path;
812 int setfilparams(struct vol *vol,
813 struct path *path, uint16_t f_bitmap, char *buf )
815 struct adouble ad, *adp;
817 int bit, isad = 1, err = AFP_OK;
819 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
820 uint16_t ashort, bshort, oshort;
823 uint16_t upriv_bit = 0;
827 int change_mdate = 0;
828 int change_parent_mdate = 0;
833 uint16_t bitmap = f_bitmap;
834 uint32_t cdate,bdate;
835 u_char finder_buf[32];
838 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
841 adp = of_ad(vol, path, &ad);
842 upath = path->u_name;
844 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
845 return AFPERR_ACCESS;
848 /* with unix priv maybe we have to change adouble file priv first */
850 while ( bitmap != 0 ) {
851 while (( bitmap & 1 ) == 0 ) {
858 memcpy(&ashort, buf, sizeof( ashort ));
859 buf += sizeof( ashort );
863 memcpy(&cdate, buf, sizeof(cdate));
864 buf += sizeof( cdate );
867 memcpy(&newdate, buf, sizeof( newdate ));
868 buf += sizeof( newdate );
872 memcpy(&bdate, buf, sizeof( bdate));
873 buf += sizeof( bdate );
877 memcpy(finder_buf, buf, 32 );
878 if (memcmp(buf,"slnkrhap",8)==0 && !S_ISLNK(path->st.st_mode)){
883 char buf[PATH_MAX+1];
884 if ((fp=open(path->u_name,O_RDONLY))>=0){
885 if ((len=read(fp,buf,PATH_MAX+1))){
886 if (unlink(path->u_name)==0){
888 erc = symlink(buf, path->u_name);
897 goto setfilparam_done;
902 case FILPBIT_UNIXPR :
903 if (!vol_unix_priv(vol)) {
904 /* this volume doesn't use unix priv */
910 change_parent_mdate = 1;
912 memcpy( &aint, buf, sizeof( aint ));
913 f_uid = ntohl (aint);
914 buf += sizeof( aint );
915 memcpy( &aint, buf, sizeof( aint ));
916 f_gid = ntohl (aint);
917 buf += sizeof( aint );
918 setfilowner(vol, f_uid, f_gid, path);
920 memcpy( &upriv, buf, sizeof( upriv ));
921 buf += sizeof( upriv );
922 upriv = ntohl (upriv);
923 if ((upriv & S_IWUSR)) {
924 setfilunixmode(vol, path, upriv);
931 case FILPBIT_PDINFO :
932 if (afp_version < 30) { /* else it's UTF8 name */
935 /* Keep special case to support crlf translations */
936 if ((unsigned int) achar == 0x04) {
937 fdType = (u_char *)"TEXT";
940 xyy[0] = ( u_char ) 'p';
951 /* break while loop */
960 /* second try with adouble open
962 if (ad_open(adp, upath, ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) < 0) {
963 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
965 * For some things, we don't need an adouble header:
966 * - change of modification date
967 * - UNIX privs (Bug-ID #2863424)
969 if (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR)) {
970 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
971 return AFPERR_ACCESS;
973 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
975 } else if ((ad_get_MD_flags( adp ) & O_CREAT) ) {
976 ad_setname(adp, path->m_name);
981 while ( bitmap != 0 ) {
982 while (( bitmap & 1 ) == 0 ) {
989 ad_getattr(adp, &bshort);
991 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
992 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
996 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
997 change_parent_mdate = 1;
998 ad_setattr(adp, bshort);
1000 case FILPBIT_CDATE :
1001 ad_setdate(adp, AD_DATE_CREATE, cdate);
1003 case FILPBIT_MDATE :
1005 case FILPBIT_BDATE :
1006 ad_setdate(adp, AD_DATE_BACKUP, bdate);
1008 case FILPBIT_FINFO :
1009 if (default_type( ad_entry( adp, ADEID_FINDERI ))
1011 ((em = getextmap( path->m_name )) &&
1012 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
1013 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
1014 || ((em = getdefextmap()) &&
1015 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
1016 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
1018 memcpy(finder_buf, ufinderi, 8 );
1020 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
1022 case FILPBIT_UNIXPR :
1024 setfilunixmode(vol, path, upriv);
1027 case FILPBIT_PDINFO :
1028 if (afp_version < 30) { /* else it's UTF8 name */
1029 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
1030 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
1035 err = AFPERR_BITMAP;
1036 goto setfilparam_done;
1043 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
1044 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1048 ad_setdate(adp, AD_DATE_MODIFY, newdate);
1049 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
1055 ad_close(adp, ADFLAGS_HF);
1058 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1059 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1060 bitmap = 1<<FILPBIT_MDATE;
1061 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1065 LOG(log_debug9, logtype_afpd, "end setfilparams:");
1071 * renamefile and copyfile take the old and new unix pathnames
1072 * and the new mac name.
1074 * sdir_fd source dir fd to which src path is relative (for openat et al semantics)
1075 * passing -1 means this is not used, src path is a full path
1076 * src the source path
1077 * dst the dest filename in current dir
1078 * newname the dest mac name
1079 * adp adouble struct of src file, if open, or & zeroed one
1082 int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp)
1086 LOG(log_debug, logtype_afpd,
1087 "renamefile: src[%d, \"%s\"] -> dst[\"%s\"]", sdir_fd, src, dst);
1089 if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) {
1092 return( AFPERR_NOOBJ );
1095 return( AFPERR_ACCESS );
1097 return AFPERR_VLOCK;
1098 case EXDEV : /* Cross device move -- try copy */
1099 /* NOTE: with open file it's an error because after the copy we will
1100 * get two files, it's fixable for our process (eg reopen the new file, get the
1101 * locks, and so on. But it doesn't solve the case with a second process
1103 if (adp->ad_open_forks) {
1104 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1105 return AFPERR_OLOCK; /* little lie */
1107 if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) {
1108 /* on error copyfile delete dest */
1111 return deletefile(vol, sdir_fd, src, 0);
1113 return( AFPERR_PARAM );
1117 if (vol->vfs->vfs_renamefile(vol, sdir_fd, src, dst) < 0 ) {
1121 /* try to undo the data fork rename,
1122 * we know we are on the same device
1125 unix_rename(-1, dst, sdir_fd, src );
1126 /* return the first error */
1129 return AFPERR_NOOBJ;
1132 return AFPERR_ACCESS ;
1134 return AFPERR_VLOCK;
1136 return AFPERR_PARAM ;
1141 /* don't care if we can't open the newly renamed ressource fork */
1142 if (ad_open(adp, dst, ADFLAGS_HF | ADFLAGS_RDWR) == 0) {
1143 ad_setname(adp, newname);
1145 ad_close( adp, ADFLAGS_HF );
1152 convert a Mac long name to an utf8 name,
1154 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1158 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1164 /* ---------------- */
1165 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1172 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1178 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1179 if (afp_version >= 30) {
1180 /* convert it to UTF8
1182 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1186 strncpy( newname, ibuf, plen );
1187 newname[ plen ] = '\0';
1189 if (strlen(newname) != plen) {
1190 /* there's \0 in newname, e.g. it's a pathname not
1198 memcpy(&hint, ibuf, sizeof(hint));
1199 ibuf += sizeof(hint);
1201 memcpy(&len16, ibuf, sizeof(len16));
1202 ibuf += sizeof(len16);
1203 plen = ntohs(len16);
1206 if (plen > AFPOBJ_TMPSIZ) {
1209 strncpy( newname, ibuf, plen );
1210 newname[ plen ] = '\0';
1211 if (strlen(newname) != plen) {
1220 /* -----------------------------------
1222 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1224 struct vol *s_vol, *d_vol;
1226 char *newname, *p, *upath;
1227 struct path *s_path;
1228 uint32_t sdid, ddid;
1229 int err, retvalue = AFP_OK;
1230 uint16_t svid, dvid;
1232 struct adouble ad, *adp;
1238 memcpy(&svid, ibuf, sizeof( svid ));
1239 ibuf += sizeof( svid );
1240 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1241 return( AFPERR_PARAM );
1244 memcpy(&sdid, ibuf, sizeof( sdid ));
1245 ibuf += sizeof( sdid );
1246 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1250 memcpy(&dvid, ibuf, sizeof( dvid ));
1251 ibuf += sizeof( dvid );
1252 memcpy(&ddid, ibuf, sizeof( ddid ));
1253 ibuf += sizeof( ddid );
1255 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1256 return get_afp_errno(AFPERR_PARAM);
1258 if ( path_isadir(s_path) ) {
1259 return( AFPERR_BADTYPE );
1262 /* don't allow copies when the file is open.
1263 * XXX: the spec only calls for read/deny write access.
1264 * however, copyfile doesn't have any of that info,
1265 * and locks need to stay coherent. as a result,
1266 * we just balk if the file is opened already. */
1268 adp = of_ad(s_vol, s_path, &ad);
1270 if (ad_open(adp, s_path->u_name, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
1271 return AFPERR_DENYCONF;
1273 denyreadset = (ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1274 ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1277 retvalue = AFPERR_DENYCONF;
1281 newname = obj->newtmp;
1282 strcpy( newname, s_path->m_name );
1284 p = ctoupath( s_vol, curdir, newname );
1286 retvalue = AFPERR_PARAM;
1290 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1291 retvalue = AFPERR_PARAM;
1295 if (d_vol->v_flags & AFPVOL_RO) {
1296 retvalue = AFPERR_VLOCK;
1300 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1301 retvalue = afp_errno;
1305 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1306 retvalue = get_afp_errno(AFPERR_NOOBJ);
1310 if ( *s_path->m_name != '\0' ) {
1311 retvalue =path_error(s_path, AFPERR_NOOBJ);
1315 /* one of the handful of places that knows about the path type */
1316 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1317 retvalue = AFPERR_PARAM;
1320 /* newname is always only a filename so curdir *is* its
1323 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1324 retvalue =AFPERR_PARAM;
1328 if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) {
1334 setvoltime(obj, d_vol );
1337 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1341 /* ----------------------- */
1342 static int copy_all(const int dfd, const void *buf,
1348 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1351 while (buflen > 0) {
1352 if ((cc = write(dfd, buf, buflen)) < 0) {
1364 LOG(log_debug9, logtype_afpd, "end copy_all:");
1370 /* --------------------------
1371 * copy only the fork data stream
1373 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1381 if (eid == ADEID_DFORK) {
1382 sfd = ad_data_fileno(ads);
1383 dfd = ad_data_fileno(add);
1386 sfd = ad_reso_fileno(ads);
1387 dfd = ad_reso_fileno(add);
1390 if (add->ad_version == AD_VERSION2)
1391 soff = doff = ad_getentryoff(ads, eid);
1393 if (eid == ADEID_DFORK)
1394 soff = doff = ad_getentryoff(ads, eid);
1399 soff = doff = ADEDOFF_RFORK_OSX;
1404 if ((off_t)-1 == lseek(sfd, soff, SEEK_SET))
1407 if ((off_t)-1 == lseek(dfd, doff, SEEK_SET))
1410 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1411 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1415 #define BUF 128*1024*1024
1417 if (fstat(sfd, &st) == 0) {
1420 if ( offset >= st.st_size) {
1423 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1424 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1427 case EINVAL: /* there's no guarantee that all fs support sendfile */
1436 lseek(sfd, offset, SEEK_SET);
1440 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1447 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1454 /* ----------------------------------
1455 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1456 * because we are doing it elsewhere.
1457 * currently if newname is NULL then adp is NULL.
1459 int copyfile(const struct vol *s_vol,
1460 const struct vol *d_vol,
1465 struct adouble *adp)
1467 struct adouble ads, add;
1474 LOG(log_debug, logtype_afpd, "copyfile(sfd:%d,s:'%s',d:'%s',n:'%s')",
1475 sfd, src, dst, newname);
1478 ad_init(&ads, s_vol);
1482 adflags = ADFLAGS_DF | ADFLAGS_RF | ADFLAGS_NORF;
1484 adflags |= ADFLAGS_HF;
1487 if (ad_openat(adp, sfd, src, adflags | ADFLAGS_NOHF | ADFLAGS_RDONLY) < 0) {
1492 if (!AD_RSRC_OPEN(adp))
1493 /* no resource fork, don't create one for dst file */
1494 adflags &= ~ADFLAGS_RF;
1496 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1498 if (stat_result < 0) {
1499 /* unlikely but if fstat fails, the default file mode will be 0666. */
1500 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1503 ad_init(&add, d_vol);
1504 if (ad_open(&add, dst, adflags | ADFLAGS_RDWR | ADFLAGS_CREATE | ADFLAGS_EXCL, st.st_mode) < 0) {
1506 ad_close( adp, adflags );
1507 if (EEXIST != ret_err) {
1508 deletefile(d_vol, -1, dst, 0);
1511 return AFPERR_EXIST;
1514 if (AD_RSRC_OPEN(adp))
1515 err = copy_fork(ADEID_RFORK, &add, adp);
1518 err = copy_fork(ADEID_DFORK, &add, adp);
1520 if ((err == 0) && (ad_meta_fileno(adp) != -1))
1521 err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst);
1526 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1527 /* set the new name in the resource fork */
1528 ad_copy_header(&add, adp);
1529 ad_setname(&add, newname);
1532 ad_close( adp, adflags );
1534 if (ad_close( &add, adflags ) <0) {
1539 deletefile(d_vol, -1, dst, 0);
1541 else if (stat_result == 0) {
1542 /* set dest modification date to src date */
1545 ut.actime = ut.modtime = st.st_mtime;
1547 /* FIXME netatalk doesn't use resource fork file date
1548 * but maybe we should set its modtime too.
1553 switch ( ret_err ) {
1559 return AFPERR_DFULL;
1561 return AFPERR_NOOBJ;
1563 return AFPERR_ACCESS;
1565 return AFPERR_VLOCK;
1567 return AFPERR_PARAM;
1571 /* -----------------------------------
1572 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1573 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1575 when deletefile is called we don't have lock on it, file is closed (for us)
1576 untrue if called by renamefile
1578 ad_open always try to open file RDWR first and ad_lock takes care of
1579 WRITE lock on read only file.
1582 static int check_attrib(struct adouble *adp)
1584 uint16_t bshort = 0;
1586 ad_getattr(adp, &bshort);
1588 * Does kFPDeleteInhibitBit (bit 8) set?
1590 if ((bshort & htons(ATTRBIT_NODELETE))) {
1591 return AFPERR_OLOCK;
1593 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1599 * dirfd can be used for unlinkat semantics
1601 int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
1604 struct adouble *adp = NULL;
1605 int adflags, err = AFP_OK;
1608 LOG(log_debug, logtype_afpd, "deletefile('%s')", file);
1612 /* was EACCESS error try to get only metadata */
1613 /* we never want to create a resource fork here, we are going to delete it
1614 * moreover sometimes deletefile is called with a no existent file and
1615 * ad_open would create a 0 byte resource fork
1617 if ( ad_metadataat(dirfd, file, ADFLAGS_CHECK_OF, &ad) == 0 ) {
1618 if ((err = check_attrib(&ad))) {
1619 ad_close(&ad, ADFLAGS_HF);
1626 /* try to open both forks at once */
1627 adflags = ADFLAGS_DF;
1628 if (ad_openat(&ad, dirfd, file, adflags | ADFLAGS_RF | ADFLAGS_NORF | ADFLAGS_RDONLY) < 0 ) {
1633 case EACCES: /* maybe it's a file with no write mode for us */
1634 break; /* was return AFPERR_ACCESS;*/
1647 if ( adp && AD_RSRC_OPEN(adp) != -1 ) { /* there's a resource fork */
1648 adflags |= ADFLAGS_RF;
1649 /* FIXME we have a pb here because we want to know if a file is open
1650 * there's a 'priority inversion' if you can't open the ressource fork RW
1651 * you can delete it if it's open because you can't get a write lock.
1653 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1656 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1658 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1664 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1665 LOG(log_error, logtype_afpd, "deletefile('%s'): ad_tmplock error: %s", file, strerror(errno));
1667 } else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) {
1669 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) {
1670 cnid_delete(vol->v_cdb, id);
1676 ad_close(&ad, ADFLAGS_HF);
1679 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1684 /* ------------------------------------ */
1685 /* return a file id */
1686 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1695 struct path *s_path;
1701 memcpy(&vid, ibuf, sizeof(vid));
1702 ibuf += sizeof(vid);
1704 if (NULL == ( vol = getvolbyvid( vid )) ) {
1705 return( AFPERR_PARAM);
1708 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1712 if (vol->v_flags & AFPVOL_RO)
1713 return AFPERR_VLOCK;
1715 memcpy(&did, ibuf, sizeof( did ));
1716 ibuf += sizeof(did);
1718 if (NULL == ( dir = dirlookup( vol, did )) ) {
1719 return afp_errno; /* was AFPERR_PARAM */
1722 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1723 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1726 if ( path_isadir(s_path) ) {
1727 return( AFPERR_BADTYPE );
1730 upath = s_path->u_name;
1731 switch (s_path->st_errno) {
1733 break; /* success */
1736 return AFPERR_ACCESS;
1738 return AFPERR_NOOBJ;
1740 return AFPERR_PARAM;
1743 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1744 memcpy(rbuf, &id, sizeof(id));
1745 *rbuflen = sizeof(id);
1746 return AFPERR_EXISTID;
1749 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1750 memcpy(rbuf, &id, sizeof(id));
1751 *rbuflen = sizeof(id);
1758 /* ------------------------------- */
1764 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1767 struct reenum *param = data;
1768 struct vol *vol = param->vol;
1769 cnid_t did = param->did;
1772 if ( lstat(de->d_name, &path.st) < 0 )
1775 /* update or add to cnid */
1776 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1781 /* --------------------
1782 * Ok the db is out of synch with the dir.
1783 * but if it's a deleted file we don't want to do it again and again.
1786 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1792 if (vol->v_cdb == NULL) {
1796 /* FIXME use of_statdir ? */
1797 if (lstat(name, &st)) {
1801 if (dirreenumerate(dir, &st)) {
1802 /* we already did it once and the dir haven't been modified */
1803 return dir->d_offcnt;
1807 data.did = dir->d_did;
1808 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1809 setdiroffcnt(curdir, &st, ret);
1810 dir->d_flags |= DIRF_CNID;
1816 /* ------------------------------
1817 resolve a file id */
1818 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1827 uint16_t vid, bitmap;
1829 static char buffer[12 + MAXPATHLEN + 1];
1830 int len = 12 + MAXPATHLEN + 1;
1835 memcpy(&vid, ibuf, sizeof(vid));
1836 ibuf += sizeof(vid);
1838 if (NULL == ( vol = getvolbyvid( vid )) ) {
1839 return( AFPERR_PARAM);
1842 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1846 memcpy(&id, ibuf, sizeof( id ));
1851 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1855 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1856 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1859 if (NULL == ( dir = dirlookup( vol, id )) ) {
1860 return AFPERR_NOID; /* idem AFPERR_PARAM */
1862 if (movecwd(vol, dir) < 0) {
1866 return AFPERR_ACCESS;
1870 return AFPERR_PARAM;
1874 memset(&path, 0, sizeof(path));
1875 path.u_name = upath;
1876 if ( of_stat(&path) < 0 ) {
1878 /* with nfs and our working directory is deleted */
1879 if (errno == ESTALE) {
1883 if ( errno == ENOENT && !retry) {
1884 /* cnid db is out of sync, reenumerate the directory and update ids */
1885 reenumerate_id(vol, ".", dir);
1893 return AFPERR_ACCESS;
1897 return AFPERR_PARAM;
1901 /* directories are bad */
1902 if (S_ISDIR(path.st.st_mode)) {
1903 /* OS9 and OSX don't return the same error code */
1904 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1907 memcpy(&bitmap, ibuf, sizeof(bitmap));
1908 bitmap = ntohs( bitmap );
1909 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1913 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1914 rbuf + sizeof(bitmap), &buflen))) {
1917 *rbuflen = buflen + sizeof(bitmap);
1918 memcpy(rbuf, ibuf, sizeof(bitmap));
1923 /* ------------------------------ */
1924 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1934 static char buffer[12 + MAXPATHLEN + 1];
1935 int len = 12 + MAXPATHLEN + 1;
1940 memcpy(&vid, ibuf, sizeof(vid));
1941 ibuf += sizeof(vid);
1943 if (NULL == ( vol = getvolbyvid( vid )) ) {
1944 return( AFPERR_PARAM);
1947 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1951 if (vol->v_flags & AFPVOL_RO)
1952 return AFPERR_VLOCK;
1954 memcpy(&id, ibuf, sizeof( id ));
1958 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1962 if (NULL == ( dir = dirlookup( vol, id )) ) {
1963 if (afp_errno == AFPERR_NOOBJ) {
1967 return( AFPERR_PARAM );
1971 if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) {
1975 return AFPERR_ACCESS;
1980 /* still try to delete the id */
1984 return AFPERR_PARAM;
1987 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1988 return AFPERR_BADTYPE;
1991 if (cnid_delete(vol->v_cdb, fileid)) {
1994 return AFPERR_VLOCK;
1997 return AFPERR_ACCESS;
1999 return AFPERR_PARAM;
2006 /* ------------------------------ */
2007 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
2011 if (path->st_errno) {
2012 switch (path->st_errno) {
2014 afp_errno = AFPERR_NOID;
2018 afp_errno = AFPERR_ACCESS;
2021 afp_errno = AFPERR_PARAM;
2026 /* we use file_access both for legacy Mac perm and
2027 * for unix privilege, rename will take care of folder perms
2029 if (file_access(path, OPENACC_WR ) < 0) {
2030 afp_errno = AFPERR_ACCESS;
2034 if ((*of = of_findname(path))) {
2035 /* reuse struct adouble so it won't break locks */
2039 ret = ad_open(adp, path->u_name, ADFLAGS_HF | ADFLAGS_RDWR);
2041 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
2043 * The user must have the Read & Write privilege for both files in order to use this command.
2045 ad_close(adp, ADFLAGS_HF);
2046 afp_errno = AFPERR_ACCESS;
2053 #define APPLETEMP ".AppleTempXXXXXX"
2055 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2057 struct stat srcst, destst;
2059 struct dir *dir, *sdir;
2060 char *spath, temp[17], *p;
2061 char *supath, *upath;
2066 struct adouble *adsp = NULL;
2067 struct adouble *addp = NULL;
2068 struct ofork *s_of = NULL;
2069 struct ofork *d_of = NULL;
2082 memcpy(&vid, ibuf, sizeof(vid));
2083 ibuf += sizeof(vid);
2085 if (NULL == ( vol = getvolbyvid( vid )) ) {
2086 return( AFPERR_PARAM);
2089 if ((vol->v_flags & AFPVOL_RO))
2090 return AFPERR_VLOCK;
2092 /* source and destination dids */
2093 memcpy(&sid, ibuf, sizeof(sid));
2094 ibuf += sizeof(sid);
2095 memcpy(&did, ibuf, sizeof(did));
2096 ibuf += sizeof(did);
2099 if (NULL == (dir = dirlookup( vol, sid )) ) {
2100 return afp_errno; /* was AFPERR_PARAM */
2103 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2104 return get_afp_errno(AFPERR_NOOBJ);
2107 if ( path_isadir(path) ) {
2108 return AFPERR_BADTYPE; /* it's a dir */
2111 /* save some stuff */
2114 spath = obj->oldtmp;
2115 supath = obj->newtmp;
2116 strcpy(spath, path->m_name);
2117 strcpy(supath, path->u_name); /* this is for the cnid changing */
2118 p = absupath( vol, sdir, supath);
2120 /* pathname too long */
2121 return AFPERR_PARAM ;
2125 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2129 /* ***** from here we may have resource fork open **** */
2131 /* look for the source cnid. if it doesn't exist, don't worry about
2133 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2135 if (NULL == ( dir = dirlookup( vol, did )) ) {
2136 err = afp_errno; /* was AFPERR_PARAM */
2137 goto err_exchangefile;
2140 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2141 err = get_afp_errno(AFPERR_NOOBJ);
2142 goto err_exchangefile;
2145 if ( path_isadir(path) ) {
2146 err = AFPERR_BADTYPE;
2147 goto err_exchangefile;
2150 /* FPExchangeFiles is the only call that can return the SameObj
2152 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2153 err = AFPERR_SAMEOBJ;
2154 goto err_exchangefile;
2158 if (!(addp = find_adouble( path, &d_of, &add))) {
2160 goto err_exchangefile;
2164 /* they are not on the same device and at least one is open
2165 * FIXME broken for for crossdev and adouble v2
2168 crossdev = (srcst.st_dev != destst.st_dev);
2169 if (/* (d_of || s_of) && */ crossdev) {
2171 goto err_exchangefile;
2174 /* look for destination id. */
2175 upath = path->u_name;
2176 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2178 /* construct a temp name.
2179 * NOTE: the temp file will be in the dest file's directory. it
2180 * will also be inaccessible from AFP. */
2181 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2182 if (!mktemp(temp)) {
2184 goto err_exchangefile;
2188 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2189 ad_close(adsp, ADFLAGS_HF);
2190 ad_close(addp, ADFLAGS_HF);
2193 /* now, quickly rename the file. we error if we can't. */
2194 if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK)
2195 goto err_exchangefile;
2196 of_rename(vol, s_of, sdir, spath, curdir, temp);
2198 /* rename destination to source */
2199 if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK)
2200 goto err_src_to_tmp;
2201 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2203 /* rename temp to destination */
2204 if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK)
2205 goto err_dest_to_src;
2206 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2208 /* id's need switching. src -> dest and dest -> src.
2209 * we need to re-stat() if it was a cross device copy.
2212 cnid_delete(vol->v_cdb, sid);
2214 cnid_delete(vol->v_cdb, did);
2216 if ((did && ( (crossdev && lstat( upath, &srcst) < 0) ||
2217 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2219 (sid && ( (crossdev && lstat(p, &destst) < 0) ||
2220 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2225 err = AFPERR_ACCESS;
2230 goto err_temp_to_dest;
2233 /* here we need to reopen if crossdev */
2234 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2239 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2244 /* change perms, src gets dest perm and vice versa */
2249 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2250 err = AFP_OK; /* ignore error */
2251 goto err_temp_to_dest;
2255 * we need to exchange ACL entries as well
2257 /* exchange_acls(vol, p, upath); */
2262 path->m_name = NULL;
2263 path->u_name = upath;
2265 setfilunixmode(vol, path, destst.st_mode);
2266 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2273 setfilunixmode(vol, path, srcst.st_mode);
2274 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2276 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2277 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2282 goto err_exchangefile;
2284 /* all this stuff is so that we can unwind a failed operation
2287 /* rename dest to temp */
2288 renamefile(vol, -1, upath, temp, temp, adsp);
2289 of_rename(vol, s_of, curdir, upath, curdir, temp);
2292 /* rename source back to dest */
2293 renamefile(vol, -1, p, upath, path->m_name, addp);
2294 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2297 /* rename temp back to source */
2298 renamefile(vol, -1, temp, p, spath, adsp);
2299 of_rename(vol, s_of, curdir, temp, sdir, spath);
2302 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2303 ad_close(adsp, ADFLAGS_HF);
2305 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2306 ad_close(addp, ADFLAGS_HF);
2310 if ((cached = dircache_search_by_did(vol, sid)) != NULL)
2311 (void)dir_remove(vol, cached);
2312 if ((cached = dircache_search_by_did(vol, did)) != NULL)
2313 (void)dir_remove(vol, cached);