]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: fileutl.cc,v 1.27 1999/04/20 05:02:09 jgg Exp $
4 /* ######################################################################
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
11 This source is placed in the Public Domain, do with it what you will
12 It was originally written by Jason Gunthorpe.
14 ##################################################################### */
16 // Include Files /*{{{*/
18 #pragma implementation "apt-pkg/fileutl.h"
20 #include <apt-pkg/fileutl.h>
21 #include <apt-pkg/error.h>
25 #include <sys/fcntl.h>
26 #include <sys/types.h>
32 // CopyFile - Buffered copy of a file /*{{{*/
33 // ---------------------------------------------------------------------
34 /* The caller is expected to set things so that failure causes erasure */
35 bool CopyFile(FileFd
&From
,FileFd
&To
)
37 if (From
.IsOpen() == false || To
.IsOpen() == false)
40 // Buffered copy between fds
41 unsigned char *Buf
= new unsigned char[64000];
42 unsigned long Size
= From
.Size();
45 unsigned long ToRead
= Size
;
49 if (From
.Read(Buf
,ToRead
) == false ||
50 To
.Write(Buf
,ToRead
) == false)
63 // GetLock - Gets a lock file /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This will create an empty file of the given name and lock it. Once this
66 is done all other calls to GetLock in any other process will fail with
67 -1. The return result is the fd of the file, the call should call
68 close at some time. */
69 int GetLock(string File
,bool Errors
)
71 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_TRUNC
,0640);
75 _error
->Errno("open","Could not open lock file %s",File
.c_str());
79 // Aquire a write lock
82 fl
.l_whence
= SEEK_SET
;
85 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
89 _error
->Warning("Not using locking for nfs mounted lock file %s",File
.c_str());
93 _error
->Errno("open","Could not get lock %s",File
.c_str());
101 // FileExists - Check if a file exists /*{{{*/
102 // ---------------------------------------------------------------------
104 bool FileExists(string File
)
107 if (stat(File
.c_str(),&Buf
) != 0)
112 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
113 // ---------------------------------------------------------------------
114 /* We return / on failure. */
117 // Stash the current dir.
120 if (getcwd(S
,sizeof(S
)-2) == 0)
122 unsigned int Len
= strlen(S
);
128 // flNotDir - Strip the directory from the filename /*{{{*/
129 // ---------------------------------------------------------------------
131 string
flNotDir(string File
)
133 string::size_type Res
= File
.rfind('/');
134 if (Res
== string::npos
)
137 return string(File
,Res
,Res
- File
.length());
140 // flNotFile - Strip the file from the directory name /*{{{*/
141 // ---------------------------------------------------------------------
143 string
flNotFile(string File
)
145 string::size_type Res
= File
.rfind('/');
146 if (Res
== string::npos
)
149 return string(File
,0,Res
);
152 // SetCloseExec - Set the close on exec flag /*{{{*/
153 // ---------------------------------------------------------------------
155 void SetCloseExec(int Fd
,bool Close
)
157 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
159 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
164 // SetNonBlock - Set the nonblocking flag /*{{{*/
165 // ---------------------------------------------------------------------
167 void SetNonBlock(int Fd
,bool Block
)
169 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
170 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
172 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
177 // WaitFd - Wait for a FD to become readable /*{{{*/
178 // ---------------------------------------------------------------------
179 /* This waits for a FD to become readable using select. It is usefull for
180 applications making use of non-blocking sockets. The timeout is
182 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
195 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
197 while (Res
< 0 && errno
== EINTR
);
207 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
209 while (Res
< 0 && errno
== EINTR
);
218 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
219 // ---------------------------------------------------------------------
220 /* This is used if you want to cleanse the environment for the forked
221 child, it fixes up the important signals and nukes all of the fds,
222 otherwise acts like normal fork. */
225 // Fork off the process
226 pid_t Process
= fork();
229 cerr
<< "FATAL -> Failed to fork." << endl
;
233 // Spawn the subprocess
237 signal(SIGPIPE
,SIG_DFL
);
238 signal(SIGQUIT
,SIG_DFL
);
239 signal(SIGINT
,SIG_DFL
);
240 signal(SIGWINCH
,SIG_DFL
);
241 signal(SIGCONT
,SIG_DFL
);
242 signal(SIGTSTP
,SIG_DFL
);
244 // Close all of our FDs - just in case
245 for (int K
= 3; K
!= 40; K
++)
246 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
253 // FileFd::FileFd - Open a file /*{{{*/
254 // ---------------------------------------------------------------------
255 /* The most commonly used open mode combinations are given with Mode */
256 FileFd::FileFd(string FileName
,OpenMode Mode
, unsigned long Perms
)
262 iFd
= open(FileName
.c_str(),O_RDONLY
);
268 if (stat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
269 unlink(FileName
.c_str());
270 iFd
= open(FileName
.c_str(),O_RDWR
| O_CREAT
| O_TRUNC
,Perms
);
275 iFd
= open(FileName
.c_str(),O_RDWR
);
279 iFd
= open(FileName
.c_str(),O_RDWR
| O_CREAT
,Perms
);
284 _error
->Errno("open","Could not open file %s",FileName
.c_str());
287 this->FileName
= FileName
;
288 SetCloseExec(iFd
,true);
292 // FileFd::~File - Closes the file /*{{{*/
293 // ---------------------------------------------------------------------
294 /* If the proper modes are selected then we close the Fd and possibly
295 unlink the file on error. */
301 // FileFd::Read - Read a bit of the file /*{{{*/
302 // ---------------------------------------------------------------------
303 /* We are carefull to handle interruption by a signal while reading
305 bool FileFd::Read(void *To
,unsigned long Size
)
311 Res
= read(iFd
,To
,Size
);
312 if (Res
< 0 && errno
== EINTR
)
317 return _error
->Errno("read","Read error");
320 To
= (char *)To
+ Res
;
323 while (Res
> 0 && Size
> 0);
329 return _error
->Error("read, still have %u to read but none left",Size
);
332 // FileFd::Write - Write to the file /*{{{*/
333 // ---------------------------------------------------------------------
335 bool FileFd::Write(const void *From
,unsigned long Size
)
341 Res
= write(iFd
,From
,Size
);
342 if (Res
< 0 && errno
== EINTR
)
347 return _error
->Errno("write","Write error");
350 From
= (char *)From
+ Res
;
353 while (Res
> 0 && Size
> 0);
359 return _error
->Error("write, still have %u to write but couldn't",Size
);
362 // FileFd::Seek - Seek in the file /*{{{*/
363 // ---------------------------------------------------------------------
365 bool FileFd::Seek(unsigned long To
)
367 if (lseek(iFd
,To
,SEEK_SET
) != (signed)To
)
370 return _error
->Error("Unable to seek to %u",To
);
376 // FileFd::Truncate - Truncate the file /*{{{*/
377 // ---------------------------------------------------------------------
379 bool FileFd::Truncate(unsigned long To
)
381 if (ftruncate(iFd
,To
) != 0)
384 return _error
->Error("Unable to truncate to %u",To
);
390 // FileFd::Tell - Current seek position /*{{{*/
391 // ---------------------------------------------------------------------
393 unsigned long FileFd::Tell()
395 off_t Res
= lseek(iFd
,0,SEEK_CUR
);
396 if (Res
== (off_t
)-1)
397 _error
->Errno("lseek","Failed to determine the current file position");
401 // FileFd::Size - Return the size of the file /*{{{*/
402 // ---------------------------------------------------------------------
404 unsigned long FileFd::Size()
407 if (fstat(iFd
,&Buf
) != 0)
408 return _error
->Errno("fstat","Unable to determine the file size");
412 // FileFd::Close - Close the file if the close flag is set /*{{{*/
413 // ---------------------------------------------------------------------
418 if ((Flags
& AutoClose
) == AutoClose
)
419 if (iFd
>= 0 && close(iFd
) != 0)
420 Res
&= _error
->Errno("close","Problem closing the file");
423 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
424 FileName
.empty() == false)
425 if (unlink(FileName
.c_str()) != 0)
426 Res
&= _error
->Warning("unlnk","Problem unlinking the file");