ide: In Posix, ide now handles non-owned files and symlinks differently #230

git-svn-id: svn://ultimatepp.org/upp/trunk@6922 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2014-02-16 13:51:30 +00:00
parent 6b1c0d81ea
commit d9fde3de2b
10 changed files with 148 additions and 61 deletions

View file

@ -257,6 +257,7 @@ void BlockStream::OpenInit(dword mode, int64 _filesize) {
if(!buffer)
SetBufferSize(4096);
if(mode == APPEND) SeekEnd();
ClearError();
}
// ---------------------------- File stream -----------------------------

View file

@ -653,6 +653,17 @@ struct stat& FindFile::Stat() const {
return statf;
}
bool FindFile::CanMode(dword usr, dword grp, dword oth) const
{
const struct stat& s = Stat();
dword mode = GetMode();
static uid_t uid = getuid();
static gid_t gid = getgid();
return (mode & oth) ||
(mode & grp) && gid == s.st_gid ||
(mode & usr) && uid == s.st_uid;
}
bool FindFile::IsSymLink() const
{
if(file) {

View file

@ -119,6 +119,7 @@ class FindFile : NoCopy {
String pattern;
struct stat &Stat() const;
bool CanMode(dword usr, dword grp, dword oth) const;
public:
bool Search(const char *name);
@ -133,7 +134,14 @@ public:
FileTime GetLastAccessTime() const { return Stat().st_atime; }
FileTime GetLastWriteTime() const { return Stat().st_mtime; }
bool IsReadOnly() const { return !(GetMode() & (S_IWUSR|S_IWGRP|S_IWOTH)); }
uid_t GetUid() { return Stat().st_uid; }
gid_t GetGid() { return Stat().st_gid; }
bool CanRead() const { return CanMode(S_IRUSR, S_IRGRP, S_IROTH); }
bool CanWrite() const { return CanMode(S_IWUSR, S_IWGRP, S_IWOTH); }
bool CanExecute() const { return CanMode(S_IXUSR, S_IXGRP, S_IXOTH); }
bool IsReadOnly() const { return CanRead() && !CanWrite(); }
bool IsHidden() const { return *name == '.'; }
bool IsDirectory() const { return S_ISDIR(GetMode()); }

View file

@ -1089,6 +1089,7 @@ void CompareStream::Open(Stream& astream) {
wrlim = buffer + 128;
ptr = buffer;
equal = true;
ClearError();
}
bool CompareStream::IsOpen() const {

View file

@ -66,6 +66,34 @@ with all filesystems.&]
_[@(0.0.255) const]&]
[s2;%% Returns the last time the entry was modified. Always works.&]
[s3;%% &]
[s4; &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: uid`_t_[* GetUid]()&]
[s6;%% `[POSIX`]&]
[s2;%% Returns user ID of file.&]
[s3; &]
[s4; &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: gid`_t_[* GetGid]()&]
[s6;%% `[POSIX`]&]
[s2;%% Returns group ID of file.&]
[s3; &]
[s4; &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanRead]()_[@(0.0.255) co
nst]&]
[s6;%% `[POSIX`]&]
[s2;%% Returns true if current user can read the file.&]
[s3; &]
[s4; &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanWrite]()_[@(0.0.255) c
onst]&]
[s6;%% `[POSIX`]&]
[s2;%% Returns true if current user can write the file.&]
[s3; &]
[s4; &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [@(0.0.255) bool]_[* CanExecute]()_[@(0.0.255) c
onst]&]
[s6;%% `[POSIX`]&]
[s2;%% Returns true if current user can execute the file.&]
[s3; &]
[s4;%% &]
[s5;:FindFile`:`:GetLastChangeTime`(`)const: [_^FileTime^ FileTime]_[* GetLastChangeTime](
)_[@(0.0.255) const]&]

View file

@ -284,7 +284,8 @@ onst]&]
[s7; [* Return value]-|Size of stream.&]
[s3; &]
[s4;%- &]
[s5;K%- [@(0.0.255) virtual] [@(0.0.255) void]_[* SetSize]([_^int64^ int64]_[*@3 size])&]
[s5;:Stream`:`:SetSize`(int64`):%- [@(0.0.255) virtual] [@(0.0.255) void]_[* SetSize]([_^int64^ i
nt64]_[*@3 size])&]
[s2; Alters the size of the stream.&]
[s7; [%-*C@3 size]-|New size.&]
[s3; &]

View file

@ -21,6 +21,7 @@ LineEdit::LineEdit() {
filter = NULL;
showspaces = false;
showlines = false;
showreadonly = true;
}
LineEdit::~LineEdit() {}
@ -100,7 +101,7 @@ void LineEdit::Paint0(Draw& w) {
if(w.IsPainting(0, y, sz.cx, fsz.cy)) {
Highlight ih;
ih.ink = color[IsShowEnabled() ? INK_NORMAL : INK_DISABLED];
ih.paper = color[IsReadOnly() || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL];
ih.paper = color[IsReadOnly() && showreadonly || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL];
if(nobg)
ih.paper = Null;
ih.font = font;
@ -221,7 +222,7 @@ void LineEdit::Paint0(Draw& w) {
selh -= len + 1;
pos += len + 1;
}
w.DrawRect(0, y, sz.cx, sz.cy - y, color[IsReadOnly() || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL]);
w.DrawRect(0, y, sz.cx, sz.cy - y, color[IsReadOnly() && showreadonly || !IsShowEnabled() ? PAPER_READONLY : PAPER_NORMAL]);
DrawTiles(w, DropCaret(), CtrlImg::checkers());
}

View file

@ -269,6 +269,7 @@ protected:
bool overwrite;
bool showspaces;
bool showlines;
bool showreadonly;
void Paint0(Draw& w);
@ -362,6 +363,9 @@ public:
LineEdit& NoCutLine() { return WithCutLine(false); }
bool IsWithCutLine() const { return cutline; }
LineEdit& SetFilter(int (*f)(int c)) { filter = f; return *this; }
LineEdit& ShowReadOnly(bool b) { showreadonly = b; Refresh(); return *this; }
LineEdit& NoShowReadOnly() { return ShowReadOnly(false); }
bool IsShowReadOnly() { return showreadonly; }
LineEdit& SetScrollBarStyle(const ScrollBar::Style& s) { sb.SetStyle(s); return *this; }

View file

@ -834,6 +834,7 @@ public:
void EditWorkspace();
void EditAnyFile();
bool IsProjectFile(const String& f) const;
void SaveEditorFile(Stream& out);
void SaveFile0(bool always);
void SaveFile(bool always = false);
void DoSaveFile() { SaveFile(); }

View file

@ -273,6 +273,24 @@ void Ide::SaveFile(bool always)
issaving--;
}
void Ide::SaveEditorFile(Stream& out)
{
if(GetFileExt(editfile) == ".t") {
for(int i = 0; i < editor.GetLineCount(); i++) {
if(i) out.PutCrLf();
out.Put(ConvertTLine(editor.GetUtf8Line(i), ASCSTRING_OCTALHI));
}
}
else {
int le = line_endings;
if(le == DETECT_CRLF)
le = Nvl(editfile_line_endings, CRLF);
if(le == DETECT_LF)
le = Nvl(editfile_line_endings, LF);
editor.Save(out, editor.GetCharset(), le == LF ? TextCtrl::LE_LF : TextCtrl::LE_CRLF);
}
}
void Ide::SaveFile0(bool always)
{
if(designer) {
@ -297,62 +315,71 @@ void Ide::SaveFile0(bool always)
fd.filetime = edittime;
if(!editor.IsDirty() && !always)
return;
#ifdef PLATFORM_POSIX
struct stat statbuf;
int statcode = stat(editfile, &statbuf);
#endif
TouchFile(editfile);
String tmpfile = editfile + ".$tmp", outfile = editfile;
{
FileOut out(tmpfile);
if(!out.IsOpen()) {
if(IsDeactivationSave())
return;
Exclamation(NFormat("Error creating temporary file [* \1%s\1].", tmpfile));
return;
}
if(designer)
designer->Save();
else
if(GetFileExt(editfile) == ".t") {
for(int i = 0; i < editor.GetLineCount(); i++) {
if(i) out.PutCrLf();
out.Put(ConvertTLine(editor.GetUtf8Line(i), ASCSTRING_OCTALHI));
}
#ifdef PLATFORM_POSIX
FindFile ff(editfile);
if(ff && !designer && (ff.GetUid() != getuid() || ff.IsSymLink())) {
for(;;) {
FileStream out;
if(out.Open(editfile, FileStream::READWRITE)) {
SaveEditorFile(out);
out.SetSize(out.GetPos());
if(!out.IsError())
break;
}
else {
int le = line_endings;
if(le == DETECT_CRLF)
le = Nvl(editfile_line_endings, CRLF);
if(le == DETECT_LF)
le = Nvl(editfile_line_endings, LF);
editor.Save(out, editor.GetCharset(), le == LF ? TextCtrl::LE_LF : TextCtrl::LE_CRLF);
console.Flush();
Sleep(200);
int art = Prompt(Ctrl::GetAppName(), CtrlImg::exclamation(),
"Unable to save current file.&"
"Retry save, ignore it or save file to another location?",
"Save as...", "Retry", "Ignore");
if(art < 0)
break;
if(art && AnySourceFs().ExecuteSaveAs()) {
editfile = AnySourceFs();
MakeTitle();
PosSync();
break;
}
out.Close();
if(out.IsError()) {
if(IsDeactivationSave())
return;
Exclamation(NFormat("Error writing temporary file [* \1%s\1].", tmpfile));
return;
}
}
Progress progress;
int time = msecs();
for(;;) {
progress.SetTotal(10000);
progress.SetText(NFormat("Saving '%s'", GetFileName(outfile)));
if(editfile != outfile || !FileExists(tmpfile))
return;
FileDelete(outfile);
if(FileMove(tmpfile, outfile))
break;
if(IsDeactivationSave())
return;
console.Flush();
Sleep(200);
if(progress.SetPosCanceled(msecs(time) % progress.GetTotal()))
}
else
#endif
{
String tmpfile = editfile + ".$tmp", outfile = editfile;
{
FileOut out(tmpfile);
if(!out.IsOpen()) {
if(IsDeactivationSave())
return;
Exclamation(NFormat("Error creating temporary file [* \1%s\1].", tmpfile));
return;
}
if(designer)
designer->Save();
else
SaveEditorFile(out);
out.Close();
if(out.IsError()) {
if(IsDeactivationSave())
return;
Exclamation(NFormat("Error writing temporary file [* \1%s\1].", tmpfile));
return;
}
}
Progress progress;
for(;;) {
if(editfile != outfile || !FileExists(tmpfile))
return;
FileDelete(outfile);
if(FileMove(tmpfile, outfile))
break;
if(IsDeactivationSave())
return;
console.Flush();
int art = Prompt(Ctrl::GetAppName(), CtrlImg::exclamation(),
"Unable to save current file.&"
"Retry save, ignore it or save file to another location?",
@ -365,15 +392,14 @@ void Ide::SaveFile0(bool always)
PosSync();
break;
}
progress.Reset();
}
#ifdef PLATFORM_POSIX
if(ff)
chmod(editfile, ff.GetMode());
#endif
}
#ifdef PLATFORM_POSIX
if(statcode == 0)
chmod(editfile, statbuf.st_mode);
#endif
if(!designer) {
FindFile ff(editfile);
fd.filetime = edittime = ff.GetLastWriteTime();
@ -484,7 +510,7 @@ void Ide::EditFile0(const String& path, byte charset, bool astext, const String&
if(edittime != fd.filetime || IsNull(fd.filetime))
fd.undodata.Clear();
FileIn in(editfile);
if(in)
if(in) {
if(tfile && editastext.Find(editfile) < 0) {
String f;
String ln;
@ -509,14 +535,19 @@ void Ide::EditFile0(const String& path, byte charset, bool astext, const String&
int le = editor.Load(in, charset);
editfile_line_endings = le == TextCtrl::LE_CRLF ? CRLF : le == TextCtrl::LE_LF ? LF : (int)Null;
}
}
else
Exclamation("Failed to read the file.");
editor.SetEditPos(fd.editpos);
if(!IsNull(fd.columnline) && fd.columnline.y >= 0 && fd.columnline.y < editor.GetLineCount())
editor.SetCursor(editor.GetColumnLinePos(fd.columnline));
editor.SetPickUndoData(fd.undodata);
editor.SetLineInfo(fd.lineinfo);
editor.SetLineInfoRem(fd.lineinforem);
if(ff.IsReadOnly() || IsNestReadOnly(editfile))
if(ff.IsReadOnly() || IsNestReadOnly(editfile)) {
editor.SetReadOnly();
editor.NoShowReadOnly();
}
fd.undodata.Clear();
PosSync();
}