dtfile: Resolve CID 89319
[oweals/cde.git] / cde / programs / dtfile / ModAttrP.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: ModAttrP.c /main/8 1999/12/09 13:07:16 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           ModAttrP.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    Processing functions for the modify file attribute dialog.
32  *
33  *   FUNCTIONS: AttrChangePipeCB
34  *              AttrChangeProcess
35  *              ModAttrChange
36  *              ModAttrClose
37  *              ShowModAttrDialog
38  *
39  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
40  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
41  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
42  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
43  *
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 #if defined __osf__ || defined _AIX
48 #include <stdio.h>
49 #endif
50   
51 #include <grp.h>
52 #include <pwd.h>
53 #include <errno.h>
54 #include <ctype.h>
55
56 #include <Xm/Xm.h>
57 #include <Xm/XmP.h>
58 #include <Xm/RowColumn.h>
59
60 #include <Dt/Connect.h>
61 #include <Dt/FileM.h>
62 #include <Dt/SharedProcs.h>
63
64 #include <Tt/tttk.h>
65
66 #include "Encaps.h"
67 #include "SharedProcs.h"
68 #include "FileMgr.h"
69 #include "Desktop.h"
70 #include "Main.h"
71 #include "Help.h"
72 #include "ModAttr.h"
73
74
75 extern int mod_attr_dialog;
76
77
78 /* types of messages sent through the pipe */
79 #define PIPEMSG_DONE 1
80
81 /* callback data for pipe input handler */
82 typedef struct
83 {
84    char *host;
85    char *directory;
86    char *file;
87    int child;
88 } AttrChangeCBData;
89
90
91 /********    Static Function Declarations    ********/
92
93 void ModAttrChange(
94                         XtPointer client_data,
95                         DialogData *old_dialog_data,
96                         DialogData *new_dialog_data,
97                         XtPointer call_data) ;
98 void ModAttrClose(
99                         XtPointer client_data,
100                         DialogData *old_dialog_data,
101                         DialogData *new_dialog_data) ;
102
103 /********    End Static Function Declarations    ********/
104
105
106 /************************************************************************
107  *
108  *  ShowModAttrDialog
109  *      Callback functions invoked from the Modify Attributes ... menu
110  *      item.  This function displays the file attribute dialog.
111  *
112  ************************************************************************/
113
114 void
115 ShowModAttrDialog(
116         Widget w,
117         XtPointer client_data,
118         XtPointer callback )
119 {
120    FileMgrRec  * file_mgr_rec;
121    DialogData  * dialog_data;
122    FileMgrData * file_mgr_data;
123    DialogData  * attr_dialog;
124    DirectorySet * directory_set;
125    FileViewData * file_view_data;
126    ModAttrRec *modAttr_rec;
127    int count, i;
128    Boolean loadOk=True;
129    char * errorMsg=NULL;
130    char * title=NULL;
131    Arg args[1];
132    Widget mbar;
133    char * tmpStr, *tempStr;
134   
135    XmUpdateDisplay (w);
136
137    if((int)(XtArgVal)client_data != 0)
138       mbar = XtParent(w);
139    else
140       mbar = XmGetPostedFromWidget(XtParent(w));
141
142    XtSetArg(args[0], XmNuserData, &file_mgr_rec);
143    XtGetValues(mbar, args, 1);
144
145    /* Ignore accelerators when we're insensitive */
146    if (client_data == NULL)
147       if ((file_mgr_rec->menuStates & MODIFY) == 0)
148          return;
149
150    /* Ignore accelerators received after we're unposted */
151    if ((dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec)) == NULL)
152       return;
153    file_mgr_data = (FileMgrData *) dialog_data->data;
154
155    /* get the file_view_data object from which the menu was invoked */
156    if (client_data == NULL)
157      file_view_data = NULL;
158    else
159    {
160      file_view_data = file_mgr_data->popup_menu_icon;
161      if (file_view_data == NULL)
162        /* the object has gone away (probably deleted) */
163        return;
164
165      file_mgr_data->popup_menu_icon = NULL; /* Reset it, we don't need it */
166    }
167
168
169    attr_dialog = _DtGetDefaultDialogData (mod_attr_dialog);
170
171    file_mgr_rec->menuStates &= ~MODIFY;
172    if (file_view_data == NULL)
173    {
174       directory_set =
175          (DirectorySet *) file_mgr_data->selection_list[0]->directory_set;
176
177       /* Determine which file is selected */
178       loadOk =  LoadFileAttributes(file_mgr_data->host, directory_set->name,
179                       file_mgr_data->selection_list[0]->file_data->file_name,
180                       (ModAttrData *)attr_dialog->data);
181    }
182    else
183    {
184       directory_set =
185          (DirectorySet *)file_view_data->directory_set;
186
187       /* Determine which file is selected */
188       loadOk =  LoadFileAttributes(file_mgr_data->host, directory_set->name,
189                       file_view_data->file_data->file_name,
190                       (ModAttrData *)attr_dialog->data);
191    }
192
193    if (loadOk)
194    {
195      /* Get the initial attribute values for seleceted file */
196      _DtAddOneSubdialog (attr_dialog,
197                       &file_mgr_data->attr_dialog_list,
198                       &file_mgr_data->attr_dialog_count);
199      /* We need the file_mgr_rec inside the create routine so
200       * we attach it here for use later.
201       */
202      ((ModAttrData *) (attr_dialog->data))->main_widget = file_mgr_rec->main;
203
204      _DtShowDialog (file_mgr_rec->shell, NULL,
205                  (XtPointer)file_mgr_rec, attr_dialog,
206                  ModAttrChange, (XtPointer)file_mgr_rec, ModAttrClose,
207                  (XtPointer)file_mgr_rec,NULL, False, False, NULL, NULL);
208
209      for(i = 0; i < file_mgr_data->attr_dialog_count; i++)
210      {
211         modAttr_rec = (ModAttrRec *)_DtGetDialogInstance(
212                                        file_mgr_data->attr_dialog_list[i]);
213
214         if(file_mgr_data->title != NULL &&
215                    strcmp(file_mgr_data->helpVol, DTFILE_HELP_NAME) != 0)
216         {
217            tmpStr = GETMESSAGE(21, 1, "File Permissions");
218            tempStr = (char *)XtMalloc(strlen(tmpStr) +
219                                  strlen(file_mgr_data->title) + 5);
220            sprintf(tempStr, "%s - %s", file_mgr_data->title, tmpStr);
221         }
222         else
223         {
224            tmpStr = (GETMESSAGE(21,34, "File Manager - Permissions"));
225            tempStr = XtNewString(tmpStr);
226         }
227         XtSetArg (args[0], XmNtitle, tempStr);
228         XtSetValues (modAttr_rec->shell, args, 1);
229         XtFree(tempStr);
230       }
231    }
232    else
233    {
234      /* Clean up used structures and put up an error dialog */
235
236      file_mgr_rec->menuStates |= MODIFY;
237      _DtFreeDialogData (attr_dialog);
238  
239      tmpStr = GETMESSAGE(22, 4, "Cannot open object.");
240      errorMsg = XtNewString(tmpStr);
241      tmpStr = GETMESSAGE(22, 5, "Set Permissions Error");
242      title = XtNewString(tmpStr);
243      _DtMessage (file_mgr_rec->shell, title, errorMsg, NULL, HelpRequestCB);
244      XtFree(title);
245      XtFree(errorMsg);
246    }
247 }
248
249
250
251
252 /************************************************************************
253  *
254  *  ModAttrChange
255  *      Callback functions invoked from the file attribute dialog's
256  *      Ok button being pressed.  This function updates the indicated
257  *      file.
258  *
259  ************************************************************************/
260
261 /*--------------------------------------------------------------------
262  * AttrChangeProcess
263  *   Main routine of background process for AttrChange
264  *------------------------------------------------------------------*/
265
266 static int
267 AttrChangeProcess(
268         int pipe_fd,
269         char *host,
270         char *directory,
271         char *file,
272         int uid,
273         int gid,
274         long mode)
275 {
276   char *path;
277   struct stat stat_buf;
278   long modify_time;
279   short pipe_msg;
280   int rc = -1;
281   Tt_status tt_status;
282
283   /* get directory timestamp */
284   path = ResolveLocalPathName(host, directory, NULL,home_host_name, &tt_status);
285   if( TT_OK == tt_status )
286   {
287     if (stat(path, &stat_buf) == 0)
288       modify_time = stat_buf.st_mtime;
289     XtFree(path);
290
291     /* change the file attributes */
292     path = ResolveLocalPathName(host, directory, file, home_host_name, &tt_status);
293     if( TT_OK == tt_status )
294     {
295       if (chmod(path, mode) == 0)
296       {
297         rc = 0;
298         chown(path, uid, gid);
299       }
300       else
301         rc = errno;
302       XtFree (path);
303     }
304   }
305
306   /* send a 'done' msg through the pipe */
307   DPRINTF(("AttrChangeProcess: sending DONE, rc %d\n", rc));
308   pipe_msg = PIPEMSG_DONE;
309   write(pipe_fd, &pipe_msg, sizeof(short));
310   write(pipe_fd, &rc, sizeof(int));
311   write(pipe_fd, &modify_time, sizeof(long));
312
313   return rc;
314 }
315
316
317 /*--------------------------------------------------------------------
318  * AttrChangePipeCB:
319  *   Read and process data sent through the pipe.
320  *------------------------------------------------------------------*/
321
322 static void
323 AttrChangePipeCB(
324    XtPointer client_data,
325    int *fd,
326    XtInputId *id)
327 {
328    AttrChangeCBData *cb_data = (AttrChangeCBData *)client_data;
329    short pipe_msg;
330    char *title, *err_msg, *err_arg;
331    long modify_time;
332    int i, n, rc;
333
334    /* read the msg from the pipe */
335    pipe_msg = -1;
336    n = PipeRead(*fd, &pipe_msg, sizeof(short));
337
338    if (pipe_msg == PIPEMSG_DONE)
339    {
340       PipeRead(*fd, &rc, sizeof(int));
341       PipeRead(*fd, &modify_time, sizeof(long));
342    }
343    else
344    {
345       fprintf(stderr, "Internal error in AttrChangePipeCB: bad pipe_msg %d\n",
346               pipe_msg);
347       rc = 0;
348       modify_time = 0;
349    }
350
351    DPRINTF(("AttrChangePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
352
353    /* if error, post error message */
354    if (rc)
355    {
356       err_msg = XtNewString(GETMESSAGE(22,3,"Cannot change properties for %s"));
357       FileOperationError(toplevel, err_msg, cb_data->file);
358       XtFree(err_msg);
359    }
360
361    /* arrange for modified directory to be updated */
362    if (modify_time != 0)
363       DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
364    DirectoryFileModified(cb_data->host, cb_data->directory, cb_data->file);
365    DirectoryEndModify(cb_data->host, cb_data->directory);
366    if(!strcmp(cb_data->file,".") || !strcmp(cb_data->file,".."))
367    {
368        char *dir;
369        char *tmpptr = strrchr(cb_data->directory,'/');
370        if(tmpptr)
371        {
372            if(tmpptr != cb_data->directory)
373                tmpptr = NULL, dir = cb_data->directory;
374            else
375                dir = "/";
376            DirectoryBeginModify(cb_data->host,dir);
377            DirectoryFileModified(cb_data->host,dir, tmpptr+1);
378            DirectoryEndModify(cb_data->host,dir);
379            
380            if(tmpptr)
381                *tmpptr='/';
382        }
383    }
384    else
385    {
386        char subdir_name[MAX_PATH + 1];
387        char *p;
388        
389        strcpy(subdir_name, cb_data->directory);
390        p = subdir_name + strlen(subdir_name);
391        if (p[-1] != '/')
392            *p++ = '/';
393        
394        strcpy(p, cb_data->file);
395        UpdateDirectory(NULL,cb_data->host, subdir_name);
396    }
397
398    /* close the pipe and cancel the callback */
399    close(*fd);
400    XtRemoveInput(*id);
401
402    /* free callback data */
403    XtFree(cb_data->host);
404    XtFree(cb_data->directory);
405    XtFree(cb_data->file);
406    XtFree((char *)cb_data);
407 }
408
409
410 /*--------------------------------------------------------------------
411  * ModAttrChange:
412  *    Start the background process and set up callback for the pipe.
413  *------------------------------------------------------------------*/
414
415 void
416 ModAttrChange(
417         XtPointer client_data,
418         DialogData *old_dialog_data,
419         DialogData *new_dialog_data,
420         XtPointer call_data )
421 {
422    static char *pname = "ModAttrChange";
423    AttrChangeCBData *cb_data;
424    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
425    ModAttrData * current;
426    ModAttrData * old;
427    struct group * gr;
428    struct passwd * pw;
429    int uid, gid;
430    long mode;
431    int pipe_fd[2];
432    int pid;
433    int rc;
434
435    /* Get current data */
436    current = (ModAttrData *) new_dialog_data->data;
437    old = (ModAttrData *) old_dialog_data->data;
438
439    /* see if anything has changed */
440    if (strcmp(current->owner, old->owner) == 0 &&
441        strcmp(current->group, old->group) == 0 &&
442        current->accessBits == old->accessBits &&
443        current->setuidBits == old->setuidBits)
444    {
445       /* nothing changed: close the dialog and return */
446        ModAttrClose ((XtPointer)file_mgr_rec, old_dialog_data, new_dialog_data);
447        return;
448    }
449
450    /* get new owner uid */
451    pw = getpwnam(current->owner);
452    if (pw)
453       uid = pw->pw_uid;
454    else if (isdigit(current->owner[0]))
455       uid = atoi(current->owner);
456    else
457       uid = -1;
458
459    /* get new group gid */
460    gr = getgrnam(current->group);
461    if (gr)
462       gid = gr->gr_gid;
463    else if (isdigit(current->group[0]))
464       gid = atoi(current->group);
465    else
466       gid = -1;
467
468    /* get new file mode */
469    mode = current->accessBits + current->setuidBits;
470
471    /* set up callback data */
472    cb_data = XtNew(AttrChangeCBData);
473    cb_data->host = XtNewString(current->host);
474    cb_data->directory = XtNewString(current->directory);
475    cb_data->file = XtNewString(current->name);
476
477    /* mark the directory as being modified in the directory cache */
478    DirectoryBeginModify(cb_data->host, cb_data->directory);
479
480    /* create a pipe */
481    pipe(pipe_fd);
482
483    /* fork the process that does the actual work */
484    pid = fork();
485    if (pid == -1)
486    {
487        DirectoryAbortModify(cb_data->host, cb_data->directory);
488        fprintf(stderr,
489                 "%s:  fork failed, ppid %d, pid %d: error %d=%s\n",
490                 pname, getppid(), getpid(), errno, strerror(errno));
491        return;
492    }
493
494    if (pid == 0)
495    {
496       /* child process */
497       DBGFORK(("%s:  child forked, pipe %d\n", pname, pipe_fd[1]));
498
499       close(pipe_fd[0]);  /* child won't read from the pipe */
500
501       rc = AttrChangeProcess(pipe_fd[1], cb_data->host, cb_data->directory,
502                              cb_data->file, uid, gid, mode);
503       close(pipe_fd[1]);
504
505       DBGFORK(("%s:  child exiting (rc %d)\n", pname, rc));
506
507       exit(rc);
508    }
509
510    DBGFORK(("%s:  forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
511
512    /* parent: set up callback to get the pipe data */
513    close(pipe_fd[1]);  /* parent won't write the pipe */
514
515    cb_data->child = pid;
516
517    XtAppAddInput(XtWidgetToApplicationContext(toplevel),
518                  pipe_fd[0], (XtPointer)XtInputReadMask,
519                  AttrChangePipeCB, (XtPointer)cb_data);
520
521    ModAttrClose ((XtPointer)file_mgr_rec, old_dialog_data, new_dialog_data);
522 }
523
524
525
526
527 /************************************************************************
528  *
529  *  ModAttrClose
530  *      Callback function invoked from the file attribute dialog's close
531  *      button.
532  *
533  ************************************************************************/
534
535 void
536 ModAttrClose(
537         XtPointer client_data,
538         DialogData *old_dialog_data,
539         DialogData *new_dialog_data )
540 {
541    FileMgrRec  * file_mgr_rec = (FileMgrRec *) client_data;
542    FileMgrData * file_mgr_data;
543    DialogData  * dialog_data;
544    int count;
545    int i, j;
546
547
548
549    dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
550    file_mgr_data = (FileMgrData *) dialog_data->data;
551
552    if(file_mgr_data->selected_file_count > 0)
553       file_mgr_rec->menuStates |= MODIFY;
554
555
556    /*  Remove the dialog data from the file managers list  */
557    _DtHideOneSubdialog( old_dialog_data,
558                      &file_mgr_data->attr_dialog_list,
559                      &file_mgr_data->attr_dialog_count);
560
561    _DtHideDialog (old_dialog_data, False);
562    _DtFreeDialogData (old_dialog_data);
563    _DtFreeDialogData (new_dialog_data);
564 }